@sfmc-bds/db-server 0.1.0 → 0.2.0-beta.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.
Files changed (112) hide show
  1. package/README.md +1 -1
  2. package/dist/db-tables.js +16 -17
  3. package/dist/db-tables.js.map +7 -1
  4. package/dist/domain/bridge.js +54 -77
  5. package/dist/domain/bridge.js.map +7 -1
  6. package/dist/domain/economy.d.ts +83 -2
  7. package/dist/domain/economy.d.ts.map +1 -1
  8. package/dist/domain/economy.js +292 -281
  9. package/dist/domain/economy.js.map +7 -1
  10. package/dist/domain/schema.js +480 -426
  11. package/dist/domain/schema.js.map +7 -1
  12. package/dist/domain/transaction.js +32 -80
  13. package/dist/domain/transaction.js.map +7 -1
  14. package/dist/env.d.ts.map +1 -1
  15. package/dist/env.js +85 -84
  16. package/dist/env.js.map +7 -1
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +218 -240
  20. package/dist/index.js.map +7 -1
  21. package/dist/lib/http.js +30 -39
  22. package/dist/lib/http.js.map +7 -1
  23. package/dist/lib/idempotency-store.js +34 -47
  24. package/dist/lib/idempotency-store.js.map +7 -1
  25. package/dist/lib/idempotency.js +8 -13
  26. package/dist/lib/idempotency.js.map +7 -1
  27. package/dist/lib/identifiers.js +18 -14
  28. package/dist/lib/identifiers.js.map +7 -1
  29. package/dist/lib/log.d.ts +3 -6
  30. package/dist/lib/log.d.ts.map +1 -1
  31. package/dist/lib/log.js +13 -14
  32. package/dist/lib/log.js.map +7 -1
  33. package/dist/lib/module-state.d.ts.map +1 -1
  34. package/dist/lib/module-state.js +32 -21
  35. package/dist/lib/module-state.js.map +7 -1
  36. package/dist/lib/order-by.d.ts +17 -0
  37. package/dist/lib/order-by.d.ts.map +1 -0
  38. package/dist/lib/order-by.js +24 -0
  39. package/dist/lib/order-by.js.map +7 -0
  40. package/dist/lib/runtime.js +16 -31
  41. package/dist/lib/runtime.js.map +7 -1
  42. package/dist/lib/sql-helpers.js +9 -27
  43. package/dist/lib/sql-helpers.js.map +7 -1
  44. package/dist/lib/sqlite.js +40 -52
  45. package/dist/lib/sqlite.js.map +7 -1
  46. package/dist/manifest-loader.d.ts.map +1 -1
  47. package/dist/manifest-loader.js +154 -195
  48. package/dist/manifest-loader.js.map +7 -1
  49. package/dist/manifest.d.ts +3 -7
  50. package/dist/manifest.d.ts.map +1 -1
  51. package/dist/manifest.js +76 -115
  52. package/dist/manifest.js.map +7 -1
  53. package/dist/module-auth.d.ts +17 -6
  54. package/dist/module-auth.d.ts.map +1 -1
  55. package/dist/module-auth.js +93 -107
  56. package/dist/module-auth.js.map +7 -1
  57. package/dist/module-runtime-sync.d.ts +37 -0
  58. package/dist/module-runtime-sync.d.ts.map +1 -0
  59. package/dist/module-runtime-sync.js +54 -0
  60. package/dist/module-runtime-sync.js.map +7 -0
  61. package/dist/permission-gate.d.ts.map +1 -1
  62. package/dist/permission-gate.js +55 -86
  63. package/dist/permission-gate.js.map +7 -1
  64. package/dist/routes/_shared.d.ts +7 -2
  65. package/dist/routes/_shared.d.ts.map +1 -1
  66. package/dist/routes/_shared.js +16 -25
  67. package/dist/routes/_shared.js.map +7 -1
  68. package/dist/routes/config.d.ts +11 -1
  69. package/dist/routes/config.d.ts.map +1 -1
  70. package/dist/routes/config.js +167 -213
  71. package/dist/routes/config.js.map +7 -1
  72. package/dist/routes/db-routes.d.ts +6 -10
  73. package/dist/routes/db-routes.d.ts.map +1 -1
  74. package/dist/routes/db-routes.js +198 -172
  75. package/dist/routes/db-routes.js.map +7 -1
  76. package/dist/routes/health.js +15 -20
  77. package/dist/routes/health.js.map +7 -1
  78. package/dist/routes/messages.d.ts.map +1 -1
  79. package/dist/routes/messages.js +56 -63
  80. package/dist/routes/messages.js.map +7 -1
  81. package/dist/routes/module-config-routes.d.ts.map +1 -1
  82. package/dist/routes/module-config-routes.js +92 -111
  83. package/dist/routes/module-config-routes.js.map +7 -1
  84. package/dist/routes/modules.d.ts.map +1 -1
  85. package/dist/routes/modules.js +82 -88
  86. package/dist/routes/modules.js.map +7 -1
  87. package/dist/routes/service-routes.d.ts.map +1 -1
  88. package/dist/routes/service-routes.js +54 -61
  89. package/dist/routes/service-routes.js.map +7 -1
  90. package/dist/runtime.test.js +248 -49
  91. package/dist/runtime.test.js.map +7 -1
  92. package/dist/schema-registry.d.ts.map +1 -1
  93. package/dist/schema-registry.js +119 -160
  94. package/dist/schema-registry.js.map +7 -1
  95. package/dist/server.js +69 -72
  96. package/dist/server.js.map +7 -1
  97. package/dist/service-registry.d.ts.map +1 -1
  98. package/dist/service-registry.js +60 -67
  99. package/dist/service-registry.js.map +7 -1
  100. package/dist/services/builtin-handlers.d.ts +4 -0
  101. package/dist/services/builtin-handlers.d.ts.map +1 -1
  102. package/dist/services/builtin-handlers.js +34 -20
  103. package/dist/services/builtin-handlers.js.map +7 -1
  104. package/dist/services/economy-handlers.js +143 -132
  105. package/dist/services/economy-handlers.js.map +7 -1
  106. package/dist/tx-runner.d.ts +35 -11
  107. package/dist/tx-runner.d.ts.map +1 -1
  108. package/dist/tx-runner.js +293 -250
  109. package/dist/tx-runner.js.map +7 -1
  110. package/dist/where.js +71 -94
  111. package/dist/where.js.map +7 -1
  112. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -1,23 +1,3 @@
1
- /**
2
- * index.ts — 入口(v2 启动顺序)
3
- *
4
- * 工作流:
5
- * 1. 加载 env
6
- * 2. 校验 Node 版本
7
- * 3. openDatabase + createPlatformTables(sfmc__audit / sfmc__idempotent)
8
- * 4. loadManifestV2() — 失败 = 启动失败
9
- * 5. filterEnabled(loaded, lockFileEnabled)
10
- * 6. buildModuleAuth({auth_token, enabled_modules}) ← data/module-tokens.json
11
- * 7. 实例化:SchemaRegistry / ServiceRegistry / IdempotencyStore / TxRunner
12
- * 8. 装配 v2 路由 (/api/sfmc/db/* + /api/sfmc/services* + /api/sfmc/configs/:key/*)
13
- * 另保留 messages(qq-bridge) + config/modules/health 平台路由
14
- * 9. createServer + listen
15
- *
16
- * 鉴权(handle 层):
17
- * - /api/sfmc/db/*, /api/sfmc/services*, /api/sfmc/configs/:key(/set|notify)*
18
- * → module token (Authorization: Bearer ...) + ?moduleId=...
19
- * - 其他:env.AUTH_TOKEN 旧 auth(NEEDS_AUTH)
20
- */
21
1
  import http from "node:http";
22
2
  import { createIdempotencyStore } from "./lib/idempotency-store.js";
23
3
  import { loadEnv } from "./env.js";
@@ -33,7 +13,8 @@ import { SchemaRegistry } from "./schema-registry.js";
33
13
  import { ServiceRegistry } from "./service-registry.js";
34
14
  import { TxRunner } from "./tx-runner.js";
35
15
  import { registerEnabledBuiltinServices } from "./services/builtin-handlers.js";
36
- import { readJson, writeJson } from "@sfmc-bds/sdk/node/config";
16
+ import { syncModuleRuntimeState } from "./module-runtime-sync.js";
17
+ import { readJson } from "@sfmc-bds/sdk/node/config";
37
18
  import { createModuleConfigRoutes } from "./routes/module-config-routes.js";
38
19
  import { createDbRoutes } from "./routes/db-routes.js";
39
20
  import { createServiceRoutes } from "./routes/service-routes.js";
@@ -43,271 +24,268 @@ import { createHealthRoutes } from "./routes/health.js";
43
24
  import { createMessagesRoutes } from "./routes/messages.js";
44
25
  import { createModuleRoutes } from "./routes/modules.js";
45
26
  import { forwardToQQBridge, makeLLBotConfig } from "./domain/bridge.js";
46
- import { isEnabled, loadModuleLock, updateModuleState } from "./lib/module-state.js";
27
+ import { isEnabled, loadModuleLock, saveModuleLock, updateModuleState } from "./lib/module-state.js";
47
28
  import { body as sharedBody, json as sharedJson } from "./lib/http.js";
48
29
  if (!assertNodeVersion(22, 13)) {
49
- process.exit(2);
30
+ process.exit(2);
50
31
  }
51
32
  const env = loadEnv();
52
33
  const db = openDatabase(env.DB_PATH);
53
- createPlatformTables(db); // sfmc__audit / sfmc__idempotent
54
- initSchema(db); // 平台业务 bootstrap 表(players/world/chat/...)——qq-bridge 在 SAPI defineTable 之前就需要
34
+ createPlatformTables(db);
35
+ initSchema(db);
55
36
  const query = createQuery(db);
56
- // ── v2 manifest 加载(失败 = 启动失败)─────────────────────────
57
- const loadedManifest = loadManifestV2(); // throws on violation
58
- log.success(`[manifest v2] loaded ${Object.keys(loadedManifest.modules).length} modules; provides ${loadedManifest.providesMap.size} services`);
59
- // ── enabled 集合(从 lock file)─────────────────────────────
37
+ const loadedManifest = loadManifestV2();
38
+ log.success(
39
+ `[manifest v2] loaded ${Object.keys(loadedManifest.modules).length} modules; provides ${loadedManifest.providesMap.size} services`
40
+ );
60
41
  const lockFile = loadModuleLock(env.MODULE_LOCK_PATH);
61
42
  const moduleCatalog = readJson(env.MODULE_CATALOG_PATH) ?? { modules: [] };
62
- const catalogIds = new Set(Array.isArray(moduleCatalog.modules)
63
- ? moduleCatalog.modules
64
- .map((m) => String(m.id || ""))
65
- .filter((id) => id.length > 0)
66
- : []);
67
- const enabledSet = new Set();
43
+ const catalogIds = new Set(
44
+ Array.isArray(moduleCatalog.modules) ? moduleCatalog.modules.map((m) => String(m.id || "")).filter((id) => id.length > 0) : []
45
+ );
46
+ const enabledSet = /* @__PURE__ */ new Set();
68
47
  for (const id of Object.keys(loadedManifest.modules)) {
69
- if (!catalogIds.has(id))
70
- continue;
71
- const catalogEntry = moduleCatalog.modules.find((m) => String(m.id) === id);
72
- if (!catalogEntry)
73
- continue;
74
- const defaultEnabled = catalogEntry.enabledByDefault !== false;
75
- if (isEnabled(lockFile, id, defaultEnabled))
76
- enabledSet.add(id);
48
+ if (!catalogIds.has(id)) continue;
49
+ const catalogEntry = moduleCatalog.modules.find(
50
+ (m) => String(m.id) === id
51
+ );
52
+ if (!catalogEntry) continue;
53
+ const defaultEnabled = catalogEntry.enabledByDefault !== false;
54
+ if (isEnabled(lockFile, id, defaultEnabled)) enabledSet.add(id);
77
55
  }
78
- const enabledManifests = new Map();
56
+ const enabledManifests = /* @__PURE__ */ new Map();
79
57
  for (const id of enabledSet) {
80
- const m = loadedManifest.modules[id];
81
- if (m)
82
- enabledManifests.set(id, m);
58
+ const m = loadedManifest.modules[id];
59
+ if (m) enabledManifests.set(id, m);
83
60
  }
84
- log.info(`[manifest v2] enabled: ${[...enabledSet].sort().join(", ") || "(none)"}`);
85
- // ── 模块 HMAC token map(写到 data/module-tokens.json)────────
61
+ log.info(
62
+ `[manifest v2] enabled: ${[...enabledSet].sort().join(", ") || "(none)"}`
63
+ );
86
64
  const moduleAuth = buildModuleAuth({
87
- projectRoot: env.PROJECT_ROOT,
88
- envAuthToken: env.AUTH_TOKEN,
89
- enabledModuleIds: [...enabledSet],
65
+ dbPath: env.DB_PATH,
66
+ envAuthToken: env.AUTH_TOKEN,
67
+ enabledModuleIds: [...enabledSet]
90
68
  });
91
- // ── 三件套 + 路由工厂 ─────────────────────────────────────
92
69
  const schemaRegistry = new SchemaRegistry(db);
93
70
  const serviceRegistry = new ServiceRegistry();
94
71
  const idempotent = createIdempotencyStore(db);
95
72
  const txRunner = new TxRunner({
96
- db,
97
- query,
98
- schema: schemaRegistry,
99
- serviceRegistry,
100
- enabled: enabledManifests,
73
+ db,
74
+ query,
75
+ schema: schemaRegistry,
76
+ serviceRegistry,
77
+ enabled: enabledManifests
101
78
  });
102
- // ── 进程内置 service handler(扩展点:BUILTIN_SERVICE_PLUGINS) ──
103
79
  {
104
- const plugins = registerEnabledBuiltinServices(serviceRegistry, { query, db }, enabledSet);
105
- if (plugins > 0) {
106
- log.success(`[service] registered ${serviceRegistry.list().length} handlers from ${plugins} builtin plugin(s)`);
107
- }
80
+ const plugins = registerEnabledBuiltinServices(serviceRegistry, { query, db }, enabledSet);
81
+ if (plugins > 0) {
82
+ log.success(
83
+ `[service] registered ${serviceRegistry.list().length} handlers from ${plugins} builtin plugin(s)`
84
+ );
85
+ }
108
86
  }
109
87
  const json = sharedJson;
110
88
  const body = sharedBody;
111
- // ── 工具函数 ──────────────────────────────────────────────
112
89
  function loadModuleCatalog() {
113
- return Array.isArray(moduleCatalog.modules) ? moduleCatalog.modules : [];
90
+ return Array.isArray(moduleCatalog.modules) ? moduleCatalog.modules : [];
114
91
  }
115
92
  function buildModuleList() {
116
- const catalog = loadModuleCatalog();
117
- return catalog
118
- .map((raw) => {
119
- const entry = raw.entry && typeof raw.entry === "object"
120
- ? raw.entry
121
- : {};
122
- const id = String(raw.id || "").trim();
123
- const configKey = String(raw.configKey || raw.config_key || "").trim();
124
- if (!id || !configKey)
125
- return null;
126
- const state = lockFile.modules[id];
127
- const enabled = isEnabled(lockFile, id, raw.enabledByDefault !== false);
128
- return {
129
- id,
130
- module_id: id,
131
- name: configKey,
132
- config_key: configKey,
133
- display_name: String(raw.name || configKey),
134
- type: String(raw.type || "feature"),
135
- description: String(raw.description || ""),
136
- default_enabled: raw.enabledByDefault !== false,
137
- can_disable: raw.canDisable !== false,
138
- requires: Array.isArray(raw.requires)
139
- ? raw.requires.filter(Boolean).map(String)
140
- : [],
141
- optional: Array.isArray(raw.optional)
142
- ? raw.optional.filter(Boolean).map(String)
143
- : [],
144
- commands: Array.isArray(raw.commands)
145
- ? raw.commands.filter(Boolean).map(String)
146
- : [],
147
- entry: {
148
- kind: String(entry.kind || ""),
149
- path: String(entry.path || ""),
150
- init: String(entry.init || ""),
151
- },
152
- updated_at: state?.updatedAt ?? null,
153
- enabled: !!enabled,
154
- };
155
- })
156
- .filter(Boolean);
93
+ const catalog = loadModuleCatalog();
94
+ return catalog.map((raw) => {
95
+ const entry = raw.entry && typeof raw.entry === "object" ? raw.entry : {};
96
+ const id = String(raw.id || "").trim();
97
+ const configKey = String(
98
+ raw.configKey || raw.config_key || ""
99
+ ).trim();
100
+ if (!id || !configKey) return null;
101
+ const state = lockFile.modules[id];
102
+ const enabled = isEnabled(lockFile, id, raw.enabledByDefault !== false);
103
+ return {
104
+ id,
105
+ module_id: id,
106
+ name: configKey,
107
+ configKey,
108
+ config_key: configKey,
109
+ display_name: String(raw.name || configKey),
110
+ type: String(raw.type || "feature"),
111
+ description: String(raw.description || ""),
112
+ default_enabled: raw.enabledByDefault !== false,
113
+ can_disable: moduleCanDisable(raw),
114
+ // ConfigManager 认 installed!==false;已装包默认 true
115
+ installed: true,
116
+ requires: Array.isArray(raw.requires) ? raw.requires.filter(Boolean).map(String) : [],
117
+ optional: Array.isArray(raw.optional) ? raw.optional.filter(Boolean).map(String) : [],
118
+ commands: Array.isArray(raw.commands) ? raw.commands.filter(Boolean).map(String) : [],
119
+ entry: {
120
+ kind: String(entry.kind || ""),
121
+ path: String(entry.path || ""),
122
+ init: String(entry.init || "")
123
+ },
124
+ updated_at: state?.updatedAt ?? null,
125
+ enabled: !!enabled
126
+ };
127
+ }).filter(Boolean);
128
+ }
129
+ function moduleCanDisable(raw) {
130
+ return raw.canDisable !== false;
157
131
  }
158
132
  function resolveModuleByKey(key) {
159
- const k = String(key || "").trim();
160
- const catalog = loadModuleCatalog();
161
- return catalog.find((m) => String(m.id || "") === k ||
162
- String(m.configKey || m.config_key || "") === k);
133
+ const k = String(key || "").trim();
134
+ const catalog = loadModuleCatalog();
135
+ const raw = catalog.find(
136
+ (m) => String(m.id || "") === k || String(m.configKey || m.config_key || "") === k
137
+ );
138
+ if (!raw) return null;
139
+ const id = String(raw.id || "").trim();
140
+ const configKey = String(raw.configKey || raw.config_key || "").trim();
141
+ if (!id || !configKey) return null;
142
+ return { id, configKey, canDisable: moduleCanDisable(raw) };
163
143
  }
164
144
  function setModuleEnabled(mod, enabled) {
165
- // 直接更新启动时缓存的 lockFile(而非另读一份新副本),
166
- // 否则 buildModuleList() 读的仍是旧缓存,导致启停后 enabled 状态不翻转。
167
- updateModuleState(lockFile, mod.id, { enabled: !!enabled });
168
- writeJson(env.MODULE_LOCK_PATH, lockFile);
145
+ updateModuleState(lockFile, mod.id, { enabled: !!enabled });
146
+ saveModuleLock(env.MODULE_LOCK_PATH, lockFile);
147
+ syncModuleRuntimeState({
148
+ moduleId: mod.id,
149
+ enabled: !!enabled,
150
+ dbPath: env.DB_PATH,
151
+ envAuthToken: env.AUTH_TOKEN,
152
+ enabledSet,
153
+ enabledManifests,
154
+ loadedManifest,
155
+ moduleAuth,
156
+ serviceRegistry,
157
+ builtinDeps: { query, db }
158
+ });
169
159
  }
170
- // ── 平台路由(非模块业务) ───────────────────────────────────
171
160
  const healthRoutes = createHealthRoutes();
172
161
  const messagesRoutes = createMessagesRoutes({
173
- query,
174
- body,
175
- json,
176
- forwardToQQBridge: (channelId, fromName, content, fromId) => forwardToQQBridge(makeLLBotConfig({
177
- LLBOT_HOST: env.LLBOT_HOST,
178
- LLBOT_PORT: env.LLBOT_PORT,
179
- LLBOT_TOKEN: env.LLBOT_TOKEN,
180
- QQ_GROUP_ID: env.QQ_GROUP_ID,
181
- }), channelId, fromName, content, fromId),
162
+ query,
163
+ body,
164
+ json,
165
+ forwardToQQBridge: (channelId, fromName, content, fromId) => forwardToQQBridge(
166
+ makeLLBotConfig({
167
+ LLBOT_HOST: env.LLBOT_HOST,
168
+ LLBOT_PORT: env.LLBOT_PORT,
169
+ LLBOT_TOKEN: env.LLBOT_TOKEN,
170
+ QQ_GROUP_ID: env.QQ_GROUP_ID
171
+ }),
172
+ channelId,
173
+ fromName,
174
+ content,
175
+ fromId
176
+ )
177
+ });
178
+ const configRoutes = createConfigRoutes({
179
+ json,
180
+ projectRoot: env.PROJECT_ROOT,
181
+ // DIP:路由不读 lock/catalog/token 文件,由入口注入与 /modules 同源数据
182
+ listModules: () => buildModuleList(),
183
+ getModuleTokens: () => ({ ...moduleAuth.tokens })
182
184
  });
183
- const configRoutes = createConfigRoutes({ json, projectRoot: env.PROJECT_ROOT });
184
185
  const moduleRoutesInstance = createModuleRoutes({
185
- loadModuleCatalog,
186
- buildModuleList: buildModuleList,
187
- resolveModuleByKey,
188
- setModuleEnabled,
189
- body,
190
- json,
186
+ loadModuleCatalog,
187
+ buildModuleList,
188
+ resolveModuleByKey,
189
+ setModuleEnabled,
190
+ body,
191
+ json
191
192
  });
192
- // ── v2 路由工厂 ───────────────────────────────────────────────
193
- // 类型断言成 unknown 函数 — v2 routes 的 ctx 类型与 RouteCtx 不兼容,
194
- // 但调用契约({path, method, params, req, res, body?})是稳定的。
195
193
  const dbRoutes = createDbRoutes({ schemaRegistry, txRunner, idempotent, json });
196
194
  const serviceRoutes = createServiceRoutes({
197
- serviceRegistry,
198
- enabled: enabledManifests,
199
- json,
195
+ serviceRegistry,
196
+ enabled: enabledManifests,
197
+ json
200
198
  });
201
199
  const moduleConfigRoutes = createModuleConfigRoutes({
202
- projectRoot: env.PROJECT_ROOT,
203
- enabled: enabledManifests,
204
- json,
200
+ projectRoot: env.PROJECT_ROOT,
201
+ enabled: enabledManifests,
202
+ json
205
203
  });
206
- // ── 主请求处理器 ────────────────────────────────────────────
207
204
  async function handle(req, res) {
208
- const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
209
- const path = url.pathname;
210
- const method = req.method || "GET";
211
- const params = url.searchParams;
212
- // loopback 绑定
213
- const remote = req.socket.remoteAddress || "";
214
- if (remote && !remote.startsWith("127.") && remote !== "::1" && remote !== "::ffff:127.") {
215
- json(res, { success: false, error: "forbidden" }, 403);
216
- return;
205
+ const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
206
+ const path = url.pathname;
207
+ const method = req.method || "GET";
208
+ const params = url.searchParams;
209
+ const remote = req.socket.remoteAddress || "";
210
+ if (remote && !remote.startsWith("127.") && remote !== "::1" && remote !== "::ffff:127.") {
211
+ json(res, { success: false, error: "forbidden" }, 403);
212
+ return;
213
+ }
214
+ await body(req);
215
+ const isLegacyConfigAll = path === "/api/sfmc/configs/all";
216
+ const needsModuleAuth = path.startsWith("/api/sfmc/db/") || path.startsWith("/api/sfmc/services") || /^\/api\/sfmc\/configs\/[A-Za-z0-9_-]+(?:\/(?:set|notify))?$/.test(path) && !isLegacyConfigAll;
217
+ let moduleAuthCtx = null;
218
+ if (needsModuleAuth) {
219
+ const id = verifyModuleAuth({
220
+ headers: req.headers,
221
+ params,
222
+ auth: moduleAuth,
223
+ enabledModuleIds: enabledSet
224
+ });
225
+ if (!id) {
226
+ jsonV2Fail(res, "unauthorized: module identity invalid", 401, "unauthorized");
227
+ return;
217
228
  }
218
- // ── 预读 body(所有路由共享) ───────────────────────────────
219
- await body(req);
220
- // ── v2 模块身份校验 → 写入路由 ctx.moduleAuth(LoD:不挂 req 私有字段) ──
221
- // 注意:`/api/sfmc/configs/all` 是旧的一次性配置快照端点(SAPI ConfigManager.init
222
- // 启动必用),不属于 v2 模块配置命名空间(configs/<模块 configKey>),必须豁免,
223
- // 否则会被模块鉴权网关拦成 401,导致插件端起不来。
224
- const isLegacyConfigAll = path === "/api/sfmc/configs/all";
225
- const needsModuleAuth = path.startsWith("/api/sfmc/db/") ||
226
- path.startsWith("/api/sfmc/services") ||
227
- (/^\/api\/sfmc\/configs\/[A-Za-z0-9_-]+(?:\/(?:set|notify))?$/.test(path) && !isLegacyConfigAll);
228
- let moduleAuthCtx = null;
229
- if (needsModuleAuth) {
230
- const id = verifyModuleAuth({
231
- headers: req.headers,
232
- params,
233
- auth: moduleAuth,
234
- enabledModuleIds: enabledSet,
235
- });
236
- if (!id) {
237
- // LSP: v2 模块门与 service-routes 同用 ok 方言
238
- jsonV2Fail(res, "unauthorized: module identity invalid", 401, "unauthorized");
239
- return;
240
- }
241
- const manifest = enabledManifests.get(id);
242
- moduleAuthCtx = {
243
- id,
244
- permissions: manifest?.permissions ?? [],
245
- };
246
- }
247
- else {
248
- // ── 旧 env token 鉴权(只对 POST/PUT 生效) ─────────────
249
- const PUBLIC_GET = path === "/api/health" ||
250
- (method === "GET" &&
251
- (path === "/api/sfmc/modules" || path === "/api/sfmc/modules/catalog" || path.startsWith("/api/sfmc/modules/")));
252
- const NEEDS_AUTH = !PUBLIC_GET && method !== "GET";
253
- if (env.AUTH_TOKEN && NEEDS_AUTH) {
254
- const auth = req.headers["authorization"] || "";
255
- const provided = auth.startsWith("Bearer ") ? auth.slice(7) : req.headers["x-db-token"] || "";
256
- if (provided !== env.AUTH_TOKEN) {
257
- json(res, { success: false, error: "unauthorized" }, 401);
258
- return;
259
- }
260
- }
261
- }
262
- try {
263
- // ── v2 路由(优先匹配) ─────────────────────────────
264
- if (moduleAuthCtx && (path.startsWith("/api/sfmc/db/") || path.startsWith("/api/sfmc/services") || (/^\/api\/sfmc\/configs\/[A-Za-z0-9_-]+/.test(path) && !isLegacyConfigAll))) {
265
- const ctx = {
266
- path,
267
- method,
268
- params,
269
- req,
270
- res,
271
- moduleAuth: moduleAuthCtx,
272
- };
273
- // body 已在上面 `await body(req)` 预读并缓存到 req._bodyPromise;
274
- // 这里复用缓存(原实现读的 req._body 从未被赋值,导致所有 v2 路由 body 恒为空)。
275
- ctx["body"] = await body(req);
276
- if (path.startsWith("/api/sfmc/db/")) {
277
- if (await dbRoutes(ctx))
278
- return;
279
- }
280
- else if (path.startsWith("/api/sfmc/services")) {
281
- if (await serviceRoutes(ctx))
282
- return;
283
- }
284
- else {
285
- if (await moduleConfigRoutes(ctx))
286
- return;
287
- }
288
- }
289
- // ── 平台路由 ────────────────────────────────────
290
- const ctxBase = { path, method, params, req, res };
291
- if (await moduleRoutesInstance(ctxBase))
292
- return;
293
- if (await healthRoutes(ctxBase))
294
- return;
295
- if (await messagesRoutes(ctxBase))
296
- return;
297
- if (await configRoutes(ctxBase))
298
- return;
299
- json(res, { success: false, error: "not_found" }, 404);
229
+ const manifest = enabledManifests.get(id);
230
+ moduleAuthCtx = {
231
+ id,
232
+ permissions: manifest?.permissions ?? []
233
+ };
234
+ } else {
235
+ const PUBLIC_GET = path === "/api/health" || method === "GET" && (path === "/api/sfmc/modules" || path === "/api/sfmc/modules/catalog" || path.startsWith("/api/sfmc/modules/"));
236
+ const NEEDS_AUTH = !PUBLIC_GET && method !== "GET";
237
+ if (env.AUTH_TOKEN && NEEDS_AUTH) {
238
+ const auth = req.headers["authorization"] || "";
239
+ const provided = auth.startsWith("Bearer ") ? auth.slice(7) : req.headers["x-db-token"] || "";
240
+ if (provided !== env.AUTH_TOKEN) {
241
+ json(res, { success: false, error: "unauthorized" }, 401);
242
+ return;
243
+ }
300
244
  }
301
- catch (err) {
302
- log.err(err, "DogeDB");
303
- json(res, { success: false, error: err.message }, 500);
245
+ }
246
+ try {
247
+ if (moduleAuthCtx && (path.startsWith("/api/sfmc/db/") || path.startsWith("/api/sfmc/services") || /^\/api\/sfmc\/configs\/[A-Za-z0-9_-]+/.test(path) && !isLegacyConfigAll)) {
248
+ const ctx = {
249
+ path,
250
+ method,
251
+ params,
252
+ req,
253
+ res,
254
+ moduleAuth: moduleAuthCtx
255
+ };
256
+ ctx["body"] = await body(req);
257
+ if (path.startsWith("/api/sfmc/db/")) {
258
+ if (await dbRoutes(ctx)) return;
259
+ } else if (path.startsWith("/api/sfmc/services")) {
260
+ if (await serviceRoutes(ctx)) return;
261
+ } else {
262
+ if (await moduleConfigRoutes(ctx)) return;
263
+ }
304
264
  }
265
+ const ctxBase = { path, method, params, req, res };
266
+ if (await moduleRoutesInstance(ctxBase)) return;
267
+ if (await healthRoutes(ctxBase)) return;
268
+ if (await messagesRoutes(ctxBase)) return;
269
+ if (await configRoutes(ctxBase)) return;
270
+ json(res, { success: false, error: "not_found" }, 404);
271
+ } catch (err) {
272
+ log.err(err, "DogeDB");
273
+ json(res, { success: false, error: err.message }, 500);
274
+ }
305
275
  }
306
- // ── 启动 ────────────────────────────────────────────────────
307
276
  const server = createServer({
308
- env: { PORT: env.PORT, HOST: env.HOST, AUTH_TOKEN: env.AUTH_TOKEN },
309
- handle,
277
+ env: { PORT: env.PORT, HOST: env.HOST, AUTH_TOKEN: env.AUTH_TOKEN },
278
+ handle
310
279
  });
311
280
  startConsole(server, db);
312
- export { db, env, query, schemaRegistry, serviceRegistry, txRunner, enabledManifests, moduleAuth };
313
- //# sourceMappingURL=index.js.map
281
+ export {
282
+ db,
283
+ enabledManifests,
284
+ env,
285
+ moduleAuth,
286
+ query,
287
+ schemaRegistry,
288
+ serviceRegistry,
289
+ txRunner
290
+ };
291
+ //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1,7 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": ["/**\n * index.ts \u2014 \u5165\u53E3(v2 \u542F\u52A8\u987A\u5E8F)\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\";\n\nimport { createIdempotencyStore } from \"./lib/idempotency-store.js\";\nimport { loadEnv } from \"./env.js\";\nimport { buildModuleAuth, verifyModuleAuth } from \"./module-auth.js\";\nimport { loadManifestV2 } from \"./manifest-loader.js\";\nimport { log } from \"./lib/log.js\";\nimport { assertNodeVersion } from \"./lib/runtime.js\";\nimport { createQuery, openDatabase } from \"./lib/sqlite.js\";\nimport { createServer, startConsole } from \"./server.js\";\nimport { createPlatformTables } from \"./db-tables.js\";\nimport { initSchema } from \"./domain/schema.js\";\nimport { SchemaRegistry } from \"./schema-registry.js\";\nimport { ServiceRegistry } from \"./service-registry.js\";\nimport { TxRunner } from \"./tx-runner.js\";\nimport { registerEnabledBuiltinServices } from \"./services/builtin-handlers.js\";\nimport { syncModuleRuntimeState } from \"./module-runtime-sync.js\";\n\nimport { readJson } from \"@sfmc-bds/sdk/node/config\";\n\nimport { createModuleConfigRoutes } from \"./routes/module-config-routes.js\";\nimport { createDbRoutes } from \"./routes/db-routes.js\";\nimport { createServiceRoutes } from \"./routes/service-routes.js\";\nimport { jsonV2Fail } from \"./routes/_shared.js\";\n\nimport { createConfigRoutes } from \"./routes/config.js\";\nimport { createHealthRoutes } from \"./routes/health.js\";\nimport { createMessagesRoutes } from \"./routes/messages.js\";\nimport { createModuleRoutes } from \"./routes/modules.js\";\n\nimport { forwardToQQBridge, makeLLBotConfig } from \"./domain/bridge.js\";\nimport { isEnabled, loadModuleLock, saveModuleLock, updateModuleState } from \"./lib/module-state.js\";\nimport { body as sharedBody, json as sharedJson } from \"./lib/http.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 }>)\n .map((m) => String(m.id || \"\"))\n .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(\n (m) => String(m.id) === id\n );\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(\n `[manifest v2] enabled: ${[...enabledSet].sort().join(\", \") || \"(none)\"}`\n);\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\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(\n `[service] registered ${serviceRegistry.list().length} handlers from ${plugins} builtin plugin(s)`\n );\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 type: String((raw as Record<string, unknown>).type || \"feature\"),\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/** 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();\nconst messagesRoutes = createMessagesRoutes({\n query,\n body,\n json,\n forwardToQQBridge: (channelId: string, fromName: string, content: string, fromId: string) =>\n forwardToQQBridge(\n makeLLBotConfig({\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 }),\n channelId,\n fromName,\n content,\n fromId\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 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 (ctx: Record<string, unknown>) => 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 (method === \"GET\" &&\n (path === \"/api/sfmc/modules\" || path === \"/api/sfmc/modules/catalog\" || path.startsWith(\"/api/sfmc/modules/\")));\n const NEEDS_AUTH = !PUBLIC_GET && method !== \"GET\";\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 // \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 (moduleAuthCtx && (path.startsWith(\"/api/sfmc/db/\") || path.startsWith(\"/api/sfmc/services\") || (/^\\/api\\/sfmc\\/configs\\/[A-Za-z0-9_-]+/.test(path) && !isLegacyConfigAll))) {\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 { path: string; method: string; params: URLSearchParams; req: http.IncomingMessage; res: http.ServerResponse };\n if (await moduleRoutesInstance(ctxBase)) return;\n if (await healthRoutes(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, env, query, schemaRegistry, serviceRegistry, txRunner, enabledManifests, moduleAuth };\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }