diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..c911968 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,57 @@ +import jsdoc from "eslint-plugin-jsdoc"; + +// Cloudflare Workers globals + custom codebase types that no-undefined-types +// must treat as defined (no tsc/jsconfig — plain ESM JS). +const DEFINED_TYPES = [ + // Cloudflare Workers runtime globals + "KVNamespace", + "D1Database", + "D1PreparedStatement", + // Web globals not always in eslint's scope + "Request", + "Response", + "URL", + // KV interface types (src/db/kv-store-interface.js) + "KVStore", + "KVStorePutOptions", + "KVStoreListOptions", + "KVStoreListResult", + // SQL interface types (src/db/sql-store-interface.js) + "SqlStore", + "SqlRunResult", + // Central typedefs (src/types.js) + "Env", + "Module", + "Command", + "Cron", + "ModuleContext", + "Trade", + "Portfolio", + "PortfolioMeta", + // Module sub-types (registry, validate-*) + "BotModule", + "RegistryEntry", + "Registry", + "ModuleCommand", + "ModuleCron", + "CronEntry", + // Trading sub-types + "ResolvedSymbol", +]; + +export default [ + { + files: ["src/**/*.js"], + plugins: { jsdoc }, + rules: { + "jsdoc/check-alignment": "warn", + "jsdoc/check-param-names": "error", + "jsdoc/check-tag-names": "error", + "jsdoc/check-types": "error", + "jsdoc/no-undefined-types": ["error", { definedTypes: DEFINED_TYPES }], + "jsdoc/require-param-type": "error", + "jsdoc/require-returns-type": "error", + "jsdoc/valid-types": "error", + }, + }, +]; diff --git a/src/types.js b/src/types.js new file mode 100644 index 0000000..34c85f6 --- /dev/null +++ b/src/types.js @@ -0,0 +1,95 @@ +/** + * @file Central JSDoc typedefs for the miti99bot codebase. + * + * No runtime exports — this file exists solely to provide type definitions + * that are visible to editor tooling and validated by eslint-plugin-jsdoc. + * + * Import-reexport typedefs from sub-modules live here so that consumers + * can `@typedef {import("../types.js").Env} Env` without chasing paths. + */ + +/** + * Cloudflare Worker bindings + environment variables. + * + * @typedef {object} Env + * @property {string} TELEGRAM_BOT_TOKEN — bot token from BotFather. + * @property {string} TELEGRAM_WEBHOOK_SECRET — secret for X-Telegram-Bot-Api-Secret-Token header. + * @property {string} MODULES — comma-separated list of module names to load (e.g. "trading,wordle"). + * @property {KVNamespace} KV — Cloudflare KV namespace binding. + * @property {D1Database|undefined} DB — Cloudflare D1 database binding; absent when not configured. + */ + +/** + * A single slash-command registered by a module. + * + * @typedef {object} Command + * @property {string} name — without leading slash; must match /^[a-z0-9_]{1,32}$/. + * @property {"public"|"protected"|"private"} visibility + * public: shown in Telegram /menu + /help. + * protected: shown in /help only. + * private: hidden easter egg — functional but undiscoverable. + * @property {string} description — ≤256 chars; required for all visibilities. + * @property {(ctx: any) => Promise} handler — grammY context handler. + */ + +/** + * A scheduled cron job registered by a module. + * + * @typedef {object} Cron + * @property {string} schedule — cron expression (e.g. "0 0 * * *"). + * @property {string} name — human-readable identifier for logging. + * @property {(event: any, ctx: ModuleContext) => Promise} handler — receives the scheduled event and module context. + */ + +/** + * Context object passed to module init() and cron handlers. + * + * @typedef {object} ModuleContext + * @property {KVStore} db — namespaced KV store for this module. + * @property {SqlStore|null} sql — namespaced D1 store; null when env.DB is not bound. + * @property {Env} env — raw worker environment bindings. + */ + +/** + * A plug-n-play module definition. + * + * @typedef {object} Module + * @property {string} name — unique module identifier; must match folder name and import-map key. + * @property {(ctx: ModuleContext) => Promise} [init] — optional async setup called once at startup. + * @property {Command[]} commands — slash-commands provided by this module. + * @property {Cron[]} [crons] — optional scheduled jobs provided by this module. + */ + +/** + * A single trade record stored in D1. + * + * @typedef {object} Trade + * @property {number} id — auto-increment primary key. + * @property {number} userId — Telegram user ID. + * @property {string} symbol — asset ticker (e.g. "TCB", "BTC"). + * @property {"buy"|"sell"} side — direction of the trade. + * @property {number} qty — quantity traded (integer for stocks). + * @property {number} priceVnd — execution price in VND. + * @property {number} ts — Unix timestamp (ms) of the trade. + */ + +// Re-export typedefs from sub-modules so consumers have a single import path. +/** + * @typedef {import("./db/kv-store-interface.js").KVStore} KVStore + * @typedef {import("./db/kv-store-interface.js").KVStorePutOptions} KVStorePutOptions + * @typedef {import("./db/kv-store-interface.js").KVStoreListOptions} KVStoreListOptions + * @typedef {import("./db/kv-store-interface.js").KVStoreListResult} KVStoreListResult + */ + +/** + * @typedef {import("./db/sql-store-interface.js").SqlStore} SqlStore + * @typedef {import("./db/sql-store-interface.js").SqlRunResult} SqlRunResult + */ + +/** + * @typedef {import("./modules/trading/portfolio.js").Portfolio} Portfolio + * @typedef {import("./modules/trading/portfolio.js").PortfolioMeta} PortfolioMeta + */ + +// JSDoc-only module. No runtime exports. +export {};