@substrat-run/kernel 0.139.0 → 0.141.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 (148) 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 +12 -1
  6. package/dist/attachment-extractor.d.ts.map +1 -1
  7. package/dist/attachment-extractor.js +10 -5
  8. package/dist/attachment-extractor.js.map +1 -1
  9. package/dist/audit-outcome.d.ts +149 -0
  10. package/dist/audit-outcome.d.ts.map +1 -0
  11. package/dist/audit-outcome.js +233 -0
  12. package/dist/audit-outcome.js.map +1 -0
  13. package/dist/capability.d.ts +5 -2
  14. package/dist/capability.d.ts.map +1 -1
  15. package/dist/capability.js +17 -8
  16. package/dist/capability.js.map +1 -1
  17. package/dist/connect-links.d.ts +91 -0
  18. package/dist/connect-links.d.ts.map +1 -0
  19. package/dist/connect-links.js +189 -0
  20. package/dist/connect-links.js.map +1 -0
  21. package/dist/connect-state.d.ts +12 -3
  22. package/dist/connect-state.d.ts.map +1 -1
  23. package/dist/connect-state.js +8 -3
  24. package/dist/connect-state.js.map +1 -1
  25. package/dist/derived-object.d.ts +14 -0
  26. package/dist/derived-object.d.ts.map +1 -0
  27. package/dist/derived-object.js +2 -0
  28. package/dist/derived-object.js.map +1 -0
  29. package/dist/derived-objects.d.ts +108 -0
  30. package/dist/derived-objects.d.ts.map +1 -0
  31. package/dist/derived-objects.js +199 -0
  32. package/dist/derived-objects.js.map +1 -0
  33. package/dist/email-intent.d.ts +56 -0
  34. package/dist/email-intent.d.ts.map +1 -0
  35. package/dist/email-intent.js +71 -0
  36. package/dist/email-intent.js.map +1 -0
  37. package/dist/entity-edges.d.ts +6 -1
  38. package/dist/entity-edges.d.ts.map +1 -1
  39. package/dist/entity-edges.js +13 -0
  40. package/dist/entity-edges.js.map +1 -1
  41. package/dist/entity-grant-shape.d.ts +94 -0
  42. package/dist/entity-grant-shape.d.ts.map +1 -0
  43. package/dist/entity-grant-shape.js +329 -0
  44. package/dist/entity-grant-shape.js.map +1 -0
  45. package/dist/entity-grant.d.ts +45 -0
  46. package/dist/entity-grant.d.ts.map +1 -0
  47. package/dist/entity-grant.js +71 -0
  48. package/dist/entity-grant.js.map +1 -0
  49. package/dist/entity-state-reads.d.ts +4 -7
  50. package/dist/entity-state-reads.d.ts.map +1 -1
  51. package/dist/entity-state-reads.js +13 -57
  52. package/dist/entity-state-reads.js.map +1 -1
  53. package/dist/entity-state.d.ts +37 -10
  54. package/dist/entity-state.d.ts.map +1 -1
  55. package/dist/entity-state.js +80 -69
  56. package/dist/entity-state.js.map +1 -1
  57. package/dist/entity-trash.d.ts +245 -0
  58. package/dist/entity-trash.d.ts.map +1 -0
  59. package/dist/entity-trash.js +380 -0
  60. package/dist/entity-trash.js.map +1 -0
  61. package/dist/grant-scoped-read.d.ts +41 -0
  62. package/dist/grant-scoped-read.d.ts.map +1 -0
  63. package/dist/grant-scoped-read.js +100 -0
  64. package/dist/grant-scoped-read.js.map +1 -0
  65. package/dist/index.d.ts +35 -8
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +22 -5
  68. package/dist/index.js.map +1 -1
  69. package/dist/kernel-outbox.d.ts +14 -0
  70. package/dist/kernel-outbox.d.ts.map +1 -0
  71. package/dist/kernel-outbox.js +37 -0
  72. package/dist/kernel-outbox.js.map +1 -0
  73. package/dist/list-index.d.ts +11 -2
  74. package/dist/list-index.d.ts.map +1 -1
  75. package/dist/list-index.js +29 -21
  76. package/dist/list-index.js.map +1 -1
  77. package/dist/mail-sender.d.ts +78 -0
  78. package/dist/mail-sender.d.ts.map +1 -0
  79. package/dist/mail-sender.js +2 -0
  80. package/dist/mail-sender.js.map +1 -0
  81. package/dist/membership-executor.d.ts +0 -52
  82. package/dist/membership-executor.d.ts.map +1 -1
  83. package/dist/membership-executor.js +19 -59
  84. package/dist/membership-executor.js.map +1 -1
  85. package/dist/migration-digest.d.ts +161 -0
  86. package/dist/migration-digest.d.ts.map +1 -0
  87. package/dist/migration-digest.js +237 -0
  88. package/dist/migration-digest.js.map +1 -0
  89. package/dist/module-erasure.d.ts +156 -0
  90. package/dist/module-erasure.d.ts.map +1 -0
  91. package/dist/module-erasure.js +440 -0
  92. package/dist/module-erasure.js.map +1 -0
  93. package/dist/peer.d.ts +9 -1
  94. package/dist/peer.d.ts.map +1 -1
  95. package/dist/peer.js +29 -0
  96. package/dist/peer.js.map +1 -1
  97. package/dist/permission-checker.d.ts +6 -0
  98. package/dist/permission-checker.d.ts.map +1 -1
  99. package/dist/permission-checker.js.map +1 -1
  100. package/dist/permission-eval.d.ts +10 -1
  101. package/dist/permission-eval.d.ts.map +1 -1
  102. package/dist/permission-eval.js +51 -2
  103. package/dist/permission-eval.js.map +1 -1
  104. package/dist/platform-sweep.d.ts +1 -1
  105. package/dist/platform-sweep.d.ts.map +1 -1
  106. package/dist/platform-sweep.js +5 -0
  107. package/dist/platform-sweep.js.map +1 -1
  108. package/dist/scope-copy-ledger.d.ts +79 -0
  109. package/dist/scope-copy-ledger.d.ts.map +1 -0
  110. package/dist/scope-copy-ledger.js +82 -0
  111. package/dist/scope-copy-ledger.js.map +1 -0
  112. package/dist/scope-host.d.ts +402 -25
  113. package/dist/scope-host.d.ts.map +1 -1
  114. package/dist/scope-host.js +74 -5
  115. package/dist/scope-host.js.map +1 -1
  116. package/dist/search-index.d.ts +8 -0
  117. package/dist/search-index.d.ts.map +1 -1
  118. package/dist/search-index.js +51 -21
  119. package/dist/search-index.js.map +1 -1
  120. package/dist/spine-guard.d.ts +7 -0
  121. package/dist/spine-guard.d.ts.map +1 -1
  122. package/dist/spine-guard.js +54 -6
  123. package/dist/spine-guard.js.map +1 -1
  124. package/dist/spine-restore.d.ts.map +1 -1
  125. package/dist/spine-restore.js +5 -0
  126. package/dist/spine-restore.js.map +1 -1
  127. package/dist/sql-statements.d.ts +71 -0
  128. package/dist/sql-statements.d.ts.map +1 -0
  129. package/dist/sql-statements.js +191 -0
  130. package/dist/sql-statements.js.map +1 -0
  131. package/dist/subject-redaction.d.ts +9 -1
  132. package/dist/subject-redaction.d.ts.map +1 -1
  133. package/dist/subject-redaction.js.map +1 -1
  134. package/dist/system-switch-record.d.ts +3 -0
  135. package/dist/system-switch-record.d.ts.map +1 -1
  136. package/dist/system-switch-record.js +2 -0
  137. package/dist/system-switch-record.js.map +1 -1
  138. package/dist/table-ownership.d.ts +103 -0
  139. package/dist/table-ownership.d.ts.map +1 -0
  140. package/dist/table-ownership.js +285 -0
  141. package/dist/table-ownership.js.map +1 -0
  142. package/dist/timeline.d.ts +4 -4
  143. package/dist/timeline.js +4 -4
  144. package/dist/visible-continuation.d.ts +38 -0
  145. package/dist/visible-continuation.d.ts.map +1 -0
  146. package/dist/visible-continuation.js +162 -0
  147. package/dist/visible-continuation.js.map +1 -0
  148. package/package.json +4 -4
@@ -0,0 +1,440 @@
1
+ /**
2
+ * Subject erasure inside a module's OWN tables (#2068) — the half of open question 17 that
3
+ * K-37 left named and unbuilt.
4
+ *
5
+ * `shredSubject` redacts the spine and destroys the key that seals the platform's copies. A
6
+ * module's rows were outside that, and §13.1 said so (limit 2). This file brings them in, two
7
+ * ways, both run by the kernel in the SAME transaction as the spine redaction and before the
8
+ * key is destroyed:
9
+ *
10
+ * - **Declared.** An entity names its subject columns beside its `erasable` fields
11
+ * (`erasure: { subjects }`, `subject-erasure.ts` in contracts), and the kernel blanks those
12
+ * fields — or deletes the row — wherever a subject column equals the id. No module code
13
+ * runs, so a vertical gets the right behaviour by declaring, and a declaration cannot forget
14
+ * a column the way a hand-written UPDATE can.
15
+ * - **A hook.** `onSubjectErased(ctx, { subjectId })` on the registration, for a link the row
16
+ * does not hold itself (a rating reached through its conversation). It is narrow on purpose:
17
+ * a `sql` that reaches the module's own tables and nothing else, and `now()`. No emit — an
18
+ * event about the erasure would be a new immutable copy of what is being erased — no
19
+ * check, grant, link or platform request, and no await: it is synchronous, so it runs inside
20
+ * the erasure's one transaction and nothing interleaves with it.
21
+ *
22
+ * **Failure is all or nothing.** A hook that throws rolls the whole scope-side unit back, the
23
+ * spine redaction with it, and the erasure throws before the key is touched or a receipt is
24
+ * written. Nothing claims an erasure that did not happen, and a re-run converges: a declared
25
+ * blank skips rows already blank, and a hook is idempotent by contract.
26
+ *
27
+ * **Derived stores.** A search index over an erased column is kept in step by its own triggers,
28
+ * but FTS5 keeps a deleted row's terms in older index segments until they merge — the words
29
+ * are still in the database file, findable by anyone reading the shadow tables. So the erasure
30
+ * runs with FTS5's `secure-delete` on for the indexes over the erasing modules' tables, which
31
+ * removes each entry where it sits rather than recording its deletion. A list index is an ordinary b-tree and loses the old value with the
32
+ * UPDATE. What neither reaches — free pages SQLite has not reused, and attachment text — is
33
+ * written down in kernel-design.md §13.1 rather than implied.
34
+ */
35
+ import { namesSpineTable, substratError, subjectErasureDeclaration, tokenizeSql, } from '@substrat-run/contracts';
36
+ import { guardSpine } from './spine-guard.js';
37
+ import { assertSqlIdentifier } from './sql-identifier.js';
38
+ import { assertTablesOwned, tableStatements } from './table-ownership.js';
39
+ /**
40
+ * The tables a module's own migration TEXT creates, lowercased — read at registration, where no
41
+ * scope exists yet, as early feedback only: it can refuse a module whose erasure names a table it
42
+ * plainly never creates, and it never grants anything. `CREATE TABLE IF NOT EXISTS` on another
43
+ * module's table reads as a creation here and creates nothing in a scope, which is why the
44
+ * authority is the ownership each scope RECORDS as its migrations run (`table-ownership.ts`),
45
+ * checked by the erasure itself before it writes.
46
+ */
47
+ export function tablesCreatedBy(migrations) {
48
+ const owned = new Set();
49
+ for (const migration of migrations) {
50
+ for (const st of tableStatements(migration.sql)) {
51
+ if (st.kind === 'create')
52
+ owned.add(st.table);
53
+ else if (st.kind === 'rename') {
54
+ if (owned.delete(st.from))
55
+ owned.add(st.to);
56
+ }
57
+ else
58
+ owned.delete(st.table);
59
+ }
60
+ }
61
+ return owned;
62
+ }
63
+ /**
64
+ * The erasure plan for one registration, or undefined when it has nothing to erase. Throws,
65
+ * at registration, for every way a module can claim an erasure it cannot deliver, or one that
66
+ * would reach past itself:
67
+ *
68
+ * - a hook with no `manifest.erasure` — the hook's reach IS that block's `tables`, and a hook
69
+ * with no reach declared is refused rather than handed the whole scope;
70
+ * - an entity declared `custom` with no hook to reach it;
71
+ * - an entity the erasure would write (`blank`, `delete`, `custom`) on a table the module's own
72
+ * migrations do not create, and — when there is a hook — any table in its reach that they do
73
+ * not create. The declaration is a claim; the migrations are what the kernel ran. A misdeclared
74
+ * entity naming another module's table would otherwise have that table erased through the
75
+ * kernel's own handle. An `unreached` entity writes nothing and is not held to it.
76
+ */
77
+ export function moduleErasurePlan(registration) {
78
+ const { manifest, onSubjectErased: hook } = registration;
79
+ if (hook !== undefined && typeof hook !== 'function') {
80
+ throw new Error(`${manifest.id}: onSubjectErased must be a function`);
81
+ }
82
+ if (!manifest.erasure) {
83
+ if (hook) {
84
+ throw new Error(`${manifest.id}: onSubjectErased is registered but the manifest declares no \`erasure\` — the ` +
85
+ "hook's reach is that block's `tables`. Spread `manifestEntities(...)` into the manifest");
86
+ }
87
+ return undefined;
88
+ }
89
+ const declaration = subjectErasureDeclaration.parse(manifest.erasure);
90
+ const custom = declaration.entities.filter((e) => e.mode === 'custom');
91
+ if (custom.length && !hook) {
92
+ throw new Error(`${manifest.id}: ${custom.map((e) => e.entityType).join(', ')} declare${custom.length === 1 ? 's' : ''} ` +
93
+ "`erasure: { mode: 'custom' }` but the module registers no onSubjectErased hook to reach them");
94
+ }
95
+ const created = tablesCreatedBy(registration.migrations ?? []);
96
+ const claimed = [
97
+ ...declaration.entities.filter((e) => e.mode !== 'unreached').map((e) => e.table),
98
+ ...(hook ? declaration.tables : []),
99
+ ];
100
+ const foreign = [...new Set(claimed.filter((t) => !created.has(t.toLowerCase())))];
101
+ if (foreign.length) {
102
+ throw new Error(`${manifest.id}: its erasure names ${foreign.map((t) => `'${t}'`).join(', ')}, which its own migrations ` +
103
+ 'do not create — an erasure reaches only the tables a module owns. Create the table in this ' +
104
+ "module's migrations, or leave the entity without an `erasure`");
105
+ }
106
+ return {
107
+ moduleId: manifest.id,
108
+ declaration,
109
+ ...(hook ? { hook } : {}),
110
+ ownTables: new Set(claimed.map((t) => t.toLowerCase())),
111
+ };
112
+ }
113
+ /** The statements a hook may run. Everything else — DDL, PRAGMA, ATTACH, VACUUM, WITH — is refused. */
114
+ const HOOK_VERBS = new Set(['select', 'update', 'delete', 'insert', 'replace']);
115
+ /** The only table-valued functions a hook may name in a FROM: they read the row's own JSON. */
116
+ const TABLE_FUNCTIONS = new Set(['json_each', 'json_tree']);
117
+ /** Words that end a FROM list (or an UPDATE / INTO target) — what follows them is no table. */
118
+ const ENDS_TABLE_LIST = new Set([
119
+ 'set', 'where', 'on', 'using', 'group', 'order', 'limit', 'values', 'select', 'returning',
120
+ 'union', 'except', 'intersect', 'default', 'having', 'window', 'left', 'right', 'full',
121
+ 'inner', 'cross', 'natural', 'outer',
122
+ ]);
123
+ /** The conflict clause words between `UPDATE` and its table: `UPDATE OR IGNORE t`. */
124
+ const CONFLICT_WORDS = new Set(['or', 'rollback', 'abort', 'replace', 'fail', 'ignore']);
125
+ /**
126
+ * Refuse a hook statement that reaches past the module's own tables (#2068).
127
+ *
128
+ * An ALLOWLIST, judged where a table can stand: every name in a table position — after `FROM`,
129
+ * `JOIN`, `INTO` and `UPDATE`, and each further name in a comma-joined `FROM` list, at any
130
+ * nesting depth — must be one of `own`, unqualified. Whatever else the scope holds — another
131
+ * module's table, a view, a TEMP object, the spine — is refused without having to be listed,
132
+ * so nothing the schema grows later widens the reach. Also refused: a qualified name
133
+ * (`main.x`, `temp.x`), a table-valued function other than `json_each`/`json_tree`, `WITH`
134
+ * (a CTE could shadow an own table's name), and any spine- or `sqlite_`-prefixed name
135
+ * anywhere. Every statement chained after a `;` starts with an allowed verb.
136
+ *
137
+ * It errs toward refusing: a name in a table position that is not a table at all
138
+ * (`a IS DISTINCT FROM b`) is held to the allowlist too, and fails closed with a message.
139
+ */
140
+ export function assertWithinErasureReach(moduleId, sql, own) {
141
+ const refuse = (what) => {
142
+ throw substratError('forbidden', `${moduleId}: onSubjectErased reaches its own module's tables only — refused ${what}`, { reason: 'erasure_reach' });
143
+ };
144
+ const tokens = tokenizeSql(sql, { punctuation: true });
145
+ const stack = [];
146
+ let f = { expect: false, clause: null, inList: false };
147
+ let start = true;
148
+ let prev = '';
149
+ for (let i = 0; i < tokens.length; i += 1) {
150
+ const token = tokens[i];
151
+ if (token.punct) {
152
+ if (token.text === ';') {
153
+ start = true;
154
+ stack.length = 0;
155
+ f = { expect: false, clause: null, inList: false };
156
+ }
157
+ else if (token.text === '(') {
158
+ // A subquery in a FROM position stands where a table would: once it closes, the outer
159
+ // list continues after it, so a `, other` that follows is still judged.
160
+ stack.push(f.expect ? { expect: false, clause: f.clause, inList: true } : { ...f, expect: false });
161
+ f = { expect: false, clause: null, inList: false };
162
+ }
163
+ else if (token.text === ')') {
164
+ f = stack.pop() ?? { expect: false, clause: null, inList: false };
165
+ }
166
+ else if (token.text === ',' && f.inList && f.clause === 'from') {
167
+ f = { ...f, expect: true, inList: false };
168
+ }
169
+ continue;
170
+ }
171
+ const word = token.quoted ? '' : token.text.toLowerCase();
172
+ for (const part of token.text.split('.')) {
173
+ const name = part.toLowerCase();
174
+ if (namesSpineTable(name) || name.startsWith('sqlite_'))
175
+ refuse(`'${part}'`);
176
+ }
177
+ if (start) {
178
+ start = false;
179
+ if (!HOOK_VERBS.has(word))
180
+ refuse(`the statement: ${sql.slice(0, 60)}`);
181
+ }
182
+ if (word === 'with')
183
+ refuse('WITH — a common table expression could shadow a table name');
184
+ if (f.expect) {
185
+ if (f.clause === 'update' && CONFLICT_WORDS.has(word))
186
+ continue;
187
+ const next = tokens[i + 1];
188
+ if (f.clause === 'from' && next?.punct && next.text === '(') {
189
+ if (!TABLE_FUNCTIONS.has(word))
190
+ refuse(`the table-valued function '${token.text}'`);
191
+ }
192
+ else if (token.text.includes('.')) {
193
+ refuse(`the qualified name '${token.text}'`);
194
+ }
195
+ else if (!own.has(token.text.toLowerCase())) {
196
+ refuse(`'${token.text}', which is not one of its tables`);
197
+ }
198
+ f = { ...f, expect: false, inList: true };
199
+ }
200
+ else if (word === 'from' || word === 'join') {
201
+ f = { expect: true, clause: 'from', inList: false };
202
+ }
203
+ else if (word === 'into') {
204
+ f = { expect: true, clause: 'into', inList: false };
205
+ }
206
+ else if (word === 'update' && prev !== 'do') {
207
+ f = { expect: true, clause: 'update', inList: false };
208
+ }
209
+ else if (f.inList && ENDS_TABLE_LIST.has(word)) {
210
+ f = { ...f, inList: false };
211
+ }
212
+ prev = word;
213
+ }
214
+ }
215
+ /**
216
+ * Refuse the erasure when a TEMP object carries the name of a table it is about to touch: an
217
+ * unqualified name resolves to the temp schema first, so the declared write or the hook would
218
+ * land on the shadow. A host whose SQLite will not show its temp schema (a Durable Object) has
219
+ * none for anything to have made.
220
+ */
221
+ function assertNoTempShadow(sql, tables) {
222
+ let temp;
223
+ try {
224
+ temp = sql.query('SELECT name FROM temp.sqlite_master');
225
+ }
226
+ catch {
227
+ return;
228
+ }
229
+ const shadow = temp.map((r) => r.name).find((n) => tables.has(n.toLowerCase()));
230
+ if (shadow) {
231
+ throw substratError('precondition_failed', `erasure: a TEMP object '${shadow}' shadows a module table this erasure would touch — nothing was erased`);
232
+ }
233
+ }
234
+ /**
235
+ * What the statement just run changed, as SQLite counts it: `changes()` is that statement's own
236
+ * rows and never a trigger's; `total_changes()` is the connection's running count, compared and
237
+ * never reported. Read rather than taken from the handle's exec result because the two adapters
238
+ * disagree there — a Durable Object's `rowsWritten` counts every index and FTS trigger write
239
+ * too — and a receipt must say the same number whichever host erased.
240
+ */
241
+ function changeCounts(sql) {
242
+ const row = sql.query('SELECT changes() AS c, total_changes() AS t')[0];
243
+ return { changes: row?.c ?? 0, total: row?.t ?? 0 };
244
+ }
245
+ /**
246
+ * The oldest SQLite that may run an erasure over a search index (#2068): FTS5 `secure-delete`
247
+ * arrived in 3.42.0, and an index deleted from under it is recorded at FTS5 format version 5,
248
+ * which no older SQLite can read. A dump never carries a search index (it is rebuilt on load),
249
+ * so the reader that matters is the runtime holding the scope's own file.
250
+ */
251
+ export const SECURE_DELETE_MIN_SQLITE = '3.42.0';
252
+ /**
253
+ * Switch `secure-delete` on for one index, or refuse the erasure if this SQLite cannot.
254
+ *
255
+ * A capability probe rather than a version check, because a Durable Object will not run
256
+ * `sqlite_version()`. The probe is exact anyway: an FTS5 older than 3.42.0 has no
257
+ * `secure-delete` command and rejects it, and that rejection comes before anything is written
258
+ * to the index's table, so the erasure fails closed — nothing erased, and no index left at a
259
+ * format the runtime holding it could not read back.
260
+ */
261
+ function enableSecureDelete(sql, idx) {
262
+ try {
263
+ sql.exec(`INSERT INTO ${idx}(${idx}, rank) VALUES('secure-delete', 1)`);
264
+ }
265
+ catch (err) {
266
+ throw substratError('precondition_failed', `erasure: erasing from a search index needs FTS5 secure-delete (SQLite ${SECURE_DELETE_MIN_SQLITE}+), ` +
267
+ `which this host's SQLite refused (${err instanceof Error ? err.message : String(err)}) — nothing was erased`);
268
+ }
269
+ }
270
+ /** A name the kernel interpolates — re-checked here, never trusted from a manifest. */
271
+ const ident = (name) => assertSqlIdentifier('erasure', 'an identifier', name, 'a module erasure');
272
+ /**
273
+ * Run the module half of one erasure: every declared entity, then every hook, with FTS5's
274
+ * `secure-delete` on for the search indexes over those modules' tables. `sql` is the kernel's
275
+ * own handle on the scope — never module code's — and the caller holds it inside the
276
+ * transaction the spine redaction runs in, so a throw from here rolls both back.
277
+ *
278
+ * Order between the two halves: declared first, hooks after, so a hook reading a declared
279
+ * entity sees it already blank and a hook that deletes cannot strand a declared blank. Order
280
+ * between modules is registration order, which nothing here depends on: each touches its own
281
+ * tables only.
282
+ */
283
+ export function eraseSubjectFromModules(input) {
284
+ const { sql, plans, subjectId, at } = input;
285
+ const out = { verticalRows: [], hookRows: [], unreachedEntities: [] };
286
+ // Before anything is written: every table this erasure would touch must be recorded, in THIS
287
+ // scope, as created by the erasing module's own migrations.
288
+ for (const plan of plans)
289
+ assertTablesOwned(sql, plan.moduleId, plan.ownTables, input.migrationSqlOf, at);
290
+ if (plans.some((p) => p.ownTables.size > 0)) {
291
+ assertNoTempShadow(sql, new Set(plans.flatMap((p) => [...p.ownTables])));
292
+ }
293
+ // FTS5 keeps a deleted row's terms in the older index segments until they merge, so an
294
+ // erased word stays in the database file after search stops finding it. `secure-delete`
295
+ // makes a delete remove the entry from the segment it sits in instead — at the cost of that
296
+ // one entry, where a full merge ('optimize') rewrites the whole index (0.5 s at 100k rows,
297
+ // measured). It is switched on lazily, for an index whose table this erasure is about to
298
+ // change and no other, and off again at the end; a throw rolls the switch back with
299
+ // everything else. Lazily because the switch leaves a row in the index's own config, which
300
+ // SQLite will not let anyone remove: an erasure that holds nothing for the subject — the
301
+ // common case, every scope it is not about — leaves every index exactly as it found it.
302
+ const indexesOf = new Map();
303
+ for (const p of input.searchPlans) {
304
+ const key = p.table.toLowerCase();
305
+ const list = indexesOf.get(key) ?? [];
306
+ list.push(ident(p.indexTable));
307
+ indexesOf.set(key, list);
308
+ }
309
+ const secured = new Set();
310
+ const secure = (table) => {
311
+ for (const idx of indexesOf.get(table.toLowerCase()) ?? []) {
312
+ if (secured.has(idx))
313
+ continue;
314
+ enableSecureDelete(sql, idx);
315
+ secured.add(idx);
316
+ }
317
+ };
318
+ for (const plan of plans) {
319
+ for (const entity of plan.declaration.entities) {
320
+ if (entity.mode === 'unreached') {
321
+ out.unreachedEntities.push({ module: plan.moduleId, entityType: entity.entityType });
322
+ continue;
323
+ }
324
+ if (entity.mode === 'custom')
325
+ continue;
326
+ const table = ident(entity.table);
327
+ const subjects = (entity.subjects ?? []).map(ident);
328
+ const match = `(${subjects.map((s) => `${s} = ?`).join(' OR ')})`;
329
+ const subjectParams = subjects.map(() => subjectId);
330
+ // Only rows still holding something: a re-run changes nothing and counts zero.
331
+ const cols = entity.fields.map((f) => ident(f.name));
332
+ const blanks = entity.fields.map((f) => f.blank);
333
+ const isDelete = entity.mode === 'delete';
334
+ const filter = isDelete ? match : `${match} AND (${cols.map((c) => `${c} IS NOT ?`).join(' OR ')})`;
335
+ const params = isDelete ? subjectParams : [...subjectParams, ...blanks];
336
+ // The probe exists only to switch an index's secure-delete on lazily; a table no index
337
+ // covers goes straight to its write.
338
+ const indexed = indexesOf.has(table.toLowerCase());
339
+ let rows = 0;
340
+ if (!indexed || sql.query(`SELECT 1 FROM ${table} WHERE ${filter} LIMIT 1`, params).length > 0) {
341
+ secure(table);
342
+ if (isDelete) {
343
+ sql.exec(`DELETE FROM ${table} WHERE ${filter}`, params);
344
+ }
345
+ else {
346
+ sql.exec(`UPDATE ${table} SET ${cols.map((c) => `${c} = ?`).join(', ')} WHERE ${filter}`, [...blanks, ...params]);
347
+ }
348
+ rows = changeCounts(sql).changes;
349
+ }
350
+ out.verticalRows.push({ module: plan.moduleId, entityType: entity.entityType, mode: entity.mode, rows });
351
+ }
352
+ }
353
+ const guarded = guardSpine(sql, input.statefulTables);
354
+ for (const plan of plans) {
355
+ if (!plan.hook)
356
+ continue;
357
+ const own = plan.ownTables;
358
+ let rows = 0;
359
+ // The hook's capability lives exactly as long as its synchronous run. A hook that kept
360
+ // `ctx` — an async continuation, a handle stored on a global — and used it later would
361
+ // write outside the erasure's transaction, after a refusal had rolled it back; revoked,
362
+ // every later call throws and writes nothing.
363
+ let live = true;
364
+ const alive = () => {
365
+ if (!live) {
366
+ throw substratError('forbidden', `${plan.moduleId}: onSubjectErased's ctx was used after the hook returned — it is valid only while the hook runs`, { reason: 'erasure_revoked' });
367
+ }
368
+ };
369
+ // `changes()` is the last WRITE's count, so a read run through `exec` would repeat the
370
+ // previous one; `total_changes()` moving at all is what says a statement wrote.
371
+ let total = changeCounts(sql).total;
372
+ const hookSql = {
373
+ query: (statement, params) => {
374
+ alive();
375
+ assertWithinErasureReach(plan.moduleId, statement, own);
376
+ return guarded.query(statement, params);
377
+ },
378
+ exec: (statement, params) => {
379
+ alive();
380
+ assertWithinErasureReach(plan.moduleId, statement, own);
381
+ // Any statement the hook runs may change any of its tables; secure their indexes first.
382
+ for (const t of own)
383
+ secure(t);
384
+ guarded.exec(statement, params);
385
+ const after = changeCounts(sql);
386
+ const changes = after.total === total ? 0 : after.changes;
387
+ total = after.total;
388
+ rows += changes;
389
+ return { changes };
390
+ },
391
+ };
392
+ const ctx = {
393
+ sql: hookSql,
394
+ now: () => {
395
+ alive();
396
+ return at;
397
+ },
398
+ };
399
+ let returned;
400
+ try {
401
+ returned = plan.hook(ctx, { subjectId });
402
+ }
403
+ finally {
404
+ live = false;
405
+ }
406
+ if (returned !== undefined) {
407
+ // Anything but `undefined` is a hook that did not finish in its synchronous run: a promise
408
+ // (an async hook), an iterator (a generator hook, whose body has not even started), or a
409
+ // value it meant as a result. Each refuses the whole erasure, before the key. A promise's
410
+ // rejection is the module's — swallowed so it does not surface unhandled after the erasure
411
+ // it belonged to has been refused and rolled back; its continuation can do nothing, `ctx`
412
+ // being revoked above.
413
+ if (returned !== null && typeof returned.then === 'function') {
414
+ returned.then(undefined, () => undefined);
415
+ }
416
+ throw substratError('precondition_failed', `${plan.moduleId}: onSubjectErased returned a value — it must run to completion synchronously and ` +
417
+ "return nothing (no async, no generator), so it runs inside the erasure's one transaction");
418
+ }
419
+ out.hookRows.push({ module: plan.moduleId, rows });
420
+ }
421
+ for (const idx of secured)
422
+ sql.exec(`INSERT INTO ${idx}(${idx}, rank) VALUES('secure-delete', 0)`);
423
+ return out;
424
+ }
425
+ /** Every row the module half changed — what the access log adds to "how much evidence this destroyed". */
426
+ export function moduleRowsErased(counts) {
427
+ return [...counts.verticalRows, ...counts.hookRows].reduce((n, c) => n + c.rows, 0);
428
+ }
429
+ /**
430
+ * Whether a host's reply carries the module half (#2068) in the shape this kernel wrote — what a
431
+ * coordinator checks before destroying the key, so a host built before the half existed is
432
+ * refused rather than read as having reached nothing.
433
+ */
434
+ export function isModuleErasureCounts(value) {
435
+ if (typeof value !== 'object' || value === null)
436
+ return false;
437
+ const v = value;
438
+ return Array.isArray(v.verticalRows) && Array.isArray(v.hookRows) && Array.isArray(v.unreachedEntities);
439
+ }
440
+ //# sourceMappingURL=module-erasure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-erasure.js","sourceRoot":"","sources":["../src/module-erasure.ts"],"names":[],"mappings":"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"}
package/dist/peer.d.ts CHANGED
@@ -36,9 +36,11 @@
36
36
  * way `getConnectorScope` trusts the connection id the control plane hands it. The door's own
37
37
  * guarantees are the ones above; the caller's liveness and tenancy are the platform's gate.
38
38
  */
39
- import { type CheckSubject, type PeerSpec, type Scope, type TenantId, type VerticalCaller, type VerticalResolution } from '@substrat-run/contracts';
39
+ import { type CheckSubject, type PeerSpec, type Scope, type TenantId, type ScopeId, type PeerInstanceResolution, type VerticalCaller, type VerticalResolution } from '@substrat-run/contracts';
40
40
  import { PEER_SUBJECT_PREFIX, peerSubjectRef, type SwitchOutcome, type SwitchSql } from './system-switch.js';
41
41
  export { PEER_SUBJECT_PREFIX, peerSubjectRef };
42
+ /** Directory-owned, on both adapters. The row survives a target's lifecycle changes. */
43
+ export declare const PEER_BINDINGS_DDL = "\n CREATE TABLE IF NOT EXISTS peer_bindings (\n tenant_id TEXT NOT NULL,\n caller_scope_id TEXT NOT NULL,\n vertical TEXT NOT NULL,\n target_scope_id TEXT NOT NULL,\n invalidated INTEGER NOT NULL DEFAULT 0,\n PRIMARY KEY (tenant_id, caller_scope_id, vertical)\n );\n CREATE INDEX IF NOT EXISTS peer_bindings_target ON peer_bindings (target_scope_id);\n";
42
44
  /** One peer vertical as every registered module declares it, together. */
43
45
  export interface PeerDeclaration {
44
46
  readonly vertical: string;
@@ -134,4 +136,10 @@ export type VerticalInstanceCandidate = Pick<Scope, 'id' | 'tenantId' | 'vertica
134
136
  * names a tenant, so a cross-tenant answer is not reachable from here.
135
137
  */
136
138
  export declare function resolveVerticalInstanceFrom(scopes: Iterable<VerticalInstanceCandidate>, tenantId: TenantId, vertical: string): VerticalResolution;
139
+ /**
140
+ * Resolve a peer call using the tenant's explicit choice, if any. Every caller of this rule
141
+ * supplies only scopes read from its own tenant; the predicate checks tenant and vertical again
142
+ * so a corrupt or forged binding cannot turn a foreign scope into a destination.
143
+ */
144
+ export declare function resolvePeerInstanceFrom(scopes: Iterable<VerticalInstanceCandidate>, tenantId: TenantId, vertical: string, boundScopeId: ScopeId | null, invalidated?: boolean): PeerInstanceResolution;
137
145
  //# sourceMappingURL=peer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"peer.d.ts","sourceRoot":"","sources":["../src/peer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACxB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,mBAAmB,EAEnB,cAAc,EAId,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,CAAC;AAG/C,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACzC,6DAA6D;IAC7D,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC3C;AACD,MAAM,MAAM,gBAAgB,GAAG,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAEpE;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC;IAAE,KAAK,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAA;CAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAe/G;AAED,iFAAiF;AACjF,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,EAAE,CAQ9E;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,EAAE,EAAE,SAAS,EACb,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,YAAY,CAuBd;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACxB,EAAE,EAAE,SAAS,EACb,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,IAAI,GAAG,KAAK,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/G,aAAa,CAGf;AAED,sDAAsD;AACtD,wBAAgB,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAExE;AAED,+EAA+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,IAAI,GAAG,KAAK,GAAG,WAAW,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,EAAE,CAW5E;AAED,8DAA8D;AAC9D,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,YAAY,CAAC,CAAC;AAEvH;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,QAAQ,CAAC,yBAAyB,CAAC,EAC3C,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,MAAM,GACf,kBAAkB,CAapB"}
1
+ {"version":3,"file":"peer.d.ts","sourceRoot":"","sources":["../src/peer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,OAAO,EACZ,KAAK,sBAAsB,EAC3B,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACxB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,mBAAmB,EAEnB,cAAc,EAId,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,CAAC;AAE/C,wFAAwF;AACxF,eAAO,MAAM,iBAAiB,0XAU7B,CAAC;AAEF,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACzC,6DAA6D;IAC7D,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC3C;AACD,MAAM,MAAM,gBAAgB,GAAG,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAEpE;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC;IAAE,KAAK,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAA;CAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAe/G;AAED,iFAAiF;AACjF,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,EAAE,CAQ9E;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,EAAE,EAAE,SAAS,EACb,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,YAAY,CAuBd;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACxB,EAAE,EAAE,SAAS,EACb,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,IAAI,GAAG,KAAK,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/G,aAAa,CAGf;AAED,sDAAsD;AACtD,wBAAgB,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAExE;AAED,+EAA+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,IAAI,GAAG,KAAK,GAAG,WAAW,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,EAAE,CAW5E;AAED,8DAA8D;AAC9D,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,YAAY,CAAC,CAAC;AAEvH;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,QAAQ,CAAC,yBAAyB,CAAC,EAC3C,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,MAAM,GACf,kBAAkB,CAapB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,QAAQ,CAAC,yBAAyB,CAAC,EAC3C,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,OAAO,GAAG,IAAI,EAC5B,WAAW,UAAQ,GAClB,sBAAsB,CAWxB"}
package/dist/peer.js CHANGED
@@ -40,6 +40,18 @@ import { substratError, } from '@substrat-run/contracts';
40
40
  import { isPrimaryScope } from './platform-sweep.js';
41
41
  import { PEER_SUBJECT_PREFIX, SYSTEM_SWITCH_OFF_RELATION, peerSubjectRef, subjectGrantState, subjectSwitchedOff, moveSwitch, } from './system-switch.js';
42
42
  export { PEER_SUBJECT_PREFIX, peerSubjectRef };
43
+ /** Directory-owned, on both adapters. The row survives a target's lifecycle changes. */
44
+ export const PEER_BINDINGS_DDL = `
45
+ CREATE TABLE IF NOT EXISTS peer_bindings (
46
+ tenant_id TEXT NOT NULL,
47
+ caller_scope_id TEXT NOT NULL,
48
+ vertical TEXT NOT NULL,
49
+ target_scope_id TEXT NOT NULL,
50
+ invalidated INTEGER NOT NULL DEFAULT 0,
51
+ PRIMARY KEY (tenant_id, caller_scope_id, vertical)
52
+ );
53
+ CREATE INDEX IF NOT EXISTS peer_bindings_target ON peer_bindings (target_scope_id);
54
+ `;
43
55
  /**
44
56
  * The union of every module's `peers` declaration, keyed by peer slug. Two modules naming one
45
57
  * peer contribute both of their allowlists and both of their key sets: each module speaks for
@@ -173,4 +185,21 @@ export function resolveVerticalInstanceFrom(scopes, tenantId, vertical) {
173
185
  return { outcome: 'not-installed', tenantId, vertical };
174
186
  return { outcome: 'ambiguous', tenantId, vertical, count: matches.length };
175
187
  }
188
+ /**
189
+ * Resolve a peer call using the tenant's explicit choice, if any. Every caller of this rule
190
+ * supplies only scopes read from its own tenant; the predicate checks tenant and vertical again
191
+ * so a corrupt or forged binding cannot turn a foreign scope into a destination.
192
+ */
193
+ export function resolvePeerInstanceFrom(scopes, tenantId, vertical, boundScopeId, invalidated = false) {
194
+ const candidates = [...scopes];
195
+ if (boundScopeId === null)
196
+ return resolveVerticalInstanceFrom(candidates, tenantId, vertical);
197
+ if (invalidated)
198
+ return { outcome: 'bound-unavailable', tenantId, vertical, targetScopeId: boundScopeId };
199
+ const target = candidates.find((scope) => scope.id === boundScopeId && scope.tenantId === tenantId && scope.vertical === vertical &&
200
+ scope.status === 'active' && isPrimaryScope(scope));
201
+ return target
202
+ ? { outcome: 'resolved', instance: { tenantId, scopeId: target.id, vertical } }
203
+ : { outcome: 'bound-unavailable', tenantId, vertical, targetScopeId: boundScopeId };
204
+ }
176
205
  //# sourceMappingURL=peer.js.map
package/dist/peer.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"peer.js","sourceRoot":"","sources":["../src/peer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"peer.js","sourceRoot":"","sources":["../src/peer.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { SubstratError, type Actor, type Coverage, type Decision, type EntityRef, type Node, type PermissionKey, type CheckSubject, type PrincipalId } from '@substrat-run/contracts';
2
+ import type { GrantedEntitiesPage } from './grant-scoped-read.js';
2
3
  /**
3
4
  * The evaluation seam (D-16): the MODEL is kernel-owned, the evaluation engine
4
5
  * is an adapter — the built-in default is a constrained relationship-tuple
@@ -16,6 +17,11 @@ export interface PermissionChecker {
16
17
  * caller passes `{ kind: 'principal', id }` and behaves exactly as before.
17
18
  */
18
19
  check(subject: CheckSubject, permission: PermissionKey, node: Node, entity?: EntityRef): Promise<Decision>;
20
+ /** Optional for a pluggable checker; an absent implementation is reported as incomplete. */
21
+ grantedEntities?(subject: CheckSubject, permission: PermissionKey, node: Node, entityType: string, checkEntity: (entity: EntityRef) => Promise<boolean>, options?: {
22
+ limit?: number;
23
+ cursor?: string;
24
+ }): Promise<GrantedEntitiesPage>;
19
25
  /**
20
26
  * Does `subject` already hold every one of `required` at `node`? (K-21,
21
27
  * membership.md §5.1.)
@@ -1 +1 @@
1
- {"version":3,"file":"permission-checker.d.ts","sourceRoot":"","sources":["../src/permission-checker.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,aAAa,EACb,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,KAAK,CACH,OAAO,EAAE,YAAY,EACrB,UAAU,EAAE,aAAa,EACzB,IAAI,EAAE,IAAI,EACV,MAAM,CAAC,EAAE,SAAS,GACjB,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrB;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,MAAM,CACJ,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,SAAS,aAAa,EAAE,EAClC,IAAI,EAAE,IAAI,GACT,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtB;AAUD,eAAO,MAAM,gBAAgB,YAAa,MAAM,KAAG,aAAwE,CAAC;AAC5H,eAAO,MAAM,kBAAkB,QAAS,OAAO,WAAW,MAAM,KAAG,OACsC,CAAC;AAE1G,sDAAsD;AACtD,eAAO,MAAM,WAAW,OAAQ,WAAW,KAAG,YAA2C,CAAC;AAE1F;;;;;GAKG;AACH,eAAO,MAAM,OAAO,YAAa,YAAY,KAAG,KAc/C,CAAC;AAEF;;;;;;GAMG;AACH,qBAAa,gBAAiB,SAAQ,aAAa;IACjD,QAAQ,CAAC,UAAU,CAAC,EAAE,aAAa,CAAC;IACpC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;IACrB,YAAY,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE;QAAE,UAAU,EAAE,aAAa,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,EAS9E;CACF;AAED,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAC5E,QAAQ,EACR;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,CAClB,CAOA;AAED,4FAA4F;AAC5F,eAAO,MAAM,cAAc,EAAE,iBAa5B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,iBAgBpC,CAAC"}
1
+ {"version":3,"file":"permission-checker.d.ts","sourceRoot":"","sources":["../src/permission-checker.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,aAAa,EACb,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAElE;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,KAAK,CACH,OAAO,EAAE,YAAY,EACrB,UAAU,EAAE,aAAa,EACzB,IAAI,EAAE,IAAI,EACV,MAAM,CAAC,EAAE,SAAS,GACjB,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrB,4FAA4F;IAC5F,eAAe,CAAC,CACd,OAAO,EAAE,YAAY,EACrB,UAAU,EAAE,aAAa,EACzB,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,OAAO,CAAC,EACpD,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAC5C,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAChC;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,MAAM,CACJ,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,SAAS,aAAa,EAAE,EAClC,IAAI,EAAE,IAAI,GACT,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtB;AAUD,eAAO,MAAM,gBAAgB,YAAa,MAAM,KAAG,aAAwE,CAAC;AAC5H,eAAO,MAAM,kBAAkB,QAAS,OAAO,WAAW,MAAM,KAAG,OACsC,CAAC;AAE1G,sDAAsD;AACtD,eAAO,MAAM,WAAW,OAAQ,WAAW,KAAG,YAA2C,CAAC;AAE1F;;;;;GAKG;AACH,eAAO,MAAM,OAAO,YAAa,YAAY,KAAG,KAc/C,CAAC;AAEF;;;;;;GAMG;AACH,qBAAa,gBAAiB,SAAQ,aAAa;IACjD,QAAQ,CAAC,UAAU,CAAC,EAAE,aAAa,CAAC;IACpC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;IACrB,YAAY,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE;QAAE,UAAU,EAAE,aAAa,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,EAS9E;CACF;AAED,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAC5E,QAAQ,EACR;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,CAClB,CAOA;AAED,4FAA4F;AAC5F,eAAO,MAAM,cAAc,EAAE,iBAa5B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,iBAgBpC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"permission-checker.js","sourceRoot":"","sources":["../src/permission-checker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"permission-checker.js","sourceRoot":"","sources":["../src/permission-checker.ts"],"names":[],"mappings":"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"}