@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.
Files changed (164) hide show
  1. package/dist/admin-log-ddl.d.ts +21 -0
  2. package/dist/admin-log-ddl.d.ts.map +1 -0
  3. package/dist/admin-log-ddl.js +32 -0
  4. package/dist/admin-log-ddl.js.map +1 -0
  5. package/dist/attachment-extractor.d.ts +21 -2
  6. package/dist/attachment-extractor.d.ts.map +1 -1
  7. package/dist/attachment-extractor.js +31 -6
  8. package/dist/attachment-extractor.js.map +1 -1
  9. package/dist/attachment-text.d.ts +64 -0
  10. package/dist/attachment-text.d.ts.map +1 -1
  11. package/dist/attachment-text.js +87 -16
  12. package/dist/attachment-text.js.map +1 -1
  13. package/dist/attribution.d.ts +36 -3
  14. package/dist/attribution.d.ts.map +1 -1
  15. package/dist/attribution.js +21 -8
  16. package/dist/attribution.js.map +1 -1
  17. package/dist/audit-outcome.d.ts +149 -0
  18. package/dist/audit-outcome.d.ts.map +1 -0
  19. package/dist/audit-outcome.js +233 -0
  20. package/dist/audit-outcome.js.map +1 -0
  21. package/dist/connect-links.d.ts +91 -0
  22. package/dist/connect-links.d.ts.map +1 -0
  23. package/dist/connect-links.js +189 -0
  24. package/dist/connect-links.js.map +1 -0
  25. package/dist/connect-state.d.ts +12 -3
  26. package/dist/connect-state.d.ts.map +1 -1
  27. package/dist/connect-state.js +8 -3
  28. package/dist/connect-state.js.map +1 -1
  29. package/dist/derived-object.d.ts +14 -0
  30. package/dist/derived-object.d.ts.map +1 -0
  31. package/dist/derived-object.js +2 -0
  32. package/dist/derived-object.js.map +1 -0
  33. package/dist/derived-objects.d.ts +108 -0
  34. package/dist/derived-objects.d.ts.map +1 -0
  35. package/dist/derived-objects.js +199 -0
  36. package/dist/derived-objects.js.map +1 -0
  37. package/dist/email-intent.d.ts +56 -0
  38. package/dist/email-intent.d.ts.map +1 -0
  39. package/dist/email-intent.js +71 -0
  40. package/dist/email-intent.js.map +1 -0
  41. package/dist/entity-edges.d.ts +6 -1
  42. package/dist/entity-edges.d.ts.map +1 -1
  43. package/dist/entity-edges.js +13 -0
  44. package/dist/entity-edges.js.map +1 -1
  45. package/dist/entity-grant-shape.d.ts +94 -0
  46. package/dist/entity-grant-shape.d.ts.map +1 -0
  47. package/dist/entity-grant-shape.js +329 -0
  48. package/dist/entity-grant-shape.js.map +1 -0
  49. package/dist/entity-grant.d.ts +45 -0
  50. package/dist/entity-grant.d.ts.map +1 -0
  51. package/dist/entity-grant.js +71 -0
  52. package/dist/entity-grant.js.map +1 -0
  53. package/dist/entity-state-reads.d.ts +40 -0
  54. package/dist/entity-state-reads.d.ts.map +1 -0
  55. package/dist/entity-state-reads.js +91 -0
  56. package/dist/entity-state-reads.js.map +1 -0
  57. package/dist/entity-state.d.ts +204 -0
  58. package/dist/entity-state.d.ts.map +1 -0
  59. package/dist/entity-state.js +356 -0
  60. package/dist/entity-state.js.map +1 -0
  61. package/dist/entity-trash.d.ts +245 -0
  62. package/dist/entity-trash.d.ts.map +1 -0
  63. package/dist/entity-trash.js +380 -0
  64. package/dist/entity-trash.js.map +1 -0
  65. package/dist/findings.d.ts +143 -0
  66. package/dist/findings.d.ts.map +1 -0
  67. package/dist/findings.js +463 -0
  68. package/dist/findings.js.map +1 -0
  69. package/dist/grant-scoped-read.d.ts +41 -0
  70. package/dist/grant-scoped-read.d.ts.map +1 -0
  71. package/dist/grant-scoped-read.js +100 -0
  72. package/dist/grant-scoped-read.js.map +1 -0
  73. package/dist/index.d.ts +40 -8
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +26 -6
  76. package/dist/index.js.map +1 -1
  77. package/dist/kernel-outbox.d.ts +14 -0
  78. package/dist/kernel-outbox.d.ts.map +1 -0
  79. package/dist/kernel-outbox.js +37 -0
  80. package/dist/kernel-outbox.js.map +1 -0
  81. package/dist/list-index.d.ts +34 -3
  82. package/dist/list-index.d.ts.map +1 -1
  83. package/dist/list-index.js +83 -31
  84. package/dist/list-index.js.map +1 -1
  85. package/dist/mail-sender.d.ts +78 -0
  86. package/dist/mail-sender.d.ts.map +1 -0
  87. package/dist/mail-sender.js +2 -0
  88. package/dist/mail-sender.js.map +1 -0
  89. package/dist/membership-executor.d.ts +7 -47
  90. package/dist/membership-executor.d.ts.map +1 -1
  91. package/dist/membership-executor.js +28 -53
  92. package/dist/membership-executor.js.map +1 -1
  93. package/dist/migration-digest.d.ts +161 -0
  94. package/dist/migration-digest.d.ts.map +1 -0
  95. package/dist/migration-digest.js +237 -0
  96. package/dist/migration-digest.js.map +1 -0
  97. package/dist/module-erasure.d.ts +156 -0
  98. package/dist/module-erasure.d.ts.map +1 -0
  99. package/dist/module-erasure.js +440 -0
  100. package/dist/module-erasure.js.map +1 -0
  101. package/dist/module-migrations.d.ts +6 -3
  102. package/dist/module-migrations.d.ts.map +1 -1
  103. package/dist/module-migrations.js +12 -5
  104. package/dist/module-migrations.js.map +1 -1
  105. package/dist/peer.d.ts +9 -1
  106. package/dist/peer.d.ts.map +1 -1
  107. package/dist/peer.js +29 -0
  108. package/dist/peer.js.map +1 -1
  109. package/dist/permission-checker.d.ts +6 -0
  110. package/dist/permission-checker.d.ts.map +1 -1
  111. package/dist/permission-checker.js.map +1 -1
  112. package/dist/permission-eval.d.ts +51 -1
  113. package/dist/permission-eval.d.ts.map +1 -1
  114. package/dist/permission-eval.js +104 -2
  115. package/dist/permission-eval.js.map +1 -1
  116. package/dist/platform-sweep.d.ts +8 -2
  117. package/dist/platform-sweep.d.ts.map +1 -1
  118. package/dist/platform-sweep.js +17 -0
  119. package/dist/platform-sweep.js.map +1 -1
  120. package/dist/scope-host.d.ts +479 -24
  121. package/dist/scope-host.d.ts.map +1 -1
  122. package/dist/scope-host.js +82 -7
  123. package/dist/scope-host.js.map +1 -1
  124. package/dist/scope-role-admin.d.ts +68 -0
  125. package/dist/scope-role-admin.d.ts.map +1 -0
  126. package/dist/scope-role-admin.js +80 -0
  127. package/dist/scope-role-admin.js.map +1 -0
  128. package/dist/search-index.d.ts +21 -1
  129. package/dist/search-index.d.ts.map +1 -1
  130. package/dist/search-index.js +60 -37
  131. package/dist/search-index.js.map +1 -1
  132. package/dist/spine-guard.d.ts +71 -2
  133. package/dist/spine-guard.d.ts.map +1 -1
  134. package/dist/spine-guard.js +393 -10
  135. package/dist/spine-guard.js.map +1 -1
  136. package/dist/spine-restore.d.ts.map +1 -1
  137. package/dist/spine-restore.js +5 -0
  138. package/dist/spine-restore.js.map +1 -1
  139. package/dist/sql-identifier.d.ts +12 -0
  140. package/dist/sql-identifier.d.ts.map +1 -0
  141. package/dist/sql-identifier.js +17 -0
  142. package/dist/sql-identifier.js.map +1 -0
  143. package/dist/sql-statements.d.ts +71 -0
  144. package/dist/sql-statements.d.ts.map +1 -0
  145. package/dist/sql-statements.js +191 -0
  146. package/dist/sql-statements.js.map +1 -0
  147. package/dist/subject-redaction.d.ts +9 -1
  148. package/dist/subject-redaction.d.ts.map +1 -1
  149. package/dist/subject-redaction.js.map +1 -1
  150. package/dist/system-switch-record.d.ts +3 -0
  151. package/dist/system-switch-record.d.ts.map +1 -1
  152. package/dist/system-switch-record.js +2 -0
  153. package/dist/system-switch-record.js.map +1 -1
  154. package/dist/table-ownership.d.ts +103 -0
  155. package/dist/table-ownership.d.ts.map +1 -0
  156. package/dist/table-ownership.js +285 -0
  157. package/dist/table-ownership.js.map +1 -0
  158. package/dist/timeline.d.ts +4 -4
  159. package/dist/timeline.js +4 -4
  160. package/dist/visible-continuation.d.ts +38 -0
  161. package/dist/visible-continuation.d.ts.map +1 -0
  162. package/dist/visible-continuation.js +162 -0
  163. package/dist/visible-continuation.js.map +1 -0
  164. package/package.json +2 -2
@@ -2,53 +2,6 @@ import { instant, orgId, principalId, z, } from '@substrat-run/contracts';
2
2
  import { isUnknownRoleError } from './permission-checker.js';
3
3
  import { refuseDelivery } from './delivery-refusal.js';
4
4
  import {} from './scope-host.js';
5
- /**
6
- * The membership executor (K-22 §4.2, membership.md §4.2; #1184) — the out-of-band half of
7
- * joining and leaving, written once so a host mounts it instead of hand-rolling the effect.
8
- *
9
- * Module code asks in its own transaction and this effects after commit, through `HostAdmin`:
10
- * an invite engine's accept emits `member.add-requested`; a vertical's removal emits
11
- * `member.remove-requested`. A rolled-back operation leaves no event and nothing to effect.
12
- * Both are driven inline by the emitting call, with the outbox and `_substrat_deliveries` as
13
- * the retry backstop, so the common case completes inside the request.
14
- *
15
- * **What it effects: a tenant-level role, and nothing else.** An add assigns the invited role
16
- * at the tenant node; a removal unassigns it. Neither joins nor leaves an org, although both
17
- * payloads name one (the invites engine keys its invitations by org): what an org confers
18
- * includes grants in each scope's own store, which no directory unit can bound, so making
19
- * someone a member of an org is authority this seam does not carry.
20
- *
21
- * **Authority.** Every payload field is module-written, so none of them is authority.
22
- *
23
- * - An ADD is bounded by the inviter: the kernel-stamped `actor` of the invitation's own
24
- * `invites.sent` event, asked through the K-21 set comparison at the tenant node. Asked
25
- * twice: early, to refuse cheaply, and again inside the directory unit that writes the role
26
- * (`applyMembership`), so a demotion, a grant lost or a role widened in between is not
27
- * written past. The joiner is the request's own actor, who must have made the invitation's
28
- * first acceptance, and the request must be the first one naming that invitation: one
29
- * invitation, one join. The most a module can do is make the principal who actually invoked
30
- * it look like the sender — the same delegation bound `ctx.grant` has.
31
- * - A REMOVE is bounded by the remover, the request's own actor (§5.1: removal takes the
32
- * same bound, or a junior admin could strip a role they could not have granted) — asked the
33
- * same two ways, so a remover demoted in between removes nobody.
34
- *
35
- * **Removal wins.** An add is refused when the joiner was removed after it was requested: by a
36
- * later `member.remove-requested` on the same membership (ordered by outbox id), or by any
37
- * tenant-level removal at all — staff's included, and a no-op one — which raises the person's
38
- * removal fence in the directory unit that revokes. The add's own unit reads the fence, and a
39
- * fence at or after `occurredAt - MEMBERSHIP_REMOVAL_SKEW_MS` refuses it.
40
- *
41
- * A refusal is terminal (`refuseDelivery`): journaled with its reason, never retried, listed
42
- * by `executorDeadLetters`, and reported to the emitting call through `onExecutorOutcomes`.
43
- *
44
- * **The trail.** Admin rows are written by `actor`, the platform identity that executed them,
45
- * `onBehalfOf` (#977) the person whose authority bounded them, and with `causedBy` = the event
46
- * id: the correlation id that joins the scope's half of the trail to the directory's. A
47
- * removal that took nothing writes no row (K-21), but still raises the fence.
48
- *
49
- * **Idempotent.** A delivered event never reaches its handler again. A crash between the
50
- * effect and its journal row re-runs the handler, and every write it makes is idempotent.
51
- */
52
5
  /** What the add path consumes, and the version it reads. */
53
6
  export const MEMBER_ADD_REQUESTED = 'member.add-requested';
54
7
  /** What the remove path consumes, and the version it reads. */
@@ -96,39 +49,57 @@ export function registerMembershipExecutor(host, options) {
96
49
  'spans the directory and a scope store. A scope role has assignScopeRoleBounded.');
97
50
  }
98
51
  const id = options.id ?? MEMBERSHIP_EXECUTOR_ID;
52
+ const removeId = membershipRemoveExecutorId(id);
53
+ // The org a request names rides along only on a mount that joins orgs (#2047).
54
+ const orgOf = (request) => (options.orgs === 'join' ? { orgId: request.orgId } : {});
99
55
  // Attributed (#977): the person whose authority bounded the write, beside the platform
100
- // actor that executed it. `causedBy` is stamped by the host.
101
- const adminFor = (who, event) => (host.attributed?.({ principal: who, tenantId: event.tenantId }) ?? host).admin;
102
- host.registerExecutor(id, MEMBER_ADD_REQUESTED, async (_admin, event, scope) => {
56
+ // actor that executed it — added to the `admin` the dispatch handed the handler, which
57
+ // already carries the event (#2069). A host built before `HostAdmin.attributed` (an adapter
58
+ // at 0.139) hands an admin without it but has the deprecated `host.attributed(…, { causedBy })`,
59
+ // so that form is the fallback, and is why it is kept. A host with neither predates #977 and
60
+ // records no person on any row; that is said aloud rather than lost quietly.
61
+ // `executorId` is the id the calling path is registered under, so a warning names that path.
62
+ const adminFor = (executorId, admin, who, event) => {
63
+ const onBehalfOf = { principal: who, tenantId: event.tenantId };
64
+ if (admin.attributed)
65
+ return admin.attributed(onBehalfOf);
66
+ if (host.attributed)
67
+ return host.attributed(onBehalfOf, { causedBy: event.id }).admin;
68
+ console.warn(`executor:${executorId}: this host cannot attribute an admin to a person; ${event.id}'s rows name no onBehalfOf`);
69
+ return admin;
70
+ };
71
+ host.registerExecutor(id, MEMBER_ADD_REQUESTED, async (admin, event, scope) => {
103
72
  const decided = await authorizeAdd(event, scope);
104
73
  if ('refused' in decided)
105
74
  return decided.refused;
106
75
  const { request, inviter } = decided;
107
76
  // One directory unit: the fence, the bound asked again, the role and its audit row. A
108
77
  // removal or a change of authority lands wholly before it or wholly after it.
109
- const applied = await adminFor(inviter, event).applyMembership(options.actor, {
78
+ const applied = await adminFor(id, admin, inviter, event).applyMembership(options.actor, {
110
79
  op: 'add',
111
80
  tenantId: event.tenantId,
112
81
  principal: request.principal,
113
82
  roleKey: request.roleKey,
114
83
  boundedBy: inviter,
84
+ ...orgOf(request),
115
85
  unlessRemovedSince: instant.parse(new Date(Date.parse(event.occurredAt) - MEMBERSHIP_REMOVAL_SKEW_MS).toISOString()),
116
86
  });
117
87
  return applied.applied ? undefined : refusalOf(applied, request, 'inviter', inviter);
118
88
  }, options.retry);
119
- host.registerExecutor(membershipRemoveExecutorId(id), MEMBER_REMOVE_REQUESTED, async (_admin, event, scope) => {
89
+ host.registerExecutor(removeId, MEMBER_REMOVE_REQUESTED, async (admin, event, scope) => {
120
90
  const decided = await authorizeRemove(event, scope);
121
91
  if ('refused' in decided)
122
92
  return decided.refused;
123
93
  const { request, remover } = decided;
124
94
  // One directory unit: the remover's bound asked again, the revoke, its audit row if it
125
95
  // took anything, and the fence — raised even with nothing held, so a pending add sees it.
126
- const applied = await adminFor(remover, event).applyMembership(options.actor, {
96
+ const applied = await adminFor(removeId, admin, remover, event).applyMembership(options.actor, {
127
97
  op: 'remove',
128
98
  tenantId: event.tenantId,
129
99
  principal: request.principal,
130
100
  roleKey: request.roleKey,
131
101
  boundedBy: remover,
102
+ ...orgOf(request),
132
103
  });
133
104
  return applied.applied ? undefined : refusalOf(applied, request, 'remover', remover);
134
105
  }, options.retry);
@@ -139,6 +110,10 @@ function refusalOf(result, request, as, who) {
139
110
  return refuseDelivery(`${request.principal} was removed after this request was made`);
140
111
  if ('unknownRole' in result)
141
112
  return refuseDelivery(`no such role in this tenant: ${result.unknownRole}`);
113
+ if ('unknownOrg' in result)
114
+ return refuseDelivery(`no such org in this tenant: ${result.unknownOrg}`);
115
+ if ('notMember' in result)
116
+ return refuseDelivery(`the ${as} ${who} is not a member of org ${result.notMember}`);
142
117
  return refuseDelivery(`the ${as} ${who} no longer holds ${result.missing.join(', ')}, which '${request.roleKey}' confers`);
143
118
  }
144
119
  const refused = (reason) => ({ refused: refuseDelivery(reason) });
@@ -1 +1 @@
1
- {"version":3,"file":"membership-executor.js","sourceRoot":"","sources":["../src/membership-executor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"membership-executor.js","sourceRoot":"","sources":["../src/membership-executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,161 @@
1
+ import { moduleMigrations } from './module-migrations.js';
2
+ import { type SqlMigration } from './scope-host.js';
3
+ /**
4
+ * What a scope's migration journal records beside each version, and the check that reads it
5
+ * (#2066). Shared by both adapters, so the rule and the sentence an operator reads are one.
6
+ *
7
+ * A scope used to record an applied migration by `(module_id, version)` alone, so a later
8
+ * `0025` whose SQL differed from the `0025` it ran was skipped as already applied: a dev
9
+ * database that ran one branch's `0025` and then `main`'s, or a preview that ran an unmerged
10
+ * branch, kept whichever schema it got first, and the first sign was a query failing against
11
+ * a column that was not there. `_substrat_migrations.sql_digest` closes that.
12
+ *
13
+ * - **The digest is SHA-256 over the exact SQL text**, lowercase hex, with no normalisation:
14
+ * not whitespace, not comments, not line endings. Any change is a different migration. A
15
+ * shipped migration's text never changes on `main` (`lint:migrations --check` refuses the
16
+ * edit upstream), so a difference at a scope means the scope ran something else.
17
+ * - **Only a module's AUTHORED migrations are held to it.** The kernel-derived DDL
18
+ * (`search/…`, `state/…`, `list/…`, see `moduleMigrations`) is versioned by its
19
+ * declaration on purpose: the version names what decides the DDL, so the kernel may change
20
+ * how it spells the same declaration between releases. Holding those rows to a digest would
21
+ * fail every scope with a searchable entity closed on the kernel upgrade that respelled a
22
+ * trigger. Their digest is still recorded, as the fact of what ran.
23
+ * - **A row applied before the column carries `'legacy'`, and is accepted.** Nobody measured
24
+ * what it ran, so it gets no digest: backfilling the registered one would write a value
25
+ * nobody measured, and bless the one row this exists to catch if that scope did run
26
+ * something else. The mark is explicit rather than a NULL, because a NULL cannot say where it
27
+ * came from: the rows present when the column arrives are marked (`MIGRATION_DIGEST_MARK_LEGACY`),
28
+ * a dump taken before the column restores as `'legacy'` (the restore derives it), and from
29
+ * then on the fence below refuses a NULL however it is written. So `'legacy'` is provenance,
30
+ * and a NULL — say a dump edited to clear a digest — is refused rather than trusted. Such a
31
+ * row is unprotected for good, which is the price of not lying in the journal.
32
+ */
33
+ export declare function migrationDigest(sql: string): Promise<string>;
34
+ /** What a journal row applied before digests were recorded carries in `sql_digest` (#2066). */
35
+ export declare const MIGRATION_DIGEST_LEGACY = "legacy";
36
+ /**
37
+ * Marks the rows present when the column arrived. Run right after the column's ALTER on every
38
+ * wake: once the fence is in place it can only ever find those rows, since nothing else can
39
+ * leave a NULL. Literal text, like the fence, so `lint:spine-ddl` and a reviewer read one spelling.
40
+ */
41
+ export declare const MIGRATION_DIGEST_MARK_LEGACY = "UPDATE _substrat_migrations SET sql_digest = 'legacy' WHERE sql_digest IS NULL";
42
+ /**
43
+ * The fence: no journal row is written, or rewritten, without a digest or the legacy mark — in
44
+ * both adapters' KERNEL_DDL, after the journal table, so `lint:spine-ddl` holds it like any
45
+ * spine trigger.
46
+ *
47
+ * Without it an older writer (an instance still on the previous release during a rollout or a
48
+ * rollback, or a second process over the same SQLite file) inserts a row that omits the
49
+ * column, and SQLite records NULL. With it that INSERT aborts, so the older writer's migration
50
+ * fails and its scope fails closed until code that records the digest serves it, which then
51
+ * applies the migration properly. KERNEL_DDL runs before the column is ALTERed onto a legacy
52
+ * journal, and on a table without the column the INSERT trigger makes any INSERT fail with
53
+ * `no such column`: there is no window in which a NULL can be written. A restore loads its
54
+ * rows under the fence too, so a dump that carries a NULL is refused (`spineRowsInsert` gives a
55
+ * dump from before the column the legacy mark instead).
56
+ *
57
+ * Migration SQL cannot drop it: `assertNoJournalSql` refuses any migration naming the journal.
58
+ * Literal text, no interpolation: `lint:spine-ddl` inlines a kernel fragment one level deep.
59
+ */
60
+ export declare const MIGRATION_DIGEST_FENCE_DDL = "\n CREATE TRIGGER IF NOT EXISTS _substrat_migrations_digest_required\n BEFORE INSERT ON _substrat_migrations WHEN NEW.sql_digest IS NULL\n BEGIN\n SELECT RAISE(ABORT, 'a migration journal row must carry its sql_digest (#2066)');\n END;\n CREATE TRIGGER IF NOT EXISTS _substrat_migrations_digest_kept\n BEFORE UPDATE OF sql_digest ON _substrat_migrations WHEN NEW.sql_digest IS NULL\n BEGIN\n SELECT RAISE(ABORT, 'a migration journal row must carry its sql_digest (#2066)');\n END;\n";
61
+ /**
62
+ * Refuse migration SQL that names the migration journal (`_substrat_migration…`: the table, its
63
+ * fence, the DO's bookmarks), in any spelling the grammar allows — quoted, any case, schema-
64
+ * qualified — before any of it runs.
65
+ *
66
+ * A migration runs on the kernel's own handle, not `ctx.sql`, so the spine write guard never
67
+ * sees it, and an authored migration that repairs `_substrat_tuples` is a reviewed, linted path
68
+ * (`boundary-lint-allow R4 migration`). The journal is different: a migration that drops the
69
+ * fence, or writes its own journal rows, makes the digest check say whatever it wrote. Nothing
70
+ * legitimate in a module's migration names it, reads included.
71
+ */
72
+ export declare function assertNoJournalSql(sql: string, what: string): void;
73
+ /**
74
+ * Refuse a migration's SQL before any of it runs, if it reaches where a migration must not.
75
+ *
76
+ * A migration runs on the kernel's own handle, not `ctx.sql`, so `ctx.sql`'s guard never sees it.
77
+ * Every migration is held to: no foreign key to the spine (#1898), and nothing that names the
78
+ * journal (`assertNoJournalSql`). An AUTHORED one is also held to the full spine write guard —
79
+ * no write, DDL or same-named TEMP object on any `_substrat_*` table — unless it is one of the
80
+ * exact reviewed texts above. Kernel-derived DDL is exempt from that last rule: creating
81
+ * `_substrat_*` indexes and triggers is what it is for.
82
+ */
83
+ export declare function assertMigrationSql(sql: string, step: {
84
+ key: string;
85
+ digest: string;
86
+ authored: boolean;
87
+ }): void;
88
+ /**
89
+ * Refuse a dump whose journal is not consistent with its own shape (#2066 r3): a table whose
90
+ * recorded DDL declares `sql_digest` while its columns omit it, or the other way round.
91
+ *
92
+ * A dump exported before digests were recorded restores as `'legacy'` (`spineRowsInsert`), so
93
+ * the shape of the journal is what says which kind of dump this is — and a current dump with
94
+ * the column stripped would otherwise pass as legacy and unprotect every row. The dump's DDL is
95
+ * `sqlite_master`'s text, which an ALTER rewrites, so a real pre-#2066 journal carries neither.
96
+ * Nothing else a dump carries changed with #2066 to cross-check against (the fence is a trigger,
97
+ * and a dump holds tables). A dump is freely editable data: a consistent edit of both is not
98
+ * detectable, and restore is privileged, audited staff work that could forge any digest anyway.
99
+ * This catches corruption and partial edits, not an author set on lying.
100
+ */
101
+ export declare function assertJournalDumpCoherent(tables: readonly {
102
+ name: string;
103
+ ddl: string;
104
+ columns: readonly string[];
105
+ }[]): void;
106
+ /** One migration a host applies, with its digest and whether it is held to it. */
107
+ export interface MigrationStep {
108
+ migration: SqlMigration;
109
+ digest: string;
110
+ /** Authored by the module, so held to its digest; false for kernel-derived DDL. */
111
+ authored: boolean;
112
+ }
113
+ /**
114
+ * A module's migrations in the order the host applies them (`moduleMigrations`), each with its
115
+ * digest and whether it is authored — read from the registration as it is now. The digest of a
116
+ * text is computed once per isolate, so a Durable Object that wakes with the same code hashes
117
+ * nothing again.
118
+ */
119
+ export declare function migrationSteps(registration: Parameters<typeof moduleMigrations>[0]): Promise<readonly MigrationStep[]>;
120
+ /** A step a migration pass still has to run, with the module it belongs to. */
121
+ export interface PendingMigration extends MigrationStep {
122
+ moduleId: string;
123
+ }
124
+ /** What a migration pass has to do, or the divergence that fails the scope closed instead. */
125
+ export type MigrationPlan = {
126
+ pending: PendingMigration[];
127
+ diverged?: undefined;
128
+ } | {
129
+ pending: [];
130
+ diverged: {
131
+ version: string;
132
+ error: string;
133
+ };
134
+ };
135
+ /**
136
+ * Plan a scope's migration pass against its journal (`module@version` → recorded digest): the
137
+ * registered steps it has not applied, or the first applied one whose SQL differs, which fails
138
+ * the scope closed before anything else runs. Both adapters plan through this.
139
+ */
140
+ export declare function planMigrations(modules: Iterable<{
141
+ readonly id: string;
142
+ readonly steps: Promise<readonly MigrationStep[]>;
143
+ }>, applied: ReadonlyMap<string, string | null>): Promise<MigrationPlan>;
144
+ /** The error a scope fails closed with when `module@version` cannot be applied or trusted. */
145
+ export declare function migrationFailedError(key: string, cause: string): Error;
146
+ /**
147
+ * Why a registered migration the scope has already applied cannot be trusted, or null when it
148
+ * can: on an authored migration, a recorded digest that differs from the registered one, or
149
+ * no digest and no legacy mark at all.
150
+ *
151
+ * The caller fails the scope closed with this as the cause, the way a migration that threw
152
+ * does — the same `migration failed for <module>@<version> — scope fails closed:` record, so
153
+ * the directory, the sweep and the dashboard read it with nothing new. The scope recovers
154
+ * when its journal and its schema agree with the deployment again: a scope that ran another
155
+ * branch's migration is rebuilt (a dev database, a preview) or restored to a dump taken before
156
+ * it ran; a deployment carrying the wrong SQL is redeployed with the SQL the scope ran. A
157
+ * migration is never edited or renumbered once a scope has it, so re-numbering is not a
158
+ * recovery: the scope would still hold the other SQL under this version.
159
+ */
160
+ export declare function migrationDivergence(recorded: string | null | undefined, registered: string, authored: boolean): string | null;
161
+ //# sourceMappingURL=migration-digest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-digest.d.ts","sourceRoot":"","sources":["../src/migration-digest.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAKtE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE5D;AAED,+FAA+F;AAC/F,eAAO,MAAM,uBAAuB,WAAW,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,mFAAmF,CAAC;AAE7H;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,0BAA0B,qfAWtC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CASlE;AAiBD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAY9G;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,EAAE,GAAG,IAAI,CAY5H;AAED,kFAAkF;AAClF,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,YAAY,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,QAAQ,EAAE,OAAO,CAAC;CACnB;AAcD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC,CAStH;AAED,+EAA+E;AAC/E,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,8FAA8F;AAC9F,MAAM,MAAM,aAAa,GACrB;IAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,GACrD;IAAE,OAAO,EAAE,EAAE,CAAC;IAAC,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAElE;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,QAAQ,CAAC;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC,CAAA;CAAE,CAAC,EAC7F,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,GAC1C,OAAO,CAAC,aAAa,CAAC,CAcxB;AAED,8FAA8F;AAC9F,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,CAEtE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,OAAO,GAChB,MAAM,GAAG,IAAI,CAgBf"}
@@ -0,0 +1,237 @@
1
+ import { substratError, tokenizeSql } from '@substrat-run/contracts';
2
+ import { moduleMigrations } from './module-migrations.js';
3
+ import { assertNoSpineReference, assertNoSpineWrite } from './spine-guard.js';
4
+ import { attachmentSha256 } from './scope-host.js';
5
+ /**
6
+ * What a scope's migration journal records beside each version, and the check that reads it
7
+ * (#2066). Shared by both adapters, so the rule and the sentence an operator reads are one.
8
+ *
9
+ * A scope used to record an applied migration by `(module_id, version)` alone, so a later
10
+ * `0025` whose SQL differed from the `0025` it ran was skipped as already applied: a dev
11
+ * database that ran one branch's `0025` and then `main`'s, or a preview that ran an unmerged
12
+ * branch, kept whichever schema it got first, and the first sign was a query failing against
13
+ * a column that was not there. `_substrat_migrations.sql_digest` closes that.
14
+ *
15
+ * - **The digest is SHA-256 over the exact SQL text**, lowercase hex, with no normalisation:
16
+ * not whitespace, not comments, not line endings. Any change is a different migration. A
17
+ * shipped migration's text never changes on `main` (`lint:migrations --check` refuses the
18
+ * edit upstream), so a difference at a scope means the scope ran something else.
19
+ * - **Only a module's AUTHORED migrations are held to it.** The kernel-derived DDL
20
+ * (`search/…`, `state/…`, `list/…`, see `moduleMigrations`) is versioned by its
21
+ * declaration on purpose: the version names what decides the DDL, so the kernel may change
22
+ * how it spells the same declaration between releases. Holding those rows to a digest would
23
+ * fail every scope with a searchable entity closed on the kernel upgrade that respelled a
24
+ * trigger. Their digest is still recorded, as the fact of what ran.
25
+ * - **A row applied before the column carries `'legacy'`, and is accepted.** Nobody measured
26
+ * what it ran, so it gets no digest: backfilling the registered one would write a value
27
+ * nobody measured, and bless the one row this exists to catch if that scope did run
28
+ * something else. The mark is explicit rather than a NULL, because a NULL cannot say where it
29
+ * came from: the rows present when the column arrives are marked (`MIGRATION_DIGEST_MARK_LEGACY`),
30
+ * a dump taken before the column restores as `'legacy'` (the restore derives it), and from
31
+ * then on the fence below refuses a NULL however it is written. So `'legacy'` is provenance,
32
+ * and a NULL — say a dump edited to clear a digest — is refused rather than trusted. Such a
33
+ * row is unprotected for good, which is the price of not lying in the journal.
34
+ */
35
+ export function migrationDigest(sql) {
36
+ return attachmentSha256(new TextEncoder().encode(sql));
37
+ }
38
+ /** What a journal row applied before digests were recorded carries in `sql_digest` (#2066). */
39
+ export const MIGRATION_DIGEST_LEGACY = 'legacy';
40
+ /**
41
+ * Marks the rows present when the column arrived. Run right after the column's ALTER on every
42
+ * wake: once the fence is in place it can only ever find those rows, since nothing else can
43
+ * leave a NULL. Literal text, like the fence, so `lint:spine-ddl` and a reviewer read one spelling.
44
+ */
45
+ export const MIGRATION_DIGEST_MARK_LEGACY = "UPDATE _substrat_migrations SET sql_digest = 'legacy' WHERE sql_digest IS NULL";
46
+ /**
47
+ * The fence: no journal row is written, or rewritten, without a digest or the legacy mark — in
48
+ * both adapters' KERNEL_DDL, after the journal table, so `lint:spine-ddl` holds it like any
49
+ * spine trigger.
50
+ *
51
+ * Without it an older writer (an instance still on the previous release during a rollout or a
52
+ * rollback, or a second process over the same SQLite file) inserts a row that omits the
53
+ * column, and SQLite records NULL. With it that INSERT aborts, so the older writer's migration
54
+ * fails and its scope fails closed until code that records the digest serves it, which then
55
+ * applies the migration properly. KERNEL_DDL runs before the column is ALTERed onto a legacy
56
+ * journal, and on a table without the column the INSERT trigger makes any INSERT fail with
57
+ * `no such column`: there is no window in which a NULL can be written. A restore loads its
58
+ * rows under the fence too, so a dump that carries a NULL is refused (`spineRowsInsert` gives a
59
+ * dump from before the column the legacy mark instead).
60
+ *
61
+ * Migration SQL cannot drop it: `assertNoJournalSql` refuses any migration naming the journal.
62
+ * Literal text, no interpolation: `lint:spine-ddl` inlines a kernel fragment one level deep.
63
+ */
64
+ export const MIGRATION_DIGEST_FENCE_DDL = `
65
+ CREATE TRIGGER IF NOT EXISTS _substrat_migrations_digest_required
66
+ BEFORE INSERT ON _substrat_migrations WHEN NEW.sql_digest IS NULL
67
+ BEGIN
68
+ SELECT RAISE(ABORT, 'a migration journal row must carry its sql_digest (#2066)');
69
+ END;
70
+ CREATE TRIGGER IF NOT EXISTS _substrat_migrations_digest_kept
71
+ BEFORE UPDATE OF sql_digest ON _substrat_migrations WHEN NEW.sql_digest IS NULL
72
+ BEGIN
73
+ SELECT RAISE(ABORT, 'a migration journal row must carry its sql_digest (#2066)');
74
+ END;
75
+ `;
76
+ /**
77
+ * Refuse migration SQL that names the migration journal (`_substrat_migration…`: the table, its
78
+ * fence, the DO's bookmarks), in any spelling the grammar allows — quoted, any case, schema-
79
+ * qualified — before any of it runs.
80
+ *
81
+ * A migration runs on the kernel's own handle, not `ctx.sql`, so the spine write guard never
82
+ * sees it, and an authored migration that repairs `_substrat_tuples` is a reviewed, linted path
83
+ * (`boundary-lint-allow R4 migration`). The journal is different: a migration that drops the
84
+ * fence, or writes its own journal rows, makes the digest check say whatever it wrote. Nothing
85
+ * legitimate in a module's migration names it, reads included.
86
+ */
87
+ export function assertNoJournalSql(sql, what) {
88
+ for (const token of tokenizeSql(sql)) {
89
+ if (!token.text.split('.').some((part) => part.toLowerCase().startsWith('_substrat_migration')))
90
+ continue;
91
+ throw substratError('forbidden', `${what} cannot name the migration journal ('${token.text}'): the journal and its digest fence are the kernel's (#2066)`, { reason: 'spine_write' });
92
+ }
93
+ }
94
+ /**
95
+ * The authored migrations allowed to write the spine: four shipped ticket0 repairs of its own
96
+ * `_substrat_tuples` edges and its hand-recreated derived list indexes, each reviewed under
97
+ * `boundary-lint-allow R4 migration`. Keyed by module, version AND the digest of the exact text,
98
+ * so only those texts pass: a new migration, or any edit to one of these, gets the full guard.
99
+ * Shipped migrations are append-only, so this list only ever shrinks — a new spine repair goes
100
+ * through the platform, not a migration.
101
+ */
102
+ const REVIEWED_SPINE_MIGRATIONS = new Set([
103
+ '@substrat-run/demo-ticket0@0020#d29122b68f3cc5d07a70fb87874085e0e6805e2e19612984160488c59789d75c',
104
+ '@substrat-run/demo-ticket0@0022#9de9088207fa914e9eb8c8344924708655cbecb11e5b64f76e1d2ec7d0bd0ea2',
105
+ '@substrat-run/demo-ticket0@0024#ba60103ae91108bfce21fd5b24818cec18aefe4ee3b03b49ca8013fd2634aae3',
106
+ '@substrat-run/demo-ticket0@0026#da0bb4e3c8b13f5febd8b2202e7267c30e9ee91a19d202181b99ccdeb71ec3a4',
107
+ ]);
108
+ /**
109
+ * Refuse a migration's SQL before any of it runs, if it reaches where a migration must not.
110
+ *
111
+ * A migration runs on the kernel's own handle, not `ctx.sql`, so `ctx.sql`'s guard never sees it.
112
+ * Every migration is held to: no foreign key to the spine (#1898), and nothing that names the
113
+ * journal (`assertNoJournalSql`). An AUTHORED one is also held to the full spine write guard —
114
+ * no write, DDL or same-named TEMP object on any `_substrat_*` table — unless it is one of the
115
+ * exact reviewed texts above. Kernel-derived DDL is exempt from that last rule: creating
116
+ * `_substrat_*` indexes and triggers is what it is for.
117
+ */
118
+ export function assertMigrationSql(sql, step) {
119
+ const what = `migration ${step.key}`;
120
+ assertNoSpineReference(sql, what);
121
+ assertNoJournalSql(sql, what);
122
+ if (!step.authored || REVIEWED_SPINE_MIGRATIONS.has(`${step.key}#${step.digest}`))
123
+ return;
124
+ try {
125
+ assertNoSpineWrite(sql);
126
+ }
127
+ catch (err) {
128
+ throw substratError('forbidden', `${what} cannot write the platform spine: ${err.message.replace(/^ctx\.sql cannot write the platform spine: /, '')}`, {
129
+ reason: 'spine_write',
130
+ });
131
+ }
132
+ }
133
+ /**
134
+ * Refuse a dump whose journal is not consistent with its own shape (#2066 r3): a table whose
135
+ * recorded DDL declares `sql_digest` while its columns omit it, or the other way round.
136
+ *
137
+ * A dump exported before digests were recorded restores as `'legacy'` (`spineRowsInsert`), so
138
+ * the shape of the journal is what says which kind of dump this is — and a current dump with
139
+ * the column stripped would otherwise pass as legacy and unprotect every row. The dump's DDL is
140
+ * `sqlite_master`'s text, which an ALTER rewrites, so a real pre-#2066 journal carries neither.
141
+ * Nothing else a dump carries changed with #2066 to cross-check against (the fence is a trigger,
142
+ * and a dump holds tables). A dump is freely editable data: a consistent edit of both is not
143
+ * detectable, and restore is privileged, audited staff work that could forge any digest anyway.
144
+ * This catches corruption and partial edits, not an author set on lying.
145
+ */
146
+ export function assertJournalDumpCoherent(tables) {
147
+ for (const t of tables) {
148
+ if (t.name.toLowerCase() !== '_substrat_migrations')
149
+ continue;
150
+ const declared = tokenizeSql(t.ddl).some((tok) => tok.text.toLowerCase() === 'sql_digest');
151
+ const carried = t.columns.some((c) => c.toLowerCase() === 'sql_digest');
152
+ if (declared === carried)
153
+ continue;
154
+ throw substratError('validation_failed', `restore refused: the dump's _substrat_migrations ${declared ? 'declares sql_digest in its DDL but carries no such column' : 'carries sql_digest but its DDL does not declare it'} — ` +
155
+ `it is neither a dump from before digests were recorded nor a whole one from after. Nothing was changed (#2066).`);
156
+ }
157
+ }
158
+ /**
159
+ * Digests by SQL text. Keyed on the content, not on the registration object: a registration
160
+ * mutated or rebuilt with other SQL under the same version gets that SQL's digest, never a
161
+ * stale one. Bounded by the distinct migration texts the isolate has registered.
162
+ */
163
+ const digestOf = new Map();
164
+ const cachedDigest = (sql) => {
165
+ let digest = digestOf.get(sql);
166
+ if (!digest)
167
+ digestOf.set(sql, (digest = migrationDigest(sql)));
168
+ return digest;
169
+ };
170
+ /**
171
+ * A module's migrations in the order the host applies them (`moduleMigrations`), each with its
172
+ * digest and whether it is authored — read from the registration as it is now. The digest of a
173
+ * text is computed once per isolate, so a Durable Object that wakes with the same code hashes
174
+ * nothing again.
175
+ */
176
+ export function migrationSteps(registration) {
177
+ const authored = new Set((registration.migrations ?? []).map((m) => m.version));
178
+ return Promise.all(moduleMigrations(registration).map(async (migration) => ({
179
+ migration,
180
+ digest: await cachedDigest(migration.sql),
181
+ authored: authored.has(migration.version),
182
+ })));
183
+ }
184
+ /**
185
+ * Plan a scope's migration pass against its journal (`module@version` → recorded digest): the
186
+ * registered steps it has not applied, or the first applied one whose SQL differs, which fails
187
+ * the scope closed before anything else runs. Both adapters plan through this.
188
+ */
189
+ export async function planMigrations(modules, applied) {
190
+ const pending = [];
191
+ for (const mod of modules) {
192
+ for (const step of await mod.steps) {
193
+ const key = `${mod.id}@${step.migration.version}`;
194
+ if (!applied.has(key)) {
195
+ pending.push({ moduleId: mod.id, ...step });
196
+ continue;
197
+ }
198
+ const error = migrationDivergence(applied.get(key), step.digest, step.authored);
199
+ if (error)
200
+ return { pending: [], diverged: { version: key, error } };
201
+ }
202
+ }
203
+ return { pending };
204
+ }
205
+ /** The error a scope fails closed with when `module@version` cannot be applied or trusted. */
206
+ export function migrationFailedError(key, cause) {
207
+ return new Error(`migration failed for ${key} — scope fails closed: ${cause}`);
208
+ }
209
+ /**
210
+ * Why a registered migration the scope has already applied cannot be trusted, or null when it
211
+ * can: on an authored migration, a recorded digest that differs from the registered one, or
212
+ * no digest and no legacy mark at all.
213
+ *
214
+ * The caller fails the scope closed with this as the cause, the way a migration that threw
215
+ * does — the same `migration failed for <module>@<version> — scope fails closed:` record, so
216
+ * the directory, the sweep and the dashboard read it with nothing new. The scope recovers
217
+ * when its journal and its schema agree with the deployment again: a scope that ran another
218
+ * branch's migration is rebuilt (a dev database, a preview) or restored to a dump taken before
219
+ * it ran; a deployment carrying the wrong SQL is redeployed with the SQL the scope ran. A
220
+ * migration is never edited or renumbered once a scope has it, so re-numbering is not a
221
+ * recovery: the scope would still hold the other SQL under this version.
222
+ */
223
+ export function migrationDivergence(recorded, registered, authored) {
224
+ if (!authored || recorded === undefined || recorded === registered || recorded === MIGRATION_DIGEST_LEGACY)
225
+ return null;
226
+ if (recorded === null) {
227
+ // The fence makes this unreachable through the kernel; a row that has it anyway was not
228
+ // written by the kernel, and says nothing about what ran.
229
+ return (`this scope's journal records neither a digest nor the legacy mark for this version, so ` +
230
+ `what it ran is unknown (registered sha256 ${registered}). Rebuild the scope, or restore it ` +
231
+ `to a dump the kernel wrote (#2066)`);
232
+ }
233
+ return (`this scope applied different SQL under this version (applied sha256 ${recorded}, ` +
234
+ `registered sha256 ${registered}). Rebuild the scope, or restore it to a dump taken before ` +
235
+ `it ran the other SQL; a migration is never edited or renumbered once a scope has applied it (#2066)`);
236
+ }
237
+ //# sourceMappingURL=migration-digest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-digest.js","sourceRoot":"","sources":["../src/migration-digest.ts"],"names":[],"mappings":"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"}