@sfmc-bds/db-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/dist/db-tables.d.ts +13 -0
- package/dist/db-tables.d.ts.map +1 -0
- package/dist/db-tables.js +35 -0
- package/dist/db-tables.js.map +1 -0
- package/dist/domain/bridge.d.ts +48 -0
- package/dist/domain/bridge.d.ts.map +1 -0
- package/dist/domain/bridge.js +82 -0
- package/dist/domain/bridge.js.map +1 -0
- package/dist/domain/economy.d.ts +120 -0
- package/dist/domain/economy.d.ts.map +1 -0
- package/dist/domain/economy.js +321 -0
- package/dist/domain/economy.js.map +1 -0
- package/dist/domain/schema.d.ts +26 -0
- package/dist/domain/schema.d.ts.map +1 -0
- package/dist/domain/schema.js +462 -0
- package/dist/domain/schema.js.map +1 -0
- package/dist/domain/transaction.d.ts +67 -0
- package/dist/domain/transaction.d.ts.map +1 -0
- package/dist/domain/transaction.js +85 -0
- package/dist/domain/transaction.js.map +1 -0
- package/dist/env.d.ts +22 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +94 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +313 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/http.d.ts +18 -0
- package/dist/lib/http.d.ts.map +1 -0
- package/dist/lib/http.js +43 -0
- package/dist/lib/http.js.map +1 -0
- package/dist/lib/idempotency-store.d.ts +28 -0
- package/dist/lib/idempotency-store.d.ts.map +1 -0
- package/dist/lib/idempotency-store.js +49 -0
- package/dist/lib/idempotency-store.js.map +1 -0
- package/dist/lib/idempotency.d.ts +9 -0
- package/dist/lib/idempotency.d.ts.map +1 -0
- package/dist/lib/idempotency.js +14 -0
- package/dist/lib/idempotency.js.map +1 -0
- package/dist/lib/identifiers.d.ts +3 -0
- package/dist/lib/identifiers.d.ts.map +1 -0
- package/dist/lib/identifiers.js +18 -0
- package/dist/lib/identifiers.js.map +1 -0
- package/dist/lib/log.d.ts +11 -0
- package/dist/lib/log.d.ts.map +1 -0
- package/dist/lib/log.js +15 -0
- package/dist/lib/log.js.map +1 -0
- package/dist/lib/module-state.d.ts +15 -0
- package/dist/lib/module-state.d.ts.map +1 -0
- package/dist/lib/module-state.js +27 -0
- package/dist/lib/module-state.js.map +1 -0
- package/dist/lib/runtime.d.ts +21 -0
- package/dist/lib/runtime.d.ts.map +1 -0
- package/dist/lib/runtime.js +34 -0
- package/dist/lib/runtime.js.map +1 -0
- package/dist/lib/sql-helpers.d.ts +31 -0
- package/dist/lib/sql-helpers.d.ts.map +1 -0
- package/dist/lib/sql-helpers.js +30 -0
- package/dist/lib/sql-helpers.js.map +1 -0
- package/dist/lib/sqlite.d.ts +20 -0
- package/dist/lib/sqlite.d.ts.map +1 -0
- package/dist/lib/sqlite.js +59 -0
- package/dist/lib/sqlite.js.map +1 -0
- package/dist/manifest-loader.d.ts +69 -0
- package/dist/manifest-loader.d.ts.map +1 -0
- package/dist/manifest-loader.js +212 -0
- package/dist/manifest-loader.js.map +1 -0
- package/dist/manifest.d.ts +76 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +128 -0
- package/dist/manifest.js.map +1 -0
- package/dist/module-auth.d.ts +58 -0
- package/dist/module-auth.d.ts.map +1 -0
- package/dist/module-auth.js +118 -0
- package/dist/module-auth.js.map +1 -0
- package/dist/permission-gate.d.ts +53 -0
- package/dist/permission-gate.d.ts.map +1 -0
- package/dist/permission-gate.js +94 -0
- package/dist/permission-gate.js.map +1 -0
- package/dist/routes/_shared.d.ts +68 -0
- package/dist/routes/_shared.d.ts.map +1 -0
- package/dist/routes/_shared.js +27 -0
- package/dist/routes/_shared.js.map +1 -0
- package/dist/routes/config.d.ts +27 -0
- package/dist/routes/config.d.ts.map +1 -0
- package/dist/routes/config.js +236 -0
- package/dist/routes/config.js.map +1 -0
- package/dist/routes/db-routes.d.ts +38 -0
- package/dist/routes/db-routes.d.ts.map +1 -0
- package/dist/routes/db-routes.js +186 -0
- package/dist/routes/db-routes.js.map +1 -0
- package/dist/routes/health.d.ts +10 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +23 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/messages.d.ts +23 -0
- package/dist/routes/messages.d.ts.map +1 -0
- package/dist/routes/messages.js +72 -0
- package/dist/routes/messages.js.map +1 -0
- package/dist/routes/module-config-routes.d.ts +31 -0
- package/dist/routes/module-config-routes.d.ts.map +1 -0
- package/dist/routes/module-config-routes.js +128 -0
- package/dist/routes/module-config-routes.js.map +1 -0
- package/dist/routes/modules.d.ts +34 -0
- package/dist/routes/modules.d.ts.map +1 -0
- package/dist/routes/modules.js +92 -0
- package/dist/routes/modules.js.map +1 -0
- package/dist/routes/service-routes.d.ts +26 -0
- package/dist/routes/service-routes.d.ts.map +1 -0
- package/dist/routes/service-routes.js +68 -0
- package/dist/routes/service-routes.js.map +1 -0
- package/dist/runtime.test.d.ts +2 -0
- package/dist/runtime.test.d.ts.map +1 -0
- package/dist/runtime.test.js +66 -0
- package/dist/runtime.test.js.map +1 -0
- package/dist/schema-registry.d.ts +63 -0
- package/dist/schema-registry.d.ts.map +1 -0
- package/dist/schema-registry.js +178 -0
- package/dist/schema-registry.js.map +1 -0
- package/dist/server.d.ts +27 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +82 -0
- package/dist/server.js.map +1 -0
- package/dist/service-registry.d.ts +46 -0
- package/dist/service-registry.d.ts.map +1 -0
- package/dist/service-registry.js +73 -0
- package/dist/service-registry.js.map +1 -0
- package/dist/services/builtin-handlers.d.ts +22 -0
- package/dist/services/builtin-handlers.d.ts.map +1 -0
- package/dist/services/builtin-handlers.js +23 -0
- package/dist/services/builtin-handlers.js.map +1 -0
- package/dist/services/economy-handlers.d.ts +14 -0
- package/dist/services/economy-handlers.d.ts.map +1 -0
- package/dist/services/economy-handlers.js +144 -0
- package/dist/services/economy-handlers.js.map +1 -0
- package/dist/tx-runner.d.ts +144 -0
- package/dist/tx-runner.d.ts.map +1 -0
- package/dist/tx-runner.js +273 -0
- package/dist/tx-runner.js.map +1 -0
- package/dist/where.d.ts +48 -0
- package/dist/where.d.ts.map +1 -0
- package/dist/where.js +107 -0
- package/dist/where.js.map +1 -0
- package/package.json +52 -0
package/dist/lib/http.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/http.ts — HTTP 工具(JSON 响应 + body 解析)
|
|
3
|
+
*
|
|
4
|
+
* 所有 db-server 路由统一走这里的 json / body / parseBody。
|
|
5
|
+
* 路由上下文 ({ path, method, params, req, res }) 在 routes/_shared.ts 定义。
|
|
6
|
+
*/
|
|
7
|
+
/** 写 JSON 响应并结束。 */
|
|
8
|
+
export function json(res, data, status = 200) {
|
|
9
|
+
res.writeHead(status, { "Content-Type": "application/json" });
|
|
10
|
+
res.end(JSON.stringify(data));
|
|
11
|
+
}
|
|
12
|
+
/** 解析请求 body 字符串为对象(解析失败返回空对象)。 */
|
|
13
|
+
export function parseBody(raw) {
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(raw || "{}");
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 异步读取请求 body,结果会缓存到 req._bodyPromise 上以避免重复读取。
|
|
23
|
+
* Buffer 累积 + 异步拼接,正确处理 binary 字节流。
|
|
24
|
+
*/
|
|
25
|
+
export function body(req) {
|
|
26
|
+
const cached = req._bodyPromise;
|
|
27
|
+
if (cached)
|
|
28
|
+
return cached;
|
|
29
|
+
const promise = new Promise((resolve) => {
|
|
30
|
+
const chunks = [];
|
|
31
|
+
req.on("data", (chunk) => {
|
|
32
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
33
|
+
});
|
|
34
|
+
req.on("end", () => {
|
|
35
|
+
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
36
|
+
resolve(parseBody(raw));
|
|
37
|
+
});
|
|
38
|
+
req.on("error", () => resolve({}));
|
|
39
|
+
});
|
|
40
|
+
req._bodyPromise = promise;
|
|
41
|
+
return promise;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/lib/http.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,oBAAoB;AACpB,MAAM,UAAU,IAAI,CAAC,GAAmB,EAAE,IAA6B,EAAE,SAAiB,GAAG;IAC3F,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC9D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,mCAAmC;AACnC,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAA4B,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,IAAI,CAAC,GAAoB;IACvC,MAAM,MAAM,GAAI,GAA6E,CAAC,YAAY,CAAC;IAC3G,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,OAAO,GAAG,IAAI,OAAO,CAA0B,CAAC,OAAO,EAAE,EAAE;QAC/D,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAsB,EAAE,EAAE;YACxC,MAAM,CAAC,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACtE,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACjB,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACpD,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IACF,GAA6E,CAAC,YAAY,GAAG,OAAO,CAAC;IACtG,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/idempotency.ts — db.idempotent() 后端
|
|
3
|
+
*
|
|
4
|
+
* 表:sfmc__idempotent (db-tables.ts 创建)
|
|
5
|
+
* key: (module_id, action, key) → cached value?
|
|
6
|
+
*
|
|
7
|
+
* probe(module_id, action, key):
|
|
8
|
+
* - 命中 → {replayed:true, cached}
|
|
9
|
+
* - 不命中 → {replayed:false}
|
|
10
|
+
*
|
|
11
|
+
* commit(module_id, action, key, value?):
|
|
12
|
+
* - INSERT … (replace) — 即使没 probe 也允许直接 commit
|
|
13
|
+
*
|
|
14
|
+
* 事务内调用一律走 tx-runner 不行(commit 必须在事务外完成,跨事务持久化);
|
|
15
|
+
* 这里单独端点 POST /api/sfmc/db/idempotent/{probe,commit},不走 tx。
|
|
16
|
+
*/
|
|
17
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
18
|
+
export interface IdempotencyStore {
|
|
19
|
+
probe(moduleId: string, action: string, key: string): Promise<{
|
|
20
|
+
replayed: boolean;
|
|
21
|
+
cached?: unknown;
|
|
22
|
+
}>;
|
|
23
|
+
commit(moduleId: string, action: string, key: string, value?: unknown): Promise<{
|
|
24
|
+
ok: boolean;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
export declare function createIdempotencyStore(db: DatabaseSync): IdempotencyStore;
|
|
28
|
+
//# sourceMappingURL=idempotency-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idempotency-store.d.ts","sourceRoot":"","sources":["../../src/lib/idempotency-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACvG,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAClG;AAED,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,YAAY,GAAG,gBAAgB,CAgCzE"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/idempotency.ts — db.idempotent() 后端
|
|
3
|
+
*
|
|
4
|
+
* 表:sfmc__idempotent (db-tables.ts 创建)
|
|
5
|
+
* key: (module_id, action, key) → cached value?
|
|
6
|
+
*
|
|
7
|
+
* probe(module_id, action, key):
|
|
8
|
+
* - 命中 → {replayed:true, cached}
|
|
9
|
+
* - 不命中 → {replayed:false}
|
|
10
|
+
*
|
|
11
|
+
* commit(module_id, action, key, value?):
|
|
12
|
+
* - INSERT … (replace) — 即使没 probe 也允许直接 commit
|
|
13
|
+
*
|
|
14
|
+
* 事务内调用一律走 tx-runner 不行(commit 必须在事务外完成,跨事务持久化);
|
|
15
|
+
* 这里单独端点 POST /api/sfmc/db/idempotent/{probe,commit},不走 tx。
|
|
16
|
+
*/
|
|
17
|
+
import { isValidIdempotencyKey } from "./idempotency.js";
|
|
18
|
+
export function createIdempotencyStore(db) {
|
|
19
|
+
const probeStmt = db.prepare("SELECT value FROM sfmc__idempotent WHERE module_id=? AND action=? AND key=?");
|
|
20
|
+
const insertStmt = db.prepare(`INSERT OR REPLACE INTO sfmc__idempotent (module_id, action, key, value, created_at)
|
|
21
|
+
VALUES (?, ?, ?, ?, ?)`);
|
|
22
|
+
return {
|
|
23
|
+
async probe(moduleId, action, key) {
|
|
24
|
+
if (!isValidIdempotencyKey(key))
|
|
25
|
+
throw new Error("invalid idempotency key");
|
|
26
|
+
const row = probeStmt.get(moduleId, action, key);
|
|
27
|
+
if (!row)
|
|
28
|
+
return { replayed: false };
|
|
29
|
+
let cached = null;
|
|
30
|
+
if (row.value) {
|
|
31
|
+
try {
|
|
32
|
+
cached = JSON.parse(row.value);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
cached = row.value;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return { replayed: true, cached };
|
|
39
|
+
},
|
|
40
|
+
async commit(moduleId, action, key, value) {
|
|
41
|
+
if (!isValidIdempotencyKey(key))
|
|
42
|
+
throw new Error("invalid idempotency key");
|
|
43
|
+
const json = value === undefined ? null : JSON.stringify(value);
|
|
44
|
+
insertStmt.run(moduleId, action, key, json, new Date().toISOString());
|
|
45
|
+
return { ok: true };
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=idempotency-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idempotency-store.js","sourceRoot":"","sources":["../../src/lib/idempotency-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAOzD,MAAM,UAAU,sBAAsB,CAAC,EAAgB;IACrD,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,CAC1B,6EAA6E,CAC9E,CAAC;IACF,MAAM,UAAU,GAAG,EAAE,CAAC,OAAO,CAC3B;4BACwB,CACzB,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG;YAC/B,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YAC5E,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAyC,CAAC;YACzF,IAAI,CAAC,GAAG;gBAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;YACrC,IAAI,MAAM,GAAY,IAAI,CAAC;YAC3B,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;gBACd,IAAI,CAAC;oBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACjC,CAAC;gBAAC,MAAM,CAAC;oBACP,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC;gBACrB,CAAC;YACH,CAAC;YACD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QACpC,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,KAAM;YACxC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YAC5E,MAAM,IAAI,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAChE,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;YACtE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACtB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idempotency.d.ts","sourceRoot":"","sources":["../../src/lib/idempotency.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAI1D"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 验证幂等键格式
|
|
3
|
+
*
|
|
4
|
+
* @export
|
|
5
|
+
* @param {string} key
|
|
6
|
+
* @return {*} {(boolean | string)}
|
|
7
|
+
*/
|
|
8
|
+
export function isValidIdempotencyKey(key) {
|
|
9
|
+
if (!key || typeof key !== "string")
|
|
10
|
+
return false;
|
|
11
|
+
const trimmed = key.trim();
|
|
12
|
+
return trimmed.length > 0 && /^[A-Za-z0-9_.:-]{1,128}$/.test(trimmed);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=idempotency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idempotency.js","sourceRoot":"","sources":["../../src/lib/idempotency.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAClD,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,0BAA0B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACxE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identifiers.d.ts","sourceRoot":"","sources":["../../src/lib/identifiers.ts"],"names":[],"mappings":"AASA,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,GAAE,MAAqB,GAAG,MAAM,CAKrF;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
class IdentifierError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
constructor(message, code) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.code = code;
|
|
6
|
+
Object.setPrototypeOf(this, IdentifierError.prototype);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function assertIdentifier(value, label = "identifier") {
|
|
10
|
+
if (typeof value !== "string" || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
|
|
11
|
+
throw new IdentifierError(`Invalid SQL ${label}`, "INVALID_IDENTIFIER");
|
|
12
|
+
}
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
export function quoteIdentifier(value, label) {
|
|
16
|
+
return `"${assertIdentifier(value, label)}"`;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=identifiers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identifiers.js","sourceRoot":"","sources":["../../src/lib/identifiers.ts"],"names":[],"mappings":"AAAA,MAAM,eAAgB,SAAQ,KAAK;IACjC,IAAI,CAAS;IACb,YAAY,OAAe,EAAE,IAAY;QACvC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;IACzD,CAAC;CACF;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAc,EAAE,QAAgB,YAAY;IAC3E,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACzE,MAAM,IAAI,eAAe,CAAC,eAAe,KAAK,EAAE,EAAE,oBAAoB,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAa,EAAE,KAAa;IAC1D,OAAO,IAAI,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* log.ts — db-server 统一日志实例
|
|
3
|
+
*
|
|
4
|
+
* 通过 @sfmc-bds/logs 共享包接入,source = "db"。
|
|
5
|
+
* sfmc 主进程通过捕获本进程 stdout 汇聚展示。
|
|
6
|
+
*
|
|
7
|
+
* bare 模式: stdout 只输出纯 text,不加时间戳/source/level 前缀
|
|
8
|
+
* (由 sfmc 的 formatLog 统一添加,避免重复)。error 走 stderr。
|
|
9
|
+
*/
|
|
10
|
+
export declare const log: import("@sfmc-bds/sdk/logs").Logger;
|
|
11
|
+
//# sourceMappingURL=log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/lib/log.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,eAAO,MAAM,GAAG,qCAGd,CAAC"}
|
package/dist/lib/log.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* log.ts — db-server 统一日志实例
|
|
3
|
+
*
|
|
4
|
+
* 通过 @sfmc-bds/logs 共享包接入,source = "db"。
|
|
5
|
+
* sfmc 主进程通过捕获本进程 stdout 汇聚展示。
|
|
6
|
+
*
|
|
7
|
+
* bare 模式: stdout 只输出纯 text,不加时间戳/source/level 前缀
|
|
8
|
+
* (由 sfmc 的 formatLog 统一添加,避免重复)。error 走 stderr。
|
|
9
|
+
*/
|
|
10
|
+
import { createLogger, createStdoutSink } from "@sfmc-bds/sdk/logs";
|
|
11
|
+
export const log = createLogger({
|
|
12
|
+
source: "db",
|
|
13
|
+
sinks: [createStdoutSink({ bare: true })],
|
|
14
|
+
});
|
|
15
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/lib/log.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEpE,MAAM,CAAC,MAAM,GAAG,GAAG,YAAY,CAAC;IAC9B,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;CAC1C,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface ModuleLock {
|
|
2
|
+
version: number;
|
|
3
|
+
modules: Record<string, {
|
|
4
|
+
enabled?: boolean;
|
|
5
|
+
updatedAt?: number;
|
|
6
|
+
}>;
|
|
7
|
+
}
|
|
8
|
+
type ModuleState = ModuleLock["modules"][string];
|
|
9
|
+
export declare function loadModuleLock(filePath: string): ModuleLock;
|
|
10
|
+
export declare function saveModuleLock(filePath: string, lock: ModuleLock): void;
|
|
11
|
+
export declare function getModuleState(lock: ModuleLock, id: string, defaults?: ModuleState): ModuleState;
|
|
12
|
+
export declare function isEnabled(lock: ModuleLock, id: string, defaultValue?: boolean): boolean;
|
|
13
|
+
export declare function updateModuleState(lock: ModuleLock, id: string, patch: Partial<Omit<ModuleState, "updatedAt">>): ModuleState;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=module-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-state.d.ts","sourceRoot":"","sources":["../../src/lib/module-state.ts"],"names":[],"mappings":"AAEA,UAAU,UAAU;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpE;AAED,KAAK,WAAW,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAI3D;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAEvE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,GAAE,WAAgB,GAAG,WAAW,CAGpG;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,YAAY,GAAE,OAAe,GAAG,OAAO,CAE9F;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,UAAU,EAChB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,GAC7C,WAAW,CASb"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { readJson, writeJson } from "@sfmc-bds/sdk/node/config";
|
|
2
|
+
export function loadModuleLock(filePath) {
|
|
3
|
+
const data = readJson(filePath);
|
|
4
|
+
const modules = data?.modules && typeof data.modules === "object" ? data.modules : {};
|
|
5
|
+
return { version: 1, modules };
|
|
6
|
+
}
|
|
7
|
+
export function saveModuleLock(filePath, lock) {
|
|
8
|
+
writeJson(filePath, lock);
|
|
9
|
+
}
|
|
10
|
+
export function getModuleState(lock, id, defaults = {}) {
|
|
11
|
+
const state = lock.modules[id];
|
|
12
|
+
return state && typeof state === "object" ? state : defaults;
|
|
13
|
+
}
|
|
14
|
+
export function isEnabled(lock, id, defaultValue = false) {
|
|
15
|
+
return getModuleState(lock, id).enabled ?? defaultValue;
|
|
16
|
+
}
|
|
17
|
+
export function updateModuleState(lock, id, patch) {
|
|
18
|
+
const now = Date.now();
|
|
19
|
+
const previous = getModuleState(lock, id);
|
|
20
|
+
lock.modules[id] = {
|
|
21
|
+
...previous,
|
|
22
|
+
...patch,
|
|
23
|
+
updatedAt: now,
|
|
24
|
+
};
|
|
25
|
+
return lock.modules[id];
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=module-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-state.js","sourceRoot":"","sources":["../../src/lib/module-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAShE,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,MAAM,IAAI,GAAG,QAAQ,CAAa,QAAQ,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,IAAI,EAAE,OAAO,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACtF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,IAAgB;IAC/D,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAgB,EAAE,EAAU,EAAE,WAAwB,EAAE;IACrF,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC/B,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAgB,EAAE,EAAU,EAAE,eAAwB,KAAK;IACnF,OAAO,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,IAAI,YAAY,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,IAAgB,EAChB,EAAU,EACV,KAA8C;IAE9C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC1C,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG;QACjB,GAAG,QAAQ;QACX,GAAG,KAAK;QACR,SAAS,EAAE,GAAG;KACf,CAAC;IACF,OAAO,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare function parseNodeVersion(version?: string): {
|
|
2
|
+
major: number;
|
|
3
|
+
minor: number;
|
|
4
|
+
patch: number;
|
|
5
|
+
} | null;
|
|
6
|
+
/**
|
|
7
|
+
* 校验当前 Node.js 版本是否满足最低要求。
|
|
8
|
+
*
|
|
9
|
+
* 默认下限 22.13 —— `node:sqlite`(db-server 的核心依赖)在 22.5.0–22.12.x
|
|
10
|
+
* 仍需 `--experimental-sqlite` CLI 参数才能加载,未带参数时会在 import 阶段
|
|
11
|
+
* 直接抛出 `ERR_UNKNOWN_BUILTIN_MODULE`;该模块从 22.13.0 起默认可用(仍标记为
|
|
12
|
+
* experimental)。注意:由于 ESM 静态 import 会在本文件被调用之前完成解析,
|
|
13
|
+
* 这里的检查无法拦截 `./lib/sqlite.ts` 自身的 import 崩溃,只能作为其余场景
|
|
14
|
+
* 的兜底防线与版本要求的单一事实来源。
|
|
15
|
+
*
|
|
16
|
+
* @param {number} [minMajor=22]
|
|
17
|
+
* @param {number} [minMinor=13]
|
|
18
|
+
* @return {*} {boolean}
|
|
19
|
+
*/
|
|
20
|
+
export declare function assertNodeVersion(minMajor?: number, minMinor?: number): boolean;
|
|
21
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/lib/runtime.ts"],"names":[],"mappings":"AAOA,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,MAA8B,GAAG;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,IAAI,CAGP;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,GAAE,MAAW,EAAE,QAAQ,GAAE,MAAW,GAAG,OAAO,CAQvF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 解析 Node.js 版本字符串,提取主版本号、次版本号和补丁号。
|
|
3
|
+
* @param version - 版本字符串(可选),例如 "v14.17.0" 或 "14.17.0"。默认为 process.versions.node。
|
|
4
|
+
* @returns 包含 major, minor, patch 的对象,若格式无效则返回 null。
|
|
5
|
+
*/
|
|
6
|
+
import { log } from "./log.js";
|
|
7
|
+
export function parseNodeVersion(version = process.versions.node) {
|
|
8
|
+
const match = String(version).match(/^v?(\d+)\.(\d+)\.(\d+)/);
|
|
9
|
+
return match ? { major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3]) } : null;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 校验当前 Node.js 版本是否满足最低要求。
|
|
13
|
+
*
|
|
14
|
+
* 默认下限 22.13 —— `node:sqlite`(db-server 的核心依赖)在 22.5.0–22.12.x
|
|
15
|
+
* 仍需 `--experimental-sqlite` CLI 参数才能加载,未带参数时会在 import 阶段
|
|
16
|
+
* 直接抛出 `ERR_UNKNOWN_BUILTIN_MODULE`;该模块从 22.13.0 起默认可用(仍标记为
|
|
17
|
+
* experimental)。注意:由于 ESM 静态 import 会在本文件被调用之前完成解析,
|
|
18
|
+
* 这里的检查无法拦截 `./lib/sqlite.ts` 自身的 import 崩溃,只能作为其余场景
|
|
19
|
+
* 的兜底防线与版本要求的单一事实来源。
|
|
20
|
+
*
|
|
21
|
+
* @param {number} [minMajor=22]
|
|
22
|
+
* @param {number} [minMinor=13]
|
|
23
|
+
* @return {*} {boolean}
|
|
24
|
+
*/
|
|
25
|
+
export function assertNodeVersion(minMajor = 22, minMinor = 13) {
|
|
26
|
+
const actual = parseNodeVersion();
|
|
27
|
+
if (!actual || actual.major < minMajor || (actual.major === minMajor && actual.minor < minMinor)) {
|
|
28
|
+
log.error(`[Runtime] Node.js ${minMajor}.${minMinor}+ is required; found ${process.versions.node}`);
|
|
29
|
+
process.exitCode = 2;
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/lib/runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,MAAM,UAAU,gBAAgB,CAAC,UAAkB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAKtE,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC9D,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACtG,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAAmB,EAAE,EAAE,WAAmB,EAAE;IAC5E,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;IAClC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,GAAG,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,GAAG,QAAQ,CAAC,EAAE,CAAC;QACjG,GAAG,CAAC,KAAK,CAAC,qBAAqB,QAAQ,IAAI,QAAQ,wBAAwB,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QACpG,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/sql-helpers.ts — SQL 构造辅助
|
|
3
|
+
*
|
|
4
|
+
* sql-template-strings 会把每一次 ${} 插值都变成 `?` 绑定值。
|
|
5
|
+
* 表名/列名等信任标识符必须嵌入 SQL 文本,不能走绑定 —— 否则会出现
|
|
6
|
+
* `FROM ?` → `near "?": syntax error`(见 economy 域修复)。
|
|
7
|
+
*/
|
|
8
|
+
import { type SQLStatement } from "sql-template-strings";
|
|
9
|
+
/** 参数化查询信封,与 createQuery / AnyQuery 的格式 2 对齐 */
|
|
10
|
+
export type BoundSql = {
|
|
11
|
+
sql: string;
|
|
12
|
+
values: unknown[];
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* 构造「标识符已嵌入、值走 ?」的查询。
|
|
16
|
+
* 表名等信任常量用模板字符串嵌入;用户输入只放进 values。
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* sql(`SELECT * FROM ${TABLE} WHERE id = ?`, [id])
|
|
20
|
+
*/
|
|
21
|
+
export declare function sql(text: string, values?: unknown[]): BoundSql;
|
|
22
|
+
/**
|
|
23
|
+
* 把一段静态 SQL 文本包装成 SQLStatement,仅可与 `.append(...)` 合用。
|
|
24
|
+
*
|
|
25
|
+
* 警告(LSP):切勿写成 `SQL\`... FROM ${raw(table)} ...\`` —— 模板插值仍会变成 `?`,
|
|
26
|
+
* 与直接插值表名同病。正确用法:
|
|
27
|
+
* SQL`SELECT * FROM `.append(raw(TABLE)).append(SQL` WHERE id = ${id}`)
|
|
28
|
+
* 纯字符串 `.append(TABLE)` 效果相同;优先用 {@link sql}。
|
|
29
|
+
*/
|
|
30
|
+
export declare function raw(text: string): SQLStatement;
|
|
31
|
+
//# sourceMappingURL=sql-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-helpers.d.ts","sourceRoot":"","sources":["../../src/lib/sql-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAE9D,gDAAgD;AAChD,MAAM,MAAM,QAAQ,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,CAAC;AAE1D;;;;;;GAMG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,OAAO,EAAO,GAAG,QAAQ,CAElE;AAED;;;;;;;GAOG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAE9C"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/sql-helpers.ts — SQL 构造辅助
|
|
3
|
+
*
|
|
4
|
+
* sql-template-strings 会把每一次 ${} 插值都变成 `?` 绑定值。
|
|
5
|
+
* 表名/列名等信任标识符必须嵌入 SQL 文本,不能走绑定 —— 否则会出现
|
|
6
|
+
* `FROM ?` → `near "?": syntax error`(见 economy 域修复)。
|
|
7
|
+
*/
|
|
8
|
+
import { SQL } from "sql-template-strings";
|
|
9
|
+
/**
|
|
10
|
+
* 构造「标识符已嵌入、值走 ?」的查询。
|
|
11
|
+
* 表名等信任常量用模板字符串嵌入;用户输入只放进 values。
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* sql(`SELECT * FROM ${TABLE} WHERE id = ?`, [id])
|
|
15
|
+
*/
|
|
16
|
+
export function sql(text, values = []) {
|
|
17
|
+
return { sql: text, values };
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 把一段静态 SQL 文本包装成 SQLStatement,仅可与 `.append(...)` 合用。
|
|
21
|
+
*
|
|
22
|
+
* 警告(LSP):切勿写成 `SQL\`... FROM ${raw(table)} ...\`` —— 模板插值仍会变成 `?`,
|
|
23
|
+
* 与直接插值表名同病。正确用法:
|
|
24
|
+
* SQL`SELECT * FROM `.append(raw(TABLE)).append(SQL` WHERE id = ${id}`)
|
|
25
|
+
* 纯字符串 `.append(TABLE)` 效果相同;优先用 {@link sql}。
|
|
26
|
+
*/
|
|
27
|
+
export function raw(text) {
|
|
28
|
+
return SQL([text]);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=sql-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-helpers.js","sourceRoot":"","sources":["../../src/lib/sql-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,GAAG,EAAqB,MAAM,sBAAsB,CAAC;AAK9D;;;;;;GAMG;AACH,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,SAAoB,EAAE;IACtD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC/B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,GAAG,CAAC,IAAY;IAC9B,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,CAAiB,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DatabaseSync } from "node:sqlite";
|
|
2
|
+
import type { SQLStatement } from "sql-template-strings";
|
|
3
|
+
export type QueryFn = (sql: string | SQLStatement | {
|
|
4
|
+
sql: string;
|
|
5
|
+
values?: unknown[];
|
|
6
|
+
}, values?: unknown[]) => unknown[] | {
|
|
7
|
+
changes: number | bigint;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* 统一 SQL 查询接口 — 支持三种调用格式:
|
|
11
|
+
* 1. query("SELECT * FROM t WHERE id=?", [1])
|
|
12
|
+
* 2. query({ sql: "SELECT * FROM t WHERE id=?", values: [1] })
|
|
13
|
+
* 3. query(SQL`SELECT * FROM t WHERE id=${1}`) ← sql-template-strings
|
|
14
|
+
*/
|
|
15
|
+
export declare function createQuery(db: DatabaseSync, maxStatements?: number): QueryFn;
|
|
16
|
+
/**
|
|
17
|
+
* 打开 SQLite 数据库(同步模式),启用外键、WAL、busy_timeout
|
|
18
|
+
*/
|
|
19
|
+
export declare function openDatabase(filePath: string): DatabaseSync;
|
|
20
|
+
//# sourceMappingURL=sqlite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/lib/sqlite.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAiB,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,MAAM,MAAM,OAAO,GAAG,CACpB,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAA;CAAE,EAChE,MAAM,CAAC,EAAE,OAAO,EAAE,KACf,OAAO,EAAE,GAAG;IAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC;AAE9C;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,YAAY,EAAE,aAAa,GAAE,MAAY,GAAG,OAAO,CAuClF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,CAO3D"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { mkdirSync } from "node:fs";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import { DatabaseSync, StatementSync } from "node:sqlite";
|
|
4
|
+
/**
|
|
5
|
+
* 统一 SQL 查询接口 — 支持三种调用格式:
|
|
6
|
+
* 1. query("SELECT * FROM t WHERE id=?", [1])
|
|
7
|
+
* 2. query({ sql: "SELECT * FROM t WHERE id=?", values: [1] })
|
|
8
|
+
* 3. query(SQL`SELECT * FROM t WHERE id=${1}`) ← sql-template-strings
|
|
9
|
+
*/
|
|
10
|
+
export function createQuery(db, maxStatements = 200) {
|
|
11
|
+
const stmts = new Map();
|
|
12
|
+
function getStmt(sql) {
|
|
13
|
+
let s = stmts.get(sql);
|
|
14
|
+
if (!s) {
|
|
15
|
+
s = db.prepare(sql);
|
|
16
|
+
if (stmts.size >= maxStatements) {
|
|
17
|
+
const first = stmts.keys().next().value;
|
|
18
|
+
if (first !== undefined)
|
|
19
|
+
stmts.delete(first);
|
|
20
|
+
}
|
|
21
|
+
stmts.set(sql, s);
|
|
22
|
+
}
|
|
23
|
+
return s;
|
|
24
|
+
}
|
|
25
|
+
function runQuery(sql, values) {
|
|
26
|
+
const s = getStmt(sql);
|
|
27
|
+
const upper = sql.trim().toUpperCase();
|
|
28
|
+
const needsRows = upper.startsWith("SELECT") ||
|
|
29
|
+
upper.startsWith("WITH") ||
|
|
30
|
+
upper.startsWith("PRAGMA") ||
|
|
31
|
+
/\bRETURNING\b/.test(upper);
|
|
32
|
+
const bind = values;
|
|
33
|
+
if (needsRows)
|
|
34
|
+
return s.all(...bind);
|
|
35
|
+
const r = s.run(...bind);
|
|
36
|
+
return { changes: r.changes };
|
|
37
|
+
}
|
|
38
|
+
return function query(raw, maybeValues) {
|
|
39
|
+
// 格式 1:string + values
|
|
40
|
+
if (typeof raw === "string") {
|
|
41
|
+
return runQuery(raw, maybeValues ?? []);
|
|
42
|
+
}
|
|
43
|
+
// 格式 2 / 3:{ sql, values } 或 sql-template-strings 对象
|
|
44
|
+
const o = raw;
|
|
45
|
+
return runQuery(o.sql, o.values ?? []);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 打开 SQLite 数据库(同步模式),启用外键、WAL、busy_timeout
|
|
50
|
+
*/
|
|
51
|
+
export function openDatabase(filePath) {
|
|
52
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
53
|
+
const db = new DatabaseSync(filePath);
|
|
54
|
+
db.exec("PRAGMA foreign_keys = ON");
|
|
55
|
+
db.exec("PRAGMA journal_mode = WAL");
|
|
56
|
+
db.exec("PRAGMA busy_timeout = 5000");
|
|
57
|
+
return db;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=sqlite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/lib/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAQ1D;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,EAAgB,EAAE,gBAAwB,GAAG;IACvE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;IAE/C,SAAS,OAAO,CAAC,GAAW;QAC1B,IAAI,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACpB,IAAI,KAAK,CAAC,IAAI,IAAI,aAAa,EAAE,CAAC;gBAChC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;gBACxC,IAAI,KAAK,KAAK,SAAS;oBAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC/C,CAAC;YACD,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACpB,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,SAAS,QAAQ,CAAC,GAAW,EAAE,MAAiB;QAC9C,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QACvB,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACvC,MAAM,SAAS,GACb,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC;YAC1B,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;YACxB,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC;YAC1B,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAG,MAAe,CAAC;QAC7B,IAAI,SAAS;YAAE,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;QACrC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;QACzB,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;IAChC,CAAC;IAED,OAAO,SAAS,KAAK,CAAC,GAAiD,EAAE,WAAuB;QAC9F,uBAAuB;QACvB,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC5B,OAAO,QAAQ,CAAC,GAAG,EAAE,WAAW,IAAI,EAAE,CAAC,CAAC;QAC1C,CAAC;QACD,qDAAqD;QACrD,MAAM,CAAC,GAAG,GAA0C,CAAC;QACrD,OAAO,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,QAAQ,CAAC,CAAC;IACtC,EAAE,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACpC,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACrC,EAAE,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IACtC,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* manifest-loader.ts — 读 v2 manifest,失败 = 启动失败
|
|
3
|
+
*
|
|
4
|
+
* v2 schema:
|
|
5
|
+
* {
|
|
6
|
+
* "schemaVersion": 2,
|
|
7
|
+
* "id": "feature-land",
|
|
8
|
+
* "name": "领地",
|
|
9
|
+
* "type": "feature",
|
|
10
|
+
* "configKey": "land",
|
|
11
|
+
* "requires": ["feature-economy"],
|
|
12
|
+
* "permissions": ["db:read:lands", "service:economy.account"],
|
|
13
|
+
* "services": {
|
|
14
|
+
* "provides": [{ "name": "lands.byOwner", "input": {...}, "output": {...} }],
|
|
15
|
+
* "requires": [{ "name": "economy.account" }]
|
|
16
|
+
* },
|
|
17
|
+
* "notes": "..."
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* 不要 routes / tables / migrations / seeds / handlers / events。
|
|
21
|
+
*
|
|
22
|
+
* 调用方:db-server/src/index.ts 启动时一次 loadManifestV2,
|
|
23
|
+
* throw 即 crash。
|
|
24
|
+
*/
|
|
25
|
+
export interface ManifestServiceIO {
|
|
26
|
+
type: "object" | "array" | "string" | "number" | "boolean" | "null";
|
|
27
|
+
properties?: Record<string, unknown>;
|
|
28
|
+
required?: string[];
|
|
29
|
+
}
|
|
30
|
+
export interface ServiceEntry {
|
|
31
|
+
name: string;
|
|
32
|
+
input?: ManifestServiceIO | undefined;
|
|
33
|
+
output?: ManifestServiceIO | undefined;
|
|
34
|
+
}
|
|
35
|
+
export interface ModuleManifestV2 {
|
|
36
|
+
schemaVersion: 2;
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
type: "core" | "feature";
|
|
40
|
+
configKey: string;
|
|
41
|
+
requires: string[];
|
|
42
|
+
permissions: string[];
|
|
43
|
+
services: {
|
|
44
|
+
provides: ServiceEntry[];
|
|
45
|
+
requires: ServiceEntry[];
|
|
46
|
+
};
|
|
47
|
+
notes?: string | undefined;
|
|
48
|
+
}
|
|
49
|
+
/** v1 / 缺 schemaVersion:跳过(直到所有模块迁 v2) */
|
|
50
|
+
export declare class ModuleV1SkippedError extends Error {
|
|
51
|
+
moduleId: string;
|
|
52
|
+
declaredVersion: unknown;
|
|
53
|
+
constructor(moduleId: string, declaredVersion: unknown);
|
|
54
|
+
}
|
|
55
|
+
export interface LoadedManifests {
|
|
56
|
+
modules: Record<string, ModuleManifestV2>;
|
|
57
|
+
providesMap: Map<string, string>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 启动期调。throw = 启动失败。
|
|
61
|
+
* 注:不读 v1 manifest。只有 schemaVersion=2 才走。
|
|
62
|
+
*/
|
|
63
|
+
export declare function loadManifestV2(packagesDir?: string): LoadedManifests;
|
|
64
|
+
/**
|
|
65
|
+
* 给定 moduleId 集合,过滤出 enabled (= lock 文件 enabled 的) 子集。
|
|
66
|
+
* map(moduleId → manifest) — 没装则跳过。
|
|
67
|
+
*/
|
|
68
|
+
export declare function filterEnabled(loaded: LoadedManifests, enabledIds: ReadonlySet<string>): Record<string, ModuleManifestV2>;
|
|
69
|
+
//# sourceMappingURL=manifest-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-loader.d.ts","sourceRoot":"","sources":["../src/manifest-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAOH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACtC,MAAM,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;CACxC;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,CAAC,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE;QAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;QAAC,QAAQ,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC;IACjE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAKD,0CAA0C;AAC1C,qBAAa,oBAAqB,SAAQ,KAAK;IAC1B,QAAQ,EAAE,MAAM;IAAS,eAAe,EAAE,OAAO;gBAAjD,QAAQ,EAAE,MAAM,EAAS,eAAe,EAAE,OAAO;CAGrE;AA8FD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC1C,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,WAAW,GAAE,MAA6B,GAAG,eAAe,CA8D1F;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,GAC9B,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAMlC"}
|