grammy 1.7.0 → 1.7.3

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 CHANGED
@@ -12,7 +12,7 @@ _<h2 align="center"> [:mag: Documentation](https://grammy.dev) | [:page_with_cur
12
12
 
13
13
  [![Bot API](https://img.shields.io/badge/Bot%20API-5.7-blue?logo=telegram&style=flat-square)](https://core.telegram.org/bots/api)
14
14
  [![npm](https://img.shields.io/npm/v/grammy?logo=npm&style=flat-square)](https://www.npmjs.org/package/grammy) <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
15
- [![All Contributors](https://img.shields.io/badge/all_contributors-50-orange.svg?style=flat-square)](#contributors-)
15
+ [![All Contributors](https://img.shields.io/badge/all_contributors-54-orange.svg?style=flat-square)](#contributors-)
16
16
  <!-- ALL-CONTRIBUTORS-BADGE:END -->
17
17
 
18
18
  <!-- deno-fmt-ignore-end -->
@@ -111,7 +111,7 @@ You may also be interested in [why we support Deno](https://grammy.dev/resources
111
111
  ## Browser Support
112
112
 
113
113
  The grammY core package in this repository is avaiable as a JavaScript bundle from the CDN at `get.grammy.dev`.
114
- Currently, we transpile all stable versions (all releases since v1.0) as well as the current `main` branch to ES3, ES5, ES6, and ESNext.
114
+ Currently, we transpile all stable versions (all releases since v1.0) as well as the current `main` branch to ES6 and ESNext.
115
115
 
116
116
  You can download them from the URL `https://get.grammy.dev/[ES version lowercased]@[grammY version including v-prefix].js`.
117
117
  For example, the most recent source on `main` in ES6 is available from <https://get.grammy.dev/es6@dev.js>.
@@ -176,7 +176,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
176
176
  <tr>
177
177
  <td align="center"><a href="https://github.com/taotie111"><img src="https://avatars.githubusercontent.com/u/44166322?v=4?s=100" width="100px;" alt=""/><br /><sub><b>taotie111</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/commits?author=taotie111" title="Documentation">📖</a> <a href="#translation-taotie111" title="Translation">🌍</a></td>
178
178
  <td align="center"><a href="https://www.linkedin.com/in/merlin-brandes-42328717a/"><img src="https://avatars.githubusercontent.com/u/14237330?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Merlin</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/commits?author=FatalMerlin" title="Documentation">📖</a></td>
179
- <td align="center"><a href="https://darve.sh"><img src="https://avatars.githubusercontent.com/u/22394081?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Darvesh</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/issues?q=author%3Adarvesh" title="Bug reports">🐛</a> <a href="https://github.com/grammyjs/grammY/commits?author=darvesh" title="Code">💻</a></td>
179
+ <td align="center"><a href="https://darve.sh"><img src="https://avatars.githubusercontent.com/u/22394081?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Darvesh</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/issues?q=author%3Adarvesh" title="Bug reports">🐛</a> <a href="https://github.com/grammyjs/grammY/commits?author=darvesh" title="Code">💻</a> <a href="https://github.com/grammyjs/grammY/pulls?q=is%3Apr+reviewed-by%3Adarvesh" title="Reviewed Pull Requests">👀</a></td>
180
180
  <td align="center"><a href="http://telegram.me/dcdunkan"><img src="https://avatars.githubusercontent.com/u/70066170?v=4?s=100" width="100px;" alt=""/><br /><sub><b>dcdunkan</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/issues?q=author%3Adcdunkan" title="Bug reports">🐛</a> <a href="https://github.com/grammyjs/grammY/commits?author=dcdunkan" title="Code">💻</a> <a href="#plugin-dcdunkan" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/grammyjs/grammY/pulls?q=is%3Apr+reviewed-by%3Adcdunkan" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/grammyjs/grammY/commits?author=dcdunkan" title="Documentation">📖</a></td>
181
181
  <td align="center"><a href="https://xuann.wang/"><img src="https://avatars.githubusercontent.com/u/44045911?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kid</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/commits?author=kidonng" title="Documentation">📖</a> <a href="#translation-kidonng" title="Translation">🌍</a></td>
182
182
  <td align="center"><a href="http://slava.fomin.io/"><img src="https://avatars.githubusercontent.com/u/1702725?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Slava Fomin II</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/issues?q=author%3Aslavafomin" title="Bug reports">🐛</a> <a href="https://github.com/grammyjs/grammY/commits?author=slavafomin" title="Documentation">📖</a></td>
@@ -193,6 +193,10 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
193
193
  </tr>
194
194
  <tr>
195
195
  <td align="center"><a href="https://github.com/abdollahzadehAli"><img src="https://avatars.githubusercontent.com/u/96317431?v=4?s=100" width="100px;" alt=""/><br /><sub><b>abdollahzadehAli</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/commits?author=abdollahzadehAli" title="Documentation">📖</a> <a href="#example-abdollahzadehAli" title="Examples">💡</a></td>
196
+ <td align="center"><a href="https://github.com/MrSaeedNasiri"><img src="https://avatars.githubusercontent.com/u/17780289?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Saeed Nasiri</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/commits?author=MrSaeedNasiri" title="Documentation">📖</a></td>
197
+ <td align="center"><a href="https://github.com/Scrip7"><img src="https://avatars.githubusercontent.com/u/37535505?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hesoyam</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/commits?author=Scrip7" title="Documentation">📖</a></td>
198
+ <td align="center"><a href="http://yrz.am"><img src="https://avatars.githubusercontent.com/u/96742416?v=4?s=100" width="100px;" alt=""/><br /><sub><b>yrzam</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/issues?q=author%3Ayrzam" title="Bug reports">🐛</a></td>
199
+ <td align="center"><a href="https://github.com/drmikecrowe"><img src="https://avatars.githubusercontent.com/u/90312?v=4?s=100" width="100px;" alt=""/><br /><sub><b>drmikecrowe</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/pulls?q=is%3Apr+reviewed-by%3Adrmikecrowe" title="Reviewed Pull Requests">👀</a></td>
196
200
  </tr>
197
201
  </table>
198
202
 
package/out/bot.d.ts CHANGED
@@ -35,13 +35,14 @@ export interface PollingOptions {
35
35
  */
36
36
  drop_pending_updates?: boolean;
37
37
  /**
38
- * Synchronous callback that is useful for logging. It will be executed once
39
- * the setup of the bot has completed, and immediately before the first
40
- * updates are being fetched. The bot information `bot.botInfo` will be
41
- * available when the function is run. For convenience, the callback
42
- * function receives the value of `bot.botInfo` as an argument.
38
+ * A callback function that is useful for logging (or setting up middleware
39
+ * if you did not do this before). It will be executed after the setup of
40
+ * the bot has completed, and immediately before the first updates are being
41
+ * fetched. The bot information `bot.botInfo` will be available when the
42
+ * function is run. For convenience, the callback function receives the
43
+ * value of `bot.botInfo` as an argument.
43
44
  */
44
- onStart?: (botInfo: UserFromGetMe) => void;
45
+ onStart?: (botInfo: UserFromGetMe) => void | Promise<void>;
45
46
  }
46
47
  export { BotError };
47
48
  /**
@@ -50,7 +51,7 @@ export { BotError };
50
51
  */
51
52
  export declare type ErrorHandler<C extends Context = Context> = (error: BotError<C>) => unknown;
52
53
  /**
53
- * Options to pass the bot when creating it.
54
+ * Options to pass to the bot when creating it.
54
55
  */
55
56
  export interface BotConfig<C extends Context> {
56
57
  /**
@@ -113,6 +114,7 @@ export declare class Bot<C extends Context = Context, A extends Api = Api> exten
113
114
  */
114
115
  readonly api: A;
115
116
  private me;
117
+ private mePromise;
116
118
  private readonly clientConfig;
117
119
  private readonly ContextConstructor;
118
120
  /**
package/out/bot.js CHANGED
@@ -50,85 +50,25 @@ class Bot extends composer_js_1.Composer {
50
50
  constructor(token, config) {
51
51
  var _a;
52
52
  super();
53
- Object.defineProperty(this, "token", {
54
- enumerable: true,
55
- configurable: true,
56
- writable: true,
57
- value: token
58
- });
59
- Object.defineProperty(this, "pollingRunning", {
60
- enumerable: true,
61
- configurable: true,
62
- writable: true,
63
- value: false
64
- });
65
- Object.defineProperty(this, "pollingAbortController", {
66
- enumerable: true,
67
- configurable: true,
68
- writable: true,
69
- value: void 0
70
- });
71
- Object.defineProperty(this, "lastTriedUpdateId", {
72
- enumerable: true,
73
- configurable: true,
74
- writable: true,
75
- value: 0
76
- });
77
- /**
78
- * Gives you full access to the Telegram Bot API.
79
- * ```ts
80
- * // This is how to call the Bot API methods:
81
- * bot.api.sendMessage(chat_id, 'Hello, grammY!')
82
- * ```
83
- *
84
- * Use this only outside of your middleware. If you have access to `ctx`,
85
- * then using `ctx.api` instead of `bot.api` is preferred.
86
- */
87
- Object.defineProperty(this, "api", {
88
- enumerable: true,
89
- configurable: true,
90
- writable: true,
91
- value: void 0
92
- });
93
- Object.defineProperty(this, "me", {
94
- enumerable: true,
95
- configurable: true,
96
- writable: true,
97
- value: void 0
98
- });
99
- Object.defineProperty(this, "clientConfig", {
100
- enumerable: true,
101
- configurable: true,
102
- writable: true,
103
- value: void 0
104
- });
105
- Object.defineProperty(this, "ContextConstructor", {
106
- enumerable: true,
107
- configurable: true,
108
- writable: true,
109
- value: void 0
110
- });
53
+ this.token = token;
54
+ this.pollingRunning = false;
55
+ this.lastTriedUpdateId = 0;
111
56
  /**
112
57
  * Holds the bot's error handler that is invoked whenever middleware throws
113
58
  * (rejects). If you set your own error handler via `bot.catch`, all that
114
59
  * happens is that this variable is assigned.
115
60
  */
116
- Object.defineProperty(this, "errorHandler", {
117
- enumerable: true,
118
- configurable: true,
119
- writable: true,
120
- value: async (err) => {
121
- var _a, _b;
122
- console.error("Error in middleware while handling update", (_b = (_a = err.ctx) === null || _a === void 0 ? void 0 : _a.update) === null || _b === void 0 ? void 0 : _b.update_id, err.error);
123
- console.error("No error handler was set!");
124
- console.error("Set your own error handler with `bot.catch = ...`");
125
- if (this.pollingRunning) {
126
- console.error("Stopping bot");
127
- await this.stop();
128
- }
129
- throw err;
61
+ this.errorHandler = async (err) => {
62
+ var _a, _b;
63
+ console.error("Error in middleware while handling update", (_b = (_a = err.ctx) === null || _a === void 0 ? void 0 : _a.update) === null || _b === void 0 ? void 0 : _b.update_id, err.error);
64
+ console.error("No error handler was set!");
65
+ console.error("Set your own error handler with `bot.catch = ...`");
66
+ if (this.pollingRunning) {
67
+ console.error("Stopping bot");
68
+ await this.stop();
130
69
  }
131
- });
70
+ throw err;
71
+ };
132
72
  if (!token)
133
73
  throw new Error("Empty token!");
134
74
  this.me = config === null || config === void 0 ? void 0 : config.botInfo;
@@ -175,9 +115,17 @@ class Bot extends composer_js_1.Composer {
175
115
  * manually.
176
116
  */
177
117
  async init() {
118
+ var _a;
178
119
  if (!this.isInited()) {
179
120
  debug("Initializing bot");
180
- const me = await this.api.getMe();
121
+ (_a = this.mePromise) !== null && _a !== void 0 ? _a : (this.mePromise = withRetries(() => this.api.getMe()));
122
+ let me;
123
+ try {
124
+ me = await this.mePromise;
125
+ }
126
+ finally {
127
+ this.mePromise = undefined;
128
+ }
181
129
  if (this.me === undefined)
182
130
  this.me = me;
183
131
  else
@@ -285,7 +233,7 @@ a known bot info object.");
285
233
  var _a;
286
234
  // Perform setup
287
235
  if (!this.isInited())
288
- await withRetries(() => this.init());
236
+ await this.init();
289
237
  if (this.pollingRunning) {
290
238
  debug("Simple long polling already running!");
291
239
  return;
@@ -293,6 +241,8 @@ a known bot info object.");
293
241
  await withRetries(() => this.api.deleteWebhook({
294
242
  drop_pending_updates: options === null || options === void 0 ? void 0 : options.drop_pending_updates,
295
243
  }));
244
+ // All async ops of setup complete, run callback
245
+ await ((_a = options === null || options === void 0 ? void 0 : options.onStart) === null || _a === void 0 ? void 0 : _a.call(options, this.botInfo));
296
246
  // Prevent common misuse that causes memory leak
297
247
  this.use = () => {
298
248
  throw new Error(`It looks like you are registering more listeners \
@@ -309,7 +259,6 @@ you can circumvent this protection against memory leaks.`);
309
259
  };
310
260
  // Start polling
311
261
  debug("Starting simple long polling");
312
- (_a = options === null || options === void 0 ? void 0 : options.onStart) === null || _a === void 0 ? void 0 : _a.call(options, this.botInfo);
313
262
  await this.loop(options);
314
263
  debug("Middleware is done running");
315
264
  }
@@ -445,11 +394,10 @@ exports.Bot = Bot;
445
394
  * @param task Async task to perform
446
395
  */
447
396
  async function withRetries(task) {
448
- let success = false;
449
- while (!success) {
397
+ let result = { ok: false };
398
+ while (!result.ok) {
450
399
  try {
451
- await task();
452
- success = true;
400
+ result = { ok: true, value: await task() };
453
401
  }
454
402
  catch (error) {
455
403
  debugErr(error);
@@ -468,6 +416,7 @@ async function withRetries(task) {
468
416
  throw error;
469
417
  }
470
418
  }
419
+ return result.value;
471
420
  }
472
421
  /**
473
422
  * Returns a new promise that resolves after the specified number of seconds.
package/out/composer.js CHANGED
@@ -11,18 +11,8 @@ const filter_js_1 = require("./filter.js");
11
11
  class BotError extends Error {
12
12
  constructor(error, ctx) {
13
13
  super(generateBotErrorMessage(error));
14
- Object.defineProperty(this, "error", {
15
- enumerable: true,
16
- configurable: true,
17
- writable: true,
18
- value: error
19
- });
20
- Object.defineProperty(this, "ctx", {
21
- enumerable: true,
22
- configurable: true,
23
- writable: true,
24
- value: ctx
25
- });
14
+ this.error = error;
15
+ this.ctx = ctx;
26
16
  this.name = "BotError";
27
17
  if (error instanceof Error)
28
18
  this.stack = error.stack;
@@ -109,12 +99,6 @@ class Composer {
109
99
  * @param middleware The middleware to compose
110
100
  */
111
101
  constructor(...middleware) {
112
- Object.defineProperty(this, "handler", {
113
- enumerable: true,
114
- configurable: true,
115
- writable: true,
116
- value: void 0
117
- });
118
102
  this.handler = middleware.length === 0
119
103
  ? pass
120
104
  : middleware.map(flatten).reduce(concat);
package/out/context.d.ts CHANGED
@@ -10,7 +10,7 @@ declare type RenamedUpdate = AliasProps<Omit<Update, "update_id">>;
10
10
  /**
11
11
  * When your bot receives a message, Telegram sends an update object to your
12
12
  * bot. The update contains information about the chat, the user, and of course
13
- * the message itself. There a numerous other updates, too:
13
+ * the message itself. There are numerous other updates, too:
14
14
  * https://core.telegram.org/bots/api#update
15
15
  *
16
16
  * When grammY receives an update, it wraps this update into a context object
package/out/context.js CHANGED
@@ -4,7 +4,7 @@ exports.Context = void 0;
4
4
  /**
5
5
  * When your bot receives a message, Telegram sends an update object to your
6
6
  * bot. The update contains information about the chat, the user, and of course
7
- * the message itself. There a numerous other updates, too:
7
+ * the message itself. There are numerous other updates, too:
8
8
  * https://core.telegram.org/bots/api#update
9
9
  *
10
10
  * When grammY receives an update, it wraps this update into a context object
@@ -53,34 +53,9 @@ class Context {
53
53
  * Information about the bot itself.
54
54
  */
55
55
  me) {
56
- Object.defineProperty(this, "update", {
57
- enumerable: true,
58
- configurable: true,
59
- writable: true,
60
- value: update
61
- });
62
- Object.defineProperty(this, "api", {
63
- enumerable: true,
64
- configurable: true,
65
- writable: true,
66
- value: api
67
- });
68
- Object.defineProperty(this, "me", {
69
- enumerable: true,
70
- configurable: true,
71
- writable: true,
72
- value: me
73
- });
74
- /**
75
- * Used by some middleware to store information about how a certain string
76
- * or regular expression was matched.
77
- */
78
- Object.defineProperty(this, "match", {
79
- enumerable: true,
80
- configurable: true,
81
- writable: true,
82
- value: void 0
83
- });
56
+ this.update = update;
57
+ this.api = api;
58
+ this.me = me;
84
59
  }
85
60
  // UPDATE SHORTCUTS
86
61
  /** Alias for `ctx.update.message` */
@@ -34,12 +34,7 @@ class Keyboard {
34
34
  * The nested array that holds the custom keyboard. It will be extended every time
35
35
  * you call one of the provided methods.
36
36
  */
37
- Object.defineProperty(this, "keyboard", {
38
- enumerable: true,
39
- configurable: true,
40
- writable: true,
41
- value: [[]]
42
- });
37
+ this.keyboard = [[]];
43
38
  }
44
39
  /**
45
40
  * Allows you to add your own `KeyboardButton` objects if you already have
@@ -141,12 +136,7 @@ class InlineKeyboard {
141
136
  * The nested array that holds the inline keyboard. It will be extended
142
137
  * every time you call one of the provided methods.
143
138
  */
144
- Object.defineProperty(this, "inline_keyboard", {
145
- enumerable: true,
146
- configurable: true,
147
- writable: true,
148
- value: [[]]
149
- });
139
+ this.inline_keyboard = [[]];
150
140
  }
151
141
  /**
152
142
  * Allows you to add your own `InlineKeyboardButton` objects if you already
@@ -212,21 +212,11 @@ class MemorySessionStorage {
212
212
  * @param timeToLive TTL in milliseconds, default is `Infinity`
213
213
  */
214
214
  constructor(timeToLive = Infinity) {
215
- Object.defineProperty(this, "timeToLive", {
216
- enumerable: true,
217
- configurable: true,
218
- writable: true,
219
- value: timeToLive
220
- });
215
+ this.timeToLive = timeToLive;
221
216
  /**
222
217
  * Internally used `Map` instance that stores the session data
223
218
  */
224
- Object.defineProperty(this, "storage", {
225
- enumerable: true,
226
- configurable: true,
227
- writable: true,
228
- value: new Map()
229
- });
219
+ this.storage = new Map();
230
220
  }
231
221
  read(key) {
232
222
  const value = this.storage.get(key);
package/out/core/api.js CHANGED
@@ -21,32 +21,6 @@ const client_js_1 = require("./client.js");
21
21
  */
22
22
  class Api {
23
23
  constructor(token, config, webhookReplyEnvelope) {
24
- /**
25
- * Provides access to all methods of the Telegram Bot API exactly as
26
- * documented on the website (https://core.telegram.org/bots/api). No
27
- * arguments are pulled up in the function signature for convenience.
28
- *
29
- * If you suppress compiler warnings, this also allows for raw api calls to
30
- * undocumented methods with arbitrary parameters—use only if you know what
31
- * you are doing.
32
- */
33
- Object.defineProperty(this, "raw", {
34
- enumerable: true,
35
- configurable: true,
36
- writable: true,
37
- value: void 0
38
- });
39
- /**
40
- * Configuration object for the API instance, used as a namespace to
41
- * separate those API operations that are related to grammY from methods of
42
- * the Telegram Bot API. Contains advanced options!
43
- */
44
- Object.defineProperty(this, "config", {
45
- enumerable: true,
46
- configurable: true,
47
- writable: true,
48
- value: void 0
49
- });
50
24
  const { raw, use, installedTransformers } = (0, client_js_1.createRawApi)(token, config, webhookReplyEnvelope);
51
25
  this.raw = raw;
52
26
  this.config = {
@@ -74,7 +74,26 @@ export interface ApiClientOptions {
74
74
  * @param method The API method to be called, e.g. `getMe`
75
75
  * @returns The URL that will be fetched during the API call
76
76
  */
77
- buildUrl?: (root: string, token: string, method: string) => Parameters<typeof fetch>[0];
77
+ buildUrl?: (root: string, token: string, method: string) => string | URL;
78
+ /**
79
+ * Maximum number of seconds that a request to the Bot API server may take.
80
+ * If a request has not completed before this time has elapsed, grammY
81
+ * aborts the request and errors. Without such a timeout, networking issues
82
+ * may cause your bot to leave open a connection indefinitely, which may
83
+ * effectively make your bot freeze.
84
+ *
85
+ * You probably do not have to care about this option. In rare cases, you
86
+ * may want to adjust it if you are transferring large files via slow
87
+ * connections to your own Bot API server.
88
+ *
89
+ * The default number of seconds is `500`, which corresponds to 8 minutes
90
+ * and 20 seconds. Note that this is also the value that is hard-coded in
91
+ * the official Bot API server, so you cannot perform any successful
92
+ * requests that exceed this time frame (even if you would allow it in
93
+ * grammY). Setting this option to higher than the default only makes sense
94
+ * with a custom Bot API server.
95
+ */
96
+ timeoutSeconds?: number;
78
97
  /**
79
98
  * If the bot is running on webhooks, as soon as the bot receives an update
80
99
  * from Telegram, it is possible to make up to one API call in the response
@@ -11,90 +11,64 @@ function concatTransformer(prev, trans) {
11
11
  }
12
12
  class ApiClient {
13
13
  constructor(token, options = {}, webhookReplyEnvelope = {}) {
14
- var _a, _b, _c, _d;
15
- Object.defineProperty(this, "token", {
16
- enumerable: true,
17
- configurable: true,
18
- writable: true,
19
- value: token
20
- });
21
- Object.defineProperty(this, "webhookReplyEnvelope", {
22
- enumerable: true,
23
- configurable: true,
24
- writable: true,
25
- value: webhookReplyEnvelope
26
- });
27
- Object.defineProperty(this, "options", {
28
- enumerable: true,
29
- configurable: true,
30
- writable: true,
31
- value: void 0
32
- });
33
- Object.defineProperty(this, "hasUsedWebhookReply", {
34
- enumerable: true,
35
- configurable: true,
36
- writable: true,
37
- value: false
38
- });
39
- Object.defineProperty(this, "installedTransformers", {
40
- enumerable: true,
41
- configurable: true,
42
- writable: true,
43
- value: []
44
- });
45
- Object.defineProperty(this, "call", {
46
- enumerable: true,
47
- configurable: true,
48
- writable: true,
49
- value: async (method, payload, signal) => {
50
- debug("Calling", method);
51
- const url = this.options.buildUrl(this.options.apiRoot, this.token, method);
52
- const formDataRequired = (0, payload_js_1.requiresFormDataUpload)(payload);
53
- if (this.webhookReplyEnvelope.send !== undefined &&
54
- !this.hasUsedWebhookReply &&
55
- !formDataRequired &&
56
- this.options.canUseWebhookReply(method)) {
57
- this.hasUsedWebhookReply = true;
58
- const config = (0, payload_js_1.createJsonPayload)({ ...payload, method });
59
- await this.webhookReplyEnvelope.send(config.body);
60
- return { ok: true, result: true };
61
- }
62
- else {
63
- const p = payload !== null && payload !== void 0 ? payload : {};
64
- const sensLogs = this.options.sensitiveLogs;
65
- const abortController = new shim_node_js_1.AbortController();
66
- const abort = combineAborts(abortController, signal);
67
- const res = await new Promise((resolve, reject) => {
68
- function onStreamError(err) {
69
- abort();
70
- reject(err);
71
- }
72
- const onHttpError = toHttpError(method, sensLogs, reject);
73
- const config = formDataRequired
74
- ? (0, payload_js_1.createFormDataPayload)(p, onStreamError)
75
- : (0, payload_js_1.createJsonPayload)(p);
76
- const opts = {
77
- ...this.options.baseFetchConfig,
78
- signal: abortController.signal,
79
- ...config,
80
- };
81
- (0, shim_node_js_1.fetch)(url, opts).then((res) => res.json()).then(resolve)
82
- .catch(onHttpError);
83
- });
84
- return res;
85
- }
14
+ var _a, _b, _c, _d, _e;
15
+ this.token = token;
16
+ this.webhookReplyEnvelope = webhookReplyEnvelope;
17
+ this.hasUsedWebhookReply = false;
18
+ this.installedTransformers = [];
19
+ this.call = async (method, p, signal) => {
20
+ const payload = p !== null && p !== void 0 ? p : {};
21
+ debug("Calling", method);
22
+ // General config
23
+ const opts = this.options;
24
+ const formDataRequired = (0, payload_js_1.requiresFormDataUpload)(payload);
25
+ // Short-circuit on webhook reply
26
+ if (this.webhookReplyEnvelope.send !== undefined &&
27
+ !this.hasUsedWebhookReply &&
28
+ !formDataRequired &&
29
+ opts.canUseWebhookReply(method)) {
30
+ this.hasUsedWebhookReply = true;
31
+ const config = (0, payload_js_1.createJsonPayload)({ ...payload, method });
32
+ await this.webhookReplyEnvelope.send(config.body);
33
+ return { ok: true, result: true };
86
34
  }
87
- });
35
+ // Handle timeouts and errors in the underlying form-data stream
36
+ const controller = createAbortControllerFromSignal(signal);
37
+ const timeout = createTimeout(controller, opts.timeoutSeconds, method);
38
+ const streamErr = createStreamError(controller);
39
+ // Build request URL and config
40
+ const url = opts.buildUrl(opts.apiRoot, this.token, method);
41
+ const config = formDataRequired
42
+ ? (0, payload_js_1.createFormDataPayload)(payload, (err) => streamErr.catch(err))
43
+ : (0, payload_js_1.createJsonPayload)(payload);
44
+ const sig = controller.signal;
45
+ const options = { ...opts.baseFetchConfig, signal: sig, ...config };
46
+ // Perform fetch call, and handle networking errors
47
+ const successPromise = (0, shim_node_js_1.fetch)(url instanceof URL ? url.href : url, options)
48
+ .catch((0, error_js_1.toHttpError)(method, opts.sensitiveLogs));
49
+ // Those are the three possible outcomes of the fetch call:
50
+ const operations = [successPromise, streamErr.promise, timeout.promise];
51
+ // Wait for result
52
+ try {
53
+ const res = await Promise.race(operations);
54
+ return await res.json();
55
+ }
56
+ finally {
57
+ if (timeout.handle !== undefined)
58
+ clearTimeout(timeout.handle);
59
+ }
60
+ };
88
61
  const apiRoot = (_a = options.apiRoot) !== null && _a !== void 0 ? _a : "https://api.telegram.org";
89
62
  this.options = {
90
63
  apiRoot,
91
64
  buildUrl: (_b = options.buildUrl) !== null && _b !== void 0 ? _b : ((root, token, method) => `${root}/bot${token}/${method}`),
65
+ timeoutSeconds: (_c = options.timeoutSeconds) !== null && _c !== void 0 ? _c : 500,
92
66
  baseFetchConfig: {
93
67
  ...(0, platform_node_js_1.baseFetchConfig)(apiRoot),
94
68
  ...options.baseFetchConfig,
95
69
  },
96
- canUseWebhookReply: (_c = options.canUseWebhookReply) !== null && _c !== void 0 ? _c : (() => false),
97
- sensitiveLogs: (_d = options.sensitiveLogs) !== null && _d !== void 0 ? _d : false,
70
+ canUseWebhookReply: (_d = options.canUseWebhookReply) !== null && _d !== void 0 ? _d : (() => false),
71
+ sensitiveLogs: (_e = options.sensitiveLogs) !== null && _e !== void 0 ? _e : false,
98
72
  };
99
73
  if (this.options.apiRoot.endsWith("/")) {
100
74
  throw new Error(`Remove the trailing '/' from the 'apiRoot' option (use '${this.options.apiRoot.substring(0, this.options.apiRoot.length - 1)}' instead of '${this.options.apiRoot}')`);
@@ -109,9 +83,8 @@ class ApiClient {
109
83
  const data = await this.call(method, payload, signal);
110
84
  if (data.ok)
111
85
  return data.result;
112
- else {
113
- throw new error_js_1.GrammyError(`Call to '${method}' failed!`, data, method, payload);
114
- }
86
+ else
87
+ throw (0, error_js_1.toGrammyError)(data, method, payload);
115
88
  }
116
89
  }
117
90
  /**
@@ -164,25 +137,36 @@ const proxyMethods = {
164
137
  return [];
165
138
  },
166
139
  };
167
- function isTelegramError(err) {
168
- return (typeof err === "object" &&
169
- err !== null &&
170
- "status" in err &&
171
- "statusText" in err);
140
+ /** Creates a timeout error which aborts a given controller */
141
+ function createTimeout(controller, seconds, method) {
142
+ let handle = undefined;
143
+ const promise = new Promise((_, reject) => {
144
+ handle = setTimeout(() => {
145
+ const msg = `Request to '${method}' timed out after ${seconds} seconds`;
146
+ reject(new Error(msg));
147
+ controller.abort();
148
+ }, 1000 * seconds);
149
+ });
150
+ return { promise, handle };
172
151
  }
173
- function toHttpError(method, sensitiveLogs, reject) {
174
- return (err) => {
175
- let msg = `Network request for '${method}' failed!`;
176
- if (isTelegramError(err))
177
- msg += ` (${err.status}: ${err.statusText})`;
178
- if (sensitiveLogs && err instanceof Error)
179
- msg += ` ${err.message}`;
180
- reject(new error_js_1.HttpError(msg, err));
152
+ /** Creates a stream error which abort a given controller */
153
+ function createStreamError(abortController) {
154
+ let onError = (err) => {
155
+ // Re-throw by default, but will be overwritten immediately
156
+ throw err;
181
157
  };
158
+ const promise = new Promise((_, reject) => {
159
+ onError = (err) => {
160
+ reject(err);
161
+ abortController.abort();
162
+ };
163
+ });
164
+ return { promise, catch: onError };
182
165
  }
183
- function combineAborts(abortController, signal) {
166
+ function createAbortControllerFromSignal(signal) {
167
+ const abortController = new shim_node_js_1.AbortController();
184
168
  if (signal === undefined)
185
- return () => abortController.abort();
169
+ return abortController;
186
170
  const sig = signal;
187
171
  function abort() {
188
172
  abortController.abort();
@@ -192,6 +176,6 @@ function combineAborts(abortController, signal) {
192
176
  abort();
193
177
  else
194
178
  sig.addEventListener("abort", abort);
195
- return abort;
179
+ return { abort, signal: abortController.signal };
196
180
  }
197
181
  const shim_node_js_1 = require("../shim.node.js");
@@ -29,6 +29,7 @@ export declare class GrammyError extends Error implements ApiError {
29
29
  /** The payload that was passed when calling the method. */
30
30
  payload: Record<string, unknown>);
31
31
  }
32
+ export declare function toGrammyError(err: ApiError, method: string, payload: Record<string, unknown>): GrammyError;
32
33
  /**
33
34
  * This class represents errors that are thrown by grammY because an HTTP call
34
35
  * to the Telegram Bot API failed.
@@ -49,3 +50,4 @@ export declare class HttpError extends Error {
49
50
  /** The thrown error object. */
50
51
  error: unknown);
51
52
  }
53
+ export declare function toHttpError(method: string, sensitiveLogs: boolean): (err: unknown) => never;
package/out/core/error.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HttpError = exports.GrammyError = void 0;
3
+ exports.toHttpError = exports.HttpError = exports.toGrammyError = exports.GrammyError = void 0;
4
4
  /**
5
5
  * This class represents errors that are thrown by grammY because the Telegram
6
6
  * Bot API responded with an error.
@@ -20,46 +20,10 @@ class GrammyError extends Error {
20
20
  payload) {
21
21
  var _a;
22
22
  super(`${message} (${err.error_code}: ${err.description})`);
23
- Object.defineProperty(this, "method", {
24
- enumerable: true,
25
- configurable: true,
26
- writable: true,
27
- value: method
28
- });
29
- Object.defineProperty(this, "payload", {
30
- enumerable: true,
31
- configurable: true,
32
- writable: true,
33
- value: payload
34
- });
23
+ this.method = method;
24
+ this.payload = payload;
35
25
  /** Flag that this request was unsuccessful. Always `false`. */
36
- Object.defineProperty(this, "ok", {
37
- enumerable: true,
38
- configurable: true,
39
- writable: true,
40
- value: false
41
- });
42
- /** An integer holding Telegram's error code. Subject to change. */
43
- Object.defineProperty(this, "error_code", {
44
- enumerable: true,
45
- configurable: true,
46
- writable: true,
47
- value: void 0
48
- });
49
- /** A human-readable description of the error. */
50
- Object.defineProperty(this, "description", {
51
- enumerable: true,
52
- configurable: true,
53
- writable: true,
54
- value: void 0
55
- });
56
- /** Further parameters that may help to automatically handle the error. */
57
- Object.defineProperty(this, "parameters", {
58
- enumerable: true,
59
- configurable: true,
60
- writable: true,
61
- value: void 0
62
- });
26
+ this.ok = false;
63
27
  this.name = "GrammyError";
64
28
  this.error_code = err.error_code;
65
29
  this.description = err.description;
@@ -67,6 +31,10 @@ class GrammyError extends Error {
67
31
  }
68
32
  }
69
33
  exports.GrammyError = GrammyError;
34
+ function toGrammyError(err, method, payload) {
35
+ return new GrammyError(`Call to '${method}' failed!`, err, method, payload);
36
+ }
37
+ exports.toGrammyError = toGrammyError;
70
38
  /**
71
39
  * This class represents errors that are thrown by grammY because an HTTP call
72
40
  * to the Telegram Bot API failed.
@@ -85,13 +53,25 @@ class HttpError extends Error {
85
53
  /** The thrown error object. */
86
54
  error) {
87
55
  super(message);
88
- Object.defineProperty(this, "error", {
89
- enumerable: true,
90
- configurable: true,
91
- writable: true,
92
- value: error
93
- });
56
+ this.error = error;
94
57
  this.name = "HttpError";
95
58
  }
96
59
  }
97
60
  exports.HttpError = HttpError;
61
+ function isTelegramError(err) {
62
+ return (typeof err === "object" &&
63
+ err !== null &&
64
+ "status" in err &&
65
+ "statusText" in err);
66
+ }
67
+ function toHttpError(method, sensitiveLogs) {
68
+ return (err) => {
69
+ let msg = `Network request for '${method}' failed!`;
70
+ if (isTelegramError(err))
71
+ msg += ` (${err.status}: ${err.statusText})`;
72
+ if (sensitiveLogs && err instanceof Error)
73
+ msg += ` ${err.message}`;
74
+ throw new HttpError(msg, err);
75
+ };
76
+ }
77
+ exports.toHttpError = toHttpError;
package/out/mod.js CHANGED
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
3
  if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[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);
5
9
  }) : (function(o, m, k, k2) {
6
10
  if (k2 === undefined) k2 = k;
7
11
  o[k2] = m[k];
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
3
  if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[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);
5
9
  }) : (function(o, m, k, k2) {
6
10
  if (k2 === undefined) k2 = k;
7
11
  o[k2] = m[k];
@@ -58,31 +62,7 @@ class InputFile {
58
62
  * @param filename Optional name of the file
59
63
  */
60
64
  constructor(file, filename) {
61
- Object.defineProperty(this, "consumed", {
62
- enumerable: true,
63
- configurable: true,
64
- writable: true,
65
- value: false
66
- });
67
- Object.defineProperty(this, "fileData", {
68
- enumerable: true,
69
- configurable: true,
70
- writable: true,
71
- value: void 0
72
- });
73
- /**
74
- * Optional name of the constructed `InputFile` instance.
75
- *
76
- * Check out the
77
- * [documenation](https://grammy.dev/guide/files.html#uploading-your-own-file)
78
- * on sending files with `InputFile`.
79
- */
80
- Object.defineProperty(this, "filename", {
81
- enumerable: true,
82
- configurable: true,
83
- writable: true,
84
- value: void 0
85
- });
65
+ this.consumed = false;
86
66
  this.fileData = file;
87
67
  filename !== null && filename !== void 0 ? filename : (filename = this.guessFilename(file));
88
68
  this.filename = filename;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "grammy",
3
3
  "description": "The Telegram Bot Framework.",
4
- "version": "1.7.0",
4
+ "version": "1.7.3",
5
5
  "author": "KnorpelSenf",
6
6
  "license": "MIT",
7
7
  "engines": {
@@ -25,15 +25,15 @@
25
25
  "dependencies": {
26
26
  "@grammyjs/types": "^2.6.0",
27
27
  "abort-controller": "^3.0.0",
28
- "debug": "^4.3.3",
29
- "node-fetch": "^2.6.5"
28
+ "debug": "^4.3.4",
29
+ "node-fetch": "^2.6.7"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/debug": "^4.1.7",
33
- "@types/node": "^12.20.36",
34
- "@types/node-fetch": "^2.5.12",
33
+ "@types/node": "^12.20.47",
34
+ "@types/node-fetch": "^2.6.1",
35
35
  "all-contributors-cli": "^6.20.0",
36
- "deno2node": "^1.1.0"
36
+ "deno2node": "^1.3.0"
37
37
  },
38
38
  "files": [
39
39
  "out/"