class Telegraf extends Composer {
constructor (token, options) {
super()
this.options = Object.assign({
retryAfter: 1,
handlerTimeout: 0
}, options)
this.token = token
this.handleError = (err) => {
console.error()
console.error((err.stack || err.toString()).replace(/^/gm, ' '))
console.error()
throw err
}
this.context = {}
this.state = {
offset: 0,
started: false
}
}
get token () {
return this.options.token
}
set token (token) {
this.options.token = token
this.telegram = new Telegram(this.options.token, this.options.telegram)
}/* eslint brace-style: 0 */
catch (handler) {
this.handleError = handler
return this
}
webhookCallback (path = '/') {
return generateCallback(path, (update, res) => this.handleUpdate(update, res), debug)
}
startPolling (timeout = 30, limit = 100, allowedUpdates) {
this.state.timeout = timeout
this.state.limit = limit
this.state.allowedUpdates = allowedUpdates
? Array.isArray(allowedUpdates) ? allowedUpdates : [`${allowedUpdates}`]
: null
if (!this.state.started) {
this.state.started = true
this.fetchUpdates()
}
return this
}
startWebhook (path, tlsOptions, port, host, cb) {
const webhookCb = this.webhookCallback(path)
const callback = cb && typeof cb === 'function'
? (req, res) => webhookCb(req, res, () => cb(req, res))
: webhookCb
this.webhookServer = tlsOptions
? require('https').createServer(tlsOptions, callback)
: require('http').createServer(callback)
this.webhookServer.listen(port, host, () => {
debug('Webhook listening on port: %s', port)
})
return this
}
stop () {
this.state.started = false
if (this.webhookServer) {
this.webhookServer.close()
}
return this
}
handleUpdates (updates) {
if (!Array.isArray(updates)) {
return Promise.reject(new Error('Updates must be an array'))
}
const processAll = Promise.all(updates.map((update) => this.handleUpdate(update)))
if (this.options.handlerTimeout === 0) {
return processAll
}
return Promise.race([
processAll,
new Promise((resolve) => setTimeout(resolve, this.options.handlerTimeout))
])
}
handleUpdate (update, webhookResponse) {
debug('âš¡ update', update.update_id)
const telegram = webhookResponse
? new Telegram(this.token, this.options.telegram, webhookResponse)
: this.telegram
const ctx = new Context(update, telegram, this.options)
Object.assign(ctx, this.context)
return this.middleware()(ctx).catch(this.handleError)
}
fetchUpdates () {
const { timeout, limit, offset, started, allowedUpdates } = this.state
if (!started) {
return
}
this.telegram.getUpdates(timeout, limit, offset, allowedUpdates)
.catch((err) => {
const wait = err.retryAfter || this.options.retryAfter
console.error(`Failed to get updates. Waiting: ${wait}s`, err)
return new Promise((resolve) => setTimeout(resolve, wait * 1000, []))
})
.then((updates) => this.handleUpdates(updates).then(() => updates))
.catch((err) => {
console.error('Failed to process updates.', err)
this.state.offset = 0
this.state.started = false
return []
})
.then((updates) => {
if (updates.length > 0) {
this.state.offset = updates[updates.length - 1].update_id + 1
}
this.fetchUpdates()
})
}
}
n/a
class Composer { constructor (...handlers) { this.handler = Composer.compose(handlers) } use (...fns) { this.handler = Composer.compose([this.handler, ...fns]) return this } on (updateTypes, ...fns) { return this.use(Composer.mount(updateTypes, Composer.compose(fns))) } hears (triggers, ...fns) { return this.use(Composer.hears(triggers, Composer.compose(fns))) } command (commands, ...fns) { return this.use(Composer.command(commands, Composer.compose(fns))) } action (triggers, ...fns) { return this.use(Composer.action(triggers, Composer.compose(fns))) } gameQuery (...fns) { return this.use(Composer.gameQuery(Composer.compose(fns))) } middleware () { return this.handler } static reply (...args) { return (ctx) => ctx.reply(...args) } static fork (middleware) { return (ctx, next) => { setImmediate(unwrap(middleware), ctx) return next() } } static passThru () { return (ctx, next) => next() } static lazy (fn) { if (typeof fn !== 'function') { throw new Error('Argument must be a function') } return (ctx, next) => Promise.resolve(fn(ctx)) .then((middleware) => { const handler = unwrap(middleware) return handler(ctx, next) }) } static log (logFn = console.log) { return Composer.fork((ctx) => logFn(JSON.stringify(ctx.update, null, 2))) } static branch (test, trueMiddleware, falseMiddleware) { if (typeof test !== 'function') { return test ? trueMiddleware : falseMiddleware } return Composer.lazy((ctx) => Promise.resolve(test(ctx)).then((value) => value ? trueMiddleware : falseMiddleware)) } static optional (test, ...fns) { return Composer.branch(test, Composer.compose(fns), Composer.passThru()) } static dispatch (test, handlers) { if (typeof test !== 'function') { return handlers[test] || Composer.passThru() } return Composer.lazy((ctx) => Promise.resolve(test(ctx)).then((value) => handlers[value])) } static mount (updateType, middleware) { let test = Array.isArray(updateType) ? (ctx) => updateType.includes(ctx.updateType) || updateType.includes(ctx.updateSubType) : (ctx) => updateType === ctx.updateType || updateType === ctx.updateSubType return Composer.optional(test, middleware) } static hears (triggers, middleware) { const tests = makeTests(triggers) return Composer.mount('text', Composer.match(tests, middleware)) } static action (triggers, middleware) { const tests = makeTests(triggers) return Composer.mount('callback_query', Composer.match(tests, middleware)) } static match (tests, middleware) { return Composer.lazy((ctx) => { const text = (ctx.message && (ctx.message.caption || ctx.message.text)) || (ctx.callbackQuery && ctx.callbackQuery.data) for (let test of tests) { const result = test(text, ctx) if (!result) { continue } ctx.match = result return middleware } return Composer.passThru() }) } static acl (userId, middleware) { let whitelistFn = userId if (typeof whitelistFn !== 'function') { const allowed = Array.isArray(userId) ? userId : [userId] whitelistFn = (ctx) => allowed.includes(ctx.from.id) || (ctx.from.username && allowed.includes(ctx.from.username)) } return Composer.optional(whitelistFn, middleware) } static gameQuery (middleware) { return Composer.mount('callback_query', Composer.optional((ctx) => ctx.callbackQuery.game_short_name, middleware)) } static command (command, middleware) { let commands = Array.isArray(command) ? command : [command] commands = commands.map((cmd) => cmd.startsWith('/') ? cmd : `/${cmd}`) return Composer.mount('text', Composer.lazy((ctx) => { const text = ctx.message.text const groupCommands = ctx.me && (ctx.chat.type === 'group' || ctx.chat.type === 'supergroup') ? commands.map((command) => `${command}@${ctx.me}`) : [] const hasM ...
n/a
class Extra { constructor (opts) { this.load(opts) } load (opts) { if (opts) { Object.assign(this, opts) } return this } inReplyTo (messageId) { this.reply_to_message_id = messageId return this } notifications (value = true) { this.disable_notification = !value return this } webPreview (value = true) { this.disable_web_page_preview = !value return this } markup (markup) { if (typeof markup === 'function') { markup = markup(new ReplyMarkup()) } this.reply_markup = Object.assign({}, markup) return this } HTML (value = true) { this.parse_mode = value ? 'HTML' : undefined return this } markdown (value = true) { this.parse_mode = value ? 'Markdown' : undefined return this } static inReplyTo (messageId) { return new Extra().inReplyTo(messageId) } static notifications (value) { return new Extra().notifications(value) } static webPreview (value) { return new Extra().webPreview(value) } static load (opts) { return new Extra(opts) } static markup (markup) { return new Extra().markup(markup) } static HTML (value) { return new Extra().HTML(value) } static markdown (value) { return new Extra().markdown(value) } }
n/a
class Markup { forceReply (value = true) { this.force_reply = value return this } removeKeyboard (value = true) { this.remove_keyboard = value return this } selective (value = true) { this.selective = value return this } extra () { return { reply_markup: Object.assign({}, this) } } keyboard (buttons, options) { const keyboard = buildKeyboard(buttons, Object.assign({columns: 1}, options)) if (keyboard && keyboard.length > 0) { this.keyboard = keyboard } return this } resize (value = true) { this.resize_keyboard = value return this } oneTime (value = true) { this.one_time_keyboard = value return this } inlineKeyboard (buttons, options) { const keyboard = buildKeyboard(buttons, Object.assign({columns: buttons.length}, options)) if (keyboard && keyboard.length > 0) { this.inline_keyboard = keyboard } return this } button (text, hide) { return Markup.button(text, hide) } contactRequestButton (text, hide) { return Markup.contactRequestButton(text, hide) } locationRequestButton (text, hide) { return Markup.locationRequestButton(text, hide) } urlButton (text, url, hide) { return Markup.urlButton(text, url, hide) } callbackButton (text, data, hide) { return Markup.callbackButton(text, data, hide) } gameButton (text, hide) { return Markup.gameButton(text, hide) } static removeKeyboard (value) { return new Markup().removeKeyboard(value) } static forceReply (value) { return new Markup().forceReply(value) } static keyboard (buttons, options) { return new Markup().keyboard(buttons, options) } static inlineKeyboard (buttons, options) { return new Markup().inlineKeyboard(buttons, options) } static resize (value = true) { return new Markup().resize(value) } static oneTime (value = true) { return new Markup().oneTime(value) } static button (text, hide) { return { text: text, hide: hide } } static contactRequestButton (text, hide = false) { return { text: text, request_contact: true, hide: hide } } static locationRequestButton (text, hide = false) { return { text: text, request_location: true, hide: hide } } static urlButton (text, url, hide = false) { return { text: text, url: url, hide: hide } } static callbackButton (text, data, hide = false) { return { text: text, callback_data: data, hide: hide } } static switchToChatButton (text, value, hide = false) { return { text: text, switch_inline_query: value, hide: hide } } static switchToCurrentChatButton (text, value, hide = false) { return { text: text, switch_inline_query_current_chat: value, hide: hide } } static gameButton (text, hide = false) { return { text: text, callback_game: {}, hide: hide } } }
n/a
class Router { constructor (routeFn) { if (!routeFn) { throw new Error('Missing routing function') } this.routeFn = routeFn this.handlers = new Map() this.otherwiseHandler = passThru() } on (route, ...fns) { if (fns.length === 0) { throw new TypeError('At least one handler must be provided') } this.handlers.set(route, compose(fns)) return this } otherwise (...fns) { if (fns.length === 0) { throw new TypeError('At least one otherwise handler must be provided') } this.otherwiseHandler = compose(fns) return this } middleware () { return lazy((ctx) => { return this.routeFn(ctx).then((result) => { if (!result || !result.route || !this.handlers.has(result.route)) { return this.otherwiseHandler } Object.assign(ctx, result.context) Object.assign(ctx.state, result.state) return this.handlers.get(result.route) }) }) } }
n/a
class Telegram extends ApiClient { getMe () { return this.callApi('getMe') } getFile (fileId) { return this.callApi('getFile', {file_id: fileId}) } getFileLink (fileId) { return Promise.resolve(fileId) .then((fileId) => { if (fileId && fileId.file_path) { return fileId } const id = fileId && fileId.file_id ? fileId.file_id : fileId return this.getFile(id) }) .then((file) => `${this.options.apiRoot}/file/bot${this.token}/${file.file_path}`) } getUpdates (timeout, limit, offset, allowedUpdates) { let url = `getUpdates?offset=${offset}&limit=${limit}&timeout=${timeout}` return this.callApi(url, { allowed_updates: allowedUpdates }) } getWebhookInfo () { return this.callApi(`getWebhookInfo`) } getGameHighScores (userId, inlineMessageId, chatId, messageId) { return this.callApi(`getGameHighScores`, { user_id: userId, inline_message_id: inlineMessageId, chat_id: chatId, message_id: messageId }) } setGameScore (userId, score, inlineMessageId, chatId, messageId, editMessage = true, force) { return this.callApi(`setGameScore`, { user_id: userId, score: score, inline_message_id: inlineMessageId, chat_id: chatId, message_id: messageId, disable_edit_message: !editMessage, force: force }) } setWebhook (url, cert, maxConnections, allowedUpdates) { return this.callApi('setWebhook', { url: url, certificate: cert, max_connections: maxConnections, allowed_updates: allowedUpdates }) } deleteWebhook () { return this.callApi('deleteWebhook') } sendMessage (chatId, text, extra) { return this.callApi('sendMessage', Object.assign({ chat_id: chatId, text: text }, extra)) } forwardMessage (chatId, fromChatId, messageId, extra) { return this.callApi('forwardMessage', Object.assign({ chat_id: chatId, from_chat_id: fromChatId, message_id: messageId }, extra)) } sendChatAction (chatId, action) { return this.callApi('sendChatAction', { chat_id: chatId, action: action }) } getUserProfilePhotos (userId, offset, limit) { return this.callApi('getUserProfilePhotos', { user_id: userId, offset: offset, limit: limit }) } sendLocation (chatId, latitude, longitude, extra) { return this.callApi('sendLocation', Object.assign({ chat_id: chatId, latitude: latitude, longitude: longitude }, extra)) } sendVenue (chatId, latitude, longitude, title, address, extra) { return this.callApi('sendVenue', Object.assign({ chat_id: chatId, latitude: latitude, longitude: longitude, title: title, address: address }, extra)) } sendContact (chatId, phoneNumber, firstName, extra) { return this.callApi('sendContact', Object.assign({ chat_id: chatId, phone_number: phoneNumber, first_name: firstName }, extra )) } sendPhoto (chatId, photo, extra) { return this.callApi('sendPhoto', Object.assign({ chat_id: chatId, photo: photo }, extra)) } sendDocument (chatId, doc, extra) { return this.callApi('sendDocument', Object.assign({ chat_id: chatId, document: doc }, extra)) } sendAudio (chatId, audio, extra) { return this.callApi('sendAudio', Object.assign({ chat_id: chatId, audio: audio }, extra)) } sendSticker (chatId, sticker, extra) { return this.callApi('sendSticker', Object.assign({ chat_id: chatId, sticker: sticker }, extra)) } sendVideo (chatId, video, extra) { return this.callApi('sendVideo', Object.assign({ chat_id: chatId, video: video }, extra)) } sendVoice (chatId, voice, extra) { return this.callApi('sendVoice', Object.assign({ chat_id: chatId, voice: voice }, extra)) } sendGame (chatId, gameName, extra) { return this.callApi('sendGame', Object.assign({ chat_id: chatId, game_short_name: gameName }, extra)) } getChat (chatId) { return this.callApi('getChat', {chat_id: chatId}) } getChatAdministrators (chatId) { return this.callApi('getCh ...
n/a
class TelegramError extends Error { constructor (payload = {}) { super(`${payload.error_code}: ${payload.description}`) this.code = payload.error_code this.description = payload.description this.retryAfter = payload.retry_after this.migrateToChatId = payload.migrate_to_chat_id } }
n/a
memorySession = function (opts) { opts = Object.assign({ sessionName: 'session', getSessionKey: (ctx) => ctx.from && ctx.chat && `${ctx.from.id}:${ctx.chat.id}` }, opts) const store = new Map() return (ctx, next) => { const key = opts.getSessionKey(ctx) if (!key) { return next() } let session = store.get(key) || {} Object.defineProperty(ctx, opts.sessionName, { get: function () { return session }, set: function (newValue) { session = Object.assign({}, newValue) } }) try { return next() } finally { store.set(key, session) } } }
n/a
class Extra { constructor (opts) { this.load(opts) } load (opts) { if (opts) { Object.assign(this, opts) } return this } inReplyTo (messageId) { this.reply_to_message_id = messageId return this } notifications (value = true) { this.disable_notification = !value return this } webPreview (value = true) { this.disable_web_page_preview = !value return this } markup (markup) { if (typeof markup === 'function') { markup = markup(new ReplyMarkup()) } this.reply_markup = Object.assign({}, markup) return this } HTML (value = true) { this.parse_mode = value ? 'HTML' : undefined return this } markdown (value = true) { this.parse_mode = value ? 'Markdown' : undefined return this } static inReplyTo (messageId) { return new Extra().inReplyTo(messageId) } static notifications (value) { return new Extra().notifications(value) } static webPreview (value) { return new Extra().webPreview(value) } static load (opts) { return new Extra(opts) } static markup (markup) { return new Extra().markup(markup) } static HTML (value) { return new Extra().HTML(value) } static markdown (value) { return new Extra().markdown(value) } }
n/a
class Markup { forceReply (value = true) { this.force_reply = value return this } removeKeyboard (value = true) { this.remove_keyboard = value return this } selective (value = true) { this.selective = value return this } extra () { return { reply_markup: Object.assign({}, this) } } keyboard (buttons, options) { const keyboard = buildKeyboard(buttons, Object.assign({columns: 1}, options)) if (keyboard && keyboard.length > 0) { this.keyboard = keyboard } return this } resize (value = true) { this.resize_keyboard = value return this } oneTime (value = true) { this.one_time_keyboard = value return this } inlineKeyboard (buttons, options) { const keyboard = buildKeyboard(buttons, Object.assign({columns: buttons.length}, options)) if (keyboard && keyboard.length > 0) { this.inline_keyboard = keyboard } return this } button (text, hide) { return Markup.button(text, hide) } contactRequestButton (text, hide) { return Markup.contactRequestButton(text, hide) } locationRequestButton (text, hide) { return Markup.locationRequestButton(text, hide) } urlButton (text, url, hide) { return Markup.urlButton(text, url, hide) } callbackButton (text, data, hide) { return Markup.callbackButton(text, data, hide) } gameButton (text, hide) { return Markup.gameButton(text, hide) } static removeKeyboard (value) { return new Markup().removeKeyboard(value) } static forceReply (value) { return new Markup().forceReply(value) } static keyboard (buttons, options) { return new Markup().keyboard(buttons, options) } static inlineKeyboard (buttons, options) { return new Markup().inlineKeyboard(buttons, options) } static resize (value = true) { return new Markup().resize(value) } static oneTime (value = true) { return new Markup().oneTime(value) } static button (text, hide) { return { text: text, hide: hide } } static contactRequestButton (text, hide = false) { return { text: text, request_contact: true, hide: hide } } static locationRequestButton (text, hide = false) { return { text: text, request_location: true, hide: hide } } static urlButton (text, url, hide = false) { return { text: text, url: url, hide: hide } } static callbackButton (text, data, hide = false) { return { text: text, callback_data: data, hide: hide } } static switchToChatButton (text, value, hide = false) { return { text: text, switch_inline_query: value, hide: hide } } static switchToCurrentChatButton (text, value, hide = false) { return { text: text, switch_inline_query_current_chat: value, hide: hide } } static gameButton (text, hide = false) { return { text: text, callback_game: {}, hide: hide } } }
n/a
class Markup { forceReply (value = true) { this.force_reply = value return this } removeKeyboard (value = true) { this.remove_keyboard = value return this } selective (value = true) { this.selective = value return this } extra () { return { reply_markup: Object.assign({}, this) } } keyboard (buttons, options) { const keyboard = buildKeyboard(buttons, Object.assign({columns: 1}, options)) if (keyboard && keyboard.length > 0) { this.keyboard = keyboard } return this } resize (value = true) { this.resize_keyboard = value return this } oneTime (value = true) { this.one_time_keyboard = value return this } inlineKeyboard (buttons, options) { const keyboard = buildKeyboard(buttons, Object.assign({columns: buttons.length}, options)) if (keyboard && keyboard.length > 0) { this.inline_keyboard = keyboard } return this } button (text, hide) { return Markup.button(text, hide) } contactRequestButton (text, hide) { return Markup.contactRequestButton(text, hide) } locationRequestButton (text, hide) { return Markup.locationRequestButton(text, hide) } urlButton (text, url, hide) { return Markup.urlButton(text, url, hide) } callbackButton (text, data, hide) { return Markup.callbackButton(text, data, hide) } gameButton (text, hide) { return Markup.gameButton(text, hide) } static removeKeyboard (value) { return new Markup().removeKeyboard(value) } static forceReply (value) { return new Markup().forceReply(value) } static keyboard (buttons, options) { return new Markup().keyboard(buttons, options) } static inlineKeyboard (buttons, options) { return new Markup().inlineKeyboard(buttons, options) } static resize (value = true) { return new Markup().resize(value) } static oneTime (value = true) { return new Markup().oneTime(value) } static button (text, hide) { return { text: text, hide: hide } } static contactRequestButton (text, hide = false) { return { text: text, request_contact: true, hide: hide } } static locationRequestButton (text, hide = false) { return { text: text, request_location: true, hide: hide } } static urlButton (text, url, hide = false) { return { text: text, url: url, hide: hide } } static callbackButton (text, data, hide = false) { return { text: text, callback_data: data, hide: hide } } static switchToChatButton (text, value, hide = false) { return { text: text, switch_inline_query: value, hide: hide } } static switchToCurrentChatButton (text, value, hide = false) { return { text: text, switch_inline_query_current_chat: value, hide: hide } } static gameButton (text, hide = false) { return { text: text, callback_game: {}, hide: hide } } }
n/a
function deprecated() { warned = exports.printDeprecationMessage(msg, warned, deprecated); if (new.target) { return Reflect.construct(fn, arguments, new.target); } return fn.apply(this, arguments); }
n/a
function deprecated() { warned = exports.printDeprecationMessage(msg, warned, deprecated); if (new.target) { return Reflect.construct(fn, arguments, new.target); } return fn.apply(this, arguments); }
n/a
class Telegram extends ApiClient { getMe () { return this.callApi('getMe') } getFile (fileId) { return this.callApi('getFile', {file_id: fileId}) } getFileLink (fileId) { return Promise.resolve(fileId) .then((fileId) => { if (fileId && fileId.file_path) { return fileId } const id = fileId && fileId.file_id ? fileId.file_id : fileId return this.getFile(id) }) .then((file) => `${this.options.apiRoot}/file/bot${this.token}/${file.file_path}`) } getUpdates (timeout, limit, offset, allowedUpdates) { let url = `getUpdates?offset=${offset}&limit=${limit}&timeout=${timeout}` return this.callApi(url, { allowed_updates: allowedUpdates }) } getWebhookInfo () { return this.callApi(`getWebhookInfo`) } getGameHighScores (userId, inlineMessageId, chatId, messageId) { return this.callApi(`getGameHighScores`, { user_id: userId, inline_message_id: inlineMessageId, chat_id: chatId, message_id: messageId }) } setGameScore (userId, score, inlineMessageId, chatId, messageId, editMessage = true, force) { return this.callApi(`setGameScore`, { user_id: userId, score: score, inline_message_id: inlineMessageId, chat_id: chatId, message_id: messageId, disable_edit_message: !editMessage, force: force }) } setWebhook (url, cert, maxConnections, allowedUpdates) { return this.callApi('setWebhook', { url: url, certificate: cert, max_connections: maxConnections, allowed_updates: allowedUpdates }) } deleteWebhook () { return this.callApi('deleteWebhook') } sendMessage (chatId, text, extra) { return this.callApi('sendMessage', Object.assign({ chat_id: chatId, text: text }, extra)) } forwardMessage (chatId, fromChatId, messageId, extra) { return this.callApi('forwardMessage', Object.assign({ chat_id: chatId, from_chat_id: fromChatId, message_id: messageId }, extra)) } sendChatAction (chatId, action) { return this.callApi('sendChatAction', { chat_id: chatId, action: action }) } getUserProfilePhotos (userId, offset, limit) { return this.callApi('getUserProfilePhotos', { user_id: userId, offset: offset, limit: limit }) } sendLocation (chatId, latitude, longitude, extra) { return this.callApi('sendLocation', Object.assign({ chat_id: chatId, latitude: latitude, longitude: longitude }, extra)) } sendVenue (chatId, latitude, longitude, title, address, extra) { return this.callApi('sendVenue', Object.assign({ chat_id: chatId, latitude: latitude, longitude: longitude, title: title, address: address }, extra)) } sendContact (chatId, phoneNumber, firstName, extra) { return this.callApi('sendContact', Object.assign({ chat_id: chatId, phone_number: phoneNumber, first_name: firstName }, extra )) } sendPhoto (chatId, photo, extra) { return this.callApi('sendPhoto', Object.assign({ chat_id: chatId, photo: photo }, extra)) } sendDocument (chatId, doc, extra) { return this.callApi('sendDocument', Object.assign({ chat_id: chatId, document: doc }, extra)) } sendAudio (chatId, audio, extra) { return this.callApi('sendAudio', Object.assign({ chat_id: chatId, audio: audio }, extra)) } sendSticker (chatId, sticker, extra) { return this.callApi('sendSticker', Object.assign({ chat_id: chatId, sticker: sticker }, extra)) } sendVideo (chatId, video, extra) { return this.callApi('sendVideo', Object.assign({ chat_id: chatId, video: video }, extra)) } sendVoice (chatId, voice, extra) { return this.callApi('sendVoice', Object.assign({ chat_id: chatId, voice: voice }, extra)) } sendGame (chatId, gameName, extra) { return this.callApi('sendGame', Object.assign({ chat_id: chatId, game_short_name: gameName }, extra)) } getChat (chatId) { return this.callApi('getChat', {chat_id: chatId}) } getChatAdministrators (chatId) { return this.callApi('getCh ...
n/a
function deprecated() { warned = exports.printDeprecationMessage(msg, warned, deprecated); if (new.target) { return Reflect.construct(fn, arguments, new.target); } return fn.apply(this, arguments); }
n/a
function deprecated() { warned = exports.printDeprecationMessage(msg, warned, deprecated); if (new.target) { return Reflect.construct(fn, arguments, new.target); } return fn.apply(this, arguments); }
n/a
(message) => { return { audio: message.audio.file_id, duration: message.audio.duration, performer: message.audio.performer, title: message.audio.title, caption: message.caption } }
n/a
(message) => { return { phone_number: message.contact.phone_number, first_name: message.contact.first_name, last_name: message.contact.last_name } }
n/a
(message) => { return { document: message.document.file_id, caption: message.caption } }
n/a
(message) => { return { latitude: message.location.latitude, longitude: message.location.longitude } }
n/a
(message) => { return { photo: message.photo[message.photo.length - 1].file_id, caption: message.caption } }
n/a
(message) => { return { sticker: message.sticker.file_id } }
n/a
(message) => { const result = { text: message.text } if (!message.entities) { return result } message.entities.reverse().forEach((entity) => { switch (entity.type) { case 'bold': result.text = insert(result.text, entity.offset + entity.length, '</b>') result.text = insert(result.text, entity.offset, '<b>') break case 'italic': result.text = insert(result.text, entity.offset + entity.length, '</i>') result.text = insert(result.text, entity.offset, '<i>') break case 'code': result.text = insert(result.text, entity.offset + entity.length, '</code>') result.text = insert(result.text, entity.offset, '<code>') break case 'pre': result.text = insert(result.text, entity.offset + entity.length, '</pre>') result.text = insert(result.text, entity.offset, '<pre>') break case 'text_link': result.text = insert(result.text, entity.offset + entity.length, '</a>') result.text = insert(result.text, entity.offset, `<a href="${entity.url}">`) break default: return } result.parse_mode = 'HTML' }) return result }
...
debug('▶︎ http', method)
const buildPayload = isMultipart ? this.buildFormDataPayload(extra) : this.buildJSONPayload(extra)
return buildPayload
.then((payload) => {
payload.agent = this.options.agent
return fetch(`${this.options.apiRoot}/bot${this.token}/${method}`, payload)
})
.then((res) => res.text())
.then((text) => {
try {
return JSON.parse(text)
} catch (err) {
throw new TelegramError({
error_code: 500,
description: 'Unsupported message received from Telegram',
...
(message) => { return { latitude: message.venue.location.latitude, longitude: message.venue.location.longitude, title: message.venue.title, address: message.venue.address, foursquare_id: message.venue.foursquare_id } }
n/a
(message) => { return { video: message.video.file_id, caption: message.caption, duration: message.video.duration, width: message.video.width, height: message.video.height } }
n/a
(message) => { return { voice: message.voice.file_id, duration: message.voice.duration, caption: message.caption } }
n/a
class Telegraf extends Composer {
constructor (token, options) {
super()
this.options = Object.assign({
retryAfter: 1,
handlerTimeout: 0
}, options)
this.token = token
this.handleError = (err) => {
console.error()
console.error((err.stack || err.toString()).replace(/^/gm, ' '))
console.error()
throw err
}
this.context = {}
this.state = {
offset: 0,
started: false
}
}
get token () {
return this.options.token
}
set token (token) {
this.options.token = token
this.telegram = new Telegram(this.options.token, this.options.telegram)
}/* eslint brace-style: 0 */
catch (handler) {
this.handleError = handler
return this
}
webhookCallback (path = '/') {
return generateCallback(path, (update, res) => this.handleUpdate(update, res), debug)
}
startPolling (timeout = 30, limit = 100, allowedUpdates) {
this.state.timeout = timeout
this.state.limit = limit
this.state.allowedUpdates = allowedUpdates
? Array.isArray(allowedUpdates) ? allowedUpdates : [`${allowedUpdates}`]
: null
if (!this.state.started) {
this.state.started = true
this.fetchUpdates()
}
return this
}
startWebhook (path, tlsOptions, port, host, cb) {
const webhookCb = this.webhookCallback(path)
const callback = cb && typeof cb === 'function'
? (req, res) => webhookCb(req, res, () => cb(req, res))
: webhookCb
this.webhookServer = tlsOptions
? require('https').createServer(tlsOptions, callback)
: require('http').createServer(callback)
this.webhookServer.listen(port, host, () => {
debug('Webhook listening on port: %s', port)
})
return this
}
stop () {
this.state.started = false
if (this.webhookServer) {
this.webhookServer.close()
}
return this
}
handleUpdates (updates) {
if (!Array.isArray(updates)) {
return Promise.reject(new Error('Updates must be an array'))
}
const processAll = Promise.all(updates.map((update) => this.handleUpdate(update)))
if (this.options.handlerTimeout === 0) {
return processAll
}
return Promise.race([
processAll,
new Promise((resolve) => setTimeout(resolve, this.options.handlerTimeout))
])
}
handleUpdate (update, webhookResponse) {
debug('âš¡ update', update.update_id)
const telegram = webhookResponse
? new Telegram(this.token, this.options.telegram, webhookResponse)
: this.telegram
const ctx = new Context(update, telegram, this.options)
Object.assign(ctx, this.context)
return this.middleware()(ctx).catch(this.handleError)
}
fetchUpdates () {
const { timeout, limit, offset, started, allowedUpdates } = this.state
if (!started) {
return
}
this.telegram.getUpdates(timeout, limit, offset, allowedUpdates)
.catch((err) => {
const wait = err.retryAfter || this.options.retryAfter
console.error(`Failed to get updates. Waiting: ${wait}s`, err)
return new Promise((resolve) => setTimeout(resolve, wait * 1000, []))
})
.then((updates) => this.handleUpdates(updates).then(() => updates))
.catch((err) => {
console.error('Failed to process updates.', err)
this.state.offset = 0
this.state.started = false
return []
})
.then((updates) => {
if (updates.length > 0) {
this.state.offset = updates[updates.length - 1].update_id + 1
}
this.fetchUpdates()
})
}
}
n/a
class Composer { constructor (...handlers) { this.handler = Composer.compose(handlers) } use (...fns) { this.handler = Composer.compose([this.handler, ...fns]) return this } on (updateTypes, ...fns) { return this.use(Composer.mount(updateTypes, Composer.compose(fns))) } hears (triggers, ...fns) { return this.use(Composer.hears(triggers, Composer.compose(fns))) } command (commands, ...fns) { return this.use(Composer.command(commands, Composer.compose(fns))) } action (triggers, ...fns) { return this.use(Composer.action(triggers, Composer.compose(fns))) } gameQuery (...fns) { return this.use(Composer.gameQuery(Composer.compose(fns))) } middleware () { return this.handler } static reply (...args) { return (ctx) => ctx.reply(...args) } static fork (middleware) { return (ctx, next) => { setImmediate(unwrap(middleware), ctx) return next() } } static passThru () { return (ctx, next) => next() } static lazy (fn) { if (typeof fn !== 'function') { throw new Error('Argument must be a function') } return (ctx, next) => Promise.resolve(fn(ctx)) .then((middleware) => { const handler = unwrap(middleware) return handler(ctx, next) }) } static log (logFn = console.log) { return Composer.fork((ctx) => logFn(JSON.stringify(ctx.update, null, 2))) } static branch (test, trueMiddleware, falseMiddleware) { if (typeof test !== 'function') { return test ? trueMiddleware : falseMiddleware } return Composer.lazy((ctx) => Promise.resolve(test(ctx)).then((value) => value ? trueMiddleware : falseMiddleware)) } static optional (test, ...fns) { return Composer.branch(test, Composer.compose(fns), Composer.passThru()) } static dispatch (test, handlers) { if (typeof test !== 'function') { return handlers[test] || Composer.passThru() } return Composer.lazy((ctx) => Promise.resolve(test(ctx)).then((value) => handlers[value])) } static mount (updateType, middleware) { let test = Array.isArray(updateType) ? (ctx) => updateType.includes(ctx.updateType) || updateType.includes(ctx.updateSubType) : (ctx) => updateType === ctx.updateType || updateType === ctx.updateSubType return Composer.optional(test, middleware) } static hears (triggers, middleware) { const tests = makeTests(triggers) return Composer.mount('text', Composer.match(tests, middleware)) } static action (triggers, middleware) { const tests = makeTests(triggers) return Composer.mount('callback_query', Composer.match(tests, middleware)) } static match (tests, middleware) { return Composer.lazy((ctx) => { const text = (ctx.message && (ctx.message.caption || ctx.message.text)) || (ctx.callbackQuery && ctx.callbackQuery.data) for (let test of tests) { const result = test(text, ctx) if (!result) { continue } ctx.match = result return middleware } return Composer.passThru() }) } static acl (userId, middleware) { let whitelistFn = userId if (typeof whitelistFn !== 'function') { const allowed = Array.isArray(userId) ? userId : [userId] whitelistFn = (ctx) => allowed.includes(ctx.from.id) || (ctx.from.username && allowed.includes(ctx.from.username)) } return Composer.optional(whitelistFn, middleware) } static gameQuery (middleware) { return Composer.mount('callback_query', Composer.optional((ctx) => ctx.callbackQuery.game_short_name, middleware)) } static command (command, middleware) { let commands = Array.isArray(command) ? command : [command] commands = commands.map((cmd) => cmd.startsWith('/') ? cmd : `/${cmd}`) return Composer.mount('text', Composer.lazy((ctx) => { const text = ctx.message.text const groupCommands = ctx.me && (ctx.chat.type === 'group' || ctx.chat.type === 'supergroup') ? commands.map((command) => `${command}@${ctx.me}`) : [] const hasM ...
n/a
class Extra { constructor (opts) { this.load(opts) } load (opts) { if (opts) { Object.assign(this, opts) } return this } inReplyTo (messageId) { this.reply_to_message_id = messageId return this } notifications (value = true) { this.disable_notification = !value return this } webPreview (value = true) { this.disable_web_page_preview = !value return this } markup (markup) { if (typeof markup === 'function') { markup = markup(new ReplyMarkup()) } this.reply_markup = Object.assign({}, markup) return this } HTML (value = true) { this.parse_mode = value ? 'HTML' : undefined return this } markdown (value = true) { this.parse_mode = value ? 'Markdown' : undefined return this } static inReplyTo (messageId) { return new Extra().inReplyTo(messageId) } static notifications (value) { return new Extra().notifications(value) } static webPreview (value) { return new Extra().webPreview(value) } static load (opts) { return new Extra(opts) } static markup (markup) { return new Extra().markup(markup) } static HTML (value) { return new Extra().HTML(value) } static markdown (value) { return new Extra().markdown(value) } }
n/a
class Markup { forceReply (value = true) { this.force_reply = value return this } removeKeyboard (value = true) { this.remove_keyboard = value return this } selective (value = true) { this.selective = value return this } extra () { return { reply_markup: Object.assign({}, this) } } keyboard (buttons, options) { const keyboard = buildKeyboard(buttons, Object.assign({columns: 1}, options)) if (keyboard && keyboard.length > 0) { this.keyboard = keyboard } return this } resize (value = true) { this.resize_keyboard = value return this } oneTime (value = true) { this.one_time_keyboard = value return this } inlineKeyboard (buttons, options) { const keyboard = buildKeyboard(buttons, Object.assign({columns: buttons.length}, options)) if (keyboard && keyboard.length > 0) { this.inline_keyboard = keyboard } return this } button (text, hide) { return Markup.button(text, hide) } contactRequestButton (text, hide) { return Markup.contactRequestButton(text, hide) } locationRequestButton (text, hide) { return Markup.locationRequestButton(text, hide) } urlButton (text, url, hide) { return Markup.urlButton(text, url, hide) } callbackButton (text, data, hide) { return Markup.callbackButton(text, data, hide) } gameButton (text, hide) { return Markup.gameButton(text, hide) } static removeKeyboard (value) { return new Markup().removeKeyboard(value) } static forceReply (value) { return new Markup().forceReply(value) } static keyboard (buttons, options) { return new Markup().keyboard(buttons, options) } static inlineKeyboard (buttons, options) { return new Markup().inlineKeyboard(buttons, options) } static resize (value = true) { return new Markup().resize(value) } static oneTime (value = true) { return new Markup().oneTime(value) } static button (text, hide) { return { text: text, hide: hide } } static contactRequestButton (text, hide = false) { return { text: text, request_contact: true, hide: hide } } static locationRequestButton (text, hide = false) { return { text: text, request_location: true, hide: hide } } static urlButton (text, url, hide = false) { return { text: text, url: url, hide: hide } } static callbackButton (text, data, hide = false) { return { text: text, callback_data: data, hide: hide } } static switchToChatButton (text, value, hide = false) { return { text: text, switch_inline_query: value, hide: hide } } static switchToCurrentChatButton (text, value, hide = false) { return { text: text, switch_inline_query_current_chat: value, hide: hide } } static gameButton (text, hide = false) { return { text: text, callback_game: {}, hide: hide } } }
n/a
class Router { constructor (routeFn) { if (!routeFn) { throw new Error('Missing routing function') } this.routeFn = routeFn this.handlers = new Map() this.otherwiseHandler = passThru() } on (route, ...fns) { if (fns.length === 0) { throw new TypeError('At least one handler must be provided') } this.handlers.set(route, compose(fns)) return this } otherwise (...fns) { if (fns.length === 0) { throw new TypeError('At least one otherwise handler must be provided') } this.otherwiseHandler = compose(fns) return this } middleware () { return lazy((ctx) => { return this.routeFn(ctx).then((result) => { if (!result || !result.route || !this.handlers.has(result.route)) { return this.otherwiseHandler } Object.assign(ctx, result.context) Object.assign(ctx.state, result.state) return this.handlers.get(result.route) }) }) } }
n/a
class Telegram extends ApiClient { getMe () { return this.callApi('getMe') } getFile (fileId) { return this.callApi('getFile', {file_id: fileId}) } getFileLink (fileId) { return Promise.resolve(fileId) .then((fileId) => { if (fileId && fileId.file_path) { return fileId } const id = fileId && fileId.file_id ? fileId.file_id : fileId return this.getFile(id) }) .then((file) => `${this.options.apiRoot}/file/bot${this.token}/${file.file_path}`) } getUpdates (timeout, limit, offset, allowedUpdates) { let url = `getUpdates?offset=${offset}&limit=${limit}&timeout=${timeout}` return this.callApi(url, { allowed_updates: allowedUpdates }) } getWebhookInfo () { return this.callApi(`getWebhookInfo`) } getGameHighScores (userId, inlineMessageId, chatId, messageId) { return this.callApi(`getGameHighScores`, { user_id: userId, inline_message_id: inlineMessageId, chat_id: chatId, message_id: messageId }) } setGameScore (userId, score, inlineMessageId, chatId, messageId, editMessage = true, force) { return this.callApi(`setGameScore`, { user_id: userId, score: score, inline_message_id: inlineMessageId, chat_id: chatId, message_id: messageId, disable_edit_message: !editMessage, force: force }) } setWebhook (url, cert, maxConnections, allowedUpdates) { return this.callApi('setWebhook', { url: url, certificate: cert, max_connections: maxConnections, allowed_updates: allowedUpdates }) } deleteWebhook () { return this.callApi('deleteWebhook') } sendMessage (chatId, text, extra) { return this.callApi('sendMessage', Object.assign({ chat_id: chatId, text: text }, extra)) } forwardMessage (chatId, fromChatId, messageId, extra) { return this.callApi('forwardMessage', Object.assign({ chat_id: chatId, from_chat_id: fromChatId, message_id: messageId }, extra)) } sendChatAction (chatId, action) { return this.callApi('sendChatAction', { chat_id: chatId, action: action }) } getUserProfilePhotos (userId, offset, limit) { return this.callApi('getUserProfilePhotos', { user_id: userId, offset: offset, limit: limit }) } sendLocation (chatId, latitude, longitude, extra) { return this.callApi('sendLocation', Object.assign({ chat_id: chatId, latitude: latitude, longitude: longitude }, extra)) } sendVenue (chatId, latitude, longitude, title, address, extra) { return this.callApi('sendVenue', Object.assign({ chat_id: chatId, latitude: latitude, longitude: longitude, title: title, address: address }, extra)) } sendContact (chatId, phoneNumber, firstName, extra) { return this.callApi('sendContact', Object.assign({ chat_id: chatId, phone_number: phoneNumber, first_name: firstName }, extra )) } sendPhoto (chatId, photo, extra) { return this.callApi('sendPhoto', Object.assign({ chat_id: chatId, photo: photo }, extra)) } sendDocument (chatId, doc, extra) { return this.callApi('sendDocument', Object.assign({ chat_id: chatId, document: doc }, extra)) } sendAudio (chatId, audio, extra) { return this.callApi('sendAudio', Object.assign({ chat_id: chatId, audio: audio }, extra)) } sendSticker (chatId, sticker, extra) { return this.callApi('sendSticker', Object.assign({ chat_id: chatId, sticker: sticker }, extra)) } sendVideo (chatId, video, extra) { return this.callApi('sendVideo', Object.assign({ chat_id: chatId, video: video }, extra)) } sendVoice (chatId, voice, extra) { return this.callApi('sendVoice', Object.assign({ chat_id: chatId, voice: voice }, extra)) } sendGame (chatId, gameName, extra) { return this.callApi('sendGame', Object.assign({ chat_id: chatId, game_short_name: gameName }, extra)) } getChat (chatId) { return this.callApi('getChat', {chat_id: chatId}) } getChatAdministrators (chatId) { return this.callApi('getCh ...
n/a
class TelegramError extends Error { constructor (payload = {}) { super(`${payload.error_code}: ${payload.description}`) this.code = payload.error_code this.description = payload.description this.retryAfter = payload.retry_after this.migrateToChatId = payload.migrate_to_chat_id } }
n/a
memorySession = function (opts) { opts = Object.assign({ sessionName: 'session', getSessionKey: (ctx) => ctx.from && ctx.chat && `${ctx.from.id}:${ctx.chat.id}` }, opts) const store = new Map() return (ctx, next) => { const key = opts.getSessionKey(ctx) if (!key) { return next() } let session = store.get(key) || {} Object.defineProperty(ctx, opts.sessionName, { get: function () { return session }, set: function (newValue) { session = Object.assign({}, newValue) } }) try { return next() } finally { store.set(key, session) } } }
n/a
function deprecated() { warned = exports.printDeprecationMessage(msg, warned, deprecated); if (new.target) { return Reflect.construct(fn, arguments, new.target); } return fn.apply(this, arguments); }
n/a
function deprecated() { warned = exports.printDeprecationMessage(msg, warned, deprecated); if (new.target) { return Reflect.construct(fn, arguments, new.target); } return fn.apply(this, arguments); }
n/a