@rilong/grammyjs-conversations-esm 2.0.2

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/out/form.js ADDED
@@ -0,0 +1,598 @@
1
+ /**
2
+ * A container for form building utilities.
3
+ *
4
+ * Each method on this class represents a differnt type of form field which can
5
+ * validate context objects and extract data from it.
6
+ */
7
+ export class ConversationForm {
8
+ /** Constructs a new form based on wait and skip callbacks */
9
+ constructor(conversation) {
10
+ this.conversation = conversation;
11
+ }
12
+ async build(builder) {
13
+ const { validate, action, otherwise, next, ...waitOptions } = builder;
14
+ const ctx = await this.conversation.wait({
15
+ collationKey: "form",
16
+ ...waitOptions,
17
+ });
18
+ const result = await validate(ctx);
19
+ if (result.ok) {
20
+ if (action !== undefined)
21
+ await action(ctx, result.value);
22
+ return result.value;
23
+ }
24
+ else {
25
+ if (otherwise !== undefined) {
26
+ if ("error" in result) {
27
+ const callback = otherwise;
28
+ const reason = result.error;
29
+ await callback(ctx, reason);
30
+ }
31
+ else {
32
+ const callback = otherwise;
33
+ await callback(ctx);
34
+ }
35
+ }
36
+ return await this.conversation.skip({ next });
37
+ }
38
+ }
39
+ /**
40
+ * Form field that checks if the incoming update contains a message or
41
+ * channel post with text, and returns this text as string. Does not check
42
+ * for captions.
43
+ *
44
+ * Accepts an optional options object that lets you perform actions when
45
+ * text is received, when a non-text update is received, and more.
46
+ *
47
+ * @param options Optional options
48
+ */
49
+ async text(options) {
50
+ return await this.build({
51
+ collationKey: "form-text",
52
+ ...options,
53
+ validate: (ctx) => {
54
+ var _a, _b;
55
+ const text = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.text;
56
+ if (text === undefined)
57
+ return { ok: false };
58
+ return { ok: true, value: text };
59
+ },
60
+ });
61
+ }
62
+ /**
63
+ * Form field that checks if the incoming update contains a message or
64
+ * channel post with text that can be parsed to a number, and returns this
65
+ * number. Does not check captions.
66
+ *
67
+ * The conversion to number uses `parseFloat`.
68
+ *
69
+ * Accepts an optional options object that lets you perform actions when a
70
+ * number is received, when a non-number update is received, and more.
71
+ *
72
+ * @param options Optional options
73
+ */
74
+ async number(options) {
75
+ return await this.build({
76
+ collationKey: "form-number",
77
+ ...options,
78
+ validate: (ctx) => {
79
+ var _a, _b;
80
+ const text = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.text;
81
+ if (text === undefined)
82
+ return { ok: false };
83
+ const num = parseFloat(text);
84
+ if (isNaN(num))
85
+ return { ok: false };
86
+ return { ok: true, value: num };
87
+ },
88
+ });
89
+ }
90
+ /**
91
+ * Form field that checks if the incoming update contains a message or
92
+ * channel post with text that can be parsed to an integer, and returns this
93
+ * integer as a `number`. Does not check for captions.
94
+ *
95
+ * The conversion to number uses `parseInt`.
96
+ *
97
+ * Accepts an optional options object that lets you specify the radix to use
98
+ * as well as perform actions when a number is received, when a non-number
99
+ * update is received, and more.
100
+ *
101
+ * @param options Optional options
102
+ */
103
+ async int(options) {
104
+ const { radix, ...opts } = options !== null && options !== void 0 ? options : {};
105
+ return await this.build({
106
+ collationKey: "form-int",
107
+ ...opts,
108
+ validate: (ctx) => {
109
+ var _a, _b;
110
+ const text = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.text;
111
+ if (text === undefined)
112
+ return { ok: false };
113
+ const num = parseInt(text, radix);
114
+ if (isNaN(num))
115
+ return { ok: false };
116
+ return { ok: true, value: num };
117
+ },
118
+ });
119
+ }
120
+ /**
121
+ * Form field that checks if the incoming update contains a message or
122
+ * channel post with one of several predefined strings, and returns the
123
+ * actual text as string. Does not check captions.
124
+ *
125
+ * This is especially useful when working with custom keyboards.
126
+ *
127
+ * ```ts
128
+ * const keyboard = new Keyboard()
129
+ * .text("A").text("B")
130
+ * .text("C").text("D")
131
+ * .oneTime()
132
+ * await ctx.reply("A, B, C, or D?", { reply_markup: keyboard })
133
+ * const answer = await conversation.form.select(["A", "B", "C", "D"], {
134
+ * otherwise: ctx => ctx.reply("Please use one of the buttons!")
135
+ * })
136
+ * switch (answer) {
137
+ * case "A":
138
+ * case "B":
139
+ * case "C":
140
+ * case "D":
141
+ * // ...
142
+ * }
143
+ * ```
144
+ *
145
+ * Accepts an optional options object that lets you perform actions when
146
+ * text is received, when a non-text update is received, and more.
147
+ *
148
+ * @param entries A string array of accepted values
149
+ * @param options Optional options
150
+ */
151
+ async select(entries, options) {
152
+ const e = entries;
153
+ return await this.build({
154
+ collationKey: "form-select",
155
+ ...options,
156
+ validate: (ctx) => {
157
+ var _a, _b;
158
+ const text = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.text;
159
+ if (text === undefined)
160
+ return { ok: false };
161
+ if (!e.includes(text))
162
+ return { ok: false };
163
+ return { ok: true, value: text };
164
+ },
165
+ });
166
+ }
167
+ /**
168
+ * Form field that checks if the incoming update contains a message or
169
+ * channel post with a given type of message entity, and returns this
170
+ * entity. The form field relies on `ctx.entities()` for data extraction, so
171
+ * both texts and captions are checked.
172
+ *
173
+ * Accepts an optional options object that lets you perform actions when
174
+ * text is received, when a non-text update is received, and more.
175
+ *
176
+ * @param type One or more types of message entities to accept
177
+ * @param options Optional options
178
+ */
179
+ async entity(type, options) {
180
+ return await this.build({
181
+ collationKey: "form-entity",
182
+ ...options,
183
+ validate: (ctx) => {
184
+ const entities = ctx.entities(type);
185
+ if (entities.length === 0)
186
+ return { ok: false };
187
+ return { ok: true, value: entities[0] };
188
+ },
189
+ });
190
+ }
191
+ /**
192
+ * Form field that checks if the incoming update contains a message or
193
+ * channel post with an animation, and returns the received animation
194
+ * object.
195
+ *
196
+ * Accepts an optional options object that lets you perform actions when an
197
+ * animation is received, when a non-animation update is received, and more.
198
+ *
199
+ * @param options Optional options
200
+ */
201
+ async animation(options) {
202
+ return await this.build({
203
+ collationKey: "form-animation",
204
+ ...options,
205
+ validate: (ctx) => {
206
+ var _a, _b;
207
+ const animation = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.animation;
208
+ if (animation === undefined)
209
+ return { ok: false };
210
+ return { ok: true, value: animation };
211
+ },
212
+ });
213
+ }
214
+ /**
215
+ * Form field that checks if the incoming update contains a message or
216
+ * channel post with an audio message, and returns the received audio
217
+ * object.
218
+ *
219
+ * Accepts an optional options object that lets you perform actions when an
220
+ * audio message is received, when a non-audio update is received, and more.
221
+ *
222
+ * @param options Optional options
223
+ */
224
+ async audio(options) {
225
+ return await this.build({
226
+ collationKey: "form-audio",
227
+ ...options,
228
+ validate: (ctx) => {
229
+ var _a, _b;
230
+ const audio = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.audio;
231
+ if (audio === undefined)
232
+ return { ok: false };
233
+ return { ok: true, value: audio };
234
+ },
235
+ });
236
+ }
237
+ /**
238
+ * Form field that checks if the incoming update contains a message or
239
+ * channel post with a document message, and returns the received document
240
+ * object.
241
+ *
242
+ * Accepts an optional options object that lets you perform actions when a
243
+ * document message is received, when a non-document update is received, and
244
+ * more.
245
+ *
246
+ * @param options Optional options
247
+ */
248
+ async document(options) {
249
+ return await this.build({
250
+ collationKey: "form-document",
251
+ ...options,
252
+ validate: (ctx) => {
253
+ var _a, _b;
254
+ const document = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.document;
255
+ if (document === undefined)
256
+ return { ok: false };
257
+ return { ok: true, value: document };
258
+ },
259
+ });
260
+ }
261
+ /**
262
+ * Form field that checks if the incoming update contains a message or
263
+ * channel post with paid media, and returns the received paid media object.
264
+ *
265
+ * Accepts an optional options object that lets you perform actions when a
266
+ * paid media message is received, when a non-paid media update is received,
267
+ * and more.
268
+ *
269
+ * @param options Optional options
270
+ */
271
+ async paidMedia(options) {
272
+ return await this.build({
273
+ collationKey: "form-paid_media",
274
+ ...options,
275
+ validate: (ctx) => {
276
+ var _a, _b;
277
+ const paid_media = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.paid_media;
278
+ if (paid_media === undefined)
279
+ return { ok: false };
280
+ return { ok: true, value: paid_media };
281
+ },
282
+ });
283
+ }
284
+ /**
285
+ * Form field that checks if the incoming update contains a message or
286
+ * channel post with a photo, and returns the received array of `PhotoSize`
287
+ * objects.
288
+ *
289
+ * Accepts an optional options object that lets you perform actions when a
290
+ * photo is received, when a non-photo update is received, and more.
291
+ *
292
+ * @param options Optional options
293
+ */
294
+ async photo(options) {
295
+ return await this.build({
296
+ collationKey: "form-photo",
297
+ ...options,
298
+ validate: (ctx) => {
299
+ var _a, _b;
300
+ const photo = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.photo;
301
+ if (photo === undefined)
302
+ return { ok: false };
303
+ return { ok: true, value: photo };
304
+ },
305
+ });
306
+ }
307
+ /**
308
+ * Form field that checks if the incoming update contains a message or
309
+ * channel post with a sticker, and returns the received sticker object.
310
+ *
311
+ * Accepts an optional options object that lets you perform actions when a
312
+ * sticker is received, when a non-sticker update is received, and more.
313
+ *
314
+ * @param options Optional options
315
+ */
316
+ async sticker(options) {
317
+ return await this.build({
318
+ collationKey: "form-sticker",
319
+ ...options,
320
+ validate: (ctx) => {
321
+ var _a, _b;
322
+ const sticker = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.sticker;
323
+ if (sticker === undefined)
324
+ return { ok: false };
325
+ return { ok: true, value: sticker };
326
+ },
327
+ });
328
+ }
329
+ /**
330
+ * Form field that checks if the incoming update contains a message or
331
+ * channel post with a story, and returns the received story object.
332
+ *
333
+ * Accepts an optional options object that lets you perform actions when a
334
+ * story is received, when a non-story update is received, and more.
335
+ *
336
+ * @param options Optional options
337
+ */
338
+ async story(options) {
339
+ return await this.build({
340
+ collationKey: "form-story",
341
+ ...options,
342
+ validate: (ctx) => {
343
+ var _a, _b;
344
+ const story = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.story;
345
+ if (story === undefined)
346
+ return { ok: false };
347
+ return { ok: true, value: story };
348
+ },
349
+ });
350
+ }
351
+ /**
352
+ * Form field that checks if the incoming update contains a message or
353
+ * channel post with a video, and returns the received video object.
354
+ *
355
+ * Accepts an optional options object that lets you perform actions when a
356
+ * video is received, when a non-video update is received, and more.
357
+ *
358
+ * @param options Optional options
359
+ */
360
+ async video(options) {
361
+ return await this.build({
362
+ collationKey: "form-video",
363
+ ...options,
364
+ validate: (ctx) => {
365
+ var _a, _b;
366
+ const video = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.video;
367
+ if (video === undefined)
368
+ return { ok: false };
369
+ return { ok: true, value: video };
370
+ },
371
+ });
372
+ }
373
+ /**
374
+ * Form field that checks if the incoming update contains a message or
375
+ * channel post with a video note, and returns the received video note
376
+ * object.
377
+ *
378
+ * Accepts an optional options object that lets you perform actions when a
379
+ * video note is received, when a non-video note update is received, and
380
+ * more.
381
+ *
382
+ * @param options Optional options
383
+ */
384
+ async video_note(options) {
385
+ return await this.build({
386
+ collationKey: "form-video_note",
387
+ ...options,
388
+ validate: (ctx) => {
389
+ var _a, _b;
390
+ const video_note = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.video_note;
391
+ if (video_note === undefined)
392
+ return { ok: false };
393
+ return { ok: true, value: video_note };
394
+ },
395
+ });
396
+ }
397
+ /**
398
+ * Form field that checks if the incoming update contains a message or
399
+ * channel post with a voice message, and returns the received voice object.
400
+ *
401
+ * Accepts an optional options object that lets you perform actions when a
402
+ * voice message is received, when a non-voice message update is received,
403
+ * and more.
404
+ *
405
+ * @param options Optional options
406
+ */
407
+ async voice(options) {
408
+ return await this.build({
409
+ collationKey: "form-voice",
410
+ ...options,
411
+ validate: (ctx) => {
412
+ var _a, _b;
413
+ const voice = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.voice;
414
+ if (voice === undefined)
415
+ return { ok: false };
416
+ return { ok: true, value: voice };
417
+ },
418
+ });
419
+ }
420
+ /**
421
+ * Form field that checks if the incoming update contains a message or
422
+ * channel post with a contact, and returns the received contact object.
423
+ *
424
+ * Accepts an optional options object that lets you perform actions when a
425
+ * contact is received, when a non-contact update is received, and more.
426
+ *
427
+ * @param options Optional options
428
+ */
429
+ async contact(options) {
430
+ return await this.build({
431
+ collationKey: "form-contact",
432
+ ...options,
433
+ validate: (ctx) => {
434
+ var _a, _b;
435
+ const contact = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.contact;
436
+ if (contact === undefined)
437
+ return { ok: false };
438
+ return { ok: true, value: contact };
439
+ },
440
+ });
441
+ }
442
+ /**
443
+ * Form field that checks if the incoming update contains a message or
444
+ * channel post with dice, and returns the received dice object.
445
+ *
446
+ * Accepts an optional options object that lets you perform actions when
447
+ * dice are received, when a non-dice update is received, and more.
448
+ *
449
+ * @param options Optional options
450
+ */
451
+ async dice(options) {
452
+ return await this.build({
453
+ collationKey: "form-dice",
454
+ ...options,
455
+ validate: (ctx) => {
456
+ var _a, _b;
457
+ const dice = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.dice;
458
+ if (dice === undefined)
459
+ return { ok: false };
460
+ return { ok: true, value: dice };
461
+ },
462
+ });
463
+ }
464
+ /**
465
+ * Form field that checks if the incoming update contains a message or
466
+ * channel post with a game, and returns the received game object.
467
+ *
468
+ * Accepts an optional options object that lets you perform actions when a
469
+ * game is received, when a non-game update is received, and more.
470
+ *
471
+ * @param options Optional options
472
+ */
473
+ async game(options) {
474
+ return await this.build({
475
+ collationKey: "form-game",
476
+ ...options,
477
+ validate: (ctx) => {
478
+ var _a, _b;
479
+ const game = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.game;
480
+ if (game === undefined)
481
+ return { ok: false };
482
+ return { ok: true, value: game };
483
+ },
484
+ });
485
+ }
486
+ /**
487
+ * Form field that checks if the incoming update contains a message or
488
+ * channel post with a poll, and returns the received poll object.
489
+ *
490
+ * Accepts an optional options object that lets you perform actions when a
491
+ * poll is received, when a non-poll update is received, and more.
492
+ *
493
+ * @param options Optional options
494
+ */
495
+ async poll(options) {
496
+ return await this.build({
497
+ collationKey: "form-poll",
498
+ ...options,
499
+ validate: (ctx) => {
500
+ var _a, _b;
501
+ const poll = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.poll;
502
+ if (poll === undefined)
503
+ return { ok: false };
504
+ return { ok: true, value: poll };
505
+ },
506
+ });
507
+ }
508
+ /**
509
+ * Form field that checks if the incoming update contains a message or
510
+ * channel post with a venue, and returns the received venue object.
511
+ *
512
+ * Accepts an optional options object that lets you perform actions when a
513
+ * venue is received, when a non-venue update is received, and more.
514
+ *
515
+ * @param options Optional options
516
+ */
517
+ async venue(options) {
518
+ return await this.build({
519
+ collationKey: "form-venue",
520
+ ...options,
521
+ validate: (ctx) => {
522
+ var _a, _b;
523
+ const venue = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.venue;
524
+ if (venue === undefined)
525
+ return { ok: false };
526
+ return { ok: true, value: venue };
527
+ },
528
+ });
529
+ }
530
+ /**
531
+ * Form field that checks if the incoming update contains a message or
532
+ * channel post with a location, and returns the received location object.
533
+ *
534
+ * Accepts an optional options object that lets you perform actions when a
535
+ * location is received, when a non-location update is received, and more.
536
+ *
537
+ * @param options Optional options
538
+ */
539
+ async location(options) {
540
+ return await this.build({
541
+ collationKey: "form-location",
542
+ ...options,
543
+ validate: (ctx) => {
544
+ var _a, _b;
545
+ const location = (_b = ((_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost)) === null || _b === void 0 ? void 0 : _b.location;
546
+ if (location === undefined)
547
+ return { ok: false };
548
+ return { ok: true, value: location };
549
+ },
550
+ });
551
+ }
552
+ /**
553
+ * Form field that checks if the incoming update contains a message or
554
+ * channel post with a photo or video, and returns the received media
555
+ * object.
556
+ *
557
+ * Accepts an optional options object that lets you perform actions when a
558
+ * media is received, when a non-media update is received, and more.
559
+ *
560
+ * @param options Optional options
561
+ */
562
+ async media(options) {
563
+ return await this.build({
564
+ collationKey: "form-location",
565
+ ...options,
566
+ validate: (ctx) => {
567
+ var _a, _b;
568
+ const msg = (_a = ctx.message) !== null && _a !== void 0 ? _a : ctx.channelPost;
569
+ const media = (_b = msg === null || msg === void 0 ? void 0 : msg.photo) !== null && _b !== void 0 ? _b : msg === null || msg === void 0 ? void 0 : msg.video;
570
+ if (media === undefined)
571
+ return { ok: false };
572
+ return { ok: true, value: media };
573
+ },
574
+ });
575
+ }
576
+ /**
577
+ * Form field that checks if the incoming update contains a message or
578
+ * channel post with a file, calls `await ctx.getFile()`, and returns the
579
+ * received file object.
580
+ *
581
+ * Accepts an optional options object that lets you perform actions when a
582
+ * file is received, when a non-file update is received, and more.
583
+ *
584
+ * @param options Optional options
585
+ */
586
+ async file(options) {
587
+ return await this.build({
588
+ collationKey: "form-location",
589
+ ...options,
590
+ validate: async (ctx) => {
591
+ if (!ctx.has(":file"))
592
+ return { ok: false };
593
+ const file = await ctx.getFile();
594
+ return { ok: true, value: file };
595
+ },
596
+ });
597
+ }
598
+ }