@yss123/cage-kernel 0.0.0-stage → 0.2.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 (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +20 -2
  3. package/dist/brands.d.ts +32 -0
  4. package/dist/brands.js +35 -0
  5. package/dist/brands.js.map +1 -0
  6. package/dist/db/connect.d.ts +28 -0
  7. package/dist/db/connect.js +57 -0
  8. package/dist/db/connect.js.map +1 -0
  9. package/dist/db/ddl.d.ts +69 -0
  10. package/dist/db/ddl.js +522 -0
  11. package/dist/db/ddl.js.map +1 -0
  12. package/dist/db/index.d.ts +5 -0
  13. package/dist/db/index.js +7 -0
  14. package/dist/db/index.js.map +1 -0
  15. package/dist/db/migrate.d.ts +22 -0
  16. package/dist/db/migrate.js +87 -0
  17. package/dist/db/migrate.js.map +1 -0
  18. package/dist/db/rows.d.ts +10 -0
  19. package/dist/db/rows.js +59 -0
  20. package/dist/db/rows.js.map +1 -0
  21. package/dist/db/session.d.ts +4 -0
  22. package/dist/db/session.js +20 -0
  23. package/dist/db/session.js.map +1 -0
  24. package/dist/errors.d.ts +44 -0
  25. package/dist/errors.js +83 -0
  26. package/dist/errors.js.map +1 -0
  27. package/dist/index.d.ts +23 -0
  28. package/dist/index.js +25 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/kernel.d.ts +99 -0
  31. package/dist/kernel.js +456 -0
  32. package/dist/kernel.js.map +1 -0
  33. package/dist/mask.d.ts +13 -0
  34. package/dist/mask.js +67 -0
  35. package/dist/mask.js.map +1 -0
  36. package/dist/org.d.ts +46 -0
  37. package/dist/org.js +127 -0
  38. package/dist/org.js.map +1 -0
  39. package/dist/pipeline/idempotency.d.ts +10 -0
  40. package/dist/pipeline/idempotency.js +29 -0
  41. package/dist/pipeline/idempotency.js.map +1 -0
  42. package/dist/pipeline/load.d.ts +15 -0
  43. package/dist/pipeline/load.js +87 -0
  44. package/dist/pipeline/load.js.map +1 -0
  45. package/dist/primitives/aggregate.d.ts +75 -0
  46. package/dist/primitives/aggregate.js +69 -0
  47. package/dist/primitives/aggregate.js.map +1 -0
  48. package/dist/primitives/command.d.ts +101 -0
  49. package/dist/primitives/command.js +49 -0
  50. package/dist/primitives/command.js.map +1 -0
  51. package/dist/primitives/constraints.d.ts +36 -0
  52. package/dist/primitives/constraints.js +41 -0
  53. package/dist/primitives/constraints.js.map +1 -0
  54. package/dist/primitives/event.d.ts +31 -0
  55. package/dist/primitives/event.js +44 -0
  56. package/dist/primitives/event.js.map +1 -0
  57. package/dist/primitives/fields.d.ts +127 -0
  58. package/dist/primitives/fields.js +151 -0
  59. package/dist/primitives/fields.js.map +1 -0
  60. package/dist/primitives/flow.d.ts +126 -0
  61. package/dist/primitives/flow.js +90 -0
  62. package/dist/primitives/flow.js.map +1 -0
  63. package/dist/primitives/states.d.ts +19 -0
  64. package/dist/primitives/states.js +37 -0
  65. package/dist/primitives/states.js.map +1 -0
  66. package/dist/read.d.ts +53 -0
  67. package/dist/read.js +217 -0
  68. package/dist/read.js.map +1 -0
  69. package/dist/registry.d.ts +71 -0
  70. package/dist/registry.js +177 -0
  71. package/dist/registry.js.map +1 -0
  72. package/dist/relations.d.ts +14 -0
  73. package/dist/relations.js +58 -0
  74. package/dist/relations.js.map +1 -0
  75. package/dist/scope/index.d.ts +42 -0
  76. package/dist/scope/index.js +90 -0
  77. package/dist/scope/index.js.map +1 -0
  78. package/dist/telemetry.d.ts +11 -0
  79. package/dist/telemetry.js +35 -0
  80. package/dist/telemetry.js.map +1 -0
  81. package/dist/transfer/csv.d.ts +8 -0
  82. package/dist/transfer/csv.js +114 -0
  83. package/dist/transfer/csv.js.map +1 -0
  84. package/dist/transfer/index.d.ts +49 -0
  85. package/dist/transfer/index.js +245 -0
  86. package/dist/transfer/index.js.map +1 -0
  87. package/dist/transfer/schema.d.ts +4 -0
  88. package/dist/transfer/schema.js +31 -0
  89. package/dist/transfer/schema.js.map +1 -0
  90. package/dist/types.d.ts +52 -0
  91. package/dist/types.js +5 -0
  92. package/dist/types.js.map +1 -0
  93. package/dist/util/names.d.ts +9 -0
  94. package/dist/util/names.js +38 -0
  95. package/dist/util/names.js.map +1 -0
  96. package/dist/worker/consumers.d.ts +29 -0
  97. package/dist/worker/consumers.js +79 -0
  98. package/dist/worker/consumers.js.map +1 -0
  99. package/dist/worker/index.d.ts +36 -0
  100. package/dist/worker/index.js +122 -0
  101. package/dist/worker/index.js.map +1 -0
  102. package/dist/worker/outbox.d.ts +38 -0
  103. package/dist/worker/outbox.js +121 -0
  104. package/dist/worker/outbox.js.map +1 -0
  105. package/dist/worker/scheduler.d.ts +7 -0
  106. package/dist/worker/scheduler.js +77 -0
  107. package/dist/worker/scheduler.js.map +1 -0
  108. package/package.json +58 -3
package/dist/db/ddl.js ADDED
@@ -0,0 +1,522 @@
1
+ import { isRelation } from '../primitives/fields.js';
2
+ import { snake } from '../util/names.js';
3
+ import { TRANSFER_MIGRATION } from '../transfer/schema.js';
4
+ import { relationTable } from '../relations.js';
5
+ export const q = (ident) => `"${ident.replace(/"/g, '""')}"`;
6
+ export const qt = (t) => `${q(t.schema)}.${q(t.name)}`;
7
+ const lit = (s) => `'${s.replace(/'/g, "''")}'`;
8
+ export function tableModel(agg, reg) {
9
+ const t = agg.table;
10
+ const columns = [
11
+ { name: 'id', type: 'uuid', notNull: true },
12
+ { name: 'tenant_id', type: 'uuid', notNull: true },
13
+ ];
14
+ for (const [k, f] of Object.entries(agg.fields)) {
15
+ if (isRelation(f))
16
+ continue;
17
+ const target = f.ref ? reg.aggregate(f.ref) : undefined;
18
+ columns.push({
19
+ name: snake(k),
20
+ type: f.sql,
21
+ notNull: !f.isOptional,
22
+ references: target ? `${target.table.schema}.${target.table.name}` : undefined,
23
+ unique: f.isUnique || undefined,
24
+ values: f.kind === 'enum' ? [...(f.values ?? [])] : undefined,
25
+ });
26
+ }
27
+ columns.push({ name: 'status', type: 'text', notNull: true }, { name: 'version', type: 'integer', notNull: true }, { name: 'created_at', type: 'timestamptz', notNull: true }, { name: 'updated_at', type: 'timestamptz', notNull: true });
28
+ const indexes = [];
29
+ const scopeCols = [agg.scope.deptField, agg.scope.ownerField].filter((x) => !!x && x !== 'id');
30
+ for (const f of scopeCols)
31
+ indexes.push({ name: `${t.name}_tenant_${snake(f)}_idx`, columns: ['tenant_id', snake(f)] });
32
+ indexes.push({ name: `${t.name}_status_idx`, columns: ['tenant_id', 'status'] });
33
+ for (const [k, f] of Object.entries(agg.fields)) {
34
+ if (f.kind === 'ref' && !scopeCols.includes(k))
35
+ indexes.push({ name: `${t.name}_${snake(k)}_idx`, columns: [snake(k)] });
36
+ }
37
+ const participates = reg.aggregates.some((owner) => Object.values(owner.fields)
38
+ .some((f) => f.kind === 'manyToMany' && (owner === agg || f.ref === agg.name)));
39
+ if (participates)
40
+ indexes.push({ name: `${t.name}_tenant_id_uq`, columns: ['tenant_id', 'id'], unique: true });
41
+ return { schema: t.schema, name: t.name, aggregate: agg.name, columns, statusValues: [...agg.states.values], indexes };
42
+ }
43
+ /** 按外键依赖排序:被引用的表在前 */
44
+ export function schemaModel(reg) {
45
+ const models = reg.aggregates.map((a) => tableModel(a, reg));
46
+ const key = (t) => `${t.schema}.${t.name}`;
47
+ const byKey = new Map(models.map((m) => [key(m), m]));
48
+ const out = [];
49
+ const seen = new Set();
50
+ const visit = (m, stack) => {
51
+ if (seen.has(key(m)))
52
+ return;
53
+ stack.add(key(m));
54
+ for (const c of m.columns) {
55
+ const dep = c.references && byKey.get(c.references);
56
+ if (dep && !stack.has(key(dep)))
57
+ visit(dep, stack);
58
+ }
59
+ stack.delete(key(m));
60
+ seen.add(key(m));
61
+ out.push(m);
62
+ };
63
+ for (const m of [...models].sort((a, b) => key(a).localeCompare(key(b))))
64
+ visit(m, new Set());
65
+ // 主表及复合唯一键先就绪,再建立关联表,避免前向外键依赖。
66
+ for (const owner of reg.aggregates)
67
+ for (const [field, f] of Object.entries(owner.fields)) {
68
+ if (f.kind !== 'manyToMany')
69
+ continue;
70
+ const target = reg.aggregate(f.ref);
71
+ const table = relationTable(owner, field);
72
+ out.push({ ...table, aggregate: owner.name, relation: {
73
+ field, source: `${owner.table.schema}.${owner.table.name}`, target: `${target.table.schema}.${target.table.name}`,
74
+ }, columns: ['tenant_id', 'source_id', 'target_id'].map((name) => ({ name, type: 'uuid', notNull: true })),
75
+ statusValues: [], indexes: [{ name: `${table.name.slice(0, 52)}_target_idx`, columns: ['tenant_id', 'target_id'] }] });
76
+ }
77
+ return { version: 1, tables: out };
78
+ }
79
+ function columnSql(t, c, forCreate) {
80
+ let s = `${q(c.name)} ${c.type}`;
81
+ if (c.name === 'id')
82
+ return `${s} PRIMARY KEY DEFAULT gen_random_uuid()`;
83
+ if (c.notNull && forCreate)
84
+ s += ' NOT NULL';
85
+ if (c.name === 'version')
86
+ s += ' DEFAULT 1';
87
+ if (c.name === 'created_at' || c.name === 'updated_at')
88
+ s += ' DEFAULT now()';
89
+ if (c.references) {
90
+ const [rs, rn] = c.references.split('.');
91
+ s += ` REFERENCES ${q(rs)}.${q(rn)}(id)`;
92
+ }
93
+ if (c.values)
94
+ s += ` CONSTRAINT ${q(`${t.name}_${c.name}_check`)} CHECK (${q(c.name)} IN (${c.values.map(lit).join(', ')}))`;
95
+ return s;
96
+ }
97
+ function statusCheckSql(t) {
98
+ return `CONSTRAINT ${q(`${t.name}_status_check`)} CHECK (status IN (${t.statusValues.map(lit).join(', ')}))`;
99
+ }
100
+ export function createTableSql(t) {
101
+ const cols = t.columns.map((c) => ` ${columnSql(t, c, true)}`);
102
+ if (t.relation) {
103
+ cols.push(' PRIMARY KEY (tenant_id, source_id, target_id)', ...relationForeignKeys(t).map((fk) => ` ${fk}`));
104
+ }
105
+ else
106
+ cols.push(` ${statusCheckSql(t)}`);
107
+ const lines = [`CREATE TABLE IF NOT EXISTS ${qt(t)} (`, cols.join(',\n'), ');'];
108
+ for (const c of t.columns.filter((x) => x.unique)) {
109
+ lines.push(`CREATE UNIQUE INDEX IF NOT EXISTS ${q(`${t.name}_${c.name}_uq`)} ON ${qt(t)} (tenant_id, ${q(c.name)});`);
110
+ }
111
+ for (const i of t.indexes) {
112
+ lines.push(indexSql(t, i));
113
+ }
114
+ if (t.relation)
115
+ lines.push(`GRANT DELETE ON ${qt(t)} TO cage_app;`);
116
+ return lines.join('\n');
117
+ }
118
+ const tableNameSql = (name) => name.split('.').map(q).join('.');
119
+ const indexSql = (t, i) => `CREATE ${i.unique ? 'UNIQUE ' : ''}INDEX IF NOT EXISTS ${q(i.name)} ON ${qt(t)} (${i.columns.map(q).join(', ')});`;
120
+ /** 两个复合外键把租户一致性放进数据库;解绑只删链接,源对象硬删除才级联清理链接。 */
121
+ function relationForeignKeys(t) {
122
+ return [
123
+ `CONSTRAINT ${q(`${t.name.slice(0, 53)}_source_fk`)} FOREIGN KEY (tenant_id, source_id) REFERENCES ${tableNameSql(t.relation.source)} (tenant_id, id) ON DELETE CASCADE`,
124
+ `CONSTRAINT ${q(`${t.name.slice(0, 53)}_target_fk`)} FOREIGN KEY (tenant_id, target_id) REFERENCES ${tableNameSql(t.relation.target)} (tenant_id, id)`,
125
+ ];
126
+ }
127
+ /**
128
+ * 比较两份结构,生成迁移草稿语句。破坏性变更(删表、删列)只生成注释,按「先扩展再收缩」由人决定。
129
+ */
130
+ export function diffSchemas(prev, next) {
131
+ const out = [];
132
+ const prevMap = new Map((prev?.tables ?? []).map((t) => [`${t.schema}.${t.name}`, t]));
133
+ const nextMap = new Map(next.tables.map((t) => [`${t.schema}.${t.name}`, t]));
134
+ for (const t of next.tables) {
135
+ const p = prevMap.get(`${t.schema}.${t.name}`);
136
+ if (!p) {
137
+ out.push(`-- 新表:来自聚合 ${t.aggregate}\n${createTableSql(t)}`);
138
+ continue;
139
+ }
140
+ const pc = new Map(p.columns.map((c) => [c.name, c]));
141
+ const nc = new Map(t.columns.map((c) => [c.name, c]));
142
+ for (const c of t.columns) {
143
+ const old = pc.get(c.name);
144
+ if (!old) {
145
+ if (c.notNull) {
146
+ out.push(`-- 新列 ${t.aggregate}.${c.name}(必填):先加可空列,回填后再加 NOT NULL\n` +
147
+ `ALTER TABLE ${qt(t)} ADD COLUMN IF NOT EXISTS ${columnSql(t, c, false)};\n` +
148
+ `-- TODO 回填:UPDATE ${qt(t)} SET ${q(c.name)} = … WHERE ${q(c.name)} IS NULL;\n` +
149
+ `ALTER TABLE ${qt(t)} ALTER COLUMN ${q(c.name)} SET NOT NULL;`);
150
+ }
151
+ else {
152
+ out.push(`ALTER TABLE ${qt(t)} ADD COLUMN IF NOT EXISTS ${columnSql(t, c, false)};`);
153
+ }
154
+ if (c.unique)
155
+ out.push(`CREATE UNIQUE INDEX IF NOT EXISTS ${q(`${t.name}_${c.name}_uq`)} ON ${qt(t)} (tenant_id, ${q(c.name)});`);
156
+ continue;
157
+ }
158
+ if (old.type !== c.type) {
159
+ out.push(`-- 列类型变化 ${t.aggregate}.${c.name}:${old.type} → ${c.type},请确认 USING 表达式\nALTER TABLE ${qt(t)} ALTER COLUMN ${q(c.name)} TYPE ${c.type} USING ${q(c.name)}::${c.type};`);
160
+ }
161
+ if (old.notNull !== c.notNull) {
162
+ out.push(`ALTER TABLE ${qt(t)} ALTER COLUMN ${q(c.name)} ${c.notNull ? 'SET' : 'DROP'} NOT NULL;`);
163
+ }
164
+ if (JSON.stringify(old.values ?? null) !== JSON.stringify(c.values ?? null)) {
165
+ out.push(`ALTER TABLE ${qt(t)} DROP CONSTRAINT IF EXISTS ${q(`${t.name}_${c.name}_check`)};`);
166
+ if (c.values)
167
+ out.push(`ALTER TABLE ${qt(t)} ADD CONSTRAINT ${q(`${t.name}_${c.name}_check`)} CHECK (${q(c.name)} IN (${c.values.map(lit).join(', ')}));`);
168
+ }
169
+ if (!old.unique && c.unique)
170
+ out.push(`CREATE UNIQUE INDEX IF NOT EXISTS ${q(`${t.name}_${c.name}_uq`)} ON ${qt(t)} (tenant_id, ${q(c.name)});`);
171
+ if (old.unique && !c.unique)
172
+ out.push(`DROP INDEX IF EXISTS ${q(t.schema)}.${q(`${t.name}_${c.name}_uq`)};`);
173
+ if (old.references !== c.references && c.references) {
174
+ const [rs, rn] = c.references.split('.');
175
+ out.push(`ALTER TABLE ${qt(t)} ADD FOREIGN KEY (${q(c.name)}) REFERENCES ${q(rs)}.${q(rn)}(id);`);
176
+ }
177
+ }
178
+ for (const c of p.columns) {
179
+ if (!nc.has(c.name)) {
180
+ out.push(`-- 收缩:字段 ${t.aggregate}.${c.name} 已从声明删除。确认所有读写都已切走后再取消注释(先扩展再收缩)\n-- ALTER TABLE ${qt(t)} DROP COLUMN ${q(c.name)};`);
181
+ }
182
+ }
183
+ if (!t.relation && JSON.stringify(p.statusValues) !== JSON.stringify(t.statusValues)) {
184
+ const removed = p.statusValues.filter((s) => !t.statusValues.includes(s));
185
+ if (removed.length)
186
+ out.push(`-- 注意:状态 ${removed.join(', ')} 被删除,先确认没有数据处于这些状态`);
187
+ out.push(`ALTER TABLE ${qt(t)} DROP CONSTRAINT IF EXISTS ${q(`${t.name}_status_check`)};\nALTER TABLE ${qt(t)} ADD ${statusCheckSql(t)};`);
188
+ }
189
+ const pi = new Set(p.indexes.map((i) => i.name));
190
+ for (const i of t.indexes)
191
+ if (!pi.has(i.name))
192
+ out.push(indexSql(t, i));
193
+ if (t.relation && p.relation && JSON.stringify(t.relation) !== JSON.stringify(p.relation)) {
194
+ out.push(`-- 关联目标变化:请先迁移已有链接,再应用新的外键`);
195
+ for (const side of ['source', 'target'])
196
+ out.push(`ALTER TABLE ${qt(t)} DROP CONSTRAINT ${q(`${t.name.slice(0, 53)}_${side}_fk`)};`);
197
+ for (const fk of relationForeignKeys(t))
198
+ out.push(`ALTER TABLE ${qt(t)} ADD ${fk};`);
199
+ }
200
+ }
201
+ for (const [k, p] of prevMap) {
202
+ if (!nextMap.has(k))
203
+ out.push(`-- 收缩:聚合 ${p.aggregate} 已从声明删除。确认后再取消注释\n-- DROP TABLE ${qt(p)};`);
204
+ }
205
+ return out;
206
+ }
207
+ // ---------------- 安全层:函数、策略、视图(每次整体重建) ----------------
208
+ export const IN_SCOPE_SQL = `
209
+ -- 生成物:范围判断。读取会话变量 app.scopes({"聚合":[{"c":"组合子","deptIds":[...]}]}),多个授权取并集。
210
+ -- SECURITY DEFINER:以表属主身份读部门表,避免部门表自己的行级策略递归。
211
+ CREATE OR REPLACE FUNCTION sys.in_scope(agg text, dept uuid, owner uuid)
212
+ RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path = pg_catalog, sys AS $$
213
+ SELECT coalesce(bool_or(
214
+ CASE g->>'c'
215
+ WHEN 'all' THEN true
216
+ WHEN 'self' THEN owner IS NOT NULL AND owner = nullif(current_setting('app.user_id', true), '')::uuid
217
+ WHEN 'dept' THEN dept IS NOT NULL AND dept = nullif(current_setting('app.dept_id', true), '')::uuid
218
+ WHEN 'deptSubtree' THEN dept IN (
219
+ SELECT d.id FROM sys.dept d
220
+ WHERE d.ancestors LIKE nullif(current_setting('app.dept_path', true), '') || '%')
221
+ WHEN 'deptSet' THEN dept = ANY (ARRAY(SELECT jsonb_array_elements_text(coalesce(g->'deptIds', '[]'::jsonb)))::uuid[])
222
+ ELSE false
223
+ END), false)
224
+ FROM jsonb_array_elements(coalesce(
225
+ nullif(current_setting('app.scopes', true), '')::jsonb -> agg,
226
+ nullif(current_setting('app.scopes', true), '')::jsonb -> '*',
227
+ '[{"c":"self"}]'::jsonb)) AS g
228
+ $$;`;
229
+ export const MASK_SQL = `
230
+ -- 生成物:按敏感种类掩码。持有「聚合.种类」明文权限时原样返回。
231
+ CREATE OR REPLACE FUNCTION sys.mask(agg text, kind text, val text)
232
+ RETURNS text LANGUAGE sql STABLE AS $$
233
+ SELECT CASE
234
+ WHEN val IS NULL THEN NULL
235
+ WHEN (agg || '.' || kind) = ANY (string_to_array(coalesce(current_setting('app.unmask', true), ''), ','))
236
+ OR ('*.' || kind) = ANY (string_to_array(coalesce(current_setting('app.unmask', true), ''), ',')) THEN val
237
+ WHEN kind = 'phone' THEN CASE WHEN length(val) >= 7 THEN left(val, 3) || '****' || right(val, 4) ELSE '****' END
238
+ WHEN kind = 'idCard' THEN CASE WHEN length(val) >= 8 THEN left(val, 4) || '**********' || right(val, 4) ELSE '****' END
239
+ WHEN kind = 'bankCard' THEN '**** **** **** ' || right(val, 4)
240
+ WHEN kind = 'email' THEN CASE WHEN strpos(val, '@') > 1 THEN left(val, 1) || '***' || substr(val, strpos(val, '@')) ELSE '******' END
241
+ WHEN kind = 'name' THEN left(val, 1) || '**'
242
+ WHEN kind = 'address' THEN left(val, 6) || '******'
243
+ ELSE '******'
244
+ END
245
+ $$;`;
246
+ export function aggregateSafeSql(agg) {
247
+ const t = agg.table;
248
+ const dept = agg.scope.deptField ? q(snake(agg.scope.deptField)) : 'NULL::uuid';
249
+ const owner = agg.scope.ownerField ? q(snake(agg.scope.ownerField)) : 'NULL::uuid';
250
+ const cols = ['id'];
251
+ for (const [k, f] of Object.entries(agg.fields)) {
252
+ if (f.isHidden || isRelation(f))
253
+ continue;
254
+ const c = q(snake(k));
255
+ cols.push(f.sensitiveKind ? `sys.mask(${lit(agg.name)}, ${lit(f.sensitiveKind)}, ${c}::text) AS ${c}` : c);
256
+ }
257
+ cols.push('status', 'version', 'created_at', 'updated_at');
258
+ const view = `${q('safe')}.${q(t.name)}`;
259
+ return [
260
+ `-- ${agg.name}:行级策略 + 安全视图`,
261
+ `ALTER TABLE ${qt(t)} ENABLE ROW LEVEL SECURITY;`,
262
+ `DROP POLICY IF EXISTS scope_read ON ${qt(t)};`,
263
+ `CREATE POLICY scope_read ON ${qt(t)} FOR SELECT TO cage_view_owner USING (`,
264
+ ` tenant_id = nullif(current_setting('app.tenant_id', true), '')::uuid`,
265
+ ` AND sys.in_scope(${lit(agg.name)}, ${dept}, ${owner}));`,
266
+ `DROP POLICY IF EXISTS kernel_rw ON ${qt(t)};`,
267
+ `CREATE POLICY kernel_rw ON ${qt(t)} TO cage_app USING (true) WITH CHECK (true);`,
268
+ `DROP VIEW IF EXISTS ${view};`,
269
+ `CREATE VIEW ${view} WITH (security_barrier) AS`,
270
+ ` SELECT ${cols.join(', ')}`,
271
+ ` FROM ${qt(t)};`,
272
+ `ALTER VIEW ${view} OWNER TO cage_view_owner;`,
273
+ `GRANT SELECT ON ${view} TO cage_read;`,
274
+ ].join('\n');
275
+ }
276
+ export const SYSTEM_SAFE_SQL = `
277
+ -- 审计查询视图:读侧账号经系统管理接口使用,按租户过滤
278
+ DROP VIEW IF EXISTS safe.audit_log;
279
+ CREATE VIEW safe.audit_log WITH (security_barrier) AS
280
+ SELECT id, at, actor, actor_kind, on_behalf_of, source, kind, capability, command, aggregate, aggregate_id,
281
+ result, diff, request_id, idempotency_key, client
282
+ FROM sys.audit_log
283
+ WHERE tenant_id = nullif(current_setting('app.tenant_id', true), '')::uuid;
284
+ ALTER VIEW safe.audit_log OWNER TO cage_view_owner;
285
+ GRANT SELECT ON safe.audit_log TO cage_read;`;
286
+ /** 整个安全层:先删掉旧的 safe 视图,再按声明重建(幂等) */
287
+ export function safeLayerSql(reg) {
288
+ // 关系视图依赖两侧主视图,先删除框架标记的旧关系视图(包括已删除声明的关系)。
289
+ // 不用 CASCADE,防止顺带移除用户自己维护的数据库对象。
290
+ const parts = [IN_SCOPE_SQL, MASK_SQL, `DO $$ DECLARE v record; BEGIN
291
+ FOR v IN SELECT c.relname FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
292
+ WHERE n.nspname = 'safe' AND c.relkind = 'v' AND obj_description(c.oid, 'pg_class') = 'cage:relation'
293
+ LOOP EXECUTE format('DROP VIEW safe.%I', v.relname); END LOOP;
294
+ END $$;`];
295
+ for (const a of reg.aggregates)
296
+ parts.push(aggregateSafeSql(a));
297
+ for (const t of schemaModel(reg).tables)
298
+ if (t.relation) {
299
+ const source = t.relation.source.split('.')[1], target = t.relation.target.split('.')[1];
300
+ const view = `${q('safe')}.${q(t.name)}`;
301
+ parts.push([
302
+ `ALTER TABLE ${qt(t)} ENABLE ROW LEVEL SECURITY;`,
303
+ `DROP POLICY IF EXISTS scope_read ON ${qt(t)};`,
304
+ `CREATE POLICY scope_read ON ${qt(t)} FOR SELECT TO cage_view_owner USING (tenant_id = nullif(current_setting('app.tenant_id', true), '')::uuid);`,
305
+ `DROP POLICY IF EXISTS kernel_rw ON ${qt(t)};`,
306
+ `CREATE POLICY kernel_rw ON ${qt(t)} TO cage_app USING (true) WITH CHECK (true);`,
307
+ `CREATE VIEW ${view} WITH (security_barrier) AS SELECT link.source_id, link.target_id FROM ${qt(t)} link`,
308
+ `JOIN safe.${q(source)} src ON src.id = link.source_id JOIN safe.${q(target)} dst ON dst.id = link.target_id`,
309
+ `WHERE src.status <> 'deleted' AND dst.status <> 'deleted';`,
310
+ `COMMENT ON VIEW ${view} IS 'cage:relation';`,
311
+ `ALTER VIEW ${view} OWNER TO cage_view_owner;`,
312
+ `GRANT SELECT ON ${view} TO cage_read;`,
313
+ ].join('\n'));
314
+ }
315
+ parts.push(SYSTEM_SAFE_SQL);
316
+ return parts.join('\n\n');
317
+ }
318
+ /** 建库时执行一次(超级用户):模式、账号、默认权限 */
319
+ export function bootstrapSql(pw, dbName) {
320
+ const role = (name, login, password) => `
321
+ DO $$ BEGIN
322
+ IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = ${lit(name)}) THEN
323
+ CREATE ROLE ${name} ${login ? 'LOGIN' : 'NOLOGIN'}${password ? ` PASSWORD ${lit(password)}` : ''};
324
+ ${password ? `ELSE ALTER ROLE ${name} ${login ? 'LOGIN' : 'NOLOGIN'} PASSWORD ${lit(password)};` : ''}
325
+ END IF;
326
+ END $$;`;
327
+ return `
328
+ -- db/bootstrap.sql:框架提供,建库时执行一次
329
+ CREATE EXTENSION IF NOT EXISTS pgcrypto;
330
+ ${role('cage_app', true, pw.app)}
331
+ ${role('cage_read', true, pw.read)}
332
+ ${role('cage_view_owner', false)}
333
+ ${role('cage_migrate', true, pw.migrate)}
334
+ ${dbName ? `GRANT CONNECT, CREATE ON DATABASE ${q(dbName)} TO cage_migrate;\nGRANT CONNECT ON DATABASE ${q(dbName)} TO cage_app, cage_read;` : ''}
335
+ CREATE SCHEMA IF NOT EXISTS core AUTHORIZATION cage_migrate;
336
+ CREATE SCHEMA IF NOT EXISTS sys AUTHORIZATION cage_migrate;
337
+ CREATE SCHEMA IF NOT EXISTS safe AUTHORIZATION cage_migrate;
338
+ CREATE SCHEMA IF NOT EXISTS flow AUTHORIZATION cage_migrate;
339
+ -- 迁移账号要把视图属主改成 cage_view_owner,必须是它的成员
340
+ GRANT cage_view_owner TO cage_migrate;
341
+ GRANT USAGE ON SCHEMA core, sys, flow TO cage_app;
342
+ GRANT USAGE ON SCHEMA core, sys TO cage_view_owner;
343
+ GRANT CREATE, USAGE ON SCHEMA safe TO cage_view_owner;
344
+ GRANT USAGE ON SCHEMA safe TO cage_read;
345
+ REVOKE ALL ON SCHEMA core, sys, flow FROM cage_read;
346
+ REVOKE ALL ON SCHEMA core, sys, safe, flow FROM PUBLIC;
347
+ -- 以后迁移建的表:内核账号读写但不能删除;视图属主只能读
348
+ ALTER DEFAULT PRIVILEGES FOR ROLE cage_migrate IN SCHEMA core GRANT SELECT, INSERT, UPDATE ON TABLES TO cage_app;
349
+ ALTER DEFAULT PRIVILEGES FOR ROLE cage_migrate IN SCHEMA core GRANT SELECT ON TABLES TO cage_view_owner;
350
+ ALTER DEFAULT PRIVILEGES FOR ROLE cage_migrate IN SCHEMA sys GRANT SELECT, INSERT, UPDATE ON TABLES TO cage_app;
351
+ ALTER DEFAULT PRIVILEGES FOR ROLE cage_migrate IN SCHEMA sys GRANT SELECT ON TABLES TO cage_view_owner;
352
+ ALTER DEFAULT PRIVILEGES FOR ROLE cage_migrate IN SCHEMA sys GRANT USAGE, SELECT ON SEQUENCES TO cage_app;
353
+ ALTER DEFAULT PRIVILEGES FOR ROLE cage_migrate IN SCHEMA flow GRANT SELECT, INSERT, UPDATE ON TABLES TO cage_app;
354
+ ALTER DEFAULT PRIVILEGES FOR ROLE cage_migrate IN SCHEMA flow GRANT USAGE, SELECT ON SEQUENCES TO cage_app;
355
+ `;
356
+ }
357
+ /** 单租户部署使用的默认租户(启用多租户时每个租户一行 sys.tenant) */
358
+ export const DEFAULT_TENANT = '00000000-0000-4000-8000-000000000001';
359
+ /** 框架系统表(框架自己的迁移流,按名字记入 sys.schema_migrations) */
360
+ export const SYSTEM_MIGRATIONS = [
361
+ {
362
+ name: 'cage:0001_system',
363
+ sql: `
364
+ CREATE TABLE IF NOT EXISTS sys.tenant (
365
+ id uuid PRIMARY KEY,
366
+ name text NOT NULL,
367
+ created_at timestamptz NOT NULL DEFAULT now()
368
+ );
369
+ INSERT INTO sys.tenant (id, name) VALUES ('${DEFAULT_TENANT}', 'default') ON CONFLICT DO NOTHING;
370
+
371
+ CREATE TABLE IF NOT EXISTS sys.session (
372
+ id text PRIMARY KEY,
373
+ user_id uuid NOT NULL,
374
+ tenant_id uuid NOT NULL,
375
+ created_at timestamptz NOT NULL DEFAULT now(),
376
+ expires_at timestamptz NOT NULL,
377
+ step_up_at timestamptz,
378
+ ip text,
379
+ user_agent text
380
+ );
381
+ CREATE INDEX IF NOT EXISTS session_user_idx ON sys.session (user_id);
382
+ GRANT DELETE ON sys.session TO cage_app;
383
+
384
+ CREATE TABLE IF NOT EXISTS sys.idempotency (
385
+ key text PRIMARY KEY,
386
+ status text NOT NULL,
387
+ result jsonb,
388
+ created_at timestamptz NOT NULL DEFAULT now(),
389
+ expires_at timestamptz NOT NULL
390
+ );
391
+ GRANT DELETE ON sys.idempotency TO cage_app;
392
+
393
+ CREATE TABLE IF NOT EXISTS sys.outbox (
394
+ id bigserial PRIMARY KEY,
395
+ tenant_id uuid NOT NULL,
396
+ event text NOT NULL,
397
+ aggregate text NOT NULL,
398
+ aggregate_id uuid NOT NULL,
399
+ payload jsonb NOT NULL,
400
+ actor jsonb,
401
+ trace jsonb,
402
+ request_id text,
403
+ status text NOT NULL DEFAULT 'pending',
404
+ attempts int NOT NULL DEFAULT 0,
405
+ last_error text,
406
+ next_at timestamptz NOT NULL DEFAULT now(),
407
+ locked_at timestamptz,
408
+ created_at timestamptz NOT NULL DEFAULT now(),
409
+ done_at timestamptz
410
+ );
411
+ CREATE INDEX IF NOT EXISTS outbox_status_next_idx ON sys.outbox (status, next_at);
412
+ CREATE INDEX IF NOT EXISTS outbox_aggregate_idx ON sys.outbox (aggregate_id, id);
413
+
414
+ CREATE TABLE IF NOT EXISTS sys.processed_event (
415
+ event_id bigint NOT NULL,
416
+ consumer text NOT NULL,
417
+ at timestamptz NOT NULL DEFAULT now(),
418
+ PRIMARY KEY (event_id, consumer)
419
+ );
420
+
421
+ CREATE TABLE IF NOT EXISTS sys.audit_log (
422
+ id bigserial,
423
+ at timestamptz NOT NULL DEFAULT now(),
424
+ tenant_id uuid NOT NULL,
425
+ actor text NOT NULL,
426
+ actor_kind text NOT NULL,
427
+ on_behalf_of uuid,
428
+ source text NOT NULL,
429
+ kind text NOT NULL DEFAULT 'write',
430
+ capability text,
431
+ command text,
432
+ aggregate text,
433
+ aggregate_id uuid,
434
+ result text NOT NULL,
435
+ diff jsonb,
436
+ request_id text,
437
+ idempotency_key text,
438
+ client jsonb,
439
+ PRIMARY KEY (id, at)
440
+ ) PARTITION BY RANGE (at);
441
+ CREATE TABLE IF NOT EXISTS sys.audit_log_default PARTITION OF sys.audit_log DEFAULT;
442
+ REVOKE ALL ON sys.audit_log FROM cage_app;
443
+ GRANT INSERT ON sys.audit_log TO cage_app;
444
+ REVOKE UPDATE, DELETE ON sys.audit_log FROM cage_app;
445
+ GRANT USAGE ON SEQUENCE sys.audit_log_id_seq TO cage_app;
446
+
447
+ -- 按月建分区:迁移时与 worker 每天调用
448
+ CREATE OR REPLACE FUNCTION sys.ensure_audit_partitions(months_ahead int DEFAULT 3)
449
+ RETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path = pg_catalog, sys AS $$
450
+ DECLARE
451
+ m date := date_trunc('month', now())::date;
452
+ i int;
453
+ name text;
454
+ BEGIN
455
+ FOR i IN 0..months_ahead LOOP
456
+ name := 'audit_log_' || to_char(m + (i || ' month')::interval, 'YYYYMM');
457
+ IF NOT EXISTS (SELECT 1 FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
458
+ WHERE n.nspname = 'sys' AND c.relname = name) THEN
459
+ BEGIN
460
+ EXECUTE format('CREATE TABLE sys.%I PARTITION OF sys.audit_log FOR VALUES FROM (%L) TO (%L)',
461
+ name, m + (i || ' month')::interval, m + ((i + 1) || ' month')::interval);
462
+ EXCEPTION WHEN others THEN
463
+ RAISE NOTICE '跳过分区 %: %', name, SQLERRM;
464
+ END;
465
+ END IF;
466
+ END LOOP;
467
+ END $$;
468
+ REVOKE ALL ON FUNCTION sys.ensure_audit_partitions(int) FROM PUBLIC;
469
+ GRANT EXECUTE ON FUNCTION sys.ensure_audit_partitions(int) TO cage_app;
470
+
471
+ CREATE TABLE IF NOT EXISTS sys.sync_record (
472
+ id bigserial PRIMARY KEY,
473
+ tenant_id uuid,
474
+ connector text NOT NULL,
475
+ operation text NOT NULL,
476
+ ref_id text,
477
+ idempotency_key text,
478
+ status text NOT NULL,
479
+ http_status int,
480
+ attempts int NOT NULL DEFAULT 1,
481
+ request jsonb,
482
+ response jsonb,
483
+ error text,
484
+ created_at timestamptz NOT NULL DEFAULT now(),
485
+ updated_at timestamptz NOT NULL DEFAULT now()
486
+ );
487
+ CREATE UNIQUE INDEX IF NOT EXISTS sync_record_key_uq ON sys.sync_record (connector, operation, idempotency_key);
488
+
489
+ CREATE TABLE IF NOT EXISTS sys.dead_letter (
490
+ id bigserial PRIMARY KEY,
491
+ outbox_id bigint NOT NULL,
492
+ tenant_id uuid NOT NULL,
493
+ event text NOT NULL,
494
+ aggregate_id uuid NOT NULL,
495
+ payload jsonb NOT NULL,
496
+ error text,
497
+ attempts int NOT NULL,
498
+ created_at timestamptz NOT NULL DEFAULT now(),
499
+ handled_by text,
500
+ handled_at timestamptz,
501
+ resolution text
502
+ );
503
+
504
+ CREATE TABLE IF NOT EXISTS sys.job_state (
505
+ name text PRIMARY KEY,
506
+ enabled boolean NOT NULL DEFAULT true,
507
+ last_run_at timestamptz,
508
+ last_status text,
509
+ last_error text,
510
+ updated_at timestamptz NOT NULL DEFAULT now()
511
+ );
512
+ `,
513
+ },
514
+ TRANSFER_MIGRATION,
515
+ ];
516
+ export const SCHEMA_MIGRATIONS_SQL = `
517
+ CREATE TABLE IF NOT EXISTS sys.schema_migrations (
518
+ name text PRIMARY KEY,
519
+ checksum text,
520
+ applied_at timestamptz NOT NULL DEFAULT now()
521
+ );`;
522
+ //# sourceMappingURL=ddl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ddl.js","sourceRoot":"","sources":["../../src/db/ddl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export * from './connect.js';
2
+ export * from './ddl.js';
3
+ export * from './migrate.js';
4
+ export * from './rows.js';
5
+ export * from './session.js';
@@ -0,0 +1,7 @@
1
+ // @yss123/cage-kernel/db:连接、DDL 生成、迁移执行(cli、testkit、http 使用;业务代码不应导入)
2
+ export * from './connect.js';
3
+ export * from './ddl.js';
4
+ export * from './migrate.js';
5
+ export * from './rows.js';
6
+ export * from './session.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { Registry } from '../registry.js';
2
+ import { type SchemaModel } from './ddl.js';
3
+ export interface MigrateResult {
4
+ applied: string[];
5
+ safeLayerRebuilt: boolean;
6
+ }
7
+ export interface MigrationFile {
8
+ name: string;
9
+ sql: string;
10
+ }
11
+ /** 读取 db/migrations 下的 .sql 文件,按文件名排序 */
12
+ export declare function readMigrations(dir: string): MigrationFile[];
13
+ /** 迁移文件末尾内嵌的结构快照(cage gen 写入),用于下一次比较 */
14
+ export declare function snapshotOf(m: MigrationFile): SchemaModel | null;
15
+ export declare function latestSnapshot(files: MigrationFile[]): SchemaModel | null;
16
+ export declare function embedSnapshot(sql: string, model: SchemaModel): string;
17
+ export declare function runMigrations(opts: {
18
+ migrateUrl: string;
19
+ registry: Registry;
20
+ migrations: MigrationFile[];
21
+ log?: (msg: string) => void;
22
+ }): Promise<MigrateResult>;