upd
This commit is contained in:
22
node_modules/telegraf/LICENSE
generated
vendored
Normal file
22
node_modules/telegraf/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Vitaly Domnikov
|
||||
Copyright (c) 2020-2023 The Telegraf Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
393
node_modules/telegraf/README.md
generated
vendored
Normal file
393
node_modules/telegraf/README.md
generated
vendored
Normal file
@@ -0,0 +1,393 @@
|
||||
<header>
|
||||
|
||||
<div align="center">
|
||||
<img src="docs/assets/logo.svg" alt="logo" height="90" align="center">
|
||||
<h1 align="center">telegraf.js</h1>
|
||||
|
||||
<p>Modern Telegram Bot API framework for Node.js</p>
|
||||
|
||||
<a href="https://core.telegram.org/bots/api">
|
||||
<img src="https://img.shields.io/badge/Bot%20API-v7.1-f36caf.svg?style=flat-square" alt="Bot API Version" />
|
||||
</a>
|
||||
<a href="https://packagephobia.com/result?p=telegraf,node-telegram-bot-api">
|
||||
<img src="https://flat.badgen.net/packagephobia/install/telegraf" alt="install size" />
|
||||
</a>
|
||||
<a href="https://github.com/telegraf/telegraf">
|
||||
<img src="https://img.shields.io/github/languages/top/telegraf/telegraf?style=flat-square&logo=github" alt="GitHub top language" />
|
||||
</a>
|
||||
<a href="https://telegram.me/TelegrafJSChat">
|
||||
<img src="https://img.shields.io/badge/English%20chat-grey?style=flat-square&logo=telegram" alt="English chat" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</header>
|
||||
|
||||
## For 3.x users
|
||||
|
||||
- [3.x docs](https://telegraf.js.org/v3)
|
||||
- [4.0 release notes](https://github.com/telegraf/telegraf/releases/tag/v4.0.0)
|
||||
|
||||
## Introduction
|
||||
|
||||
Bots are special [Telegram](https://telegram.org) accounts designed to handle messages automatically.
|
||||
Users can interact with bots by sending them command messages in private or group chats.
|
||||
These accounts serve as an interface for code running somewhere on your server.
|
||||
|
||||
Telegraf is a library that makes it simple for you to develop your own Telegram bots using JavaScript or [TypeScript](https://www.typescriptlang.org/).
|
||||
|
||||
### Features
|
||||
|
||||
- Full [Telegram Bot API 7.1](https://core.telegram.org/bots/api) support
|
||||
- [Excellent TypeScript typings](https://github.com/telegraf/telegraf/releases/tag/v4.0.0)
|
||||
- [Lightweight](https://packagephobia.com/result?p=telegraf,node-telegram-bot-api)
|
||||
- [AWS **λ**](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html)
|
||||
/ [Firebase](https://firebase.google.com/products/functions/)
|
||||
/ [Glitch](https://glitch.com/edit/#!/dashing-light)
|
||||
/ [Fly.io](https://fly.io/docs/languages-and-frameworks/node)
|
||||
/ Whatever ready
|
||||
- `http/https/fastify/Connect.js/express.js` compatible webhooks
|
||||
- Extensible
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
const { Telegraf } = require('telegraf')
|
||||
const { message } = require('telegraf/filters')
|
||||
|
||||
const bot = new Telegraf(process.env.BOT_TOKEN)
|
||||
bot.start((ctx) => ctx.reply('Welcome'))
|
||||
bot.help((ctx) => ctx.reply('Send me a sticker'))
|
||||
bot.on(message('sticker'), (ctx) => ctx.reply('👍'))
|
||||
bot.hears('hi', (ctx) => ctx.reply('Hey there'))
|
||||
bot.launch()
|
||||
|
||||
// Enable graceful stop
|
||||
process.once('SIGINT', () => bot.stop('SIGINT'))
|
||||
process.once('SIGTERM', () => bot.stop('SIGTERM'))
|
||||
```
|
||||
|
||||
```js
|
||||
const { Telegraf } = require('telegraf')
|
||||
|
||||
const bot = new Telegraf(process.env.BOT_TOKEN)
|
||||
bot.command('oldschool', (ctx) => ctx.reply('Hello'))
|
||||
bot.command('hipster', Telegraf.reply('λ'))
|
||||
bot.launch()
|
||||
|
||||
// Enable graceful stop
|
||||
process.once('SIGINT', () => bot.stop('SIGINT'))
|
||||
process.once('SIGTERM', () => bot.stop('SIGTERM'))
|
||||
```
|
||||
|
||||
For additional bot examples see the new [`docs repo`](https://github.com/feathers-studio/telegraf-docs/).
|
||||
|
||||
### Resources
|
||||
|
||||
- [Getting started](#getting-started)
|
||||
- [API reference](https://telegraf.js.org/modules.html)
|
||||
- Telegram groups (sorted by number of members):
|
||||
- [English](https://t.me/TelegrafJSChat)
|
||||
- [Russian](https://t.me/telegrafjs_ru)
|
||||
- [Uzbek](https://t.me/botjs_uz)
|
||||
- [Ethiopian](https://t.me/telegraf_et)
|
||||
- [GitHub Discussions](https://github.com/telegraf/telegraf/discussions)
|
||||
- [Dependent repositories](https://libraries.io/npm/telegraf/dependent_repositories)
|
||||
|
||||
## Getting started
|
||||
|
||||
### Telegram token
|
||||
|
||||
To use the [Telegram Bot API](https://core.telegram.org/bots/api),
|
||||
you first have to [get a bot account](https://core.telegram.org/bots)
|
||||
by [chatting with BotFather](https://core.telegram.org/bots#6-botfather).
|
||||
|
||||
BotFather will give you a _token_, something like `123456789:AbCdefGhIJKlmNoPQRsTUVwxyZ`.
|
||||
|
||||
### Installation
|
||||
|
||||
```shellscript
|
||||
$ npm install telegraf
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```shellscript
|
||||
$ yarn add telegraf
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```shellscript
|
||||
$ pnpm add telegraf
|
||||
```
|
||||
|
||||
### `Telegraf` class
|
||||
|
||||
[`Telegraf`] instance represents your bot. It's responsible for obtaining updates and passing them to your handlers.
|
||||
|
||||
Start by [listening to commands](https://telegraf.js.org/classes/Telegraf-1.html#command) and [launching](https://telegraf.js.org/classes/Telegraf-1.html#launch) your bot.
|
||||
|
||||
### `Context` class
|
||||
|
||||
`ctx` you can see in every example is a [`Context`] instance.
|
||||
[`Telegraf`] creates one for each incoming update and passes it to your middleware.
|
||||
It contains the `update`, `botInfo`, and `telegram` for making arbitrary Bot API requests,
|
||||
as well as shorthand methods and getters.
|
||||
|
||||
This is probably the class you'll be using the most.
|
||||
|
||||
<!--
|
||||
TODO: Verify and update list
|
||||
Here is a list of
|
||||
|
||||
#### Known middleware
|
||||
|
||||
- [Internationalization](https://github.com/telegraf/telegraf-i18n)—simplifies selecting the right translation to use when responding to a user.
|
||||
- [Redis powered session](https://github.com/telegraf/telegraf-session-redis)—store session data using Redis.
|
||||
- [Local powered session (via lowdb)](https://github.com/RealSpeaker/telegraf-session-local)—store session data in a local file.
|
||||
- [Rate-limiting](https://github.com/telegraf/telegraf-ratelimit)—apply rate limitting to chats or users.
|
||||
- [Bottleneck powered throttling](https://github.com/KnightNiwrem/telegraf-throttler)—apply throttling to both incoming updates and outgoing API calls.
|
||||
- [Menus via inline keyboards](https://github.com/EdJoPaTo/telegraf-inline-menu)—simplify creating interfaces based on menus.
|
||||
- [Stateless Questions](https://github.com/EdJoPaTo/telegraf-stateless-question)—create stateless questions to Telegram users working in privacy mode.
|
||||
- [Natural language processing via wit.ai](https://github.com/telegraf/telegraf-wit)
|
||||
- [Natural language processing via recast.ai](https://github.com/telegraf/telegraf-recast)
|
||||
- [Multivariate and A/B testing](https://github.com/telegraf/telegraf-experiments)—add experiments to see how different versions of a feature are used.
|
||||
- [Powerfull bot stats via Mixpanel](https://github.com/telegraf/telegraf-mixpanel)
|
||||
- [statsd integration](https://github.com/telegraf/telegraf-statsd)
|
||||
- [and more...](https://www.npmjs.com/search?q=telegraf-)
|
||||
-->
|
||||
|
||||
#### Shorthand methods
|
||||
|
||||
```js
|
||||
import { Telegraf } from 'telegraf'
|
||||
import { message } from 'telegraf/filters'
|
||||
|
||||
const bot = new Telegraf(process.env.BOT_TOKEN)
|
||||
|
||||
bot.command('quit', async (ctx) => {
|
||||
// Explicit usage
|
||||
await ctx.telegram.leaveChat(ctx.message.chat.id)
|
||||
|
||||
// Using context shortcut
|
||||
await ctx.leaveChat()
|
||||
})
|
||||
|
||||
bot.on(message('text'), async (ctx) => {
|
||||
// Explicit usage
|
||||
await ctx.telegram.sendMessage(ctx.message.chat.id, `Hello ${ctx.state.role}`)
|
||||
|
||||
// Using context shortcut
|
||||
await ctx.reply(`Hello ${ctx.state.role}`)
|
||||
})
|
||||
|
||||
bot.on('callback_query', async (ctx) => {
|
||||
// Explicit usage
|
||||
await ctx.telegram.answerCbQuery(ctx.callbackQuery.id)
|
||||
|
||||
// Using context shortcut
|
||||
await ctx.answerCbQuery()
|
||||
})
|
||||
|
||||
bot.on('inline_query', async (ctx) => {
|
||||
const result = []
|
||||
// Explicit usage
|
||||
await ctx.telegram.answerInlineQuery(ctx.inlineQuery.id, result)
|
||||
|
||||
// Using context shortcut
|
||||
await ctx.answerInlineQuery(result)
|
||||
})
|
||||
|
||||
bot.launch()
|
||||
|
||||
// Enable graceful stop
|
||||
process.once('SIGINT', () => bot.stop('SIGINT'))
|
||||
process.once('SIGTERM', () => bot.stop('SIGTERM'))
|
||||
```
|
||||
|
||||
## Production
|
||||
|
||||
### Webhooks
|
||||
|
||||
```TS
|
||||
import { Telegraf } from "telegraf";
|
||||
import { message } from 'telegraf/filters';
|
||||
|
||||
const bot = new Telegraf(token);
|
||||
|
||||
bot.on(message("text"), ctx => ctx.reply("Hello"));
|
||||
|
||||
// Start webhook via launch method (preferred)
|
||||
bot.launch({
|
||||
webhook: {
|
||||
// Public domain for webhook; e.g.: example.com
|
||||
domain: webhookDomain,
|
||||
|
||||
// Port to listen on; e.g.: 8080
|
||||
port: port,
|
||||
|
||||
// Optional path to listen for.
|
||||
// `bot.secretPathComponent()` will be used by default
|
||||
path: webhookPath,
|
||||
|
||||
// Optional secret to be sent back in a header for security.
|
||||
// e.g.: `crypto.randomBytes(64).toString("hex")`
|
||||
secretToken: randomAlphaNumericString,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Use `createWebhook()` if you want to attach Telegraf to an existing http server.
|
||||
|
||||
<!-- global bot, tlsOptions -->
|
||||
|
||||
```TS
|
||||
import { createServer } from "http";
|
||||
|
||||
createServer(await bot.createWebhook({ domain: "example.com" })).listen(3000);
|
||||
```
|
||||
|
||||
```TS
|
||||
import { createServer } from "https";
|
||||
|
||||
createServer(tlsOptions, await bot.createWebhook({ domain: "example.com" })).listen(8443);
|
||||
```
|
||||
|
||||
- [AWS Lambda example integration](https://github.com/feathers-studio/telegraf-docs/tree/master/examples/functions/aws-lambda)
|
||||
- [Google Cloud Functions example integration](https://github.com/feathers-studio/telegraf-docs/blob/master/examples/functions/google-cloud-function.ts)
|
||||
- [`express` example integration](https://github.com/feathers-studio/telegraf-docs/blob/master/examples/webhook/express.ts)
|
||||
- [`fastify` example integration](https://github.com/feathers-studio/telegraf-docs/blob/master/examples/webhook/fastify.ts)
|
||||
- [`koa` example integration](https://github.com/feathers-studio/telegraf-docs/blob/master/examples/webhook/koa.ts)
|
||||
- [NestJS framework integration module](https://github.com/bukhalo/nestjs-telegraf)
|
||||
- [Cloudflare Workers integration module](https://github.com/Tsuk1ko/cfworker-middware-telegraf)
|
||||
- Use [`bot.handleUpdate`](https://telegraf.js.org/classes/Telegraf-1.html#handleupdate) to write new integrations
|
||||
|
||||
### Error handling
|
||||
|
||||
If middleware throws an error or times out, Telegraf calls `bot.handleError`. If it rethrows, update source closes, and then the error is printed to console and process terminates. If it does not rethrow, the error is swallowed.
|
||||
|
||||
Default `bot.handleError` always rethrows. You can overwrite it using `bot.catch` if you need to.
|
||||
|
||||
⚠️ Swallowing unknown errors might leave the process in invalid state!
|
||||
|
||||
ℹ️ In production, `systemd` or [`pm2`](https://www.npmjs.com/package/pm2) can restart your bot if it exits for any reason.
|
||||
|
||||
## Advanced topics
|
||||
|
||||
### Working with files
|
||||
|
||||
Supported file sources:
|
||||
|
||||
- `Existing file_id`
|
||||
- `File path`
|
||||
- `Url`
|
||||
- `Buffer`
|
||||
- `ReadStream`
|
||||
|
||||
Also, you can provide an optional name of a file as `filename` when you send the file.
|
||||
|
||||
<!-- global bot, fs -->
|
||||
|
||||
```js
|
||||
bot.on('message', async (ctx) => {
|
||||
// resend existing file by file_id
|
||||
await ctx.replyWithSticker('123123jkbhj6b')
|
||||
|
||||
// send file
|
||||
await ctx.replyWithVideo(Input.fromLocalFile('/path/to/video.mp4'))
|
||||
|
||||
// send stream
|
||||
await ctx.replyWithVideo(
|
||||
Input.fromReadableStream(fs.createReadStream('/path/to/video.mp4'))
|
||||
)
|
||||
|
||||
// send buffer
|
||||
await ctx.replyWithVoice(Input.fromBuffer(Buffer.alloc()))
|
||||
|
||||
// send url via Telegram server
|
||||
await ctx.replyWithPhoto(Input.fromURL('https://picsum.photos/200/300/'))
|
||||
|
||||
// pipe url content
|
||||
await ctx.replyWithPhoto(
|
||||
Input.fromURLStream('https://picsum.photos/200/300/?random', 'kitten.jpg')
|
||||
)
|
||||
})
|
||||
```
|
||||
|
||||
### Middleware
|
||||
|
||||
In addition to `ctx: Context`, each middleware receives `next: () => Promise<void>`.
|
||||
|
||||
As in Koa and some other middleware-based libraries,
|
||||
`await next()` will call next middleware and wait for it to finish:
|
||||
|
||||
```TS
|
||||
import { Telegraf } from 'telegraf';
|
||||
import { message } from 'telegraf/filters';
|
||||
|
||||
const bot = new Telegraf(process.env.BOT_TOKEN);
|
||||
|
||||
bot.use(async (ctx, next) => {
|
||||
console.time(`Processing update ${ctx.update.update_id}`);
|
||||
await next() // runs next middleware
|
||||
// runs after next middleware finishes
|
||||
console.timeEnd(`Processing update ${ctx.update.update_id}`);
|
||||
})
|
||||
|
||||
bot.on(message('text'), (ctx) => ctx.reply('Hello World'));
|
||||
bot.launch();
|
||||
|
||||
// Enable graceful stop
|
||||
process.once('SIGINT', () => bot.stop('SIGINT'));
|
||||
process.once('SIGTERM', () => bot.stop('SIGTERM'));
|
||||
```
|
||||
|
||||
With this simple ability, you can:
|
||||
|
||||
- extract information from updates and then `await next()` to avoid disrupting other middleware,
|
||||
- like [`Composer`] and [`Router`], `await next()` for updates you don't wish to handle,
|
||||
- like [`session`] and [`Scenes`], [extend the context](#extending-context) by mutating `ctx` before `await next()`,
|
||||
- [intercept API calls](https://github.com/telegraf/telegraf/discussions/1267#discussioncomment-254525),
|
||||
- reuse [other people's code](https://www.npmjs.com/search?q=telegraf-),
|
||||
- do whatever **you** come up with!
|
||||
|
||||
[`Telegraf`]: https://telegraf.js.org/classes/Telegraf-1.html
|
||||
[`Composer`]: https://telegraf.js.org/classes/Composer.html
|
||||
[`Context`]: https://telegraf.js.org/classes/Context.html
|
||||
[`Router`]: https://telegraf.js.org/classes/Router.html
|
||||
[`session`]: https://telegraf.js.org/modules.html#session
|
||||
[`Scenes`]: https://telegraf.js.org/modules/Scenes.html
|
||||
|
||||
### Usage with TypeScript
|
||||
|
||||
Telegraf is written in TypeScript and therefore ships with declaration files for the entire library.
|
||||
Moreover, it includes types for the complete Telegram API via the [`typegram`](https://github.com/KnorpelSenf/typegram) package.
|
||||
While most types of Telegraf's API surface are self-explanatory, there's some notable things to keep in mind.
|
||||
|
||||
#### Extending `Context`
|
||||
|
||||
The exact shape of `ctx` can vary based on the installed middleware.
|
||||
Some custom middleware might register properties on the context object that Telegraf is not aware of.
|
||||
Consequently, you can change the type of `ctx` to fit your needs in order for you to have proper TypeScript types for your data.
|
||||
This is done through Generics:
|
||||
|
||||
```ts
|
||||
import { Context, Telegraf } from 'telegraf'
|
||||
|
||||
// Define your own context type
|
||||
interface MyContext extends Context {
|
||||
myProp?: string
|
||||
myOtherProp?: number
|
||||
}
|
||||
|
||||
// Create your bot and tell it about your context type
|
||||
const bot = new Telegraf<MyContext>('SECRET TOKEN')
|
||||
|
||||
// Register middleware and launch your bot as usual
|
||||
bot.use((ctx, next) => {
|
||||
// Yay, `myProp` is now available here as `string | undefined`!
|
||||
ctx.myProp = ctx.chat?.first_name?.toUpperCase()
|
||||
return next()
|
||||
})
|
||||
// ...
|
||||
```
|
||||
1
node_modules/telegraf/filters.d.ts
generated
vendored
Normal file
1
node_modules/telegraf/filters.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './typings/filters'
|
||||
1
node_modules/telegraf/filters.js
generated
vendored
Normal file
1
node_modules/telegraf/filters.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./lib/filters')
|
||||
1
node_modules/telegraf/format.d.ts
generated
vendored
Normal file
1
node_modules/telegraf/format.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './typings/format'
|
||||
1
node_modules/telegraf/format.js
generated
vendored
Normal file
1
node_modules/telegraf/format.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./lib/format')
|
||||
1
node_modules/telegraf/future.d.ts
generated
vendored
Normal file
1
node_modules/telegraf/future.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './typings/future'
|
||||
1
node_modules/telegraf/future.js
generated
vendored
Normal file
1
node_modules/telegraf/future.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./lib/future')
|
||||
101
node_modules/telegraf/lib/button.js
generated
vendored
Normal file
101
node_modules/telegraf/lib/button.js
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.webApp = exports.login = exports.pay = exports.game = exports.switchToCurrentChat = exports.switchToChat = exports.callback = exports.url = exports.channelRequest = exports.groupRequest = exports.botRequest = exports.userRequest = exports.pollRequest = exports.locationRequest = exports.contactRequest = exports.text = void 0;
|
||||
function text(text, hide = false) {
|
||||
return { text, hide };
|
||||
}
|
||||
exports.text = text;
|
||||
function contactRequest(text, hide = false) {
|
||||
return { text, request_contact: true, hide };
|
||||
}
|
||||
exports.contactRequest = contactRequest;
|
||||
function locationRequest(text, hide = false) {
|
||||
return { text, request_location: true, hide };
|
||||
}
|
||||
exports.locationRequest = locationRequest;
|
||||
function pollRequest(text, type, hide = false) {
|
||||
return { text, request_poll: { type }, hide };
|
||||
}
|
||||
exports.pollRequest = pollRequest;
|
||||
function userRequest(text,
|
||||
/** Must fit in a signed 32 bit int */
|
||||
request_id, extra, hide = false) {
|
||||
return {
|
||||
text,
|
||||
request_users: { request_id, ...extra },
|
||||
hide,
|
||||
};
|
||||
}
|
||||
exports.userRequest = userRequest;
|
||||
function botRequest(text,
|
||||
/** Must fit in a signed 32 bit int */
|
||||
request_id, extra, hide = false) {
|
||||
return {
|
||||
text,
|
||||
request_users: { request_id, user_is_bot: true, ...extra },
|
||||
hide,
|
||||
};
|
||||
}
|
||||
exports.botRequest = botRequest;
|
||||
function groupRequest(text,
|
||||
/** Must fit in a signed 32 bit int */
|
||||
request_id, extra, hide = false) {
|
||||
return {
|
||||
text,
|
||||
request_chat: { request_id, chat_is_channel: false, ...extra },
|
||||
hide,
|
||||
};
|
||||
}
|
||||
exports.groupRequest = groupRequest;
|
||||
function channelRequest(text,
|
||||
/** Must fit in a signed 32 bit int */
|
||||
request_id, extra, hide = false) {
|
||||
return {
|
||||
text,
|
||||
request_chat: { request_id, chat_is_channel: true, ...extra },
|
||||
hide,
|
||||
};
|
||||
}
|
||||
exports.channelRequest = channelRequest;
|
||||
function url(text, url, hide = false) {
|
||||
return { text, url, hide };
|
||||
}
|
||||
exports.url = url;
|
||||
function callback(text, data, hide = false) {
|
||||
return { text, callback_data: data, hide };
|
||||
}
|
||||
exports.callback = callback;
|
||||
function switchToChat(text, value, hide = false) {
|
||||
return { text, switch_inline_query: value, hide };
|
||||
}
|
||||
exports.switchToChat = switchToChat;
|
||||
function switchToCurrentChat(text, value, hide = false) {
|
||||
return { text, switch_inline_query_current_chat: value, hide };
|
||||
}
|
||||
exports.switchToCurrentChat = switchToCurrentChat;
|
||||
function game(text, hide = false) {
|
||||
return { text, callback_game: {}, hide };
|
||||
}
|
||||
exports.game = game;
|
||||
function pay(text, hide = false) {
|
||||
return { text, pay: true, hide };
|
||||
}
|
||||
exports.pay = pay;
|
||||
function login(text, url, opts = {}, hide = false) {
|
||||
return {
|
||||
text,
|
||||
login_url: { ...opts, url },
|
||||
hide,
|
||||
};
|
||||
}
|
||||
exports.login = login;
|
||||
function webApp(text, url, hide = false
|
||||
// works as both InlineKeyboardButton and KeyboardButton
|
||||
) {
|
||||
return {
|
||||
text,
|
||||
web_app: { url },
|
||||
hide,
|
||||
};
|
||||
}
|
||||
exports.webApp = webApp;
|
||||
105
node_modules/telegraf/lib/cli.mjs
generated
vendored
Executable file
105
node_modules/telegraf/lib/cli.mjs
generated
vendored
Executable file
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env node
|
||||
import d from 'debug';
|
||||
import parse from 'mri';
|
||||
import path from 'path';
|
||||
import { Telegraf } from './index.js';
|
||||
const debug = d('telegraf:cli');
|
||||
const helpMsg = `Usage: telegraf [opts] <bot-file>
|
||||
|
||||
-t Bot token [$BOT_TOKEN]
|
||||
-d Webhook domain [$BOT_DOMAIN]
|
||||
-H Webhook host [0.0.0.0]
|
||||
-p Webhook port [$PORT or 3000]
|
||||
-l Enable logs
|
||||
-h Show this help message
|
||||
-m Bot API method to run directly
|
||||
-D Data to pass to the Bot API method`;
|
||||
const help = () => console.log(helpMsg);
|
||||
/**
|
||||
* Runs the cli program and returns exit code
|
||||
*/
|
||||
export async function main(argv, env = {}) {
|
||||
const args = parse(argv, {
|
||||
alias: {
|
||||
// string params, all optional
|
||||
t: 'token',
|
||||
d: 'domain',
|
||||
m: 'method',
|
||||
D: 'data',
|
||||
// defaults exist
|
||||
H: 'host',
|
||||
p: 'port',
|
||||
// boolean params
|
||||
l: 'logs',
|
||||
h: 'help',
|
||||
},
|
||||
boolean: ['h', 'l'],
|
||||
default: {
|
||||
H: '0.0.0.0',
|
||||
p: env.PORT || '3000',
|
||||
},
|
||||
});
|
||||
if (args.help) {
|
||||
help();
|
||||
return 0;
|
||||
}
|
||||
const token = args.token || env.BOT_TOKEN;
|
||||
const domain = args.domain || env.BOT_DOMAIN;
|
||||
if (!token) {
|
||||
console.error('Please supply Bot Token');
|
||||
help();
|
||||
return 1;
|
||||
}
|
||||
const bot = new Telegraf(token);
|
||||
if (args.method) {
|
||||
const method = args.method;
|
||||
console.log(await bot.telegram.callApi(method, JSON.parse(args.data || '{}')));
|
||||
return 0;
|
||||
}
|
||||
let [, , file] = args._;
|
||||
if (!file) {
|
||||
try {
|
||||
const packageJson = (await import(path.resolve(process.cwd(), 'package.json')));
|
||||
file = packageJson.main || 'index.js';
|
||||
// eslint-disable-next-line no-empty
|
||||
}
|
||||
catch (err) { }
|
||||
}
|
||||
if (!file) {
|
||||
console.error('Please supply a bot handler file.\n');
|
||||
help();
|
||||
return 2;
|
||||
}
|
||||
if (file[0] !== '/')
|
||||
file = path.resolve(process.cwd(), file);
|
||||
try {
|
||||
if (args.logs)
|
||||
d.enable('telegraf:*');
|
||||
const mod = await import(file);
|
||||
const botHandler = mod.botHandler || mod.default;
|
||||
const httpHandler = mod.httpHandler;
|
||||
const tlsOptions = mod.tlsOptions;
|
||||
const config = {};
|
||||
if (domain) {
|
||||
config.webhook = {
|
||||
domain,
|
||||
host: args.host,
|
||||
port: Number(args.port),
|
||||
tlsOptions,
|
||||
cb: httpHandler,
|
||||
};
|
||||
}
|
||||
bot.use(botHandler);
|
||||
debug(`Starting module ${file}`);
|
||||
await bot.launch(config);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(`Error launching bot from ${file}`, err === null || err === void 0 ? void 0 : err.stack);
|
||||
return 3;
|
||||
}
|
||||
// Enable graceful stop
|
||||
process.once('SIGINT', () => bot.stop('SIGINT'));
|
||||
process.once('SIGTERM', () => bot.stop('SIGTERM'));
|
||||
return 0;
|
||||
}
|
||||
process.exitCode = await main(process.argv, process.env);
|
||||
582
node_modules/telegraf/lib/composer.js
generated
vendored
Normal file
582
node_modules/telegraf/lib/composer.js
generated
vendored
Normal file
@@ -0,0 +1,582 @@
|
||||
"use strict";
|
||||
/** @format */
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Composer = void 0;
|
||||
const context_1 = __importDefault(require("./context"));
|
||||
const filters_1 = require("./filters");
|
||||
const args_1 = require("./core/helpers/args");
|
||||
function always(x) {
|
||||
return () => x;
|
||||
}
|
||||
const anoop = always(Promise.resolve());
|
||||
class Composer {
|
||||
constructor(...fns) {
|
||||
this.handler = Composer.compose(fns);
|
||||
}
|
||||
/**
|
||||
* Registers a middleware.
|
||||
*/
|
||||
use(...fns) {
|
||||
this.handler = Composer.compose([this.handler, ...fns]);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Registers middleware for handling updates
|
||||
* matching given type guard function.
|
||||
* @deprecated use `Composer::on`
|
||||
*/
|
||||
guard(guardFn, ...fns) {
|
||||
return this.use(Composer.guard(guardFn, ...fns));
|
||||
}
|
||||
on(filters, ...fns) {
|
||||
// @ts-expect-error This should get resolved when the overloads are removed in v5
|
||||
return this.use(Composer.on(filters, ...fns));
|
||||
}
|
||||
/**
|
||||
* Registers middleware for handling matching text messages.
|
||||
*/
|
||||
hears(triggers, ...fns) {
|
||||
return this.use(Composer.hears(triggers, ...fns));
|
||||
}
|
||||
/**
|
||||
* Registers middleware for handling specified commands.
|
||||
*/
|
||||
command(command, ...fns) {
|
||||
return this.use(Composer.command(command, ...fns));
|
||||
}
|
||||
/**
|
||||
* Registers middleware for handling matching callback queries.
|
||||
*/
|
||||
action(triggers, ...fns) {
|
||||
return this.use(Composer.action(triggers, ...fns));
|
||||
}
|
||||
/**
|
||||
* Registers middleware for handling matching inline queries.
|
||||
*/
|
||||
inlineQuery(triggers, ...fns) {
|
||||
return this.use(Composer.inlineQuery(triggers, ...fns));
|
||||
}
|
||||
/**
|
||||
* Registers middleware for handling game queries
|
||||
*/
|
||||
gameQuery(...fns) {
|
||||
return this.use(Composer.gameQuery(...fns));
|
||||
}
|
||||
reaction(reaction, ...fns) {
|
||||
return this.use(Composer.reaction(reaction, ...fns));
|
||||
}
|
||||
/**
|
||||
* Registers middleware for dropping matching updates.
|
||||
*/
|
||||
drop(predicate) {
|
||||
return this.use(Composer.drop(predicate));
|
||||
}
|
||||
/** @deprecated use `Composer::drop` */
|
||||
filter(predicate) {
|
||||
return this.use(Composer.filter(predicate));
|
||||
}
|
||||
entity(predicate, ...fns) {
|
||||
return this.use(Composer.entity(predicate, ...fns));
|
||||
}
|
||||
email(email, ...fns) {
|
||||
return this.use(Composer.email(email, ...fns));
|
||||
}
|
||||
url(url, ...fns) {
|
||||
return this.use(Composer.url(url, ...fns));
|
||||
}
|
||||
textLink(link, ...fns) {
|
||||
return this.use(Composer.textLink(link, ...fns));
|
||||
}
|
||||
textMention(mention, ...fns) {
|
||||
return this.use(Composer.textMention(mention, ...fns));
|
||||
}
|
||||
mention(mention, ...fns) {
|
||||
return this.use(Composer.mention(mention, ...fns));
|
||||
}
|
||||
phone(number, ...fns) {
|
||||
return this.use(Composer.phone(number, ...fns));
|
||||
}
|
||||
hashtag(hashtag, ...fns) {
|
||||
return this.use(Composer.hashtag(hashtag, ...fns));
|
||||
}
|
||||
cashtag(cashtag, ...fns) {
|
||||
return this.use(Composer.cashtag(cashtag, ...fns));
|
||||
}
|
||||
spoiler(text, ...fns) {
|
||||
return this.use(Composer.spoiler(text, ...fns));
|
||||
}
|
||||
/**
|
||||
* Registers a middleware for handling /start
|
||||
*/
|
||||
start(...fns) {
|
||||
const handler = Composer.compose(fns);
|
||||
return this.command('start', (ctx, next) => handler(Object.assign(ctx, { startPayload: ctx.payload }), next));
|
||||
}
|
||||
/**
|
||||
* Registers a middleware for handling /help
|
||||
*/
|
||||
help(...fns) {
|
||||
return this.command('help', ...fns);
|
||||
}
|
||||
/**
|
||||
* Registers a middleware for handling /settings
|
||||
*/
|
||||
settings(...fns) {
|
||||
return this.command('settings', ...fns);
|
||||
}
|
||||
middleware() {
|
||||
return this.handler;
|
||||
}
|
||||
static reply(...args) {
|
||||
return (ctx) => ctx.reply(...args);
|
||||
}
|
||||
static catch(errorHandler, ...fns) {
|
||||
const handler = Composer.compose(fns);
|
||||
// prettier-ignore
|
||||
return (ctx, next) => Promise.resolve(handler(ctx, next))
|
||||
.catch((err) => errorHandler(err, ctx));
|
||||
}
|
||||
/**
|
||||
* Generates middleware that runs in the background.
|
||||
*/
|
||||
static fork(middleware) {
|
||||
const handler = Composer.unwrap(middleware);
|
||||
return async (ctx, next) => {
|
||||
await Promise.all([handler(ctx, anoop), next()]);
|
||||
};
|
||||
}
|
||||
static tap(middleware) {
|
||||
const handler = Composer.unwrap(middleware);
|
||||
return (ctx, next) => Promise.resolve(handler(ctx, anoop)).then(() => next());
|
||||
}
|
||||
/**
|
||||
* Generates middleware that gives up control to the next middleware.
|
||||
*/
|
||||
static passThru() {
|
||||
return (ctx, next) => next();
|
||||
}
|
||||
static lazy(factoryFn) {
|
||||
if (typeof factoryFn !== 'function') {
|
||||
throw new Error('Argument must be a function');
|
||||
}
|
||||
return (ctx, next) => Promise.resolve(factoryFn(ctx)).then((middleware) => Composer.unwrap(middleware)(ctx, next));
|
||||
}
|
||||
static log(logFn = console.log) {
|
||||
return (ctx, next) => {
|
||||
logFn(JSON.stringify(ctx.update, null, 2));
|
||||
return next();
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @param trueMiddleware middleware to run if the predicate returns true
|
||||
* @param falseMiddleware middleware to run if the predicate returns false
|
||||
*/
|
||||
static branch(predicate, trueMiddleware, falseMiddleware) {
|
||||
if (typeof predicate !== 'function') {
|
||||
return Composer.unwrap(predicate ? trueMiddleware : falseMiddleware);
|
||||
}
|
||||
return Composer.lazy((ctx) => Promise.resolve(predicate(ctx)).then((value) => value ? trueMiddleware : falseMiddleware));
|
||||
}
|
||||
/**
|
||||
* Generates optional middleware.
|
||||
* @param predicate predicate to decide on a context object whether to run the middleware
|
||||
* @param fns middleware to run if the predicate returns true
|
||||
*/
|
||||
static optional(predicate, ...fns) {
|
||||
return Composer.branch(predicate, Composer.compose(fns), Composer.passThru());
|
||||
}
|
||||
/** @deprecated use `Composer.drop` */
|
||||
static filter(predicate) {
|
||||
return Composer.branch(predicate, Composer.passThru(), anoop);
|
||||
}
|
||||
/**
|
||||
* Generates middleware for dropping matching updates.
|
||||
*/
|
||||
static drop(predicate) {
|
||||
return Composer.branch(predicate, anoop, Composer.passThru());
|
||||
}
|
||||
static dispatch(routeFn, handlers) {
|
||||
return Composer.lazy((ctx) => Promise.resolve(routeFn(ctx)).then((value) => handlers[value]));
|
||||
}
|
||||
// EXPLANATION FOR THE ts-expect-error ANNOTATIONS
|
||||
// The annotations around function invocations with `...fns` are there
|
||||
// whenever we perform validation logic that the flow analysis of TypeScript
|
||||
// cannot comprehend. We always make sure that the middleware functions are
|
||||
// only invoked with properly constrained context objects, but this cannot be
|
||||
// determined automatically.
|
||||
/**
|
||||
* Generates optional middleware based on a predicate that only operates on `ctx.update`.
|
||||
*
|
||||
* Example:
|
||||
* ```ts
|
||||
* import { Composer, Update } from 'telegraf'
|
||||
*
|
||||
* const predicate = (u): u is Update.MessageUpdate => 'message' in u
|
||||
* const middleware = Composer.guard(predicate, (ctx) => {
|
||||
* const message = ctx.update.message
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* Note that `Composer.on('message')` is preferred over this.
|
||||
*
|
||||
* @param guardFn predicate to decide whether to run the middleware based on the `ctx.update` object
|
||||
* @param fns middleware to run if the predicate returns true
|
||||
* @see `Composer.optional` for a more generic version of this method that allows the predicate to operate on `ctx` itself
|
||||
* @deprecated use `Composer.on`
|
||||
*/
|
||||
static guard(guardFn, ...fns) {
|
||||
return Composer.optional((ctx) => guardFn(ctx.update),
|
||||
// @ts-expect-error see explanation above
|
||||
...fns);
|
||||
}
|
||||
static on(updateType, ...fns) {
|
||||
const filters = Array.isArray(updateType) ? updateType : [updateType];
|
||||
const predicate = (update) => {
|
||||
for (const filter of filters) {
|
||||
if (
|
||||
// TODO: this should change to === 'function' once TS bug is fixed
|
||||
// https://github.com/microsoft/TypeScript/pull/51502
|
||||
typeof filter !== 'string'
|
||||
? // filter is a type guard
|
||||
filter(update)
|
||||
: // check if filter is the update type
|
||||
filter in update ||
|
||||
// check if filter is the msg type
|
||||
// TODO: remove in v5!
|
||||
('message' in update && filter in update.message)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
return Composer.optional((ctx) => predicate(ctx.update), ...fns);
|
||||
}
|
||||
static entity(predicate, ...fns) {
|
||||
if (typeof predicate !== 'function') {
|
||||
const entityTypes = normaliseTextArguments(predicate);
|
||||
return Composer.entity(({ type }) => entityTypes.includes(type), ...fns);
|
||||
}
|
||||
return Composer.optional((ctx) => {
|
||||
var _a;
|
||||
const msg = (_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost;
|
||||
if (msg === undefined) {
|
||||
return false;
|
||||
}
|
||||
const text = getText(msg);
|
||||
const entities = getEntities(msg);
|
||||
if (text === undefined)
|
||||
return false;
|
||||
return entities.some((entity) => predicate(entity, text.substring(entity.offset, entity.offset + entity.length), ctx));
|
||||
},
|
||||
// @ts-expect-error see explanation above
|
||||
...fns);
|
||||
}
|
||||
static entityText(entityType, predicate, ...fns) {
|
||||
if (fns.length === 0) {
|
||||
// prettier-ignore
|
||||
return Array.isArray(predicate)
|
||||
// @ts-expect-error predicate is really the middleware
|
||||
? Composer.entity(entityType, ...predicate)
|
||||
// @ts-expect-error predicate is really the middleware
|
||||
: Composer.entity(entityType, predicate);
|
||||
}
|
||||
const triggers = normaliseTriggers(predicate);
|
||||
return Composer.entity(({ type }, value, ctx) => {
|
||||
if (type !== entityType) {
|
||||
return false;
|
||||
}
|
||||
for (const trigger of triggers) {
|
||||
// @ts-expect-error define so far unknown property `match`
|
||||
if ((ctx.match = trigger(value, ctx))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
// @ts-expect-error see explanation above
|
||||
...fns);
|
||||
}
|
||||
static email(email, ...fns) {
|
||||
return Composer.entityText('email', email, ...fns);
|
||||
}
|
||||
static phone(number, ...fns) {
|
||||
return Composer.entityText('phone_number', number, ...fns);
|
||||
}
|
||||
static url(url, ...fns) {
|
||||
return Composer.entityText('url', url, ...fns);
|
||||
}
|
||||
static textLink(link, ...fns) {
|
||||
return Composer.entityText('text_link', link, ...fns);
|
||||
}
|
||||
static textMention(mention, ...fns) {
|
||||
return Composer.entityText('text_mention', mention, ...fns);
|
||||
}
|
||||
static mention(mention, ...fns) {
|
||||
return Composer.entityText('mention', normaliseTextArguments(mention, '@'), ...fns);
|
||||
}
|
||||
static hashtag(hashtag, ...fns) {
|
||||
return Composer.entityText('hashtag', normaliseTextArguments(hashtag, '#'), ...fns);
|
||||
}
|
||||
static cashtag(cashtag, ...fns) {
|
||||
return Composer.entityText('cashtag', normaliseTextArguments(cashtag, '$'), ...fns);
|
||||
}
|
||||
static spoiler(text, ...fns) {
|
||||
return Composer.entityText('spoiler', text, ...fns);
|
||||
}
|
||||
static match(triggers, ...fns) {
|
||||
const handler = Composer.compose(fns);
|
||||
return (ctx, next) => {
|
||||
var _a, _b, _c, _d;
|
||||
const text = (_c = (_b = (_a = getText(ctx.message)) !== null && _a !== void 0 ? _a : getText(ctx.channelPost)) !== null && _b !== void 0 ? _b : getText(ctx.callbackQuery)) !== null && _c !== void 0 ? _c : (_d = ctx.inlineQuery) === null || _d === void 0 ? void 0 : _d.query;
|
||||
if (text === undefined)
|
||||
return next();
|
||||
for (const trigger of triggers) {
|
||||
const match = trigger(text, ctx);
|
||||
if (match)
|
||||
return handler(Object.assign(ctx, { match }), next);
|
||||
}
|
||||
return next();
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Generates middleware for handling matching text messages.
|
||||
*/
|
||||
static hears(triggers, ...fns) {
|
||||
return Composer.on('text', Composer.match(normaliseTriggers(triggers), ...fns));
|
||||
}
|
||||
/**
|
||||
* Generates middleware for handling specified commands.
|
||||
*/
|
||||
static command(command, ...fns) {
|
||||
if (fns.length === 0)
|
||||
// @ts-expect-error command is really the middleware
|
||||
return Composer.entity('bot_command', command);
|
||||
const triggers = normaliseTriggers(command);
|
||||
const filter = (0, filters_1.message)('text');
|
||||
const handler = Composer.compose(fns);
|
||||
return Composer.on(filter, (ctx, next) => {
|
||||
const { entities } = ctx.message;
|
||||
const cmdEntity = entities === null || entities === void 0 ? void 0 : entities[0];
|
||||
if ((cmdEntity === null || cmdEntity === void 0 ? void 0 : cmdEntity.type) !== 'bot_command')
|
||||
return next();
|
||||
if (cmdEntity.offset > 0)
|
||||
return next();
|
||||
const len = cmdEntity.length;
|
||||
const text = ctx.message.text;
|
||||
const [cmdPart, to] = text.slice(0, len).split('@');
|
||||
if (!cmdPart)
|
||||
return next();
|
||||
// always check for bot's own username case-insensitively
|
||||
if (to && to.toLowerCase() !== ctx.me.toLowerCase())
|
||||
return next();
|
||||
const command = cmdPart.slice(1);
|
||||
for (const trigger of triggers) {
|
||||
const match = trigger(command, ctx);
|
||||
if (match) {
|
||||
const payloadOffset = len + 1;
|
||||
const payload = text.slice(payloadOffset);
|
||||
const c = Object.assign(ctx, { match, command, payload, args: [] });
|
||||
let _args = undefined;
|
||||
// using defineProperty only to make parsing lazy on access
|
||||
Object.defineProperty(c, 'args', {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get() {
|
||||
if (_args != null)
|
||||
return _args;
|
||||
// once parsed, cache and don't parse again on every access
|
||||
return (_args = (0, args_1.argsParser)(payload, entities, payloadOffset));
|
||||
},
|
||||
set(args) {
|
||||
_args = args;
|
||||
},
|
||||
});
|
||||
return handler(c, next);
|
||||
}
|
||||
}
|
||||
return next();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Generates middleware for handling matching callback queries.
|
||||
*/
|
||||
static action(triggers, ...fns) {
|
||||
return Composer.on('callback_query', Composer.match(normaliseTriggers(triggers), ...fns));
|
||||
}
|
||||
/**
|
||||
* Generates middleware for handling matching inline queries.
|
||||
*/
|
||||
static inlineQuery(triggers, ...fns) {
|
||||
return Composer.on('inline_query', Composer.match(normaliseTriggers(triggers), ...fns));
|
||||
}
|
||||
static reaction(reaction, ...fns) {
|
||||
const reactions = Array.isArray(reaction) ? reaction : [reaction];
|
||||
const handler = Composer.compose(fns);
|
||||
return Composer.on('message_reaction', (ctx, next) => {
|
||||
const match = reactions.find((r) => typeof r === 'string' && r.startsWith('-')
|
||||
? ctx.reactions.removed.has(r.slice(1))
|
||||
: ctx.reactions.added.has(r));
|
||||
if (match)
|
||||
return handler(Object.assign(ctx, { match }), next);
|
||||
return next();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Generates middleware responding only to specified users.
|
||||
*/
|
||||
static acl(userId, ...fns) {
|
||||
if (typeof userId === 'function') {
|
||||
return Composer.optional(userId, ...fns);
|
||||
}
|
||||
const allowed = Array.isArray(userId) ? userId : [userId];
|
||||
// prettier-ignore
|
||||
return Composer.optional((ctx) => !ctx.from || allowed.includes(ctx.from.id), ...fns);
|
||||
}
|
||||
static memberStatus(status, ...fns) {
|
||||
const statuses = Array.isArray(status) ? status : [status];
|
||||
return Composer.optional(async (ctx) => {
|
||||
if (ctx.message === undefined)
|
||||
return false;
|
||||
const member = await ctx.getChatMember(ctx.message.from.id);
|
||||
return statuses.includes(member.status);
|
||||
}, ...fns);
|
||||
}
|
||||
/**
|
||||
* Generates middleware responding only to chat admins and chat creator.
|
||||
*/
|
||||
static admin(...fns) {
|
||||
return Composer.memberStatus(['administrator', 'creator'], ...fns);
|
||||
}
|
||||
/**
|
||||
* Generates middleware responding only to chat creator.
|
||||
*/
|
||||
static creator(...fns) {
|
||||
return Composer.memberStatus('creator', ...fns);
|
||||
}
|
||||
/**
|
||||
* Generates middleware running only in specified chat types.
|
||||
*/
|
||||
static chatType(type, ...fns) {
|
||||
const types = Array.isArray(type) ? type : [type];
|
||||
return Composer.optional((ctx) => {
|
||||
const chat = ctx.chat;
|
||||
return chat !== undefined && types.includes(chat.type);
|
||||
}, ...fns);
|
||||
}
|
||||
/**
|
||||
* Generates middleware running only in private chats.
|
||||
*/
|
||||
static privateChat(...fns) {
|
||||
return Composer.chatType('private', ...fns);
|
||||
}
|
||||
/**
|
||||
* Generates middleware running only in groups and supergroups.
|
||||
*/
|
||||
static groupChat(...fns) {
|
||||
return Composer.chatType(['group', 'supergroup'], ...fns);
|
||||
}
|
||||
/**
|
||||
* Generates middleware for handling game queries.
|
||||
*/
|
||||
static gameQuery(...fns) {
|
||||
return Composer.guard((0, filters_1.callbackQuery)('game_short_name'), ...fns);
|
||||
}
|
||||
static unwrap(handler) {
|
||||
if (!handler) {
|
||||
throw new Error('Handler is undefined');
|
||||
}
|
||||
return 'middleware' in handler ? handler.middleware() : handler;
|
||||
}
|
||||
static compose(middlewares) {
|
||||
if (!Array.isArray(middlewares)) {
|
||||
throw new Error('Middlewares must be an array');
|
||||
}
|
||||
if (middlewares.length === 0) {
|
||||
return Composer.passThru();
|
||||
}
|
||||
if (middlewares.length === 1) {
|
||||
// Quite literally asserted in the above condition
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
return Composer.unwrap(middlewares[0]);
|
||||
}
|
||||
return (ctx, next) => {
|
||||
let index = -1;
|
||||
return execute(0, ctx);
|
||||
async function execute(i, context) {
|
||||
var _a;
|
||||
if (!(context instanceof context_1.default)) {
|
||||
throw new Error('next(ctx) called with invalid context');
|
||||
}
|
||||
if (i <= index) {
|
||||
throw new Error('next() called multiple times');
|
||||
}
|
||||
index = i;
|
||||
const handler = Composer.unwrap((_a = middlewares[i]) !== null && _a !== void 0 ? _a : next);
|
||||
await handler(context, async (ctx = context) => {
|
||||
await execute(i + 1, ctx);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
exports.Composer = Composer;
|
||||
/**
|
||||
* Generates middleware for handling provided update types.
|
||||
* @deprecated use `Composer.on` instead
|
||||
*/
|
||||
Composer.mount = Composer.on;
|
||||
function escapeRegExp(s) {
|
||||
// $& means the whole matched string
|
||||
return s.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
function normaliseTriggers(triggers) {
|
||||
if (!Array.isArray(triggers))
|
||||
triggers = [triggers];
|
||||
return triggers.map((trigger) => {
|
||||
if (!trigger)
|
||||
throw new Error('Invalid trigger');
|
||||
if (typeof trigger === 'function')
|
||||
return trigger;
|
||||
if (trigger instanceof RegExp)
|
||||
return (value = '') => {
|
||||
trigger.lastIndex = 0;
|
||||
return trigger.exec(value);
|
||||
};
|
||||
const regex = new RegExp(`^${escapeRegExp(trigger)}$`);
|
||||
return (value) => regex.exec(value);
|
||||
});
|
||||
}
|
||||
function getEntities(msg) {
|
||||
var _a, _b;
|
||||
if (msg == null)
|
||||
return [];
|
||||
if ('caption_entities' in msg)
|
||||
return (_a = msg.caption_entities) !== null && _a !== void 0 ? _a : [];
|
||||
if ('entities' in msg)
|
||||
return (_b = msg.entities) !== null && _b !== void 0 ? _b : [];
|
||||
return [];
|
||||
}
|
||||
function getText(msg) {
|
||||
if (msg == null)
|
||||
return undefined;
|
||||
if ('caption' in msg)
|
||||
return msg.caption;
|
||||
if ('text' in msg)
|
||||
return msg.text;
|
||||
if ('data' in msg)
|
||||
return msg.data;
|
||||
if ('game_short_name' in msg)
|
||||
return msg.game_short_name;
|
||||
return undefined;
|
||||
}
|
||||
function normaliseTextArguments(argument, prefix = '') {
|
||||
const args = Array.isArray(argument) ? argument : [argument];
|
||||
// prettier-ignore
|
||||
return args
|
||||
.filter(Boolean)
|
||||
.map((arg) => prefix && typeof arg === 'string' && !arg.startsWith(prefix) ? `${prefix}${arg}` : arg);
|
||||
}
|
||||
exports.default = Composer;
|
||||
1219
node_modules/telegraf/lib/context.js
generated
vendored
Normal file
1219
node_modules/telegraf/lib/context.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
58
node_modules/telegraf/lib/core/helpers/args.js
generated
vendored
Normal file
58
node_modules/telegraf/lib/core/helpers/args.js
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.argsParser = void 0;
|
||||
const SINGLE_QUOTE = "'";
|
||||
const DOUBLE_QUOTE = '"';
|
||||
function argsParser(str, entities = [], entityOffset = 0) {
|
||||
const mentions = {};
|
||||
for (const entity of entities) // extract all text_mentions into an { offset: length } map
|
||||
if (entity.type === 'text_mention' || entity.type === 'text_link')
|
||||
mentions[entity.offset - entityOffset] = entity.length;
|
||||
const args = [];
|
||||
let done = 0;
|
||||
let inside = undefined;
|
||||
let buf = '';
|
||||
function flush(to) {
|
||||
if (done !== to)
|
||||
args.push(buf + str.slice(done, to)), (inside = undefined);
|
||||
buf = '';
|
||||
done = to + 1;
|
||||
}
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const char = str[i];
|
||||
// quick lookup length of mention starting at i
|
||||
const mention = mentions[i];
|
||||
if (mention) {
|
||||
// if we're inside a quote, eagerly flush existing state
|
||||
flush(i);
|
||||
// this also consumes current index, so decrement
|
||||
done--;
|
||||
// fast forward to end of mention
|
||||
i += mention;
|
||||
flush(i);
|
||||
}
|
||||
else if (char === SINGLE_QUOTE || char === DOUBLE_QUOTE)
|
||||
if (inside)
|
||||
if (inside === char)
|
||||
flush(i);
|
||||
else
|
||||
continue;
|
||||
else
|
||||
flush(i), (inside = char);
|
||||
else if (char === ' ')
|
||||
if (inside)
|
||||
continue;
|
||||
else
|
||||
flush(i);
|
||||
else if (char === '\n')
|
||||
flush(i);
|
||||
else if (char === '\\')
|
||||
(buf += str.slice(done, i)), (done = ++i); // skip parsing the next char
|
||||
else
|
||||
continue;
|
||||
}
|
||||
if (done < str.length)
|
||||
flush(str.length);
|
||||
return args;
|
||||
}
|
||||
exports.argsParser = argsParser;
|
||||
56
node_modules/telegraf/lib/core/helpers/check.js
generated
vendored
Normal file
56
node_modules/telegraf/lib/core/helpers/check.js
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.is2D = exports.hasPropType = exports.hasProp = void 0;
|
||||
/**
|
||||
* Checks if a given object has a property with a given name.
|
||||
*
|
||||
* Example invocation:
|
||||
* ```js
|
||||
* let obj = { 'foo': 'bar', 'baz': () => {} }
|
||||
* hasProp(obj, 'foo') // true
|
||||
* hasProp(obj, 'baz') // true
|
||||
* hasProp(obj, 'abc') // false
|
||||
* ```
|
||||
*
|
||||
* @param obj An object to test
|
||||
* @param prop The name of the property
|
||||
*/
|
||||
function hasProp(obj, prop) {
|
||||
return obj !== undefined && prop in obj;
|
||||
}
|
||||
exports.hasProp = hasProp;
|
||||
/**
|
||||
* Checks if a given object has a property with a given name.
|
||||
* Furthermore performs a `typeof` check on the property if it exists.
|
||||
*
|
||||
* Example invocation:
|
||||
* ```js
|
||||
* let obj = { 'foo': 'bar', 'baz': () => {} }
|
||||
* hasPropType(obj, 'foo', 'string') // true
|
||||
* hasPropType(obj, 'baz', 'function') // true
|
||||
* hasPropType(obj, 'abc', 'number') // false
|
||||
* ```
|
||||
*
|
||||
* @param obj An object to test
|
||||
* @param prop The name of the property
|
||||
* @param type The type the property is expected to have
|
||||
*/
|
||||
function hasPropType(obj, prop, type) {
|
||||
return hasProp(obj, prop) && type === typeof obj[prop];
|
||||
}
|
||||
exports.hasPropType = hasPropType;
|
||||
/**
|
||||
* Checks if the supplied array has two dimensions or not.
|
||||
*
|
||||
* Example invocations:
|
||||
* is2D([]) // false
|
||||
* is2D([[]]) // true
|
||||
* is2D([[], []]) // true
|
||||
* is2D([42]) // false
|
||||
*
|
||||
* @param arr an array with one or two dimensions
|
||||
*/
|
||||
function is2D(arr) {
|
||||
return Array.isArray(arr[0]);
|
||||
}
|
||||
exports.is2D = is2D;
|
||||
17
node_modules/telegraf/lib/core/helpers/compact.js
generated
vendored
Normal file
17
node_modules/telegraf/lib/core/helpers/compact.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.compactOptions = void 0;
|
||||
function compactOptions(options) {
|
||||
if (!options) {
|
||||
return options;
|
||||
}
|
||||
const compacted = {};
|
||||
for (const key in options)
|
||||
if (
|
||||
// todo(mkr): replace with Object.hasOwn in v5 (Node 16+)
|
||||
Object.prototype.hasOwnProperty.call(options, key) &&
|
||||
options[key] !== undefined)
|
||||
compacted[key] = options[key];
|
||||
return compacted;
|
||||
}
|
||||
exports.compactOptions = compactOptions;
|
||||
13
node_modules/telegraf/lib/core/helpers/deunionize.js
generated
vendored
Normal file
13
node_modules/telegraf/lib/core/helpers/deunionize.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.deunionize = void 0;
|
||||
/**
|
||||
* Expose properties from all union variants.
|
||||
* @deprectated
|
||||
* @see https://github.com/telegraf/telegraf/issues/1388#issuecomment-791573609
|
||||
* @see https://millsp.github.io/ts-toolbelt/modules/union_strict.html
|
||||
*/
|
||||
function deunionize(t) {
|
||||
return t;
|
||||
}
|
||||
exports.deunionize = deunionize;
|
||||
91
node_modules/telegraf/lib/core/helpers/formatting.js
generated
vendored
Normal file
91
node_modules/telegraf/lib/core/helpers/formatting.js
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.linkOrMention = exports.createFmt = exports.join = exports.FmtString = void 0;
|
||||
const util_1 = require("./util");
|
||||
class FmtString {
|
||||
constructor(text, entities) {
|
||||
this.text = text;
|
||||
if (entities) {
|
||||
this.entities = entities;
|
||||
// force parse_mode to undefined if entities are present
|
||||
this.parse_mode = undefined;
|
||||
}
|
||||
}
|
||||
static normalise(content) {
|
||||
if (content instanceof FmtString)
|
||||
return content;
|
||||
return new FmtString(String(content));
|
||||
}
|
||||
}
|
||||
exports.FmtString = FmtString;
|
||||
const isArray = Array.isArray;
|
||||
/** Given a base FmtString and something to append to it, mutates the base */
|
||||
const _add = (base, next) => {
|
||||
var _a;
|
||||
const len = base.text.length;
|
||||
if (next instanceof FmtString) {
|
||||
base.text = `${base.text}${next.text}`;
|
||||
// next.entities could be undefined and condition will fail
|
||||
for (let i = 0; i < (((_a = next.entities) === null || _a === void 0 ? void 0 : _a.length) || 0); i++) {
|
||||
// because of the above condition, next.entities[i] cannot be undefined
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const entity = next.entities[i];
|
||||
// base.entities is ensured by caller
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
base.entities.push({ ...entity, offset: entity.offset + len });
|
||||
}
|
||||
}
|
||||
else
|
||||
base.text = `${base.text}${next}`;
|
||||
};
|
||||
/**
|
||||
* Given an `Iterable<FmtString | string | Any>` and a separator, flattens the list into a single FmtString.
|
||||
* Analogous to Array#join -> string, but for FmtString
|
||||
*/
|
||||
const join = (fragments, separator) => {
|
||||
const result = new FmtString('');
|
||||
// ensure entities array so loop doesn't need to check
|
||||
result.entities = [];
|
||||
const iter = fragments[Symbol.iterator]();
|
||||
let curr = iter.next();
|
||||
while (!curr.done) {
|
||||
_add(result, curr.value);
|
||||
curr = iter.next();
|
||||
if (separator && !curr.done)
|
||||
_add(result, separator);
|
||||
}
|
||||
// set parse_mode: undefined if entities are present
|
||||
if (result.entities.length)
|
||||
result.parse_mode = undefined;
|
||||
// remove entities array if not relevant
|
||||
else
|
||||
delete result.entities;
|
||||
return result;
|
||||
};
|
||||
exports.join = join;
|
||||
/** Internal constructor for all fmt helpers */
|
||||
function createFmt(kind, opts) {
|
||||
return function fmt(parts, ...items) {
|
||||
var _a;
|
||||
parts = isArray(parts) ? parts : [parts];
|
||||
const result = (0, exports.join)((0, util_1.zip)(parts, items));
|
||||
if (kind) {
|
||||
(_a = result.entities) !== null && _a !== void 0 ? _a : (result.entities = []);
|
||||
result.entities.unshift({
|
||||
type: kind,
|
||||
offset: 0,
|
||||
length: result.text.length,
|
||||
...opts,
|
||||
});
|
||||
result.parse_mode = undefined;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
exports.createFmt = createFmt;
|
||||
const linkOrMention = (content, data) => {
|
||||
const { text, entities = [] } = FmtString.normalise(content);
|
||||
entities.unshift(Object.assign(data, { offset: 0, length: text.length }));
|
||||
return new FmtString(text, entities);
|
||||
};
|
||||
exports.linkOrMention = linkOrMention;
|
||||
50
node_modules/telegraf/lib/core/helpers/util.js
generated
vendored
Normal file
50
node_modules/telegraf/lib/core/helpers/util.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.indexed = exports.zip = exports.fmtCaption = exports.env = void 0;
|
||||
exports.env = process.env;
|
||||
function fmtCaption(extra) {
|
||||
if (!extra)
|
||||
return;
|
||||
const caption = extra.caption;
|
||||
if (!caption || typeof caption === 'string')
|
||||
return extra;
|
||||
const { text, entities } = caption;
|
||||
return {
|
||||
...extra,
|
||||
caption: text,
|
||||
...(entities && {
|
||||
caption_entities: entities,
|
||||
parse_mode: undefined,
|
||||
}),
|
||||
};
|
||||
}
|
||||
exports.fmtCaption = fmtCaption;
|
||||
function* zip(xs, ys) {
|
||||
const x = xs[Symbol.iterator]();
|
||||
const y = ys[Symbol.iterator]();
|
||||
let x1 = x.next();
|
||||
let y1 = y.next();
|
||||
while (!x1.done) {
|
||||
yield x1.value;
|
||||
if (!y1.done)
|
||||
yield y1.value;
|
||||
x1 = x.next();
|
||||
y1 = y.next();
|
||||
}
|
||||
while (!y1.done) {
|
||||
yield y1.value;
|
||||
y1 = y.next();
|
||||
}
|
||||
}
|
||||
exports.zip = zip;
|
||||
function indexed(target, indexer) {
|
||||
return new Proxy(target, {
|
||||
get: function (target, prop, receiver) {
|
||||
if ((typeof prop === 'string' || typeof prop === 'number') &&
|
||||
!isNaN(+prop))
|
||||
return indexer.call(target, +prop);
|
||||
return Reflect.get(target, prop, receiver);
|
||||
},
|
||||
});
|
||||
}
|
||||
exports.indexed = indexed;
|
||||
320
node_modules/telegraf/lib/core/network/client.js
generated
vendored
Normal file
320
node_modules/telegraf/lib/core/network/client.js
generated
vendored
Normal file
@@ -0,0 +1,320 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
/* eslint @typescript-eslint/restrict-template-expressions: [ "error", { "allowNumber": true, "allowBoolean": true } ] */
|
||||
const crypto = __importStar(require("crypto"));
|
||||
const fs = __importStar(require("fs"));
|
||||
const promises_1 = require("fs/promises");
|
||||
const https = __importStar(require("https"));
|
||||
const path = __importStar(require("path"));
|
||||
const node_fetch_1 = __importDefault(require("node-fetch"));
|
||||
const check_1 = require("../helpers/check");
|
||||
const compact_1 = require("../helpers/compact");
|
||||
const multipart_stream_1 = __importDefault(require("./multipart-stream"));
|
||||
const error_1 = __importDefault(require("./error"));
|
||||
const url_1 = require("url");
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const debug = require('debug')('telegraf:client');
|
||||
const { isStream } = multipart_stream_1.default;
|
||||
const WEBHOOK_REPLY_METHOD_ALLOWLIST = new Set([
|
||||
'answerCallbackQuery',
|
||||
'answerInlineQuery',
|
||||
'deleteMessage',
|
||||
'leaveChat',
|
||||
'sendChatAction',
|
||||
]);
|
||||
const DEFAULT_EXTENSIONS = {
|
||||
audio: 'mp3',
|
||||
photo: 'jpg',
|
||||
sticker: 'webp',
|
||||
video: 'mp4',
|
||||
animation: 'mp4',
|
||||
video_note: 'mp4',
|
||||
voice: 'ogg',
|
||||
};
|
||||
const DEFAULT_OPTIONS = {
|
||||
apiRoot: 'https://api.telegram.org',
|
||||
apiMode: 'bot',
|
||||
webhookReply: true,
|
||||
agent: new https.Agent({
|
||||
keepAlive: true,
|
||||
keepAliveMsecs: 10000,
|
||||
}),
|
||||
attachmentAgent: undefined,
|
||||
testEnv: false,
|
||||
};
|
||||
function includesMedia(payload) {
|
||||
return Object.entries(payload).some(([key, value]) => {
|
||||
if (key === 'link_preview_options')
|
||||
return false;
|
||||
if (Array.isArray(value)) {
|
||||
return value.some(({ media }) => media && typeof media === 'object' && (media.source || media.url));
|
||||
}
|
||||
return (value &&
|
||||
typeof value === 'object' &&
|
||||
(((0, check_1.hasProp)(value, 'source') && value.source) ||
|
||||
((0, check_1.hasProp)(value, 'url') && value.url) ||
|
||||
((0, check_1.hasPropType)(value, 'media', 'object') &&
|
||||
(((0, check_1.hasProp)(value.media, 'source') && value.media.source) ||
|
||||
((0, check_1.hasProp)(value.media, 'url') && value.media.url)))));
|
||||
});
|
||||
}
|
||||
function replacer(_, value) {
|
||||
if (value == null)
|
||||
return undefined;
|
||||
return value;
|
||||
}
|
||||
function buildJSONConfig(payload) {
|
||||
return Promise.resolve({
|
||||
method: 'POST',
|
||||
compress: true,
|
||||
headers: { 'content-type': 'application/json', connection: 'keep-alive' },
|
||||
body: JSON.stringify(payload, replacer),
|
||||
});
|
||||
}
|
||||
const FORM_DATA_JSON_FIELDS = [
|
||||
'results',
|
||||
'reply_markup',
|
||||
'mask_position',
|
||||
'shipping_options',
|
||||
'errors',
|
||||
];
|
||||
async function buildFormDataConfig(payload, agent) {
|
||||
for (const field of FORM_DATA_JSON_FIELDS) {
|
||||
if ((0, check_1.hasProp)(payload, field) && typeof payload[field] !== 'string') {
|
||||
payload[field] = JSON.stringify(payload[field]);
|
||||
}
|
||||
}
|
||||
const boundary = crypto.randomBytes(32).toString('hex');
|
||||
const formData = new multipart_stream_1.default(boundary);
|
||||
await Promise.all(Object.keys(payload).map((key) =>
|
||||
// @ts-expect-error payload[key] can obviously index payload, but TS doesn't trust us
|
||||
attachFormValue(formData, key, payload[key], agent)));
|
||||
return {
|
||||
method: 'POST',
|
||||
compress: true,
|
||||
headers: {
|
||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
||||
connection: 'keep-alive',
|
||||
},
|
||||
body: formData,
|
||||
};
|
||||
}
|
||||
async function attachFormValue(form, id, value, agent) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
if (typeof value === 'string' ||
|
||||
typeof value === 'boolean' ||
|
||||
typeof value === 'number') {
|
||||
form.addPart({
|
||||
headers: { 'content-disposition': `form-data; name="${id}"` },
|
||||
body: `${value}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (id === 'thumb' || id === 'thumbnail') {
|
||||
const attachmentId = crypto.randomBytes(16).toString('hex');
|
||||
await attachFormMedia(form, value, attachmentId, agent);
|
||||
return form.addPart({
|
||||
headers: { 'content-disposition': `form-data; name="${id}"` },
|
||||
body: `attach://${attachmentId}`,
|
||||
});
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
const items = await Promise.all(value.map(async (item) => {
|
||||
var _a;
|
||||
if (typeof item.media !== 'object') {
|
||||
return await Promise.resolve(item);
|
||||
}
|
||||
const attachmentId = crypto.randomBytes(16).toString('hex');
|
||||
await attachFormMedia(form, item.media, attachmentId, agent);
|
||||
const thumb = (_a = item.thumb) !== null && _a !== void 0 ? _a : item.thumbnail;
|
||||
if (typeof thumb === 'object') {
|
||||
const thumbAttachmentId = crypto.randomBytes(16).toString('hex');
|
||||
await attachFormMedia(form, thumb, thumbAttachmentId, agent);
|
||||
return {
|
||||
...item,
|
||||
media: `attach://${attachmentId}`,
|
||||
thumbnail: `attach://${thumbAttachmentId}`,
|
||||
};
|
||||
}
|
||||
return { ...item, media: `attach://${attachmentId}` };
|
||||
}));
|
||||
return form.addPart({
|
||||
headers: { 'content-disposition': `form-data; name="${id}"` },
|
||||
body: JSON.stringify(items),
|
||||
});
|
||||
}
|
||||
if (value &&
|
||||
typeof value === 'object' &&
|
||||
(0, check_1.hasProp)(value, 'media') &&
|
||||
(0, check_1.hasProp)(value, 'type') &&
|
||||
typeof value.media !== 'undefined' &&
|
||||
typeof value.type !== 'undefined') {
|
||||
const attachmentId = crypto.randomBytes(16).toString('hex');
|
||||
await attachFormMedia(form, value.media, attachmentId, agent);
|
||||
return form.addPart({
|
||||
headers: { 'content-disposition': `form-data; name="${id}"` },
|
||||
body: JSON.stringify({
|
||||
...value,
|
||||
media: `attach://${attachmentId}`,
|
||||
}),
|
||||
});
|
||||
}
|
||||
return await attachFormMedia(form, value, id, agent);
|
||||
}
|
||||
async function attachFormMedia(form, media, id, agent) {
|
||||
var _a, _b, _c;
|
||||
let fileName = (_a = media.filename) !== null && _a !== void 0 ? _a : `${id}.${(_b = DEFAULT_EXTENSIONS[id]) !== null && _b !== void 0 ? _b : 'dat'}`;
|
||||
if ('url' in media && media.url !== undefined) {
|
||||
const timeout = 500000; // ms
|
||||
const res = await (0, node_fetch_1.default)(media.url, { agent, timeout });
|
||||
return form.addPart({
|
||||
headers: {
|
||||
'content-disposition': `form-data; name="${id}"; filename="${fileName}"`,
|
||||
},
|
||||
body: res.body,
|
||||
});
|
||||
}
|
||||
if ('source' in media && media.source) {
|
||||
let mediaSource = media.source;
|
||||
if (typeof media.source === 'string') {
|
||||
const source = await (0, promises_1.realpath)(media.source);
|
||||
if ((await (0, promises_1.stat)(source)).isFile()) {
|
||||
fileName = (_c = media.filename) !== null && _c !== void 0 ? _c : path.basename(media.source);
|
||||
mediaSource = await fs.createReadStream(media.source);
|
||||
}
|
||||
else {
|
||||
throw new TypeError(`Unable to upload '${media.source}', not a file`);
|
||||
}
|
||||
}
|
||||
if (isStream(mediaSource) || Buffer.isBuffer(mediaSource)) {
|
||||
form.addPart({
|
||||
headers: {
|
||||
'content-disposition': `form-data; name="${id}"; filename="${fileName}"`,
|
||||
},
|
||||
body: mediaSource,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
async function answerToWebhook(response, payload, options) {
|
||||
if (!includesMedia(payload)) {
|
||||
if (!response.headersSent) {
|
||||
response.setHeader('content-type', 'application/json');
|
||||
}
|
||||
response.end(JSON.stringify(payload), 'utf-8');
|
||||
return true;
|
||||
}
|
||||
const { headers, body } = await buildFormDataConfig(payload, options.attachmentAgent);
|
||||
if (!response.headersSent) {
|
||||
for (const [key, value] of Object.entries(headers)) {
|
||||
response.setHeader(key, value);
|
||||
}
|
||||
}
|
||||
await new Promise((resolve) => {
|
||||
response.on('finish', resolve);
|
||||
body.pipe(response);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
function redactToken(error) {
|
||||
error.message = error.message.replace(/\/(bot|user)(\d+):[^/]+\//, '/$1$2:[REDACTED]/');
|
||||
throw error;
|
||||
}
|
||||
class ApiClient {
|
||||
constructor(token, options, response) {
|
||||
this.token = token;
|
||||
this.response = response;
|
||||
this.options = {
|
||||
...DEFAULT_OPTIONS,
|
||||
...(0, compact_1.compactOptions)(options),
|
||||
};
|
||||
if (this.options.apiRoot.startsWith('http://')) {
|
||||
this.options.agent = undefined;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* If set to `true`, first _eligible_ call will avoid performing a POST request.
|
||||
* Note that such a call:
|
||||
* 1. cannot report errors or return meaningful values,
|
||||
* 2. resolves before bot API has a chance to process it,
|
||||
* 3. prematurely confirms the update as processed.
|
||||
*
|
||||
* https://core.telegram.org/bots/faq#how-can-i-make-requests-in-response-to-updates
|
||||
* https://github.com/telegraf/telegraf/pull/1250
|
||||
*/
|
||||
set webhookReply(enable) {
|
||||
this.options.webhookReply = enable;
|
||||
}
|
||||
get webhookReply() {
|
||||
return this.options.webhookReply;
|
||||
}
|
||||
async callApi(method, payload, { signal } = {}) {
|
||||
const { token, options, response } = this;
|
||||
if (options.webhookReply &&
|
||||
(response === null || response === void 0 ? void 0 : response.writableEnded) === false &&
|
||||
WEBHOOK_REPLY_METHOD_ALLOWLIST.has(method)) {
|
||||
debug('Call via webhook', method, payload);
|
||||
// @ts-expect-error using webhookReply is an optimisation that doesn't respond with normal result
|
||||
// up to the user to deal with this
|
||||
return await answerToWebhook(response, { method, ...payload }, options);
|
||||
}
|
||||
if (!token) {
|
||||
throw new error_1.default({
|
||||
error_code: 401,
|
||||
description: 'Bot Token is required',
|
||||
});
|
||||
}
|
||||
debug('HTTP call', method, payload);
|
||||
const config = includesMedia(payload)
|
||||
? await buildFormDataConfig({ method, ...payload }, options.attachmentAgent)
|
||||
: await buildJSONConfig(payload);
|
||||
const apiUrl = new url_1.URL(`./${options.apiMode}${token}${options.testEnv ? '/test' : ''}/${method}`, options.apiRoot);
|
||||
config.agent = options.agent;
|
||||
// @ts-expect-error AbortSignal shim is missing some props from Request.AbortSignal
|
||||
config.signal = signal;
|
||||
config.timeout = 500000; // ms
|
||||
const res = await (0, node_fetch_1.default)(apiUrl, config).catch(redactToken);
|
||||
if (res.status >= 500) {
|
||||
const errorPayload = {
|
||||
error_code: res.status,
|
||||
description: res.statusText,
|
||||
};
|
||||
throw new error_1.default(errorPayload, { method, payload });
|
||||
}
|
||||
const data = await res.json();
|
||||
if (!data.ok) {
|
||||
debug('API call failed', data);
|
||||
throw new error_1.default(data, { method, payload });
|
||||
}
|
||||
return data.result;
|
||||
}
|
||||
}
|
||||
exports.default = ApiClient;
|
||||
21
node_modules/telegraf/lib/core/network/error.js
generated
vendored
Normal file
21
node_modules/telegraf/lib/core/network/error.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TelegramError = void 0;
|
||||
class TelegramError extends Error {
|
||||
constructor(response, on = {}) {
|
||||
super(`${response.error_code}: ${response.description}`);
|
||||
this.response = response;
|
||||
this.on = on;
|
||||
}
|
||||
get code() {
|
||||
return this.response.error_code;
|
||||
}
|
||||
get description() {
|
||||
return this.response.description;
|
||||
}
|
||||
get parameters() {
|
||||
return this.response.parameters;
|
||||
}
|
||||
}
|
||||
exports.TelegramError = TelegramError;
|
||||
exports.default = TelegramError;
|
||||
61
node_modules/telegraf/lib/core/network/multipart-stream.js
generated
vendored
Normal file
61
node_modules/telegraf/lib/core/network/multipart-stream.js
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const stream = __importStar(require("stream"));
|
||||
const check_1 = require("../helpers/check");
|
||||
const sandwich_stream_1 = __importDefault(require("sandwich-stream"));
|
||||
const CRNL = '\r\n';
|
||||
class MultipartStream extends sandwich_stream_1.default {
|
||||
constructor(boundary) {
|
||||
super({
|
||||
head: `--${boundary}${CRNL}`,
|
||||
tail: `${CRNL}--${boundary}--`,
|
||||
separator: `${CRNL}--${boundary}${CRNL}`,
|
||||
});
|
||||
}
|
||||
addPart(part) {
|
||||
const partStream = new stream.PassThrough();
|
||||
for (const [key, header] of Object.entries(part.headers)) {
|
||||
partStream.write(`${key}:${header}${CRNL}`);
|
||||
}
|
||||
partStream.write(CRNL);
|
||||
if (MultipartStream.isStream(part.body)) {
|
||||
part.body.pipe(partStream);
|
||||
}
|
||||
else {
|
||||
partStream.end(part.body);
|
||||
}
|
||||
this.add(partStream);
|
||||
}
|
||||
static isStream(stream) {
|
||||
return (typeof stream === 'object' &&
|
||||
stream !== null &&
|
||||
(0, check_1.hasPropType)(stream, 'pipe', 'function'));
|
||||
}
|
||||
}
|
||||
exports.default = MultipartStream;
|
||||
87
node_modules/telegraf/lib/core/network/polling.js
generated
vendored
Normal file
87
node_modules/telegraf/lib/core/network/polling.js
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Polling = void 0;
|
||||
const abort_controller_1 = __importDefault(require("abort-controller"));
|
||||
const debug_1 = __importDefault(require("debug"));
|
||||
const util_1 = require("util");
|
||||
const error_1 = require("./error");
|
||||
const debug = (0, debug_1.default)('telegraf:polling');
|
||||
const wait = (0, util_1.promisify)(setTimeout);
|
||||
function always(x) {
|
||||
return () => x;
|
||||
}
|
||||
const noop = always(Promise.resolve());
|
||||
class Polling {
|
||||
constructor(telegram, allowedUpdates) {
|
||||
this.telegram = telegram;
|
||||
this.allowedUpdates = allowedUpdates;
|
||||
this.abortController = new abort_controller_1.default();
|
||||
this.skipOffsetSync = false;
|
||||
this.offset = 0;
|
||||
}
|
||||
async *[Symbol.asyncIterator]() {
|
||||
var _a, _b;
|
||||
debug('Starting long polling');
|
||||
do {
|
||||
try {
|
||||
const updates = await this.telegram.callApi('getUpdates', {
|
||||
timeout: 50,
|
||||
offset: this.offset,
|
||||
allowed_updates: this.allowedUpdates,
|
||||
}, this.abortController);
|
||||
const last = updates[updates.length - 1];
|
||||
if (last !== undefined) {
|
||||
this.offset = last.update_id + 1;
|
||||
}
|
||||
yield updates;
|
||||
}
|
||||
catch (error) {
|
||||
const err = error;
|
||||
if (err.name === 'AbortError')
|
||||
return;
|
||||
if (err.name === 'FetchError' ||
|
||||
(err instanceof error_1.TelegramError && err.code === 429) ||
|
||||
(err instanceof error_1.TelegramError && err.code >= 500)) {
|
||||
const retryAfter = (_b = (_a = err.parameters) === null || _a === void 0 ? void 0 : _a.retry_after) !== null && _b !== void 0 ? _b : 5;
|
||||
debug('Failed to fetch updates, retrying after %ds.', retryAfter, err);
|
||||
await wait(retryAfter * 1000);
|
||||
continue;
|
||||
}
|
||||
if (err instanceof error_1.TelegramError &&
|
||||
// Unauthorized Conflict
|
||||
(err.code === 401 || err.code === 409)) {
|
||||
this.skipOffsetSync = true;
|
||||
throw err;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
} while (!this.abortController.signal.aborted);
|
||||
}
|
||||
async syncUpdateOffset() {
|
||||
if (this.skipOffsetSync)
|
||||
return;
|
||||
debug('Syncing update offset...');
|
||||
await this.telegram.callApi('getUpdates', { offset: this.offset, limit: 1 });
|
||||
}
|
||||
async loop(handleUpdate) {
|
||||
if (this.abortController.signal.aborted)
|
||||
throw new Error('Polling instances must not be reused!');
|
||||
try {
|
||||
for await (const updates of this)
|
||||
await Promise.all(updates.map(handleUpdate));
|
||||
}
|
||||
finally {
|
||||
debug('Long polling stopped');
|
||||
// prevent instance reuse
|
||||
this.stop();
|
||||
await this.syncUpdateOffset().catch(noop);
|
||||
}
|
||||
}
|
||||
stop() {
|
||||
this.abortController.abort();
|
||||
}
|
||||
}
|
||||
exports.Polling = Polling;
|
||||
54
node_modules/telegraf/lib/core/network/webhook.js
generated
vendored
Normal file
54
node_modules/telegraf/lib/core/network/webhook.js
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const debug_1 = __importDefault(require("debug"));
|
||||
const debug = (0, debug_1.default)('telegraf:webhook');
|
||||
function generateWebhook(filter, updateHandler) {
|
||||
return async (req, res, next = () => {
|
||||
res.statusCode = 403;
|
||||
debug('Replying with status code', res.statusCode);
|
||||
res.end();
|
||||
}) => {
|
||||
debug('Incoming request', req.method, req.url);
|
||||
if (!filter(req)) {
|
||||
debug('Webhook filter failed', req.method, req.url);
|
||||
return next();
|
||||
}
|
||||
let update;
|
||||
try {
|
||||
if (req.body != null) {
|
||||
/* If req.body is already set, we expect it to be the parsed
|
||||
request body (update object) received from Telegram
|
||||
However, some libraries such as `serverless-http` set req.body to the
|
||||
raw buffer, so we'll handle that additionally */
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let body = req.body;
|
||||
// if body is Buffer, parse it into string
|
||||
if (body instanceof Buffer)
|
||||
body = String(req.body);
|
||||
// if body is string, parse it into object
|
||||
if (typeof body === 'string')
|
||||
body = JSON.parse(body);
|
||||
update = body;
|
||||
}
|
||||
else {
|
||||
let body = '';
|
||||
// parse each buffer to string and append to body
|
||||
for await (const chunk of req)
|
||||
body += String(chunk);
|
||||
// parse body to object
|
||||
update = JSON.parse(body);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
// if any of the parsing steps fails, give up and respond with error
|
||||
res.writeHead(415).end();
|
||||
debug('Failed to parse request body:', error);
|
||||
return;
|
||||
}
|
||||
return await updateHandler(update, res);
|
||||
};
|
||||
}
|
||||
exports.default = generateWebhook;
|
||||
27
node_modules/telegraf/lib/core/types/typegram.js
generated
vendored
Normal file
27
node_modules/telegraf/lib/core/types/typegram.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
// internal type provisions
|
||||
__exportStar(require("@telegraf/types/api"), exports);
|
||||
__exportStar(require("@telegraf/types/inline"), exports);
|
||||
__exportStar(require("@telegraf/types/manage"), exports);
|
||||
__exportStar(require("@telegraf/types/markup"), exports);
|
||||
__exportStar(require("@telegraf/types/message"), exports);
|
||||
__exportStar(require("@telegraf/types/methods"), exports);
|
||||
__exportStar(require("@telegraf/types/passport"), exports);
|
||||
__exportStar(require("@telegraf/types/payment"), exports);
|
||||
__exportStar(require("@telegraf/types/settings"), exports);
|
||||
__exportStar(require("@telegraf/types/update"), exports);
|
||||
69
node_modules/telegraf/lib/filters.js
generated
vendored
Normal file
69
node_modules/telegraf/lib/filters.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.allOf = exports.anyOf = exports.callbackQuery = exports.editedChannelPost = exports.channelPost = exports.editedMessage = exports.message = void 0;
|
||||
const message = (...keys) => (update) => {
|
||||
if (!('message' in update))
|
||||
return false;
|
||||
for (const key of keys) {
|
||||
if (!(key in update.message))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
exports.message = message;
|
||||
const editedMessage = (...keys) => (update) => {
|
||||
if (!('edited_message' in update))
|
||||
return false;
|
||||
for (const key of keys) {
|
||||
if (!(key in update.edited_message))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
exports.editedMessage = editedMessage;
|
||||
const channelPost = (...keys) => (update) => {
|
||||
if (!('channel_post' in update))
|
||||
return false;
|
||||
for (const key of keys) {
|
||||
if (!(key in update.channel_post))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
exports.channelPost = channelPost;
|
||||
const editedChannelPost = (...keys) => (update) => {
|
||||
if (!('edited_channel_post' in update))
|
||||
return false;
|
||||
for (const key of keys) {
|
||||
if (!(key in update.edited_channel_post))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
exports.editedChannelPost = editedChannelPost;
|
||||
const callbackQuery = (...keys) => (update) => {
|
||||
if (!('callback_query' in update))
|
||||
return false;
|
||||
for (const key of keys) {
|
||||
if (!(key in update.callback_query))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
exports.callbackQuery = callbackQuery;
|
||||
/** Any of the provided filters must match */
|
||||
const anyOf = (...filters) => (update) => {
|
||||
for (const filter of filters)
|
||||
if (filter(update))
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
exports.anyOf = anyOf;
|
||||
/** All of the provided filters must match */
|
||||
const allOf = (...filters) => (update) => {
|
||||
for (const filter of filters)
|
||||
if (!filter(update))
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
exports.allOf = allOf;
|
||||
38
node_modules/telegraf/lib/format.js
generated
vendored
Normal file
38
node_modules/telegraf/lib/format.js
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.mention = exports.link = exports.pre = exports.code = exports.quote = exports.underline = exports.strikethrough = exports.spoiler = exports.italic = exports.bold = exports.fmt = exports.join = exports.FmtString = void 0;
|
||||
const formatting_1 = require("./core/helpers/formatting");
|
||||
Object.defineProperty(exports, "FmtString", { enumerable: true, get: function () { return formatting_1.FmtString; } });
|
||||
// Nests<A, B> means the function will return A, and it can nest B
|
||||
// Nests<'fmt', string> means it will nest anything
|
||||
// Nests<'code', never> means it will not nest anything
|
||||
// Allowing everything to nest 'fmt' is a necessary evil; it allows to indirectly nest illegal entities
|
||||
// Except for 'code' and 'pre', which don't nest anything anyway, so they only deal with strings
|
||||
exports.join = formatting_1.join;
|
||||
exports.fmt = (0, formatting_1.createFmt)();
|
||||
exports.bold = (0, formatting_1.createFmt)('bold');
|
||||
exports.italic = (0, formatting_1.createFmt)('italic');
|
||||
exports.spoiler = (0, formatting_1.createFmt)('spoiler');
|
||||
exports.strikethrough =
|
||||
//
|
||||
(0, formatting_1.createFmt)('strikethrough');
|
||||
exports.underline =
|
||||
//
|
||||
(0, formatting_1.createFmt)('underline');
|
||||
exports.quote =
|
||||
//
|
||||
(0, formatting_1.createFmt)('blockquote');
|
||||
exports.code = (0, formatting_1.createFmt)('code');
|
||||
const pre = (language) => (0, formatting_1.createFmt)('pre', { language });
|
||||
exports.pre = pre;
|
||||
const link = (content, url) =>
|
||||
//
|
||||
(0, formatting_1.linkOrMention)(content, { type: 'text_link', url });
|
||||
exports.link = link;
|
||||
const mention = (name, user) => typeof user === 'number'
|
||||
? (0, exports.link)(name, 'tg://user?id=' + user)
|
||||
: (0, formatting_1.linkOrMention)(name, {
|
||||
type: 'text_mention',
|
||||
user,
|
||||
});
|
||||
exports.mention = mention;
|
||||
150
node_modules/telegraf/lib/future.js
generated
vendored
Normal file
150
node_modules/telegraf/lib/future.js
generated
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.useNewReplies = void 0;
|
||||
function makeReply(ctx, extra) {
|
||||
if (ctx.msgId)
|
||||
return {
|
||||
// overrides in this order so user can override all properties
|
||||
reply_parameters: {
|
||||
message_id: ctx.msgId,
|
||||
...extra === null || extra === void 0 ? void 0 : extra.reply_parameters,
|
||||
},
|
||||
...extra,
|
||||
};
|
||||
else
|
||||
return extra;
|
||||
}
|
||||
const replyContext = {
|
||||
replyWithChatAction: function () {
|
||||
throw new TypeError('ctx.replyWithChatAction has been removed, use ctx.sendChatAction instead');
|
||||
},
|
||||
reply(text, extra) {
|
||||
this.assert(this.chat, 'reply');
|
||||
return this.telegram.sendMessage(this.chat.id, text, makeReply(this, extra));
|
||||
},
|
||||
replyWithAnimation(animation, extra) {
|
||||
this.assert(this.chat, 'replyWithAnimation');
|
||||
return this.telegram.sendAnimation(this.chat.id, animation, makeReply(this, extra));
|
||||
},
|
||||
replyWithAudio(audio, extra) {
|
||||
this.assert(this.chat, 'replyWithAudio');
|
||||
return this.telegram.sendAudio(this.chat.id, audio, makeReply(this, extra));
|
||||
},
|
||||
replyWithContact(phoneNumber, firstName, extra) {
|
||||
this.assert(this.chat, 'replyWithContact');
|
||||
return this.telegram.sendContact(this.chat.id, phoneNumber, firstName, makeReply(this, extra));
|
||||
},
|
||||
replyWithDice(extra) {
|
||||
this.assert(this.chat, 'replyWithDice');
|
||||
return this.telegram.sendDice(this.chat.id, makeReply(this, extra));
|
||||
},
|
||||
replyWithDocument(document, extra) {
|
||||
this.assert(this.chat, 'replyWithDocument');
|
||||
return this.telegram.sendDocument(this.chat.id, document, makeReply(this, extra));
|
||||
},
|
||||
replyWithGame(gameName, extra) {
|
||||
this.assert(this.chat, 'replyWithGame');
|
||||
return this.telegram.sendGame(this.chat.id, gameName, makeReply(this, extra));
|
||||
},
|
||||
replyWithHTML(html, extra) {
|
||||
this.assert(this.chat, 'replyWithHTML');
|
||||
return this.telegram.sendMessage(this.chat.id, html, {
|
||||
parse_mode: 'HTML',
|
||||
...makeReply(this, extra),
|
||||
});
|
||||
},
|
||||
replyWithInvoice(invoice, extra) {
|
||||
this.assert(this.chat, 'replyWithInvoice');
|
||||
return this.telegram.sendInvoice(this.chat.id, invoice, makeReply(this, extra));
|
||||
},
|
||||
replyWithLocation(latitude, longitude, extra) {
|
||||
this.assert(this.chat, 'replyWithLocation');
|
||||
return this.telegram.sendLocation(this.chat.id, latitude, longitude, makeReply(this, extra));
|
||||
},
|
||||
replyWithMarkdown(markdown, extra) {
|
||||
this.assert(this.chat, 'replyWithMarkdown');
|
||||
return this.telegram.sendMessage(this.chat.id, markdown, {
|
||||
parse_mode: 'Markdown',
|
||||
...makeReply(this, extra),
|
||||
});
|
||||
},
|
||||
replyWithMarkdownV2(markdown, extra) {
|
||||
this.assert(this.chat, 'replyWithMarkdownV2');
|
||||
return this.telegram.sendMessage(this.chat.id, markdown, {
|
||||
parse_mode: 'MarkdownV2',
|
||||
...makeReply(this, extra),
|
||||
});
|
||||
},
|
||||
replyWithMediaGroup(media, extra) {
|
||||
this.assert(this.chat, 'replyWithMediaGroup');
|
||||
return this.telegram.sendMediaGroup(this.chat.id, media, makeReply(this, extra));
|
||||
},
|
||||
replyWithPhoto(photo, extra) {
|
||||
this.assert(this.chat, 'replyWithPhoto');
|
||||
return this.telegram.sendPhoto(this.chat.id, photo, makeReply(this, extra));
|
||||
},
|
||||
replyWithPoll(question, options, extra) {
|
||||
this.assert(this.chat, 'replyWithPoll');
|
||||
return this.telegram.sendPoll(this.chat.id, question, options, makeReply(this, extra));
|
||||
},
|
||||
replyWithQuiz(question, options, extra) {
|
||||
this.assert(this.chat, 'replyWithQuiz');
|
||||
return this.telegram.sendQuiz(this.chat.id, question, options, makeReply(this, extra));
|
||||
},
|
||||
replyWithSticker(sticker, extra) {
|
||||
this.assert(this.chat, 'replyWithSticker');
|
||||
return this.telegram.sendSticker(this.chat.id, sticker, makeReply(this, extra));
|
||||
},
|
||||
replyWithVenue(latitude, longitude, title, address, extra) {
|
||||
this.assert(this.chat, 'replyWithVenue');
|
||||
return this.telegram.sendVenue(this.chat.id, latitude, longitude, title, address, makeReply(this, extra));
|
||||
},
|
||||
replyWithVideo(video, extra) {
|
||||
this.assert(this.chat, 'replyWithVideo');
|
||||
return this.telegram.sendVideo(this.chat.id, video, makeReply(this, extra));
|
||||
},
|
||||
replyWithVideoNote(videoNote, extra) {
|
||||
this.assert(this.chat, 'replyWithVideoNote');
|
||||
return this.telegram.sendVideoNote(this.chat.id, videoNote, makeReply(this, extra));
|
||||
},
|
||||
replyWithVoice(voice, extra) {
|
||||
this.assert(this.chat, 'replyWithVoice');
|
||||
return this.telegram.sendVoice(this.chat.id, voice, makeReply(this, extra));
|
||||
},
|
||||
};
|
||||
/**
|
||||
* Sets up Context to use the new reply methods.
|
||||
* This middleware makes `ctx.reply()` and `ctx.replyWith*()` methods will actually reply to the message they are replying to.
|
||||
* Use `ctx.sendMessage()` to send a message in chat without replying to it.
|
||||
*
|
||||
* If the message to reply is deleted, `reply()` will send a normal message.
|
||||
* If the update is not a message and we are unable to reply, `reply()` will send a normal message.
|
||||
*/
|
||||
function useNewReplies() {
|
||||
return (ctx, next) => {
|
||||
ctx.reply = replyContext.reply;
|
||||
ctx.replyWithPhoto = replyContext.replyWithPhoto;
|
||||
ctx.replyWithMediaGroup = replyContext.replyWithMediaGroup;
|
||||
ctx.replyWithAudio = replyContext.replyWithAudio;
|
||||
ctx.replyWithDice = replyContext.replyWithDice;
|
||||
ctx.replyWithDocument = replyContext.replyWithDocument;
|
||||
ctx.replyWithSticker = replyContext.replyWithSticker;
|
||||
ctx.replyWithVideo = replyContext.replyWithVideo;
|
||||
ctx.replyWithAnimation = replyContext.replyWithAnimation;
|
||||
ctx.replyWithVideoNote = replyContext.replyWithVideoNote;
|
||||
ctx.replyWithInvoice = replyContext.replyWithInvoice;
|
||||
ctx.replyWithGame = replyContext.replyWithGame;
|
||||
ctx.replyWithVoice = replyContext.replyWithVoice;
|
||||
ctx.replyWithPoll = replyContext.replyWithPoll;
|
||||
ctx.replyWithQuiz = replyContext.replyWithQuiz;
|
||||
ctx.replyWithChatAction = replyContext.replyWithChatAction;
|
||||
ctx.replyWithLocation = replyContext.replyWithLocation;
|
||||
ctx.replyWithVenue = replyContext.replyWithVenue;
|
||||
ctx.replyWithContact = replyContext.replyWithContact;
|
||||
ctx.replyWithMarkdown = replyContext.replyWithMarkdown;
|
||||
ctx.replyWithMarkdownV2 = replyContext.replyWithMarkdownV2;
|
||||
ctx.replyWithHTML = replyContext.replyWithHTML;
|
||||
return next();
|
||||
};
|
||||
}
|
||||
exports.useNewReplies = useNewReplies;
|
||||
48
node_modules/telegraf/lib/index.js
generated
vendored
Normal file
48
node_modules/telegraf/lib/index.js
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Scenes = exports.MemorySessionStore = exports.session = exports.deunionize = exports.Format = exports.Input = exports.Markup = exports.Types = exports.Telegram = exports.TelegramError = exports.Router = exports.Composer = exports.Context = exports.Telegraf = void 0;
|
||||
var telegraf_1 = require("./telegraf");
|
||||
Object.defineProperty(exports, "Telegraf", { enumerable: true, get: function () { return telegraf_1.Telegraf; } });
|
||||
var context_1 = require("./context");
|
||||
Object.defineProperty(exports, "Context", { enumerable: true, get: function () { return context_1.Context; } });
|
||||
var composer_1 = require("./composer");
|
||||
Object.defineProperty(exports, "Composer", { enumerable: true, get: function () { return composer_1.Composer; } });
|
||||
var router_1 = require("./router");
|
||||
Object.defineProperty(exports, "Router", { enumerable: true, get: function () { return router_1.Router; } });
|
||||
var error_1 = require("./core/network/error");
|
||||
Object.defineProperty(exports, "TelegramError", { enumerable: true, get: function () { return error_1.TelegramError; } });
|
||||
var telegram_1 = require("./telegram");
|
||||
Object.defineProperty(exports, "Telegram", { enumerable: true, get: function () { return telegram_1.Telegram; } });
|
||||
exports.Types = __importStar(require("./telegram-types"));
|
||||
exports.Markup = __importStar(require("./markup"));
|
||||
exports.Input = __importStar(require("./input"));
|
||||
exports.Format = __importStar(require("./format"));
|
||||
var deunionize_1 = require("./core/helpers/deunionize");
|
||||
Object.defineProperty(exports, "deunionize", { enumerable: true, get: function () { return deunionize_1.deunionize; } });
|
||||
var session_1 = require("./session");
|
||||
Object.defineProperty(exports, "session", { enumerable: true, get: function () { return session_1.session; } });
|
||||
Object.defineProperty(exports, "MemorySessionStore", { enumerable: true, get: function () { return session_1.MemorySessionStore; } });
|
||||
exports.Scenes = __importStar(require("./scenes"));
|
||||
61
node_modules/telegraf/lib/input.js
generated
vendored
Normal file
61
node_modules/telegraf/lib/input.js
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.fromFileId = exports.fromURL = exports.fromURLStream = exports.fromReadableStream = exports.fromBuffer = exports.fromLocalFile = void 0;
|
||||
/**
|
||||
* The local file specified by path will be uploaded to Telegram using multipart/form-data.
|
||||
*
|
||||
* 10 MB max size for photos, 50 MB for other files.
|
||||
*/
|
||||
// prettier-ignore
|
||||
const fromLocalFile = (path, filename) => ({ source: path, filename });
|
||||
exports.fromLocalFile = fromLocalFile;
|
||||
/**
|
||||
* The buffer will be uploaded as file to Telegram using multipart/form-data.
|
||||
*
|
||||
* 10 MB max size for photos, 50 MB for other files.
|
||||
*/
|
||||
// prettier-ignore
|
||||
const fromBuffer = (buffer, filename) => ({ source: buffer, filename });
|
||||
exports.fromBuffer = fromBuffer;
|
||||
/**
|
||||
* Contents of the stream will be uploaded as file to Telegram using multipart/form-data.
|
||||
*
|
||||
* 10 MB max size for photos, 50 MB for other files.
|
||||
*/
|
||||
// prettier-ignore
|
||||
const fromReadableStream = (stream, filename) => ({ source: stream, filename });
|
||||
exports.fromReadableStream = fromReadableStream;
|
||||
/**
|
||||
* Contents of the URL will be streamed to Telegram.
|
||||
*
|
||||
* 10 MB max size for photos, 50 MB for other files.
|
||||
*/
|
||||
// prettier-ignore
|
||||
const fromURLStream = (url, filename) => ({ url: url.toString(), filename });
|
||||
exports.fromURLStream = fromURLStream;
|
||||
/**
|
||||
* Provide Telegram with an HTTP URL for the file to be sent.
|
||||
* Telegram will download and send the file.
|
||||
*
|
||||
* * The target file must have the correct MIME type (e.g., audio/mpeg for `sendAudio`, etc.).
|
||||
* * `sendDocument` with URL will currently only work for GIF, PDF and ZIP files.
|
||||
* * To use `sendVoice`, the file must have the type audio/ogg and be no more than 1MB in size.
|
||||
* 1-20MB voice notes will be sent as files.
|
||||
*
|
||||
* 5 MB max size for photos and 20 MB max for other types of content.
|
||||
*/
|
||||
const fromURL = (url) => url.toString();
|
||||
exports.fromURL = fromURL;
|
||||
/**
|
||||
* If the file is already stored somewhere on the Telegram servers, you don't need to reupload it:
|
||||
* each file object has a file_id field, simply pass this file_id as a parameter instead of uploading.
|
||||
*
|
||||
* It is not possible to change the file type when resending by file_id.
|
||||
*
|
||||
* It is not possible to resend thumbnails using file_id.
|
||||
* They have to be uploaded using one of the other Input methods.
|
||||
*
|
||||
* There are no limits for files sent this way.
|
||||
*/
|
||||
const fromFileId = (fileId) => fileId;
|
||||
exports.fromFileId = fromFileId;
|
||||
111
node_modules/telegraf/lib/markup.js
generated
vendored
Normal file
111
node_modules/telegraf/lib/markup.js
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.inlineKeyboard = exports.keyboard = exports.forceReply = exports.removeKeyboard = exports.button = exports.Markup = void 0;
|
||||
const check_1 = require("./core/helpers/check");
|
||||
class Markup {
|
||||
constructor(reply_markup) {
|
||||
this.reply_markup = reply_markup;
|
||||
}
|
||||
selective(value = true) {
|
||||
return new Markup({ ...this.reply_markup, selective: value });
|
||||
}
|
||||
placeholder(placeholder) {
|
||||
return new Markup({
|
||||
...this.reply_markup,
|
||||
input_field_placeholder: placeholder,
|
||||
});
|
||||
}
|
||||
resize(value = true) {
|
||||
return new Markup({
|
||||
...this.reply_markup,
|
||||
resize_keyboard: value,
|
||||
});
|
||||
}
|
||||
oneTime(value = true) {
|
||||
return new Markup({
|
||||
...this.reply_markup,
|
||||
one_time_keyboard: value,
|
||||
});
|
||||
}
|
||||
persistent(value = true) {
|
||||
return new Markup({
|
||||
...this.reply_markup,
|
||||
is_persistent: value,
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.Markup = Markup;
|
||||
exports.button = __importStar(require("./button"));
|
||||
function removeKeyboard() {
|
||||
return new Markup({ remove_keyboard: true });
|
||||
}
|
||||
exports.removeKeyboard = removeKeyboard;
|
||||
function forceReply() {
|
||||
return new Markup({ force_reply: true });
|
||||
}
|
||||
exports.forceReply = forceReply;
|
||||
function keyboard(buttons, options) {
|
||||
const keyboard = buildKeyboard(buttons, {
|
||||
columns: 1,
|
||||
...options,
|
||||
});
|
||||
return new Markup({ keyboard });
|
||||
}
|
||||
exports.keyboard = keyboard;
|
||||
function inlineKeyboard(buttons, options) {
|
||||
const inlineKeyboard = buildKeyboard(buttons, {
|
||||
columns: buttons.length,
|
||||
...options,
|
||||
});
|
||||
return new Markup({ inline_keyboard: inlineKeyboard });
|
||||
}
|
||||
exports.inlineKeyboard = inlineKeyboard;
|
||||
function buildKeyboard(buttons, options) {
|
||||
const result = [];
|
||||
if (!Array.isArray(buttons)) {
|
||||
return result;
|
||||
}
|
||||
if ((0, check_1.is2D)(buttons)) {
|
||||
return buttons.map((row) => row.filter((button) => !button.hide));
|
||||
}
|
||||
const wrapFn = options.wrap !== undefined
|
||||
? options.wrap
|
||||
: (_btn, _index, currentRow) => currentRow.length >= options.columns;
|
||||
let currentRow = [];
|
||||
let index = 0;
|
||||
for (const btn of buttons.filter((button) => !button.hide)) {
|
||||
if (wrapFn(btn, index, currentRow) && currentRow.length > 0) {
|
||||
result.push(currentRow);
|
||||
currentRow = [];
|
||||
}
|
||||
currentRow.push(btn);
|
||||
index++;
|
||||
}
|
||||
if (currentRow.length > 0) {
|
||||
result.push(currentRow);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
2
node_modules/telegraf/lib/middleware.js
generated
vendored
Normal file
2
node_modules/telegraf/lib/middleware.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
84
node_modules/telegraf/lib/reactions.js
generated
vendored
Normal file
84
node_modules/telegraf/lib/reactions.js
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.MessageReactions = exports.ReactionList = exports.Digit = void 0;
|
||||
const util_1 = require("./core/helpers/util");
|
||||
exports.Digit = new Set(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']);
|
||||
const inspectReaction = (reaction) => {
|
||||
if (reaction.type === 'custom_emoji')
|
||||
return `Custom(${reaction.custom_emoji_id})`;
|
||||
else
|
||||
return reaction.emoji;
|
||||
};
|
||||
class ReactionList {
|
||||
constructor(list) {
|
||||
this.list = list;
|
||||
}
|
||||
static fromArray(list = []) {
|
||||
return (0, util_1.indexed)(new ReactionList(list), function (index) {
|
||||
return this.list[index];
|
||||
});
|
||||
}
|
||||
static has(reactions, reaction) {
|
||||
if (typeof reaction === 'string')
|
||||
if (exports.Digit.has(reaction[0]))
|
||||
return reactions.some((r) => r.custom_emoji_id === reaction);
|
||||
else
|
||||
return reactions.some((r) => r.emoji === reaction);
|
||||
return reactions.some((r) => {
|
||||
if (r.type === 'custom_emoji')
|
||||
return r.custom_emoji_id === reaction.custom_emoji_id;
|
||||
else if (r.type === 'emoji')
|
||||
return r.emoji === reaction.emoji;
|
||||
});
|
||||
}
|
||||
toArray() {
|
||||
return [...this.list];
|
||||
}
|
||||
filter(filterFn) {
|
||||
return ReactionList.fromArray(this.list.filter(filterFn));
|
||||
}
|
||||
has(reaction) {
|
||||
return ReactionList.has(this.list, reaction);
|
||||
}
|
||||
get count() {
|
||||
return this.list.length;
|
||||
}
|
||||
[Symbol.iterator]() {
|
||||
return this.list[Symbol.iterator]();
|
||||
}
|
||||
[Symbol.for('nodejs.util.inspect.custom')]() {
|
||||
const flattened = this.list.map(inspectReaction).join(', ');
|
||||
return ['ReactionList {', flattened, '}'].join(' ');
|
||||
}
|
||||
}
|
||||
exports.ReactionList = ReactionList;
|
||||
class MessageReactions extends ReactionList {
|
||||
constructor(ctx) {
|
||||
var _a, _b;
|
||||
super((_b = (_a = ctx.update.message_reaction) === null || _a === void 0 ? void 0 : _a.new_reaction) !== null && _b !== void 0 ? _b : []);
|
||||
this.ctx = ctx;
|
||||
}
|
||||
static from(ctx) {
|
||||
return (0, util_1.indexed)(new MessageReactions(ctx), function (index) {
|
||||
return this.list[index];
|
||||
});
|
||||
}
|
||||
get old() {
|
||||
var _a;
|
||||
return ReactionList.fromArray((_a = this.ctx.update.message_reaction) === null || _a === void 0 ? void 0 : _a.old_reaction);
|
||||
}
|
||||
get new() {
|
||||
var _a;
|
||||
return ReactionList.fromArray((_a = this.ctx.update.message_reaction) === null || _a === void 0 ? void 0 : _a.new_reaction);
|
||||
}
|
||||
get added() {
|
||||
return this.new.filter((reaction) => !this.old.has(reaction));
|
||||
}
|
||||
get removed() {
|
||||
return this.old.filter((reaction) => !this.new.has(reaction));
|
||||
}
|
||||
get kept() {
|
||||
return this.new.filter((reaction) => this.old.has(reaction));
|
||||
}
|
||||
}
|
||||
exports.MessageReactions = MessageReactions;
|
||||
46
node_modules/telegraf/lib/router.js
generated
vendored
Normal file
46
node_modules/telegraf/lib/router.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
"use strict";
|
||||
/** @format */
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Router = void 0;
|
||||
const composer_1 = __importDefault(require("./composer"));
|
||||
/** @deprecated in favor of {@link Composer.dispatch} */
|
||||
class Router {
|
||||
constructor(routeFn, handlers = new Map()) {
|
||||
this.routeFn = routeFn;
|
||||
this.handlers = handlers;
|
||||
this.otherwiseHandler = composer_1.default.passThru();
|
||||
if (typeof routeFn !== 'function') {
|
||||
throw new Error('Missing routing function');
|
||||
}
|
||||
}
|
||||
on(route, ...fns) {
|
||||
if (fns.length === 0) {
|
||||
throw new TypeError('At least one handler must be provided');
|
||||
}
|
||||
this.handlers.set(route, composer_1.default.compose(fns));
|
||||
return this;
|
||||
}
|
||||
otherwise(...fns) {
|
||||
if (fns.length === 0) {
|
||||
throw new TypeError('At least one otherwise handler must be provided');
|
||||
}
|
||||
this.otherwiseHandler = composer_1.default.compose(fns);
|
||||
return this;
|
||||
}
|
||||
middleware() {
|
||||
return composer_1.default.lazy((ctx) => {
|
||||
var _a;
|
||||
const result = this.routeFn(ctx);
|
||||
if (result == null) {
|
||||
return this.otherwiseHandler;
|
||||
}
|
||||
Object.assign(ctx, result.context);
|
||||
Object.assign(ctx.state, result.state);
|
||||
return (_a = this.handlers.get(result.route)) !== null && _a !== void 0 ? _a : this.otherwiseHandler;
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.Router = Router;
|
||||
17
node_modules/telegraf/lib/scenes.js
generated
vendored
Normal file
17
node_modules/telegraf/lib/scenes.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
__exportStar(require("./scenes/index.js"), exports);
|
||||
39
node_modules/telegraf/lib/scenes/base.js
generated
vendored
Normal file
39
node_modules/telegraf/lib/scenes/base.js
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.BaseScene = void 0;
|
||||
const composer_1 = __importDefault(require("../composer"));
|
||||
const { compose } = composer_1.default;
|
||||
class BaseScene extends composer_1.default {
|
||||
constructor(id, options) {
|
||||
const opts = {
|
||||
handlers: [],
|
||||
enterHandlers: [],
|
||||
leaveHandlers: [],
|
||||
...options,
|
||||
};
|
||||
super(...opts.handlers);
|
||||
this.id = id;
|
||||
this.ttl = opts.ttl;
|
||||
this.enterHandler = compose(opts.enterHandlers);
|
||||
this.leaveHandler = compose(opts.leaveHandlers);
|
||||
}
|
||||
enter(...fns) {
|
||||
this.enterHandler = compose([this.enterHandler, ...fns]);
|
||||
return this;
|
||||
}
|
||||
leave(...fns) {
|
||||
this.leaveHandler = compose([this.leaveHandler, ...fns]);
|
||||
return this;
|
||||
}
|
||||
enterMiddleware() {
|
||||
return this.enterHandler;
|
||||
}
|
||||
leaveMiddleware() {
|
||||
return this.leaveHandler;
|
||||
}
|
||||
}
|
||||
exports.BaseScene = BaseScene;
|
||||
exports.default = BaseScene;
|
||||
104
node_modules/telegraf/lib/scenes/context.js
generated
vendored
Normal file
104
node_modules/telegraf/lib/scenes/context.js
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const composer_1 = __importDefault(require("../composer"));
|
||||
const debug_1 = __importDefault(require("debug"));
|
||||
const debug = (0, debug_1.default)('telegraf:scenes:context');
|
||||
const noop = () => Promise.resolve();
|
||||
const now = () => Math.floor(Date.now() / 1000);
|
||||
class SceneContextScene {
|
||||
constructor(ctx, scenes, options) {
|
||||
this.ctx = ctx;
|
||||
this.scenes = scenes;
|
||||
this.leaving = false;
|
||||
// @ts-expect-error {} might not be assignable to D
|
||||
const fallbackSessionDefault = {};
|
||||
this.options = { defaultSession: fallbackSessionDefault, ...options };
|
||||
}
|
||||
get session() {
|
||||
var _a, _b;
|
||||
const defaultSession = Object.assign({}, this.options.defaultSession);
|
||||
let session = (_b = (_a = this.ctx.session) === null || _a === void 0 ? void 0 : _a.__scenes) !== null && _b !== void 0 ? _b : defaultSession;
|
||||
if (session.expires !== undefined && session.expires < now()) {
|
||||
session = defaultSession;
|
||||
}
|
||||
if (this.ctx.session === undefined) {
|
||||
this.ctx.session = { __scenes: session };
|
||||
}
|
||||
else {
|
||||
this.ctx.session.__scenes = session;
|
||||
}
|
||||
return session;
|
||||
}
|
||||
get state() {
|
||||
var _a;
|
||||
var _b;
|
||||
return ((_a = (_b = this.session).state) !== null && _a !== void 0 ? _a : (_b.state = {}));
|
||||
}
|
||||
set state(value) {
|
||||
this.session.state = { ...value };
|
||||
}
|
||||
get current() {
|
||||
var _a;
|
||||
const sceneId = (_a = this.session.current) !== null && _a !== void 0 ? _a : this.options.default;
|
||||
return sceneId === undefined || !this.scenes.has(sceneId)
|
||||
? undefined
|
||||
: this.scenes.get(sceneId);
|
||||
}
|
||||
reset() {
|
||||
if (this.ctx.session !== undefined)
|
||||
this.ctx.session.__scenes = Object.assign({}, this.options.defaultSession);
|
||||
}
|
||||
async enter(sceneId, initialState = {}, silent = false) {
|
||||
var _a, _b;
|
||||
if (!this.scenes.has(sceneId)) {
|
||||
throw new Error(`Can't find scene: ${sceneId}`);
|
||||
}
|
||||
if (!silent) {
|
||||
await this.leave();
|
||||
}
|
||||
debug('Entering scene', sceneId, initialState, silent);
|
||||
this.session.current = sceneId;
|
||||
this.state = initialState;
|
||||
const ttl = (_b = (_a = this.current) === null || _a === void 0 ? void 0 : _a.ttl) !== null && _b !== void 0 ? _b : this.options.ttl;
|
||||
if (ttl !== undefined) {
|
||||
this.session.expires = now() + ttl;
|
||||
}
|
||||
if (this.current === undefined || silent) {
|
||||
return;
|
||||
}
|
||||
const handler = 'enterMiddleware' in this.current &&
|
||||
typeof this.current.enterMiddleware === 'function'
|
||||
? this.current.enterMiddleware()
|
||||
: this.current.middleware();
|
||||
return await handler(this.ctx, noop);
|
||||
}
|
||||
reenter() {
|
||||
return this.session.current === undefined
|
||||
? undefined
|
||||
: this.enter(this.session.current, this.state);
|
||||
}
|
||||
async leave() {
|
||||
if (this.leaving)
|
||||
return;
|
||||
debug('Leaving scene');
|
||||
try {
|
||||
this.leaving = true;
|
||||
if (this.current === undefined) {
|
||||
return;
|
||||
}
|
||||
const handler = 'leaveMiddleware' in this.current &&
|
||||
typeof this.current.leaveMiddleware === 'function'
|
||||
? this.current.leaveMiddleware()
|
||||
: composer_1.default.passThru();
|
||||
await handler(this.ctx, noop);
|
||||
return this.reset();
|
||||
}
|
||||
finally {
|
||||
this.leaving = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.default = SceneContextScene;
|
||||
21
node_modules/telegraf/lib/scenes/index.js
generated
vendored
Normal file
21
node_modules/telegraf/lib/scenes/index.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
"use strict";
|
||||
/**
|
||||
* @see https://github.com/telegraf/telegraf/issues/705#issuecomment-549056045
|
||||
* @see https://www.npmjs.com/package/telegraf-stateless-question
|
||||
* @packageDocumentation
|
||||
*/
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.WizardContextWizard = exports.WizardScene = exports.BaseScene = exports.SceneContextScene = exports.Stage = void 0;
|
||||
var stage_1 = require("./stage");
|
||||
Object.defineProperty(exports, "Stage", { enumerable: true, get: function () { return stage_1.Stage; } });
|
||||
var context_1 = require("./context");
|
||||
Object.defineProperty(exports, "SceneContextScene", { enumerable: true, get: function () { return __importDefault(context_1).default; } });
|
||||
var base_1 = require("./base");
|
||||
Object.defineProperty(exports, "BaseScene", { enumerable: true, get: function () { return base_1.BaseScene; } });
|
||||
var wizard_1 = require("./wizard");
|
||||
Object.defineProperty(exports, "WizardScene", { enumerable: true, get: function () { return wizard_1.WizardScene; } });
|
||||
var context_2 = require("./wizard/context");
|
||||
Object.defineProperty(exports, "WizardContextWizard", { enumerable: true, get: function () { return __importDefault(context_2).default; } });
|
||||
49
node_modules/telegraf/lib/scenes/stage.js
generated
vendored
Normal file
49
node_modules/telegraf/lib/scenes/stage.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Stage = void 0;
|
||||
const session_1 = require("../session");
|
||||
const context_1 = __importDefault(require("./context"));
|
||||
const composer_1 = require("../composer");
|
||||
class Stage extends composer_1.Composer {
|
||||
constructor(scenes = [], options) {
|
||||
super();
|
||||
this.options = { ...options };
|
||||
this.scenes = new Map();
|
||||
scenes.forEach((scene) => this.register(scene));
|
||||
}
|
||||
register(...scenes) {
|
||||
scenes.forEach((scene) => {
|
||||
if ((scene === null || scene === void 0 ? void 0 : scene.id) == null || typeof scene.middleware !== 'function') {
|
||||
throw new Error('telegraf: Unsupported scene');
|
||||
}
|
||||
this.scenes.set(scene.id, scene);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
middleware() {
|
||||
const handler = composer_1.Composer.compose([
|
||||
(ctx, next) => {
|
||||
const scenes = this.scenes;
|
||||
const scene = new context_1.default(ctx, scenes, this.options);
|
||||
ctx.scene = scene;
|
||||
return next();
|
||||
},
|
||||
super.middleware(),
|
||||
composer_1.Composer.lazy((ctx) => { var _a; return (_a = ctx.scene.current) !== null && _a !== void 0 ? _a : composer_1.Composer.passThru(); }),
|
||||
]);
|
||||
return composer_1.Composer.optional(session_1.isSessionContext, handler);
|
||||
}
|
||||
static enter(...args) {
|
||||
return (ctx) => ctx.scene.enter(...args);
|
||||
}
|
||||
static reenter(...args) {
|
||||
return (ctx) => ctx.scene.reenter(...args);
|
||||
}
|
||||
static leave(...args) {
|
||||
return (ctx) => ctx.scene.leave(...args);
|
||||
}
|
||||
}
|
||||
exports.Stage = Stage;
|
||||
31
node_modules/telegraf/lib/scenes/wizard/context.js
generated
vendored
Normal file
31
node_modules/telegraf/lib/scenes/wizard/context.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
class WizardContextWizard {
|
||||
constructor(ctx, steps) {
|
||||
var _a;
|
||||
this.ctx = ctx;
|
||||
this.steps = steps;
|
||||
this.state = ctx.scene.state;
|
||||
this.cursor = (_a = ctx.scene.session.cursor) !== null && _a !== void 0 ? _a : 0;
|
||||
}
|
||||
get step() {
|
||||
return this.steps[this.cursor];
|
||||
}
|
||||
get cursor() {
|
||||
return this.ctx.scene.session.cursor;
|
||||
}
|
||||
set cursor(cursor) {
|
||||
this.ctx.scene.session.cursor = cursor;
|
||||
}
|
||||
selectStep(index) {
|
||||
this.cursor = index;
|
||||
return this;
|
||||
}
|
||||
next() {
|
||||
return this.selectStep(this.cursor + 1);
|
||||
}
|
||||
back() {
|
||||
return this.selectStep(this.cursor - 1);
|
||||
}
|
||||
}
|
||||
exports.default = WizardContextWizard;
|
||||
45
node_modules/telegraf/lib/scenes/wizard/index.js
generated
vendored
Normal file
45
node_modules/telegraf/lib/scenes/wizard/index.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.WizardScene = void 0;
|
||||
const base_1 = __importDefault(require("../base"));
|
||||
const context_1 = __importDefault(require("./context"));
|
||||
const composer_1 = __importDefault(require("../../composer"));
|
||||
class WizardScene extends base_1.default {
|
||||
constructor(id, options, ...steps) {
|
||||
let opts;
|
||||
let s;
|
||||
if (typeof options === 'function' || 'middleware' in options) {
|
||||
opts = undefined;
|
||||
s = [options, ...steps];
|
||||
}
|
||||
else {
|
||||
opts = options;
|
||||
s = steps;
|
||||
}
|
||||
super(id, opts);
|
||||
this.steps = s;
|
||||
}
|
||||
middleware() {
|
||||
return composer_1.default.compose([
|
||||
(ctx, next) => {
|
||||
ctx.wizard = new context_1.default(ctx, this.steps);
|
||||
return next();
|
||||
},
|
||||
super.middleware(),
|
||||
(ctx, next) => {
|
||||
if (ctx.wizard.step === undefined) {
|
||||
ctx.wizard.selectStep(0);
|
||||
return ctx.scene.leave();
|
||||
}
|
||||
return composer_1.default.unwrap(ctx.wizard.step)(ctx, next);
|
||||
},
|
||||
]);
|
||||
}
|
||||
enterMiddleware() {
|
||||
return composer_1.default.compose([this.enterHandler, this.middleware()]);
|
||||
}
|
||||
}
|
||||
exports.WizardScene = WizardScene;
|
||||
166
node_modules/telegraf/lib/session.js
generated
vendored
Normal file
166
node_modules/telegraf/lib/session.js
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.isSessionContext = exports.MemorySessionStore = exports.session = void 0;
|
||||
const debug_1 = __importDefault(require("debug"));
|
||||
const debug = (0, debug_1.default)('telegraf:session');
|
||||
/**
|
||||
* Returns middleware that adds `ctx.session` for storing arbitrary state per session key.
|
||||
*
|
||||
* The default `getSessionKey` is `${ctx.from.id}:${ctx.chat.id}`.
|
||||
* If either `ctx.from` or `ctx.chat` is `undefined`, default session key and thus `ctx.session` are also `undefined`.
|
||||
*
|
||||
* > ⚠️ Session data is kept only in memory by default, which means that all data will be lost when the process is terminated.
|
||||
* >
|
||||
* > If you want to persist data across process restarts, or share it among multiple instances, you should use
|
||||
* [@telegraf/session](https://www.npmjs.com/package/@telegraf/session), or pass custom `storage`.
|
||||
*
|
||||
* @see {@link https://github.com/feathers-studio/telegraf-docs/blob/b694bcc36b4f71fb1cd650a345c2009ab4d2a2a5/guide/session.md Telegraf Docs | Session}
|
||||
* @see {@link https://github.com/feathers-studio/telegraf-docs/blob/master/examples/session-bot.ts Example}
|
||||
*/
|
||||
function session(options) {
|
||||
var _a, _b, _c;
|
||||
const prop = (_a = options === null || options === void 0 ? void 0 : options.property) !== null && _a !== void 0 ? _a : 'session';
|
||||
const getSessionKey = (_b = options === null || options === void 0 ? void 0 : options.getSessionKey) !== null && _b !== void 0 ? _b : defaultGetSessionKey;
|
||||
const store = (_c = options === null || options === void 0 ? void 0 : options.store) !== null && _c !== void 0 ? _c : new MemorySessionStore();
|
||||
// caches value from store in-memory while simultaneous updates share it
|
||||
// when counter reaches 0, the cached ref will be freed from memory
|
||||
const cache = new Map();
|
||||
// temporarily stores concurrent requests
|
||||
const concurrents = new Map();
|
||||
// this function must be handled with care
|
||||
// read full description on the original PR: https://github.com/telegraf/telegraf/pull/1713
|
||||
// make sure to update the tests in test/session.js if you make any changes or fix bugs here
|
||||
return async (ctx, next) => {
|
||||
var _a;
|
||||
const updId = ctx.update.update_id;
|
||||
let released = false;
|
||||
function releaseChecks() {
|
||||
if (released && process.env.EXPERIMENTAL_SESSION_CHECKS)
|
||||
throw new Error("Session was accessed or assigned to after the middleware chain exhausted. This is a bug in your code. You're probably accessing session asynchronously and missing awaits.");
|
||||
}
|
||||
// because this is async, requests may still race here, but it will get autocorrected at (1)
|
||||
// v5 getSessionKey should probably be synchronous to avoid that
|
||||
const key = await getSessionKey(ctx);
|
||||
if (!key) {
|
||||
// Leaving this here could be useful to check for `prop in ctx` in future middleware
|
||||
ctx[prop] = undefined;
|
||||
return await next();
|
||||
}
|
||||
let cached = cache.get(key);
|
||||
if (cached) {
|
||||
debug(`(${updId}) found cached session, reusing from cache`);
|
||||
++cached.counter;
|
||||
}
|
||||
else {
|
||||
debug(`(${updId}) did not find cached session`);
|
||||
// if another concurrent request has already sent a store request, fetch that instead
|
||||
let promise = concurrents.get(key);
|
||||
if (promise)
|
||||
debug(`(${updId}) found a concurrent request, reusing promise`);
|
||||
else {
|
||||
debug(`(${updId}) fetching from upstream store`);
|
||||
promise = store.get(key);
|
||||
}
|
||||
// synchronously store promise so concurrent requests can share response
|
||||
concurrents.set(key, promise);
|
||||
const upstream = await promise;
|
||||
// all concurrent awaits will have promise in their closure, safe to remove now
|
||||
concurrents.delete(key);
|
||||
debug(`(${updId}) updating cache`);
|
||||
// another request may have beaten us to the punch
|
||||
const c = cache.get(key);
|
||||
if (c) {
|
||||
// another request did beat us to the punch
|
||||
c.counter++;
|
||||
// (1) preserve cached reference; in-memory reference is always newer than from store
|
||||
cached = c;
|
||||
}
|
||||
else {
|
||||
// we're the first, so we must cache the reference
|
||||
cached = { ref: upstream !== null && upstream !== void 0 ? upstream : (_a = options === null || options === void 0 ? void 0 : options.defaultSession) === null || _a === void 0 ? void 0 : _a.call(options, ctx), counter: 1 };
|
||||
cache.set(key, cached);
|
||||
}
|
||||
}
|
||||
// TS already knows cached is always defined by this point, but does not guard cached.
|
||||
// It will, however, guard `c` here.
|
||||
const c = cached;
|
||||
let touched = false;
|
||||
Object.defineProperty(ctx, prop, {
|
||||
get() {
|
||||
releaseChecks();
|
||||
touched = true;
|
||||
return c.ref;
|
||||
},
|
||||
set(value) {
|
||||
releaseChecks();
|
||||
touched = true;
|
||||
c.ref = value;
|
||||
},
|
||||
});
|
||||
try {
|
||||
await next();
|
||||
released = true;
|
||||
}
|
||||
finally {
|
||||
if (--c.counter === 0) {
|
||||
// decrement to avoid memory leak
|
||||
debug(`(${updId}) refcounter reached 0, removing cached`);
|
||||
cache.delete(key);
|
||||
}
|
||||
debug(`(${updId}) middlewares completed, checking session`);
|
||||
// only update store if ctx.session was touched
|
||||
if (touched)
|
||||
if (c.ref == null) {
|
||||
debug(`(${updId}) ctx.${prop} missing, removing from store`);
|
||||
await store.delete(key);
|
||||
}
|
||||
else {
|
||||
debug(`(${updId}) ctx.${prop} found, updating store`);
|
||||
await store.set(key, c.ref);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
exports.session = session;
|
||||
function defaultGetSessionKey(ctx) {
|
||||
var _a, _b;
|
||||
const fromId = (_a = ctx.from) === null || _a === void 0 ? void 0 : _a.id;
|
||||
const chatId = (_b = ctx.chat) === null || _b === void 0 ? void 0 : _b.id;
|
||||
if (fromId == null || chatId == null)
|
||||
return undefined;
|
||||
return `${fromId}:${chatId}`;
|
||||
}
|
||||
/** @deprecated Use `Map` */
|
||||
class MemorySessionStore {
|
||||
constructor(ttl = Infinity) {
|
||||
this.ttl = ttl;
|
||||
this.store = new Map();
|
||||
}
|
||||
get(name) {
|
||||
const entry = this.store.get(name);
|
||||
if (entry == null) {
|
||||
return undefined;
|
||||
}
|
||||
else if (entry.expires < Date.now()) {
|
||||
this.delete(name);
|
||||
return undefined;
|
||||
}
|
||||
return entry.session;
|
||||
}
|
||||
set(name, value) {
|
||||
const now = Date.now();
|
||||
this.store.set(name, { session: value, expires: now + this.ttl });
|
||||
}
|
||||
delete(name) {
|
||||
this.store.delete(name);
|
||||
}
|
||||
}
|
||||
exports.MemorySessionStore = MemorySessionStore;
|
||||
/** @deprecated session can use custom properties now. Directly use `'session' in ctx` instead */
|
||||
function isSessionContext(ctx) {
|
||||
return 'session' in ctx;
|
||||
}
|
||||
exports.isSessionContext = isSessionContext;
|
||||
246
node_modules/telegraf/lib/telegraf.js
generated
vendored
Normal file
246
node_modules/telegraf/lib/telegraf.js
generated
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Telegraf = void 0;
|
||||
const crypto = __importStar(require("crypto"));
|
||||
const http = __importStar(require("http"));
|
||||
const https = __importStar(require("https"));
|
||||
const composer_1 = require("./composer");
|
||||
const compact_1 = require("./core/helpers/compact");
|
||||
const context_1 = __importDefault(require("./context"));
|
||||
const debug_1 = __importDefault(require("debug"));
|
||||
const webhook_1 = __importDefault(require("./core/network/webhook"));
|
||||
const polling_1 = require("./core/network/polling");
|
||||
const p_timeout_1 = __importDefault(require("p-timeout"));
|
||||
const telegram_1 = __importDefault(require("./telegram"));
|
||||
const url_1 = require("url");
|
||||
const safeCompare = require("safe-compare");
|
||||
const debug = (0, debug_1.default)('telegraf:main');
|
||||
const DEFAULT_OPTIONS = {
|
||||
telegram: {},
|
||||
handlerTimeout: 90000,
|
||||
contextType: context_1.default,
|
||||
};
|
||||
function always(x) {
|
||||
return () => x;
|
||||
}
|
||||
const anoop = always(Promise.resolve());
|
||||
const TOKEN_HEADER = 'x-telegram-bot-api-secret-token';
|
||||
class Telegraf extends composer_1.Composer {
|
||||
constructor(token, options) {
|
||||
super();
|
||||
this.context = {};
|
||||
/** Assign to this to customise the webhook filter middleware.
|
||||
* `{ path, secretToken }` will be bound to this rather than the Telegraf instance.
|
||||
* Remember to assign a regular function and not an arrow function so it's bindable.
|
||||
*/
|
||||
this.webhookFilter = function (req) {
|
||||
const debug = (0, debug_1.default)('telegraf:webhook');
|
||||
if (req.method === 'POST') {
|
||||
if (safeCompare(this.path, req.url)) {
|
||||
// no need to check if secret_token was not set
|
||||
if (!this.secretToken)
|
||||
return true;
|
||||
else {
|
||||
const token = req.headers[TOKEN_HEADER];
|
||||
if (safeCompare(this.secretToken, token))
|
||||
return true;
|
||||
else
|
||||
debug('Secret token does not match:', token, this.secretToken);
|
||||
}
|
||||
}
|
||||
else
|
||||
debug('Path does not match:', req.url, this.path);
|
||||
}
|
||||
else
|
||||
debug('Unexpected request method, not POST. Received:', req.method);
|
||||
return false;
|
||||
};
|
||||
this.handleError = (err, ctx) => {
|
||||
// set exit code to emulate `warn-with-error-code` behavior of
|
||||
// https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode
|
||||
// to prevent a clean exit despite an error being thrown
|
||||
process.exitCode = 1;
|
||||
console.error('Unhandled error while processing', ctx.update);
|
||||
throw err;
|
||||
};
|
||||
// @ts-expect-error Trust me, TS
|
||||
this.options = {
|
||||
...DEFAULT_OPTIONS,
|
||||
...(0, compact_1.compactOptions)(options),
|
||||
};
|
||||
this.telegram = new telegram_1.default(token, this.options.telegram);
|
||||
debug('Created a `Telegraf` instance');
|
||||
}
|
||||
get token() {
|
||||
return this.telegram.token;
|
||||
}
|
||||
/** @deprecated use `ctx.telegram.webhookReply` */
|
||||
set webhookReply(webhookReply) {
|
||||
this.telegram.webhookReply = webhookReply;
|
||||
}
|
||||
/** @deprecated use `ctx.telegram.webhookReply` */
|
||||
get webhookReply() {
|
||||
return this.telegram.webhookReply;
|
||||
}
|
||||
/**
|
||||
* _Override_ error handling
|
||||
*/
|
||||
catch(handler) {
|
||||
this.handleError = handler;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* You must call `bot.telegram.setWebhook` for this to work.
|
||||
* You should probably use {@link Telegraf.createWebhook} instead.
|
||||
*/
|
||||
webhookCallback(path = '/', opts = {}) {
|
||||
const { secretToken } = opts;
|
||||
return (0, webhook_1.default)(this.webhookFilter.bind({ hookPath: path, path, secretToken }), (update, res) => this.handleUpdate(update, res));
|
||||
}
|
||||
getDomainOpts(opts) {
|
||||
var _a;
|
||||
const protocol = opts.domain.startsWith('https://') || opts.domain.startsWith('http://');
|
||||
if (protocol)
|
||||
debug('Unexpected protocol in domain, telegraf will use https:', opts.domain);
|
||||
const domain = protocol ? new url_1.URL(opts.domain).host : opts.domain;
|
||||
const path = (_a = opts.path) !== null && _a !== void 0 ? _a : `/telegraf/${this.secretPathComponent()}`;
|
||||
const url = `https://${domain}${path}`;
|
||||
return { domain, path, url };
|
||||
}
|
||||
/**
|
||||
* Specify a url to receive incoming updates via webhook.
|
||||
* Returns an Express-style middleware you can pass to app.use()
|
||||
*/
|
||||
async createWebhook(opts) {
|
||||
const { domain, path, ...extra } = opts;
|
||||
const domainOpts = this.getDomainOpts({ domain, path });
|
||||
await this.telegram.setWebhook(domainOpts.url, extra);
|
||||
debug(`Webhook set to ${domainOpts.url}`);
|
||||
return this.webhookCallback(domainOpts.path, {
|
||||
secretToken: extra.secret_token,
|
||||
});
|
||||
}
|
||||
startPolling(allowedUpdates = []) {
|
||||
this.polling = new polling_1.Polling(this.telegram, allowedUpdates);
|
||||
return this.polling.loop(async (update) => {
|
||||
await this.handleUpdate(update);
|
||||
});
|
||||
}
|
||||
startWebhook(path, tlsOptions, port, host, cb, secretToken) {
|
||||
const webhookCb = this.webhookCallback(path, { secretToken });
|
||||
const callback = typeof cb === 'function'
|
||||
? (req, res) => webhookCb(req, res, () => cb(req, res))
|
||||
: webhookCb;
|
||||
this.webhookServer =
|
||||
tlsOptions != null
|
||||
? https.createServer(tlsOptions, callback)
|
||||
: http.createServer(callback);
|
||||
this.webhookServer.listen(port, host, () => {
|
||||
debug('Webhook listening on port: %s', port);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
secretPathComponent() {
|
||||
return crypto
|
||||
.createHash('sha3-256')
|
||||
.update(this.token)
|
||||
.update(process.version) // salt
|
||||
.digest('hex');
|
||||
}
|
||||
/**
|
||||
* @see https://github.com/telegraf/telegraf/discussions/1344#discussioncomment-335700
|
||||
*/
|
||||
async launch(config = {},
|
||||
/** @experimental */
|
||||
onLaunch) {
|
||||
var _a, _b;
|
||||
const [cfg, onMe] = typeof config === 'function' ? [{}, config] : [config, onLaunch];
|
||||
const drop_pending_updates = cfg.dropPendingUpdates;
|
||||
const allowed_updates = cfg.allowedUpdates;
|
||||
const webhook = cfg.webhook;
|
||||
debug('Connecting to Telegram');
|
||||
(_a = this.botInfo) !== null && _a !== void 0 ? _a : (this.botInfo = await this.telegram.getMe());
|
||||
onMe === null || onMe === void 0 ? void 0 : onMe();
|
||||
debug(`Launching @${this.botInfo.username}`);
|
||||
if (webhook === undefined) {
|
||||
await this.telegram.deleteWebhook({ drop_pending_updates });
|
||||
debug('Bot started with long polling');
|
||||
await this.startPolling(allowed_updates);
|
||||
return;
|
||||
}
|
||||
const domainOpts = this.getDomainOpts({
|
||||
domain: webhook.domain,
|
||||
path: (_b = webhook.path) !== null && _b !== void 0 ? _b : webhook.hookPath,
|
||||
});
|
||||
const { tlsOptions, port, host, cb, secretToken } = webhook;
|
||||
this.startWebhook(domainOpts.path, tlsOptions, port, host, cb, secretToken);
|
||||
await this.telegram.setWebhook(domainOpts.url, {
|
||||
drop_pending_updates: drop_pending_updates,
|
||||
allowed_updates: allowed_updates,
|
||||
ip_address: webhook.ipAddress,
|
||||
max_connections: webhook.maxConnections,
|
||||
secret_token: webhook.secretToken,
|
||||
certificate: webhook.certificate,
|
||||
});
|
||||
debug(`Bot started with webhook @ ${domainOpts.url}`);
|
||||
}
|
||||
stop(reason = 'unspecified') {
|
||||
var _a, _b;
|
||||
debug('Stopping bot... Reason:', reason);
|
||||
// https://github.com/telegraf/telegraf/pull/1224#issuecomment-742693770
|
||||
if (this.polling === undefined && this.webhookServer === undefined) {
|
||||
throw new Error('Bot is not running!');
|
||||
}
|
||||
(_a = this.webhookServer) === null || _a === void 0 ? void 0 : _a.close();
|
||||
(_b = this.polling) === null || _b === void 0 ? void 0 : _b.stop();
|
||||
}
|
||||
async handleUpdate(update, webhookResponse) {
|
||||
var _a, _b;
|
||||
(_a = this.botInfo) !== null && _a !== void 0 ? _a : (this.botInfo = (debug('Update %d is waiting for `botInfo` to be initialized', update.update_id),
|
||||
await ((_b = this.botInfoCall) !== null && _b !== void 0 ? _b : (this.botInfoCall = this.telegram.getMe()))));
|
||||
debug('Processing update', update.update_id);
|
||||
const tg = new telegram_1.default(this.token, this.telegram.options, webhookResponse);
|
||||
const TelegrafContext = this.options.contextType;
|
||||
const ctx = new TelegrafContext(update, tg, this.botInfo);
|
||||
Object.assign(ctx, this.context);
|
||||
try {
|
||||
await (0, p_timeout_1.default)(Promise.resolve(this.middleware()(ctx, anoop)), this.options.handlerTimeout);
|
||||
}
|
||||
catch (err) {
|
||||
return await this.handleError(err, ctx);
|
||||
}
|
||||
finally {
|
||||
if ((webhookResponse === null || webhookResponse === void 0 ? void 0 : webhookResponse.writableEnded) === false) {
|
||||
webhookResponse.end();
|
||||
}
|
||||
debug('Finished processing update', update.update_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.Telegraf = Telegraf;
|
||||
6
node_modules/telegraf/lib/telegram-types.js
generated
vendored
Normal file
6
node_modules/telegraf/lib/telegram-types.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
"use strict";
|
||||
/** @format */
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Markup = void 0;
|
||||
var markup_1 = require("./markup");
|
||||
Object.defineProperty(exports, "Markup", { enumerable: true, get: function () { return markup_1.Markup; } });
|
||||
1240
node_modules/telegraf/lib/telegram.js
generated
vendored
Normal file
1240
node_modules/telegraf/lib/telegram.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
node_modules/telegraf/lib/types.js
generated
vendored
Normal file
2
node_modules/telegraf/lib/types.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
5
node_modules/telegraf/lib/utils.js
generated
vendored
Normal file
5
node_modules/telegraf/lib/utils.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.argsParser = void 0;
|
||||
var args_1 = require("./core/helpers/args");
|
||||
Object.defineProperty(exports, "argsParser", { enumerable: true, get: function () { return args_1.argsParser; } });
|
||||
1
node_modules/telegraf/markup.d.ts
generated
vendored
Normal file
1
node_modules/telegraf/markup.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './typings/markup'
|
||||
1
node_modules/telegraf/markup.js
generated
vendored
Normal file
1
node_modules/telegraf/markup.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./lib/markup')
|
||||
134
node_modules/telegraf/package.json
generated
vendored
Normal file
134
node_modules/telegraf/package.json
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"name": "telegraf",
|
||||
"version": "4.16.3",
|
||||
"description": "Modern Telegram Bot Framework",
|
||||
"license": "MIT",
|
||||
"author": "The Telegraf Contributors",
|
||||
"homepage": "https://telegraf.js.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+ssh://git@github.com/telegraf/telegraf.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/telegraf/telegraf/issues"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./typings/index.d.ts",
|
||||
"default": "./lib/index.js"
|
||||
},
|
||||
"./filters": {
|
||||
"types": "./filters.d.ts",
|
||||
"default": "./filters.js"
|
||||
},
|
||||
"./future": {
|
||||
"types": "./future.d.ts",
|
||||
"default": "./future.js"
|
||||
},
|
||||
"./scenes": {
|
||||
"types": "./scenes.d.ts",
|
||||
"default": "./scenes.js"
|
||||
},
|
||||
"./types": {
|
||||
"types": "./types.d.ts",
|
||||
"default": "./types.js"
|
||||
},
|
||||
"./format": {
|
||||
"types": "./format.d.ts",
|
||||
"default": "./format.js"
|
||||
},
|
||||
"./utils": {
|
||||
"types": "./utils.d.ts",
|
||||
"default": "./utils.js"
|
||||
},
|
||||
"./markup": {
|
||||
"types": "./markup.d.ts",
|
||||
"default": "./markup.js"
|
||||
},
|
||||
"./session": {
|
||||
"types": "./session.d.ts",
|
||||
"default": "./session.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"bin/*",
|
||||
"src/**/*.ts",
|
||||
"lib/**/*.js",
|
||||
"typings/**/*.d.ts",
|
||||
"typings/**/*.d.ts.map",
|
||||
"types.*",
|
||||
"format.*",
|
||||
"filters.*",
|
||||
"future.*",
|
||||
"scenes.*",
|
||||
"utils.*",
|
||||
"markup.*",
|
||||
"session.*"
|
||||
],
|
||||
"bin": {
|
||||
"telegraf": "lib/cli.mjs"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "npm run --silent build",
|
||||
"build": "tsc && npm run expose",
|
||||
"expose": "tsx build/expose.ts types scenes filters format future utils markup session",
|
||||
"build:docs": "typedoc src/index.ts",
|
||||
"pretest": "npm run build",
|
||||
"test": "ava",
|
||||
"lint": "eslint .",
|
||||
"checks": "npm test && npm run lint",
|
||||
"refresh": "npm run clean && npm ci",
|
||||
"clean": "git clean -fX .eslintcache docs/build/ lib/ typings/"
|
||||
},
|
||||
"ava": {
|
||||
"files": [
|
||||
"test/*",
|
||||
"!test/_*"
|
||||
]
|
||||
},
|
||||
"type": "commonjs",
|
||||
"engines": {
|
||||
"node": "^12.20.0 || >=14.13.1"
|
||||
},
|
||||
"types": "./typings/index.d.ts",
|
||||
"dependencies": {
|
||||
"@telegraf/types": "^7.1.0",
|
||||
"abort-controller": "^3.0.0",
|
||||
"debug": "^4.3.4",
|
||||
"mri": "^1.2.0",
|
||||
"node-fetch": "^2.7.0",
|
||||
"p-timeout": "^4.1.0",
|
||||
"safe-compare": "^1.1.4",
|
||||
"sandwich-stream": "^2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/debug": "^4.1.8",
|
||||
"@types/node": "^20.4.2",
|
||||
"@types/node-fetch": "^2.6.2",
|
||||
"@types/safe-compare": "^1.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.1.0",
|
||||
"@typescript-eslint/parser": "^6.1.0",
|
||||
"ava": "^5.3.1",
|
||||
"eslint": "^8.45.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-ava": "^14.0.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"fast-check": "^3.12.0",
|
||||
"prettier": "^3.0.3",
|
||||
"tsx": "^4.7.1",
|
||||
"typedoc": "^0.25.0",
|
||||
"typescript": "^5.2.2"
|
||||
},
|
||||
"keywords": [
|
||||
"telegraf",
|
||||
"telegram",
|
||||
"telegram bot api",
|
||||
"bot",
|
||||
"botapi",
|
||||
"bot framework"
|
||||
]
|
||||
}
|
||||
1
node_modules/telegraf/scenes.d.ts
generated
vendored
Normal file
1
node_modules/telegraf/scenes.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './typings/scenes'
|
||||
1
node_modules/telegraf/scenes.js
generated
vendored
Normal file
1
node_modules/telegraf/scenes.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./lib/scenes')
|
||||
1
node_modules/telegraf/session.d.ts
generated
vendored
Normal file
1
node_modules/telegraf/session.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './typings/session'
|
||||
1
node_modules/telegraf/session.js
generated
vendored
Normal file
1
node_modules/telegraf/session.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./lib/session')
|
||||
182
node_modules/telegraf/src/button.ts
generated
vendored
Normal file
182
node_modules/telegraf/src/button.ts
generated
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
import {
|
||||
InlineKeyboardButton,
|
||||
KeyboardButton,
|
||||
KeyboardButtonRequestChat,
|
||||
KeyboardButtonRequestUsers,
|
||||
} from './core/types/typegram'
|
||||
|
||||
type Hideable<B> = B & { hide: boolean }
|
||||
|
||||
export function text(
|
||||
text: string,
|
||||
hide = false
|
||||
): Hideable<KeyboardButton.CommonButton> {
|
||||
return { text, hide }
|
||||
}
|
||||
|
||||
export function contactRequest(
|
||||
text: string,
|
||||
hide = false
|
||||
): Hideable<KeyboardButton.RequestContactButton> {
|
||||
return { text, request_contact: true, hide }
|
||||
}
|
||||
|
||||
export function locationRequest(
|
||||
text: string,
|
||||
hide = false
|
||||
): Hideable<KeyboardButton.RequestLocationButton> {
|
||||
return { text, request_location: true, hide }
|
||||
}
|
||||
|
||||
export function pollRequest(
|
||||
text: string,
|
||||
type?: 'quiz' | 'regular',
|
||||
hide = false
|
||||
): Hideable<KeyboardButton.RequestPollButton> {
|
||||
return { text, request_poll: { type }, hide }
|
||||
}
|
||||
|
||||
export function userRequest(
|
||||
text: string,
|
||||
/** Must fit in a signed 32 bit int */
|
||||
request_id: number,
|
||||
extra?: Omit<KeyboardButtonRequestUsers, 'request_id' | 'text'>,
|
||||
hide = false
|
||||
): Hideable<KeyboardButton.RequestUsersButton> {
|
||||
return {
|
||||
text,
|
||||
request_users: { request_id, ...extra },
|
||||
hide,
|
||||
}
|
||||
}
|
||||
|
||||
export function botRequest(
|
||||
text: string,
|
||||
/** Must fit in a signed 32 bit int */
|
||||
request_id: number,
|
||||
extra?: Omit<
|
||||
KeyboardButtonRequestUsers,
|
||||
'request_id' | 'user_is_bot' | 'text'
|
||||
>,
|
||||
hide = false
|
||||
): Hideable<KeyboardButton.RequestUsersButton> {
|
||||
return {
|
||||
text,
|
||||
request_users: { request_id, user_is_bot: true, ...extra },
|
||||
hide,
|
||||
}
|
||||
}
|
||||
|
||||
type KeyboardButtonRequestGroup = Omit<
|
||||
KeyboardButtonRequestChat,
|
||||
'request_id' | 'chat_is_channel'
|
||||
>
|
||||
|
||||
export function groupRequest(
|
||||
text: string,
|
||||
/** Must fit in a signed 32 bit int */
|
||||
request_id: number,
|
||||
extra?: KeyboardButtonRequestGroup,
|
||||
hide = false
|
||||
): Hideable<KeyboardButton.RequestChatButton> {
|
||||
return {
|
||||
text,
|
||||
request_chat: { request_id, chat_is_channel: false, ...extra },
|
||||
hide,
|
||||
}
|
||||
}
|
||||
|
||||
type KeyboardButtonRequestChannel = Omit<
|
||||
KeyboardButtonRequestChat,
|
||||
'request_id' | 'chat_is_channel' | 'chat_is_forum'
|
||||
>
|
||||
|
||||
export function channelRequest(
|
||||
text: string,
|
||||
/** Must fit in a signed 32 bit int */
|
||||
request_id: number,
|
||||
extra?: KeyboardButtonRequestChannel,
|
||||
hide = false
|
||||
): Hideable<KeyboardButton.RequestChatButton> {
|
||||
return {
|
||||
text,
|
||||
request_chat: { request_id, chat_is_channel: true, ...extra },
|
||||
hide,
|
||||
}
|
||||
}
|
||||
|
||||
export function url(
|
||||
text: string,
|
||||
url: string,
|
||||
hide = false
|
||||
): Hideable<InlineKeyboardButton.UrlButton> {
|
||||
return { text, url, hide }
|
||||
}
|
||||
|
||||
export function callback(
|
||||
text: string,
|
||||
data: string,
|
||||
hide = false
|
||||
): Hideable<InlineKeyboardButton.CallbackButton> {
|
||||
return { text, callback_data: data, hide }
|
||||
}
|
||||
|
||||
export function switchToChat(
|
||||
text: string,
|
||||
value: string,
|
||||
hide = false
|
||||
): Hideable<InlineKeyboardButton.SwitchInlineButton> {
|
||||
return { text, switch_inline_query: value, hide }
|
||||
}
|
||||
|
||||
export function switchToCurrentChat(
|
||||
text: string,
|
||||
value: string,
|
||||
hide = false
|
||||
): Hideable<InlineKeyboardButton.SwitchInlineCurrentChatButton> {
|
||||
return { text, switch_inline_query_current_chat: value, hide }
|
||||
}
|
||||
|
||||
export function game(
|
||||
text: string,
|
||||
hide = false
|
||||
): Hideable<InlineKeyboardButton.GameButton> {
|
||||
return { text, callback_game: {}, hide }
|
||||
}
|
||||
|
||||
export function pay(
|
||||
text: string,
|
||||
hide = false
|
||||
): Hideable<InlineKeyboardButton.PayButton> {
|
||||
return { text, pay: true, hide }
|
||||
}
|
||||
|
||||
export function login(
|
||||
text: string,
|
||||
url: string,
|
||||
opts: {
|
||||
forward_text?: string
|
||||
bot_username?: string
|
||||
request_write_access?: boolean
|
||||
} = {},
|
||||
hide = false
|
||||
): Hideable<InlineKeyboardButton.LoginButton> {
|
||||
return {
|
||||
text,
|
||||
login_url: { ...opts, url },
|
||||
hide,
|
||||
}
|
||||
}
|
||||
|
||||
export function webApp(
|
||||
text: string,
|
||||
url: string,
|
||||
hide = false
|
||||
// works as both InlineKeyboardButton and KeyboardButton
|
||||
): Hideable<InlineKeyboardButton.WebAppButton> {
|
||||
return {
|
||||
text,
|
||||
web_app: { url },
|
||||
hide,
|
||||
}
|
||||
}
|
||||
1008
node_modules/telegraf/src/composer.ts
generated
vendored
Normal file
1008
node_modules/telegraf/src/composer.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1663
node_modules/telegraf/src/context.ts
generated
vendored
Normal file
1663
node_modules/telegraf/src/context.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
63
node_modules/telegraf/src/core/helpers/args.ts
generated
vendored
Normal file
63
node_modules/telegraf/src/core/helpers/args.ts
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
interface Entity {
|
||||
/** Type of the entity. Currently, can be “mention” (@username), “hashtag” (#hashtag), “cashtag” ($USD), “bot_command” (/start@jobs_bot), “url” (https://telegram.org), “email” (do-not-reply@telegram.org), “phone_number” (+1-212-555-0123), “bold” (bold text), “italic” (italic text), “underline” (underlined text), “strikethrough” (strikethrough text), “spoiler” (spoiler message), “code” (monowidth string), “pre” (monowidth block), “text_link” (for clickable text URLs), “text_mention” (for users without usernames), “custom_emoji” (for inline custom emoji stickers) */
|
||||
type: string
|
||||
/** Offset in UTF-16 code units to the start of the entity */
|
||||
offset: number
|
||||
/** Length of the entity in UTF-16 code units */
|
||||
length: number
|
||||
}
|
||||
|
||||
const SINGLE_QUOTE = "'"
|
||||
const DOUBLE_QUOTE = '"'
|
||||
|
||||
export function argsParser(
|
||||
str: string,
|
||||
entities: Entity[] = [],
|
||||
entityOffset = 0
|
||||
) {
|
||||
const mentions: { [offset: string]: number } = {}
|
||||
for (const entity of entities) // extract all text_mentions into an { offset: length } map
|
||||
if (entity.type === 'text_mention' || entity.type === 'text_link')
|
||||
mentions[entity.offset - entityOffset] = entity.length
|
||||
|
||||
const args: string[] = []
|
||||
let done = 0
|
||||
let inside: `'` | `"` | undefined = undefined
|
||||
let buf = ''
|
||||
|
||||
function flush(to: number) {
|
||||
if (done !== to) args.push(buf + str.slice(done, to)), (inside = undefined)
|
||||
buf = ''
|
||||
done = to + 1
|
||||
}
|
||||
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const char = str[i]
|
||||
// quick lookup length of mention starting at i
|
||||
const mention = mentions[i]
|
||||
if (mention) {
|
||||
// if we're inside a quote, eagerly flush existing state
|
||||
flush(i)
|
||||
// this also consumes current index, so decrement
|
||||
done--
|
||||
// fast forward to end of mention
|
||||
i += mention
|
||||
flush(i)
|
||||
} else if (char === SINGLE_QUOTE || char === DOUBLE_QUOTE)
|
||||
if (inside)
|
||||
if (inside === char) flush(i)
|
||||
else continue
|
||||
else flush(i), (inside = char)
|
||||
else if (char === ' ')
|
||||
if (inside) continue
|
||||
else flush(i)
|
||||
else if (char === '\n') flush(i)
|
||||
else if (char === '\\')
|
||||
(buf += str.slice(done, i)), (done = ++i) // skip parsing the next char
|
||||
else continue
|
||||
}
|
||||
|
||||
if (done < str.length) flush(str.length)
|
||||
|
||||
return args
|
||||
}
|
||||
71
node_modules/telegraf/src/core/helpers/check.ts
generated
vendored
Normal file
71
node_modules/telegraf/src/core/helpers/check.ts
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
interface Mapping {
|
||||
string: string
|
||||
number: number
|
||||
bigint: bigint
|
||||
boolean: boolean
|
||||
symbol: symbol
|
||||
undefined: undefined
|
||||
object: Record<string, unknown>
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function: (...props: any[]) => any
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given object has a property with a given name.
|
||||
*
|
||||
* Example invocation:
|
||||
* ```js
|
||||
* let obj = { 'foo': 'bar', 'baz': () => {} }
|
||||
* hasProp(obj, 'foo') // true
|
||||
* hasProp(obj, 'baz') // true
|
||||
* hasProp(obj, 'abc') // false
|
||||
* ```
|
||||
*
|
||||
* @param obj An object to test
|
||||
* @param prop The name of the property
|
||||
*/
|
||||
export function hasProp<O extends object, K extends PropertyKey>(
|
||||
obj: O | undefined,
|
||||
prop: K
|
||||
): obj is O & Record<K, unknown> {
|
||||
return obj !== undefined && prop in obj
|
||||
}
|
||||
/**
|
||||
* Checks if a given object has a property with a given name.
|
||||
* Furthermore performs a `typeof` check on the property if it exists.
|
||||
*
|
||||
* Example invocation:
|
||||
* ```js
|
||||
* let obj = { 'foo': 'bar', 'baz': () => {} }
|
||||
* hasPropType(obj, 'foo', 'string') // true
|
||||
* hasPropType(obj, 'baz', 'function') // true
|
||||
* hasPropType(obj, 'abc', 'number') // false
|
||||
* ```
|
||||
*
|
||||
* @param obj An object to test
|
||||
* @param prop The name of the property
|
||||
* @param type The type the property is expected to have
|
||||
*/
|
||||
export function hasPropType<
|
||||
O extends object,
|
||||
K extends PropertyKey,
|
||||
T extends keyof Mapping,
|
||||
V extends Mapping[T],
|
||||
>(obj: O | undefined, prop: K, type: T): obj is O & Record<K, V> {
|
||||
return hasProp(obj, prop) && type === typeof obj[prop]
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the supplied array has two dimensions or not.
|
||||
*
|
||||
* Example invocations:
|
||||
* is2D([]) // false
|
||||
* is2D([[]]) // true
|
||||
* is2D([[], []]) // true
|
||||
* is2D([42]) // false
|
||||
*
|
||||
* @param arr an array with one or two dimensions
|
||||
*/
|
||||
export function is2D<E>(arr: E[] | E[][]): arr is E[][] {
|
||||
return Array.isArray(arr[0])
|
||||
}
|
||||
18
node_modules/telegraf/src/core/helpers/compact.ts
generated
vendored
Normal file
18
node_modules/telegraf/src/core/helpers/compact.ts
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
export function compactOptions<T extends { [key: string]: unknown }>(
|
||||
options?: T
|
||||
): T | undefined {
|
||||
if (!options) {
|
||||
return options
|
||||
}
|
||||
|
||||
const compacted: Partial<T> = {}
|
||||
for (const key in options)
|
||||
if (
|
||||
// todo(mkr): replace with Object.hasOwn in v5 (Node 16+)
|
||||
Object.prototype.hasOwnProperty.call(options, key) &&
|
||||
options[key] !== undefined
|
||||
)
|
||||
compacted[key] = options[key]
|
||||
|
||||
return compacted as T | undefined
|
||||
}
|
||||
26
node_modules/telegraf/src/core/helpers/deunionize.ts
generated
vendored
Normal file
26
node_modules/telegraf/src/core/helpers/deunionize.ts
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
export type PropOr<
|
||||
T extends object | undefined,
|
||||
P extends string | symbol | number,
|
||||
D = undefined,
|
||||
> = T extends Partial<Record<P, unknown>> ? T[P] : D
|
||||
|
||||
export type UnionKeys<T> = T extends unknown ? keyof T : never
|
||||
|
||||
type AddOptionalKeys<K extends PropertyKey> = { readonly [P in K]?: never }
|
||||
|
||||
/**
|
||||
* @see https://millsp.github.io/ts-toolbelt/modules/union_strict.html
|
||||
*/
|
||||
export type Deunionize<B extends object | undefined, T = B> = T extends object
|
||||
? T & AddOptionalKeys<Exclude<UnionKeys<B>, keyof T>>
|
||||
: T
|
||||
|
||||
/**
|
||||
* Expose properties from all union variants.
|
||||
* @deprectated
|
||||
* @see https://github.com/telegraf/telegraf/issues/1388#issuecomment-791573609
|
||||
* @see https://millsp.github.io/ts-toolbelt/modules/union_strict.html
|
||||
*/
|
||||
export function deunionize<T extends object | undefined>(t: T) {
|
||||
return t as Deunionize<T>
|
||||
}
|
||||
119
node_modules/telegraf/src/core/helpers/formatting.ts
generated
vendored
Normal file
119
node_modules/telegraf/src/core/helpers/formatting.ts
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
|
||||
import { MessageEntity, User } from '@telegraf/types'
|
||||
import { Any, zip } from './util'
|
||||
|
||||
export type Nestable<Kind extends string> =
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| FmtString<Kind>
|
||||
export type MaybeNestableList<Kind extends string> =
|
||||
| Nestable<Kind>
|
||||
| readonly Nestable<Kind>[]
|
||||
|
||||
export interface FmtString<Brand extends string> {
|
||||
text: string
|
||||
entities?: MessageEntity[]
|
||||
parse_mode?: undefined
|
||||
__to_nest: Brand
|
||||
}
|
||||
|
||||
export class FmtString<Brand extends string = string>
|
||||
implements FmtString<Brand>
|
||||
{
|
||||
constructor(
|
||||
public text: string,
|
||||
entities?: MessageEntity[]
|
||||
) {
|
||||
if (entities) {
|
||||
this.entities = entities
|
||||
// force parse_mode to undefined if entities are present
|
||||
this.parse_mode = undefined
|
||||
}
|
||||
}
|
||||
static normalise(content: Nestable<string>) {
|
||||
if (content instanceof FmtString) return content
|
||||
return new FmtString(String(content))
|
||||
}
|
||||
}
|
||||
|
||||
const isArray: <T>(xs: T | readonly T[]) => xs is readonly T[] = Array.isArray
|
||||
|
||||
/** Given a base FmtString and something to append to it, mutates the base */
|
||||
const _add = (base: FmtString, next: FmtString | Any) => {
|
||||
const len = base.text.length
|
||||
if (next instanceof FmtString) {
|
||||
base.text = `${base.text}${next.text}`
|
||||
// next.entities could be undefined and condition will fail
|
||||
for (let i = 0; i < (next.entities?.length || 0); i++) {
|
||||
// because of the above condition, next.entities[i] cannot be undefined
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const entity = next.entities![i]!
|
||||
// base.entities is ensured by caller
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
base.entities!.push({ ...entity, offset: entity.offset + len })
|
||||
}
|
||||
} else base.text = `${base.text}${next}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an `Iterable<FmtString | string | Any>` and a separator, flattens the list into a single FmtString.
|
||||
* Analogous to Array#join -> string, but for FmtString
|
||||
*/
|
||||
export const join = (
|
||||
fragments: Iterable<FmtString | string | Any>,
|
||||
separator?: string | FmtString
|
||||
) => {
|
||||
const result = new FmtString('')
|
||||
// ensure entities array so loop doesn't need to check
|
||||
result.entities = []
|
||||
|
||||
const iter = fragments[Symbol.iterator]()
|
||||
|
||||
let curr = iter.next()
|
||||
while (!curr.done) {
|
||||
_add(result, curr.value)
|
||||
curr = iter.next()
|
||||
if (separator && !curr.done) _add(result, separator)
|
||||
}
|
||||
|
||||
// set parse_mode: undefined if entities are present
|
||||
if (result.entities.length) result.parse_mode = undefined
|
||||
// remove entities array if not relevant
|
||||
else delete result.entities
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/** Internal constructor for all fmt helpers */
|
||||
export function createFmt(kind?: MessageEntity['type'], opts?: object) {
|
||||
return function fmt(
|
||||
parts: MaybeNestableList<string>,
|
||||
...items: Nestable<string>[]
|
||||
) {
|
||||
parts = isArray(parts) ? parts : [parts]
|
||||
const result = join(zip(parts, items))
|
||||
if (kind) {
|
||||
result.entities ??= []
|
||||
result.entities.unshift({
|
||||
type: kind,
|
||||
offset: 0,
|
||||
length: result.text.length,
|
||||
...opts,
|
||||
} as MessageEntity)
|
||||
result.parse_mode = undefined
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
export const linkOrMention = (
|
||||
content: Nestable<string>,
|
||||
data:
|
||||
| { type: 'text_link'; url: string }
|
||||
| { type: 'text_mention'; user: User }
|
||||
) => {
|
||||
const { text, entities = [] } = FmtString.normalise(content)
|
||||
entities.unshift(Object.assign(data, { offset: 0, length: text.length }))
|
||||
return new FmtString(text, entities)
|
||||
}
|
||||
96
node_modules/telegraf/src/core/helpers/util.ts
generated
vendored
Normal file
96
node_modules/telegraf/src/core/helpers/util.ts
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
import { FmtString } from './formatting'
|
||||
import { Deunionize, UnionKeys } from './deunionize'
|
||||
|
||||
export const env = process.env
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export type Any = {} | undefined | null
|
||||
|
||||
export type Expand<T> = T extends object
|
||||
? T extends infer O
|
||||
? { [K in keyof O]: O[K] }
|
||||
: never
|
||||
: T
|
||||
|
||||
export type MaybeArray<T> = T | T[]
|
||||
export type MaybePromise<T> = T | Promise<T>
|
||||
export type NonemptyReadonlyArray<T> = readonly [T, ...T[]]
|
||||
|
||||
// prettier-ignore
|
||||
export type ExclusiveKeys<A extends object, B extends object> = keyof Omit<A, keyof B>
|
||||
|
||||
export function fmtCaption<
|
||||
Extra extends { caption?: string | FmtString } | undefined,
|
||||
>(
|
||||
extra?: Extra
|
||||
): Extra extends undefined
|
||||
? undefined
|
||||
: Omit<Extra, 'caption'> & { caption?: string }
|
||||
|
||||
export function fmtCaption(extra?: { caption?: string | FmtString }) {
|
||||
if (!extra) return
|
||||
const caption = extra.caption
|
||||
if (!caption || typeof caption === 'string') return extra
|
||||
const { text, entities } = caption
|
||||
return {
|
||||
...extra,
|
||||
caption: text,
|
||||
...(entities && {
|
||||
caption_entities: entities,
|
||||
parse_mode: undefined,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
export type DistinctKeys<T extends object> = Exclude<UnionKeys<T>, keyof T>
|
||||
|
||||
// prettier-ignore
|
||||
/* eslint-disable-next-line @typescript-eslint/ban-types */
|
||||
export type KeyedDistinct<T extends object, K extends DistinctKeys<T>> = Record<K, {}> & Deunionize<Record<K, {}>, T>
|
||||
|
||||
// prettier-ignore
|
||||
/* eslint-disable-next-line @typescript-eslint/ban-types */
|
||||
export type Keyed<T extends object, K extends UnionKeys<T>> = Record<K, {}> & Deunionize<Record<K, {}>, T>
|
||||
|
||||
/** Construct a generic type guard */
|
||||
export type Guard<X = unknown, Y extends X = X> = (x: X) => x is Y
|
||||
|
||||
/** Extract the guarded type from a type guard, defaults to never. */
|
||||
export type Guarded<F> =
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
F extends (x: any) => x is infer T ? T : never
|
||||
|
||||
export function* zip<X, Y>(xs: Iterable<X>, ys: Iterable<Y>): Iterable<X | Y> {
|
||||
const x = xs[Symbol.iterator]()
|
||||
const y = ys[Symbol.iterator]()
|
||||
let x1 = x.next()
|
||||
let y1 = y.next()
|
||||
|
||||
while (!x1.done) {
|
||||
yield x1.value
|
||||
if (!y1.done) yield y1.value
|
||||
x1 = x.next()
|
||||
y1 = y.next()
|
||||
}
|
||||
|
||||
while (!y1.done) {
|
||||
yield y1.value
|
||||
y1 = y.next()
|
||||
}
|
||||
}
|
||||
|
||||
export function indexed<T extends object, U>(
|
||||
target: T,
|
||||
indexer: (index: number) => U
|
||||
) {
|
||||
return new Proxy(target, {
|
||||
get: function (target, prop, receiver) {
|
||||
if (
|
||||
(typeof prop === 'string' || typeof prop === 'number') &&
|
||||
!isNaN(+prop)
|
||||
)
|
||||
return indexer.call(target, +prop)
|
||||
return Reflect.get(target, prop, receiver)
|
||||
},
|
||||
})
|
||||
}
|
||||
396
node_modules/telegraf/src/core/network/client.ts
generated
vendored
Normal file
396
node_modules/telegraf/src/core/network/client.ts
generated
vendored
Normal file
@@ -0,0 +1,396 @@
|
||||
/* eslint @typescript-eslint/restrict-template-expressions: [ "error", { "allowNumber": true, "allowBoolean": true } ] */
|
||||
import * as crypto from 'crypto'
|
||||
import * as fs from 'fs'
|
||||
import { stat, realpath } from 'fs/promises'
|
||||
import * as http from 'http'
|
||||
import * as https from 'https'
|
||||
import * as path from 'path'
|
||||
import fetch, { RequestInit } from 'node-fetch'
|
||||
import { hasProp, hasPropType } from '../helpers/check'
|
||||
import { InputFile, Opts, Telegram } from '../types/typegram'
|
||||
import { AbortSignal } from 'abort-controller'
|
||||
import { compactOptions } from '../helpers/compact'
|
||||
import MultipartStream from './multipart-stream'
|
||||
import TelegramError from './error'
|
||||
import { URL } from 'url'
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const debug = require('debug')('telegraf:client')
|
||||
const { isStream } = MultipartStream
|
||||
|
||||
const WEBHOOK_REPLY_METHOD_ALLOWLIST = new Set<keyof Telegram>([
|
||||
'answerCallbackQuery',
|
||||
'answerInlineQuery',
|
||||
'deleteMessage',
|
||||
'leaveChat',
|
||||
'sendChatAction',
|
||||
])
|
||||
|
||||
namespace ApiClient {
|
||||
export type Agent = http.Agent | ((parsedUrl: URL) => http.Agent) | undefined
|
||||
export interface Options {
|
||||
/**
|
||||
* Agent for communicating with the bot API.
|
||||
*/
|
||||
agent?: http.Agent
|
||||
/**
|
||||
* Agent for attaching files via URL.
|
||||
* 1. Not all agents support both `http:` and `https:`.
|
||||
* 2. When passing a function, create the agents once, outside of the function.
|
||||
* Creating new agent every request probably breaks `keepAlive`.
|
||||
*/
|
||||
attachmentAgent?: Agent
|
||||
apiRoot: string
|
||||
/**
|
||||
* @default 'bot'
|
||||
* @see https://github.com/tdlight-team/tdlight-telegram-bot-api#user-mode
|
||||
*/
|
||||
apiMode: 'bot' | 'user'
|
||||
webhookReply: boolean
|
||||
testEnv: boolean
|
||||
}
|
||||
|
||||
export interface CallApiOptions {
|
||||
signal?: AbortSignal
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_EXTENSIONS: Record<string, string | undefined> = {
|
||||
audio: 'mp3',
|
||||
photo: 'jpg',
|
||||
sticker: 'webp',
|
||||
video: 'mp4',
|
||||
animation: 'mp4',
|
||||
video_note: 'mp4',
|
||||
voice: 'ogg',
|
||||
}
|
||||
|
||||
const DEFAULT_OPTIONS: ApiClient.Options = {
|
||||
apiRoot: 'https://api.telegram.org',
|
||||
apiMode: 'bot',
|
||||
webhookReply: true,
|
||||
agent: new https.Agent({
|
||||
keepAlive: true,
|
||||
keepAliveMsecs: 10000,
|
||||
}),
|
||||
attachmentAgent: undefined,
|
||||
testEnv: false,
|
||||
}
|
||||
|
||||
function includesMedia(payload: Record<string, unknown>) {
|
||||
return Object.entries(payload).some(([key, value]) => {
|
||||
if (key === 'link_preview_options') return false
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
return value.some(
|
||||
({ media }) =>
|
||||
media && typeof media === 'object' && (media.source || media.url)
|
||||
)
|
||||
}
|
||||
return (
|
||||
value &&
|
||||
typeof value === 'object' &&
|
||||
((hasProp(value, 'source') && value.source) ||
|
||||
(hasProp(value, 'url') && value.url) ||
|
||||
(hasPropType(value, 'media', 'object') &&
|
||||
((hasProp(value.media, 'source') && value.media.source) ||
|
||||
(hasProp(value.media, 'url') && value.media.url))))
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function replacer(_: unknown, value: unknown) {
|
||||
if (value == null) return undefined
|
||||
return value
|
||||
}
|
||||
|
||||
function buildJSONConfig(payload: unknown): Promise<RequestInit> {
|
||||
return Promise.resolve({
|
||||
method: 'POST',
|
||||
compress: true,
|
||||
headers: { 'content-type': 'application/json', connection: 'keep-alive' },
|
||||
body: JSON.stringify(payload, replacer),
|
||||
})
|
||||
}
|
||||
|
||||
const FORM_DATA_JSON_FIELDS = [
|
||||
'results',
|
||||
'reply_markup',
|
||||
'mask_position',
|
||||
'shipping_options',
|
||||
'errors',
|
||||
] as const
|
||||
|
||||
async function buildFormDataConfig(
|
||||
payload: Opts<keyof Telegram>,
|
||||
agent: ApiClient.Agent
|
||||
) {
|
||||
for (const field of FORM_DATA_JSON_FIELDS) {
|
||||
if (hasProp(payload, field) && typeof payload[field] !== 'string') {
|
||||
payload[field] = JSON.stringify(payload[field])
|
||||
}
|
||||
}
|
||||
const boundary = crypto.randomBytes(32).toString('hex')
|
||||
const formData = new MultipartStream(boundary)
|
||||
await Promise.all(
|
||||
Object.keys(payload).map((key) =>
|
||||
// @ts-expect-error payload[key] can obviously index payload, but TS doesn't trust us
|
||||
attachFormValue(formData, key, payload[key], agent)
|
||||
)
|
||||
)
|
||||
return {
|
||||
method: 'POST',
|
||||
compress: true,
|
||||
headers: {
|
||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
||||
connection: 'keep-alive',
|
||||
},
|
||||
body: formData,
|
||||
}
|
||||
}
|
||||
|
||||
async function attachFormValue(
|
||||
form: MultipartStream,
|
||||
id: string,
|
||||
value: unknown,
|
||||
agent: ApiClient.Agent
|
||||
) {
|
||||
if (value == null) {
|
||||
return
|
||||
}
|
||||
if (
|
||||
typeof value === 'string' ||
|
||||
typeof value === 'boolean' ||
|
||||
typeof value === 'number'
|
||||
) {
|
||||
form.addPart({
|
||||
headers: { 'content-disposition': `form-data; name="${id}"` },
|
||||
body: `${value}`,
|
||||
})
|
||||
return
|
||||
}
|
||||
if (id === 'thumb' || id === 'thumbnail') {
|
||||
const attachmentId = crypto.randomBytes(16).toString('hex')
|
||||
await attachFormMedia(form, value as InputFile, attachmentId, agent)
|
||||
return form.addPart({
|
||||
headers: { 'content-disposition': `form-data; name="${id}"` },
|
||||
body: `attach://${attachmentId}`,
|
||||
})
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
const items = await Promise.all(
|
||||
value.map(async (item) => {
|
||||
if (typeof item.media !== 'object') {
|
||||
return await Promise.resolve(item)
|
||||
}
|
||||
const attachmentId = crypto.randomBytes(16).toString('hex')
|
||||
await attachFormMedia(form, item.media, attachmentId, agent)
|
||||
const thumb = item.thumb ?? item.thumbnail
|
||||
if (typeof thumb === 'object') {
|
||||
const thumbAttachmentId = crypto.randomBytes(16).toString('hex')
|
||||
await attachFormMedia(form, thumb, thumbAttachmentId, agent)
|
||||
return {
|
||||
...item,
|
||||
media: `attach://${attachmentId}`,
|
||||
thumbnail: `attach://${thumbAttachmentId}`,
|
||||
}
|
||||
}
|
||||
return { ...item, media: `attach://${attachmentId}` }
|
||||
})
|
||||
)
|
||||
return form.addPart({
|
||||
headers: { 'content-disposition': `form-data; name="${id}"` },
|
||||
body: JSON.stringify(items),
|
||||
})
|
||||
}
|
||||
if (
|
||||
value &&
|
||||
typeof value === 'object' &&
|
||||
hasProp(value, 'media') &&
|
||||
hasProp(value, 'type') &&
|
||||
typeof value.media !== 'undefined' &&
|
||||
typeof value.type !== 'undefined'
|
||||
) {
|
||||
const attachmentId = crypto.randomBytes(16).toString('hex')
|
||||
await attachFormMedia(form, value.media as InputFile, attachmentId, agent)
|
||||
return form.addPart({
|
||||
headers: { 'content-disposition': `form-data; name="${id}"` },
|
||||
body: JSON.stringify({
|
||||
...value,
|
||||
media: `attach://${attachmentId}`,
|
||||
}),
|
||||
})
|
||||
}
|
||||
return await attachFormMedia(form, value as InputFile, id, agent)
|
||||
}
|
||||
|
||||
async function attachFormMedia(
|
||||
form: MultipartStream,
|
||||
media: InputFile,
|
||||
id: string,
|
||||
agent: ApiClient.Agent
|
||||
) {
|
||||
let fileName = media.filename ?? `${id}.${DEFAULT_EXTENSIONS[id] ?? 'dat'}`
|
||||
if ('url' in media && media.url !== undefined) {
|
||||
const timeout = 500_000 // ms
|
||||
const res = await fetch(media.url, { agent, timeout })
|
||||
return form.addPart({
|
||||
headers: {
|
||||
'content-disposition': `form-data; name="${id}"; filename="${fileName}"`,
|
||||
},
|
||||
body: res.body,
|
||||
})
|
||||
}
|
||||
if ('source' in media && media.source) {
|
||||
let mediaSource = media.source
|
||||
if (typeof media.source === 'string') {
|
||||
const source = await realpath(media.source)
|
||||
if ((await stat(source)).isFile()) {
|
||||
fileName = media.filename ?? path.basename(media.source)
|
||||
mediaSource = await fs.createReadStream(media.source)
|
||||
} else {
|
||||
throw new TypeError(`Unable to upload '${media.source}', not a file`)
|
||||
}
|
||||
}
|
||||
if (isStream(mediaSource) || Buffer.isBuffer(mediaSource)) {
|
||||
form.addPart({
|
||||
headers: {
|
||||
'content-disposition': `form-data; name="${id}"; filename="${fileName}"`,
|
||||
},
|
||||
body: mediaSource,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function answerToWebhook(
|
||||
response: Response,
|
||||
payload: Opts<keyof Telegram>,
|
||||
options: ApiClient.Options
|
||||
): Promise<true> {
|
||||
if (!includesMedia(payload)) {
|
||||
if (!response.headersSent) {
|
||||
response.setHeader('content-type', 'application/json')
|
||||
}
|
||||
response.end(JSON.stringify(payload), 'utf-8')
|
||||
return true
|
||||
}
|
||||
|
||||
const { headers, body } = await buildFormDataConfig(
|
||||
payload,
|
||||
options.attachmentAgent
|
||||
)
|
||||
if (!response.headersSent) {
|
||||
for (const [key, value] of Object.entries(headers)) {
|
||||
response.setHeader(key, value)
|
||||
}
|
||||
}
|
||||
await new Promise((resolve) => {
|
||||
response.on('finish', resolve)
|
||||
body.pipe(response)
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
function redactToken(error: Error): never {
|
||||
error.message = error.message.replace(
|
||||
/\/(bot|user)(\d+):[^/]+\//,
|
||||
'/$1$2:[REDACTED]/'
|
||||
)
|
||||
throw error
|
||||
}
|
||||
|
||||
type Response = http.ServerResponse
|
||||
class ApiClient {
|
||||
readonly options: ApiClient.Options
|
||||
|
||||
constructor(
|
||||
readonly token: string,
|
||||
options?: Partial<ApiClient.Options>,
|
||||
private readonly response?: Response
|
||||
) {
|
||||
this.options = {
|
||||
...DEFAULT_OPTIONS,
|
||||
...compactOptions(options),
|
||||
}
|
||||
if (this.options.apiRoot.startsWith('http://')) {
|
||||
this.options.agent = undefined
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to `true`, first _eligible_ call will avoid performing a POST request.
|
||||
* Note that such a call:
|
||||
* 1. cannot report errors or return meaningful values,
|
||||
* 2. resolves before bot API has a chance to process it,
|
||||
* 3. prematurely confirms the update as processed.
|
||||
*
|
||||
* https://core.telegram.org/bots/faq#how-can-i-make-requests-in-response-to-updates
|
||||
* https://github.com/telegraf/telegraf/pull/1250
|
||||
*/
|
||||
set webhookReply(enable: boolean) {
|
||||
this.options.webhookReply = enable
|
||||
}
|
||||
|
||||
get webhookReply() {
|
||||
return this.options.webhookReply
|
||||
}
|
||||
|
||||
async callApi<M extends keyof Telegram>(
|
||||
method: M,
|
||||
payload: Opts<M>,
|
||||
{ signal }: ApiClient.CallApiOptions = {}
|
||||
): Promise<ReturnType<Telegram[M]>> {
|
||||
const { token, options, response } = this
|
||||
|
||||
if (
|
||||
options.webhookReply &&
|
||||
response?.writableEnded === false &&
|
||||
WEBHOOK_REPLY_METHOD_ALLOWLIST.has(method)
|
||||
) {
|
||||
debug('Call via webhook', method, payload)
|
||||
// @ts-expect-error using webhookReply is an optimisation that doesn't respond with normal result
|
||||
// up to the user to deal with this
|
||||
return await answerToWebhook(response, { method, ...payload }, options)
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
throw new TelegramError({
|
||||
error_code: 401,
|
||||
description: 'Bot Token is required',
|
||||
})
|
||||
}
|
||||
|
||||
debug('HTTP call', method, payload)
|
||||
|
||||
const config: RequestInit = includesMedia(payload)
|
||||
? await buildFormDataConfig(
|
||||
{ method, ...payload },
|
||||
options.attachmentAgent
|
||||
)
|
||||
: await buildJSONConfig(payload)
|
||||
const apiUrl = new URL(
|
||||
`./${options.apiMode}${token}${options.testEnv ? '/test' : ''}/${method}`,
|
||||
options.apiRoot
|
||||
)
|
||||
config.agent = options.agent
|
||||
// @ts-expect-error AbortSignal shim is missing some props from Request.AbortSignal
|
||||
config.signal = signal
|
||||
config.timeout = 500_000 // ms
|
||||
const res = await fetch(apiUrl, config).catch(redactToken)
|
||||
if (res.status >= 500) {
|
||||
const errorPayload = {
|
||||
error_code: res.status,
|
||||
description: res.statusText,
|
||||
}
|
||||
throw new TelegramError(errorPayload, { method, payload })
|
||||
}
|
||||
const data = await res.json()
|
||||
if (!data.ok) {
|
||||
debug('API call failed', data)
|
||||
throw new TelegramError(data, { method, payload })
|
||||
}
|
||||
return data.result
|
||||
}
|
||||
}
|
||||
|
||||
export default ApiClient
|
||||
29
node_modules/telegraf/src/core/network/error.ts
generated
vendored
Normal file
29
node_modules/telegraf/src/core/network/error.ts
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
import { ResponseParameters } from '../types/typegram'
|
||||
|
||||
interface ErrorPayload {
|
||||
error_code: number
|
||||
description: string
|
||||
parameters?: ResponseParameters
|
||||
}
|
||||
export class TelegramError extends Error {
|
||||
constructor(
|
||||
readonly response: ErrorPayload,
|
||||
readonly on = {}
|
||||
) {
|
||||
super(`${response.error_code}: ${response.description}`)
|
||||
}
|
||||
|
||||
get code() {
|
||||
return this.response.error_code
|
||||
}
|
||||
|
||||
get description() {
|
||||
return this.response.description
|
||||
}
|
||||
|
||||
get parameters() {
|
||||
return this.response.parameters
|
||||
}
|
||||
}
|
||||
|
||||
export default TelegramError
|
||||
45
node_modules/telegraf/src/core/network/multipart-stream.ts
generated
vendored
Normal file
45
node_modules/telegraf/src/core/network/multipart-stream.ts
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
import * as stream from 'stream'
|
||||
import { hasPropType } from '../helpers/check'
|
||||
import SandwichStream from 'sandwich-stream'
|
||||
const CRNL = '\r\n'
|
||||
|
||||
interface Part {
|
||||
headers: { [key: string]: string }
|
||||
body: NodeJS.ReadStream | NodeJS.ReadableStream | Buffer | string
|
||||
}
|
||||
|
||||
class MultipartStream extends SandwichStream {
|
||||
constructor(boundary: string) {
|
||||
super({
|
||||
head: `--${boundary}${CRNL}`,
|
||||
tail: `${CRNL}--${boundary}--`,
|
||||
separator: `${CRNL}--${boundary}${CRNL}`,
|
||||
})
|
||||
}
|
||||
|
||||
addPart(part: Part) {
|
||||
const partStream = new stream.PassThrough()
|
||||
for (const [key, header] of Object.entries(part.headers)) {
|
||||
partStream.write(`${key}:${header}${CRNL}`)
|
||||
}
|
||||
partStream.write(CRNL)
|
||||
if (MultipartStream.isStream(part.body)) {
|
||||
part.body.pipe(partStream)
|
||||
} else {
|
||||
partStream.end(part.body)
|
||||
}
|
||||
this.add(partStream)
|
||||
}
|
||||
|
||||
static isStream(
|
||||
stream: unknown
|
||||
): stream is { pipe: MultipartStream['pipe'] } {
|
||||
return (
|
||||
typeof stream === 'object' &&
|
||||
stream !== null &&
|
||||
hasPropType(stream, 'pipe', 'function')
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MultipartStream
|
||||
94
node_modules/telegraf/src/core/network/polling.ts
generated
vendored
Normal file
94
node_modules/telegraf/src/core/network/polling.ts
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
import * as tg from '../types/typegram'
|
||||
import * as tt from '../../telegram-types'
|
||||
import AbortController from 'abort-controller'
|
||||
import ApiClient from './client'
|
||||
import d from 'debug'
|
||||
import { promisify } from 'util'
|
||||
import { TelegramError } from './error'
|
||||
const debug = d('telegraf:polling')
|
||||
const wait = promisify(setTimeout)
|
||||
function always<T>(x: T) {
|
||||
return () => x
|
||||
}
|
||||
const noop = always(Promise.resolve())
|
||||
|
||||
export class Polling {
|
||||
private readonly abortController = new AbortController()
|
||||
private skipOffsetSync = false
|
||||
private offset = 0
|
||||
constructor(
|
||||
private readonly telegram: ApiClient,
|
||||
private readonly allowedUpdates: readonly tt.UpdateType[]
|
||||
) {}
|
||||
|
||||
private async *[Symbol.asyncIterator]() {
|
||||
debug('Starting long polling')
|
||||
do {
|
||||
try {
|
||||
const updates = await this.telegram.callApi(
|
||||
'getUpdates',
|
||||
{
|
||||
timeout: 50,
|
||||
offset: this.offset,
|
||||
allowed_updates: this.allowedUpdates,
|
||||
},
|
||||
this.abortController
|
||||
)
|
||||
const last = updates[updates.length - 1]
|
||||
if (last !== undefined) {
|
||||
this.offset = last.update_id + 1
|
||||
}
|
||||
yield updates
|
||||
} catch (error) {
|
||||
const err = error as Error & {
|
||||
parameters?: { retry_after: number }
|
||||
}
|
||||
|
||||
if (err.name === 'AbortError') return
|
||||
if (
|
||||
err.name === 'FetchError' ||
|
||||
(err instanceof TelegramError && err.code === 429) ||
|
||||
(err instanceof TelegramError && err.code >= 500)
|
||||
) {
|
||||
const retryAfter: number = err.parameters?.retry_after ?? 5
|
||||
debug('Failed to fetch updates, retrying after %ds.', retryAfter, err)
|
||||
await wait(retryAfter * 1000)
|
||||
continue
|
||||
}
|
||||
if (
|
||||
err instanceof TelegramError &&
|
||||
// Unauthorized Conflict
|
||||
(err.code === 401 || err.code === 409)
|
||||
) {
|
||||
this.skipOffsetSync = true
|
||||
throw err
|
||||
}
|
||||
throw err
|
||||
}
|
||||
} while (!this.abortController.signal.aborted)
|
||||
}
|
||||
|
||||
private async syncUpdateOffset() {
|
||||
if (this.skipOffsetSync) return
|
||||
debug('Syncing update offset...')
|
||||
await this.telegram.callApi('getUpdates', { offset: this.offset, limit: 1 })
|
||||
}
|
||||
|
||||
async loop(handleUpdate: (updates: tg.Update) => Promise<void>) {
|
||||
if (this.abortController.signal.aborted)
|
||||
throw new Error('Polling instances must not be reused!')
|
||||
try {
|
||||
for await (const updates of this)
|
||||
await Promise.all(updates.map(handleUpdate))
|
||||
} finally {
|
||||
debug('Long polling stopped')
|
||||
// prevent instance reuse
|
||||
this.stop()
|
||||
await this.syncUpdateOffset().catch(noop)
|
||||
}
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.abortController.abort()
|
||||
}
|
||||
}
|
||||
58
node_modules/telegraf/src/core/network/webhook.ts
generated
vendored
Normal file
58
node_modules/telegraf/src/core/network/webhook.ts
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
import * as http from 'http'
|
||||
import d from 'debug'
|
||||
import { type Update } from '../types/typegram'
|
||||
const debug = d('telegraf:webhook')
|
||||
|
||||
export default function generateWebhook(
|
||||
filter: (req: http.IncomingMessage) => boolean,
|
||||
updateHandler: (update: Update, res: http.ServerResponse) => Promise<void>
|
||||
) {
|
||||
return async (
|
||||
req: http.IncomingMessage & { body?: Update },
|
||||
res: http.ServerResponse,
|
||||
next = (): void => {
|
||||
res.statusCode = 403
|
||||
debug('Replying with status code', res.statusCode)
|
||||
res.end()
|
||||
}
|
||||
): Promise<void> => {
|
||||
debug('Incoming request', req.method, req.url)
|
||||
|
||||
if (!filter(req)) {
|
||||
debug('Webhook filter failed', req.method, req.url)
|
||||
return next()
|
||||
}
|
||||
|
||||
let update: Update
|
||||
|
||||
try {
|
||||
if (req.body != null) {
|
||||
/* If req.body is already set, we expect it to be the parsed
|
||||
request body (update object) received from Telegram
|
||||
However, some libraries such as `serverless-http` set req.body to the
|
||||
raw buffer, so we'll handle that additionally */
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let body: any = req.body
|
||||
// if body is Buffer, parse it into string
|
||||
if (body instanceof Buffer) body = String(req.body)
|
||||
// if body is string, parse it into object
|
||||
if (typeof body === 'string') body = JSON.parse(body)
|
||||
update = body
|
||||
} else {
|
||||
let body = ''
|
||||
// parse each buffer to string and append to body
|
||||
for await (const chunk of req) body += String(chunk)
|
||||
// parse body to object
|
||||
update = JSON.parse(body)
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
// if any of the parsing steps fails, give up and respond with error
|
||||
res.writeHead(415).end()
|
||||
debug('Failed to parse request body:', error)
|
||||
return
|
||||
}
|
||||
|
||||
return await updateHandler(update, res)
|
||||
}
|
||||
}
|
||||
54
node_modules/telegraf/src/core/types/typegram.ts
generated
vendored
Normal file
54
node_modules/telegraf/src/core/types/typegram.ts
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
import * as Typegram from '@telegraf/types'
|
||||
|
||||
// internal type provisions
|
||||
export * from '@telegraf/types/api'
|
||||
export * from '@telegraf/types/inline'
|
||||
export * from '@telegraf/types/manage'
|
||||
export * from '@telegraf/types/markup'
|
||||
export * from '@telegraf/types/message'
|
||||
export * from '@telegraf/types/methods'
|
||||
export * from '@telegraf/types/passport'
|
||||
export * from '@telegraf/types/payment'
|
||||
export * from '@telegraf/types/settings'
|
||||
export * from '@telegraf/types/update'
|
||||
|
||||
// telegraf input file definition
|
||||
interface InputFileByPath {
|
||||
source: string
|
||||
filename?: string
|
||||
}
|
||||
interface InputFileByReadableStream {
|
||||
source: NodeJS.ReadableStream
|
||||
filename?: string
|
||||
}
|
||||
interface InputFileByBuffer {
|
||||
source: Buffer
|
||||
filename?: string
|
||||
}
|
||||
interface InputFileByURL {
|
||||
url: string
|
||||
filename?: string
|
||||
}
|
||||
export type InputFile =
|
||||
| InputFileByPath
|
||||
| InputFileByReadableStream
|
||||
| InputFileByBuffer
|
||||
| InputFileByURL
|
||||
|
||||
export type Telegram = Typegram.ApiMethods<InputFile>
|
||||
|
||||
export type Opts<M extends keyof Telegram> = Typegram.Opts<InputFile>[M]
|
||||
export type InputMedia = Typegram.InputMedia<InputFile>
|
||||
export type InputMediaPhoto = Typegram.InputMediaPhoto<InputFile>
|
||||
export type InputMediaVideo = Typegram.InputMediaVideo<InputFile>
|
||||
export type InputMediaAnimation = Typegram.InputMediaAnimation<InputFile>
|
||||
export type InputMediaAudio = Typegram.InputMediaAudio<InputFile>
|
||||
export type InputMediaDocument = Typegram.InputMediaDocument<InputFile>
|
||||
|
||||
// tiny helper types
|
||||
export type ChatAction = Opts<'sendChatAction'>['action']
|
||||
|
||||
/**
|
||||
* Sending video notes by a URL is currently unsupported
|
||||
*/
|
||||
export type InputFileVideoNote = Exclude<InputFile, InputFileByURL>
|
||||
109
node_modules/telegraf/src/filters.ts
generated
vendored
Normal file
109
node_modules/telegraf/src/filters.ts
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
import type {
|
||||
CallbackQuery,
|
||||
CommonMessageBundle,
|
||||
Message,
|
||||
Update,
|
||||
} from '@telegraf/types'
|
||||
import { DistinctKeys, KeyedDistinct, Guarded } from './core/helpers/util'
|
||||
|
||||
export type Filter<U extends Update> = (update: Update) => update is U
|
||||
|
||||
export { Guarded }
|
||||
|
||||
export type AllGuarded<Fs extends Filter<Update>[]> = Fs extends [
|
||||
infer A,
|
||||
...infer B,
|
||||
]
|
||||
? B extends []
|
||||
? Guarded<A>
|
||||
: // TS doesn't know otherwise that B is Filter[]
|
||||
B extends Filter<Update>[]
|
||||
? Guarded<A> & AllGuarded<B>
|
||||
: never
|
||||
: never
|
||||
|
||||
export const message =
|
||||
<Ks extends DistinctKeys<Message>[]>(...keys: Ks) =>
|
||||
(
|
||||
update: Update
|
||||
): update is Update.MessageUpdate<KeyedDistinct<Message, Ks[number]>> => {
|
||||
if (!('message' in update)) return false
|
||||
for (const key of keys) {
|
||||
if (!(key in update.message)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export const editedMessage =
|
||||
<Ks extends DistinctKeys<CommonMessageBundle>[]>(...keys: Ks) =>
|
||||
(
|
||||
update: Update
|
||||
): update is Update.EditedMessageUpdate<
|
||||
KeyedDistinct<CommonMessageBundle, Ks[number]>
|
||||
> => {
|
||||
if (!('edited_message' in update)) return false
|
||||
for (const key of keys) {
|
||||
if (!(key in update.edited_message)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export const channelPost =
|
||||
<Ks extends DistinctKeys<Message>[]>(...keys: Ks) =>
|
||||
(
|
||||
update: Update
|
||||
): update is Update.ChannelPostUpdate<KeyedDistinct<Message, Ks[number]>> => {
|
||||
if (!('channel_post' in update)) return false
|
||||
for (const key of keys) {
|
||||
if (!(key in update.channel_post)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export const editedChannelPost =
|
||||
<Ks extends DistinctKeys<CommonMessageBundle>[]>(...keys: Ks) =>
|
||||
(
|
||||
update: Update
|
||||
): update is Update.EditedChannelPostUpdate<
|
||||
KeyedDistinct<CommonMessageBundle, Ks[number]>
|
||||
> => {
|
||||
if (!('edited_channel_post' in update)) return false
|
||||
for (const key of keys) {
|
||||
if (!(key in update.edited_channel_post)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export const callbackQuery =
|
||||
<Ks extends DistinctKeys<CallbackQuery>[]>(...keys: Ks) =>
|
||||
(
|
||||
update: Update
|
||||
): update is Update.CallbackQueryUpdate<
|
||||
KeyedDistinct<CallbackQuery, Ks[number]>
|
||||
> => {
|
||||
if (!('callback_query' in update)) return false
|
||||
for (const key of keys) {
|
||||
if (!(key in update.callback_query)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/** Any of the provided filters must match */
|
||||
export const anyOf =
|
||||
<Us extends Update[]>(
|
||||
...filters: {
|
||||
[UIdx in keyof Us]: Filter<Us[UIdx]>
|
||||
}
|
||||
) =>
|
||||
(update: Update): update is Us[number] => {
|
||||
for (const filter of filters) if (filter(update)) return true
|
||||
return false
|
||||
}
|
||||
|
||||
/** All of the provided filters must match */
|
||||
export const allOf =
|
||||
<U extends Update, Fs extends Filter<U>[]>(...filters: Fs) =>
|
||||
(update: Update): update is AllGuarded<Fs> => {
|
||||
for (const filter of filters) if (!filter(update)) return false
|
||||
return true
|
||||
}
|
||||
110
node_modules/telegraf/src/format.ts
generated
vendored
Normal file
110
node_modules/telegraf/src/format.ts
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
import { User } from '@telegraf/types'
|
||||
import {
|
||||
FmtString,
|
||||
createFmt,
|
||||
linkOrMention,
|
||||
join as _join,
|
||||
} from './core/helpers/formatting'
|
||||
|
||||
export { FmtString }
|
||||
|
||||
type Nestable<Kind extends string> = string | number | boolean | FmtString<Kind>
|
||||
type Nesting<Kind extends string> = [
|
||||
parts: Nestable<Kind> | readonly Nestable<Kind>[],
|
||||
...items: Nestable<Kind>[],
|
||||
]
|
||||
type Nests<Is extends string, Kind extends string> = (
|
||||
...args: Nesting<Kind>
|
||||
) => FmtString<Is>
|
||||
|
||||
// Nests<A, B> means the function will return A, and it can nest B
|
||||
// Nests<'fmt', string> means it will nest anything
|
||||
// Nests<'code', never> means it will not nest anything
|
||||
|
||||
// Allowing everything to nest 'fmt' is a necessary evil; it allows to indirectly nest illegal entities
|
||||
// Except for 'code' and 'pre', which don't nest anything anyway, so they only deal with strings
|
||||
|
||||
export const join = _join as Nests<'fmt', string>
|
||||
|
||||
export const fmt = createFmt() as Nests<'fmt', string>
|
||||
|
||||
export const bold = createFmt('bold') as Nests<
|
||||
'bold',
|
||||
'fmt' | 'bold' | 'italic' | 'underline' | 'strikethrough' | 'spoiler'
|
||||
>
|
||||
|
||||
export const italic = createFmt('italic') as Nests<
|
||||
'italic',
|
||||
'fmt' | 'bold' | 'italic' | 'underline' | 'strikethrough' | 'spoiler'
|
||||
>
|
||||
|
||||
export const spoiler = createFmt('spoiler') as Nests<
|
||||
'spoiler',
|
||||
'fmt' | 'bold' | 'italic' | 'underline' | 'strikethrough' | 'spoiler'
|
||||
>
|
||||
|
||||
export const strikethrough =
|
||||
//
|
||||
createFmt('strikethrough') as Nests<
|
||||
'strikethrough',
|
||||
'fmt' | 'bold' | 'italic' | 'underline' | 'strikethrough' | 'spoiler'
|
||||
>
|
||||
|
||||
export const underline =
|
||||
//
|
||||
createFmt('underline') as Nests<
|
||||
'underline',
|
||||
'fmt' | 'bold' | 'italic' | 'underline' | 'strikethrough' | 'spoiler'
|
||||
>
|
||||
|
||||
export const quote =
|
||||
//
|
||||
createFmt('blockquote') as Nests<
|
||||
'blockquote',
|
||||
| 'fmt'
|
||||
| 'bold'
|
||||
| 'italic'
|
||||
| 'underline'
|
||||
| 'strikethrough'
|
||||
| 'spoiler'
|
||||
| 'code'
|
||||
>
|
||||
|
||||
export const code = createFmt('code') as Nests<'code', never>
|
||||
|
||||
export const pre = (language: string) =>
|
||||
createFmt('pre', { language }) as Nests<'pre', never>
|
||||
|
||||
export const link = (
|
||||
content: Nestable<
|
||||
| 'fmt'
|
||||
| 'bold'
|
||||
| 'italic'
|
||||
| 'underline'
|
||||
| 'strikethrough'
|
||||
| 'spoiler'
|
||||
| 'code'
|
||||
>,
|
||||
url: string
|
||||
) =>
|
||||
//
|
||||
linkOrMention(content, { type: 'text_link', url }) as FmtString<'text_link'>
|
||||
|
||||
export const mention = (
|
||||
name: Nestable<
|
||||
| 'fmt'
|
||||
| 'bold'
|
||||
| 'italic'
|
||||
| 'underline'
|
||||
| 'strikethrough'
|
||||
| 'spoiler'
|
||||
| 'code'
|
||||
>,
|
||||
user: number | User
|
||||
) =>
|
||||
typeof user === 'number'
|
||||
? link(name, 'tg://user?id=' + user)
|
||||
: (linkOrMention(name, {
|
||||
type: 'text_mention',
|
||||
user,
|
||||
}) as FmtString<'text_mention'>)
|
||||
213
node_modules/telegraf/src/future.ts
generated
vendored
Normal file
213
node_modules/telegraf/src/future.ts
generated
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
import { ReplyParameters } from '@telegraf/types'
|
||||
import Context from './context'
|
||||
import { Middleware } from './middleware'
|
||||
|
||||
type ReplyContext = { [key in keyof Context & `reply${string}`]: Context[key] }
|
||||
|
||||
function makeReply<
|
||||
C extends Context,
|
||||
E extends { reply_parameters?: ReplyParameters },
|
||||
>(ctx: C, extra?: E) {
|
||||
if (ctx.msgId)
|
||||
return {
|
||||
// overrides in this order so user can override all properties
|
||||
reply_parameters: {
|
||||
message_id: ctx.msgId,
|
||||
...extra?.reply_parameters,
|
||||
},
|
||||
...extra,
|
||||
}
|
||||
else return extra
|
||||
}
|
||||
|
||||
const replyContext: ReplyContext = {
|
||||
replyWithChatAction: function () {
|
||||
throw new TypeError(
|
||||
'ctx.replyWithChatAction has been removed, use ctx.sendChatAction instead'
|
||||
)
|
||||
},
|
||||
reply(this: Context, text, extra) {
|
||||
this.assert(this.chat, 'reply')
|
||||
return this.telegram.sendMessage(this.chat.id, text, makeReply(this, extra))
|
||||
},
|
||||
replyWithAnimation(this: Context, animation, extra) {
|
||||
this.assert(this.chat, 'replyWithAnimation')
|
||||
return this.telegram.sendAnimation(
|
||||
this.chat.id,
|
||||
animation,
|
||||
makeReply(this, extra)
|
||||
)
|
||||
},
|
||||
replyWithAudio(this: Context, audio, extra) {
|
||||
this.assert(this.chat, 'replyWithAudio')
|
||||
return this.telegram.sendAudio(this.chat.id, audio, makeReply(this, extra))
|
||||
},
|
||||
replyWithContact(this: Context, phoneNumber, firstName, extra) {
|
||||
this.assert(this.chat, 'replyWithContact')
|
||||
return this.telegram.sendContact(
|
||||
this.chat.id,
|
||||
phoneNumber,
|
||||
firstName,
|
||||
makeReply(this, extra)
|
||||
)
|
||||
},
|
||||
replyWithDice(this: Context, extra) {
|
||||
this.assert(this.chat, 'replyWithDice')
|
||||
return this.telegram.sendDice(this.chat.id, makeReply(this, extra))
|
||||
},
|
||||
replyWithDocument(this: Context, document, extra) {
|
||||
this.assert(this.chat, 'replyWithDocument')
|
||||
return this.telegram.sendDocument(
|
||||
this.chat.id,
|
||||
document,
|
||||
makeReply(this, extra)
|
||||
)
|
||||
},
|
||||
replyWithGame(this: Context, gameName, extra) {
|
||||
this.assert(this.chat, 'replyWithGame')
|
||||
return this.telegram.sendGame(
|
||||
this.chat.id,
|
||||
gameName,
|
||||
makeReply(this, extra)
|
||||
)
|
||||
},
|
||||
replyWithHTML(this: Context, html, extra) {
|
||||
this.assert(this.chat, 'replyWithHTML')
|
||||
return this.telegram.sendMessage(this.chat.id, html, {
|
||||
parse_mode: 'HTML',
|
||||
...makeReply(this, extra),
|
||||
})
|
||||
},
|
||||
replyWithInvoice(this: Context, invoice, extra) {
|
||||
this.assert(this.chat, 'replyWithInvoice')
|
||||
return this.telegram.sendInvoice(
|
||||
this.chat.id,
|
||||
invoice,
|
||||
makeReply(this, extra)
|
||||
)
|
||||
},
|
||||
replyWithLocation(this: Context, latitude, longitude, extra) {
|
||||
this.assert(this.chat, 'replyWithLocation')
|
||||
return this.telegram.sendLocation(
|
||||
this.chat.id,
|
||||
latitude,
|
||||
longitude,
|
||||
makeReply(this, extra)
|
||||
)
|
||||
},
|
||||
replyWithMarkdown(this: Context, markdown, extra) {
|
||||
this.assert(this.chat, 'replyWithMarkdown')
|
||||
return this.telegram.sendMessage(this.chat.id, markdown, {
|
||||
parse_mode: 'Markdown',
|
||||
...makeReply(this, extra),
|
||||
})
|
||||
},
|
||||
replyWithMarkdownV2(this: Context, markdown, extra) {
|
||||
this.assert(this.chat, 'replyWithMarkdownV2')
|
||||
return this.telegram.sendMessage(this.chat.id, markdown, {
|
||||
parse_mode: 'MarkdownV2',
|
||||
...makeReply(this, extra),
|
||||
})
|
||||
},
|
||||
replyWithMediaGroup(this: Context, media, extra) {
|
||||
this.assert(this.chat, 'replyWithMediaGroup')
|
||||
return this.telegram.sendMediaGroup(
|
||||
this.chat.id,
|
||||
media,
|
||||
makeReply(this, extra)
|
||||
)
|
||||
},
|
||||
replyWithPhoto(this: Context, photo, extra) {
|
||||
this.assert(this.chat, 'replyWithPhoto')
|
||||
return this.telegram.sendPhoto(this.chat.id, photo, makeReply(this, extra))
|
||||
},
|
||||
replyWithPoll(this: Context, question, options, extra) {
|
||||
this.assert(this.chat, 'replyWithPoll')
|
||||
return this.telegram.sendPoll(
|
||||
this.chat.id,
|
||||
question,
|
||||
options,
|
||||
makeReply(this, extra)
|
||||
)
|
||||
},
|
||||
replyWithQuiz(this: Context, question, options, extra) {
|
||||
this.assert(this.chat, 'replyWithQuiz')
|
||||
return this.telegram.sendQuiz(
|
||||
this.chat.id,
|
||||
question,
|
||||
options,
|
||||
makeReply(this, extra)
|
||||
)
|
||||
},
|
||||
replyWithSticker(this: Context, sticker, extra) {
|
||||
this.assert(this.chat, 'replyWithSticker')
|
||||
return this.telegram.sendSticker(
|
||||
this.chat.id,
|
||||
sticker,
|
||||
makeReply(this, extra)
|
||||
)
|
||||
},
|
||||
replyWithVenue(this: Context, latitude, longitude, title, address, extra) {
|
||||
this.assert(this.chat, 'replyWithVenue')
|
||||
return this.telegram.sendVenue(
|
||||
this.chat.id,
|
||||
latitude,
|
||||
longitude,
|
||||
title,
|
||||
address,
|
||||
makeReply(this, extra)
|
||||
)
|
||||
},
|
||||
replyWithVideo(this: Context, video, extra) {
|
||||
this.assert(this.chat, 'replyWithVideo')
|
||||
return this.telegram.sendVideo(this.chat.id, video, makeReply(this, extra))
|
||||
},
|
||||
replyWithVideoNote(this: Context, videoNote, extra) {
|
||||
this.assert(this.chat, 'replyWithVideoNote')
|
||||
return this.telegram.sendVideoNote(
|
||||
this.chat.id,
|
||||
videoNote,
|
||||
makeReply(this, extra)
|
||||
)
|
||||
},
|
||||
replyWithVoice(this: Context, voice, extra) {
|
||||
this.assert(this.chat, 'replyWithVoice')
|
||||
return this.telegram.sendVoice(this.chat.id, voice, makeReply(this, extra))
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up Context to use the new reply methods.
|
||||
* This middleware makes `ctx.reply()` and `ctx.replyWith*()` methods will actually reply to the message they are replying to.
|
||||
* Use `ctx.sendMessage()` to send a message in chat without replying to it.
|
||||
*
|
||||
* If the message to reply is deleted, `reply()` will send a normal message.
|
||||
* If the update is not a message and we are unable to reply, `reply()` will send a normal message.
|
||||
*/
|
||||
export function useNewReplies<C extends Context>(): Middleware<C> {
|
||||
return (ctx, next) => {
|
||||
ctx.reply = replyContext.reply
|
||||
ctx.replyWithPhoto = replyContext.replyWithPhoto
|
||||
ctx.replyWithMediaGroup = replyContext.replyWithMediaGroup
|
||||
ctx.replyWithAudio = replyContext.replyWithAudio
|
||||
ctx.replyWithDice = replyContext.replyWithDice
|
||||
ctx.replyWithDocument = replyContext.replyWithDocument
|
||||
ctx.replyWithSticker = replyContext.replyWithSticker
|
||||
ctx.replyWithVideo = replyContext.replyWithVideo
|
||||
ctx.replyWithAnimation = replyContext.replyWithAnimation
|
||||
ctx.replyWithVideoNote = replyContext.replyWithVideoNote
|
||||
ctx.replyWithInvoice = replyContext.replyWithInvoice
|
||||
ctx.replyWithGame = replyContext.replyWithGame
|
||||
ctx.replyWithVoice = replyContext.replyWithVoice
|
||||
ctx.replyWithPoll = replyContext.replyWithPoll
|
||||
ctx.replyWithQuiz = replyContext.replyWithQuiz
|
||||
ctx.replyWithChatAction = replyContext.replyWithChatAction
|
||||
ctx.replyWithLocation = replyContext.replyWithLocation
|
||||
ctx.replyWithVenue = replyContext.replyWithVenue
|
||||
ctx.replyWithContact = replyContext.replyWithContact
|
||||
ctx.replyWithMarkdown = replyContext.replyWithMarkdown
|
||||
ctx.replyWithMarkdownV2 = replyContext.replyWithMarkdownV2
|
||||
ctx.replyWithHTML = replyContext.replyWithHTML
|
||||
return next()
|
||||
}
|
||||
}
|
||||
17
node_modules/telegraf/src/index.ts
generated
vendored
Normal file
17
node_modules/telegraf/src/index.ts
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
export { Telegraf } from './telegraf'
|
||||
export { Context, NarrowedContext } from './context'
|
||||
export { Composer } from './composer'
|
||||
export { Middleware, MiddlewareFn, MiddlewareObj } from './middleware'
|
||||
export { Router } from './router'
|
||||
export { TelegramError } from './core/network/error'
|
||||
export { Telegram } from './telegram'
|
||||
|
||||
export * as Types from './telegram-types'
|
||||
export * as Markup from './markup'
|
||||
export * as Input from './input'
|
||||
export * as Format from './format'
|
||||
|
||||
export { deunionize } from './core/helpers/deunionize'
|
||||
export { session, MemorySessionStore, SessionStore } from './session'
|
||||
|
||||
export * as Scenes from './scenes'
|
||||
59
node_modules/telegraf/src/input.ts
generated
vendored
Normal file
59
node_modules/telegraf/src/input.ts
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
import { InputFile } from './core/types/typegram'
|
||||
|
||||
/**
|
||||
* The local file specified by path will be uploaded to Telegram using multipart/form-data.
|
||||
*
|
||||
* 10 MB max size for photos, 50 MB for other files.
|
||||
*/
|
||||
// prettier-ignore
|
||||
export const fromLocalFile = (path: string, filename?: string): InputFile => ({ source: path, filename })
|
||||
|
||||
/**
|
||||
* The buffer will be uploaded as file to Telegram using multipart/form-data.
|
||||
*
|
||||
* 10 MB max size for photos, 50 MB for other files.
|
||||
*/
|
||||
// prettier-ignore
|
||||
export const fromBuffer = (buffer: Buffer, filename?: string): InputFile => ({ source: buffer, filename })
|
||||
|
||||
/**
|
||||
* Contents of the stream will be uploaded as file to Telegram using multipart/form-data.
|
||||
*
|
||||
* 10 MB max size for photos, 50 MB for other files.
|
||||
*/
|
||||
// prettier-ignore
|
||||
export const fromReadableStream = (stream: NodeJS.ReadableStream, filename?: string): InputFile => ({ source: stream, filename })
|
||||
|
||||
/**
|
||||
* Contents of the URL will be streamed to Telegram.
|
||||
*
|
||||
* 10 MB max size for photos, 50 MB for other files.
|
||||
*/
|
||||
// prettier-ignore
|
||||
export const fromURLStream = (url: string | URL, filename?: string): InputFile => ({ url: url.toString(), filename })
|
||||
|
||||
/**
|
||||
* Provide Telegram with an HTTP URL for the file to be sent.
|
||||
* Telegram will download and send the file.
|
||||
*
|
||||
* * The target file must have the correct MIME type (e.g., audio/mpeg for `sendAudio`, etc.).
|
||||
* * `sendDocument` with URL will currently only work for GIF, PDF and ZIP files.
|
||||
* * To use `sendVoice`, the file must have the type audio/ogg and be no more than 1MB in size.
|
||||
* 1-20MB voice notes will be sent as files.
|
||||
*
|
||||
* 5 MB max size for photos and 20 MB max for other types of content.
|
||||
*/
|
||||
export const fromURL = (url: string | URL): string => url.toString()
|
||||
|
||||
/**
|
||||
* If the file is already stored somewhere on the Telegram servers, you don't need to reupload it:
|
||||
* each file object has a file_id field, simply pass this file_id as a parameter instead of uploading.
|
||||
*
|
||||
* It is not possible to change the file type when resending by file_id.
|
||||
*
|
||||
* It is not possible to resend thumbnails using file_id.
|
||||
* They have to be uploaded using one of the other Input methods.
|
||||
*
|
||||
* There are no limits for files sent this way.
|
||||
*/
|
||||
export const fromFileId = (fileId: string): string => fileId
|
||||
142
node_modules/telegraf/src/markup.ts
generated
vendored
Normal file
142
node_modules/telegraf/src/markup.ts
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
import {
|
||||
ForceReply,
|
||||
InlineKeyboardButton,
|
||||
InlineKeyboardMarkup,
|
||||
KeyboardButton,
|
||||
ReplyKeyboardMarkup,
|
||||
ReplyKeyboardRemove,
|
||||
} from './core/types/typegram'
|
||||
import { is2D } from './core/helpers/check'
|
||||
|
||||
type Hideable<B> = B & { hide?: boolean }
|
||||
type HideableKBtn = Hideable<KeyboardButton>
|
||||
type HideableIKBtn = Hideable<InlineKeyboardButton>
|
||||
|
||||
export class Markup<
|
||||
T extends
|
||||
| InlineKeyboardMarkup
|
||||
| ReplyKeyboardMarkup
|
||||
| ReplyKeyboardRemove
|
||||
| ForceReply,
|
||||
> {
|
||||
constructor(readonly reply_markup: T) {}
|
||||
|
||||
selective<T extends ForceReply | ReplyKeyboardMarkup>(
|
||||
this: Markup<T>,
|
||||
value = true
|
||||
) {
|
||||
return new Markup<T>({ ...this.reply_markup, selective: value })
|
||||
}
|
||||
|
||||
placeholder<T extends ForceReply | ReplyKeyboardMarkup>(
|
||||
this: Markup<T>,
|
||||
placeholder: string
|
||||
) {
|
||||
return new Markup<T>({
|
||||
...this.reply_markup,
|
||||
input_field_placeholder: placeholder,
|
||||
})
|
||||
}
|
||||
|
||||
resize(this: Markup<ReplyKeyboardMarkup>, value = true) {
|
||||
return new Markup<ReplyKeyboardMarkup>({
|
||||
...this.reply_markup,
|
||||
resize_keyboard: value,
|
||||
})
|
||||
}
|
||||
|
||||
oneTime(this: Markup<ReplyKeyboardMarkup>, value = true) {
|
||||
return new Markup<ReplyKeyboardMarkup>({
|
||||
...this.reply_markup,
|
||||
one_time_keyboard: value,
|
||||
})
|
||||
}
|
||||
|
||||
persistent(this: Markup<ReplyKeyboardMarkup>, value = true) {
|
||||
return new Markup<ReplyKeyboardMarkup>({
|
||||
...this.reply_markup,
|
||||
is_persistent: value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export * as button from './button'
|
||||
|
||||
export function removeKeyboard(): Markup<ReplyKeyboardRemove> {
|
||||
return new Markup<ReplyKeyboardRemove>({ remove_keyboard: true })
|
||||
}
|
||||
|
||||
export function forceReply(): Markup<ForceReply> {
|
||||
return new Markup<ForceReply>({ force_reply: true })
|
||||
}
|
||||
|
||||
export function keyboard(buttons: HideableKBtn[][]): Markup<ReplyKeyboardMarkup>
|
||||
export function keyboard(
|
||||
buttons: HideableKBtn[],
|
||||
options?: Partial<KeyboardBuildingOptions<HideableKBtn>>
|
||||
): Markup<ReplyKeyboardMarkup>
|
||||
export function keyboard(
|
||||
buttons: HideableKBtn[] | HideableKBtn[][],
|
||||
options?: Partial<KeyboardBuildingOptions<HideableKBtn>>
|
||||
): Markup<ReplyKeyboardMarkup> {
|
||||
const keyboard = buildKeyboard(buttons, {
|
||||
columns: 1,
|
||||
...options,
|
||||
})
|
||||
return new Markup<ReplyKeyboardMarkup>({ keyboard })
|
||||
}
|
||||
|
||||
export function inlineKeyboard(
|
||||
buttons: HideableIKBtn[][]
|
||||
): Markup<InlineKeyboardMarkup>
|
||||
export function inlineKeyboard(
|
||||
buttons: HideableIKBtn[],
|
||||
options?: Partial<KeyboardBuildingOptions<HideableIKBtn>>
|
||||
): Markup<InlineKeyboardMarkup>
|
||||
export function inlineKeyboard(
|
||||
buttons: HideableIKBtn[] | HideableIKBtn[][],
|
||||
options?: Partial<KeyboardBuildingOptions<HideableIKBtn>>
|
||||
): Markup<InlineKeyboardMarkup> {
|
||||
const inlineKeyboard = buildKeyboard(buttons, {
|
||||
columns: buttons.length,
|
||||
...options,
|
||||
})
|
||||
return new Markup<InlineKeyboardMarkup>({ inline_keyboard: inlineKeyboard })
|
||||
}
|
||||
|
||||
interface KeyboardBuildingOptions<B extends HideableKBtn | HideableIKBtn> {
|
||||
wrap?: (btn: B, index: number, currentRow: B[]) => boolean
|
||||
columns: number
|
||||
}
|
||||
|
||||
function buildKeyboard<B extends HideableKBtn | HideableIKBtn>(
|
||||
buttons: B[] | B[][],
|
||||
options: KeyboardBuildingOptions<B>
|
||||
): B[][] {
|
||||
const result: B[][] = []
|
||||
if (!Array.isArray(buttons)) {
|
||||
return result
|
||||
}
|
||||
if (is2D(buttons)) {
|
||||
return buttons.map((row) => row.filter((button) => !button.hide))
|
||||
}
|
||||
const wrapFn =
|
||||
options.wrap !== undefined
|
||||
? options.wrap
|
||||
: (_btn: B, _index: number, currentRow: B[]) =>
|
||||
currentRow.length >= options.columns
|
||||
let currentRow: B[] = []
|
||||
let index = 0
|
||||
for (const btn of buttons.filter((button) => !button.hide)) {
|
||||
if (wrapFn(btn, index, currentRow) && currentRow.length > 0) {
|
||||
result.push(currentRow)
|
||||
currentRow = []
|
||||
}
|
||||
currentRow.push(btn)
|
||||
index++
|
||||
}
|
||||
if (currentRow.length > 0) {
|
||||
result.push(currentRow)
|
||||
}
|
||||
return result
|
||||
}
|
||||
24
node_modules/telegraf/src/middleware.ts
generated
vendored
Normal file
24
node_modules/telegraf/src/middleware.ts
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Context } from './context'
|
||||
import { Update } from './core/types/typegram'
|
||||
|
||||
/*
|
||||
next's parameter is in a contravariant position, and thus, trying to type it
|
||||
prevents assigning `MiddlewareFn<ContextMessageUpdate>`
|
||||
to `MiddlewareFn<CustomContext>`.
|
||||
Middleware passing the parameter should be a separate type instead.
|
||||
*/
|
||||
export type MiddlewareFn<C extends Context<U>, U extends Update = Update> = (
|
||||
ctx: C,
|
||||
next: () => Promise<void>
|
||||
) => Promise<unknown> | void
|
||||
|
||||
export interface MiddlewareObj<
|
||||
C extends Context<U>,
|
||||
U extends Update = Update,
|
||||
> {
|
||||
middleware: () => MiddlewareFn<C, U>
|
||||
}
|
||||
|
||||
export type Middleware<C extends Context<U>, U extends Update = Update> =
|
||||
| MiddlewareFn<C, U>
|
||||
| MiddlewareObj<C, U>
|
||||
118
node_modules/telegraf/src/reactions.ts
generated
vendored
Normal file
118
node_modules/telegraf/src/reactions.ts
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
import { Deunionize } from './core/helpers/deunionize'
|
||||
import { indexed } from './core/helpers/util'
|
||||
import * as tg from './core/types/typegram'
|
||||
|
||||
export type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
|
||||
export const Digit = new Set(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'])
|
||||
export type Reaction =
|
||||
| tg.TelegramEmoji
|
||||
| `${Digit}${string}`
|
||||
| Deunionize<tg.ReactionType>
|
||||
|
||||
type ReactionCtx = { update: Partial<tg.Update.MessageReactionUpdate> }
|
||||
|
||||
const inspectReaction = (reaction: tg.ReactionType) => {
|
||||
if (reaction.type === 'custom_emoji')
|
||||
return `Custom(${reaction.custom_emoji_id})`
|
||||
else return reaction.emoji
|
||||
}
|
||||
|
||||
export class ReactionList {
|
||||
// this is a lie, proxy will be used to access the properties
|
||||
[index: number]: Deunionize<tg.ReactionType>
|
||||
|
||||
protected constructor(protected list: tg.ReactionType[]) {}
|
||||
|
||||
static fromArray(list: tg.ReactionType[] = []): ReactionList {
|
||||
return indexed(
|
||||
new ReactionList(list),
|
||||
function (this: ReactionList, index) {
|
||||
return this.list[index]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
static has(reactions: tg.ReactionType[], reaction: Reaction): boolean {
|
||||
if (typeof reaction === 'string')
|
||||
if (Digit.has(reaction[0] as string))
|
||||
return reactions.some(
|
||||
(r: Deunionize<tg.ReactionType>) => r.custom_emoji_id === reaction
|
||||
)
|
||||
else
|
||||
return reactions.some(
|
||||
(r: Deunionize<tg.ReactionType>) => r.emoji === reaction
|
||||
)
|
||||
|
||||
return reactions.some((r: Deunionize<tg.ReactionType>) => {
|
||||
if (r.type === 'custom_emoji')
|
||||
return r.custom_emoji_id === reaction.custom_emoji_id
|
||||
else if (r.type === 'emoji') return r.emoji === reaction.emoji
|
||||
})
|
||||
}
|
||||
|
||||
toArray(): tg.ReactionType[] {
|
||||
return [...this.list]
|
||||
}
|
||||
|
||||
filter(
|
||||
filterFn: (value: tg.ReactionType, index: number) => boolean
|
||||
): ReactionList {
|
||||
return ReactionList.fromArray(this.list.filter(filterFn))
|
||||
}
|
||||
|
||||
has(reaction: Reaction): boolean {
|
||||
return ReactionList.has(this.list, reaction)
|
||||
}
|
||||
|
||||
get count(): number {
|
||||
return this.list.length
|
||||
}
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this.list[Symbol.iterator]()
|
||||
}
|
||||
|
||||
[Symbol.for('nodejs.util.inspect.custom')]() {
|
||||
const flattened = this.list.map(inspectReaction).join(', ')
|
||||
return ['ReactionList {', flattened, '}'].join(' ')
|
||||
}
|
||||
}
|
||||
|
||||
export class MessageReactions extends ReactionList {
|
||||
private constructor(public ctx: ReactionCtx) {
|
||||
super(ctx.update.message_reaction?.new_reaction ?? [])
|
||||
}
|
||||
|
||||
static from(ctx: ReactionCtx) {
|
||||
return indexed(
|
||||
new MessageReactions(ctx),
|
||||
function (this: MessageReactions, index) {
|
||||
return this.list[index]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
get old() {
|
||||
return ReactionList.fromArray(
|
||||
this.ctx.update.message_reaction?.old_reaction
|
||||
)
|
||||
}
|
||||
|
||||
get new() {
|
||||
return ReactionList.fromArray(
|
||||
this.ctx.update.message_reaction?.new_reaction
|
||||
)
|
||||
}
|
||||
|
||||
get added(): ReactionList {
|
||||
return this.new.filter((reaction) => !this.old.has(reaction))
|
||||
}
|
||||
|
||||
get removed(): ReactionList {
|
||||
return this.old.filter((reaction) => !this.new.has(reaction))
|
||||
}
|
||||
|
||||
get kept(): ReactionList {
|
||||
return this.new.filter((reaction) => this.old.has(reaction))
|
||||
}
|
||||
}
|
||||
55
node_modules/telegraf/src/router.ts
generated
vendored
Normal file
55
node_modules/telegraf/src/router.ts
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
/** @format */
|
||||
|
||||
import { Middleware, MiddlewareObj } from './middleware'
|
||||
import Composer from './composer'
|
||||
import Context from './context'
|
||||
|
||||
type NonemptyReadonlyArray<T> = readonly [T, ...T[]]
|
||||
|
||||
type RouteFn<TContext extends Context> = (ctx: TContext) => {
|
||||
route: string
|
||||
context?: Partial<TContext>
|
||||
state?: Partial<TContext['state']>
|
||||
} | null
|
||||
|
||||
/** @deprecated in favor of {@link Composer.dispatch} */
|
||||
export class Router<C extends Context> implements MiddlewareObj<C> {
|
||||
private otherwiseHandler: Middleware<C> = Composer.passThru()
|
||||
|
||||
constructor(
|
||||
private readonly routeFn: RouteFn<C>,
|
||||
public handlers = new Map<string, Middleware<C>>()
|
||||
) {
|
||||
if (typeof routeFn !== 'function') {
|
||||
throw new Error('Missing routing function')
|
||||
}
|
||||
}
|
||||
|
||||
on(route: string, ...fns: NonemptyReadonlyArray<Middleware<C>>) {
|
||||
if (fns.length === 0) {
|
||||
throw new TypeError('At least one handler must be provided')
|
||||
}
|
||||
this.handlers.set(route, Composer.compose(fns))
|
||||
return this
|
||||
}
|
||||
|
||||
otherwise(...fns: NonemptyReadonlyArray<Middleware<C>>) {
|
||||
if (fns.length === 0) {
|
||||
throw new TypeError('At least one otherwise handler must be provided')
|
||||
}
|
||||
this.otherwiseHandler = Composer.compose(fns)
|
||||
return this
|
||||
}
|
||||
|
||||
middleware() {
|
||||
return Composer.lazy<C>((ctx) => {
|
||||
const result = this.routeFn(ctx)
|
||||
if (result == null) {
|
||||
return this.otherwiseHandler
|
||||
}
|
||||
Object.assign(ctx, result.context)
|
||||
Object.assign(ctx.state, result.state)
|
||||
return this.handlers.get(result.route) ?? this.otherwiseHandler
|
||||
})
|
||||
}
|
||||
}
|
||||
1
node_modules/telegraf/src/scenes.ts
generated
vendored
Normal file
1
node_modules/telegraf/src/scenes.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './scenes/index.js'
|
||||
52
node_modules/telegraf/src/scenes/base.ts
generated
vendored
Normal file
52
node_modules/telegraf/src/scenes/base.ts
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Middleware, MiddlewareFn } from '../middleware'
|
||||
import Composer from '../composer'
|
||||
import Context from '../context'
|
||||
|
||||
const { compose } = Composer
|
||||
|
||||
export interface SceneOptions<C extends Context> {
|
||||
ttl?: number
|
||||
handlers: ReadonlyArray<MiddlewareFn<C>>
|
||||
enterHandlers: ReadonlyArray<MiddlewareFn<C>>
|
||||
leaveHandlers: ReadonlyArray<MiddlewareFn<C>>
|
||||
}
|
||||
|
||||
export class BaseScene<C extends Context = Context> extends Composer<C> {
|
||||
id: string
|
||||
ttl?: number
|
||||
enterHandler: MiddlewareFn<C>
|
||||
leaveHandler: MiddlewareFn<C>
|
||||
constructor(id: string, options?: SceneOptions<C>) {
|
||||
const opts: SceneOptions<C> = {
|
||||
handlers: [],
|
||||
enterHandlers: [],
|
||||
leaveHandlers: [],
|
||||
...options,
|
||||
}
|
||||
super(...opts.handlers)
|
||||
this.id = id
|
||||
this.ttl = opts.ttl
|
||||
this.enterHandler = compose(opts.enterHandlers)
|
||||
this.leaveHandler = compose(opts.leaveHandlers)
|
||||
}
|
||||
|
||||
enter(...fns: Array<Middleware<C>>) {
|
||||
this.enterHandler = compose([this.enterHandler, ...fns])
|
||||
return this
|
||||
}
|
||||
|
||||
leave(...fns: Array<Middleware<C>>) {
|
||||
this.leaveHandler = compose([this.leaveHandler, ...fns])
|
||||
return this
|
||||
}
|
||||
|
||||
enterMiddleware() {
|
||||
return this.enterHandler
|
||||
}
|
||||
|
||||
leaveMiddleware() {
|
||||
return this.leaveHandler
|
||||
}
|
||||
}
|
||||
|
||||
export default BaseScene
|
||||
136
node_modules/telegraf/src/scenes/context.ts
generated
vendored
Normal file
136
node_modules/telegraf/src/scenes/context.ts
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
import BaseScene from './base'
|
||||
import Composer from '../composer'
|
||||
import Context from '../context'
|
||||
import d from 'debug'
|
||||
import { SessionContext } from '../session'
|
||||
const debug = d('telegraf:scenes:context')
|
||||
|
||||
const noop = () => Promise.resolve()
|
||||
const now = () => Math.floor(Date.now() / 1000)
|
||||
|
||||
export interface SceneContext<D extends SceneSessionData = SceneSessionData>
|
||||
extends Context {
|
||||
session: SceneSession<D>
|
||||
scene: SceneContextScene<SceneContext<D>, D>
|
||||
}
|
||||
|
||||
export interface SceneSessionData {
|
||||
current?: string
|
||||
expires?: number
|
||||
state?: object
|
||||
}
|
||||
|
||||
export interface SceneSession<S extends SceneSessionData = SceneSessionData> {
|
||||
__scenes?: S
|
||||
}
|
||||
|
||||
export interface SceneContextSceneOptions<D extends SceneSessionData> {
|
||||
ttl?: number
|
||||
default?: string
|
||||
defaultSession: D
|
||||
}
|
||||
|
||||
export default class SceneContextScene<
|
||||
C extends SessionContext<SceneSession<D>>,
|
||||
D extends SceneSessionData = SceneSessionData,
|
||||
> {
|
||||
private readonly options: SceneContextSceneOptions<D>
|
||||
|
||||
constructor(
|
||||
private readonly ctx: C,
|
||||
private readonly scenes: Map<string, BaseScene<C>>,
|
||||
options: Partial<SceneContextSceneOptions<D>>
|
||||
) {
|
||||
// @ts-expect-error {} might not be assignable to D
|
||||
const fallbackSessionDefault: D = {}
|
||||
|
||||
this.options = { defaultSession: fallbackSessionDefault, ...options }
|
||||
}
|
||||
|
||||
get session(): D {
|
||||
const defaultSession = Object.assign({}, this.options.defaultSession)
|
||||
|
||||
let session = this.ctx.session?.__scenes ?? defaultSession
|
||||
if (session.expires !== undefined && session.expires < now()) {
|
||||
session = defaultSession
|
||||
}
|
||||
if (this.ctx.session === undefined) {
|
||||
this.ctx.session = { __scenes: session }
|
||||
} else {
|
||||
this.ctx.session.__scenes = session
|
||||
}
|
||||
return session
|
||||
}
|
||||
|
||||
get state() {
|
||||
return (this.session.state ??= {})
|
||||
}
|
||||
|
||||
set state(value) {
|
||||
this.session.state = { ...value }
|
||||
}
|
||||
|
||||
get current() {
|
||||
const sceneId = this.session.current ?? this.options.default
|
||||
return sceneId === undefined || !this.scenes.has(sceneId)
|
||||
? undefined
|
||||
: this.scenes.get(sceneId)
|
||||
}
|
||||
|
||||
reset() {
|
||||
if (this.ctx.session !== undefined)
|
||||
this.ctx.session.__scenes = Object.assign({}, this.options.defaultSession)
|
||||
}
|
||||
|
||||
async enter(sceneId: string, initialState: object = {}, silent = false) {
|
||||
if (!this.scenes.has(sceneId)) {
|
||||
throw new Error(`Can't find scene: ${sceneId}`)
|
||||
}
|
||||
if (!silent) {
|
||||
await this.leave()
|
||||
}
|
||||
debug('Entering scene', sceneId, initialState, silent)
|
||||
this.session.current = sceneId
|
||||
this.state = initialState
|
||||
const ttl = this.current?.ttl ?? this.options.ttl
|
||||
if (ttl !== undefined) {
|
||||
this.session.expires = now() + ttl
|
||||
}
|
||||
if (this.current === undefined || silent) {
|
||||
return
|
||||
}
|
||||
const handler =
|
||||
'enterMiddleware' in this.current &&
|
||||
typeof this.current.enterMiddleware === 'function'
|
||||
? this.current.enterMiddleware()
|
||||
: this.current.middleware()
|
||||
return await handler(this.ctx, noop)
|
||||
}
|
||||
|
||||
reenter() {
|
||||
return this.session.current === undefined
|
||||
? undefined
|
||||
: this.enter(this.session.current, this.state)
|
||||
}
|
||||
|
||||
private leaving = false
|
||||
async leave() {
|
||||
if (this.leaving) return
|
||||
debug('Leaving scene')
|
||||
try {
|
||||
this.leaving = true
|
||||
if (this.current === undefined) {
|
||||
return
|
||||
}
|
||||
const handler =
|
||||
'leaveMiddleware' in this.current &&
|
||||
typeof this.current.leaveMiddleware === 'function'
|
||||
? this.current.leaveMiddleware()
|
||||
: Composer.passThru()
|
||||
await handler(this.ctx, noop)
|
||||
return this.reset()
|
||||
} finally {
|
||||
this.leaving = false
|
||||
}
|
||||
}
|
||||
}
|
||||
21
node_modules/telegraf/src/scenes/index.ts
generated
vendored
Normal file
21
node_modules/telegraf/src/scenes/index.ts
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @see https://github.com/telegraf/telegraf/issues/705#issuecomment-549056045
|
||||
* @see https://www.npmjs.com/package/telegraf-stateless-question
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export { Stage } from './stage'
|
||||
export {
|
||||
SceneContext,
|
||||
SceneSession,
|
||||
default as SceneContextScene,
|
||||
SceneSessionData,
|
||||
} from './context'
|
||||
export { BaseScene } from './base'
|
||||
export { WizardScene } from './wizard'
|
||||
export {
|
||||
WizardContext,
|
||||
WizardSession,
|
||||
default as WizardContextWizard,
|
||||
WizardSessionData,
|
||||
} from './wizard/context'
|
||||
71
node_modules/telegraf/src/scenes/stage.ts
generated
vendored
Normal file
71
node_modules/telegraf/src/scenes/stage.ts
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
import { isSessionContext, SessionContext } from '../session'
|
||||
import SceneContextScene, {
|
||||
SceneContextSceneOptions,
|
||||
SceneSession,
|
||||
SceneSessionData,
|
||||
} from './context'
|
||||
import { BaseScene } from './base'
|
||||
import { Composer } from '../composer'
|
||||
import { Context } from '../context'
|
||||
|
||||
export class Stage<
|
||||
C extends SessionContext<SceneSession<D>> & {
|
||||
scene: SceneContextScene<C, D>
|
||||
},
|
||||
D extends SceneSessionData = SceneSessionData,
|
||||
> extends Composer<C> {
|
||||
options: Partial<SceneContextSceneOptions<D>>
|
||||
scenes: Map<string, BaseScene<C>>
|
||||
|
||||
constructor(
|
||||
scenes: ReadonlyArray<BaseScene<C>> = [],
|
||||
options?: Partial<SceneContextSceneOptions<D>>
|
||||
) {
|
||||
super()
|
||||
this.options = { ...options }
|
||||
this.scenes = new Map<string, BaseScene<C>>()
|
||||
scenes.forEach((scene) => this.register(scene))
|
||||
}
|
||||
|
||||
register(...scenes: ReadonlyArray<BaseScene<C>>) {
|
||||
scenes.forEach((scene) => {
|
||||
if (scene?.id == null || typeof scene.middleware !== 'function') {
|
||||
throw new Error('telegraf: Unsupported scene')
|
||||
}
|
||||
this.scenes.set(scene.id, scene)
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
||||
middleware() {
|
||||
const handler = Composer.compose<C>([
|
||||
(ctx, next) => {
|
||||
const scenes: Map<string, BaseScene<C>> = this.scenes
|
||||
const scene = new SceneContextScene<C, D>(ctx, scenes, this.options)
|
||||
ctx.scene = scene
|
||||
return next()
|
||||
},
|
||||
super.middleware(),
|
||||
Composer.lazy<C>((ctx) => ctx.scene.current ?? Composer.passThru()),
|
||||
])
|
||||
return Composer.optional(isSessionContext, handler)
|
||||
}
|
||||
|
||||
static enter<C extends Context & { scene: SceneContextScene<C> }>(
|
||||
...args: Parameters<SceneContextScene<C>['enter']>
|
||||
) {
|
||||
return (ctx: C) => ctx.scene.enter(...args)
|
||||
}
|
||||
|
||||
static reenter<C extends Context & { scene: SceneContextScene<C> }>(
|
||||
...args: Parameters<SceneContextScene<C>['reenter']>
|
||||
) {
|
||||
return (ctx: C) => ctx.scene.reenter(...args)
|
||||
}
|
||||
|
||||
static leave<C extends Context & { scene: SceneContextScene<C> }>(
|
||||
...args: Parameters<SceneContextScene<C>['leave']>
|
||||
) {
|
||||
return (ctx: C) => ctx.scene.leave(...args)
|
||||
}
|
||||
}
|
||||
58
node_modules/telegraf/src/scenes/wizard/context.ts
generated
vendored
Normal file
58
node_modules/telegraf/src/scenes/wizard/context.ts
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
import SceneContextScene, { SceneSession, SceneSessionData } from '../context'
|
||||
import Context from '../../context'
|
||||
import { Middleware } from '../../middleware'
|
||||
import { SessionContext } from '../../session'
|
||||
|
||||
export interface WizardContext<D extends WizardSessionData = WizardSessionData>
|
||||
extends Context {
|
||||
session: WizardSession<D>
|
||||
scene: SceneContextScene<WizardContext<D>, D>
|
||||
wizard: WizardContextWizard<WizardContext<D>>
|
||||
}
|
||||
|
||||
export interface WizardSessionData extends SceneSessionData {
|
||||
cursor: number
|
||||
}
|
||||
|
||||
export interface WizardSession<S extends WizardSessionData = WizardSessionData>
|
||||
extends SceneSession<S> {}
|
||||
|
||||
export default class WizardContextWizard<
|
||||
C extends SessionContext<WizardSession> & {
|
||||
scene: SceneContextScene<C, WizardSessionData>
|
||||
},
|
||||
> {
|
||||
readonly state: object
|
||||
constructor(
|
||||
private readonly ctx: C,
|
||||
private readonly steps: ReadonlyArray<Middleware<C>>
|
||||
) {
|
||||
this.state = ctx.scene.state
|
||||
this.cursor = ctx.scene.session.cursor ?? 0
|
||||
}
|
||||
|
||||
get step() {
|
||||
return this.steps[this.cursor]
|
||||
}
|
||||
|
||||
get cursor() {
|
||||
return this.ctx.scene.session.cursor
|
||||
}
|
||||
|
||||
set cursor(cursor: number) {
|
||||
this.ctx.scene.session.cursor = cursor
|
||||
}
|
||||
|
||||
selectStep(index: number) {
|
||||
this.cursor = index
|
||||
return this
|
||||
}
|
||||
|
||||
next() {
|
||||
return this.selectStep(this.cursor + 1)
|
||||
}
|
||||
|
||||
back() {
|
||||
return this.selectStep(this.cursor - 1)
|
||||
}
|
||||
}
|
||||
63
node_modules/telegraf/src/scenes/wizard/index.ts
generated
vendored
Normal file
63
node_modules/telegraf/src/scenes/wizard/index.ts
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
import BaseScene, { SceneOptions } from '../base'
|
||||
import { Middleware, MiddlewareObj } from '../../middleware'
|
||||
import WizardContextWizard, { WizardSessionData } from './context'
|
||||
import Composer from '../../composer'
|
||||
import Context from '../../context'
|
||||
import SceneContextScene from '../context'
|
||||
|
||||
export class WizardScene<
|
||||
C extends Context & {
|
||||
scene: SceneContextScene<C, WizardSessionData>
|
||||
wizard: WizardContextWizard<C>
|
||||
},
|
||||
>
|
||||
extends BaseScene<C>
|
||||
implements MiddlewareObj<C>
|
||||
{
|
||||
steps: Array<Middleware<C>>
|
||||
|
||||
constructor(id: string, ...steps: Array<Middleware<C>>)
|
||||
constructor(
|
||||
id: string,
|
||||
options: SceneOptions<C>,
|
||||
...steps: Array<Middleware<C>>
|
||||
)
|
||||
constructor(
|
||||
id: string,
|
||||
options: SceneOptions<C> | Middleware<C>,
|
||||
...steps: Array<Middleware<C>>
|
||||
) {
|
||||
let opts: SceneOptions<C> | undefined
|
||||
let s: Array<Middleware<C>>
|
||||
if (typeof options === 'function' || 'middleware' in options) {
|
||||
opts = undefined
|
||||
s = [options, ...steps]
|
||||
} else {
|
||||
opts = options
|
||||
s = steps
|
||||
}
|
||||
super(id, opts)
|
||||
this.steps = s
|
||||
}
|
||||
|
||||
middleware() {
|
||||
return Composer.compose<C>([
|
||||
(ctx, next) => {
|
||||
ctx.wizard = new WizardContextWizard<C>(ctx, this.steps)
|
||||
return next()
|
||||
},
|
||||
super.middleware(),
|
||||
(ctx, next) => {
|
||||
if (ctx.wizard.step === undefined) {
|
||||
ctx.wizard.selectStep(0)
|
||||
return ctx.scene.leave()
|
||||
}
|
||||
return Composer.unwrap(ctx.wizard.step)(ctx, next)
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
enterMiddleware() {
|
||||
return Composer.compose([this.enterHandler, this.middleware()])
|
||||
}
|
||||
}
|
||||
204
node_modules/telegraf/src/session.ts
generated
vendored
Normal file
204
node_modules/telegraf/src/session.ts
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
import { Context } from './context'
|
||||
import { ExclusiveKeys, MaybePromise } from './core/helpers/util'
|
||||
import { MiddlewareFn } from './middleware'
|
||||
import d from 'debug'
|
||||
const debug = d('telegraf:session')
|
||||
|
||||
export interface SyncSessionStore<T> {
|
||||
get: (name: string) => T | undefined
|
||||
set: (name: string, value: T) => void
|
||||
delete: (name: string) => void
|
||||
}
|
||||
|
||||
export interface AsyncSessionStore<T> {
|
||||
get: (name: string) => Promise<T | undefined>
|
||||
set: (name: string, value: T) => Promise<unknown>
|
||||
delete: (name: string) => Promise<unknown>
|
||||
}
|
||||
|
||||
export type SessionStore<T> = SyncSessionStore<T> | AsyncSessionStore<T>
|
||||
|
||||
interface SessionOptions<S, C extends Context, P extends string> {
|
||||
/** Customise the session prop. Defaults to "session" and is available as ctx.session. */
|
||||
property?: P
|
||||
getSessionKey?: (ctx: C) => MaybePromise<string | undefined>
|
||||
store?: SessionStore<S>
|
||||
defaultSession?: (ctx: C) => S
|
||||
}
|
||||
|
||||
/** @deprecated session can use custom properties now. Construct this type directly. */
|
||||
export interface SessionContext<S extends object> extends Context {
|
||||
session?: S
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns middleware that adds `ctx.session` for storing arbitrary state per session key.
|
||||
*
|
||||
* The default `getSessionKey` is `${ctx.from.id}:${ctx.chat.id}`.
|
||||
* If either `ctx.from` or `ctx.chat` is `undefined`, default session key and thus `ctx.session` are also `undefined`.
|
||||
*
|
||||
* > ⚠️ Session data is kept only in memory by default, which means that all data will be lost when the process is terminated.
|
||||
* >
|
||||
* > If you want to persist data across process restarts, or share it among multiple instances, you should use
|
||||
* [@telegraf/session](https://www.npmjs.com/package/@telegraf/session), or pass custom `storage`.
|
||||
*
|
||||
* @see {@link https://github.com/feathers-studio/telegraf-docs/blob/b694bcc36b4f71fb1cd650a345c2009ab4d2a2a5/guide/session.md Telegraf Docs | Session}
|
||||
* @see {@link https://github.com/feathers-studio/telegraf-docs/blob/master/examples/session-bot.ts Example}
|
||||
*/
|
||||
export function session<
|
||||
S extends NonNullable<C[P]>,
|
||||
C extends Context & { [key in P]?: C[P] },
|
||||
P extends (ExclusiveKeys<C, Context> & string) | 'session' = 'session',
|
||||
// ^ Only allow prop names that aren't keys in base Context.
|
||||
// At type level, this is cosmetic. To not get cluttered with all Context keys.
|
||||
>(options?: SessionOptions<S, C, P>): MiddlewareFn<C> {
|
||||
const prop = options?.property ?? ('session' as P)
|
||||
const getSessionKey = options?.getSessionKey ?? defaultGetSessionKey
|
||||
const store = options?.store ?? new MemorySessionStore()
|
||||
// caches value from store in-memory while simultaneous updates share it
|
||||
// when counter reaches 0, the cached ref will be freed from memory
|
||||
const cache = new Map<string, { ref?: S; counter: number }>()
|
||||
// temporarily stores concurrent requests
|
||||
const concurrents = new Map<string, MaybePromise<S | undefined>>()
|
||||
|
||||
// this function must be handled with care
|
||||
// read full description on the original PR: https://github.com/telegraf/telegraf/pull/1713
|
||||
// make sure to update the tests in test/session.js if you make any changes or fix bugs here
|
||||
return async (ctx, next) => {
|
||||
const updId = ctx.update.update_id
|
||||
|
||||
let released = false
|
||||
|
||||
function releaseChecks() {
|
||||
if (released && process.env.EXPERIMENTAL_SESSION_CHECKS)
|
||||
throw new Error(
|
||||
"Session was accessed or assigned to after the middleware chain exhausted. This is a bug in your code. You're probably accessing session asynchronously and missing awaits."
|
||||
)
|
||||
}
|
||||
|
||||
// because this is async, requests may still race here, but it will get autocorrected at (1)
|
||||
// v5 getSessionKey should probably be synchronous to avoid that
|
||||
const key = await getSessionKey(ctx)
|
||||
if (!key) {
|
||||
// Leaving this here could be useful to check for `prop in ctx` in future middleware
|
||||
ctx[prop] = undefined as unknown as S
|
||||
return await next()
|
||||
}
|
||||
|
||||
let cached = cache.get(key)
|
||||
if (cached) {
|
||||
debug(`(${updId}) found cached session, reusing from cache`)
|
||||
++cached.counter
|
||||
} else {
|
||||
debug(`(${updId}) did not find cached session`)
|
||||
// if another concurrent request has already sent a store request, fetch that instead
|
||||
let promise = concurrents.get(key)
|
||||
if (promise)
|
||||
debug(`(${updId}) found a concurrent request, reusing promise`)
|
||||
else {
|
||||
debug(`(${updId}) fetching from upstream store`)
|
||||
promise = store.get(key)
|
||||
}
|
||||
// synchronously store promise so concurrent requests can share response
|
||||
concurrents.set(key, promise)
|
||||
const upstream = await promise
|
||||
// all concurrent awaits will have promise in their closure, safe to remove now
|
||||
concurrents.delete(key)
|
||||
debug(`(${updId}) updating cache`)
|
||||
// another request may have beaten us to the punch
|
||||
const c = cache.get(key)
|
||||
if (c) {
|
||||
// another request did beat us to the punch
|
||||
c.counter++
|
||||
// (1) preserve cached reference; in-memory reference is always newer than from store
|
||||
cached = c
|
||||
} else {
|
||||
// we're the first, so we must cache the reference
|
||||
cached = { ref: upstream ?? options?.defaultSession?.(ctx), counter: 1 }
|
||||
cache.set(key, cached)
|
||||
}
|
||||
}
|
||||
|
||||
// TS already knows cached is always defined by this point, but does not guard cached.
|
||||
// It will, however, guard `c` here.
|
||||
const c = cached
|
||||
|
||||
let touched = false
|
||||
|
||||
Object.defineProperty(ctx, prop, {
|
||||
get() {
|
||||
releaseChecks()
|
||||
touched = true
|
||||
return c.ref
|
||||
},
|
||||
set(value: S) {
|
||||
releaseChecks()
|
||||
touched = true
|
||||
c.ref = value
|
||||
},
|
||||
})
|
||||
|
||||
try {
|
||||
await next()
|
||||
released = true
|
||||
} finally {
|
||||
if (--c.counter === 0) {
|
||||
// decrement to avoid memory leak
|
||||
debug(`(${updId}) refcounter reached 0, removing cached`)
|
||||
cache.delete(key)
|
||||
}
|
||||
debug(`(${updId}) middlewares completed, checking session`)
|
||||
|
||||
// only update store if ctx.session was touched
|
||||
if (touched)
|
||||
if (c.ref == null) {
|
||||
debug(`(${updId}) ctx.${prop} missing, removing from store`)
|
||||
await store.delete(key)
|
||||
} else {
|
||||
debug(`(${updId}) ctx.${prop} found, updating store`)
|
||||
await store.set(key, c.ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function defaultGetSessionKey(ctx: Context): string | undefined {
|
||||
const fromId = ctx.from?.id
|
||||
const chatId = ctx.chat?.id
|
||||
if (fromId == null || chatId == null) return undefined
|
||||
return `${fromId}:${chatId}`
|
||||
}
|
||||
|
||||
/** @deprecated Use `Map` */
|
||||
export class MemorySessionStore<T> implements SyncSessionStore<T> {
|
||||
private readonly store = new Map<string, { session: T; expires: number }>()
|
||||
|
||||
constructor(private readonly ttl = Infinity) {}
|
||||
|
||||
get(name: string): T | undefined {
|
||||
const entry = this.store.get(name)
|
||||
if (entry == null) {
|
||||
return undefined
|
||||
} else if (entry.expires < Date.now()) {
|
||||
this.delete(name)
|
||||
return undefined
|
||||
}
|
||||
return entry.session
|
||||
}
|
||||
|
||||
set(name: string, value: T): void {
|
||||
const now = Date.now()
|
||||
this.store.set(name, { session: value, expires: now + this.ttl })
|
||||
}
|
||||
|
||||
delete(name: string): void {
|
||||
this.store.delete(name)
|
||||
}
|
||||
}
|
||||
|
||||
/** @deprecated session can use custom properties now. Directly use `'session' in ctx` instead */
|
||||
export function isSessionContext<S extends object>(
|
||||
ctx: Context
|
||||
): ctx is SessionContext<S> {
|
||||
return 'session' in ctx
|
||||
}
|
||||
354
node_modules/telegraf/src/telegraf.ts
generated
vendored
Normal file
354
node_modules/telegraf/src/telegraf.ts
generated
vendored
Normal file
@@ -0,0 +1,354 @@
|
||||
import * as crypto from 'crypto'
|
||||
import * as http from 'http'
|
||||
import * as https from 'https'
|
||||
import * as tg from './core/types/typegram'
|
||||
import * as tt from './telegram-types'
|
||||
import { Composer } from './composer'
|
||||
import { MaybePromise } from './core/helpers/util'
|
||||
import ApiClient from './core/network/client'
|
||||
import { compactOptions } from './core/helpers/compact'
|
||||
import Context from './context'
|
||||
import d from 'debug'
|
||||
import generateCallback from './core/network/webhook'
|
||||
import { Polling } from './core/network/polling'
|
||||
import pTimeout from 'p-timeout'
|
||||
import Telegram from './telegram'
|
||||
import { TlsOptions } from 'tls'
|
||||
import { URL } from 'url'
|
||||
import safeCompare = require('safe-compare')
|
||||
const debug = d('telegraf:main')
|
||||
|
||||
const DEFAULT_OPTIONS: Telegraf.Options<Context> = {
|
||||
telegram: {},
|
||||
handlerTimeout: 90_000, // 90s in ms
|
||||
contextType: Context,
|
||||
}
|
||||
|
||||
function always<T>(x: T) {
|
||||
return () => x
|
||||
}
|
||||
|
||||
const anoop = always(Promise.resolve())
|
||||
|
||||
export namespace Telegraf {
|
||||
export interface Options<TContext extends Context> {
|
||||
contextType: new (
|
||||
...args: ConstructorParameters<typeof Context>
|
||||
) => TContext
|
||||
handlerTimeout: number
|
||||
telegram?: Partial<ApiClient.Options>
|
||||
}
|
||||
|
||||
export interface LaunchOptions {
|
||||
dropPendingUpdates?: boolean
|
||||
/** List the types of updates you want your bot to receive */
|
||||
allowedUpdates?: tt.UpdateType[]
|
||||
/** Configuration options for when the bot is run via webhooks */
|
||||
webhook?: {
|
||||
/** Public domain for webhook. */
|
||||
domain: string
|
||||
|
||||
/**
|
||||
* Webhook url path; will be automatically generated if not specified
|
||||
* @deprecated Pass `path` instead
|
||||
* */
|
||||
hookPath?: string
|
||||
|
||||
/** Webhook url path; will be automatically generated if not specified */
|
||||
path?: string
|
||||
|
||||
host?: string
|
||||
port?: number
|
||||
|
||||
/** The fixed IP address which will be used to send webhook requests instead of the IP address resolved through DNS */
|
||||
ipAddress?: string
|
||||
|
||||
/**
|
||||
* Maximum allowed number of simultaneous HTTPS connections to the webhook for update delivery, 1-100. Defaults to 40.
|
||||
* Use lower values to limit the load on your bot's server, and higher values to increase your bot's throughput.
|
||||
*/
|
||||
maxConnections?: number
|
||||
|
||||
/** TLS server options. Omit to use http. */
|
||||
tlsOptions?: TlsOptions
|
||||
|
||||
/**
|
||||
* A secret token to be sent in a header `“X-Telegram-Bot-Api-Secret-Token”` in every webhook request.
|
||||
* 1-256 characters. Only characters `A-Z`, `a-z`, `0-9`, `_` and `-` are allowed.
|
||||
* The header is useful to ensure that the request comes from a webhook set by you.
|
||||
*/
|
||||
secretToken?: string
|
||||
|
||||
/**
|
||||
* Upload your public key certificate so that the root certificate in use can be checked.
|
||||
* See [self-signed guide](https://core.telegram.org/bots/self-signed) for details.
|
||||
*/
|
||||
certificate?: tg.InputFile
|
||||
|
||||
cb?: http.RequestListener
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const TOKEN_HEADER = 'x-telegram-bot-api-secret-token'
|
||||
|
||||
export class Telegraf<C extends Context = Context> extends Composer<C> {
|
||||
private readonly options: Telegraf.Options<C>
|
||||
private webhookServer?: http.Server | https.Server
|
||||
private polling?: Polling
|
||||
/** Set manually to avoid implicit `getMe` call in `launch` or `webhookCallback` */
|
||||
public botInfo?: tg.UserFromGetMe
|
||||
public telegram: Telegram
|
||||
readonly context: Partial<C> = {}
|
||||
|
||||
/** Assign to this to customise the webhook filter middleware.
|
||||
* `{ path, secretToken }` will be bound to this rather than the Telegraf instance.
|
||||
* Remember to assign a regular function and not an arrow function so it's bindable.
|
||||
*/
|
||||
public webhookFilter = function (
|
||||
// NOTE: this function is assigned to a variable instead of being a method to signify that it's assignable
|
||||
// NOTE: the `this` binding is so custom impls don't need to double wrap
|
||||
this: {
|
||||
/** @deprecated Use path instead */
|
||||
hookPath: string
|
||||
path: string
|
||||
secretToken?: string
|
||||
},
|
||||
req: http.IncomingMessage
|
||||
) {
|
||||
const debug = d('telegraf:webhook')
|
||||
|
||||
if (req.method === 'POST') {
|
||||
if (safeCompare(this.path, req.url as string)) {
|
||||
// no need to check if secret_token was not set
|
||||
if (!this.secretToken) return true
|
||||
else {
|
||||
const token = req.headers[TOKEN_HEADER] as string
|
||||
if (safeCompare(this.secretToken, token)) return true
|
||||
else debug('Secret token does not match:', token, this.secretToken)
|
||||
}
|
||||
} else debug('Path does not match:', req.url, this.path)
|
||||
} else debug('Unexpected request method, not POST. Received:', req.method)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private handleError = (err: unknown, ctx: C): MaybePromise<void> => {
|
||||
// set exit code to emulate `warn-with-error-code` behavior of
|
||||
// https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode
|
||||
// to prevent a clean exit despite an error being thrown
|
||||
process.exitCode = 1
|
||||
console.error('Unhandled error while processing', ctx.update)
|
||||
throw err
|
||||
}
|
||||
|
||||
constructor(token: string, options?: Partial<Telegraf.Options<C>>) {
|
||||
super()
|
||||
// @ts-expect-error Trust me, TS
|
||||
this.options = {
|
||||
...DEFAULT_OPTIONS,
|
||||
...compactOptions(options),
|
||||
}
|
||||
this.telegram = new Telegram(token, this.options.telegram)
|
||||
debug('Created a `Telegraf` instance')
|
||||
}
|
||||
|
||||
private get token() {
|
||||
return this.telegram.token
|
||||
}
|
||||
|
||||
/** @deprecated use `ctx.telegram.webhookReply` */
|
||||
set webhookReply(webhookReply: boolean) {
|
||||
this.telegram.webhookReply = webhookReply
|
||||
}
|
||||
|
||||
/** @deprecated use `ctx.telegram.webhookReply` */
|
||||
get webhookReply() {
|
||||
return this.telegram.webhookReply
|
||||
}
|
||||
|
||||
/**
|
||||
* _Override_ error handling
|
||||
*/
|
||||
catch(handler: (err: unknown, ctx: C) => MaybePromise<void>) {
|
||||
this.handleError = handler
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* You must call `bot.telegram.setWebhook` for this to work.
|
||||
* You should probably use {@link Telegraf.createWebhook} instead.
|
||||
*/
|
||||
webhookCallback(path = '/', opts: { secretToken?: string } = {}) {
|
||||
const { secretToken } = opts
|
||||
return generateCallback(
|
||||
this.webhookFilter.bind({ hookPath: path, path, secretToken }),
|
||||
(update: tg.Update, res: http.ServerResponse) =>
|
||||
this.handleUpdate(update, res)
|
||||
)
|
||||
}
|
||||
|
||||
private getDomainOpts(opts: { domain: string; path?: string }) {
|
||||
const protocol =
|
||||
opts.domain.startsWith('https://') || opts.domain.startsWith('http://')
|
||||
|
||||
if (protocol)
|
||||
debug(
|
||||
'Unexpected protocol in domain, telegraf will use https:',
|
||||
opts.domain
|
||||
)
|
||||
|
||||
const domain = protocol ? new URL(opts.domain).host : opts.domain
|
||||
const path = opts.path ?? `/telegraf/${this.secretPathComponent()}`
|
||||
const url = `https://${domain}${path}`
|
||||
|
||||
return { domain, path, url }
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a url to receive incoming updates via webhook.
|
||||
* Returns an Express-style middleware you can pass to app.use()
|
||||
*/
|
||||
async createWebhook(
|
||||
opts: { domain: string; path?: string } & tt.ExtraSetWebhook
|
||||
) {
|
||||
const { domain, path, ...extra } = opts
|
||||
|
||||
const domainOpts = this.getDomainOpts({ domain, path })
|
||||
|
||||
await this.telegram.setWebhook(domainOpts.url, extra)
|
||||
debug(`Webhook set to ${domainOpts.url}`)
|
||||
|
||||
return this.webhookCallback(domainOpts.path, {
|
||||
secretToken: extra.secret_token,
|
||||
})
|
||||
}
|
||||
|
||||
private startPolling(allowedUpdates: tt.UpdateType[] = []) {
|
||||
this.polling = new Polling(this.telegram, allowedUpdates)
|
||||
return this.polling.loop(async (update) => {
|
||||
await this.handleUpdate(update)
|
||||
})
|
||||
}
|
||||
|
||||
private startWebhook(
|
||||
path: string,
|
||||
tlsOptions?: TlsOptions,
|
||||
port?: number,
|
||||
host?: string,
|
||||
cb?: http.RequestListener,
|
||||
secretToken?: string
|
||||
) {
|
||||
const webhookCb = this.webhookCallback(path, { secretToken })
|
||||
const callback: http.RequestListener =
|
||||
typeof cb === 'function'
|
||||
? (req, res) => webhookCb(req, res, () => cb(req, res))
|
||||
: webhookCb
|
||||
this.webhookServer =
|
||||
tlsOptions != null
|
||||
? https.createServer(tlsOptions, callback)
|
||||
: http.createServer(callback)
|
||||
this.webhookServer.listen(port, host, () => {
|
||||
debug('Webhook listening on port: %s', port)
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
||||
secretPathComponent() {
|
||||
return crypto
|
||||
.createHash('sha3-256')
|
||||
.update(this.token)
|
||||
.update(process.version) // salt
|
||||
.digest('hex')
|
||||
}
|
||||
|
||||
async launch(onLaunch?: () => void): Promise<void>
|
||||
async launch(
|
||||
config: Telegraf.LaunchOptions,
|
||||
onLaunch?: () => void
|
||||
): Promise<void>
|
||||
/**
|
||||
* @see https://github.com/telegraf/telegraf/discussions/1344#discussioncomment-335700
|
||||
*/
|
||||
async launch(
|
||||
config: Telegraf.LaunchOptions | (() => void) = {},
|
||||
/** @experimental */
|
||||
onLaunch?: () => void
|
||||
) {
|
||||
const [cfg, onMe] =
|
||||
typeof config === 'function' ? [{}, config] : [config, onLaunch]
|
||||
const drop_pending_updates = cfg.dropPendingUpdates
|
||||
const allowed_updates = cfg.allowedUpdates
|
||||
const webhook = cfg.webhook
|
||||
|
||||
debug('Connecting to Telegram')
|
||||
this.botInfo ??= await this.telegram.getMe()
|
||||
onMe?.()
|
||||
debug(`Launching @${this.botInfo.username}`)
|
||||
|
||||
if (webhook === undefined) {
|
||||
await this.telegram.deleteWebhook({ drop_pending_updates })
|
||||
debug('Bot started with long polling')
|
||||
await this.startPolling(allowed_updates)
|
||||
return
|
||||
}
|
||||
|
||||
const domainOpts = this.getDomainOpts({
|
||||
domain: webhook.domain,
|
||||
path: webhook.path ?? webhook.hookPath,
|
||||
})
|
||||
|
||||
const { tlsOptions, port, host, cb, secretToken } = webhook
|
||||
|
||||
this.startWebhook(domainOpts.path, tlsOptions, port, host, cb, secretToken)
|
||||
|
||||
await this.telegram.setWebhook(domainOpts.url, {
|
||||
drop_pending_updates: drop_pending_updates,
|
||||
allowed_updates: allowed_updates,
|
||||
ip_address: webhook.ipAddress,
|
||||
max_connections: webhook.maxConnections,
|
||||
secret_token: webhook.secretToken,
|
||||
certificate: webhook.certificate,
|
||||
})
|
||||
|
||||
debug(`Bot started with webhook @ ${domainOpts.url}`)
|
||||
}
|
||||
|
||||
stop(reason = 'unspecified') {
|
||||
debug('Stopping bot... Reason:', reason)
|
||||
// https://github.com/telegraf/telegraf/pull/1224#issuecomment-742693770
|
||||
if (this.polling === undefined && this.webhookServer === undefined) {
|
||||
throw new Error('Bot is not running!')
|
||||
}
|
||||
this.webhookServer?.close()
|
||||
this.polling?.stop()
|
||||
}
|
||||
|
||||
private botInfoCall?: Promise<tg.UserFromGetMe>
|
||||
async handleUpdate(update: tg.Update, webhookResponse?: http.ServerResponse) {
|
||||
this.botInfo ??=
|
||||
(debug(
|
||||
'Update %d is waiting for `botInfo` to be initialized',
|
||||
update.update_id
|
||||
),
|
||||
await (this.botInfoCall ??= this.telegram.getMe()))
|
||||
debug('Processing update', update.update_id)
|
||||
const tg = new Telegram(this.token, this.telegram.options, webhookResponse)
|
||||
const TelegrafContext = this.options.contextType
|
||||
const ctx = new TelegrafContext(update, tg, this.botInfo)
|
||||
Object.assign(ctx, this.context)
|
||||
try {
|
||||
await pTimeout(
|
||||
Promise.resolve(this.middleware()(ctx, anoop)),
|
||||
this.options.handlerTimeout
|
||||
)
|
||||
} catch (err) {
|
||||
return await this.handleError(err, ctx)
|
||||
} finally {
|
||||
if (webhookResponse?.writableEnded === false) {
|
||||
webhookResponse.end()
|
||||
}
|
||||
debug('Finished processing update', update.update_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
219
node_modules/telegraf/src/telegram-types.ts
generated
vendored
Normal file
219
node_modules/telegraf/src/telegram-types.ts
generated
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
/** @format */
|
||||
|
||||
import { Expand } from './core/helpers/util'
|
||||
import {
|
||||
Message,
|
||||
Opts,
|
||||
Telegram,
|
||||
Update,
|
||||
InputMediaAudio,
|
||||
InputMediaDocument,
|
||||
InputMediaPhoto,
|
||||
InputMediaVideo,
|
||||
} from './core/types/typegram'
|
||||
|
||||
import { UnionKeys } from './core/helpers/deunionize'
|
||||
import { FmtString } from './format'
|
||||
|
||||
export { Markup } from './markup'
|
||||
|
||||
// tiny helper types
|
||||
export type ChatAction = Opts<'sendChatAction'>['action']
|
||||
|
||||
// Modify type so caption, if exists, can be FmtString
|
||||
export type WrapCaption<T> = T extends { caption?: string }
|
||||
? Expand<Omit<T, 'caption'> & { caption?: string | FmtString }>
|
||||
: T
|
||||
|
||||
// extra types
|
||||
/**
|
||||
* Create an `Extra*` type from the arguments of a given method `M extends keyof Telegram` but `Omit`ting fields with key `K` from it.
|
||||
*
|
||||
* Note that `chat_id` may not be specified in `K` because it is `Omit`ted by default.
|
||||
*/
|
||||
type MakeExtra<
|
||||
M extends keyof Telegram,
|
||||
K extends keyof Omit<Opts<M>, 'chat_id'> = never,
|
||||
> = WrapCaption<Omit<Opts<M>, 'chat_id' | K>>
|
||||
|
||||
export type ExtraAddStickerToSet = MakeExtra<
|
||||
'addStickerToSet',
|
||||
'name' | 'user_id'
|
||||
>
|
||||
export type ExtraAnimation = MakeExtra<'sendAnimation', 'animation'>
|
||||
export type ExtraAnswerCbQuery = MakeExtra<
|
||||
'answerCallbackQuery',
|
||||
'text' | 'callback_query_id'
|
||||
>
|
||||
export type ExtraAnswerInlineQuery = MakeExtra<
|
||||
'answerInlineQuery',
|
||||
'inline_query_id' | 'results'
|
||||
>
|
||||
export type ExtraSetChatPermissions = MakeExtra<
|
||||
'setChatPermissions',
|
||||
'permissions'
|
||||
>
|
||||
export type ExtraAudio = MakeExtra<'sendAudio', 'audio'>
|
||||
export type ExtraContact = MakeExtra<
|
||||
'sendContact',
|
||||
'phone_number' | 'first_name'
|
||||
>
|
||||
export type ExtraCopyMessage = MakeExtra<
|
||||
'copyMessage',
|
||||
'from_chat_id' | 'message_id'
|
||||
>
|
||||
export type ExtraCopyMessages = MakeExtra<
|
||||
'copyMessages',
|
||||
'from_chat_id' | 'message_ids'
|
||||
>
|
||||
export type ExtraCreateChatInviteLink = MakeExtra<'createChatInviteLink'>
|
||||
export type NewInvoiceLinkParameters = MakeExtra<'createInvoiceLink'>
|
||||
export type ExtraCreateNewStickerSet = MakeExtra<
|
||||
'createNewStickerSet',
|
||||
'name' | 'title' | 'user_id'
|
||||
>
|
||||
export type ExtraDice = MakeExtra<'sendDice'>
|
||||
export type ExtraDocument = MakeExtra<'sendDocument', 'document'>
|
||||
export type ExtraEditChatInviteLink = MakeExtra<
|
||||
'editChatInviteLink',
|
||||
'invite_link'
|
||||
>
|
||||
export type ExtraEditMessageCaption = MakeExtra<
|
||||
'editMessageCaption',
|
||||
'message_id' | 'inline_message_id' | 'caption'
|
||||
>
|
||||
export type ExtraEditMessageLiveLocation = MakeExtra<
|
||||
'editMessageLiveLocation',
|
||||
'message_id' | 'inline_message_id' | 'latitude' | 'longitude'
|
||||
>
|
||||
export type ExtraEditMessageMedia = MakeExtra<
|
||||
'editMessageMedia',
|
||||
'message_id' | 'inline_message_id' | 'media'
|
||||
>
|
||||
export type ExtraEditMessageText = MakeExtra<
|
||||
'editMessageText',
|
||||
'message_id' | 'inline_message_id' | 'text'
|
||||
>
|
||||
export type ExtraGame = MakeExtra<'sendGame', 'game_short_name'>
|
||||
export type NewInvoiceParameters = MakeExtra<
|
||||
'sendInvoice',
|
||||
| 'disable_notification'
|
||||
| 'reply_parameters'
|
||||
| 'reply_markup'
|
||||
| 'message_thread_id'
|
||||
>
|
||||
export type ExtraInvoice = MakeExtra<'sendInvoice', keyof NewInvoiceParameters>
|
||||
export type ExtraBanChatMember = MakeExtra<
|
||||
'banChatMember',
|
||||
'user_id' | 'until_date'
|
||||
>
|
||||
export type ExtraKickChatMember = ExtraBanChatMember
|
||||
export type ExtraLocation = MakeExtra<'sendLocation', 'latitude' | 'longitude'>
|
||||
export type ExtraMediaGroup = MakeExtra<'sendMediaGroup', 'media'>
|
||||
export type ExtraPhoto = MakeExtra<'sendPhoto', 'photo'>
|
||||
export type ExtraPoll = MakeExtra<'sendPoll', 'question' | 'options' | 'type'>
|
||||
export type ExtraPromoteChatMember = MakeExtra<'promoteChatMember', 'user_id'>
|
||||
export type ExtraReplyMessage = MakeExtra<'sendMessage', 'text'>
|
||||
export type ExtraForwardMessage = MakeExtra<
|
||||
'forwardMessage',
|
||||
'from_chat_id' | 'message_id'
|
||||
>
|
||||
export type ExtraForwardMessages = MakeExtra<
|
||||
'forwardMessages',
|
||||
'from_chat_id' | 'message_ids'
|
||||
>
|
||||
export type ExtraSendChatAction = MakeExtra<'sendChatAction', 'action'>
|
||||
export type ExtraRestrictChatMember = MakeExtra<'restrictChatMember', 'user_id'>
|
||||
export type ExtraSetMyCommands = MakeExtra<'setMyCommands', 'commands'>
|
||||
export type ExtraSetWebhook = MakeExtra<'setWebhook', 'url'>
|
||||
export type ExtraSticker = MakeExtra<'sendSticker', 'sticker'>
|
||||
export type ExtraStopPoll = MakeExtra<'stopPoll', 'message_id'>
|
||||
export type ExtraVenue = MakeExtra<
|
||||
'sendVenue',
|
||||
'latitude' | 'longitude' | 'title' | 'address'
|
||||
>
|
||||
export type ExtraVideo = MakeExtra<'sendVideo', 'video'>
|
||||
export type ExtraVideoNote = MakeExtra<'sendVideoNote', 'video_note'>
|
||||
export type ExtraVoice = MakeExtra<'sendVoice', 'voice'>
|
||||
export type ExtraBanChatSenderChat = MakeExtra<
|
||||
'banChatSenderChat',
|
||||
'sender_chat_id'
|
||||
>
|
||||
export type ExtraCreateForumTopic = MakeExtra<'createForumTopic', 'name'>
|
||||
export type ExtraEditForumTopic = MakeExtra<
|
||||
'editForumTopic',
|
||||
'message_thread_id'
|
||||
>
|
||||
|
||||
export type MediaGroup =
|
||||
| readonly (InputMediaPhoto | InputMediaVideo)[]
|
||||
| readonly InputMediaAudio[]
|
||||
| readonly InputMediaDocument[]
|
||||
|
||||
// types used for inference of ctx object
|
||||
|
||||
/** Possible update types */
|
||||
export type UpdateType = Exclude<UnionKeys<Update>, keyof Update>
|
||||
|
||||
/** Possible message subtypes. Same as the properties on a message object */
|
||||
export type MessageSubType =
|
||||
| 'forward_date'
|
||||
| Exclude<
|
||||
UnionKeys<Message>,
|
||||
keyof Message.CaptionableMessage | 'entities' | 'media_group_id'
|
||||
>
|
||||
|
||||
type ExtractPartial<T extends object, U extends object> = T extends unknown
|
||||
? Required<T> extends U
|
||||
? T
|
||||
: never
|
||||
: never
|
||||
|
||||
/**
|
||||
* Maps [[`Composer.on`]]'s `updateType` or `messageSubType` to a `tt.Update` subtype.
|
||||
* @deprecated
|
||||
*/
|
||||
export type MountMap = {
|
||||
[T in UpdateType]: Extract<Update, Record<T, object>>
|
||||
} & {
|
||||
[T in MessageSubType]: {
|
||||
message: ExtractPartial<Update.MessageUpdate['message'], Record<T, unknown>>
|
||||
update_id: number
|
||||
}
|
||||
}
|
||||
|
||||
export interface CommandContextExtn {
|
||||
match: RegExpExecArray
|
||||
/**
|
||||
* Matched command. This will always be the actual command, excluding preceeding slash and `@botname`
|
||||
*
|
||||
* Examples:
|
||||
* ```
|
||||
* /command abc -> command
|
||||
* /command@xyzbot abc -> command
|
||||
* ```
|
||||
*/
|
||||
command: string
|
||||
/**
|
||||
* The unparsed payload part of the command
|
||||
*
|
||||
* Examples:
|
||||
* ```
|
||||
* /command abc def -> "abc def"
|
||||
* /command "token1 token2" -> "\"token1 token2\""
|
||||
* ```
|
||||
*/
|
||||
payload: string
|
||||
/**
|
||||
* Command args parsed into an array.
|
||||
*
|
||||
* Examples:
|
||||
* ```
|
||||
* /command token1 token2 -> [ "token1", "token2" ]
|
||||
* /command "token1 token2" -> [ "token1 token2" ]
|
||||
* /command token1 "token2 token3" -> [ "token1" "token2 token3" ]
|
||||
* ```
|
||||
* @unstable Parser implementation might vary until considered stable
|
||||
* */
|
||||
args: string[]
|
||||
}
|
||||
1635
node_modules/telegraf/src/telegram.ts
generated
vendored
Normal file
1635
node_modules/telegraf/src/telegram.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
node_modules/telegraf/src/types.ts
generated
vendored
Normal file
2
node_modules/telegraf/src/types.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export type * from './core/types/typegram'
|
||||
export type * as Convenience from './telegram-types'
|
||||
1
node_modules/telegraf/src/utils.ts
generated
vendored
Normal file
1
node_modules/telegraf/src/utils.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export { argsParser } from './core/helpers/args'
|
||||
1
node_modules/telegraf/types.d.ts
generated
vendored
Normal file
1
node_modules/telegraf/types.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './typings/types'
|
||||
1
node_modules/telegraf/types.js
generated
vendored
Normal file
1
node_modules/telegraf/types.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./lib/types')
|
||||
36
node_modules/telegraf/typings/button.d.ts
generated
vendored
Normal file
36
node_modules/telegraf/typings/button.d.ts
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
import { InlineKeyboardButton, KeyboardButton, KeyboardButtonRequestChat, KeyboardButtonRequestUsers } from './core/types/typegram';
|
||||
type Hideable<B> = B & {
|
||||
hide: boolean;
|
||||
};
|
||||
export declare function text(text: string, hide?: boolean): Hideable<KeyboardButton.CommonButton>;
|
||||
export declare function contactRequest(text: string, hide?: boolean): Hideable<KeyboardButton.RequestContactButton>;
|
||||
export declare function locationRequest(text: string, hide?: boolean): Hideable<KeyboardButton.RequestLocationButton>;
|
||||
export declare function pollRequest(text: string, type?: 'quiz' | 'regular', hide?: boolean): Hideable<KeyboardButton.RequestPollButton>;
|
||||
export declare function userRequest(text: string,
|
||||
/** Must fit in a signed 32 bit int */
|
||||
request_id: number, extra?: Omit<KeyboardButtonRequestUsers, 'request_id' | 'text'>, hide?: boolean): Hideable<KeyboardButton.RequestUsersButton>;
|
||||
export declare function botRequest(text: string,
|
||||
/** Must fit in a signed 32 bit int */
|
||||
request_id: number, extra?: Omit<KeyboardButtonRequestUsers, 'request_id' | 'user_is_bot' | 'text'>, hide?: boolean): Hideable<KeyboardButton.RequestUsersButton>;
|
||||
type KeyboardButtonRequestGroup = Omit<KeyboardButtonRequestChat, 'request_id' | 'chat_is_channel'>;
|
||||
export declare function groupRequest(text: string,
|
||||
/** Must fit in a signed 32 bit int */
|
||||
request_id: number, extra?: KeyboardButtonRequestGroup, hide?: boolean): Hideable<KeyboardButton.RequestChatButton>;
|
||||
type KeyboardButtonRequestChannel = Omit<KeyboardButtonRequestChat, 'request_id' | 'chat_is_channel' | 'chat_is_forum'>;
|
||||
export declare function channelRequest(text: string,
|
||||
/** Must fit in a signed 32 bit int */
|
||||
request_id: number, extra?: KeyboardButtonRequestChannel, hide?: boolean): Hideable<KeyboardButton.RequestChatButton>;
|
||||
export declare function url(text: string, url: string, hide?: boolean): Hideable<InlineKeyboardButton.UrlButton>;
|
||||
export declare function callback(text: string, data: string, hide?: boolean): Hideable<InlineKeyboardButton.CallbackButton>;
|
||||
export declare function switchToChat(text: string, value: string, hide?: boolean): Hideable<InlineKeyboardButton.SwitchInlineButton>;
|
||||
export declare function switchToCurrentChat(text: string, value: string, hide?: boolean): Hideable<InlineKeyboardButton.SwitchInlineCurrentChatButton>;
|
||||
export declare function game(text: string, hide?: boolean): Hideable<InlineKeyboardButton.GameButton>;
|
||||
export declare function pay(text: string, hide?: boolean): Hideable<InlineKeyboardButton.PayButton>;
|
||||
export declare function login(text: string, url: string, opts?: {
|
||||
forward_text?: string;
|
||||
bot_username?: string;
|
||||
request_write_access?: boolean;
|
||||
}, hide?: boolean): Hideable<InlineKeyboardButton.LoginButton>;
|
||||
export declare function webApp(text: string, url: string, hide?: boolean): Hideable<InlineKeyboardButton.WebAppButton>;
|
||||
export {};
|
||||
//# sourceMappingURL=button.d.ts.map
|
||||
1
node_modules/telegraf/typings/button.d.ts.map
generated
vendored
Normal file
1
node_modules/telegraf/typings/button.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../src/button.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,yBAAyB,EACzB,0BAA0B,EAC3B,MAAM,uBAAuB,CAAA;AAE9B,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAA;AAExC,wBAAgB,IAAI,CAClB,IAAI,EAAE,MAAM,EACZ,IAAI,UAAQ,GACX,QAAQ,CAAC,cAAc,CAAC,YAAY,CAAC,CAEvC;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,UAAQ,GACX,QAAQ,CAAC,cAAc,CAAC,oBAAoB,CAAC,CAE/C;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,UAAQ,GACX,QAAQ,CAAC,cAAc,CAAC,qBAAqB,CAAC,CAEhD;AAED,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,EACzB,IAAI,UAAQ,GACX,QAAQ,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAE5C;AAED,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM;AACZ,sCAAsC;AACtC,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,IAAI,CAAC,0BAA0B,EAAE,YAAY,GAAG,MAAM,CAAC,EAC/D,IAAI,UAAQ,GACX,QAAQ,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAM7C;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM;AACZ,sCAAsC;AACtC,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,IAAI,CACV,0BAA0B,EAC1B,YAAY,GAAG,aAAa,GAAG,MAAM,CACtC,EACD,IAAI,UAAQ,GACX,QAAQ,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAM7C;AAED,KAAK,0BAA0B,GAAG,IAAI,CACpC,yBAAyB,EACzB,YAAY,GAAG,iBAAiB,CACjC,CAAA;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM;AACZ,sCAAsC;AACtC,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,0BAA0B,EAClC,IAAI,UAAQ,GACX,QAAQ,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAM5C;AAED,KAAK,4BAA4B,GAAG,IAAI,CACtC,yBAAyB,EACzB,YAAY,GAAG,iBAAiB,GAAG,eAAe,CACnD,CAAA;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM;AACZ,sCAAsC;AACtC,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,4BAA4B,EACpC,IAAI,UAAQ,GACX,QAAQ,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAM5C;AAED,wBAAgB,GAAG,CACjB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,IAAI,UAAQ,GACX,QAAQ,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAE1C;AAED,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,UAAQ,GACX,QAAQ,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAE/C;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,UAAQ,GACX,QAAQ,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,CAEnD;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,UAAQ,GACX,QAAQ,CAAC,oBAAoB,CAAC,6BAA6B,CAAC,CAE9D;AAED,wBAAgB,IAAI,CAClB,IAAI,EAAE,MAAM,EACZ,IAAI,UAAQ,GACX,QAAQ,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAE3C;AAED,wBAAgB,GAAG,CACjB,IAAI,EAAE,MAAM,EACZ,IAAI,UAAQ,GACX,QAAQ,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAE1C;AAED,wBAAgB,KAAK,CACnB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,IAAI,GAAE;IACJ,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC1B,EACN,IAAI,UAAQ,GACX,QAAQ,CAAC,oBAAoB,CAAC,WAAW,CAAC,CAM5C;AAED,wBAAgB,MAAM,CACpB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,IAAI,UAAQ,GAEX,QAAQ,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAM7C"}
|
||||
227
node_modules/telegraf/typings/composer.d.ts
generated
vendored
Normal file
227
node_modules/telegraf/typings/composer.d.ts
generated
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
/** @format */
|
||||
import * as tg from './core/types/typegram';
|
||||
import * as tt from './telegram-types';
|
||||
import { Middleware, MiddlewareFn, MiddlewareObj } from './middleware';
|
||||
import Context, { FilteredContext, NarrowedContext } from './context';
|
||||
import { MaybeArray, NonemptyReadonlyArray, MaybePromise, Guard } from './core/helpers/util';
|
||||
import { type CallbackQuery } from './core/types/typegram';
|
||||
import { Digit, Reaction } from './reactions';
|
||||
type ReactionAddedOrRemoved = Reaction | `-${tg.TelegramEmoji}` | `-${Digit}${string}`;
|
||||
export type Triggers<C> = MaybeArray<string | RegExp | TriggerFn<C>>;
|
||||
type TriggerFn<C> = (value: string, ctx: C) => RegExpExecArray | null;
|
||||
export type Predicate<T> = (t: T) => boolean;
|
||||
export type AsyncPredicate<T> = (t: T) => Promise<boolean>;
|
||||
export type MatchedMiddleware<C extends Context, T extends tt.UpdateType | tt.MessageSubType = 'message' | 'channel_post'> = NonemptyReadonlyArray<Middleware<NarrowedContext<C, tt.MountMap[T]> & {
|
||||
match: RegExpExecArray;
|
||||
}, tt.MountMap[T]>>;
|
||||
interface StartContextExtn extends tt.CommandContextExtn {
|
||||
/**
|
||||
* @deprecated Use ctx.payload instead
|
||||
*/
|
||||
startPayload: string;
|
||||
}
|
||||
export declare class Composer<C extends Context> implements MiddlewareObj<C> {
|
||||
private handler;
|
||||
constructor(...fns: ReadonlyArray<Middleware<C>>);
|
||||
/**
|
||||
* Registers a middleware.
|
||||
*/
|
||||
use(...fns: ReadonlyArray<Middleware<C>>): this;
|
||||
/**
|
||||
* Registers middleware for handling updates
|
||||
* matching given type guard function.
|
||||
* @deprecated use `Composer::on`
|
||||
*/
|
||||
guard<U extends tg.Update>(guardFn: (update: tg.Update) => update is U, ...fns: NonemptyReadonlyArray<Middleware<NarrowedContext<C, U>, U>>): this;
|
||||
/**
|
||||
* Registers middleware for handling updates narrowed by update types or filter queries.
|
||||
*/
|
||||
on<Filter extends tt.UpdateType | Guard<C['update']>>(filters: MaybeArray<Filter>, ...fns: NonemptyReadonlyArray<Middleware<FilteredContext<C, Filter>>>): this;
|
||||
/**
|
||||
* Registers middleware for handling updates narrowed by update types or message subtypes.
|
||||
* @deprecated Use filter utils instead. Support for Message subtype in `Composer::on` will be removed in Telegraf v5.
|
||||
*/
|
||||
on<Filter extends tt.UpdateType | tt.MessageSubType>(filters: MaybeArray<Filter>, ...fns: NonemptyReadonlyArray<Middleware<NarrowedContext<C, tt.MountMap[Filter]>, tt.MountMap[Filter]>>): this;
|
||||
/**
|
||||
* Registers middleware for handling matching text messages.
|
||||
*/
|
||||
hears(triggers: Triggers<NarrowedContext<C, tt.MountMap['text']>>, ...fns: MatchedMiddleware<C, 'text'>): this;
|
||||
/**
|
||||
* Registers middleware for handling specified commands.
|
||||
*/
|
||||
command(command: Triggers<NarrowedContext<C, tt.MountMap['text']>>, ...fns: NonemptyReadonlyArray<Middleware<NarrowedContext<C, tt.MountMap['text']> & tt.CommandContextExtn>>): this;
|
||||
/**
|
||||
* Registers middleware for handling matching callback queries.
|
||||
*/
|
||||
action(triggers: Triggers<NarrowedContext<C, tt.MountMap['callback_query']>>, ...fns: MatchedMiddleware<C, 'callback_query'>): this;
|
||||
/**
|
||||
* Registers middleware for handling matching inline queries.
|
||||
*/
|
||||
inlineQuery(triggers: Triggers<NarrowedContext<C, tt.MountMap['inline_query']>>, ...fns: MatchedMiddleware<C, 'inline_query'>): this;
|
||||
/**
|
||||
* Registers middleware for handling game queries
|
||||
*/
|
||||
gameQuery(...fns: NonemptyReadonlyArray<Middleware<NarrowedContext<C, tg.Update.CallbackQueryUpdate<CallbackQuery.GameQuery>>>>): this;
|
||||
reaction(reaction: MaybeArray<ReactionAddedOrRemoved>, ...fns: NonemptyReadonlyArray<Middleware<NarrowedContext<C, tg.Update.MessageReactionUpdate> & {
|
||||
match: ReactionAddedOrRemoved;
|
||||
}, tg.Update.MessageReactionUpdate>>): this;
|
||||
/**
|
||||
* Registers middleware for dropping matching updates.
|
||||
*/
|
||||
drop(predicate: Predicate<C>): this;
|
||||
/** @deprecated use `Composer::drop` */
|
||||
filter(predicate: Predicate<C>): this;
|
||||
private entity;
|
||||
email(email: Triggers<C>, ...fns: MatchedMiddleware<C>): this;
|
||||
url(url: Triggers<C>, ...fns: MatchedMiddleware<C>): this;
|
||||
textLink(link: Triggers<C>, ...fns: MatchedMiddleware<C>): this;
|
||||
textMention(mention: Triggers<C>, ...fns: MatchedMiddleware<C>): this;
|
||||
mention(mention: MaybeArray<string>, ...fns: MatchedMiddleware<C>): this;
|
||||
phone(number: Triggers<C>, ...fns: MatchedMiddleware<C>): this;
|
||||
hashtag(hashtag: MaybeArray<string>, ...fns: MatchedMiddleware<C>): this;
|
||||
cashtag(cashtag: MaybeArray<string>, ...fns: MatchedMiddleware<C>): this;
|
||||
spoiler(text: Triggers<C>, ...fns: MatchedMiddleware<C>): this;
|
||||
/**
|
||||
* Registers a middleware for handling /start
|
||||
*/
|
||||
start(...fns: NonemptyReadonlyArray<Middleware<NarrowedContext<C, tt.MountMap['text']> & StartContextExtn>>): this;
|
||||
/**
|
||||
* Registers a middleware for handling /help
|
||||
*/
|
||||
help(...fns: NonemptyReadonlyArray<Middleware<NarrowedContext<C, tt.MountMap['text']> & tt.CommandContextExtn>>): this;
|
||||
/**
|
||||
* Registers a middleware for handling /settings
|
||||
*/
|
||||
settings(...fns: NonemptyReadonlyArray<Middleware<NarrowedContext<C, tt.MountMap['text']> & tt.CommandContextExtn>>): this;
|
||||
middleware(): MiddlewareFn<C>;
|
||||
static reply(...args: Parameters<Context['reply']>): MiddlewareFn<Context>;
|
||||
static catch<C extends Context>(errorHandler: (err: unknown, ctx: C) => void, ...fns: ReadonlyArray<Middleware<C>>): MiddlewareFn<C>;
|
||||
/**
|
||||
* Generates middleware that runs in the background.
|
||||
*/
|
||||
static fork<C extends Context>(middleware: Middleware<C>): MiddlewareFn<C>;
|
||||
static tap<C extends Context>(middleware: Middleware<C>): MiddlewareFn<C>;
|
||||
/**
|
||||
* Generates middleware that gives up control to the next middleware.
|
||||
*/
|
||||
static passThru(): MiddlewareFn<Context>;
|
||||
static lazy<C extends Context>(factoryFn: (ctx: C) => MaybePromise<Middleware<C>>): MiddlewareFn<C>;
|
||||
static log(logFn?: (s: string) => void): MiddlewareFn<Context>;
|
||||
/**
|
||||
* @param trueMiddleware middleware to run if the predicate returns true
|
||||
* @param falseMiddleware middleware to run if the predicate returns false
|
||||
*/
|
||||
static branch<C extends Context>(predicate: boolean | Predicate<C> | AsyncPredicate<C>, trueMiddleware: Middleware<C>, falseMiddleware: Middleware<C>): MiddlewareFn<C>;
|
||||
/**
|
||||
* Generates optional middleware.
|
||||
* @param predicate predicate to decide on a context object whether to run the middleware
|
||||
* @param fns middleware to run if the predicate returns true
|
||||
*/
|
||||
static optional<C extends Context>(predicate: Predicate<C> | AsyncPredicate<C>, ...fns: NonemptyReadonlyArray<Middleware<C>>): MiddlewareFn<C>;
|
||||
/** @deprecated use `Composer.drop` */
|
||||
static filter<C extends Context>(predicate: Predicate<C>): MiddlewareFn<C>;
|
||||
/**
|
||||
* Generates middleware for dropping matching updates.
|
||||
*/
|
||||
static drop<C extends Context>(predicate: Predicate<C>): MiddlewareFn<C>;
|
||||
static dispatch<C extends Context, Handlers extends Record<string | number | symbol, Middleware<C>>>(routeFn: (ctx: C) => MaybePromise<keyof Handlers>, handlers: Handlers): Middleware<C>;
|
||||
/**
|
||||
* Generates optional middleware based on a predicate that only operates on `ctx.update`.
|
||||
*
|
||||
* Example:
|
||||
* ```ts
|
||||
* import { Composer, Update } from 'telegraf'
|
||||
*
|
||||
* const predicate = (u): u is Update.MessageUpdate => 'message' in u
|
||||
* const middleware = Composer.guard(predicate, (ctx) => {
|
||||
* const message = ctx.update.message
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* Note that `Composer.on('message')` is preferred over this.
|
||||
*
|
||||
* @param guardFn predicate to decide whether to run the middleware based on the `ctx.update` object
|
||||
* @param fns middleware to run if the predicate returns true
|
||||
* @see `Composer.optional` for a more generic version of this method that allows the predicate to operate on `ctx` itself
|
||||
* @deprecated use `Composer.on`
|
||||
*/
|
||||
static guard<C extends Context, U extends tg.Update>(guardFn: (u: tg.Update) => u is U, ...fns: NonemptyReadonlyArray<Middleware<NarrowedContext<C, U>, U>>): MiddlewareFn<C>;
|
||||
/**
|
||||
* Generates middleware for handling updates narrowed by update types or filter queries.
|
||||
*/
|
||||
static on<Ctx extends Context, Filter extends tt.UpdateType | Guard<Ctx['update']>>(filters: MaybeArray<Filter>, ...fns: NonemptyReadonlyArray<Middleware<FilteredContext<Ctx, Filter>>>): MiddlewareFn<Ctx>;
|
||||
/**
|
||||
* Generates middleware for handling updates narrowed by update types or message subtype.
|
||||
* @deprecated Use filter utils instead. Support for Message subtype in `Composer.on` will be removed in Telegraf v5.
|
||||
*/
|
||||
static on<Ctx extends Context, Filter extends tt.UpdateType | tt.MessageSubType>(filters: MaybeArray<Filter>, ...fns: NonemptyReadonlyArray<Middleware<NarrowedContext<Ctx, tt.MountMap[Filter]>, tt.MountMap[Filter]>>): MiddlewareFn<Ctx>;
|
||||
/**
|
||||
* Generates middleware for handling provided update types.
|
||||
* @deprecated use `Composer.on` instead
|
||||
*/
|
||||
static mount: typeof Composer.on;
|
||||
private static entity;
|
||||
static entityText<C extends Context>(entityType: MaybeArray<string>, predicate: Triggers<C>, ...fns: MatchedMiddleware<C>): MiddlewareFn<C>;
|
||||
static email<C extends Context>(email: Triggers<C>, ...fns: MatchedMiddleware<C>): MiddlewareFn<C>;
|
||||
static phone<C extends Context>(number: Triggers<C>, ...fns: MatchedMiddleware<C>): MiddlewareFn<C>;
|
||||
static url<C extends Context>(url: Triggers<C>, ...fns: MatchedMiddleware<C>): MiddlewareFn<C>;
|
||||
static textLink<C extends Context>(link: Triggers<C>, ...fns: MatchedMiddleware<C>): MiddlewareFn<C>;
|
||||
static textMention<C extends Context>(mention: Triggers<C>, ...fns: MatchedMiddleware<C>): MiddlewareFn<C>;
|
||||
static mention<C extends Context>(mention: MaybeArray<string>, ...fns: MatchedMiddleware<C>): MiddlewareFn<C>;
|
||||
static hashtag<C extends Context>(hashtag: MaybeArray<string>, ...fns: MatchedMiddleware<C>): MiddlewareFn<C>;
|
||||
static cashtag<C extends Context>(cashtag: MaybeArray<string>, ...fns: MatchedMiddleware<C>): MiddlewareFn<C>;
|
||||
static spoiler<C extends Context>(text: Triggers<C>, ...fns: MatchedMiddleware<C>): MiddlewareFn<C>;
|
||||
private static match;
|
||||
/**
|
||||
* Generates middleware for handling matching text messages.
|
||||
*/
|
||||
static hears<C extends Context>(triggers: Triggers<NarrowedContext<C, tt.MountMap['text']>>, ...fns: MatchedMiddleware<C, 'text'>): MiddlewareFn<C>;
|
||||
/**
|
||||
* Generates middleware for handling specified commands.
|
||||
*/
|
||||
static command<C extends Context>(command: Triggers<NarrowedContext<C, tt.MountMap['text']>>, ...fns: NonemptyReadonlyArray<Middleware<NarrowedContext<C, tt.MountMap['text']> & tt.CommandContextExtn>>): MiddlewareFn<C>;
|
||||
/**
|
||||
* Generates middleware for handling matching callback queries.
|
||||
*/
|
||||
static action<C extends Context>(triggers: Triggers<NarrowedContext<C, tt.MountMap['callback_query']>>, ...fns: MatchedMiddleware<C, 'callback_query'>): MiddlewareFn<C>;
|
||||
/**
|
||||
* Generates middleware for handling matching inline queries.
|
||||
*/
|
||||
static inlineQuery<C extends Context>(triggers: Triggers<NarrowedContext<C, tt.MountMap['inline_query']>>, ...fns: MatchedMiddleware<C, 'inline_query'>): MiddlewareFn<C>;
|
||||
static reaction<C extends Context>(reaction: MaybeArray<ReactionAddedOrRemoved>, ...fns: NonemptyReadonlyArray<Middleware<NarrowedContext<C, tg.Update.MessageReactionUpdate> & {
|
||||
match: ReactionAddedOrRemoved;
|
||||
}, tg.Update.MessageReactionUpdate>>): MiddlewareFn<C>;
|
||||
/**
|
||||
* Generates middleware responding only to specified users.
|
||||
*/
|
||||
static acl<C extends Context>(userId: MaybeArray<number>, ...fns: NonemptyReadonlyArray<Middleware<C>>): MiddlewareFn<C>;
|
||||
private static memberStatus;
|
||||
/**
|
||||
* Generates middleware responding only to chat admins and chat creator.
|
||||
*/
|
||||
static admin<C extends Context>(...fns: NonemptyReadonlyArray<Middleware<C>>): MiddlewareFn<C>;
|
||||
/**
|
||||
* Generates middleware responding only to chat creator.
|
||||
*/
|
||||
static creator<C extends Context>(...fns: NonemptyReadonlyArray<Middleware<C>>): MiddlewareFn<C>;
|
||||
/**
|
||||
* Generates middleware running only in specified chat types.
|
||||
*/
|
||||
static chatType<C extends Context>(type: MaybeArray<tg.Chat['type']>, ...fns: NonemptyReadonlyArray<Middleware<C>>): MiddlewareFn<C>;
|
||||
/**
|
||||
* Generates middleware running only in private chats.
|
||||
*/
|
||||
static privateChat<C extends Context>(...fns: NonemptyReadonlyArray<Middleware<C>>): MiddlewareFn<C>;
|
||||
/**
|
||||
* Generates middleware running only in groups and supergroups.
|
||||
*/
|
||||
static groupChat<C extends Context>(...fns: NonemptyReadonlyArray<Middleware<C>>): MiddlewareFn<C>;
|
||||
/**
|
||||
* Generates middleware for handling game queries.
|
||||
*/
|
||||
static gameQuery<C extends Context>(...fns: NonemptyReadonlyArray<Middleware<NarrowedContext<C, tg.Update.CallbackQueryUpdate<CallbackQuery.GameQuery>>>>): MiddlewareFn<C>;
|
||||
static unwrap<C extends Context>(handler: Middleware<C>): MiddlewareFn<C>;
|
||||
static compose<C extends Context>(middlewares: ReadonlyArray<Middleware<C>>): MiddlewareFn<C>;
|
||||
}
|
||||
export default Composer;
|
||||
//# sourceMappingURL=composer.d.ts.map
|
||||
1
node_modules/telegraf/typings/composer.d.ts.map
generated
vendored
Normal file
1
node_modules/telegraf/typings/composer.d.ts.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
655
node_modules/telegraf/typings/context.d.ts
generated
vendored
Normal file
655
node_modules/telegraf/typings/context.d.ts
generated
vendored
Normal file
@@ -0,0 +1,655 @@
|
||||
import * as tg from './core/types/typegram';
|
||||
import * as tt from './telegram-types';
|
||||
import { Deunionize, PropOr, UnionKeys } from './core/helpers/deunionize';
|
||||
import ApiClient from './core/network/client';
|
||||
import { Guard, Guarded, Keyed, MaybeArray } from './core/helpers/util';
|
||||
import Telegram from './telegram';
|
||||
import { FmtString } from './format';
|
||||
import { Digit, MessageReactions } from './reactions';
|
||||
type Tail<T> = T extends [unknown, ...infer U] ? U : never;
|
||||
type Shorthand<FName extends Exclude<keyof Telegram, keyof ApiClient>> = Tail<Parameters<Telegram[FName]>>;
|
||||
/**
|
||||
* Narrows down `C['update']` (and derived getters)
|
||||
* to specific update type `U`.
|
||||
*
|
||||
* Used by [[`Composer`]],
|
||||
* possibly useful for splitting a bot into multiple files.
|
||||
*/
|
||||
export type NarrowedContext<C extends Context, U extends tg.Update> = Context<U> & Omit<C, keyof Context>;
|
||||
export type FilteredContext<Ctx extends Context, Filter extends tt.UpdateType | Guard<Ctx['update']>> = Filter extends tt.UpdateType ? NarrowedContext<Ctx, Extract<tg.Update, Record<Filter, object>>> : NarrowedContext<Ctx, Guarded<Filter>>;
|
||||
export declare class Context<U extends Deunionize<tg.Update> = tg.Update> {
|
||||
readonly update: U;
|
||||
readonly telegram: Telegram;
|
||||
readonly botInfo: tg.UserFromGetMe;
|
||||
readonly state: Record<string | symbol, any>;
|
||||
constructor(update: U, telegram: Telegram, botInfo: tg.UserFromGetMe);
|
||||
get updateType(): Extract<UnionKeys<U>, tt.UpdateType>;
|
||||
get me(): string;
|
||||
/**
|
||||
* @deprecated Use ctx.telegram instead
|
||||
*/
|
||||
get tg(): Telegram;
|
||||
get message(): PropOr<U, "message">;
|
||||
get editedMessage(): PropOr<U, "edited_message">;
|
||||
get inlineQuery(): PropOr<U, "inline_query">;
|
||||
get shippingQuery(): PropOr<U, "shipping_query">;
|
||||
get preCheckoutQuery(): PropOr<U, "pre_checkout_query">;
|
||||
get chosenInlineResult(): PropOr<U, "chosen_inline_result">;
|
||||
get channelPost(): PropOr<U, "channel_post">;
|
||||
get editedChannelPost(): PropOr<U, "edited_channel_post">;
|
||||
get messageReaction(): PropOr<U, "message_reaction">;
|
||||
get messageReactionCount(): PropOr<U, "message_reaction_count">;
|
||||
get callbackQuery(): PropOr<U, "callback_query">;
|
||||
get poll(): PropOr<U, "poll">;
|
||||
get pollAnswer(): PropOr<U, "poll_answer">;
|
||||
get myChatMember(): PropOr<U, "my_chat_member">;
|
||||
get chatMember(): PropOr<U, "chat_member">;
|
||||
get chatJoinRequest(): PropOr<U, "chat_join_request">;
|
||||
get chatBoost(): PropOr<U, "chat_boost">;
|
||||
get removedChatBoost(): PropOr<U, "removed_chat_boost">;
|
||||
/** Shorthand for any `message` object present in the current update. One of
|
||||
* `message`, `edited_message`, `channel_post`, `edited_channel_post` or
|
||||
* `callback_query.message`
|
||||
*/
|
||||
get msg(): GetMsg<U> & Msg;
|
||||
/** Shorthand for any message_id present in the current update. */
|
||||
get msgId(): GetMsgId<U>;
|
||||
get chat(): Getter<U, 'chat'>;
|
||||
get senderChat(): PropOr<GetUpdateContent<U>, "sender_chat", undefined>;
|
||||
get from(): GetUserFromAnySource<U>;
|
||||
get inlineMessageId(): string | undefined;
|
||||
get passportData(): tg.PassportData | undefined;
|
||||
get webAppData(): {
|
||||
data: {
|
||||
json<T>(): T;
|
||||
text(): string;
|
||||
};
|
||||
button_text: string;
|
||||
} | undefined;
|
||||
/**
|
||||
* @deprecated use {@link Telegram.webhookReply}
|
||||
*/
|
||||
get webhookReply(): boolean;
|
||||
set webhookReply(enable: boolean);
|
||||
get reactions(): MessageReactions;
|
||||
has<Filter extends tt.UpdateType | Guard<Context['update']>>(filters: MaybeArray<Filter>): this is FilteredContext<Context, Filter>;
|
||||
get text(): GetText<U>;
|
||||
entities<EntityTypes extends tg.MessageEntity['type'][]>(...types: EntityTypes): (tg.MessageEntity & {
|
||||
type: EntityTypes extends [] ? "mention" | "hashtag" | "cashtag" | "bot_command" | "url" | "email" | "phone_number" | "bold" | "blockquote" | "italic" | "underline" | "strikethrough" | "spoiler" | "code" | "custom_emoji" | "pre" | "text_link" | "text_mention" : EntityTypes[number];
|
||||
fragment: string;
|
||||
})[];
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#answerinlinequery
|
||||
*/
|
||||
answerInlineQuery(...args: Shorthand<'answerInlineQuery'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#answercallbackquery
|
||||
*/
|
||||
answerCbQuery(...args: Shorthand<'answerCbQuery'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#answercallbackquery
|
||||
*/
|
||||
answerGameQuery(...args: Shorthand<'answerGameQuery'>): Promise<true>;
|
||||
/**
|
||||
* Shorthand for {@link Telegram.getUserChatBoosts}
|
||||
*/
|
||||
getUserChatBoosts(): Promise<tg.UserChatBoosts[]>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#answershippingquery
|
||||
*/
|
||||
answerShippingQuery(...args: Shorthand<'answerShippingQuery'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#answerprecheckoutquery
|
||||
*/
|
||||
answerPreCheckoutQuery(...args: Shorthand<'answerPreCheckoutQuery'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#editmessagetext
|
||||
*/
|
||||
editMessageText(text: string | FmtString, extra?: tt.ExtraEditMessageText): Promise<true | (tg.Update.Edited & tg.Message.TextMessage)>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#editmessagecaption
|
||||
*/
|
||||
editMessageCaption(caption: string | FmtString | undefined, extra?: tt.ExtraEditMessageCaption): Promise<true | (tg.Update.Edited & tg.Message.CaptionableMessage)>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#editmessagemedia
|
||||
*/
|
||||
editMessageMedia(media: tt.WrapCaption<tg.InputMedia>, extra?: tt.ExtraEditMessageMedia): Promise<true | (tg.Update.Edited & tg.Message)>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#editmessagereplymarkup
|
||||
*/
|
||||
editMessageReplyMarkup(markup: tg.InlineKeyboardMarkup | undefined): Promise<true | (tg.Update.Edited & tg.Message)>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#editmessagelivelocation
|
||||
*/
|
||||
editMessageLiveLocation(latitude: number, longitude: number, extra?: tt.ExtraEditMessageLiveLocation): Promise<true | (tg.Update.Edited & tg.Message.LocationMessage)>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#stopmessagelivelocation
|
||||
*/
|
||||
stopMessageLiveLocation(markup?: tg.InlineKeyboardMarkup): Promise<true | (tg.Update.Edited & tg.Message.LocationMessage)>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendmessage
|
||||
*/
|
||||
sendMessage(text: string | FmtString, extra?: tt.ExtraReplyMessage): Promise<tg.Message.TextMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendmessage
|
||||
*/
|
||||
reply(...args: Shorthand<'sendMessage'>): Promise<tg.Message.TextMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#getchat
|
||||
*/
|
||||
getChat(...args: Shorthand<'getChat'>): Promise<tg.ChatFromGetChat>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#exportchatinvitelink
|
||||
*/
|
||||
exportChatInviteLink(...args: Shorthand<'exportChatInviteLink'>): Promise<string>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#createchatinvitelink
|
||||
*/
|
||||
createChatInviteLink(...args: Shorthand<'createChatInviteLink'>): Promise<tg.ChatInviteLink>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#editchatinvitelink
|
||||
*/
|
||||
editChatInviteLink(...args: Shorthand<'editChatInviteLink'>): Promise<tg.ChatInviteLink>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#revokechatinvitelink
|
||||
*/
|
||||
revokeChatInviteLink(...args: Shorthand<'revokeChatInviteLink'>): Promise<tg.ChatInviteLink>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#banchatmember
|
||||
*/
|
||||
banChatMember(...args: Shorthand<'banChatMember'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#banchatmember
|
||||
* @deprecated since API 5.3. Use {@link Context.banChatMember}
|
||||
*/
|
||||
get kickChatMember(): (userId: number, untilDate?: number | undefined, extra?: Omit<{
|
||||
chat_id: string | number;
|
||||
user_id: number;
|
||||
until_date?: number | undefined;
|
||||
revoke_messages?: boolean | undefined;
|
||||
}, "chat_id" | "user_id" | "until_date"> | undefined) => Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#unbanchatmember
|
||||
*/
|
||||
unbanChatMember(...args: Shorthand<'unbanChatMember'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#restrictchatmember
|
||||
*/
|
||||
restrictChatMember(...args: Shorthand<'restrictChatMember'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#promotechatmember
|
||||
*/
|
||||
promoteChatMember(...args: Shorthand<'promoteChatMember'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#setchatadministratorcustomtitle
|
||||
*/
|
||||
setChatAdministratorCustomTitle(...args: Shorthand<'setChatAdministratorCustomTitle'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#setchatphoto
|
||||
*/
|
||||
setChatPhoto(...args: Shorthand<'setChatPhoto'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#deletechatphoto
|
||||
*/
|
||||
deleteChatPhoto(...args: Shorthand<'deleteChatPhoto'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#setchattitle
|
||||
*/
|
||||
setChatTitle(...args: Shorthand<'setChatTitle'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#setchatdescription
|
||||
*/
|
||||
setChatDescription(...args: Shorthand<'setChatDescription'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#pinchatmessage
|
||||
*/
|
||||
pinChatMessage(...args: Shorthand<'pinChatMessage'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#unpinchatmessage
|
||||
*/
|
||||
unpinChatMessage(...args: Shorthand<'unpinChatMessage'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#unpinallchatmessages
|
||||
*/
|
||||
unpinAllChatMessages(...args: Shorthand<'unpinAllChatMessages'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#leavechat
|
||||
*/
|
||||
leaveChat(...args: Shorthand<'leaveChat'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#setchatpermissions
|
||||
*/
|
||||
setChatPermissions(...args: Shorthand<'setChatPermissions'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#getchatadministrators
|
||||
*/
|
||||
getChatAdministrators(...args: Shorthand<'getChatAdministrators'>): Promise<(tg.ChatMemberOwner | tg.ChatMemberAdministrator)[]>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#getchatmember
|
||||
*/
|
||||
getChatMember(...args: Shorthand<'getChatMember'>): Promise<tg.ChatMember>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#getchatmembercount
|
||||
*/
|
||||
getChatMembersCount(...args: Shorthand<'getChatMembersCount'>): Promise<number>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#setpassportdataerrors
|
||||
*/
|
||||
setPassportDataErrors(errors: readonly tg.PassportElementError[]): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendphoto
|
||||
*/
|
||||
sendPhoto(photo: string | tg.InputFile, extra?: tt.ExtraPhoto): Promise<tg.Message.PhotoMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendphoto
|
||||
*/
|
||||
replyWithPhoto(...args: Shorthand<'sendPhoto'>): Promise<tg.Message.PhotoMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendmediagroup
|
||||
*/
|
||||
sendMediaGroup(media: tt.MediaGroup, extra?: tt.ExtraMediaGroup): Promise<(tg.Message.DocumentMessage | tg.Message.AudioMessage | tg.Message.PhotoMessage | tg.Message.VideoMessage)[]>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendmediagroup
|
||||
*/
|
||||
replyWithMediaGroup(...args: Shorthand<'sendMediaGroup'>): Promise<(tg.Message.DocumentMessage | tg.Message.AudioMessage | tg.Message.PhotoMessage | tg.Message.VideoMessage)[]>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendaudio
|
||||
*/
|
||||
sendAudio(audio: string | tg.InputFile, extra?: tt.ExtraAudio): Promise<tg.Message.AudioMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendaudio
|
||||
*/
|
||||
replyWithAudio(...args: Shorthand<'sendAudio'>): Promise<tg.Message.AudioMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#senddice
|
||||
*/
|
||||
sendDice(extra?: tt.ExtraDice): Promise<tg.Message.DiceMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#senddice
|
||||
*/
|
||||
replyWithDice(...args: Shorthand<'sendDice'>): Promise<tg.Message.DiceMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#senddocument
|
||||
*/
|
||||
sendDocument(document: string | tg.InputFile, extra?: tt.ExtraDocument): Promise<tg.Message.DocumentMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#senddocument
|
||||
*/
|
||||
replyWithDocument(...args: Shorthand<'sendDocument'>): Promise<tg.Message.DocumentMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendsticker
|
||||
*/
|
||||
sendSticker(sticker: string | tg.InputFile, extra?: tt.ExtraSticker): Promise<tg.Message.StickerMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendsticker
|
||||
*/
|
||||
replyWithSticker(...args: Shorthand<'sendSticker'>): Promise<tg.Message.StickerMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendvideo
|
||||
*/
|
||||
sendVideo(video: string | tg.InputFile, extra?: tt.ExtraVideo): Promise<tg.Message.VideoMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendvideo
|
||||
*/
|
||||
replyWithVideo(...args: Shorthand<'sendVideo'>): Promise<tg.Message.VideoMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendanimation
|
||||
*/
|
||||
sendAnimation(animation: string | tg.InputFile, extra?: tt.ExtraAnimation): Promise<tg.Message.AnimationMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendanimation
|
||||
*/
|
||||
replyWithAnimation(...args: Shorthand<'sendAnimation'>): Promise<tg.Message.AnimationMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendvideonote
|
||||
*/
|
||||
sendVideoNote(videoNote: string | tg.InputFileVideoNote, extra?: tt.ExtraVideoNote): Promise<tg.Message.VideoNoteMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendvideonote
|
||||
*/
|
||||
replyWithVideoNote(...args: Shorthand<'sendVideoNote'>): Promise<tg.Message.VideoNoteMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendinvoice
|
||||
*/
|
||||
sendInvoice(invoice: tt.NewInvoiceParameters, extra?: tt.ExtraInvoice): Promise<tg.Message.InvoiceMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendinvoice
|
||||
*/
|
||||
replyWithInvoice(...args: Shorthand<'sendInvoice'>): Promise<tg.Message.InvoiceMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendgame
|
||||
*/
|
||||
sendGame(game: string, extra?: tt.ExtraGame): Promise<tg.Message.GameMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendgame
|
||||
*/
|
||||
replyWithGame(...args: Shorthand<'sendGame'>): Promise<tg.Message.GameMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendvoice
|
||||
*/
|
||||
sendVoice(voice: string | tg.InputFile, extra?: tt.ExtraVoice): Promise<tg.Message.VoiceMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendvoice
|
||||
*/
|
||||
replyWithVoice(...args: Shorthand<'sendVoice'>): Promise<tg.Message.VoiceMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendpoll
|
||||
*/
|
||||
sendPoll(poll: string, options: readonly string[], extra?: tt.ExtraPoll): Promise<tg.Message.PollMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendpoll
|
||||
*/
|
||||
replyWithPoll(...args: Shorthand<'sendPoll'>): Promise<tg.Message.PollMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendpoll
|
||||
*/
|
||||
sendQuiz(quiz: string, options: readonly string[], extra?: tt.ExtraPoll): Promise<tg.Message.PollMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendpoll
|
||||
*/
|
||||
replyWithQuiz(...args: Shorthand<'sendQuiz'>): Promise<tg.Message.PollMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#stoppoll
|
||||
*/
|
||||
stopPoll(...args: Shorthand<'stopPoll'>): Promise<tg.Poll>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendchataction
|
||||
*/
|
||||
sendChatAction(action: Shorthand<'sendChatAction'>[0], extra?: tt.ExtraSendChatAction): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendchataction
|
||||
*
|
||||
* Sends the sendChatAction request repeatedly, with a delay between requests,
|
||||
* as long as the provided callback function is being processed.
|
||||
*
|
||||
* The sendChatAction errors should be ignored, because the goal is the actual long process completing and performing an action.
|
||||
*
|
||||
* @param action - chat action type.
|
||||
* @param callback - a function to run along with the chat action.
|
||||
* @param extra - extra parameters for sendChatAction.
|
||||
* @param {number} [extra.intervalDuration=8000] - The duration (in milliseconds) between subsequent sendChatAction requests.
|
||||
*/
|
||||
persistentChatAction(action: Shorthand<'sendChatAction'>[0], callback: () => Promise<void>, { intervalDuration, ...extra }?: tt.ExtraSendChatAction & {
|
||||
intervalDuration?: number;
|
||||
}): Promise<void>;
|
||||
/**
|
||||
* @deprecated use {@link Context.sendChatAction} instead
|
||||
* @see https://core.telegram.org/bots/api#sendchataction
|
||||
*/
|
||||
replyWithChatAction(...args: Shorthand<'sendChatAction'>): Promise<true>;
|
||||
/**
|
||||
* Shorthand for {@link Telegram.setMessageReaction}
|
||||
* @param reaction An emoji or custom_emoji_id to set as reaction to current message. Leave empty to remove reactions.
|
||||
* @param is_big Pass True to set the reaction with a big animation
|
||||
*/
|
||||
react(reaction?: MaybeArray<tg.TelegramEmoji | `${Digit}${string}` | tg.ReactionType>, is_big?: boolean): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendlocation
|
||||
*/
|
||||
sendLocation(latitude: number, longitude: number, extra?: tt.ExtraLocation): Promise<tg.Message.LocationMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendlocation
|
||||
*/
|
||||
replyWithLocation(...args: Shorthand<'sendLocation'>): Promise<tg.Message.LocationMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendvenue
|
||||
*/
|
||||
sendVenue(latitude: number, longitude: number, title: string, address: string, extra?: tt.ExtraVenue): Promise<tg.Message.VenueMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendvenue
|
||||
*/
|
||||
replyWithVenue(...args: Shorthand<'sendVenue'>): Promise<tg.Message.VenueMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendcontact
|
||||
*/
|
||||
sendContact(phoneNumber: string, firstName: string, extra?: tt.ExtraContact): Promise<tg.Message.ContactMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendcontact
|
||||
*/
|
||||
replyWithContact(...args: Shorthand<'sendContact'>): Promise<tg.Message.ContactMessage>;
|
||||
/**
|
||||
* @deprecated use {@link Telegram.getStickerSet}
|
||||
* @see https://core.telegram.org/bots/api#getstickerset
|
||||
*/
|
||||
getStickerSet(setName: string): Promise<tg.StickerSet>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#setchatstickerset
|
||||
*/
|
||||
setChatStickerSet(setName: string): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#deletechatstickerset
|
||||
*/
|
||||
deleteChatStickerSet(): Promise<true>;
|
||||
/**
|
||||
* Use this method to create a topic in a forum supergroup chat. The bot must be an administrator in the chat for this
|
||||
* to work and must have the can_manage_topics administrator rights. Returns information about the created topic as a
|
||||
* ForumTopic object.
|
||||
*
|
||||
* @see https://core.telegram.org/bots/api#createforumtopic
|
||||
*/
|
||||
createForumTopic(...args: Shorthand<'createForumTopic'>): Promise<tg.ForumTopic>;
|
||||
/**
|
||||
* Use this method to edit name and icon of a topic in a forum supergroup chat. The bot must be an administrator in
|
||||
* the chat for this to work and must have can_manage_topics administrator rights, unless it is the creator of the
|
||||
* topic. Returns True on success.
|
||||
*
|
||||
* @see https://core.telegram.org/bots/api#editforumtopic
|
||||
*/
|
||||
editForumTopic(extra: tt.ExtraEditForumTopic): Promise<true>;
|
||||
/**
|
||||
* Use this method to close an open topic in a forum supergroup chat. The bot must be an administrator in the chat
|
||||
* for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic.
|
||||
* Returns True on success.
|
||||
*
|
||||
* @see https://core.telegram.org/bots/api#closeforumtopic
|
||||
*/
|
||||
closeForumTopic(): Promise<true>;
|
||||
/**
|
||||
* Use this method to reopen a closed topic in a forum supergroup chat. The bot must be an administrator in the chat
|
||||
* for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic.
|
||||
* Returns True on success.
|
||||
*
|
||||
* @see https://core.telegram.org/bots/api#reopenforumtopic
|
||||
*/
|
||||
reopenForumTopic(): Promise<true>;
|
||||
/**
|
||||
* Use this method to delete a forum topic along with all its messages in a forum supergroup chat. The bot must be an
|
||||
* administrator in the chat for this to work and must have the can_delete_messages administrator rights.
|
||||
* Returns True on success.
|
||||
*
|
||||
* @see https://core.telegram.org/bots/api#deleteforumtopic
|
||||
*/
|
||||
deleteForumTopic(): Promise<true>;
|
||||
/**
|
||||
* Use this method to clear the list of pinned messages in a forum topic. The bot must be an administrator in the chat
|
||||
* for this to work and must have the can_pin_messages administrator right in the supergroup. Returns True on success.
|
||||
*
|
||||
* @see https://core.telegram.org/bots/api#unpinallforumtopicmessages
|
||||
*/
|
||||
unpinAllForumTopicMessages(): Promise<true>;
|
||||
/**
|
||||
* Use this method to edit the name of the 'General' topic in a forum supergroup chat. The bot must be an administrator
|
||||
* in the chat for this to work and must have can_manage_topics administrator rights. Returns True on success.
|
||||
*
|
||||
* @see https://core.telegram.org/bots/api#editgeneralforumtopic
|
||||
*/
|
||||
editGeneralForumTopic(name: string): Promise<true>;
|
||||
/**
|
||||
* Use this method to close an open 'General' topic in a forum supergroup chat. The bot must be an administrator in the
|
||||
* chat for this to work and must have the can_manage_topics administrator rights. Returns True on success.
|
||||
*
|
||||
* @see https://core.telegram.org/bots/api#closegeneralforumtopic
|
||||
*/
|
||||
closeGeneralForumTopic(): Promise<true>;
|
||||
/**
|
||||
* Use this method to reopen a closed 'General' topic in a forum supergroup chat. The bot must be an administrator in
|
||||
* the chat for this to work and must have the can_manage_topics administrator rights. The topic will be automatically
|
||||
* unhidden if it was hidden. Returns True on success.
|
||||
*
|
||||
* @see https://core.telegram.org/bots/api#reopengeneralforumtopic
|
||||
*/
|
||||
reopenGeneralForumTopic(): Promise<true>;
|
||||
/**
|
||||
* Use this method to hide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat
|
||||
* for this to work and must have the can_manage_topics administrator rights. The topic will be automatically closed
|
||||
* if it was open. Returns True on success.
|
||||
*
|
||||
* @see https://core.telegram.org/bots/api#hidegeneralforumtopic
|
||||
*/
|
||||
hideGeneralForumTopic(): Promise<true>;
|
||||
/**
|
||||
* Use this method to unhide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the
|
||||
* chat for this to work and must have the can_manage_topics administrator rights. Returns True on success.
|
||||
*
|
||||
* @see https://core.telegram.org/bots/api#unhidegeneralforumtopic
|
||||
*/
|
||||
unhideGeneralForumTopic(): Promise<true>;
|
||||
/**
|
||||
* Use this method to clear the list of pinned messages in a General forum topic.
|
||||
* The bot must be an administrator in the chat for this to work and must have the can_pin_messages administrator
|
||||
* right in the supergroup.
|
||||
*
|
||||
* @param chat_id Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername)
|
||||
*
|
||||
* @see https://core.telegram.org/bots/api#unpinallgeneralforumtopicmessages
|
||||
*/
|
||||
unpinAllGeneralForumTopicMessages(): Promise<true>;
|
||||
/**
|
||||
* @deprecated use {@link Telegram.setStickerPositionInSet}
|
||||
* @see https://core.telegram.org/bots/api#setstickerpositioninset
|
||||
*/
|
||||
setStickerPositionInSet(sticker: string, position: number): Promise<true>;
|
||||
/**
|
||||
* @deprecated use {@link Telegram.setStickerSetThumbnail}
|
||||
* @see https://core.telegram.org/bots/api#setstickersetthumbnail
|
||||
*/
|
||||
setStickerSetThumb(...args: Parameters<Telegram['setStickerSetThumbnail']>): Promise<true>;
|
||||
setStickerSetThumbnail(...args: Parameters<Telegram['setStickerSetThumbnail']>): Promise<true>;
|
||||
setStickerMaskPosition(...args: Parameters<Telegram['setStickerMaskPosition']>): Promise<true>;
|
||||
setStickerKeywords(...args: Parameters<Telegram['setStickerKeywords']>): Promise<true>;
|
||||
setStickerEmojiList(...args: Parameters<Telegram['setStickerEmojiList']>): Promise<true>;
|
||||
deleteStickerSet(...args: Parameters<Telegram['deleteStickerSet']>): Promise<true>;
|
||||
setStickerSetTitle(...args: Parameters<Telegram['setStickerSetTitle']>): Promise<true>;
|
||||
setCustomEmojiStickerSetThumbnail(...args: Parameters<Telegram['setCustomEmojiStickerSetThumbnail']>): Promise<true>;
|
||||
/**
|
||||
* @deprecated use {@link Telegram.deleteStickerFromSet}
|
||||
* @see https://core.telegram.org/bots/api#deletestickerfromset
|
||||
*/
|
||||
deleteStickerFromSet(sticker: string): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#uploadstickerfile
|
||||
*/
|
||||
uploadStickerFile(...args: Shorthand<'uploadStickerFile'>): Promise<tg.File>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#createnewstickerset
|
||||
*/
|
||||
createNewStickerSet(...args: Shorthand<'createNewStickerSet'>): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#addstickertoset
|
||||
*/
|
||||
addStickerToSet(...args: Shorthand<'addStickerToSet'>): Promise<true>;
|
||||
/**
|
||||
* @deprecated use {@link Telegram.getMyCommands}
|
||||
* @see https://core.telegram.org/bots/api#getmycommands
|
||||
*/
|
||||
getMyCommands(): Promise<tg.BotCommand[]>;
|
||||
/**
|
||||
* @deprecated use {@link Telegram.setMyCommands}
|
||||
* @see https://core.telegram.org/bots/api#setmycommands
|
||||
*/
|
||||
setMyCommands(commands: readonly tg.BotCommand[]): Promise<true>;
|
||||
/**
|
||||
* @deprecated use {@link Context.replyWithMarkdownV2}
|
||||
* @see https://core.telegram.org/bots/api#sendmessage
|
||||
*/
|
||||
replyWithMarkdown(markdown: string, extra?: tt.ExtraReplyMessage): Promise<tg.Message.TextMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendmessage
|
||||
*/
|
||||
replyWithMarkdownV2(markdown: string, extra?: tt.ExtraReplyMessage): Promise<tg.Message.TextMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#sendmessage
|
||||
*/
|
||||
replyWithHTML(html: string, extra?: tt.ExtraReplyMessage): Promise<tg.Message.TextMessage>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#deletemessage
|
||||
*/
|
||||
deleteMessage(messageId?: number): Promise<true>;
|
||||
/**
|
||||
* Context-aware shorthand for {@link Telegram.deleteMessages}
|
||||
* @param messageIds Identifiers of 1-100 messages to delete. See deleteMessage for limitations on which messages can be deleted
|
||||
*/
|
||||
deleteMessages(messageIds: number[]): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#forwardmessage
|
||||
*/
|
||||
forwardMessage(chatId: string | number, extra?: Shorthand<'forwardMessage'>[2]): Promise<tg.Message>;
|
||||
/**
|
||||
* Shorthand for {@link Telegram.forwardMessages}
|
||||
* @see https://core.telegram.org/bots/api#forwardmessages
|
||||
*/
|
||||
forwardMessages(chatId: string | number, messageIds: number[], extra?: Shorthand<'forwardMessages'>[2]): Promise<tg.MessageId[]>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#copymessage
|
||||
*/
|
||||
copyMessage(chatId: string | number, extra?: tt.ExtraCopyMessage): Promise<tg.MessageId>;
|
||||
/**
|
||||
* Context-aware shorthand for {@link Telegram.copyMessages}
|
||||
* @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername)
|
||||
* @param messageIds Identifiers of 1-100 messages in the chat from_chat_id to copy. The identifiers must be specified in a strictly increasing order.
|
||||
*/
|
||||
copyMessages(chatId: number | string, messageIds: number[], extra?: tt.ExtraCopyMessages): Promise<tg.MessageId[]>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#approvechatjoinrequest
|
||||
*/
|
||||
approveChatJoinRequest(userId: number): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#declinechatjoinrequest
|
||||
*/
|
||||
declineChatJoinRequest(userId: number): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#banchatsenderchat
|
||||
*/
|
||||
banChatSenderChat(senderChatId: number): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#unbanchatsenderchat
|
||||
*/
|
||||
unbanChatSenderChat(senderChatId: number): Promise<true>;
|
||||
/**
|
||||
* Use this method to change the bot's menu button in the current private chat. Returns true on success.
|
||||
* @see https://core.telegram.org/bots/api#setchatmenubutton
|
||||
*/
|
||||
setChatMenuButton(menuButton?: tg.MenuButton): Promise<true>;
|
||||
/**
|
||||
* Use this method to get the current value of the bot's menu button in the current private chat. Returns MenuButton on success.
|
||||
* @see https://core.telegram.org/bots/api#getchatmenubutton
|
||||
*/
|
||||
getChatMenuButton(): Promise<tg.MenuButton>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#setmydefaultadministratorrights
|
||||
*/
|
||||
setMyDefaultAdministratorRights(extra?: Parameters<Telegram['setMyDefaultAdministratorRights']>[0]): Promise<true>;
|
||||
/**
|
||||
* @see https://core.telegram.org/bots/api#getmydefaultadministratorrights
|
||||
*/
|
||||
getMyDefaultAdministratorRights(extra?: Parameters<Telegram['getMyDefaultAdministratorRights']>[0]): Promise<tg.ChatAdministratorRights>;
|
||||
}
|
||||
export default Context;
|
||||
type UpdateTypes<U extends Deunionize<tg.Update>> = Extract<UnionKeys<U>, tt.UpdateType>;
|
||||
export type GetUpdateContent<U extends tg.Update> = U extends tg.Update.CallbackQueryUpdate ? U['callback_query']['message'] : U[UpdateTypes<U>];
|
||||
type Getter<U extends Deunionize<tg.Update>, P extends string> = PropOr<GetUpdateContent<U>, P>;
|
||||
interface Msg {
|
||||
isAccessible(): this is MaybeMessage<tg.Message>;
|
||||
has<Ks extends UnionKeys<tg.Message>[]>(...keys: Ks): this is MaybeMessage<Keyed<tg.Message, Ks[number]>>;
|
||||
}
|
||||
declare const Msg: Msg;
|
||||
export type MaybeMessage<M extends tg.MaybeInaccessibleMessage = tg.MaybeInaccessibleMessage> = M & Msg;
|
||||
type GetMsg<U extends tg.Update> = U extends tg.Update.MessageUpdate ? U['message'] : U extends tg.Update.ChannelPostUpdate ? U['channel_post'] : U extends tg.Update.EditedChannelPostUpdate ? U['edited_channel_post'] : U extends tg.Update.EditedMessageUpdate ? U['edited_message'] : U extends tg.Update.CallbackQueryUpdate ? U['callback_query']['message'] : undefined;
|
||||
type GetUserFromAnySource<U extends tg.Update> = GetMsg<U> extends {
|
||||
from: tg.User;
|
||||
} ? tg.User : U extends tg.Update.CallbackQueryUpdate | tg.Update.InlineQueryUpdate | tg.Update.ShippingQueryUpdate | tg.Update.PreCheckoutQueryUpdate | tg.Update.ChosenInlineResultUpdate | tg.Update.ChatMemberUpdate | tg.Update.MyChatMemberUpdate | tg.Update.ChatJoinRequestUpdate | tg.Update.MessageReactionUpdate | tg.Update.PollAnswerUpdate | tg.Update.ChatBoostUpdate ? tg.User : undefined;
|
||||
type GetMsgId<U extends tg.Update> = GetMsg<U> extends {
|
||||
message_id: number;
|
||||
} ? number : U extends tg.Update.MessageReactionUpdate ? number : U extends tg.Update.MessageReactionCountUpdate ? number : undefined;
|
||||
type GetText<U extends tg.Update> = GetMsg<U> extends tg.Message.TextMessage ? string : GetMsg<U> extends tg.Message ? string | undefined : U extends tg.Update.PollUpdate ? string | undefined : undefined;
|
||||
//# sourceMappingURL=context.d.ts.map
|
||||
1
node_modules/telegraf/typings/context.d.ts.map
generated
vendored
Normal file
1
node_modules/telegraf/typings/context.d.ts.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
11
node_modules/telegraf/typings/core/helpers/args.d.ts
generated
vendored
Normal file
11
node_modules/telegraf/typings/core/helpers/args.d.ts
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
interface Entity {
|
||||
/** Type of the entity. Currently, can be “mention” (@username), “hashtag” (#hashtag), “cashtag” ($USD), “bot_command” (/start@jobs_bot), “url” (https://telegram.org), “email” (do-not-reply@telegram.org), “phone_number” (+1-212-555-0123), “bold” (bold text), “italic” (italic text), “underline” (underlined text), “strikethrough” (strikethrough text), “spoiler” (spoiler message), “code” (monowidth string), “pre” (monowidth block), “text_link” (for clickable text URLs), “text_mention” (for users without usernames), “custom_emoji” (for inline custom emoji stickers) */
|
||||
type: string;
|
||||
/** Offset in UTF-16 code units to the start of the entity */
|
||||
offset: number;
|
||||
/** Length of the entity in UTF-16 code units */
|
||||
length: number;
|
||||
}
|
||||
export declare function argsParser(str: string, entities?: Entity[], entityOffset?: number): string[];
|
||||
export {};
|
||||
//# sourceMappingURL=args.d.ts.map
|
||||
1
node_modules/telegraf/typings/core/helpers/args.d.ts.map
generated
vendored
Normal file
1
node_modules/telegraf/typings/core/helpers/args.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../../src/core/helpers/args.ts"],"names":[],"mappings":"AAAA,UAAU,MAAM;IACd,0jBAA0jB;IAC1jB,IAAI,EAAE,MAAM,CAAA;IACZ,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAA;IACd,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAA;CACf;AAKD,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,MAAM,EAAO,EACvB,YAAY,SAAI,YA+CjB"}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user