@sfmc-bds/db-server 0.2.0-beta.1 → 0.2.0-beta.11
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/LICENSE +663 -0
- package/dist/domain/bridge.d.ts +57 -23
- package/dist/domain/bridge.d.ts.map +1 -1
- package/dist/domain/bridge.js +77 -6
- package/dist/domain/bridge.js.map +2 -2
- package/dist/domain/bridge.test.d.ts +2 -0
- package/dist/domain/bridge.test.d.ts.map +1 -0
- package/dist/domain/bridge.test.js +87 -0
- package/dist/domain/bridge.test.js.map +7 -0
- package/dist/domain/economy.d.ts +38 -7
- package/dist/domain/economy.d.ts.map +1 -1
- package/dist/domain/economy.js.map +2 -2
- package/dist/domain/messages-bridge-filter.test.d.ts +5 -0
- package/dist/domain/messages-bridge-filter.test.d.ts.map +1 -0
- package/dist/domain/messages-bridge-filter.test.js +20 -0
- package/dist/domain/messages-bridge-filter.test.js.map +7 -0
- package/dist/domain/player-session.d.ts +8 -0
- package/dist/domain/player-session.d.ts.map +1 -0
- package/dist/domain/player-session.js +16 -0
- package/dist/domain/player-session.js.map +7 -0
- package/dist/domain/player-session.test.d.ts +2 -0
- package/dist/domain/player-session.test.d.ts.map +1 -0
- package/dist/domain/player-session.test.js +33 -0
- package/dist/domain/player-session.test.js.map +7 -0
- package/dist/domain/qq-bind-status.test.d.ts +2 -0
- package/dist/domain/qq-bind-status.test.d.ts.map +1 -0
- package/dist/domain/qq-bind-status.test.js +211 -0
- package/dist/domain/qq-bind-status.test.js.map +7 -0
- package/dist/domain/qq-events.d.ts +84 -0
- package/dist/domain/qq-events.d.ts.map +1 -0
- package/dist/domain/qq-events.js +193 -0
- package/dist/domain/qq-events.js.map +7 -0
- package/dist/domain/qq-events.test.d.ts +5 -0
- package/dist/domain/qq-events.test.d.ts.map +1 -0
- package/dist/domain/qq-events.test.js +170 -0
- package/dist/domain/qq-events.test.js.map +7 -0
- package/dist/domain/qq-join.test.d.ts +2 -0
- package/dist/domain/qq-join.test.d.ts.map +1 -0
- package/dist/domain/qq-join.test.js +353 -0
- package/dist/domain/qq-join.test.js.map +7 -0
- package/dist/domain/schema.d.ts +15 -18
- package/dist/domain/schema.d.ts.map +1 -1
- package/dist/domain/schema.js +104 -453
- package/dist/domain/schema.js.map +2 -2
- package/dist/domain/system-status.d.ts +75 -0
- package/dist/domain/system-status.d.ts.map +1 -0
- package/dist/domain/system-status.js +181 -0
- package/dist/domain/system-status.js.map +7 -0
- package/dist/domain/system-status.test.d.ts +5 -0
- package/dist/domain/system-status.test.d.ts.map +1 -0
- package/dist/domain/system-status.test.js +19 -0
- package/dist/domain/system-status.test.js.map +7 -0
- package/dist/domain/transaction.d.ts +5 -4
- package/dist/domain/transaction.d.ts.map +1 -1
- package/dist/domain/transaction.js.map +2 -2
- package/dist/env.d.ts +7 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +57 -9
- package/dist/env.js.map +2 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +128 -38
- package/dist/index.js.map +2 -2
- package/dist/lib/idempotency-store.d.ts +17 -11
- package/dist/lib/idempotency-store.d.ts.map +1 -1
- package/dist/lib/idempotency-store.js.map +2 -2
- package/dist/lib/idempotency.d.ts +3 -4
- package/dist/lib/idempotency.d.ts.map +1 -1
- package/dist/lib/idempotency.js.map +2 -2
- package/dist/lib/log.d.ts.map +1 -1
- package/dist/lib/log.js +3 -6
- package/dist/lib/log.js.map +2 -2
- package/dist/lib/module-state.d.ts +38 -8
- package/dist/lib/module-state.d.ts.map +1 -1
- package/dist/lib/module-state.js.map +2 -2
- package/dist/lib/order-by.d.ts +8 -6
- package/dist/lib/order-by.d.ts.map +1 -1
- package/dist/lib/order-by.js.map +2 -2
- package/dist/lib/sql-helpers.d.ts +25 -13
- package/dist/lib/sql-helpers.d.ts.map +1 -1
- package/dist/lib/sql-helpers.js.map +2 -2
- package/dist/lib/sqlite.d.ts +14 -5
- package/dist/lib/sqlite.d.ts.map +1 -1
- package/dist/lib/sqlite.js.map +2 -2
- package/dist/manifest-loader.d.ts +5 -2
- package/dist/manifest-loader.d.ts.map +1 -1
- package/dist/manifest-loader.js +16 -6
- package/dist/manifest-loader.js.map +2 -2
- package/dist/manifest.d.ts +1 -2
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +13 -8
- package/dist/manifest.js.map +2 -2
- package/dist/module-auth.d.ts.map +1 -1
- package/dist/module-auth.js +2 -6
- package/dist/module-auth.js.map +2 -2
- package/dist/permission-gate.d.ts.map +1 -1
- package/dist/permission-gate.js +8 -2
- package/dist/permission-gate.js.map +2 -2
- package/dist/project-root.d.ts +6 -0
- package/dist/project-root.d.ts.map +1 -0
- package/dist/project-root.js +9 -0
- package/dist/project-root.js.map +7 -0
- package/dist/routes/_shared.d.ts +14 -5
- package/dist/routes/_shared.d.ts.map +1 -1
- package/dist/routes/_shared.js.map +2 -2
- package/dist/routes/config.d.ts +8 -11
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/config.js +17 -23
- package/dist/routes/config.js.map +2 -2
- package/dist/routes/db-routes.d.ts +8 -2
- package/dist/routes/db-routes.d.ts.map +1 -1
- package/dist/routes/db-routes.js +5 -12
- package/dist/routes/db-routes.js.map +2 -2
- package/dist/routes/messages.d.ts +6 -2
- package/dist/routes/messages.d.ts.map +1 -1
- package/dist/routes/messages.js +17 -3
- package/dist/routes/messages.js.map +2 -2
- package/dist/routes/module-config-routes.d.ts +13 -9
- package/dist/routes/module-config-routes.d.ts.map +1 -1
- package/dist/routes/module-config-routes.js.map +2 -2
- package/dist/routes/modules.d.ts +6 -0
- package/dist/routes/modules.d.ts.map +1 -1
- package/dist/routes/modules.js.map +2 -2
- package/dist/routes/qq-bind.d.ts +24 -0
- package/dist/routes/qq-bind.d.ts.map +1 -0
- package/dist/routes/qq-bind.js +179 -0
- package/dist/routes/qq-bind.js.map +7 -0
- package/dist/routes/qq-events.d.ts +20 -0
- package/dist/routes/qq-events.d.ts.map +1 -0
- package/dist/routes/qq-events.js +39 -0
- package/dist/routes/qq-events.js.map +7 -0
- package/dist/routes/qq-join.d.ts +46 -0
- package/dist/routes/qq-join.d.ts.map +1 -0
- package/dist/routes/qq-join.js +277 -0
- package/dist/routes/qq-join.js.map +7 -0
- package/dist/routes/service-routes.d.ts +6 -0
- package/dist/routes/service-routes.d.ts.map +1 -1
- package/dist/routes/service-routes.js.map +2 -2
- package/dist/routes/status.d.ts +19 -0
- package/dist/routes/status.d.ts.map +1 -0
- package/dist/routes/status.js +74 -0
- package/dist/routes/status.js.map +7 -0
- package/dist/runtime.test.js +216 -4
- package/dist/runtime.test.js.map +2 -2
- package/dist/schema-registry.d.ts +17 -16
- package/dist/schema-registry.d.ts.map +1 -1
- package/dist/schema-registry.js +76 -6
- package/dist/schema-registry.js.map +2 -2
- package/dist/server.d.ts +19 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js.map +2 -2
- package/dist/service-registry.d.ts +39 -9
- package/dist/service-registry.d.ts.map +1 -1
- package/dist/service-registry.js +30 -2
- package/dist/service-registry.js.map +2 -2
- package/dist/services/builtin-handlers.d.ts +27 -7
- package/dist/services/builtin-handlers.d.ts.map +1 -1
- package/dist/services/builtin-handlers.js.map +2 -2
- package/dist/tx-runner.d.ts +48 -9
- package/dist/tx-runner.d.ts.map +1 -1
- package/dist/tx-runner.js +99 -27
- package/dist/tx-runner.js.map +2 -2
- package/package.json +26 -24
package/dist/tx-runner.d.ts
CHANGED
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
* 实现:handler 返回 result 写回 step 输出;若 handler 还要写 db,应走其它接口在事务外做。
|
|
25
25
|
*/
|
|
26
26
|
import type { DatabaseSync } from "node:sqlite";
|
|
27
|
+
import type { ModuleManifestV2 } from "./manifest-loader.js";
|
|
27
28
|
import type { SchemaRegistry } from "./schema-registry.js";
|
|
28
|
-
import type { WhereExpr } from "./where.js";
|
|
29
29
|
import { type ServiceRegistry } from "./service-registry.js";
|
|
30
|
-
import type {
|
|
30
|
+
import type { WhereExpr } from "./where.js";
|
|
31
31
|
export interface TxStepQuery {
|
|
32
32
|
op: "query";
|
|
33
33
|
table: string;
|
|
@@ -112,12 +112,18 @@ export type TxError = {
|
|
|
112
112
|
ok: false;
|
|
113
113
|
step: number;
|
|
114
114
|
error: string;
|
|
115
|
-
code: "permission_denied" | "forbidden" | "no_such_service" | "not_in_requires" | "domain_error" | "internal" | "no_such_table";
|
|
115
|
+
code: "permission_denied" | "forbidden" | "no_such_service" | "not_in_requires" | "domain_error" | "transaction_busy" | "internal" | "no_such_table";
|
|
116
116
|
};
|
|
117
117
|
export interface TxRequest {
|
|
118
118
|
moduleId: string;
|
|
119
119
|
steps: TxStep[];
|
|
120
120
|
}
|
|
121
|
+
export interface TxRunnerOptions {
|
|
122
|
+
/** 等待全局 SQLite 事务槽的最长时间。 */
|
|
123
|
+
slotWaitTimeoutMs?: number;
|
|
124
|
+
/** 交互式事务两次请求之间允许空闲的最长时间。 */
|
|
125
|
+
sessionIdleTimeoutMs?: number;
|
|
126
|
+
}
|
|
121
127
|
export interface TxRunnerDeps {
|
|
122
128
|
db: DatabaseSync;
|
|
123
129
|
query: import("./lib/sqlite.js").QueryFn;
|
|
@@ -128,26 +134,59 @@ export interface TxRunnerDeps {
|
|
|
128
134
|
export declare class TxRunner {
|
|
129
135
|
private readonly deps;
|
|
130
136
|
private readonly sessions;
|
|
131
|
-
|
|
137
|
+
private transactionBusy;
|
|
138
|
+
private readonly transactionWaiters;
|
|
139
|
+
private readonly slotWaitTimeoutMs;
|
|
140
|
+
private readonly sessionIdleTimeoutMs;
|
|
141
|
+
constructor(deps: TxRunnerDeps, options?: TxRunnerOptions);
|
|
132
142
|
run(req: TxRequest): Promise<TxResponse | TxError>;
|
|
133
143
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
144
|
+
* 开启交互式事务会话(协议流程:begin → step* → commit | rollback)。
|
|
145
|
+
* 供客户端 `db.tx` 在回调内部异步执行并实时读回 query / get / call 的服务端执行结果。
|
|
146
|
+
* 单连接互斥保护:与批量 run() 共用事务队列,并在提交/回滚时唤醒下一个等待者。
|
|
147
|
+
*
|
|
148
|
+
* @param moduleId 请求模块唯一标识符。
|
|
149
|
+
* @returns 成功返回分配的会话 txId,失败返回错误响应。
|
|
137
150
|
*/
|
|
138
|
-
beginSession(moduleId: string): {
|
|
151
|
+
beginSession(moduleId: string): Promise<{
|
|
139
152
|
ok: true;
|
|
140
153
|
txId: string;
|
|
141
|
-
} | TxError
|
|
154
|
+
} | TxError>;
|
|
155
|
+
/**
|
|
156
|
+
* 在当前交互式事务会话中顺序执行单个步骤。
|
|
157
|
+
*
|
|
158
|
+
* @param txId 会话唯一标识符。
|
|
159
|
+
* @param moduleId 调用模块标识。
|
|
160
|
+
* @param step 待执行的操作步骤对象。
|
|
161
|
+
* @returns 步骤执行结果或错误响应。
|
|
162
|
+
*/
|
|
142
163
|
stepSession(txId: string, moduleId: string, step: TxStep): Promise<{
|
|
143
164
|
ok: true;
|
|
144
165
|
result: TxStepResult;
|
|
145
166
|
} | TxError>;
|
|
167
|
+
/**
|
|
168
|
+
* 提交当前交互式事务会话,将所有步骤的修改持久化并释放连接。
|
|
169
|
+
*
|
|
170
|
+
* @param txId 会话唯一标识符。
|
|
171
|
+
* @param moduleId 调用模块标识。
|
|
172
|
+
* @returns 提交结果响应。
|
|
173
|
+
*/
|
|
146
174
|
commitSession(txId: string, moduleId: string): TxResponse | TxError;
|
|
175
|
+
/**
|
|
176
|
+
* 回滚当前交互式事务会话,撤销所有未提交的数据库变更。
|
|
177
|
+
* 具有幂等性:会话已结束或已回滚时同样返回成功。
|
|
178
|
+
*
|
|
179
|
+
* @param txId 会话唯一标识符。
|
|
180
|
+
* @param moduleId 调用模块标识。
|
|
181
|
+
* @returns 回滚确认结果。
|
|
182
|
+
*/
|
|
147
183
|
rollbackSession(txId: string, moduleId: string): {
|
|
148
184
|
ok: true;
|
|
149
185
|
} | TxError;
|
|
150
186
|
private abortSession;
|
|
187
|
+
private acquireTransactionSlot;
|
|
188
|
+
private releaseTransactionSlot;
|
|
189
|
+
private createSessionIdleTimer;
|
|
151
190
|
private mapErrorCode;
|
|
152
191
|
private rollback;
|
|
153
192
|
/** 单 step 由对应权限检查 + SQL 路径执行 */
|
package/dist/tx-runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tx-runner.d.ts","sourceRoot":"","sources":["../src/tx-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"tx-runner.d.ts","sourceRoot":"","sources":["../src/tx-runner.ts"],"names":[],"mappings":"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"}
|
package/dist/tx-runner.js
CHANGED
|
@@ -1,32 +1,38 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { compile } from "./where.js";
|
|
3
2
|
import { log } from "./lib/log.js";
|
|
4
|
-
import { DispatchError } from "./service-registry.js";
|
|
5
|
-
import {
|
|
6
|
-
PermissionDeniedError,
|
|
7
|
-
Perm,
|
|
8
|
-
assertModulePermission
|
|
9
|
-
} from "./permission-gate.js";
|
|
10
3
|
import { normalizeOrderBy } from "./lib/order-by.js";
|
|
4
|
+
import { Perm, PermissionDeniedError, assertModulePermission } from "./permission-gate.js";
|
|
5
|
+
import { DispatchError } from "./service-registry.js";
|
|
6
|
+
import { compile } from "./where.js";
|
|
11
7
|
const IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
12
8
|
function identOk(t) {
|
|
13
9
|
if (!IDENT.test(t)) throw new Error(`[tx] invalid table name "${t}"`);
|
|
14
10
|
}
|
|
15
11
|
class TxRunner {
|
|
16
|
-
constructor(deps) {
|
|
12
|
+
constructor(deps, options = {}) {
|
|
17
13
|
this.deps = deps;
|
|
14
|
+
this.slotWaitTimeoutMs = options.slotWaitTimeoutMs ?? 2e3;
|
|
15
|
+
this.sessionIdleTimeoutMs = options.sessionIdleTimeoutMs ?? 15e3;
|
|
18
16
|
}
|
|
19
17
|
deps;
|
|
20
18
|
sessions = /* @__PURE__ */ new Map();
|
|
19
|
+
transactionBusy = false;
|
|
20
|
+
transactionWaiters = [];
|
|
21
|
+
slotWaitTimeoutMs;
|
|
22
|
+
sessionIdleTimeoutMs;
|
|
21
23
|
async run(req) {
|
|
22
24
|
const { moduleId, steps } = req;
|
|
23
25
|
const manifest = this.deps.enabled.get(moduleId);
|
|
24
26
|
if (!manifest) return { ok: false, step: -1, error: "\u6A21\u5757\u672A enabled", code: "forbidden" };
|
|
25
27
|
const traceId = randomUUID().slice(0, 8);
|
|
26
28
|
const results = [];
|
|
29
|
+
if (!await this.acquireTransactionSlot()) {
|
|
30
|
+
return { ok: false, step: -1, error: "\u4E8B\u52A1\u7E41\u5FD9\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5", code: "transaction_busy" };
|
|
31
|
+
}
|
|
27
32
|
try {
|
|
28
33
|
this.deps.db.exec("BEGIN IMMEDIATE");
|
|
29
34
|
} catch (e) {
|
|
35
|
+
this.releaseTransactionSlot();
|
|
30
36
|
return { ok: false, step: -1, error: `BEGIN \u5931\u8D25: ${e.message}`, code: "internal" };
|
|
31
37
|
}
|
|
32
38
|
for (let i = 0; i < steps.length; i++) {
|
|
@@ -36,6 +42,7 @@ class TxRunner {
|
|
|
36
42
|
results.push(r);
|
|
37
43
|
} catch (err) {
|
|
38
44
|
this.rollback();
|
|
45
|
+
this.releaseTransactionSlot();
|
|
39
46
|
const code = this.mapErrorCode(err);
|
|
40
47
|
log.warn(`[tx ${traceId}] step=${i} failed: ${err.message}`);
|
|
41
48
|
return { ok: false, step: i, error: err.message, code };
|
|
@@ -45,38 +52,50 @@ class TxRunner {
|
|
|
45
52
|
this.deps.db.exec("COMMIT");
|
|
46
53
|
} catch (e) {
|
|
47
54
|
this.rollback();
|
|
55
|
+
this.releaseTransactionSlot();
|
|
48
56
|
return { ok: false, step: -1, error: `COMMIT \u5931\u8D25: ${e.message}`, code: "internal" };
|
|
49
57
|
}
|
|
58
|
+
this.releaseTransactionSlot();
|
|
50
59
|
log.info(`[tx ${traceId}] module=${moduleId} ${steps.length} steps OK`);
|
|
51
60
|
return { ok: true, results };
|
|
52
61
|
}
|
|
53
62
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
63
|
+
* 开启交互式事务会话(协议流程:begin → step* → commit | rollback)。
|
|
64
|
+
* 供客户端 `db.tx` 在回调内部异步执行并实时读回 query / get / call 的服务端执行结果。
|
|
65
|
+
* 单连接互斥保护:与批量 run() 共用事务队列,并在提交/回滚时唤醒下一个等待者。
|
|
66
|
+
*
|
|
67
|
+
* @param moduleId 请求模块唯一标识符。
|
|
68
|
+
* @returns 成功返回分配的会话 txId,失败返回错误响应。
|
|
57
69
|
*/
|
|
58
|
-
beginSession(moduleId) {
|
|
70
|
+
async beginSession(moduleId) {
|
|
59
71
|
const manifest = this.deps.enabled.get(moduleId);
|
|
60
72
|
if (!manifest) return { ok: false, step: -1, error: "\u6A21\u5757\u672A enabled", code: "forbidden" };
|
|
61
|
-
if (this.
|
|
62
|
-
|
|
63
|
-
this.abortSession(id);
|
|
64
|
-
}
|
|
73
|
+
if (!await this.acquireTransactionSlot()) {
|
|
74
|
+
return { ok: false, step: -1, error: "\u4E8B\u52A1\u7E41\u5FD9\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5", code: "transaction_busy" };
|
|
65
75
|
}
|
|
66
76
|
try {
|
|
67
77
|
this.deps.db.exec("BEGIN IMMEDIATE");
|
|
68
78
|
} catch (e) {
|
|
79
|
+
this.releaseTransactionSlot();
|
|
69
80
|
return { ok: false, step: -1, error: `BEGIN \u5931\u8D25: ${e.message}`, code: "internal" };
|
|
70
81
|
}
|
|
71
82
|
const txId = randomUUID();
|
|
72
83
|
this.sessions.set(txId, {
|
|
73
84
|
moduleId,
|
|
74
85
|
results: [],
|
|
75
|
-
|
|
86
|
+
idleTimer: this.createSessionIdleTimer(txId, moduleId)
|
|
76
87
|
});
|
|
77
88
|
log.info(`[tx-session ${txId.slice(0, 8)}] begin module=${moduleId}`);
|
|
78
89
|
return { ok: true, txId };
|
|
79
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* 在当前交互式事务会话中顺序执行单个步骤。
|
|
93
|
+
*
|
|
94
|
+
* @param txId 会话唯一标识符。
|
|
95
|
+
* @param moduleId 调用模块标识。
|
|
96
|
+
* @param step 待执行的操作步骤对象。
|
|
97
|
+
* @returns 步骤执行结果或错误响应。
|
|
98
|
+
*/
|
|
80
99
|
async stepSession(txId, moduleId, step) {
|
|
81
100
|
const session = this.sessions.get(txId);
|
|
82
101
|
if (!session) {
|
|
@@ -85,6 +104,7 @@ class TxRunner {
|
|
|
85
104
|
if (session.moduleId !== moduleId) {
|
|
86
105
|
return { ok: false, step: session.results.length, error: "moduleId \u4E0E\u4F1A\u8BDD\u4E0D\u7B26", code: "forbidden" };
|
|
87
106
|
}
|
|
107
|
+
clearTimeout(session.idleTimer);
|
|
88
108
|
const manifest = this.deps.enabled.get(moduleId);
|
|
89
109
|
if (!manifest) {
|
|
90
110
|
this.abortSession(txId);
|
|
@@ -94,6 +114,7 @@ class TxRunner {
|
|
|
94
114
|
try {
|
|
95
115
|
const r = await this.runOne(moduleId, manifest, step);
|
|
96
116
|
session.results.push(r);
|
|
117
|
+
session.idleTimer = this.createSessionIdleTimer(txId, moduleId);
|
|
97
118
|
return { ok: true, result: r };
|
|
98
119
|
} catch (err) {
|
|
99
120
|
this.abortSession(txId);
|
|
@@ -102,6 +123,13 @@ class TxRunner {
|
|
|
102
123
|
return { ok: false, step: stepIndex, error: err.message, code };
|
|
103
124
|
}
|
|
104
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* 提交当前交互式事务会话,将所有步骤的修改持久化并释放连接。
|
|
128
|
+
*
|
|
129
|
+
* @param txId 会话唯一标识符。
|
|
130
|
+
* @param moduleId 调用模块标识。
|
|
131
|
+
* @returns 提交结果响应。
|
|
132
|
+
*/
|
|
105
133
|
commitSession(txId, moduleId) {
|
|
106
134
|
const session = this.sessions.get(txId);
|
|
107
135
|
if (!session) {
|
|
@@ -110,6 +138,7 @@ class TxRunner {
|
|
|
110
138
|
if (session.moduleId !== moduleId) {
|
|
111
139
|
return { ok: false, step: -1, error: "moduleId \u4E0E\u4F1A\u8BDD\u4E0D\u7B26", code: "forbidden" };
|
|
112
140
|
}
|
|
141
|
+
clearTimeout(session.idleTimer);
|
|
113
142
|
try {
|
|
114
143
|
this.deps.db.exec("COMMIT");
|
|
115
144
|
} catch (e) {
|
|
@@ -118,9 +147,18 @@ class TxRunner {
|
|
|
118
147
|
}
|
|
119
148
|
const results = session.results;
|
|
120
149
|
this.sessions.delete(txId);
|
|
150
|
+
this.releaseTransactionSlot();
|
|
121
151
|
log.info(`[tx-session ${txId.slice(0, 8)}] commit ${results.length} steps OK`);
|
|
122
152
|
return { ok: true, results };
|
|
123
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* 回滚当前交互式事务会话,撤销所有未提交的数据库变更。
|
|
156
|
+
* 具有幂等性:会话已结束或已回滚时同样返回成功。
|
|
157
|
+
*
|
|
158
|
+
* @param txId 会话唯一标识符。
|
|
159
|
+
* @param moduleId 调用模块标识。
|
|
160
|
+
* @returns 回滚确认结果。
|
|
161
|
+
*/
|
|
124
162
|
rollbackSession(txId, moduleId) {
|
|
125
163
|
const session = this.sessions.get(txId);
|
|
126
164
|
if (!session) {
|
|
@@ -133,10 +171,49 @@ class TxRunner {
|
|
|
133
171
|
return { ok: true };
|
|
134
172
|
}
|
|
135
173
|
abortSession(txId) {
|
|
174
|
+
const session = this.sessions.get(txId);
|
|
175
|
+
if (!session) return;
|
|
176
|
+
clearTimeout(session.idleTimer);
|
|
136
177
|
this.sessions.delete(txId);
|
|
137
178
|
this.rollback();
|
|
179
|
+
this.releaseTransactionSlot();
|
|
138
180
|
log.info(`[tx-session ${txId.slice(0, 8)}] aborted`);
|
|
139
181
|
}
|
|
182
|
+
async acquireTransactionSlot() {
|
|
183
|
+
if (!this.transactionBusy) {
|
|
184
|
+
this.transactionBusy = true;
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
return new Promise((resolve) => {
|
|
188
|
+
const waiter = {
|
|
189
|
+
resolve,
|
|
190
|
+
timer: setTimeout(() => {
|
|
191
|
+
const index = this.transactionWaiters.indexOf(waiter);
|
|
192
|
+
if (index >= 0) this.transactionWaiters.splice(index, 1);
|
|
193
|
+
resolve(false);
|
|
194
|
+
}, this.slotWaitTimeoutMs)
|
|
195
|
+
};
|
|
196
|
+
this.transactionWaiters.push(waiter);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
releaseTransactionSlot() {
|
|
200
|
+
const next = this.transactionWaiters.shift();
|
|
201
|
+
if (next) {
|
|
202
|
+
clearTimeout(next.timer);
|
|
203
|
+
next.resolve(true);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
this.transactionBusy = false;
|
|
207
|
+
}
|
|
208
|
+
createSessionIdleTimer(txId, moduleId) {
|
|
209
|
+
const timer = setTimeout(() => {
|
|
210
|
+
if (!this.sessions.has(txId)) return;
|
|
211
|
+
log.warn(`[tx-session ${txId.slice(0, 8)}] idle timeout module=${moduleId} after ${this.sessionIdleTimeoutMs}ms`);
|
|
212
|
+
this.abortSession(txId);
|
|
213
|
+
}, this.sessionIdleTimeoutMs);
|
|
214
|
+
timer.unref?.();
|
|
215
|
+
return timer;
|
|
216
|
+
}
|
|
140
217
|
mapErrorCode(err) {
|
|
141
218
|
return err instanceof PermissionDeniedError ? "permission_denied" : err instanceof DispatchError && (err.code === "no_such_service" || err.code === "not_in_requires" || err.code === "forbidden" || err.code === "domain_error") ? err.code : err.code === "no_such_service" ? "no_such_service" : err.code === "not_in_requires" ? "not_in_requires" : err.code === "no_such_table" ? "no_such_table" : "internal";
|
|
142
219
|
}
|
|
@@ -281,9 +358,7 @@ class TxRunner {
|
|
|
281
358
|
const cols = this.deps.db.prepare(`PRAGMA table_info("${step.table}")`).all();
|
|
282
359
|
const hasDeletedAt = cols.find((c) => c.name === "_deleted_at");
|
|
283
360
|
if (!hasDeletedAt) {
|
|
284
|
-
throw new Error(
|
|
285
|
-
`[tx] ${step.table} \u6CA1\u542F\u7528 softDelete,\u5220\u4E0D\u6389;\u8BF7 hard=true \u6216 schema \u8BBE softDelete=true`
|
|
286
|
-
);
|
|
361
|
+
throw new Error(`[tx] ${step.table} \u6CA1\u542F\u7528 softDelete,\u5220\u4E0D\u6389;\u8BF7 hard=true \u6216 schema \u8BBE softDelete=true`);
|
|
287
362
|
}
|
|
288
363
|
const sql = `UPDATE "${step.table}" SET "_deleted_at" = ?, "_version" = COALESCE("_version",0)+1 WHERE ${where.clause}`;
|
|
289
364
|
const r = this.deps.db.prepare(sql).run(Date.now(), ...where.values);
|
|
@@ -300,13 +375,10 @@ class TxRunner {
|
|
|
300
375
|
}
|
|
301
376
|
async doService(_mid, mod, step) {
|
|
302
377
|
assertModulePermission(mod.id, mod.permissions, Perm.service(step.name));
|
|
303
|
-
const result = await this.deps.serviceRegistry.dispatch(
|
|
304
|
-
this.deps.
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
step.input,
|
|
308
|
-
{ query: this.deps.query, db: this.deps.db }
|
|
309
|
-
);
|
|
378
|
+
const result = await this.deps.serviceRegistry.dispatch(this.deps.enabled, mod.id, step.name, step.input, {
|
|
379
|
+
query: this.deps.query,
|
|
380
|
+
db: this.deps.db
|
|
381
|
+
});
|
|
310
382
|
return { op: "service", result: result.result };
|
|
311
383
|
}
|
|
312
384
|
}
|
package/dist/tx-runner.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/tx-runner.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * tx-runner.ts \u2014 \u4E8B\u52A1 RPC \u5904\u7406\u5668\n *\n * \u534F\u8BAE(\u4E24\u79CD):\n * A. \u6279\u91CF: POST /api/sfmc/db/tx body={ steps } \u2192 { ok, results? } | { ok:false, step, error, code }\n * B. \u4EA4\u4E92: begin \u2192 step* \u2192 commit|rollback(SDK db.tx \u7528;\u56DE\u8C03\u5185\u53EF\u8BFB\u56DE query/get/call)\n *\n * \u6D41\u7A0B(\u6279\u91CF):\n * 1. \u6821\u9A8C moduleId in enabled\n * 2. BEGIN IMMEDIATE\n * 3. \u987A\u5E8F\u8DD1 steps \u2014 \u4EFB\u4E00\u629B\u9519 \u2192 ROLLBACK + reply { ok:false, step:<i>, ... }\n * 4. \u5168\u8FC7 \u2192 COMMIT + reply { ok:true, results }\n *\n * step.op:\n * - query { table, opts? }\n * - get { table, id }\n * - insert { table, row }\n * - update { table, id, patch }\n * - delete { table, id, hard }\n * - audit { table, rowId, action, data? } \u2192 \u5E73\u53F0 sfmc__audit \u8868\n * - service { name, input } \u2192 \u6D3E\u53D1;\u5931\u8D25\u629B\u9519\u56DE\u9000\u6574\u4E8B\u52A1\n *\n * \u4E8B\u52A1\u5185 service call:\u4E0D\u6301\u6709 db handle \u7ED9 handler(\u907F\u514D\u5E76\u53D1\u5199) \u2014\n * \u5B9E\u73B0:handler \u8FD4\u56DE result \u5199\u56DE step \u8F93\u51FA;\u82E5 handler \u8FD8\u8981\u5199 db,\u5E94\u8D70\u5176\u5B83\u63A5\u53E3\u5728\u4E8B\u52A1\u5916\u505A\u3002\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport type { DatabaseSync } from \"node:sqlite\";\nimport type { SchemaRegistry } from \"./schema-registry.js\";\nimport type { WhereExpr } from \"./where.js\";\nimport { compile } from \"./where.js\";\nimport { log } from \"./lib/log.js\";\nimport { DispatchError, type ServiceRegistry } from \"./service-registry.js\";\nimport type { ModuleManifestV2 } from \"./manifest-loader.js\";\nimport {\n PermissionDeniedError,\n Perm,\n assertModulePermission,\n} from \"./permission-gate.js\";\nimport { normalizeOrderBy } from \"./lib/order-by.js\";\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nfunction identOk(t: string): void {\n if (!IDENT.test(t)) throw new Error(`[tx] invalid table name \"${t}\"`);\n}\n\nexport interface TxStepQuery {\n op: \"query\";\n table: string;\n opts?: {\n where?: WhereExpr;\n /** SDK \u7528 field;\u5386\u53F2 col \u4ECD\u63A5\u53D7(normalizeOrderBy) */\n orderBy?:\n | { field?: string; col?: string; dir?: \"asc\" | \"desc\" }\n | Array<{ field?: string; col?: string; dir?: \"asc\" | \"desc\" }>;\n limit?: number;\n offset?: number;\n };\n}\n\nexport interface TxStepGet {\n op: \"get\";\n table: string;\n id: string;\n}\n\nexport interface TxStepInsert {\n op: \"insert\";\n table: string;\n row: Record<string, unknown>;\n}\n\nexport interface TxStepUpdate {\n op: \"update\";\n table: string;\n id: string;\n patch: Record<string, unknown>;\n}\n\nexport interface TxStepDelete {\n op: \"delete\";\n table: string;\n id: string;\n hard: boolean;\n}\n\nexport interface TxStepAudit {\n op: \"audit\";\n table: string;\n rowId: string;\n action: string;\n data?: Record<string, unknown>;\n}\n\nexport interface TxStepService {\n op: \"service\";\n name: string;\n input: Record<string, unknown>;\n}\n\nexport type TxStep =\n | TxStepQuery\n | TxStepGet\n | TxStepInsert\n | TxStepUpdate\n | TxStepDelete\n | TxStepAudit\n | TxStepService;\n\nexport type TxStepResult =\n | { op: \"query\"; rows: Record<string, unknown>[] }\n | { op: \"get\"; row: Record<string, unknown> | null }\n | { op: \"insert\"; row: Record<string, unknown> }\n | { op: \"update\"; row: Record<string, unknown> }\n | { op: \"delete\"; changes: number }\n | { op: \"audit\"; changes: number }\n | { op: \"service\"; result: unknown };\n\nexport interface TxResponse {\n ok: true;\n results: TxStepResult[];\n}\n\nexport type TxError = {\n ok: false;\n step: number;\n error: string;\n code:\n | \"permission_denied\"\n | \"forbidden\"\n | \"no_such_service\"\n | \"not_in_requires\"\n | \"domain_error\"\n | \"internal\"\n | \"no_such_table\";\n};\n\nexport interface TxRequest {\n moduleId: string;\n steps: TxStep[];\n}\n\ninterface TxSession {\n moduleId: string;\n results: TxStepResult[];\n openedAt: number;\n}\n\nexport interface TxRunnerDeps {\n db: DatabaseSync;\n query: import(\"./lib/sqlite.js\").QueryFn;\n schema: SchemaRegistry;\n serviceRegistry: ServiceRegistry;\n enabled: Map<string, ModuleManifestV2>;\n}\n\nexport class TxRunner {\n private readonly sessions = new Map<string, TxSession>();\n\n constructor(private readonly deps: TxRunnerDeps) {}\n\n async run(req: TxRequest): Promise<TxResponse | TxError> {\n const { moduleId, steps } = req;\n const manifest = this.deps.enabled.get(moduleId);\n if (!manifest) return { ok: false, step: -1, error: \"\u6A21\u5757\u672A enabled\", code: \"forbidden\" };\n // \u6CE8\u610F:\u4E0D\u5728\u6B64\u5904\u505A\u300C\u6574\u4F53 db:write:*\u300D\u65AD\u8A00\u3002\n // \u901A\u914D `db:write:*` \u65E0\u6CD5\u901A\u8FC7 permission-gate \u7684 validPermissionKey \u6821\u9A8C(\u6A21\u5757\u58F0\u660E\u5B83\u4F1A\u542F\u52A8\u5931\u8D25),\n // \u56E0\u6B64\u8BE5\u65AD\u8A00\u4F1A\u8BA9\u6240\u6709\u4E8B\u52A1(\u542B\u53EA\u8BFB\u4E8B\u52A1)\u6052\u88AB\u62D2\u3002\u771F\u6B63\u7684\u8BFB\u5199\u6743\u9650\u7531\u6BCF\u4E2A step \u7684\n // requireTableRead / requireTableWrite \u6309\u5177\u4F53\u8868\u7CBE\u786E gate\u3002\n\n const traceId = randomUUID().slice(0, 8);\n const results: TxStepResult[] = [];\n\n try {\n this.deps.db.exec(\"BEGIN IMMEDIATE\");\n } catch (e) {\n return { ok: false, step: -1, error: `BEGIN \u5931\u8D25: ${(e as Error).message}`, code: \"internal\" };\n }\n\n for (let i = 0; i < steps.length; i++) {\n const step: TxStep = steps[i]!;\n try {\n const r = await this.runOne(moduleId, manifest, step);\n results.push(r);\n } catch (err) {\n this.rollback();\n const code = this.mapErrorCode(err);\n log.warn(`[tx ${traceId}] step=${i} failed: ${(err as Error).message}`);\n return { ok: false, step: i, error: (err as Error).message, code };\n }\n }\n\n try {\n this.deps.db.exec(\"COMMIT\");\n } catch (e) {\n this.rollback();\n return { ok: false, step: -1, error: `COMMIT \u5931\u8D25: ${(e as Error).message}`, code: \"internal\" };\n }\n\n log.info(`[tx ${traceId}] module=${moduleId} ${steps.length} steps OK`);\n return { ok: true, results };\n }\n\n /**\n * \u4EA4\u4E92\u5F0F\u4E8B\u52A1:begin \u2192 step* \u2192 commit|rollback\u3002\n * \u4F9B SDK db.tx \u5728\u56DE\u8C03\u5185 await query/get/call \u771F\u5B9E\u7ED3\u679C(PR #31 \u672A\u5B8C\u6210\u9879)\u3002\n * \u5355\u8FDE\u63A5\u6A21\u578B:\u65B0\u4F1A\u8BDD\u4F1A\u5148\u6E05\u6389\u6B8B\u7559\u4F1A\u8BDD(\u907F\u514D BEGIN \u9501\u6B7B)\u3002\n */\n beginSession(moduleId: string): { ok: true; txId: string } | TxError {\n const manifest = this.deps.enabled.get(moduleId);\n if (!manifest) return { ok: false, step: -1, error: \"\u6A21\u5757\u672A enabled\", code: \"forbidden\" };\n // \u6E05\u6B8B\u7559\u4F1A\u8BDD(\u5D29\u6E83/\u672A commit),\u518D\u5F00\u65B0\u4E8B\u52A1\n if (this.sessions.size > 0) {\n for (const id of [...this.sessions.keys()]) {\n this.abortSession(id);\n }\n }\n try {\n this.deps.db.exec(\"BEGIN IMMEDIATE\");\n } catch (e) {\n return { ok: false, step: -1, error: `BEGIN \u5931\u8D25: ${(e as Error).message}`, code: \"internal\" };\n }\n const txId = randomUUID();\n this.sessions.set(txId, {\n moduleId,\n results: [],\n openedAt: Date.now(),\n });\n log.info(`[tx-session ${txId.slice(0, 8)}] begin module=${moduleId}`);\n return { ok: true, txId };\n }\n\n async stepSession(\n txId: string,\n moduleId: string,\n step: TxStep\n ): Promise<{ ok: true; result: TxStepResult } | TxError> {\n const session = this.sessions.get(txId);\n if (!session) {\n return { ok: false, step: -1, error: \"\u4E8B\u52A1\u4F1A\u8BDD\u4E0D\u5B58\u5728\u6216\u5DF2\u7ED3\u675F\", code: \"internal\" };\n }\n if (session.moduleId !== moduleId) {\n return { ok: false, step: session.results.length, error: \"moduleId \u4E0E\u4F1A\u8BDD\u4E0D\u7B26\", code: \"forbidden\" };\n }\n const manifest = this.deps.enabled.get(moduleId);\n if (!manifest) {\n this.abortSession(txId);\n return { ok: false, step: session.results.length, error: \"\u6A21\u5757\u672A enabled\", code: \"forbidden\" };\n }\n const stepIndex = session.results.length;\n try {\n const r = await this.runOne(moduleId, manifest, step);\n session.results.push(r);\n return { ok: true, result: r };\n } catch (err) {\n this.abortSession(txId);\n const code = this.mapErrorCode(err);\n log.warn(`[tx-session ${txId.slice(0, 8)}] step=${stepIndex} failed: ${(err as Error).message}`);\n return { ok: false, step: stepIndex, error: (err as Error).message, code };\n }\n }\n\n commitSession(txId: string, moduleId: string): TxResponse | TxError {\n const session = this.sessions.get(txId);\n if (!session) {\n return { ok: false, step: -1, error: \"\u4E8B\u52A1\u4F1A\u8BDD\u4E0D\u5B58\u5728\u6216\u5DF2\u7ED3\u675F\", code: \"internal\" };\n }\n if (session.moduleId !== moduleId) {\n return { ok: false, step: -1, error: \"moduleId \u4E0E\u4F1A\u8BDD\u4E0D\u7B26\", code: \"forbidden\" };\n }\n try {\n this.deps.db.exec(\"COMMIT\");\n } catch (e) {\n this.abortSession(txId);\n return { ok: false, step: -1, error: `COMMIT \u5931\u8D25: ${(e as Error).message}`, code: \"internal\" };\n }\n const results = session.results;\n this.sessions.delete(txId);\n log.info(`[tx-session ${txId.slice(0, 8)}] commit ${results.length} steps OK`);\n return { ok: true, results };\n }\n\n rollbackSession(txId: string, moduleId: string): { ok: true } | TxError {\n const session = this.sessions.get(txId);\n if (!session) {\n // \u5E42\u7B49:\u5DF2\u7ED3\u675F\u89C6\u4E3A\u6210\u529F\u56DE\u6EDA\n return { ok: true };\n }\n if (session.moduleId !== moduleId) {\n return { ok: false, step: -1, error: \"moduleId \u4E0E\u4F1A\u8BDD\u4E0D\u7B26\", code: \"forbidden\" };\n }\n this.abortSession(txId);\n return { ok: true };\n }\n\n private abortSession(txId: string): void {\n this.sessions.delete(txId);\n this.rollback();\n log.info(`[tx-session ${txId.slice(0, 8)}] aborted`);\n }\n\n private mapErrorCode(err: unknown): TxError[\"code\"] {\n return err instanceof PermissionDeniedError\n ? \"permission_denied\"\n : err instanceof DispatchError &&\n (err.code === \"no_such_service\" ||\n err.code === \"not_in_requires\" ||\n err.code === \"forbidden\" ||\n err.code === \"domain_error\")\n ? err.code\n : (err as { code?: string }).code === \"no_such_service\"\n ? \"no_such_service\"\n : (err as { code?: string }).code === \"not_in_requires\"\n ? \"not_in_requires\"\n : (err as { code?: string }).code === \"no_such_table\"\n ? \"no_such_table\"\n : \"internal\";\n }\n\n private rollback(): void {\n try {\n this.deps.db.exec(\"ROLLBACK\");\n } catch {\n // best-effort; fall through\n }\n }\n\n /** \u5355 step \u7531\u5BF9\u5E94\u6743\u9650\u68C0\u67E5 + SQL \u8DEF\u5F84\u6267\u884C */\n private async runOne(\n moduleId: string,\n manifest: ModuleManifestV2,\n step: TxStep\n ): Promise<TxStepResult> {\n switch (step.op) {\n case \"query\":\n return this.doQuery(moduleId, manifest, step);\n case \"get\":\n return this.doGet(moduleId, manifest, step);\n case \"insert\":\n return this.doInsert(moduleId, manifest, step);\n case \"update\":\n return this.doUpdate(moduleId, manifest, step);\n case \"delete\":\n return this.doDelete(moduleId, manifest, step);\n case \"audit\":\n return this.doAudit(moduleId, manifest, step);\n case \"service\":\n return this.doService(moduleId, manifest, step);\n }\n }\n\n private requireTableRead(mod: ModuleManifestV2, table: string): void {\n identOk(table);\n this.assertTableRegistered(table);\n assertModulePermission(mod.id, mod.permissions, Perm.dbRead(table));\n }\n private requireTableWrite(mod: ModuleManifestV2, table: string): void {\n identOk(table);\n this.assertTableRegistered(table);\n assertModulePermission(mod.id, mod.permissions, Perm.dbWrite(table));\n }\n private assertTableRegistered(table: string): void {\n if (table.startsWith(\"sfmc_\")) return; // \u5E73\u53F0\u8868 \u2014 \u59CB\u7EC8\u53EF\u8BFB\u5199(\u5E73\u53F0\u5C42)\n if (!this.deps.schema.isRegistered(table)) {\n const err = new Error(`\u8868 \"${table}\" \u672A\u6CE8\u518C\u5230 schema-registry`);\n (err as { code?: string }).code = \"no_such_table\";\n throw err;\n }\n }\n\n private doQuery(_mid: string, mod: ModuleManifestV2, step: TxStepQuery): TxStepResult {\n this.requireTableRead(mod, step.table);\n const where = compile(step.opts?.where);\n // LSP:\u4E0E SDK QueryOptions.orderBy({field}|[]) \u5BF9\u9F50,\u517C\u6536\u9057\u7559 {col}\n const orders = normalizeOrderBy(step.opts?.orderBy);\n const limit = typeof step.opts?.limit === \"number\" ? step.opts?.limit : undefined;\n const offset = typeof step.opts?.offset === \"number\" ? step.opts?.offset : undefined;\n\n const whereClause = where.sql;\n const params = [...where.values];\n let extra = \"\";\n if (orders.length > 0) {\n const parts: string[] = [];\n for (const o of orders) {\n if (!IDENT.test(o.col)) throw new Error(`[tx] orderBy bad column \"${o.col}\"`);\n parts.push(`\"${o.col}\" ${o.dir === \"desc\" ? \"DESC\" : \"ASC\"}`);\n }\n extra += ` ORDER BY ${parts.join(\", \")}`;\n }\n if (typeof limit === \"number\") {\n extra += \" LIMIT \" + Math.max(0, Math.floor(limit));\n }\n if (typeof offset === \"number\") {\n extra += \" OFFSET \" + Math.max(0, Math.floor(offset));\n }\n\n const sql = `SELECT * FROM \"${step.table}\" WHERE ${whereClause}${extra}`;\n const rows = this.deps.db.prepare(sql).all(...(params as never[])) as Record<string, unknown>[];\n return { op: \"query\", rows };\n }\n\n /** \u89E3\u6790\u4E3B\u952E WHERE\u3002\u5355\u5217\u76F4\u63A5\u7B49\u503C;\u8054\u5408\u4E3B\u952E\u652F\u6301 `a|b|c`(\u4E0E data-backup \u7EA6\u5B9A\u4E00\u81F4)\u3002 */\n private pkWhere(table: string, id: string | number): { clause: string; values: unknown[] } {\n const cols = this.deps.db.prepare(`PRAGMA table_info(\"${table}\")`).all() as Array<{\n name: string;\n pk: number;\n }>;\n const pkCols = cols\n .filter((c) => c.pk > 0)\n .sort((a, b) => a.pk - b.pk)\n .map((c) => c.name);\n if (pkCols.length === 0) {\n throw new Error(`[tx] ${table} \u6CA1\u6709 primary key`);\n }\n if (pkCols.length === 1) {\n return { clause: `\"${pkCols[0]}\" = ?`, values: [id] };\n }\n const parts = String(id).split(\"|\");\n if (parts.length === pkCols.length) {\n return {\n clause: pkCols.map((c) => `\"${c}\" = ?`).join(\" AND \"),\n values: parts,\n };\n }\n // \u8054\u5408\u4E3B\u952E\u4F46\u53EA\u4F20\u4E86\u9996\u5217(\u9891\u9053 id \u7B49):\u6309\u7B2C\u4E00\u4E3B\u952E\u5217\u5339\u914D\n return { clause: `\"${pkCols[0]}\" = ?`, values: [id] };\n }\n\n private doGet(_mid: string, mod: ModuleManifestV2, step: TxStepGet): TxStepResult {\n this.requireTableRead(mod, step.table);\n const where = this.pkWhere(step.table, step.id);\n const row = this.deps.db\n .prepare(`SELECT * FROM \"${step.table}\" WHERE ${where.clause}`)\n .get(...(where.values as never[])) as Record<string, unknown> | undefined;\n return { op: \"get\", row: row ?? null };\n }\n\n private doInsert(_mid: string, mod: ModuleManifestV2, step: TxStepInsert): TxStepResult {\n this.requireTableWrite(mod, step.table);\n const cols = Object.keys(step.row);\n if (cols.length === 0) throw new Error(\"[tx] insert row \u5FC5\u987B\u81F3\u5C11\u4E00\u4E2A\u5B57\u6BB5\");\n for (const c of cols) {\n if (!IDENT.test(c)) throw new Error(`[tx] invalid column name \"${c}\"`);\n }\n const placeholders = cols.map(() => \"?\").join(\",\");\n const quoted = cols.map((c) => `\"${c}\"`).join(\",\");\n const values = cols.map((c) => step.row[c]);\n const sql = `INSERT INTO \"${step.table}\" (${quoted}) VALUES (${placeholders})`;\n try {\n this.deps.db.prepare(sql).run(...(values as never[]));\n } catch (e) {\n throw new Error(`INSERT ${step.table} \u5931\u8D25: ${(e as Error).message}`);\n }\n return { op: \"insert\", row: { ...step.row } };\n }\n\n private doUpdate(_mid: string, mod: ModuleManifestV2, step: TxStepUpdate): TxStepResult {\n this.requireTableWrite(mod, step.table);\n const cols = Object.keys(step.patch);\n if (cols.length === 0) throw new Error(\"[tx] update patch \u4E0D\u80FD\u4E3A\u7A7A\");\n for (const c of cols) {\n if (!IDENT.test(c)) throw new Error(`[tx] invalid column name \"${c}\"`);\n }\n const where = this.pkWhere(step.table, step.id);\n const sets = cols.map((c) => `\"${c}\" = ?`).join(\",\");\n const params = [...cols.map((c) => step.patch[c]), ...where.values];\n const sql = `UPDATE \"${step.table}\" SET ${sets} WHERE ${where.clause}`;\n const result = this.deps.db.prepare(sql).run(...(params as never[]));\n if (result.changes === 0) {\n throw new Error(`UPDATE ${step.table} id=${step.id} \u5F71\u54CD 0 \u884C(\u627E\u4E0D\u5230 / \u5DF2\u5220?)`);\n }\n return { op: \"update\", row: { ...step.patch, id: step.id } as unknown as Record<string, unknown> };\n }\n\n private doDelete(_mid: string, mod: ModuleManifestV2, step: TxStepDelete): TxStepResult {\n this.requireTableWrite(mod, step.table);\n const where = this.pkWhere(step.table, step.id);\n if (step.hard) {\n const sql = `DELETE FROM \"${step.table}\" WHERE ${where.clause}`;\n const r = this.deps.db.prepare(sql).run(...(where.values as never[]));\n return { op: \"delete\", changes: Number(r.changes) };\n }\n const cols = this.deps.db.prepare(`PRAGMA table_info(\"${step.table}\")`).all() as Array<{\n name: string;\n }>;\n const hasDeletedAt = cols.find((c) => c.name === \"_deleted_at\");\n if (!hasDeletedAt) {\n throw new Error(\n `[tx] ${step.table} \u6CA1\u542F\u7528 softDelete,\u5220\u4E0D\u6389;\u8BF7 hard=true \u6216 schema \u8BBE softDelete=true`\n );\n }\n const sql = `UPDATE \"${step.table}\" SET \"_deleted_at\" = ?, \"_version\" = COALESCE(\"_version\",0)+1 WHERE ${where.clause}`;\n const r = this.deps.db.prepare(sql).run(Date.now() as never, ...(where.values as never[]));\n return { op: \"delete\", changes: Number(r.changes) };\n }\n\n private doAudit(_mid: string, mod: ModuleManifestV2, step: TxStepAudit): TxStepResult {\n this.requireTableWrite(mod, step.table);\n const dataJson = step.data ? JSON.stringify(step.data) : null;\n const r = this.deps.db\n .prepare(\n `INSERT INTO sfmc__audit (module_id, table_name, row_id, action, data, created_at)\n VALUES (?, ?, ?, ?, ?, ?)`\n )\n .run(mod.id, step.table, step.rowId, step.action, dataJson, new Date().toISOString());\n return { op: \"audit\", changes: Number(r.changes) };\n }\n\n private async doService(\n _mid: string,\n mod: ModuleManifestV2,\n step: TxStepService\n ): Promise<TxStepResult> {\n // requires / \u81EA\u8C03\u7528\u8C41\u514D\u7684\u552F\u4E00\u6743\u5A01\u5728 ServiceRegistry.dispatch(DRY/LSP);\n // \u6B64\u5904\u53EA\u8865 dispatch \u4E0D\u505A\u7684 service:<name> \u6743\u9650\u95E8(\u4E0E HTTP service-routes \u5BF9\u9F50)\u3002\n assertModulePermission(mod.id, mod.permissions, Perm.service(step.name));\n const result = await this.deps.serviceRegistry.dispatch(\n this.deps.enabled,\n mod.id,\n step.name,\n step.input,\n { query: this.deps.query, db: this.deps.db }\n );\n return { op: \"service\", result: result.result };\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * tx-runner.ts \u2014 \u4E8B\u52A1 RPC \u5904\u7406\u5668\n *\n * \u534F\u8BAE(\u4E24\u79CD):\n * A. \u6279\u91CF: POST /api/sfmc/db/tx body={ steps } \u2192 { ok, results? } | { ok:false, step, error, code }\n * B. \u4EA4\u4E92: begin \u2192 step* \u2192 commit|rollback(SDK db.tx \u7528;\u56DE\u8C03\u5185\u53EF\u8BFB\u56DE query/get/call)\n *\n * \u6D41\u7A0B(\u6279\u91CF):\n * 1. \u6821\u9A8C moduleId in enabled\n * 2. BEGIN IMMEDIATE\n * 3. \u987A\u5E8F\u8DD1 steps \u2014 \u4EFB\u4E00\u629B\u9519 \u2192 ROLLBACK + reply { ok:false, step:<i>, ... }\n * 4. \u5168\u8FC7 \u2192 COMMIT + reply { ok:true, results }\n *\n * step.op:\n * - query { table, opts? }\n * - get { table, id }\n * - insert { table, row }\n * - update { table, id, patch }\n * - delete { table, id, hard }\n * - audit { table, rowId, action, data? } \u2192 \u5E73\u53F0 sfmc__audit \u8868\n * - service { name, input } \u2192 \u6D3E\u53D1;\u5931\u8D25\u629B\u9519\u56DE\u9000\u6574\u4E8B\u52A1\n *\n * \u4E8B\u52A1\u5185 service call:\u4E0D\u6301\u6709 db handle \u7ED9 handler(\u907F\u514D\u5E76\u53D1\u5199) \u2014\n * \u5B9E\u73B0:handler \u8FD4\u56DE result \u5199\u56DE step \u8F93\u51FA;\u82E5 handler \u8FD8\u8981\u5199 db,\u5E94\u8D70\u5176\u5B83\u63A5\u53E3\u5728\u4E8B\u52A1\u5916\u505A\u3002\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport type { DatabaseSync } from \"node:sqlite\";\nimport { log } from \"./lib/log.js\";\nimport { normalizeOrderBy } from \"./lib/order-by.js\";\nimport type { ModuleManifestV2 } from \"./manifest-loader.js\";\nimport { Perm, PermissionDeniedError, assertModulePermission } from \"./permission-gate.js\";\nimport type { SchemaRegistry } from \"./schema-registry.js\";\nimport { DispatchError, type ServiceRegistry } from \"./service-registry.js\";\nimport type { WhereExpr } from \"./where.js\";\nimport { compile } from \"./where.js\";\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nfunction identOk(t: string): void {\n if (!IDENT.test(t)) throw new Error(`[tx] invalid table name \"${t}\"`);\n}\n\nexport interface TxStepQuery {\n op: \"query\";\n table: string;\n opts?: {\n where?: WhereExpr;\n /** SDK \u7528 field;\u5386\u53F2 col \u4ECD\u63A5\u53D7(normalizeOrderBy) */\n orderBy?:\n | { field?: string; col?: string; dir?: \"asc\" | \"desc\" }\n | Array<{ field?: string; col?: string; dir?: \"asc\" | \"desc\" }>;\n limit?: number;\n offset?: number;\n };\n}\n\nexport interface TxStepGet {\n op: \"get\";\n table: string;\n id: string;\n}\n\nexport interface TxStepInsert {\n op: \"insert\";\n table: string;\n row: Record<string, unknown>;\n}\n\nexport interface TxStepUpdate {\n op: \"update\";\n table: string;\n id: string;\n patch: Record<string, unknown>;\n}\n\nexport interface TxStepDelete {\n op: \"delete\";\n table: string;\n id: string;\n hard: boolean;\n}\n\nexport interface TxStepAudit {\n op: \"audit\";\n table: string;\n rowId: string;\n action: string;\n data?: Record<string, unknown>;\n}\n\nexport interface TxStepService {\n op: \"service\";\n name: string;\n input: Record<string, unknown>;\n}\n\nexport type TxStep = TxStepQuery | TxStepGet | TxStepInsert | TxStepUpdate | TxStepDelete | TxStepAudit | TxStepService;\n\nexport type TxStepResult =\n | { op: \"query\"; rows: Record<string, unknown>[] }\n | { op: \"get\"; row: Record<string, unknown> | null }\n | { op: \"insert\"; row: Record<string, unknown> }\n | { op: \"update\"; row: Record<string, unknown> }\n | { op: \"delete\"; changes: number }\n | { op: \"audit\"; changes: number }\n | { op: \"service\"; result: unknown };\n\nexport interface TxResponse {\n ok: true;\n results: TxStepResult[];\n}\n\nexport type TxError = {\n ok: false;\n step: number;\n error: string;\n code:\n | \"permission_denied\"\n | \"forbidden\"\n | \"no_such_service\"\n | \"not_in_requires\"\n | \"domain_error\"\n | \"transaction_busy\"\n | \"internal\"\n | \"no_such_table\";\n};\n\nexport interface TxRequest {\n moduleId: string;\n steps: TxStep[];\n}\n\ninterface TxSession {\n moduleId: string;\n results: TxStepResult[];\n idleTimer: ReturnType<typeof setTimeout>;\n}\n\ninterface TransactionWaiter {\n resolve: (acquired: boolean) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\nexport interface TxRunnerOptions {\n /** \u7B49\u5F85\u5168\u5C40 SQLite \u4E8B\u52A1\u69FD\u7684\u6700\u957F\u65F6\u95F4\u3002 */\n slotWaitTimeoutMs?: number;\n /** \u4EA4\u4E92\u5F0F\u4E8B\u52A1\u4E24\u6B21\u8BF7\u6C42\u4E4B\u95F4\u5141\u8BB8\u7A7A\u95F2\u7684\u6700\u957F\u65F6\u95F4\u3002 */\n sessionIdleTimeoutMs?: number;\n}\n\nexport interface TxRunnerDeps {\n db: DatabaseSync;\n query: import(\"./lib/sqlite.js\").QueryFn;\n schema: SchemaRegistry;\n serviceRegistry: ServiceRegistry;\n enabled: Map<string, ModuleManifestV2>;\n}\n\nexport class TxRunner {\n private readonly sessions = new Map<string, TxSession>();\n private transactionBusy = false;\n private readonly transactionWaiters: TransactionWaiter[] = [];\n private readonly slotWaitTimeoutMs: number;\n private readonly sessionIdleTimeoutMs: number;\n\n constructor(\n private readonly deps: TxRunnerDeps,\n options: TxRunnerOptions = {}\n ) {\n this.slotWaitTimeoutMs = options.slotWaitTimeoutMs ?? 2_000;\n this.sessionIdleTimeoutMs = options.sessionIdleTimeoutMs ?? 15_000;\n }\n\n async run(req: TxRequest): Promise<TxResponse | TxError> {\n const { moduleId, steps } = req;\n const manifest = this.deps.enabled.get(moduleId);\n if (!manifest) return { ok: false, step: -1, error: \"\u6A21\u5757\u672A enabled\", code: \"forbidden\" };\n // \u6CE8\u610F:\u4E0D\u5728\u6B64\u5904\u505A\u300C\u6574\u4F53 db:write:*\u300D\u65AD\u8A00\u3002\n // \u901A\u914D `db:write:*` \u65E0\u6CD5\u901A\u8FC7 permission-gate \u7684 validPermissionKey \u6821\u9A8C(\u6A21\u5757\u58F0\u660E\u5B83\u4F1A\u542F\u52A8\u5931\u8D25),\n // \u56E0\u6B64\u8BE5\u65AD\u8A00\u4F1A\u8BA9\u6240\u6709\u4E8B\u52A1(\u542B\u53EA\u8BFB\u4E8B\u52A1)\u6052\u88AB\u62D2\u3002\u771F\u6B63\u7684\u8BFB\u5199\u6743\u9650\u7531\u6BCF\u4E2A step \u7684\n // requireTableRead / requireTableWrite \u6309\u5177\u4F53\u8868\u7CBE\u786E gate\u3002\n\n const traceId = randomUUID().slice(0, 8);\n const results: TxStepResult[] = [];\n\n if (!(await this.acquireTransactionSlot())) {\n return { ok: false, step: -1, error: \"\u4E8B\u52A1\u7E41\u5FD9\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\", code: \"transaction_busy\" };\n }\n try {\n this.deps.db.exec(\"BEGIN IMMEDIATE\");\n } catch (e) {\n this.releaseTransactionSlot();\n return { ok: false, step: -1, error: `BEGIN \u5931\u8D25: ${(e as Error).message}`, code: \"internal\" };\n }\n\n for (let i = 0; i < steps.length; i++) {\n const step: TxStep = steps[i]!;\n try {\n const r = await this.runOne(moduleId, manifest, step);\n results.push(r);\n } catch (err) {\n this.rollback();\n this.releaseTransactionSlot();\n const code = this.mapErrorCode(err);\n log.warn(`[tx ${traceId}] step=${i} failed: ${(err as Error).message}`);\n return { ok: false, step: i, error: (err as Error).message, code };\n }\n }\n\n try {\n this.deps.db.exec(\"COMMIT\");\n } catch (e) {\n this.rollback();\n this.releaseTransactionSlot();\n return { ok: false, step: -1, error: `COMMIT \u5931\u8D25: ${(e as Error).message}`, code: \"internal\" };\n }\n\n this.releaseTransactionSlot();\n log.info(`[tx ${traceId}] module=${moduleId} ${steps.length} steps OK`);\n return { ok: true, results };\n }\n\n /**\n * \u5F00\u542F\u4EA4\u4E92\u5F0F\u4E8B\u52A1\u4F1A\u8BDD\uFF08\u534F\u8BAE\u6D41\u7A0B\uFF1Abegin \u2192 step* \u2192 commit | rollback\uFF09\u3002\n * \u4F9B\u5BA2\u6237\u7AEF `db.tx` \u5728\u56DE\u8C03\u5185\u90E8\u5F02\u6B65\u6267\u884C\u5E76\u5B9E\u65F6\u8BFB\u56DE query / get / call \u7684\u670D\u52A1\u7AEF\u6267\u884C\u7ED3\u679C\u3002\n * \u5355\u8FDE\u63A5\u4E92\u65A5\u4FDD\u62A4\uFF1A\u4E0E\u6279\u91CF run() \u5171\u7528\u4E8B\u52A1\u961F\u5217\uFF0C\u5E76\u5728\u63D0\u4EA4/\u56DE\u6EDA\u65F6\u5524\u9192\u4E0B\u4E00\u4E2A\u7B49\u5F85\u8005\u3002\n *\n * @param moduleId \u8BF7\u6C42\u6A21\u5757\u552F\u4E00\u6807\u8BC6\u7B26\u3002\n * @returns \u6210\u529F\u8FD4\u56DE\u5206\u914D\u7684\u4F1A\u8BDD txId\uFF0C\u5931\u8D25\u8FD4\u56DE\u9519\u8BEF\u54CD\u5E94\u3002\n */\n async beginSession(moduleId: string): Promise<{ ok: true; txId: string } | TxError> {\n const manifest = this.deps.enabled.get(moduleId);\n if (!manifest) return { ok: false, step: -1, error: \"\u6A21\u5757\u672A enabled\", code: \"forbidden\" };\n\n // run() \u4E0E\u4EA4\u4E92\u5F0F\u4F1A\u8BDD\u5171\u7528\u540C\u4E00 SQLite \u8FDE\u63A5\uFF0C\u5FC5\u987B\u5171\u7528\u540C\u4E00\u4E2A\u4E8B\u52A1\u69FD\u3002\n if (!(await this.acquireTransactionSlot())) {\n return { ok: false, step: -1, error: \"\u4E8B\u52A1\u7E41\u5FD9\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\", code: \"transaction_busy\" };\n }\n\n try {\n this.deps.db.exec(\"BEGIN IMMEDIATE\");\n } catch (e) {\n this.releaseTransactionSlot();\n return { ok: false, step: -1, error: `BEGIN \u5931\u8D25: ${(e as Error).message}`, code: \"internal\" };\n }\n const txId = randomUUID();\n this.sessions.set(txId, {\n moduleId,\n results: [],\n idleTimer: this.createSessionIdleTimer(txId, moduleId),\n });\n log.info(`[tx-session ${txId.slice(0, 8)}] begin module=${moduleId}`);\n return { ok: true, txId };\n }\n\n /**\n * \u5728\u5F53\u524D\u4EA4\u4E92\u5F0F\u4E8B\u52A1\u4F1A\u8BDD\u4E2D\u987A\u5E8F\u6267\u884C\u5355\u4E2A\u6B65\u9AA4\u3002\n *\n * @param txId \u4F1A\u8BDD\u552F\u4E00\u6807\u8BC6\u7B26\u3002\n * @param moduleId \u8C03\u7528\u6A21\u5757\u6807\u8BC6\u3002\n * @param step \u5F85\u6267\u884C\u7684\u64CD\u4F5C\u6B65\u9AA4\u5BF9\u8C61\u3002\n * @returns \u6B65\u9AA4\u6267\u884C\u7ED3\u679C\u6216\u9519\u8BEF\u54CD\u5E94\u3002\n */\n async stepSession(\n txId: string,\n moduleId: string,\n step: TxStep\n ): Promise<{ ok: true; result: TxStepResult } | TxError> {\n const session = this.sessions.get(txId);\n if (!session) {\n return { ok: false, step: -1, error: \"\u4E8B\u52A1\u4F1A\u8BDD\u4E0D\u5B58\u5728\u6216\u5DF2\u7ED3\u675F\", code: \"internal\" };\n }\n if (session.moduleId !== moduleId) {\n return { ok: false, step: session.results.length, error: \"moduleId \u4E0E\u4F1A\u8BDD\u4E0D\u7B26\", code: \"forbidden\" };\n }\n clearTimeout(session.idleTimer);\n const manifest = this.deps.enabled.get(moduleId);\n if (!manifest) {\n this.abortSession(txId);\n return { ok: false, step: session.results.length, error: \"\u6A21\u5757\u672A enabled\", code: \"forbidden\" };\n }\n const stepIndex = session.results.length;\n try {\n const r = await this.runOne(moduleId, manifest, step);\n session.results.push(r);\n session.idleTimer = this.createSessionIdleTimer(txId, moduleId);\n return { ok: true, result: r };\n } catch (err) {\n this.abortSession(txId);\n const code = this.mapErrorCode(err);\n log.warn(`[tx-session ${txId.slice(0, 8)}] step=${stepIndex} failed: ${(err as Error).message}`);\n return { ok: false, step: stepIndex, error: (err as Error).message, code };\n }\n }\n\n /**\n * \u63D0\u4EA4\u5F53\u524D\u4EA4\u4E92\u5F0F\u4E8B\u52A1\u4F1A\u8BDD\uFF0C\u5C06\u6240\u6709\u6B65\u9AA4\u7684\u4FEE\u6539\u6301\u4E45\u5316\u5E76\u91CA\u653E\u8FDE\u63A5\u3002\n *\n * @param txId \u4F1A\u8BDD\u552F\u4E00\u6807\u8BC6\u7B26\u3002\n * @param moduleId \u8C03\u7528\u6A21\u5757\u6807\u8BC6\u3002\n * @returns \u63D0\u4EA4\u7ED3\u679C\u54CD\u5E94\u3002\n */\n commitSession(txId: string, moduleId: string): TxResponse | TxError {\n const session = this.sessions.get(txId);\n if (!session) {\n return { ok: false, step: -1, error: \"\u4E8B\u52A1\u4F1A\u8BDD\u4E0D\u5B58\u5728\u6216\u5DF2\u7ED3\u675F\", code: \"internal\" };\n }\n if (session.moduleId !== moduleId) {\n return { ok: false, step: -1, error: \"moduleId \u4E0E\u4F1A\u8BDD\u4E0D\u7B26\", code: \"forbidden\" };\n }\n clearTimeout(session.idleTimer);\n try {\n this.deps.db.exec(\"COMMIT\");\n } catch (e) {\n this.abortSession(txId);\n return { ok: false, step: -1, error: `COMMIT \u5931\u8D25: ${(e as Error).message}`, code: \"internal\" };\n }\n const results = session.results;\n this.sessions.delete(txId);\n this.releaseTransactionSlot();\n log.info(`[tx-session ${txId.slice(0, 8)}] commit ${results.length} steps OK`);\n return { ok: true, results };\n }\n\n /**\n * \u56DE\u6EDA\u5F53\u524D\u4EA4\u4E92\u5F0F\u4E8B\u52A1\u4F1A\u8BDD\uFF0C\u64A4\u9500\u6240\u6709\u672A\u63D0\u4EA4\u7684\u6570\u636E\u5E93\u53D8\u66F4\u3002\n * \u5177\u6709\u5E42\u7B49\u6027\uFF1A\u4F1A\u8BDD\u5DF2\u7ED3\u675F\u6216\u5DF2\u56DE\u6EDA\u65F6\u540C\u6837\u8FD4\u56DE\u6210\u529F\u3002\n *\n * @param txId \u4F1A\u8BDD\u552F\u4E00\u6807\u8BC6\u7B26\u3002\n * @param moduleId \u8C03\u7528\u6A21\u5757\u6807\u8BC6\u3002\n * @returns \u56DE\u6EDA\u786E\u8BA4\u7ED3\u679C\u3002\n */\n rollbackSession(txId: string, moduleId: string): { ok: true } | TxError {\n const session = this.sessions.get(txId);\n if (!session) {\n // \u5E42\u7B49\uFF1A\u5DF2\u7ED3\u675F\u89C6\u4E3A\u6210\u529F\u56DE\u6EDA\n return { ok: true };\n }\n if (session.moduleId !== moduleId) {\n return { ok: false, step: -1, error: \"moduleId \u4E0E\u4F1A\u8BDD\u4E0D\u7B26\", code: \"forbidden\" };\n }\n this.abortSession(txId);\n return { ok: true };\n }\n\n private abortSession(txId: string): void {\n const session = this.sessions.get(txId);\n if (!session) return;\n clearTimeout(session.idleTimer);\n this.sessions.delete(txId);\n this.rollback();\n this.releaseTransactionSlot();\n log.info(`[tx-session ${txId.slice(0, 8)}] aborted`);\n }\n\n private async acquireTransactionSlot(): Promise<boolean> {\n if (!this.transactionBusy) {\n this.transactionBusy = true;\n return true;\n }\n return new Promise<boolean>((resolve) => {\n const waiter: TransactionWaiter = {\n resolve,\n timer: setTimeout(() => {\n const index = this.transactionWaiters.indexOf(waiter);\n if (index >= 0) this.transactionWaiters.splice(index, 1);\n resolve(false);\n }, this.slotWaitTimeoutMs),\n };\n this.transactionWaiters.push(waiter);\n });\n }\n\n private releaseTransactionSlot(): void {\n const next = this.transactionWaiters.shift();\n if (next) {\n clearTimeout(next.timer);\n next.resolve(true);\n return;\n }\n this.transactionBusy = false;\n }\n\n private createSessionIdleTimer(txId: string, moduleId: string): ReturnType<typeof setTimeout> {\n const timer = setTimeout(() => {\n if (!this.sessions.has(txId)) return;\n log.warn(`[tx-session ${txId.slice(0, 8)}] idle timeout module=${moduleId} after ${this.sessionIdleTimeoutMs}ms`);\n this.abortSession(txId);\n }, this.sessionIdleTimeoutMs);\n timer.unref?.();\n return timer;\n }\n\n private mapErrorCode(err: unknown): TxError[\"code\"] {\n return err instanceof PermissionDeniedError\n ? \"permission_denied\"\n : err instanceof DispatchError &&\n (err.code === \"no_such_service\" ||\n err.code === \"not_in_requires\" ||\n err.code === \"forbidden\" ||\n err.code === \"domain_error\")\n ? err.code\n : (err as { code?: string }).code === \"no_such_service\"\n ? \"no_such_service\"\n : (err as { code?: string }).code === \"not_in_requires\"\n ? \"not_in_requires\"\n : (err as { code?: string }).code === \"no_such_table\"\n ? \"no_such_table\"\n : \"internal\";\n }\n\n private rollback(): void {\n try {\n this.deps.db.exec(\"ROLLBACK\");\n } catch {\n // best-effort; fall through\n }\n }\n\n /** \u5355 step \u7531\u5BF9\u5E94\u6743\u9650\u68C0\u67E5 + SQL \u8DEF\u5F84\u6267\u884C */\n private async runOne(moduleId: string, manifest: ModuleManifestV2, step: TxStep): Promise<TxStepResult> {\n switch (step.op) {\n case \"query\":\n return this.doQuery(moduleId, manifest, step);\n case \"get\":\n return this.doGet(moduleId, manifest, step);\n case \"insert\":\n return this.doInsert(moduleId, manifest, step);\n case \"update\":\n return this.doUpdate(moduleId, manifest, step);\n case \"delete\":\n return this.doDelete(moduleId, manifest, step);\n case \"audit\":\n return this.doAudit(moduleId, manifest, step);\n case \"service\":\n return this.doService(moduleId, manifest, step);\n }\n }\n\n private requireTableRead(mod: ModuleManifestV2, table: string): void {\n identOk(table);\n this.assertTableRegistered(table);\n assertModulePermission(mod.id, mod.permissions, Perm.dbRead(table));\n }\n private requireTableWrite(mod: ModuleManifestV2, table: string): void {\n identOk(table);\n this.assertTableRegistered(table);\n assertModulePermission(mod.id, mod.permissions, Perm.dbWrite(table));\n }\n private assertTableRegistered(table: string): void {\n if (table.startsWith(\"sfmc_\")) return; // \u5E73\u53F0\u8868 \u2014 \u59CB\u7EC8\u53EF\u8BFB\u5199(\u5E73\u53F0\u5C42)\n if (!this.deps.schema.isRegistered(table)) {\n const err = new Error(`\u8868 \"${table}\" \u672A\u6CE8\u518C\u5230 schema-registry`);\n (err as { code?: string }).code = \"no_such_table\";\n throw err;\n }\n }\n\n private doQuery(_mid: string, mod: ModuleManifestV2, step: TxStepQuery): TxStepResult {\n this.requireTableRead(mod, step.table);\n const where = compile(step.opts?.where);\n // LSP:\u4E0E SDK QueryOptions.orderBy({field}|[]) \u5BF9\u9F50,\u517C\u6536\u9057\u7559 {col}\n const orders = normalizeOrderBy(step.opts?.orderBy);\n const limit = typeof step.opts?.limit === \"number\" ? step.opts?.limit : undefined;\n const offset = typeof step.opts?.offset === \"number\" ? step.opts?.offset : undefined;\n\n const whereClause = where.sql;\n const params = [...where.values];\n let extra = \"\";\n if (orders.length > 0) {\n const parts: string[] = [];\n for (const o of orders) {\n if (!IDENT.test(o.col)) throw new Error(`[tx] orderBy bad column \"${o.col}\"`);\n parts.push(`\"${o.col}\" ${o.dir === \"desc\" ? \"DESC\" : \"ASC\"}`);\n }\n extra += ` ORDER BY ${parts.join(\", \")}`;\n }\n if (typeof limit === \"number\") {\n extra += \" LIMIT \" + Math.max(0, Math.floor(limit));\n }\n if (typeof offset === \"number\") {\n extra += \" OFFSET \" + Math.max(0, Math.floor(offset));\n }\n\n const sql = `SELECT * FROM \"${step.table}\" WHERE ${whereClause}${extra}`;\n const rows = this.deps.db.prepare(sql).all(...(params as never[])) as Record<string, unknown>[];\n return { op: \"query\", rows };\n }\n\n /** \u89E3\u6790\u4E3B\u952E WHERE\u3002\u5355\u5217\u76F4\u63A5\u7B49\u503C;\u8054\u5408\u4E3B\u952E\u652F\u6301 `a|b|c`(\u4E0E data-backup \u7EA6\u5B9A\u4E00\u81F4)\u3002 */\n private pkWhere(table: string, id: string | number): { clause: string; values: unknown[] } {\n const cols = this.deps.db.prepare(`PRAGMA table_info(\"${table}\")`).all() as Array<{\n name: string;\n pk: number;\n }>;\n const pkCols = cols\n .filter((c) => c.pk > 0)\n .sort((a, b) => a.pk - b.pk)\n .map((c) => c.name);\n if (pkCols.length === 0) {\n throw new Error(`[tx] ${table} \u6CA1\u6709 primary key`);\n }\n if (pkCols.length === 1) {\n return { clause: `\"${pkCols[0]}\" = ?`, values: [id] };\n }\n const parts = String(id).split(\"|\");\n if (parts.length === pkCols.length) {\n return {\n clause: pkCols.map((c) => `\"${c}\" = ?`).join(\" AND \"),\n values: parts,\n };\n }\n // \u8054\u5408\u4E3B\u952E\u4F46\u53EA\u4F20\u4E86\u9996\u5217(\u9891\u9053 id \u7B49):\u6309\u7B2C\u4E00\u4E3B\u952E\u5217\u5339\u914D\n return { clause: `\"${pkCols[0]}\" = ?`, values: [id] };\n }\n\n private doGet(_mid: string, mod: ModuleManifestV2, step: TxStepGet): TxStepResult {\n this.requireTableRead(mod, step.table);\n const where = this.pkWhere(step.table, step.id);\n const row = this.deps.db\n .prepare(`SELECT * FROM \"${step.table}\" WHERE ${where.clause}`)\n .get(...(where.values as never[])) as Record<string, unknown> | undefined;\n return { op: \"get\", row: row ?? null };\n }\n\n private doInsert(_mid: string, mod: ModuleManifestV2, step: TxStepInsert): TxStepResult {\n this.requireTableWrite(mod, step.table);\n const cols = Object.keys(step.row);\n if (cols.length === 0) throw new Error(\"[tx] insert row \u5FC5\u987B\u81F3\u5C11\u4E00\u4E2A\u5B57\u6BB5\");\n for (const c of cols) {\n if (!IDENT.test(c)) throw new Error(`[tx] invalid column name \"${c}\"`);\n }\n const placeholders = cols.map(() => \"?\").join(\",\");\n const quoted = cols.map((c) => `\"${c}\"`).join(\",\");\n const values = cols.map((c) => step.row[c]);\n const sql = `INSERT INTO \"${step.table}\" (${quoted}) VALUES (${placeholders})`;\n try {\n this.deps.db.prepare(sql).run(...(values as never[]));\n } catch (e) {\n throw new Error(`INSERT ${step.table} \u5931\u8D25: ${(e as Error).message}`);\n }\n return { op: \"insert\", row: { ...step.row } };\n }\n\n private doUpdate(_mid: string, mod: ModuleManifestV2, step: TxStepUpdate): TxStepResult {\n this.requireTableWrite(mod, step.table);\n const cols = Object.keys(step.patch);\n if (cols.length === 0) throw new Error(\"[tx] update patch \u4E0D\u80FD\u4E3A\u7A7A\");\n for (const c of cols) {\n if (!IDENT.test(c)) throw new Error(`[tx] invalid column name \"${c}\"`);\n }\n const where = this.pkWhere(step.table, step.id);\n const sets = cols.map((c) => `\"${c}\" = ?`).join(\",\");\n const params = [...cols.map((c) => step.patch[c]), ...where.values];\n const sql = `UPDATE \"${step.table}\" SET ${sets} WHERE ${where.clause}`;\n const result = this.deps.db.prepare(sql).run(...(params as never[]));\n if (result.changes === 0) {\n throw new Error(`UPDATE ${step.table} id=${step.id} \u5F71\u54CD 0 \u884C(\u627E\u4E0D\u5230 / \u5DF2\u5220?)`);\n }\n return { op: \"update\", row: { ...step.patch, id: step.id } as unknown as Record<string, unknown> };\n }\n\n private doDelete(_mid: string, mod: ModuleManifestV2, step: TxStepDelete): TxStepResult {\n this.requireTableWrite(mod, step.table);\n const where = this.pkWhere(step.table, step.id);\n if (step.hard) {\n const sql = `DELETE FROM \"${step.table}\" WHERE ${where.clause}`;\n const r = this.deps.db.prepare(sql).run(...(where.values as never[]));\n return { op: \"delete\", changes: Number(r.changes) };\n }\n const cols = this.deps.db.prepare(`PRAGMA table_info(\"${step.table}\")`).all() as Array<{\n name: string;\n }>;\n const hasDeletedAt = cols.find((c) => c.name === \"_deleted_at\");\n if (!hasDeletedAt) {\n throw new Error(`[tx] ${step.table} \u6CA1\u542F\u7528 softDelete,\u5220\u4E0D\u6389;\u8BF7 hard=true \u6216 schema \u8BBE softDelete=true`);\n }\n const sql = `UPDATE \"${step.table}\" SET \"_deleted_at\" = ?, \"_version\" = COALESCE(\"_version\",0)+1 WHERE ${where.clause}`;\n const r = this.deps.db.prepare(sql).run(Date.now() as never, ...(where.values as never[]));\n return { op: \"delete\", changes: Number(r.changes) };\n }\n\n private doAudit(_mid: string, mod: ModuleManifestV2, step: TxStepAudit): TxStepResult {\n this.requireTableWrite(mod, step.table);\n const dataJson = step.data ? JSON.stringify(step.data) : null;\n const r = this.deps.db\n .prepare(\n `INSERT INTO sfmc__audit (module_id, table_name, row_id, action, data, created_at)\n VALUES (?, ?, ?, ?, ?, ?)`\n )\n .run(mod.id, step.table, step.rowId, step.action, dataJson, new Date().toISOString());\n return { op: \"audit\", changes: Number(r.changes) };\n }\n\n private async doService(_mid: string, mod: ModuleManifestV2, step: TxStepService): Promise<TxStepResult> {\n // requires / \u81EA\u8C03\u7528\u8C41\u514D\u7684\u552F\u4E00\u6743\u5A01\u5728 ServiceRegistry.dispatch(DRY/LSP);\n // \u6B64\u5904\u53EA\u8865 dispatch \u4E0D\u505A\u7684 service:<name> \u6743\u9650\u95E8(\u4E0E HTTP service-routes \u5BF9\u9F50)\u3002\n assertModulePermission(mod.id, mod.permissions, Perm.service(step.name));\n const result = await this.deps.serviceRegistry.dispatch(this.deps.enabled, mod.id, step.name, step.input, {\n query: this.deps.query,\n db: this.deps.db,\n });\n return { op: \"service\", result: result.result };\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["sql", "r"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,52 +1,54 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sfmc-bds/db-server",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
4
|
-
"description": "SFMC SQLite HTTP REST backend — configs, modules, gameplay data
|
|
5
|
-
"type": "module",
|
|
6
|
-
"license": "ISC",
|
|
3
|
+
"version": "0.2.0-beta.11",
|
|
4
|
+
"description": "SFMC SQLite HTTP REST backend — configs, modules, gameplay data",
|
|
7
5
|
"author": "Shiroha7z",
|
|
8
|
-
"
|
|
6
|
+
"license": "AGPL-3.0-only",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"homepage": "https://github.com/DogeLakeDev/ScriptsForMinecraftServer/tree/main/packages/db-server#readme",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
11
|
"url": "git+https://github.com/DogeLakeDev/ScriptsForMinecraftServer.git",
|
|
12
|
-
"directory": "db-server"
|
|
12
|
+
"directory": "packages/db-server"
|
|
13
13
|
},
|
|
14
14
|
"bugs": {
|
|
15
15
|
"url": "https://github.com/DogeLakeDev/ScriptsForMinecraftServer/issues"
|
|
16
16
|
},
|
|
17
17
|
"keywords": [
|
|
18
18
|
"minecraft-bedrock",
|
|
19
|
-
"sfmc",
|
|
20
|
-
"sqlite",
|
|
21
19
|
"rest-api",
|
|
22
|
-
"scriptsforminecraftserver"
|
|
20
|
+
"scriptsforminecraftserver",
|
|
21
|
+
"sfmc",
|
|
22
|
+
"sqlite"
|
|
23
23
|
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=22.13.0"
|
|
26
|
+
},
|
|
24
27
|
"main": "dist/index.js",
|
|
25
28
|
"types": "./dist/index.d.ts",
|
|
26
29
|
"files": [
|
|
27
30
|
"dist",
|
|
28
31
|
"README.md"
|
|
29
32
|
],
|
|
30
|
-
"scripts": {
|
|
31
|
-
"start": "node dist/index.js",
|
|
32
|
-
"dev": "tsx src/index.ts",
|
|
33
|
-
"build": "node ../scripts/esbuild-transpile.mjs --dts",
|
|
34
|
-
"typecheck": "tsc7 --noEmit",
|
|
35
|
-
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
36
|
-
"test": "npm run build && node --test dist/*.test.js",
|
|
37
|
-
"format": "prettier --write \"src/**/*.{ts,tsx,js,json}\"",
|
|
38
|
-
"prepublishOnly": "npm run build"
|
|
39
|
-
},
|
|
40
33
|
"dependencies": {
|
|
41
|
-
"@sfmc-bds/sdk": "^0.2.0-beta.0",
|
|
42
34
|
"sql-template-strings": "^2.2.2",
|
|
43
|
-
"
|
|
35
|
+
"@sfmc-bds/sdk": "0.2.0-beta.14"
|
|
44
36
|
},
|
|
45
|
-
"
|
|
46
|
-
"
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@sfmc-bds/tools": "0.2.0-beta.15"
|
|
47
39
|
},
|
|
48
40
|
"publishConfig": {
|
|
49
41
|
"access": "public",
|
|
50
42
|
"registry": "https://registry.npmjs.org/"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "sfmc-esbuild-transpile --dts",
|
|
46
|
+
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
47
|
+
"dev": "tsx src/index.ts",
|
|
48
|
+
"format": "prettier --write \"src/**/*.{ts,tsx,js,json}\"",
|
|
49
|
+
"start": "node dist/index.js",
|
|
50
|
+
"test": "node --test dist/**/*.test.js dist/*.test.js",
|
|
51
|
+
"test:api": "pnpm run build && node scripts/test-db-api.mjs",
|
|
52
|
+
"typecheck": "tsc7 --noEmit"
|
|
51
53
|
}
|
|
52
|
-
}
|
|
54
|
+
}
|