1 | "use strict";
|
2 |
|
3 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
4 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
5 | };
|
6 | Object.defineProperty(exports, "__esModule", { value: true });
|
7 | exports.Composer = void 0;
|
8 | const context_1 = __importDefault(require("./context"));
|
9 | const filters_1 = require("./filters");
|
10 | const args_1 = require("./core/helpers/args");
|
11 | function always(x) {
|
12 | return () => x;
|
13 | }
|
14 | const anoop = always(Promise.resolve());
|
15 | class Composer {
|
16 | constructor(...fns) {
|
17 | this.handler = Composer.compose(fns);
|
18 | }
|
19 | |
20 |
|
21 |
|
22 | use(...fns) {
|
23 | this.handler = Composer.compose([this.handler, ...fns]);
|
24 | return this;
|
25 | }
|
26 | |
27 |
|
28 |
|
29 |
|
30 |
|
31 | guard(guardFn, ...fns) {
|
32 | return this.use(Composer.guard(guardFn, ...fns));
|
33 | }
|
34 | on(filters, ...fns) {
|
35 |
|
36 | return this.use(Composer.on(filters, ...fns));
|
37 | }
|
38 | |
39 |
|
40 |
|
41 | hears(triggers, ...fns) {
|
42 | return this.use(Composer.hears(triggers, ...fns));
|
43 | }
|
44 | |
45 |
|
46 |
|
47 | command(command, ...fns) {
|
48 | return this.use(Composer.command(command, ...fns));
|
49 | }
|
50 | |
51 |
|
52 |
|
53 | action(triggers, ...fns) {
|
54 | return this.use(Composer.action(triggers, ...fns));
|
55 | }
|
56 | |
57 |
|
58 |
|
59 | inlineQuery(triggers, ...fns) {
|
60 | return this.use(Composer.inlineQuery(triggers, ...fns));
|
61 | }
|
62 | |
63 |
|
64 |
|
65 | gameQuery(...fns) {
|
66 | return this.use(Composer.gameQuery(...fns));
|
67 | }
|
68 | |
69 |
|
70 |
|
71 | drop(predicate) {
|
72 | return this.use(Composer.drop(predicate));
|
73 | }
|
74 |
|
75 | filter(predicate) {
|
76 | return this.use(Composer.filter(predicate));
|
77 | }
|
78 | entity(predicate, ...fns) {
|
79 | return this.use(Composer.entity(predicate, ...fns));
|
80 | }
|
81 | email(email, ...fns) {
|
82 | return this.use(Composer.email(email, ...fns));
|
83 | }
|
84 | url(url, ...fns) {
|
85 | return this.use(Composer.url(url, ...fns));
|
86 | }
|
87 | textLink(link, ...fns) {
|
88 | return this.use(Composer.textLink(link, ...fns));
|
89 | }
|
90 | textMention(mention, ...fns) {
|
91 | return this.use(Composer.textMention(mention, ...fns));
|
92 | }
|
93 | mention(mention, ...fns) {
|
94 | return this.use(Composer.mention(mention, ...fns));
|
95 | }
|
96 | phone(number, ...fns) {
|
97 | return this.use(Composer.phone(number, ...fns));
|
98 | }
|
99 | hashtag(hashtag, ...fns) {
|
100 | return this.use(Composer.hashtag(hashtag, ...fns));
|
101 | }
|
102 | cashtag(cashtag, ...fns) {
|
103 | return this.use(Composer.cashtag(cashtag, ...fns));
|
104 | }
|
105 | spoiler(text, ...fns) {
|
106 | return this.use(Composer.spoiler(text, ...fns));
|
107 | }
|
108 | |
109 |
|
110 |
|
111 | start(...fns) {
|
112 | const handler = Composer.compose(fns);
|
113 | return this.command('start', (ctx, next) => handler(Object.assign(ctx, { startPayload: ctx.payload }), next));
|
114 | }
|
115 | |
116 |
|
117 |
|
118 | help(...fns) {
|
119 | return this.command('help', ...fns);
|
120 | }
|
121 | |
122 |
|
123 |
|
124 | settings(...fns) {
|
125 | return this.command('settings', ...fns);
|
126 | }
|
127 | middleware() {
|
128 | return this.handler;
|
129 | }
|
130 | static reply(...args) {
|
131 | return (ctx) => ctx.reply(...args);
|
132 | }
|
133 | static catch(errorHandler, ...fns) {
|
134 | const handler = Composer.compose(fns);
|
135 |
|
136 | return (ctx, next) => Promise.resolve(handler(ctx, next))
|
137 | .catch((err) => errorHandler(err, ctx));
|
138 | }
|
139 | |
140 |
|
141 |
|
142 | static fork(middleware) {
|
143 | const handler = Composer.unwrap(middleware);
|
144 | return async (ctx, next) => {
|
145 | await Promise.all([handler(ctx, anoop), next()]);
|
146 | };
|
147 | }
|
148 | static tap(middleware) {
|
149 | const handler = Composer.unwrap(middleware);
|
150 | return (ctx, next) => Promise.resolve(handler(ctx, anoop)).then(() => next());
|
151 | }
|
152 | |
153 |
|
154 |
|
155 | static passThru() {
|
156 | return (ctx, next) => next();
|
157 | }
|
158 | static lazy(factoryFn) {
|
159 | if (typeof factoryFn !== 'function') {
|
160 | throw new Error('Argument must be a function');
|
161 | }
|
162 | return (ctx, next) => Promise.resolve(factoryFn(ctx)).then((middleware) => Composer.unwrap(middleware)(ctx, next));
|
163 | }
|
164 | static log(logFn = console.log) {
|
165 | return (ctx, next) => {
|
166 | logFn(JSON.stringify(ctx.update, null, 2));
|
167 | return next();
|
168 | };
|
169 | }
|
170 | |
171 |
|
172 |
|
173 |
|
174 | static branch(predicate, trueMiddleware, falseMiddleware) {
|
175 | if (typeof predicate !== 'function') {
|
176 | return Composer.unwrap(predicate ? trueMiddleware : falseMiddleware);
|
177 | }
|
178 | return Composer.lazy((ctx) => Promise.resolve(predicate(ctx)).then((value) => value ? trueMiddleware : falseMiddleware));
|
179 | }
|
180 | |
181 |
|
182 |
|
183 |
|
184 |
|
185 | static optional(predicate, ...fns) {
|
186 | return Composer.branch(predicate, Composer.compose(fns), Composer.passThru());
|
187 | }
|
188 |
|
189 | static filter(predicate) {
|
190 | return Composer.branch(predicate, Composer.passThru(), anoop);
|
191 | }
|
192 | |
193 |
|
194 |
|
195 | static drop(predicate) {
|
196 | return Composer.branch(predicate, anoop, Composer.passThru());
|
197 | }
|
198 | static dispatch(routeFn, handlers) {
|
199 | return Composer.lazy((ctx) => Promise.resolve(routeFn(ctx)).then((value) => handlers[value]));
|
200 | }
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 | |
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 | static guard(guardFn, ...fns) {
|
228 | return Composer.optional((ctx) => guardFn(ctx.update),
|
229 |
|
230 | ...fns);
|
231 | }
|
232 | static on(updateType, ...fns) {
|
233 | const filters = Array.isArray(updateType) ? updateType : [updateType];
|
234 | const predicate = (update) => {
|
235 | for (const filter of filters) {
|
236 | if (
|
237 |
|
238 |
|
239 | typeof filter !== 'string'
|
240 | ?
|
241 | filter(update)
|
242 | :
|
243 | filter in update ||
|
244 |
|
245 |
|
246 | ('message' in update && filter in update.message)) {
|
247 | return true;
|
248 | }
|
249 | }
|
250 | return false;
|
251 | };
|
252 | return Composer.optional((ctx) => predicate(ctx.update), ...fns);
|
253 | }
|
254 | static entity(predicate, ...fns) {
|
255 | if (typeof predicate !== 'function') {
|
256 | const entityTypes = normaliseTextArguments(predicate);
|
257 | return Composer.entity(({ type }) => entityTypes.includes(type), ...fns);
|
258 | }
|
259 | return Composer.optional((ctx) => {
|
260 | var _a;
|
261 | const msg = (_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost;
|
262 | if (msg === undefined) {
|
263 | return false;
|
264 | }
|
265 | const text = getText(msg);
|
266 | const entities = getEntities(msg);
|
267 | if (text === undefined)
|
268 | return false;
|
269 | return entities.some((entity) => predicate(entity, text.substring(entity.offset, entity.offset + entity.length), ctx));
|
270 | },
|
271 |
|
272 | ...fns);
|
273 | }
|
274 | static entityText(entityType, predicate, ...fns) {
|
275 | if (fns.length === 0) {
|
276 |
|
277 | return Array.isArray(predicate)
|
278 |
|
279 | ? Composer.entity(entityType, ...predicate)
|
280 |
|
281 | : Composer.entity(entityType, predicate);
|
282 | }
|
283 | const triggers = normaliseTriggers(predicate);
|
284 | return Composer.entity(({ type }, value, ctx) => {
|
285 | if (type !== entityType) {
|
286 | return false;
|
287 | }
|
288 | for (const trigger of triggers) {
|
289 |
|
290 | if ((ctx.match = trigger(value, ctx))) {
|
291 | return true;
|
292 | }
|
293 | }
|
294 | return false;
|
295 | },
|
296 |
|
297 | ...fns);
|
298 | }
|
299 | static email(email, ...fns) {
|
300 | return Composer.entityText('email', email, ...fns);
|
301 | }
|
302 | static phone(number, ...fns) {
|
303 | return Composer.entityText('phone_number', number, ...fns);
|
304 | }
|
305 | static url(url, ...fns) {
|
306 | return Composer.entityText('url', url, ...fns);
|
307 | }
|
308 | static textLink(link, ...fns) {
|
309 | return Composer.entityText('text_link', link, ...fns);
|
310 | }
|
311 | static textMention(mention, ...fns) {
|
312 | return Composer.entityText('text_mention', mention, ...fns);
|
313 | }
|
314 | static mention(mention, ...fns) {
|
315 | return Composer.entityText('mention', normaliseTextArguments(mention, '@'), ...fns);
|
316 | }
|
317 | static hashtag(hashtag, ...fns) {
|
318 | return Composer.entityText('hashtag', normaliseTextArguments(hashtag, '#'), ...fns);
|
319 | }
|
320 | static cashtag(cashtag, ...fns) {
|
321 | return Composer.entityText('cashtag', normaliseTextArguments(cashtag, '$'), ...fns);
|
322 | }
|
323 | static spoiler(text, ...fns) {
|
324 | return Composer.entityText('spoiler', text, ...fns);
|
325 | }
|
326 | static match(triggers, ...fns) {
|
327 | const handler = Composer.compose(fns);
|
328 | return (ctx, next) => {
|
329 | var _a, _b, _c, _d;
|
330 | const text = (_c = (_b = (_a = getText(ctx.message)) !== null && _a !== void 0 ? _a : getText(ctx.channelPost)) !== null && _b !== void 0 ? _b : getText(ctx.callbackQuery)) !== null && _c !== void 0 ? _c : (_d = ctx.inlineQuery) === null || _d === void 0 ? void 0 : _d.query;
|
331 | if (text === undefined)
|
332 | return next();
|
333 | for (const trigger of triggers) {
|
334 | const match = trigger(text, ctx);
|
335 | if (match)
|
336 | return handler(Object.assign(ctx, { match }), next);
|
337 | }
|
338 | return next();
|
339 | };
|
340 | }
|
341 | |
342 |
|
343 |
|
344 | static hears(triggers, ...fns) {
|
345 | return Composer.on('text', Composer.match(normaliseTriggers(triggers), ...fns));
|
346 | }
|
347 | |
348 |
|
349 |
|
350 | static command(command, ...fns) {
|
351 | if (fns.length === 0)
|
352 |
|
353 | return Composer.entity('bot_command', command);
|
354 | const triggers = normaliseTriggers(command);
|
355 | const filter = (0, filters_1.message)('text');
|
356 | const handler = Composer.compose(fns);
|
357 | return Composer.on(filter, (ctx, next) => {
|
358 | const { entities } = ctx.message;
|
359 | const cmdEntity = entities === null || entities === void 0 ? void 0 : entities[0];
|
360 | if ((cmdEntity === null || cmdEntity === void 0 ? void 0 : cmdEntity.type) !== 'bot_command')
|
361 | return next();
|
362 | if (cmdEntity.offset > 0)
|
363 | return next();
|
364 | const len = cmdEntity.length;
|
365 | const text = ctx.message.text;
|
366 | const [cmdPart, to] = text.slice(0, len).split('@');
|
367 | if (!cmdPart)
|
368 | return next();
|
369 |
|
370 | if (to && to.toLowerCase() !== ctx.me.toLowerCase())
|
371 | return next();
|
372 | const command = cmdPart.slice(1);
|
373 | for (const trigger of triggers)
|
374 | if (trigger(command, ctx)) {
|
375 | const payloadOffset = len + 1;
|
376 | const payload = text.slice(payloadOffset);
|
377 | const c = Object.assign(ctx, { command, payload, args: [] });
|
378 | let _args = undefined;
|
379 |
|
380 | Object.defineProperty(c, 'args', {
|
381 | enumerable: true,
|
382 | configurable: true,
|
383 | get() {
|
384 | if (_args != null)
|
385 | return _args;
|
386 |
|
387 | return (_args = (0, args_1.argsParser)(payload, entities, payloadOffset));
|
388 | },
|
389 | set(args) {
|
390 | _args = args;
|
391 | },
|
392 | });
|
393 | return handler(c, next);
|
394 | }
|
395 | return next();
|
396 | });
|
397 | }
|
398 | |
399 |
|
400 |
|
401 | static action(triggers, ...fns) {
|
402 | return Composer.on('callback_query', Composer.match(normaliseTriggers(triggers), ...fns));
|
403 | }
|
404 | |
405 |
|
406 |
|
407 | static inlineQuery(triggers, ...fns) {
|
408 | return Composer.on('inline_query', Composer.match(normaliseTriggers(triggers), ...fns));
|
409 | }
|
410 | |
411 |
|
412 |
|
413 | static acl(userId, ...fns) {
|
414 | if (typeof userId === 'function') {
|
415 | return Composer.optional(userId, ...fns);
|
416 | }
|
417 | const allowed = Array.isArray(userId) ? userId : [userId];
|
418 |
|
419 | return Composer.optional((ctx) => !ctx.from || allowed.includes(ctx.from.id), ...fns);
|
420 | }
|
421 | static memberStatus(status, ...fns) {
|
422 | const statuses = Array.isArray(status) ? status : [status];
|
423 | return Composer.optional(async (ctx) => {
|
424 | if (ctx.message === undefined)
|
425 | return false;
|
426 | const member = await ctx.getChatMember(ctx.message.from.id);
|
427 | return statuses.includes(member.status);
|
428 | }, ...fns);
|
429 | }
|
430 | |
431 |
|
432 |
|
433 | static admin(...fns) {
|
434 | return Composer.memberStatus(['administrator', 'creator'], ...fns);
|
435 | }
|
436 | |
437 |
|
438 |
|
439 | static creator(...fns) {
|
440 | return Composer.memberStatus('creator', ...fns);
|
441 | }
|
442 | |
443 |
|
444 |
|
445 | static chatType(type, ...fns) {
|
446 | const types = Array.isArray(type) ? type : [type];
|
447 | return Composer.optional((ctx) => {
|
448 | const chat = ctx.chat;
|
449 | return chat !== undefined && types.includes(chat.type);
|
450 | }, ...fns);
|
451 | }
|
452 | |
453 |
|
454 |
|
455 | static privateChat(...fns) {
|
456 | return Composer.chatType('private', ...fns);
|
457 | }
|
458 | |
459 |
|
460 |
|
461 | static groupChat(...fns) {
|
462 | return Composer.chatType(['group', 'supergroup'], ...fns);
|
463 | }
|
464 | |
465 |
|
466 |
|
467 | static gameQuery(...fns) {
|
468 | return Composer.guard((0, filters_1.callbackQuery)('game_short_name'), ...fns);
|
469 | }
|
470 | static unwrap(handler) {
|
471 | if (!handler) {
|
472 | throw new Error('Handler is undefined');
|
473 | }
|
474 | return 'middleware' in handler ? handler.middleware() : handler;
|
475 | }
|
476 | static compose(middlewares) {
|
477 | if (!Array.isArray(middlewares)) {
|
478 | throw new Error('Middlewares must be an array');
|
479 | }
|
480 | if (middlewares.length === 0) {
|
481 | return Composer.passThru();
|
482 | }
|
483 | if (middlewares.length === 1) {
|
484 |
|
485 |
|
486 | return Composer.unwrap(middlewares[0]);
|
487 | }
|
488 | return (ctx, next) => {
|
489 | let index = -1;
|
490 | return execute(0, ctx);
|
491 | async function execute(i, context) {
|
492 | var _a;
|
493 | if (!(context instanceof context_1.default)) {
|
494 | throw new Error('next(ctx) called with invalid context');
|
495 | }
|
496 | if (i <= index) {
|
497 | throw new Error('next() called multiple times');
|
498 | }
|
499 | index = i;
|
500 | const handler = Composer.unwrap((_a = middlewares[i]) !== null && _a !== void 0 ? _a : next);
|
501 | await handler(context, async (ctx = context) => {
|
502 | await execute(i + 1, ctx);
|
503 | });
|
504 | }
|
505 | };
|
506 | }
|
507 | }
|
508 | exports.Composer = Composer;
|
509 |
|
510 |
|
511 |
|
512 |
|
513 | Composer.mount = Composer.on;
|
514 | function escapeRegExp(s) {
|
515 |
|
516 | return s.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');
|
517 | }
|
518 | function normaliseTriggers(triggers) {
|
519 | if (!Array.isArray(triggers))
|
520 | triggers = [triggers];
|
521 | return triggers.map((trigger) => {
|
522 | if (!trigger)
|
523 | throw new Error('Invalid trigger');
|
524 | if (typeof trigger === 'function')
|
525 | return trigger;
|
526 | if (trigger instanceof RegExp)
|
527 | return (value = '') => {
|
528 | trigger.lastIndex = 0;
|
529 | return trigger.exec(value);
|
530 | };
|
531 | const regex = new RegExp(`^${escapeRegExp(trigger)}$`);
|
532 | return (value) => regex.exec(value);
|
533 | });
|
534 | }
|
535 | function getEntities(msg) {
|
536 | var _a, _b;
|
537 | if (msg == null)
|
538 | return [];
|
539 | if ('caption_entities' in msg)
|
540 | return (_a = msg.caption_entities) !== null && _a !== void 0 ? _a : [];
|
541 | if ('entities' in msg)
|
542 | return (_b = msg.entities) !== null && _b !== void 0 ? _b : [];
|
543 | return [];
|
544 | }
|
545 | function getText(msg) {
|
546 | if (msg == null)
|
547 | return undefined;
|
548 | if ('caption' in msg)
|
549 | return msg.caption;
|
550 | if ('text' in msg)
|
551 | return msg.text;
|
552 | if ('data' in msg)
|
553 | return msg.data;
|
554 | if ('game_short_name' in msg)
|
555 | return msg.game_short_name;
|
556 | return undefined;
|
557 | }
|
558 | function normaliseTextArguments(argument, prefix = '') {
|
559 | const args = Array.isArray(argument) ? argument : [argument];
|
560 |
|
561 | return args
|
562 | .filter(Boolean)
|
563 | .map((arg) => prefix && typeof arg === 'string' && !arg.startsWith(prefix) ? `${prefix}${arg}` : arg);
|
564 | }
|
565 | exports.default = Composer;
|