@substrat-run/kernel 0.119.0 → 0.121.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 (39) hide show
  1. package/dist/index.d.ts +9 -5
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +7 -4
  4. package/dist/index.js.map +1 -1
  5. package/dist/list-index.d.ts.map +1 -1
  6. package/dist/list-index.js +5 -2
  7. package/dist/list-index.js.map +1 -1
  8. package/dist/module-migrations.d.ts +26 -0
  9. package/dist/module-migrations.d.ts.map +1 -0
  10. package/dist/module-migrations.js +21 -0
  11. package/dist/module-migrations.js.map +1 -0
  12. package/dist/platform-call.d.ts +20 -0
  13. package/dist/platform-call.d.ts.map +1 -1
  14. package/dist/platform-call.js +24 -0
  15. package/dist/platform-call.js.map +1 -1
  16. package/dist/platform-sweep.d.ts +157 -4
  17. package/dist/platform-sweep.d.ts.map +1 -1
  18. package/dist/platform-sweep.js +574 -45
  19. package/dist/platform-sweep.js.map +1 -1
  20. package/dist/scope-host.d.ts +110 -5
  21. package/dist/scope-host.d.ts.map +1 -1
  22. package/dist/scope-host.js.map +1 -1
  23. package/dist/sql-limits.d.ts +70 -0
  24. package/dist/sql-limits.d.ts.map +1 -0
  25. package/dist/sql-limits.js +197 -0
  26. package/dist/sql-limits.js.map +1 -0
  27. package/dist/system-switch-record.d.ts +158 -0
  28. package/dist/system-switch-record.d.ts.map +1 -0
  29. package/dist/system-switch-record.js +227 -0
  30. package/dist/system-switch-record.js.map +1 -0
  31. package/dist/ulid.d.ts +6 -0
  32. package/dist/ulid.d.ts.map +1 -1
  33. package/dist/ulid.js +21 -7
  34. package/dist/ulid.js.map +1 -1
  35. package/dist/vertical-events.d.ts +96 -2
  36. package/dist/vertical-events.d.ts.map +1 -1
  37. package/dist/vertical-events.js +230 -1
  38. package/dist/vertical-events.js.map +1 -1
  39. package/package.json +2 -2
@@ -0,0 +1,227 @@
1
+ /**
2
+ * The table. Interpolated into both adapters' directory DDL, so `lint:spine-ddl` sees the
3
+ * one spelling on each side. No CHECK on `position`: the drift gate does not compare
4
+ * constraints, and the writers below are the only thing that sets it.
5
+ */
6
+ export const SYSTEM_SWITCHES_DDL = `
7
+ CREATE TABLE IF NOT EXISTS _substrat_system_switches (
8
+ tenant_id TEXT NOT NULL,
9
+ scope_id TEXT NOT NULL,
10
+ module_id TEXT NOT NULL,
11
+ -- 'on' or 'off'. A row exists only for a module some switch call actually held.
12
+ position TEXT NOT NULL,
13
+ actor TEXT NOT NULL,
14
+ reason TEXT NOT NULL,
15
+ -- The switch call's own id, the one its admin-log intent and outcome rows carry.
16
+ -- A ULID, so it is also the fleet read's chronological keyset cursor.
17
+ operation_id TEXT NOT NULL,
18
+ switched_at TEXT NOT NULL,
19
+ PRIMARY KEY (tenant_id, scope_id, module_id)
20
+ );
21
+ CREATE INDEX IF NOT EXISTS _substrat_system_switches_position
22
+ ON _substrat_system_switches (position, operation_id);
23
+ CREATE INDEX IF NOT EXISTS _substrat_system_switches_operation
24
+ ON _substrat_system_switches (operation_id);
25
+ `;
26
+ /**
27
+ * The one-time backfill from the admin log: every switch moved before the record existed.
28
+ * Without it, those are exactly the switches a wipe would still lose.
29
+ *
30
+ * It reads the admin-log shape `revokeFromSystem` / `restoreToSystem` have written since
31
+ * #1666, two rows per call sharing `after.operationId`: an `intent` row carrying
32
+ * `after.moduleId` and `after.reason`, then an outcome row whose `after.phase` is
33
+ * `applied`, `refused` or `failed`. Only calls whose outcome is `applied` count, because a
34
+ * refused call moved nothing and a failed one may not have. Of those, only the LATEST per
35
+ * (tenant, scope, module) is taken, by the intent's ULID id. `at` is the intent's, the
36
+ * same instant the status read's who/why join reports. A key whose calls include no
37
+ * applied OFF gets no row, even when its latest applied call is an ON: a live
38
+ * `restoreToSystem` of a module never switched off writes none either
39
+ * (`recordSystemSwitchedOn`), and the backfill must not record what the live path would not.
40
+ *
41
+ * `INSERT OR IGNORE`, so a row the switch wrote itself is never overwritten by history.
42
+ * The adapters run it only on the construction that creates the table, so it runs once.
43
+ */
44
+ export const SYSTEM_SWITCHES_BACKFILL_SQL = `
45
+ WITH applied AS (
46
+ SELECT DISTINCT action, json_extract(after, '$.operationId') AS operation_id
47
+ FROM _substrat_admin_log
48
+ WHERE action IN ('revokeFromSystem', 'restoreToSystem')
49
+ AND json_extract(after, '$.phase') = 'applied'
50
+ ),
51
+ intents AS (
52
+ SELECT i.id AS id, i.tenant_id AS tenant_id, i.scope_id AS scope_id,
53
+ json_extract(i.after, '$.moduleId') AS module_id,
54
+ CASE i.action WHEN 'revokeFromSystem' THEN 'off' ELSE 'on' END AS position,
55
+ i.actor AS actor,
56
+ json_extract(i.after, '$.reason') AS reason,
57
+ json_extract(i.after, '$.operationId') AS operation_id,
58
+ i.at AS at
59
+ FROM _substrat_admin_log i
60
+ JOIN applied a
61
+ ON a.action = i.action AND a.operation_id = json_extract(i.after, '$.operationId')
62
+ WHERE i.action IN ('revokeFromSystem', 'restoreToSystem')
63
+ AND i.tenant_id IS NOT NULL AND i.scope_id IS NOT NULL
64
+ AND json_extract(i.after, '$.phase') = 'intent'
65
+ AND json_extract(i.after, '$.moduleId') IS NOT NULL
66
+ AND json_extract(i.after, '$.reason') IS NOT NULL
67
+ ),
68
+ ranked AS (
69
+ SELECT *,
70
+ ROW_NUMBER() OVER (PARTITION BY tenant_id, scope_id, module_id ORDER BY id DESC) AS latest,
71
+ MAX(position = 'off') OVER (PARTITION BY tenant_id, scope_id, module_id) AS ever_off
72
+ FROM intents
73
+ )
74
+ INSERT OR IGNORE INTO _substrat_system_switches
75
+ (tenant_id, scope_id, module_id, position, actor, reason, operation_id, switched_at)
76
+ SELECT tenant_id, scope_id, module_id, position, actor, reason, operation_id, at
77
+ FROM ranked
78
+ WHERE latest = 1 AND ever_off = 1
79
+ `;
80
+ /** "Does the record table exist yet?" — asked BEFORE the DDL, so the backfill runs once. */
81
+ export function systemSwitchesTableExists(db) {
82
+ return (db.all(`SELECT 1 AS present FROM sqlite_master WHERE type = 'table' AND name = '_substrat_system_switches'`)
83
+ .length > 0);
84
+ }
85
+ const positionOf = (v) => (v === 'on' ? 'on' : 'off');
86
+ const COLUMNS = `r.tenant_id, r.scope_id, r.module_id, s.vertical, r.position, r.actor, r.reason,
87
+ r.operation_id, r.switched_at`;
88
+ const rowOf = (r) => ({
89
+ tenantId: String(r.tenant_id),
90
+ scopeId: String(r.scope_id),
91
+ moduleId: String(r.module_id),
92
+ vertical: r.vertical == null ? null : String(r.vertical),
93
+ position: positionOf(r.position),
94
+ actor: String(r.actor),
95
+ reason: String(r.reason),
96
+ operationId: String(r.operation_id),
97
+ at: String(r.switched_at),
98
+ });
99
+ /**
100
+ * The fleet read (`GET /system-switches`): records, keyset-paged by `operation_id`.
101
+ *
102
+ * The key is the call that last moved the switch, so a row whose switch moves during a walk
103
+ * is re-keyed to a newer id and jumps to the end of the order. Ascending (the default) never
104
+ * skips a row for it; at worst it is seen twice, once per position. A DESCENDING walk can
105
+ * miss a row that moved after the walk started, so use ascending for "every switch".
106
+ */
107
+ export function listSystemSwitchRecords(db, filter = {}) {
108
+ const where = [];
109
+ const params = [];
110
+ const eq = (col, v) => {
111
+ if (v !== undefined) {
112
+ where.push(`${col} = ?`);
113
+ params.push(v);
114
+ }
115
+ };
116
+ eq('r.position', filter.position);
117
+ eq('r.tenant_id', filter.tenantId);
118
+ eq('r.scope_id', filter.scopeId);
119
+ eq('r.module_id', filter.moduleId);
120
+ eq('s.vertical', filter.vertical);
121
+ const order = filter.order === 'desc' ? 'DESC' : 'ASC';
122
+ if (filter.cursor !== undefined) {
123
+ where.push(order === 'DESC' ? 'r.operation_id < ?' : 'r.operation_id > ?');
124
+ params.push(filter.cursor);
125
+ }
126
+ // LEFT JOIN: a record outlives nothing it needs from `scopes`, and a scope row the
127
+ // directory lost must not hide a switch that is still off in the scope's store.
128
+ let sql = `SELECT ${COLUMNS} FROM _substrat_system_switches r LEFT JOIN scopes s ON s.scope_id = r.scope_id` +
129
+ (where.length ? ` WHERE ${where.join(' AND ')}` : '') +
130
+ ` ORDER BY r.operation_id ${order}`;
131
+ if (filter.limit !== undefined) {
132
+ sql += ` LIMIT ${Math.max(0, Math.floor(filter.limit))}`;
133
+ }
134
+ return db.all(sql, ...params).map(rowOf);
135
+ }
136
+ /** One scope's record rows by module — what the per-scope status read joins as `recorded`. */
137
+ export function systemSwitchRecordsOf(db, tenantId, scopeId) {
138
+ const rows = db.all(`SELECT module_id, position FROM _substrat_system_switches WHERE tenant_id = ? AND scope_id = ?`, tenantId, scopeId);
139
+ return new Map(rows.map((r) => [String(r.module_id), positionOf(r.position)]));
140
+ }
141
+ /**
142
+ * The per-scope status read's rows with the record joined on. Each module the scope
143
+ * reports gets its recorded position (or null). A module the record holds that the scope
144
+ * no longer reports at all is ADDED, as `ungranted`: that is the scope a wipe emptied, and
145
+ * the drift is the whole reason to show it. Sorted by module id, as the scope's rows are.
146
+ */
147
+ export function withRecorded(states, recorded) {
148
+ const rows = states.map((s) => ({ ...s, recorded: recorded.get(s.moduleId) ?? null }));
149
+ const reported = new Set(states.map((s) => s.moduleId));
150
+ for (const [moduleId, position] of recorded) {
151
+ if (!reported.has(moduleId))
152
+ rows.push({ moduleId, schedules: 'ungranted', recorded: position });
153
+ }
154
+ return rows.sort((a, b) => (a.moduleId < b.moduleId ? -1 : a.moduleId > b.moduleId ? 1 : 0));
155
+ }
156
+ /** The modules a reconcile must re-assert OFF on this scope. */
157
+ export function switchedOffModulesOf(db, tenantId, scopeId) {
158
+ return db
159
+ .all(`SELECT module_id FROM _substrat_system_switches
160
+ WHERE tenant_id = ? AND scope_id = ? AND position = 'off' ORDER BY module_id`, tenantId, scopeId)
161
+ .map((r) => String(r.module_id));
162
+ }
163
+ /**
164
+ * Overwrite one existing row's position and provenance — ON's write, and its undo. With
165
+ * `ifOperationId`, only while the row is still the one that operation wrote (a CAS).
166
+ */
167
+ function setRecordRow(db, key, row, ifOperationId) {
168
+ db.run(`UPDATE _substrat_system_switches
169
+ SET position = ?, actor = ?, reason = ?, operation_id = ?, switched_at = ?
170
+ WHERE tenant_id = ? AND scope_id = ? AND module_id = ?` +
171
+ (ifOperationId === undefined ? '' : ' AND operation_id = ?'), row.position, row.actor, row.reason, row.operationId, row.at, key.tenantId, key.scopeId, key.moduleId, ...(ifOperationId === undefined ? [] : [ifOperationId]));
172
+ }
173
+ /**
174
+ * OFF's write, made AFTER the scope's switch held. An upsert: a repeat OFF refreshes the
175
+ * actor, reason and time, as the status read reports the latest reason. Never made for a
176
+ * call that held nothing, because a row saying `off` for a module the scope never ran
177
+ * would switch it off on the day it is installed (the kernel's `held` check, for the same
178
+ * reason).
179
+ */
180
+ export function recordSystemSwitchedOff(db, row) {
181
+ db.run(`INSERT INTO _substrat_system_switches
182
+ (tenant_id, scope_id, module_id, position, actor, reason, operation_id, switched_at)
183
+ VALUES (?, ?, ?, 'off', ?, ?, ?, ?)
184
+ ON CONFLICT (tenant_id, scope_id, module_id) DO UPDATE SET
185
+ position = 'off', actor = excluded.actor, reason = excluded.reason,
186
+ operation_id = excluded.operation_id, switched_at = excluded.switched_at`, row.tenantId, row.scopeId, row.moduleId, row.actor, row.reason, row.operationId, row.at);
187
+ }
188
+ /**
189
+ * ON's write, made BEFORE the scope's switch moves, and only to a row that exists. Before,
190
+ * because the other order fails unsafely: a scope switched on whose record write then
191
+ * failed would still read `off`, and the next reconcile would switch the operator's
192
+ * restore back off. This order fails toward a record of `on` beside a live marker, which
193
+ * the marker wins. Answers the row as it was, for `restoreSystemSwitchRecord`.
194
+ */
195
+ export function recordSystemSwitchedOn(db, row) {
196
+ const prior = db.all(`SELECT position, actor, reason, operation_id, switched_at FROM _substrat_system_switches
197
+ WHERE tenant_id = ? AND scope_id = ? AND module_id = ?`, row.tenantId, row.scopeId, row.moduleId)[0];
198
+ if (!prior)
199
+ return null;
200
+ setRecordRow(db, row, { position: 'on', actor: row.actor, reason: row.reason, operationId: row.operationId, at: row.at });
201
+ return {
202
+ position: positionOf(prior.position),
203
+ actor: String(prior.actor),
204
+ reason: String(prior.reason),
205
+ operationId: String(prior.operation_id),
206
+ at: String(prior.switched_at),
207
+ };
208
+ }
209
+ /**
210
+ * Put a row back as `recordSystemSwitchedOn` found it — the ON that wrote it threw, or held
211
+ * nothing. A compare-and-set on the ON's own `operationId`: if another switch call has
212
+ * written the row since (a concurrent OFF), the row is left as that call wrote it, so an
213
+ * ON's undo can never clobber a newer position.
214
+ */
215
+ export function restoreSystemSwitchRecord(db, on, prior) {
216
+ if (prior)
217
+ setRecordRow(db, on, prior, on.operationId);
218
+ }
219
+ /**
220
+ * Forget one scope's switch records — the scope's directory row is going too (a reaped
221
+ * preview or fork, a reaped scope). Without this the fleet read keeps listing a switch on
222
+ * a scope that no longer exists. The admin log keeps the history, as it keeps the scope's.
223
+ */
224
+ export function forgetSystemSwitchesOf(db, scopeId) {
225
+ db.run(`DELETE FROM _substrat_system_switches WHERE scope_id = ?`, scopeId);
226
+ }
227
+ //# sourceMappingURL=system-switch-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-switch-record.js","sourceRoot":"","sources":["../src/system-switch-record.ts"],"names":[],"mappings":"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"}
package/dist/ulid.d.ts CHANGED
@@ -27,6 +27,12 @@ export interface UlidMint {
27
27
  */
28
28
  export declare function createUlid(): UlidMint;
29
29
  export declare function ulid(now?: number): string;
30
+ /**
31
+ * The greatest ULID a millisecond can carry (#1705 PR 3): every id minted at or before `now`
32
+ * sorts at or below it, and every id minted after sorts above. It is what "skip to now" moves
33
+ * a watermark to, because a watermark is compared with `id > cursor`.
34
+ */
35
+ export declare function ulidCeiling(now: number): string;
30
36
  /**
31
37
  * The epoch-millisecond timestamp a ULID carries in its first ten characters.
32
38
  *
@@ -1 +1 @@
1
- {"version":3,"file":"ulid.d.ts","sourceRoot":"","sources":["../src/ulid.ts"],"names":[],"mappings":"AA0CA,yFAAyF;AACzF,MAAM,WAAW,QAAQ;IACvB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,IAAI,QAAQ,CAmFrC;AAKD,wBAAgB,IAAI,CAAC,GAAG,GAAE,MAAmB,GAAG,MAAM,CAErD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAO3C"}
1
+ {"version":3,"file":"ulid.d.ts","sourceRoot":"","sources":["../src/ulid.ts"],"names":[],"mappings":"AAqDA,yFAAyF;AACzF,MAAM,WAAW,QAAQ;IACvB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,IAAI,QAAQ,CA6ErC;AAKD,wBAAgB,IAAI,CAAC,GAAG,GAAE,MAAmB,GAAG,MAAM,CAErD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAO3C"}
package/dist/ulid.js CHANGED
@@ -30,6 +30,16 @@ const MAX_ULID_TIME = 2 ** 48 - 1;
30
30
  /** All 26 digits, Crockford's alphabet — `I`, `L`, `O` and `U` are not in it. */
31
31
  const ULID_SHAPE = /^[0-9A-HJKMNP-TV-Z]{26}$/;
32
32
  const unencodable = (t) => `not an encodable ULID instant: ${t} (want 0..${MAX_ULID_TIME})`;
33
+ /** The ten base32 digits of an instant 48 bits can hold. The caller has range-checked it. */
34
+ function encodeTime(time) {
35
+ let ts = '';
36
+ let t = time;
37
+ for (let i = 0; i < 10; i++) {
38
+ ts = B32[t % 32] + ts;
39
+ t = Math.floor(t / 32);
40
+ }
41
+ return ts;
42
+ }
33
43
  /**
34
44
  * A ULID mint with its OWN monotonic state — one writer's floor, not the process's.
35
45
  *
@@ -85,16 +95,10 @@ export function createUlid() {
85
95
  if (time < 0 || time > MAX_ULID_TIME)
86
96
  throw new RangeError(unencodable(time));
87
97
  lastTime = time;
88
- let ts = '';
89
- let t = time;
90
- for (let i = 0; i < 10; i++) {
91
- ts = B32[t % 32] + ts;
92
- t = Math.floor(t / 32);
93
- }
94
98
  let r = '';
95
99
  for (const d of lastRand)
96
100
  r += B32[d];
97
- return ts + r;
101
+ return encodeTime(time) + r;
98
102
  });
99
103
  mint.seedFrom = (id) => {
100
104
  const time = ulidTime(id); // refuses anything that is not a ULID
@@ -129,6 +133,16 @@ const processUlid = createUlid();
129
133
  export function ulid(now = Date.now()) {
130
134
  return processUlid(now);
131
135
  }
136
+ /**
137
+ * The greatest ULID a millisecond can carry (#1705 PR 3): every id minted at or before `now`
138
+ * sorts at or below it, and every id minted after sorts above. It is what "skip to now" moves
139
+ * a watermark to, because a watermark is compared with `id > cursor`.
140
+ */
141
+ export function ulidCeiling(now) {
142
+ if (!Number.isSafeInteger(now) || now < 0 || now > MAX_ULID_TIME)
143
+ throw new RangeError(unencodable(now));
144
+ return encodeTime(now) + 'Z'.repeat(16);
145
+ }
132
146
  /**
133
147
  * The epoch-millisecond timestamp a ULID carries in its first ten characters.
134
148
  *
package/dist/ulid.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ulid.js","sourceRoot":"","sources":["../src/ulid.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ulid.js","sourceRoot":"","sources":["../src/ulid.ts"],"names":[],"mappings":"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"}
@@ -23,10 +23,11 @@
23
23
  * production builds them, and one definition is what keeps the two identical.
24
24
  * `lint:spine-ddl` holds each adapter to including it.
25
25
  */
26
- import { type EventExport, type ModuleManifest, type ExportedBatch, type WantedEvent, type WithheldEvent } from '@substrat-run/contracts';
26
+ import { type ImportCursorMove, type ImportCursorMoved, type ScopeId, type TenantId, type VerticalResolution, type EventExport, type ModuleManifest, type ExportedBatch, type WantedEvent, type WithheldEvent } from '@substrat-run/contracts';
27
27
  import { type OutboxEnvelopeRow } from './outbox-event.js';
28
28
  import type { ImportHandler } from './scope-host.js';
29
- export declare const VERTICAL_EVENTS_DDL = "\n -- #1705: every event this scope has received from another vertical. The envelope only, and\n -- never the payload. The producer's outbox keeps the one copy, where erasure already reaches.\n CREATE TABLE IF NOT EXISTS _substrat_imports (\n -- The PRODUCER's event id. A ULID the producer's host minted, so it is unique across\n -- every source this scope imports from, and it is the dedupe key: a batch delivered\n -- twice finds its events here and its handlers' journal rows in _substrat_deliveries.\n event_id TEXT PRIMARY KEY,\n source_scope_id TEXT NOT NULL,\n source_vertical TEXT NOT NULL,\n type TEXT NOT NULL,\n schema_version INTEGER NOT NULL,\n occurred_at TEXT NOT NULL,\n entity_type TEXT NOT NULL,\n entity_id TEXT NOT NULL,\n -- How many vertical boundaries this event's cause chain has crossed, this one included.\n -- An export read in THIS scope counts from here when one of its own events was caused by\n -- an import, which is how a loop between two verticals is stopped.\n hops INTEGER NOT NULL,\n -- NULL: released, and handed to this scope's handlers. Otherwise the producer's reason\n -- for NOT releasing it ('pii', 'version', 'cascade', 'undecodable'). Such a row was\n -- named but never carried.\n withheld TEXT,\n imported_at TEXT NOT NULL\n );\n -- #1705: how far this scope has read each producer. Written in the same store as the\n -- handlers' writes, so a restore of this scope rewinds the watermark with the data and the\n -- producer re-delivers what the restore undid. A watermark the platform held instead would\n -- skip it.\n CREATE TABLE IF NOT EXISTS _substrat_import_cursors (\n source_scope_id TEXT PRIMARY KEY,\n source_vertical TEXT NOT NULL,\n -- The id of the last producer row the reads walked (released or withheld). NULL is not\n -- stored: a producer with no row here has never been read, which the absence says.\n cursor TEXT NOT NULL,\n updated_at TEXT NOT NULL\n );\n -- #1705: the export read, on the PRODUCER side. It asks for a few types after a watermark,\n -- in id order. Without this index SQLite walks the primary key from the watermark forward and\n -- steps over every row of every other type. A consumer that is caught up would then pay, on\n -- every pass, for all the unexported activity since the last exported event. With it, the read\n -- seeks each type's range and costs what it returns.\n CREATE INDEX IF NOT EXISTS _substrat_outbox_type_id ON _substrat_outbox (type, id);\n";
29
+ import type { SwitchSql } from './system-switch.js';
30
+ export declare const VERTICAL_EVENTS_DDL = "\n -- #1705: every event this scope has received from another vertical. The envelope only, and\n -- never the payload. The producer's outbox keeps the one copy, where erasure already reaches.\n CREATE TABLE IF NOT EXISTS _substrat_imports (\n -- The PRODUCER's event id. A ULID the producer's host minted, so it is unique across\n -- every source this scope imports from, and it is the dedupe key: a batch delivered\n -- twice finds its events here and its handlers' journal rows in _substrat_deliveries.\n event_id TEXT PRIMARY KEY,\n source_scope_id TEXT NOT NULL,\n source_vertical TEXT NOT NULL,\n type TEXT NOT NULL,\n schema_version INTEGER NOT NULL,\n occurred_at TEXT NOT NULL,\n entity_type TEXT NOT NULL,\n entity_id TEXT NOT NULL,\n -- How many vertical boundaries this event's cause chain has crossed, this one included.\n -- An export read in THIS scope counts from here when one of its own events was caused by\n -- an import, which is how a loop between two verticals is stopped.\n hops INTEGER NOT NULL,\n -- NULL: released, and handed to this scope's handlers. Otherwise the producer's reason\n -- for NOT releasing it ('pii', 'version', 'cascade', 'undecodable'). Such a row was\n -- named but never carried.\n withheld TEXT,\n imported_at TEXT NOT NULL\n );\n -- #1705: how far this scope has read each producer. Written in the same store as the\n -- handlers' writes, so a restore of this scope rewinds the watermark with the data and the\n -- producer re-delivers what the restore undid. A watermark the platform held instead would\n -- skip it.\n CREATE TABLE IF NOT EXISTS _substrat_import_cursors (\n source_scope_id TEXT PRIMARY KEY,\n source_vertical TEXT NOT NULL,\n -- The id of the last producer row the reads walked (released or withheld). NULL is not\n -- stored: a producer with no row here has never been read, which the absence says.\n cursor TEXT NOT NULL,\n updated_at TEXT NOT NULL\n );\n -- #1705: the export read, on the PRODUCER side. It asks for a few types after a watermark,\n -- in id order. Without this index SQLite walks the primary key from the watermark forward and\n -- steps over every row of every other type. A consumer that is caught up would then pay, on\n -- every pass, for all the unexported activity since the last exported event. With it, the read\n -- seeks each type's range and costs what it returns.\n CREATE INDEX IF NOT EXISTS _substrat_outbox_type_id ON _substrat_outbox (type, id);\n -- #1705 PR 3: what a REPLAY moved out of the live journal. A replay re-delivers events this\n -- scope already took, and the live tables are also the dedupe (a row in _substrat_deliveries\n -- means \"do not run this handler again\"). So the rows for the replayed range leave them. They\n -- are moved here rather than dropped, because they are the record that a handler ran on an\n -- event, when, and what it reported: evidence the spine keeps. One row per moved row, the\n -- whole row as JSON under the replay that moved it. Nothing reads this to deliver.\n -- ERASURE: today no erasure path touches imported copies, because only piiClass 'none' crosses\n -- and the delivery-error rewrite (#1632) reaches only this scope's OWN outbox events. If a\n -- consumer-side erasure of imported copies is ever added, it must reach `row` here too (a\n -- moved delivery row's `error` is a handler's own sentence), or the history keeps what the\n -- live tables gave up. Follow-up: #1757.\n CREATE TABLE IF NOT EXISTS _substrat_import_replays (\n -- The act (a ULID). The admin log's row for the replay carries the same id.\n replay_id TEXT NOT NULL,\n replayed_at TEXT NOT NULL,\n source_scope_id TEXT NOT NULL,\n -- 'journal': a _substrat_imports row. 'delivery': a _substrat_deliveries row.\n kind TEXT NOT NULL,\n event_id TEXT NOT NULL,\n -- The handler's module on a 'delivery' row, and '' on a 'journal' row.\n consumer_module TEXT NOT NULL,\n row TEXT NOT NULL,\n PRIMARY KEY (replay_id, kind, event_id, consumer_module)\n );\n";
30
31
  /**
31
32
  * The producer-side read: rows of the given types after the watermark, oldest first.
32
33
  *
@@ -96,6 +97,27 @@ export declare function exportsOf(manifests: readonly {
96
97
  exports?: readonly EventExport[];
97
98
  };
98
99
  }[]): Map<string, EventExport>;
100
+ /**
101
+ * The outbox's insertion mark (#1705 PR 2): the kick's "before", taken ahead of an invoke.
102
+ *
103
+ * `rowid`, not the event id. A ULID minted in the same millisecond as the newest row can sort
104
+ * BELOW it, so "ids above the newest id" can miss an event this invoke wrote. SQLite assigns a
105
+ * new row `max(rowid) + 1` while the newest row is still there. No code path deletes outbox rows
106
+ * inside an invoke: the only removals are a restore and a wipe, and they replace the whole table
107
+ * outside any invocation. So every row the invoke and its consumers add sits above the mark. If
108
+ * that ever stopped being true, the effect is bounded: an exported event would miss its kick and
109
+ * wait for the sweep, and no event would be lost or sent twice.
110
+ */
111
+ export declare const OUTBOX_MARK_SQL = "SELECT COALESCE(MAX(rowid), 0) AS mark FROM _substrat_outbox";
112
+ /**
113
+ * How many rows of the exported `types` were added after `mark` (#1705 PR 2). This is the
114
+ * count `ScopeStubOptions.onExportedEvents` reports. A seek on the rowid, so it walks only
115
+ * what the invoke added. Callers skip it entirely when the deployment exports nothing.
116
+ */
117
+ export declare function exportedSinceQuery(types: readonly string[], mark: number): {
118
+ sql: string;
119
+ params: unknown[];
120
+ };
99
121
  /** The consumer's watermark per producer, oldest source first. */
100
122
  export declare const IMPORT_CURSORS_SQL = "SELECT source_scope_id, source_vertical, cursor, updated_at FROM _substrat_import_cursors ORDER BY source_scope_id";
101
123
  /** One producer's watermark, for the compare-and-set a batch is applied under. */
@@ -115,6 +137,74 @@ export declare const IMPORT_CURSOR_ADVANCE_SQL = "\n INSERT INTO _substrat_impo
115
137
  * `imported_at` forward or rewrite what was withheld and why.
116
138
  */
117
139
  export declare const IMPORT_RECORD_SQL = "\n INSERT OR IGNORE INTO _substrat_imports\n (event_id, source_scope_id, source_vertical, type, schema_version, occurred_at,\n entity_type, entity_id, hops, withheld, imported_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n";
140
+ /**
141
+ * The producer end of the edge a lever moves, resolved by the sweep's own rule (#1705 PR 3).
142
+ *
143
+ * Both ends must be their tenant's one primary instance, exactly as `sweepEdge` requires. A
144
+ * watermark on any other pair is one no pass reads, so a move there would report success and
145
+ * change nothing. `resolve` is the directory's `resolveVerticalInstance`, and it takes the
146
+ * CONSUMER's tenant, so a producer in another tenant is not found rather than moved.
147
+ */
148
+ export declare function importCursorSourceOf(resolve: (tenantId: TenantId, vertical: string) => Promise<VerticalResolution>, consumer: {
149
+ tenantId: TenantId;
150
+ scopeId: ScopeId;
151
+ vertical: string | null;
152
+ }, from: string): Promise<{
153
+ vertical: string;
154
+ scopeId: ScopeId;
155
+ }>;
156
+ /**
157
+ * Move one edge's watermark (#1705 PR 3). The adapter supplies the store (as the switches'
158
+ * `SwitchSql`), the transaction, the queue, the clock and the act's id. Run on the scope's own
159
+ * queue, so a pass delivering on the same edge can never interleave with the move. Everything the move decides is decided here, once, for
160
+ * both adapters.
161
+ *
162
+ * Why a bare rewind is not a replay. Three guards stand between an event and a second run of
163
+ * its handler, and a replay must pass each one on purpose:
164
+ *
165
+ * 1. `IMPORT_CURSOR_ADVANCE_SQL` moves the watermark forward only. The lever sets it here.
166
+ * 2. `_substrat_deliveries` holds a row per (event, module) that ran, and the delivery path
167
+ * skips any pair it finds. Rewound but not cleared, every replayed event would come back
168
+ * as a `duplicate` and nothing would run.
169
+ * 3. `_substrat_imports` is `INSERT OR IGNORE`. Left in place, an event first withheld for its
170
+ * version would stay recorded as withheld after the consumer's upgrade released it.
171
+ *
172
+ * So a replay moves the range's rows in (2) and (3) into `_substrat_import_replays` under
173
+ * `replayId`, then clears them, then sets the watermark. The evidence stays, and the live tables
174
+ * take the events again. Two things are true between the move and the redelivery, and are
175
+ * stated rather than hidden: a cause walk through a moved event's id ends at `missing`, and an
176
+ * export read in this scope counts fewer hops for a chain through it. Both heal when the next
177
+ * pass redelivers. The undercount only loosens the loop bound (the hop cap bounds loops, and
178
+ * authorizes nothing), so a loop may run a round longer; no event crosses that exports, grants
179
+ * and the PII rule would not already release.
180
+ *
181
+ * Refused, with the reason a person reads:
182
+ * - a replay whose `after` is AHEAD of the watermark (that is a skip), or a skip whose `through`
183
+ * is BEHIND it (that is a replay). The acknowledgement names one direction, and it must be
184
+ * the direction that moves;
185
+ * - a skip past now, which would pass over events not yet written while the edge read as
186
+ * caught up;
187
+ * - a replay on an edge that has delivered nothing yet: there is nothing to run again.
188
+ */
189
+ export declare function moveImportCursor(sql: SwitchSql, input: {
190
+ move: ImportCursorMove;
191
+ source: {
192
+ vertical: string;
193
+ scopeId: string;
194
+ };
195
+ replayId: string;
196
+ /** Epoch ms: the rows' time, and "now" for a skip, as the watermark's ceiling. */
197
+ now: number;
198
+ /**
199
+ * What the code running this scope imports (`CrossVerticalRegistry.consumes()`). A move names
200
+ * an edge only if the consumer declares it. Otherwise a skip would plant a watermark for an
201
+ * edge that does not exist yet, and the backfill of a later version that adds the import would
202
+ * silently start from it.
203
+ */
204
+ imports: readonly {
205
+ from: string;
206
+ }[];
207
+ }): ImportCursorMoved;
118
208
  /** The note a withheld event's dead letter carries at the consumer. Names the reason, never the content. */
119
209
  export declare function withheldNote(reason: WithheldEvent['reason'], vertical: string): string;
120
210
  /** One registered import handler: which module, from which vertical, for which (type, version). */
@@ -145,9 +235,13 @@ export declare class CrossVerticalRegistry {
145
235
  private readonly exportsByType;
146
236
  private readonly importVersion;
147
237
  private readonly registered;
238
+ /** `exportTypes()`, kept current by `register`: an invoke reads it, and must not rebuild a map to. */
239
+ private exportTypeList;
148
240
  register(manifest: Pick<ModuleManifest, 'id' | 'events'>, handlers: Record<string, Record<string, ImportHandler>> | undefined): void;
149
241
  /** type → export, over every registered module: what this deployment releases. */
150
242
  exports(): Map<string, EventExport>;
243
+ /** The exported type names (#1705 PR 2), for the per-invoke kick count. Empty: exports nothing. */
244
+ exportTypes(): readonly string[];
151
245
  /** What this deployment imports, one row per (source, type), sorted. */
152
246
  consumes(): {
153
247
  from: string;
@@ -1 +1 @@
1
- {"version":3,"file":"vertical-events.d.ts","sourceRoot":"","sources":["../src/vertical-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,aAAa,EAElB,KAAK,WAAW,EAChB,KAAK,aAAa,EACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAiB,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,eAAO,MAAM,mBAAmB,s/EA2C/B,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,KAAK,EAAE,MAAM,GACZ;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,CAUpC;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,0VAU3B,CAAC;AAEF,4FAA4F;AAC5F,MAAM,MAAM,SAAS,GAAG,iBAAiB,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAE1E;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,IAAI,EAAE,SAAS,SAAS,EAAE,CAAC;IAC3B,oDAAoD;IACpD,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,0EAA0E;IAC1E,UAAU,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,MAAM,CAAC;IACvC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC,CA0D/D;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,EACzC,KAAK,EAAE,SAAS,WAAW,EAAE,GAC5B;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,UAAU,EAAE,WAAW,EAAE,CAAA;CAAE,CAgB7F;AAED,sGAAsG;AACtG,wBAAgB,SAAS,CACvB,SAAS,EAAE,SAAS;IAAE,MAAM,EAAE;QAAE,OAAO,CAAC,EAAE,SAAS,WAAW,EAAE,CAAA;KAAE,CAAA;CAAE,EAAE,GACrE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAI1B;AAED,kEAAkE;AAClE,eAAO,MAAM,kBAAkB,uHACuF,CAAC;AAEvH,kFAAkF;AAClF,eAAO,MAAM,oBAAoB,0EAA0E,CAAC;AAE5G;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,6VAQrC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,8OAK7B,CAAC;AAEF,4GAA4G;AAC5G,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQtF;AAED,mGAAmG;AACnG,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,aAAa,CAAC;CACxB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA2D;IACzF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoE;IAClG,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0B;IAErD,QAAQ,CACN,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,IAAI,GAAG,QAAQ,CAAC,EAC/C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,GAAG,SAAS,GAClE,IAAI,CAgDN;IAED,kFAAkF;IAClF,OAAO,IAAI,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAElC;IAED,wEAAwE;IACxE,QAAQ,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,EAAE,CAOlE;IAED,kEAAkE;IAClE,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAE1D;IAED,yGAAyG;IACzG,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAErD;CACF"}
1
+ {"version":3,"file":"vertical-events.d.ts","sourceRoot":"","sources":["../src/vertical-events.ts"],"names":[],"mappings":"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"}