@gramio/prompt
Version:
Prompt plugin for GramIO
193 lines (187 loc) • 7.12 kB
JavaScript
;
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;