@line/bot-sdk
Advanced tools
Comparing version 4.0.0 to 5.0.0
@@ -0,1 +1,17 @@ | ||
## 5.0.0 (2 Nov 2017) | ||
#### Major | ||
* Implement rich menu API (#34) | ||
#### Type | ||
* Rename `ImageMapArea` and `TemplateAction`s into general ones | ||
#### Misc | ||
* Do not enforce `checkJSON` for some APIs where it means nothing | ||
* Change how to check request object in test cases | ||
## 4.0.0 (25 Oct 2017) | ||
@@ -2,0 +18,0 @@ |
/// <reference types="node" /> | ||
import { Readable } from "stream"; | ||
import * as Types from "./types"; | ||
@@ -14,9 +15,20 @@ export default class Client { | ||
getRoomMemberIds(roomId: string): Promise<string[]>; | ||
getMessageContent(messageId: string): Promise<NodeJS.ReadableStream>; | ||
getMessageContent(messageId: string): Promise<Readable>; | ||
leaveGroup(groupId: string): Promise<any>; | ||
leaveRoom(roomId: string): Promise<any>; | ||
getRichMenu(richMenuId: string): Promise<Types.RichMenuResponse>; | ||
createRichMenu(richMenu: Types.RichMenu): Promise<string>; | ||
deleteRichMenu(richMenuId: string): Promise<any>; | ||
getRichMenuIdOfUser(userId: string): Promise<string>; | ||
linkRichMenuToUser(userId: string, richMenuId: string): Promise<any>; | ||
unlinkRichMenuFromUser(userId: string, richMenuId: string): Promise<any>; | ||
getRichMenuImage(richMenuId: string): Promise<Readable>; | ||
setRichMenuImage(richMenuId: string, data: Buffer | Readable, contentType?: string): Promise<any>; | ||
getRichMenuList(): Promise<Array<Types.RichMenuResponse>>; | ||
private authHeader(); | ||
private delete(url); | ||
private get(url); | ||
private post(url, body?); | ||
private postBinary(url, data, contentType?); | ||
private stream(url); | ||
} |
@@ -5,3 +5,14 @@ "use strict"; | ||
const URL = require("./urls"); | ||
const util_1 = require("./util"); | ||
const exceptions_1 = require("./exceptions"); | ||
function toArray(maybeArr) { | ||
return Array.isArray(maybeArr) ? maybeArr : [maybeArr]; | ||
} | ||
function checkJSON(raw) { | ||
if (typeof raw === "object") { | ||
return raw; | ||
} | ||
else { | ||
throw new exceptions_1.JSONParseError("Failed to parse response body as JSON", raw); | ||
} | ||
} | ||
class Client { | ||
@@ -16,3 +27,3 @@ constructor(config) { | ||
return this.post(URL.push, { | ||
messages: util_1.toArray(messages), | ||
messages: toArray(messages), | ||
to, | ||
@@ -23,3 +34,3 @@ }); | ||
return this.post(URL.reply, { | ||
messages: util_1.toArray(messages), | ||
messages: toArray(messages), | ||
replyToken, | ||
@@ -30,3 +41,3 @@ }); | ||
return this.post(URL.multicast, { | ||
messages: util_1.toArray(messages), | ||
messages: toArray(messages), | ||
to, | ||
@@ -36,12 +47,14 @@ }); | ||
getProfile(userId) { | ||
return this.get(URL.profile(userId)); | ||
return this.get(URL.profile(userId)).then(checkJSON); | ||
} | ||
getGroupMemberProfile(groupId, userId) { | ||
return this.get(URL.groupMemberProfile(groupId, userId)); | ||
return this.get(URL.groupMemberProfile(groupId, userId)).then(checkJSON); | ||
} | ||
getRoomMemberProfile(roomId, userId) { | ||
return this.get(URL.roomMemberProfile(roomId, userId)); | ||
return this.get(URL.roomMemberProfile(roomId, userId)).then(checkJSON); | ||
} | ||
getGroupMemberIds(groupId) { | ||
const load = (start) => this.get(URL.groupMemberIds(groupId, start)).then((res) => { | ||
const load = (start) => this.get(URL.groupMemberIds(groupId, start)) | ||
.then(checkJSON) | ||
.then((res) => { | ||
if (!res.next) { | ||
@@ -55,3 +68,5 @@ return res.memberIds; | ||
getRoomMemberIds(roomId) { | ||
const load = (start) => this.get(URL.roomMemberIds(roomId, start)).then((res) => { | ||
const load = (start) => this.get(URL.roomMemberIds(roomId, start)) | ||
.then(checkJSON) | ||
.then((res) => { | ||
if (!res.next) { | ||
@@ -73,5 +88,41 @@ return res.memberIds; | ||
} | ||
getRichMenu(richMenuId) { | ||
return this.get(URL.richMenu(richMenuId)).then(checkJSON); | ||
} | ||
createRichMenu(richMenu) { | ||
return this.post(URL.richMenu(), richMenu) | ||
.then(checkJSON) | ||
.then(res => res.richMenuId); | ||
} | ||
deleteRichMenu(richMenuId) { | ||
return this.delete(URL.richMenu(richMenuId)); | ||
} | ||
getRichMenuIdOfUser(userId) { | ||
return this.get(URL.userRichMenu(userId)) | ||
.then(checkJSON) | ||
.then(res => res.richMenuId); | ||
} | ||
linkRichMenuToUser(userId, richMenuId) { | ||
return this.post(URL.userRichMenu(userId, richMenuId)); | ||
} | ||
unlinkRichMenuFromUser(userId, richMenuId) { | ||
return this.delete(URL.userRichMenu(userId, richMenuId)); | ||
} | ||
getRichMenuImage(richMenuId) { | ||
return this.stream(URL.richMenuContent(richMenuId)); | ||
} | ||
setRichMenuImage(richMenuId, data, contentType) { | ||
return this.postBinary(URL.richMenuContent(richMenuId), data, contentType); | ||
} | ||
getRichMenuList() { | ||
return this.get(URL.richMenuList()) | ||
.then(checkJSON) | ||
.then(res => res.richmenus); | ||
} | ||
authHeader() { | ||
return { Authorization: "Bearer " + this.config.channelAccessToken }; | ||
} | ||
delete(url) { | ||
return http_1.del(url, this.authHeader()); | ||
} | ||
get(url) { | ||
@@ -83,2 +134,5 @@ return http_1.get(url, this.authHeader()); | ||
} | ||
postBinary(url, data, contentType) { | ||
return http_1.postBinary(url, this.authHeader(), data, contentType); | ||
} | ||
stream(url) { | ||
@@ -85,0 +139,0 @@ return http_1.stream(url, this.authHeader()); |
/// <reference types="node" /> | ||
export declare function stream(url: string, headers: any): Promise<NodeJS.ReadableStream>; | ||
import { Readable } from "stream"; | ||
export declare function stream(url: string, headers: any): Promise<Readable>; | ||
export declare function get(url: string, headers: any): Promise<any>; | ||
export declare function post(url: string, headers: any, data?: any): Promise<any>; | ||
export declare function postBinary(url: string, headers: any, data: Buffer | Readable, contentType?: string): Promise<any>; | ||
export declare function del(url: string, headers: any): Promise<any>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const axios_1 = require("axios"); | ||
const stream_1 = require("stream"); | ||
const exceptions_1 = require("./exceptions"); | ||
const fileType = require("file-type"); | ||
const fileTypeStream = require("file-type-stream").default; | ||
const pkg = require("../package.json"); | ||
function checkJSON(raw) { | ||
if (typeof raw === "object") { | ||
return raw; | ||
} | ||
else { | ||
throw new exceptions_1.JSONParseError("Failed to parse response body as JSON", raw); | ||
} | ||
} | ||
function wrapError(err) { | ||
@@ -40,3 +35,3 @@ if (err.response) { | ||
.get(url, { headers }) | ||
.then(res => checkJSON(res.data)) | ||
.then(res => res.data) | ||
.catch(wrapError); | ||
@@ -50,5 +45,45 @@ } | ||
.post(url, data, { headers }) | ||
.then(res => checkJSON(res.data)) | ||
.then(res => res.data) | ||
.catch(wrapError); | ||
} | ||
exports.post = post; | ||
function postBinary(url, headers, data, contentType) { | ||
let contentTypeGetter; | ||
if (contentType) { | ||
contentTypeGetter = Promise.resolve(contentType); | ||
} | ||
else if (Buffer.isBuffer(data)) { | ||
contentTypeGetter = Promise.resolve(fileType(data).mime); | ||
} | ||
else { | ||
contentTypeGetter = new Promise(resolve => { | ||
if (data instanceof stream_1.Readable) { | ||
const passThrough = new stream_1.PassThrough(); | ||
data | ||
.pipe(fileTypeStream((result) => resolve(result.mime))) | ||
.pipe(passThrough); | ||
data = passThrough; | ||
} | ||
else { | ||
throw new Error("invalid data type for postBinary"); | ||
} | ||
}); | ||
} | ||
return contentTypeGetter.then((contentType) => { | ||
headers["Content-Type"] = contentType; | ||
headers["User-Agent"] = userAgent; | ||
return axios_1.default | ||
.post(url, data, { headers }) | ||
.then(res => res.data) | ||
.catch(wrapError); | ||
}); | ||
} | ||
exports.postBinary = postBinary; | ||
function del(url, headers) { | ||
headers["User-Agent"] = userAgent; | ||
return axios_1.default | ||
.delete(url, { headers }) | ||
.then(res => res.data) | ||
.catch(wrapError); | ||
} | ||
exports.del = del; |
@@ -146,6 +146,3 @@ export interface Config { | ||
altText: string; | ||
baseSize: { | ||
width: number; | ||
height: number; | ||
}; | ||
baseSize: Size; | ||
actions: ImageMapAction[]; | ||
@@ -160,3 +157,3 @@ }; | ||
export declare type ImageMapActionBase = { | ||
area: ImageMapArea; | ||
area: Area; | ||
}; | ||
@@ -171,3 +168,3 @@ export declare type ImageMapURIAction = { | ||
} & ImageMapActionBase; | ||
export declare type ImageMapArea = { | ||
export declare type Area = { | ||
x: number; | ||
@@ -184,3 +181,3 @@ y: number; | ||
text: string; | ||
actions: TemplateAction<{ | ||
actions: Action<{ | ||
label: string; | ||
@@ -192,3 +189,3 @@ }>[]; | ||
text: string; | ||
actions: TemplateAction<{ | ||
actions: Action<{ | ||
label: string; | ||
@@ -205,3 +202,3 @@ }>[]; | ||
text: string; | ||
actions: TemplateAction<{ | ||
actions: Action<{ | ||
label: string; | ||
@@ -216,8 +213,8 @@ }>[]; | ||
imageUrl: string; | ||
action: TemplateAction<{ | ||
action: Action<{ | ||
label?: string; | ||
}>; | ||
}; | ||
export declare type TemplateAction<Label> = TemplatePostbackAction & Label | TemplateMessageAction & Label | TemplateURIAction & Label | TemplateDatetimePickerAction & Label; | ||
export declare type TemplatePostbackAction = { | ||
export declare type Action<Label> = PostbackAction & Label | MessageAction & Label | URIAction & Label | DatetimePickerAction & Label; | ||
export declare type PostbackAction = { | ||
type: "postback"; | ||
@@ -227,11 +224,11 @@ data: string; | ||
}; | ||
export declare type TemplateMessageAction = { | ||
export declare type MessageAction = { | ||
type: "message"; | ||
text: string; | ||
}; | ||
export declare type TemplateURIAction = { | ||
export declare type URIAction = { | ||
type: "uri"; | ||
uri: string; | ||
}; | ||
export declare type TemplateDatetimePickerAction = { | ||
export declare type DatetimePickerAction = { | ||
type: "datetimepicker"; | ||
@@ -244,1 +241,18 @@ data: string; | ||
}; | ||
export declare type Size = { | ||
width: number; | ||
height: number; | ||
}; | ||
export declare type RichMenu = { | ||
size: Size; | ||
selected: boolean; | ||
name: string; | ||
chatBarText: string; | ||
areas: Array<{ | ||
bounds: Area; | ||
action: Action<{}>; | ||
}>; | ||
}; | ||
export declare type RichMenuResponse = { | ||
richMenuId: string; | ||
} & RichMenu; |
@@ -12,1 +12,5 @@ export declare const reply: string; | ||
export declare const leaveRoom: (roomId: string) => string; | ||
export declare const richMenu: (richMenuId?: string) => string; | ||
export declare const richMenuList: () => string; | ||
export declare const userRichMenu: (userId: string, richMenuId?: string) => string; | ||
export declare const richMenuContent: (richMenuId: string) => string; |
@@ -17,1 +17,5 @@ "use strict"; | ||
exports.leaveRoom = (roomId) => apiURL(`room/${roomId}/leave`); | ||
exports.richMenu = (richMenuId) => apiURL("richmenu" + (richMenuId ? `/${richMenuId}` : "")); | ||
exports.richMenuList = () => apiURL(`richmenu/list`); | ||
exports.userRichMenu = (userId, richMenuId) => apiURL(`user/${userId}/richmenu` + (richMenuId ? `/${richMenuId}` : "")); | ||
exports.richMenuContent = (richMenuId) => apiURL(`richmenu/${richMenuId}/content`); |
@@ -12,15 +12,33 @@ # `new Client(config)` | ||
constructor(config: ClientConfig) | ||
constructor(config: ClientConfig) {} | ||
pushMessage(to: string, messages: Message | Message[]): Promise<{}> | ||
replyMessage(replyToken: string, messages: Message | Message[]): Promise<{}> | ||
multicast(to: string[], messages: Message | Message[]): Promise<{}> | ||
// Message | ||
pushMessage(to: string, messages: Message | Message[]): Promise<any> | ||
replyMessage(replyToken: string, messages: Message | Message[]): Promise<any> | ||
multicast(to: string[], messages: Message | Message[]): Promise<any> | ||
getMessageContent(messageId: string): Promise<Readable> | ||
// Profile | ||
getProfile(userId: string): Promise<Profile> | ||
// Group | ||
getGroupMemberProfile(groupId: string, userId: string): Promise<Profile> | ||
getGroupMemberIds(groupId: string): Promise<string[]> | ||
leaveGroup(groupId: string): Promise<any> | ||
// Room | ||
getRoomMemberProfile(roomId: string, userId: string): Promise<Profile> | ||
getGroupMemberIds(groupId: string): Promise<string[]> | ||
getRoomMemberIds(roomId: string): Promise<string[]> | ||
getMessageContent(messageId: string): Promise<ReadableStream> | ||
leaveGroup(groupId: string): Promise<{}> | ||
leaveRoom(roomId: string): Promise<{}> | ||
leaveRoom(roomId: string): Promise<any> | ||
// Rich menu | ||
getRichMenu(richMenuId: string): Promise<RichMenuResponse> | ||
createRichMenu(richMenu: RichMenu): Promise<string> | ||
deleteRichMenu(richMenuId: string): Promise<any> | ||
getRichMenuIdOfUser(userId: string): Promise<string> | ||
linkRichMenuToUser(userId: string, richMenuId: string): Promise<any> | ||
unlinkRichMenuFromUser(userId: string, richMenuId: string): Promise<any> | ||
getRichMenuImage(richMenuId: string): Promise<Readable> | ||
setRichMenuImage(richMenuId: string, data: Buffer | Readable, contentType?: string): Promise<any> | ||
getRichMenuList(): Promise<Array<RichMenuResponse>> | ||
} | ||
@@ -55,4 +73,6 @@ ``` | ||
### `pushMessage(to: string, messages: Message | Message[]): Promise<{}>` | ||
### Message | ||
#### `pushMessage(to: string, messages: Message | Message[]): Promise<any>` | ||
It corresponds to the [Push message](https://developers.line.me/en/docs/messaging-api/reference/#send-push-message) API. | ||
@@ -69,3 +89,3 @@ | ||
### `replyMessage(replyToken: string, messages: Message | Message[]): Promise<{}>` | ||
#### `replyMessage(replyToken: string, messages: Message | Message[]): Promise<any>` | ||
@@ -85,3 +105,3 @@ It corresponds to the [Reply message](https://developers.line.me/en/docs/messaging-api/reference/#send-reply-message) API. | ||
### `multicast(to: string[], messages: Message | Message[]): Promise<{}>` | ||
#### `multicast(to: string[], messages: Message | Message[]): Promise<any>` | ||
@@ -100,4 +120,29 @@ It corresponds to the [Multicast](https://developers.line.me/en/docs/messaging-api/reference/#send-multicast-messages) API. | ||
### `getProfile(userId: string): Promise<Profile>` | ||
#### `getMessageContent(messageId: string): Promise<Readable>` | ||
It corresponds to the [Content](https://developers.line.me/en/docs/messaging-api/reference/#get-content) API. | ||
The argument is an ID of media messages, such as image, video, and audio. The ID | ||
can be retrieved from a message object of a message event. | ||
Please beware that what it returns is promise of [readable stream](https://nodejs.org/dist/latest/docs/api/stream.html#stream_readable_streams). | ||
You can pipe the stream into a file, an HTTP response, etc. | ||
``` js | ||
client.getMessageContent('message_id') | ||
.then((stream) => { | ||
stream.on('data', (chunk) => { | ||
... | ||
}) | ||
stream.on('error', (err) => { | ||
... | ||
}) | ||
stream.pipe(...) | ||
}) | ||
``` | ||
### Profile | ||
#### `getProfile(userId: string): Promise<Profile>` | ||
It corresponds to the [Profile](https://developers.line.me/en/docs/messaging-api/reference/#get-profile) API. | ||
@@ -113,4 +158,6 @@ | ||
### `getGroupMemberProfile(groupId: string, userId: string): Promise<Profile>` | ||
### Group | ||
#### `getGroupMemberProfile(groupId: string, userId: string): Promise<Profile>` | ||
It corresponds to the [Group Member Profile](https://developers.line.me/en/docs/messaging-api/reference/#get-group-member-profile) API. | ||
@@ -127,4 +174,30 @@ | ||
### `getRoomMemberProfile(roomId: string, userId: string): Promise<Profile>` | ||
#### `getGroupMemberIds(groupId: string): Promise<string[]>` | ||
It corresponds to the [Group Member IDs](https://developers.line.me/en/docs/messaging-api/reference/#get-group-member-user-ids) API. | ||
*FYI: This feature is only available for LINE@ Approved accounts or official accounts.* | ||
The argument is a group ID and the method returns a promise of an array of user IDs. | ||
``` js | ||
client.getGroupMemberIds('group_id').then((ids) => { | ||
ids.forEach((id) => console.log(id)); | ||
}) | ||
``` | ||
#### `leaveGroup(groupId: string): Promise<any>` | ||
It corresponds to the [Leave group](https://developers.line.me/en/docs/messaging-api/reference/#leave-group) API. | ||
The argument is a group ID. | ||
``` js | ||
client.leaveGroup('group_id') | ||
``` | ||
### Room | ||
#### `getRoomMemberProfile(roomId: string, userId: string): Promise<Profile>` | ||
It corresponds to the [Room Member Profile](https://developers.line.me/en/docs/messaging-api/reference/#get-room-member-profile) API. | ||
@@ -141,12 +214,12 @@ | ||
### `getGroupMemberIds(groupId: string): Promise<string[]>` | ||
#### `getRoomMemberIds(roomId: string): Promise<string[]>` | ||
It corresponds to the [Group Member IDs](https://developers.line.me/en/docs/messaging-api/reference/#get-group-member-user-ids) API. | ||
It corresponds to the [Room Member IDs](https://developers.line.me/en/docs/messaging-api/reference/#get-room-member-user-ids) API. | ||
*FYI: This feature is only available for LINE@ Approved accounts or official accounts.* | ||
The argument is a group ID and the method returns a promise of an array of user IDs. | ||
The argument is a room ID and the method returns a promise of an array of user IDs. | ||
``` js | ||
client.getGroupMemberIds('group_id').then((ids) => { | ||
client.getRoomMemberIds('room_id').then((ids) => { | ||
ids.forEach((id) => console.log(id)); | ||
@@ -156,23 +229,88 @@ }) | ||
### `getRoomMemberIds(roomId: string): Promise<string[]>` | ||
#### `leaveRoom(roomId: string): Promise<any>` | ||
It corresponds to the [Room Member IDs](https://developers.line.me/en/docs/messaging-api/reference/#get-room-member-user-ids) API. | ||
It corresponds to the [Leave room](https://developers.line.me/en/docs/messaging-api/reference/#leave-room) API. | ||
*FYI: This feature is only available for LINE@ Approved accounts or official accounts.* | ||
The argument is a room ID. | ||
The argument is a room ID and the method returns a promise of an array of user IDs. | ||
``` js | ||
client.leaveGroup('room_id') | ||
``` | ||
### Rich menu | ||
#### `getRichMenu(richMenuId: string): Promise<RichMenuResponse>` | ||
It corresponds to the [Get rich menu](https://developers.line.me/en/docs/messaging-api/reference/#get-rich-menu) API. | ||
The argument is a rich menu ID. The return type is [a rich menu response object](https://developers.line.me/en/docs/messaging-api/reference/#rich-menu-response-object). | ||
``` js | ||
client.getRoomMemberIds('room_id').then((ids) => { | ||
ids.forEach((id) => console.log(id)); | ||
client.getRichMenu('rich_menu_id').then((richMenu) => { | ||
console.log(richMenu.size); | ||
console.log(richMenu.areas[0].bounds); | ||
}) | ||
``` | ||
### `getMessageContent(messageId: string): Promise<ReadableStream>` | ||
#### `createRichMenu(richMenu: RichMenu): Promise<string>` | ||
It corresponds to the [Content](https://developers.line.me/en/docs/messaging-api/reference/#get-content) API. | ||
It corresponds to the [Create rich menu](https://developers.line.me/en/docs/messaging-api/reference/#create-rich-menu) API. | ||
The argument is an ID of media messages, such as image, video, and audio. The ID | ||
can be retrieved from a message object of a message event. | ||
The argument is [a rich menu object](https://developers.line.me/en/docs/messaging-api/reference/#rich-menu-object). | ||
For the detail of the object format, please refer to the official documentation. | ||
It returns the result rich menu ID. | ||
``` js | ||
client.createRichMenu({ size: { width: 2500, height: 1686 }, ... }) | ||
.then((richMenuId) => console.log(richMenuId)) | ||
``` | ||
#### `deleteRichMenu(richMenuId: string): Promise<any>` | ||
It corresponds to the [Delete rich menu](https://developers.line.me/en/docs/messaging-api/reference/#delete-rich-menu) API. | ||
The argument is a rich menu ID. | ||
``` js | ||
client.deleteRichMenu('rich_menu_id') | ||
``` | ||
#### `getRichMenuIdOfUser(userId: string): Promise<string>` | ||
It corresponds to the [Get rich menu ID of user](https://developers.line.me/en/docs/messaging-api/reference/#get-rich-menu-id-of-user) API. | ||
The argument is a user ID. It returns a rich menu ID to be used with other APIs. | ||
``` js | ||
client.getRichMenuIdOfUser('user_id').then((richMenuId) => { | ||
console.log(richMenuId); | ||
}) | ||
``` | ||
#### `linkRichMenuToUser(userId: string, richMenuId: string): Promise<any>` | ||
It corresponds to the [Link rich menu to user](https://developers.line.me/en/docs/messaging-api/reference/#link-rich-menu-to-user) API. | ||
The arguments are a user ID and a rich menu ID. | ||
``` js | ||
client.linkRichMenuToUser('user_id', 'rich_menu_id') | ||
``` | ||
#### `unlinkRichMenuFromUser(userId: string, richMenuId: string): Promise<any>` | ||
It corresponds to the [Unlink rich menu from user](https://developers.line.me/en/docs/messaging-api/reference/#unlink-rich-menu-from-user) API. | ||
The arguments are a user ID and a rich menu ID. | ||
``` js | ||
client.unlinkRichMenuFromUser('user_id', 'rich_menu_id') | ||
``` | ||
#### `getRichMenuImage(richMenuId: string): Promise<Readable>` | ||
It corresponds to the [Download rich menu image](https://developers.line.me/en/docs/messaging-api/reference/#download-rich-menu-image) API. | ||
The argument is a rich menu ID. | ||
Please beware that what it returns is promise of [readable stream](https://nodejs.org/dist/latest/docs/api/stream.html#stream_readable_streams). | ||
@@ -182,3 +320,3 @@ You can pipe the stream into a file, an HTTP response, etc. | ||
``` js | ||
client.getMessageContent('message_id') | ||
client.getRichMenuImage('rich_menu_id') | ||
.then((stream) => { | ||
@@ -195,20 +333,20 @@ stream.on('data', (chunk) => { | ||
### `leaveGroup(groupId: string): Promise<{}>` | ||
#### `setRichMenuImage(richMenuId: string, data: Buffer | Readable, contentType?: string): Promise<any>` | ||
It corresponds to the [Leave group](https://developers.line.me/en/docs/messaging-api/reference/#leave-group) API. | ||
It corresponds to the [Upload rich menu image](https://developers.line.me/en/docs/messaging-api/reference/#upload-rich-menu-image) API. | ||
The argument is a group ID. | ||
The 1st argument is a rich menu ID. For 2nd argument, a buffer or a readable | ||
stream of an image should be provided. For the restriction of the image, please | ||
refer to the official documentation. The last argument is optional. If it's not | ||
provided, the mime type will be guessted from `data`. Only `image/jpeg` or | ||
`image/png` is allowed for the content type. | ||
``` js | ||
client.leaveGroup('group_id') | ||
client.setRichMenuImage('rich_menu_id', fs.createReadStream('./some_image.png')) | ||
``` | ||
### `leaveRoom(roomId: string): Promise<{}>` | ||
#### `getRichMenuList(): Promise<Array<RichMenuResponse>>` | ||
It corresponds to the [Leave room](https://developers.line.me/en/docs/messaging-api/reference/#leave-room) API. | ||
It corresponds to the [Get rich menu list](https://developers.line.me/en/docs/messaging-api/reference/#get-rich-menu-list) API. | ||
The argument is a room ID. | ||
``` js | ||
client.leaveGroup('room_id') | ||
``` | ||
The return type is a list of [rich menu response objects](https://developers.line.me/en/docs/messaging-api/reference/#rich-menu-response-object). |
@@ -1,6 +0,19 @@ | ||
import { get, post, stream } from "./http"; | ||
import { Readable } from "stream"; | ||
import { get, post, stream, del, postBinary } from "./http"; | ||
import * as Types from "./types"; | ||
import * as URL from "./urls"; | ||
import { toArray } from "./util"; | ||
import { JSONParseError } from "./exceptions"; | ||
function toArray<T>(maybeArr: T | T[]): T[] { | ||
return Array.isArray(maybeArr) ? maybeArr : [maybeArr]; | ||
} | ||
function checkJSON(raw: any): any { | ||
if (typeof raw === "object") { | ||
return raw; | ||
} else { | ||
throw new JSONParseError("Failed to parse response body as JSON", raw); | ||
} | ||
} | ||
export default class Client { | ||
@@ -48,3 +61,3 @@ public config: Types.ClientConfig; | ||
public getProfile(userId: string): Promise<Types.Profile> { | ||
return this.get(URL.profile(userId)); | ||
return this.get(URL.profile(userId)).then(checkJSON); | ||
} | ||
@@ -56,3 +69,3 @@ | ||
): Promise<Types.Profile> { | ||
return this.get(URL.groupMemberProfile(groupId, userId)); | ||
return this.get(URL.groupMemberProfile(groupId, userId)).then(checkJSON); | ||
} | ||
@@ -64,3 +77,3 @@ | ||
): Promise<Types.Profile> { | ||
return this.get(URL.roomMemberProfile(roomId, userId)); | ||
return this.get(URL.roomMemberProfile(roomId, userId)).then(checkJSON); | ||
} | ||
@@ -70,11 +83,13 @@ | ||
const load = (start?: string): Promise<string[]> => | ||
this.get( | ||
URL.groupMemberIds(groupId, start), | ||
).then((res: { memberIds: string[]; next?: string }) => { | ||
if (!res.next) { | ||
return res.memberIds; | ||
} | ||
this.get(URL.groupMemberIds(groupId, start)) | ||
.then(checkJSON) | ||
.then((res: { memberIds: string[]; next?: string }) => { | ||
if (!res.next) { | ||
return res.memberIds; | ||
} | ||
return load(res.next).then(extraIds => res.memberIds.concat(extraIds)); | ||
}); | ||
return load(res.next).then(extraIds => | ||
res.memberIds.concat(extraIds), | ||
); | ||
}); | ||
return load(); | ||
@@ -85,15 +100,17 @@ } | ||
const load = (start?: string): Promise<string[]> => | ||
this.get( | ||
URL.roomMemberIds(roomId, start), | ||
).then((res: { memberIds: string[]; next?: string }) => { | ||
if (!res.next) { | ||
return res.memberIds; | ||
} | ||
this.get(URL.roomMemberIds(roomId, start)) | ||
.then(checkJSON) | ||
.then((res: { memberIds: string[]; next?: string }) => { | ||
if (!res.next) { | ||
return res.memberIds; | ||
} | ||
return load(res.next).then(extraIds => res.memberIds.concat(extraIds)); | ||
}); | ||
return load(res.next).then(extraIds => | ||
res.memberIds.concat(extraIds), | ||
); | ||
}); | ||
return load(); | ||
} | ||
public getMessageContent(messageId: string): Promise<NodeJS.ReadableStream> { | ||
public getMessageContent(messageId: string): Promise<Readable> { | ||
return this.stream(URL.content(messageId)); | ||
@@ -110,2 +127,51 @@ } | ||
public getRichMenu(richMenuId: string): Promise<Types.RichMenuResponse> { | ||
return this.get(URL.richMenu(richMenuId)).then(checkJSON); | ||
} | ||
public createRichMenu(richMenu: Types.RichMenu): Promise<string> { | ||
return this.post(URL.richMenu(), richMenu) | ||
.then(checkJSON) | ||
.then(res => res.richMenuId); | ||
} | ||
public deleteRichMenu(richMenuId: string): Promise<any> { | ||
return this.delete(URL.richMenu(richMenuId)); | ||
} | ||
public getRichMenuIdOfUser(userId: string): Promise<string> { | ||
return this.get(URL.userRichMenu(userId)) | ||
.then(checkJSON) | ||
.then(res => res.richMenuId); | ||
} | ||
public linkRichMenuToUser(userId: string, richMenuId: string): Promise<any> { | ||
return this.post(URL.userRichMenu(userId, richMenuId)); | ||
} | ||
public unlinkRichMenuFromUser( | ||
userId: string, | ||
richMenuId: string, | ||
): Promise<any> { | ||
return this.delete(URL.userRichMenu(userId, richMenuId)); | ||
} | ||
public getRichMenuImage(richMenuId: string): Promise<Readable> { | ||
return this.stream(URL.richMenuContent(richMenuId)); | ||
} | ||
public setRichMenuImage( | ||
richMenuId: string, | ||
data: Buffer | Readable, | ||
contentType?: string, | ||
): Promise<any> { | ||
return this.postBinary(URL.richMenuContent(richMenuId), data, contentType); | ||
} | ||
public getRichMenuList(): Promise<Array<Types.RichMenuResponse>> { | ||
return this.get(URL.richMenuList()) | ||
.then(checkJSON) | ||
.then(res => res.richmenus); | ||
} | ||
private authHeader(): { [key: string]: string } { | ||
@@ -115,2 +181,6 @@ return { Authorization: "Bearer " + this.config.channelAccessToken }; | ||
private delete(url: string): Promise<any> { | ||
return del(url, this.authHeader()); | ||
} | ||
private get(url: string): Promise<any> { | ||
@@ -124,5 +194,13 @@ return get(url, this.authHeader()); | ||
private stream(url: string): Promise<NodeJS.ReadableStream> { | ||
private postBinary( | ||
url: string, | ||
data: Buffer | Readable, | ||
contentType?: string, | ||
) { | ||
return postBinary(url, this.authHeader(), data, contentType); | ||
} | ||
private stream(url: string): Promise<Readable> { | ||
return stream(url, this.authHeader()); | ||
} | ||
} |
import axios, { AxiosError } from "axios"; | ||
import { | ||
HTTPError, | ||
JSONParseError, | ||
ReadError, | ||
RequestError, | ||
} from "./exceptions"; | ||
import { Readable, PassThrough } from "stream"; | ||
import { HTTPError, ReadError, RequestError } from "./exceptions"; | ||
import * as fileType from "file-type"; | ||
const fileTypeStream = require("file-type-stream").default; | ||
const pkg = require("../package.json"); | ||
function checkJSON(raw: any): any { | ||
if (typeof raw === "object") { | ||
return raw; | ||
} else { | ||
throw new JSONParseError("Failed to parse response body as JSON", raw); | ||
} | ||
} | ||
function wrapError(err: AxiosError) { | ||
@@ -40,10 +31,7 @@ if (err.response) { | ||
export function stream( | ||
url: string, | ||
headers: any, | ||
): Promise<NodeJS.ReadableStream> { | ||
export function stream(url: string, headers: any): Promise<Readable> { | ||
headers["User-Agent"] = userAgent; | ||
return axios | ||
.get(url, { headers, responseType: "stream" }) | ||
.then(res => res.data as NodeJS.ReadableStream); | ||
.then(res => res.data as Readable); | ||
} | ||
@@ -56,3 +44,3 @@ | ||
.get(url, { headers }) | ||
.then(res => checkJSON(res.data)) | ||
.then(res => res.data) | ||
.catch(wrapError); | ||
@@ -66,4 +54,48 @@ } | ||
.post(url, data, { headers }) | ||
.then(res => checkJSON(res.data)) | ||
.then(res => res.data) | ||
.catch(wrapError); | ||
} | ||
export function postBinary( | ||
url: string, | ||
headers: any, | ||
data: Buffer | Readable, | ||
contentType?: string, | ||
): Promise<any> { | ||
let contentTypeGetter; | ||
if (contentType) { | ||
contentTypeGetter = Promise.resolve(contentType); | ||
} else if (Buffer.isBuffer(data)) { | ||
contentTypeGetter = Promise.resolve(fileType(data).mime); | ||
} else { | ||
contentTypeGetter = new Promise(resolve => { | ||
if (data instanceof Readable) { | ||
const passThrough = new PassThrough(); | ||
data | ||
.pipe(fileTypeStream((result: any) => resolve(result.mime))) | ||
.pipe(passThrough); | ||
data = passThrough; | ||
} else { | ||
throw new Error("invalid data type for postBinary"); | ||
} | ||
}); | ||
} | ||
return contentTypeGetter.then((contentType: string) => { | ||
headers["Content-Type"] = contentType; | ||
headers["User-Agent"] = userAgent; | ||
return axios | ||
.post(url, data, { headers }) | ||
.then(res => res.data) | ||
.catch(wrapError); | ||
}); | ||
} | ||
export function del(url: string, headers: any): Promise<any> { | ||
headers["User-Agent"] = userAgent; | ||
return axios | ||
.delete(url, { headers }) | ||
.then(res => res.data) | ||
.catch(wrapError); | ||
} |
@@ -173,3 +173,3 @@ export interface Config { | ||
altText: string; | ||
baseSize: { width: number; height: number }; | ||
baseSize: Size; | ||
actions: ImageMapAction[]; | ||
@@ -186,3 +186,3 @@ }; | ||
export type ImageMapActionBase = { area: ImageMapArea }; | ||
export type ImageMapActionBase = { area: Area }; | ||
@@ -199,3 +199,3 @@ export type ImageMapURIAction = { | ||
export type ImageMapArea = { | ||
export type Area = { | ||
x: number; | ||
@@ -218,3 +218,3 @@ y: number; | ||
text: string; | ||
actions: TemplateAction<{ label: string }>[]; | ||
actions: Action<{ label: string }>[]; | ||
}; | ||
@@ -225,3 +225,3 @@ | ||
text: string; | ||
actions: TemplateAction<{ label: string }>[]; | ||
actions: Action<{ label: string }>[]; | ||
}; | ||
@@ -235,3 +235,3 @@ | ||
text: string; | ||
actions: TemplateAction<{ label: string }>[]; | ||
actions: Action<{ label: string }>[]; | ||
}; | ||
@@ -246,12 +246,12 @@ | ||
imageUrl: string; | ||
action: TemplateAction<{ label?: string }>; | ||
action: Action<{ label?: string }>; | ||
}; | ||
export type TemplateAction<Label> = | ||
| TemplatePostbackAction & Label | ||
| TemplateMessageAction & Label | ||
| TemplateURIAction & Label | ||
| TemplateDatetimePickerAction & Label; | ||
export type Action<Label> = | ||
| PostbackAction & Label | ||
| MessageAction & Label | ||
| URIAction & Label | ||
| DatetimePickerAction & Label; | ||
export type TemplatePostbackAction = { | ||
export type PostbackAction = { | ||
type: "postback"; | ||
@@ -262,3 +262,3 @@ data: string; | ||
export type TemplateMessageAction = { | ||
export type MessageAction = { | ||
type: "message"; | ||
@@ -268,3 +268,3 @@ text: string; | ||
export type TemplateURIAction = { | ||
export type URIAction = { | ||
type: "uri"; | ||
@@ -274,3 +274,3 @@ uri: string; | ||
export type TemplateDatetimePickerAction = { | ||
export type DatetimePickerAction = { | ||
type: "datetimepicker"; | ||
@@ -283,1 +283,16 @@ data: string; | ||
}; | ||
export type Size = { | ||
width: number; | ||
height: number; | ||
}; | ||
export type RichMenu = { | ||
size: Size; | ||
selected: boolean; | ||
name: string; | ||
chatBarText: string; | ||
areas: Array<{ bounds: Area; action: Action<{}> }>; | ||
}; | ||
export type RichMenuResponse = { richMenuId: string } & RichMenu; |
@@ -35,1 +35,12 @@ import * as qs from "querystring"; | ||
export const leaveRoom = (roomId: string) => apiURL(`room/${roomId}/leave`); | ||
export const richMenu = (richMenuId?: string) => | ||
apiURL("richmenu" + (richMenuId ? `/${richMenuId}` : "")); | ||
export const richMenuList = () => apiURL(`richmenu/list`); | ||
export const userRichMenu = (userId: string, richMenuId?: string) => | ||
apiURL(`user/${userId}/richmenu` + (richMenuId ? `/${richMenuId}` : "")); | ||
export const richMenuContent = (richMenuId: string) => | ||
apiURL(`richmenu/${richMenuId}/content`); |
{ | ||
"name": "@line/bot-sdk", | ||
"version": "4.0.0", | ||
"version": "5.0.0", | ||
"description": "Node.js SDK for LINE Messaging API", | ||
@@ -41,5 +41,8 @@ "engines": { | ||
"@types/body-parser": "^1.16.3", | ||
"@types/file-type": "^5.2.1", | ||
"@types/node": "^7.0.31", | ||
"axios": "^0.16.2", | ||
"body-parser": "^1.17.2" | ||
"body-parser": "^1.17.2", | ||
"file-type": "^7.2.0", | ||
"file-type-stream": "^1.0.0" | ||
}, | ||
@@ -46,0 +49,0 @@ "devDependencies": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
1877003
3808
6
7
86
+ Added@types/file-type@^5.2.1
+ Addedfile-type@^7.2.0
+ Addedfile-type-stream@^1.0.0
+ Added@types/file-type@5.2.2(transitive)
+ Addedfile-type@3.9.07.7.1(transitive)
+ Addedfile-type-stream@1.0.0(transitive)