gramio 0.4.12 → 0.4.13

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/dist/index.cjs CHANGED
@@ -7,7 +7,7 @@ var contexts = require('@gramio/contexts');
7
7
  var files = require('@gramio/files');
8
8
  var format = require('@gramio/format');
9
9
  var debug = require('debug');
10
- var utils = require('./utils-CYIya32k.cjs');
10
+ var utils = require('./utils-C46rnh-r.cjs');
11
11
  var middlewareIo = require('middleware-io');
12
12
  var keyboards = require('@gramio/keyboards');
13
13
 
@@ -102,6 +102,8 @@ class Plugin {
102
102
  onResponses: [],
103
103
  /** Store plugin onResponseErrors hooks */
104
104
  onResponseErrors: [],
105
+ /** Store plugin onApiCalls hooks */
106
+ onApiCalls: [],
105
107
  /**
106
108
  * Store plugin groups
107
109
  *
@@ -185,6 +187,13 @@ class Plugin {
185
187
  this._.onResponseErrors.push([methodsOrHandler, void 0]);
186
188
  return this;
187
189
  }
190
+ onApiCall(methodsOrHandler, handler) {
191
+ if ((typeof methodsOrHandler === "string" || Array.isArray(methodsOrHandler)) && handler)
192
+ this._.onApiCalls.push([handler, methodsOrHandler]);
193
+ else if (typeof methodsOrHandler === "function")
194
+ this._.onApiCalls.push([methodsOrHandler, void 0]);
195
+ return this;
196
+ }
188
197
  /**
189
198
  * This hook called when the bot is `started`.
190
199
  *
@@ -427,9 +436,6 @@ class Bot {
427
436
  /** @deprecated use `~.derives` instead @internal. Remap generic */
428
437
  __Derives;
429
438
  "~" = this._;
430
- filters = {
431
- context: (name) => (context) => context.is(name)
432
- };
433
439
  /** Options provided to instance */
434
440
  options;
435
441
  /** Bot data (filled in when calling bot.init/bot.start) */
@@ -451,7 +457,13 @@ class Bot {
451
457
  get: (_target, method) => (
452
458
  // @ts-expect-error
453
459
  // biome-ignore lint/suspicious/noAssignInExpressions: <explanation>
454
- _target[method] ??= (args) => this._callApi(method, args)
460
+ _target[method] ??= (args) => {
461
+ const callSite = new Error();
462
+ if (Error.captureStackTrace) {
463
+ Error.captureStackTrace(callSite, _target[method]);
464
+ }
465
+ return this._callApi(method, args, callSite);
466
+ }
455
467
  )
456
468
  });
457
469
  lazyloadPlugins = [];
@@ -477,7 +489,8 @@ class Bot {
477
489
  onResponseError: [],
478
490
  onError: [],
479
491
  onStart: [],
480
- onStop: []
492
+ onStop: [],
493
+ onApiCall: []
481
494
  };
482
495
  constructor(tokenOrOptions, optionsRaw) {
483
496
  const token = typeof tokenOrOptions === "string" ? tokenOrOptions : tokenOrOptions?.token;
@@ -500,7 +513,10 @@ class Bot {
500
513
  new Plugin("@gramio/format").preRequest((context) => {
501
514
  if (!context.params) return context;
502
515
  const formattable = format.FormattableMap[context.method];
503
- if (formattable) context.params = formattable(context.params);
516
+ if (formattable)
517
+ context.params = formattable(
518
+ context.params
519
+ );
504
520
  return context;
505
521
  })
506
522
  );
@@ -517,63 +533,66 @@ class Bot {
517
533
  await hook(...context);
518
534
  }
519
535
  }
520
- async _callApi(method, params = {}) {
521
- const debug$api$method = debug(`gramio:api:${method}`);
522
- let url = `${this.options.api.baseURL}${this.options.token}/${this.options.api.useTest ? "test/" : ""}${method}`;
523
- const reqOptions = {
524
- method: "POST",
525
- ...this.options.api.fetchOptions,
526
- // @ts-ignore types node/bun and global missmatch
527
- headers: new Headers(this.options.api.fetchOptions?.headers)
528
- };
529
- const context = await this.runHooks(
530
- "preRequest",
531
- // TODO: fix type error
532
- // @ts-expect-error
533
- {
536
+ async _callApi(method, params = {}, callSite) {
537
+ const executeCall = async () => {
538
+ const debug$api$method = debug(`gramio:api:${method}`);
539
+ let url = `${this.options.api.baseURL}${this.options.token}/${this.options.api.useTest ? "test/" : ""}${method}`;
540
+ const reqOptions = {
541
+ method: "POST",
542
+ ...this.options.api.fetchOptions,
543
+ headers: new Headers(this.options.api.fetchOptions?.headers)
544
+ };
545
+ const context = await this.runHooks("preRequest", {
534
546
  method,
535
547
  params
536
- }
537
- );
538
- params = context.params;
539
- if (params && files.isMediaUpload(method, params)) {
540
- if (utils.IS_BUN) {
541
- const formData = await files.convertJsonToFormData(method, params);
542
- reqOptions.body = formData;
548
+ });
549
+ params = context.params;
550
+ if (params && files.isMediaUpload(method, params)) {
551
+ if (utils.IS_BUN) {
552
+ const formData = await files.convertJsonToFormData(method, params);
553
+ reqOptions.body = formData;
554
+ } else {
555
+ const [formData, paramsWithoutFiles] = await files.extractFilesToFormData(
556
+ method,
557
+ params
558
+ );
559
+ reqOptions.body = formData;
560
+ const simplifiedParams = utils.simplifyObject(paramsWithoutFiles);
561
+ url += `?${new URLSearchParams(simplifiedParams).toString()}`;
562
+ }
543
563
  } else {
544
- const [formData, paramsWithoutFiles] = await files.extractFilesToFormData(
545
- method,
546
- params
547
- );
548
- reqOptions.body = formData;
549
- const simplifiedParams = utils.simplifyObject(paramsWithoutFiles);
550
- url += `?${new URLSearchParams(simplifiedParams).toString()}`;
564
+ reqOptions.headers.set("Content-Type", "application/json");
565
+ reqOptions.body = JSON.stringify(params);
551
566
  }
552
- } else {
553
- reqOptions.headers.set("Content-Type", "application/json");
554
- reqOptions.body = JSON.stringify(params);
555
- }
556
- debug$api$method("options: %j", reqOptions);
557
- const response = await fetch(url, reqOptions);
558
- const data = await response.json();
559
- debug$api$method("response: %j", data);
560
- if (!data.ok) {
561
- const err = new utils.TelegramError(data, method, params);
562
- this.runImmutableHooks("onResponseError", err, this.api);
563
- if (!params?.suppress) throw err;
564
- return err;
565
- }
566
- this.runImmutableHooks(
567
- "onResponse",
568
- // TODO: fix type error
569
- // @ts-expect-error
570
- {
571
- method,
572
- params,
573
- response: data.result
567
+ debug$api$method("options: %j", reqOptions);
568
+ const response = await fetch(url, reqOptions);
569
+ const data = await response.json();
570
+ debug$api$method("response: %j", data);
571
+ if (!data.ok) {
572
+ const err = new utils.TelegramError(data, method, params, callSite);
573
+ this.runImmutableHooks("onResponseError", err, this.api);
574
+ if (!params?.suppress) throw err;
575
+ return err;
574
576
  }
575
- );
576
- return data.result;
577
+ this.runImmutableHooks(
578
+ "onResponse",
579
+ // TODO: fix type error
580
+ // @ts-expect-error
581
+ {
582
+ method,
583
+ params,
584
+ response: data.result
585
+ }
586
+ );
587
+ return data.result;
588
+ };
589
+ if (!this.hooks.onApiCall.length) return executeCall();
590
+ let fn = executeCall;
591
+ for (const hook of [...this.hooks.onApiCall].reverse()) {
592
+ const prev = fn;
593
+ fn = () => hook({ method, params }, prev);
594
+ }
595
+ return fn();
577
596
  }
578
597
  async downloadFile(attachment, path) {
579
598
  function getFileId(attachment2) {
@@ -761,6 +780,19 @@ class Bot {
761
780
  } else this.hooks.onResponseError.push(methodsOrHandler);
762
781
  return this;
763
782
  }
783
+ onApiCall(methodsOrHandler, handler) {
784
+ if (typeof methodsOrHandler === "string" || Array.isArray(methodsOrHandler)) {
785
+ if (!handler) throw new Error("TODO:");
786
+ const methods = typeof methodsOrHandler === "string" ? [methodsOrHandler] : methodsOrHandler;
787
+ this.hooks.onApiCall.push(async (context, next) => {
788
+ if (methods.includes(context.method)) return handler(context, next);
789
+ return next();
790
+ });
791
+ } else {
792
+ this.hooks.onApiCall.push(methodsOrHandler);
793
+ }
794
+ return this;
795
+ }
764
796
  // onExperimental(
765
797
  // // filter: Filters,
766
798
  // filter: (
@@ -843,6 +875,11 @@ class Bot {
843
875
  if (!updateName) this.onResponseError(onResponseError);
844
876
  else this.onResponseError(updateName, onResponseError);
845
877
  }
878
+ for (const value of plugin._.onApiCalls) {
879
+ const [onApiCall, methods] = value;
880
+ if (!methods) this.onApiCall(onApiCall);
881
+ else this.onApiCall(methods, onApiCall);
882
+ }
846
883
  for (const handler of plugin._.groups) {
847
884
  this.group(handler);
848
885
  }
package/dist/index.d.cts CHANGED
@@ -23,7 +23,7 @@ declare class TelegramError<T extends keyof APIMethods> extends Error {
23
23
  /** Describes why a request was unsuccessful. */
24
24
  payload?: TelegramResponseParameters;
25
25
  /** Construct new TelegramError */
26
- constructor(error: TelegramAPIResponseError, method: T, params: MaybeSuppressedParams<T>);
26
+ constructor(error: TelegramAPIResponseError, method: T, params: MaybeSuppressedParams<T>, callSite?: Error);
27
27
  }
28
28
 
29
29
  type MaybeArray<T> = T | T[] | ReadonlyArray<T>;
@@ -116,6 +116,8 @@ declare class Plugin<Errors extends ErrorDefinitions = {}, Derives extends Deriv
116
116
  onResponses: [Hooks.OnResponse<any>, MaybeArray<keyof APIMethods> | undefined][];
117
117
  /** Store plugin onResponseErrors hooks */
118
118
  onResponseErrors: [Hooks.OnResponseError<any>, MaybeArray<keyof APIMethods> | undefined][];
119
+ /** Store plugin onApiCalls hooks */
120
+ onApiCalls: [Hooks.OnApiCall<any>, MaybeArray<keyof APIMethods> | undefined][];
119
121
  /**
120
122
  * Store plugin groups
121
123
  *
@@ -152,6 +154,8 @@ declare class Plugin<Errors extends ErrorDefinitions = {}, Derives extends Deriv
152
154
  onResponses: [Hooks.OnResponse<any>, MaybeArray<keyof APIMethods> | undefined][];
153
155
  /** Store plugin onResponseErrors hooks */
154
156
  onResponseErrors: [Hooks.OnResponseError<any>, MaybeArray<keyof APIMethods> | undefined][];
157
+ /** Store plugin onApiCalls hooks */
158
+ onApiCalls: [Hooks.OnApiCall<any>, MaybeArray<keyof APIMethods> | undefined][];
155
159
  /**
156
160
  * Store plugin groups
157
161
  *
@@ -256,6 +260,21 @@ declare class Plugin<Errors extends ErrorDefinitions = {}, Derives extends Deriv
256
260
  * */
257
261
  onResponseError<Methods extends keyof APIMethods, Handler extends Hooks.OnResponseError<Methods>>(methods: MaybeArray<Methods>, handler: Handler): this;
258
262
  onResponseError(handler: Hooks.OnResponseError): this;
263
+ /**
264
+ * This hook wraps the entire API call, enabling tracing/instrumentation.
265
+ *
266
+ * @example
267
+ * ```typescript
268
+ * const plugin = new Plugin("example").onApiCall(async (context, next) => {
269
+ * console.log(`Calling ${context.method}`);
270
+ * const result = await next();
271
+ * console.log(`${context.method} completed`);
272
+ * return result;
273
+ * });
274
+ * ```
275
+ * */
276
+ onApiCall<Methods extends keyof APIMethods, Handler extends Hooks.OnApiCall<Methods>>(methods: MaybeArray<Methods>, handler: Handler): this;
277
+ onApiCall(handler: Hooks.OnApiCall): this;
259
278
  /**
260
279
  * This hook called when the bot is `started`.
261
280
  *
@@ -539,6 +558,27 @@ declare namespace Hooks {
539
558
  * [Documentation](https://gramio.dev/hooks/on-response.html)
540
559
  * */
541
560
  type OnResponse<Methods extends keyof APIMethods = keyof APIMethods> = (context: AnyTelegramMethodWithReturn<Methods>) => unknown;
561
+ /** Argument type for {@link OnApiCall} */
562
+ type OnApiCallContext<Methods extends keyof APIMethods> = AnyTelegramMethod<Methods>;
563
+ /**
564
+ * Type for `onApiCall` hook (wrap-style)
565
+ *
566
+ * This hook wraps the entire API call execution, enabling span creation
567
+ * around API calls for tracing/instrumentation.
568
+ *
569
+ * @example
570
+ * ```typescript
571
+ * import { Bot } from "gramio";
572
+ *
573
+ * const bot = new Bot(process.env.TOKEN!).onApiCall(async (context, next) => {
574
+ * console.log(`Calling ${context.method}`);
575
+ * const result = await next();
576
+ * console.log(`${context.method} completed`);
577
+ * return result;
578
+ * });
579
+ * ```
580
+ * */
581
+ type OnApiCall<Methods extends keyof APIMethods = keyof APIMethods> = (context: OnApiCallContext<Methods>, next: () => Promise<unknown>) => Promise<unknown>;
542
582
  /** Store hooks */
543
583
  interface Store<T extends ErrorDefinitions> {
544
584
  preRequest: PreRequest[];
@@ -547,6 +587,7 @@ declare namespace Hooks {
547
587
  onError: OnError<T>[];
548
588
  onStart: OnStart[];
549
589
  onStop: OnStop[];
590
+ onApiCall: OnApiCall[];
550
591
  }
551
592
  }
552
593
  /** Error map should be map of string: error */
@@ -634,7 +675,6 @@ declare class Bot<Errors extends ErrorDefinitions = {}, Derives extends DeriveDe
634
675
  /** @deprecated @internal. Remap generic */
635
676
  derives: Derives;
636
677
  };
637
- private filters;
638
678
  /** Options provided to instance */
639
679
  readonly options: BotOptions;
640
680
  /** Bot data (filled in when calling bot.init/bot.start) */
@@ -843,6 +883,23 @@ declare class Bot<Errors extends ErrorDefinitions = {}, Derives extends DeriveDe
843
883
  * */
844
884
  onResponseError<Methods extends keyof APIMethods, Handler extends Hooks.OnResponseError<Methods>>(methods: MaybeArray<Methods>, handler: Handler): this;
845
885
  onResponseError(handler: Hooks.OnResponseError): this;
886
+ /**
887
+ * This hook wraps the entire API call, enabling tracing/instrumentation.
888
+ *
889
+ * @example
890
+ * ```typescript
891
+ * import { Bot } from "gramio";
892
+ *
893
+ * const bot = new Bot(process.env.TOKEN!).onApiCall(async (context, next) => {
894
+ * console.log(`Calling ${context.method}`);
895
+ * const result = await next();
896
+ * console.log(`${context.method} completed`);
897
+ * return result;
898
+ * });
899
+ * ```
900
+ * */
901
+ onApiCall<Methods extends keyof APIMethods, Handler extends Hooks.OnApiCall<Methods>>(methods: MaybeArray<Methods>, handler: Handler): this;
902
+ onApiCall(handler: Hooks.OnApiCall): this;
846
903
  /** Register handler to one or many Updates */
847
904
  on<T extends UpdateName>(updateName: MaybeArray<T>, handler: Handler<ContextType<typeof this, T>>): this;
848
905
  /** Register handler to any Updates */
package/dist/index.d.ts CHANGED
@@ -23,7 +23,7 @@ declare class TelegramError<T extends keyof APIMethods> extends Error {
23
23
  /** Describes why a request was unsuccessful. */
24
24
  payload?: TelegramResponseParameters;
25
25
  /** Construct new TelegramError */
26
- constructor(error: TelegramAPIResponseError, method: T, params: MaybeSuppressedParams<T>);
26
+ constructor(error: TelegramAPIResponseError, method: T, params: MaybeSuppressedParams<T>, callSite?: Error);
27
27
  }
28
28
 
29
29
  type MaybeArray<T> = T | T[] | ReadonlyArray<T>;
@@ -116,6 +116,8 @@ declare class Plugin<Errors extends ErrorDefinitions = {}, Derives extends Deriv
116
116
  onResponses: [Hooks.OnResponse<any>, MaybeArray<keyof APIMethods> | undefined][];
117
117
  /** Store plugin onResponseErrors hooks */
118
118
  onResponseErrors: [Hooks.OnResponseError<any>, MaybeArray<keyof APIMethods> | undefined][];
119
+ /** Store plugin onApiCalls hooks */
120
+ onApiCalls: [Hooks.OnApiCall<any>, MaybeArray<keyof APIMethods> | undefined][];
119
121
  /**
120
122
  * Store plugin groups
121
123
  *
@@ -152,6 +154,8 @@ declare class Plugin<Errors extends ErrorDefinitions = {}, Derives extends Deriv
152
154
  onResponses: [Hooks.OnResponse<any>, MaybeArray<keyof APIMethods> | undefined][];
153
155
  /** Store plugin onResponseErrors hooks */
154
156
  onResponseErrors: [Hooks.OnResponseError<any>, MaybeArray<keyof APIMethods> | undefined][];
157
+ /** Store plugin onApiCalls hooks */
158
+ onApiCalls: [Hooks.OnApiCall<any>, MaybeArray<keyof APIMethods> | undefined][];
155
159
  /**
156
160
  * Store plugin groups
157
161
  *
@@ -256,6 +260,21 @@ declare class Plugin<Errors extends ErrorDefinitions = {}, Derives extends Deriv
256
260
  * */
257
261
  onResponseError<Methods extends keyof APIMethods, Handler extends Hooks.OnResponseError<Methods>>(methods: MaybeArray<Methods>, handler: Handler): this;
258
262
  onResponseError(handler: Hooks.OnResponseError): this;
263
+ /**
264
+ * This hook wraps the entire API call, enabling tracing/instrumentation.
265
+ *
266
+ * @example
267
+ * ```typescript
268
+ * const plugin = new Plugin("example").onApiCall(async (context, next) => {
269
+ * console.log(`Calling ${context.method}`);
270
+ * const result = await next();
271
+ * console.log(`${context.method} completed`);
272
+ * return result;
273
+ * });
274
+ * ```
275
+ * */
276
+ onApiCall<Methods extends keyof APIMethods, Handler extends Hooks.OnApiCall<Methods>>(methods: MaybeArray<Methods>, handler: Handler): this;
277
+ onApiCall(handler: Hooks.OnApiCall): this;
259
278
  /**
260
279
  * This hook called when the bot is `started`.
261
280
  *
@@ -539,6 +558,27 @@ declare namespace Hooks {
539
558
  * [Documentation](https://gramio.dev/hooks/on-response.html)
540
559
  * */
541
560
  type OnResponse<Methods extends keyof APIMethods = keyof APIMethods> = (context: AnyTelegramMethodWithReturn<Methods>) => unknown;
561
+ /** Argument type for {@link OnApiCall} */
562
+ type OnApiCallContext<Methods extends keyof APIMethods> = AnyTelegramMethod<Methods>;
563
+ /**
564
+ * Type for `onApiCall` hook (wrap-style)
565
+ *
566
+ * This hook wraps the entire API call execution, enabling span creation
567
+ * around API calls for tracing/instrumentation.
568
+ *
569
+ * @example
570
+ * ```typescript
571
+ * import { Bot } from "gramio";
572
+ *
573
+ * const bot = new Bot(process.env.TOKEN!).onApiCall(async (context, next) => {
574
+ * console.log(`Calling ${context.method}`);
575
+ * const result = await next();
576
+ * console.log(`${context.method} completed`);
577
+ * return result;
578
+ * });
579
+ * ```
580
+ * */
581
+ type OnApiCall<Methods extends keyof APIMethods = keyof APIMethods> = (context: OnApiCallContext<Methods>, next: () => Promise<unknown>) => Promise<unknown>;
542
582
  /** Store hooks */
543
583
  interface Store<T extends ErrorDefinitions> {
544
584
  preRequest: PreRequest[];
@@ -547,6 +587,7 @@ declare namespace Hooks {
547
587
  onError: OnError<T>[];
548
588
  onStart: OnStart[];
549
589
  onStop: OnStop[];
590
+ onApiCall: OnApiCall[];
550
591
  }
551
592
  }
552
593
  /** Error map should be map of string: error */
@@ -634,7 +675,6 @@ declare class Bot<Errors extends ErrorDefinitions = {}, Derives extends DeriveDe
634
675
  /** @deprecated @internal. Remap generic */
635
676
  derives: Derives;
636
677
  };
637
- private filters;
638
678
  /** Options provided to instance */
639
679
  readonly options: BotOptions;
640
680
  /** Bot data (filled in when calling bot.init/bot.start) */
@@ -843,6 +883,23 @@ declare class Bot<Errors extends ErrorDefinitions = {}, Derives extends DeriveDe
843
883
  * */
844
884
  onResponseError<Methods extends keyof APIMethods, Handler extends Hooks.OnResponseError<Methods>>(methods: MaybeArray<Methods>, handler: Handler): this;
845
885
  onResponseError(handler: Hooks.OnResponseError): this;
886
+ /**
887
+ * This hook wraps the entire API call, enabling tracing/instrumentation.
888
+ *
889
+ * @example
890
+ * ```typescript
891
+ * import { Bot } from "gramio";
892
+ *
893
+ * const bot = new Bot(process.env.TOKEN!).onApiCall(async (context, next) => {
894
+ * console.log(`Calling ${context.method}`);
895
+ * const result = await next();
896
+ * console.log(`${context.method} completed`);
897
+ * return result;
898
+ * });
899
+ * ```
900
+ * */
901
+ onApiCall<Methods extends keyof APIMethods, Handler extends Hooks.OnApiCall<Methods>>(methods: MaybeArray<Methods>, handler: Handler): this;
902
+ onApiCall(handler: Hooks.OnApiCall): this;
846
903
  /** Register handler to one or many Updates */
847
904
  on<T extends UpdateName>(updateName: MaybeArray<T>, handler: Handler<ContextType<typeof this, T>>): this;
848
905
  /** Register handler to any Updates */
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ export * from '@gramio/files';
9
9
  import { FormattableMap } from '@gramio/format';
10
10
  export * from '@gramio/format';
11
11
  import debug from 'debug';
12
- import { E as ErrorKind, s as sleep, w as withRetries, T as TelegramError, d as debug$updates, I as IS_BUN, a as simplifyObject, t as timeoutWebhook } from './utils-CJfJNxc_.js';
12
+ import { E as ErrorKind, s as sleep, w as withRetries, T as TelegramError, d as debug$updates, I as IS_BUN, a as simplifyObject, t as timeoutWebhook } from './utils-En0iVLWH.js';
13
13
  import { Composer as Composer$1, noopNext } from 'middleware-io';
14
14
  export * from '@gramio/keyboards';
15
15
 
@@ -104,6 +104,8 @@ class Plugin {
104
104
  onResponses: [],
105
105
  /** Store plugin onResponseErrors hooks */
106
106
  onResponseErrors: [],
107
+ /** Store plugin onApiCalls hooks */
108
+ onApiCalls: [],
107
109
  /**
108
110
  * Store plugin groups
109
111
  *
@@ -187,6 +189,13 @@ class Plugin {
187
189
  this._.onResponseErrors.push([methodsOrHandler, void 0]);
188
190
  return this;
189
191
  }
192
+ onApiCall(methodsOrHandler, handler) {
193
+ if ((typeof methodsOrHandler === "string" || Array.isArray(methodsOrHandler)) && handler)
194
+ this._.onApiCalls.push([handler, methodsOrHandler]);
195
+ else if (typeof methodsOrHandler === "function")
196
+ this._.onApiCalls.push([methodsOrHandler, void 0]);
197
+ return this;
198
+ }
190
199
  /**
191
200
  * This hook called when the bot is `started`.
192
201
  *
@@ -429,9 +438,6 @@ class Bot {
429
438
  /** @deprecated use `~.derives` instead @internal. Remap generic */
430
439
  __Derives;
431
440
  "~" = this._;
432
- filters = {
433
- context: (name) => (context) => context.is(name)
434
- };
435
441
  /** Options provided to instance */
436
442
  options;
437
443
  /** Bot data (filled in when calling bot.init/bot.start) */
@@ -453,7 +459,13 @@ class Bot {
453
459
  get: (_target, method) => (
454
460
  // @ts-expect-error
455
461
  // biome-ignore lint/suspicious/noAssignInExpressions: <explanation>
456
- _target[method] ??= (args) => this._callApi(method, args)
462
+ _target[method] ??= (args) => {
463
+ const callSite = new Error();
464
+ if (Error.captureStackTrace) {
465
+ Error.captureStackTrace(callSite, _target[method]);
466
+ }
467
+ return this._callApi(method, args, callSite);
468
+ }
457
469
  )
458
470
  });
459
471
  lazyloadPlugins = [];
@@ -479,7 +491,8 @@ class Bot {
479
491
  onResponseError: [],
480
492
  onError: [],
481
493
  onStart: [],
482
- onStop: []
494
+ onStop: [],
495
+ onApiCall: []
483
496
  };
484
497
  constructor(tokenOrOptions, optionsRaw) {
485
498
  const token = typeof tokenOrOptions === "string" ? tokenOrOptions : tokenOrOptions?.token;
@@ -502,7 +515,10 @@ class Bot {
502
515
  new Plugin("@gramio/format").preRequest((context) => {
503
516
  if (!context.params) return context;
504
517
  const formattable = FormattableMap[context.method];
505
- if (formattable) context.params = formattable(context.params);
518
+ if (formattable)
519
+ context.params = formattable(
520
+ context.params
521
+ );
506
522
  return context;
507
523
  })
508
524
  );
@@ -519,63 +535,66 @@ class Bot {
519
535
  await hook(...context);
520
536
  }
521
537
  }
522
- async _callApi(method, params = {}) {
523
- const debug$api$method = debug(`gramio:api:${method}`);
524
- let url = `${this.options.api.baseURL}${this.options.token}/${this.options.api.useTest ? "test/" : ""}${method}`;
525
- const reqOptions = {
526
- method: "POST",
527
- ...this.options.api.fetchOptions,
528
- // @ts-ignore types node/bun and global missmatch
529
- headers: new Headers(this.options.api.fetchOptions?.headers)
530
- };
531
- const context = await this.runHooks(
532
- "preRequest",
533
- // TODO: fix type error
534
- // @ts-expect-error
535
- {
538
+ async _callApi(method, params = {}, callSite) {
539
+ const executeCall = async () => {
540
+ const debug$api$method = debug(`gramio:api:${method}`);
541
+ let url = `${this.options.api.baseURL}${this.options.token}/${this.options.api.useTest ? "test/" : ""}${method}`;
542
+ const reqOptions = {
543
+ method: "POST",
544
+ ...this.options.api.fetchOptions,
545
+ headers: new Headers(this.options.api.fetchOptions?.headers)
546
+ };
547
+ const context = await this.runHooks("preRequest", {
536
548
  method,
537
549
  params
538
- }
539
- );
540
- params = context.params;
541
- if (params && isMediaUpload(method, params)) {
542
- if (IS_BUN) {
543
- const formData = await convertJsonToFormData(method, params);
544
- reqOptions.body = formData;
550
+ });
551
+ params = context.params;
552
+ if (params && isMediaUpload(method, params)) {
553
+ if (IS_BUN) {
554
+ const formData = await convertJsonToFormData(method, params);
555
+ reqOptions.body = formData;
556
+ } else {
557
+ const [formData, paramsWithoutFiles] = await extractFilesToFormData(
558
+ method,
559
+ params
560
+ );
561
+ reqOptions.body = formData;
562
+ const simplifiedParams = simplifyObject(paramsWithoutFiles);
563
+ url += `?${new URLSearchParams(simplifiedParams).toString()}`;
564
+ }
545
565
  } else {
546
- const [formData, paramsWithoutFiles] = await extractFilesToFormData(
547
- method,
548
- params
549
- );
550
- reqOptions.body = formData;
551
- const simplifiedParams = simplifyObject(paramsWithoutFiles);
552
- url += `?${new URLSearchParams(simplifiedParams).toString()}`;
566
+ reqOptions.headers.set("Content-Type", "application/json");
567
+ reqOptions.body = JSON.stringify(params);
553
568
  }
554
- } else {
555
- reqOptions.headers.set("Content-Type", "application/json");
556
- reqOptions.body = JSON.stringify(params);
557
- }
558
- debug$api$method("options: %j", reqOptions);
559
- const response = await fetch(url, reqOptions);
560
- const data = await response.json();
561
- debug$api$method("response: %j", data);
562
- if (!data.ok) {
563
- const err = new TelegramError(data, method, params);
564
- this.runImmutableHooks("onResponseError", err, this.api);
565
- if (!params?.suppress) throw err;
566
- return err;
567
- }
568
- this.runImmutableHooks(
569
- "onResponse",
570
- // TODO: fix type error
571
- // @ts-expect-error
572
- {
573
- method,
574
- params,
575
- response: data.result
569
+ debug$api$method("options: %j", reqOptions);
570
+ const response = await fetch(url, reqOptions);
571
+ const data = await response.json();
572
+ debug$api$method("response: %j", data);
573
+ if (!data.ok) {
574
+ const err = new TelegramError(data, method, params, callSite);
575
+ this.runImmutableHooks("onResponseError", err, this.api);
576
+ if (!params?.suppress) throw err;
577
+ return err;
576
578
  }
577
- );
578
- return data.result;
579
+ this.runImmutableHooks(
580
+ "onResponse",
581
+ // TODO: fix type error
582
+ // @ts-expect-error
583
+ {
584
+ method,
585
+ params,
586
+ response: data.result
587
+ }
588
+ );
589
+ return data.result;
590
+ };
591
+ if (!this.hooks.onApiCall.length) return executeCall();
592
+ let fn = executeCall;
593
+ for (const hook of [...this.hooks.onApiCall].reverse()) {
594
+ const prev = fn;
595
+ fn = () => hook({ method, params }, prev);
596
+ }
597
+ return fn();
579
598
  }
580
599
  async downloadFile(attachment, path) {
581
600
  function getFileId(attachment2) {
@@ -763,6 +782,19 @@ class Bot {
763
782
  } else this.hooks.onResponseError.push(methodsOrHandler);
764
783
  return this;
765
784
  }
785
+ onApiCall(methodsOrHandler, handler) {
786
+ if (typeof methodsOrHandler === "string" || Array.isArray(methodsOrHandler)) {
787
+ if (!handler) throw new Error("TODO:");
788
+ const methods = typeof methodsOrHandler === "string" ? [methodsOrHandler] : methodsOrHandler;
789
+ this.hooks.onApiCall.push(async (context, next) => {
790
+ if (methods.includes(context.method)) return handler(context, next);
791
+ return next();
792
+ });
793
+ } else {
794
+ this.hooks.onApiCall.push(methodsOrHandler);
795
+ }
796
+ return this;
797
+ }
766
798
  // onExperimental(
767
799
  // // filter: Filters,
768
800
  // filter: (
@@ -845,6 +877,11 @@ class Bot {
845
877
  if (!updateName) this.onResponseError(onResponseError);
846
878
  else this.onResponseError(updateName, onResponseError);
847
879
  }
880
+ for (const value of plugin._.onApiCalls) {
881
+ const [onApiCall, methods] = value;
882
+ if (!methods) this.onApiCall(onApiCall);
883
+ else this.onApiCall(methods, onApiCall);
884
+ }
848
885
  for (const handler of plugin._.groups) {
849
886
  this.group(handler);
850
887
  }
@@ -13,13 +13,19 @@ class TelegramError extends Error {
13
13
  /** Describes why a request was unsuccessful. */
14
14
  payload;
15
15
  /** Construct new TelegramError */
16
- constructor(error, method, params) {
16
+ constructor(error, method, params, callSite) {
17
17
  super(error.description);
18
18
  this.name = method;
19
19
  this.method = method;
20
20
  this.params = params;
21
21
  this.code = error.error_code;
22
22
  if (error.parameters) this.payload = error.parameters;
23
+ if (callSite?.stack) {
24
+ const callSiteLines = callSite.stack.split("\n");
25
+ const relevantFrames = callSiteLines.slice(1);
26
+ this.stack = `${this.name}: ${this.message}
27
+ ${relevantFrames.join("\n")}`;
28
+ }
23
29
  }
24
30
  }
25
31
  TelegramError.constructor[ErrorKind] = "TELEGRAM";
@@ -11,13 +11,19 @@ class TelegramError extends Error {
11
11
  /** Describes why a request was unsuccessful. */
12
12
  payload;
13
13
  /** Construct new TelegramError */
14
- constructor(error, method, params) {
14
+ constructor(error, method, params, callSite) {
15
15
  super(error.description);
16
16
  this.name = method;
17
17
  this.method = method;
18
18
  this.params = params;
19
19
  this.code = error.error_code;
20
20
  if (error.parameters) this.payload = error.parameters;
21
+ if (callSite?.stack) {
22
+ const callSiteLines = callSite.stack.split("\n");
23
+ const relevantFrames = callSiteLines.slice(1);
24
+ this.stack = `${this.name}: ${this.message}
25
+ ${relevantFrames.join("\n")}`;
26
+ }
21
27
  }
22
28
  }
23
29
  TelegramError.constructor[ErrorKind] = "TELEGRAM";
package/dist/utils.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var utils = require('./utils-CYIya32k.cjs');
3
+ var utils = require('./utils-C46rnh-r.cjs');
4
4
  require('debug');
5
5
 
6
6
 
package/dist/utils.js CHANGED
@@ -1,2 +1,2 @@
1
- export { w as withRetries } from './utils-CJfJNxc_.js';
1
+ export { w as withRetries } from './utils-En0iVLWH.js';
2
2
  import 'debug';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gramio",
3
3
  "type": "module",
4
- "version": "0.4.12",
4
+ "version": "0.4.13",
5
5
  "description": "Powerful, extensible and really type-safe Telegram Bot API framework",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.js",
@@ -56,10 +56,10 @@
56
56
  "license": "MIT",
57
57
  "devDependencies": {
58
58
  "@biomejs/biome": "2.3.14",
59
- "@types/bun": "^1.3.8",
59
+ "@types/bun": "^1.3.9",
60
60
  "@types/debug": "^4.1.12",
61
61
  "expect-type": "^1.3.0",
62
- "pkgroll": "^2.23.0",
62
+ "pkgroll": "^2.24.0",
63
63
  "typescript": "^5.9.3"
64
64
  },
65
65
  "dependencies": {
@@ -68,7 +68,7 @@
68
68
  "@gramio/files": "^0.3.0",
69
69
  "@gramio/format": "^0.3.4",
70
70
  "@gramio/keyboards": "^1.3.0",
71
- "@gramio/types": "^9.3.1",
71
+ "@gramio/types": "^9.4.0",
72
72
  "debug": "^4.4.3",
73
73
  "middleware-io": "^2.8.1"
74
74
  },