mirror of
https://github.com/tiennm99/miti99bot.git
synced 2026-04-17 15:20:58 +00:00
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/
2.6 KiB
2.6 KiB
Researcher Report: Cloudflare Workers KV basics
Date: 2026-04-11 Scope: KV API surface, wrangler binding, limits relevant to plugin framework.
API surface (KVNamespace binding)
await env.KV.get(key, { type: "text" | "json" | "arrayBuffer" | "stream" });
await env.KV.put(key, value, { expirationTtl, expiration, metadata });
await env.KV.delete(key);
await env.KV.list({ prefix, limit, cursor });
list() shape
{
keys: [{ name, expiration?, metadata? }, ...],
list_complete: boolean,
cursor: string, // present when list_complete === false
}
- Max
limitper call: 1000 (also the default). - Pagination via
cursor. Loop untillist_complete === true. - Prefix filter is server-side — efficient for per-module namespacing (
wordle:prefix).
Limits that shape the module API
| Limit | Value | Impact on design |
|---|---|---|
| Write/sec per key | 1 | Counters / leaderboards must avoid hot keys. Plugin authors must know this. Document in phase-03. |
| Value size | 25 MiB | Non-issue for bot state. |
| Key size | 512 bytes | Prefixing adds ~10 bytes — no issue. |
| Consistency | Eventual (up to ~60s globally) | Read-after-write may not see update immediately from a different edge. OK for game state, NOT OK for auth sessions. |
list() |
Eventually consistent, max 1000/call | Paginate. |
wrangler.toml binding
[[kv_namespaces]]
binding = "KV"
id = "<namespace-id-from-dashboard-or-wrangler-kv-create>"
preview_id = "<separate-id-for-wrangler-dev>"
- Access in code:
env.KV. preview_idletswrangler devuse a separate namespace — recommended.- Create namespace:
wrangler kv namespace create miti99bot-kv(prints IDs to paste).
Design implications for the DB abstraction
- Interface must support
get / put / delete / list({ prefix })— all four map 1:1 to KV. - Namespaced factory auto-prefixes with
<module>:—list()from a module only sees its own keys because prefix is applied on top of the requested prefix (e.g. modulewordlecallslist({ prefix: "games:" })→ final KV prefix becomeswordle:games:). - Return shape normalization: wrap KV's
list()output in a simpler{ keys: string[], cursor?: string, done: boolean }to hide KV-specific metadata fields. Modules that need metadata can take the hit later. getdefault type: return string. Modules do their own JSON parse, or expose agetJSON/putJSONhelper.
Unresolved questions
- Do we need
metadataandexpirationTtlpassthrough in v1? Recommendation: yes forexpirationTtl(useful for easter-egg cooldowns), no for metadata (YAGNI).