@substrat-run/kernel 0.138.0 → 0.140.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/dist/admin-log-ddl.d.ts +21 -0
- package/dist/admin-log-ddl.d.ts.map +1 -0
- package/dist/admin-log-ddl.js +32 -0
- package/dist/admin-log-ddl.js.map +1 -0
- package/dist/attachment-extractor.d.ts +21 -2
- package/dist/attachment-extractor.d.ts.map +1 -1
- package/dist/attachment-extractor.js +31 -6
- package/dist/attachment-extractor.js.map +1 -1
- package/dist/attachment-text.d.ts +64 -0
- package/dist/attachment-text.d.ts.map +1 -1
- package/dist/attachment-text.js +87 -16
- package/dist/attachment-text.js.map +1 -1
- package/dist/attribution.d.ts +36 -3
- package/dist/attribution.d.ts.map +1 -1
- package/dist/attribution.js +21 -8
- package/dist/attribution.js.map +1 -1
- package/dist/audit-outcome.d.ts +149 -0
- package/dist/audit-outcome.d.ts.map +1 -0
- package/dist/audit-outcome.js +233 -0
- package/dist/audit-outcome.js.map +1 -0
- package/dist/connect-links.d.ts +91 -0
- package/dist/connect-links.d.ts.map +1 -0
- package/dist/connect-links.js +189 -0
- package/dist/connect-links.js.map +1 -0
- package/dist/connect-state.d.ts +12 -3
- package/dist/connect-state.d.ts.map +1 -1
- package/dist/connect-state.js +8 -3
- package/dist/connect-state.js.map +1 -1
- package/dist/derived-object.d.ts +14 -0
- package/dist/derived-object.d.ts.map +1 -0
- package/dist/derived-object.js +2 -0
- package/dist/derived-object.js.map +1 -0
- package/dist/derived-objects.d.ts +108 -0
- package/dist/derived-objects.d.ts.map +1 -0
- package/dist/derived-objects.js +199 -0
- package/dist/derived-objects.js.map +1 -0
- package/dist/email-intent.d.ts +56 -0
- package/dist/email-intent.d.ts.map +1 -0
- package/dist/email-intent.js +71 -0
- package/dist/email-intent.js.map +1 -0
- package/dist/entity-edges.d.ts +6 -1
- package/dist/entity-edges.d.ts.map +1 -1
- package/dist/entity-edges.js +13 -0
- package/dist/entity-edges.js.map +1 -1
- package/dist/entity-grant-shape.d.ts +94 -0
- package/dist/entity-grant-shape.d.ts.map +1 -0
- package/dist/entity-grant-shape.js +329 -0
- package/dist/entity-grant-shape.js.map +1 -0
- package/dist/entity-grant.d.ts +45 -0
- package/dist/entity-grant.d.ts.map +1 -0
- package/dist/entity-grant.js +71 -0
- package/dist/entity-grant.js.map +1 -0
- package/dist/entity-state-reads.d.ts +40 -0
- package/dist/entity-state-reads.d.ts.map +1 -0
- package/dist/entity-state-reads.js +91 -0
- package/dist/entity-state-reads.js.map +1 -0
- package/dist/entity-state.d.ts +204 -0
- package/dist/entity-state.d.ts.map +1 -0
- package/dist/entity-state.js +356 -0
- package/dist/entity-state.js.map +1 -0
- package/dist/entity-trash.d.ts +245 -0
- package/dist/entity-trash.d.ts.map +1 -0
- package/dist/entity-trash.js +380 -0
- package/dist/entity-trash.js.map +1 -0
- package/dist/findings.d.ts +143 -0
- package/dist/findings.d.ts.map +1 -0
- package/dist/findings.js +463 -0
- package/dist/findings.js.map +1 -0
- package/dist/grant-scoped-read.d.ts +41 -0
- package/dist/grant-scoped-read.d.ts.map +1 -0
- package/dist/grant-scoped-read.js +100 -0
- package/dist/grant-scoped-read.js.map +1 -0
- package/dist/index.d.ts +40 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -6
- package/dist/index.js.map +1 -1
- package/dist/kernel-outbox.d.ts +14 -0
- package/dist/kernel-outbox.d.ts.map +1 -0
- package/dist/kernel-outbox.js +37 -0
- package/dist/kernel-outbox.js.map +1 -0
- package/dist/list-index.d.ts +34 -3
- package/dist/list-index.d.ts.map +1 -1
- package/dist/list-index.js +83 -31
- package/dist/list-index.js.map +1 -1
- package/dist/mail-sender.d.ts +78 -0
- package/dist/mail-sender.d.ts.map +1 -0
- package/dist/mail-sender.js +2 -0
- package/dist/mail-sender.js.map +1 -0
- package/dist/membership-executor.d.ts +7 -47
- package/dist/membership-executor.d.ts.map +1 -1
- package/dist/membership-executor.js +28 -53
- package/dist/membership-executor.js.map +1 -1
- package/dist/migration-digest.d.ts +161 -0
- package/dist/migration-digest.d.ts.map +1 -0
- package/dist/migration-digest.js +237 -0
- package/dist/migration-digest.js.map +1 -0
- package/dist/module-erasure.d.ts +156 -0
- package/dist/module-erasure.d.ts.map +1 -0
- package/dist/module-erasure.js +440 -0
- package/dist/module-erasure.js.map +1 -0
- package/dist/module-migrations.d.ts +6 -3
- package/dist/module-migrations.d.ts.map +1 -1
- package/dist/module-migrations.js +12 -5
- package/dist/module-migrations.js.map +1 -1
- package/dist/peer.d.ts +9 -1
- package/dist/peer.d.ts.map +1 -1
- package/dist/peer.js +29 -0
- package/dist/peer.js.map +1 -1
- package/dist/permission-checker.d.ts +6 -0
- package/dist/permission-checker.d.ts.map +1 -1
- package/dist/permission-checker.js.map +1 -1
- package/dist/permission-eval.d.ts +51 -1
- package/dist/permission-eval.d.ts.map +1 -1
- package/dist/permission-eval.js +104 -2
- package/dist/permission-eval.js.map +1 -1
- package/dist/platform-sweep.d.ts +8 -2
- package/dist/platform-sweep.d.ts.map +1 -1
- package/dist/platform-sweep.js +17 -0
- package/dist/platform-sweep.js.map +1 -1
- package/dist/scope-host.d.ts +479 -24
- package/dist/scope-host.d.ts.map +1 -1
- package/dist/scope-host.js +82 -7
- package/dist/scope-host.js.map +1 -1
- package/dist/scope-role-admin.d.ts +68 -0
- package/dist/scope-role-admin.d.ts.map +1 -0
- package/dist/scope-role-admin.js +80 -0
- package/dist/scope-role-admin.js.map +1 -0
- package/dist/search-index.d.ts +21 -1
- package/dist/search-index.d.ts.map +1 -1
- package/dist/search-index.js +60 -37
- package/dist/search-index.js.map +1 -1
- package/dist/spine-guard.d.ts +71 -2
- package/dist/spine-guard.d.ts.map +1 -1
- package/dist/spine-guard.js +393 -10
- package/dist/spine-guard.js.map +1 -1
- package/dist/spine-restore.d.ts.map +1 -1
- package/dist/spine-restore.js +5 -0
- package/dist/spine-restore.js.map +1 -1
- package/dist/sql-identifier.d.ts +12 -0
- package/dist/sql-identifier.d.ts.map +1 -0
- package/dist/sql-identifier.js +17 -0
- package/dist/sql-identifier.js.map +1 -0
- package/dist/sql-statements.d.ts +71 -0
- package/dist/sql-statements.d.ts.map +1 -0
- package/dist/sql-statements.js +191 -0
- package/dist/sql-statements.js.map +1 -0
- package/dist/subject-redaction.d.ts +9 -1
- package/dist/subject-redaction.d.ts.map +1 -1
- package/dist/subject-redaction.js.map +1 -1
- package/dist/system-switch-record.d.ts +3 -0
- package/dist/system-switch-record.d.ts.map +1 -1
- package/dist/system-switch-record.js +2 -0
- package/dist/system-switch-record.js.map +1 -1
- package/dist/table-ownership.d.ts +103 -0
- package/dist/table-ownership.d.ts.map +1 -0
- package/dist/table-ownership.js +285 -0
- package/dist/table-ownership.js.map +1 -0
- package/dist/timeline.d.ts +4 -4
- package/dist/timeline.js +4 -4
- package/dist/visible-continuation.d.ts +38 -0
- package/dist/visible-continuation.d.ts.map +1 -0
- package/dist/visible-continuation.js +162 -0
- package/dist/visible-continuation.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which module owns which table in a scope, as the migrations ACTUALLY made it (#2068).
|
|
3
|
+
*
|
|
4
|
+
* A subject erasure writes to a module's own tables with the kernel's handle, so "own" has to
|
|
5
|
+
* be a fact the kernel recorded, not a claim a manifest makes or a parse of migration text can
|
|
6
|
+
* infer: `CREATE TABLE IF NOT EXISTS other_modules_table` reads as creating a table and creates
|
|
7
|
+
* nothing when it already exists.
|
|
8
|
+
*
|
|
9
|
+
* **Recorded statement by statement.** Both adapters run an authored migration one statement at
|
|
10
|
+
* a time (`splitSqlStatements`) and diff the scope's tables around each one
|
|
11
|
+
* (`runMigrationStatements`, then `recordOwnershipSteps`). One statement changes at most one table
|
|
12
|
+
* (with its shadow tables, for a virtual one), so the diff names
|
|
13
|
+
* it exactly: a table that appeared was created by the migrating module; one table gone and one
|
|
14
|
+
* appeared is a rename, and the row moves with it; a table gone was dropped, and its row goes.
|
|
15
|
+
* A table that existed before the statement is never attributed to it. Diffing a whole migration
|
|
16
|
+
* instead could not tell `RENAME a TO b; CREATE TABLE a` from nothing having happened to `a`.
|
|
17
|
+
*
|
|
18
|
+
* **Guarded.** The ledger is a spine table, so module code cannot write it through `ctx.sql`, and
|
|
19
|
+
* an authored migration that names it is refused before it runs (`assertMigrationLeavesLedgerAlone`).
|
|
20
|
+
*
|
|
21
|
+
* **Backfilled conservatively.** Scopes migrated before the ledger existed have tables with no
|
|
22
|
+
* row. On the first erasure that needs them, the journal is replayed in applied order through the
|
|
23
|
+
* SAME transition function (`applyTableChange`), statement by statement, from each entry's
|
|
24
|
+
* migration text. The replay only ever attributes what it can prove: a plain `CREATE TABLE`
|
|
25
|
+
* (which would have failed had the table existed) proves its creator; `IF NOT EXISTS` proves
|
|
26
|
+
* nothing, since the table may already have been there; and an entry whose text is unavailable
|
|
27
|
+
* (its module no longer registered) makes every table it could have touched unowned. Unowned
|
|
28
|
+
* means the erasure refuses that table — the conservative answer, never a guess.
|
|
29
|
+
*/
|
|
30
|
+
import { namesSpineTable, substratError, tokenizeSql } from '@substrat-run/contracts';
|
|
31
|
+
import { executableSqlStatements, splitSqlStatements } from './sql-statements.js';
|
|
32
|
+
/** The ledger's name — also what an authored migration may never name. */
|
|
33
|
+
export const TABLE_OWNERS = '_substrat_table_owners';
|
|
34
|
+
/**
|
|
35
|
+
* The spine table the ownership lives in — a scope table, so it travels with the scope's data.
|
|
36
|
+
* The name is spelled out rather than interpolated: `lint:spine-ddl` reads this text as written.
|
|
37
|
+
*/
|
|
38
|
+
export const TABLE_OWNERS_DDL = `
|
|
39
|
+
CREATE TABLE IF NOT EXISTS _substrat_table_owners (
|
|
40
|
+
table_name TEXT PRIMARY KEY,
|
|
41
|
+
module_id TEXT NOT NULL,
|
|
42
|
+
source TEXT NOT NULL,
|
|
43
|
+
recorded_at TEXT NOT NULL
|
|
44
|
+
);
|
|
45
|
+
`;
|
|
46
|
+
/**
|
|
47
|
+
* Refuse an authored migration that names the ownership ledger — in any statement, read or
|
|
48
|
+
* write, quoted or qualified. Each adapter runs it beside `assertNoSpineReference`, before the
|
|
49
|
+
* migration executes, so a refused migration changes nothing and the scope fails closed.
|
|
50
|
+
*/
|
|
51
|
+
export function assertMigrationLeavesLedgerAlone(sql, what) {
|
|
52
|
+
for (const token of tokenizeSql(sql)) {
|
|
53
|
+
if (token.text.split('.').some((part) => part.toLowerCase() === TABLE_OWNERS)) {
|
|
54
|
+
throw substratError('forbidden', `${what} names ${TABLE_OWNERS}, the kernel's record of which module created which table — ` +
|
|
55
|
+
'a migration may not read or write it', { reason: 'spine_write' });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** The scope's own tables, lowercased: no spine, no SQLite or workerd internals, no views. */
|
|
60
|
+
export function moduleTableNames(sql) {
|
|
61
|
+
return new Set(sql
|
|
62
|
+
.query("SELECT name FROM sqlite_master WHERE type = 'table'")
|
|
63
|
+
.map((r) => r.name.toLowerCase())
|
|
64
|
+
.filter((n) => !namesSpineTable(n) && !n.startsWith('sqlite_') && !n.startsWith('_cf_')));
|
|
65
|
+
}
|
|
66
|
+
/** A table name a statement names, lowercased; `main.` is the default schema, any other is not ours. */
|
|
67
|
+
function nameOf(token) {
|
|
68
|
+
if (!token)
|
|
69
|
+
return undefined;
|
|
70
|
+
const parts = token.text.toLowerCase().split('.');
|
|
71
|
+
if (parts.length === 1)
|
|
72
|
+
return parts[0];
|
|
73
|
+
return parts.length === 2 && parts[0] === 'main' ? parts[1] : undefined;
|
|
74
|
+
}
|
|
75
|
+
/** The table DDL in one migration's text, in statement order. TEMP tables are nobody's and are left out. */
|
|
76
|
+
export function tableStatements(sqlText) {
|
|
77
|
+
const out = [];
|
|
78
|
+
// The same statement boundaries the adapters execute on, so the replay reads what ran.
|
|
79
|
+
const statements = splitSqlStatements(sqlText).map((text) => tokenizeSql(text).filter((t) => !t.punct));
|
|
80
|
+
for (const st of statements) {
|
|
81
|
+
const w = (i) => (st[i] && !st[i].quoted ? st[i].text.toLowerCase() : '');
|
|
82
|
+
if (w(0) === 'create') {
|
|
83
|
+
let k = 1;
|
|
84
|
+
const temp = w(k) === 'temp' || w(k) === 'temporary';
|
|
85
|
+
if (temp)
|
|
86
|
+
k += 1;
|
|
87
|
+
if (w(k) === 'virtual')
|
|
88
|
+
k += 1;
|
|
89
|
+
if (w(k) !== 'table')
|
|
90
|
+
continue;
|
|
91
|
+
k += 1;
|
|
92
|
+
const ifNotExists = w(k) === 'if' && w(k + 1) === 'not' && w(k + 2) === 'exists';
|
|
93
|
+
if (ifNotExists)
|
|
94
|
+
k += 3;
|
|
95
|
+
const table = nameOf(st[k]);
|
|
96
|
+
if (table && !temp)
|
|
97
|
+
out.push({ kind: 'create', table, ifNotExists });
|
|
98
|
+
}
|
|
99
|
+
else if (w(0) === 'alter' && w(1) === 'table') {
|
|
100
|
+
const from = nameOf(st[2]);
|
|
101
|
+
const at = st.findIndex((t, i) => i > 2 && !t.quoted && t.text.toLowerCase() === 'rename');
|
|
102
|
+
const to = at > 0 && w(at + 1) === 'to' ? nameOf(st[at + 2]) : undefined;
|
|
103
|
+
if (from && to)
|
|
104
|
+
out.push({ kind: 'rename', from, to });
|
|
105
|
+
}
|
|
106
|
+
else if (w(0) === 'drop' && w(1) === 'table') {
|
|
107
|
+
const table = nameOf(st[w(2) === 'if' && w(3) === 'exists' ? 4 : 2]);
|
|
108
|
+
if (table)
|
|
109
|
+
out.push({ kind: 'drop', table });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* THE transition, shared by the live record and the journal replay: a create sets its owner (or
|
|
116
|
+
* an unknown one), a rename moves the row to the new name, a drop removes it.
|
|
117
|
+
*/
|
|
118
|
+
export function applyTableChange(store, change) {
|
|
119
|
+
switch (change.kind) {
|
|
120
|
+
case 'create':
|
|
121
|
+
store.set(change.table, change.owner);
|
|
122
|
+
return;
|
|
123
|
+
case 'rename': {
|
|
124
|
+
const owner = store.get(change.from);
|
|
125
|
+
store.delete(change.from);
|
|
126
|
+
store.set(change.to, owner ?? null);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
case 'drop':
|
|
130
|
+
store.delete(change.table);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** The ledger as an `OwnerStore`: an unknown owner is no row, so an erasure refuses that table. */
|
|
134
|
+
function ledgerStore(sql, source, at) {
|
|
135
|
+
return {
|
|
136
|
+
get: (table) => sql.query(`SELECT module_id FROM ${TABLE_OWNERS} WHERE table_name = ?`, [table])[0]
|
|
137
|
+
?.module_id ?? null,
|
|
138
|
+
set: (table, owner) => {
|
|
139
|
+
if (owner === null) {
|
|
140
|
+
sql.exec(`DELETE FROM ${TABLE_OWNERS} WHERE table_name = ?`, [table]);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
sql.exec(`INSERT INTO ${TABLE_OWNERS} (table_name, module_id, source, recorded_at) VALUES (?, ?, ?, ?)
|
|
144
|
+
ON CONFLICT(table_name) DO UPDATE SET module_id = excluded.module_id, source = excluded.source,
|
|
145
|
+
recorded_at = excluded.recorded_at`, [table, owner, source, at]);
|
|
146
|
+
},
|
|
147
|
+
delete: (table) => {
|
|
148
|
+
sql.exec(`DELETE FROM ${TABLE_OWNERS} WHERE table_name = ?`, [table]);
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Run an authored migration ONE statement at a time, through the adapter's `exec`, and return
|
|
154
|
+
* the table set either side of every statement that changed it. Both adapters run their
|
|
155
|
+
* authored migrations through this, inside the migration's transaction; recording happens
|
|
156
|
+
* afterwards (`recordOwnershipSteps`), so the journal's `rows_changed` counts the migration's
|
|
157
|
+
* own writes and none of the kernel's bookkeeping.
|
|
158
|
+
*/
|
|
159
|
+
export function runMigrationStatements(sql, migrationSql, exec) {
|
|
160
|
+
const steps = [];
|
|
161
|
+
let tables = moduleTableNames(sql);
|
|
162
|
+
// Comment-blanked text, at the same boundaries: what SQLite stores is what a later ALTER rewrites.
|
|
163
|
+
for (const statement of executableSqlStatements(migrationSql)) {
|
|
164
|
+
exec(statement);
|
|
165
|
+
const after = moduleTableNames(sql);
|
|
166
|
+
if (after.size !== tables.size || [...after].some((t) => !tables.has(t)))
|
|
167
|
+
steps.push({ before: tables, after });
|
|
168
|
+
tables = after;
|
|
169
|
+
}
|
|
170
|
+
return steps;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* The table a group of names belongs to, when there is one: the shortest name, with every other
|
|
174
|
+
* name its shadow (`root_…`) — what one `CREATE VIRTUAL TABLE … USING fts5` makes (`x`, `x_data`,
|
|
175
|
+
* `x_idx`, …), drops or renames together. Undefined when the names are not one such group.
|
|
176
|
+
*/
|
|
177
|
+
function rootOf(names) {
|
|
178
|
+
if (names.length === 0)
|
|
179
|
+
return undefined;
|
|
180
|
+
const root = [...names].sort((a, b) => a.length - b.length)[0];
|
|
181
|
+
return names.every((n) => n === root || n.startsWith(`${root}_`)) ? root : undefined;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* The changes one statement made, from the table set either side of it. A single SQLite
|
|
185
|
+
* statement changes ONE table — with its shadow tables, for a virtual table — so: tables only
|
|
186
|
+
* appearing are a create by `moduleId`; only disappearing, a drop; one group gone and one
|
|
187
|
+
* appeared, a rename, each shadow moving with its root. Anything else is not a shape a single
|
|
188
|
+
* statement produces, and is refused rather than guessed at.
|
|
189
|
+
*/
|
|
190
|
+
export function tableChangesOf(moduleId, step) {
|
|
191
|
+
const gone = [...step.before].filter((t) => !step.after.has(t));
|
|
192
|
+
const appeared = [...step.after].filter((t) => !step.before.has(t));
|
|
193
|
+
const from = rootOf(gone);
|
|
194
|
+
const to = rootOf(appeared);
|
|
195
|
+
if (gone.length === 0 && to !== undefined) {
|
|
196
|
+
return appeared.map((table) => ({ kind: 'create', table, owner: moduleId }));
|
|
197
|
+
}
|
|
198
|
+
if (appeared.length === 0 && from !== undefined)
|
|
199
|
+
return gone.map((table) => ({ kind: 'drop', table }));
|
|
200
|
+
if (from !== undefined && to !== undefined && gone.length === appeared.length) {
|
|
201
|
+
const renamed = gone.map((g) => ({ from: g, to: `${to}${g.slice(from.length)}` }));
|
|
202
|
+
if (renamed.every((r) => appeared.includes(r.to))) {
|
|
203
|
+
return renamed.map((r) => ({ kind: 'rename', from: r.from, to: r.to }));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
throw substratError('internal', `migration of ${moduleId}: one statement changed unrelated tables (gone: ${gone.join(', ') || '-'}; ` +
|
|
207
|
+
`appeared: ${appeared.join(', ') || '-'}), which the ownership record cannot attribute`);
|
|
208
|
+
}
|
|
209
|
+
/** Apply each recorded step to the ledger, in statement order, through `applyTableChange`. */
|
|
210
|
+
export function recordOwnershipSteps(sql, moduleId, steps, at) {
|
|
211
|
+
const store = ledgerStore(sql, 'migration', at);
|
|
212
|
+
for (const step of steps)
|
|
213
|
+
for (const change of tableChangesOf(moduleId, step))
|
|
214
|
+
applyTableChange(store, change);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Attribute the given tables, where they have no row yet, by replaying the migration journal in
|
|
218
|
+
* applied order, statement by statement, through `applyTableChange` — the one-time backfill for a
|
|
219
|
+
* scope migrated before ownership was recorded. Only what the replay can prove is attributed:
|
|
220
|
+
*
|
|
221
|
+
* - a plain `CREATE TABLE` proves its creator — it would have failed had the table existed;
|
|
222
|
+
* - `CREATE TABLE IF NOT EXISTS` proves nothing: an earlier migration, or runtime DDL, may already
|
|
223
|
+
* have made the table, so it leaves the table's owner unknown;
|
|
224
|
+
* - an entry whose migration text is not available — its module no longer registered — could have
|
|
225
|
+
* created, renamed or dropped anything, so every table that exists at that point becomes
|
|
226
|
+
* unknown. A later plain `CREATE` still proves its own creation.
|
|
227
|
+
*
|
|
228
|
+
* An unknown owner is no row, and the erasure refuses that table.
|
|
229
|
+
*/
|
|
230
|
+
export function backfillOwnershipFromJournal(sql, tables, migrationSqlOf, at) {
|
|
231
|
+
const missing = [...tables]
|
|
232
|
+
.map((t) => t.toLowerCase())
|
|
233
|
+
.filter((t) => sql.query(`SELECT 1 FROM ${TABLE_OWNERS} WHERE table_name = ?`, [t]).length === 0);
|
|
234
|
+
if (missing.length === 0)
|
|
235
|
+
return;
|
|
236
|
+
const journal = sql.query('SELECT module_id, version FROM _substrat_migrations ORDER BY applied_at, rowid');
|
|
237
|
+
const model = new Map();
|
|
238
|
+
const store = {
|
|
239
|
+
get: (t) => model.get(t),
|
|
240
|
+
set: (t, o) => void model.set(t, o),
|
|
241
|
+
delete: (t) => void model.delete(t),
|
|
242
|
+
};
|
|
243
|
+
for (const entry of journal) {
|
|
244
|
+
const text = migrationSqlOf(entry.module_id, entry.version);
|
|
245
|
+
if (text === undefined) {
|
|
246
|
+
for (const t of model.keys())
|
|
247
|
+
model.set(t, null);
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
for (const st of tableStatements(text)) {
|
|
251
|
+
if (st.kind === 'create') {
|
|
252
|
+
if (st.ifNotExists && model.has(st.table))
|
|
253
|
+
continue;
|
|
254
|
+
applyTableChange(store, { kind: 'create', table: st.table, owner: st.ifNotExists ? null : entry.module_id });
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
applyTableChange(store, st);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const live = moduleTableNames(sql);
|
|
262
|
+
const ledger = ledgerStore(sql, 'journal', at);
|
|
263
|
+
for (const t of missing) {
|
|
264
|
+
const owner = model.get(t);
|
|
265
|
+
if (owner && live.has(t))
|
|
266
|
+
ledger.set(t, owner);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Refuse, before anything is written, an erasure that would touch a table the scope does not
|
|
271
|
+
* record as the erasing module's. Missing rows are backfilled from the journal first.
|
|
272
|
+
*/
|
|
273
|
+
export function assertTablesOwned(sql, moduleId, tables, migrationSqlOf, at) {
|
|
274
|
+
const list = [...tables].map((t) => t.toLowerCase());
|
|
275
|
+
if (list.length === 0)
|
|
276
|
+
return;
|
|
277
|
+
backfillOwnershipFromJournal(sql, list, migrationSqlOf, at);
|
|
278
|
+
const refused = list.filter((t) => sql.query(`SELECT module_id FROM ${TABLE_OWNERS} WHERE table_name = ?`, [t])[0]
|
|
279
|
+
?.module_id !== moduleId);
|
|
280
|
+
if (refused.length > 0) {
|
|
281
|
+
throw substratError('precondition_failed', `erasure: ${moduleId} names ${refused.map((t) => `'${t}'`).join(', ')}, which this scope does not record as ` +
|
|
282
|
+
'created by its migrations — an erasure touches only the tables a module owns. Nothing was erased.');
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
//# sourceMappingURL=table-ownership.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table-ownership.js","sourceRoot":"","sources":["../src/table-ownership.ts"],"names":[],"mappings":"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"}
|
package/dist/timeline.d.ts
CHANGED
|
@@ -139,10 +139,10 @@ export interface ScopeWalkPage extends ListPage {
|
|
|
139
139
|
* A caller who can only justify SOME entities must not use this read and filter
|
|
140
140
|
* afterwards without saying so: post-filtering with `ctx.check(perm, entry.entity)`
|
|
141
141
|
* per row is legitimate, but it changes the page size (a page of 20 can come back
|
|
142
|
-
* with 3) and the cursor
|
|
143
|
-
*
|
|
144
|
-
* visits what the caller may read is a different read with
|
|
145
|
-
* is deliberately not this one.
|
|
142
|
+
* with 3), and the cursor of a refused row is that row's position — so walk it
|
|
143
|
+
* with `pageVisible`, which never returns one (#2073), as callout's `portal-orders`
|
|
144
|
+
* does. A walk that only visits what the caller may read is a different read with
|
|
145
|
+
* a different cost, and is deliberately not this one.
|
|
146
146
|
*/
|
|
147
147
|
export declare function readScopeTimeline(ctx: TimelineReader, page?: ScopeWalkPage): Page<ScopeTimelineEntry>;
|
|
148
148
|
/**
|
package/dist/timeline.js
CHANGED
|
@@ -236,10 +236,10 @@ function entityOfRow(d, row) {
|
|
|
236
236
|
* A caller who can only justify SOME entities must not use this read and filter
|
|
237
237
|
* afterwards without saying so: post-filtering with `ctx.check(perm, entry.entity)`
|
|
238
238
|
* per row is legitimate, but it changes the page size (a page of 20 can come back
|
|
239
|
-
* with 3) and the cursor
|
|
240
|
-
*
|
|
241
|
-
* visits what the caller may read is a different read with
|
|
242
|
-
* is deliberately not this one.
|
|
239
|
+
* with 3), and the cursor of a refused row is that row's position — so walk it
|
|
240
|
+
* with `pageVisible`, which never returns one (#2073), as callout's `portal-orders`
|
|
241
|
+
* does. A walk that only visits what the caller may read is a different read with
|
|
242
|
+
* a different cost, and is deliberately not this one.
|
|
243
243
|
*/
|
|
244
244
|
export function readScopeTimeline(ctx, page) {
|
|
245
245
|
const limit = listLimitOf(page?.limit);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type SealedSecret } from './secret-box.js';
|
|
2
|
+
export declare const CONTINUATION_POSITION_CAP = 256;
|
|
3
|
+
export interface ContinuationKey {
|
|
4
|
+
id: string;
|
|
5
|
+
/** Raw AES-256 key, base64 encoded only inside adapter-private storage. */
|
|
6
|
+
material: string;
|
|
7
|
+
createdAt: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ContinuationKeys {
|
|
10
|
+
active: ContinuationKey;
|
|
11
|
+
previous?: ContinuationKey;
|
|
12
|
+
}
|
|
13
|
+
export interface ContinuationPosition {
|
|
14
|
+
sealed: SealedSecret;
|
|
15
|
+
expiresAt: number;
|
|
16
|
+
}
|
|
17
|
+
/** Neither keys nor positions may be stored in module-readable scope SQL or a dump. */
|
|
18
|
+
export interface ContinuationStore {
|
|
19
|
+
keys(): Promise<ContinuationKeys | null>;
|
|
20
|
+
setKeys(keys: ContinuationKeys): Promise<void>;
|
|
21
|
+
position(id: string, expiresAt: number): Promise<ContinuationPosition | null>;
|
|
22
|
+
setPosition(id: string, position: ContinuationPosition): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
/** Everything that makes the position mean the same walk, with no raw input kept. */
|
|
25
|
+
export interface ContinuationBinding {
|
|
26
|
+
scopeId: string;
|
|
27
|
+
principal: string;
|
|
28
|
+
operation: string;
|
|
29
|
+
list: string;
|
|
30
|
+
query: unknown;
|
|
31
|
+
}
|
|
32
|
+
/** Full visible pages are stateless; only a hidden budget stop needs a private locator. */
|
|
33
|
+
export declare function visibleContinuation(store: ContinuationStore, binding: ContinuationBinding, now?: () => number, legacyUsed?: () => void, writable?: boolean): {
|
|
34
|
+
writable: boolean;
|
|
35
|
+
seal(position: string, hidden?: boolean): Promise<string | null>;
|
|
36
|
+
open(cursor: string): Promise<string>;
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=visible-continuation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visible-continuation.d.ts","sourceRoot":"","sources":["../src/visible-continuation.ts"],"names":[],"mappings":"AAEA,OAAO,EAA4C,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAa9F,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAI7C,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,uFAAuF;AACvF,MAAM,WAAW,iBAAiB;IAChC,IAAI,IAAI,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACzC,OAAO,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;IAC9E,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxE;AAED,qFAAqF;AACrF,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB;AAiDD,2FAA2F;AAC3F,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,iBAAiB,EACxB,OAAO,EAAE,mBAAmB,EAC5B,GAAG,GAAE,MAAM,MAAiB,EAC5B,UAAU,CAAC,EAAE,MAAM,IAAI,EACvB,QAAQ,UAAO;;mBAkBQ,MAAM,qBAAkB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;iBAgChD,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;EAqC9C"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/** Private, short-lived positions for a per-row-filtered walk (#2074). */
|
|
2
|
+
import { PAGE_CURSOR_RESTART, substratError } from '@substrat-run/contracts';
|
|
3
|
+
import { fromBase64, toBase64, webCryptoSecretBox } from './secret-box.js';
|
|
4
|
+
import { isPlainPageCursor } from './list-index.js';
|
|
5
|
+
const TOKEN_PREFIX = 'sc1';
|
|
6
|
+
const TOKEN_PLAINTEXT_LENGTH = 192;
|
|
7
|
+
const LIFETIME_MS = 15 * 60_000;
|
|
8
|
+
const ROTATION_MS = 24 * 60 * 60_000;
|
|
9
|
+
export const CONTINUATION_POSITION_CAP = 256;
|
|
10
|
+
/** Remove this migration window at the next cursor-breaking release. */
|
|
11
|
+
const ACCEPT_LEGACY_VISIBLE_CURSORS = true;
|
|
12
|
+
const restart = () => substratError('validation_failed', 'list: this cursor cannot continue this walk — restart paging from the first page, without a cursor', { reason: PAGE_CURSOR_RESTART });
|
|
13
|
+
const random = (size) => crypto.getRandomValues(new Uint8Array(size));
|
|
14
|
+
const base64url = (bytes) => toBase64(bytes).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
|
|
15
|
+
const unbase64url = (text) => fromBase64(text.replace(/-/g, '+').replace(/_/g, '/'));
|
|
16
|
+
const key = (now) => ({ id: base64url(random(9)), material: toBase64(random(32)), createdAt: now });
|
|
17
|
+
function canonical(value) {
|
|
18
|
+
if (value === null || typeof value !== 'object')
|
|
19
|
+
return JSON.stringify(value) ?? 'null';
|
|
20
|
+
if (Array.isArray(value))
|
|
21
|
+
return `[${value.map(canonical).join(',')}]`;
|
|
22
|
+
if (value instanceof Set)
|
|
23
|
+
return `[${[...value].map(canonical).sort().join(',')}]`;
|
|
24
|
+
if (value instanceof Map)
|
|
25
|
+
return `{${[...value].map(([k, v]) => [canonical(k), canonical(v)])
|
|
26
|
+
.sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}:${v}`).join(',')}}`;
|
|
27
|
+
return `{${Object.entries(value).filter(([, v]) => v !== undefined).sort(([a], [b]) => a.localeCompare(b))
|
|
28
|
+
.map(([k, v]) => `${JSON.stringify(k)}:${canonical(v)}`).join(',')}}`;
|
|
29
|
+
}
|
|
30
|
+
/** SQL IN filters are sets; request order and duplicates must not change a walk's identity. */
|
|
31
|
+
function normalizeFilter(value) {
|
|
32
|
+
if (Array.isArray(value)) {
|
|
33
|
+
const members = new Map(value.map((item) => {
|
|
34
|
+
const normalized = normalizeFilter(item);
|
|
35
|
+
return [canonical(normalized), normalized];
|
|
36
|
+
}));
|
|
37
|
+
return [...members.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([, item]) => item);
|
|
38
|
+
}
|
|
39
|
+
if (value && typeof value === 'object' && !(value instanceof Set) && !(value instanceof Map)) {
|
|
40
|
+
return Object.fromEntries(Object.entries(value).map(([name, item]) => [name, normalizeFilter(item)]));
|
|
41
|
+
}
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
async function bindingHash(binding) {
|
|
45
|
+
const bytes = new TextEncoder().encode(canonical(binding));
|
|
46
|
+
return base64url(new Uint8Array(await crypto.subtle.digest('SHA-256', bytes)));
|
|
47
|
+
}
|
|
48
|
+
function box(material) {
|
|
49
|
+
const bytes = fromBase64(material.material);
|
|
50
|
+
if (bytes.length !== 32)
|
|
51
|
+
throw restart();
|
|
52
|
+
return webCryptoSecretBox(material.id, bytes);
|
|
53
|
+
}
|
|
54
|
+
/** Full visible pages are stateless; only a hidden budget stop needs a private locator. */
|
|
55
|
+
export function visibleContinuation(store, binding, now = Date.now, legacyUsed, writable = true) {
|
|
56
|
+
// Pagination mechanics do not change the rows in the walk. Every other input,
|
|
57
|
+
// including a grant constraint, does; bind it without retaining its raw value.
|
|
58
|
+
const query = binding.query && typeof binding.query === 'object' && !Array.isArray(binding.query)
|
|
59
|
+
? Object.fromEntries(Object.entries(binding.query).filter(([name]) => !['cursor', 'limit', 'rowCursors', 'total'].includes(name)))
|
|
60
|
+
: binding.query ?? {};
|
|
61
|
+
if (query && typeof query === 'object' && !Array.isArray(query) && 'filters' in query) {
|
|
62
|
+
query.filters = normalizeFilter(query.filters);
|
|
63
|
+
}
|
|
64
|
+
let fingerprint;
|
|
65
|
+
const hash = () => (fingerprint ??= bindingHash({ ...binding, query }));
|
|
66
|
+
const readKeys = async () => {
|
|
67
|
+
try {
|
|
68
|
+
return await store.keys();
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
throw restart();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
return {
|
|
75
|
+
writable,
|
|
76
|
+
async seal(position, hidden = true) {
|
|
77
|
+
// A read-only invocation (including a copy) cannot persist a hidden
|
|
78
|
+
// position. It keeps the former bounded-walk result at this budget stop.
|
|
79
|
+
if (hidden && !writable)
|
|
80
|
+
return null;
|
|
81
|
+
try {
|
|
82
|
+
const at = now();
|
|
83
|
+
let keys = await readKeys();
|
|
84
|
+
if (!writable && !keys)
|
|
85
|
+
return null;
|
|
86
|
+
if (writable && (!keys || at - keys.active.createdAt >= ROTATION_MS)) {
|
|
87
|
+
keys = { active: key(at), ...(keys ? { previous: keys.active } : {}) };
|
|
88
|
+
await store.setKeys(keys);
|
|
89
|
+
}
|
|
90
|
+
if (!keys)
|
|
91
|
+
return null;
|
|
92
|
+
const expiresAt = at + LIFETIME_MS;
|
|
93
|
+
let payload;
|
|
94
|
+
if (hidden) {
|
|
95
|
+
const id = base64url(random(16));
|
|
96
|
+
const sealed = await box(keys.active).seal(JSON.stringify({ id, position }));
|
|
97
|
+
await store.setPosition(id, { sealed, expiresAt });
|
|
98
|
+
payload = JSON.stringify({ i: id, e: expiresAt, b: await hash() });
|
|
99
|
+
if (payload.length > TOKEN_PLAINTEXT_LENGTH)
|
|
100
|
+
throw restart();
|
|
101
|
+
payload = payload.padEnd(TOKEN_PLAINTEXT_LENGTH, ' ');
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
payload = JSON.stringify({ p: position, e: expiresAt, b: await hash() });
|
|
105
|
+
}
|
|
106
|
+
const token = await box(keys.active).seal(payload);
|
|
107
|
+
return `${TOKEN_PREFIX}.${keys.active.id}.${base64url(fromBase64(token.ciphertext))}`;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
if (!writable)
|
|
111
|
+
return null;
|
|
112
|
+
throw restart();
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
async open(cursor) {
|
|
116
|
+
if (!cursor.startsWith(`${TOKEN_PREFIX}.`)) {
|
|
117
|
+
try {
|
|
118
|
+
if (ACCEPT_LEGACY_VISIBLE_CURSORS && isPlainPageCursor(cursor)) {
|
|
119
|
+
legacyUsed?.();
|
|
120
|
+
return cursor;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch { /* All invalid legacy cursors have the same restart response. */ }
|
|
124
|
+
throw restart();
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const parts = cursor.split('.');
|
|
128
|
+
if (parts.length !== 3 || !/^[A-Za-z0-9_-]{12}$/.test(parts[1]) ||
|
|
129
|
+
!/^[A-Za-z0-9_-]+$/.test(parts[2]))
|
|
130
|
+
throw restart();
|
|
131
|
+
const keys = await readKeys();
|
|
132
|
+
const selected = [keys?.active, keys?.previous].find((candidate) => candidate?.id === parts[1]);
|
|
133
|
+
if (!selected)
|
|
134
|
+
throw restart();
|
|
135
|
+
const decoded = await box(selected).open({ keyId: selected.id, ciphertext: toBase64(unbase64url(parts[2])) });
|
|
136
|
+
const payload = JSON.parse(decoded.trimEnd());
|
|
137
|
+
if (typeof payload.e !== 'number' || payload.e <= now() || payload.b !== await hash())
|
|
138
|
+
throw restart();
|
|
139
|
+
if ('p' in payload) {
|
|
140
|
+
if (typeof payload.p !== 'string')
|
|
141
|
+
throw restart();
|
|
142
|
+
return payload.p;
|
|
143
|
+
}
|
|
144
|
+
if (decoded.length !== TOKEN_PLAINTEXT_LENGTH ||
|
|
145
|
+
typeof payload.i !== 'string' || !/^[A-Za-z0-9_-]{22}$/.test(payload.i))
|
|
146
|
+
throw restart();
|
|
147
|
+
const record = await store.position(payload.i, payload.e);
|
|
148
|
+
if (!record || record.expiresAt !== payload.e || record.expiresAt <= now())
|
|
149
|
+
throw restart();
|
|
150
|
+
const opened = JSON.parse(await box(selected).open(record.sealed));
|
|
151
|
+
if (opened.id !== payload.i || typeof opened.position !== 'string')
|
|
152
|
+
throw restart();
|
|
153
|
+
return opened.position;
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// No parsing, key, authentication, expiry or binding detail reaches a caller.
|
|
157
|
+
throw restart();
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=visible-continuation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visible-continuation.js","sourceRoot":"","sources":["../src/visible-continuation.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@substrat-run/kernel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.140.0",
|
|
4
4
|
"description": "Substrat kernel contracts and services — pure TypeScript, no platform imports (D-14)",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dist"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@substrat-run/contracts": "^0.
|
|
25
|
+
"@substrat-run/contracts": "^0.140.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^22.20.5",
|