@mtcute/dispatcher 0.12.4 → 0.13.4

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.
@@ -1,4 +1,4 @@
1
- import { CallbackQuery, MaybeArray, MaybePromise } from '@mtcute/core';
1
+ import { CallbackQuery, InlineCallbackQuery, MaybeArray, MaybePromise } from '@mtcute/core';
2
2
  import { UpdateFilter } from './filters/types.js';
3
3
  /**
4
4
  * Callback data builder, inspired by [aiogram](https://github.com/aiogram/aiogram).
@@ -43,7 +43,7 @@ export declare class CallbackDataBuilder<T extends string> {
43
43
  *
44
44
  * @param params
45
45
  */
46
- filter(params?: ((upd: CallbackQuery, parsed: Record<T, string>) => MaybePromise<Partial<Record<T, MaybeArray<string | RegExp>>> | boolean>) | Partial<Record<T, MaybeArray<string | RegExp>>>): UpdateFilter<CallbackQuery, {
46
+ filter<Update extends CallbackQuery | InlineCallbackQuery>(params?: ((upd: Update, parsed: Record<T, string>) => MaybePromise<Partial<Record<T, MaybeArray<string | RegExp>>> | boolean>) | Partial<Record<T, MaybeArray<string | RegExp>>>): UpdateFilter<Update, {
47
47
  match: Record<T, string>;
48
48
  }>;
49
49
  }
@@ -1 +1 @@
1
- {"version":3,"file":"callback-data-builder.js","sourceRoot":"","sources":["../../src/callback-data-builder.ts"],"names":[],"mappings":"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","sourcesContent":["import { CallbackQuery, MaybeArray, MaybePromise, MtArgumentError } from '@mtcute/core'\n\nimport { UpdateFilter } from './filters/types.js'\n\n/**\n * Callback data builder, inspired by [aiogram](https://github.com/aiogram/aiogram).\n *\n * This can be used to simplify management of different callbacks.\n *\n * [Learn more in the docs](/guide/topics/keyboards.html#callback-data-builders)\n */\nexport class CallbackDataBuilder<T extends string> {\n private readonly _fields: T[]\n\n sep = ':'\n\n /**\n * @param prefix Prefix for the data. Use something unique across your bot.\n * @param fields Field names in the order they will be serialized.\n */\n constructor(\n public prefix: string,\n ...fields: T[]\n ) {\n this._fields = fields\n }\n\n /**\n * Build a callback data string\n *\n * @param obj Object containing the data\n */\n build(obj: Record<T, string>): string {\n const ret =\n this.prefix +\n this.sep +\n this._fields\n .map((f) => {\n const val = obj[f]\n\n if (val.includes(this.sep)) {\n throw new MtArgumentError(\n `Value for ${f} ${val} contains separator ${this.sep} and cannot be used.`,\n )\n }\n\n return val\n })\n .join(this.sep)\n\n if (ret.length > 64) {\n throw new MtArgumentError('Resulting callback data is too long.')\n }\n\n return ret\n }\n\n /**\n * Parse callback data to object\n *\n * @param data Callback data as string\n * @param safe If `true`, will return `null` instead of throwing on invalid data\n */\n parse(data: string, safe?: false): Record<T, string>\n parse(data: string, safe: true): Record<T, string> | null\n parse(data: string, safe = false): Record<T, string> | null {\n const parts = data.split(this.sep)\n\n if (parts[0] !== this.prefix) {\n if (safe) return null\n throw new MtArgumentError(\n `Invalid data passed: \"${data}\" (bad prefix, expected ${this.prefix}, got ${parts[0]})`,\n )\n }\n\n if (parts.length !== this._fields.length + 1) {\n if (safe) return null\n throw new MtArgumentError(\n `Invalid data passed: \"${data}\" (bad parts count, expected ${this._fields.length}, got ${\n parts.length - 1\n })`,\n )\n }\n\n const ret = {} as Record<T, string>\n parts.forEach((it, idx) => {\n if (idx === 0) return // skip prefix\n\n ret[this._fields[idx - 1]] = it\n })\n\n return ret\n }\n\n /**\n * Create a filter for this callback data.\n *\n * You can either pass an object with field names as keys and values as strings or regexes,\n * which will be compiled to a RegExp, or a function that will be called with the parsed data.\n * Note that the strings will be passed to `RegExp` **directly**, so you may want to escape them.\n *\n * When using a function, you can either return a boolean, or an object with field names as keys\n * and values as strings or regexes. In the latter case, the resulting object will be matched\n * against the parsed data the same way as if you passed it directly.\n *\n * @param params\n */\n filter(\n params:\n | ((\n upd: CallbackQuery,\n parsed: Record<T, string>,\n ) => MaybePromise<Partial<Record<T, MaybeArray<string | RegExp>>> | boolean>)\n | Partial<Record<T, MaybeArray<string | RegExp>>> = {},\n ): UpdateFilter<\n CallbackQuery,\n {\n match: Record<T, string>\n }\n > {\n if (typeof params === 'function') {\n return async (query) => {\n if (!query.dataStr) return false\n\n const data = this.parse(query.dataStr, true)\n if (!data) return false\n\n const fnResult = await params(query, data)\n\n if (typeof fnResult === 'boolean') {\n (\n query as CallbackQuery & {\n match: Record<T, string>\n }\n ).match = data\n\n return fnResult\n }\n\n // validate result\n for (const key in fnResult) {\n const value = data[key]\n if (value === undefined) return false\n\n let matchers = fnResult[key] as MaybeArray<string | RegExp>\n if (!Array.isArray(matchers)) matchers = [matchers]\n\n for (const matcher of matchers) {\n if (typeof matcher === 'string') {\n if (value !== matcher) return false\n } else if (!matcher.test(value)) return false\n }\n }\n\n (\n query as CallbackQuery & {\n match: Record<T, string>\n }\n ).match = data\n\n return true\n }\n }\n\n const parts: string[] = []\n\n this._fields.forEach((field) => {\n if (!(field in params)) {\n parts.push(`[^${this.sep}]*?`)\n\n return\n }\n\n const value = params[field]\n\n if (Array.isArray(value)) {\n parts.push(`(${value.map((i) => (typeof i === 'string' ? i : i.source)).join('|')})`)\n } else {\n // noinspection SuspiciousTypeOfGuard\n parts.push(typeof value === 'string' ? value : (value as RegExp).source)\n }\n })\n\n const regex = new RegExp(`^${this.prefix}${this.sep}${parts.join(this.sep)}$`)\n\n return (query) => {\n const m = query.dataStr?.match(regex)\n if (!m) return false\n ;(\n query as CallbackQuery & {\n match: Record<T, string>\n }\n ).match = this.parse(m[0])\n\n return true\n }\n }\n}\n"]}
1
+ {"version":3,"file":"callback-data-builder.js","sourceRoot":"","sources":["../../src/callback-data-builder.ts"],"names":[],"mappings":"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","sourcesContent":["import { CallbackQuery, InlineCallbackQuery, MaybeArray, MaybePromise, MtArgumentError } from '@mtcute/core'\n\nimport { UpdateFilter } from './filters/types.js'\n\n/**\n * Callback data builder, inspired by [aiogram](https://github.com/aiogram/aiogram).\n *\n * This can be used to simplify management of different callbacks.\n *\n * [Learn more in the docs](/guide/topics/keyboards.html#callback-data-builders)\n */\nexport class CallbackDataBuilder<T extends string> {\n private readonly _fields: T[]\n\n sep = ':'\n\n /**\n * @param prefix Prefix for the data. Use something unique across your bot.\n * @param fields Field names in the order they will be serialized.\n */\n constructor(\n public prefix: string,\n ...fields: T[]\n ) {\n this._fields = fields\n }\n\n /**\n * Build a callback data string\n *\n * @param obj Object containing the data\n */\n build(obj: Record<T, string>): string {\n const ret =\n this.prefix +\n this.sep +\n this._fields\n .map((f) => {\n const val = obj[f]\n\n if (val.includes(this.sep)) {\n throw new MtArgumentError(\n `Value for ${f} ${val} contains separator ${this.sep} and cannot be used.`,\n )\n }\n\n return val\n })\n .join(this.sep)\n\n if (ret.length > 64) {\n throw new MtArgumentError('Resulting callback data is too long.')\n }\n\n return ret\n }\n\n /**\n * Parse callback data to object\n *\n * @param data Callback data as string\n * @param safe If `true`, will return `null` instead of throwing on invalid data\n */\n parse(data: string, safe?: false): Record<T, string>\n parse(data: string, safe: true): Record<T, string> | null\n parse(data: string, safe = false): Record<T, string> | null {\n const parts = data.split(this.sep)\n\n if (parts[0] !== this.prefix) {\n if (safe) return null\n throw new MtArgumentError(\n `Invalid data passed: \"${data}\" (bad prefix, expected ${this.prefix}, got ${parts[0]})`,\n )\n }\n\n if (parts.length !== this._fields.length + 1) {\n if (safe) return null\n throw new MtArgumentError(\n `Invalid data passed: \"${data}\" (bad parts count, expected ${this._fields.length}, got ${\n parts.length - 1\n })`,\n )\n }\n\n const ret = {} as Record<T, string>\n parts.forEach((it, idx) => {\n if (idx === 0) return // skip prefix\n\n ret[this._fields[idx - 1]] = it\n })\n\n return ret\n }\n\n /**\n * Create a filter for this callback data.\n *\n * You can either pass an object with field names as keys and values as strings or regexes,\n * which will be compiled to a RegExp, or a function that will be called with the parsed data.\n * Note that the strings will be passed to `RegExp` **directly**, so you may want to escape them.\n *\n * When using a function, you can either return a boolean, or an object with field names as keys\n * and values as strings or regexes. In the latter case, the resulting object will be matched\n * against the parsed data the same way as if you passed it directly.\n *\n * @param params\n */\n filter<Update extends CallbackQuery | InlineCallbackQuery>(\n params:\n | ((\n upd: Update,\n parsed: Record<T, string>,\n ) => MaybePromise<Partial<Record<T, MaybeArray<string | RegExp>>> | boolean>)\n | Partial<Record<T, MaybeArray<string | RegExp>>> = {},\n ): UpdateFilter<\n Update,\n {\n match: Record<T, string>\n }\n > {\n if (typeof params === 'function') {\n return async (query) => {\n if (!query.dataStr) return false\n\n const data = this.parse(query.dataStr, true)\n if (!data) return false\n\n const fnResult = await params(query, data)\n\n if (typeof fnResult === 'boolean') {\n (\n query as Update & {\n match: Record<T, string>\n }\n ).match = data\n\n return fnResult\n }\n\n // validate result\n for (const key in fnResult) {\n const value = data[key]\n if (value === undefined) return false\n\n let matchers = fnResult[key] as MaybeArray<string | RegExp>\n if (!Array.isArray(matchers)) matchers = [matchers]\n\n for (const matcher of matchers) {\n if (typeof matcher === 'string') {\n if (value !== matcher) return false\n } else if (!matcher.test(value)) return false\n }\n }\n\n (\n query as Update & {\n match: Record<T, string>\n }\n ).match = data\n\n return true\n }\n }\n\n const parts: string[] = []\n\n this._fields.forEach((field) => {\n if (!(field in params)) {\n parts.push(`[^${this.sep}]*?`)\n\n return\n }\n\n const value = params[field]\n\n if (Array.isArray(value)) {\n parts.push(`(${value.map((i) => (typeof i === 'string' ? i : i.source)).join('|')})`)\n } else {\n // noinspection SuspiciousTypeOfGuard\n parts.push(typeof value === 'string' ? value : (value as RegExp).source)\n }\n })\n\n const regex = new RegExp(`^${this.prefix}${this.sep}${parts.join(this.sep)}$`)\n\n return (query) => {\n const m = query.dataStr?.match(regex)\n if (!m) return false\n ;(\n query as Update & {\n match: Record<T, string>\n }\n ).match = this.parse(m[0])\n\n return true\n }\n }\n}\n"]}
@@ -2,12 +2,12 @@ import { ParsedUpdate } from '@mtcute/core';
2
2
  import { TelegramClient } from '@mtcute/core/client.js';
3
3
  import { UpdateContextDistributed } from './base.js';
4
4
  import { BusinessMessageContext } from './business-message.js';
5
- import { CallbackQueryContext } from './callback-query.js';
5
+ import { CallbackQueryContext, InlineCallbackQueryContext } from './callback-query.js';
6
6
  import { ChatJoinRequestUpdateContext } from './chat-join-request.js';
7
7
  import { ChosenInlineResultContext } from './chosen-inline-result.js';
8
8
  import { InlineQueryContext } from './inline-query.js';
9
9
  import { MessageContext } from './message.js';
10
10
  import { PreCheckoutQueryContext } from './pre-checkout-query.js';
11
11
  /** @internal */
12
- export declare function _parsedUpdateToContext(client: TelegramClient, update: ParsedUpdate): BusinessMessageContext | CallbackQueryContext | ChatJoinRequestUpdateContext | ChosenInlineResultContext | InlineQueryContext | MessageContext | PreCheckoutQueryContext | UpdateContextDistributed<import("@mtcute/core").DeleteMessageUpdate | import("@mtcute/core").ChatMemberUpdate | import("@mtcute/core").InlineCallbackQuery | import("@mtcute/core").PollUpdate | import("@mtcute/core").PollVoteUpdate | import("@mtcute/core").UserStatusUpdate | import("@mtcute/core").UserTypingUpdate | import("@mtcute/core").HistoryReadUpdate | import("@mtcute/core").BotStoppedUpdate | import("@mtcute/core").ChatJoinRequestUpdate | import("@mtcute/core").StoryUpdate | import("@mtcute/core").DeleteStoryUpdate | import("@mtcute/core").BotReactionUpdate | import("@mtcute/core").BotReactionCountUpdate | import("@mtcute/core").BusinessConnection | import("@mtcute/core").DeleteBusinessMessageUpdate>;
12
+ export declare function _parsedUpdateToContext(client: TelegramClient, update: ParsedUpdate): BusinessMessageContext | CallbackQueryContext | InlineCallbackQueryContext | ChatJoinRequestUpdateContext | ChosenInlineResultContext | InlineQueryContext | MessageContext | PreCheckoutQueryContext | UpdateContextDistributed<import("@mtcute/core").DeleteMessageUpdate | import("@mtcute/core").ChatMemberUpdate | import("@mtcute/core").PollUpdate | import("@mtcute/core").PollVoteUpdate | import("@mtcute/core").UserStatusUpdate | import("@mtcute/core").UserTypingUpdate | import("@mtcute/core").HistoryReadUpdate | import("@mtcute/core").BotStoppedUpdate | import("@mtcute/core").ChatJoinRequestUpdate | import("@mtcute/core").StoryUpdate | import("@mtcute/core").DeleteStoryUpdate | import("@mtcute/core").BotReactionUpdate | import("@mtcute/core").BotReactionCountUpdate | import("@mtcute/core").BusinessConnection | import("@mtcute/core").DeleteBusinessMessageUpdate>;
13
13
  export type UpdateContextType = ReturnType<typeof _parsedUpdateToContext>;
@@ -21,6 +21,8 @@ function _parsedUpdateToContext(client, update) {
21
21
  return new chosen_inline_result_js_1.ChosenInlineResultContext(client, update.data);
22
22
  case 'callback_query':
23
23
  return new callback_query_js_1.CallbackQueryContext(client, update.data);
24
+ case 'inline_callback_query':
25
+ return new callback_query_js_1.InlineCallbackQueryContext(client, update.data);
24
26
  case 'bot_chat_join_request':
25
27
  return new chat_join_request_js_1.ChatJoinRequestUpdateContext(client, update.data);
26
28
  case 'pre_checkout_query':
@@ -1 +1 @@
1
- {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../src/context/parse.ts"],"names":[],"mappings":";;;AAIA,+DAA8D;AAC9D,2DAA0D;AAC1D,iEAAqE;AACrE,uEAAqE;AACrE,uDAAsD;AACtD,6CAA6C;AAC7C,mEAAiE;AAEjE,gBAAgB;AAChB,SAAgB,sBAAsB,CAAC,MAAsB,EAAE,MAAoB;IAC/E,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,aAAa,CAAC;QACnB,KAAK,cAAc,CAAC;QACpB,KAAK,eAAe;YAChB,OAAO,IAAI,2BAAc,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;QAClD,KAAK,cAAc;YACf,OAAO,IAAI,oCAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;QACtD,KAAK,sBAAsB;YACvB,OAAO,IAAI,mDAAyB,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;QAC7D,KAAK,gBAAgB;YACjB,OAAO,IAAI,wCAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;QACxD,KAAK,uBAAuB;YACxB,OAAO,IAAI,mDAA4B,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;QAChE,KAAK,oBAAoB;YACrB,OAAO,IAAI,+CAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;QAC3D,KAAK,sBAAsB,CAAC;QAC5B,KAAK,uBAAuB,CAAC;QAC7B,KAAK,wBAAwB;YACzB,OAAO,IAAI,4CAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;IAC9D,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,IAAoD,CAAA;IAC3E,OAAO,CAAC,MAAM,GAAG,MAAM,CAAA;IACvB,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAA;IAE3B,OAAO,OAAO,CAAA;AAClB,CAAC;AA3BD,wDA2BC","sourcesContent":["import { ParsedUpdate } from '@mtcute/core'\nimport { TelegramClient } from '@mtcute/core/client.js'\n\nimport { UpdateContextDistributed } from './base.js'\nimport { BusinessMessageContext } from './business-message.js'\nimport { CallbackQueryContext } from './callback-query.js'\nimport { ChatJoinRequestUpdateContext } from './chat-join-request.js'\nimport { ChosenInlineResultContext } from './chosen-inline-result.js'\nimport { InlineQueryContext } from './inline-query.js'\nimport { MessageContext } from './message.js'\nimport { PreCheckoutQueryContext } from './pre-checkout-query.js'\n\n/** @internal */\nexport function _parsedUpdateToContext(client: TelegramClient, update: ParsedUpdate) {\n switch (update.name) {\n case 'new_message':\n case 'edit_message':\n case 'message_group':\n return new MessageContext(client, update.data)\n case 'inline_query':\n return new InlineQueryContext(client, update.data)\n case 'chosen_inline_result':\n return new ChosenInlineResultContext(client, update.data)\n case 'callback_query':\n return new CallbackQueryContext(client, update.data)\n case 'bot_chat_join_request':\n return new ChatJoinRequestUpdateContext(client, update.data)\n case 'pre_checkout_query':\n return new PreCheckoutQueryContext(client, update.data)\n case 'new_business_message':\n case 'edit_business_message':\n case 'business_message_group':\n return new BusinessMessageContext(client, update.data)\n }\n\n const _update = update.data as UpdateContextDistributed<typeof update.data>\n _update.client = client\n _update._name = update.name\n\n return _update\n}\n\nexport type UpdateContextType = ReturnType<typeof _parsedUpdateToContext>\n"]}
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../src/context/parse.ts"],"names":[],"mappings":";;;AAIA,+DAA8D;AAC9D,2DAAsF;AACtF,iEAAqE;AACrE,uEAAqE;AACrE,uDAAsD;AACtD,6CAA6C;AAC7C,mEAAiE;AAEjE,gBAAgB;AAChB,SAAgB,sBAAsB,CAAC,MAAsB,EAAE,MAAoB;IAC/E,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,aAAa,CAAC;QACnB,KAAK,cAAc,CAAC;QACpB,KAAK,eAAe;YAChB,OAAO,IAAI,2BAAc,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;QAClD,KAAK,cAAc;YACf,OAAO,IAAI,oCAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;QACtD,KAAK,sBAAsB;YACvB,OAAO,IAAI,mDAAyB,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;QAC7D,KAAK,gBAAgB;YACjB,OAAO,IAAI,wCAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;QACxD,KAAK,uBAAuB;YACxB,OAAO,IAAI,8CAA0B,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;QAC9D,KAAK,uBAAuB;YACxB,OAAO,IAAI,mDAA4B,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;QAChE,KAAK,oBAAoB;YACrB,OAAO,IAAI,+CAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;QAC3D,KAAK,sBAAsB,CAAC;QAC5B,KAAK,uBAAuB,CAAC;QAC7B,KAAK,wBAAwB;YACzB,OAAO,IAAI,4CAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;IAC9D,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,IAAoD,CAAA;IAC3E,OAAO,CAAC,MAAM,GAAG,MAAM,CAAA;IACvB,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAA;IAE3B,OAAO,OAAO,CAAA;AAClB,CAAC;AA7BD,wDA6BC","sourcesContent":["import { ParsedUpdate } from '@mtcute/core'\nimport { TelegramClient } from '@mtcute/core/client.js'\n\nimport { UpdateContextDistributed } from './base.js'\nimport { BusinessMessageContext } from './business-message.js'\nimport { CallbackQueryContext, InlineCallbackQueryContext } from './callback-query.js'\nimport { ChatJoinRequestUpdateContext } from './chat-join-request.js'\nimport { ChosenInlineResultContext } from './chosen-inline-result.js'\nimport { InlineQueryContext } from './inline-query.js'\nimport { MessageContext } from './message.js'\nimport { PreCheckoutQueryContext } from './pre-checkout-query.js'\n\n/** @internal */\nexport function _parsedUpdateToContext(client: TelegramClient, update: ParsedUpdate) {\n switch (update.name) {\n case 'new_message':\n case 'edit_message':\n case 'message_group':\n return new MessageContext(client, update.data)\n case 'inline_query':\n return new InlineQueryContext(client, update.data)\n case 'chosen_inline_result':\n return new ChosenInlineResultContext(client, update.data)\n case 'callback_query':\n return new CallbackQueryContext(client, update.data)\n case 'inline_callback_query':\n return new InlineCallbackQueryContext(client, update.data)\n case 'bot_chat_join_request':\n return new ChatJoinRequestUpdateContext(client, update.data)\n case 'pre_checkout_query':\n return new PreCheckoutQueryContext(client, update.data)\n case 'new_business_message':\n case 'edit_business_message':\n case 'business_message_group':\n return new BusinessMessageContext(client, update.data)\n }\n\n const _update = update.data as UpdateContextDistributed<typeof update.data>\n _update.client = client\n _update._name = update.name\n\n return _update\n}\n\nexport type UpdateContextType = ReturnType<typeof _parsedUpdateToContext>\n"]}
@@ -0,0 +1,24 @@
1
+ import { BusinessMessageContext } from './business-message.js';
2
+ import { CallbackQueryContext, InlineCallbackQueryContext } from './callback-query.js';
3
+ import { MessageContext } from './message.js';
4
+ import { UpdateContextType } from './parse.js';
5
+ /** Update which is dispatched whenever scene is entered or exited */
6
+ export declare class SceneTransitionContext {
7
+ /** Name of the previous scene, if any */
8
+ readonly previousScene: string | null;
9
+ /** Update, handler for which triggered the transition */
10
+ readonly update: UpdateContextType;
11
+ constructor(
12
+ /** Name of the previous scene, if any */
13
+ previousScene: string | null,
14
+ /** Update, handler for which triggered the transition */
15
+ update: UpdateContextType);
16
+ /** Get {@link update}, asserting it is a message-related update */
17
+ get message(): MessageContext;
18
+ /** Get {@link update}, asserting it is a business message-related update */
19
+ get businessMessage(): BusinessMessageContext;
20
+ /** Get {@link update}, asserting it is a callback query update */
21
+ get callbackQuery(): CallbackQueryContext;
22
+ /** Get {@link update}, asserting it is an inline callback query update */
23
+ get inlineCallbackQuery(): InlineCallbackQueryContext;
24
+ }
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SceneTransitionContext = void 0;
4
+ const core_1 = require("@mtcute/core");
5
+ const utils_js_1 = require("@mtcute/core/utils.js");
6
+ const business_message_js_1 = require("./business-message.js");
7
+ const callback_query_js_1 = require("./callback-query.js");
8
+ const message_js_1 = require("./message.js");
9
+ /** Update which is dispatched whenever scene is entered or exited */
10
+ class SceneTransitionContext {
11
+ previousScene;
12
+ update;
13
+ constructor(
14
+ /** Name of the previous scene, if any */
15
+ previousScene,
16
+ /** Update, handler for which triggered the transition */
17
+ update) {
18
+ this.previousScene = previousScene;
19
+ this.update = update;
20
+ }
21
+ /** Get {@link update}, asserting it is a message-related update */
22
+ get message() {
23
+ if (this.update instanceof message_js_1.MessageContext) {
24
+ return this.update;
25
+ }
26
+ throw new core_1.MtTypeAssertionError('SceneTransitionContext.message', 'message', this.update._name);
27
+ }
28
+ /** Get {@link update}, asserting it is a business message-related update */
29
+ get businessMessage() {
30
+ if (this.update instanceof business_message_js_1.BusinessMessageContext) {
31
+ return this.update;
32
+ }
33
+ throw new core_1.MtTypeAssertionError('SceneTransitionContext.businessMessage', 'business message', this.update._name);
34
+ }
35
+ /** Get {@link update}, asserting it is a callback query update */
36
+ get callbackQuery() {
37
+ if (this.update instanceof callback_query_js_1.CallbackQueryContext) {
38
+ return this.update;
39
+ }
40
+ throw new core_1.MtTypeAssertionError('SceneTransitionContext.callbackQuery', 'callback query', this.update._name);
41
+ }
42
+ /** Get {@link update}, asserting it is an inline callback query update */
43
+ get inlineCallbackQuery() {
44
+ if (this.update instanceof callback_query_js_1.InlineCallbackQueryContext) {
45
+ return this.update;
46
+ }
47
+ throw new core_1.MtTypeAssertionError('SceneTransitionContext.inlineCallbackQuery', 'inline callback query', this.update._name);
48
+ }
49
+ }
50
+ exports.SceneTransitionContext = SceneTransitionContext;
51
+ (0, utils_js_1.makeInspectable)(SceneTransitionContext);
52
+ //# sourceMappingURL=scene-transition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene-transition.js","sourceRoot":"","sources":["../../../src/context/scene-transition.ts"],"names":[],"mappings":";;;AAAA,uCAAmD;AACnD,oDAAuD;AAEvD,+DAA8D;AAC9D,2DAAsF;AACtF,6CAA6C;AAG7C,qEAAqE;AACrE,MAAa,sBAAsB;IAGlB;IAEA;IAJb;IACI,yCAAyC;IAChC,aAA4B;IACrC,yDAAyD;IAChD,MAAyB;QAFzB,kBAAa,GAAb,aAAa,CAAe;QAE5B,WAAM,GAAN,MAAM,CAAmB;IACnC,CAAC;IAEJ,mEAAmE;IACnE,IAAI,OAAO;QACP,IAAI,IAAI,CAAC,MAAM,YAAY,2BAAc,EAAE,CAAC;YACxC,OAAO,IAAI,CAAC,MAAM,CAAA;QACtB,CAAC;QAED,MAAM,IAAI,2BAAoB,CAAC,gCAAgC,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAClG,CAAC;IAED,4EAA4E;IAC5E,IAAI,eAAe;QACf,IAAI,IAAI,CAAC,MAAM,YAAY,4CAAsB,EAAE,CAAC;YAChD,OAAO,IAAI,CAAC,MAAM,CAAA;QACtB,CAAC;QAED,MAAM,IAAI,2BAAoB,CAAC,wCAAwC,EAAE,kBAAkB,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACnH,CAAC;IAED,kEAAkE;IAClE,IAAI,aAAa;QACb,IAAI,IAAI,CAAC,MAAM,YAAY,wCAAoB,EAAE,CAAC;YAC9C,OAAO,IAAI,CAAC,MAAM,CAAA;QACtB,CAAC;QAED,MAAM,IAAI,2BAAoB,CAAC,sCAAsC,EAAE,gBAAgB,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC/G,CAAC;IAED,0EAA0E;IAC1E,IAAI,mBAAmB;QACnB,IAAI,IAAI,CAAC,MAAM,YAAY,8CAA0B,EAAE,CAAC;YACpD,OAAO,IAAI,CAAC,MAAM,CAAA;QACtB,CAAC;QAED,MAAM,IAAI,2BAAoB,CAC1B,4CAA4C,EAC5C,uBAAuB,EACvB,IAAI,CAAC,MAAM,CAAC,KAAK,CACpB,CAAA;IACL,CAAC;CACJ;AA/CD,wDA+CC;AAED,IAAA,0BAAe,EAAC,sBAAsB,CAAC,CAAA","sourcesContent":["import { MtTypeAssertionError } from '@mtcute/core'\nimport { makeInspectable } from '@mtcute/core/utils.js'\n\nimport { BusinessMessageContext } from './business-message.js'\nimport { CallbackQueryContext, InlineCallbackQueryContext } from './callback-query.js'\nimport { MessageContext } from './message.js'\nimport { UpdateContextType } from './parse.js'\n\n/** Update which is dispatched whenever scene is entered or exited */\nexport class SceneTransitionContext {\n constructor(\n /** Name of the previous scene, if any */\n readonly previousScene: string | null,\n /** Update, handler for which triggered the transition */\n readonly update: UpdateContextType,\n ) {}\n\n /** Get {@link update}, asserting it is a message-related update */\n get message(): MessageContext {\n if (this.update instanceof MessageContext) {\n return this.update\n }\n\n throw new MtTypeAssertionError('SceneTransitionContext.message', 'message', this.update._name)\n }\n\n /** Get {@link update}, asserting it is a business message-related update */\n get businessMessage(): BusinessMessageContext {\n if (this.update instanceof BusinessMessageContext) {\n return this.update\n }\n\n throw new MtTypeAssertionError('SceneTransitionContext.businessMessage', 'business message', this.update._name)\n }\n\n /** Get {@link update}, asserting it is a callback query update */\n get callbackQuery(): CallbackQueryContext {\n if (this.update instanceof CallbackQueryContext) {\n return this.update\n }\n\n throw new MtTypeAssertionError('SceneTransitionContext.callbackQuery', 'callback query', this.update._name)\n }\n\n /** Get {@link update}, asserting it is an inline callback query update */\n get inlineCallbackQuery(): InlineCallbackQueryContext {\n if (this.update instanceof InlineCallbackQueryContext) {\n return this.update\n }\n\n throw new MtTypeAssertionError(\n 'SceneTransitionContext.inlineCallbackQuery',\n 'inline callback query',\n this.update._name,\n )\n }\n}\n\nmakeInspectable(SceneTransitionContext)\n"]}
@@ -3,6 +3,7 @@ import { TelegramClient } from '@mtcute/core/client.js';
3
3
  import { UpdateContext } from './context/base.js';
4
4
  import { BusinessMessageContext } from './context/business-message.js';
5
5
  import { CallbackQueryContext, ChatJoinRequestUpdateContext, ChosenInlineResultContext, InlineCallbackQueryContext, InlineQueryContext, MessageContext, PreCheckoutQueryContext } from './context/index.js';
6
+ import { SceneTransitionContext } from './context/scene-transition.js';
6
7
  import { filters, UpdateFilter } from './filters/index.js';
7
8
  import { BotChatJoinRequestHandler, BotReactionCountUpdateHandler, BotReactionUpdateHandler, BotStoppedHandler, BusinessConnectionUpdateHandler, BusinessMessageGroupHandler, CallbackQueryHandler, ChatJoinRequestHandler, ChatMemberUpdateHandler, ChosenInlineResultHandler, DeleteBusinessMessageHandler, DeleteMessageHandler, DeleteStoryHandler, EditBusinessMessageHandler, EditMessageHandler, HistoryReadHandler, InlineCallbackQueryHandler, InlineQueryHandler, MessageGroupHandler, NewBusinessMessageHandler, NewMessageHandler, PollUpdateHandler, PollVoteHandler, PreCheckoutQueryHandler, RawUpdateHandler, StoryUpdateHandler, UpdateHandler, UserStatusUpdateHandler, UserTypingHandler } from './handler.js';
8
9
  import { PropagationAction } from './propagation.js';
@@ -47,11 +48,14 @@ export declare class Dispatcher<State extends object = never> {
47
48
  private _errorHandler?;
48
49
  private _preUpdateHandler?;
49
50
  private _postUpdateHandler?;
51
+ private _sceneTransitionHandler?;
50
52
  protected constructor(client?: TelegramClient, params?: DispatcherParams);
51
53
  /**
52
54
  * Create a new dispatcher and bind it to the client.
53
55
  */
54
- static for<State extends object = never>(client: TelegramClient, params?: DispatcherParams): Dispatcher<State>;
56
+ static for<State extends object = never>(client: TelegramClient, ...args: [State] extends [never] ? [params?: DispatcherParams] : [params: DispatcherParams & {
57
+ storage: IStateStorageProvider;
58
+ }]): Dispatcher<State>;
55
59
  /**
56
60
  * Create a new child dispatcher.
57
61
  */
@@ -340,6 +344,47 @@ export declare class Dispatcher<State extends object = never> {
340
344
  * @param group Handler group index
341
345
  */
342
346
  onRawUpdate(filter: RawUpdateHandler['check'], handler: RawUpdateHandler['callback'], group?: number): void;
347
+ /**
348
+ * Register a scene transition handler
349
+ *
350
+ * This handler is called whenever a scene transition occurs
351
+ * in the context of the scene that is being entered,
352
+ * and before any of the its own handlers are called,
353
+ * and can be used to customize the transition behavior:
354
+ * - `Stop` to prevent dispatching the update any further **even if ToScene/ToRoot was used**
355
+ * - `Continue` same as Stop, but still dispatch the update to children
356
+ * - `ToScene` to prevent the transition and dispatch the update to the scene entered in the transition handler
357
+ *
358
+ * > **Note**: if multiple `state.enter()` calls were made within the same update,
359
+ * > this handler will only be called for the last one.
360
+ *
361
+ * @param handler Raw update handler
362
+ * @param group Handler group index
363
+ */
364
+ onSceneTransition(handler: ((ctx: SceneTransitionContext, state: UpdateState<State>) => MaybePromise<PropagationAction | void>) | null): void;
365
+ /**
366
+ * Register a callback query (both inline and non-inline) handler without any filters
367
+ *
368
+ * @param handler Callback query handler
369
+ * @param group Handler group index
370
+ */
371
+ onAnyCallbackQuery(handler: CallbackQueryHandler<CallbackQueryContext | InlineCallbackQueryContext, State extends never ? never : UpdateState<State>>['callback'], group?: number): void;
372
+ /**
373
+ * Register a callback query (both inline and non-inline) handler with a filter
374
+ *
375
+ * @param filter Update filter
376
+ * @param handler Callback query handler
377
+ * @param group Handler group index
378
+ */
379
+ onAnyCallbackQuery<Mod>(filter: UpdateFilter<CallbackQueryContext | InlineCallbackQueryContext, Mod, State>, handler: CallbackQueryHandler<filters.Modify<CallbackQueryContext | InlineCallbackQueryContext, Mod>, State extends never ? never : UpdateState<State>>['callback'], group?: number): void;
380
+ /**
381
+ * Register a callback query (both inline and non-inline) handler with a filter
382
+ *
383
+ * @param filter Update filter
384
+ * @param handler Callback query handler
385
+ * @param group Handler group index
386
+ */
387
+ onAnyCallbackQuery<Mod>(filter: UpdateFilter<CallbackQueryContext | InlineCallbackQueryContext, Mod>, handler: CallbackQueryHandler<filters.Modify<CallbackQueryContext | InlineCallbackQueryContext, Mod>, State extends never ? never : UpdateState<State>>['callback'], group?: number): void;
343
388
  /**
344
389
  * Register a new message handler without any filters
345
390
  *
package/cjs/dispatcher.js CHANGED
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.Dispatcher = void 0;
8
8
  const core_1 = require("@mtcute/core");
9
9
  const parse_js_1 = require("./context/parse.js");
10
+ const scene_transition_js_1 = require("./context/scene-transition.js");
10
11
  const index_js_1 = require("./state/index.js");
11
12
  const service_js_1 = require("./state/service.js");
12
13
  /**
@@ -29,6 +30,7 @@ class Dispatcher {
29
30
  _errorHandler;
30
31
  _preUpdateHandler;
31
32
  _postUpdateHandler;
33
+ _sceneTransitionHandler;
32
34
  constructor(client, params) {
33
35
  this.dispatchRawUpdate = this.dispatchRawUpdate.bind(this);
34
36
  this.dispatchUpdate = this.dispatchUpdate.bind(this);
@@ -57,9 +59,6 @@ class Dispatcher {
57
59
  }
58
60
  }
59
61
  }
60
- /**
61
- * Create a new dispatcher and bind it to the client.
62
- */
63
62
  static for(client, params) {
64
63
  return new Dispatcher(client, params);
65
64
  }
@@ -245,7 +244,10 @@ class Dispatcher {
245
244
  (update.name === 'new_message' ||
246
245
  update.name === 'edit_message' ||
247
246
  update.name === 'callback_query' ||
248
- update.name === 'message_group')) {
247
+ update.name === 'message_group' ||
248
+ update.name === 'new_business_message' ||
249
+ update.name === 'edit_business_message' ||
250
+ update.name === 'business_message_group')) {
249
251
  // no need to fetch scene if there are no registered scenes
250
252
  if (!parsedContext)
251
253
  parsedContext = (0, parse_js_1._parsedUpdateToContext)(this._client, update);
@@ -281,7 +283,10 @@ class Dispatcher {
281
283
  (update.name === 'new_message' ||
282
284
  update.name === 'edit_message' ||
283
285
  update.name === 'callback_query' ||
284
- update.name === 'message_group')) {
286
+ update.name === 'message_group' ||
287
+ update.name === 'new_business_message' ||
288
+ update.name === 'edit_business_message' ||
289
+ update.name === 'business_message_group')) {
285
290
  if (!parsedContext)
286
291
  parsedContext = (0, parse_js_1._parsedUpdateToContext)(this._client, update);
287
292
  const key = await this._stateKeyDelegate(parsedContext);
@@ -327,6 +332,31 @@ class Dispatcher {
327
332
  }
328
333
  else
329
334
  continue;
335
+ if (parsedState && this._scenes) {
336
+ // check if scene transition was made
337
+ const newScene = parsedState.scene;
338
+ if (parsedScene !== newScene) {
339
+ const nextDp = newScene ? this._scenes.get(newScene) : this._parent;
340
+ if (!nextDp) {
341
+ throw new core_1.MtArgumentError(`Scene ${newScene} not found`);
342
+ }
343
+ if (nextDp._sceneTransitionHandler) {
344
+ const transition = new scene_transition_js_1.SceneTransitionContext(parsedScene, parsedContext);
345
+ const transitionResult = await nextDp._sceneTransitionHandler?.(transition, parsedState);
346
+ switch (transitionResult) {
347
+ case 'stop':
348
+ return true;
349
+ case 'continue':
350
+ continue;
351
+ case 'scene': {
352
+ const scene = parsedState.scene;
353
+ const dp = scene ? nextDp._scenes.get(scene) : nextDp._parent;
354
+ return dp._dispatchUpdateNowImpl(update, undefined, scene, true);
355
+ }
356
+ }
357
+ }
358
+ }
359
+ }
330
360
  switch (result) {
331
361
  case 'continue':
332
362
  continue;
@@ -339,11 +369,9 @@ class Dispatcher {
339
369
  if (!parsedState) {
340
370
  throw new core_1.MtArgumentError('Cannot use ToScene without state');
341
371
  }
342
- const scene = parsedState['_scene'];
343
- if (!scene) {
344
- throw new core_1.MtArgumentError('Cannot use ToScene without entering a scene');
345
- }
346
- return this._scenes.get(scene)._dispatchUpdateNowImpl(update, undefined, scene, true);
372
+ const scene = parsedState.scene;
373
+ const dp = scene ? this._scenes.get(scene) : this._parent;
374
+ return dp._dispatchUpdateNowImpl(update, undefined, scene, true);
347
375
  }
348
376
  }
349
377
  break;
@@ -513,6 +541,7 @@ class Dispatcher {
513
541
  child._client = this._client;
514
542
  child._storage = this._storage;
515
543
  child._deps = this._deps;
544
+ child._scenes = this._scenes;
516
545
  child._stateKeyDelegate = this._stateKeyDelegate;
517
546
  child._customStorage ??= this._customStorage;
518
547
  child._customStateKeyDelegate ??= this._customStateKeyDelegate;
@@ -730,6 +759,34 @@ class Dispatcher {
730
759
  onRawUpdate(filter, handler, group) {
731
760
  this._addKnownHandler('raw', filter, handler, group);
732
761
  }
762
+ /**
763
+ * Register a scene transition handler
764
+ *
765
+ * This handler is called whenever a scene transition occurs
766
+ * in the context of the scene that is being entered,
767
+ * and before any of the its own handlers are called,
768
+ * and can be used to customize the transition behavior:
769
+ * - `Stop` to prevent dispatching the update any further **even if ToScene/ToRoot was used**
770
+ * - `Continue` same as Stop, but still dispatch the update to children
771
+ * - `ToScene` to prevent the transition and dispatch the update to the scene entered in the transition handler
772
+ *
773
+ * > **Note**: if multiple `state.enter()` calls were made within the same update,
774
+ * > this handler will only be called for the last one.
775
+ *
776
+ * @param handler Raw update handler
777
+ * @param group Handler group index
778
+ */
779
+ onSceneTransition(handler) {
780
+ if (handler)
781
+ this._sceneTransitionHandler = handler;
782
+ else
783
+ this._sceneTransitionHandler = undefined;
784
+ }
785
+ /** @internal */
786
+ onAnyCallbackQuery(filter, handler, group) {
787
+ this._addKnownHandler('callback_query', filter, handler, group);
788
+ this._addKnownHandler('inline_callback_query', filter, handler, group);
789
+ }
733
790
  /** @internal */
734
791
  onNewMessage(filter, handler, group) {
735
792
  this._addKnownHandler('new_message', filter, handler, group);