@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
@@ -1,186 +1,212 @@
1
- /**
2
- * routes/db-routes.ts — /api/sfmc/db/* 处理器
3
- *
4
- * 端点:
5
- * POST /api/sfmc/db/define-table body {name, columns, softDelete?} → {table, created}
6
- * POST /api/sfmc/db/tx body {steps[]} → TxResponse | TxError
7
- * POST /api/sfmc/db/query body {table, opts?} → {rows}
8
- * POST /api/sfmc/db/get body {table, id} → {row}
9
- * POST /api/sfmc/db/insert body {table, row} → {row}
10
- * POST /api/sfmc/db/update body {table, id, patch} → {row}
11
- * POST /api/sfmc/db/delete body {table, id, hard?} → {changes}
12
- * POST /api/sfmc/db/audit body {table, rowId, action, data?} → {ok}
13
- * POST /api/sfmc/db/idempotent/probe body {action, key} → {replayed, cached?}
14
- * POST /api/sfmc/db/idempotent/commit body {action, key, value?} → {ok}
15
- *
16
- * 鉴权:handle() 校验后把 {id, permissions} 写到 ctx.moduleAuth(不挂 req)。
17
- */
18
1
  import { json as defaultJson } from "../lib/http.js";
19
- import { jsonV2Fail } from "./_shared.js";
2
+ import { jsonV2Fail, jsonV2Ok } from "./_shared.js";
20
3
  import { PermissionDeniedError } from "../permission-gate.js";
21
- export function createDbRoutes(depsIn) {
22
- const deps = depsIn;
23
- if (!deps.schemaRegistry || !deps.txRunner || !deps.idempotent) {
24
- throw new Error("createDbRoutes: 缺少 schemaRegistry / txRunner / idempotent");
4
+ function createDbRoutes(depsIn) {
5
+ const deps = depsIn;
6
+ if (!deps.schemaRegistry || !deps.txRunner || !deps.idempotent) {
7
+ throw new Error("createDbRoutes: \u7F3A\u5C11 schemaRegistry / txRunner / idempotent");
8
+ }
9
+ const json = deps.json || defaultJson;
10
+ return async (ctx) => {
11
+ const { path, method, res } = ctx;
12
+ if (!path.startsWith("/api/sfmc/db/")) return false;
13
+ if (method !== "POST" && method !== "DELETE") return false;
14
+ const auth = ctx.moduleAuth ?? null;
15
+ if (!auth) {
16
+ jsonV2Fail(res, "unauthorized: module identity missing", 401, "unauthorized");
17
+ return true;
25
18
  }
26
- const json = deps.json || defaultJson;
27
- return async (ctx) => {
28
- const { path, method, res } = ctx;
29
- if (!path.startsWith("/api/sfmc/db/"))
30
- return false;
31
- if (method !== "POST" && method !== "DELETE")
32
- return false;
33
- const auth = ctx.moduleAuth ?? null;
34
- if (!auth) {
35
- jsonV2Fail(res, "unauthorized: module identity missing", 401, "unauthorized");
36
- return true;
19
+ const body = await ctx.body || {};
20
+ const moduleId = auth.id;
21
+ if (path === "/api/sfmc/db/define-table") {
22
+ try {
23
+ const req2 = body;
24
+ delete req2.moduleId;
25
+ const result = deps.schemaRegistry.define(moduleId, req2);
26
+ jsonV2Ok(res, { table: result.table, created: result.created });
27
+ } catch (e) {
28
+ jsonV2Fail(res, e.message, 400);
29
+ }
30
+ return true;
31
+ }
32
+ if (path === "/api/sfmc/db/tx") {
33
+ try {
34
+ const txReq = body;
35
+ const steps = Array.isArray(txReq.steps) ? txReq.steps : [];
36
+ const result = await deps.txRunner.run({ moduleId, steps });
37
+ const status = result.ok ? 200 : 400;
38
+ json(res, result, status);
39
+ } catch (e) {
40
+ jsonV2Fail(res, e.message, 500);
41
+ }
42
+ return true;
43
+ }
44
+ const sessionOps = [
45
+ {
46
+ path: "/api/sfmc/db/tx/begin",
47
+ run: () => deps.txRunner.beginSession(moduleId)
48
+ },
49
+ {
50
+ path: "/api/sfmc/db/tx/step",
51
+ requireTxId: true,
52
+ requireStep: true,
53
+ run: ({ txId, step }) => deps.txRunner.stepSession(txId, moduleId, step)
54
+ },
55
+ {
56
+ path: "/api/sfmc/db/tx/commit",
57
+ requireTxId: true,
58
+ run: ({ txId }) => deps.txRunner.commitSession(txId, moduleId)
59
+ },
60
+ {
61
+ path: "/api/sfmc/db/tx/rollback",
62
+ requireTxId: true,
63
+ run: ({ txId }) => deps.txRunner.rollbackSession(txId, moduleId)
64
+ }
65
+ ];
66
+ for (const op of sessionOps) {
67
+ if (path !== op.path) continue;
68
+ try {
69
+ const txId = String(body.txId || "");
70
+ const step = body.step;
71
+ if (op.requireTxId && !txId) {
72
+ jsonV2Fail(res, `${op.path.split("/").pop()} \u9700\u8981 { txId }`, 400);
73
+ return true;
37
74
  }
38
- const body = (await ctx.body) || {};
39
- const moduleId = auth.id;
40
- if (path === "/api/sfmc/db/define-table") {
41
- try {
42
- const req2 = body;
43
- delete req2.moduleId;
44
- const result = deps.schemaRegistry.define(moduleId, req2);
45
- json(res, { success: true, table: result.table, created: result.created }, 200);
46
- }
47
- catch (e) {
48
- json(res, { success: false, error: e.message }, 400);
49
- }
50
- return true;
75
+ if (op.requireStep && (!step || typeof step !== "object" || !("op" in step))) {
76
+ jsonV2Fail(res, "tx/step \u9700\u8981 { txId, step }", 400);
77
+ return true;
51
78
  }
52
- if (path === "/api/sfmc/db/tx") {
53
- try {
54
- const txReq = body;
55
- // 强制以「鉴权身份」执行事务:忽略 body 里自带的 moduleId,
56
- // 既防止持 A 的 token 冒用 B 的权限越权,也修复客户端只发 {steps}
57
- // moduleId 缺失导致的事务恒被拒。
58
- const steps = Array.isArray(txReq.steps) ? txReq.steps : [];
59
- const result = await deps.txRunner.run({ moduleId, steps });
60
- const status = result.ok ? 200 : 400;
61
- json(res, result, status);
62
- }
63
- catch (e) {
64
- json(res, { success: false, error: e.message }, 500);
65
- }
79
+ const result = await op.run(step !== void 0 ? { txId, step } : { txId });
80
+ json(res, result, result.ok ? 200 : 400);
81
+ } catch (e) {
82
+ jsonV2Fail(res, e.message, 500);
83
+ }
84
+ return true;
85
+ }
86
+ const singles = [
87
+ { match: /^\/api\/sfmc\/db\/query$/, op: "query" },
88
+ { match: /^\/api\/sfmc\/db\/get$/, op: "get" },
89
+ { match: /^\/api\/sfmc\/db\/insert$/, op: "insert" },
90
+ { match: /^\/api\/sfmc\/db\/update$/, op: "update" },
91
+ { match: /^\/api\/sfmc\/db\/delete$/, op: "delete" }
92
+ ];
93
+ for (const cand of singles) {
94
+ if (cand.match.test(path)) {
95
+ try {
96
+ const step = buildSingleStep(cand.op, body);
97
+ const result = await deps.txRunner.run({ moduleId, steps: [step] });
98
+ if (!result.ok) {
99
+ const code = result.code === "permission_denied" ? 403 : 400;
100
+ jsonV2Fail(res, result.error, code, result.code, { step: result.step });
66
101
  return true;
67
- }
68
- const singles = [
69
- { match: /^\/api\/sfmc\/db\/query$/, op: "query" },
70
- { match: /^\/api\/sfmc\/db\/get$/, op: "get" },
71
- { match: /^\/api\/sfmc\/db\/insert$/, op: "insert" },
72
- { match: /^\/api\/sfmc\/db\/update$/, op: "update" },
73
- { match: /^\/api\/sfmc\/db\/delete$/, op: "delete" },
74
- ];
75
- for (const cand of singles) {
76
- if (cand.match.test(path)) {
77
- try {
78
- const step = buildSingleStep(cand.op, body);
79
- const result = await deps.txRunner.run({ moduleId, steps: [step] });
80
- if (!result.ok) {
81
- const code = result.code === "permission_denied" ? 403 : 400;
82
- json(res, { success: false, error: result.error, step: result.step, code: result.code }, code);
83
- return true;
84
- }
85
- const first = result.results[0];
86
- json(res, { success: true, ...unwrapResult(first, cand.op) }, 200);
87
- }
88
- catch (e) {
89
- if (e instanceof PermissionDeniedError) {
90
- json(res, { success: false, error: e.message, code: "permission_denied" }, 403);
91
- return true;
92
- }
93
- json(res, { success: false, error: e.message }, 500);
94
- }
95
- return true;
96
- }
97
- }
98
- if (path === "/api/sfmc/db/audit") {
99
- try {
100
- const step = {
101
- op: "audit",
102
- table: String(body.table),
103
- rowId: String(body.rowId),
104
- action: String(body.action),
105
- ...(body.data ? { data: body.data } : {}),
106
- };
107
- const result = await deps.txRunner.run({ moduleId, steps: [step] });
108
- if (!result.ok) {
109
- json(res, { success: false, error: result.error }, 400);
110
- return true;
111
- }
112
- json(res, { success: true });
113
- }
114
- catch (e) {
115
- json(res, { success: false, error: e.message }, 500);
116
- }
102
+ }
103
+ const first = result.results[0];
104
+ jsonV2Ok(res, unwrapResult(first, cand.op));
105
+ } catch (e) {
106
+ if (e instanceof PermissionDeniedError) {
107
+ jsonV2Fail(res, e.message, 403, "permission_denied");
117
108
  return true;
109
+ }
110
+ jsonV2Fail(res, e.message, 500);
118
111
  }
119
- const m = path.match(/^\/api\/sfmc\/db\/idempotent\/(probe|commit)$/);
120
- if (m) {
121
- try {
122
- if (m[1] === "probe") {
123
- const r = await deps.idempotent.probe(moduleId, String(body.action), String(body.key));
124
- json(res, r);
125
- }
126
- else {
127
- const r = await deps.idempotent.commit(moduleId, String(body.action), String(body.key), body.value);
128
- json(res, { success: r.ok });
129
- }
130
- }
131
- catch (e) {
132
- json(res, { success: false, error: e.message }, 500);
133
- }
134
- return true;
112
+ return true;
113
+ }
114
+ }
115
+ if (path === "/api/sfmc/db/audit") {
116
+ try {
117
+ const step = {
118
+ op: "audit",
119
+ table: String(body.table),
120
+ rowId: String(body.rowId),
121
+ action: String(body.action),
122
+ ...body.data ? { data: body.data } : {}
123
+ };
124
+ const result = await deps.txRunner.run({ moduleId, steps: [step] });
125
+ if (!result.ok) {
126
+ jsonV2Fail(res, result.error, 400, result.code);
127
+ return true;
128
+ }
129
+ jsonV2Ok(res);
130
+ } catch (e) {
131
+ jsonV2Fail(res, e.message, 500);
132
+ }
133
+ return true;
134
+ }
135
+ const m = path.match(/^\/api\/sfmc\/db\/idempotent\/(probe|commit)$/);
136
+ if (m) {
137
+ try {
138
+ if (m[1] === "probe") {
139
+ const r = await deps.idempotent.probe(
140
+ moduleId,
141
+ String(body.action),
142
+ String(body.key)
143
+ );
144
+ json(res, r);
145
+ } else {
146
+ const r = await deps.idempotent.commit(
147
+ moduleId,
148
+ String(body.action),
149
+ String(body.key),
150
+ body.value
151
+ );
152
+ jsonV2Ok(res, { committed: r.ok });
135
153
  }
136
- return false;
137
- };
154
+ } catch (e) {
155
+ jsonV2Fail(res, e.message, 500);
156
+ }
157
+ return true;
158
+ }
159
+ return false;
160
+ };
138
161
  }
139
162
  function buildSingleStep(op, body) {
140
- switch (op) {
141
- case "query":
142
- return {
143
- op: "query",
144
- table: String(body.table),
145
- ...(body.opts ? { opts: body.opts } : {}),
146
- };
147
- case "get":
148
- return { op: "get", table: String(body.table), id: String(body.id) };
149
- case "insert":
150
- return {
151
- op: "insert",
152
- table: String(body.table),
153
- row: body.row,
154
- };
155
- case "update":
156
- return {
157
- op: "update",
158
- table: String(body.table),
159
- id: String(body.id),
160
- patch: body.patch,
161
- };
162
- case "delete":
163
- return {
164
- op: "delete",
165
- table: String(body.table),
166
- id: String(body.id),
167
- hard: Boolean(body.hard),
168
- };
169
- }
163
+ switch (op) {
164
+ case "query":
165
+ return {
166
+ op: "query",
167
+ table: String(body.table),
168
+ ...body.opts ? { opts: body.opts } : {}
169
+ };
170
+ case "get":
171
+ return { op: "get", table: String(body.table), id: String(body.id) };
172
+ case "insert":
173
+ return {
174
+ op: "insert",
175
+ table: String(body.table),
176
+ row: body.row
177
+ };
178
+ case "update":
179
+ return {
180
+ op: "update",
181
+ table: String(body.table),
182
+ id: String(body.id),
183
+ patch: body.patch
184
+ };
185
+ case "delete":
186
+ return {
187
+ op: "delete",
188
+ table: String(body.table),
189
+ id: String(body.id),
190
+ hard: Boolean(body.hard)
191
+ };
192
+ }
170
193
  }
171
194
  function unwrapResult(r, op) {
172
- const step = r;
173
- switch (op) {
174
- case "query":
175
- return step.rows ? { rows: step.rows } : {};
176
- case "get":
177
- case "insert":
178
- case "update":
179
- return step.row !== undefined ? { row: step.row } : {};
180
- case "delete":
181
- return typeof step.changes === "number" ? { changes: step.changes } : {};
182
- default:
183
- return {};
184
- }
195
+ const step = r;
196
+ switch (op) {
197
+ case "query":
198
+ return step.rows ? { rows: step.rows } : {};
199
+ case "get":
200
+ case "insert":
201
+ case "update":
202
+ return step.row !== void 0 ? { row: step.row } : {};
203
+ case "delete":
204
+ return typeof step.changes === "number" ? { changes: step.changes } : {};
205
+ default:
206
+ return {};
207
+ }
185
208
  }
186
- //# sourceMappingURL=db-routes.js.map
209
+ export {
210
+ createDbRoutes
211
+ };
212
+ //# sourceMappingURL=db-routes.js.map
@@ -1 +1,7 @@
1
- {"version":3,"file":"db-routes.js","sourceRoot":"","sources":["../../src/routes/db-routes.ts"],"names":[],"mappings":"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"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/routes/db-routes.ts"],
4
+ "sourcesContent": ["/**\n * routes/db-routes.ts \u2014 /api/sfmc/db/* \u5904\u7406\u5668\n *\n * \u7AEF\u70B9:\n * POST /api/sfmc/db/define-table body {name, columns, softDelete?} \u2192 {table, created}\n * POST /api/sfmc/db/tx body {steps[]} \u2192 TxResponse | TxError (\u6279\u91CF)\n * POST /api/sfmc/db/tx/begin body {} \u2192 {txId}\n * POST /api/sfmc/db/tx/step body {txId, step} \u2192 {result}\n * POST /api/sfmc/db/tx/commit body {txId} \u2192 TxResponse\n * POST /api/sfmc/db/tx/rollback body {txId} \u2192 {ok}\n * POST /api/sfmc/db/query body {table, opts?} \u2192 {rows}\n * ...\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { json as defaultJson, type Method } from \"../lib/http.js\";\nimport { jsonV2Fail, jsonV2Ok, type ModuleAuth } from \"./_shared.js\";\nimport type {\n DefineTableRequest,\n SchemaRegistry,\n} from \"../schema-registry.js\";\nimport type {\n TxRequest,\n TxRunner,\n TxStep,\n} from \"../tx-runner.js\";\nimport { PermissionDeniedError } from \"../permission-gate.js\";\nimport type { IdempotencyStore } from \"../lib/idempotency-store.js\";\n\nexport interface DbRoutesDeps {\n schemaRegistry: SchemaRegistry;\n txRunner: TxRunner;\n idempotent: IdempotencyStore;\n json?: typeof defaultJson;\n}\n\nexport function createDbRoutes(depsIn: Partial<DbRoutesDeps>) {\n const deps = depsIn as Partial<DbRoutesDeps>;\n if (!deps.schemaRegistry || !deps.txRunner || !deps.idempotent) {\n throw new Error(\"createDbRoutes: \u7F3A\u5C11 schemaRegistry / txRunner / idempotent\");\n }\n const json = deps.json || defaultJson;\n\n return async (ctx: {\n path: string;\n method: Method | string;\n req: IncomingMessage;\n res: ServerResponse;\n body?: Promise<Record<string, unknown>> | Record<string, unknown>;\n moduleAuth?: ModuleAuth;\n }): Promise<boolean> => {\n const { path, method, res } = ctx;\n if (!path.startsWith(\"/api/sfmc/db/\")) return false;\n if (method !== \"POST\" && method !== \"DELETE\") return false;\n\n const auth = ctx.moduleAuth ?? null;\n if (!auth) {\n jsonV2Fail(res, \"unauthorized: module identity missing\", 401, \"unauthorized\");\n return true;\n }\n\n const body = (await (ctx.body as Promise<Record<string, unknown>> | undefined)) || {};\n const moduleId = auth.id;\n\n if (path === \"/api/sfmc/db/define-table\") {\n try {\n const req2 = body as unknown as DefineTableRequest & { moduleId?: string };\n delete (req2 as { moduleId?: string }).moduleId;\n const result = deps.schemaRegistry!.define(moduleId, req2);\n jsonV2Ok(res, { table: result.table, created: result.created });\n } catch (e) {\n jsonV2Fail(res, (e as Error).message, 400);\n }\n return true;\n }\n\n if (path === \"/api/sfmc/db/tx\") {\n try {\n const txReq = body as unknown as TxRequest;\n // \u5F3A\u5236\u4EE5\u300C\u9274\u6743\u8EAB\u4EFD\u300D\u6267\u884C\u4E8B\u52A1:\u5FFD\u7565 body \u91CC\u81EA\u5E26\u7684 moduleId,\n // \u65E2\u9632\u6B62\u6301 A \u7684 token \u5192\u7528 B \u7684\u6743\u9650\u8D8A\u6743,\u4E5F\u4FEE\u590D\u5BA2\u6237\u7AEF\u53EA\u53D1 {steps} \u65F6\n // moduleId \u7F3A\u5931\u5BFC\u81F4\u7684\u4E8B\u52A1\u6052\u88AB\u62D2\u3002\n const steps = Array.isArray(txReq.steps) ? txReq.steps : [];\n const result = await deps.txRunner!.run({ moduleId, steps });\n const status = result.ok ? 200 : 400;\n // TxResponse/TxError \u81EA\u8EAB\u5DF2\u5E26 ok \u5B57\u6BB5;\u539F\u6837\u56DE\u4F20\u4FDD\u6301\u5951\u7EA6\n json(res, result as unknown as Record<string, unknown>, status);\n } catch (e) {\n jsonV2Fail(res, (e as Error).message, 500);\n }\n return true;\n }\n\n // \u4EA4\u4E92\u5F0F\u4E8B\u52A1\u4F1A\u8BDD \u2014 \u4F9B SDK \u5728\u56DE\u8C03\u5185\u8BFB\u56DE query/get/call \u7ED3\u679C\n // OCP/DRY:\u65B0\u4F1A\u8BDD\u52A8\u8BCD\u53EA\u5F80\u8868\u91CC\u52A0\u4E00\u9879,\u52FF\u518D\u590D\u5236 try/catch \u56DB\u4EFD\n type SessionReply = { ok: boolean } & Record<string, unknown>;\n const sessionOps: Array<{\n path: string;\n requireTxId?: boolean;\n requireStep?: boolean;\n run: (args: { txId: string; step?: TxStep | undefined }) => Promise<SessionReply> | SessionReply;\n }> = [\n {\n path: \"/api/sfmc/db/tx/begin\",\n run: () => deps.txRunner!.beginSession(moduleId) as SessionReply,\n },\n {\n path: \"/api/sfmc/db/tx/step\",\n requireTxId: true,\n requireStep: true,\n run: ({ txId, step }) => deps.txRunner!.stepSession(txId, moduleId, step!) as Promise<SessionReply>,\n },\n {\n path: \"/api/sfmc/db/tx/commit\",\n requireTxId: true,\n run: ({ txId }) => deps.txRunner!.commitSession(txId, moduleId) as SessionReply,\n },\n {\n path: \"/api/sfmc/db/tx/rollback\",\n requireTxId: true,\n run: ({ txId }) => deps.txRunner!.rollbackSession(txId, moduleId) as SessionReply,\n },\n ];\n for (const op of sessionOps) {\n if (path !== op.path) continue;\n try {\n const txId = String(body.txId || \"\");\n const step = body.step as TxStep | undefined;\n if (op.requireTxId && !txId) {\n jsonV2Fail(res, `${op.path.split(\"/\").pop()} \u9700\u8981 { txId }`, 400);\n return true;\n }\n if (op.requireStep && (!step || typeof step !== \"object\" || !(\"op\" in step))) {\n jsonV2Fail(res, \"tx/step \u9700\u8981 { txId, step }\", 400);\n return true;\n }\n const result = await op.run(step !== undefined ? { txId, step } : { txId });\n json(res, result as Record<string, unknown>, result.ok ? 200 : 400);\n } catch (e) {\n jsonV2Fail(res, (e as Error).message, 500);\n }\n return true;\n }\n\n type SingleOp = \"query\" | \"get\" | \"insert\" | \"update\" | \"delete\";\n const singles: { match: RegExp; op: SingleOp }[] = [\n { match: /^\\/api\\/sfmc\\/db\\/query$/, op: \"query\" },\n { match: /^\\/api\\/sfmc\\/db\\/get$/, op: \"get\" },\n { match: /^\\/api\\/sfmc\\/db\\/insert$/, op: \"insert\" },\n { match: /^\\/api\\/sfmc\\/db\\/update$/, op: \"update\" },\n { match: /^\\/api\\/sfmc\\/db\\/delete$/, op: \"delete\" },\n ];\n for (const cand of singles) {\n if (cand.match.test(path)) {\n try {\n const step = buildSingleStep(cand.op, body);\n const result = await deps.txRunner!.run({ moduleId, steps: [step] });\n if (!result.ok) {\n const code = result.code === \"permission_denied\" ? 403 : 400;\n jsonV2Fail(res, result.error, code, result.code, { step: result.step });\n return true;\n }\n const first = result.results[0];\n jsonV2Ok(res, unwrapResult(first, cand.op) as Record<string, unknown>);\n } catch (e) {\n if (e instanceof PermissionDeniedError) {\n jsonV2Fail(res, e.message, 403, \"permission_denied\");\n return true;\n }\n jsonV2Fail(res, (e as Error).message, 500);\n }\n return true;\n }\n }\n\n if (path === \"/api/sfmc/db/audit\") {\n try {\n const step: TxStep = {\n op: \"audit\",\n table: String(body.table),\n rowId: String(body.rowId),\n action: String(body.action),\n ...(body.data ? { data: body.data as Record<string, unknown> } : {}),\n };\n const result = await deps.txRunner!.run({ moduleId, steps: [step] });\n if (!result.ok) {\n jsonV2Fail(res, result.error, 400, result.code);\n return true;\n }\n jsonV2Ok(res);\n } catch (e) {\n jsonV2Fail(res, (e as Error).message, 500);\n }\n return true;\n }\n\n const m = path.match(/^\\/api\\/sfmc\\/db\\/idempotent\\/(probe|commit)$/);\n if (m) {\n try {\n if (m[1] === \"probe\") {\n const r = await deps.idempotent!.probe(\n moduleId,\n String(body.action),\n String(body.key)\n );\n json(res, r as unknown as Record<string, unknown>);\n } else {\n const r = await deps.idempotent!.commit(\n moduleId,\n String(body.action),\n String(body.key),\n body.value\n );\n jsonV2Ok(res, { committed: r.ok });\n }\n } catch (e) {\n jsonV2Fail(res, (e as Error).message, 500);\n }\n return true;\n }\n\n return false;\n };\n}\n\nfunction buildSingleStep(op: \"query\" | \"get\" | \"insert\" | \"update\" | \"delete\", body: Record<string, unknown>): TxStep {\n switch (op) {\n case \"query\":\n return {\n op: \"query\",\n table: String(body.table),\n ...(body.opts ? { opts: body.opts as Parameters<typeof JSON.parse>[0] } : {}),\n } as TxStep;\n case \"get\":\n return { op: \"get\", table: String(body.table), id: String(body.id) };\n case \"insert\":\n return {\n op: \"insert\",\n table: String(body.table),\n row: body.row as Record<string, unknown>,\n };\n case \"update\":\n return {\n op: \"update\",\n table: String(body.table),\n id: String(body.id),\n patch: body.patch as Record<string, unknown>,\n };\n case \"delete\":\n return {\n op: \"delete\",\n table: String(body.table),\n id: String(body.id),\n hard: Boolean(body.hard),\n };\n }\n}\n\ninterface UnwrappedRow {\n rows?: unknown[];\n row?: unknown;\n changes?: number;\n}\n\nfunction unwrapResult(r: unknown, op: string): UnwrappedRow {\n const step = r as { op: string; rows?: unknown[]; row?: unknown; changes?: number };\n switch (op) {\n case \"query\":\n return step.rows ? { rows: step.rows } : {};\n case \"get\":\n case \"insert\":\n case \"update\":\n return step.row !== undefined ? { row: step.row } : {};\n case \"delete\":\n return typeof step.changes === \"number\" ? { changes: step.changes } : {};\n default:\n return {};\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,23 +1,18 @@
1
- /**
2
- * routes/health.ts — 健康检查
3
- *
4
- * 路由列表:
5
- * GET /api/health — 返回 db-server 的运行状态
6
- */
7
1
  import { json } from "./_shared.js";
8
2
  function createHealthRoutes() {
9
- return async function handle({ path, method, res }) {
10
- if (path === "/api/health") {
11
- if (method === "GET") {
12
- json(res, { status: "ok", uptime: process.uptime() });
13
- }
14
- else {
15
- json(res, { success: false, error: "not_found" }, 404);
16
- }
17
- return true;
18
- }
19
- return false;
20
- };
3
+ return async function handle({ path, method, res }) {
4
+ if (path === "/api/health") {
5
+ if (method === "GET") {
6
+ json(res, { status: "ok", uptime: process.uptime() });
7
+ } else {
8
+ json(res, { success: false, error: "not_found" }, 404);
9
+ }
10
+ return true;
11
+ }
12
+ return false;
13
+ };
21
14
  }
22
- export { createHealthRoutes };
23
- //# sourceMappingURL=health.js.map
15
+ export {
16
+ createHealthRoutes
17
+ };
18
+ //# sourceMappingURL=health.js.map
@@ -1 +1,7 @@
1
- {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/routes/health.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAqB,MAAM,cAAc,CAAC;AAEvD,SAAS,kBAAkB;IACzB,OAAO,KAAK,UAAU,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;QAChD,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;YAC3B,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBACrB,IAAI,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YACxD,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/routes/health.ts"],
4
+ "sourcesContent": ["/**\n * routes/health.ts \u2014 \u5065\u5EB7\u68C0\u67E5\n *\n * \u8DEF\u7531\u5217\u8868\uFF1A\n * GET /api/health \u2014 \u8FD4\u56DE db-server \u7684\u8FD0\u884C\u72B6\u6001\n */\n\nimport { json, type RouteFactory } from \"./_shared.js\";\n\nfunction createHealthRoutes(): ReturnType<RouteFactory> {\n return async function handle({ path, method, res }): Promise<boolean> {\n if (path === \"/api/health\") {\n if (method === \"GET\") {\n json(res, { status: \"ok\", uptime: process.uptime() });\n } else {\n json(res, { success: false, error: \"not_found\" }, 404);\n }\n return true;\n }\n return false;\n };\n}\n\nexport { createHealthRoutes };\n"],
5
+ "mappings": "AAOA,SAAS,YAA+B;AAExC,SAAS,qBAA+C;AACtD,SAAO,eAAe,OAAO,EAAE,MAAM,QAAQ,IAAI,GAAqB;AACpE,QAAI,SAAS,eAAe;AAC1B,UAAI,WAAW,OAAO;AACpB,aAAK,KAAK,EAAE,QAAQ,MAAM,QAAQ,QAAQ,OAAO,EAAE,CAAC;AAAA,MACtD,OAAO;AACL,aAAK,KAAK,EAAE,SAAS,OAAO,OAAO,YAAY,GAAG,GAAG;AAAA,MACvD;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AACF;",
6
+ "names": []
7
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/routes/messages.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEhD,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,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACnG;AAED,iBAAS,oBAAoB,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE,IAAI,IAC7C,qCAM1B;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,CAqDrB;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAC"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/routes/messages.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEhD,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,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACnG;AAED,iBAAS,oBAAoB,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE,IAAI,yCAOvE;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,CAqDrB;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAC"}
@@ -1,72 +1,65 @@
1
- /**
2
- * routes/messages.ts — 聊天消息 (sfmc_chat_messages)
3
- *
4
- * 路由列表:
5
- * GET /api/sfmc/messages — 模糊/过滤查询消息
6
- * POST /api/sfmc/messages — 批量 INSERT OR REPLACE 消息(同时转发至 QQ Bridge)
7
- */
8
1
  import { SQL } from "sql-template-strings";
9
2
  function createMessagesRoutes({ query, body, json, forwardToQQBridge }) {
10
- return async function handle({ path, method, params, req, res, }) {
11
- if (path === "/api/sfmc/messages") {
12
- if (method === "GET") {
13
- const stmt = SQL `SELECT * FROM sfmc_chat_messages WHERE 1=1`;
14
- const search = params.get("search")?.trim();
15
- if (search)
16
- stmt.append(SQL ` AND (content LIKE ${`%${search}%`})`);
17
- const type = params.get("type")?.trim();
18
- if (type)
19
- stmt.append(SQL ` AND type = ${type}`);
20
- const channelId = params.get("channelId")?.trim();
21
- if (channelId)
22
- stmt.append(SQL ` AND channel_id = ${channelId}`);
23
- const from = params.get("from")?.trim();
24
- if (from)
25
- stmt.append(SQL ` AND from_id = ${from}`);
26
- const minCreatedAt = params.get("minCreatedAt")?.trim();
27
- if (minCreatedAt)
28
- stmt.append(SQL ` AND created_at >= ${Number(minCreatedAt)}`);
29
- const minSentAt = params.get("minSentAt")?.trim();
30
- if (minSentAt)
31
- stmt.append(SQL ` AND created_at >= ${Number(minSentAt)}`);
32
- const maxCreatedAt = params.get("maxCreatedAt")?.trim();
33
- if (maxCreatedAt)
34
- stmt.append(SQL ` AND created_at <= ${Number(maxCreatedAt)}`);
35
- stmt.append(SQL ` ORDER BY created_at ASC`);
36
- json(res, { messages: query(stmt) });
37
- }
38
- else if (method === "POST") {
39
- const { messages } = await body(req);
40
- if (!Array.isArray(messages) || messages.length === 0) {
41
- json(res, { success: false, error: "invalid" }, 400);
42
- return true;
43
- }
44
- if (messages.length > 100) {
45
- json(res, { success: false, error: "too many requests" }, 413);
46
- return true;
47
- }
48
- // 多行 INSERT 改成循环单条 INSERT OR REPLACE —— 简单优先
49
- for (const m of messages) {
50
- query(SQL `INSERT OR REPLACE INTO sfmc_chat_messages (
3
+ return async function handle({
4
+ path,
5
+ method,
6
+ params,
7
+ req,
8
+ res
9
+ }) {
10
+ if (path === "/api/sfmc/messages") {
11
+ if (method === "GET") {
12
+ const stmt = SQL`SELECT * FROM sfmc_chat_messages WHERE 1=1`;
13
+ const search = params.get("search")?.trim();
14
+ if (search) stmt.append(SQL` AND (content LIKE ${`%${search}%`})`);
15
+ const type = params.get("type")?.trim();
16
+ if (type) stmt.append(SQL` AND type = ${type}`);
17
+ const channelId = params.get("channelId")?.trim();
18
+ if (channelId) stmt.append(SQL` AND channel_id = ${channelId}`);
19
+ const from = params.get("from")?.trim();
20
+ if (from) stmt.append(SQL` AND from_id = ${from}`);
21
+ const minCreatedAt = params.get("minCreatedAt")?.trim();
22
+ if (minCreatedAt) stmt.append(SQL` AND created_at >= ${Number(minCreatedAt)}`);
23
+ const minSentAt = params.get("minSentAt")?.trim();
24
+ if (minSentAt) stmt.append(SQL` AND created_at >= ${Number(minSentAt)}`);
25
+ const maxCreatedAt = params.get("maxCreatedAt")?.trim();
26
+ if (maxCreatedAt) stmt.append(SQL` AND created_at <= ${Number(maxCreatedAt)}`);
27
+ stmt.append(SQL` ORDER BY created_at ASC`);
28
+ json(res, { messages: query(stmt) });
29
+ } else if (method === "POST") {
30
+ const { messages } = await body(req);
31
+ if (!Array.isArray(messages) || messages.length === 0) {
32
+ json(res, { success: false, error: "invalid" }, 400);
33
+ return true;
34
+ }
35
+ if (messages.length > 100) {
36
+ json(res, { success: false, error: "too many requests" }, 413);
37
+ return true;
38
+ }
39
+ for (const m of messages) {
40
+ query(
41
+ SQL`INSERT OR REPLACE INTO sfmc_chat_messages (
51
42
  id, channel_id, from_id, from_name, type, content, attachment, show_timestamp, created_at
52
43
  ) VALUES (
53
44
  ${m.id}, ${m.channelId}, ${m.fromid}, ${m.fromName},
54
45
  ${m.type ?? "text"}, ${m.content}, ${m.attachment ?? null},
55
46
  ${m.showTimestamp ? 1 : 0}, ${m.timestamp}
56
- )`);
57
- }
58
- for (const m of messages) {
59
- forwardToQQBridge(m.channelId, m.fromName, m.content, m.fromid);
60
- }
61
- json(res, { success: true });
62
- }
63
- else {
64
- json(res, { success: false, error: "not_found" }, 404);
65
- }
66
- return true;
47
+ )`
48
+ );
49
+ }
50
+ for (const m of messages) {
51
+ forwardToQQBridge(m.channelId, m.fromName, m.content, m.fromid);
67
52
  }
68
- return false;
69
- };
53
+ json(res, { success: true });
54
+ } else {
55
+ json(res, { success: false, error: "not_found" }, 404);
56
+ }
57
+ return true;
58
+ }
59
+ return false;
60
+ };
70
61
  }
71
- export { createMessagesRoutes };
72
- //# sourceMappingURL=messages.js.map
62
+ export {
63
+ createMessagesRoutes
64
+ };
65
+ //# sourceMappingURL=messages.js.map