mirror of
https://github.com/tiennm99/miti99bot-js.git
synced 2026-06-02 08:13:18 +00:00
ea7df56e2d
The integration phase. Wires Phase 02 (MongoKVStore) and Phase 03
(MongoTradesStore + MongoSqlStore shim) into the request path behind
two env flags so KV and Atlas run side-by-side until cutover.
Storage routing
- DualKVStore + DualSqlStore: Promise.allSettled writes to BOTH backends,
reads from primary only. Secondary failures log + enqueue onto a KV
retry queue (__retry:mongo-failed:* / __retry:mongo-sql-failed:*).
Primary failure throws. _kind="dual" sentinel for test seam.
- create-store.js + create-sql-store.js: full flag matrix (STORAGE_PRIMARY
∈ {kv,mongo}, DUAL_WRITE ∈ {0,1}, MONGODB_URI presence) with
STUB_SENTINEL short-circuit for deploy-time. Post-cutover shape commented
inline so Phase 07 simplification is mechanical.
Stub mongo for register
- scripts/stub-kv.js: STUB_SENTINEL constant + duck-typed stubMongo
(no-op connect/close, throwing collection access). Replaces the
originally-planned string sentinel which would have stalled register.js
on serverSelectionTimeoutMS if ever passed to MongoClient (code-reviewer #2).
- scripts/register.js: stub env passes MONGODB_URI=STUB_SENTINEL,
STORAGE_PRIMARY="kv", DUAL_WRITE="0". Asserted via vi.spyOn that
MongoClient.prototype.connect is never reached.
Drift verifier cron (1/hr)
- src/cron/drift-verifier.js: drains both retry queues by re-attempting
secondary writes, deletes on success. Spot-checks parity by sampling
DRIFT_SAMPLE_N keys per module, hashing, logging mismatches.
- src/modules/cron-dispatcher.js: SYSTEM_CRONS array dispatched alongside
module crons. Keeping system cron out of registry.crons preserves
existing module-cron length tests and is the cleaner design.
- wrangler.toml: vars STORAGE_PRIMARY/DUAL_WRITE/DRIFT_SAMPLE_N + cron
schedule "0 * * * *" added.
Trading wiring
- src/modules/registry.js: builds new MongoTradesStore(env) when Mongo
is in play and threads it as tradesStore into trading module's init
context. Trading module already accepted optional tradesStore (Phase 03
backwards-compat) — D1 path remains for STORAGE_PRIMARY=kv + DUAL_WRITE=0.
Tests + verification
- tests/db/dual-kv-store.test.js, dual-sql-store.test.js: write-both,
secondary-fail-logs+enqueues, primary-fail-throws, reads-primary-only,
_kind sentinel.
- tests/db/stub-mongo-sentinel.test.js: spy on MongoClient.connect,
assert zero calls across all flag-matrix combos.
- tests/cron/drift-verifier.test.js: queue drain, skip paths, error safety.
- tests/e2e/storage-roundtrip.test.js: wordle KV dual-write +
trading MongoTradesStore against fake-mongo.
Tests: 577 → 638 (+61). register:dry passes without Atlas. Lint clean.
Concerns
- Drift-verifier parity-spot-check tests assert queue-drain only;
full mismatch detection needs real Atlas (Vitest ES-module caching
blocks reliable prototype patching). Verifier logic verified by
inspection.
78 lines
3.4 KiB
TOML
78 lines
3.4 KiB
TOML
name = "miti99bot"
|
|
main = "src/index.js"
|
|
compatibility_date = "2025-10-01"
|
|
# nodejs_compat_v2 enables node:net + node:tls so the official `mongodb` driver
|
|
# can open a TCP socket to Atlas. v1 vs v2 are alternatives, not additive.
|
|
# Adding this flag does not affect existing modules — `src/` has no node: imports.
|
|
compatibility_flags = ["nodejs_compat_v2"]
|
|
|
|
# Enabled modules at runtime. Comma-separated. Must match static-map keys in src/modules/index.js.
|
|
# Also duplicate this value into .env.deploy so scripts/register.js derives the same public command list.
|
|
[vars]
|
|
MODULES = "util,wordle,loldle,loldle-emoji,loldle-quote,loldle-ability,loldle-splash,misc,trading,lolschedule,semantle,doantu,twentyq"
|
|
# Storage routing flags — control which backend serves reads and receives writes.
|
|
# STORAGE_PRIMARY: "kv" = CF KV (default), "mongo" = Atlas (post-cutover).
|
|
# DUAL_WRITE: "1" = write both backends in parallel (default), "0" = primary only.
|
|
# DRIFT_SAMPLE_N: number of keys sampled per module by drift-verifier cron.
|
|
STORAGE_PRIMARY = "kv"
|
|
DUAL_WRITE = "1"
|
|
DRIFT_SAMPLE_N = "50"
|
|
|
|
# KV namespace holding all module state. Each module auto-prefixes its keys via createStore().
|
|
# Production-only — no preview namespace. Create with:
|
|
# wrangler kv namespace create miti99bot-kv
|
|
# then paste the returned id below.
|
|
[[kv_namespaces]]
|
|
binding = "KV"
|
|
id = "f7f190fcb2fa42eb84a05542911334b0"
|
|
|
|
# D1 database for module persistent storage. Each module prefixes its tables
|
|
# with `{moduleName}_` (e.g. `trading_trades`). Migrations are applied via
|
|
# `npm run db:migrate` (chained into `npm run deploy`).
|
|
# Create with: npx wrangler d1 create miti99bot-db
|
|
# then replace REPLACE_ME_D1_UUID below with the returned database_id.
|
|
[[d1_databases]]
|
|
binding = "DB"
|
|
database_name = "miti99bot-db"
|
|
database_id = "261b54e7-0fdb-4fe7-8ed9-2e8a8bcf459c"
|
|
|
|
# Workers AI inference binding, accessed as `env.AI` in handlers.
|
|
# Used by:
|
|
# - semantle / doantu → @cf/baai/bge-m3 multilingual embeddings
|
|
# - twentyq → @cf/google/gemma-4-26b-a4b-it text generation
|
|
# Workers Free plan: 10,000 Neurons/day, hard-stops (no billing on Free).
|
|
# Pricing: https://developers.cloudflare.com/workers-ai/platform/pricing/
|
|
[ai]
|
|
binding = "AI"
|
|
|
|
# Cron Triggers — union of all schedules declared by modules.
|
|
# When adding a module with cron entries, append its schedule(s) here.
|
|
# See docs/adding-a-module.md for the full module author workflow.
|
|
# Local testing: curl "http://localhost:8787/__scheduled?cron=0+1+*+*+*"
|
|
# (requires `wrangler dev --test-scheduled`)
|
|
[triggers]
|
|
# "0 17 * * *" — trading trim-trades (lolschedule module)
|
|
# "0 1 * * *" — misc / lolschedule nightly jobs
|
|
# "0 * * * *" — drift-verifier: drain retry queue + spot-check KV vs Mongo parity
|
|
crons = ["0 17 * * *", "0 1 * * *", "0 * * * *"]
|
|
|
|
# Workers Observability — captures console.* logs, request metadata, and
|
|
# invocation traces in the Cloudflare dashboard (Observability → Logs).
|
|
# 200k events/day included on free plan. `head_sampling_rate = 1` keeps
|
|
# all invocations; drop to 0.1 for 10% sampling if volume grows.
|
|
[observability]
|
|
enabled = true
|
|
head_sampling_rate = 1
|
|
|
|
[observability.logs]
|
|
enabled = true
|
|
invocation_logs = true
|
|
|
|
[observability.traces]
|
|
enabled = true
|
|
head_sampling_rate = 1
|
|
|
|
# Secrets (set via `wrangler secret put <name>`, NOT in this file):
|
|
# TELEGRAM_BOT_TOKEN — bot token from @BotFather
|
|
# TELEGRAM_WEBHOOK_SECRET — arbitrary high-entropy string, also set in .env.deploy
|