@xbibzlibrary/telebibz 0.4.4 → 3.0.1
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/CHANGELOG.md +35 -138
- package/LICENSE +1 -1
- package/NOTICE.md +9 -4
- package/README.md +173 -242
- package/examples/01-quickstart.js +13 -0
- package/examples/02-menu-tombol.js +22 -0
- package/examples/03-wizard.js +29 -0
- package/examples/04-broadcast.js +25 -0
- package/examples/05-kirim-file.js +19 -0
- package/examples/06-menu.js +35 -0
- package/examples/07-inline-query.js +18 -0
- package/index.d.ts +81 -0
- package/index.js +42 -0
- package/lib/api.js +154 -0
- package/lib/broadcast.js +35 -0
- package/lib/composer.js +174 -0
- package/lib/context.js +190 -0
- package/lib/errors.js +35 -0
- package/lib/file.js +41 -0
- package/lib/inline-query.js +28 -0
- package/lib/keyboard.js +83 -0
- package/lib/logger.js +38 -0
- package/lib/menus.js +90 -0
- package/lib/net.js +115 -0
- package/lib/ratelimit.js +61 -0
- package/lib/runner.js +45 -0
- package/lib/session.js +36 -0
- package/lib/telebibz.js +190 -0
- package/lib/wizard.js +81 -0
- package/package.json +35 -97
- package/test/all.test.js +334 -0
- package/CODE_OF_CONDUCT.md +0 -37
- package/CONTRIBUTING.md +0 -59
- package/CONTRIBUTION_RULES.md +0 -41
- package/GOVERNANCE.md +0 -47
- package/README.id.md +0 -292
- package/README.zh-CN.md +0 -292
- package/RELEASE_AUTOMATION.md +0 -78
- package/RELEASE_POLICY.md +0 -32
- package/SECURITY.md +0 -47
- package/SHOWCASE.md +0 -29
- package/SUPPORT.md +0 -30
- package/assets/readme-preview.html +0 -75
- package/assets/telebibz-logo.png +0 -0
- package/assets/telebibz-readme-preview.png +0 -0
- package/bin/telebibz.mjs +0 -3
- package/dist/generated/api.d.ts +0 -13
- package/dist/generated/api.d.ts.map +0 -1
- package/dist/generated/api.js +0 -192
- package/dist/generated/api.js.map +0 -1
- package/dist/src/api/client.d.ts +0 -62
- package/dist/src/api/client.d.ts.map +0 -1
- package/dist/src/api/client.js +0 -104
- package/dist/src/api/client.js.map +0 -1
- package/dist/src/api/errors.d.ts +0 -45
- package/dist/src/api/errors.d.ts.map +0 -1
- package/dist/src/api/errors.js +0 -65
- package/dist/src/api/errors.js.map +0 -1
- package/dist/src/api/index.d.ts +0 -6
- package/dist/src/api/index.d.ts.map +0 -1
- package/dist/src/api/index.js +0 -6
- package/dist/src/api/index.js.map +0 -1
- package/dist/src/api/telegram-types/LICENSE +0 -21
- package/dist/src/api/telegram-types/api.d.ts +0 -22
- package/dist/src/api/telegram-types/checklist.d.ts +0 -72
- package/dist/src/api/telegram-types/inline.d.ts +0 -692
- package/dist/src/api/telegram-types/langs.d.ts +0 -193
- package/dist/src/api/telegram-types/manage.d.ts +0 -1144
- package/dist/src/api/telegram-types/markup.d.ts +0 -268
- package/dist/src/api/telegram-types/message.d.ts +0 -1537
- package/dist/src/api/telegram-types/methods.d.ts +0 -2870
- package/dist/src/api/telegram-types/mod.d.ts +0 -14
- package/dist/src/api/telegram-types/passport.d.ts +0 -163
- package/dist/src/api/telegram-types/payment.d.ts +0 -570
- package/dist/src/api/telegram-types/rich.d.ts +0 -1010
- package/dist/src/api/telegram-types/settings.d.ts +0 -120
- package/dist/src/api/telegram-types/story.d.ts +0 -89
- package/dist/src/api/telegram-types/update.d.ts +0 -84
- package/dist/src/api/telegram.d.ts +0 -7
- package/dist/src/api/telegram.d.ts.map +0 -1
- package/dist/src/api/telegram.js +0 -2
- package/dist/src/api/telegram.js.map +0 -1
- package/dist/src/api/transport.d.ts +0 -68
- package/dist/src/api/transport.d.ts.map +0 -1
- package/dist/src/api/transport.js +0 -264
- package/dist/src/api/transport.js.map +0 -1
- package/dist/src/api/types.d.ts +0 -466
- package/dist/src/api/types.d.ts.map +0 -1
- package/dist/src/api/types.js +0 -2
- package/dist/src/api/types.js.map +0 -1
- package/dist/src/branding/terminal.d.ts +0 -77
- package/dist/src/branding/terminal.d.ts.map +0 -1
- package/dist/src/branding/terminal.js +0 -328
- package/dist/src/branding/terminal.js.map +0 -1
- package/dist/src/broadcast/broadcast.d.ts +0 -50
- package/dist/src/broadcast/broadcast.d.ts.map +0 -1
- package/dist/src/broadcast/broadcast.js +0 -56
- package/dist/src/broadcast/broadcast.js.map +0 -1
- package/dist/src/cache/cache.d.ts +0 -34
- package/dist/src/cache/cache.d.ts.map +0 -1
- package/dist/src/cache/cache.js +0 -41
- package/dist/src/cache/cache.js.map +0 -1
- package/dist/src/cli.d.ts +0 -2
- package/dist/src/cli.d.ts.map +0 -1
- package/dist/src/cli.js +0 -84
- package/dist/src/cli.js.map +0 -1
- package/dist/src/context/context.d.ts +0 -124
- package/dist/src/context/context.d.ts.map +0 -1
- package/dist/src/context/context.js +0 -302
- package/dist/src/context/context.js.map +0 -1
- package/dist/src/core/bot.d.ts +0 -204
- package/dist/src/core/bot.d.ts.map +0 -1
- package/dist/src/core/bot.js +0 -506
- package/dist/src/core/bot.js.map +0 -1
- package/dist/src/core/events.d.ts +0 -75
- package/dist/src/core/events.d.ts.map +0 -1
- package/dist/src/core/events.js +0 -35
- package/dist/src/core/events.js.map +0 -1
- package/dist/src/core/webhook-reply.d.ts +0 -34
- package/dist/src/core/webhook-reply.d.ts.map +0 -1
- package/dist/src/core/webhook-reply.js +0 -37
- package/dist/src/core/webhook-reply.js.map +0 -1
- package/dist/src/index.d.ts +0 -24
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js +0 -24
- package/dist/src/index.js.map +0 -1
- package/dist/src/keyboard/index.d.ts +0 -46
- package/dist/src/keyboard/index.d.ts.map +0 -1
- package/dist/src/keyboard/index.js +0 -55
- package/dist/src/keyboard/index.js.map +0 -1
- package/dist/src/middleware/compose.d.ts +0 -5
- package/dist/src/middleware/compose.d.ts.map +0 -1
- package/dist/src/middleware/compose.js +0 -17
- package/dist/src/middleware/compose.js.map +0 -1
- package/dist/src/observability/logger.d.ts +0 -78
- package/dist/src/observability/logger.d.ts.map +0 -1
- package/dist/src/observability/logger.js +0 -285
- package/dist/src/observability/logger.js.map +0 -1
- package/dist/src/plugins/plugin.d.ts +0 -38
- package/dist/src/plugins/plugin.d.ts.map +0 -1
- package/dist/src/plugins/plugin.js +0 -59
- package/dist/src/plugins/plugin.js.map +0 -1
- package/dist/src/queue/queue.d.ts +0 -77
- package/dist/src/queue/queue.d.ts.map +0 -1
- package/dist/src/queue/queue.js +0 -213
- package/dist/src/queue/queue.js.map +0 -1
- package/dist/src/router/router.d.ts +0 -61
- package/dist/src/router/router.d.ts.map +0 -1
- package/dist/src/router/router.js +0 -183
- package/dist/src/router/router.js.map +0 -1
- package/dist/src/state/conversation.d.ts +0 -56
- package/dist/src/state/conversation.d.ts.map +0 -1
- package/dist/src/state/conversation.js +0 -133
- package/dist/src/state/conversation.js.map +0 -1
- package/dist/src/state/forms.d.ts +0 -34
- package/dist/src/state/forms.d.ts.map +0 -1
- package/dist/src/state/forms.js +0 -44
- package/dist/src/state/forms.js.map +0 -1
- package/dist/src/state/menu.d.ts +0 -78
- package/dist/src/state/menu.d.ts.map +0 -1
- package/dist/src/state/menu.js +0 -127
- package/dist/src/state/menu.js.map +0 -1
- package/dist/src/storage/storage.d.ts +0 -146
- package/dist/src/storage/storage.d.ts.map +0 -1
- package/dist/src/storage/storage.js +0 -195
- package/dist/src/storage/storage.js.map +0 -1
- package/dist/src/telegram-features.d.ts +0 -33
- package/dist/src/telegram-features.d.ts.map +0 -1
- package/dist/src/telegram-features.js +0 -71
- package/dist/src/telegram-features.js.map +0 -1
- package/dist/src/testing.d.ts +0 -24
- package/dist/src/testing.d.ts.map +0 -1
- package/dist/src/testing.js +0 -38
- package/dist/src/testing.js.map +0 -1
- package/dist/src/utils/concurrency.d.ts +0 -25
- package/dist/src/utils/concurrency.d.ts.map +0 -1
- package/dist/src/utils/concurrency.js +0 -52
- package/dist/src/utils/concurrency.js.map +0 -1
- package/dist/src/utils/files.d.ts +0 -45
- package/dist/src/utils/files.d.ts.map +0 -1
- package/dist/src/utils/files.js +0 -53
- package/dist/src/utils/files.js.map +0 -1
- package/dist/src/utils/text.d.ts +0 -39
- package/dist/src/utils/text.d.ts.map +0 -1
- package/dist/src/utils/text.js +0 -56
- package/dist/src/utils/text.js.map +0 -1
- package/dist/src/webhook/handler.d.ts +0 -19
- package/dist/src/webhook/handler.d.ts.map +0 -1
- package/dist/src/webhook/handler.js +0 -141
- package/dist/src/webhook/handler.js.map +0 -1
- package/dist-cjs/generated/api.js +0 -194
- package/dist-cjs/package.json +0 -3
- package/dist-cjs/src/api/client.js +0 -107
- package/dist-cjs/src/api/errors.js +0 -74
- package/dist-cjs/src/api/index.js +0 -21
- package/dist-cjs/src/api/telegram-types/LICENSE +0 -21
- package/dist-cjs/src/api/telegram-types/api.d.ts +0 -22
- package/dist-cjs/src/api/telegram-types/checklist.d.ts +0 -72
- package/dist-cjs/src/api/telegram-types/inline.d.ts +0 -692
- package/dist-cjs/src/api/telegram-types/langs.d.ts +0 -193
- package/dist-cjs/src/api/telegram-types/manage.d.ts +0 -1144
- package/dist-cjs/src/api/telegram-types/markup.d.ts +0 -268
- package/dist-cjs/src/api/telegram-types/message.d.ts +0 -1537
- package/dist-cjs/src/api/telegram-types/methods.d.ts +0 -2870
- package/dist-cjs/src/api/telegram-types/mod.d.ts +0 -14
- package/dist-cjs/src/api/telegram-types/passport.d.ts +0 -163
- package/dist-cjs/src/api/telegram-types/payment.d.ts +0 -570
- package/dist-cjs/src/api/telegram-types/rich.d.ts +0 -1010
- package/dist-cjs/src/api/telegram-types/settings.d.ts +0 -120
- package/dist-cjs/src/api/telegram-types/story.d.ts +0 -89
- package/dist-cjs/src/api/telegram-types/update.d.ts +0 -84
- package/dist-cjs/src/api/telegram.js +0 -2
- package/dist-cjs/src/api/transport.js +0 -267
- package/dist-cjs/src/api/types.js +0 -2
- package/dist-cjs/src/branding/terminal.js +0 -338
- package/dist-cjs/src/broadcast/broadcast.js +0 -58
- package/dist-cjs/src/cache/cache.js +0 -45
- package/dist-cjs/src/cli.js +0 -86
- package/dist-cjs/src/context/context.js +0 -305
- package/dist-cjs/src/core/bot.js +0 -510
- package/dist-cjs/src/core/events.js +0 -38
- package/dist-cjs/src/core/webhook-reply.js +0 -42
- package/dist-cjs/src/index.js +0 -47
- package/dist-cjs/src/keyboard/index.js +0 -61
- package/dist-cjs/src/middleware/compose.js +0 -20
- package/dist-cjs/src/observability/logger.js +0 -293
- package/dist-cjs/src/plugins/plugin.js +0 -63
- package/dist-cjs/src/queue/queue.js +0 -219
- package/dist-cjs/src/router/router.js +0 -186
- package/dist-cjs/src/state/conversation.js +0 -139
- package/dist-cjs/src/state/forms.js +0 -47
- package/dist-cjs/src/state/menu.js +0 -133
- package/dist-cjs/src/storage/storage.js +0 -202
- package/dist-cjs/src/telegram-features.js +0 -76
- package/dist-cjs/src/testing.js +0 -45
- package/dist-cjs/src/utils/concurrency.js +0 -57
- package/dist-cjs/src/utils/files.js +0 -58
- package/dist-cjs/src/utils/text.js +0 -63
- package/dist-cjs/src/webhook/handler.js +0 -144
- package/docs/API.id.md +0 -1935
- package/docs/API.md +0 -1969
- package/docs/API.zh-CN.md +0 -1929
- package/docs/GETTING_STARTED.id.md +0 -85
- package/docs/GETTING_STARTED.md +0 -85
- package/docs/GETTING_STARTED.zh-CN.md +0 -85
- package/docs/GITHUB_PACKAGES.id.md +0 -82
- package/docs/GITHUB_PACKAGES.md +0 -82
- package/docs/GITHUB_PACKAGES.zh-CN.md +0 -82
- package/docs/README.md +0 -48
- package/docs/STORAGE.id.md +0 -105
- package/docs/STORAGE.md +0 -105
- package/docs/STORAGE.zh-CN.md +0 -105
- package/examples/README.md +0 -37
- package/examples/files.ts +0 -35
- package/examples/minimal.ts +0 -12
- package/examples/tsconfig.json +0 -9
- package/examples/webhook.ts +0 -42
- package/examples/wizard-registration.ts +0 -42
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Router = exports.UPDATE_FILTER_TYPES = void 0;
|
|
4
|
-
const compose_js_1 = require("../middleware/compose.js");
|
|
5
|
-
function testRegExp(expression, value) {
|
|
6
|
-
expression.lastIndex = 0;
|
|
7
|
-
return expression.test(value);
|
|
8
|
-
}
|
|
9
|
-
/** Update types accepted by `on()` filters, mirroring the Telegram `Update` object. */
|
|
10
|
-
exports.UPDATE_FILTER_TYPES = [
|
|
11
|
-
"message",
|
|
12
|
-
"edited_message",
|
|
13
|
-
"channel_post",
|
|
14
|
-
"edited_channel_post",
|
|
15
|
-
"business_connection",
|
|
16
|
-
"business_message",
|
|
17
|
-
"edited_business_message",
|
|
18
|
-
"deleted_business_messages",
|
|
19
|
-
"guest_message",
|
|
20
|
-
"message_reaction",
|
|
21
|
-
"message_reaction_count",
|
|
22
|
-
"inline_query",
|
|
23
|
-
"chosen_inline_result",
|
|
24
|
-
"callback_query",
|
|
25
|
-
"shipping_query",
|
|
26
|
-
"pre_checkout_query",
|
|
27
|
-
"purchased_paid_media",
|
|
28
|
-
"poll",
|
|
29
|
-
"poll_answer",
|
|
30
|
-
"my_chat_member",
|
|
31
|
-
"chat_member",
|
|
32
|
-
"chat_join_request",
|
|
33
|
-
"chat_boost",
|
|
34
|
-
"removed_chat_boost",
|
|
35
|
-
];
|
|
36
|
-
const updateFilterTypes = new Set(exports.UPDATE_FILTER_TYPES);
|
|
37
|
-
function assertValidFilter(filter) {
|
|
38
|
-
const type = filter.split(":", 1)[0] ?? "";
|
|
39
|
-
if (!updateFilterTypes.has(type))
|
|
40
|
-
throw new TypeError(`Unknown update type in filter "${filter}". Expected one of: ${exports.UPDATE_FILTER_TYPES.join(", ")}.`);
|
|
41
|
-
}
|
|
42
|
-
function matchesFilter(ctx, filter) {
|
|
43
|
-
const separator = filter.indexOf(":");
|
|
44
|
-
const type = separator < 0 ? filter : filter.slice(0, separator);
|
|
45
|
-
const field = separator < 0 ? undefined : filter.slice(separator + 1);
|
|
46
|
-
const payload = ctx.update[type];
|
|
47
|
-
if (payload === undefined || payload === null)
|
|
48
|
-
return false;
|
|
49
|
-
if (field === undefined || field === "")
|
|
50
|
-
return true;
|
|
51
|
-
return typeof payload === "object" && payload[field] !== undefined;
|
|
52
|
-
}
|
|
53
|
-
class Router {
|
|
54
|
-
middlewares = [];
|
|
55
|
-
routes = [];
|
|
56
|
-
sequence = 0;
|
|
57
|
-
matchMode;
|
|
58
|
-
constructor(options = {}) {
|
|
59
|
-
this.matchMode = options.matchMode ?? "first";
|
|
60
|
-
}
|
|
61
|
-
use(...middleware) {
|
|
62
|
-
if (middleware.length === 0)
|
|
63
|
-
return this;
|
|
64
|
-
this.middlewares.push(...middleware);
|
|
65
|
-
return this;
|
|
66
|
-
}
|
|
67
|
-
route(matcher, ...middleware) {
|
|
68
|
-
if (middleware.length === 0)
|
|
69
|
-
throw new Error("A route requires at least one middleware handler.");
|
|
70
|
-
this.routes.push({ priority: this.sequence++, matcher, middleware });
|
|
71
|
-
return this;
|
|
72
|
-
}
|
|
73
|
-
command(name, ...middleware) {
|
|
74
|
-
return this.route(async (ctx) => {
|
|
75
|
-
const text = ctx.message?.text ?? ctx.message?.caption;
|
|
76
|
-
if (!text?.startsWith("/"))
|
|
77
|
-
return false;
|
|
78
|
-
const parts = text.slice(1).split(/\s+/);
|
|
79
|
-
const commandWithBot = parts[0] ?? "";
|
|
80
|
-
const [command, botUsername] = commandWithBot.split("@");
|
|
81
|
-
if (botUsername && ctx.me?.username && botUsername.toLowerCase() !== ctx.me.username.toLowerCase()) {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
const matched = typeof name === "string"
|
|
85
|
-
? command === name.replace(/^\//, "")
|
|
86
|
-
: testRegExp(name, command ?? "");
|
|
87
|
-
if (matched) {
|
|
88
|
-
ctx.args = parts.slice(1);
|
|
89
|
-
}
|
|
90
|
-
return matched;
|
|
91
|
-
}, ...middleware);
|
|
92
|
-
}
|
|
93
|
-
text(value, ...middleware) {
|
|
94
|
-
return this.route((ctx) => {
|
|
95
|
-
const text = ctx.message?.text ?? ctx.message?.caption;
|
|
96
|
-
return text === value;
|
|
97
|
-
}, ...middleware);
|
|
98
|
-
}
|
|
99
|
-
regex(expression, ...middleware) {
|
|
100
|
-
return this.route((ctx) => {
|
|
101
|
-
const text = ctx.message?.text ?? ctx.message?.caption ?? "";
|
|
102
|
-
const match = text.match(expression);
|
|
103
|
-
if (match) {
|
|
104
|
-
ctx.match = match;
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
return false;
|
|
108
|
-
}, ...middleware);
|
|
109
|
-
}
|
|
110
|
-
callback(pattern, ...middleware) {
|
|
111
|
-
return this.route((ctx) => {
|
|
112
|
-
const data = ctx.callbackQuery?.data ?? "";
|
|
113
|
-
if (typeof pattern === "string") {
|
|
114
|
-
if (pattern.endsWith("*")) {
|
|
115
|
-
const prefix = pattern.slice(0, -1);
|
|
116
|
-
if (data.startsWith(prefix)) {
|
|
117
|
-
ctx.params = { ...ctx.params, wildcard: data.slice(prefix.length) };
|
|
118
|
-
return true;
|
|
119
|
-
}
|
|
120
|
-
return false;
|
|
121
|
-
}
|
|
122
|
-
return data === pattern;
|
|
123
|
-
}
|
|
124
|
-
const match = data.match(pattern);
|
|
125
|
-
if (match) {
|
|
126
|
-
ctx.match = match;
|
|
127
|
-
return true;
|
|
128
|
-
}
|
|
129
|
-
return false;
|
|
130
|
-
}, ...middleware);
|
|
131
|
-
}
|
|
132
|
-
chat(chatId, ...middleware) {
|
|
133
|
-
return this.route((ctx) => {
|
|
134
|
-
const id = ctx.message?.chat?.id;
|
|
135
|
-
return id !== undefined && (id === chatId || String(id) === String(chatId));
|
|
136
|
-
}, ...middleware);
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Registers handlers for update types, with optional payload narrowing:
|
|
140
|
-
* `on("message")`, `on("message:photo")`, `on("callback_query:data")`,
|
|
141
|
-
* or an array such as `["message:text", "callback_query:data"]`.
|
|
142
|
-
*/
|
|
143
|
-
on(filter, ...middleware) {
|
|
144
|
-
const filters = (Array.isArray(filter) ? filter : [filter]).map((value) => String(value));
|
|
145
|
-
if (filters.length === 0)
|
|
146
|
-
throw new Error("At least one update filter is required.");
|
|
147
|
-
for (const value of filters)
|
|
148
|
-
assertValidFilter(value);
|
|
149
|
-
return this.route((ctx) => filters.some((value) => matchesFilter(ctx, value)), ...middleware);
|
|
150
|
-
}
|
|
151
|
-
predicate(matcher, ...middleware) {
|
|
152
|
-
return this.route(matcher, ...middleware);
|
|
153
|
-
}
|
|
154
|
-
nest(child) {
|
|
155
|
-
return this.route(() => true, async (ctx, next) => {
|
|
156
|
-
await child.handle(ctx, next);
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
async handle(ctx, terminal) {
|
|
160
|
-
const routeDispatcher = async (currentCtx, next) => {
|
|
161
|
-
const ordered = [...this.routes].sort((left, right) => left.priority - right.priority);
|
|
162
|
-
let matched = false;
|
|
163
|
-
for (const route of ordered) {
|
|
164
|
-
if (!(await route.matcher(currentCtx)))
|
|
165
|
-
continue;
|
|
166
|
-
matched = true;
|
|
167
|
-
await (0, compose_js_1.compose)(route.middleware)(currentCtx);
|
|
168
|
-
if (this.matchMode === "first")
|
|
169
|
-
break;
|
|
170
|
-
}
|
|
171
|
-
if (!matched) {
|
|
172
|
-
if (terminal)
|
|
173
|
-
await terminal();
|
|
174
|
-
else
|
|
175
|
-
await next();
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
if (this.middlewares.length === 0) {
|
|
179
|
-
await routeDispatcher(ctx, async () => { });
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
await (0, compose_js_1.compose)([...this.middlewares, routeDispatcher])(ctx);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
exports.Router = Router;
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Wizard = exports.ConversationManager = exports.ConversationFlow = void 0;
|
|
4
|
-
exports.conversationKeyFromContext = conversationKeyFromContext;
|
|
5
|
-
const storage_js_1 = require("../storage/storage.js");
|
|
6
|
-
function conversationKeyFromContext(ctx) {
|
|
7
|
-
return ctx.chat?.id !== undefined ? `${ctx.chat.id}:${ctx.from?.id ?? "anonymous"}` : `update:${ctx.update.update_id}`;
|
|
8
|
-
}
|
|
9
|
-
class ConversationFlow {
|
|
10
|
-
ctx;
|
|
11
|
-
state;
|
|
12
|
-
constructor(ctx, state) {
|
|
13
|
-
this.ctx = ctx;
|
|
14
|
-
this.state = state;
|
|
15
|
-
}
|
|
16
|
-
get values() { return this.state.values; }
|
|
17
|
-
set(key, value) { this.state.values[key] = value; this.state.updatedAt = Date.now(); return this; }
|
|
18
|
-
get(key) { return this.state.values[key]; }
|
|
19
|
-
next() { this.state.step += 1; this.state.updatedAt = Date.now(); return this; }
|
|
20
|
-
previous() { this.state.step = Math.max(0, this.state.step - 1); this.state.updatedAt = Date.now(); return this; }
|
|
21
|
-
complete() { this.state.status = "completed"; this.state.updatedAt = Date.now(); }
|
|
22
|
-
cancel() { this.state.status = "cancelled"; this.state.updatedAt = Date.now(); }
|
|
23
|
-
}
|
|
24
|
-
exports.ConversationFlow = ConversationFlow;
|
|
25
|
-
class ConversationManager {
|
|
26
|
-
active = new Map();
|
|
27
|
-
storage;
|
|
28
|
-
constructor(storage = new storage_js_1.MemoryStorage()) {
|
|
29
|
-
this.storage = storage;
|
|
30
|
-
}
|
|
31
|
-
start(key, name, values = {}) {
|
|
32
|
-
const state = { name, step: 0, values, status: "active", updatedAt: Date.now() };
|
|
33
|
-
this.active.set(key, state);
|
|
34
|
-
void this.storage.set(key, state).catch(() => undefined);
|
|
35
|
-
return state;
|
|
36
|
-
}
|
|
37
|
-
async startAsync(key, name, values = {}) {
|
|
38
|
-
const state = { name, step: 0, values, status: "active", updatedAt: Date.now() };
|
|
39
|
-
this.active.set(key, state);
|
|
40
|
-
await this.storage.set(key, state);
|
|
41
|
-
return state;
|
|
42
|
-
}
|
|
43
|
-
get(key) { return this.active.get(key); }
|
|
44
|
-
async getAsync(key) {
|
|
45
|
-
const cached = this.active.get(key);
|
|
46
|
-
if (cached)
|
|
47
|
-
return cached;
|
|
48
|
-
const stored = await this.storage.get(key);
|
|
49
|
-
if (stored)
|
|
50
|
-
this.active.set(key, stored);
|
|
51
|
-
return stored;
|
|
52
|
-
}
|
|
53
|
-
cancel(key) {
|
|
54
|
-
const state = this.active.get(key);
|
|
55
|
-
if (!state)
|
|
56
|
-
return false;
|
|
57
|
-
state.status = "cancelled";
|
|
58
|
-
state.updatedAt = Date.now();
|
|
59
|
-
void this.storage.set(key, state).catch(() => undefined);
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
async cancelAsync(key) {
|
|
63
|
-
const state = await this.getAsync(key);
|
|
64
|
-
if (!state)
|
|
65
|
-
return false;
|
|
66
|
-
state.status = "cancelled";
|
|
67
|
-
state.updatedAt = Date.now();
|
|
68
|
-
await this.storage.set(key, state);
|
|
69
|
-
return true;
|
|
70
|
-
}
|
|
71
|
-
clearExpired(maxAgeMs) {
|
|
72
|
-
if (!Number.isFinite(maxAgeMs) || maxAgeMs < 0)
|
|
73
|
-
throw new RangeError("maxAgeMs must be non-negative");
|
|
74
|
-
const threshold = Date.now() - maxAgeMs;
|
|
75
|
-
let removed = 0;
|
|
76
|
-
for (const [key, state] of this.active)
|
|
77
|
-
if (state.updatedAt < threshold) {
|
|
78
|
-
this.active.delete(key);
|
|
79
|
-
void this.storage.delete(key);
|
|
80
|
-
removed += 1;
|
|
81
|
-
}
|
|
82
|
-
return removed;
|
|
83
|
-
}
|
|
84
|
-
async clearExpiredAsync(maxAgeMs) {
|
|
85
|
-
if (!Number.isFinite(maxAgeMs) || maxAgeMs < 0)
|
|
86
|
-
throw new RangeError("maxAgeMs must be non-negative");
|
|
87
|
-
const threshold = Date.now() - maxAgeMs;
|
|
88
|
-
let removed = 0;
|
|
89
|
-
for await (const [key, state] of this.storage.entries()) {
|
|
90
|
-
if (state.updatedAt < threshold) {
|
|
91
|
-
await this.storage.delete(key);
|
|
92
|
-
this.active.delete(key);
|
|
93
|
-
removed += 1;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return removed;
|
|
97
|
-
}
|
|
98
|
-
async run(ctx, key, name, steps) {
|
|
99
|
-
const existing = await this.getAsync(key);
|
|
100
|
-
const state = existing ?? await this.startAsync(key, name);
|
|
101
|
-
if (state.name !== name)
|
|
102
|
-
throw new Error(`Conversation ${key} belongs to ${state.name}, not ${name}`);
|
|
103
|
-
if (state.status !== "active")
|
|
104
|
-
return state;
|
|
105
|
-
const flow = new ConversationFlow(ctx, state);
|
|
106
|
-
const step = steps[state.step];
|
|
107
|
-
if (!step)
|
|
108
|
-
state.status = "completed";
|
|
109
|
-
else {
|
|
110
|
-
await step(flow);
|
|
111
|
-
if (state.step >= steps.length)
|
|
112
|
-
state.status = "completed";
|
|
113
|
-
}
|
|
114
|
-
state.updatedAt = Date.now();
|
|
115
|
-
await this.storage.set(key, state);
|
|
116
|
-
this.active.set(key, state);
|
|
117
|
-
return state;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
exports.ConversationManager = ConversationManager;
|
|
121
|
-
class Wizard {
|
|
122
|
-
stepsList = [];
|
|
123
|
-
defaultManager;
|
|
124
|
-
constructor(manager) {
|
|
125
|
-
this.defaultManager = manager ?? new ConversationManager();
|
|
126
|
-
}
|
|
127
|
-
step(step) { this.stepsList.push(step); return this; }
|
|
128
|
-
/**
|
|
129
|
-
* Runs the active step for a conversation key. The default manager belongs to
|
|
130
|
-
* this Wizard instance and is intentionally reused across updates; passing a
|
|
131
|
-
* manager is useful when the application owns persistent storage explicitly.
|
|
132
|
-
*/
|
|
133
|
-
async run(ctx, key = conversationKeyFromContext(ctx), manager) {
|
|
134
|
-
return (manager ?? this.defaultManager).run(ctx, key, "wizard", this.stepsList.map((step) => step.run));
|
|
135
|
-
}
|
|
136
|
-
get steps() { return this.stepsList; }
|
|
137
|
-
get manager() { return this.defaultManager; }
|
|
138
|
-
}
|
|
139
|
-
exports.Wizard = Wizard;
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validators = exports.Form = void 0;
|
|
4
|
-
class Form {
|
|
5
|
-
fields = new Map();
|
|
6
|
-
field(definition) { this.fields.set(definition.name, definition); return this; }
|
|
7
|
-
async parse(input) {
|
|
8
|
-
const issues = [];
|
|
9
|
-
const values = {};
|
|
10
|
-
for (const [name, field] of this.fields) {
|
|
11
|
-
const raw = input[name];
|
|
12
|
-
if ((raw === undefined || raw === null || raw === "") && field.required) {
|
|
13
|
-
issues.push({ path: name, message: "Field is required", code: "required" });
|
|
14
|
-
continue;
|
|
15
|
-
}
|
|
16
|
-
if (raw === undefined || raw === null || raw === "")
|
|
17
|
-
continue;
|
|
18
|
-
try {
|
|
19
|
-
let value = field.parse(raw);
|
|
20
|
-
if (field.transform)
|
|
21
|
-
value = await field.transform(value);
|
|
22
|
-
const error = await field.validate?.(value);
|
|
23
|
-
if (error)
|
|
24
|
-
issues.push({ path: name, message: error, code: "invalid" });
|
|
25
|
-
else
|
|
26
|
-
values[name] = value;
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
issues.push({ path: name, message: error instanceof Error ? error.message : "Invalid value", code: "parse" });
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return issues.length ? { success: false, issues } : { success: true, data: values };
|
|
33
|
-
}
|
|
34
|
-
reset() { }
|
|
35
|
-
}
|
|
36
|
-
exports.Form = Form;
|
|
37
|
-
exports.validators = { string: (value) => { if (typeof value !== "string")
|
|
38
|
-
throw new TypeError("Expected string"); return value; }, number: (value) => { const number = typeof value === "number" ? value : Number(value); if (!Number.isFinite(number))
|
|
39
|
-
throw new TypeError("Expected number"); return number; }, integer: (value) => { const number = exports.validators.number(value); if (!Number.isInteger(number))
|
|
40
|
-
throw new TypeError("Expected integer"); return number; }, email: (value) => { const email = exports.validators.string(value); if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email))
|
|
41
|
-
throw new TypeError("Expected email"); return email; }, url: (value) => { const url = exports.validators.string(value); try {
|
|
42
|
-
new URL(url);
|
|
43
|
-
return url;
|
|
44
|
-
}
|
|
45
|
-
catch {
|
|
46
|
-
throw new TypeError("Expected URL");
|
|
47
|
-
} } };
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MenuController = exports.Menu = void 0;
|
|
4
|
-
exports.paginate = paginate;
|
|
5
|
-
exports.paginationButtons = paginationButtons;
|
|
6
|
-
const index_js_1 = require("../keyboard/index.js");
|
|
7
|
-
function paginate(items, page, pageSize) {
|
|
8
|
-
if (!Number.isInteger(page) || page < 0)
|
|
9
|
-
throw new RangeError("page must be a non-negative integer");
|
|
10
|
-
if (!Number.isInteger(pageSize) || pageSize < 1)
|
|
11
|
-
throw new RangeError("pageSize must be a positive integer");
|
|
12
|
-
const pageCount = Math.max(1, Math.ceil(items.length / pageSize));
|
|
13
|
-
const safePage = Math.min(page, pageCount - 1);
|
|
14
|
-
const start = safePage * pageSize;
|
|
15
|
-
return { items: items.slice(start, start + pageSize), page: safePage, pageCount, hasPrevious: safePage > 0, hasNext: safePage < pageCount - 1 };
|
|
16
|
-
}
|
|
17
|
-
function paginationButtons(page, prefix, labels = {}) {
|
|
18
|
-
const buttons = [];
|
|
19
|
-
if (page.hasPrevious)
|
|
20
|
-
buttons.push({ text: labels.previous ?? "Previous", callback_data: `${prefix}:page:${page.page - 1}` });
|
|
21
|
-
buttons.push({ text: `${page.page + 1}/${page.pageCount}`, callback_data: `${prefix}:noop` });
|
|
22
|
-
if (page.hasNext)
|
|
23
|
-
buttons.push({ text: labels.next ?? "Next", callback_data: `${prefix}:page:${page.page + 1}` });
|
|
24
|
-
return buttons;
|
|
25
|
-
}
|
|
26
|
-
class Menu {
|
|
27
|
-
id;
|
|
28
|
-
itemsList = [];
|
|
29
|
-
parents = [];
|
|
30
|
-
constructor(id) {
|
|
31
|
-
this.id = id;
|
|
32
|
-
}
|
|
33
|
-
item(item) {
|
|
34
|
-
if (!item.id || !item.label)
|
|
35
|
-
throw new Error("Menu item id and label are required.");
|
|
36
|
-
if (item.url !== undefined && item.callbackData !== undefined)
|
|
37
|
-
throw new Error("A menu item cannot have both url and callbackData.");
|
|
38
|
-
this.itemsList.push(item);
|
|
39
|
-
return this;
|
|
40
|
-
}
|
|
41
|
-
breadcrumb(label) { if (label)
|
|
42
|
-
this.parents.push(label); return this; }
|
|
43
|
-
get items() { return this.itemsList; }
|
|
44
|
-
get breadcrumbs() { return this.parents; }
|
|
45
|
-
async visibleItems(context = {}) {
|
|
46
|
-
const permissions = context.permissions ? new Set(context.permissions) : undefined;
|
|
47
|
-
const result = [];
|
|
48
|
-
for (const item of this.itemsList) {
|
|
49
|
-
const visible = typeof item.visible === "function" ? await item.visible(context, item) : item.visible ?? true;
|
|
50
|
-
if (!visible)
|
|
51
|
-
continue;
|
|
52
|
-
const allowed = typeof item.permission === "function"
|
|
53
|
-
? await item.permission(context, item)
|
|
54
|
-
: item.permission === undefined
|
|
55
|
-
? true
|
|
56
|
-
: permissions?.has(item.permission) ?? false;
|
|
57
|
-
if (allowed)
|
|
58
|
-
result.push(item);
|
|
59
|
-
}
|
|
60
|
-
return result;
|
|
61
|
-
}
|
|
62
|
-
async build(context = {}, options = {}) {
|
|
63
|
-
const columns = options.columns ?? 1;
|
|
64
|
-
if (!Number.isInteger(columns) || columns < 1)
|
|
65
|
-
throw new RangeError("columns must be a positive integer");
|
|
66
|
-
const keyboard = new index_js_1.InlineKeyboard();
|
|
67
|
-
if (options.includeBreadcrumbs && this.parents.length)
|
|
68
|
-
keyboard.text(this.parents.join(" / "), `${this.id}:breadcrumb`);
|
|
69
|
-
const buttons = (await this.visibleItems(context)).map((item) => item.url
|
|
70
|
-
? { text: item.label, url: item.url }
|
|
71
|
-
: { text: item.label, callback_data: item.callbackData ?? `${this.id}:${item.id}` });
|
|
72
|
-
keyboard.grid(buttons, columns);
|
|
73
|
-
return keyboard;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
exports.Menu = Menu;
|
|
77
|
-
class MenuController {
|
|
78
|
-
currentPage = 0;
|
|
79
|
-
options;
|
|
80
|
-
constructor(options) {
|
|
81
|
-
if (!options.id || !options.id.trim())
|
|
82
|
-
throw new Error("MenuController id is required.");
|
|
83
|
-
if (!Number.isInteger(options.pageSize) || options.pageSize < 1)
|
|
84
|
-
throw new RangeError("pageSize must be a positive integer");
|
|
85
|
-
this.options = options;
|
|
86
|
-
}
|
|
87
|
-
get page() { return this.currentPage; }
|
|
88
|
-
async allItems() { return typeof this.options.items === "function" ? await this.options.items() : this.options.items; }
|
|
89
|
-
async render(context = this.options.context ?? {}) {
|
|
90
|
-
const items = await this.allItems();
|
|
91
|
-
const page = paginate(items, this.currentPage, this.options.pageSize);
|
|
92
|
-
this.currentPage = page.page;
|
|
93
|
-
const keyboard = new index_js_1.InlineKeyboard();
|
|
94
|
-
for (let index = 0; index < page.items.length; index += 1) {
|
|
95
|
-
const absoluteIndex = page.page * this.options.pageSize + index;
|
|
96
|
-
keyboard.text(this.options.label(page.items[index], absoluteIndex), `${this.options.id}:select:${absoluteIndex}`);
|
|
97
|
-
}
|
|
98
|
-
const navigation = paginationButtons(page, this.options.id, this.options.labels);
|
|
99
|
-
if (navigation.length)
|
|
100
|
-
keyboard.row(...navigation);
|
|
101
|
-
void context;
|
|
102
|
-
return keyboard.build();
|
|
103
|
-
}
|
|
104
|
-
async handle(data, context = this.options.context ?? {}) {
|
|
105
|
-
const prefix = `${this.options.id}:`;
|
|
106
|
-
if (!data.startsWith(prefix))
|
|
107
|
-
return undefined;
|
|
108
|
-
const action = data.slice(prefix.length);
|
|
109
|
-
if (action === "noop" || action === "breadcrumb")
|
|
110
|
-
return { type: "noop" };
|
|
111
|
-
if (action.startsWith("page:")) {
|
|
112
|
-
const page = Number(action.slice("page:".length));
|
|
113
|
-
if (!Number.isInteger(page) || page < 0)
|
|
114
|
-
return undefined;
|
|
115
|
-
this.currentPage = page;
|
|
116
|
-
const items = await this.allItems();
|
|
117
|
-
const pageData = paginate(items, this.currentPage, this.options.pageSize);
|
|
118
|
-
this.currentPage = pageData.page;
|
|
119
|
-
return { type: "page", page: pageData, keyboard: await this.render(context) };
|
|
120
|
-
}
|
|
121
|
-
if (action.startsWith("select:")) {
|
|
122
|
-
const index = Number(action.slice("select:".length));
|
|
123
|
-
const items = await this.allItems();
|
|
124
|
-
const item = items[index];
|
|
125
|
-
if (item === undefined || !Number.isInteger(index) || index < 0)
|
|
126
|
-
return undefined;
|
|
127
|
-
await this.options.callback?.(item, context);
|
|
128
|
-
return { type: "select", item, index };
|
|
129
|
-
}
|
|
130
|
-
return undefined;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
exports.MenuController = MenuController;
|