grammy 1.5.5 β†’ 1.7.0

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021 KnorpelSenf
3
+ Copyright (c) 2022 KnorpelSenf
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -10,9 +10,9 @@ _<h2 align="center"> [:mag: Documentation](https://grammy.dev) | [:page_with_cur
10
10
 
11
11
  <!-- deno-fmt-ignore-start -->
12
12
 
13
- [![Bot API](https://img.shields.io/badge/Bot%20API-5.5-blue?logo=telegram&style=flat-square)](https://core.telegram.org/bots/api)
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-48-orange.svg?style=flat-square)](#contributors-)
15
+ [![All Contributors](https://img.shields.io/badge/all_contributors-50-orange.svg?style=flat-square)](#contributors-)
16
16
  <!-- ALL-CONTRIBUTORS-BADGE:END -->
17
17
 
18
18
  <!-- deno-fmt-ignore-end -->
@@ -130,7 +130,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
130
130
  <table>
131
131
  <tr>
132
132
  <td align="center"><a href="https://github.com/KnorpelSenf"><img src="https://avatars.githubusercontent.com/u/12952387?v=4?s=100" width="100px;" alt=""/><br /><sub><b>KnorpelSenf</b></sub></a><br /><a href="#ideas-KnorpelSenf" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/grammyjs/grammY/commits?author=KnorpelSenf" title="Code">πŸ’»</a> <a href="https://github.com/grammyjs/grammY/commits?author=KnorpelSenf" title="Documentation">πŸ“–</a> <a href="#design-KnorpelSenf" title="Design">🎨</a> <a href="#example-KnorpelSenf" title="Examples">πŸ’‘</a> <a href="https://github.com/grammyjs/grammY/commits?author=KnorpelSenf" title="Tests">⚠️</a> <a href="#plugin-KnorpelSenf" title="Plugin/utility libraries">πŸ”Œ</a> <a href="#platform-KnorpelSenf" title="Packaging/porting to new platform">πŸ“¦</a> <a href="https://github.com/grammyjs/grammY/pulls?q=is%3Apr+reviewed-by%3AKnorpelSenf" title="Reviewed Pull Requests">πŸ‘€</a> <a href="#mentoring-KnorpelSenf" title="Mentoring">πŸ§‘β€πŸ«</a> <a href="#projectManagement-KnorpelSenf" title="Project Management">πŸ“†</a> <a href="#infra-KnorpelSenf" title="Infrastructure (Hosting, Build-Tools, etc)">πŸš‡</a></td>
133
- <td align="center"><a href="https://github.com/Tecardo1"><img src="https://avatars.githubusercontent.com/u/42873000?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tecardo1</b></sub></a><br /><a href="#plugin-Tecardo1" title="Plugin/utility libraries">πŸ”Œ</a> <a href="#userTesting-Tecardo1" title="User Testing">πŸ““</a> <a href="#example-Tecardo1" title="Examples">πŸ’‘</a> <a href="https://github.com/grammyjs/grammY/commits?author=Tecardo1" title="Documentation">πŸ“–</a></td>
133
+ <td align="center"><a href="https://github.com/Tecardo1"><img src="https://avatars.githubusercontent.com/u/42873000?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tecardo1</b></sub></a><br /><a href="#plugin-Tecardo1" title="Plugin/utility libraries">πŸ”Œ</a> <a href="#userTesting-Tecardo1" title="User Testing">πŸ““</a> <a href="#example-Tecardo1" title="Examples">πŸ’‘</a> <a href="https://github.com/grammyjs/grammY/commits?author=Tecardo1" title="Documentation">πŸ“–</a> <a href="https://github.com/grammyjs/grammY/pulls?q=is%3Apr+reviewed-by%3ATecardo1" title="Reviewed Pull Requests">πŸ‘€</a></td>
134
134
  <td align="center"><a href="https://github.com/wojpawlik"><img src="https://avatars.githubusercontent.com/u/23058303?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Wojciech Pawlik</b></sub></a><br /><a href="#ideas-wojpawlik" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/grammyjs/grammY/pulls?q=is%3Apr+reviewed-by%3Awojpawlik" title="Reviewed Pull Requests">πŸ‘€</a> <a href="#infra-wojpawlik" title="Infrastructure (Hosting, Build-Tools, etc)">πŸš‡</a> <a href="#platform-wojpawlik" title="Packaging/porting to new platform">πŸ“¦</a> <a href="#tool-wojpawlik" title="Tools">πŸ”§</a></td>
135
135
  <td align="center"><a href="https://github.com/MegaITA"><img src="https://avatars.githubusercontent.com/u/32493080?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alessandro Bertozzi</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/commits?author=MegaITA" title="Documentation">πŸ“–</a></td>
136
136
  <td align="center"><a href="https://trgwii.no/"><img src="https://avatars.githubusercontent.com/u/11262022?v=4?s=100" width="100px;" alt=""/><br /><sub><b>trgwii</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/commits?author=trgwii" title="Code">πŸ’»</a> <a href="https://github.com/grammyjs/grammY/pulls?q=is%3Apr+reviewed-by%3Atrgwii" title="Reviewed Pull Requests">πŸ‘€</a></td>
@@ -189,6 +189,10 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
189
189
  <td align="center"><a href="http://glukki.ru"><img src="https://avatars.githubusercontent.com/u/140462?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vitaliy Meshchaninov</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/issues?q=author%3Aglukki" title="Bug reports">πŸ›</a> <a href="https://github.com/grammyjs/grammY/commits?author=glukki" title="Code">πŸ’»</a></td>
190
190
  <td align="center"><a href="https://github.com/dilyanpalauzov"><img src="https://avatars.githubusercontent.com/u/4992947?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Дилян ΠŸΠ°Π»Π°ΡƒΠ·ΠΎΠ²</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/issues?q=author%3Adilyanpalauzov" title="Bug reports">πŸ›</a> <a href="https://github.com/grammyjs/grammY/commits?author=dilyanpalauzov" title="Code">πŸ’»</a></td>
191
191
  <td align="center"><a href="https://github.com/lmx-Hexagram"><img src="https://avatars.githubusercontent.com/u/52130356?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lmx-Hexagram</b></sub></a><br /><a href="https://github.com/grammyjs/grammY/commits?author=lmx-Hexagram" title="Documentation">πŸ“–</a></td>
192
+ <td align="center"><a href="https://github.com/IlyaSemenov"><img src="https://avatars.githubusercontent.com/u/128121?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ilya Semenov</b></sub></a><br /><a href="#ideas-IlyaSemenov" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/grammyjs/grammY/pulls?q=is%3Apr+reviewed-by%3AIlyaSemenov" title="Reviewed Pull Requests">πŸ‘€</a></td>
193
+ </tr>
194
+ <tr>
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>
192
196
  </tr>
193
197
  </table>
194
198
 
package/out/bot.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { BotError, Composer } from "./composer.js";
2
2
  import { Context } from "./context.js";
3
3
  import { Api } from "./core/api.js";
4
- import { ApiClientOptions, WebhookReplyEnvelope } from "./core/client.js";
5
- import { Update, UserFromGetMe } from "./platform.node.js";
4
+ import { type ApiClientOptions, type WebhookReplyEnvelope } from "./core/client.js";
5
+ import { type Update, type UserFromGetMe } from "./platform.node.js";
6
6
  /**
7
7
  * Options that can be specified when running the bot via simple long polling.
8
8
  */
@@ -153,11 +153,30 @@ export declare class Bot<C extends Context = Context, A extends Api = Api> exten
153
153
  */
154
154
  set botInfo(botInfo: UserFromGetMe);
155
155
  get botInfo(): UserFromGetMe;
156
+ /**
157
+ * Checks if the bot has been initialized. A bot is initialized if the bot
158
+ * information is set. The bot information can either be set automatically
159
+ * by calling `bot.init`, or manually through the bot constructor. Note that
160
+ * usually, initialization is done automatically and you do not have to care
161
+ * about this method.
162
+ *
163
+ * @returns true if the bot is initialized, and false otherwise
164
+ */
165
+ isInited(): boolean;
156
166
  /**
157
167
  * Initializes the bot, i.e. fetches information about the bot itself. This
158
- * method is called automatically, you don't have to call it manually.
168
+ * method is called automatically, you usually don't have to call it
169
+ * manually.
159
170
  */
160
171
  init(): Promise<void>;
172
+ /**
173
+ * Internal. Do not call. Handles an update batch sequentially by supplying
174
+ * it one-by-one to the middleware. Handles middleware errors and stores the
175
+ * last update identifier that was being tried to handle.
176
+ *
177
+ * @param updates An array of updates to handle
178
+ */
179
+ private handleUpdates;
161
180
  /**
162
181
  * This is an internal method that you probably will not ever need to call.
163
182
  * It is used whenever a new update arrives from the Telegram servers that
@@ -238,4 +257,23 @@ export declare class Bot<C extends Context = Context, A extends Api = Api> exten
238
257
  * @param errorHandler A function that handles potential middleware errors
239
258
  */
240
259
  catch(errorHandler: ErrorHandler<C>): void;
260
+ /**
261
+ * Internal. Do not call. Enters a loop that will perform long polling until
262
+ * the bot is stopped.
263
+ */
264
+ private loop;
265
+ /**
266
+ * Internal. Do not call. Reliably fetches an update batch via `getUpdates`.
267
+ * Handles all known errors. Returns `undefined` if the bot is stopped and
268
+ * the call gets cancelled.
269
+ *
270
+ * @param options Polling options
271
+ * @returns An array of updates, or `undefined` if the bot is stopped.
272
+ */
273
+ private fetchUpdates;
274
+ /**
275
+ * Internal. Do not call. Handles an error that occurred during long
276
+ * polling.
277
+ */
278
+ private handlePollingError;
241
279
  }
package/out/bot.js CHANGED
@@ -157,12 +157,25 @@ class Bot extends composer_js_1.Composer {
157
157
  }
158
158
  return this.me;
159
159
  }
160
+ /**
161
+ * Checks if the bot has been initialized. A bot is initialized if the bot
162
+ * information is set. The bot information can either be set automatically
163
+ * by calling `bot.init`, or manually through the bot constructor. Note that
164
+ * usually, initialization is done automatically and you do not have to care
165
+ * about this method.
166
+ *
167
+ * @returns true if the bot is initialized, and false otherwise
168
+ */
169
+ isInited() {
170
+ return this.me !== undefined;
171
+ }
160
172
  /**
161
173
  * Initializes the bot, i.e. fetches information about the bot itself. This
162
- * method is called automatically, you don't have to call it manually.
174
+ * method is called automatically, you usually don't have to call it
175
+ * manually.
163
176
  */
164
177
  async init() {
165
- if (this.me === undefined) {
178
+ if (!this.isInited()) {
166
179
  debug("Initializing bot");
167
180
  const me = await this.api.getMe();
168
181
  if (this.me === undefined)
@@ -170,11 +183,34 @@ class Bot extends composer_js_1.Composer {
170
183
  else
171
184
  debug("Bot info was set manually by now, will not overwrite");
172
185
  }
173
- else {
174
- debug("Bot already initialized!");
175
- }
176
186
  debug(`I am ${this.me.username}!`);
177
187
  }
188
+ /**
189
+ * Internal. Do not call. Handles an update batch sequentially by supplying
190
+ * it one-by-one to the middleware. Handles middleware errors and stores the
191
+ * last update identifier that was being tried to handle.
192
+ *
193
+ * @param updates An array of updates to handle
194
+ */
195
+ async handleUpdates(updates) {
196
+ // handle updates sequentially (!)
197
+ for (const update of updates) {
198
+ this.lastTriedUpdateId = update.update_id;
199
+ try {
200
+ await this.handleUpdate(update);
201
+ }
202
+ catch (err) {
203
+ // should always be true
204
+ if (err instanceof composer_js_1.BotError) {
205
+ await this.errorHandler(err);
206
+ }
207
+ else {
208
+ console.error("FATAL: grammY unable to handle:", err);
209
+ throw err;
210
+ }
211
+ }
212
+ }
213
+ }
178
214
  /**
179
215
  * This is an internal method that you probably will not ever need to call.
180
216
  * It is used whenever a new update arrives from the Telegram servers that
@@ -246,9 +282,10 @@ a known bot info object.");
246
282
  * @param options Options to use for simple long polling
247
283
  */
248
284
  async start(options) {
249
- var _a, _b;
285
+ var _a;
250
286
  // Perform setup
251
- await withRetries(() => this.init());
287
+ if (!this.isInited())
288
+ await withRetries(() => this.init());
252
289
  if (this.pollingRunning) {
253
290
  debug("Simple long polling already running!");
254
291
  return;
@@ -272,76 +309,8 @@ you can circumvent this protection against memory leaks.`);
272
309
  };
273
310
  // Start polling
274
311
  debug("Starting simple long polling");
275
- this.pollingRunning = true;
276
- this.pollingAbortController = new shim_node_js_1.AbortController();
277
- const limit = options === null || options === void 0 ? void 0 : options.limit;
278
- const timeout = (_a = options === null || options === void 0 ? void 0 : options.timeout) !== null && _a !== void 0 ? _a : 30; // seconds
279
- let allowed_updates = options === null || options === void 0 ? void 0 : options.allowed_updates;
280
- try {
281
- (_b = options === null || options === void 0 ? void 0 : options.onStart) === null || _b === void 0 ? void 0 : _b.call(options, this.botInfo);
282
- }
283
- catch (error) {
284
- this.pollingRunning = false;
285
- this.pollingAbortController = undefined;
286
- throw error;
287
- }
288
- const handleErr = async (error) => {
289
- if (!this.pollingRunning)
290
- throw error;
291
- else if (error instanceof error_js_1.GrammyError) {
292
- debugErr(error.message);
293
- if (error.error_code === 401) {
294
- debugErr("Make sure you are using the bot token you obtained from @BotFather (https://t.me/BotFather).");
295
- throw error;
296
- }
297
- else if (error.error_code === 409) {
298
- debugErr("Consider revoking the bot token if you believe that no other instance is running.");
299
- throw error;
300
- }
301
- }
302
- else
303
- debugErr(error);
304
- debugErr("Call to getUpdates failed, retrying in 3 seconds ...");
305
- await new Promise((r) => setTimeout(r, 3000));
306
- };
307
- while (this.pollingRunning) {
308
- // fetch updates
309
- const offset = this.lastTriedUpdateId + 1;
310
- let updates = undefined;
311
- do {
312
- try {
313
- updates = await this.api.getUpdates({ offset, limit, timeout, allowed_updates }, this.pollingAbortController.signal);
314
- }
315
- catch (error) {
316
- if (this.pollingRunning)
317
- await handleErr(error);
318
- else
319
- debug("Pending getUpdates request cancelled");
320
- }
321
- } while (updates === undefined && this.pollingRunning);
322
- if (updates === undefined)
323
- break;
324
- // handle them sequentially (!)
325
- for (const update of updates) {
326
- this.lastTriedUpdateId = update.update_id;
327
- try {
328
- await this.handleUpdate(update);
329
- }
330
- catch (err) {
331
- // should always be true
332
- if (err instanceof composer_js_1.BotError) {
333
- await this.errorHandler(err);
334
- }
335
- else {
336
- console.error("FATAL: grammY unable to handle:", err);
337
- throw err;
338
- }
339
- }
340
- }
341
- // Telegram uses the last setting if `allowed_updates` is omitted so
342
- // we can save same traffic by only sending it in the first request
343
- allowed_updates = undefined;
344
- }
312
+ (_a = options === null || options === void 0 ? void 0 : options.onStart) === null || _a === void 0 ? void 0 : _a.call(options, this.botInfo);
313
+ await this.loop(options);
345
314
  debug("Middleware is done running");
346
315
  }
347
316
  /**
@@ -391,8 +360,90 @@ you can circumvent this protection against memory leaks.`);
391
360
  catch(errorHandler) {
392
361
  this.errorHandler = errorHandler;
393
362
  }
363
+ /**
364
+ * Internal. Do not call. Enters a loop that will perform long polling until
365
+ * the bot is stopped.
366
+ */
367
+ async loop(options) {
368
+ var _a;
369
+ this.pollingRunning = true;
370
+ this.pollingAbortController = new shim_node_js_1.AbortController();
371
+ const limit = options === null || options === void 0 ? void 0 : options.limit;
372
+ const timeout = (_a = options === null || options === void 0 ? void 0 : options.timeout) !== null && _a !== void 0 ? _a : 30; // seconds
373
+ let allowed_updates = options === null || options === void 0 ? void 0 : options.allowed_updates;
374
+ while (this.pollingRunning) {
375
+ // fetch updates
376
+ const updates = await this.fetchUpdates({ limit, timeout, allowed_updates });
377
+ // check if polling stopped
378
+ if (updates === undefined)
379
+ break;
380
+ // handle updates
381
+ await this.handleUpdates(updates);
382
+ // Telegram uses the last setting if `allowed_updates` is omitted so
383
+ // we can save same traffic by only sending it in the first request
384
+ allowed_updates = undefined;
385
+ }
386
+ }
387
+ /**
388
+ * Internal. Do not call. Reliably fetches an update batch via `getUpdates`.
389
+ * Handles all known errors. Returns `undefined` if the bot is stopped and
390
+ * the call gets cancelled.
391
+ *
392
+ * @param options Polling options
393
+ * @returns An array of updates, or `undefined` if the bot is stopped.
394
+ */
395
+ async fetchUpdates({ limit, timeout, allowed_updates }) {
396
+ var _a;
397
+ const offset = this.lastTriedUpdateId + 1;
398
+ let updates = undefined;
399
+ do {
400
+ try {
401
+ updates = await this.api.getUpdates({ offset, limit, timeout, allowed_updates }, (_a = this.pollingAbortController) === null || _a === void 0 ? void 0 : _a.signal);
402
+ }
403
+ catch (error) {
404
+ await this.handlePollingError(error);
405
+ }
406
+ } while (updates === undefined && this.pollingRunning);
407
+ return updates;
408
+ }
409
+ /**
410
+ * Internal. Do not call. Handles an error that occurred during long
411
+ * polling.
412
+ */
413
+ async handlePollingError(error) {
414
+ var _a;
415
+ if (!this.pollingRunning) {
416
+ debug("Pending getUpdates request cancelled");
417
+ return;
418
+ }
419
+ let sleepSeconds = 3;
420
+ if (error instanceof error_js_1.GrammyError) {
421
+ debugErr(error.message);
422
+ if (error.error_code === 401) {
423
+ debugErr("Make sure you are using the bot token you obtained from @BotFather (https://t.me/BotFather).");
424
+ throw error;
425
+ }
426
+ else if (error.error_code === 409) {
427
+ debugErr("Consider revoking the bot token if you believe that no other instance is running.");
428
+ throw error;
429
+ }
430
+ else if (error.error_code === 429) {
431
+ debugErr("Bot API server is closing.");
432
+ sleepSeconds = (_a = error.parameters.retry_after) !== null && _a !== void 0 ? _a : sleepSeconds;
433
+ }
434
+ }
435
+ else
436
+ debugErr(error);
437
+ debugErr(`Call to getUpdates failed, retrying in ${sleepSeconds} seconds ...`);
438
+ await sleep(sleepSeconds);
439
+ }
394
440
  }
395
441
  exports.Bot = Bot;
442
+ /**
443
+ * Performs a network call task, retrying upon known errors until success.
444
+ *
445
+ * @param task Async task to perform
446
+ */
396
447
  async function withRetries(task) {
397
448
  let success = false;
398
449
  while (!success) {
@@ -409,9 +460,8 @@ async function withRetries(task) {
409
460
  continue;
410
461
  if (error.error_code === 429) {
411
462
  const retryAfter = error.parameters.retry_after;
412
- if (retryAfter !== undefined) {
413
- await new Promise((resolve) => setTimeout(resolve, 1000 * retryAfter));
414
- }
463
+ if (retryAfter !== undefined)
464
+ await sleep(retryAfter);
415
465
  continue;
416
466
  }
417
467
  }
@@ -419,4 +469,10 @@ async function withRetries(task) {
419
469
  }
420
470
  }
421
471
  }
472
+ /**
473
+ * Returns a new promise that resolves after the specified number of seconds.
474
+ */
475
+ function sleep(seconds) {
476
+ return new Promise((r) => setTimeout(r, 1000 * seconds));
477
+ }
422
478
  const shim_node_js_1 = require("./shim.node.js");
package/out/composer.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Context } from "./context.js";
2
- import { Filter, FilterQuery } from "./filter.js";
1
+ import { type Context } from "./context.js";
2
+ import { type Filter, type FilterQuery } from "./filter.js";
3
3
  declare type MaybePromise<T> = T | Promise<T>;
4
4
  declare type MaybeArray<T> = T | T[];
5
5
  declare type StringWithSuggestions<S extends string> = (string & {}) | S;
package/out/composer.js CHANGED
@@ -45,7 +45,7 @@ function generateBotErrorMessage(error) {
45
45
  msg += `: ${error}`;
46
46
  break;
47
47
  case "string":
48
- msg += `: ${String(error).substr(0, 50)}`;
48
+ msg += `: ${String(error).substring(0, 50)}`;
49
49
  break;
50
50
  default:
51
51
  msg += "!";
@@ -299,24 +299,23 @@ class Composer {
299
299
  const noAtCommands = new Set();
300
300
  toArray(command).forEach((cmd) => {
301
301
  if (cmd.startsWith("/")) {
302
- throw new Error(`Do not include '/' when registering command handlers (use '${cmd.substr(1)}' not '${cmd}')`);
302
+ throw new Error(`Do not include '/' when registering command handlers (use '${cmd.substring(1)}' not '${cmd}')`);
303
303
  }
304
304
  const set = cmd.indexOf("@") === -1 ? noAtCommands : atCommands;
305
305
  set.add(cmd);
306
306
  });
307
307
  return this.on(":entities:bot_command").filter((ctx) => {
308
- var _a, _b, _c;
308
+ var _a;
309
309
  const msg = (_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost;
310
- const txt = (_b = msg.text) !== null && _b !== void 0 ? _b : msg.caption;
311
- const entities = (_c = msg.entities) !== null && _c !== void 0 ? _c : msg.caption_entities;
312
- return entities.some((e) => {
310
+ const txt = msg.text;
311
+ return msg.entities.some((e) => {
313
312
  if (e.type !== "bot_command")
314
313
  return false;
315
314
  if (e.offset !== 0)
316
315
  return false;
317
316
  const cmd = txt.substring(1, e.length);
318
317
  if (noAtCommands.has(cmd) || atCommands.has(cmd)) {
319
- ctx.match = txt.substr(cmd.length + 1).trimStart();
318
+ ctx.match = txt.substring(cmd.length + 1).trimStart();
320
319
  return true;
321
320
  }
322
321
  const index = cmd.indexOf("@");
@@ -327,7 +326,7 @@ class Composer {
327
326
  return false;
328
327
  const atCommand = cmd.substring(0, index);
329
328
  if (noAtCommands.has(atCommand)) {
330
- ctx.match = txt.substr(cmd.length + 1).trimStart();
329
+ ctx.match = txt.substring(cmd.length + 1).trimStart();
331
330
  return true;
332
331
  }
333
332
  return false;
package/out/context.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { Api, Other as OtherApi } from "./core/api.js";
2
- import { Methods, RawApi } from "./core/client.js";
3
- import { Chat, ChatPermissions, InlineQueryResult, InputFile, InputMedia, InputMediaAudio, InputMediaDocument, InputMediaPhoto, InputMediaVideo, LabeledPrice, Message, PassportElementError, Update, User, UserFromGetMe } from "./platform.node.js";
1
+ import { type Api, type Other as OtherApi } from "./core/api.js";
2
+ import { type Methods, type RawApi } from "./core/client.js";
3
+ import { type Chat, type ChatPermissions, type InlineQueryResult, type InputFile, type InputMedia, type InputMediaAudio, type InputMediaDocument, type InputMediaPhoto, type InputMediaVideo, type LabeledPrice, type Message, type PassportElementError, type Update, type User, type UserFromGetMe } from "./platform.node.js";
4
4
  declare type Other<M extends Methods<RawApi>, X extends string = never> = OtherApi<RawApi, M, X>;
5
5
  declare type SnakeToCamelCase<S extends string> = S extends `${infer L}_${infer R}` ? `${L}${Capitalize<SnakeToCamelCase<R>>}` : S;
6
6
  export declare type AliasProps<U> = {
@@ -735,7 +735,7 @@ export declare class Context implements RenamedUpdate {
735
735
  */
736
736
  deleteMessage(signal?: AbortSignal): Promise<true>;
737
737
  /**
738
- * Context-aware alias for `api.sendSticker`. Use this method to send static .WEBP or animated .TGS stickers. On success, the sent Message is returned.
738
+ * Context-aware alias for `api.sendSticker`. Use this method to send static .WEBP, animated .TGS, or video .WEBM stickers. On success, the sent Message is returned.
739
739
  *
740
740
  * @param sticker Sticker to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a .WEBP file from the Internet, or upload a new one using multipart/form-data.
741
741
  * @param other Optional remaining parameters, confer the official reference below
package/out/context.js CHANGED
@@ -940,7 +940,7 @@ class Context {
940
940
  return this.api.deleteMessage(orThrow(this.chat, "deleteMessage").id, orThrow(this.msg, "deleteMessage").message_id, signal);
941
941
  }
942
942
  /**
943
- * Context-aware alias for `api.sendSticker`. Use this method to send static .WEBP or animated .TGS stickers. On success, the sent Message is returned.
943
+ * Context-aware alias for `api.sendSticker`. Use this method to send static .WEBP, animated .TGS, or video .WEBM stickers. On success, the sent Message is returned.
944
944
  *
945
945
  * @param sticker Sticker to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a .WEBP file from the Internet, or upload a new one using multipart/form-data.
946
946
  * @param other Optional remaining parameters, confer the official reference below
@@ -1,14 +1,15 @@
1
- import type { IncomingMessage, ServerResponse } from "http";
1
+ /// <reference types="node" />
2
+ import { type IncomingMessage, type ServerResponse } from "http";
2
3
  export declare const adapters: {
3
4
  http: (req: IncomingMessage, res: ServerResponse) => {
4
5
  update: Promise<any>;
5
- end: () => void;
6
- respond: (json: string) => void;
6
+ end: () => ServerResponse;
7
+ respond: (json: string) => ServerResponse;
7
8
  };
8
9
  https: (req: IncomingMessage, res: ServerResponse) => {
9
10
  update: Promise<any>;
10
- end: () => void;
11
- respond: (json: string) => void;
11
+ end: () => ServerResponse;
12
+ respond: (json: string) => ServerResponse;
12
13
  };
13
14
  express: (req: any, res: any) => {
14
15
  update: Promise<any>;
@@ -1,4 +1,4 @@
1
- import { InlineKeyboardButton, KeyboardButton, LoginUrl } from "../platform.node.js";
1
+ import { type InlineKeyboardButton, type KeyboardButton, type LoginUrl } from "../platform.node.js";
2
2
  /**
3
3
  * Use this class to simplify building a custom keyboard (something like this:
4
4
  * https://core.telegram.org/bots#keyboards).
@@ -1,5 +1,5 @@
1
- import { Context } from "../context.js";
2
- import { MiddlewareFn } from "../composer.js";
1
+ import { type Context } from "../context.js";
2
+ import { type MiddlewareFn } from "../composer.js";
3
3
  declare type MaybePromise<T> = Promise<T> | T;
4
4
  /**
5
5
  * A session flavor is a context flavor that holds session data under
@@ -1,18 +1,18 @@
1
1
  /// <reference types="node" />
2
- import { Bot } from "../bot.js";
3
- import { Update } from "../platform.node.js";
4
- import { Context } from "../context.js";
2
+ import { type Bot } from "../bot.js";
3
+ import { type Update } from "../platform.node.js";
4
+ import { type Context } from "../context.js";
5
5
  declare const adapters: {
6
6
  callback: FrameworkAdapter;
7
7
  http: (req: import("http").IncomingMessage, res: import("http").ServerResponse) => {
8
8
  update: Promise<any>;
9
- end: () => void;
10
- respond: (json: string) => void;
9
+ end: () => import("http").ServerResponse;
10
+ respond: (json: string) => import("http").ServerResponse;
11
11
  };
12
12
  https: (req: import("http").IncomingMessage, res: import("http").ServerResponse) => {
13
13
  update: Promise<any>;
14
- end: () => void;
15
- respond: (json: string) => void;
14
+ end: () => import("http").ServerResponse;
15
+ respond: (json: string) => import("http").ServerResponse;
16
16
  };
17
17
  express: (req: any, res: any) => {
18
18
  update: Promise<any>;
@@ -31,6 +31,10 @@ declare const adapters: {
31
31
  };
32
32
  worktop: (req: any, res: any) => {
33
33
  update: Promise<any>;
34
+ /**
35
+ * Middleware for a web framework. Creates a request-response handler for a
36
+ * request. The handler will be used to integrate with the compatible framework.
37
+ */
34
38
  end: () => any;
35
39
  respond: (json: string) => any;
36
40
  };
package/out/core/api.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { BotCommand, ChatPermissions, InlineQueryResult, InputFile, InputMedia, InputMediaAudio, InputMediaDocument, InputMediaPhoto, InputMediaVideo, LabeledPrice, PassportElementError } from "../platform.node.js";
2
- import { ApiClientOptions, Methods, Payload, RawApi, Transformer, TransformerConsumer, WebhookReplyEnvelope } from "./client.js";
1
+ import { type BotCommand, type ChatPermissions, type InlineQueryResult, type InputFile, type InputMedia, type InputMediaAudio, type InputMediaDocument, type InputMediaPhoto, type InputMediaVideo, type LabeledPrice, type PassportElementError } from "../platform.node.js";
2
+ import { type ApiClientOptions, type Methods, type Payload, type RawApi, type Transformer, type TransformerConsumer, type WebhookReplyEnvelope } from "./client.js";
3
3
  declare type AlwaysOmittedInOther = "chat_id";
4
4
  /**
5
5
  * Helper type to derive remaining properties of a given API method call M,
@@ -589,7 +589,7 @@ export declare class Api<R extends RawApi = RawApi> {
589
589
  *
590
590
  * **Official reference:** https://core.telegram.org/bots/api#setchatdescription
591
591
  */
592
- setChatDescription(chat_id: number | string, description: string | undefined, signal?: AbortSignal): Promise<true>;
592
+ setChatDescription(chat_id: number | string, description?: string, signal?: AbortSignal): Promise<true>;
593
593
  /**
594
594
  * Use this method to add a message to the list of pinned messages in a chat. If the chat is not a private chat, the bot must be an administrator in the chat for this to work and must have the 'can_pin_messages' administrator right in a supergroup or 'can_edit_messages' administrator right in a channel. Returns True on success.
595
595
  *
@@ -845,7 +845,7 @@ export declare class Api<R extends RawApi = RawApi> {
845
845
  */
846
846
  deleteMessage(chat_id: number | string, message_id: number, signal?: AbortSignal): Promise<true>;
847
847
  /**
848
- * Use this method to send static .WEBP or animated .TGS stickers. On success, the sent Message is returned.
848
+ * Use this method to send static .WEBP, animated .TGS, or video .WEBM stickers. On success, the sent Message is returned.
849
849
  *
850
850
  * @param chat_id Unique identifier for the target chat or username of the target channel (in the format @channelusername)
851
851
  * @param sticker Sticker to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a .WEBP file from the Internet, or upload a new one using multipart/form-data.
@@ -875,7 +875,7 @@ export declare class Api<R extends RawApi = RawApi> {
875
875
  */
876
876
  uploadStickerFile(user_id: number, png_sticker: InputFile, signal?: AbortSignal): Promise<import("@grammyjs/types/manage").File>;
877
877
  /**
878
- * Use this method to create a new sticker set owned by a user. The bot will be able to edit the sticker set thus created. You must use exactly one of the fields png_sticker or tgs_sticker. Returns True on success.
878
+ * Use this method to create a new sticker set owned by a user. The bot will be able to edit the sticker set thus created. You must use exactly one of the fields png_sticker, tgs_sticker, or webm_sticker. Returns True on success.
879
879
  *
880
880
  * @param user_id User identifier of created sticker set owner
881
881
  * @param name Short name of sticker set, to be used in t.me/addstickers/ URLs (e.g., animals). Can contain only english letters, digits and underscores. Must begin with a letter, can't contain consecutive underscores and must end in β€œ_by_<bot username>”. <bot_username> is case insensitive. 1-64 characters.
@@ -888,7 +888,7 @@ export declare class Api<R extends RawApi = RawApi> {
888
888
  */
889
889
  createNewStickerSet(user_id: number, name: string, title: string, emojis: string, other?: Other<R, "createNewStickerSet", "user_id" | "name" | "title" | "emojis">, signal?: AbortSignal): Promise<true>;
890
890
  /**
891
- * Use this method to add a new sticker to a set created by the bot. You must use exactly one of the fields png_sticker or tgs_sticker. Animated stickers can be added to animated sticker sets and only to them. Animated sticker sets can have up to 50 stickers. Static sticker sets can have up to 120 stickers. Returns True on success.
891
+ * Use this method to add a new sticker to a set created by the bot. You must use exactly one of the fields png_sticker, tgs_sticker, or webm_sticker. Animated stickers can be added to animated sticker sets and only to them. Animated sticker sets can have up to 50 stickers. Static sticker sets can have up to 120 stickers. Returns True on success.
892
892
  *
893
893
  * @param user_id User identifier of sticker set owner
894
894
  * @param name Sticker set name
@@ -919,16 +919,16 @@ export declare class Api<R extends RawApi = RawApi> {
919
919
  */
920
920
  deleteStickerFromSet(sticker: string, signal?: AbortSignal): Promise<true>;
921
921
  /**
922
- * Use this method to set the thumbnail of a sticker set. Animated thumbnails can be set for animated sticker sets only. Returns True on success.
922
+ * Use this method to set the thumbnail of a sticker set. Animated thumbnails can be set for animated sticker sets only. Video thumbnails can be set only for video sticker sets only. Returns True on success.
923
923
  *
924
924
  * @param name Sticker set name
925
925
  * @param user_id User identifier of the sticker set owner
926
- * @param thumb A PNG image with the thumbnail, must be up to 128 kilobytes in size and have width and height exactly 100px, or a TGS animation with the thumbnail up to 32 kilobytes in size; see https://core.telegram.org/animated_stickers#technical-requirements for animated sticker technical requirements. Pass a file_id as a String to send a file that already exists on the Telegram servers, pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data.. Animated sticker set thumbnail can't be uploaded via HTTP URL.
926
+ * @param thumb A PNG image with the thumbnail, must be up to 128 kilobytes in size and have width and height exactly 100px, or a TGS animation with the thumbnail up to 32 kilobytes in size; see https://core.telegram.org/stickers#animated-sticker-requirements for animated sticker technical requirements, or a WEBM video with the thumbnail up to 32 kilobytes in size; see https://core.telegram.org/stickers#video-sticker-requirements for video sticker technical requirements. Pass a file_id as a String to send a file that already exists on the Telegram servers, pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data. More info on Sending Files Β». Animated sticker set thumbnails can't be uploaded via HTTP URL.
927
927
  * @param signal Optional `AbortSignal` to cancel the request
928
928
  *
929
929
  * **Official reference:** https://core.telegram.org/bots/api#setstickersetthumb
930
930
  */
931
- setStickerSetThumb(name: string, user_id: number, thumb: InputFile | string, signal?: AbortSignal): Promise<true>;
931
+ setStickerSetThumb(name: string, user_id: number, thumb?: InputFile | string, signal?: AbortSignal): Promise<true>;
932
932
  /**
933
933
  * Use this method to send answers to an inline query. On success, True is returned.
934
934
  * No more than 50 results per query are allowed.
package/out/core/api.js CHANGED
@@ -987,7 +987,7 @@ class Api {
987
987
  return this.raw.deleteMessage({ chat_id, message_id }, signal);
988
988
  }
989
989
  /**
990
- * Use this method to send static .WEBP or animated .TGS stickers. On success, the sent Message is returned.
990
+ * Use this method to send static .WEBP, animated .TGS, or video .WEBM stickers. On success, the sent Message is returned.
991
991
  *
992
992
  * @param chat_id Unique identifier for the target chat or username of the target channel (in the format @channelusername)
993
993
  * @param sticker Sticker to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a .WEBP file from the Internet, or upload a new one using multipart/form-data.
@@ -1023,7 +1023,7 @@ class Api {
1023
1023
  return this.raw.uploadStickerFile({ user_id, png_sticker }, signal);
1024
1024
  }
1025
1025
  /**
1026
- * Use this method to create a new sticker set owned by a user. The bot will be able to edit the sticker set thus created. You must use exactly one of the fields png_sticker or tgs_sticker. Returns True on success.
1026
+ * Use this method to create a new sticker set owned by a user. The bot will be able to edit the sticker set thus created. You must use exactly one of the fields png_sticker, tgs_sticker, or webm_sticker. Returns True on success.
1027
1027
  *
1028
1028
  * @param user_id User identifier of created sticker set owner
1029
1029
  * @param name Short name of sticker set, to be used in t.me/addstickers/ URLs (e.g., animals). Can contain only english letters, digits and underscores. Must begin with a letter, can't contain consecutive underscores and must end in β€œ_by_<bot username>”. <bot_username> is case insensitive. 1-64 characters.
@@ -1038,7 +1038,7 @@ class Api {
1038
1038
  return this.raw.createNewStickerSet({ user_id, name, title, emojis, ...other }, signal);
1039
1039
  }
1040
1040
  /**
1041
- * Use this method to add a new sticker to a set created by the bot. You must use exactly one of the fields png_sticker or tgs_sticker. Animated stickers can be added to animated sticker sets and only to them. Animated sticker sets can have up to 50 stickers. Static sticker sets can have up to 120 stickers. Returns True on success.
1041
+ * Use this method to add a new sticker to a set created by the bot. You must use exactly one of the fields png_sticker, tgs_sticker, or webm_sticker. Animated stickers can be added to animated sticker sets and only to them. Animated sticker sets can have up to 50 stickers. Static sticker sets can have up to 120 stickers. Returns True on success.
1042
1042
  *
1043
1043
  * @param user_id User identifier of sticker set owner
1044
1044
  * @param name Sticker set name
@@ -1075,11 +1075,11 @@ class Api {
1075
1075
  return this.raw.deleteStickerFromSet({ sticker }, signal);
1076
1076
  }
1077
1077
  /**
1078
- * Use this method to set the thumbnail of a sticker set. Animated thumbnails can be set for animated sticker sets only. Returns True on success.
1078
+ * Use this method to set the thumbnail of a sticker set. Animated thumbnails can be set for animated sticker sets only. Video thumbnails can be set only for video sticker sets only. Returns True on success.
1079
1079
  *
1080
1080
  * @param name Sticker set name
1081
1081
  * @param user_id User identifier of the sticker set owner
1082
- * @param thumb A PNG image with the thumbnail, must be up to 128 kilobytes in size and have width and height exactly 100px, or a TGS animation with the thumbnail up to 32 kilobytes in size; see https://core.telegram.org/animated_stickers#technical-requirements for animated sticker technical requirements. Pass a file_id as a String to send a file that already exists on the Telegram servers, pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data.. Animated sticker set thumbnail can't be uploaded via HTTP URL.
1082
+ * @param thumb A PNG image with the thumbnail, must be up to 128 kilobytes in size and have width and height exactly 100px, or a TGS animation with the thumbnail up to 32 kilobytes in size; see https://core.telegram.org/stickers#animated-sticker-requirements for animated sticker technical requirements, or a WEBM video with the thumbnail up to 32 kilobytes in size; see https://core.telegram.org/stickers#video-sticker-requirements for video sticker technical requirements. Pass a file_id as a String to send a file that already exists on the Telegram servers, pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data. More info on Sending Files Β». Animated sticker set thumbnails can't be uploaded via HTTP URL.
1083
1083
  * @param signal Optional `AbortSignal` to cancel the request
1084
1084
  *
1085
1085
  * **Official reference:** https://core.telegram.org/bots/api#setstickersetthumb
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node-fetch" />
2
- import { ApiResponse, Opts, Telegram } from "../platform.node.js";
2
+ import { type ApiResponse, type Opts, type Telegram } from "../platform.node.js";
3
3
  export declare type Methods<R extends RawApi> = string & keyof R;
4
4
  /**
5
5
  * Represents the raw Telegram Bot API with all methods specified 1:1 as
@@ -97,7 +97,7 @@ class ApiClient {
97
97
  sensitiveLogs: (_d = options.sensitiveLogs) !== null && _d !== void 0 ? _d : false,
98
98
  };
99
99
  if (this.options.apiRoot.endsWith("/")) {
100
- throw new Error(`Remove the trailing '/' from the 'apiRoot' option (use '${this.options.apiRoot.substr(0, this.options.apiRoot.length - 1)}' instead of '${this.options.apiRoot}')`);
100
+ 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}')`);
101
101
  }
102
102
  }
103
103
  use(...transformers) {
@@ -1,4 +1,4 @@
1
- import { ApiError, ResponseParameters } from "../platform.node.js";
1
+ import { type ApiError, type ResponseParameters } from "../platform.node.js";
2
2
  /**
3
3
  * This class represents errors that are thrown by grammY because the Telegram
4
4
  * Bot API responded with an error.
package/out/filter.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { AliasProps, Context } from "./context.js";
2
- import { Update } from "./platform.node.js";
1
+ import { type AliasProps, type Context } from "./context.js";
2
+ import { type Update } from "./platform.node.js";
3
3
  declare type FilterFunction<C extends Context, D extends C> = (ctx: C) => ctx is D;
4
4
  /**
5
5
  * > This is an advanced function of grammY.
@@ -82,6 +82,7 @@ declare const UPDATE_KEYS: {
82
82
  readonly italic: {};
83
83
  readonly underline: {};
84
84
  readonly strikethrough: {};
85
+ readonly spoiler: {};
85
86
  readonly code: {};
86
87
  readonly pre: {};
87
88
  readonly text_link: {};
@@ -99,6 +100,7 @@ declare const UPDATE_KEYS: {
99
100
  readonly italic: {};
100
101
  readonly underline: {};
101
102
  readonly strikethrough: {};
103
+ readonly spoiler: {};
102
104
  readonly code: {};
103
105
  readonly pre: {};
104
106
  readonly text_link: {};
@@ -162,6 +164,7 @@ declare const UPDATE_KEYS: {
162
164
  readonly italic: {};
163
165
  readonly underline: {};
164
166
  readonly strikethrough: {};
167
+ readonly spoiler: {};
165
168
  readonly code: {};
166
169
  readonly pre: {};
167
170
  readonly text_link: {};
@@ -179,6 +182,7 @@ declare const UPDATE_KEYS: {
179
182
  readonly italic: {};
180
183
  readonly underline: {};
181
184
  readonly strikethrough: {};
185
+ readonly spoiler: {};
182
186
  readonly code: {};
183
187
  readonly pre: {};
184
188
  readonly text_link: {};
@@ -228,6 +232,7 @@ declare const UPDATE_KEYS: {
228
232
  readonly italic: {};
229
233
  readonly underline: {};
230
234
  readonly strikethrough: {};
235
+ readonly spoiler: {};
231
236
  readonly code: {};
232
237
  readonly pre: {};
233
238
  readonly text_link: {};
@@ -245,6 +250,7 @@ declare const UPDATE_KEYS: {
245
250
  readonly italic: {};
246
251
  readonly underline: {};
247
252
  readonly strikethrough: {};
253
+ readonly spoiler: {};
248
254
  readonly code: {};
249
255
  readonly pre: {};
250
256
  readonly text_link: {};
@@ -294,6 +300,7 @@ declare const UPDATE_KEYS: {
294
300
  readonly italic: {};
295
301
  readonly underline: {};
296
302
  readonly strikethrough: {};
303
+ readonly spoiler: {};
297
304
  readonly code: {};
298
305
  readonly pre: {};
299
306
  readonly text_link: {};
@@ -311,6 +318,7 @@ declare const UPDATE_KEYS: {
311
318
  readonly italic: {};
312
319
  readonly underline: {};
313
320
  readonly strikethrough: {};
321
+ readonly spoiler: {};
314
322
  readonly code: {};
315
323
  readonly pre: {};
316
324
  readonly text_link: {};
@@ -344,11 +352,11 @@ declare const UPDATE_KEYS: {
344
352
  };
345
353
  declare type KeyOf<T> = string & keyof T;
346
354
  declare type S = typeof UPDATE_KEYS;
347
- declare type L1 = KeyOf<S>;
348
- declare type L2<K extends L1 = L1> = K extends unknown ? `${K}:${KeyOf<S[K]>}` : never;
349
- declare type L3<K0 extends L1 = L1> = K0 extends unknown ? L3_<K0> : never;
350
- declare type L3_<K0 extends L1, K1 extends KeyOf<S[K0]> = KeyOf<S[K0]>> = K1 extends unknown ? `${K0}:${K1}:${KeyOf<S[K0][K1]>}` : never;
351
- declare type L123 = L1 | L2 | L3;
355
+ declare type L1S = KeyOf<S>;
356
+ declare type L2S<L1 extends L1S = L1S> = L1 extends unknown ? `${L1}:${KeyOf<S[L1]>}` : never;
357
+ declare type L3S<L1 extends L1S = L1S> = L1 extends unknown ? L3S_<L1> : never;
358
+ declare type L3S_<L1 extends L1S, L2 extends KeyOf<S[L1]> = KeyOf<S[L1]>> = L2 extends unknown ? `${L1}:${L2}:${KeyOf<S[L1][L2]>}` : never;
359
+ declare type L123 = L1S | L2S | L3S;
352
360
  declare type InjectShortcuts<Q extends L123 = L123> = Q extends `${infer R}:${infer S}:${infer T}` ? `${CollapseL1<R, L1Shortcuts>}:${CollapseL2<S, L2Shortcuts>}:${T}` : Q extends `${infer R}:${infer S}` ? `${CollapseL1<R, L1Shortcuts>}:${CollapseL2<S>}` : CollapseL1<Q>;
353
361
  declare type CollapseL1<Q extends string, L extends L1Shortcuts = Exclude<L1Shortcuts, "">> = Q | (L extends string ? Q extends typeof L1_SHORTCUTS[L][number] ? L : never : never);
354
362
  declare type CollapseL2<Q extends string, L extends L2Shortcuts = Exclude<L2Shortcuts, "">> = Q | (L extends string ? Q extends typeof L2_SHORTCUTS[L][number] ? L : never : never);
@@ -380,14 +388,17 @@ declare type NotUndefined = string | number | boolean | SomeObject;
380
388
  * Given a FilterQuery, returns an object that, when intersected with an Update,
381
389
  * marks those properties as required that are guaranteed to exist.
382
390
  */
383
- declare type RunQuery<Q extends string> = L1Combinations<Q, L1Parts<Q>>;
384
- declare type L1Combinations<Q extends string, L1 extends string> = Combine<L1Fields<Q, L1>, L1>;
385
- declare type L1Fields<Q extends string, L1 extends string> = L1 extends unknown ? Record<L1, L2Combinations<L2Parts<Q, L1>>> : never;
386
- declare type L2Combinations<L2 extends string> = [L2] extends [never] ? NotUndefined : Combine<L2Fields<L2>, L2>;
387
- declare type L2Fields<L2 extends string> = L2 extends unknown ? Record<L2 | Twins<L2>, NotUndefined> : never;
391
+ declare type RunQuery<Q extends string> = L1Discriminator<Q, L1Parts<Q>>;
392
+ declare type L1Parts<Q extends string> = Q extends `${infer L1}:${string}` ? L1 : Q;
393
+ declare type L2Parts<Q extends string, L1 extends string> = Q extends `${L1}:${infer L2}:${string}` ? L2 : Q extends `${L1}:${infer L2}` ? L2 : never;
394
+ declare type L1Discriminator<Q extends string, L1 extends string> = Combine<L1Fragment<Q, L1>, L1>;
395
+ declare type L1Fragment<Q extends string, L1 extends string> = L1 extends unknown ? Record<L1, L2Discriminator<L1, L2Parts<Q, L1>>> : never;
396
+ declare type L2Discriminator<L1 extends string, L2 extends string> = [L2] extends [
397
+ never
398
+ ] ? L2ShallowFragment<L1> : Combine<L2Fragment<L1, L2>, L2>;
399
+ declare type L2Fragment<L1 extends string, L2 extends string> = L2 extends unknown ? Record<L2 | AddTwins<L1, L2>, NotUndefined> : never;
400
+ declare type L2ShallowFragment<L1 extends string> = Record<AddTwins<L1, never>, NotUndefined>;
388
401
  declare type Combine<U, K extends string> = U extends unknown ? U & Partial<Record<Exclude<K, keyof U>, undefined>> : never;
389
- declare type L1Parts<Q extends string> = Q extends `${infer U}:${string}` ? U : Q;
390
- declare type L2Parts<Q extends string, P extends string> = Q extends `${P}:${infer U}:${string}` ? U : Q extends `${P}:${infer U}` ? U : never;
391
402
  /**
392
403
  * This type infers which properties will be present on the given context object
393
404
  * provided it matches the given filter query. If the filter query is a union
@@ -403,6 +414,7 @@ declare type FilteredContext<C extends Context, U extends Update> = C & Record<"
403
414
  interface Shortcuts<U extends Update> {
404
415
  msg: [U["callback_query"]] extends [SomeObject] ? U["callback_query"]["message"] : [U["message"]] extends [SomeObject] ? U["message"] : [U["edited_message"]] extends [SomeObject] ? U["edited_message"] : [U["channel_post"]] extends [SomeObject] ? U["channel_post"] : [U["edited_channel_post"]] extends [SomeObject] ? U["edited_channel_post"] : undefined;
405
416
  chat: [U["callback_query"]] extends [SomeObject] ? NonNullable<U["callback_query"]["message"]>["chat"] | undefined : [Shortcuts<U>["msg"]] extends [SomeObject] ? Shortcuts<U>["msg"]["chat"] : [U["my_chat_member"]] extends [SomeObject] ? U["my_chat_member"]["chat"] : [U["chat_member"]] extends [SomeObject] ? U["chat_member"]["chat"] : [U["chat_join_request"]] extends [SomeObject] ? U["chat_join_request"]["chat"] : undefined;
417
+ senderChat: [Shortcuts<U>["msg"]] extends [SomeObject] ? Shortcuts<U>["msg"]["sender_chat"] : undefined;
406
418
  from: [U["callback_query"]] extends [SomeObject] ? U["callback_query"]["from"] : [U["inline_query"]] extends [SomeObject] ? U["inline_query"]["from"] : [U["shipping_query"]] extends [SomeObject] ? U["shipping_query"]["from"] : [U["pre_checkout_query"]] extends [SomeObject] ? U["pre_checkout_query"]["from"] : [U["chosen_inline_result"]] extends [SomeObject] ? U["chosen_inline_result"]["from"] : [U["message"]] extends [SomeObject] ? NonNullable<U["message"]["from"]> : [U["edited_message"]] extends [SomeObject] ? NonNullable<U["edited_message"]["from"]> : [U["my_chat_member"]] extends [SomeObject] ? U["my_chat_member"]["from"] : [U["chat_member"]] extends [SomeObject] ? U["chat_member"]["from"] : [U["chat_join_request"]] extends [SomeObject] ? U["chat_join_request"]["from"] : undefined;
407
419
  }
408
420
  declare const L1_SHORTCUTS: {
@@ -417,16 +429,29 @@ declare const L2_SHORTCUTS: {
417
429
  };
418
430
  declare type L1Shortcuts = KeyOf<typeof L1_SHORTCUTS>;
419
431
  declare type L2Shortcuts = KeyOf<typeof L2_SHORTCUTS>;
420
- declare type ExpandShortcuts<Q extends string> = Q extends `${infer R}:${infer S}:${infer T}` ? `${ExpandL1<R>}:${ExpandL2<S>}:${T}` : Q extends `${infer R}:${infer S}` ? `${ExpandL1<R>}:${ExpandL2<S>}` : ExpandL1<Q>;
432
+ declare type ExpandShortcuts<Q extends string> = Q extends `${infer L1}:${infer L2}:${infer L3}` ? `${ExpandL1<L1>}:${ExpandL2<L2>}:${L3}` : Q extends `${infer L1}:${infer L2}` ? `${ExpandL1<L1>}:${ExpandL2<L2>}` : ExpandL1<Q>;
421
433
  declare type ExpandL1<S extends string> = S extends L1Shortcuts ? typeof L1_SHORTCUTS[S][number] : S;
422
434
  declare type ExpandL2<S extends string> = S extends L2Shortcuts ? typeof L2_SHORTCUTS[S][number] : S;
423
- declare type Twins<V extends string> = V extends KeyOf<Equivalents> ? Equivalents[V] : V;
424
- declare type Equivalents = {
435
+ declare type AddTwins<L1 extends string, L2 extends string> = TwinsFromL1<L1, L2> | TwinsFromL2<L1, L2>;
436
+ declare type TwinsFromL1<L1 extends string, L2 extends string> = L1 extends KeyOf<L1Equivalents> ? L1Equivalents[L1] : L2;
437
+ declare type L1Equivalents = {
438
+ message: "from";
439
+ edited_message: "from" | "edit_date";
440
+ channel_post: "sender_chat";
441
+ edited_channel_post: "sender_chat" | "edit_date";
442
+ };
443
+ declare type TwinsFromL2<L1 extends string, L2 extends string> = L1 extends KeyOf<L2Equivalents> ? L2 extends KeyOf<L2Equivalents[L1]> ? L2Equivalents[L1][L2] : L2 : L2;
444
+ declare type L2Equivalents = {
445
+ message: MessageEquivalents;
446
+ edited_message: MessageEquivalents;
447
+ channel_post: MessageEquivalents;
448
+ edited_channel_post: MessageEquivalents;
449
+ };
450
+ declare type MessageEquivalents = {
425
451
  animation: "document";
426
- entities: TextMessages;
452
+ entities: "text";
427
453
  caption: CaptionMessages;
428
454
  caption_entities: CaptionMessages;
429
455
  };
430
- declare type TextMessages = "text";
431
456
  declare type CaptionMessages = "animation" | "audio" | "document" | "photo" | "video" | "voice";
432
457
  export {};
package/out/filter.js CHANGED
@@ -203,6 +203,7 @@ const ENTITY_KEYS = {
203
203
  italic: {},
204
204
  underline: {},
205
205
  strikethrough: {},
206
+ spoiler: {},
206
207
  code: {},
207
208
  pre: {},
208
209
  text_link: {},
package/out/mod.d.ts CHANGED
@@ -1,14 +1,11 @@
1
- export { Bot, BotError } from "./bot.js";
2
- export type { BotConfig, ErrorHandler, PollingOptions } from "./bot.js";
1
+ export { Bot, type BotConfig, BotError, type ErrorHandler, type PollingOptions, } from "./bot.js";
3
2
  export { InputFile } from "./platform.node.js";
4
3
  export { Context } from "./context.js";
5
4
  export * from "./convenience/keyboard.js";
6
5
  export * from "./convenience/session.js";
7
6
  export * from "./convenience/webhook.js";
8
- export { Composer } from "./composer.js";
9
- export type { Middleware, MiddlewareFn, MiddlewareObj, NextFunction, } from "./composer.js";
10
- export { matchFilter } from "./filter.js";
11
- export type { Filter, FilterQuery } from "./filter.js";
7
+ export { Composer, type Middleware, type MiddlewareFn, type MiddlewareObj, type NextFunction, } from "./composer.js";
8
+ export { type Filter, type FilterQuery, matchFilter } from "./filter.js";
12
9
  export { Api } from "./core/api.js";
13
- export type { ApiCallFn, ApiClientOptions, RawApi, TransformableApi, Transformer, WebhookReplyEnvelope, } from "./core/client.js";
10
+ export { type ApiCallFn, type ApiClientOptions, type RawApi, type TransformableApi, type Transformer, type WebhookReplyEnvelope, } from "./core/client.js";
14
11
  export { GrammyError, HttpError } from "./core/error.js";
@@ -1,9 +1,9 @@
1
1
  /// <reference types="node" />
2
- import { InputFileProxy } from "@grammyjs/types";
2
+ import { type InputFileProxy } from "@grammyjs/types";
3
3
  import { Agent as HttpAgent } from "http";
4
4
  import { Agent as HttpsAgent } from "https";
5
5
  import { Readable } from "stream";
6
- import type { ReadStream } from "fs";
6
+ import { type ReadStream } from "fs";
7
7
  import { URL } from "url";
8
8
  export * from "@grammyjs/types";
9
9
  import { debug as d } from "debug";
@@ -13,6 +13,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.InputFile = exports.toRaw = exports.baseFetchConfig = exports.itrToStream = exports.debug = void 0;
14
14
  const http_1 = require("http");
15
15
  const https_1 = require("https");
16
+ const node_fetch_1 = require("node-fetch");
16
17
  const path_1 = require("path");
17
18
  const stream_1 = require("stream");
18
19
  const url_1 = require("url");
@@ -126,7 +127,7 @@ class InputFile {
126
127
  }
127
128
  exports.InputFile = InputFile;
128
129
  async function* fetchFile(url) {
129
- const { body } = await (0, shim_node_js_1.fetch)(url);
130
+ const { body } = await (0, node_fetch_1.default)(url);
130
131
  for await (const chunk of body) {
131
132
  if (typeof chunk === "string") {
132
133
  throw new Error(`Could not transfer file, received string data instead of bytes from '${url}'`);
@@ -134,4 +135,3 @@ async function* fetchFile(url) {
134
135
  yield chunk;
135
136
  }
136
137
  }
137
- const shim_node_js_1 = require("./shim.node.js");
@@ -1,2 +1,2 @@
1
- export { AbortController, AbortSignal } from "abort-controller";
1
+ export { AbortController, type AbortSignal } from "abort-controller";
2
2
  export { default as fetch } from "node-fetch";
package/out/shim.node.js CHANGED
@@ -1,8 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fetch = exports.AbortSignal = exports.AbortController = void 0;
3
+ exports.fetch = exports.AbortController = void 0;
4
4
  var abort_controller_1 = require("abort-controller");
5
5
  Object.defineProperty(exports, "AbortController", { enumerable: true, get: function () { return abort_controller_1.AbortController; } });
6
- Object.defineProperty(exports, "AbortSignal", { enumerable: true, get: function () { return abort_controller_1.AbortSignal; } });
7
6
  var node_fetch_1 = require("node-fetch");
8
7
  Object.defineProperty(exports, "fetch", { enumerable: true, get: function () { return node_fetch_1.default; } });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "grammy",
3
3
  "description": "The Telegram Bot Framework.",
4
- "version": "1.5.5",
4
+ "version": "1.7.0",
5
5
  "author": "KnorpelSenf",
6
6
  "license": "MIT",
7
7
  "engines": {
@@ -23,7 +23,7 @@
23
23
  "contribs": "all-contributors"
24
24
  },
25
25
  "dependencies": {
26
- "@grammyjs/types": "^2.4.5",
26
+ "@grammyjs/types": "^2.6.0",
27
27
  "abort-controller": "^3.0.0",
28
28
  "debug": "^4.3.3",
29
29
  "node-fetch": "^2.6.5"
@@ -33,7 +33,7 @@
33
33
  "@types/node": "^12.20.36",
34
34
  "@types/node-fetch": "^2.5.12",
35
35
  "all-contributors-cli": "^6.20.0",
36
- "deno2node": "1.0.0"
36
+ "deno2node": "^1.1.0"
37
37
  },
38
38
  "files": [
39
39
  "out/"