@substrat-run/kernel 0.128.0 → 0.130.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.
@@ -18,7 +18,8 @@
18
18
  * What is refused: a statement whose write TARGET is a `_substrat_*` table —
19
19
  * `INSERT`/`REPLACE INTO`, `UPDATE`, `DELETE FROM`, `DROP`, `ALTER`, `CREATE` — and
20
20
  * the second table a statement can reach past the one it names first: `CREATE
21
- * TRIGGER … ON`, `CREATE INDEX … ON`, `ALTER TABLE … RENAME TO`.
21
+ * TRIGGER … ON`, `CREATE INDEX … ON`, `ALTER TABLE … RENAME TO`, and a `REFERENCES` clause
22
+ * naming the spine (`assertNoSpineReference`, #1898).
22
23
  * What is allowed, deliberately: every read of the spine, including one that feeds
23
24
  * a write — `INSERT INTO my_timeline SELECT … FROM _substrat_events` is the
24
25
  * projection pattern CLAUDE.md explicitly blesses, and only the target is judged.
@@ -27,20 +28,13 @@
27
28
  * runtime refuses them outright, and widening this guard to cover them would make
28
29
  * it a second read-only console rather than a rule about forging.
29
30
  *
30
- * The scan tokenises OUTSIDE comments and string literals but KEEPS quoted
31
- * identifiers as tokens — `INSERT INTO "_substrat_tuples"` is the first thing
32
- * anyone tries, and a scanner that skips quotes hands it through. Dotted names
33
- * (`main._substrat_tuples`) merge into one token, and every part is checked.
31
+ * The scan is `tokenizeSql` from `@substrat-run/contracts`, the one reading of the grammar
32
+ * the dump checks share: comments and string literals skipped, quoted identifiers kept as
33
+ * tokens, dotted names merged into one, and every part of one checked.
34
34
  * Multiple statements in one string are walked in full: the DO's `sql.exec` accepts
35
35
  * them, so a forge chained after a legitimate write must not slip past.
36
36
  */
37
- import { substratError } from '@substrat-run/contracts';
38
- /**
39
- * The platform spine's table prefix — the same one `isSystemTable` groups on, and the one a
40
- * restore builds from the kernel's DDL (`isSpineTable`, #1883). Compared lowercased: SQLite
41
- * matches table names without regard to case, so `_SUBSTRAT_TUPLES` is the tuples table.
42
- */
43
- export const SPINE_PREFIX = '_substrat';
37
+ import { namesSpineTable, referencedTablesIn, substratError, tokenizeSql } from '@substrat-run/contracts';
44
38
  /**
45
39
  * Tokens that may stand between a write verb and the table it names. The first
46
40
  * following token that is NOT one of these (or that is quoted) is the target.
@@ -66,120 +60,6 @@ const MODIFIERS = {
66
60
  'exists',
67
61
  ]),
68
62
  };
69
- function tokenize(sql) {
70
- const tokens = [];
71
- const n = sql.length;
72
- let i = 0;
73
- // Set when the previous token ended on a `.`, so `main . tbl` folds into one name.
74
- let continues = false;
75
- const push = (text, quoted) => {
76
- const prev = tokens[tokens.length - 1];
77
- if (continues && prev) {
78
- tokens[tokens.length - 1] = { text: `${prev.text}.${text}`, quoted: prev.quoted || quoted };
79
- }
80
- else {
81
- tokens.push({ text, quoted });
82
- }
83
- // Look ahead for the dot that joins this name to the next part. SQLite treats a
84
- // COMMENT as whitespace, so `main /* … */ . _substrat_tuples` is one qualified
85
- // name — skipping only spaces here would record `main` as the target and miss it.
86
- let j = i;
87
- for (;;) {
88
- if (j < n && /\s/.test(sql[j])) {
89
- j += 1;
90
- continue;
91
- }
92
- if (sql[j] === '-' && sql[j + 1] === '-') {
93
- while (j < n && sql[j] !== '\n')
94
- j += 1;
95
- continue;
96
- }
97
- if (sql[j] === '/' && sql[j + 1] === '*') {
98
- j += 2;
99
- while (j < n && !(sql[j] === '*' && sql[j + 1] === '/'))
100
- j += 1;
101
- j += 2;
102
- continue;
103
- }
104
- break;
105
- }
106
- if (sql[j] === '.') {
107
- continues = true;
108
- i = j + 1;
109
- }
110
- else {
111
- continues = false;
112
- }
113
- };
114
- while (i < n) {
115
- const c = sql[i];
116
- const c2 = sql[i + 1];
117
- if (c === '-' && c2 === '-') {
118
- while (i < n && sql[i] !== '\n')
119
- i += 1;
120
- continue;
121
- }
122
- if (c === '/' && c2 === '*') {
123
- i += 2;
124
- while (i < n && !(sql[i] === '*' && sql[i + 1] === '/'))
125
- i += 1;
126
- i += 2;
127
- continue;
128
- }
129
- if (c === "'" || c === '"' || c === '`') {
130
- // A quoted identifier, or a string literal SQLite would still accept as one
131
- // in a table position. The closing quote doubles to escape itself.
132
- i += 1;
133
- let text = '';
134
- while (i < n) {
135
- if (sql[i] === c) {
136
- if (sql[i + 1] === c) {
137
- text += c;
138
- i += 2;
139
- continue;
140
- }
141
- i += 1;
142
- break;
143
- }
144
- text += sql[i];
145
- i += 1;
146
- }
147
- push(text, true);
148
- continue;
149
- }
150
- if (c === '[') {
151
- i += 1;
152
- let text = '';
153
- while (i < n && sql[i] !== ']') {
154
- text += sql[i];
155
- i += 1;
156
- }
157
- i += 1;
158
- push(text, true);
159
- continue;
160
- }
161
- if (/[A-Za-z_]/.test(c)) {
162
- let j = i;
163
- while (j < n && /[A-Za-z0-9_$]/.test(sql[j]))
164
- j += 1;
165
- const text = sql.slice(i, j);
166
- i = j;
167
- push(text, false);
168
- continue;
169
- }
170
- // Whitespace does not break a dotted name (`main . tbl` is one); anything else does.
171
- if (!/\s/.test(c))
172
- continues = false;
173
- i += 1;
174
- }
175
- return tokens;
176
- }
177
- /** True when any part of a (possibly dotted, possibly quoted) name is spine. */
178
- function namesSpine(token) {
179
- return token.text
180
- .split('.')
181
- .some((part) => part.toLowerCase().startsWith(SPINE_PREFIX));
182
- }
183
63
  /**
184
64
  * A SECOND table a statement can reach, past the one it names first.
185
65
  *
@@ -194,7 +74,7 @@ const SECOND_TARGET = { create: 'on', alter: 'to' };
194
74
  /** The first token at or after `from` that names the spine, following this verb's grammar. */
195
75
  function spineTargetFrom(tokens, from, verb) {
196
76
  const first = tokens[from];
197
- if (first && namesSpine(first))
77
+ if (first && namesSpineTable(first.text))
198
78
  return first;
199
79
  const keyword = SECOND_TARGET[verb];
200
80
  if (!keyword)
@@ -203,7 +83,7 @@ function spineTargetFrom(tokens, from, verb) {
203
83
  if (tokens[k].quoted || tokens[k].text.toLowerCase() !== keyword)
204
84
  continue;
205
85
  const after = tokens[k + 1];
206
- return after && namesSpine(after) ? after : undefined;
86
+ return after && namesSpineTable(after.text) ? after : undefined;
207
87
  }
208
88
  return undefined;
209
89
  }
@@ -215,7 +95,7 @@ function spineTargetFrom(tokens, from, verb) {
215
95
  * the table so the author sees which line to delete.
216
96
  */
217
97
  export function assertNoSpineWrite(sql) {
218
- const tokens = tokenize(sql);
98
+ const tokens = tokenizeSql(sql);
219
99
  for (let i = 0; i < tokens.length; i += 1) {
220
100
  const token = tokens[i];
221
101
  if (token.quoted)
@@ -234,6 +114,29 @@ export function assertNoSpineWrite(sql) {
234
114
  throw substratError('forbidden', `ctx.sql cannot write the platform spine: ${verb.toUpperCase()} on '${target.text}'. ` +
235
115
  'Reads are fine; writes go through ctx.emit / ctx.link / ctx.grant.', { reason: 'spine_write' });
236
116
  }
117
+ refuseSpineReference(referencedTablesIn(tokens), 'ctx.sql');
118
+ }
119
+ /**
120
+ * Refuse a statement whose `REFERENCES` clause names a `_substrat_*` table (#1898), for the
121
+ * same reason `CREATE TRIGGER … ON` is refused above: the spine's rows become the parent of a
122
+ * module's, and with foreign keys enforced the kernel's own writes to that table (a revoke, a
123
+ * restore's re-point, an outbox prune) then fail on the module's rows. That denies the spine
124
+ * rather than forging it. `what` names the SQL's source in the message.
125
+ *
126
+ * `ctx.sql` passes through here (`assertNoSpineWrite`), and so does every migration a scope
127
+ * applies, which reaches the database on the kernel's own handle rather than through
128
+ * `ctx.sql`. A dump's replayed DDL is held to the same rule by `assertReplayableDump`.
129
+ */
130
+ export function assertNoSpineReference(sql, what) {
131
+ refuseSpineReference(referencedTablesIn(tokenizeSql(sql)), what);
132
+ }
133
+ /** The refusal itself, over a statement's `REFERENCES` targets. */
134
+ function refuseSpineReference(referenced, what) {
135
+ const target = referenced.find(namesSpineTable);
136
+ if (target === undefined)
137
+ return;
138
+ throw substratError('forbidden', `${what} cannot declare a foreign key to the platform spine: REFERENCES '${target}'. ` +
139
+ 'A module table may reference its own tables; spine rows are reached through the kernel, never as a parent.', { reason: 'spine_write' });
237
140
  }
238
141
  /**
239
142
  * Wrap a module-facing `ScopedSql` so every statement passes `assertNoSpineWrite`
@@ -1 +1 @@
1
- {"version":3,"file":"spine-guard.js","sourceRoot":"","sources":["../src/spine-guard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"spine-guard.js","sourceRoot":"","sources":["../src/spine-guard.ts"],"names":[],"mappings":"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"}
@@ -23,7 +23,10 @@
23
23
  * - a spine table the kernel does not build is refused (`assertSpineTablesBuilt`), every such
24
24
  * table named at once.
25
25
  *
26
- * Tables outside the spine keep the dump's own DDL: a vertical's schema is the dump's to say.
26
+ * In a scope, tables outside the spine keep the dump's own DDL: a vertical's schema is the
27
+ * dump's to say. A directory has no vertical tables, so there every table is built by the
28
+ * host and loaded by these same rules, and a table it does not build is refused
29
+ * (`assertDirectoryTablesBuilt`, #1912).
27
30
  */
28
31
  /**
29
32
  * A kernel-owned table, which a restore builds from the kernel's DDL rather than the dump's.
@@ -41,14 +44,28 @@ export declare function isSpineTable(name: string): boolean;
41
44
  * tables (`_substrat_roles`, `_substrat_tenant_tuples`, …) that a node scope keeps in its
42
45
  * directory instead. Loading one anyway would mean dropping its rows, which a restore does not
43
46
  * do silently.
47
+ *
48
+ * Every `_substrat*` name is judged, the search index's namespace included (`namesSpineTable`,
49
+ * not `isSpineTable`): a scope restore has skipped its index tables before this, since it
50
+ * rebuilds them. A directory restore judges every table instead (`assertDirectoryTablesBuilt`).
44
51
  */
45
52
  export declare function assertSpineTablesBuilt(names: readonly string[], columnsOf: KernelColumnsOf): void;
46
53
  /** A table's columns as the kernel built it here, or `undefined` when it built no such table. */
47
54
  export type KernelColumnsOf = (name: string) => readonly string[] | undefined;
55
+ /**
56
+ * Refuse a directory dump carrying any table the directory does not build, spine or not, naming
57
+ * every one of them (#1912). A directory holds only the platform's own tables, so there is no
58
+ * vertical table whose DDL the dump could have a say in: an extra table would keep the dump's
59
+ * DDL, and with it whatever that declares, such as a `REFERENCES tenants` that fails the
60
+ * delete of a referenced row. `loadDirectoryDump` calls it first, where `assertSpineTablesBuilt`
61
+ * is in a scope restore, with the same `columnsOf`.
62
+ */
63
+ export declare function assertDirectoryTablesBuilt(names: readonly string[], columnsOf: KernelColumnsOf): void;
48
64
  /**
49
65
  * The `INSERT` that loads one dumped table's rows, one row of positional parameters per
50
66
  * execution, in the dump's column order: `spineRowsInsert` for a spine table, and the dump's
51
- * own columns for a vertical one. The names are quoted as given: the loader has already passed
67
+ * own columns for a vertical one. A directory builds every table, so it calls
68
+ * `spineRowsInsert` directly. The names are quoted as given: the loader has already passed
52
69
  * the dump through `assertReplayableDump`.
53
70
  */
54
71
  export declare function dumpRowsInsert(table: {
@@ -56,22 +73,24 @@ export declare function dumpRowsInsert(table: {
56
73
  columns: readonly string[];
57
74
  }, columnsOf: KernelColumnsOf): string;
58
75
  /**
59
- * The statements that add to a kernel-built spine table each column the dump carries and the
60
- * kernel does not, as a plain untyped column: `ADD COLUMN "<name>"`, lowercased, and nothing after it, so it
61
- * has no type, collation, constraint or default. Run after `assertSpineTablesBuilt` and before
62
- * the table's rows go in, inside the load's transaction. The names are the dump's, which
63
- * `assertReplayableDump` has already held to the identifier rule. Empty for a table the kernel
64
- * did not build, which `assertSpineTablesBuilt` has refused.
76
+ * The statements that add to a table the host built (a spine table, or any directory table,
77
+ * #1912) each column the dump carries and the host's table does not, as a plain untyped column:
78
+ * `ADD COLUMN "<name>"`, lowercased, and nothing after it, so it has no type, collation,
79
+ * constraint or default. Run after `assertSpineTablesBuilt` / `assertDirectoryTablesBuilt` and
80
+ * before the table's rows go in, inside the load's transaction. The names are the dump's, which
81
+ * `assertReplayableDump` has already held to the identifier rule. Empty for a table the host
82
+ * did not build, which those have refused.
65
83
  */
66
84
  export declare function spineColumnAdditions(table: {
67
85
  name: string;
68
86
  columns: readonly string[];
69
87
  }, kernelColumns: readonly string[] | undefined): string[];
70
88
  /**
71
- * The `INSERT` that loads one dumped spine table's rows into the table the kernel built.
89
+ * The `INSERT` that loads one dumped table's rows into the table the host built: a spine table,
90
+ * or any directory table (#1912).
72
91
  *
73
- * `kernelColumns` is the kernel table's column list as the loader reads it back after
74
- * `spineColumnAdditions`, or `undefined` when the kernel built no such table. Either refusal
92
+ * `kernelColumns` is the built table's column list as the loader reads it back after
93
+ * `spineColumnAdditions`, or `undefined` when the host built no such table. Either refusal
75
94
  * below is a backstop the loader's order makes unreachable, and throws `validation_failed`
76
95
  * inside the load's transaction, so the target keeps what it held.
77
96
  */
@@ -79,4 +98,44 @@ export declare function spineRowsInsert(table: {
79
98
  name: string;
80
99
  columns: readonly string[];
81
100
  }, kernelColumns: readonly string[] | undefined): string;
101
+ /**
102
+ * The naming columns a scope row from before the directory left NULL, filled with the defaults
103
+ * `resolveScopeRecord` applies: a ULID lowercases into a valid slug, so the placeholder is unique
104
+ * by construction. Run by both adapters' schema pass on every start, and by a directory restore
105
+ * after its rows are in, inside its transaction (#1912). One statement per entry, since a
106
+ * Durable Object's `exec` and better-sqlite3's `prepare` each take one.
107
+ */
108
+ export declare const LEGACY_SCOPE_ROWS_BACKFILL: readonly string[];
109
+ /**
110
+ * Load a directory dump's rows into the tables the host has just built from its own schema
111
+ * (#1912): the one sequence both adapters' directory restores run, inside their transaction,
112
+ * after dropping the old directory and running the schema pass.
113
+ *
114
+ * 1. refuse a table the directory does not build (`assertDirectoryTablesBuilt`), and one that
115
+ * would pass `maxColumns` once the dump's unknown columns join this code's own;
116
+ * 2. add each column the dump carries and this code does not know, bare and lowercased, and
117
+ * refuse one named for the rowid (`spineColumnAdditions`);
118
+ * 3. insert every row by column name, against the columns read back after step 2
119
+ * (`spineRowsInsert`);
120
+ * 4. fill a pre-directory scope row's naming columns (`LEGACY_SCOPE_ROWS_BACKFILL`);
121
+ * 5. backfill the schedule switch's record from the dump's own admin log, when the dump
122
+ * predates it (#1674). One that carried it keeps its rows and is never backfilled over.
123
+ *
124
+ * A throw anywhere is the caller's transaction rolling back, so the directory keeps what it held.
125
+ */
126
+ export declare function loadDirectoryDump(tables: readonly {
127
+ name: string;
128
+ columns: readonly string[];
129
+ rows: readonly (readonly unknown[])[];
130
+ }[], host: {
131
+ columnsOf: KernelColumnsOf;
132
+ exec: (sql: string) => void;
133
+ insert: (sql: string, rows: readonly (readonly unknown[])[]) => void;
134
+ /**
135
+ * The most columns a table here may hold: a Durable Object's cap. `assertReplayableDump`
136
+ * holds the dump's own column list to it, but a table grows by this code's columns plus the
137
+ * dump's unknown ones, which can pass it while each list alone does not.
138
+ */
139
+ maxColumns?: number;
140
+ }): void;
82
141
  //# sourceMappingURL=spine-restore.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"spine-restore.d.ts","sourceRoot":"","sources":["../src/spine-restore.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAIlD;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,eAAe,GAAG,IAAI,CAGjG;AAED,iGAAiG;AACjG,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;AAmB9E;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,EAAE,SAAS,EAAE,eAAe,GAAG,MAAM,CAEtH;AASD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,EACnD,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAC3C,MAAM,EAAE,CAkBV;AAKD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,EACnD,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAC3C,MAAM,CAyBR"}
1
+ {"version":3,"file":"spine-restore.d.ts","sourceRoot":"","sources":["../src/spine-restore.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAIlD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,eAAe,GAAG,IAAI,CAGjG;AAED,iGAAiG;AACjG,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;AAE9E;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,eAAe,GAAG,IAAI,CAUrG;AAmBD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,EAAE,SAAS,EAAE,eAAe,GAAG,MAAM,CAEtH;AASD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,EACnD,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAC3C,MAAM,EAAE,CAmBV;AAKD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,EACnD,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAC3C,MAAM,CAyBR;AAED;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,EAAE,SAAS,MAAM,EAIvD,CAAC;AAsBF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAA;CAAE,EAAE,EACtG,IAAI,EAAE;IACJ,SAAS,EAAE,eAAe,CAAC;IAC3B,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;IACrE;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GACA,IAAI,CASN"}
@@ -1,7 +1,7 @@
1
- import { substratError } from '@substrat-run/contracts';
1
+ import { SPINE_PREFIX, namesSpineTable, substratError } from '@substrat-run/contracts';
2
2
  import { SCHEDULE_STATE_KIND_OF_OP } from './platform-sweep.js';
3
3
  import { isSearchIndexTable } from './search-index.js';
4
- import { SPINE_PREFIX } from './spine-guard.js';
4
+ import { SYSTEM_SWITCHES_BACKFILL_SQL, dumpCarriesSystemSwitches } from './system-switch-record.js';
5
5
  /**
6
6
  * How a restore, fork or carry loads a dump's `_substrat_*` spine tables (#1883). One
7
7
  * definition for both adapters' loaders, so the DO and the pure host build the same tables
@@ -27,7 +27,10 @@ import { SPINE_PREFIX } from './spine-guard.js';
27
27
  * - a spine table the kernel does not build is refused (`assertSpineTablesBuilt`), every such
28
28
  * table named at once.
29
29
  *
30
- * Tables outside the spine keep the dump's own DDL: a vertical's schema is the dump's to say.
30
+ * In a scope, tables outside the spine keep the dump's own DDL: a vertical's schema is the
31
+ * dump's to say. A directory has no vertical tables, so there every table is built by the
32
+ * host and loaded by these same rules, and a table it does not build is refused
33
+ * (`assertDirectoryTablesBuilt`, #1912).
31
34
  */
32
35
  /**
33
36
  * A kernel-owned table, which a restore builds from the kernel's DDL rather than the dump's.
@@ -49,12 +52,32 @@ export function isSpineTable(name) {
49
52
  * tables (`_substrat_roles`, `_substrat_tenant_tuples`, …) that a node scope keeps in its
50
53
  * directory instead. Loading one anyway would mean dropping its rows, which a restore does not
51
54
  * do silently.
55
+ *
56
+ * Every `_substrat*` name is judged, the search index's namespace included (`namesSpineTable`,
57
+ * not `isSpineTable`): a scope restore has skipped its index tables before this, since it
58
+ * rebuilds them. A directory restore judges every table instead (`assertDirectoryTablesBuilt`).
52
59
  */
53
60
  export function assertSpineTablesBuilt(names, columnsOf) {
54
- const missing = names.filter((n) => isSpineTable(n) && columnsOf(n) === undefined);
61
+ const missing = names.filter((n) => namesSpineTable(n) && columnsOf(n) === undefined);
55
62
  if (missing.length > 0)
56
63
  throw unbuiltSpineTables(missing);
57
64
  }
65
+ /**
66
+ * Refuse a directory dump carrying any table the directory does not build, spine or not, naming
67
+ * every one of them (#1912). A directory holds only the platform's own tables, so there is no
68
+ * vertical table whose DDL the dump could have a say in: an extra table would keep the dump's
69
+ * DDL, and with it whatever that declares, such as a `REFERENCES tenants` that fails the
70
+ * delete of a referenced row. `loadDirectoryDump` calls it first, where `assertSpineTablesBuilt`
71
+ * is in a scope restore, with the same `columnsOf`.
72
+ */
73
+ export function assertDirectoryTablesBuilt(names, columnsOf) {
74
+ const missing = names.filter((n) => columnsOf(n) === undefined);
75
+ if (missing.length > 0) {
76
+ throw substratError('validation_failed', `restore refused: the dump carries table(s) this directory does not build: ${missing.join(', ')}. ` +
77
+ 'A directory holds only the platform\'s own tables, each built by this code, and a table it does not ' +
78
+ 'build would keep the dump\'s own schema. Nothing was changed.');
79
+ }
80
+ }
58
81
  const unbuiltSpineTables = (names) => substratError('validation_failed', `restore refused: the dump carries spine table(s) this host's kernel does not build: ${names.join(', ')}. ` +
59
82
  'It was exported by a different kind of host (a Durable Object scope holds spine tables a node scope ' +
60
83
  'keeps in its directory) or by a newer kernel, and its rows would have nowhere to go. Nothing was changed.');
@@ -69,7 +92,8 @@ const DERIVED_COLUMNS = {
69
92
  /**
70
93
  * The `INSERT` that loads one dumped table's rows, one row of positional parameters per
71
94
  * execution, in the dump's column order: `spineRowsInsert` for a spine table, and the dump's
72
- * own columns for a vertical one. The names are quoted as given: the loader has already passed
95
+ * own columns for a vertical one. A directory builds every table, so it calls
96
+ * `spineRowsInsert` directly. The names are quoted as given: the loader has already passed
73
97
  * the dump through `assertReplayableDump`.
74
98
  */
75
99
  export function dumpRowsInsert(table, columnsOf) {
@@ -80,12 +104,13 @@ const plainInsert = (table) => `INSERT INTO "${table.name}" (${table.columns.map
80
104
  /** Column names as SQLite resolves them, without case. */
81
105
  const lowered = (columns) => new Set(columns.map((c) => c.toLowerCase()));
82
106
  /**
83
- * The statements that add to a kernel-built spine table each column the dump carries and the
84
- * kernel does not, as a plain untyped column: `ADD COLUMN "<name>"`, lowercased, and nothing after it, so it
85
- * has no type, collation, constraint or default. Run after `assertSpineTablesBuilt` and before
86
- * the table's rows go in, inside the load's transaction. The names are the dump's, which
87
- * `assertReplayableDump` has already held to the identifier rule. Empty for a table the kernel
88
- * did not build, which `assertSpineTablesBuilt` has refused.
107
+ * The statements that add to a table the host built (a spine table, or any directory table,
108
+ * #1912) each column the dump carries and the host's table does not, as a plain untyped column:
109
+ * `ADD COLUMN "<name>"`, lowercased, and nothing after it, so it has no type, collation,
110
+ * constraint or default. Run after `assertSpineTablesBuilt` / `assertDirectoryTablesBuilt` and
111
+ * before the table's rows go in, inside the load's transaction. The names are the dump's, which
112
+ * `assertReplayableDump` has already held to the identifier rule. Empty for a table the host
113
+ * did not build, which those have refused.
89
114
  */
90
115
  export function spineColumnAdditions(table, kernelColumns) {
91
116
  if (kernelColumns === undefined)
@@ -94,7 +119,8 @@ export function spineColumnAdditions(table, kernelColumns) {
94
119
  const unknown = table.columns.filter((c) => !known.has(c.toLowerCase()));
95
120
  // A real column named for the rowid shadows SQLite's alias. On the outbox, `rowid` is the mark
96
121
  // the #1705 and #1746 since-queries read (`OUTBOX_MARK_SQL`), so a dump's value would silence
97
- // them from then on, and survive every later export.
122
+ // them from then on, and survive every later export. A directory table is held to the same
123
+ // rule: whatever reads its rowid, now or later, reads the dump's value instead.
98
124
  const aliased = unknown.filter((c) => ROWID_ALIASES.has(c.toLowerCase()));
99
125
  if (aliased.length > 0) {
100
126
  throw substratError('validation_failed', `restore refused: the dump's ${table.name} has column(s) named for SQLite's rowid: ${aliased.join(', ')}. ` +
@@ -107,15 +133,16 @@ export function spineColumnAdditions(table, kernelColumns) {
107
133
  /** The names SQLite resolves to a table's rowid, unless a real column takes one. */
108
134
  const ROWID_ALIASES = new Set(['rowid', 'oid', '_rowid_']);
109
135
  /**
110
- * The `INSERT` that loads one dumped spine table's rows into the table the kernel built.
136
+ * The `INSERT` that loads one dumped table's rows into the table the host built: a spine table,
137
+ * or any directory table (#1912).
111
138
  *
112
- * `kernelColumns` is the kernel table's column list as the loader reads it back after
113
- * `spineColumnAdditions`, or `undefined` when the kernel built no such table. Either refusal
139
+ * `kernelColumns` is the built table's column list as the loader reads it back after
140
+ * `spineColumnAdditions`, or `undefined` when the host built no such table. Either refusal
114
141
  * below is a backstop the loader's order makes unreachable, and throws `validation_failed`
115
142
  * inside the load's transaction, so the target keeps what it held.
116
143
  */
117
144
  export function spineRowsInsert(table, kernelColumns) {
118
- // `assertSpineTablesBuilt` has refused this already, naming every such table.
145
+ // `assertSpineTablesBuilt` / `assertDirectoryTablesBuilt` has refused this already, naming every such table.
119
146
  if (kernelColumns === undefined)
120
147
  throw unbuiltSpineTables([table.name]);
121
148
  const known = lowered(kernelColumns);
@@ -135,4 +162,61 @@ export function spineRowsInsert(table, kernelColumns) {
135
162
  return (`INSERT INTO "${table.name}" (${[...quoted, ...derived.map(([c]) => `"${c}"`)].join(', ')}) ` +
136
163
  `SELECT ${[...quoted, ...derived.map(([, expr]) => expr)].join(', ')} FROM (SELECT ${row})`);
137
164
  }
165
+ /**
166
+ * The naming columns a scope row from before the directory left NULL, filled with the defaults
167
+ * `resolveScopeRecord` applies: a ULID lowercases into a valid slug, so the placeholder is unique
168
+ * by construction. Run by both adapters' schema pass on every start, and by a directory restore
169
+ * after its rows are in, inside its transaction (#1912). One statement per entry, since a
170
+ * Durable Object's `exec` and better-sqlite3's `prepare` each take one.
171
+ */
172
+ export const LEGACY_SCOPE_ROWS_BACKFILL = [
173
+ 'UPDATE scopes SET slug = lower(scope_id) WHERE slug IS NULL',
174
+ "UPDATE scopes SET kind = 'scope' WHERE kind IS NULL",
175
+ 'UPDATE scopes SET name = slug WHERE name IS NULL',
176
+ ];
177
+ /** Refuse a table whose built columns plus the dump's unknown ones would pass `max`. */
178
+ function assertWithinColumnCap(tables, columnsOf, max) {
179
+ for (const t of tables) {
180
+ const built = columnsOf(t.name) ?? [];
181
+ const known = lowered(built);
182
+ const width = built.length + new Set(t.columns.map((c) => c.toLowerCase()).filter((c) => !known.has(c))).size;
183
+ if (width > max) {
184
+ throw substratError('validation_failed', `restore refused: the dump's ${t.name} would hold ${width} columns once the ones this code does not ` +
185
+ `know are added to its own, and a table here holds at most ${max}. Nothing was changed.`);
186
+ }
187
+ }
188
+ }
189
+ /**
190
+ * Load a directory dump's rows into the tables the host has just built from its own schema
191
+ * (#1912): the one sequence both adapters' directory restores run, inside their transaction,
192
+ * after dropping the old directory and running the schema pass.
193
+ *
194
+ * 1. refuse a table the directory does not build (`assertDirectoryTablesBuilt`), and one that
195
+ * would pass `maxColumns` once the dump's unknown columns join this code's own;
196
+ * 2. add each column the dump carries and this code does not know, bare and lowercased, and
197
+ * refuse one named for the rowid (`spineColumnAdditions`);
198
+ * 3. insert every row by column name, against the columns read back after step 2
199
+ * (`spineRowsInsert`);
200
+ * 4. fill a pre-directory scope row's naming columns (`LEGACY_SCOPE_ROWS_BACKFILL`);
201
+ * 5. backfill the schedule switch's record from the dump's own admin log, when the dump
202
+ * predates it (#1674). One that carried it keeps its rows and is never backfilled over.
203
+ *
204
+ * A throw anywhere is the caller's transaction rolling back, so the directory keeps what it held.
205
+ */
206
+ export function loadDirectoryDump(tables, host) {
207
+ assertDirectoryTablesBuilt(tables.map((t) => t.name), host.columnsOf);
208
+ if (host.maxColumns !== undefined)
209
+ assertWithinColumnCap(tables, host.columnsOf, host.maxColumns);
210
+ for (const t of tables)
211
+ for (const alter of spineColumnAdditions(t, host.columnsOf(t.name)))
212
+ host.exec(alter);
213
+ for (const t of tables) {
214
+ if (t.rows.length > 0)
215
+ host.insert(spineRowsInsert(t, host.columnsOf(t.name)), t.rows);
216
+ }
217
+ for (const stmt of LEGACY_SCOPE_ROWS_BACKFILL)
218
+ host.exec(stmt);
219
+ if (!dumpCarriesSystemSwitches(tables.map((t) => t.name)))
220
+ host.exec(SYSTEM_SWITCHES_BACKFILL_SQL);
221
+ }
138
222
  //# sourceMappingURL=spine-restore.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"spine-restore.js","sourceRoot":"","sources":["../src/spine-restore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"spine-restore.js","sourceRoot":"","sources":["../src/spine-restore.ts"],"names":[],"mappings":"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"}
@@ -26,6 +26,8 @@
26
26
  */
27
27
  import type { ListPage } from '@substrat-run/contracts';
28
28
  import type { SwitchSql, SwitchedOff, SystemScheduleState } from './system-switch.js';
29
+ /** The record's table name, as the DDL below spells it. */
30
+ export declare const SYSTEM_SWITCHES_TABLE = "_substrat_system_switches";
29
31
  /**
30
32
  * The table. Interpolated into both adapters' directory DDL, so `lint:spine-ddl` sees the
31
33
  * one spelling on each side. No CHECK on `position`: the drift gate does not compare
@@ -51,6 +53,12 @@ export declare const SYSTEM_SWITCHES_DDL = "\n CREATE TABLE IF NOT EXISTS _subs
51
53
  * The adapters run it only on the construction that creates the table, so it runs once.
52
54
  */
53
55
  export declare const SYSTEM_SWITCHES_BACKFILL_SQL = "\n WITH applied AS (\n SELECT DISTINCT action, json_extract(after, '$.operationId') AS operation_id\n FROM _substrat_admin_log\n WHERE action IN ('revokeFromSystem', 'restoreToSystem')\n AND json_extract(after, '$.phase') = 'applied'\n ),\n intents AS (\n SELECT i.id AS id, i.tenant_id AS tenant_id, i.scope_id AS scope_id,\n json_extract(i.after, '$.moduleId') AS module_id,\n CASE i.action WHEN 'revokeFromSystem' THEN 'off' ELSE 'on' END AS position,\n i.actor AS actor,\n json_extract(i.after, '$.reason') AS reason,\n json_extract(i.after, '$.operationId') AS operation_id,\n i.at AS at\n FROM _substrat_admin_log i\n JOIN applied a\n ON a.action = i.action AND a.operation_id = json_extract(i.after, '$.operationId')\n WHERE i.action IN ('revokeFromSystem', 'restoreToSystem')\n AND i.tenant_id IS NOT NULL AND i.scope_id IS NOT NULL\n AND json_extract(i.after, '$.phase') = 'intent'\n AND json_extract(i.after, '$.moduleId') IS NOT NULL\n AND json_extract(i.after, '$.reason') IS NOT NULL\n ),\n ranked AS (\n SELECT *,\n ROW_NUMBER() OVER (PARTITION BY tenant_id, scope_id, module_id ORDER BY id DESC) AS latest,\n MAX(position = 'off') OVER (PARTITION BY tenant_id, scope_id, module_id) AS ever_off\n FROM intents\n )\n INSERT OR IGNORE INTO _substrat_system_switches\n (tenant_id, scope_id, module_id, position, actor, reason, operation_id, switched_at)\n SELECT tenant_id, scope_id, module_id, position, actor, reason, operation_id, at\n FROM ranked\n WHERE latest = 1 AND ever_off = 1\n";
56
+ /**
57
+ * Does a dump carry the record table? A directory restore builds the table either way, and
58
+ * backfills it from the dump's own admin log only when the dump did not (#1898). Compared
59
+ * without case, as SQLite resolves a table name.
60
+ */
61
+ export declare function dumpCarriesSystemSwitches(names: readonly string[]): boolean;
54
62
  /** "Does the record table exist yet?" — asked BEFORE the DDL, so the backfill runs once. */
55
63
  export declare function systemSwitchesTableExists(db: SwitchSql): boolean;
56
64
  /** One record row as the directory holds it, with the scope's binding joined on. */
@@ -1 +1 @@
1
- {"version":3,"file":"system-switch-record.d.ts","sourceRoot":"","sources":["../src/system-switch-record.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"system-switch-record.d.ts","sourceRoot":"","sources":["../src/system-switch-record.ts"],"names":[],"mappings":"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"}