UNPKG

@gramio/prompt

Version:
193 lines (187 loc) 7.12 kB
'use strict'; var gramio = require('gramio'); class PromptCancelError extends Error { constructor(type) { super(type); this.type = type; } } function isObject(item) { return item && typeof item === "object" && !Array.isArray(item); } function deepMerge(target, source) { const output = Object.assign({}, target); if (isObject(target) && isObject(source)) { for (const key of Object.keys(source)) { if (isObject(source[key])) { if (!(key in target)) Object.assign(output, { [key]: source[key] }); else output[key] = deepMerge(target[key], source[key]); } else { Object.assign(output, { [key]: source[key] }); } } } return output; } const events = [ "message", "edited_message", "channel_post", "edited_channel_post", "callback_query" ]; function isEvent(maybeEvent) { if (Array.isArray(maybeEvent)) return maybeEvent.every((event) => events.includes(event)); return events.includes(maybeEvent.toString()); } function getPrompt(prompts, id, context, defaults, timeoutStrategy) { async function prompt(eventOrText, textOrParams, params) { const { validate, transform, onValidateError, timeout, ...sendParams } = deepMerge( defaults, params || (typeof textOrParams === "object" && !(textOrParams instanceof gramio.FormattableString) ? textOrParams : {}) ); const text = isEvent(eventOrText) && (typeof textOrParams === "string" || textOrParams && typeof textOrParams !== "string" && textOrParams instanceof gramio.FormattableString) ? textOrParams : eventOrText; const message = await context.send(text, sendParams); const events2 = isEvent(eventOrText) ? eventOrText : void 0; return new Promise((resolve, reject) => { prompts.set(id, { actionReturn: message, // @ts-expect-error TODO: fix this resolve, reject, timeoutExpiresAt: timeout ? Date.now() + timeout : void 0, timeoutId: timeoutStrategy === "on-timer" && timeout ? setTimeoutCancel(prompts, id, timeout) : void 0, events: Array.isArray(events2) ? events2 : events2 ? [events2] : void 0, validate, // @ts-expect-error transform, onValidateError, sendParams, text: text.toString() }); }); } return prompt; } function setTimeoutCancel(prompts, id, timeout) { return setTimeout(() => emitCancelError(prompts, id), timeout)[Symbol.toPrimitive](); } function getWait(prompts, id, timeoutStrategy) { async function wait(eventOrValidate, validateOrOptions) { const events2 = eventOrValidate && typeof eventOrValidate !== "function" && isEvent(eventOrValidate) ? eventOrValidate : void 0; const timeout = typeof validateOrOptions === "object" && "timeout" in validateOrOptions ? validateOrOptions.timeout : void 0; return new Promise((resolve, reject) => { prompts.set(id, { // @ts-expect-error TODO: fix this resolve, reject, events: Array.isArray(events2) ? events2 : events2 ? [events2] : void 0, timeoutExpiresAt: timeout ? Date.now() + timeout : void 0, timeoutId: timeoutStrategy === "on-timer" && timeout ? setTimeoutCancel(prompts, id, timeout) : void 0, // @ts-expect-error TODO: fix this validate: typeof eventOrValidate === "function" ? eventOrValidate : typeof validateOrOptions === "object" ? validateOrOptions.validate : void 0, // @ts-expect-error transform: typeof validateOrOptions === "object" ? validateOrOptions.transform : void 0, // @ts-expect-error TODO: fix this onValidateError: typeof validateOrOptions === "object" || typeof validateOrOptions === "string" ? validateOrOptions.onValidateError : void 0 }); }); } return wait; } function getWaitWithAction(prompts, id, defaults, timeoutStrategy) { async function prompt(events2, action, validateOrOptions) { const actionReturn = await action(); const options = deepMerge( defaults, typeof validateOrOptions === "function" ? { validate: validateOrOptions } : validateOrOptions ?? {} ); const timeout = typeof validateOrOptions === "object" && "timeout" in validateOrOptions ? validateOrOptions.timeout : void 0; return new Promise( (resolve, reject) => { prompts.set(id, { actionReturn, // @ts-expect-error TODO: fix this resolve, reject, events: Array.isArray(events2) ? events2 : [events2], validate: options.validate, // @ts-expect-error transform: async (context) => { const transformedContext = options.transform ? await options.transform(context) : context; return [transformedContext, actionReturn]; }, onValidateError: options.onValidateError, timeoutExpiresAt: timeout ? Date.now() + timeout : void 0, timeoutId: timeoutStrategy === "on-timer" && timeout ? setTimeoutCancel(prompts, id, timeout) : void 0 }); } ); } return prompt; } function emitCancelError(prompts, id) { const prompt = prompts.get(id); if (prompt) { prompt.reject(new PromptCancelError("timeout")); prompts.delete(id); } else console.warn( `[Timeout] Prompt with id ${id} not found. Please share it with GramIO author.` ); } function prompt(options) { const prompts = options?.map ?? /* @__PURE__ */ new Map(); const timeoutStrategy = options?.timeoutStrategy ?? "on-answer"; return new gramio.Plugin("@gramio/prompt").error("prompt-cancel", PromptCancelError).derive(events, (context) => { const id = context.senderId || 0; return { prompt: getPrompt( prompts, id, // @ts-expect-error TODO: fix this context, options?.defaults || {}, timeoutStrategy ), wait: getWait(prompts, id, timeoutStrategy), waitWithAction: getWaitWithAction( prompts, id, options?.defaults || {}, timeoutStrategy ) }; }).on(events, async (context, next) => { const id = context.senderId || 0; const prompt2 = prompts.get(id); if (prompt2) { if (prompt2?.events && !context.is(prompt2.events)) return next(); if (prompt2.timeoutExpiresAt && prompt2.timeoutExpiresAt < Date.now()) { emitCancelError(prompts, id); return; } if (prompt2.validate && !await prompt2.validate(context)) { if (typeof prompt2.onValidateError === "string") return context.send(prompt2.onValidateError); if (prompt2.onValidateError) return prompt2.onValidateError(context, prompt2.actionReturn); if (prompt2.text) return context.send(prompt2.text, prompt2.sendParams); return; } if (prompt2.timeoutId) { clearTimeout(prompt2.timeoutId); } prompt2.resolve( // @ts-expect-error TODO: fix this prompt2.transform ? prompt2.transform(context) : context ); return prompts.delete(id); } return next(); }); } exports.prompt = prompt;