- [new] add member join/leave event to LineEvent
event.isMemberJoined;
event.memberJoined;
event.isMemberLeft;
event.memberLeft;
- [deps] upgrade messaging-api-messenger to 0.7.16
- [new] Add
page.id
to Messenger sessions:
session.page.id;
- [new] Add
skipProfile
toLinekBot
andLinekConnector
. - [new] Add
destination
toLineEvent
.
- [new] Add
skipProfile
toSlackBot
andSlackConnector
.
- [fix] Add missing cli alias
-w
for--webhook
.
- [new] provide useful information when setting webhook
- [new] Add
context.usePersona
:
context.usePersona('<PERSONA_ID>');
await context.sendText('Hello');
await context.sendText('World');
- [new] Add
skipProfile
option toMessengerBot
andMessengerConnector
to skip auto updating user profile:
const bot = new MessengerBot({
accessToken: ACCESS_TOKEN,
appSecret: APP_SECRET,
skipProfile: true,
});
- [new] Add
skipAppSecretProof
option toMessengerBot
andMessengerConnector
:
const bot = new MessengerBot({
accessToken: ACCESS_TOKEN,
appSecret: APP_SECRET,
skipAppSecretProof: true,
});
- [new] platform bots: add
origin
option for testing purpose:
new MessengerBot({
// ...
origin: 'https://mydummytestserver.com',
});
new LineBot({
// ...
origin: 'https://mydummytestserver.com',
});
new SlackBot({
// ...
origin: 'https://mydummytestserver.com',
});
new ViberBot({
// ...
origin: 'https://mydummytestserver.com',
});
new TelegramBot({
// ...
origin: 'https://mydummytestserver.com',
});
- [fix] update Messenger profile_pic check logic
- [fix] fix persona cli error messages
- [new] Add CLI commands for Messenger persona API:
List all personas:
$ bottender messenger persona list
Create a new persona with name and profile picture url:
$ bottender messenger persona create --name <PERSONA_NAME> --pic <PROFILE_IMAGE_URL>
Get persona by persona ID:
$ bottender messenger persona get --id <PERSONA_ID>
Delete persona by persona ID:
$ bottender messenger persona delete --id <PERSONA_ID>
- [new] Add
sessionStore.all()
to fetch all of sessions from the store:
// for those session stores
const sessionStore = new MemorySessionStore(500);
const sessionStore = new MongoSessionStore('mongodb://localhost:27017/');
const sessionStore = new FileSessionStore();
const sessionStore = new RedisSessionStore();
const sessions = await sessionStore.all();
- [deps] update
messaging-apis
(which support messenger persona api)
- [new] upgrade
messaging-apis
, so now we can useDEBUG
env variable to enable request debugger:
DEBUG=messaging-api*
- [fix] fix
ConsoleBot
recognize symbol as_methodMissing
(#333) - [deps] upgrade dependencies
- [new] make sure all of methods support quick reply (#331):
context.sendText('hahaha', {
quickReply: {
items: [
{
type: 'action',
action: {
type: 'cameraRoll',
label: 'Send photo',
},
},
{
type: 'action',
action: {
type: 'camera',
label: 'Open camera',
},
},
],
},
});
- [new] add
isReplyToMessage
,replyToMessage
(#330):
event.isReplyToMessage;
event.replyToMessage;
- [fix] get correct channel id from more slack event format
- [new] add debugger for sync response
DEBUG=bottender:response
print:
bottender:response Outgoing response:
bottender:response {
bottender:response body: {
bottender:response }
bottender:response }
Useful when debugging synchronized connectors.
- [fix] makes
context.platform
consistent withcontext.session.platform
- [new] Add
mockPlatform
option:
const bot = new ConsoleBot({
fallbackMethods: true,
mockPlatform: 'messenger',
});
bot.connector.platform; // 'messenger'
bot.onEvent(context => {
context.platform; // 'messenger'
});
- [new] Add
context.isThreadOwner()
:
await context.isThreadOwner(); // true | false
- [fix] fix cli hint (#311)
- [fix] not print empty array other args in ConsoleBot fallbackMethods (#314)
v0.15
is the second major version after we open sourced Bottender. In this version, we introduce a lot of helpful, community requested features based on Messaging APIs v0.7.
- [new] add
context.requestContext
:
Express, Micro, Restify:
context.requestContext; // { req, res }
Koa:
context.requestContext; // ctx in koa
- [new] add more debug logs and key change (#239, #295), so you can run bots with following
DEBUG
env:
DEBUG=bottender:*
DEBUG=bottender:request
DEBUG=bottender:session:read
DEBUG=bottender:session:write
- [new] skip and show warning when calling send API in Messenger echo delivery read event (#306)
- [fix] deepClone when read from
MemoryCacheStore
(#235) - [deps] Upgrade to Babel 7
- [breaking] remove deprecated
MessengerContext
method -sendQuickReplies
- [new] support Messenger platform v2.4.
- [new] enable verifying graph API calls with
appsecret_proof
by default. - [new]
context.getThreadOwner
const threadOwner = await context.getThreadOwner();
// {
// app_id: '12345678910'
// }
- [new] add
pageId
,gamePlay
,brandedCamera
,isRequestThreadControlFromPageInbox
getters toMessengerEvent
context.event.pageId; // "<PAGE_ID>"
context.event.isRequestThreadControlFromPageInbox; // true
context.event.isGamePlay; //
context.event.gamePlay; //
context.event.isBrandedCamera; //
context.event.brandedCamera; //
- [new] implement Batch Mode to send multiple requests in one batch (up to 50 messages):
const { isError613 } = require('messenger-batch');
new MessengerBot({
// ...
batchConfig: {
delay: 1000,
shouldRetry: isError613, // (#613) Calls to this api have exceeded the rate limit.
retryTimes: 2,
},
});
It will enable message batching functionality via messaging-api-messenger under the hood.
- [deprecated]
sendAirlineFlightUpdateTemplate
has been renamed tosendAirlineUpdateTemplate
.
- [new] support LINE Flex Message with
replyFlex
,pushFlex
,sendFlex
:
context.sendFlex('this is a flex', {
type: 'bubble',
header: {
type: 'box',
layout: 'vertical',
contents: [
{
type: 'text',
text: 'Header text',
},
],
},
hero: {
type: 'image',
url: 'https://example.com/flex/images/image.jpg',
},
body: {
type: 'box',
layout: 'vertical',
contents: [
{
type: 'text',
text: 'Body text',
},
],
},
footer: {
type: 'box',
layout: 'vertical',
contents: [
{
type: 'text',
text: 'Footer text',
},
],
},
styles: {
comment: 'See the example of a bubble style object',
},
});
- [new] add
issueLinkToken
toLineContext
(#245):
const result = await context.issueLinkToken();
// {
// linkToken: 'NMZTNuVrPTqlr2IF8Bnymkb7rXfYv5EY',
// }
- [new] add LINE
linkAccount
events support (#243):
context.event.isAccountLink; // true
context.event.linkAccount;
// {
// result: 'ok',
// nonce: 'xxxxxxxxxxxxxxx',
// }
- [new] add
shouldBatch
option:
new LineBot({
// ...
shouldBatch: true, // Default: false
});
When batching is enabled,
context.replyText('Hi');
context.replyText('Hi');
context.replyText('Hi');
context.replyText('Hi');
context.replyText('Hi');
Those 5 messages will be sent in one API call, just like the below one.
const { Line } = require('messaging-api-line');
context.reply([
Line.createText('Hi'),
Line.createText('Hi'),
Line.createText('Hi'),
Line.createText('Hi'),
Line.createText('Hi'),
]);
- [new] add
sendMethod
option:
new LineBot({
// ...
sendMethod: 'reply', // Default: 'push'
});
- [breaking] Now context methods throw error when
ok
isfalse
in Telegram:
{
ok: false,
result: { /* ... */ }
}
- [new] pass merged query and body to handler:
{
...query,
...body,
}
It's useful in custom connectors.
- [new] export Context from entry (#250)
const { Context } = require('bottender');
class MyContext extends Context {
//...
}
- [fix] MemoryCacheStore: make sure read as different object to prevent reading same key multiple times, causing freezed by other events.
- [new] alias LINE ButtonsTemplate to ButtonTemplate to match type name
buttons
#219
Aliases:
- replyButtonsTemplate -> replyButtonTemplate
- pushButtonsTemplate -> pushButtonTemplate
- sendButtonsTemplate -> sendButtonTemplate
- [new] Add cli option
-t
,--token
to overwrite token setting.
- [new] Add new Update APIs to
TelegramContext
:
editMessageText(text [, options])
editMessageCaption(caption [, options])
editMessageReplyMarkup(replyMarkup [, options])
deleteMessage(messageId)
editMessageLiveLocation(location [, options])
stopMessageLiveLocation(options)
forwardMessageFrom(fromChatId, messageId [, options])
forwardMessageTo(toChatId, messageId [, options])
- [new] Add new Get APIs to
TelegramContext
:
context.getUserProfilePhotos({ limit: 1 }).then(result => {
console.log(result);
// {
// total_count: 3,
// photos: [
// [
// {
// file_id: 'AgADBAADGTo4Gz8cZAeR-ouu4XBx78EeqRkABHahi76pN-aO0UoDA050',
// file_size: 14650,
// width: 160,
// height: 160,
// },
// {
// file_id: 'AgADBAADGTo4Gz8cZAeR-ouu4XBx78EeqRkABKCfooqTgFUX0EoD5B1C',
// file_size: 39019,
// width: 320,
// height: 320,
// },
// {
// file_id: 'AgADBAADGTo4Gz8cZAeR-ouu4XBx78EeqRkABPL_pC9K3UpI0koD1B1C',
// file_size: 132470,
// width: 640,
// height: 640,
// },
// ],
// ],
// }
});
context.getChat().then(result => {
console.log(result);
// {
// id: 313534466,
// first_name: 'first',
// last_name: 'last',
// username: 'username',
// type: 'private',
// }
});
context.getChatAdministrators().then(result => {
console.log(result);
// [
// {
// user: {
// id: 313534466,
// first_name: 'first',
// last_name: 'last',
// username: 'username',
// languange_code: 'zh-TW',
// },
// status: 'creator',
// },
// ]
});
context.getChatMembersCount().then(result => {
console.log(result);
// '6'
});
context.getChatMember().then(result => {
console.log(result);
// {
// user: {
// id: 313534466,
// first_name: 'first',
// last_name: 'last',
// username: 'username',
// languange_code: 'zh-TW',
// },
// status: 'creator',
// }
});
- [new] Add new Group APIs to
TelegramContext
:
context.kickChatMember
context.unbanChatMember
context.restrictChatMember
context.promoteChatMember
context.exportChatInviteLink
context.setChatPhoto
context.deleteChatPhoto
context.setChatTitle
context.setChatDescription
context.setChatStickerSet
context.deleteChatStickerSet
context.pinChatMessage
context.unpinChatMessage
context.leaveChat
- [new] Add new Payment APIs to
TelegramContext
:
- [new] Add new
LineContext
methods:
context.getUserProfile().then(profile => {
console.log(profile);
// {
// displayName: 'LINE taro',
// userId: USER_ID,
// pictureUrl: 'http://obs.line-apps.com/...',
// statusMessage: 'Hello, LINE!',
// }
});
context.getMemberProfile(USER_ID).then(member => {
console.log(member);
// {
// "displayName":"LINE taro",
// "userId":"Uxxxxxxxxxxxxxx...",
// "pictureUrl":"http://obs.line-apps.com/..."
// }
});
context.getMemberIds(CURSOR).then(res => {
console.log(res);
// {
// memberIds: [
// 'Uxxxxxxxxxxxxxx...',
// 'Uxxxxxxxxxxxxxx...',
// 'Uxxxxxxxxxxxxxx...'
// ],
// next: 'jxEWCEEP...'
// }
});
context.getAllMemberIds().then(ids => {
console.log(ids);
// [
// 'Uxxxxxxxxxxxxxx..1',
// 'Uxxxxxxxxxxxxxx..2',
// 'Uxxxxxxxxxxxxxx..3',
// 'Uxxxxxxxxxxxxxx..4',
// 'Uxxxxxxxxxxxxxx..5',
// 'Uxxxxxxxxxxxxxx..6',
// ]
});
- [new] Implement
context.getUserProfile
:
const user = await context.getUserProfile();
// {
// first_name: 'Kevin',
// last_name: 'Durant',
// profile_pic: 'https://example.com/pic.png',
// locale: 'en_US',
// timezone: 8,
// gender: 'male',
// };
- [new] Implement
context.sendSenderAction
:
context.sendSenderAction('typing_on');
// same as
context.typingOn();
- [fix] Fix metadata argument in handover methods (#208)
- [new] Implement
context.getUserDetails
:
const user = await context.getUserDetails();
// {
// id: '01234567890A=',
// name: 'John McClane',
// avatar: 'http://avatar.example.com',
// country: 'UK',
// language: 'en',
// primary_device_os: 'android 7.1',
// api_version: 1,
// viber_version: '6.5.0',
// mcc: 1,
// mnc: 1,
// device_type: 'iPhone9,4',
// };
- [new] Implement
context.getOnlineStatus
:
const status = await context.getOnlineStatus();
// {
// id: '01234567890=',
// online_status: 0,
// online_status_message: 'online',
// }
- [new] Support using
/exit
to exit
- [new] Support passing
verifyToken
toMessengerBot
orMessengerConnector
(#204)
Support both:
- pass verifyToken in server config
const bot = new MessengerBot({
accessToken: config.accessToken,
appSecret: config.appSecret,
});
const server = createServer(bot, { verifyToken: config.verifyToken });
- pass verifyToken in bot config
const bot = new MessengerBot({
accessToken: config.accessToken,
appSecret: config.appSecret,
verifyToken: config.verifyToken,
});
const server = createServer(bot);
- [fix] Fix LINE join, leave events which do not have userId will fail get profile (#206)
- [fix] Upgrade
@slack/client
deps to fix security vulnerability
- [fix] fix context simulator initialState (#198)
- [new] Support request thread control:
context.requestThreadControl();
context.event.isRequestThreadControl; // true or false
context.event.requestThreadControl;
/*
{
metadata: 'additional content that the caller wants to set',
requested_owner_app_id: '123456789',
}
*/
- [fix] fix error on verifying facebook signature.
- [deps] bump messaging-apis to v0.6.13
- [new] Support trigger payload in
ConsoleBot
You > /payload PAYLOAD
Receive event:
context.event.isMessage; // false
context.event.message; // null
context.event.isText; // false
context.event.text; // null
context.event.isPayload; // true
context.event.payload; // PAYLOAD
- [new] Support all of methods on
ConsoleContext
withfallbackMethods: true
#184, for example:
const bot = new ConsoleBot({ fallbackMethods: true });
bot.onEvent(async context => {
await context.sendText('Hello World');
await context.sendImage('https://example.com/vr.jpg');
await context.sendButtonTemplate('What do you want to do next?', [
{
type: 'web_url',
url: 'https://petersapparel.parseapp.com',
title: 'Show Website',
},
{
type: 'postback',
title: 'Start Chatting',
payload: 'USER_DEFINED_PAYLOAD',
},
]);
});
Result:
Bot > Hello World
Bot > sendImage: ["https://example.com/vr.jpg"]
Bot > sendButtonTemplate: ["What do you want to do next?",[{"type":"web_url","url":"https://petersapparel.parseapp.com","title":"Show Website"},{"type":"postback","title":"Start Chatting","payload":"USER_DEFINED_PAYLOAD"}]]
- [fix] Catch write session error in async mode #185
- [improve] Show warning when calling
setState
orresetState
after session have been written #186
- [fix] Use sync mode in
ConsoleBot
to fix some format issue.
- [new] Support
--ngrok-port
when setting webhook #171. For example:
bottender messenger webhook set --ngrok-port 1234
bottender telegram webhook set --ngrok-port 1234
bottender viber webhook set --ngrok-port 1234
- [deps] Update part of dependencies.
- [new] Implement signature verify for viber
- [fix] Prevent applying any mutations to
initialState
#164
- [new] Added
context.answerInlineQuery
for Telegram #165:
context.answerInlineQuery(
[
{
type: 'photo',
id: 'UNIQUE_ID',
photo_file_id: 'FILE_ID',
title: 'PHOTO_TITLE',
},
{
type: 'audio',
id: 'UNIQUE_ID',
audio_file_id: 'FILE_ID',
caption: 'AUDIO_TITLE',
},
],
{
cache_time: 1000,
}
);
- [changed] Improve config schema validation.
- [experimental] add Slack RTM API support:
const { SlackBot } = require('bottender');
const bot = new SlackBot({
accessToken: '__FILL_YOUR_TOKEN_HERE__',
});
bot.onEvent(async context => {
await context.sendText('Hello World');
});
bot.createRtmRuntime();
- [new] Handle all of telegram event types includes:
message
edited_message
channel_post
edited_channel_post
inline_query
chosen_inline_result
callback_query
shipping_query
pre_checkout_query
- [new] Support group chat events.
- [new] Better handle Messenger getUserProfile failure #155
If getUserProfile
throw error, session.user
will fallback to have only id
and _updatedAt
keys.
- [new] Added more event parser and getter to telegram event #150
event.isEditedMessage
event.editedMessage
event.isChannelPost
event.channelPost
event.isEditedChannelPost
event.editedChannelPost
event.isInlineQuery
event.inlineQuery
event.isChosenInlineResult
event.chosenInlineResult
event.isShippingQuery
event.shippingQuery
event.isPreCheckoutQuery
event.preCheckoutQuery
- [new] Add
context.postEphemeral
:
context.postEphemeral({ text: 'hello' });
- [fix] Reply to thread instead of channel when receiving events in thread #145
- [fix] Use
message.chat.id
to reply #148
- [fix] Improve error handling in express middleware #142
- [new] Add optional
--yes
for Messenger force upload attachment #127 - [new] Initial State in test-utils #126
- [fix] Improve context simulator and add some tests #131
- [fix] Support Messenger webhook test requests #139
- [new] Support running Telegram bots with long polling #117
const { TelegramBot } = require('bottender');
const bot = new TelegramBot({
accessToken: '__FILL_YOUR_TOKEN_HERE__',
});
bot.onEvent(async context => {
await context.sendText('Hello World');
});
bot.createLongPollingRuntime({
limit: 100,
timeout: 60,
allowed_updates: ['message', 'callback_query'],
});
See more details in examples/telegram-long-polling
- [fix] Result destructing bugs in Telegram webhook commands
- [fix] ContextSimulator: sendState to setState #108
- [deprecated]
sendXXXWithDelay
is deprecated. UsesendXXX
withoptions.delay
instead.
- [fix] update messaging-api-messenger to fix empty array quick_replies bug
- [new] Add LINE
context.leave()
function for group and room #107
- [fix] Fix
context.sendVideoNote
usingmessaging-api-telegram
v0.6.5 - [new] Add context.methods:
sendMediaGroup:
context.sendMediaGroup([
{ type: 'photo', media: 'BQADBAADApYAAgcZZAfj2-xeidueWwI' },
]);
Payment API:
context.sendInvoice({
title: 'product name',
description: 'product description',
payload: 'bot-defined invoice payload',
provider_token: 'PROVIDER_TOKEN',
start_parameter: 'pay',
currency: 'USD',
prices: [
{ label: 'product', amount: 11000 },
{ label: 'tax', amount: 11000 },
],
});
Game API:
context.sendGame('Mario Bros.');
context.setGameScore(999);
context.getGameHighScores().then(result => {
console.log(result);
/*
{
ok: true,
result: [
{
position: 1,
user: {
id: 427770117,
is_bot: false,
first_name: 'first',
},
score: 999,
},
],
};
*/
});
Introducing Viber Support to Bottender!
const { ViberBot } = require('bottender');
const { createServer } = require('bottender/express');
const bot = new ViberBot({
accessToken: '__FILL_YOUR_TOKEN_HERE__',
});
bot.onEvent(async context => {
if (context.event.isMessage) {
await context.sendText('Hello World');
}
});
const server = createServer(bot);
server.listen(5000, () => {
console.log('server is running on 5000 port...');
});
See viber-hello-world for more details.
- [new] Add
update-notifier
in CLI #99 - [deps] Update messaging API clients to
v0.6.x
.
- [fix] Fix domain whitelisting usage
- [fix] Check messenger menu item length #71
- [fix] Handle LINE webhook verify request in LineConnector #100
- [new] Add Slack signature validation #94
- [improve] Let slack connector handle promises parallelly #105
- [new] Add referral getters for
MessengerEvent
:
event.isReferral; // true or false
event.referral; // { source: 'SHORTLINK', type: 'OPEN_THREAD', ref: 'my_ref' }
event.ref; // 'my_ref'
- [new] Create
README.md
and.gitignore
whenbottender init
- [deps] Update messaging-apis to
v0.5.16
- [new] Add
event.isFromCustomerChatPlugin
getter - [new] Implement CLI attachment force upload #70
- [fix] Fix CLI profile bug
- [fix] Add huge like sticker support to isLikeSticker #67
- [fix] Use timingSafeEqual to validate signature #79
- [fix] Use timingSafeEqual to validate signature #79
- [new] Add
mapPageToAccessToken
to support multiple pages (Experimental) #47
new MessengerBot({
appSecret: '__FILL_YOUR_SECRET_HERE__',
mapPageToAccessToken: pageId => accessToken,
});
Note: API may changes between any versions.
- [new] Export
context.reply
andcontext.push
methods. #52 - [new] New CLI commands to sync LINE rich menus: #50
$ bottender line menu get
$ bottender line menu set
$ bottender line menu delete
- [new] Add support to interactive messages, and you can get action from it: #41
if (context.event.isInteractiveMessage) {
console.log(context.event.action);
}
- [new] A new command to upload your messenger attachments from
/assets
directory (in beta):
$ bottender messenger attachment upload
Then, you can import them with getAttachment
util function:
const { getAttachment } = require('bottender/utils');
console.log(getAttachment('mypic.jpg').id); // '1591074914293017'
- [new] Add
--force
option tobottender messenger profile set
(delete all and set all) - [fix] Fix file export for
test-utils.js
#44 - [fix] Refined affected methods in
withTyping
#35
- [fix] Stop passing
as_user: true
#33
- [new] Add
--skip-validate
cli option to skipJoi
schema validation #31 - [fix] Allow unknown keys in config and fix schema rules #29
- [new] Add options for
postMessage
#25
You can use it to send additional attachments, like below:
context.postMessage('I am a test message', {
attachments: [
{
text: "And here's an attachment!",
},
],
});
See official docs for more available options.
-
[new] Implement richmenu api methods on context #23
context.getLinkedRichMenu()
context.linkRichMenu(richMenuId)
context.unlinkRichMenu()
- [new] Add new send methods #19
context.sendMessage
context.sendTemplate
context.sendOpenGraphTemplate
context.sendMediaTemplate
- [new] Implement label api methods for targeting broadcast messages #18
context.associateLabel(labelId)
context.dissociateLabel(labelId)
context.getAssociatedLabels()
- [new] Implement thread control methods #15
context.passThreadControl(targetAppId, metadata)
context.passThreadControlToPageInbox
context.takeThreadControl
- [new] Send
messaging_type
asRESPONSE
when reply anything in the context. #12 - [deps] Upgrade Messaging APIs clients to latest.
First public release.