@mtcute/dispatcher 0.16.0 → 0.16.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/cjs/callback-data-builder.d.ts +2 -2
- package/cjs/callback-data-builder.js +8 -6
- package/cjs/callback-data-builder.js.map +1 -1
- package/cjs/context/base.d.ts +2 -2
- package/cjs/context/base.js.map +1 -1
- package/cjs/context/business-message.d.ts +20 -19
- package/cjs/context/business-message.js +3 -3
- package/cjs/context/business-message.js.map +1 -1
- package/cjs/context/callback-query.d.ts +4 -3
- package/cjs/context/callback-query.js.map +1 -1
- package/cjs/context/chat-join-request.d.ts +2 -2
- package/cjs/context/chat-join-request.js.map +1 -1
- package/cjs/context/chosen-inline-result.d.ts +2 -2
- package/cjs/context/chosen-inline-result.js.map +1 -1
- package/cjs/context/inline-query.d.ts +4 -3
- package/cjs/context/inline-query.js.map +1 -1
- package/cjs/context/message.d.ts +6 -5
- package/cjs/context/message.js +3 -3
- package/cjs/context/message.js.map +1 -1
- package/cjs/context/parse.d.ts +5 -5
- package/cjs/context/parse.js +1 -2
- package/cjs/context/parse.js.map +1 -1
- package/cjs/context/pre-checkout-query.d.ts +2 -2
- package/cjs/context/pre-checkout-query.js.map +1 -1
- package/cjs/context/scene-transition.d.ts +1 -1
- package/cjs/context/scene-transition.js.map +1 -1
- package/cjs/dispatcher.d.ts +10 -9
- package/cjs/dispatcher.js +34 -31
- package/cjs/dispatcher.js.map +1 -1
- package/cjs/filters/bots.d.ts +15 -25
- package/cjs/filters/bots.js +36 -34
- package/cjs/filters/bots.js.map +1 -1
- package/cjs/filters/chat.d.ts +5 -5
- package/cjs/filters/chat.js +10 -9
- package/cjs/filters/chat.js.map +1 -1
- package/cjs/filters/group.d.ts +4 -4
- package/cjs/filters/group.js +3 -6
- package/cjs/filters/group.js.map +1 -1
- package/cjs/filters/index.js.map +1 -1
- package/cjs/filters/logic.d.ts +1 -1
- package/cjs/filters/logic.js +5 -7
- package/cjs/filters/logic.js.map +1 -1
- package/cjs/filters/message.d.ts +29 -146
- package/cjs/filters/message.js +84 -72
- package/cjs/filters/message.js.map +1 -1
- package/cjs/filters/state.d.ts +3 -3
- package/cjs/filters/state.js +5 -4
- package/cjs/filters/state.js.map +1 -1
- package/cjs/filters/text.d.ts +8 -8
- package/cjs/filters/text.js +27 -26
- package/cjs/filters/text.js.map +1 -1
- package/cjs/filters/types.d.ts +2 -2
- package/cjs/filters/types.js +0 -3
- package/cjs/filters/types.js.map +1 -1
- package/cjs/filters/updates.d.ts +2 -2
- package/cjs/filters/updates.js +7 -7
- package/cjs/filters/updates.js.map +1 -1
- package/cjs/filters/user.d.ts +4 -3
- package/cjs/filters/user.js +15 -16
- package/cjs/filters/user.js.map +1 -1
- package/cjs/handler.d.ts +5 -5
- package/cjs/handler.js.map +1 -1
- package/cjs/state/key.d.ts +3 -3
- package/cjs/state/key.js.map +1 -1
- package/cjs/state/provider.d.ts +2 -2
- package/cjs/state/provider.js.map +1 -1
- package/cjs/state/providers/memory.d.ts +4 -3
- package/cjs/state/providers/memory.js.map +1 -1
- package/cjs/state/providers/sqlite.d.ts +3 -3
- package/cjs/state/providers/sqlite.js.map +1 -1
- package/cjs/state/repository.d.ts +7 -7
- package/cjs/state/repository.js.map +1 -1
- package/cjs/state/service.d.ts +4 -3
- package/cjs/state/service.js.map +1 -1
- package/cjs/state/update-state.d.ts +1 -1
- package/cjs/state/update-state.js +3 -4
- package/cjs/state/update-state.js.map +1 -1
- package/cjs/wizard.d.ts +8 -7
- package/cjs/wizard.js +3 -1
- package/cjs/wizard.js.map +1 -1
- package/esm/callback-data-builder.d.ts +2 -2
- package/esm/callback-data-builder.js +8 -6
- package/esm/callback-data-builder.js.map +1 -1
- package/esm/context/base.d.ts +2 -2
- package/esm/context/base.js.map +1 -1
- package/esm/context/business-message.d.ts +20 -19
- package/esm/context/business-message.js +3 -3
- package/esm/context/business-message.js.map +1 -1
- package/esm/context/callback-query.d.ts +4 -3
- package/esm/context/callback-query.js.map +1 -1
- package/esm/context/chat-join-request.d.ts +2 -2
- package/esm/context/chat-join-request.js.map +1 -1
- package/esm/context/chosen-inline-result.d.ts +2 -2
- package/esm/context/chosen-inline-result.js.map +1 -1
- package/esm/context/inline-query.d.ts +4 -3
- package/esm/context/inline-query.js.map +1 -1
- package/esm/context/message.d.ts +6 -5
- package/esm/context/message.js +3 -3
- package/esm/context/message.js.map +1 -1
- package/esm/context/parse.d.ts +5 -5
- package/esm/context/parse.js.map +1 -1
- package/esm/context/pre-checkout-query.d.ts +2 -2
- package/esm/context/pre-checkout-query.js.map +1 -1
- package/esm/context/scene-transition.d.ts +1 -1
- package/esm/context/scene-transition.js.map +1 -1
- package/esm/dispatcher.d.ts +10 -9
- package/esm/dispatcher.js +35 -32
- package/esm/dispatcher.js.map +1 -1
- package/esm/filters/bots.d.ts +15 -25
- package/esm/filters/bots.js +32 -30
- package/esm/filters/bots.js.map +1 -1
- package/esm/filters/chat.d.ts +5 -5
- package/esm/filters/chat.js +8 -7
- package/esm/filters/chat.js.map +1 -1
- package/esm/filters/group.d.ts +4 -4
- package/esm/filters/group.js +1 -3
- package/esm/filters/group.js.map +1 -1
- package/esm/filters/index.js.map +1 -1
- package/esm/filters/logic.d.ts +1 -1
- package/esm/filters/logic.js +1 -3
- package/esm/filters/logic.js.map +1 -1
- package/esm/filters/message.d.ts +29 -146
- package/esm/filters/message.js +60 -48
- package/esm/filters/message.js.map +1 -1
- package/esm/filters/state.d.ts +3 -3
- package/esm/filters/state.js +3 -2
- package/esm/filters/state.js.map +1 -1
- package/esm/filters/text.d.ts +8 -8
- package/esm/filters/text.js +22 -20
- package/esm/filters/text.js.map +1 -1
- package/esm/filters/types.d.ts +2 -2
- package/esm/filters/types.js +0 -3
- package/esm/filters/types.js.map +1 -1
- package/esm/filters/updates.d.ts +2 -2
- package/esm/filters/updates.js +7 -7
- package/esm/filters/updates.js.map +1 -1
- package/esm/filters/user.d.ts +4 -3
- package/esm/filters/user.js +15 -16
- package/esm/filters/user.js.map +1 -1
- package/esm/handler.d.ts +5 -5
- package/esm/handler.js.map +1 -1
- package/esm/state/key.d.ts +3 -3
- package/esm/state/key.js.map +1 -1
- package/esm/state/provider.d.ts +2 -2
- package/esm/state/provider.js.map +1 -1
- package/esm/state/providers/memory.d.ts +4 -3
- package/esm/state/providers/memory.js.map +1 -1
- package/esm/state/providers/sqlite.d.ts +3 -3
- package/esm/state/providers/sqlite.js.map +1 -1
- package/esm/state/repository.d.ts +7 -7
- package/esm/state/repository.js.map +1 -1
- package/esm/state/service.d.ts +4 -3
- package/esm/state/service.js +1 -1
- package/esm/state/service.js.map +1 -1
- package/esm/state/update-state.d.ts +1 -1
- package/esm/state/update-state.js +3 -4
- package/esm/state/update-state.js.map +1 -1
- package/esm/wizard.d.ts +8 -7
- package/esm/wizard.js +3 -1
- package/esm/wizard.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../../../src/state/providers/sqlite.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../../../src/state/providers/sqlite.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BaseSqliteStorage, BaseSqliteStorageDriver, ISqliteStatement, MaybePromise } from '@mtcute/core'\n\nimport type { IStateStorageProvider } from '../provider.js'\nimport type { IStateRepository } from '../repository.js'\n\ninterface StateDto {\n value: string\n expires_at: number | null\n}\n\ninterface RateLimitDto {\n reset: number\n remaining: number\n}\n\nclass SqliteStateRepository implements IStateRepository {\n constructor(readonly _driver: BaseSqliteStorageDriver) {\n _driver.registerMigration('state', 1, (db) => {\n db.exec(`\n create table fsm_state (\n key text primary key,\n value text not null,\n expires_at integer\n );\n create table rl_state (\n key text primary key,\n reset integer not null,\n remaining integer not null\n );\n `)\n })\n _driver.onLoad(() => {\n this._setState = _driver.db.prepare(\n 'insert or replace into fsm_state (key, value, expires_at) values (?, ?, ?)',\n )\n this._getState = _driver.db.prepare('select value, expires_at from fsm_state where key = ?')\n this._deleteState = _driver.db.prepare('delete from fsm_state where key = ?')\n this._deleteOldState = _driver.db.prepare('delete from fsm_state where expires_at < ?')\n\n this._setRl = _driver.db.prepare('insert or replace into rl_state (key, reset, remaining) values (?, ?, ?)')\n this._getRl = _driver.db.prepare('select reset, remaining from rl_state where key = ?')\n this._deleteRl = _driver.db.prepare('delete from rl_state where key = ?')\n this._deleteOldRl = _driver.db.prepare('delete from rl_state where reset < ?')\n })\n _driver.registerLegacyMigration('state', (db) => {\n // not too important information, just drop the table\n db.exec('drop table state')\n })\n }\n\n private _setState!: ISqliteStatement\n setState(key: string, state: string, ttl?: number | undefined): MaybePromise<void> {\n this._setState.run(key, state, ttl ? Date.now() + ttl * 1000 : undefined)\n }\n\n private _getState!: ISqliteStatement\n getState(key: string, now: number): MaybePromise<string | null> {\n const res_ = this._getState.get(key)\n if (!res_) return null\n const res = res_ as StateDto\n\n if (res.expires_at && res.expires_at < now) {\n this._deleteState.run(key)\n\n return null\n }\n\n return res.value\n }\n\n private _deleteState!: ISqliteStatement\n deleteState(key: string): MaybePromise<void> {\n this._deleteState.run(key)\n }\n\n private _deleteOldState!: ISqliteStatement\n private _deleteOldRl!: ISqliteStatement\n vacuum(now: number): MaybePromise<void> {\n this._deleteOldState.run(now)\n this._deleteOldRl.run(now)\n }\n\n private _setRl!: ISqliteStatement\n private _getRl!: ISqliteStatement\n private _deleteRl!: ISqliteStatement\n\n getRateLimit(key: string, now: number, limit: number, window: number): [number, number] {\n const val = this._getRl.get(key) as RateLimitDto | undefined\n\n // hot path. rate limit fsm entries always have an expiration date\n\n if (!val || val.reset < now) {\n // expired or does not exist\n const item: RateLimitDto = {\n reset: now + window * 1000,\n remaining: limit,\n }\n\n this._setRl.run(key, item.reset, item.remaining)\n\n return [item.remaining, item.reset]\n }\n\n if (val.remaining > 0) {\n val.remaining -= 1\n\n this._setRl.run(key, val.reset, val.remaining)\n }\n\n return [val.remaining, val.reset]\n }\n\n resetRateLimit(key: string): MaybePromise<void> {\n this._deleteRl.run(key)\n }\n}\n\nexport class SqliteStateStorage implements IStateStorageProvider {\n readonly state: SqliteStateRepository\n constructor(readonly driver: BaseSqliteStorageDriver) {\n this.state = new SqliteStateRepository(driver)\n }\n\n static from(provider: BaseSqliteStorage): SqliteStateStorage {\n return new SqliteStateStorage(provider.driver)\n }\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MaybePromise } from '@mtcute/core';
|
|
1
|
+
import type { MaybePromise } from '@mtcute/core';
|
|
2
2
|
/**
|
|
3
3
|
* Interface for FSM storage for the dispatcher.
|
|
4
4
|
*
|
|
@@ -18,7 +18,7 @@ export interface IStateRepository {
|
|
|
18
18
|
*
|
|
19
19
|
* @param key Key of the state, as defined by {@link StateKeyDelegate}
|
|
20
20
|
*/
|
|
21
|
-
getState(key: string, now: number)
|
|
21
|
+
getState: (key: string, now: number) => MaybePromise<string | null>;
|
|
22
22
|
/**
|
|
23
23
|
* Save state to the storage
|
|
24
24
|
*
|
|
@@ -26,19 +26,19 @@ export interface IStateRepository {
|
|
|
26
26
|
* @param state String representing the state
|
|
27
27
|
* @param ttl TTL for the state, in seconds
|
|
28
28
|
*/
|
|
29
|
-
setState(key: string, state: string, ttl?: number)
|
|
29
|
+
setState: (key: string, state: string, ttl?: number) => MaybePromise<void>;
|
|
30
30
|
/**
|
|
31
31
|
* Delete state from the storage
|
|
32
32
|
*
|
|
33
33
|
* @param key Key of the state, as defined by {@link StateKeyDelegate}
|
|
34
34
|
*/
|
|
35
|
-
deleteState(key: string)
|
|
35
|
+
deleteState: (key: string) => MaybePromise<void>;
|
|
36
36
|
/**
|
|
37
37
|
* Clean up expired states and rate limits.
|
|
38
38
|
*
|
|
39
39
|
* @param now Current unix time in ms
|
|
40
40
|
*/
|
|
41
|
-
vacuum(now: number)
|
|
41
|
+
vacuum: (now: number) => MaybePromise<void>;
|
|
42
42
|
/**
|
|
43
43
|
* Get information about a rate limit.
|
|
44
44
|
*
|
|
@@ -52,11 +52,11 @@ export interface IStateRepository {
|
|
|
52
52
|
* @returns Tuple containing the number of remaining and
|
|
53
53
|
* unix time in ms when the user can try again
|
|
54
54
|
*/
|
|
55
|
-
getRateLimit(key: string, now: number, limit: number, window: number)
|
|
55
|
+
getRateLimit: (key: string, now: number, limit: number, window: number) => MaybePromise<[number, number]>;
|
|
56
56
|
/**
|
|
57
57
|
* Reset a rate limit.
|
|
58
58
|
*
|
|
59
59
|
* @param key Key of the rate limit
|
|
60
60
|
*/
|
|
61
|
-
resetRateLimit(key: string)
|
|
61
|
+
resetRateLimit: (key: string) => MaybePromise<void>;
|
|
62
62
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../../../src/state/repository.ts"],"names":[],"mappings":"","sourcesContent":["import { MaybePromise } from '@mtcute/core'\n\n/**\n * Interface for FSM storage for the dispatcher.\n *\n * All of the officially supported storages already implement\n * this interface, so you can just re-use it.\n *\n * Current scene is a special case of a `string` state,\n * Most of the time you can just store it the same way\n * as normal state, prefixing with something like `$current_state_`\n * (scene name can't start with `$`).\n * Alternatively, you can store them as simple strings\n */\nexport interface IStateRepository {\n /**\n * Retrieve state from the storage\n * If state is not found or has expired, return `null`\n *\n * @param key Key of the state, as defined by {@link StateKeyDelegate}\n */\n getState(key: string, now: number)
|
|
1
|
+
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../../../src/state/repository.ts"],"names":[],"mappings":"","sourcesContent":["import type { MaybePromise } from '@mtcute/core'\n\n/**\n * Interface for FSM storage for the dispatcher.\n *\n * All of the officially supported storages already implement\n * this interface, so you can just re-use it.\n *\n * Current scene is a special case of a `string` state,\n * Most of the time you can just store it the same way\n * as normal state, prefixing with something like `$current_state_`\n * (scene name can't start with `$`).\n * Alternatively, you can store them as simple strings\n */\nexport interface IStateRepository {\n /**\n * Retrieve state from the storage\n * If state is not found or has expired, return `null`\n *\n * @param key Key of the state, as defined by {@link StateKeyDelegate}\n */\n getState: (key: string, now: number) => MaybePromise<string | null>\n\n /**\n * Save state to the storage\n *\n * @param key Key of the state, as defined by {@link StateKeyDelegate}\n * @param state String representing the state\n * @param ttl TTL for the state, in seconds\n */\n setState: (key: string, state: string, ttl?: number) => MaybePromise<void>\n\n /**\n * Delete state from the storage\n *\n * @param key Key of the state, as defined by {@link StateKeyDelegate}\n */\n deleteState: (key: string) => MaybePromise<void>\n\n /**\n * Clean up expired states and rate limits.\n *\n * @param now Current unix time in ms\n */\n vacuum: (now: number) => MaybePromise<void>\n\n /**\n * Get information about a rate limit.\n *\n * It is recommended that you use sliding window or leaky bucket\n * to implement rate limiting ([learn more](https://konghq.com/blog/how-to-design-a-scalable-rate-limiting-algorithm/)),\n *\n * @param key Key of the rate limit\n * @param now Current unix time in ms\n * @param limit Maximum number of requests in `window`\n * @param window Window size in seconds\n * @returns Tuple containing the number of remaining and\n * unix time in ms when the user can try again\n */\n getRateLimit: (key: string, now: number, limit: number, window: number) => MaybePromise<[number, number]>\n\n /**\n * Reset a rate limit.\n *\n * @param key Key of the rate limit\n */\n resetRateLimit: (key: string) => MaybePromise<void>\n}\n"]}
|
package/cjs/state/service.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { MaybePromise } from '@mtcute/core';
|
|
2
|
+
import type { IStateStorageProvider } from './provider.js';
|
|
2
3
|
export declare class StateService {
|
|
3
4
|
readonly provider: IStateStorageProvider;
|
|
4
5
|
constructor(provider: IStateStorageProvider);
|
|
@@ -14,6 +15,6 @@ export declare class StateService {
|
|
|
14
15
|
getCurrentScene(key: string): Promise<string | null>;
|
|
15
16
|
setCurrentScene(key: string, scene: string, ttl?: number): Promise<void>;
|
|
16
17
|
deleteCurrentScene(key: string): Promise<void>;
|
|
17
|
-
getRateLimit(key: string, limit: number, window: number):
|
|
18
|
-
resetRateLimit(key: string):
|
|
18
|
+
getRateLimit(key: string, limit: number, window: number): MaybePromise<[number, number]>;
|
|
19
|
+
resetRateLimit(key: string): MaybePromise<void>;
|
|
19
20
|
}
|
package/cjs/state/service.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/state/service.ts"],"names":[],"mappings":";;;AAAA,oDAA+D;
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/state/service.ts"],"names":[],"mappings":"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","sourcesContent":["import { LruMap, asyncResettable } from '@mtcute/core/utils.js'\nimport type { MaybePromise } from '@mtcute/core'\n\nimport type { IStateStorageProvider } from './provider.js'\n\nconst makeCurrentSceneKey = (key: string) => `$current_scene_${key}`\n\nexport class StateService {\n constructor(readonly provider: IStateStorageProvider) {}\n\n private _cache: LruMap<string, unknown> = new LruMap(100)\n private _vacuumTimer?: NodeJS.Timeout\n\n private _loaded = false\n private _load = asyncResettable(async () => {\n await this.provider.driver.load?.()\n this._loaded = true\n })\n\n async load(): Promise<void> {\n await this._load.run()\n this._vacuumTimer = setInterval(() => {\n Promise.resolve(this.provider.state.vacuum(Date.now())).catch(() => {})\n }, 300_000)\n }\n\n async destroy(): Promise<void> {\n await this.provider.driver.save?.()\n await this.provider.driver.destroy?.()\n clearInterval(this._vacuumTimer)\n this._loaded = false\n }\n\n async getState<T>(key: string): Promise<T | null> {\n if (!this._loaded) await this.load()\n\n const cached = this._cache.get(key)\n if (cached) return cached as T\n\n const state = await this.provider.state.getState(key, Date.now())\n if (!state) return null\n\n return JSON.parse(state) as T\n }\n\n async setState<T>(key: string, state: T, ttl?: number): Promise<void> {\n if (!this._loaded) await this.load()\n\n this._cache.set(key, state)\n await this.provider.state.setState(key, JSON.stringify(state), ttl)\n }\n\n async deleteState(key: string): Promise<void> {\n if (!this._loaded) await this.load()\n\n this._cache.delete(key)\n await this.provider.state.deleteState(key)\n }\n\n getCurrentScene(key: string): Promise<string | null> {\n return this.getState(makeCurrentSceneKey(key))\n }\n\n setCurrentScene(key: string, scene: string, ttl?: number): Promise<void> {\n return this.setState(makeCurrentSceneKey(key), scene, ttl)\n }\n\n deleteCurrentScene(key: string): Promise<void> {\n return this.deleteState(makeCurrentSceneKey(key))\n }\n\n getRateLimit(key: string, limit: number, window: number): MaybePromise<[number, number]> {\n return this.provider.state.getRateLimit(key, Date.now(), limit, window)\n }\n\n resetRateLimit(key: string): MaybePromise<void> {\n return this.provider.state.resetRateLimit(key)\n }\n}\n"]}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.UpdateState = exports.RateLimitError = void 0;
|
|
4
|
-
/* eslint-disable dot-notation */
|
|
5
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
6
4
|
const core_1 = require("@mtcute/core");
|
|
7
5
|
const utils_js_1 = require("@mtcute/core/utils.js");
|
|
8
6
|
/**
|
|
@@ -45,10 +43,11 @@ class UpdateState {
|
|
|
45
43
|
return this._scene;
|
|
46
44
|
}
|
|
47
45
|
_updateLocalKey() {
|
|
48
|
-
if (!this._scoped)
|
|
46
|
+
if (!this._scoped) {
|
|
49
47
|
this._localKey = this._localKeyBase;
|
|
48
|
+
}
|
|
50
49
|
else {
|
|
51
|
-
this._localKey = this._scene ? this._scene
|
|
50
|
+
this._localKey = this._scene ? `${this._scene}_${this._localKeyBase}` : this._localKeyBase;
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
53
|
async get(fallback, force) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-state.js","sourceRoot":"","sources":["../../../src/state/update-state.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable dot-notation */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { MtArgumentError, MtcuteError } from '@mtcute/core'\nimport { sleep } from '@mtcute/core/utils.js'\n\nimport type { Dispatcher } from '../dispatcher.js'\nimport { StateService } from './service.js'\n\n/**\n * Error thrown by `.rateLimit()`\n */\nexport class RateLimitError extends MtcuteError {\n constructor(readonly reset: number) {\n super('You are being rate limited.')\n }\n}\n\n/**\n * State of the current update.\n *\n * @template State Type that represents the state\n * @template SceneName Possible scene names\n */\nexport class UpdateState<State extends object> {\n private _key: string\n private _localKey!: string\n\n private _storage: StateService\n\n private _scene: string | null\n private _scoped?: boolean\n private _cached?: State | null\n\n private _localStorage: StateService\n private _localKeyBase: string\n\n constructor(\n storage: StateService,\n key: string,\n scene: string | null,\n scoped?: boolean,\n customStorage?: StateService,\n customKey?: string,\n ) {\n this._storage = storage\n this._key = key\n this._scene = scene\n this._scoped = scoped\n\n this._localStorage = customStorage ?? storage\n this._localKeyBase = customKey ?? key\n\n this._updateLocalKey()\n }\n\n /** Name of the current scene */\n get scene(): string | null {\n return this._scene\n }\n\n private _updateLocalKey(): void {\n if (!this._scoped) this._localKey = this._localKeyBase\n else {\n this._localKey = this._scene ? this._scene + '_' + this._localKeyBase : this._localKeyBase\n }\n }\n\n /**\n * Retrieve the state from the storage, falling back to default\n * if not found\n *\n * @param fallback Default state value\n * @param force Whether to ignore cached state (def. `false`)\n */\n async get(fallback: State | (() => State), force?: boolean): Promise<State>\n\n /**\n * Retrieve the state from the storage, falling back to default\n * if not found\n *\n * @param fallback Default state value\n * @param force Whether to ignore cached state (def. `false`)\n */\n async get(fallback?: State | (() => State), force?: boolean): Promise<State | null>\n /**\n * Retrieve the state from the storage\n *\n * @param force Whether to ignore cached state (def. `false`)\n */\n async get(force?: boolean): Promise<State | null>\n async get(fallback?: State | (() => State) | boolean, force?: boolean): Promise<State | null> {\n if (typeof fallback === 'boolean') {\n force = fallback\n fallback = undefined\n }\n\n if (!force && this._cached !== undefined) {\n if (!this._cached && fallback) {\n return typeof fallback === 'function' ? fallback() : fallback\n }\n\n return this._cached\n }\n\n let res = (await this._localStorage.getState(this._localKey)) as State | null\n\n if (!res && fallback) {\n res = typeof fallback === 'function' ? fallback() : fallback\n }\n this._cached = res\n\n return res\n }\n\n /**\n * Set new state to the storage\n *\n * @param state New state\n * @param ttl TTL for the new state (in seconds)\n */\n async set(state: State, ttl?: number): Promise<void> {\n this._cached = state\n await this._localStorage.setState(this._localKey, state, ttl)\n }\n\n /**\n * Merge the given object to the current state.\n *\n * > **Note**: If the storage currently has no state,\n * > then `fallback` must be provided.\n *\n * Basically a shorthand to calling `.get()`,\n * modifying and then calling `.set()`\n *\n * @param state State to be merged\n * @param fallback Default state\n * @param ttl TTL for the new state (in seconds)\n * @param forceLoad Whether to force load the old state from storage\n */\n async merge(\n state: Partial<State>,\n params: {\n fallback?: State | (() => State)\n ttl?: number\n forceLoad?: boolean\n } = {},\n ): Promise<State> {\n const { fallback, ttl, forceLoad } = params\n\n const old = await this.get(forceLoad)\n\n if (!old) {\n if (!fallback) {\n throw new MtArgumentError('Cannot use merge on empty state without fallback.')\n }\n\n const fallback_ = typeof fallback === 'function' ? fallback() : fallback\n\n await this.set({ ...fallback_, ...state }, ttl)\n } else {\n await this.set({ ...old, ...state }, ttl)\n }\n\n // _cached is set by .set()\n\n return this._cached!\n }\n\n /**\n * Delete the state from the storage\n */\n async delete(): Promise<void> {\n this._cached = null\n await this._localStorage.deleteState(this._localKey)\n }\n\n /**\n * Enter some scene\n */\n async enter<SceneState extends object, Scene extends Dispatcher<SceneState>>(\n scene: Scene,\n params?: {\n /**\n * Initial state for the scene\n *\n * Note that this will only work if the scene uses the same key delegate as this state.\n */\n with?: SceneState\n\n /** TTL for the scene (in seconds) */\n ttl?: number\n\n /**\n * If currently in a scoped scene, whether to reset the state\n *\n * @default true\n */\n reset?: boolean\n },\n ): Promise<void> {\n const { with: with_, ttl, reset = true } = params ?? {}\n\n if (reset && this._scoped) await this.delete()\n\n if (!scene['_scene']) {\n throw new MtArgumentError('Cannot enter a non-scene Dispatcher')\n }\n\n if (!scene['_parent']) {\n throw new MtArgumentError('This scene has not been registered')\n }\n\n this._scene = scene['_scene']\n this._scoped = scene['_sceneScoped']\n this._updateLocalKey()\n\n await this._storage.setCurrentScene(this._key, this._scene, ttl)\n\n if (with_) {\n if (scene['_customStateKeyDelegate']) {\n throw new MtArgumentError('Cannot use `with` parameter when the scene uses a custom state key delegate')\n }\n\n await scene.getState(this._key).set(with_, ttl)\n }\n }\n\n /**\n * Exit from current scene to the root\n *\n * @param reset\n * Whether to reset scene state (only applicable in case this is a scoped scene)\n */\n async exit(reset = true): Promise<void> {\n if (reset && this._scoped) await this.delete()\n this._scene = null\n this._updateLocalKey()\n await this._storage.deleteCurrentScene(this._key)\n }\n\n /**\n * Rate limit some handler.\n *\n * When the rate limit exceeds, {@link RateLimitError} is thrown.\n *\n * This is a simple rate-limiting solution that uses\n * the same key as the state. If you need something more\n * sophisticated and/or customizable, you'll have to implement\n * your own rate-limiter.\n *\n * > **Note**: `key` is used to prefix the local key\n * > derived using the given key delegate.\n *\n * @param key Key of the rate limit\n * @param limit Maximum number of requests in `window`\n * @param window Window size in seconds\n * @returns Tuple containing the number of remaining and\n * unix time in ms when the user can try again\n */\n async rateLimit(key: string, limit: number, window: number): Promise<[number, number]> {\n const [remaining, reset] = await this._localStorage.getRateLimit(`${key}:${this._localKey}`, limit, window)\n\n if (!remaining) {\n throw new RateLimitError(reset)\n }\n\n return [remaining - 1, reset]\n }\n\n /**\n * Throttle some handler.\n *\n * When the rate limit exceeds, this function waits for it to reset.\n *\n * This is a simple wrapper over {@link rateLimit}, and follows the same logic.\n *\n * > **Note**: `key` is used to prefix the local key\n * > derived using the given key delegate.\n *\n * @param key Key of the rate limit\n * @param limit Maximum number of requests in `window`\n * @param window Window size in seconds\n * @returns Tuple containing the number of remaining and\n * unix time in ms when the user can try again\n */\n async throttle(key: string, limit: number, window: number): Promise<[number, number]> {\n try {\n return await this.rateLimit(key, limit, window)\n } catch (e: unknown) {\n if (e instanceof RateLimitError) {\n await sleep(e.reset - Date.now())\n\n return this.throttle(key, limit, window)\n }\n\n throw e\n }\n }\n\n /**\n * Reset the rate limit\n *\n * @param key Key of the rate limit\n */\n async resetRateLimit(key: string): Promise<void> {\n await this._localStorage.resetRateLimit(`${key}:${this._localKey}`)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"update-state.js","sourceRoot":"","sources":["../../../src/state/update-state.ts"],"names":[],"mappings":"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","sourcesContent":["import { MtArgumentError, MtcuteError } from '@mtcute/core'\nimport { sleep } from '@mtcute/core/utils.js'\n\nimport type { Dispatcher } from '../dispatcher.js'\n\nimport type { StateService } from './service.js'\n\n/**\n * Error thrown by `.rateLimit()`\n */\nexport class RateLimitError extends MtcuteError {\n constructor(readonly reset: number) {\n super('You are being rate limited.')\n }\n}\n\n/**\n * State of the current update.\n *\n * @template State Type that represents the state\n * @template SceneName Possible scene names\n */\nexport class UpdateState<State extends object> {\n private _key: string\n private _localKey!: string\n\n private _storage: StateService\n\n private _scene: string | null\n private _scoped?: boolean\n private _cached?: State | null\n\n private _localStorage: StateService\n private _localKeyBase: string\n\n constructor(\n storage: StateService,\n key: string,\n scene: string | null,\n scoped?: boolean,\n customStorage?: StateService,\n customKey?: string,\n ) {\n this._storage = storage\n this._key = key\n this._scene = scene\n this._scoped = scoped\n\n this._localStorage = customStorage ?? storage\n this._localKeyBase = customKey ?? key\n\n this._updateLocalKey()\n }\n\n /** Name of the current scene */\n get scene(): string | null {\n return this._scene\n }\n\n private _updateLocalKey(): void {\n if (!this._scoped) {\n this._localKey = this._localKeyBase\n } else {\n this._localKey = this._scene ? `${this._scene}_${this._localKeyBase}` : this._localKeyBase\n }\n }\n\n /**\n * Retrieve the state from the storage, falling back to default\n * if not found\n *\n * @param fallback Default state value\n * @param force Whether to ignore cached state (def. `false`)\n */\n async get(fallback: State | (() => State), force?: boolean): Promise<State>\n\n /**\n * Retrieve the state from the storage, falling back to default\n * if not found\n *\n * @param fallback Default state value\n * @param force Whether to ignore cached state (def. `false`)\n */\n async get(fallback?: State | (() => State), force?: boolean): Promise<State | null>\n /**\n * Retrieve the state from the storage\n *\n * @param force Whether to ignore cached state (def. `false`)\n */\n async get(force?: boolean): Promise<State | null>\n async get(fallback?: State | (() => State) | boolean, force?: boolean): Promise<State | null> {\n if (typeof fallback === 'boolean') {\n force = fallback\n fallback = undefined\n }\n\n if (!force && this._cached !== undefined) {\n if (!this._cached && fallback) {\n return typeof fallback === 'function' ? fallback() : fallback\n }\n\n return this._cached\n }\n\n let res = (await this._localStorage.getState(this._localKey)) as State | null\n\n if (!res && fallback) {\n res = typeof fallback === 'function' ? fallback() : fallback\n }\n this._cached = res\n\n return res\n }\n\n /**\n * Set new state to the storage\n *\n * @param state New state\n * @param ttl TTL for the new state (in seconds)\n */\n async set(state: State, ttl?: number): Promise<void> {\n this._cached = state\n await this._localStorage.setState(this._localKey, state, ttl)\n }\n\n /**\n * Merge the given object to the current state.\n *\n * > **Note**: If the storage currently has no state,\n * > then `fallback` must be provided.\n *\n * Basically a shorthand to calling `.get()`,\n * modifying and then calling `.set()`\n *\n * @param state State to be merged\n * @param fallback Default state\n * @param ttl TTL for the new state (in seconds)\n * @param forceLoad Whether to force load the old state from storage\n */\n async merge(\n state: Partial<State>,\n params: {\n fallback?: State | (() => State)\n ttl?: number\n forceLoad?: boolean\n } = {},\n ): Promise<State> {\n const { fallback, ttl, forceLoad } = params\n\n const old = await this.get(forceLoad)\n\n if (!old) {\n if (!fallback) {\n throw new MtArgumentError('Cannot use merge on empty state without fallback.')\n }\n\n const fallback_ = typeof fallback === 'function' ? fallback() : fallback\n\n await this.set({ ...fallback_, ...state }, ttl)\n } else {\n await this.set({ ...old, ...state }, ttl)\n }\n\n // _cached is set by .set()\n\n return this._cached!\n }\n\n /**\n * Delete the state from the storage\n */\n async delete(): Promise<void> {\n this._cached = null\n await this._localStorage.deleteState(this._localKey)\n }\n\n /**\n * Enter some scene\n */\n async enter<SceneState extends object, Scene extends Dispatcher<SceneState>>(\n scene: Scene,\n params?: {\n /**\n * Initial state for the scene\n *\n * Note that this will only work if the scene uses the same key delegate as this state.\n */\n with?: SceneState\n\n /** TTL for the scene (in seconds) */\n ttl?: number\n\n /**\n * If currently in a scoped scene, whether to reset the state\n *\n * @default true\n */\n reset?: boolean\n },\n ): Promise<void> {\n const { with: with_, ttl, reset = true } = params ?? {}\n\n if (reset && this._scoped) await this.delete()\n\n if (!scene['_scene']) {\n throw new MtArgumentError('Cannot enter a non-scene Dispatcher')\n }\n\n if (!scene['_parent']) {\n throw new MtArgumentError('This scene has not been registered')\n }\n\n this._scene = scene['_scene']\n this._scoped = scene['_sceneScoped']\n this._updateLocalKey()\n\n await this._storage.setCurrentScene(this._key, this._scene, ttl)\n\n if (with_) {\n if (scene['_customStateKeyDelegate']) {\n throw new MtArgumentError('Cannot use `with` parameter when the scene uses a custom state key delegate')\n }\n\n await scene.getState(this._key).set(with_, ttl)\n }\n }\n\n /**\n * Exit from current scene to the root\n *\n * @param reset\n * Whether to reset scene state (only applicable in case this is a scoped scene)\n */\n async exit(reset = true): Promise<void> {\n if (reset && this._scoped) await this.delete()\n this._scene = null\n this._updateLocalKey()\n await this._storage.deleteCurrentScene(this._key)\n }\n\n /**\n * Rate limit some handler.\n *\n * When the rate limit exceeds, {@link RateLimitError} is thrown.\n *\n * This is a simple rate-limiting solution that uses\n * the same key as the state. If you need something more\n * sophisticated and/or customizable, you'll have to implement\n * your own rate-limiter.\n *\n * > **Note**: `key` is used to prefix the local key\n * > derived using the given key delegate.\n *\n * @param key Key of the rate limit\n * @param limit Maximum number of requests in `window`\n * @param window Window size in seconds\n * @returns Tuple containing the number of remaining and\n * unix time in ms when the user can try again\n */\n async rateLimit(key: string, limit: number, window: number): Promise<[number, number]> {\n const [remaining, reset] = await this._localStorage.getRateLimit(`${key}:${this._localKey}`, limit, window)\n\n if (!remaining) {\n throw new RateLimitError(reset)\n }\n\n return [remaining - 1, reset]\n }\n\n /**\n * Throttle some handler.\n *\n * When the rate limit exceeds, this function waits for it to reset.\n *\n * This is a simple wrapper over {@link rateLimit}, and follows the same logic.\n *\n * > **Note**: `key` is used to prefix the local key\n * > derived using the given key delegate.\n *\n * @param key Key of the rate limit\n * @param limit Maximum number of requests in `window`\n * @param window Window size in seconds\n * @returns Tuple containing the number of remaining and\n * unix time in ms when the user can try again\n */\n async throttle(key: string, limit: number, window: number): Promise<[number, number]> {\n try {\n return await this.rateLimit(key, limit, window)\n } catch (e: unknown) {\n if (e instanceof RateLimitError) {\n await sleep(e.reset - Date.now())\n\n return this.throttle(key, limit, window)\n }\n\n throw e\n }\n }\n\n /**\n * Reset the rate limit\n *\n * @param key Key of the rate limit\n */\n async resetRateLimit(key: string): Promise<void> {\n await this._localStorage.resetRateLimit(`${key}:${this._localKey}`)\n }\n}\n"]}
|
package/cjs/wizard.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { MaybePromise } from '@mtcute/core';
|
|
2
|
-
import { MessageContext } from './context/message.js';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import type { MaybePromise } from '@mtcute/core';
|
|
2
|
+
import type { MessageContext } from './context/message.js';
|
|
3
|
+
import type { DispatcherParams } from './dispatcher.js';
|
|
4
|
+
import { Dispatcher } from './dispatcher.js';
|
|
5
|
+
import type { UpdateFilter } from './filters/index.js';
|
|
6
|
+
import type { UpdateState } from './state/update-state.js';
|
|
6
7
|
/**
|
|
7
8
|
* Action for the wizard scene.
|
|
8
9
|
*
|
|
@@ -51,11 +52,11 @@ export declare class WizardScene<State extends object> extends Dispatcher<State
|
|
|
51
52
|
/**
|
|
52
53
|
* Filter that will only pass if the current step is `step`
|
|
53
54
|
*/
|
|
54
|
-
static onNthStep(step: number):
|
|
55
|
+
static onNthStep(step: number): UpdateFilter<any, {}, WizardInternalState>;
|
|
55
56
|
/**
|
|
56
57
|
* Filter that will only pass if the current step is the one after last one added
|
|
57
58
|
*/
|
|
58
|
-
onCurrentStep():
|
|
59
|
+
onCurrentStep(): UpdateFilter<any, {}, WizardInternalState>;
|
|
59
60
|
/**
|
|
60
61
|
* Add a step to the wizard
|
|
61
62
|
*/
|
package/cjs/wizard.js
CHANGED
|
@@ -64,8 +64,9 @@ class WizardScene extends dispatcher_js_1.Dispatcher {
|
|
|
64
64
|
/**
|
|
65
65
|
* Filter that will only pass if the current step is `step`
|
|
66
66
|
*/
|
|
67
|
+
// eslint-disable-next-line ts/no-empty-object-type
|
|
67
68
|
static onNthStep(step) {
|
|
68
|
-
const filter = index_js_1.filters.state(
|
|
69
|
+
const filter = index_js_1.filters.state(it => it.$step === step);
|
|
69
70
|
if (step === 0)
|
|
70
71
|
return index_js_1.filters.or(index_js_1.filters.stateEmpty, filter);
|
|
71
72
|
return filter;
|
|
@@ -73,6 +74,7 @@ class WizardScene extends dispatcher_js_1.Dispatcher {
|
|
|
73
74
|
/**
|
|
74
75
|
* Filter that will only pass if the current step is the one after last one added
|
|
75
76
|
*/
|
|
77
|
+
// eslint-disable-next-line ts/no-empty-object-type
|
|
76
78
|
onCurrentStep() {
|
|
77
79
|
return WizardScene.onNthStep(this._steps);
|
|
78
80
|
}
|
package/cjs/wizard.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wizard.js","sourceRoot":"","sources":["../../src/wizard.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"wizard.js","sourceRoot":"","sources":["../../src/wizard.ts"],"names":[],"mappings":"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","sourcesContent":["import type { MaybePromise } from '@mtcute/core'\n\nimport type { MessageContext } from './context/message.js'\nimport type { DispatcherParams } from './dispatcher.js'\nimport { Dispatcher } from './dispatcher.js'\nimport type { UpdateFilter } from './filters/index.js'\nimport { filters } from './filters/index.js'\nimport type { UpdateState } from './state/update-state.js'\n\n/**\n * Action for the wizard scene.\n *\n * `Next`: Continue to the next registered step\n * (or exit, if this is the last step)\n *\n * `Stay`: Stay on the same step\n *\n * `Exit`: Exit from the wizard scene\n *\n * You can also return a `number` to jump to that step\n */\nexport enum WizardSceneAction {\n Next = 'next',\n Stay = 'stay',\n Exit = 'exit',\n}\n\ninterface WizardInternalState {\n $step?: number\n}\n\n/**\n * Wizard is a special type of Dispatcher\n * that can be used to simplify implementing\n * step-by-step scenes.\n */\nexport class WizardScene<State extends object> extends Dispatcher<State & WizardInternalState> {\n private _steps = 0\n\n private _defaultState: State & WizardInternalState = {} as State & WizardInternalState\n\n constructor(name: string, params?: Omit<DispatcherParams, 'sceneName'>) {\n super(undefined, { sceneName: name, ...params })\n }\n\n // remove inherited statics from Dispatcher\n declare static for: never\n declare static child: never\n declare static scene: never\n\n setDefaultState(defaultState: State): void {\n this._defaultState = defaultState as State & WizardInternalState\n }\n\n /**\n * Get the total number of registered steps\n */\n get totalSteps(): number {\n return this._steps\n }\n\n /**\n * Go to the Nth step\n */\n async goToStep(state: UpdateState<WizardInternalState>, step: number): Promise<void> {\n if (step >= this._steps) {\n await state.exit()\n } else {\n await state.merge({ $step: step }, this._defaultState)\n }\n }\n\n /**\n * Skip N steps\n */\n async skip(state: UpdateState<WizardInternalState>, count = 1): Promise<void> {\n const { $step } = (await state.get()) || {}\n if ($step === undefined) throw new Error('Wizard state is not initialized')\n\n return this.goToStep(state, $step + count)\n }\n\n /**\n * Filter that will only pass if the current step is `step`\n */\n // eslint-disable-next-line ts/no-empty-object-type\n static onNthStep(step: number): UpdateFilter<any, {}, WizardInternalState> {\n const filter = filters.state<WizardInternalState>(it => it.$step === step)\n\n if (step === 0) return filters.or(filters.stateEmpty, filter)\n\n return filter\n }\n\n /**\n * Filter that will only pass if the current step is the one after last one added\n */\n // eslint-disable-next-line ts/no-empty-object-type\n onCurrentStep(): UpdateFilter<any, {}, WizardInternalState> {\n return WizardScene.onNthStep(this._steps)\n }\n\n /**\n * Add a step to the wizard\n */\n addStep(\n handler: (\n msg: MessageContext,\n state: UpdateState<State & WizardInternalState>,\n ) => MaybePromise<WizardSceneAction | number>,\n ): void {\n const step = this._steps++\n\n this.onNewMessage(WizardScene.onNthStep(step), async (msg, state) => {\n const result = await handler(msg, state)\n\n if (typeof result === 'number') {\n await this.goToStep(state, result)\n\n return\n }\n\n switch (result) {\n case 'next': {\n await this.goToStep(state, step + 1)\n break\n }\n case 'exit':\n await state.exit()\n break\n }\n })\n }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BusinessCallbackQuery, CallbackQuery, InlineCallbackQuery, MaybeArray, MaybePromise } from '@mtcute/core';
|
|
2
|
-
import { UpdateFilter } from './filters/types.js';
|
|
1
|
+
import type { BusinessCallbackQuery, CallbackQuery, InlineCallbackQuery, MaybeArray, MaybePromise } from '@mtcute/core';
|
|
2
|
+
import type { UpdateFilter } from './filters/types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Callback data builder, inspired by [aiogram](https://github.com/aiogram/aiogram).
|
|
5
5
|
*
|
|
@@ -24,9 +24,9 @@ export class CallbackDataBuilder {
|
|
|
24
24
|
* @param obj Object containing the data
|
|
25
25
|
*/
|
|
26
26
|
build(obj) {
|
|
27
|
-
const ret = this.prefix
|
|
28
|
-
this.sep
|
|
29
|
-
this._fields
|
|
27
|
+
const ret = this.prefix
|
|
28
|
+
+ this.sep
|
|
29
|
+
+ this._fields
|
|
30
30
|
.map((f) => {
|
|
31
31
|
const val = obj[f];
|
|
32
32
|
if (val.includes(this.sep)) {
|
|
@@ -99,8 +99,9 @@ export class CallbackDataBuilder {
|
|
|
99
99
|
if (value !== matcher)
|
|
100
100
|
return false;
|
|
101
101
|
}
|
|
102
|
-
else if (!matcher.test(value))
|
|
102
|
+
else if (!matcher.test(value)) {
|
|
103
103
|
return false;
|
|
104
|
+
}
|
|
104
105
|
}
|
|
105
106
|
}
|
|
106
107
|
query.match = data;
|
|
@@ -115,7 +116,7 @@ export class CallbackDataBuilder {
|
|
|
115
116
|
}
|
|
116
117
|
const value = params[field];
|
|
117
118
|
if (Array.isArray(value)) {
|
|
118
|
-
parts.push(`(${value.map(
|
|
119
|
+
parts.push(`(${value.map(i => (typeof i === 'string' ? i : i.source)).join('|')})`);
|
|
119
120
|
}
|
|
120
121
|
else {
|
|
121
122
|
// noinspection SuspiciousTypeOfGuard
|
|
@@ -125,8 +126,9 @@ export class CallbackDataBuilder {
|
|
|
125
126
|
const regex = new RegExp(`^${this.prefix}${this.sep}${parts.join(this.sep)}$`);
|
|
126
127
|
return (query) => {
|
|
127
128
|
const m = query.dataStr?.match(regex);
|
|
128
|
-
if (!m)
|
|
129
|
+
if (!m) {
|
|
129
130
|
return false;
|
|
131
|
+
}
|
|
130
132
|
query.match = this.parse(m[0]);
|
|
131
133
|
return true;
|
|
132
134
|
};
|
|
@@ -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 {\n BusinessCallbackQuery,\n CallbackQuery,\n InlineCallbackQuery,\n MaybeArray,\n MaybePromise,\n MtArgumentError,\n} 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 | BusinessCallbackQuery>(\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"]}
|
|
1
|
+
{"version":3,"file":"callback-data-builder.js","sourceRoot":"","sources":["../../src/callback-data-builder.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n BusinessCallbackQuery,\n CallbackQuery,\n InlineCallbackQuery,\n MaybeArray,\n MaybePromise,\n} from '@mtcute/core'\nimport {\n MtArgumentError,\n} from '@mtcute/core'\n\nimport type { 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 | BusinessCallbackQuery>(\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)) {\n return false\n }\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) {\n 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"]}
|
package/esm/context/base.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ParsedUpdate } from '@mtcute/core';
|
|
2
|
-
import { TelegramClient } from '@mtcute/core/client.js';
|
|
1
|
+
import type { ParsedUpdate } from '@mtcute/core';
|
|
2
|
+
import type { TelegramClient } from '@mtcute/core/client.js';
|
|
3
3
|
export type UpdateContext<T> = T & {
|
|
4
4
|
client: TelegramClient;
|
|
5
5
|
_name: Extract<ParsedUpdate, {
|
package/esm/context/base.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/context/base.ts"],"names":[],"mappings":"","sourcesContent":["import { ParsedUpdate } from '@mtcute/core'\nimport { TelegramClient } from '@mtcute/core/client.js'\n\nexport type UpdateContext<T> = T & {\n client: TelegramClient\n _name: Extract<ParsedUpdate, { data: T }>['name']\n}\n\nexport type UpdateContextDistributed<T> = T extends never ? never : UpdateContext<T>\n"]}
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/context/base.ts"],"names":[],"mappings":"","sourcesContent":["import type { ParsedUpdate } from '@mtcute/core'\nimport type { TelegramClient } from '@mtcute/core/client.js'\n\nexport type UpdateContext<T> = T & {\n client: TelegramClient\n _name: Extract<ParsedUpdate, { data: T }>['name']\n}\n\nexport type UpdateContextDistributed<T> = T extends never ? never : UpdateContext<T>\n"]}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import type { Message, OmitInputMessageId, ParametersSkip1, Sticker } from '@mtcute/core';
|
|
2
|
+
import { BusinessMessage } from '@mtcute/core';
|
|
3
|
+
import type { TelegramClient } from '@mtcute/core/client.js';
|
|
4
|
+
import type { DeleteMessagesParams, ForwardMessageOptions, SendCopyGroupParams, SendCopyParams } from '@mtcute/core/methods.js';
|
|
5
|
+
import type { UpdateContext } from './base.js';
|
|
5
6
|
/**
|
|
6
7
|
* Context of a business message related update.
|
|
7
8
|
*
|
|
@@ -24,37 +25,37 @@ export declare class BusinessMessageContext extends BusinessMessage implements U
|
|
|
24
25
|
readonly isMessageGroup: boolean;
|
|
25
26
|
constructor(client: TelegramClient, message: BusinessMessage | BusinessMessage[]);
|
|
26
27
|
/** Get all custom emojis contained in this message (message group), if any */
|
|
27
|
-
getCustomEmojis(): Promise<
|
|
28
|
+
getCustomEmojis(): Promise<Sticker[]>;
|
|
28
29
|
/** Send a text message to the same chat (and topic, if applicable) as a given message */
|
|
29
|
-
answerText(...params: ParametersSkip1<TelegramClient['answerText']>): Promise<
|
|
30
|
+
answerText(...params: ParametersSkip1<TelegramClient['answerText']>): Promise<Message>;
|
|
30
31
|
/** Send a media to the same chat (and topic, if applicable) as a given message */
|
|
31
|
-
answerMedia(...params: ParametersSkip1<TelegramClient['answerMedia']>): Promise<
|
|
32
|
+
answerMedia(...params: ParametersSkip1<TelegramClient['answerMedia']>): Promise<Message>;
|
|
32
33
|
/** Send a media group to the same chat (and topic, if applicable) as a given message */
|
|
33
|
-
answerMediaGroup(...params: ParametersSkip1<TelegramClient['answerMediaGroup']>): Promise<
|
|
34
|
+
answerMediaGroup(...params: ParametersSkip1<TelegramClient['answerMediaGroup']>): Promise<Message[]>;
|
|
34
35
|
/** Send a text message in reply to this message */
|
|
35
|
-
replyText(...params: ParametersSkip1<TelegramClient['replyText']>): Promise<
|
|
36
|
+
replyText(...params: ParametersSkip1<TelegramClient['replyText']>): Promise<Message>;
|
|
36
37
|
/** Send a media in reply to this message */
|
|
37
|
-
replyMedia(...params: ParametersSkip1<TelegramClient['replyMedia']>): Promise<
|
|
38
|
+
replyMedia(...params: ParametersSkip1<TelegramClient['replyMedia']>): Promise<Message>;
|
|
38
39
|
/** Send a media group in reply to this message */
|
|
39
|
-
replyMediaGroup(...params: ParametersSkip1<TelegramClient['replyMediaGroup']>): Promise<
|
|
40
|
+
replyMediaGroup(...params: ParametersSkip1<TelegramClient['replyMediaGroup']>): Promise<Message[]>;
|
|
40
41
|
/** Send a text message in reply to this message */
|
|
41
|
-
quoteWithText(params: Parameters<TelegramClient['quoteWithText']>[1]): Promise<
|
|
42
|
+
quoteWithText(params: Parameters<TelegramClient['quoteWithText']>[1]): Promise<Message>;
|
|
42
43
|
/** Send a media in reply to this message */
|
|
43
|
-
quoteWithMedia(params: Parameters<TelegramClient['quoteWithMedia']>[1]): Promise<
|
|
44
|
+
quoteWithMedia(params: Parameters<TelegramClient['quoteWithMedia']>[1]): Promise<Message>;
|
|
44
45
|
/** Send a media group in reply to this message */
|
|
45
|
-
quoteWithMediaGroup(params: Parameters<TelegramClient['quoteWithMediaGroup']>[1]): Promise<
|
|
46
|
+
quoteWithMediaGroup(params: Parameters<TelegramClient['quoteWithMediaGroup']>[1]): Promise<Message[]>;
|
|
46
47
|
/** Delete this message (message group) */
|
|
47
48
|
delete(params?: DeleteMessagesParams): Promise<void>;
|
|
48
49
|
/** Pin this message */
|
|
49
|
-
pin(params?: OmitInputMessageId<Parameters<TelegramClient['pinMessage']>[0]>): Promise<
|
|
50
|
+
pin(params?: OmitInputMessageId<Parameters<TelegramClient['pinMessage']>[0]>): Promise<Message | null>;
|
|
50
51
|
/** Unpin this message */
|
|
51
52
|
unpin(): Promise<void>;
|
|
52
53
|
/** Edit this message */
|
|
53
|
-
edit(params: OmitInputMessageId<Parameters<TelegramClient['editMessage']>[0]>): Promise<
|
|
54
|
+
edit(params: OmitInputMessageId<Parameters<TelegramClient['editMessage']>[0]>): Promise<Message>;
|
|
54
55
|
/** Forward this message (message group) */
|
|
55
|
-
forwardTo(params: ForwardMessageOptions): Promise<
|
|
56
|
+
forwardTo(params: ForwardMessageOptions): Promise<Message[]>;
|
|
56
57
|
/** Send a copy of this message (message group) */
|
|
57
|
-
copy(params: SendCopyParams & SendCopyGroupParams): Promise<
|
|
58
|
+
copy(params: SendCopyParams & SendCopyGroupParams): Promise<Message | Message[]>;
|
|
58
59
|
/** React to this message */
|
|
59
|
-
react(params: OmitInputMessageId<Parameters<TelegramClient['sendReaction']>[0]>): Promise<
|
|
60
|
+
react(params: OmitInputMessageId<Parameters<TelegramClient['sendReaction']>[0]>): Promise<Message | null>;
|
|
60
61
|
}
|
|
@@ -24,7 +24,7 @@ export class BusinessMessageContext extends BusinessMessage {
|
|
|
24
24
|
const msg = Array.isArray(message) ? message[message.length - 1] : message;
|
|
25
25
|
super(msg.update, msg._peers);
|
|
26
26
|
this.client = client;
|
|
27
|
-
this.messages = Array.isArray(message) ? message.map(
|
|
27
|
+
this.messages = Array.isArray(message) ? message.map(it => new BusinessMessageContext(client, it)) : [this];
|
|
28
28
|
this.isMessageGroup = Array.isArray(message);
|
|
29
29
|
}
|
|
30
30
|
/** Get all custom emojis contained in this message (message group), if any */
|
|
@@ -84,7 +84,7 @@ export class BusinessMessageContext extends BusinessMessage {
|
|
|
84
84
|
}
|
|
85
85
|
/** Delete this message (message group) */
|
|
86
86
|
delete(params) {
|
|
87
|
-
return this.client.deleteMessagesById(this.chat.inputPeer, this.messages.map(
|
|
87
|
+
return this.client.deleteMessagesById(this.chat.inputPeer, this.messages.map(it => it.id), params);
|
|
88
88
|
}
|
|
89
89
|
/** Pin this message */
|
|
90
90
|
pin(params) {
|
|
@@ -113,7 +113,7 @@ export class BusinessMessageContext extends BusinessMessage {
|
|
|
113
113
|
forwardTo(params) {
|
|
114
114
|
return this.client.forwardMessagesById({
|
|
115
115
|
fromChatId: this.chat.inputPeer,
|
|
116
|
-
messages: this.messages.map(
|
|
116
|
+
messages: this.messages.map(it => it.id),
|
|
117
117
|
...params,
|
|
118
118
|
});
|
|
119
119
|
}
|