@tgify/tgify 0.1.4 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -29
- package/lib/button.js +20 -19
- package/lib/core/types/typegram.js +10 -10
- package/lib/index.js +3 -1
- package/lib/reactions.js +3 -1
- package/lib/telegraf.js +2 -253
- package/lib/telegram.js +7 -5
- package/lib/tgify.js +254 -0
- package/package.json +2 -2
- package/src/button.ts +48 -36
- package/src/composer.ts +13 -13
- package/src/context.ts +22 -22
- package/src/core/helpers/formatting.ts +2 -3
- package/src/core/types/typegram.ts +11 -11
- package/src/filters.ts +60 -60
- package/src/format.ts +4 -4
- package/src/future.ts +1 -1
- package/src/index.ts +1 -0
- package/src/markup.ts +5 -5
- package/src/reactions.ts +3 -1
- package/src/session.ts +2 -2
- package/src/telegraf.ts +1 -354
- package/src/telegram-types.ts +5 -5
- package/src/telegram.ts +12 -10
- package/src/tgify.ts +351 -0
- package/typings/button.d.ts +17 -17
- package/typings/button.d.ts.map +1 -1
- package/typings/context.d.ts +49 -49
- package/typings/context.d.ts.map +1 -1
- package/typings/core/helpers/formatting.d.ts +1 -1
- package/typings/core/helpers/formatting.d.ts.map +1 -1
- package/typings/core/types/typegram.d.ts +11 -11
- package/typings/core/types/typegram.d.ts.map +1 -1
- package/typings/filters.d.ts +1 -1
- package/typings/filters.d.ts.map +1 -1
- package/typings/format.d.ts +1 -1
- package/typings/format.d.ts.map +1 -1
- package/typings/index.d.ts +1 -0
- package/typings/index.d.ts.map +1 -1
- package/typings/markup.d.ts.map +1 -1
- package/typings/reactions.d.ts.map +1 -1
- package/typings/telegraf.d.ts +1 -114
- package/typings/telegraf.d.ts.map +1 -1
- package/typings/telegram-types.d.ts.map +1 -1
- package/typings/telegram.d.ts +31 -30
- package/typings/telegram.d.ts.map +1 -1
- package/typings/tgify.d.ts +118 -0
- package/typings/tgify.d.ts.map +1 -0
package/README.md
CHANGED
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
|
|
6
6
|
<p>Modern Telegram Bot API framework for Node.js</p>
|
|
7
7
|
|
|
8
|
+
<i>This is a fork of the Telegraf library and its continuation as I envision it. I will do my best to maintain full compatibility so that anyone who lacks certain functionality can migrate to this solution quickly and without friction.</i>
|
|
9
|
+
|
|
8
10
|
<a href="https://core.telegram.org/bots/api">
|
|
9
11
|
<img src="https://img.shields.io/badge/Bot%20API-v7.1-f36caf.svg?style=flat-square" alt="Bot API Version" />
|
|
10
12
|
</a>
|
|
11
|
-
<a href="https://packagephobia.com/result?p
|
|
12
|
-
<img src="https://flat.badgen.net/packagephobia/install/tgify" alt="install size" />
|
|
13
|
+
<a href="https://packagephobia.com/result?p=@tgify/tgify,node-telegram-bot-api">
|
|
14
|
+
<img src="https://flat.badgen.net/packagephobia/install/@tgify/tgify" alt="install size" />
|
|
13
15
|
</a>
|
|
14
16
|
<a href="https://github.com/IATNAOD/tgify">
|
|
15
17
|
<img src="https://img.shields.io/github/languages/top/IATNAOD/tgify?style=flat-square&logo=github" alt="GitHub top language" />
|
|
@@ -26,11 +28,15 @@ These accounts serve as an interface for code running somewhere on your server.
|
|
|
26
28
|
|
|
27
29
|
Tgify is a library that makes it simple for you to develop your own Telegram bots using JavaScript or [TypeScript](https://www.typescriptlang.org/).
|
|
28
30
|
|
|
31
|
+
### Release-notes
|
|
32
|
+
|
|
33
|
+
- Version [1.0.0](https://github.com/IATNAOD/tgify/tree/main/release-notes/1.0.0.md) from 18.02.26
|
|
34
|
+
|
|
29
35
|
### Features
|
|
30
36
|
|
|
31
37
|
- Full [Telegram Bot API 7.1](https://core.telegram.org/bots/api) support
|
|
32
38
|
- [Excellent TypeScript typings](https://github.com/IATNAOD/tgify/releases/tag/v4.0.0)
|
|
33
|
-
- [Lightweight](https://packagephobia.com/result?p
|
|
39
|
+
- [Lightweight](https://packagephobia.com/result?p=@tgify/tgify,node-telegram-bot-api)
|
|
34
40
|
- [AWS **λ**](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html)
|
|
35
41
|
/ [Firebase](https://firebase.google.com/products/functions/)
|
|
36
42
|
/ [Glitch](https://glitch.com/edit/#!/dashing-light)
|
|
@@ -42,10 +48,10 @@ Tgify is a library that makes it simple for you to develop your own Telegram bot
|
|
|
42
48
|
### Example
|
|
43
49
|
|
|
44
50
|
```js
|
|
45
|
-
const {
|
|
46
|
-
const { message } = require('
|
|
51
|
+
const { Tgify } = require('@tgify/tgify')
|
|
52
|
+
const { message } = require('@tgify/tgify/filters')
|
|
47
53
|
|
|
48
|
-
const bot = new
|
|
54
|
+
const bot = new Tgify(process.env.BOT_TOKEN)
|
|
49
55
|
bot.start((ctx) => ctx.reply('Welcome'))
|
|
50
56
|
bot.help((ctx) => ctx.reply('Send me a sticker'))
|
|
51
57
|
bot.on(message('sticker'), (ctx) => ctx.reply('👍'))
|
|
@@ -57,8 +63,10 @@ process.once('SIGINT', () => bot.stop('SIGINT'))
|
|
|
57
63
|
process.once('SIGTERM', () => bot.stop('SIGTERM'))
|
|
58
64
|
```
|
|
59
65
|
|
|
66
|
+
The `Telegraf` class can also be used, it will replicate all the basic functionality:
|
|
67
|
+
|
|
60
68
|
```js
|
|
61
|
-
const { Telegraf } = require('
|
|
69
|
+
const { Telegraf } = require('@tgify/tgify')
|
|
62
70
|
|
|
63
71
|
const bot = new Telegraf(process.env.BOT_TOKEN)
|
|
64
72
|
bot.command('oldschool', (ctx) => ctx.reply('Hello'))
|
|
@@ -76,7 +84,7 @@ For additional bot examples see the new [`docs repo`](https://github.com/feather
|
|
|
76
84
|
|
|
77
85
|
- [Getting started](#getting-started)
|
|
78
86
|
- [GitHub Discussions](https://github.com/IATNAOD/tgify/discussions)
|
|
79
|
-
- [Dependent repositories](https://libraries.io/npm/tgify/dependent_repositories)
|
|
87
|
+
- [Dependent repositories](https://libraries.io/npm/@tgify/tgify/dependent_repositories)
|
|
80
88
|
|
|
81
89
|
## Getting started
|
|
82
90
|
|
|
@@ -91,31 +99,31 @@ BotFather will give you a _token_, something like `123456789:AbCdefGhIJKlmNoPQRs
|
|
|
91
99
|
### Installation
|
|
92
100
|
|
|
93
101
|
```shellscript
|
|
94
|
-
$ npm install tgify
|
|
102
|
+
$ npm install @tgify/tgify
|
|
95
103
|
```
|
|
96
104
|
|
|
97
105
|
or
|
|
98
106
|
|
|
99
107
|
```shellscript
|
|
100
|
-
$ yarn add tgify
|
|
108
|
+
$ yarn add @tgify/tgify
|
|
101
109
|
```
|
|
102
110
|
|
|
103
111
|
or
|
|
104
112
|
|
|
105
113
|
```shellscript
|
|
106
|
-
$ pnpm add tgify
|
|
114
|
+
$ pnpm add @tgify/tgify
|
|
107
115
|
```
|
|
108
116
|
|
|
109
|
-
### `
|
|
117
|
+
### `Tgify` class
|
|
110
118
|
|
|
111
|
-
[`
|
|
119
|
+
[`Tgify`] instance represents your bot. It's responsible for obtaining updates and passing them to your handlers.
|
|
112
120
|
|
|
113
121
|
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.
|
|
114
122
|
|
|
115
123
|
### `Context` class
|
|
116
124
|
|
|
117
125
|
`ctx` you can see in every example is a [`Context`] instance.
|
|
118
|
-
[`
|
|
126
|
+
[`Tgify`] creates one for each incoming update and passes it to your middleware.
|
|
119
127
|
It contains the `update`, `botInfo`, and `telegram` for making arbitrary Bot API requests,
|
|
120
128
|
as well as shorthand methods and getters.
|
|
121
129
|
|
|
@@ -124,10 +132,10 @@ This is probably the class you'll be using the most.
|
|
|
124
132
|
#### Shorthand methods
|
|
125
133
|
|
|
126
134
|
```js
|
|
127
|
-
import {
|
|
128
|
-
import { message } from '
|
|
135
|
+
import { Tgify } from '@tgify/tgify'
|
|
136
|
+
import { message } from '@tgify/tgify/filters'
|
|
129
137
|
|
|
130
|
-
const bot = new
|
|
138
|
+
const bot = new Tgify(process.env.BOT_TOKEN)
|
|
131
139
|
|
|
132
140
|
bot.command('quit', async (ctx) => {
|
|
133
141
|
// Explicit usage
|
|
@@ -174,10 +182,10 @@ process.once('SIGTERM', () => bot.stop('SIGTERM'))
|
|
|
174
182
|
### Webhooks
|
|
175
183
|
|
|
176
184
|
```TS
|
|
177
|
-
import {
|
|
178
|
-
import { message } from '
|
|
185
|
+
import { Tgify } from "@tgify/tgify";
|
|
186
|
+
import { message } from '@tgify/tgify/filters';
|
|
179
187
|
|
|
180
|
-
const bot = new
|
|
188
|
+
const bot = new Tgify(token);
|
|
181
189
|
|
|
182
190
|
bot.on(message("text"), ctx => ctx.reply("Hello"));
|
|
183
191
|
|
|
@@ -201,7 +209,7 @@ bot.launch({
|
|
|
201
209
|
});
|
|
202
210
|
```
|
|
203
211
|
|
|
204
|
-
Use `createWebhook()` if you want to attach
|
|
212
|
+
Use `createWebhook()` if you want to attach Tgify to an existing http server.
|
|
205
213
|
|
|
206
214
|
<!-- global bot, tlsOptions -->
|
|
207
215
|
|
|
@@ -227,7 +235,7 @@ createServer(tlsOptions, await bot.createWebhook({ domain: "example.com" })).lis
|
|
|
227
235
|
|
|
228
236
|
### Error handling
|
|
229
237
|
|
|
230
|
-
If middleware throws an error or times out,
|
|
238
|
+
If middleware throws an error or times out, Tgify 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.
|
|
231
239
|
|
|
232
240
|
Default `bot.handleError` always rethrows. You can overwrite it using `bot.catch` if you need to.
|
|
233
241
|
|
|
@@ -285,10 +293,10 @@ As in Koa and some other middleware-based libraries,
|
|
|
285
293
|
`await next()` will call next middleware and wait for it to finish:
|
|
286
294
|
|
|
287
295
|
```TS
|
|
288
|
-
import {
|
|
289
|
-
import { message } from '
|
|
296
|
+
import { Tgify } from '@tgify/tgify';
|
|
297
|
+
import { message } from '@tgify/tgify/filters';
|
|
290
298
|
|
|
291
|
-
const bot = new
|
|
299
|
+
const bot = new Tgify(process.env.BOT_TOKEN);
|
|
292
300
|
|
|
293
301
|
bot.use(async (ctx, next) => {
|
|
294
302
|
console.time(`Processing update ${ctx.update.update_id}`);
|
|
@@ -314,7 +322,7 @@ With this simple ability, you can:
|
|
|
314
322
|
- reuse [other people's code](https://www.npmjs.com/search?q=telegraf-),
|
|
315
323
|
- do whatever **you** come up with!
|
|
316
324
|
|
|
317
|
-
[`
|
|
325
|
+
[`Tgify`]: https://telegraf.js.org/classes/Telegraf-1.html
|
|
318
326
|
[`Composer`]: https://telegraf.js.org/classes/Composer.html
|
|
319
327
|
[`Context`]: https://telegraf.js.org/classes/Context.html
|
|
320
328
|
[`Router`]: https://telegraf.js.org/classes/Router.html
|
|
@@ -330,12 +338,12 @@ While most types of Tgify's API surface are self-explanatory, there's some notab
|
|
|
330
338
|
#### Extending `Context`
|
|
331
339
|
|
|
332
340
|
The exact shape of `ctx` can vary based on the installed middleware.
|
|
333
|
-
Some custom middleware might register properties on the context object that
|
|
341
|
+
Some custom middleware might register properties on the context object that Tgify is not aware of.
|
|
334
342
|
Consequently, you can change the type of `ctx` to fit your needs in order for you to have proper TypeScript types for your data.
|
|
335
343
|
This is done through Generics:
|
|
336
344
|
|
|
337
345
|
```ts
|
|
338
|
-
import { Context,
|
|
346
|
+
import { Context, Tgify } from '@tgify/tgify'
|
|
339
347
|
|
|
340
348
|
// Define your own context type
|
|
341
349
|
interface MyContext extends Context {
|
|
@@ -344,7 +352,7 @@ interface MyContext extends Context {
|
|
|
344
352
|
}
|
|
345
353
|
|
|
346
354
|
// Create your bot and tell it about your context type
|
|
347
|
-
const bot = new
|
|
355
|
+
const bot = new Tgify<MyContext>('SECRET TOKEN')
|
|
348
356
|
|
|
349
357
|
// Register middleware and launch your bot as usual
|
|
350
358
|
bot.use((ctx, next) => {
|
package/lib/button.js
CHANGED
|
@@ -16,8 +16,8 @@ exports.game = game;
|
|
|
16
16
|
exports.pay = pay;
|
|
17
17
|
exports.login = login;
|
|
18
18
|
exports.webApp = webApp;
|
|
19
|
-
function text(text, hide = false) {
|
|
20
|
-
return { text, hide };
|
|
19
|
+
function text(text, hide = false, extra) {
|
|
20
|
+
return { text, hide, ...extra };
|
|
21
21
|
}
|
|
22
22
|
function contactRequest(text, hide = false) {
|
|
23
23
|
return { text, request_contact: true, hide };
|
|
@@ -64,37 +64,38 @@ request_id, extra, hide = false) {
|
|
|
64
64
|
hide,
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
|
-
function url(text, url, hide = false) {
|
|
68
|
-
return { text, url, hide };
|
|
67
|
+
function url(text, url, hide = false, extra) {
|
|
68
|
+
return { text, url, hide, ...extra };
|
|
69
69
|
}
|
|
70
|
-
function callback(text, data, hide = false) {
|
|
71
|
-
return { text, callback_data: data, hide };
|
|
70
|
+
function callback(text, data, hide = false, extra) {
|
|
71
|
+
return { text, callback_data: data, hide, ...extra };
|
|
72
72
|
}
|
|
73
|
-
function switchToChat(text, value, hide = false) {
|
|
74
|
-
return { text, switch_inline_query: value, hide };
|
|
73
|
+
function switchToChat(text, value, hide = false, extra) {
|
|
74
|
+
return { text, switch_inline_query: value, hide, ...extra };
|
|
75
75
|
}
|
|
76
|
-
function switchToCurrentChat(text, value, hide = false) {
|
|
77
|
-
return { text, switch_inline_query_current_chat: value, hide };
|
|
76
|
+
function switchToCurrentChat(text, value, hide = false, extra) {
|
|
77
|
+
return { text, switch_inline_query_current_chat: value, hide, ...extra };
|
|
78
78
|
}
|
|
79
|
-
function game(text, hide = false) {
|
|
80
|
-
return { text, callback_game: {}, hide };
|
|
79
|
+
function game(text, hide = false, extra) {
|
|
80
|
+
return { text, callback_game: {}, hide, ...extra };
|
|
81
81
|
}
|
|
82
|
-
function pay(text, hide = false) {
|
|
83
|
-
return { text, pay: true, hide };
|
|
82
|
+
function pay(text, hide = false, extra) {
|
|
83
|
+
return { text, pay: true, hide, ...extra };
|
|
84
84
|
}
|
|
85
|
-
function login(text, url, opts = {}, hide = false) {
|
|
85
|
+
function login(text, url, opts = {}, hide = false, extra) {
|
|
86
86
|
return {
|
|
87
87
|
text,
|
|
88
|
-
login_url: { ...opts, url },
|
|
89
88
|
hide,
|
|
89
|
+
login_url: { ...opts, url },
|
|
90
|
+
...extra
|
|
90
91
|
};
|
|
91
92
|
}
|
|
92
|
-
function webApp(text, url, hide = false
|
|
93
93
|
// works as both InlineKeyboardButton and KeyboardButton
|
|
94
|
-
) {
|
|
94
|
+
function webApp(text, url, hide = false, extra) {
|
|
95
95
|
return {
|
|
96
96
|
text,
|
|
97
|
-
web_app: { url },
|
|
98
97
|
hide,
|
|
98
|
+
web_app: { url },
|
|
99
|
+
...extra
|
|
99
100
|
};
|
|
100
101
|
}
|
|
@@ -15,13 +15,13 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
// internal type provisions
|
|
18
|
-
__exportStar(require("@
|
|
19
|
-
__exportStar(require("@
|
|
20
|
-
__exportStar(require("@
|
|
21
|
-
__exportStar(require("@
|
|
22
|
-
__exportStar(require("@
|
|
23
|
-
__exportStar(require("@
|
|
24
|
-
__exportStar(require("@
|
|
25
|
-
__exportStar(require("@
|
|
26
|
-
__exportStar(require("@
|
|
27
|
-
__exportStar(require("@
|
|
18
|
+
__exportStar(require("@tgify/types/api"), exports);
|
|
19
|
+
__exportStar(require("@tgify/types/inline"), exports);
|
|
20
|
+
__exportStar(require("@tgify/types/manage"), exports);
|
|
21
|
+
__exportStar(require("@tgify/types/markup"), exports);
|
|
22
|
+
__exportStar(require("@tgify/types/message"), exports);
|
|
23
|
+
__exportStar(require("@tgify/types/methods"), exports);
|
|
24
|
+
__exportStar(require("@tgify/types/passport"), exports);
|
|
25
|
+
__exportStar(require("@tgify/types/payment"), exports);
|
|
26
|
+
__exportStar(require("@tgify/types/settings"), exports);
|
|
27
|
+
__exportStar(require("@tgify/types/update"), exports);
|
package/lib/index.js
CHANGED
|
@@ -33,7 +33,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
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;
|
|
36
|
+
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 = exports.Tgify = void 0;
|
|
37
|
+
var tgify_1 = require("./tgify");
|
|
38
|
+
Object.defineProperty(exports, "Tgify", { enumerable: true, get: function () { return tgify_1.Tgify; } });
|
|
37
39
|
var telegraf_1 = require("./telegraf");
|
|
38
40
|
Object.defineProperty(exports, "Telegraf", { enumerable: true, get: function () { return telegraf_1.Telegraf; } });
|
|
39
41
|
var context_1 = require("./context");
|
package/lib/reactions.js
CHANGED
|
@@ -4,10 +4,12 @@ exports.MessageReactions = exports.ReactionList = exports.Digit = void 0;
|
|
|
4
4
|
const util_1 = require("./core/helpers/util");
|
|
5
5
|
exports.Digit = new Set(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']);
|
|
6
6
|
const inspectReaction = (reaction) => {
|
|
7
|
+
if (reaction.type === 'emoji')
|
|
8
|
+
return reaction.emoji;
|
|
7
9
|
if (reaction.type === 'custom_emoji')
|
|
8
10
|
return `Custom(${reaction.custom_emoji_id})`;
|
|
9
11
|
else
|
|
10
|
-
return
|
|
12
|
+
return 'paid()';
|
|
11
13
|
};
|
|
12
14
|
class ReactionList {
|
|
13
15
|
constructor(list) {
|
package/lib/telegraf.js
CHANGED
|
@@ -1,256 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
3
|
exports.Telegraf = void 0;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const https = __importStar(require("https"));
|
|
43
|
-
const composer_1 = require("./composer");
|
|
44
|
-
const compact_1 = require("./core/helpers/compact");
|
|
45
|
-
const context_1 = __importDefault(require("./context"));
|
|
46
|
-
const debug_1 = __importDefault(require("debug"));
|
|
47
|
-
const webhook_1 = __importDefault(require("./core/network/webhook"));
|
|
48
|
-
const polling_1 = require("./core/network/polling");
|
|
49
|
-
const p_timeout_1 = __importDefault(require("p-timeout"));
|
|
50
|
-
const telegram_1 = __importDefault(require("./telegram"));
|
|
51
|
-
const url_1 = require("url");
|
|
52
|
-
const safeCompare = require("safe-compare");
|
|
53
|
-
const debug = (0, debug_1.default)('telegraf:main');
|
|
54
|
-
const DEFAULT_OPTIONS = {
|
|
55
|
-
telegram: {},
|
|
56
|
-
handlerTimeout: 90000, // 90s in ms
|
|
57
|
-
contextType: context_1.default,
|
|
58
|
-
};
|
|
59
|
-
function always(x) {
|
|
60
|
-
return () => x;
|
|
61
|
-
}
|
|
62
|
-
const anoop = always(Promise.resolve());
|
|
63
|
-
const TOKEN_HEADER = 'x-telegram-bot-api-secret-token';
|
|
64
|
-
class Telegraf extends composer_1.Composer {
|
|
65
|
-
constructor(token, options) {
|
|
66
|
-
super();
|
|
67
|
-
this.context = {};
|
|
68
|
-
/** Assign to this to customise the webhook filter middleware.
|
|
69
|
-
* `{ path, secretToken }` will be bound to this rather than the Telegraf instance.
|
|
70
|
-
* Remember to assign a regular function and not an arrow function so it's bindable.
|
|
71
|
-
*/
|
|
72
|
-
this.webhookFilter = function (req) {
|
|
73
|
-
const debug = (0, debug_1.default)('telegraf:webhook');
|
|
74
|
-
if (req.method === 'POST') {
|
|
75
|
-
if (safeCompare(this.path, req.url)) {
|
|
76
|
-
// no need to check if secret_token was not set
|
|
77
|
-
if (!this.secretToken)
|
|
78
|
-
return true;
|
|
79
|
-
else {
|
|
80
|
-
const token = req.headers[TOKEN_HEADER];
|
|
81
|
-
if (safeCompare(this.secretToken, token))
|
|
82
|
-
return true;
|
|
83
|
-
else
|
|
84
|
-
debug('Secret token does not match:', token, this.secretToken);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
else
|
|
88
|
-
debug('Path does not match:', req.url, this.path);
|
|
89
|
-
}
|
|
90
|
-
else
|
|
91
|
-
debug('Unexpected request method, not POST. Received:', req.method);
|
|
92
|
-
return false;
|
|
93
|
-
};
|
|
94
|
-
this.handleError = (err, ctx) => {
|
|
95
|
-
// set exit code to emulate `warn-with-error-code` behavior of
|
|
96
|
-
// https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode
|
|
97
|
-
// to prevent a clean exit despite an error being thrown
|
|
98
|
-
process.exitCode = 1;
|
|
99
|
-
console.error('Unhandled error while processing', ctx.update);
|
|
100
|
-
throw err;
|
|
101
|
-
};
|
|
102
|
-
// @ts-expect-error Trust me, TS
|
|
103
|
-
this.options = {
|
|
104
|
-
...DEFAULT_OPTIONS,
|
|
105
|
-
...(0, compact_1.compactOptions)(options),
|
|
106
|
-
};
|
|
107
|
-
this.telegram = new telegram_1.default(token, this.options.telegram);
|
|
108
|
-
debug('Created a `Telegraf` instance');
|
|
109
|
-
}
|
|
110
|
-
get token() {
|
|
111
|
-
return this.telegram.token;
|
|
112
|
-
}
|
|
113
|
-
/** @deprecated use `ctx.telegram.webhookReply` */
|
|
114
|
-
set webhookReply(webhookReply) {
|
|
115
|
-
this.telegram.webhookReply = webhookReply;
|
|
116
|
-
}
|
|
117
|
-
/** @deprecated use `ctx.telegram.webhookReply` */
|
|
118
|
-
get webhookReply() {
|
|
119
|
-
return this.telegram.webhookReply;
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* _Override_ error handling
|
|
123
|
-
*/
|
|
124
|
-
catch(handler) {
|
|
125
|
-
this.handleError = handler;
|
|
126
|
-
return this;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* You must call `bot.telegram.setWebhook` for this to work.
|
|
130
|
-
* You should probably use {@link Telegraf.createWebhook} instead.
|
|
131
|
-
*/
|
|
132
|
-
webhookCallback(path = '/', opts = {}) {
|
|
133
|
-
const { secretToken } = opts;
|
|
134
|
-
return (0, webhook_1.default)(this.webhookFilter.bind({ hookPath: path, path, secretToken }), (update, res) => this.handleUpdate(update, res));
|
|
135
|
-
}
|
|
136
|
-
getDomainOpts(opts) {
|
|
137
|
-
var _a;
|
|
138
|
-
const protocol = opts.domain.startsWith('https://') || opts.domain.startsWith('http://');
|
|
139
|
-
if (protocol)
|
|
140
|
-
debug('Unexpected protocol in domain, telegraf will use https:', opts.domain);
|
|
141
|
-
const domain = protocol ? new url_1.URL(opts.domain).host : opts.domain;
|
|
142
|
-
const path = (_a = opts.path) !== null && _a !== void 0 ? _a : `/telegraf/${this.secretPathComponent()}`;
|
|
143
|
-
const url = `https://${domain}${path}`;
|
|
144
|
-
return { domain, path, url };
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Specify a url to receive incoming updates via webhook.
|
|
148
|
-
* Returns an Express-style middleware you can pass to app.use()
|
|
149
|
-
*/
|
|
150
|
-
async createWebhook(opts) {
|
|
151
|
-
const { domain, path, ...extra } = opts;
|
|
152
|
-
const domainOpts = this.getDomainOpts({ domain, path });
|
|
153
|
-
await this.telegram.setWebhook(domainOpts.url, extra);
|
|
154
|
-
debug(`Webhook set to ${domainOpts.url}`);
|
|
155
|
-
return this.webhookCallback(domainOpts.path, {
|
|
156
|
-
secretToken: extra.secret_token,
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
startPolling(allowedUpdates = []) {
|
|
160
|
-
this.polling = new polling_1.Polling(this.telegram, allowedUpdates);
|
|
161
|
-
return this.polling.loop(async (update) => {
|
|
162
|
-
await this.handleUpdate(update);
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
startWebhook(path, tlsOptions, port, host, cb, secretToken) {
|
|
166
|
-
const webhookCb = this.webhookCallback(path, { secretToken });
|
|
167
|
-
const callback = typeof cb === 'function'
|
|
168
|
-
? (req, res) => webhookCb(req, res, () => cb(req, res))
|
|
169
|
-
: webhookCb;
|
|
170
|
-
this.webhookServer =
|
|
171
|
-
tlsOptions != null
|
|
172
|
-
? https.createServer(tlsOptions, callback)
|
|
173
|
-
: http.createServer(callback);
|
|
174
|
-
this.webhookServer.listen(port, host, () => {
|
|
175
|
-
debug('Webhook listening on port: %s', port);
|
|
176
|
-
});
|
|
177
|
-
return this;
|
|
178
|
-
}
|
|
179
|
-
secretPathComponent() {
|
|
180
|
-
return crypto
|
|
181
|
-
.createHash('sha3-256')
|
|
182
|
-
.update(this.token)
|
|
183
|
-
.update(process.version) // salt
|
|
184
|
-
.digest('hex');
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* @see https://github.com/telegraf/telegraf/discussions/1344#discussioncomment-335700
|
|
188
|
-
*/
|
|
189
|
-
async launch(config = {},
|
|
190
|
-
/** @experimental */
|
|
191
|
-
onLaunch) {
|
|
192
|
-
var _a, _b;
|
|
193
|
-
const [cfg, onMe] = typeof config === 'function' ? [{}, config] : [config, onLaunch];
|
|
194
|
-
const drop_pending_updates = cfg.dropPendingUpdates;
|
|
195
|
-
const allowed_updates = cfg.allowedUpdates;
|
|
196
|
-
const webhook = cfg.webhook;
|
|
197
|
-
debug('Connecting to Telegram');
|
|
198
|
-
(_a = this.botInfo) !== null && _a !== void 0 ? _a : (this.botInfo = await this.telegram.getMe());
|
|
199
|
-
onMe === null || onMe === void 0 ? void 0 : onMe();
|
|
200
|
-
debug(`Launching @${this.botInfo.username}`);
|
|
201
|
-
if (webhook === undefined) {
|
|
202
|
-
await this.telegram.deleteWebhook({ drop_pending_updates });
|
|
203
|
-
debug('Bot started with long polling');
|
|
204
|
-
await this.startPolling(allowed_updates);
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
const domainOpts = this.getDomainOpts({
|
|
208
|
-
domain: webhook.domain,
|
|
209
|
-
path: (_b = webhook.path) !== null && _b !== void 0 ? _b : webhook.hookPath,
|
|
210
|
-
});
|
|
211
|
-
const { tlsOptions, port, host, cb, secretToken } = webhook;
|
|
212
|
-
this.startWebhook(domainOpts.path, tlsOptions, port, host, cb, secretToken);
|
|
213
|
-
await this.telegram.setWebhook(domainOpts.url, {
|
|
214
|
-
drop_pending_updates: drop_pending_updates,
|
|
215
|
-
allowed_updates: allowed_updates,
|
|
216
|
-
ip_address: webhook.ipAddress,
|
|
217
|
-
max_connections: webhook.maxConnections,
|
|
218
|
-
secret_token: webhook.secretToken,
|
|
219
|
-
certificate: webhook.certificate,
|
|
220
|
-
});
|
|
221
|
-
debug(`Bot started with webhook @ ${domainOpts.url}`);
|
|
222
|
-
}
|
|
223
|
-
stop(reason = 'unspecified') {
|
|
224
|
-
var _a, _b;
|
|
225
|
-
debug('Stopping bot... Reason:', reason);
|
|
226
|
-
// https://github.com/telegraf/telegraf/pull/1224#issuecomment-742693770
|
|
227
|
-
if (this.polling === undefined && this.webhookServer === undefined) {
|
|
228
|
-
throw new Error('Bot is not running!');
|
|
229
|
-
}
|
|
230
|
-
(_a = this.webhookServer) === null || _a === void 0 ? void 0 : _a.close();
|
|
231
|
-
(_b = this.polling) === null || _b === void 0 ? void 0 : _b.stop();
|
|
232
|
-
}
|
|
233
|
-
async handleUpdate(update, webhookResponse) {
|
|
234
|
-
var _a, _b;
|
|
235
|
-
(_a = this.botInfo) !== null && _a !== void 0 ? _a : (this.botInfo = (debug('Update %d is waiting for `botInfo` to be initialized', update.update_id),
|
|
236
|
-
await ((_b = this.botInfoCall) !== null && _b !== void 0 ? _b : (this.botInfoCall = this.telegram.getMe()))));
|
|
237
|
-
debug('Processing update', update.update_id);
|
|
238
|
-
const tg = new telegram_1.default(this.token, this.telegram.options, webhookResponse);
|
|
239
|
-
const TelegrafContext = this.options.contextType;
|
|
240
|
-
const ctx = new TelegrafContext(update, tg, this.botInfo);
|
|
241
|
-
Object.assign(ctx, this.context);
|
|
242
|
-
try {
|
|
243
|
-
await (0, p_timeout_1.default)(Promise.resolve(this.middleware()(ctx, anoop)), this.options.handlerTimeout);
|
|
244
|
-
}
|
|
245
|
-
catch (err) {
|
|
246
|
-
return await this.handleError(err, ctx);
|
|
247
|
-
}
|
|
248
|
-
finally {
|
|
249
|
-
if ((webhookResponse === null || webhookResponse === void 0 ? void 0 : webhookResponse.writableEnded) === false) {
|
|
250
|
-
webhookResponse.end();
|
|
251
|
-
}
|
|
252
|
-
debug('Finished processing update', update.update_id);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
exports.Telegraf = Telegraf;
|
|
4
|
+
var tgify_1 = require("./tgify");
|
|
5
|
+
Object.defineProperty(exports, "Telegraf", { enumerable: true, get: function () { return tgify_1.Tgify; } });
|
package/lib/telegram.js
CHANGED
|
@@ -681,9 +681,9 @@ class Telegram extends client_1.default {
|
|
|
681
681
|
*/
|
|
682
682
|
editMessageReplyMarkup(chatId, messageId, inlineMessageId, markup) {
|
|
683
683
|
return this.callApi('editMessageReplyMarkup', {
|
|
684
|
-
chat_id: chatId,
|
|
685
|
-
message_id: messageId,
|
|
686
|
-
inline_message_id: inlineMessageId,
|
|
684
|
+
...(chatId !== undefined && { chat_id: chatId }),
|
|
685
|
+
...(messageId !== undefined && { message_id: messageId }),
|
|
686
|
+
...(inlineMessageId !== undefined && { inline_message_id: inlineMessageId }),
|
|
687
687
|
reply_markup: markup,
|
|
688
688
|
});
|
|
689
689
|
}
|
|
@@ -989,12 +989,14 @@ class Telegram extends client_1.default {
|
|
|
989
989
|
* HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using
|
|
990
990
|
* Input helpers. Animated and video sticker set thumbnails can't be uploaded via HTTP URL.
|
|
991
991
|
* If omitted, then the thumbnail is dropped and the first sticker is used as the thumbnail.
|
|
992
|
+
* @param format Format of the sticker set thumbnail; must be one of "static", "animated", or "video"
|
|
992
993
|
*/
|
|
993
|
-
setStickerSetThumbnail(name, userId, thumbnail) {
|
|
994
|
+
setStickerSetThumbnail(name, userId, thumbnail, format = 'static') {
|
|
994
995
|
return this.callApi('setStickerSetThumbnail', {
|
|
995
996
|
name,
|
|
996
|
-
|
|
997
|
+
format,
|
|
997
998
|
thumbnail,
|
|
999
|
+
user_id: userId,
|
|
998
1000
|
});
|
|
999
1001
|
}
|
|
1000
1002
|
setStickerMaskPosition(sticker, mask_position) {
|