@sfmc-bds/db-server 0.5.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/domain/bind-providers.d.ts +59 -0
- package/dist/domain/bind-providers.d.ts.map +1 -0
- package/dist/domain/bind-providers.js +33 -0
- package/dist/domain/bind-providers.js.map +7 -0
- package/dist/domain/metrics.d.ts +5 -0
- package/dist/domain/metrics.d.ts.map +1 -1
- package/dist/domain/metrics.js +28 -2
- package/dist/domain/metrics.js.map +2 -2
- package/dist/domain/player-level.d.ts +29 -0
- package/dist/domain/player-level.d.ts.map +1 -0
- package/dist/domain/player-level.js +30 -0
- package/dist/domain/player-level.js.map +7 -0
- package/dist/domain/process-resources.d.ts +12 -0
- package/dist/domain/process-resources.d.ts.map +1 -1
- package/dist/domain/process-resources.js +72 -1
- package/dist/domain/process-resources.js.map +2 -2
- package/dist/domain/qq-bind.d.ts +21 -0
- package/dist/domain/qq-bind.d.ts.map +1 -0
- package/dist/domain/qq-bind.js +54 -0
- package/dist/domain/qq-bind.js.map +7 -0
- package/dist/domain/schema.d.ts +1 -0
- package/dist/domain/schema.d.ts.map +1 -1
- package/dist/domain/schema.js +26 -0
- package/dist/domain/schema.js.map +2 -2
- package/dist/domain/tracked-processes.d.ts +30 -0
- package/dist/domain/tracked-processes.d.ts.map +1 -0
- package/dist/domain/tracked-processes.js +78 -0
- package/dist/domain/tracked-processes.js.map +7 -0
- package/dist/domain/wechat-bind.d.ts +56 -0
- package/dist/domain/wechat-bind.d.ts.map +1 -0
- package/dist/domain/wechat-bind.js +84 -0
- package/dist/domain/wechat-bind.js.map +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -7
- package/dist/index.js.map +2 -2
- package/dist/lib/sqlite.d.ts +10 -0
- package/dist/lib/sqlite.d.ts.map +1 -1
- package/dist/lib/sqlite.js +17 -2
- package/dist/lib/sqlite.js.map +2 -2
- package/dist/routes/bind-confirm.d.ts +30 -0
- package/dist/routes/bind-confirm.d.ts.map +1 -0
- package/dist/routes/bind-confirm.js +27 -0
- package/dist/routes/bind-confirm.js.map +7 -0
- package/dist/routes/qq-bind.d.ts +3 -1
- package/dist/routes/qq-bind.d.ts.map +1 -1
- package/dist/routes/qq-bind.js +8 -64
- package/dist/routes/qq-bind.js.map +2 -2
- package/dist/routes/status.d.ts.map +1 -1
- package/dist/routes/status.js +10 -2
- package/dist/routes/status.js.map +2 -2
- package/dist/routes/wechat-bind.d.ts +39 -0
- package/dist/routes/wechat-bind.d.ts.map +1 -0
- package/dist/routes/wechat-bind.js +56 -0
- package/dist/routes/wechat-bind.js.map +7 -0
- package/package.json +5 -4
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n *\n * \u5DE5\u4F5C\u6D41:\n * 1. \u52A0\u8F7D env\n * 2. \u6821\u9A8C Node \u7248\u672C\n * 3. openDatabase + createPlatformTables(sfmc__audit / sfmc__idempotent)\n * 4. loadManifestV2() \u2014 \u5931\u8D25 = \u542F\u52A8\u5931\u8D25\n * 5. filterEnabled(loaded, lockFileEnabled)\n * 6. buildModuleAuth({auth_token, enabled_modules}) \u2190 \u4E0E DB \u540C\u76EE\u5F55 module-tokens.json\n * 7. \u5B9E\u4F8B\u5316:SchemaRegistry / ServiceRegistry / IdempotencyStore / TxRunner\n * 8. \u88C5\u914D v2 \u8DEF\u7531 (/api/sfmc/db/* + /api/sfmc/services* + /api/sfmc/configs/:key/*)\n * \u53E6\u4FDD\u7559 messages(qq-bridge) + config/modules/health \u5E73\u53F0\u8DEF\u7531\n * 9. createServer + listen\n *\n * \u9274\u6743(handle \u5C42):\n * - /api/sfmc/db/*, /api/sfmc/services*, /api/sfmc/configs/:key(/set|notify)*\n * \u2192 module token (Authorization: Bearer ...) + ?moduleId=...\n * - \u5176\u4ED6:env.AUTH_TOKEN \u65E7 auth(NEEDS_AUTH)\n */\n\nimport http from \"node:http\";\nimport { PLATFORM_MONITORING_SERVICES, PLATFORM_SERVICE_OWNER } from \"@sfmc-bds/sdk/contracts\";\nimport { SQL } from \"sql-template-strings\";\n\nimport { createPlatformTables } from \"./db-tables.js\";\nimport { syncPlayerSession } from \"./domain/player-session.js\";\nimport { initSchema } from \"./domain/schema.js\";\nimport { loadEnv } from \"./env.js\";\nimport { createIdempotencyStore } from \"./lib/idempotency-store.js\";\nimport { log } from \"./lib/log.js\";\nimport { assertNodeVersion } from \"./lib/runtime.js\";\nimport { createQuery, openDatabase } from \"./lib/sqlite.js\";\nimport { loadManifestV2 } from \"./manifest-loader.js\";\nimport { buildModuleAuth, ensureModuleToken, persistModuleAuth, verifyModuleAuth } from \"./module-auth.js\";\nimport { syncModuleRuntimeState } from \"./module-runtime-sync.js\";\nimport { SchemaRegistry } from \"./schema-registry.js\";\nimport { createServer, startConsole } from \"./server.js\";\nimport { ServiceRegistry } from \"./service-registry.js\";\nimport { registerEnabledBuiltinServices } from \"./services/builtin-handlers.js\";\nimport { TxRunner } from \"./tx-runner.js\";\n\nimport { configPath, ensureJson, patchJson, readJson } from \"@sfmc-bds/sdk/node/config\";\nimport path, { join } from \"node:path\";\n\nimport { jsonV2Fail } from \"./routes/_shared.js\";\nimport { createDbRoutes } from \"./routes/db-routes.js\";\nimport { createModuleConfigRoutes } from \"./routes/module-config-routes.js\";\nimport { createServiceRoutes } from \"./routes/service-routes.js\";\n\nimport { forwardToQQBridge, makeOutboundConfig } from \"./domain/bridge.js\";\nimport { loadContentSnapshot } from \"./domain/installed-content.js\";\nimport { createQqEventsDispatcher, resolveQqEventsConfig, type ResolvedQqEventsConfig } from \"./domain/qq-events.js\";\nimport { body as sharedBody, json as sharedJson } from \"./lib/http.js\";\nimport { isEnabled, loadModuleLock, saveModuleLock, updateModuleState } from \"./lib/module-state.js\";\nimport { createConfigRoutes } from \"./routes/config.js\";\nimport { createContentRoutes } from \"./routes/content.js\";\nimport { createHealthRoutes } from \"./routes/health.js\";\nimport { createMessagesRoutes, gameChatForwardPayload, type ChatChannelQQFlags } from \"./routes/messages.js\";\nimport { createModuleRoutes } from \"./routes/modules.js\";\nimport { createQqBindRoutes } from \"./routes/qq-bind.js\";\nimport { createQqEventsRoutes } from \"./routes/qq-events.js\";\nimport { createQqJoinRoutes, type JoinFeatureFlags } from \"./routes/qq-join.js\";\nimport { createStatusRoutes } from \"./routes/status.js\";\n\nif (!assertNodeVersion(22, 13)) {\n process.exit(2);\n}\n\nconst env = loadEnv();\nconst db = openDatabase(env.DB_PATH);\ncreatePlatformTables(db); // sfmc__audit / sfmc__idempotent\ninitSchema(db); // \u5E73\u53F0\u4E1A\u52A1 bootstrap \u8868(players/world/chat/...)\u2014\u2014qq-bridge \u5728 SAPI defineTable \u4E4B\u524D\u5C31\u9700\u8981\nconst query = createQuery(db);\n\n// \u2500\u2500 v2 manifest \u52A0\u8F7D(\u5931\u8D25 = \u542F\u52A8\u5931\u8D25)\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst loadedManifest = loadManifestV2(); // throws on violation\nlog.success(\n `[manifest v2] loaded ${Object.keys(loadedManifest.modules).length} modules; provides ${loadedManifest.providesMap.size} services`\n);\n\n// \u2500\u2500 enabled \u96C6\u5408(\u4ECE lock file)\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst lockFile = loadModuleLock(env.MODULE_LOCK_PATH);\nconst moduleCatalog = readJson<{ modules?: unknown[] }>(env.MODULE_CATALOG_PATH) ?? { modules: [] };\nconst catalogIds = new Set(\n Array.isArray(moduleCatalog.modules)\n ? (moduleCatalog.modules as Array<{ id?: string }>).map((m) => String(m.id || \"\")).filter((id) => id.length > 0)\n : []\n);\nconst enabledSet = new Set<string>();\nfor (const id of Object.keys(loadedManifest.modules)) {\n if (!catalogIds.has(id)) continue;\n const catalogEntry = (moduleCatalog.modules as Array<Record<string, unknown>>).find((m) => String(m.id) === id);\n if (!catalogEntry) continue;\n const defaultEnabled = catalogEntry.enabledByDefault !== false;\n if (isEnabled(lockFile, id, defaultEnabled)) enabledSet.add(id);\n}\nconst enabledManifests = new Map<string, NonNullable<(typeof loadedManifest.modules)[string]>>();\nfor (const id of enabledSet) {\n const m = loadedManifest.modules[id];\n if (m) enabledManifests.set(id, m);\n}\nlog.info(`[manifest v2] enabled: ${[...enabledSet].sort().join(\", \") || \"(none)\"}`);\n\n// \u2500\u2500 \u6A21\u5757 HMAC token map(\u4E0E DB \u540C\u76EE\u5F55 module-tokens.json)\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst moduleAuth = buildModuleAuth({\n dbPath: env.DB_PATH,\n envAuthToken: env.AUTH_TOKEN,\n enabledModuleIds: [...enabledSet],\n});\n// \u5E73\u53F0\u5BBF\u4E3B\uFF08QQ \u7ED1\u5B9A/\u8D26\u53F7\u5FEB\u7167\uFF09\u9700\u8981\u7A33\u5B9A token\uFF0C\u7ECF configs/all.module_tokens \u4E0B\u53D1\u5230 BDS\nif (ensureModuleToken(moduleAuth, PLATFORM_SERVICE_OWNER)) {\n persistModuleAuth(env.DB_PATH, moduleAuth, env.AUTH_TOKEN);\n log.info(`[auth] \u5DF2\u6D3E\u751F\u5E73\u53F0\u5BBF\u4E3B token: ${PLATFORM_SERVICE_OWNER}`);\n}\n\n// \u2500\u2500 \u4E09\u4EF6\u5957 + \u8DEF\u7531\u5DE5\u5382 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst schemaRegistry = new SchemaRegistry(db);\nconst serviceRegistry = new ServiceRegistry();\nconst idempotent = createIdempotencyStore(db);\nconst txRunner = new TxRunner({\n db,\n query,\n schema: schemaRegistry,\n serviceRegistry,\n enabled: enabledManifests,\n});\n\n// \u2500\u2500 \u8FDB\u7A0B\u5185\u7F6E service handler(\u6269\u5C55\u70B9:BUILTIN_SERVICE_PLUGINS) \u2500\u2500\n{\n const plugins = registerEnabledBuiltinServices(serviceRegistry, { query, db }, enabledSet);\n if (plugins > 0) {\n log.success(`[service] registered ${serviceRegistry.list().length} handlers from ${plugins} builtin plugin(s)`);\n }\n}\n\nconst json = sharedJson;\nconst body = sharedBody;\n\n// \u2500\u2500 \u5DE5\u5177\u51FD\u6570 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction loadModuleCatalog() {\n return Array.isArray(moduleCatalog.modules) ? moduleCatalog.modules : [];\n}\n\nfunction buildModuleList() {\n const catalog = loadModuleCatalog();\n return catalog\n .map((raw) => {\n const entry =\n (raw as Record<string, unknown>).entry && typeof (raw as Record<string, unknown>).entry === \"object\"\n ? ((raw as Record<string, unknown>).entry as Record<string, unknown>)\n : {};\n const id = String((raw as Record<string, unknown>).id || \"\").trim();\n const configKey = String(\n (raw as Record<string, unknown>).configKey || (raw as Record<string, unknown>).config_key || \"\"\n ).trim();\n if (!id || !configKey) return null;\n const state = lockFile.modules[id];\n const enabled = isEnabled(lockFile, id, (raw as Record<string, unknown>).enabledByDefault !== false);\n return {\n id,\n module_id: id,\n name: configKey,\n configKey,\n config_key: configKey,\n display_name: String((raw as Record<string, unknown>).name || configKey),\n description: String((raw as Record<string, unknown>).description || \"\"),\n default_enabled: (raw as Record<string, unknown>).enabledByDefault !== false,\n can_disable: moduleCanDisable(raw as Record<string, unknown>),\n // ConfigManager \u8BA4 installed!==false;\u5DF2\u88C5\u5305\u9ED8\u8BA4 true\n installed: true,\n requires: Array.isArray((raw as Record<string, unknown>).requires)\n ? ((raw as Record<string, unknown>).requires as unknown[]).filter(Boolean).map(String)\n : [],\n optional: Array.isArray((raw as Record<string, unknown>).optional)\n ? ((raw as Record<string, unknown>).optional as unknown[]).filter(Boolean).map(String)\n : [],\n commands: Array.isArray((raw as Record<string, unknown>).commands)\n ? ((raw as Record<string, unknown>).commands as unknown[]).filter(Boolean).map(String)\n : [],\n entry: {\n kind: String(entry.kind || \"\"),\n path: String(entry.path || \"\"),\n init: String(entry.init || \"\"),\n },\n updated_at: state?.updatedAt ?? null,\n enabled: !!enabled,\n };\n })\n .filter(Boolean);\n}\n\n/**\n * QQ\u300C\u6A21\u5757 / \u8D44\u6E90\u5305\u300D\u5FEB\u7167\u3002\u6BCF\u6B21\u8BF7\u6C42\u73B0\u8BFB catalog \u4E0E\u78C1\u76D8\uFF0C\u88C5\u5305\u540E\u4E0D\u7528\u91CD\u542F db-server\u3002\n */\nfunction loadContentSnapshotForRequest() {\n const modules = (buildModuleList() ?? []).flatMap((raw) => {\n if (!raw || typeof raw !== \"object\") return [];\n const row = raw as { id?: unknown; display_name?: unknown; enabled?: unknown };\n const id = String(row.id ?? \"\").trim();\n if (!id) return [];\n return [\n {\n id,\n display_name: String(row.display_name || id),\n enabled: row.enabled !== false,\n },\n ];\n });\n const cfg = readJson<{ bds_path?: string }>(configPath(env.PROJECT_ROOT, \"bds_updater.json\"));\n const rawBds = typeof cfg?.bds_path === \"string\" ? cfg.bds_path.trim() : \"\";\n const bdsRoot = rawBds ? (path.isAbsolute(rawBds) ? rawBds : path.resolve(env.PROJECT_ROOT, rawBds)) : null;\n return loadContentSnapshot({\n packagesDir: join(env.MODULES_DIR, \"packages\"),\n modules,\n bdsRoot,\n });\n}\n\n/** catalog \u7701\u7565 canDisable \u65F6\u9ED8\u8BA4\u5141\u8BB8\u7981\u7528(\u4E0E buildModuleList.can_disable \u540C\u6E90)\u3002 */\nfunction moduleCanDisable(raw: Record<string, unknown>): boolean {\n return raw.canDisable !== false;\n}\n\nfunction resolveModuleByKey(key: string) {\n const k = String(key || \"\").trim();\n const catalog = loadModuleCatalog();\n const raw = catalog.find(\n (m) =>\n String((m as Record<string, unknown>).id || \"\") === k ||\n String((m as Record<string, unknown>).configKey || (m as Record<string, unknown>).config_key || \"\") === k\n ) as Record<string, unknown> | undefined;\n if (!raw) return null;\n const id = String(raw.id || \"\").trim();\n const configKey = String(raw.configKey || raw.config_key || \"\").trim();\n if (!id || !configKey) return null;\n /* LSP:\u4E0E buildModuleList.can_disable \u540C\u6E90 \u2014 \u7701\u7565\u5B57\u6BB5\u89C6\u4E3A\u53EF\u7981\u7528 */\n return { id, configKey, canDisable: moduleCanDisable(raw) };\n}\n\nfunction setModuleEnabled(mod: { id: string; canDisable: boolean }, enabled: boolean) {\n // \u76F4\u63A5\u66F4\u65B0\u542F\u52A8\u65F6\u7F13\u5B58\u7684 lockFile(\u800C\u975E\u53E6\u8BFB\u4E00\u4EFD\u65B0\u526F\u672C),\n // \u5426\u5219 buildModuleList() \u8BFB\u7684\u4ECD\u662F\u65E7\u7F13\u5B58,\u5BFC\u81F4\u542F\u505C\u540E enabled \u72B6\u6001\u4E0D\u7FFB\u8F6C\u3002\n updateModuleState(lockFile, mod.id, { enabled: !!enabled });\n // DRY:\u4E0E loadModuleLock \u5BF9\u79F0\u8D70 saveModuleLock,\u52FF\u6563\u843D writeJson\n saveModuleLock(env.MODULE_LOCK_PATH, lockFile);\n\n // DIP:\u70ED\u540C\u6B65 enabledSet / tokens / manifests / builtin handlers(\u4E0D\u91CD\u542F db-server)\n syncModuleRuntimeState({\n moduleId: mod.id,\n enabled: !!enabled,\n dbPath: env.DB_PATH,\n envAuthToken: env.AUTH_TOKEN,\n enabledSet,\n enabledManifests,\n loadedManifest,\n moduleAuth,\n serviceRegistry,\n builtinDeps: { query, db },\n });\n}\n\n// \u2500\u2500 \u5E73\u53F0\u8DEF\u7531(\u975E\u6A21\u5757\u4E1A\u52A1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst healthRoutes = createHealthRoutes();\n// \u6307\u6807\u72EC\u7ACB\u843D\u5E93\uFF0C\u907F\u514D\u5199\u5165\u4E1A\u52A1\u6A21\u5757\u6B63\u5728\u6301\u6709\u7684\u8DE8\u8BF7\u6C42\u4E8B\u52A1\u3002\nconst metricsDb = openDatabase(path.join(path.dirname(env.DB_PATH), \"runtime-metrics.sqlite\"));\nconst statusRoutes = createStatusRoutes({ query: createQuery(metricsDb) });\nfor (const name of PLATFORM_MONITORING_SERVICES) serviceRegistry.registerHandler(PLATFORM_SERVICE_OWNER, name, async () => {\n const response = await fetch(`http://127.0.0.1:${env.PORT}/api/sfmc/metrics`, { signal: AbortSignal.timeout(10_000) });\n if (!response.ok) throw new Error(\"\u5E73\u53F0\u8FD0\u884C\u6307\u6807\u8BFB\u53D6\u5931\u8D25\");\n const result = await response.json() as { current: { tps: number | null; chunkEstimate: number | null } | null };\n const tps = result.current?.tps ?? null;\n const grade = tps === null ? \"unknown\" : tps >= 19.5 ? \"green\" : tps >= 15 ? \"yellow\" : tps >= 10 ? \"gold\" : \"red\";\n if (name === \"tps.current\") return tps;\n if (name === \"tps.status\") return { tps, grade, text: `\u00A77[TPS] \u00A7f${tps?.toFixed(2) ?? \"\u672A\u77E5\"} \u00A77/ 20.00` };\n return result.current ? { ...result.current, grade, totalLoadedChunks: result.current.chunkEstimate } : null;\n});\nconst qqBindRoutes = createQqBindRoutes({ query, body, json });\n\n/** \u5E73\u53F0 QQ \u7ED1\u5B9A\u76F8\u5173\u914D\u7F6E\uFF08\u975E SDK qq_config\uFF1B\u539F qq-link \u6A21\u5757\u914D\u7F6E\u952E\uFF09 */\nconst QQ_LINK_CONFIG_KEY = \"qq_link\";\nconst QQ_LINK_DEFAULTS = {\n allowlist_enabled: true,\n require_approval: true,\n /** \u662F\u5426\u5C06 QQ \u7FA4\u4E3B/\u7FA4\u7BA1\u89C6\u4F5C SFMC \u7BA1\u7406\u5458\uFF1B\u7F3A\u7701\u5F00\u542F\uFF0C\u4EC5\u6539\u672C\u6587\u4EF6\u53EF\u5173\u95ED\uFF0CAPI/\u7FA4\u804A\u4E0D\u53EF\u5199 */\n treat_group_admins_as_admins: true,\n} as const;\n\nfunction asConfigBool(v: unknown, fallback: boolean): boolean {\n if (v === undefined || v === null) return fallback;\n if (typeof v === \"boolean\") return v;\n const s = String(v).trim().toLowerCase();\n if (s === \"true\" || s === \"1\" || s === \"yes\" || s === \"on\") return true;\n if (s === \"false\" || s === \"0\" || s === \"no\" || s === \"off\") return false;\n return fallback;\n}\n\nfunction qqLinkConfigFile(): string {\n return join(env.PROJECT_ROOT, \"configs\", `${QQ_LINK_CONFIG_KEY}.json`);\n}\n\nfunction readJoinFlags(): JoinFeatureFlags {\n // \u5E73\u53F0\u914D\u7F6E configs/qq_link.json\uFF08\u975E SDK qq_config\uFF09\n const disk = ensureJson<Record<string, unknown>>(qqLinkConfigFile(), { ...QQ_LINK_DEFAULTS });\n return {\n allowlistEnabled: asConfigBool(disk.allowlist_enabled, QQ_LINK_DEFAULTS.allowlist_enabled),\n requireApproval: asConfigBool(disk.require_approval, QQ_LINK_DEFAULTS.require_approval),\n treatGroupAdminsAsAdmins: asConfigBool(\n disk.treat_group_admins_as_admins,\n QQ_LINK_DEFAULTS.treat_group_admins_as_admins\n ),\n };\n}\n\nfunction writeJoinFlags(partial: Partial<JoinFeatureFlags>): JoinFeatureFlags {\n const file = qqLinkConfigFile();\n ensureJson<Record<string, unknown>>(file, { ...QQ_LINK_DEFAULTS });\n const patch: Record<string, boolean> = {};\n if (partial.allowlistEnabled !== undefined) patch.allowlist_enabled = partial.allowlistEnabled;\n if (partial.requireApproval !== undefined) patch.require_approval = partial.requireApproval;\n // \u6545\u610F\u4E0D\u5199 treat_group_admins_as_admins\uFF1A\u4EC5\u4EBA\u5DE5\u6539 configs/qq_link.json\n if (Object.keys(patch).length > 0) {\n patchJson(file, patch);\n }\n return readJoinFlags();\n}\n\n// \u542F\u52A8\u5373\u843D\u76D8\u5E73\u53F0\u9ED8\u8BA4\u914D\u7F6E\uFF0C\u907F\u514D\u300C\u4ECE\u672A\u70B9\u8FC7\u914D\u7F6E/\u7533\u8BF7\u300D\u65F6 configs/qq_link.json \u4E0D\u5B58\u5728\n{\n const created = !readJson(qqLinkConfigFile());\n ensureJson<Record<string, unknown>>(qqLinkConfigFile(), { ...QQ_LINK_DEFAULTS });\n if (created) {\n log.info(`\u5DF2\u5199\u5165\u5E73\u53F0\u914D\u7F6E\u9AA8\u67B6: configs/${QQ_LINK_CONFIG_KEY}.json`);\n }\n}\n\nconst qqJoinRoutes = createQqJoinRoutes({\n query,\n body,\n json,\n getAdminOpenids: () => {\n const raw = (env.qqconfig[\"official\"] as { admin_openids?: unknown } | undefined)?.admin_openids;\n if (!Array.isArray(raw)) return [];\n return raw.map((x) => String(x).trim()).filter(Boolean);\n },\n getJoinFlags: () => readJoinFlags(),\n setJoinFlags: (partial) => writeJoinFlags(partial),\n});\n\nfunction readQqEventsSettings(): ResolvedQqEventsConfig {\n const disk = readJson<Record<string, unknown>>(join(env.PROJECT_ROOT, \"configs\", \"qq_config.json\"));\n if (!disk) throw new Error(\"qq_config.json \u65E0\u6CD5\u8BFB\u53D6\uFF0C\u4E8B\u4EF6\u8BBE\u7F6E\u672A\u4FEE\u6539\");\n return resolveQqEventsConfig(disk.qq_events);\n}\n\nfunction writeQqEventsSettings(patch: Partial<ResolvedQqEventsConfig>): ResolvedQqEventsConfig {\n const file = join(env.PROJECT_ROOT, \"configs\", \"qq_config.json\");\n const settings = { ...readQqEventsSettings(), ...patch };\n patchJson(file, { qq_events: settings });\n return settings;\n}\n\nfunction currentOutbound() {\n return makeOutboundConfig({\n QQ_BACKEND: env.QQ_BACKEND,\n LLBOT_HOST: env.LLBOT_HOST,\n LLBOT_PORT: env.LLBOT_PORT,\n LLBOT_TOKEN: env.LLBOT_TOKEN,\n QQ_GROUP_ID: env.QQ_GROUP_ID,\n QQ_APP_ID: env.QQ_APP_ID,\n QQ_APP_SECRET: env.QQ_APP_SECRET,\n QQ_SANDBOX: env.QQ_SANDBOX,\n QQ_GROUP_OPENID: env.QQ_GROUP_OPENID,\n });\n}\n\nconst qqEventsDispatcher = createQqEventsDispatcher({\n getConfig: readQqEventsSettings,\n getOutbound: () => currentOutbound(),\n});\nconst qqEventsRoutes = createQqEventsRoutes({\n body,\n json,\n dispatcher: qqEventsDispatcher,\n getSettings: readQqEventsSettings,\n setSettings: writeQqEventsSettings,\n isAdmin: (openid, asGroupAdmin) => {\n const admins = (env.qqconfig[\"official\"] as { admin_openids?: unknown } | undefined)?.admin_openids;\n return (\n (Array.isArray(admins) && admins.includes(openid)) || (asGroupAdmin && readJoinFlags().treatGroupAdminsAsAdmins)\n );\n },\n});\n\n/** \u8BFB\u53D6\u5355\u4E2A\u804A\u5929\u9891\u9053\u3002\u8868\u5C1A\u672A\u7531\u804A\u5929\u6A21\u5757\u5EFA\u51FA\u65F6\u8FD4\u56DE null\uFF0C\u4E0D\u8BA9\u8BF7\u6C42 500\u3002 */\nfunction readChatChannel(channelId: string): ChatChannelQQFlags | null {\n try {\n const rows = query(SQL`SELECT * FROM sfmc_chat_channels WHERE id = ${channelId}`);\n return Array.isArray(rows) ? ((rows[0] as ChatChannelQQFlags | undefined) ?? null) : null;\n } catch (err) {\n log.warn(`\u8BFB\u53D6\u804A\u5929\u9891\u9053\u5931\u8D25: ${(err as Error).message}`);\n return null;\n }\n}\n\n/** \u6D88\u606F\u6765\u6E90\u4E3A QQ \u7684\u9891\u9053\u3002QQ \u5165\u7AD9\u53EA\u6295\u5230\u8FD9\u4E9B\u9891\u9053\u3002 */\nfunction listQQSourceChannels(): ChatChannelQQFlags[] {\n try {\n const rows = query(SQL`SELECT * FROM sfmc_chat_channels`);\n if (!Array.isArray(rows)) return [];\n return (rows as ChatChannelQQFlags[]).filter((row) => row.source_qq === 1);\n } catch (err) {\n log.warn(`\u8BFB\u53D6 QQ \u6765\u6E90\u9891\u9053\u5931\u8D25: ${(err as Error).message}`);\n return [];\n }\n}\n\nconst messagesRoutes = createMessagesRoutes({\n query,\n body,\n json,\n getChannelForQQ: readChatChannel,\n listQQSourceChannels,\n forwardToQQBridge: (channelId: string, prefix: string, fromName: string, content: string, fromId: string) =>\n forwardToQQBridge(currentOutbound(), channelId, prefix, fromName, content, fromId),\n});\n\n// \u6E38\u620F\u53D1\u8A00\u8D70 db.tx \u63D2\u5165\uFF0C\u4E0D\u7ECF\u8FC7 /api/sfmc/messages\u3002\u63D0\u4EA4\u540E\u518D\u6309\u9891\u9053\u5F00\u5173\u8F6C\u53D1\u5230 QQ\u3002\ntxRunner.setAfterCommit((inserts) => {\n for (const item of inserts) {\n if (item.table !== \"sfmc_chat_messages\") continue;\n const payload = gameChatForwardPayload(item.row, readChatChannel(String(item.row.channel_id ?? \"\")));\n if (!payload) continue;\n forwardToQQBridge(\n currentOutbound(),\n payload.channelId,\n payload.prefix,\n payload.fromName,\n payload.content,\n payload.fromId,\n );\n }\n});\nconst configRoutes = createConfigRoutes({\n json,\n projectRoot: env.PROJECT_ROOT,\n // DIP:\u8DEF\u7531\u4E0D\u8BFB lock/catalog/token \u6587\u4EF6,\u7531\u5165\u53E3\u6CE8\u5165\u4E0E /modules \u540C\u6E90\u6570\u636E\n listModules: () => buildModuleList() as Array<Record<string, unknown>>,\n getModuleTokens: () => ({ ...moduleAuth.tokens }),\n});\nconst contentRoutes = createContentRoutes({\n json,\n loadSnapshot: loadContentSnapshotForRequest,\n});\nconst moduleRoutesInstance = createModuleRoutes({\n loadModuleCatalog,\n buildModuleList: buildModuleList as unknown as () => Array<Record<string, unknown>>,\n resolveModuleByKey,\n setModuleEnabled,\n body,\n json,\n});\n\n// \u2500\u2500 v2 \u8DEF\u7531\u5DE5\u5382 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// \u7C7B\u578B\u65AD\u8A00\u6210 unknown \u51FD\u6570 \u2014 v2 routes \u7684 ctx \u7C7B\u578B\u4E0E RouteCtx \u4E0D\u517C\u5BB9,\n// \u4F46\u8C03\u7528\u5951\u7EA6({path, method, params, req, res, body?})\u662F\u7A33\u5B9A\u7684\u3002\nconst dbRoutes = createDbRoutes({ schemaRegistry, txRunner, idempotent, json }) as unknown as (\n ctx: Record<string, unknown>\n) => Promise<boolean>;\nconst serviceRoutes = createServiceRoutes({\n serviceRegistry,\n enabled: enabledManifests,\n json,\n}) as unknown as (ctx: Record<string, unknown>) => Promise<boolean>;\nconst moduleConfigRoutes = createModuleConfigRoutes({\n projectRoot: env.PROJECT_ROOT,\n enabled: enabledManifests,\n json,\n}) as unknown as (ctx: Record<string, unknown>) => Promise<boolean>;\n\n// \u2500\u2500 \u4E3B\u8BF7\u6C42\u5904\u7406\u5668 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function handle(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {\n const url = new URL(req.url || \"/\", `http://${req.headers.host || \"localhost\"}`);\n const path = url.pathname;\n const method = req.method || \"GET\";\n const params = url.searchParams;\n\n // loopback \u7ED1\u5B9A\n const remote = req.socket.remoteAddress || \"\";\n if (remote && !remote.startsWith(\"127.\") && remote !== \"::1\" && remote !== \"::ffff:127.\") {\n json(res, { success: false, error: \"forbidden\" }, 403);\n return;\n }\n\n // \u2500\u2500 \u9884\u8BFB body(\u6240\u6709\u8DEF\u7531\u5171\u4EAB) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n await body(req);\n\n // \u2500\u2500 v2 \u6A21\u5757\u8EAB\u4EFD\u6821\u9A8C \u2192 \u5199\u5165\u8DEF\u7531 ctx.moduleAuth(LoD:\u4E0D\u6302 req \u79C1\u6709\u5B57\u6BB5) \u2500\u2500\n // \u6CE8\u610F:`/api/sfmc/configs/all` \u662F\u65E7\u7684\u4E00\u6B21\u6027\u914D\u7F6E\u5FEB\u7167\u7AEF\u70B9(SAPI ConfigManager.init\n // \u542F\u52A8\u5FC5\u7528),\u4E0D\u5C5E\u4E8E v2 \u6A21\u5757\u914D\u7F6E\u547D\u540D\u7A7A\u95F4(configs/<\u6A21\u5757 configKey>),\u5FC5\u987B\u8C41\u514D,\n // \u5426\u5219\u4F1A\u88AB\u6A21\u5757\u9274\u6743\u7F51\u5173\u62E6\u6210 401,\u5BFC\u81F4\u63D2\u4EF6\u7AEF\u8D77\u4E0D\u6765\u3002\n const isLegacyConfigAll = path === \"/api/sfmc/configs/all\";\n const needsModuleAuth =\n path.startsWith(\"/api/sfmc/db/\") ||\n path.startsWith(\"/api/sfmc/services\") ||\n (/^\\/api\\/sfmc\\/configs\\/[A-Za-z0-9_-]+(?:\\/(?:set|notify))?$/.test(path) && !isLegacyConfigAll);\n let moduleAuthCtx: { id: string; permissions: string[] } | null = null;\n if (needsModuleAuth) {\n const id = verifyModuleAuth({\n headers: req.headers,\n params,\n auth: moduleAuth,\n enabledModuleIds: enabledSet,\n });\n if (!id) {\n // LSP: v2 \u6A21\u5757\u95E8\u4E0E service-routes \u540C\u7528 ok \u65B9\u8A00\n jsonV2Fail(res, \"unauthorized: module identity invalid\", 401, \"unauthorized\");\n return;\n }\n const manifest = enabledManifests.get(id);\n moduleAuthCtx = {\n id,\n permissions: manifest?.permissions ?? [],\n };\n } else {\n // \u2500\u2500 \u65E7 env token \u9274\u6743(\u53EA\u5BF9 POST/PUT \u751F\u6548) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const PUBLIC_GET =\n path === \"/api/health\" ||\n path === \"/api/sfmc/status\" ||\n path === \"/api/sfmc/qq/join/apply-queue\" ||\n path === \"/api/sfmc/qq/join/settings\" ||\n (method === \"GET\" &&\n (path === \"/api/sfmc/content\" ||\n path === \"/api/sfmc/modules\" ||\n path === \"/api/sfmc/modules/catalog\" ||\n path.startsWith(\"/api/sfmc/modules/\") ||\n path === \"/api/sfmc/qq/bind/me\" ||\n path === \"/api/sfmc/qq/join/pending\"));\n // bind/join/events POST \u4E0E messages \u4E00\u6837\u8D70\u65E7 AUTH_TOKEN\uFF08\u82E5\u914D\u7F6E\uFF09\uFF1B\u6E38\u620F/\u6865\u540C\u4E3A loopback\n const NEEDS_AUTH =\n !PUBLIC_GET &&\n method !== \"GET\" &&\n !(\n path.startsWith(\"/api/sfmc/qq/bind/\") ||\n path.startsWith(\"/api/sfmc/qq/join/\") ||\n path.startsWith(\"/api/sfmc/qq/events\")\n );\n if (env.AUTH_TOKEN && NEEDS_AUTH) {\n const auth = req.headers[\"authorization\"] || \"\";\n const provided = auth.startsWith(\"Bearer \") ? auth.slice(7) : (req.headers[\"x-db-token\"] as string) || \"\";\n if (provided !== env.AUTH_TOKEN) {\n json(res, { success: false, error: \"unauthorized\" }, 401);\n return;\n }\n }\n }\n\n try {\n if (path === \"/api/sfmc/player-session\" && method === \"POST\") {\n const data = (await body(req)) as Record<string, unknown>;\n const playerName = String(data.playerName ?? \"\").trim();\n const xuid = String(data.xuid ?? \"\").trim();\n if (!playerName || !xuid) {\n json(res, { success: false, error: \"playerName_and_xuid_required\" }, 400);\n return;\n }\n syncPlayerSession(query, { playerName, xuid });\n json(res, { success: true });\n return;\n }\n // \u2500\u2500 v2 \u8DEF\u7531(\u4F18\u5148\u5339\u914D) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (\n moduleAuthCtx &&\n (path.startsWith(\"/api/sfmc/db/\") ||\n path.startsWith(\"/api/sfmc/services\") ||\n (/^\\/api\\/sfmc\\/configs\\/[A-Za-z0-9_-]+/.test(path) && !isLegacyConfigAll))\n ) {\n const ctx: Record<string, unknown> = {\n path,\n method,\n params,\n req,\n res,\n moduleAuth: moduleAuthCtx,\n };\n // body \u5DF2\u5728\u4E0A\u9762 `await body(req)` \u9884\u8BFB\u5E76\u7F13\u5B58\u5230 req._bodyPromise;\n // \u8FD9\u91CC\u590D\u7528\u7F13\u5B58(\u539F\u5B9E\u73B0\u8BFB\u7684 req._body \u4ECE\u672A\u88AB\u8D4B\u503C,\u5BFC\u81F4\u6240\u6709 v2 \u8DEF\u7531 body \u6052\u4E3A\u7A7A)\u3002\n ctx[\"body\"] = await body(req);\n if (path.startsWith(\"/api/sfmc/db/\")) {\n if (await dbRoutes(ctx)) return;\n } else if (path.startsWith(\"/api/sfmc/services\")) {\n if (await serviceRoutes(ctx)) return;\n } else {\n if (await moduleConfigRoutes(ctx)) return;\n }\n }\n\n // \u2500\u2500 \u5E73\u53F0\u8DEF\u7531 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const ctxBase = { path, method, params, req, res } as {\n path: string;\n method: string;\n params: URLSearchParams;\n req: http.IncomingMessage;\n res: http.ServerResponse;\n };\n if (await contentRoutes(ctxBase)) return;\n if (await moduleRoutesInstance(ctxBase)) return;\n if (await healthRoutes(ctxBase)) return;\n if (await statusRoutes(ctxBase)) return;\n if (await qqBindRoutes(ctxBase)) return;\n if (await qqJoinRoutes(ctxBase)) return;\n if (await qqEventsRoutes(ctxBase)) return;\n if (await messagesRoutes(ctxBase)) return;\n if (await configRoutes(ctxBase)) return;\n\n json(res, { success: false, error: \"not_found\" }, 404);\n } catch (err) {\n log.err(err, \"DogeDB\");\n json(res, { success: false, error: (err as Error).message }, 500);\n }\n}\n\n// \u2500\u2500 \u542F\u52A8 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst server = createServer({\n env: { PORT: env.PORT, HOST: env.HOST, AUTH_TOKEN: env.AUTH_TOKEN },\n handle,\n});\nstartConsole(server, db);\n\nexport { db, enabledManifests, env, moduleAuth, query, schemaRegistry, serviceRegistry, txRunner };\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n *\n * \u5DE5\u4F5C\u6D41:\n * 1. \u52A0\u8F7D env\n * 2. \u6821\u9A8C Node \u7248\u672C\n * 3. openDatabase + createPlatformTables(sfmc__audit / sfmc__idempotent)\n * 4. loadManifestV2() \u2014 \u5931\u8D25 = \u542F\u52A8\u5931\u8D25\n * 5. filterEnabled(loaded, lockFileEnabled)\n * 6. buildModuleAuth({auth_token, enabled_modules}) \u2190 \u4E0E DB \u540C\u76EE\u5F55 module-tokens.json\n * 7. \u5B9E\u4F8B\u5316:SchemaRegistry / ServiceRegistry / IdempotencyStore / TxRunner\n * 8. \u88C5\u914D v2 \u8DEF\u7531 (/api/sfmc/db/* + /api/sfmc/services* + /api/sfmc/configs/:key/*)\n * \u53E6\u4FDD\u7559 messages(qq-bridge) + config/modules/health \u5E73\u53F0\u8DEF\u7531\n * 9. createServer + listen\n *\n * \u9274\u6743(handle \u5C42):\n * - /api/sfmc/db/*, /api/sfmc/services*, /api/sfmc/configs/:key(/set|notify)*\n * \u2192 module token (Authorization: Bearer ...) + ?moduleId=...\n * - \u5176\u4ED6:env.AUTH_TOKEN \u65E7 auth(NEEDS_AUTH)\n */\n\nimport http from \"node:http\";\nimport { PLATFORM_MONITORING_SERVICES, PLATFORM_SERVICE_OWNER } from \"@sfmc-bds/sdk/contracts\";\nimport { SQL } from \"sql-template-strings\";\n\nimport { createPlatformTables } from \"./db-tables.js\";\nimport { syncPlayerSession } from \"./domain/player-session.js\";\nimport { initSchema } from \"./domain/schema.js\";\nimport { loadEnv } from \"./env.js\";\nimport { createIdempotencyStore } from \"./lib/idempotency-store.js\";\nimport { log } from \"./lib/log.js\";\nimport { assertNodeVersion } from \"./lib/runtime.js\";\nimport { createQuery, openDatabase } from \"./lib/sqlite.js\";\nimport { loadManifestV2 } from \"./manifest-loader.js\";\nimport { buildModuleAuth, ensureModuleToken, persistModuleAuth, verifyModuleAuth } from \"./module-auth.js\";\nimport { syncModuleRuntimeState } from \"./module-runtime-sync.js\";\nimport { SchemaRegistry } from \"./schema-registry.js\";\nimport { createServer, startConsole } from \"./server.js\";\nimport { ServiceRegistry } from \"./service-registry.js\";\nimport { registerEnabledBuiltinServices } from \"./services/builtin-handlers.js\";\nimport { TxRunner } from \"./tx-runner.js\";\n\nimport { configPath, ensureJson, patchJson, readJson } from \"@sfmc-bds/sdk/node/config\";\nimport path, { join } from \"node:path\";\n\nimport { jsonV2Fail } from \"./routes/_shared.js\";\nimport { createDbRoutes } from \"./routes/db-routes.js\";\nimport { createModuleConfigRoutes } from \"./routes/module-config-routes.js\";\nimport { createServiceRoutes } from \"./routes/service-routes.js\";\n\nimport { forwardToQQBridge, makeOutboundConfig } from \"./domain/bridge.js\";\nimport { loadContentSnapshot } from \"./domain/installed-content.js\";\nimport { createQqEventsDispatcher, resolveQqEventsConfig, type ResolvedQqEventsConfig } from \"./domain/qq-events.js\";\nimport { body as sharedBody, json as sharedJson } from \"./lib/http.js\";\nimport { isEnabled, loadModuleLock, saveModuleLock, updateModuleState } from \"./lib/module-state.js\";\nimport { createConfigRoutes } from \"./routes/config.js\";\nimport { createContentRoutes } from \"./routes/content.js\";\nimport { createHealthRoutes } from \"./routes/health.js\";\nimport { createMessagesRoutes, gameChatForwardPayload, type ChatChannelQQFlags } from \"./routes/messages.js\";\nimport { createModuleRoutes } from \"./routes/modules.js\";\nimport { codeTakenBy, type BindProvider } from \"./domain/bind-providers.js\";\nimport { resolvePlayerLevel } from \"./domain/player-level.js\";\nimport { createQqBindProvider } from \"./domain/qq-bind.js\";\nimport { createWechatBindProvider } from \"./domain/wechat-bind.js\";\nimport { createBindConfirmRoutes } from \"./routes/bind-confirm.js\";\nimport { createQqBindRoutes } from \"./routes/qq-bind.js\";\nimport { createWechatBindRoutes } from \"./routes/wechat-bind.js\";\nimport { createQqEventsRoutes } from \"./routes/qq-events.js\";\nimport { createQqJoinRoutes, type JoinFeatureFlags } from \"./routes/qq-join.js\";\nimport { createStatusRoutes } from \"./routes/status.js\";\n\nif (!assertNodeVersion(22, 13)) {\n process.exit(2);\n}\n\nconst env = loadEnv();\nconst db = openDatabase(env.DB_PATH);\ncreatePlatformTables(db); // sfmc__audit / sfmc__idempotent\ninitSchema(db); // \u5E73\u53F0\u4E1A\u52A1 bootstrap \u8868(players/world/chat/...)\u2014\u2014qq-bridge \u5728 SAPI defineTable \u4E4B\u524D\u5C31\u9700\u8981\nconst query = createQuery(db);\n\n// \u2500\u2500 v2 manifest \u52A0\u8F7D(\u5931\u8D25 = \u542F\u52A8\u5931\u8D25)\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst loadedManifest = loadManifestV2(); // throws on violation\nlog.success(\n `[manifest v2] loaded ${Object.keys(loadedManifest.modules).length} modules; provides ${loadedManifest.providesMap.size} services`\n);\n\n// \u2500\u2500 enabled \u96C6\u5408(\u4ECE lock file)\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst lockFile = loadModuleLock(env.MODULE_LOCK_PATH);\nconst moduleCatalog = readJson<{ modules?: unknown[] }>(env.MODULE_CATALOG_PATH) ?? { modules: [] };\nconst catalogIds = new Set(\n Array.isArray(moduleCatalog.modules)\n ? (moduleCatalog.modules as Array<{ id?: string }>).map((m) => String(m.id || \"\")).filter((id) => id.length > 0)\n : []\n);\nconst enabledSet = new Set<string>();\nfor (const id of Object.keys(loadedManifest.modules)) {\n if (!catalogIds.has(id)) continue;\n const catalogEntry = (moduleCatalog.modules as Array<Record<string, unknown>>).find((m) => String(m.id) === id);\n if (!catalogEntry) continue;\n const defaultEnabled = catalogEntry.enabledByDefault !== false;\n if (isEnabled(lockFile, id, defaultEnabled)) enabledSet.add(id);\n}\nconst enabledManifests = new Map<string, NonNullable<(typeof loadedManifest.modules)[string]>>();\nfor (const id of enabledSet) {\n const m = loadedManifest.modules[id];\n if (m) enabledManifests.set(id, m);\n}\nlog.info(`[manifest v2] enabled: ${[...enabledSet].sort().join(\", \") || \"(none)\"}`);\n\n// \u2500\u2500 \u6A21\u5757 HMAC token map(\u4E0E DB \u540C\u76EE\u5F55 module-tokens.json)\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst moduleAuth = buildModuleAuth({\n dbPath: env.DB_PATH,\n envAuthToken: env.AUTH_TOKEN,\n enabledModuleIds: [...enabledSet],\n});\n// \u5E73\u53F0\u5BBF\u4E3B\uFF08QQ \u7ED1\u5B9A/\u8D26\u53F7\u5FEB\u7167\uFF09\u9700\u8981\u7A33\u5B9A token\uFF0C\u7ECF configs/all.module_tokens \u4E0B\u53D1\u5230 BDS\nif (ensureModuleToken(moduleAuth, PLATFORM_SERVICE_OWNER)) {\n persistModuleAuth(env.DB_PATH, moduleAuth, env.AUTH_TOKEN);\n log.info(`[auth] \u5DF2\u6D3E\u751F\u5E73\u53F0\u5BBF\u4E3B token: ${PLATFORM_SERVICE_OWNER}`);\n}\n\n// \u2500\u2500 \u4E09\u4EF6\u5957 + \u8DEF\u7531\u5DE5\u5382 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst schemaRegistry = new SchemaRegistry(db);\nconst serviceRegistry = new ServiceRegistry();\nconst idempotent = createIdempotencyStore(db);\nconst txRunner = new TxRunner({\n db,\n query,\n schema: schemaRegistry,\n serviceRegistry,\n enabled: enabledManifests,\n});\n\n// \u2500\u2500 \u8FDB\u7A0B\u5185\u7F6E service handler(\u6269\u5C55\u70B9:BUILTIN_SERVICE_PLUGINS) \u2500\u2500\n{\n const plugins = registerEnabledBuiltinServices(serviceRegistry, { query, db }, enabledSet);\n if (plugins > 0) {\n log.success(`[service] registered ${serviceRegistry.list().length} handlers from ${plugins} builtin plugin(s)`);\n }\n}\n\nconst json = sharedJson;\nconst body = sharedBody;\n\n// \u2500\u2500 \u5DE5\u5177\u51FD\u6570 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction loadModuleCatalog() {\n return Array.isArray(moduleCatalog.modules) ? moduleCatalog.modules : [];\n}\n\nfunction buildModuleList() {\n const catalog = loadModuleCatalog();\n return catalog\n .map((raw) => {\n const entry =\n (raw as Record<string, unknown>).entry && typeof (raw as Record<string, unknown>).entry === \"object\"\n ? ((raw as Record<string, unknown>).entry as Record<string, unknown>)\n : {};\n const id = String((raw as Record<string, unknown>).id || \"\").trim();\n const configKey = String(\n (raw as Record<string, unknown>).configKey || (raw as Record<string, unknown>).config_key || \"\"\n ).trim();\n if (!id || !configKey) return null;\n const state = lockFile.modules[id];\n const enabled = isEnabled(lockFile, id, (raw as Record<string, unknown>).enabledByDefault !== false);\n return {\n id,\n module_id: id,\n name: configKey,\n configKey,\n config_key: configKey,\n display_name: String((raw as Record<string, unknown>).name || configKey),\n description: String((raw as Record<string, unknown>).description || \"\"),\n default_enabled: (raw as Record<string, unknown>).enabledByDefault !== false,\n can_disable: moduleCanDisable(raw as Record<string, unknown>),\n // ConfigManager \u8BA4 installed!==false;\u5DF2\u88C5\u5305\u9ED8\u8BA4 true\n installed: true,\n requires: Array.isArray((raw as Record<string, unknown>).requires)\n ? ((raw as Record<string, unknown>).requires as unknown[]).filter(Boolean).map(String)\n : [],\n optional: Array.isArray((raw as Record<string, unknown>).optional)\n ? ((raw as Record<string, unknown>).optional as unknown[]).filter(Boolean).map(String)\n : [],\n commands: Array.isArray((raw as Record<string, unknown>).commands)\n ? ((raw as Record<string, unknown>).commands as unknown[]).filter(Boolean).map(String)\n : [],\n entry: {\n kind: String(entry.kind || \"\"),\n path: String(entry.path || \"\"),\n init: String(entry.init || \"\"),\n },\n updated_at: state?.updatedAt ?? null,\n enabled: !!enabled,\n };\n })\n .filter(Boolean);\n}\n\n/**\n * QQ\u300C\u6A21\u5757 / \u8D44\u6E90\u5305\u300D\u5FEB\u7167\u3002\u6BCF\u6B21\u8BF7\u6C42\u73B0\u8BFB catalog \u4E0E\u78C1\u76D8\uFF0C\u88C5\u5305\u540E\u4E0D\u7528\u91CD\u542F db-server\u3002\n */\nfunction loadContentSnapshotForRequest() {\n const modules = (buildModuleList() ?? []).flatMap((raw) => {\n if (!raw || typeof raw !== \"object\") return [];\n const row = raw as { id?: unknown; display_name?: unknown; enabled?: unknown };\n const id = String(row.id ?? \"\").trim();\n if (!id) return [];\n return [\n {\n id,\n display_name: String(row.display_name || id),\n enabled: row.enabled !== false,\n },\n ];\n });\n return loadContentSnapshot({\n packagesDir: join(env.MODULES_DIR, \"packages\"),\n modules,\n bdsRoot: currentBdsRoot(),\n });\n}\n\n/**\n * BDS \u6839\u76EE\u5F55\uFF08configs/bds_updater.json \u7684 bds_path\uFF0C\u76F8\u5BF9\u8DEF\u5F84\u6309\u9879\u76EE\u6839\u89E3\u6790\uFF09\uFF1B\u672A\u914D\u7F6E\u65F6\u4E3A null\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u5185\u5BB9\u5FEB\u7167\u8BFB\u53D6\u5DF2\u88C5\u5305\uFF0C\u5FAE\u4FE1\u7ED1\u5B9A\u67E5\u8BE2\u8BFB\u53D6 BDS permissions.json \u8BA1\u7B97\u73A9\u5BB6\u539F\u751F\u7B49\u7EA7\uFF08DRY\uFF1A\u540C\u4E00\u5904\u89E3\u6790\uFF09\u3002\n */\nfunction currentBdsRoot(): string | null {\n const cfg = readJson<{ bds_path?: string }>(configPath(env.PROJECT_ROOT, \"bds_updater.json\"));\n const rawBds = typeof cfg?.bds_path === \"string\" ? cfg.bds_path.trim() : \"\";\n return rawBds ? (path.isAbsolute(rawBds) ? rawBds : path.resolve(env.PROJECT_ROOT, rawBds)) : null;\n}\n\n/** catalog \u7701\u7565 canDisable \u65F6\u9ED8\u8BA4\u5141\u8BB8\u7981\u7528(\u4E0E buildModuleList.can_disable \u540C\u6E90)\u3002 */\nfunction moduleCanDisable(raw: Record<string, unknown>): boolean {\n return raw.canDisable !== false;\n}\n\nfunction resolveModuleByKey(key: string) {\n const k = String(key || \"\").trim();\n const catalog = loadModuleCatalog();\n const raw = catalog.find(\n (m) =>\n String((m as Record<string, unknown>).id || \"\") === k ||\n String((m as Record<string, unknown>).configKey || (m as Record<string, unknown>).config_key || \"\") === k\n ) as Record<string, unknown> | undefined;\n if (!raw) return null;\n const id = String(raw.id || \"\").trim();\n const configKey = String(raw.configKey || raw.config_key || \"\").trim();\n if (!id || !configKey) return null;\n /* LSP:\u4E0E buildModuleList.can_disable \u540C\u6E90 \u2014 \u7701\u7565\u5B57\u6BB5\u89C6\u4E3A\u53EF\u7981\u7528 */\n return { id, configKey, canDisable: moduleCanDisable(raw) };\n}\n\nfunction setModuleEnabled(mod: { id: string; canDisable: boolean }, enabled: boolean) {\n // \u76F4\u63A5\u66F4\u65B0\u542F\u52A8\u65F6\u7F13\u5B58\u7684 lockFile(\u800C\u975E\u53E6\u8BFB\u4E00\u4EFD\u65B0\u526F\u672C),\n // \u5426\u5219 buildModuleList() \u8BFB\u7684\u4ECD\u662F\u65E7\u7F13\u5B58,\u5BFC\u81F4\u542F\u505C\u540E enabled \u72B6\u6001\u4E0D\u7FFB\u8F6C\u3002\n updateModuleState(lockFile, mod.id, { enabled: !!enabled });\n // DRY:\u4E0E loadModuleLock \u5BF9\u79F0\u8D70 saveModuleLock,\u52FF\u6563\u843D writeJson\n saveModuleLock(env.MODULE_LOCK_PATH, lockFile);\n\n // DIP:\u70ED\u540C\u6B65 enabledSet / tokens / manifests / builtin handlers(\u4E0D\u91CD\u542F db-server)\n syncModuleRuntimeState({\n moduleId: mod.id,\n enabled: !!enabled,\n dbPath: env.DB_PATH,\n envAuthToken: env.AUTH_TOKEN,\n enabledSet,\n enabledManifests,\n loadedManifest,\n moduleAuth,\n serviceRegistry,\n builtinDeps: { query, db },\n });\n}\n\n// \u2500\u2500 \u5E73\u53F0\u8DEF\u7531(\u975E\u6A21\u5757\u4E1A\u52A1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst healthRoutes = createHealthRoutes();\n// \u6307\u6807\u72EC\u7ACB\u843D\u5E93\uFF0C\u907F\u514D\u5199\u5165\u4E1A\u52A1\u6A21\u5757\u6B63\u5728\u6301\u6709\u7684\u8DE8\u8BF7\u6C42\u4E8B\u52A1\u3002\nconst metricsDb = openDatabase(path.join(path.dirname(env.DB_PATH), \"runtime-metrics.sqlite\"));\nconst statusRoutes = createStatusRoutes({ query: createQuery(metricsDb) });\nfor (const name of PLATFORM_MONITORING_SERVICES) serviceRegistry.registerHandler(PLATFORM_SERVICE_OWNER, name, async () => {\n const response = await fetch(`http://127.0.0.1:${env.PORT}/api/sfmc/metrics`, { signal: AbortSignal.timeout(10_000) });\n if (!response.ok) throw new Error(\"\u5E73\u53F0\u8FD0\u884C\u6307\u6807\u8BFB\u53D6\u5931\u8D25\");\n const result = await response.json() as { current: { tps: number | null; chunkEstimate: number | null } | null };\n const tps = result.current?.tps ?? null;\n const grade = tps === null ? \"unknown\" : tps >= 19.5 ? \"green\" : tps >= 15 ? \"yellow\" : tps >= 10 ? \"gold\" : \"red\";\n if (name === \"tps.current\") return tps;\n if (name === \"tps.status\") return { tps, grade, text: `\u00A77[TPS] \u00A7f${tps?.toFixed(2) ?? \"\u672A\u77E5\"} \u00A77/ 20.00` };\n return result.current ? { ...result.current, grade, totalLoadedChunks: result.current.chunkEstimate } : null;\n});\n/**\n * \u5DF2\u6CE8\u518C\u7684\u5916\u90E8\u8D26\u53F7\u7ED1\u5B9A\u6E20\u9053\uFF08QQ\u3001\u5FAE\u4FE1\uFF09\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u7EDF\u4E00\u786E\u8BA4\u5165\u53E3\u6309\u987A\u5E8F\u8BE2\u95EE\uFF1B\u4E24\u4E2A\u6E20\u9053\u7533\u8BF7\u77ED\u7801\u65F6\u5171\u7528 isBindCodeTaken \u8DE8\u6E20\u9053\u67E5\u91CD\u3002\u65B0\u589E\u6E20\u9053\u5728\u6B64\u8FFD\u52A0\uFF08OCP\uFF09\u3002\n */\nconst bindProviders: readonly BindProvider[] = [createQqBindProvider(query), createWechatBindProvider(query)];\nconst isBindCodeTaken = codeTakenBy(() => bindProviders);\nconst qqBindRoutes = createQqBindRoutes({ query, body, json, isCodeTaken: isBindCodeTaken });\nconst bindConfirmRoutes = createBindConfirmRoutes({ body, json, providers: () => bindProviders });\nconst wechatBindRoutes = createWechatBindRoutes({\n query,\n body,\n json,\n isCodeTaken: isBindCodeTaken,\n // \u6BCF\u6B21\u73B0\u8BFB\u4E24\u4EFD\u6743\u9650\u6587\u4EF6\uFF1A\u7BA1\u7406\u5458\u8C03\u6574\u6743\u9650\u540E\uFF0C\u5C0F\u7A0B\u5E8F\u7BA1\u7406\u7AEF\u6388\u6743\u7ACB\u5373\u968F\u4E4B\u53D8\u5316\n resolveLevel: (player) =>\n resolvePlayerLevel(\n {\n readSfmcPermissions: () => readJson(configPath(env.PROJECT_ROOT, \"permissions.json\")),\n readBdsPermissions: () => {\n const bdsRoot = currentBdsRoot();\n return bdsRoot ? readJson(join(bdsRoot, \"permissions.json\")) : null;\n },\n },\n player\n ),\n});\n\n/** \u5E73\u53F0 QQ \u7ED1\u5B9A\u76F8\u5173\u914D\u7F6E\uFF08\u975E SDK qq_config\uFF1B\u539F qq-link \u6A21\u5757\u914D\u7F6E\u952E\uFF09 */\nconst QQ_LINK_CONFIG_KEY = \"qq_link\";\nconst QQ_LINK_DEFAULTS = {\n allowlist_enabled: true,\n require_approval: true,\n /** \u662F\u5426\u5C06 QQ \u7FA4\u4E3B/\u7FA4\u7BA1\u89C6\u4F5C SFMC \u7BA1\u7406\u5458\uFF1B\u7F3A\u7701\u5F00\u542F\uFF0C\u4EC5\u6539\u672C\u6587\u4EF6\u53EF\u5173\u95ED\uFF0CAPI/\u7FA4\u804A\u4E0D\u53EF\u5199 */\n treat_group_admins_as_admins: true,\n} as const;\n\nfunction asConfigBool(v: unknown, fallback: boolean): boolean {\n if (v === undefined || v === null) return fallback;\n if (typeof v === \"boolean\") return v;\n const s = String(v).trim().toLowerCase();\n if (s === \"true\" || s === \"1\" || s === \"yes\" || s === \"on\") return true;\n if (s === \"false\" || s === \"0\" || s === \"no\" || s === \"off\") return false;\n return fallback;\n}\n\nfunction qqLinkConfigFile(): string {\n return join(env.PROJECT_ROOT, \"configs\", `${QQ_LINK_CONFIG_KEY}.json`);\n}\n\nfunction readJoinFlags(): JoinFeatureFlags {\n // \u5E73\u53F0\u914D\u7F6E configs/qq_link.json\uFF08\u975E SDK qq_config\uFF09\n const disk = ensureJson<Record<string, unknown>>(qqLinkConfigFile(), { ...QQ_LINK_DEFAULTS });\n return {\n allowlistEnabled: asConfigBool(disk.allowlist_enabled, QQ_LINK_DEFAULTS.allowlist_enabled),\n requireApproval: asConfigBool(disk.require_approval, QQ_LINK_DEFAULTS.require_approval),\n treatGroupAdminsAsAdmins: asConfigBool(\n disk.treat_group_admins_as_admins,\n QQ_LINK_DEFAULTS.treat_group_admins_as_admins\n ),\n };\n}\n\nfunction writeJoinFlags(partial: Partial<JoinFeatureFlags>): JoinFeatureFlags {\n const file = qqLinkConfigFile();\n ensureJson<Record<string, unknown>>(file, { ...QQ_LINK_DEFAULTS });\n const patch: Record<string, boolean> = {};\n if (partial.allowlistEnabled !== undefined) patch.allowlist_enabled = partial.allowlistEnabled;\n if (partial.requireApproval !== undefined) patch.require_approval = partial.requireApproval;\n // \u6545\u610F\u4E0D\u5199 treat_group_admins_as_admins\uFF1A\u4EC5\u4EBA\u5DE5\u6539 configs/qq_link.json\n if (Object.keys(patch).length > 0) {\n patchJson(file, patch);\n }\n return readJoinFlags();\n}\n\n// \u542F\u52A8\u5373\u843D\u76D8\u5E73\u53F0\u9ED8\u8BA4\u914D\u7F6E\uFF0C\u907F\u514D\u300C\u4ECE\u672A\u70B9\u8FC7\u914D\u7F6E/\u7533\u8BF7\u300D\u65F6 configs/qq_link.json \u4E0D\u5B58\u5728\n{\n const created = !readJson(qqLinkConfigFile());\n ensureJson<Record<string, unknown>>(qqLinkConfigFile(), { ...QQ_LINK_DEFAULTS });\n if (created) {\n log.info(`\u5DF2\u5199\u5165\u5E73\u53F0\u914D\u7F6E\u9AA8\u67B6: configs/${QQ_LINK_CONFIG_KEY}.json`);\n }\n}\n\nconst qqJoinRoutes = createQqJoinRoutes({\n query,\n body,\n json,\n getAdminOpenids: () => {\n const raw = (env.qqconfig[\"official\"] as { admin_openids?: unknown } | undefined)?.admin_openids;\n if (!Array.isArray(raw)) return [];\n return raw.map((x) => String(x).trim()).filter(Boolean);\n },\n getJoinFlags: () => readJoinFlags(),\n setJoinFlags: (partial) => writeJoinFlags(partial),\n});\n\nfunction readQqEventsSettings(): ResolvedQqEventsConfig {\n const disk = readJson<Record<string, unknown>>(join(env.PROJECT_ROOT, \"configs\", \"qq_config.json\"));\n if (!disk) throw new Error(\"qq_config.json \u65E0\u6CD5\u8BFB\u53D6\uFF0C\u4E8B\u4EF6\u8BBE\u7F6E\u672A\u4FEE\u6539\");\n return resolveQqEventsConfig(disk.qq_events);\n}\n\nfunction writeQqEventsSettings(patch: Partial<ResolvedQqEventsConfig>): ResolvedQqEventsConfig {\n const file = join(env.PROJECT_ROOT, \"configs\", \"qq_config.json\");\n const settings = { ...readQqEventsSettings(), ...patch };\n patchJson(file, { qq_events: settings });\n return settings;\n}\n\nfunction currentOutbound() {\n return makeOutboundConfig({\n QQ_BACKEND: env.QQ_BACKEND,\n LLBOT_HOST: env.LLBOT_HOST,\n LLBOT_PORT: env.LLBOT_PORT,\n LLBOT_TOKEN: env.LLBOT_TOKEN,\n QQ_GROUP_ID: env.QQ_GROUP_ID,\n QQ_APP_ID: env.QQ_APP_ID,\n QQ_APP_SECRET: env.QQ_APP_SECRET,\n QQ_SANDBOX: env.QQ_SANDBOX,\n QQ_GROUP_OPENID: env.QQ_GROUP_OPENID,\n });\n}\n\nconst qqEventsDispatcher = createQqEventsDispatcher({\n getConfig: readQqEventsSettings,\n getOutbound: () => currentOutbound(),\n});\nconst qqEventsRoutes = createQqEventsRoutes({\n body,\n json,\n dispatcher: qqEventsDispatcher,\n getSettings: readQqEventsSettings,\n setSettings: writeQqEventsSettings,\n isAdmin: (openid, asGroupAdmin) => {\n const admins = (env.qqconfig[\"official\"] as { admin_openids?: unknown } | undefined)?.admin_openids;\n return (\n (Array.isArray(admins) && admins.includes(openid)) || (asGroupAdmin && readJoinFlags().treatGroupAdminsAsAdmins)\n );\n },\n});\n\n/** \u8BFB\u53D6\u5355\u4E2A\u804A\u5929\u9891\u9053\u3002\u8868\u5C1A\u672A\u7531\u804A\u5929\u6A21\u5757\u5EFA\u51FA\u65F6\u8FD4\u56DE null\uFF0C\u4E0D\u8BA9\u8BF7\u6C42 500\u3002 */\nfunction readChatChannel(channelId: string): ChatChannelQQFlags | null {\n try {\n const rows = query(SQL`SELECT * FROM sfmc_chat_channels WHERE id = ${channelId}`);\n return Array.isArray(rows) ? ((rows[0] as ChatChannelQQFlags | undefined) ?? null) : null;\n } catch (err) {\n log.warn(`\u8BFB\u53D6\u804A\u5929\u9891\u9053\u5931\u8D25: ${(err as Error).message}`);\n return null;\n }\n}\n\n/** \u6D88\u606F\u6765\u6E90\u4E3A QQ \u7684\u9891\u9053\u3002QQ \u5165\u7AD9\u53EA\u6295\u5230\u8FD9\u4E9B\u9891\u9053\u3002 */\nfunction listQQSourceChannels(): ChatChannelQQFlags[] {\n try {\n const rows = query(SQL`SELECT * FROM sfmc_chat_channels`);\n if (!Array.isArray(rows)) return [];\n return (rows as ChatChannelQQFlags[]).filter((row) => row.source_qq === 1);\n } catch (err) {\n log.warn(`\u8BFB\u53D6 QQ \u6765\u6E90\u9891\u9053\u5931\u8D25: ${(err as Error).message}`);\n return [];\n }\n}\n\nconst messagesRoutes = createMessagesRoutes({\n query,\n body,\n json,\n getChannelForQQ: readChatChannel,\n listQQSourceChannels,\n forwardToQQBridge: (channelId: string, prefix: string, fromName: string, content: string, fromId: string) =>\n forwardToQQBridge(currentOutbound(), channelId, prefix, fromName, content, fromId),\n});\n\n// \u6E38\u620F\u53D1\u8A00\u8D70 db.tx \u63D2\u5165\uFF0C\u4E0D\u7ECF\u8FC7 /api/sfmc/messages\u3002\u63D0\u4EA4\u540E\u518D\u6309\u9891\u9053\u5F00\u5173\u8F6C\u53D1\u5230 QQ\u3002\ntxRunner.setAfterCommit((inserts) => {\n for (const item of inserts) {\n if (item.table !== \"sfmc_chat_messages\") continue;\n const payload = gameChatForwardPayload(item.row, readChatChannel(String(item.row.channel_id ?? \"\")));\n if (!payload) continue;\n forwardToQQBridge(\n currentOutbound(),\n payload.channelId,\n payload.prefix,\n payload.fromName,\n payload.content,\n payload.fromId,\n );\n }\n});\nconst configRoutes = createConfigRoutes({\n json,\n projectRoot: env.PROJECT_ROOT,\n // DIP:\u8DEF\u7531\u4E0D\u8BFB lock/catalog/token \u6587\u4EF6,\u7531\u5165\u53E3\u6CE8\u5165\u4E0E /modules \u540C\u6E90\u6570\u636E\n listModules: () => buildModuleList() as Array<Record<string, unknown>>,\n getModuleTokens: () => ({ ...moduleAuth.tokens }),\n});\nconst contentRoutes = createContentRoutes({\n json,\n loadSnapshot: loadContentSnapshotForRequest,\n});\nconst moduleRoutesInstance = createModuleRoutes({\n loadModuleCatalog,\n buildModuleList: buildModuleList as unknown as () => Array<Record<string, unknown>>,\n resolveModuleByKey,\n setModuleEnabled,\n body,\n json,\n});\n\n// \u2500\u2500 v2 \u8DEF\u7531\u5DE5\u5382 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// \u7C7B\u578B\u65AD\u8A00\u6210 unknown \u51FD\u6570 \u2014 v2 routes \u7684 ctx \u7C7B\u578B\u4E0E RouteCtx \u4E0D\u517C\u5BB9,\n// \u4F46\u8C03\u7528\u5951\u7EA6({path, method, params, req, res, body?})\u662F\u7A33\u5B9A\u7684\u3002\nconst dbRoutes = createDbRoutes({ schemaRegistry, txRunner, idempotent, json }) as unknown as (\n ctx: Record<string, unknown>\n) => Promise<boolean>;\nconst serviceRoutes = createServiceRoutes({\n serviceRegistry,\n enabled: enabledManifests,\n json,\n}) as unknown as (ctx: Record<string, unknown>) => Promise<boolean>;\nconst moduleConfigRoutes = createModuleConfigRoutes({\n projectRoot: env.PROJECT_ROOT,\n enabled: enabledManifests,\n json,\n}) as unknown as (ctx: Record<string, unknown>) => Promise<boolean>;\n\n// \u2500\u2500 \u4E3B\u8BF7\u6C42\u5904\u7406\u5668 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function handle(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {\n const url = new URL(req.url || \"/\", `http://${req.headers.host || \"localhost\"}`);\n const path = url.pathname;\n const method = req.method || \"GET\";\n const params = url.searchParams;\n\n // loopback \u7ED1\u5B9A\n const remote = req.socket.remoteAddress || \"\";\n if (remote && !remote.startsWith(\"127.\") && remote !== \"::1\" && remote !== \"::ffff:127.\") {\n json(res, { success: false, error: \"forbidden\" }, 403);\n return;\n }\n\n // \u2500\u2500 \u9884\u8BFB body(\u6240\u6709\u8DEF\u7531\u5171\u4EAB) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n await body(req);\n\n // \u2500\u2500 v2 \u6A21\u5757\u8EAB\u4EFD\u6821\u9A8C \u2192 \u5199\u5165\u8DEF\u7531 ctx.moduleAuth(LoD:\u4E0D\u6302 req \u79C1\u6709\u5B57\u6BB5) \u2500\u2500\n // \u6CE8\u610F:`/api/sfmc/configs/all` \u662F\u65E7\u7684\u4E00\u6B21\u6027\u914D\u7F6E\u5FEB\u7167\u7AEF\u70B9(SAPI ConfigManager.init\n // \u542F\u52A8\u5FC5\u7528),\u4E0D\u5C5E\u4E8E v2 \u6A21\u5757\u914D\u7F6E\u547D\u540D\u7A7A\u95F4(configs/<\u6A21\u5757 configKey>),\u5FC5\u987B\u8C41\u514D,\n // \u5426\u5219\u4F1A\u88AB\u6A21\u5757\u9274\u6743\u7F51\u5173\u62E6\u6210 401,\u5BFC\u81F4\u63D2\u4EF6\u7AEF\u8D77\u4E0D\u6765\u3002\n const isLegacyConfigAll = path === \"/api/sfmc/configs/all\";\n const needsModuleAuth =\n path.startsWith(\"/api/sfmc/db/\") ||\n path.startsWith(\"/api/sfmc/services\") ||\n (/^\\/api\\/sfmc\\/configs\\/[A-Za-z0-9_-]+(?:\\/(?:set|notify))?$/.test(path) && !isLegacyConfigAll);\n let moduleAuthCtx: { id: string; permissions: string[] } | null = null;\n if (needsModuleAuth) {\n const id = verifyModuleAuth({\n headers: req.headers,\n params,\n auth: moduleAuth,\n enabledModuleIds: enabledSet,\n });\n if (!id) {\n // LSP: v2 \u6A21\u5757\u95E8\u4E0E service-routes \u540C\u7528 ok \u65B9\u8A00\n jsonV2Fail(res, \"unauthorized: module identity invalid\", 401, \"unauthorized\");\n return;\n }\n const manifest = enabledManifests.get(id);\n moduleAuthCtx = {\n id,\n permissions: manifest?.permissions ?? [],\n };\n } else {\n // \u2500\u2500 \u65E7 env token \u9274\u6743(\u53EA\u5BF9 POST/PUT \u751F\u6548) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const PUBLIC_GET =\n path === \"/api/health\" ||\n path === \"/api/sfmc/status\" ||\n path === \"/api/sfmc/qq/join/apply-queue\" ||\n path === \"/api/sfmc/qq/join/settings\" ||\n (method === \"GET\" &&\n (path === \"/api/sfmc/content\" ||\n path === \"/api/sfmc/modules\" ||\n path === \"/api/sfmc/modules/catalog\" ||\n path.startsWith(\"/api/sfmc/modules/\") ||\n path === \"/api/sfmc/qq/bind/me\" ||\n path === \"/api/sfmc/wechat/bind/me\" ||\n path === \"/api/sfmc/qq/join/pending\"));\n // bind/join/events POST \u4E0E messages \u4E00\u6837\u8D70\u65E7 AUTH_TOKEN\uFF08\u82E5\u914D\u7F6E\uFF09\uFF1B\u6E38\u620F/\u6865\u540C\u4E3A loopback\n // \u5FAE\u4FE1\u7ED1\u5B9A\uFF08mp-gateway \u8C03\u7528\uFF09\u4E0E\u7EDF\u4E00\u786E\u8BA4\u5165\u53E3\uFF08\u6E38\u620F\u8C03\u7528\uFF09\u4E0E QQ \u7ED1\u5B9A\u540C\u4E00\u4FE1\u4EFB\u8FB9\u754C\uFF1A\u4EC5\u672C\u673A\n const NEEDS_AUTH =\n !PUBLIC_GET &&\n method !== \"GET\" &&\n !(\n path.startsWith(\"/api/sfmc/qq/bind/\") ||\n path.startsWith(\"/api/sfmc/qq/join/\") ||\n path.startsWith(\"/api/sfmc/qq/events\") ||\n path.startsWith(\"/api/sfmc/wechat/bind/\") ||\n path === \"/api/sfmc/bind/confirm\"\n );\n if (env.AUTH_TOKEN && NEEDS_AUTH) {\n const auth = req.headers[\"authorization\"] || \"\";\n const provided = auth.startsWith(\"Bearer \") ? auth.slice(7) : (req.headers[\"x-db-token\"] as string) || \"\";\n if (provided !== env.AUTH_TOKEN) {\n json(res, { success: false, error: \"unauthorized\" }, 401);\n return;\n }\n }\n }\n\n try {\n if (path === \"/api/sfmc/player-session\" && method === \"POST\") {\n const data = (await body(req)) as Record<string, unknown>;\n const playerName = String(data.playerName ?? \"\").trim();\n const xuid = String(data.xuid ?? \"\").trim();\n if (!playerName || !xuid) {\n json(res, { success: false, error: \"playerName_and_xuid_required\" }, 400);\n return;\n }\n syncPlayerSession(query, { playerName, xuid });\n json(res, { success: true });\n return;\n }\n // \u2500\u2500 v2 \u8DEF\u7531(\u4F18\u5148\u5339\u914D) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (\n moduleAuthCtx &&\n (path.startsWith(\"/api/sfmc/db/\") ||\n path.startsWith(\"/api/sfmc/services\") ||\n (/^\\/api\\/sfmc\\/configs\\/[A-Za-z0-9_-]+/.test(path) && !isLegacyConfigAll))\n ) {\n const ctx: Record<string, unknown> = {\n path,\n method,\n params,\n req,\n res,\n moduleAuth: moduleAuthCtx,\n };\n // body \u5DF2\u5728\u4E0A\u9762 `await body(req)` \u9884\u8BFB\u5E76\u7F13\u5B58\u5230 req._bodyPromise;\n // \u8FD9\u91CC\u590D\u7528\u7F13\u5B58(\u539F\u5B9E\u73B0\u8BFB\u7684 req._body \u4ECE\u672A\u88AB\u8D4B\u503C,\u5BFC\u81F4\u6240\u6709 v2 \u8DEF\u7531 body \u6052\u4E3A\u7A7A)\u3002\n ctx[\"body\"] = await body(req);\n if (path.startsWith(\"/api/sfmc/db/\")) {\n if (await dbRoutes(ctx)) return;\n } else if (path.startsWith(\"/api/sfmc/services\")) {\n if (await serviceRoutes(ctx)) return;\n } else {\n if (await moduleConfigRoutes(ctx)) return;\n }\n }\n\n // \u2500\u2500 \u5E73\u53F0\u8DEF\u7531 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const ctxBase = { path, method, params, req, res } as {\n path: string;\n method: string;\n params: URLSearchParams;\n req: http.IncomingMessage;\n res: http.ServerResponse;\n };\n if (await contentRoutes(ctxBase)) return;\n if (await moduleRoutesInstance(ctxBase)) return;\n if (await healthRoutes(ctxBase)) return;\n if (await statusRoutes(ctxBase)) return;\n if (await qqBindRoutes(ctxBase)) return;\n if (await bindConfirmRoutes(ctxBase)) return;\n if (await wechatBindRoutes(ctxBase)) return;\n if (await qqJoinRoutes(ctxBase)) return;\n if (await qqEventsRoutes(ctxBase)) return;\n if (await messagesRoutes(ctxBase)) return;\n if (await configRoutes(ctxBase)) return;\n\n json(res, { success: false, error: \"not_found\" }, 404);\n } catch (err) {\n log.err(err, \"DogeDB\");\n json(res, { success: false, error: (err as Error).message }, 500);\n }\n}\n\n// \u2500\u2500 \u542F\u52A8 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst server = createServer({\n env: { PORT: env.PORT, HOST: env.HOST, AUTH_TOKEN: env.AUTH_TOKEN },\n handle,\n});\nstartConsole(server, db);\n\nexport { db, enabledManifests, env, moduleAuth, query, schemaRegistry, serviceRegistry, txRunner };\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["path"]
|
|
7
7
|
}
|
package/dist/lib/sqlite.d.ts
CHANGED
|
@@ -26,4 +26,14 @@ export declare function createQuery(db: DatabaseSync, maxStatements?: number): Q
|
|
|
26
26
|
* @returns SQLite DatabaseSync 连接实例。
|
|
27
27
|
*/
|
|
28
28
|
export declare function openDatabase(filePath: string): DatabaseSync;
|
|
29
|
+
/**
|
|
30
|
+
* 以只读连接打开业务库,执行一次查询后立即关闭。
|
|
31
|
+
* 使用场景:db-server 进程之外(CLI 管理通道)读取模块表,例如 activity.query / activity.stats。
|
|
32
|
+
* 文件不存在时调用 missing() 返回兜底结果,不创建数据库;查询本身的异常原样抛出,交给调用方提示。
|
|
33
|
+
*
|
|
34
|
+
* @param filePath 业务库绝对路径。
|
|
35
|
+
* @param missing 数据库文件不存在时的兜底结果。
|
|
36
|
+
* @param run 使用只读 QueryFn 执行的查询。
|
|
37
|
+
*/
|
|
38
|
+
export declare function withReadonlyQuery<T>(filePath: string, missing: () => T, run: (query: QueryFn) => T): T;
|
|
29
39
|
//# sourceMappingURL=sqlite.d.ts.map
|
package/dist/lib/sqlite.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/lib/sqlite.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAiB,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,MAAM,MAAM,OAAO,GAAG,CACpB,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAA;CAAE,EAChE,MAAM,CAAC,EAAE,OAAO,EAAE,KACf,OAAO,EAAE,GAAG;IAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC;AAE9C;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,YAAY,EAAE,aAAa,GAAE,MAAY,GAAG,OAAO,CAwClF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,CAO3D"}
|
|
1
|
+
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/lib/sqlite.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAiB,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,MAAM,MAAM,OAAO,GAAG,CACpB,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAA;CAAE,EAChE,MAAM,CAAC,EAAE,OAAO,EAAE,KACf,OAAO,EAAE,GAAG;IAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC;AAE9C;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,YAAY,EAAE,aAAa,GAAE,MAAY,GAAG,OAAO,CAwClF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,CAO3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC,GAAG,CAAC,CAUtG"}
|
package/dist/lib/sqlite.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdirSync } from "node:fs";
|
|
1
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
3
|
import { DatabaseSync, StatementSync } from "node:sqlite";
|
|
4
4
|
function createQuery(db, maxStatements = 200) {
|
|
@@ -40,8 +40,23 @@ function openDatabase(filePath) {
|
|
|
40
40
|
db.exec("PRAGMA busy_timeout = 5000");
|
|
41
41
|
return db;
|
|
42
42
|
}
|
|
43
|
+
function withReadonlyQuery(filePath, missing, run) {
|
|
44
|
+
if (!existsSync(filePath)) return missing();
|
|
45
|
+
const db = new DatabaseSync(filePath, { readOnly: true });
|
|
46
|
+
try {
|
|
47
|
+
db.exec("PRAGMA query_only = ON");
|
|
48
|
+
db.exec("PRAGMA busy_timeout = 5000");
|
|
49
|
+
return run(createQuery(db, 16));
|
|
50
|
+
} finally {
|
|
51
|
+
try {
|
|
52
|
+
db.close();
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
43
57
|
export {
|
|
44
58
|
createQuery,
|
|
45
|
-
openDatabase
|
|
59
|
+
openDatabase,
|
|
60
|
+
withReadonlyQuery
|
|
46
61
|
};
|
|
47
62
|
//# sourceMappingURL=sqlite.js.map
|
package/dist/lib/sqlite.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/sqlite.ts"],
|
|
4
|
-
"sourcesContent": ["import { mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { DatabaseSync, StatementSync } from \"node:sqlite\";\nimport type { SQLStatement } from \"sql-template-strings\";\n\nexport type QueryFn = (\n sql: string | SQLStatement | { sql: string; values?: unknown[] },\n values?: unknown[]\n) => unknown[] | { changes: number | bigint };\n\n/**\n * \u521B\u5EFA\u7EDF\u4E00\u7684 SQL \u67E5\u8BE2\u63A5\u53E3\uFF08\u5185\u7F6E LRU \u9884\u7F16\u8BD1\u8BED\u53E5\u7F13\u5B58\u673A\u5236\uFF09\u3002\n * \u652F\u6301\u4E09\u79CD\u8C03\u7528\u5F62\u6001\uFF1A\n * 1. `query(\"SELECT * FROM t WHERE id = ?\", [1])`\n * 2. `query({ sql: \"SELECT * FROM t WHERE id = ?\", values: [1] })`\n * 3. `query(SQL`SELECT * FROM t WHERE id = ${1}`)`\uFF08sql-template-strings\uFF09\n *\n * @param db SQLite \u6570\u636E\u5E93\u8FDE\u63A5\u5B9E\u4F8B\u3002\n * @param maxStatements \u9884\u7F16\u8BD1\u8BED\u53E5\u7F13\u5B58\u4E0A\u9650\uFF08\u9ED8\u8BA4\u4E3A 200\uFF09\u3002\n * @returns \u7EDF\u4E00\u67E5\u8BE2\u6267\u884C\u51FD\u6570\u3002\n */\nexport function createQuery(db: DatabaseSync, maxStatements: number = 200): QueryFn {\n\n const stmts = new Map<string, StatementSync>();\n\n function getStmt(sql: string): StatementSync {\n let s = stmts.get(sql);\n if (!s) {\n s = db.prepare(sql);\n if (stmts.size >= maxStatements) {\n const first = stmts.keys().next().value;\n if (first !== undefined) stmts.delete(first);\n }\n stmts.set(sql, s);\n }\n return s;\n }\n\n function runQuery(sql: string, values: unknown[]): any[] | { changes: number | bigint } {\n const s = getStmt(sql);\n const upper = sql.trim().toUpperCase();\n const needsRows =\n upper.startsWith(\"SELECT\") ||\n upper.startsWith(\"WITH\") ||\n upper.startsWith(\"PRAGMA\") ||\n /\\bRETURNING\\b/.test(upper);\n const bind = values as any[];\n if (needsRows) return s.all(...bind);\n const r = s.run(...bind);\n return { changes: r.changes };\n }\n\n return function query(raw: string | { sql: string; values?: unknown[] }, maybeValues?: unknown[]): any[] | { changes: number | bigint } {\n // \u683C\u5F0F 1\uFF1Astring + values\n if (typeof raw === \"string\") {\n return runQuery(raw, maybeValues ?? []);\n }\n // \u683C\u5F0F 2 / 3\uFF1A{ sql, values } \u6216 sql-template-strings \u5BF9\u8C61\n const o = raw as { sql: string; values?: unknown[] };\n return runQuery(o.sql, o.values ?? []);\n };\n}\n\n/**\n * \u6253\u5F00 SQLite \u6570\u636E\u5E93\u6587\u4EF6\uFF08\u57FA\u4E8E Node.js \u539F\u751F DatabaseSync \u540C\u6B65\u6A21\u5757\uFF09\u3002\n * \u81EA\u52A8\u9012\u5F52\u521B\u5EFA\u6240\u5728\u7236\u7EA7\u76EE\u5F55\uFF0C\u5E76\u521D\u59CB\u5316\u914D\u7F6E\u5916\u952E\u7EA6\u675F\uFF08`foreign_keys = ON`\uFF09\u3001\u9884\u5199\u65E5\u5FD7\uFF08`journal_mode = WAL`\uFF09\u4E0E\u5FD9\u7B49\u5F85\u8D85\u65F6\uFF08`busy_timeout = 5000`\uFF09\u3002\n *\n * @param filePath \u6570\u636E\u5E93\u6587\u4EF6\u7EDD\u5BF9\u8DEF\u5F84\u3002\n * @returns SQLite DatabaseSync \u8FDE\u63A5\u5B9E\u4F8B\u3002\n */\nexport function openDatabase(filePath: string): DatabaseSync {\n mkdirSync(dirname(filePath), { recursive: true });\n const db = new DatabaseSync(filePath);\n db.exec(\"PRAGMA foreign_keys = ON\");\n db.exec(\"PRAGMA journal_mode = WAL\");\n db.exec(\"PRAGMA busy_timeout = 5000\");\n return db;\n}\n\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,iBAAiB;
|
|
4
|
+
"sourcesContent": ["import { existsSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { DatabaseSync, StatementSync } from \"node:sqlite\";\nimport type { SQLStatement } from \"sql-template-strings\";\n\nexport type QueryFn = (\n sql: string | SQLStatement | { sql: string; values?: unknown[] },\n values?: unknown[]\n) => unknown[] | { changes: number | bigint };\n\n/**\n * \u521B\u5EFA\u7EDF\u4E00\u7684 SQL \u67E5\u8BE2\u63A5\u53E3\uFF08\u5185\u7F6E LRU \u9884\u7F16\u8BD1\u8BED\u53E5\u7F13\u5B58\u673A\u5236\uFF09\u3002\n * \u652F\u6301\u4E09\u79CD\u8C03\u7528\u5F62\u6001\uFF1A\n * 1. `query(\"SELECT * FROM t WHERE id = ?\", [1])`\n * 2. `query({ sql: \"SELECT * FROM t WHERE id = ?\", values: [1] })`\n * 3. `query(SQL`SELECT * FROM t WHERE id = ${1}`)`\uFF08sql-template-strings\uFF09\n *\n * @param db SQLite \u6570\u636E\u5E93\u8FDE\u63A5\u5B9E\u4F8B\u3002\n * @param maxStatements \u9884\u7F16\u8BD1\u8BED\u53E5\u7F13\u5B58\u4E0A\u9650\uFF08\u9ED8\u8BA4\u4E3A 200\uFF09\u3002\n * @returns \u7EDF\u4E00\u67E5\u8BE2\u6267\u884C\u51FD\u6570\u3002\n */\nexport function createQuery(db: DatabaseSync, maxStatements: number = 200): QueryFn {\n\n const stmts = new Map<string, StatementSync>();\n\n function getStmt(sql: string): StatementSync {\n let s = stmts.get(sql);\n if (!s) {\n s = db.prepare(sql);\n if (stmts.size >= maxStatements) {\n const first = stmts.keys().next().value;\n if (first !== undefined) stmts.delete(first);\n }\n stmts.set(sql, s);\n }\n return s;\n }\n\n function runQuery(sql: string, values: unknown[]): any[] | { changes: number | bigint } {\n const s = getStmt(sql);\n const upper = sql.trim().toUpperCase();\n const needsRows =\n upper.startsWith(\"SELECT\") ||\n upper.startsWith(\"WITH\") ||\n upper.startsWith(\"PRAGMA\") ||\n /\\bRETURNING\\b/.test(upper);\n const bind = values as any[];\n if (needsRows) return s.all(...bind);\n const r = s.run(...bind);\n return { changes: r.changes };\n }\n\n return function query(raw: string | { sql: string; values?: unknown[] }, maybeValues?: unknown[]): any[] | { changes: number | bigint } {\n // \u683C\u5F0F 1\uFF1Astring + values\n if (typeof raw === \"string\") {\n return runQuery(raw, maybeValues ?? []);\n }\n // \u683C\u5F0F 2 / 3\uFF1A{ sql, values } \u6216 sql-template-strings \u5BF9\u8C61\n const o = raw as { sql: string; values?: unknown[] };\n return runQuery(o.sql, o.values ?? []);\n };\n}\n\n/**\n * \u6253\u5F00 SQLite \u6570\u636E\u5E93\u6587\u4EF6\uFF08\u57FA\u4E8E Node.js \u539F\u751F DatabaseSync \u540C\u6B65\u6A21\u5757\uFF09\u3002\n * \u81EA\u52A8\u9012\u5F52\u521B\u5EFA\u6240\u5728\u7236\u7EA7\u76EE\u5F55\uFF0C\u5E76\u521D\u59CB\u5316\u914D\u7F6E\u5916\u952E\u7EA6\u675F\uFF08`foreign_keys = ON`\uFF09\u3001\u9884\u5199\u65E5\u5FD7\uFF08`journal_mode = WAL`\uFF09\u4E0E\u5FD9\u7B49\u5F85\u8D85\u65F6\uFF08`busy_timeout = 5000`\uFF09\u3002\n *\n * @param filePath \u6570\u636E\u5E93\u6587\u4EF6\u7EDD\u5BF9\u8DEF\u5F84\u3002\n * @returns SQLite DatabaseSync \u8FDE\u63A5\u5B9E\u4F8B\u3002\n */\nexport function openDatabase(filePath: string): DatabaseSync {\n mkdirSync(dirname(filePath), { recursive: true });\n const db = new DatabaseSync(filePath);\n db.exec(\"PRAGMA foreign_keys = ON\");\n db.exec(\"PRAGMA journal_mode = WAL\");\n db.exec(\"PRAGMA busy_timeout = 5000\");\n return db;\n}\n\n/**\n * \u4EE5\u53EA\u8BFB\u8FDE\u63A5\u6253\u5F00\u4E1A\u52A1\u5E93\uFF0C\u6267\u884C\u4E00\u6B21\u67E5\u8BE2\u540E\u7ACB\u5373\u5173\u95ED\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1Adb-server \u8FDB\u7A0B\u4E4B\u5916\uFF08CLI \u7BA1\u7406\u901A\u9053\uFF09\u8BFB\u53D6\u6A21\u5757\u8868\uFF0C\u4F8B\u5982 activity.query / activity.stats\u3002\n * \u6587\u4EF6\u4E0D\u5B58\u5728\u65F6\u8C03\u7528 missing() \u8FD4\u56DE\u515C\u5E95\u7ED3\u679C\uFF0C\u4E0D\u521B\u5EFA\u6570\u636E\u5E93\uFF1B\u67E5\u8BE2\u672C\u8EAB\u7684\u5F02\u5E38\u539F\u6837\u629B\u51FA\uFF0C\u4EA4\u7ED9\u8C03\u7528\u65B9\u63D0\u793A\u3002\n *\n * @param filePath \u4E1A\u52A1\u5E93\u7EDD\u5BF9\u8DEF\u5F84\u3002\n * @param missing \u6570\u636E\u5E93\u6587\u4EF6\u4E0D\u5B58\u5728\u65F6\u7684\u515C\u5E95\u7ED3\u679C\u3002\n * @param run \u4F7F\u7528\u53EA\u8BFB QueryFn \u6267\u884C\u7684\u67E5\u8BE2\u3002\n */\nexport function withReadonlyQuery<T>(filePath: string, missing: () => T, run: (query: QueryFn) => T): T {\n if (!existsSync(filePath)) return missing();\n const db = new DatabaseSync(filePath, { readOnly: true });\n try {\n db.exec(\"PRAGMA query_only = ON\");\n db.exec(\"PRAGMA busy_timeout = 5000\");\n return run(createQuery(db, 16));\n } finally {\n try { db.close(); } catch { /* \u53EA\u8BFB\u8FDE\u63A5\u5173\u95ED\u5931\u8D25\u4E0D\u5F71\u54CD\u5DF2\u53D6\u5F97\u7684\u7ED3\u679C */ }\n }\n}\n\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,YAAY,iBAAiB;AACtC,SAAS,eAAe;AACxB,SAAS,cAAc,qBAAqB;AAmBrC,SAAS,YAAY,IAAkB,gBAAwB,KAAc;AAElF,QAAM,QAAQ,oBAAI,IAA2B;AAE7C,WAAS,QAAQ,KAA4B;AAC3C,QAAI,IAAI,MAAM,IAAI,GAAG;AACrB,QAAI,CAAC,GAAG;AACN,UAAI,GAAG,QAAQ,GAAG;AAClB,UAAI,MAAM,QAAQ,eAAe;AAC/B,cAAM,QAAQ,MAAM,KAAK,EAAE,KAAK,EAAE;AAClC,YAAI,UAAU,OAAW,OAAM,OAAO,KAAK;AAAA,MAC7C;AACA,YAAM,IAAI,KAAK,CAAC;AAAA,IAClB;AACA,WAAO;AAAA,EACT;AAEA,WAAS,SAAS,KAAa,QAAyD;AACtF,UAAM,IAAI,QAAQ,GAAG;AACrB,UAAM,QAAQ,IAAI,KAAK,EAAE,YAAY;AACrC,UAAM,YACJ,MAAM,WAAW,QAAQ,KACzB,MAAM,WAAW,MAAM,KACvB,MAAM,WAAW,QAAQ,KACzB,gBAAgB,KAAK,KAAK;AAC5B,UAAM,OAAO;AACb,QAAI,UAAW,QAAO,EAAE,IAAI,GAAG,IAAI;AACnC,UAAM,IAAI,EAAE,IAAI,GAAG,IAAI;AACvB,WAAO,EAAE,SAAS,EAAE,QAAQ;AAAA,EAC9B;AAEA,SAAO,SAAS,MAAM,KAAmD,aAA+D;AAEtI,QAAI,OAAO,QAAQ,UAAU;AAC3B,aAAO,SAAS,KAAK,eAAe,CAAC,CAAC;AAAA,IACxC;AAEA,UAAM,IAAI;AACV,WAAO,SAAS,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;AAAA,EACvC;AACF;AASO,SAAS,aAAa,UAAgC;AAC3D,YAAU,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAChD,QAAM,KAAK,IAAI,aAAa,QAAQ;AACpC,KAAG,KAAK,0BAA0B;AAClC,KAAG,KAAK,2BAA2B;AACnC,KAAG,KAAK,4BAA4B;AACpC,SAAO;AACT;AAWO,SAAS,kBAAqB,UAAkB,SAAkB,KAA+B;AACtG,MAAI,CAAC,WAAW,QAAQ,EAAG,QAAO,QAAQ;AAC1C,QAAM,KAAK,IAAI,aAAa,UAAU,EAAE,UAAU,KAAK,CAAC;AACxD,MAAI;AACF,OAAG,KAAK,wBAAwB;AAChC,OAAG,KAAK,4BAA4B;AACpC,WAAO,IAAI,YAAY,IAAI,EAAE,CAAC;AAAA,EAChC,UAAE;AACA,QAAI;AAAE,SAAG,MAAM;AAAA,IAAG,QAAQ;AAAA,IAA0B;AAAA,EACtD;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* routes/bind-confirm.ts — 游戏内 /c:bind 的统一确认入口(平台 HTTP,仅本机)
|
|
3
|
+
*
|
|
4
|
+
* POST /api/sfmc/bind/confirm { code, xuid, name }
|
|
5
|
+
* → 成功 { success: true, provider: "qq" | "wechat", binding }
|
|
6
|
+
* → 失败 { success: false, error, hint? }(错误码与 QQ 原接口一致,新增 wechat_already_bound / player_already_bound_wechat)
|
|
7
|
+
*
|
|
8
|
+
* 按注册的绑定提供方查找持有该短码的渠道并确认(OCP:新增渠道不改本路由)。
|
|
9
|
+
* 旧接口 POST /api/sfmc/qq/bind/confirm 保留,供旧版游戏侧脚本使用。
|
|
10
|
+
*/
|
|
11
|
+
import type http from "node:http";
|
|
12
|
+
import { type BindProvider } from "../domain/bind-providers.js";
|
|
13
|
+
interface Deps {
|
|
14
|
+
body: (req: http.IncomingMessage) => Promise<Record<string, unknown>>;
|
|
15
|
+
json: (res: http.ServerResponse, data: Record<string, unknown>, status?: number) => void;
|
|
16
|
+
/** 已注册的绑定提供方(按顺序询问) */
|
|
17
|
+
providers: () => readonly BindProvider[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 创建统一确认路由。
|
|
21
|
+
* 使用场景:index.ts 装配到平台路由链。
|
|
22
|
+
*/
|
|
23
|
+
declare function createBindConfirmRoutes({ body, json, providers }: Deps): ({ path, method, req, res, }: {
|
|
24
|
+
path: string;
|
|
25
|
+
method: string;
|
|
26
|
+
req: http.IncomingMessage;
|
|
27
|
+
res: http.ServerResponse;
|
|
28
|
+
}) => Promise<boolean>;
|
|
29
|
+
export { createBindConfirmRoutes };
|
|
30
|
+
//# sourceMappingURL=bind-confirm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind-confirm.d.ts","sourceRoot":"","sources":["../../src/routes/bind-confirm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAwB,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEtF,UAAU,IAAI;IACZ,IAAI,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACtE,IAAI,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzF,uBAAuB;IACvB,SAAS,EAAE,MAAM,SAAS,YAAY,EAAE,CAAC;CAC1C;AAED;;;GAGG;AACH,iBAAS,uBAAuB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,IAAI,iCAM3D;IACD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,IAAI,CAAC,eAAe,CAAC;IAC1B,GAAG,EAAE,IAAI,CAAC,cAAc,CAAC;CAC1B,KAAG,OAAO,CAAC,OAAO,CAAC,CAerB;AAED,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { confirmWithProviders } from "../domain/bind-providers.js";
|
|
2
|
+
function createBindConfirmRoutes({ body, json, providers }) {
|
|
3
|
+
return async function handle({
|
|
4
|
+
path,
|
|
5
|
+
method,
|
|
6
|
+
req,
|
|
7
|
+
res
|
|
8
|
+
}) {
|
|
9
|
+
if (path !== "/api/sfmc/bind/confirm" || method !== "POST") return false;
|
|
10
|
+
const data = await body(req);
|
|
11
|
+
const code = String(data.code ?? "").trim();
|
|
12
|
+
const xuid = String(data.xuid ?? data.player_xuid ?? "").trim();
|
|
13
|
+
const name = String(data.name ?? data.player_name ?? "").trim();
|
|
14
|
+
if (!code || !xuid) {
|
|
15
|
+
json(res, { success: false, error: "code_and_xuid_required" }, 400);
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
const result = confirmWithProviders(providers(), { code, xuid, name, now: Date.now() });
|
|
19
|
+
if (result.ok) json(res, { success: true, provider: result.provider, binding: result.binding });
|
|
20
|
+
else json(res, { success: false, error: result.error, ...result.hint ? { hint: result.hint } : {} }, result.status);
|
|
21
|
+
return true;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export {
|
|
25
|
+
createBindConfirmRoutes
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=bind-confirm.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/routes/bind-confirm.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * routes/bind-confirm.ts \u2014 \u6E38\u620F\u5185 /c:bind \u7684\u7EDF\u4E00\u786E\u8BA4\u5165\u53E3\uFF08\u5E73\u53F0 HTTP\uFF0C\u4EC5\u672C\u673A\uFF09\n *\n * POST /api/sfmc/bind/confirm { code, xuid, name }\n * \u2192 \u6210\u529F { success: true, provider: \"qq\" | \"wechat\", binding }\n * \u2192 \u5931\u8D25 { success: false, error, hint? }\uFF08\u9519\u8BEF\u7801\u4E0E QQ \u539F\u63A5\u53E3\u4E00\u81F4\uFF0C\u65B0\u589E wechat_already_bound / player_already_bound_wechat\uFF09\n *\n * \u6309\u6CE8\u518C\u7684\u7ED1\u5B9A\u63D0\u4F9B\u65B9\u67E5\u627E\u6301\u6709\u8BE5\u77ED\u7801\u7684\u6E20\u9053\u5E76\u786E\u8BA4\uFF08OCP\uFF1A\u65B0\u589E\u6E20\u9053\u4E0D\u6539\u672C\u8DEF\u7531\uFF09\u3002\n * \u65E7\u63A5\u53E3 POST /api/sfmc/qq/bind/confirm \u4FDD\u7559\uFF0C\u4F9B\u65E7\u7248\u6E38\u620F\u4FA7\u811A\u672C\u4F7F\u7528\u3002\n */\n\nimport type http from \"node:http\";\nimport { confirmWithProviders, type BindProvider } from \"../domain/bind-providers.js\";\n\ninterface Deps {\n body: (req: http.IncomingMessage) => Promise<Record<string, unknown>>;\n json: (res: http.ServerResponse, data: Record<string, unknown>, status?: number) => void;\n /** \u5DF2\u6CE8\u518C\u7684\u7ED1\u5B9A\u63D0\u4F9B\u65B9\uFF08\u6309\u987A\u5E8F\u8BE2\u95EE\uFF09 */\n providers: () => readonly BindProvider[];\n}\n\n/**\n * \u521B\u5EFA\u7EDF\u4E00\u786E\u8BA4\u8DEF\u7531\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1Aindex.ts \u88C5\u914D\u5230\u5E73\u53F0\u8DEF\u7531\u94FE\u3002\n */\nfunction createBindConfirmRoutes({ body, json, providers }: Deps) {\n return async function handle({\n path,\n method,\n req,\n res,\n }: {\n path: string;\n method: string;\n req: http.IncomingMessage;\n res: http.ServerResponse;\n }): Promise<boolean> {\n if (path !== \"/api/sfmc/bind/confirm\" || method !== \"POST\") return false;\n const data = await body(req);\n const code = String(data.code ?? \"\").trim();\n const xuid = String(data.xuid ?? data.player_xuid ?? \"\").trim();\n const name = String(data.name ?? data.player_name ?? \"\").trim();\n if (!code || !xuid) {\n json(res, { success: false, error: \"code_and_xuid_required\" }, 400);\n return true;\n }\n const result = confirmWithProviders(providers(), { code, xuid, name, now: Date.now() });\n if (result.ok) json(res, { success: true, provider: result.provider, binding: result.binding });\n else json(res, { success: false, error: result.error, ...(result.hint ? { hint: result.hint } : {}) }, result.status);\n return true;\n };\n}\n\nexport { createBindConfirmRoutes };\n"],
|
|
5
|
+
"mappings": "AAYA,SAAS,4BAA+C;AAaxD,SAAS,wBAAwB,EAAE,MAAM,MAAM,UAAU,GAAS;AAChE,SAAO,eAAe,OAAO;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAKqB;AACnB,QAAI,SAAS,4BAA4B,WAAW,OAAQ,QAAO;AACnE,UAAM,OAAO,MAAM,KAAK,GAAG;AAC3B,UAAM,OAAO,OAAO,KAAK,QAAQ,EAAE,EAAE,KAAK;AAC1C,UAAM,OAAO,OAAO,KAAK,QAAQ,KAAK,eAAe,EAAE,EAAE,KAAK;AAC9D,UAAM,OAAO,OAAO,KAAK,QAAQ,KAAK,eAAe,EAAE,EAAE,KAAK;AAC9D,QAAI,CAAC,QAAQ,CAAC,MAAM;AAClB,WAAK,KAAK,EAAE,SAAS,OAAO,OAAO,yBAAyB,GAAG,GAAG;AAClE,aAAO;AAAA,IACT;AACA,UAAM,SAAS,qBAAqB,UAAU,GAAG,EAAE,MAAM,MAAM,MAAM,KAAK,KAAK,IAAI,EAAE,CAAC;AACtF,QAAI,OAAO,GAAI,MAAK,KAAK,EAAE,SAAS,MAAM,UAAU,OAAO,UAAU,SAAS,OAAO,QAAQ,CAAC;AAAA,QACzF,MAAK,KAAK,EAAE,SAAS,OAAO,OAAO,OAAO,OAAO,GAAI,OAAO,OAAO,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC,EAAG,GAAG,OAAO,MAAM;AACpH,WAAO;AAAA,EACT;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/routes/qq-bind.d.ts
CHANGED
|
@@ -12,8 +12,10 @@ interface Deps {
|
|
|
12
12
|
query: QueryFn;
|
|
13
13
|
body: (req: import("http").IncomingMessage) => Promise<Record<string, unknown>>;
|
|
14
14
|
json: (res: import("http").ServerResponse, data: Record<string, unknown>, status?: number) => void;
|
|
15
|
+
/** 短码是否已被任一绑定渠道占用;缺省只查 QQ 待确认表(与原行为一致) */
|
|
16
|
+
isCodeTaken?: (code: string) => boolean;
|
|
15
17
|
}
|
|
16
|
-
declare function createQqBindRoutes({ query, body, json }: Deps): ({ path, method, params, req, res, }: {
|
|
18
|
+
declare function createQqBindRoutes({ query, body, json, isCodeTaken }: Deps): ({ path, method, params, req, res, }: {
|
|
17
19
|
path: string;
|
|
18
20
|
method: string;
|
|
19
21
|
params: URLSearchParams;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qq-bind.d.ts","sourceRoot":"","sources":["../../src/routes/qq-bind.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"qq-bind.d.ts","sourceRoot":"","sources":["../../src/routes/qq-bind.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEhD,QAAA,MAAM,WAAW,QAAmB,CAAC;AAErC,UAAU,IAAI;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,MAAM,EAAE,eAAe,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAChF,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACnG,0CAA0C;IAC1C,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACzC;AAED,iBAAS,kBAAkB,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,WAAqD,EAAE,EAAE,IAAI,yCAOzG;IACD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,CAAC;IACxB,GAAG,EAAE,OAAO,MAAM,EAAE,eAAe,CAAC;IACpC,GAAG,EAAE,OAAO,MAAM,EAAE,cAAc,CAAC;CACpC,KAAG,OAAO,CAAC,OAAO,CAAC,CA0JrB;AAED,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,CAAC"}
|
package/dist/routes/qq-bind.js
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
import { randomInt } from "node:crypto";
|
|
2
1
|
import { SQL } from "sql-template-strings";
|
|
2
|
+
import { BIND_CODE_TTL_MS, generateBindCode } from "../domain/bind-providers.js";
|
|
3
3
|
import { loadQqAccountProfile, saveQqAccountProfile } from "../domain/qq-account-profile.js";
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
function
|
|
7
|
-
let s = "";
|
|
8
|
-
for (let i = 0; i < CODE_LEN; i++) s += String(randomInt(0, 10));
|
|
9
|
-
return s;
|
|
10
|
-
}
|
|
11
|
-
function createQqBindRoutes({ query, body, json }) {
|
|
4
|
+
import { confirmQqBind, hasQqPendingCode } from "../domain/qq-bind.js";
|
|
5
|
+
const CODE_TTL_MS = BIND_CODE_TTL_MS;
|
|
6
|
+
function createQqBindRoutes({ query, body, json, isCodeTaken = (code) => hasQqPendingCode(query, code) }) {
|
|
12
7
|
return async function handle({
|
|
13
8
|
path,
|
|
14
9
|
method,
|
|
@@ -91,17 +86,7 @@ function createQqBindRoutes({ query, body, json }) {
|
|
|
91
86
|
}
|
|
92
87
|
const now = Date.now();
|
|
93
88
|
query(SQL`DELETE FROM sfmc_qq_bind_pending WHERE qq_user_openid = ${openid} OR expires_at < ${now}`);
|
|
94
|
-
|
|
95
|
-
for (let attempt = 0; attempt < 8; attempt++) {
|
|
96
|
-
const candidate = genCode();
|
|
97
|
-
const clash = query(
|
|
98
|
-
SQL`SELECT 1 AS ok FROM sfmc_qq_bind_pending WHERE code = ${candidate} LIMIT 1`
|
|
99
|
-
);
|
|
100
|
-
if (clash.length === 0) {
|
|
101
|
-
code = candidate;
|
|
102
|
-
break;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
89
|
+
const code = generateBindCode(isCodeTaken);
|
|
105
90
|
if (!code) {
|
|
106
91
|
json(res, { success: false, error: "code_gen_failed" }, 500);
|
|
107
92
|
return true;
|
|
@@ -123,50 +108,9 @@ function createQqBindRoutes({ query, body, json }) {
|
|
|
123
108
|
json(res, { success: false, error: "code_and_xuid_required" }, 400);
|
|
124
109
|
return true;
|
|
125
110
|
}
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
);
|
|
130
|
-
const row = pending[0];
|
|
131
|
-
if (!row) {
|
|
132
|
-
json(res, { success: false, error: "invalid_code" }, 400);
|
|
133
|
-
return true;
|
|
134
|
-
}
|
|
135
|
-
if (Number(row.expires_at) < now) {
|
|
136
|
-
query(SQL`DELETE FROM sfmc_qq_bind_pending WHERE code = ${code}`);
|
|
137
|
-
json(res, { success: false, error: "code_expired" }, 400);
|
|
138
|
-
return true;
|
|
139
|
-
}
|
|
140
|
-
const byOpenid = query(
|
|
141
|
-
SQL`SELECT player_xuid FROM sfmc_qq_bindings WHERE qq_user_openid = ${row.qq_user_openid} LIMIT 1`
|
|
142
|
-
);
|
|
143
|
-
if (byOpenid[0] && byOpenid[0].player_xuid !== xuid) {
|
|
144
|
-
json(res, { success: false, error: "qq_already_bound", hint: "\u8BF7\u5148\u5728 QQ \u4FA7\u89E3\u7ED1" }, 409);
|
|
145
|
-
return true;
|
|
146
|
-
}
|
|
147
|
-
const byXuid = query(
|
|
148
|
-
SQL`SELECT qq_user_openid FROM sfmc_qq_bindings WHERE player_xuid = ${xuid} LIMIT 1`
|
|
149
|
-
);
|
|
150
|
-
if (byXuid[0] && byXuid[0].qq_user_openid !== row.qq_user_openid) {
|
|
151
|
-
json(res, { success: false, error: "player_already_bound", hint: "\u8BF7\u5148\u89E3\u7ED1\u5F53\u524D QQ" }, 409);
|
|
152
|
-
return true;
|
|
153
|
-
}
|
|
154
|
-
query(SQL`DELETE FROM sfmc_qq_bindings WHERE qq_user_openid = ${row.qq_user_openid} OR player_xuid = ${xuid}`);
|
|
155
|
-
query(
|
|
156
|
-
SQL`INSERT INTO sfmc_qq_bindings (qq_user_openid, player_xuid, player_name, qq_backend, bound_at)
|
|
157
|
-
VALUES (${row.qq_user_openid}, ${xuid}, ${name}, ${row.qq_backend}, ${now})`
|
|
158
|
-
);
|
|
159
|
-
query(SQL`DELETE FROM sfmc_qq_bind_pending WHERE code = ${code}`);
|
|
160
|
-
json(res, {
|
|
161
|
-
success: true,
|
|
162
|
-
binding: {
|
|
163
|
-
qq_user_openid: row.qq_user_openid,
|
|
164
|
-
player_xuid: xuid,
|
|
165
|
-
player_name: name,
|
|
166
|
-
qq_backend: row.qq_backend,
|
|
167
|
-
bound_at: now
|
|
168
|
-
}
|
|
169
|
-
});
|
|
111
|
+
const result = confirmQqBind(query, { code, xuid, name, now: Date.now() });
|
|
112
|
+
if (result.ok) json(res, { success: true, binding: result.binding });
|
|
113
|
+
else json(res, { success: false, error: result.error, ...result.hint ? { hint: result.hint } : {} }, result.status);
|
|
170
114
|
return true;
|
|
171
115
|
}
|
|
172
116
|
if (path === "/api/sfmc/qq/bind/unbind" && method === "POST") {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/routes/qq-bind.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * routes/qq-bind.ts \u2014 QQ\u2194MC \u8EAB\u4EFD\u7ED1\u5B9A\uFF08\u5E73\u53F0 HTTP\uFF09\n *\n * POST /api/sfmc/qq/bind/request \u2014 QQ \u4FA7\u7533\u8BF7\u77ED\u7801\n * POST /api/sfmc/qq/bind/confirm \u2014 \u6E38\u620F\u4FA7\u786E\u8BA4\n * POST /api/sfmc/qq/bind/unbind \u2014 \u89E3\u7ED1\n * GET /api/sfmc/qq/bind/me \u2014 \u67E5\u8BE2\n */\n\nimport {
|
|
5
|
-
"mappings": "AASA,SAAS,
|
|
4
|
+
"sourcesContent": ["/**\n * routes/qq-bind.ts \u2014 QQ\u2194MC \u8EAB\u4EFD\u7ED1\u5B9A\uFF08\u5E73\u53F0 HTTP\uFF09\n *\n * POST /api/sfmc/qq/bind/request \u2014 QQ \u4FA7\u7533\u8BF7\u77ED\u7801\n * POST /api/sfmc/qq/bind/confirm \u2014 \u6E38\u620F\u4FA7\u786E\u8BA4\n * POST /api/sfmc/qq/bind/unbind \u2014 \u89E3\u7ED1\n * GET /api/sfmc/qq/bind/me \u2014 \u67E5\u8BE2\n */\n\nimport { SQL } from \"sql-template-strings\";\nimport { BIND_CODE_TTL_MS, generateBindCode } from \"../domain/bind-providers.js\";\nimport { loadQqAccountProfile, saveQqAccountProfile } from \"../domain/qq-account-profile.js\";\nimport { confirmQqBind, hasQqPendingCode } from \"../domain/qq-bind.js\";\nimport type { QueryFn } from \"../lib/sqlite.js\";\n\nconst CODE_TTL_MS = BIND_CODE_TTL_MS;\n\ninterface Deps {\n query: QueryFn;\n body: (req: import(\"http\").IncomingMessage) => Promise<Record<string, unknown>>;\n json: (res: import(\"http\").ServerResponse, data: Record<string, unknown>, status?: number) => void;\n /** \u77ED\u7801\u662F\u5426\u5DF2\u88AB\u4EFB\u4E00\u7ED1\u5B9A\u6E20\u9053\u5360\u7528\uFF1B\u7F3A\u7701\u53EA\u67E5 QQ \u5F85\u786E\u8BA4\u8868\uFF08\u4E0E\u539F\u884C\u4E3A\u4E00\u81F4\uFF09 */\n isCodeTaken?: (code: string) => boolean;\n}\n\nfunction createQqBindRoutes({ query, body, json, isCodeTaken = (code) => hasQqPendingCode(query, code) }: Deps) {\n return async function handle({\n path,\n method,\n params,\n req,\n res,\n }: {\n path: string;\n method: string;\n params: URLSearchParams;\n req: import(\"http\").IncomingMessage;\n res: import(\"http\").ServerResponse;\n }): Promise<boolean> {\n if (!path.startsWith(\"/api/sfmc/qq/bind\")) return false;\n\n if (path === \"/api/sfmc/qq/bind/me\" && method === \"GET\") {\n const openid = String(params.get(\"openid\") ?? \"\").trim();\n const xuid = String(params.get(\"xuid\") ?? \"\").trim();\n if (!openid && !xuid) {\n json(res, { success: false, error: \"openid_or_xuid_required\" }, 400);\n return true;\n }\n const rows = openid\n ? (query(SQL`SELECT * FROM sfmc_qq_bindings WHERE qq_user_openid = ${openid} LIMIT 1`) as Array<\n Record<string, unknown>\n >)\n : (query(SQL`SELECT * FROM sfmc_qq_bindings WHERE player_xuid = ${xuid} LIMIT 1`) as Array<\n Record<string, unknown>\n >);\n const row = rows[0] ?? null;\n const playerId = row ? String(row.player_xuid ?? \"\") : \"\";\n const playerName = row ? String(row.player_name ?? \"\") : \"\";\n json(res, {\n success: true,\n bound: !!row,\n binding: row\n ? {\n qq_user_openid: row.qq_user_openid,\n player_xuid: row.player_xuid,\n player_name: row.player_name,\n qq_backend: row.qq_backend,\n bound_at: row.bound_at,\n }\n : null,\n ...(row ? { profile: loadQqAccountProfile(query, playerId, playerName) } : {}),\n });\n return true;\n }\n\n if (path === \"/api/sfmc/qq/bind/profile\" && method === \"POST\") {\n const data = await body(req);\n const playerId = String(data.xuid ?? data.player_xuid ?? \"\").trim();\n const playerName = String(data.name ?? data.player_name ?? \"\").trim();\n if (!playerId) {\n json(res, { success: false, error: \"xuid_required\" }, 400);\n return true;\n }\n const optionalNumber = (value: unknown): number | null => {\n if (value == null || value === \"\") return null;\n const n = Number(value);\n return Number.isFinite(n) && n >= 0 ? Math.floor(n) : null;\n };\n saveQqAccountProfile(query, {\n playerId,\n playerName,\n balance: optionalNumber(data.balance),\n todaySeconds: optionalNumber(data.today_seconds),\n monthSeconds: optionalNumber(data.month_seconds),\n totalSeconds: optionalNumber(data.total_seconds),\n });\n json(res, { success: true });\n return true;\n }\n\n if (path === \"/api/sfmc/qq/bind/request\" && method === \"POST\") {\n const data = await body(req);\n const openid = String(data.openid ?? data.qq_user_openid ?? \"\").trim();\n const backend = String(data.qq_backend ?? \"official\").trim() || \"official\";\n if (!openid) {\n json(res, { success: false, error: \"openid_required\" }, 400);\n return true;\n }\n // \u5DF2\u7ED1\u5B9A\u5219\u62D2\u7EDD\u518D\u7533\u8BF7\uFF08\u987B\u5148\u89E3\u7ED1\uFF09\n const existing = query(\n SQL`SELECT player_name FROM sfmc_qq_bindings WHERE qq_user_openid = ${openid} LIMIT 1`\n ) as Array<{ player_name: string }>;\n if (existing[0]) {\n json(\n res,\n {\n success: false,\n error: \"already_bound\",\n player_name: existing[0].player_name,\n },\n 409\n );\n return true;\n }\n\n const now = Date.now();\n query(SQL`DELETE FROM sfmc_qq_bind_pending WHERE qq_user_openid = ${openid} OR expires_at < ${now}`);\n\n // \u67E5\u91CD\u8303\u56F4\u7531\u5165\u53E3\u6CE8\u5165\uFF08QQ + \u5FAE\u4FE1\u5F85\u786E\u8BA4\u8868\uFF09\uFF0C\u4FDD\u8BC1\u7EDF\u4E00\u786E\u8BA4\u5165\u53E3\u6309\u77ED\u7801\u80FD\u552F\u4E00\u5B9A\u4F4D\u6E20\u9053\n const code = generateBindCode(isCodeTaken);\n if (!code) {\n json(res, { success: false, error: \"code_gen_failed\" }, 500);\n return true;\n }\n\n const expiresAt = now + CODE_TTL_MS;\n query(\n SQL`INSERT INTO sfmc_qq_bind_pending (code, qq_user_openid, qq_backend, created_at, expires_at)\n VALUES (${code}, ${openid}, ${backend}, ${now}, ${expiresAt})`\n );\n json(res, { success: true, code, expires_at: expiresAt, ttl_ms: CODE_TTL_MS });\n return true;\n }\n\n if (path === \"/api/sfmc/qq/bind/confirm\" && method === \"POST\") {\n const data = await body(req);\n const code = String(data.code ?? \"\").trim();\n const xuid = String(data.xuid ?? data.player_xuid ?? \"\").trim();\n const name = String(data.name ?? data.player_name ?? \"\").trim();\n if (!code || !xuid) {\n json(res, { success: false, error: \"code_and_xuid_required\" }, 400);\n return true;\n }\n\n // \u786E\u8BA4\u903B\u8F91\u4E0E\u7EDF\u4E00\u5165\u53E3 /api/sfmc/bind/confirm \u5171\u7528 domain/qq-bind.ts\uFF08DRY\uFF09\uFF0C\u54CD\u5E94\u7ED3\u6784\u4FDD\u6301\u4E0D\u53D8\n const result = confirmQqBind(query, { code, xuid, name, now: Date.now() });\n if (result.ok) json(res, { success: true, binding: result.binding });\n else json(res, { success: false, error: result.error, ...(result.hint ? { hint: result.hint } : {}) }, result.status);\n return true;\n }\n\n if (path === \"/api/sfmc/qq/bind/unbind\" && method === \"POST\") {\n const data = await body(req);\n const openid = String(data.openid ?? data.qq_user_openid ?? \"\").trim();\n const xuid = String(data.xuid ?? data.player_xuid ?? \"\").trim();\n if (!openid && !xuid) {\n json(res, { success: false, error: \"openid_or_xuid_required\" }, 400);\n return true;\n }\n let removed = 0;\n if (openid) {\n const before = query(\n SQL`SELECT qq_user_openid FROM sfmc_qq_bindings WHERE qq_user_openid = ${openid}`\n ) as unknown[];\n query(SQL`DELETE FROM sfmc_qq_bindings WHERE qq_user_openid = ${openid}`);\n query(SQL`DELETE FROM sfmc_qq_bind_pending WHERE qq_user_openid = ${openid}`);\n removed += before.length;\n }\n if (xuid) {\n const before = query(\n SQL`SELECT qq_user_openid FROM sfmc_qq_bindings WHERE player_xuid = ${xuid}`\n ) as unknown[];\n query(SQL`DELETE FROM sfmc_qq_bindings WHERE player_xuid = ${xuid}`);\n removed += before.length;\n }\n json(res, { success: true, unbound: removed > 0, removed });\n return true;\n }\n\n json(res, { success: false, error: \"not_found\" }, 404);\n return true;\n };\n}\n\nexport { createQqBindRoutes, CODE_TTL_MS };\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/routes/status.ts"],"names":[],"mappings":"AAAA,yCAAyC;AAEzC,OAAO,EAAuB,KAAK,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/routes/status.ts"],"names":[],"mappings":"AAAA,yCAAyC;AAEzC,OAAO,EAAuB,KAAK,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAK5F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAIhD,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAE7D,QAAA,MAAM,QAAQ,QAAS,CAAC;AAQxB,UAAU,IAAI;IACZ,aAAa,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACvE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,iBAAS,kBAAkB,CAAC,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,IAAI,GAAG,UAAU,CAAC,YAAY,CAAC,CA2IjG;AAED,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,CAAC"}
|