@sfmc-bds/db-server 0.1.0 → 0.2.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +1 -1
  2. package/dist/db-tables.js +16 -17
  3. package/dist/db-tables.js.map +7 -1
  4. package/dist/domain/bridge.js +54 -77
  5. package/dist/domain/bridge.js.map +7 -1
  6. package/dist/domain/economy.d.ts +83 -2
  7. package/dist/domain/economy.d.ts.map +1 -1
  8. package/dist/domain/economy.js +292 -281
  9. package/dist/domain/economy.js.map +7 -1
  10. package/dist/domain/schema.js +480 -426
  11. package/dist/domain/schema.js.map +7 -1
  12. package/dist/domain/transaction.js +32 -80
  13. package/dist/domain/transaction.js.map +7 -1
  14. package/dist/env.d.ts.map +1 -1
  15. package/dist/env.js +85 -84
  16. package/dist/env.js.map +7 -1
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +218 -240
  20. package/dist/index.js.map +7 -1
  21. package/dist/lib/http.js +30 -39
  22. package/dist/lib/http.js.map +7 -1
  23. package/dist/lib/idempotency-store.js +34 -47
  24. package/dist/lib/idempotency-store.js.map +7 -1
  25. package/dist/lib/idempotency.js +8 -13
  26. package/dist/lib/idempotency.js.map +7 -1
  27. package/dist/lib/identifiers.js +18 -14
  28. package/dist/lib/identifiers.js.map +7 -1
  29. package/dist/lib/log.d.ts +3 -6
  30. package/dist/lib/log.d.ts.map +1 -1
  31. package/dist/lib/log.js +13 -14
  32. package/dist/lib/log.js.map +7 -1
  33. package/dist/lib/module-state.d.ts.map +1 -1
  34. package/dist/lib/module-state.js +32 -21
  35. package/dist/lib/module-state.js.map +7 -1
  36. package/dist/lib/order-by.d.ts +17 -0
  37. package/dist/lib/order-by.d.ts.map +1 -0
  38. package/dist/lib/order-by.js +24 -0
  39. package/dist/lib/order-by.js.map +7 -0
  40. package/dist/lib/runtime.js +16 -31
  41. package/dist/lib/runtime.js.map +7 -1
  42. package/dist/lib/sql-helpers.js +9 -27
  43. package/dist/lib/sql-helpers.js.map +7 -1
  44. package/dist/lib/sqlite.js +40 -52
  45. package/dist/lib/sqlite.js.map +7 -1
  46. package/dist/manifest-loader.d.ts.map +1 -1
  47. package/dist/manifest-loader.js +154 -195
  48. package/dist/manifest-loader.js.map +7 -1
  49. package/dist/manifest.d.ts +3 -7
  50. package/dist/manifest.d.ts.map +1 -1
  51. package/dist/manifest.js +76 -115
  52. package/dist/manifest.js.map +7 -1
  53. package/dist/module-auth.d.ts +17 -6
  54. package/dist/module-auth.d.ts.map +1 -1
  55. package/dist/module-auth.js +93 -107
  56. package/dist/module-auth.js.map +7 -1
  57. package/dist/module-runtime-sync.d.ts +37 -0
  58. package/dist/module-runtime-sync.d.ts.map +1 -0
  59. package/dist/module-runtime-sync.js +54 -0
  60. package/dist/module-runtime-sync.js.map +7 -0
  61. package/dist/permission-gate.d.ts.map +1 -1
  62. package/dist/permission-gate.js +55 -86
  63. package/dist/permission-gate.js.map +7 -1
  64. package/dist/routes/_shared.d.ts +7 -2
  65. package/dist/routes/_shared.d.ts.map +1 -1
  66. package/dist/routes/_shared.js +16 -25
  67. package/dist/routes/_shared.js.map +7 -1
  68. package/dist/routes/config.d.ts +11 -1
  69. package/dist/routes/config.d.ts.map +1 -1
  70. package/dist/routes/config.js +167 -213
  71. package/dist/routes/config.js.map +7 -1
  72. package/dist/routes/db-routes.d.ts +6 -10
  73. package/dist/routes/db-routes.d.ts.map +1 -1
  74. package/dist/routes/db-routes.js +198 -172
  75. package/dist/routes/db-routes.js.map +7 -1
  76. package/dist/routes/health.js +15 -20
  77. package/dist/routes/health.js.map +7 -1
  78. package/dist/routes/messages.d.ts.map +1 -1
  79. package/dist/routes/messages.js +56 -63
  80. package/dist/routes/messages.js.map +7 -1
  81. package/dist/routes/module-config-routes.d.ts.map +1 -1
  82. package/dist/routes/module-config-routes.js +92 -111
  83. package/dist/routes/module-config-routes.js.map +7 -1
  84. package/dist/routes/modules.d.ts.map +1 -1
  85. package/dist/routes/modules.js +82 -88
  86. package/dist/routes/modules.js.map +7 -1
  87. package/dist/routes/service-routes.d.ts.map +1 -1
  88. package/dist/routes/service-routes.js +54 -61
  89. package/dist/routes/service-routes.js.map +7 -1
  90. package/dist/runtime.test.js +248 -49
  91. package/dist/runtime.test.js.map +7 -1
  92. package/dist/schema-registry.d.ts.map +1 -1
  93. package/dist/schema-registry.js +119 -160
  94. package/dist/schema-registry.js.map +7 -1
  95. package/dist/server.js +69 -72
  96. package/dist/server.js.map +7 -1
  97. package/dist/service-registry.d.ts.map +1 -1
  98. package/dist/service-registry.js +60 -67
  99. package/dist/service-registry.js.map +7 -1
  100. package/dist/services/builtin-handlers.d.ts +4 -0
  101. package/dist/services/builtin-handlers.d.ts.map +1 -1
  102. package/dist/services/builtin-handlers.js +34 -20
  103. package/dist/services/builtin-handlers.js.map +7 -1
  104. package/dist/services/economy-handlers.js +143 -132
  105. package/dist/services/economy-handlers.js.map +7 -1
  106. package/dist/tx-runner.d.ts +35 -11
  107. package/dist/tx-runner.d.ts.map +1 -1
  108. package/dist/tx-runner.js +293 -250
  109. package/dist/tx-runner.js.map +7 -1
  110. package/dist/where.js +71 -94
  111. package/dist/where.js.map +7 -1
  112. package/package.json +4 -4
@@ -1,178 +1,137 @@
1
- /**
2
- * schema-registry.ts — 收集模块 defineTable,统一建表
3
- *
4
- * 协议:
5
- * - 模块 SAPI 启动时调 db.defineTable(name, columns, {softDelete})
6
- * → POST /api/sfmc/db/define-table {moduleId, name, columns, softDelete}
7
- * - schema-registry 收集所有调用,CAS 锁
8
- * - 等所有"已注册模块"都调过(超时 fallback 或 explicit `finalize()`),
9
- * 一次性 CREATE TABLE IF NOT EXISTS + CREATE INDEX IF NOT EXISTS
10
- * - 同一 module 重复 define 同名表 = 幂等(同名 columns 允许)
11
- * - 不同 module 抢同名表 = 启动失败
12
- * - 平台表(moduleId = "__platform__")由 db-tables.ts 在 initSchema 直接 bootstrap
13
- *
14
- * 列类型白名单:
15
- * text / integer / real / blob
16
- * 修饰: primary / notNull / unique / default / index
17
- * softDelete = 自动加 _deleted_at INTEGER(列名带下划线) 和 _version INTEGER
18
- */
19
1
  import { log } from "./lib/log.js";
20
- export const PLATFORM_MODULE_ID = "__platform__";
2
+ const PLATFORM_MODULE_ID = "__platform__";
21
3
  const IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/;
22
- const VALID_TYPES = new Set(["text", "integer", "real", "blob"]);
4
+ const VALID_TYPES = /* @__PURE__ */ new Set(["text", "integer", "real", "blob"]);
23
5
  function assertValid(req, moduleId) {
24
- if (!IDENT.test(req.name))
25
- throw new Error(`[schema] ${moduleId}: invalid table name "${req.name}"`);
26
- if (!req.columns || Object.keys(req.columns).length === 0) {
27
- throw new Error(`[schema] ${moduleId}: ${req.name} has no columns`);
6
+ if (!IDENT.test(req.name)) throw new Error(`[schema] ${moduleId}: invalid table name "${req.name}"`);
7
+ if (!req.columns || Object.keys(req.columns).length === 0) {
8
+ throw new Error(`[schema] ${moduleId}: ${req.name} has no columns`);
9
+ }
10
+ let pks = 0;
11
+ for (const [colName, def] of Object.entries(req.columns)) {
12
+ if (!IDENT.test(colName)) throw new Error(`[schema] ${moduleId}: invalid column name "${colName}" in ${req.name}`);
13
+ if (!VALID_TYPES.has(def.type)) {
14
+ throw new Error(`[schema] ${moduleId}: ${req.name}.${colName} bad type "${def.type}"`);
28
15
  }
29
- let pks = 0;
30
- for (const [colName, def] of Object.entries(req.columns)) {
31
- if (!IDENT.test(colName))
32
- throw new Error(`[schema] ${moduleId}: invalid column name "${colName}" in ${req.name}`);
33
- if (!VALID_TYPES.has(def.type)) {
34
- throw new Error(`[schema] ${moduleId}: ${req.name}.${colName} bad type "${def.type}"`);
35
- }
36
- if (def.primary)
37
- pks++;
38
- if (def.ref) {
39
- const [t, c] = def.ref.split(".");
40
- if (!t || !c || !IDENT.test(t) || !IDENT.test(c)) {
41
- throw new Error(`[schema] ${moduleId}: ${req.name}.${colName} invalid ref "${def.ref}"`);
42
- }
43
- }
16
+ if (def.primary) pks++;
17
+ if (def.ref) {
18
+ const [t, c] = def.ref.split(".");
19
+ if (!t || !c || !IDENT.test(t) || !IDENT.test(c)) {
20
+ throw new Error(`[schema] ${moduleId}: ${req.name}.${colName} invalid ref "${def.ref}"`);
21
+ }
44
22
  }
45
- if (pks > 1)
46
- throw new Error(`[schema] ${moduleId}: ${req.name} has ${pks} primary keys (max 1)`);
23
+ }
24
+ if (pks > 1) throw new Error(`[schema] ${moduleId}: ${req.name} has ${pks} primary keys (max 1)`);
47
25
  }
48
- /**
49
- * 一次性把 columns 翻译成 CREATE TABLE。
50
- * 例如 {id:{type:"text",primary:true},name:{type:"text",notNull:true}}
51
- * → "id" TEXT PRIMARY KEY, "name" TEXT NOT NULL
52
- */
53
26
  function buildColumnClause(name, def) {
54
- const parts = [`"${name}"`, def.type.toUpperCase()];
55
- if (def.primary)
56
- parts.push("PRIMARY KEY");
57
- if (def.notNull && !def.primary)
58
- parts.push("NOT NULL");
59
- if (def.unique)
60
- parts.push("UNIQUE");
61
- if (def.default !== undefined && def.default !== null) {
62
- if (typeof def.default === "string")
63
- parts.push(`DEFAULT '${def.default.replace(/'/g, "''")}'`);
64
- else
65
- parts.push(`DEFAULT ${def.default}`);
66
- }
67
- if (def.ref)
68
- parts.push(`REFERENCES ${def.ref}`);
69
- return parts.join(" ");
27
+ const parts = [`"${name}"`, def.type.toUpperCase()];
28
+ if (def.primary) parts.push("PRIMARY KEY");
29
+ if (def.notNull && !def.primary) parts.push("NOT NULL");
30
+ if (def.unique) parts.push("UNIQUE");
31
+ if (def.default !== void 0 && def.default !== null) {
32
+ if (typeof def.default === "string") parts.push(`DEFAULT '${def.default.replace(/'/g, "''")}'`);
33
+ else parts.push(`DEFAULT ${def.default}`);
34
+ }
35
+ if (def.ref) parts.push(`REFERENCES ${def.ref}`);
36
+ return parts.join(" ");
70
37
  }
71
- /**
72
- * 把一张表的所有列(含 softDelete 隐式列)拼成 CREATE TABLE 的列定义数组。
73
- * 隐式 _deleted_at / _version 作为独立列在末尾追加「一次」(此前误在每个列
74
- * 子句里各追加一次,且无逗号分隔,导致 softDelete 表建表 SQL 语法错误)。
75
- */
76
38
  function buildColumnList(columns, softDelete) {
77
- const cols = [];
78
- for (const [n, def] of Object.entries(columns)) {
79
- cols.push(buildColumnClause(n, def));
80
- }
81
- if (softDelete) {
82
- cols.push('"_deleted_at" INTEGER', '"_version" INTEGER DEFAULT 0');
83
- }
84
- return cols;
39
+ const cols = [];
40
+ for (const [n, def] of Object.entries(columns)) {
41
+ cols.push(buildColumnClause(n, def));
42
+ }
43
+ if (softDelete) {
44
+ cols.push('"_deleted_at" INTEGER', '"_version" INTEGER DEFAULT 0');
45
+ }
46
+ return cols;
85
47
  }
86
- export class SchemaRegistry {
87
- db;
88
- tables = new Map();
89
- finalized = false;
90
- constructor(db) {
91
- this.db = db;
48
+ class SchemaRegistry {
49
+ db;
50
+ tables = /* @__PURE__ */ new Map();
51
+ finalized = false;
52
+ constructor(db) {
53
+ this.db = db;
54
+ }
55
+ /** 模块 SAPI 启动时调。 */
56
+ define(moduleId, req) {
57
+ if (this.finalized) {
58
+ throw new Error(`[schema] registry \u5DF2 finalize,\u6A21\u5757 ${moduleId} \u4E0D\u80FD\u518D defineTable`);
92
59
  }
93
- /** 模块 SAPI 启动时调。 */
94
- define(moduleId, req) {
95
- if (this.finalized) {
96
- throw new Error(`[schema] registry finalize,模块 ${moduleId} 不能再 defineTable`);
60
+ assertValid(req, moduleId);
61
+ const existing = this.tables.get(req.name);
62
+ if (existing) {
63
+ if (existing.moduleId === moduleId) {
64
+ if (JSON.stringify(existing.columns) !== JSON.stringify(req.columns)) {
65
+ throw new Error(`[schema] ${moduleId} \u91CD\u590D defineTable "${req.name}",columns \u4E0D\u4E00\u81F4`);
97
66
  }
98
- assertValid(req, moduleId);
99
- const existing = this.tables.get(req.name);
100
- if (existing) {
101
- if (existing.moduleId === moduleId) {
102
- // 同模块重复定义:校验 columns 一致
103
- if (JSON.stringify(existing.columns) !== JSON.stringify(req.columns)) {
104
- throw new Error(`[schema] ${moduleId} 重复 defineTable "${req.name}",columns 不一致`);
105
- }
106
- if (existing.softDelete !== (req.softDelete ?? true)) {
107
- throw new Error(`[schema] ${moduleId} 重复 defineTable "${req.name}",softDelete 不一致`);
108
- }
109
- log.info(`[schema] ${moduleId} 重复 define "${req.name}" 跳过`);
110
- return { table: req.name, created: false, indices: [] };
111
- }
112
- throw new Error(`[schema] 表 "${req.name}" 已被模块 ${existing.moduleId} 定义,${moduleId} 不能抢同名表`);
67
+ if (existing.softDelete !== (req.softDelete ?? true)) {
68
+ throw new Error(`[schema] ${moduleId} \u91CD\u590D defineTable "${req.name}",softDelete \u4E0D\u4E00\u81F4`);
113
69
  }
114
- const softDelete = req.softDelete ?? true;
115
- const defined = {
116
- moduleId,
117
- name: req.name,
118
- columns: req.columns,
119
- softDelete,
120
- };
121
- this.tables.set(req.name, defined);
122
- // 立即物理建表(幂等 CREATE TABLE IF NOT EXISTS)。
123
- // 原设计是「define 收集 → finalize 统一建表」,但 finalize() 从未被调用,
124
- // 导致模块表永远不会落地、后续 insert/query 全部 no such table。
125
- // 采用 define 即建表:碰撞检测已在上方按内存表完成,不影响单一 owner 保证。
126
- this.createPhysical(defined);
127
- return { table: req.name, created: true, indices: [] };
70
+ log.info(`[schema] ${moduleId} \u91CD\u590D define "${req.name}" \u8DF3\u8FC7`);
71
+ return { table: req.name, created: false, indices: [] };
72
+ }
73
+ throw new Error(
74
+ `[schema] \u8868 "${req.name}" \u5DF2\u88AB\u6A21\u5757 ${existing.moduleId} \u5B9A\u4E49,${moduleId} \u4E0D\u80FD\u62A2\u540C\u540D\u8868`
75
+ );
128
76
  }
129
- /** 幂等地物理建表 + 建索引(供 define / finalize 共用)。 */
130
- createPhysical(t) {
131
- const cols = buildColumnList(t.columns, t.softDelete);
132
- this.db.exec(`CREATE TABLE IF NOT EXISTS "${t.name}" (${cols.join(", ")})`);
133
- for (const [n, def] of Object.entries(t.columns)) {
134
- if (def.index) {
135
- const idxName = `idx_${t.name}_${n}`.slice(0, 60);
136
- this.db.exec(`CREATE INDEX IF NOT EXISTS "${idxName}" ON "${t.name}"("${n}")`);
137
- }
138
- }
77
+ const softDelete = req.softDelete ?? true;
78
+ const defined = {
79
+ moduleId,
80
+ name: req.name,
81
+ columns: req.columns,
82
+ softDelete
83
+ };
84
+ this.tables.set(req.name, defined);
85
+ this.createPhysical(defined);
86
+ return { table: req.name, created: true, indices: [] };
87
+ }
88
+ /** 幂等地物理建表 + 建索引(供 define / finalize 共用)。 */
89
+ createPhysical(t) {
90
+ const cols = buildColumnList(t.columns, t.softDelete);
91
+ this.db.exec(`CREATE TABLE IF NOT EXISTS "${t.name}" (${cols.join(", ")})`);
92
+ for (const [n, def] of Object.entries(t.columns)) {
93
+ if (def.index) {
94
+ const idxName = `idx_${t.name}_${n}`.slice(0, 60);
95
+ this.db.exec(`CREATE INDEX IF NOT EXISTS "${idxName}" ON "${t.name}"("${n}")`);
96
+ }
139
97
  }
140
- /**
141
- * 真正建表的时刻。所有 enabled 模块 init 完成(或明确调)后再 finalize。
142
- * CREATE TABLE IF NOT EXISTS + CREATE INDEX IF NOT EXISTS,幂等。
143
- */
144
- finalize() {
145
- if (this.finalized)
146
- return { tableNames: [...this.tables.keys()], created: [] };
147
- this.finalized = true;
148
- const created = [];
149
- for (const t of this.tables.values()) {
150
- const cols = buildColumnList(t.columns, t.softDelete);
151
- const ddl = `CREATE TABLE IF NOT EXISTS "${t.name}" (${cols.join(", ")})`;
152
- this.db.exec(ddl);
153
- for (const [n, def] of Object.entries(t.columns)) {
154
- if (def.index) {
155
- const idxName = `idx_${t.name}_${n}`.slice(0, 60);
156
- this.db.exec(`CREATE INDEX IF NOT EXISTS "${idxName}" ON "${t.name}"("${n}")`);
157
- }
158
- }
159
- const exists = this.db
160
- .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?")
161
- .get(t.name)?.name === t.name;
162
- if (exists)
163
- created.push(t.name);
164
- log.success(`[schema] ${t.moduleId} → ${t.name} (softDelete=${t.softDelete})`);
98
+ }
99
+ /**
100
+ * 真正建表的时刻。所有 enabled 模块 init 完成(或明确调)后再 finalize。
101
+ * CREATE TABLE IF NOT EXISTS + CREATE INDEX IF NOT EXISTS,幂等。
102
+ */
103
+ finalize() {
104
+ if (this.finalized) return { tableNames: [...this.tables.keys()], created: [] };
105
+ this.finalized = true;
106
+ const created = [];
107
+ for (const t of this.tables.values()) {
108
+ const cols = buildColumnList(t.columns, t.softDelete);
109
+ const ddl = `CREATE TABLE IF NOT EXISTS "${t.name}" (${cols.join(", ")})`;
110
+ this.db.exec(ddl);
111
+ for (const [n, def] of Object.entries(t.columns)) {
112
+ if (def.index) {
113
+ const idxName = `idx_${t.name}_${n}`.slice(0, 60);
114
+ this.db.exec(`CREATE INDEX IF NOT EXISTS "${idxName}" ON "${t.name}"("${n}")`);
165
115
  }
166
- return { tableNames: [...this.tables.keys()], created };
167
- }
168
- listTables() {
169
- return [...this.tables.keys()];
170
- }
171
- isRegistered(name) {
172
- return this.tables.has(name);
173
- }
174
- getOwner(name) {
175
- return this.tables.get(name)?.moduleId;
116
+ }
117
+ const exists = this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(t.name)?.name === t.name;
118
+ if (exists) created.push(t.name);
119
+ log.success(`[schema] ${t.moduleId} \u2192 ${t.name} (softDelete=${t.softDelete})`);
176
120
  }
121
+ return { tableNames: [...this.tables.keys()], created };
122
+ }
123
+ listTables() {
124
+ return [...this.tables.keys()];
125
+ }
126
+ isRegistered(name) {
127
+ return this.tables.has(name);
128
+ }
129
+ getOwner(name) {
130
+ return this.tables.get(name)?.moduleId;
131
+ }
177
132
  }
178
- //# sourceMappingURL=schema-registry.js.map
133
+ export {
134
+ PLATFORM_MODULE_ID,
135
+ SchemaRegistry
136
+ };
137
+ //# sourceMappingURL=schema-registry.js.map
@@ -1 +1,7 @@
1
- {"version":3,"file":"schema-registry.js","sourceRoot":"","sources":["../src/schema-registry.ts"],"names":[],"mappings":"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"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/schema-registry.ts"],
4
+ "sourcesContent": ["/**\n * schema-registry.ts \u2014 \u6536\u96C6\u6A21\u5757 defineTable,\u7EDF\u4E00\u5EFA\u8868\n *\n * \u534F\u8BAE:\n * - \u6A21\u5757 SAPI \u542F\u52A8\u65F6\u8C03 db.defineTable(name, columns, {softDelete})\n * \u2192 POST /api/sfmc/db/define-table {moduleId, name, columns, softDelete}\n * - schema-registry \u6536\u96C6\u6240\u6709\u8C03\u7528,CAS \u9501\n * - \u7B49\u6240\u6709\"\u5DF2\u6CE8\u518C\u6A21\u5757\"\u90FD\u8C03\u8FC7(\u8D85\u65F6 fallback \u6216 explicit `finalize()`),\n * \u4E00\u6B21\u6027 CREATE TABLE IF NOT EXISTS + CREATE INDEX IF NOT EXISTS\n * - \u540C\u4E00 module \u91CD\u590D define \u540C\u540D\u8868 = \u5E42\u7B49(\u540C\u540D columns \u5141\u8BB8)\n * - \u4E0D\u540C module \u62A2\u540C\u540D\u8868 = \u542F\u52A8\u5931\u8D25\n * - \u5E73\u53F0\u8868(moduleId = \"__platform__\")\u7531 db-tables.ts \u5728 initSchema \u76F4\u63A5 bootstrap\n *\n * \u5217\u7C7B\u578B\u767D\u540D\u5355:\n * text / integer / real / blob\n * \u4FEE\u9970: primary / notNull / unique / default / index\n * softDelete = \u81EA\u52A8\u52A0 _deleted_at INTEGER(\u5217\u540D\u5E26\u4E0B\u5212\u7EBF) \u548C _version INTEGER\n */\n\nimport type { DatabaseSync } from \"node:sqlite\";\nimport { log } from \"./lib/log.js\";\n\nexport type ColumnType = \"text\" | \"integer\" | \"real\" | \"blob\";\n\nexport interface ColumnDef {\n type: ColumnType;\n primary?: boolean;\n notNull?: boolean;\n unique?: boolean;\n default?: Primitive;\n index?: boolean;\n ref?: string;\n}\n\nexport type Primitive = string | number | boolean | null;\n\nexport interface DefineTableRequest {\n name: string;\n columns: Record<string, ColumnDef>;\n softDelete?: boolean;\n}\n\nexport interface DefineTableResult {\n table: string;\n created: boolean;\n indices: string[];\n}\n\ninterface DefinedTable {\n moduleId: string;\n name: string;\n columns: Record<string, ColumnDef>;\n softDelete: boolean;\n}\n\nexport const PLATFORM_MODULE_ID = \"__platform__\";\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/;\nconst VALID_TYPES: Set<ColumnType> = new Set([\"text\", \"integer\", \"real\", \"blob\"]);\n\nfunction assertValid(req: DefineTableRequest, moduleId: string): void {\n if (!IDENT.test(req.name)) throw new Error(`[schema] ${moduleId}: invalid table name \"${req.name}\"`);\n if (!req.columns || Object.keys(req.columns).length === 0) {\n throw new Error(`[schema] ${moduleId}: ${req.name} has no columns`);\n }\n let pks = 0;\n for (const [colName, def] of Object.entries(req.columns)) {\n if (!IDENT.test(colName)) throw new Error(`[schema] ${moduleId}: invalid column name \"${colName}\" in ${req.name}`);\n if (!VALID_TYPES.has(def.type)) {\n throw new Error(`[schema] ${moduleId}: ${req.name}.${colName} bad type \"${def.type}\"`);\n }\n if (def.primary) pks++;\n if (def.ref) {\n const [t, c] = def.ref.split(\".\");\n if (!t || !c || !IDENT.test(t) || !IDENT.test(c)) {\n throw new Error(`[schema] ${moduleId}: ${req.name}.${colName} invalid ref \"${def.ref}\"`);\n }\n }\n }\n if (pks > 1) throw new Error(`[schema] ${moduleId}: ${req.name} has ${pks} primary keys (max 1)`);\n}\n\n/**\n * \u4E00\u6B21\u6027\u628A columns \u7FFB\u8BD1\u6210 CREATE TABLE\u3002\n * \u4F8B\u5982 {id:{type:\"text\",primary:true},name:{type:\"text\",notNull:true}}\n * \u2192 \"id\" TEXT PRIMARY KEY, \"name\" TEXT NOT NULL\n */\nfunction buildColumnClause(name: string, def: ColumnDef): string {\n const parts: string[] = [`\"${name}\"`, def.type.toUpperCase()];\n if (def.primary) parts.push(\"PRIMARY KEY\");\n if (def.notNull && !def.primary) parts.push(\"NOT NULL\");\n if (def.unique) parts.push(\"UNIQUE\");\n if (def.default !== undefined && def.default !== null) {\n if (typeof def.default === \"string\") parts.push(`DEFAULT '${def.default.replace(/'/g, \"''\")}'`);\n else parts.push(`DEFAULT ${def.default}`);\n }\n if (def.ref) parts.push(`REFERENCES ${def.ref}`);\n return parts.join(\" \");\n}\n\n/**\n * \u628A\u4E00\u5F20\u8868\u7684\u6240\u6709\u5217(\u542B softDelete \u9690\u5F0F\u5217)\u62FC\u6210 CREATE TABLE \u7684\u5217\u5B9A\u4E49\u6570\u7EC4\u3002\n * \u9690\u5F0F _deleted_at / _version \u4F5C\u4E3A\u72EC\u7ACB\u5217\u5728\u672B\u5C3E\u8FFD\u52A0\u300C\u4E00\u6B21\u300D(\u6B64\u524D\u8BEF\u5728\u6BCF\u4E2A\u5217\n * \u5B50\u53E5\u91CC\u5404\u8FFD\u52A0\u4E00\u6B21,\u4E14\u65E0\u9017\u53F7\u5206\u9694,\u5BFC\u81F4 softDelete \u8868\u5EFA\u8868 SQL \u8BED\u6CD5\u9519\u8BEF)\u3002\n */\nfunction buildColumnList(columns: Record<string, ColumnDef>, softDelete: boolean): string[] {\n const cols: string[] = [];\n for (const [n, def] of Object.entries(columns)) {\n cols.push(buildColumnClause(n, def));\n }\n if (softDelete) {\n cols.push('\"_deleted_at\" INTEGER', '\"_version\" INTEGER DEFAULT 0');\n }\n return cols;\n}\n\nexport class SchemaRegistry {\n private readonly db: DatabaseSync;\n private readonly tables = new Map<string, DefinedTable>();\n private finalized = false;\n\n constructor(db: DatabaseSync) {\n this.db = db;\n }\n\n /** \u6A21\u5757 SAPI \u542F\u52A8\u65F6\u8C03\u3002 */\n define(moduleId: string, req: DefineTableRequest): DefineTableResult {\n if (this.finalized) {\n throw new Error(`[schema] registry \u5DF2 finalize,\u6A21\u5757 ${moduleId} \u4E0D\u80FD\u518D defineTable`);\n }\n assertValid(req, moduleId);\n\n const existing = this.tables.get(req.name);\n if (existing) {\n if (existing.moduleId === moduleId) {\n // \u540C\u6A21\u5757\u91CD\u590D\u5B9A\u4E49:\u6821\u9A8C columns \u4E00\u81F4\n if (JSON.stringify(existing.columns) !== JSON.stringify(req.columns)) {\n throw new Error(`[schema] ${moduleId} \u91CD\u590D defineTable \"${req.name}\",columns \u4E0D\u4E00\u81F4`);\n }\n if (existing.softDelete !== (req.softDelete ?? true)) {\n throw new Error(`[schema] ${moduleId} \u91CD\u590D defineTable \"${req.name}\",softDelete \u4E0D\u4E00\u81F4`);\n }\n log.info(`[schema] ${moduleId} \u91CD\u590D define \"${req.name}\" \u8DF3\u8FC7`);\n return { table: req.name, created: false, indices: [] };\n }\n throw new Error(\n `[schema] \u8868 \"${req.name}\" \u5DF2\u88AB\u6A21\u5757 ${existing.moduleId} \u5B9A\u4E49,${moduleId} \u4E0D\u80FD\u62A2\u540C\u540D\u8868`\n );\n }\n\n const softDelete = req.softDelete ?? true;\n const defined: DefinedTable = {\n moduleId,\n name: req.name,\n columns: req.columns,\n softDelete,\n };\n this.tables.set(req.name, defined);\n // \u7ACB\u5373\u7269\u7406\u5EFA\u8868(\u5E42\u7B49 CREATE TABLE IF NOT EXISTS)\u3002\n // \u539F\u8BBE\u8BA1\u662F\u300Cdefine \u6536\u96C6 \u2192 finalize \u7EDF\u4E00\u5EFA\u8868\u300D,\u4F46 finalize() \u4ECE\u672A\u88AB\u8C03\u7528,\n // \u5BFC\u81F4\u6A21\u5757\u8868\u6C38\u8FDC\u4E0D\u4F1A\u843D\u5730\u3001\u540E\u7EED insert/query \u5168\u90E8 no such table\u3002\n // \u91C7\u7528 define \u5373\u5EFA\u8868:\u78B0\u649E\u68C0\u6D4B\u5DF2\u5728\u4E0A\u65B9\u6309\u5185\u5B58\u8868\u5B8C\u6210,\u4E0D\u5F71\u54CD\u5355\u4E00 owner \u4FDD\u8BC1\u3002\n this.createPhysical(defined);\n return { table: req.name, created: true, indices: [] };\n }\n\n /** \u5E42\u7B49\u5730\u7269\u7406\u5EFA\u8868 + \u5EFA\u7D22\u5F15(\u4F9B define / finalize \u5171\u7528)\u3002 */\n private createPhysical(t: DefinedTable): void {\n const cols = buildColumnList(t.columns, t.softDelete);\n this.db.exec(`CREATE TABLE IF NOT EXISTS \"${t.name}\" (${cols.join(\", \")})`);\n for (const [n, def] of Object.entries(t.columns)) {\n if (def.index) {\n const idxName = `idx_${t.name}_${n}`.slice(0, 60);\n this.db.exec(`CREATE INDEX IF NOT EXISTS \"${idxName}\" ON \"${t.name}\"(\"${n}\")`);\n }\n }\n }\n\n /**\n * \u771F\u6B63\u5EFA\u8868\u7684\u65F6\u523B\u3002\u6240\u6709 enabled \u6A21\u5757 init \u5B8C\u6210(\u6216\u660E\u786E\u8C03)\u540E\u518D finalize\u3002\n * CREATE TABLE IF NOT EXISTS + CREATE INDEX IF NOT EXISTS,\u5E42\u7B49\u3002\n */\n finalize(): { tableNames: string[]; created: string[] } {\n if (this.finalized) return { tableNames: [...this.tables.keys()], created: [] };\n this.finalized = true;\n const created: string[] = [];\n\n for (const t of this.tables.values()) {\n const cols = buildColumnList(t.columns, t.softDelete);\n const ddl = `CREATE TABLE IF NOT EXISTS \"${t.name}\" (${cols.join(\", \")})`;\n this.db.exec(ddl);\n\n for (const [n, def] of Object.entries(t.columns)) {\n if (def.index) {\n const idxName = `idx_${t.name}_${n}`.slice(0, 60);\n this.db.exec(`CREATE INDEX IF NOT EXISTS \"${idxName}\" ON \"${t.name}\"(\"${n}\")`);\n }\n }\n\n const exists =\n (this.db\n .prepare(\"SELECT name FROM sqlite_master WHERE type='table' AND name=?\")\n .get(t.name) as { name?: string } | undefined)?.name === t.name;\n if (exists) created.push(t.name);\n log.success(`[schema] ${t.moduleId} \u2192 ${t.name} (softDelete=${t.softDelete})`);\n }\n\n return { tableNames: [...this.tables.keys()], created };\n }\n\n listTables(): string[] {\n return [...this.tables.keys()];\n }\n\n isRegistered(name: string): boolean {\n return this.tables.has(name);\n }\n\n getOwner(name: string): string | undefined {\n return this.tables.get(name)?.moduleId;\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/dist/server.js CHANGED
@@ -1,82 +1,79 @@
1
- /**
2
- * server.ts — HTTP 服务 + 控制台
3
- */
4
1
  import http from "node:http";
5
2
  import net from "node:net";
6
3
  import readline from "node:readline";
7
4
  import { log } from "./lib/log.js";
8
- export function checkPortConflict(port) {
9
- return new Promise((resolve) => {
10
- const server = net.createServer();
11
- server.once("error", (err) => {
12
- const result = { ok: false, port };
13
- if (err.code) {
14
- result.error = err.code;
15
- }
16
- resolve(result);
17
- });
18
- server.once("listening", () => {
19
- server.close();
20
- resolve({ ok: true, port });
21
- });
22
- server.listen(port, "127.0.0.1");
5
+ function checkPortConflict(port) {
6
+ return new Promise((resolve) => {
7
+ const server = net.createServer();
8
+ server.once("error", (err) => {
9
+ const result = { ok: false, port };
10
+ if (err.code) {
11
+ result.error = err.code;
12
+ }
13
+ resolve(result);
23
14
  });
15
+ server.once("listening", () => {
16
+ server.close();
17
+ resolve({ ok: true, port });
18
+ });
19
+ server.listen(port, "127.0.0.1");
20
+ });
24
21
  }
25
- export function createServer({ handle, env, onListening }) {
26
- const server = http.createServer((req, res) => {
27
- const startedAt = Date.now();
28
- let bodyStr = "";
29
- const chunks = [];
30
- req.on("data", (c) => chunks.push(c));
31
- req.on("end", () => {
32
- bodyStr = Buffer.concat(chunks).toString("utf-8").slice(0, 300);
33
- req.bodyBuffer = bodyStr;
34
- });
35
- res.once("finish", () => {
36
- const quietPoll = (req.url ?? "").startsWith("/api/sfmc/messages?") && res.statusCode < 400;
37
- const bodySnippet = req.method === "GET" ? "" : ` ${bodyStr.slice(0, 200)}`;
38
- if (!quietPoll)
39
- log.info(`[HTTP] ${req.method} ${req.url} ${res.statusCode} ${Date.now() - startedAt}ms${bodySnippet}`);
40
- });
41
- void handle(req, res);
22
+ function createServer({ handle, env, onListening }) {
23
+ const server = http.createServer((req, res) => {
24
+ const startedAt = Date.now();
25
+ let bodyStr = "";
26
+ const chunks = [];
27
+ req.on("data", (c) => chunks.push(c));
28
+ req.on("end", () => {
29
+ bodyStr = Buffer.concat(chunks).toString("utf-8").slice(0, 300);
30
+ req.bodyBuffer = bodyStr;
42
31
  });
43
- server.listen(env.PORT, env.HOST, () => {
44
- log.success(`HTTP 服务已启动,端口 ${env.PORT} (loopback only)`);
45
- log.info(`API 健康检查: http://${env.HOST}:${env.PORT}/api/health`);
46
- log.info(`鉴权: ${env.AUTH_TOKEN ? "已启用 token" : "未启用"}`);
47
- if (onListening)
48
- onListening(server);
32
+ res.once("finish", () => {
33
+ const quietPoll = (req.url ?? "").startsWith("/api/sfmc/messages?") && res.statusCode < 400;
34
+ const bodySnippet = req.method === "GET" ? "" : ` ${bodyStr.slice(0, 200)}`;
35
+ if (!quietPoll)
36
+ log.info(`[HTTP] ${req.method} ${req.url} ${res.statusCode} ${Date.now() - startedAt}ms${bodySnippet}`);
49
37
  });
50
- return server;
38
+ void handle(req, res);
39
+ });
40
+ server.listen(env.PORT, env.HOST, () => {
41
+ log.success(`HTTP \u670D\u52A1\u5DF2\u542F\u52A8\uFF0C\u7AEF\u53E3 ${env.PORT} (loopback only)`);
42
+ log.info(`API \u5065\u5EB7\u68C0\u67E5: http://${env.HOST}:${env.PORT}/api/health`);
43
+ log.info(`\u9274\u6743: ${env.AUTH_TOKEN ? "\u5DF2\u542F\u7528 token" : "\u672A\u542F\u7528"}`);
44
+ if (onListening) onListening(server);
45
+ });
46
+ return server;
51
47
  }
52
- export function startConsole(server, db) {
53
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
54
- rl.on("line", (line) => {
55
- const cmd = line.trim().toLowerCase();
56
- if (cmd === "help") {
57
- console.log("DB Server 可用命令:");
58
- console.log(" help 显示帮助");
59
- console.log(" status 显示服务状态");
60
- console.log(" stop 停止服务");
61
- }
62
- else if (cmd === "status") {
63
- console.log(`状态: 运行中`);
64
- console.log(` HTTP 端口: ${server.address().port}`);
65
- console.log(` 数据库: ${db ? "(已连接)" : "(未连接)"}`);
66
- }
67
- else if (cmd === "stop") {
68
- log.info("正在停止服务...");
69
- rl.close();
70
- server.close();
71
- if (db)
72
- db.close();
73
- process.exit(0);
74
- }
75
- else {
76
- log.warn(`未知命令: ${cmd},输入 help 查看帮助`);
77
- }
78
- });
79
- rl.on("SIGINT", () => process.exit());
80
- return rl;
48
+ function startConsole(server, db) {
49
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
50
+ rl.on("line", (line) => {
51
+ const cmd = line.trim().toLowerCase();
52
+ if (cmd === "help") {
53
+ console.log("DB Server \u53EF\u7528\u547D\u4EE4:");
54
+ console.log(" help \u2014 \u663E\u793A\u5E2E\u52A9");
55
+ console.log(" status \u2014 \u663E\u793A\u670D\u52A1\u72B6\u6001");
56
+ console.log(" stop \u2014 \u505C\u6B62\u670D\u52A1");
57
+ } else if (cmd === "status") {
58
+ console.log(`\u72B6\u6001: \u8FD0\u884C\u4E2D`);
59
+ console.log(` HTTP \u7AEF\u53E3: ${server.address().port}`);
60
+ console.log(` \u6570\u636E\u5E93: ${db ? "(\u5DF2\u8FDE\u63A5)" : "(\u672A\u8FDE\u63A5)"}`);
61
+ } else if (cmd === "stop") {
62
+ log.info("\u6B63\u5728\u505C\u6B62\u670D\u52A1...");
63
+ rl.close();
64
+ server.close();
65
+ if (db) db.close();
66
+ process.exit(0);
67
+ } else {
68
+ log.warn(`\u672A\u77E5\u547D\u4EE4: ${cmd}\uFF0C\u8F93\u5165 help \u67E5\u770B\u5E2E\u52A9`);
69
+ }
70
+ });
71
+ rl.on("SIGINT", () => process.exit());
72
+ return rl;
81
73
  }
82
- //# sourceMappingURL=server.js.map
74
+ export {
75
+ checkPortConflict,
76
+ createServer,
77
+ startConsole
78
+ };
79
+ //# sourceMappingURL=server.js.map
@@ -1 +1,7 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/server.ts"],
4
+ "sourcesContent": ["/**\n * server.ts \u2014 HTTP \u670D\u52A1 + \u63A7\u5236\u53F0\n */\n\nimport http from \"node:http\";\nimport net from \"node:net\";\nimport readline from \"node:readline\";\nimport type { DatabaseSync } from \"node:sqlite\";\n\nimport { log } from \"./lib/log.js\";\n\ninterface CheckResult {\n ok: boolean;\n port: number;\n error?: string;\n}\n\nexport function checkPortConflict(port: number): Promise<CheckResult> {\n return new Promise((resolve) => {\n const server = net.createServer();\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n const result: { ok: false; port: number; error?: string } = { ok: false, port };\n if (err.code) {\n result.error = err.code;\n }\n resolve(result);\n });\n server.once(\"listening\", () => {\n server.close();\n resolve({ ok: true, port });\n });\n server.listen(port, \"127.0.0.1\");\n });\n}\n\nexport type ServerEnv = {\n PORT: number;\n HOST: string;\n AUTH_TOKEN?: string;\n};\n\nexport type Handler = (req: http.IncomingMessage, res: http.ServerResponse) => void | Promise<void>;\n\nexport interface ServerOptions {\n env: ServerEnv;\n handle: Handler;\n onListening?: (server: http.Server) => void;\n}\n\nexport function createServer({ handle, env, onListening }: ServerOptions): http.Server {\n const server = http.createServer((req, res) => {\n const startedAt = Date.now();\n let bodyStr = \"\";\n const chunks: Buffer[] = [];\n req.on(\"data\", (c: Buffer) => chunks.push(c));\n req.on(\"end\", () => {\n bodyStr = Buffer.concat(chunks).toString(\"utf-8\").slice(0, 300);\n (req as http.IncomingMessage & { bodyBuffer: string }).bodyBuffer = bodyStr;\n });\n res.once(\"finish\", () => {\n const quietPoll = (req.url ?? \"\").startsWith(\"/api/sfmc/messages?\") && res.statusCode < 400;\n const bodySnippet = req.method === \"GET\" ? \"\" : ` ${bodyStr.slice(0, 200)}`;\n if (!quietPoll)\n log.info(`[HTTP] ${req.method} ${req.url} ${res.statusCode} ${Date.now() - startedAt}ms${bodySnippet}`);\n });\n void handle(req, res);\n });\n\n server.listen(env.PORT, env.HOST, () => {\n log.success(`HTTP \u670D\u52A1\u5DF2\u542F\u52A8\uFF0C\u7AEF\u53E3 ${env.PORT} (loopback only)`);\n log.info(`API \u5065\u5EB7\u68C0\u67E5: http://${env.HOST}:${env.PORT}/api/health`);\n log.info(`\u9274\u6743: ${env.AUTH_TOKEN ? \"\u5DF2\u542F\u7528 token\" : \"\u672A\u542F\u7528\"}`);\n if (onListening) onListening(server);\n });\n\n return server;\n}\n\nexport function startConsole(server: http.Server, db: DatabaseSync | null): readline.Interface {\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n rl.on(\"line\", (line: string) => {\n const cmd = line.trim().toLowerCase();\n if (cmd === \"help\") {\n console.log(\"DB Server \u53EF\u7528\u547D\u4EE4:\");\n console.log(\" help \u2014 \u663E\u793A\u5E2E\u52A9\");\n console.log(\" status \u2014 \u663E\u793A\u670D\u52A1\u72B6\u6001\");\n console.log(\" stop \u2014 \u505C\u6B62\u670D\u52A1\");\n } else if (cmd === \"status\") {\n console.log(`\u72B6\u6001: \u8FD0\u884C\u4E2D`);\n console.log(` HTTP \u7AEF\u53E3: ${(server.address() as { port: number }).port}`);\n console.log(` \u6570\u636E\u5E93: ${db ? \"(\u5DF2\u8FDE\u63A5)\" : \"(\u672A\u8FDE\u63A5)\"}`);\n } else if (cmd === \"stop\") {\n log.info(\"\u6B63\u5728\u505C\u6B62\u670D\u52A1...\");\n rl.close();\n server.close();\n if (db) db.close();\n process.exit(0);\n } else {\n log.warn(`\u672A\u77E5\u547D\u4EE4: ${cmd}\uFF0C\u8F93\u5165 help \u67E5\u770B\u5E2E\u52A9`);\n }\n });\n rl.on(\"SIGINT\", () => process.exit());\n return rl;\n}\n\n"],
5
+ "mappings": "AAIA,OAAO,UAAU;AACjB,OAAO,SAAS;AAChB,OAAO,cAAc;AAGrB,SAAS,WAAW;AAQb,SAAS,kBAAkB,MAAoC;AACpE,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,SAAS,IAAI,aAAa;AAChC,WAAO,KAAK,SAAS,CAAC,QAA+B;AACnD,YAAM,SAAsD,EAAE,IAAI,OAAO,KAAK;AAC9E,UAAI,IAAI,MAAM;AACZ,eAAO,QAAQ,IAAI;AAAA,MACrB;AACA,cAAQ,MAAM;AAAA,IAChB,CAAC;AACD,WAAO,KAAK,aAAa,MAAM;AAC7B,aAAO,MAAM;AACb,cAAQ,EAAE,IAAI,MAAM,KAAK,CAAC;AAAA,IAC5B,CAAC;AACD,WAAO,OAAO,MAAM,WAAW;AAAA,EACjC,CAAC;AACH;AAgBO,SAAS,aAAa,EAAE,QAAQ,KAAK,YAAY,GAA+B;AACrF,QAAM,SAAS,KAAK,aAAa,CAAC,KAAK,QAAQ;AAC7C,UAAM,YAAY,KAAK,IAAI;AAC3B,QAAI,UAAU;AACd,UAAM,SAAmB,CAAC;AAC1B,QAAI,GAAG,QAAQ,CAAC,MAAc,OAAO,KAAK,CAAC,CAAC;AAC5C,QAAI,GAAG,OAAO,MAAM;AAClB,gBAAU,OAAO,OAAO,MAAM,EAAE,SAAS,OAAO,EAAE,MAAM,GAAG,GAAG;AAC9D,MAAC,IAAsD,aAAa;AAAA,IACtE,CAAC;AACD,QAAI,KAAK,UAAU,MAAM;AACvB,YAAM,aAAa,IAAI,OAAO,IAAI,WAAW,qBAAqB,KAAK,IAAI,aAAa;AACxF,YAAM,cAAc,IAAI,WAAW,QAAQ,KAAK,IAAI,QAAQ,MAAM,GAAG,GAAG,CAAC;AACzE,UAAI,CAAC;AACH,YAAI,KAAK,UAAU,IAAI,MAAM,IAAI,IAAI,GAAG,IAAI,IAAI,UAAU,IAAI,KAAK,IAAI,IAAI,SAAS,KAAK,WAAW,EAAE;AAAA,IAC1G,CAAC;AACD,SAAK,OAAO,KAAK,GAAG;AAAA,EACtB,CAAC;AAED,SAAO,OAAO,IAAI,MAAM,IAAI,MAAM,MAAM;AACtC,QAAI,QAAQ,yDAAiB,IAAI,IAAI,kBAAkB;AACvD,QAAI,KAAK,wCAAoB,IAAI,IAAI,IAAI,IAAI,IAAI,aAAa;AAC9D,QAAI,KAAK,iBAAO,IAAI,aAAa,6BAAc,oBAAK,EAAE;AACtD,QAAI,YAAa,aAAY,MAAM;AAAA,EACrC,CAAC;AAED,SAAO;AACT;AAEO,SAAS,aAAa,QAAqB,IAA6C;AAC7F,QAAM,KAAK,SAAS,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AACpF,KAAG,GAAG,QAAQ,CAAC,SAAiB;AAC9B,UAAM,MAAM,KAAK,KAAK,EAAE,YAAY;AACpC,QAAI,QAAQ,QAAQ;AAClB,cAAQ,IAAI,qCAAiB;AAC7B,cAAQ,IAAI,2CAAkB;AAC9B,cAAQ,IAAI,uDAAoB;AAChC,cAAQ,IAAI,2CAAkB;AAAA,IAChC,WAAW,QAAQ,UAAU;AAC3B,cAAQ,IAAI,kCAAS;AACrB,cAAQ,IAAI,wBAAe,OAAO,QAAQ,EAAuB,IAAI,EAAE;AACvE,cAAQ,IAAI,yBAAU,KAAK,yBAAU,sBAAO,EAAE;AAAA,IAChD,WAAW,QAAQ,QAAQ;AACzB,UAAI,KAAK,yCAAW;AACpB,SAAG,MAAM;AACT,aAAO,MAAM;AACb,UAAI,GAAI,IAAG,MAAM;AACjB,cAAQ,KAAK,CAAC;AAAA,IAChB,OAAO;AACL,UAAI,KAAK,6BAAS,GAAG,kDAAe;AAAA,IACtC;AAAA,EACF,CAAC;AACD,KAAG,GAAG,UAAU,MAAM,QAAQ,KAAK,CAAC;AACpC,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"service-registry.d.ts","sourceRoot":"","sources":["../src/service-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,EAAE,EAAE,YAAY,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,8CAA8C;IAC9C,EAAE,CAAC,EAAE,gBAAgB,CAAC;CACvB;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,sBAAsB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAO/E,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwC;IAEjE,mCAAmC;IACnC,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI;IAO7E,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIrC,IAAI,IAAI,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAI3C,QAAQ,CACZ,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,EACtC,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,EAChB,EAAE,CAAC,EAAE,gBAAgB,GACpB,OAAO,CAAC,iBAAiB,CAAC;CAuC9B;AAED,qBAAa,aAAc,SAAQ,KAAK;IACtC,IAAI,EAAE,iBAAiB,GAAG,iBAAiB,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,CAAC;IACxF,MAAM,EAAE,MAAM,CAAC;gBAEb,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,iBAAiB,GAAG,iBAAiB,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,EACvF,MAAM,EAAE,MAAM;CAMjB"}
1
+ {"version":3,"file":"service-registry.d.ts","sourceRoot":"","sources":["../src/service-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,EAAE,EAAE,YAAY,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,8CAA8C;IAC9C,EAAE,CAAC,EAAE,gBAAgB,CAAC;CACvB;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,sBAAsB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAO/E,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwC;IAEjE,mCAAmC;IACnC,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,CAK5E;IAED,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEpC;IAED,IAAI,IAAI,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAEhD;IAEK,QAAQ,CACZ,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,EACtC,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,EAChB,EAAE,CAAC,EAAE,gBAAgB,GACpB,OAAO,CAAC,iBAAiB,CAAC,CAqC5B;CAEF;AAED,qBAAa,aAAc,SAAQ,KAAK;IACtC,IAAI,EAAE,iBAAiB,GAAG,iBAAiB,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,CAAC;IACxF,MAAM,EAAE,MAAM,CAAC;IACf,YACE,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,iBAAiB,GAAG,iBAAiB,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,EACvF,MAAM,EAAE,MAAM,EAKf;CACF"}