@grammy-x/conversations 0.2.0 → 2.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/dist/index.cjs ADDED
@@ -0,0 +1,451 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ QuestionHelper: () => QuestionHelper,
24
+ createCustomConversation: () => createCustomConversation
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/question-helper.ts
29
+ var import_grammy = require("grammy");
30
+ var import_core = require("@grammy-x/core");
31
+ function randomInteger(minimum, maximum) {
32
+ return Math.floor(Math.random() * (maximum - minimum + 1) + minimum);
33
+ }
34
+ var QuestionHelper = class {
35
+ conversation;
36
+ config;
37
+ ctx;
38
+ message_id;
39
+ constructor(conversation, ctx, config) {
40
+ this.conversation = conversation;
41
+ this.config = config ?? {};
42
+ this.ctx = ctx;
43
+ }
44
+ updateCtx = (ctx) => {
45
+ Object.keys(this.ctx).forEach((key) => delete this.ctx[key]);
46
+ Object.assign(this.ctx, ctx);
47
+ };
48
+ delete = async () => {
49
+ if (this.message_id) {
50
+ await this.ctx.api.deleteMessage(this.ctx.from.id, this.message_id);
51
+ }
52
+ };
53
+ back = async () => {
54
+ const gx = this.ctx.session?._gx;
55
+ if (gx?.history.length > 0) {
56
+ gx.history.pop();
57
+ }
58
+ const targetId = gx?.history.length > 0 ? gx.history.pop() : void 0;
59
+ if (targetId) {
60
+ const menu = import_core.GlobalMenuRegistry.get(targetId);
61
+ if (menu) return menu.send(this.ctx);
62
+ }
63
+ };
64
+ reply = async (text, options) => {
65
+ let newText = text;
66
+ const mergedOptions = { ...this.config, ...options };
67
+ if (mergedOptions.autoBold !== false) newText = `<b>${newText}</b>`;
68
+ if (options?.markup instanceof import_grammy.InlineKeyboard) mergedOptions.markup = options.markup;
69
+ if (!mergedOptions.markup) mergedOptions.markup = new import_grammy.InlineKeyboard();
70
+ if (mergedOptions.markup instanceof import_grammy.InlineKeyboard && this.config.markup instanceof import_grammy.InlineKeyboard)
71
+ mergedOptions.markup.append(this.config.markup);
72
+ if (mergedOptions.fastMenu && mergedOptions.markup instanceof import_grammy.InlineKeyboard) {
73
+ const markup = mergedOptions.markup;
74
+ markup.text(mergedOptions.fastMenuText ?? this.config?.fastMenuText ?? "Main Menu", mergedOptions.fastMenuCallbackData ?? "start");
75
+ }
76
+ if (options?.sendContinueButton && mergedOptions.continueInlineEnd && mergedOptions.markup instanceof import_grammy.InlineKeyboard) {
77
+ const markup = mergedOptions.markup;
78
+ markup.text(options?.continueButton ?? this.config?.continueButton ?? "Continue", "continue");
79
+ }
80
+ const message = await (0, import_core.smartReply)(this.ctx, text, {
81
+ options: {
82
+ entities: mergedOptions.entities,
83
+ reply_markup: mergedOptions.markup
84
+ },
85
+ messageToEdit: this.message_id,
86
+ newMessage: mergedOptions?.newMessage,
87
+ embolden: false,
88
+ dedent: false
89
+ });
90
+ this.message_id = message?.message_id ?? this.message_id;
91
+ return message;
92
+ };
93
+ getCallbackDataFromKeyboard = (keyboard) => {
94
+ if (keyboard && keyboard instanceof import_grammy.InlineKeyboard)
95
+ return keyboard.inline_keyboard.flat().map((b) => b.callback_data).filter(Boolean);
96
+ return [];
97
+ };
98
+ textParser = async (text, parser, validator, options) => {
99
+ const message = await this.reply(text, options);
100
+ const additionalTriggers = this.getCallbackDataFromKeyboard(options?.markup);
101
+ const answer = await this.conversation.waitUntil(
102
+ (ctx) => import_grammy.Context.has.callbackQuery(additionalTriggers)(ctx) || ctx.has(":text")
103
+ );
104
+ this.updateCtx(answer);
105
+ const callbackQuery = answer.callbackQuery?.data;
106
+ if (callbackQuery) return { callbackQuery, answerCtx: answer, message };
107
+ if (answer.message?.text?.startsWith("/")) {
108
+ await this.ctx.api.deleteMessage(this.ctx.from.id, answer.message.message_id).catch(() => {
109
+ });
110
+ const cmd = answer.message.text.split(" ")[0];
111
+ const err = new Error(`CommandInterrupt:${cmd}`);
112
+ err.name = "CommandInterruptError";
113
+ err.ctx = answer;
114
+ throw err;
115
+ }
116
+ const result = parser(answer.msg.text);
117
+ await this.ctx.api.deleteMessage(this.ctx.from.id, answer.msg.message_id).catch(() => {
118
+ });
119
+ if (!validator(result)) return await this.conversation.skip();
120
+ return { result, answerCtx: answer, message };
121
+ };
122
+ text = (text, options) => this.textParser(
123
+ text,
124
+ (r) => r,
125
+ () => true,
126
+ options
127
+ );
128
+ int = (text, options) => this.textParser(text, parseInt, (r) => !isNaN(r), options);
129
+ float = (text, options) => this.textParser(text, parseFloat, (r) => !isNaN(r), options);
130
+ chat = async (text, options) => {
131
+ const chat = options.chat;
132
+ const markup = new import_grammy.Keyboard().requestChat("\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0447\u0430\u0442 \u{1F50D}", randomInteger(0, 999999), {
133
+ chat_is_channel: chat.isChannel,
134
+ bot_administrator_rights: chat.requiredBotRights,
135
+ bot_is_member: chat.botIsMember,
136
+ request_photo: chat.requestPhoto,
137
+ request_title: chat.requestTitle,
138
+ request_username: chat.requestUsername ?? true,
139
+ user_administrator_rights: chat.requiredUserRights
140
+ }).oneTime(true).resized(true);
141
+ const message = await this.reply(text, { ...options, markup });
142
+ const answer = await this.conversation.waitFor(":chat_shared");
143
+ this.updateCtx(answer);
144
+ await answer?.msg?.delete?.().catch?.(() => {
145
+ });
146
+ return answer.msg.chat_shared;
147
+ };
148
+ user = async (text, options) => {
149
+ const user = options?.user;
150
+ const markup = new import_grammy.Keyboard().requestUsers("\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u{1F50D}", randomInteger(0, 999999), {
151
+ max_quantity: 1,
152
+ request_name: user?.requestName,
153
+ request_photo: user?.requestPhoto,
154
+ request_username: user?.requestUsername ?? true,
155
+ user_is_bot: user?.isBot,
156
+ user_is_premium: user?.isPremium
157
+ }).oneTime(true).resized(true);
158
+ const message = await this.reply(text, { ...options, markup });
159
+ const answer = await this.conversation.waitFor(":users_shared");
160
+ this.updateCtx(answer);
161
+ await answer?.msg?.delete?.().catch?.(() => {
162
+ });
163
+ return answer.msg.users_shared?.users[0];
164
+ };
165
+ users = async (text, options) => {
166
+ const users = options?.users;
167
+ const markup = new import_grammy.Keyboard().requestUsers("\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u{1F50D}", randomInteger(0, 999999), {
168
+ max_quantity: users?.maxQuantity,
169
+ request_name: users?.requestName,
170
+ request_photo: users?.requestPhoto,
171
+ request_username: users?.requestUsername ?? true,
172
+ user_is_bot: users?.isBot,
173
+ user_is_premium: users?.isPremium
174
+ }).oneTime(true).resized(true);
175
+ const message = await this.reply(text, { ...options, markup });
176
+ const answer = await this.conversation.waitFor(":users_shared");
177
+ this.updateCtx(answer);
178
+ await answer?.msg?.delete?.().catch?.(() => {
179
+ });
180
+ return answer.msg.users_shared;
181
+ };
182
+ contact = async (text, options) => {
183
+ const markup = new import_grammy.Keyboard().requestContact("\u041F\u043E\u0434\u0435\u043B\u0438\u0442\u044C\u0441\u044F \u043A\u043E\u043D\u0442\u0430\u043A\u0442\u043E\u043C \u{1F4DE}").oneTime(true).resized(true);
184
+ const message = await this.reply(text, { ...options, markup });
185
+ const answer = await this.conversation.waitFor(":contact");
186
+ this.updateCtx(answer);
187
+ await answer?.msg?.delete?.().catch?.(() => {
188
+ });
189
+ return answer.msg.contact;
190
+ };
191
+ location = async (text, options) => {
192
+ const markup = new import_grammy.Keyboard().requestLocation("\u041F\u043E\u0434\u0435\u043B\u0438\u0442\u044C\u0441\u044F \u0433\u0435\u043E\u043F\u043E\u0437\u0438\u0446\u0438\u0435\u0439 \u{1F4CD}").oneTime(true).resized(true);
193
+ const message = await this.reply(text, { ...options, markup });
194
+ const answer = await this.conversation.waitFor(":location");
195
+ this.updateCtx(answer);
196
+ await answer?.msg?.delete?.().catch?.(() => {
197
+ });
198
+ return answer.msg.location;
199
+ };
200
+ poll = async (text, options) => {
201
+ const pollType = options?.poll?.type;
202
+ const markup = new import_grammy.Keyboard().requestPoll("\u041E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u043E\u043F\u0440\u043E\u0441 \u{1F4CA}", pollType).oneTime(true).resized(true);
203
+ const message = await this.reply(text, { ...options, markup });
204
+ const answer = await this.conversation.waitFor(":poll");
205
+ this.updateCtx(answer);
206
+ await answer?.msg?.delete?.().catch?.(() => {
207
+ });
208
+ return answer.msg.poll;
209
+ };
210
+ renderPaginationButtons = (pagesCount, currentPage, markup, columnCount, extraControls) => {
211
+ const oddColumnCount = columnCount % 2 === 0 ? columnCount + 1 : columnCount;
212
+ const emptyColumns = oddColumnCount >= 5 ? extraControls ? 0 : 1 : 0;
213
+ for (let i = 0; i < emptyColumns; i++) {
214
+ markup.text(" ", " ");
215
+ }
216
+ if (extraControls) {
217
+ markup.text(currentPage > 2 ? "\u22D8" : " ", "first");
218
+ }
219
+ markup.text(currentPage > 1 ? "\u2190" : " ", "prev");
220
+ markup.text(currentPage + " / " + pagesCount, "page");
221
+ markup.text(currentPage < pagesCount ? "\u2192" : " ", "next");
222
+ if (extraControls) {
223
+ markup.text(currentPage < pagesCount - 1 ? "\u22D9" : " ", "last");
224
+ }
225
+ for (let i = 0; i < emptyColumns; i++) {
226
+ markup.text(" ", " ");
227
+ }
228
+ return markup.row();
229
+ };
230
+ resetChoice = (session) => {
231
+ if (!session._gx.conversations) session._gx.conversations = {
232
+ currentChoices: /* @__PURE__ */ new Set(),
233
+ currentPage: 1
234
+ };
235
+ else {
236
+ session._gx.conversations.currentChoices = /* @__PURE__ */ new Set();
237
+ session._gx.conversations.currentPage = 1;
238
+ }
239
+ };
240
+ async basicChoice(text, choices, multi = false, options, inProgress) {
241
+ const markup = new import_grammy.InlineKeyboard();
242
+ const session = await this.conversation.external(
243
+ () => this.ctx.session
244
+ );
245
+ if (!session._gx.conversations) this.resetChoice(session);
246
+ await this.conversation.external(() => !inProgress && this.resetChoice(session));
247
+ let currentRow = [];
248
+ const columnCount = options?.columnCount ?? this.config.columnCount ?? 1;
249
+ const rowCount = options?.rowCount ?? this.config.rowCount ?? 3;
250
+ const filledChoices = options?.pagination?.enabled ? choices.concat(
251
+ Array.from({ length: columnCount * rowCount - choices.length % (columnCount * rowCount) }).map(
252
+ () => [" ", "empty"]
253
+ )
254
+ ) : choices;
255
+ const pagesCount = Math.ceil(choices.length / (columnCount * rowCount));
256
+ const currentPage = session._gx.conversations.currentPage ?? 1;
257
+ let currentRowId = 0;
258
+ for (const [choiceId, choice] of filledChoices.entries()) {
259
+ if (options?.pagination?.enabled && choiceId < (currentPage - 1) * columnCount * rowCount) continue;
260
+ const checked = session._gx.conversations.currentChoices.has(choice[1]);
261
+ currentRow.push([`${choice[0]}${checked ? " \u2705" : ""}`, choice[1]]);
262
+ if (currentRow.length === columnCount) {
263
+ currentRow.forEach(
264
+ ([label, value]) => markup.text(label, value == "empty" ? "empty" : `answer:${value}`)
265
+ );
266
+ markup.row();
267
+ currentRow = [];
268
+ currentRowId++;
269
+ if (options?.pagination?.enabled && (currentRowId === rowCount || choiceId === filledChoices.length - 1)) {
270
+ this.renderPaginationButtons(
271
+ pagesCount,
272
+ currentPage,
273
+ markup,
274
+ columnCount,
275
+ options?.pagination?.extraControls ?? false
276
+ );
277
+ break;
278
+ }
279
+ }
280
+ }
281
+ if (currentRow.length > 0) {
282
+ currentRow.forEach(([label, value]) => {
283
+ markup.text(label, `answer:${value}`);
284
+ });
285
+ markup.row();
286
+ }
287
+ const additionalTriggers = this.getCallbackDataFromKeyboard(options?.markup);
288
+ if (options?.markup instanceof import_grammy.InlineKeyboard) markup.append(options.markup).row();
289
+ const sendContinueButton = session._gx.conversations.currentChoices.size > 0;
290
+ const continueInlineEnd = options?.continueInlineEnd ?? this.config.continueInlineEnd;
291
+ if (multi && !options?.noChoiceAllowed && !continueInlineEnd && sendContinueButton)
292
+ markup.text(options?.continueButton ?? this.config?.continueButton ?? "Continue", "continue").row();
293
+ const messageText = typeof text === "function" ? await text(
294
+ Array.from(session._gx.conversations.currentChoices),
295
+ session._gx.conversations.currentPage,
296
+ pagesCount
297
+ ) : text;
298
+ const message = await this.reply(messageText, {
299
+ ...options,
300
+ markup,
301
+ continueButton: options?.continueButton,
302
+ continueInlineEnd,
303
+ sendContinueButton: continueInlineEnd && sendContinueButton
304
+ });
305
+ let additionalTriggerCalled;
306
+ let answer;
307
+ const paginationsCallbacks = ["prev", "next", "page", "empty", "first", "last"];
308
+ do {
309
+ answer = await this.conversation.waitForCallbackQuery([
310
+ ...choices.map((c) => `answer:${c[1]}`),
311
+ ...multi ? ["continue"] : [],
312
+ ...options?.pagination?.enabled ? paginationsCallbacks : [],
313
+ ...additionalTriggers
314
+ ]);
315
+ this.updateCtx(answer);
316
+ const callbackData2 = answer.callbackQuery.data;
317
+ additionalTriggerCalled = additionalTriggers.includes(callbackData2);
318
+ if (callbackData2 == "continue" || additionalTriggerCalled) {
319
+ const choices2 = Array.from(session._gx.conversations.currentChoices);
320
+ this.ctx.session._gx.conversations.currentChoices = /* @__PURE__ */ new Set();
321
+ if (additionalTriggerCalled) return { result: choices2, callbackQuery: callbackData2, message };
322
+ return { result: choices2, message };
323
+ }
324
+ } while (additionalTriggerCalled);
325
+ const questionData = session._gx.conversations;
326
+ const callbackData = answer.callbackQuery.data;
327
+ const data = callbackData.split(":")[1];
328
+ const skip = await this.conversation.external(async () => {
329
+ if (callbackData == "prev") questionData.currentPage = Math.max(currentPage - 1, 1);
330
+ if (callbackData == "next") questionData.currentPage = Math.min(currentPage + 1, pagesCount);
331
+ if (callbackData == "first") questionData.currentPage = 1;
332
+ if (callbackData == "last") questionData.currentPage = pagesCount;
333
+ if (data) {
334
+ if (questionData.currentChoices.has(data)) questionData.currentChoices.delete(data);
335
+ else questionData.currentChoices.add(data);
336
+ }
337
+ ;
338
+ this.ctx.session._gx.conversations = questionData;
339
+ if (paginationsCallbacks.includes(callbackData) && questionData.currentPage == currentPage) {
340
+ await this.ctx.answerCallbackQuery();
341
+ return true;
342
+ }
343
+ });
344
+ if (skip) return this.conversation.skip({ drop: true });
345
+ if (!multi && data) {
346
+ ;
347
+ this.ctx.session._gx.conversations.currentChoices = /* @__PURE__ */ new Set();
348
+ return {
349
+ result: data,
350
+ message
351
+ };
352
+ }
353
+ return this.basicChoice(text, choices, multi, options, true);
354
+ }
355
+ choice = async (text, choices, options) => this.basicChoice(text, choices, false, options);
356
+ multi = async (text, choices, options) => this.basicChoice(text, choices, true, options);
357
+ boolean = async (text, yesNoStrings, options) => {
358
+ const { result, message } = await this.choice(
359
+ text,
360
+ [
361
+ [yesNoStrings?.[0] ?? "\u2705 \u0414\u0430", "true"],
362
+ [yesNoStrings?.[1] ?? "\u274C \u041D\u0435\u0442", "false"]
363
+ ],
364
+ { columnCount: 2, ...options }
365
+ );
366
+ const boolResult = result === "true";
367
+ return { result: boolResult, message };
368
+ };
369
+ photo = async (text, options) => {
370
+ const message = await this.reply(text, options);
371
+ const answer = await this.conversation.waitFor(":photo");
372
+ this.updateCtx(answer);
373
+ await answer?.msg?.delete?.().catch?.(() => {
374
+ });
375
+ const photo = answer.msg.photo?.[0];
376
+ if (!photo) {
377
+ throw new Error("No photo found in update");
378
+ }
379
+ return photo.file_id;
380
+ };
381
+ file = async (text, options) => {
382
+ const message = await this.reply(text, options);
383
+ const answer = await this.conversation.waitFor(":file");
384
+ this.updateCtx(answer);
385
+ await answer?.msg?.delete?.().catch?.(() => {
386
+ });
387
+ return answer.msg.document?.file_id;
388
+ };
389
+ };
390
+
391
+ // src/conversation.ts
392
+ var import_conversations = require("@grammyjs/conversations");
393
+ var import_hydrate = require("@grammyjs/hydrate");
394
+ var import_core2 = require("@grammy-x/core");
395
+ function createCustomConversation(builder, config) {
396
+ let cfg = typeof config === "string" ? { id: config } : config;
397
+ cfg = cfg ?? {};
398
+ const id = cfg.id ?? builder.name;
399
+ cfg.id = id;
400
+ import_core2.GlobalMenuRegistry.register({
401
+ menuName: id,
402
+ send: async (ctx) => {
403
+ if (!ctx.conversation) {
404
+ console.error(`[Grammy-X] Cannot enter conversation '${id}': ctx.conversation is undefined. Make sure bot.use(conversations()) is registered before components that use it.`);
405
+ return;
406
+ }
407
+ if (ctx.conversation.active) {
408
+ await ctx.conversation.exit();
409
+ }
410
+ return ctx.conversation.enter(id);
411
+ }
412
+ });
413
+ return (0, import_conversations.createConversation)(
414
+ (async (conversation, ctx) => {
415
+ await conversation.run((0, import_hydrate.hydrate)());
416
+ const gx = ctx.session?._gx;
417
+ if (gx && gx.history[gx.history.length - 1] !== id) {
418
+ gx.history.push(id);
419
+ if (gx.history.length > 20) gx.history.shift();
420
+ }
421
+ try {
422
+ return await builder(conversation, ctx);
423
+ } catch (e) {
424
+ if (e.name === "CommandInterruptError") {
425
+ const cmd = e.message.split(":")[1];
426
+ const opts = (0, import_core2.getGrammyXOptions)(e.ctx);
427
+ const targetMenu = opts?.interruptCommands?.[cmd];
428
+ if (targetMenu) {
429
+ try {
430
+ if (typeof targetMenu === "string") {
431
+ await e.ctx.menu.nav(targetMenu);
432
+ } else if (typeof targetMenu.send === "function") {
433
+ await targetMenu.send(e.ctx);
434
+ }
435
+ } catch (err) {
436
+ console.error(`Could not auto-nav to target menu for command ${cmd}`, err);
437
+ }
438
+ }
439
+ return;
440
+ }
441
+ throw e;
442
+ }
443
+ }),
444
+ cfg
445
+ );
446
+ }
447
+ // Annotate the CommonJS export names for ESM import in node:
448
+ 0 && (module.exports = {
449
+ QuestionHelper,
450
+ createCustomConversation
451
+ });
@@ -0,0 +1,116 @@
1
+ import * as grammy_types from 'grammy/types';
2
+ import { ChatAdministratorRights, ChatShared, UsersShared, Contact, Location, Poll } from 'grammy/types';
3
+ import { Conversation, ConversationConfig } from '@grammyjs/conversations';
4
+ import { Context, InlineKeyboard, Keyboard, MiddlewareFn } from 'grammy';
5
+
6
+ type MaybePromise<T> = PromiseLike<T> | T;
7
+ type ButtonsMarkup = InlineKeyboard | Keyboard;
8
+ interface QuestionParameters {
9
+ markup?: ButtonsMarkup;
10
+ autoBold?: boolean;
11
+ entities?: any[];
12
+ fastMenu?: boolean;
13
+ fastMenuCallbackData?: string;
14
+ fastMenuText?: string;
15
+ newMessage?: boolean;
16
+ }
17
+ interface QuestionCallbackParameters extends QuestionParameters {
18
+ columnCount?: number;
19
+ noChoiceAllowed?: boolean;
20
+ rowCount?: number;
21
+ continueButton?: string;
22
+ pagination?: {
23
+ enabled: boolean;
24
+ extraControls?: boolean;
25
+ };
26
+ }
27
+ interface QuestionMultiParameters extends QuestionCallbackParameters {
28
+ continueInlineEnd?: boolean;
29
+ }
30
+ interface QuestionChatParameters extends QuestionParameters {
31
+ chat: {
32
+ requiredUserRights?: ChatAdministratorRights;
33
+ requiredBotRights?: ChatAdministratorRights;
34
+ botIsMember?: boolean;
35
+ isChannel: boolean;
36
+ requestTitle?: boolean;
37
+ requestUsername?: boolean;
38
+ requestPhoto?: boolean;
39
+ };
40
+ }
41
+ interface QuestionUserParameters extends QuestionParameters {
42
+ user?: {
43
+ isBot?: boolean;
44
+ isPremium?: boolean;
45
+ requestName?: boolean;
46
+ requestUsername?: boolean;
47
+ requestPhoto?: boolean;
48
+ };
49
+ }
50
+ interface QuestionUsersParameters extends QuestionParameters {
51
+ users?: {
52
+ maxQuantity?: number;
53
+ isBot?: boolean;
54
+ isPremium?: boolean;
55
+ requestName?: boolean;
56
+ requestUsername?: boolean;
57
+ requestPhoto?: boolean;
58
+ };
59
+ }
60
+ interface QuestionPollParameters extends QuestionParameters {
61
+ poll?: {
62
+ type?: "regular" | "quiz";
63
+ };
64
+ }
65
+ type QuestionUniversalParameters = Partial<QuestionMultiParameters & QuestionChatParameters & QuestionUserParameters & QuestionUsersParameters & QuestionPollParameters>;
66
+ interface TextParserResult<R> {
67
+ result?: R;
68
+ callbackQuery?: string;
69
+ answerCtx?: any;
70
+ message?: any;
71
+ }
72
+ declare class QuestionHelper<C extends Context = Context, T extends Conversation<C> = Conversation<C>> {
73
+ private conversation;
74
+ private config;
75
+ private ctx;
76
+ message_id?: number;
77
+ constructor(conversation: T, ctx: C, config?: QuestionUniversalParameters);
78
+ private updateCtx;
79
+ delete: () => Promise<void>;
80
+ back: () => Promise<unknown>;
81
+ private reply;
82
+ private getCallbackDataFromKeyboard;
83
+ private textParser;
84
+ text: (text: string, options?: QuestionParameters) => Promise<TextParserResult<string>>;
85
+ int: (text: string, options?: QuestionParameters) => Promise<TextParserResult<number>>;
86
+ float: (text: string, options?: QuestionParameters) => Promise<TextParserResult<number>>;
87
+ chat: (text: string, options: QuestionChatParameters) => Promise<ChatShared>;
88
+ user: (text: string, options?: QuestionUserParameters) => Promise<grammy_types.SharedUser>;
89
+ users: (text: string, options?: QuestionUsersParameters) => Promise<UsersShared>;
90
+ contact: (text: string, options?: QuestionParameters) => Promise<Contact>;
91
+ location: (text: string, options?: QuestionParameters) => Promise<Location>;
92
+ poll: (text: string, options?: QuestionPollParameters) => Promise<Poll>;
93
+ private renderPaginationButtons;
94
+ private resetChoice;
95
+ private basicChoice;
96
+ choice: <const R_1 extends string>(text: string, choices: [string, R_1][], options?: QuestionCallbackParameters) => Promise<{
97
+ result: R_1;
98
+ message: any;
99
+ }>;
100
+ multi: <const R_1 extends string>(text: string | ((choices: R_1[], currentPage: number, pagesCount: number) => MaybePromise<string>), choices: [string, R_1][], options?: QuestionCallbackParameters) => Promise<{
101
+ result: R_1[];
102
+ callbackData?: string;
103
+ message: any;
104
+ }>;
105
+ boolean: (text: string, yesNoStrings?: string[], options?: QuestionCallbackParameters) => Promise<{
106
+ result: boolean;
107
+ message: any;
108
+ }>;
109
+ photo: (text: string, options?: QuestionParameters) => Promise<string>;
110
+ file: (text: string, options?: QuestionParameters) => Promise<string>;
111
+ }
112
+
113
+ type ConversationFn<C extends Context = Context> = (conversation: Conversation<C>, ctx: C) => unknown | Promise<unknown>;
114
+ declare function createCustomConversation<C extends Context = Context>(builder: ConversationFn<C>, config?: string | ConversationConfig): MiddlewareFn<any>;
115
+
116
+ export { type ConversationFn, QuestionHelper, createCustomConversation };
@@ -0,0 +1,116 @@
1
+ import * as grammy_types from 'grammy/types';
2
+ import { ChatAdministratorRights, ChatShared, UsersShared, Contact, Location, Poll } from 'grammy/types';
3
+ import { Conversation, ConversationConfig } from '@grammyjs/conversations';
4
+ import { Context, InlineKeyboard, Keyboard, MiddlewareFn } from 'grammy';
5
+
6
+ type MaybePromise<T> = PromiseLike<T> | T;
7
+ type ButtonsMarkup = InlineKeyboard | Keyboard;
8
+ interface QuestionParameters {
9
+ markup?: ButtonsMarkup;
10
+ autoBold?: boolean;
11
+ entities?: any[];
12
+ fastMenu?: boolean;
13
+ fastMenuCallbackData?: string;
14
+ fastMenuText?: string;
15
+ newMessage?: boolean;
16
+ }
17
+ interface QuestionCallbackParameters extends QuestionParameters {
18
+ columnCount?: number;
19
+ noChoiceAllowed?: boolean;
20
+ rowCount?: number;
21
+ continueButton?: string;
22
+ pagination?: {
23
+ enabled: boolean;
24
+ extraControls?: boolean;
25
+ };
26
+ }
27
+ interface QuestionMultiParameters extends QuestionCallbackParameters {
28
+ continueInlineEnd?: boolean;
29
+ }
30
+ interface QuestionChatParameters extends QuestionParameters {
31
+ chat: {
32
+ requiredUserRights?: ChatAdministratorRights;
33
+ requiredBotRights?: ChatAdministratorRights;
34
+ botIsMember?: boolean;
35
+ isChannel: boolean;
36
+ requestTitle?: boolean;
37
+ requestUsername?: boolean;
38
+ requestPhoto?: boolean;
39
+ };
40
+ }
41
+ interface QuestionUserParameters extends QuestionParameters {
42
+ user?: {
43
+ isBot?: boolean;
44
+ isPremium?: boolean;
45
+ requestName?: boolean;
46
+ requestUsername?: boolean;
47
+ requestPhoto?: boolean;
48
+ };
49
+ }
50
+ interface QuestionUsersParameters extends QuestionParameters {
51
+ users?: {
52
+ maxQuantity?: number;
53
+ isBot?: boolean;
54
+ isPremium?: boolean;
55
+ requestName?: boolean;
56
+ requestUsername?: boolean;
57
+ requestPhoto?: boolean;
58
+ };
59
+ }
60
+ interface QuestionPollParameters extends QuestionParameters {
61
+ poll?: {
62
+ type?: "regular" | "quiz";
63
+ };
64
+ }
65
+ type QuestionUniversalParameters = Partial<QuestionMultiParameters & QuestionChatParameters & QuestionUserParameters & QuestionUsersParameters & QuestionPollParameters>;
66
+ interface TextParserResult<R> {
67
+ result?: R;
68
+ callbackQuery?: string;
69
+ answerCtx?: any;
70
+ message?: any;
71
+ }
72
+ declare class QuestionHelper<C extends Context = Context, T extends Conversation<C> = Conversation<C>> {
73
+ private conversation;
74
+ private config;
75
+ private ctx;
76
+ message_id?: number;
77
+ constructor(conversation: T, ctx: C, config?: QuestionUniversalParameters);
78
+ private updateCtx;
79
+ delete: () => Promise<void>;
80
+ back: () => Promise<unknown>;
81
+ private reply;
82
+ private getCallbackDataFromKeyboard;
83
+ private textParser;
84
+ text: (text: string, options?: QuestionParameters) => Promise<TextParserResult<string>>;
85
+ int: (text: string, options?: QuestionParameters) => Promise<TextParserResult<number>>;
86
+ float: (text: string, options?: QuestionParameters) => Promise<TextParserResult<number>>;
87
+ chat: (text: string, options: QuestionChatParameters) => Promise<ChatShared>;
88
+ user: (text: string, options?: QuestionUserParameters) => Promise<grammy_types.SharedUser>;
89
+ users: (text: string, options?: QuestionUsersParameters) => Promise<UsersShared>;
90
+ contact: (text: string, options?: QuestionParameters) => Promise<Contact>;
91
+ location: (text: string, options?: QuestionParameters) => Promise<Location>;
92
+ poll: (text: string, options?: QuestionPollParameters) => Promise<Poll>;
93
+ private renderPaginationButtons;
94
+ private resetChoice;
95
+ private basicChoice;
96
+ choice: <const R_1 extends string>(text: string, choices: [string, R_1][], options?: QuestionCallbackParameters) => Promise<{
97
+ result: R_1;
98
+ message: any;
99
+ }>;
100
+ multi: <const R_1 extends string>(text: string | ((choices: R_1[], currentPage: number, pagesCount: number) => MaybePromise<string>), choices: [string, R_1][], options?: QuestionCallbackParameters) => Promise<{
101
+ result: R_1[];
102
+ callbackData?: string;
103
+ message: any;
104
+ }>;
105
+ boolean: (text: string, yesNoStrings?: string[], options?: QuestionCallbackParameters) => Promise<{
106
+ result: boolean;
107
+ message: any;
108
+ }>;
109
+ photo: (text: string, options?: QuestionParameters) => Promise<string>;
110
+ file: (text: string, options?: QuestionParameters) => Promise<string>;
111
+ }
112
+
113
+ type ConversationFn<C extends Context = Context> = (conversation: Conversation<C>, ctx: C) => unknown | Promise<unknown>;
114
+ declare function createCustomConversation<C extends Context = Context>(builder: ConversationFn<C>, config?: string | ConversationConfig): MiddlewareFn<any>;
115
+
116
+ export { type ConversationFn, QuestionHelper, createCustomConversation };