mirror of
https://github.com/tiennm99/miti99bot.git
synced 2026-04-20 09:21:27 +00:00
feat: scaffold plug-n-play telegram bot on cloudflare workers
grammY-based bot with a module plugin system loaded from the MODULES env var. Three command visibility levels (public/protected/private) share a unified command namespace with conflict detection at registry build. - 4 initial modules (util, wordle, loldle, misc); util fully implemented, others are stubs proving the plugin system end-to-end - util: /info (chat/thread/sender ids) + /help (pure renderer over the registry, HTML parse mode, escapes user-influenced strings) - KVStore interface with CFKVStore and a per-module prefixing factory; getJSON/putJSON convenience helpers; other backends drop in via one file - Webhook at POST /webhook with secret-token validation via grammY's webhookCallback; no admin HTTP surface - Post-deploy register script (npm run deploy = wrangler deploy && node --env-file=.env.deploy scripts/register.js) for setWebhook and setMyCommands; --dry-run flag for preview - 56 vitest unit tests across 7 suites covering registry, db wrapper, dispatcher, help renderer, validators, and HTML escaper - biome for lint + format; phased implementation plan under plans/
This commit is contained in:
54
src/modules/misc/index.js
Normal file
54
src/modules/misc/index.js
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* @file misc module stub — proves the plugin system end-to-end AND
|
||||
* demonstrates DB usage via getJSON/putJSON in /ping.
|
||||
*/
|
||||
|
||||
/** @type {import("../../db/kv-store-interface.js").KVStore | null} */
|
||||
let db = null;
|
||||
|
||||
/** @type {import("../registry.js").BotModule} */
|
||||
const miscModule = {
|
||||
name: "misc",
|
||||
init: async ({ db: store }) => {
|
||||
db = store;
|
||||
},
|
||||
commands: [
|
||||
{
|
||||
name: "ping",
|
||||
visibility: "public",
|
||||
description: "Health check — replies pong and records last ping",
|
||||
handler: async (ctx) => {
|
||||
// Best-effort write — if KV is unavailable, still reply.
|
||||
try {
|
||||
await db?.putJSON("last_ping", { at: Date.now() });
|
||||
} catch (err) {
|
||||
console.warn("misc /ping: putJSON failed", String(err));
|
||||
}
|
||||
await ctx.reply("pong");
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mstats",
|
||||
visibility: "protected",
|
||||
description: "Show the timestamp of the last /ping",
|
||||
handler: async (ctx) => {
|
||||
const last = await db?.getJSON("last_ping");
|
||||
if (last?.at) {
|
||||
await ctx.reply(`last ping: ${new Date(last.at).toISOString()}`);
|
||||
} else {
|
||||
await ctx.reply("last ping: never");
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fortytwo",
|
||||
visibility: "private",
|
||||
description: "Easter egg — the answer",
|
||||
handler: async (ctx) => {
|
||||
await ctx.reply("The answer.");
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default miscModule;
|
||||
Reference in New Issue
Block a user