@substrat-run/contracts 0.147.0 → 0.149.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 (85) hide show
  1. package/dist/assistant-stream.d.ts +311 -0
  2. package/dist/assistant-stream.d.ts.map +1 -0
  3. package/dist/assistant-stream.js +360 -0
  4. package/dist/assistant-stream.js.map +1 -0
  5. package/dist/attachments.d.ts +184 -1
  6. package/dist/attachments.d.ts.map +1 -1
  7. package/dist/attachments.js +146 -2
  8. package/dist/attachments.js.map +1 -1
  9. package/dist/connections.d.ts +5 -6
  10. package/dist/connections.d.ts.map +1 -1
  11. package/dist/connections.js +11 -2
  12. package/dist/connections.js.map +1 -1
  13. package/dist/control-plane.d.ts +92 -3
  14. package/dist/control-plane.d.ts.map +1 -1
  15. package/dist/control-plane.js +79 -7
  16. package/dist/control-plane.js.map +1 -1
  17. package/dist/deploy.d.ts +165 -32
  18. package/dist/deploy.d.ts.map +1 -1
  19. package/dist/deploy.js +260 -48
  20. package/dist/deploy.js.map +1 -1
  21. package/dist/errors.d.ts +1 -0
  22. package/dist/errors.d.ts.map +1 -1
  23. package/dist/errors.js +6 -1
  24. package/dist/errors.js.map +1 -1
  25. package/dist/index.d.ts +3 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +4 -1
  28. package/dist/index.js.map +1 -1
  29. package/dist/introspection.d.ts +12 -3
  30. package/dist/introspection.d.ts.map +1 -1
  31. package/dist/introspection.js +10 -2
  32. package/dist/introspection.js.map +1 -1
  33. package/dist/invocation-record.d.ts +17 -0
  34. package/dist/invocation-record.d.ts.map +1 -1
  35. package/dist/invocation-record.js +20 -0
  36. package/dist/invocation-record.js.map +1 -1
  37. package/dist/kernel-events.d.ts.map +1 -1
  38. package/dist/kernel-events.js +4 -1
  39. package/dist/kernel-events.js.map +1 -1
  40. package/dist/lake.d.ts +109 -0
  41. package/dist/lake.d.ts.map +1 -0
  42. package/dist/lake.js +85 -0
  43. package/dist/lake.js.map +1 -0
  44. package/dist/manifest.d.ts +4 -0
  45. package/dist/manifest.d.ts.map +1 -1
  46. package/dist/manifest.js +5 -0
  47. package/dist/manifest.js.map +1 -1
  48. package/dist/migration-diff.d.ts +48 -7
  49. package/dist/migration-diff.d.ts.map +1 -1
  50. package/dist/migration-diff.js +61 -17
  51. package/dist/migration-diff.js.map +1 -1
  52. package/dist/model.d.ts +4 -0
  53. package/dist/model.d.ts.map +1 -1
  54. package/dist/model.js.map +1 -1
  55. package/dist/registry.d.ts +48 -0
  56. package/dist/registry.d.ts.map +1 -1
  57. package/dist/registry.js +74 -0
  58. package/dist/registry.js.map +1 -1
  59. package/dist/review-text.d.ts +49 -0
  60. package/dist/review-text.d.ts.map +1 -0
  61. package/dist/review-text.js +87 -0
  62. package/dist/review-text.js.map +1 -0
  63. package/dist/routing.d.ts +1 -1
  64. package/dist/routing.js +2 -2
  65. package/dist/routing.js.map +1 -1
  66. package/dist/scope-store-envelope.d.ts +187 -0
  67. package/dist/scope-store-envelope.d.ts.map +1 -0
  68. package/dist/scope-store-envelope.js +438 -0
  69. package/dist/scope-store-envelope.js.map +1 -0
  70. package/dist/scope-store-transport.d.ts +1 -1
  71. package/dist/scope-store-transport.js +2 -2
  72. package/dist/scope-store-transport.js.map +1 -1
  73. package/dist/script-names.d.ts +19 -8
  74. package/dist/script-names.d.ts.map +1 -1
  75. package/dist/script-names.js +27 -11
  76. package/dist/script-names.js.map +1 -1
  77. package/dist/sql-tokens.d.ts +7 -0
  78. package/dist/sql-tokens.d.ts.map +1 -1
  79. package/dist/sql-tokens.js +2 -2
  80. package/dist/sql-tokens.js.map +1 -1
  81. package/package.json +8 -4
  82. package/dist/scope-store-mac.d.ts +0 -24
  83. package/dist/scope-store-mac.d.ts.map +0 -1
  84. package/dist/scope-store-mac.js +0 -61
  85. package/dist/scope-store-mac.js.map +0 -1
@@ -0,0 +1,438 @@
1
+ /**
2
+ * The signed envelope a scope-store call carries (#2287, RFC scope-stores §10.3).
3
+ *
4
+ * Ed25519 over a canonical encoding of every field the store acts on. The router signs
5
+ * audience `caller` and the control plane signs audience `platform`, each with its own
6
+ * private key. A store script holds only public keys, a list per audience, so a key can be
7
+ * rotated without a moment where no key verifies. The encoding is nine lines joined by
8
+ * `\n`, with no trailing newline, so a verifier in another language can rebuild it:
9
+ *
10
+ * ```
11
+ * 1
12
+ * caller|platform
13
+ * <kid: base64url of the first 8 bytes of SHA-256 over the raw public key>
14
+ * <store script name>
15
+ * <object name>
16
+ * <operation>
17
+ * <sha256 hex of the exact request body>
18
+ * <iat, unix seconds>
19
+ * <nonce, base64url of 16 bytes>
20
+ * ```
21
+ *
22
+ * The signature is base64url over those exact UTF-8 bytes. An envelope is fresh for
23
+ * {@link SCOPE_STORE_ENVELOPE_WINDOW_SECONDS} on either side of the verifier's clock. A
24
+ * store does not remember nonces (RFC Q2): an envelope replayed inside the window, at the
25
+ * same script and object with the same body, is accepted again. The reserved operations are
26
+ * idempotent, and a driver operation's retry safety is the vertical's.
27
+ *
28
+ * The script line is an opaque string compared for equality: the signer builds it, the
29
+ * verifier is told its own. Nothing here parses it.
30
+ *
31
+ * This module imports nothing, so a store entry can load it as one file.
32
+ */
33
+ export const SCOPE_STORE_ENVELOPE_VERSION = 1;
34
+ export const SCOPE_STORE_ENVELOPE_WINDOW_SECONDS = 60;
35
+ /** The request header carrying base64url of the canonical bytes. */
36
+ export const SCOPE_STORE_ENVELOPE_HEADER = 'x-substrat-store-envelope';
37
+ /** The request header carrying the base64url signature. */
38
+ export const SCOPE_STORE_SIGNATURE_HEADER = 'x-substrat-store-signature';
39
+ /**
40
+ * The operations only the platform may send to a scope store (#2207). A vertical's
41
+ * stub refuses every one of them. A driver's registration has to answer all of them,
42
+ * `substrat.erase` included, before a hosted deploy may store tenant data.
43
+ */
44
+ export const RESERVED_STORE_OPERATIONS = [
45
+ 'substrat.export',
46
+ 'substrat.import',
47
+ 'substrat.size',
48
+ 'substrat.wipe',
49
+ 'substrat.erase',
50
+ ];
51
+ /**
52
+ * Which operations each (version, audience) admits. Closed: a pair not in this table is
53
+ * refused. `platform` sends exactly the reserved operations, and `caller` sends anything
54
+ * else, never a `substrat.*` name.
55
+ */
56
+ const ADMITTED = {
57
+ '1': {
58
+ platform: (op) => RESERVED_STORE_OPERATIONS.includes(op),
59
+ caller: (op) => !op.startsWith('substrat.'),
60
+ },
61
+ };
62
+ /** Whether this version admits `op` from `aud`. */
63
+ export function scopeStoreEnvelopeAdmits(v, aud, op) {
64
+ const byAudience = Object.hasOwn(ADMITTED, String(v)) ? ADMITTED[String(v)] : undefined;
65
+ if (!byAudience || !Object.hasOwn(byAudience, aud))
66
+ return false;
67
+ return byAudience[aud](op);
68
+ }
69
+ export function bytesToBase64Url(bytes) {
70
+ let binary = '';
71
+ for (const byte of bytes)
72
+ binary += String.fromCharCode(byte);
73
+ return btoa(binary).replaceAll('+', '-').replaceAll('/', '_').replaceAll('=', '');
74
+ }
75
+ export function base64UrlToBytes(value) {
76
+ if (!/^[A-Za-z0-9_-]+$/.test(value))
77
+ return undefined;
78
+ const padded = value.replaceAll('-', '+').replaceAll('_', '/') + '='.repeat((4 - (value.length % 4)) % 4);
79
+ try {
80
+ const binary = atob(padded);
81
+ const bytes = new Uint8Array(binary.length);
82
+ for (let i = 0; i < binary.length; i++)
83
+ bytes[i] = binary.charCodeAt(i);
84
+ return bytes;
85
+ }
86
+ catch {
87
+ return undefined;
88
+ }
89
+ }
90
+ function copyBytes(bytes) {
91
+ const copy = new ArrayBuffer(bytes.byteLength);
92
+ new Uint8Array(copy).set(bytes);
93
+ return copy;
94
+ }
95
+ /**
96
+ * Whether `text` is the canonical base64url of exactly `length` bytes: it decodes to that many
97
+ * bytes and re-encodes to the same text, so its unused trailing bits are zero and no second
98
+ * spelling names the same value.
99
+ */
100
+ function isCanonicalBase64Url(text, length) {
101
+ const bytes = base64UrlToBytes(text);
102
+ return bytes?.length === length && bytesToBase64Url(bytes) === text;
103
+ }
104
+ const NONCE = /^[A-Za-z0-9_-]{22}$/;
105
+ const KID = /^[A-Za-z0-9_-]{11}$/;
106
+ const DIGEST = /^[0-9a-f]{64}$/;
107
+ // At most 15 digits, so every value it admits is a safe integer, as the encoder requires.
108
+ const IAT = /^(0|[1-9]\d{0,14})$/;
109
+ /** Nine lines, no trailing newline. Throws on a field the parser would refuse. */
110
+ export function canonicalScopeStoreEnvelope(envelope) {
111
+ if (envelope.v !== SCOPE_STORE_ENVELOPE_VERSION)
112
+ throw new Error(`unknown store envelope version ${envelope.v}`);
113
+ for (const field of [envelope.aud, envelope.kid, envelope.script, envelope.name, envelope.op, envelope.digest, envelope.nonce]) {
114
+ if (field.length === 0)
115
+ throw new Error('a store envelope field is empty');
116
+ if (field.includes('\n'))
117
+ throw new Error('a store envelope field contains a newline');
118
+ }
119
+ if (!Number.isSafeInteger(envelope.iat) || envelope.iat < 0)
120
+ throw new Error('a store envelope iat is not a non-negative integer');
121
+ const canonical = [
122
+ String(envelope.v),
123
+ envelope.aud,
124
+ envelope.kid,
125
+ envelope.script,
126
+ envelope.name,
127
+ envelope.op,
128
+ envelope.digest,
129
+ String(envelope.iat),
130
+ envelope.nonce,
131
+ ].join('\n');
132
+ if (!parseScopeStoreEnvelope(canonical))
133
+ throw new Error('a store envelope field is malformed');
134
+ return canonical;
135
+ }
136
+ /** The envelope those bytes name, or undefined when they are not exactly what the encoder emits. */
137
+ export function parseScopeStoreEnvelope(canonical) {
138
+ const lines = canonical.split('\n');
139
+ if (lines.length !== 9)
140
+ return undefined;
141
+ const [version, aud, kid, script, name, op, digest, iatText, nonce] = lines;
142
+ if (version !== '1' || (aud !== 'caller' && aud !== 'platform'))
143
+ return undefined;
144
+ if (!script || !name || !op)
145
+ return undefined;
146
+ if (!KID.test(kid) || !DIGEST.test(digest) || !IAT.test(iatText) || !NONCE.test(nonce))
147
+ return undefined;
148
+ // The kid is 8 bytes and the nonce 16, each in canonical base64url. IAT's grammar already
149
+ // admits only the decimal text `String(n)` gives for a safe integer n: no sign, no leading zero.
150
+ if (!isCanonicalBase64Url(kid, 8) || !isCanonicalBase64Url(nonce, 16))
151
+ return undefined;
152
+ return { v: 1, aud, kid, script, name, op, digest, iat: Number(iatText), nonce };
153
+ }
154
+ /** SHA-256 of the exact request body, lowercase hex. */
155
+ export async function scopeStoreBodyDigest(body) {
156
+ const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(body));
157
+ return [...new Uint8Array(hash)].map((byte) => byte.toString(16).padStart(2, '0')).join('');
158
+ }
159
+ /** Whether `iat` is inside the freshness window of `nowSeconds`. */
160
+ export function scopeStoreEnvelopeFresh(iat, nowSeconds, windowSeconds = SCOPE_STORE_ENVELOPE_WINDOW_SECONDS) {
161
+ return Math.abs(nowSeconds - iat) <= windowSeconds;
162
+ }
163
+ /**
164
+ * The encodings of Ed25519's eight small-order points, with the sign bit (the top bit of the
165
+ * last byte) cleared, including the non-canonical encodings p and p+1 of y: the list libsodium
166
+ * refuses. Under such a key a forged signature verifies for many messages (with the identity,
167
+ * R = identity and S = 0 verifies for any message under some verifiers), so no store accepts one.
168
+ */
169
+ const SMALL_ORDER_KEYS = [
170
+ '0000000000000000000000000000000000000000000000000000000000000000', // y = 0, order 4
171
+ '0100000000000000000000000000000000000000000000000000000000000000', // the identity, order 1
172
+ '26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05', // order 8
173
+ 'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a', // order 8
174
+ 'ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f', // y = p - 1, order 2
175
+ 'edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f', // y = p, a non-canonical 0
176
+ 'eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f', // y = p + 1, a non-canonical identity
177
+ ];
178
+ /** Whether 32 key bytes encode a small-order point, in either sign. */
179
+ function isSmallOrderKey(bytes) {
180
+ const unsigned = Uint8Array.from(bytes);
181
+ unsigned[31] = unsigned[31] & 0x7f;
182
+ const hex = [...unsigned].map((byte) => byte.toString(16).padStart(2, '0')).join('');
183
+ return SMALL_ORDER_KEYS.includes(hex);
184
+ }
185
+ /**
186
+ * The key id of a raw Ed25519 public key (base64url): base64url of SHA-256's first 8 bytes.
187
+ * Throws on a key that is not 32 bytes or encodes a small-order point, so a verifier given one
188
+ * never matches it.
189
+ */
190
+ export async function scopeStoreKeyId(publicKey) {
191
+ const bytes = base64UrlToBytes(publicKey);
192
+ if (!bytes || bytes.length !== 32)
193
+ throw new Error('a store public key is not 32 bytes of base64url');
194
+ if (isSmallOrderKey(bytes))
195
+ throw new Error('a store public key is a small-order point');
196
+ const hash = await crypto.subtle.digest('SHA-256', copyBytes(bytes));
197
+ return bytesToBase64Url(new Uint8Array(hash).slice(0, 8));
198
+ }
199
+ /**
200
+ * Why a store refuses one configured public key, or undefined when it accepts it: empty, not
201
+ * 32 bytes of base64url, a small-order point, or not in canonical base64url (its unused trailing
202
+ * bits set, so two spellings would name one key).
203
+ */
204
+ export function scopeStorePublicKeyProblem(key) {
205
+ if (key.length === 0)
206
+ return 'empty';
207
+ const bytes = base64UrlToBytes(key);
208
+ if (bytes?.length !== 32)
209
+ return 'length';
210
+ if (isSmallOrderKey(bytes))
211
+ return 'small-order';
212
+ // Canonical means the bytes re-encode to the same text, so equal text is equal bytes.
213
+ if (bytesToBase64Url(bytes) !== key)
214
+ return 'non-canonical';
215
+ return undefined;
216
+ }
217
+ const PUBLIC_KEY_PROBLEM = {
218
+ empty: 'a store public key list is empty or has an empty entry',
219
+ length: 'a store public key is not 32 bytes of base64url',
220
+ 'small-order': 'a store public key is a small-order point',
221
+ 'non-canonical': 'a store public key is not canonical base64url',
222
+ };
223
+ /**
224
+ * A store's public keys for one audience, as configured: raw Ed25519 keys, base64url,
225
+ * separated by commas (whitespace around each is ignored). Throws on an empty list, any key
226
+ * {@link scopeStorePublicKeyProblem} refuses, or the same key twice. Rotation is: add the new
227
+ * key, switch the signer, then drop the old key.
228
+ */
229
+ export function parseScopeStorePublicKeys(text) {
230
+ const keys = text.split(',').map((key) => key.trim());
231
+ if (keys.some((key) => key.length === 0))
232
+ throw new Error(PUBLIC_KEY_PROBLEM.empty);
233
+ const seen = new Set();
234
+ for (const key of keys) {
235
+ const problem = scopeStorePublicKeyProblem(key);
236
+ if (problem)
237
+ throw new Error(PUBLIC_KEY_PROBLEM[problem]);
238
+ if (seen.has(key))
239
+ throw new Error('a store public key is listed twice');
240
+ seen.add(key);
241
+ }
242
+ return keys;
243
+ }
244
+ /**
245
+ * Both audiences' public keys, from their configured lists. Throws on anything
246
+ * {@link parseScopeStorePublicKeys} refuses, and on a key listed for both audiences: whoever
247
+ * holds the `caller` private key could then sign `platform` envelopes, `substrat.erase`
248
+ * included (L16). A store builds its keys only through this.
249
+ */
250
+ export function scopeStorePublicKeysFrom(config) {
251
+ const caller = parseScopeStorePublicKeys(config.caller);
252
+ const platform = parseScopeStorePublicKeys(config.platform);
253
+ if (caller.some((key) => platform.includes(key))) {
254
+ throw new Error('a store public key is listed for both audiences');
255
+ }
256
+ return { caller, platform };
257
+ }
258
+ /**
259
+ * A fresh Ed25519 pair in the shapes this module takes: the PKCS8 private key a signer holds
260
+ * and the raw public key a store lists, both base64url, with the key id the envelope names.
261
+ */
262
+ export async function generateScopeStoreKeyPair() {
263
+ const pair = (await crypto.subtle.generateKey({ name: 'Ed25519' }, true, ['sign', 'verify']));
264
+ const privateKey = bytesToBase64Url(new Uint8Array((await crypto.subtle.exportKey('pkcs8', pair.privateKey))));
265
+ const publicKey = bytesToBase64Url(new Uint8Array((await crypto.subtle.exportKey('raw', pair.publicKey))));
266
+ return { privateKey, publicKey, kid: await scopeStoreKeyId(publicKey) };
267
+ }
268
+ /**
269
+ * The DER prefix of an Ed25519 PKCS8 v1 private key (RFC 8410 §7): SEQUENCE, version 0, the
270
+ * Ed25519 algorithm identifier, then a 34-byte OCTET STRING wrapping the 32-byte seed. With the
271
+ * seed it is exactly 48 bytes, the form WebCrypto exports and `generateScopeStoreKeyPair` writes.
272
+ */
273
+ const PKCS8_V1_ED25519_PREFIX = [0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20];
274
+ /**
275
+ * Import a PKCS8 Ed25519 private key (base64url) and derive its key id from its public half.
276
+ * Only the canonical 48-byte v1 form is accepted: a DER parser may tolerate trailing bytes or
277
+ * another encoding of the same seed, and whether it does differs between runtimes, so a key a
278
+ * tool accepts here could otherwise be one the deployed signer refuses.
279
+ */
280
+ async function signingKey(pkcs8) {
281
+ const bytes = base64UrlToBytes(pkcs8);
282
+ if (!bytes)
283
+ throw new ScopeStoreKeyError('the store signing key is not base64url', 'encoding');
284
+ if (bytes.length !== 48 || PKCS8_V1_ED25519_PREFIX.some((byte, i) => bytes[i] !== byte)) {
285
+ throw new ScopeStoreKeyError('the store signing key is not a 48-byte Ed25519 PKCS8 v1 key', 'not-pkcs8-v1');
286
+ }
287
+ let key;
288
+ let x;
289
+ try {
290
+ // Extractable only so its public half (`x`) can be read for the key id; it never leaves here.
291
+ key = await crypto.subtle.importKey('pkcs8', copyBytes(bytes), { name: 'Ed25519' }, true, ['sign']);
292
+ x = (await crypto.subtle.exportKey('jwk', key)).x;
293
+ }
294
+ catch {
295
+ throw new ScopeStoreKeyError('the store signing key is not an Ed25519 PKCS8 key', 'not-ed25519');
296
+ }
297
+ if (typeof x !== 'string')
298
+ throw new ScopeStoreKeyError('the store signing key has no public half', 'no-public-half');
299
+ // The only key a JWK export can name that scopeStoreKeyId refuses is a small-order point.
300
+ if (scopeStorePublicKeyProblem(x))
301
+ throw new ScopeStoreKeyError('the store signing key is a small-order point', 'small-order');
302
+ return { key, publicKey: x, kid: await scopeStoreKeyId(x) };
303
+ }
304
+ /**
305
+ * The raw public key and key id a PKCS8 Ed25519 private key (base64url) signs under, derived the
306
+ * way {@link issueScopeStoreEnvelope} derives them. Throws {@link ScopeStoreKeyError} when the key
307
+ * is unusable, whose message never carries the key.
308
+ */
309
+ export async function scopeStoreSignerPublicKey(pkcs8) {
310
+ const { publicKey, kid } = await signingKey(pkcs8);
311
+ return { publicKey, kid };
312
+ }
313
+ /** A signing key that is present but cannot be used. Its message never carries the key. */
314
+ export class ScopeStoreKeyError extends Error {
315
+ reason;
316
+ name = 'ScopeStoreKeyError';
317
+ constructor(message, reason) {
318
+ super(message);
319
+ this.reason = reason;
320
+ }
321
+ }
322
+ /**
323
+ * Whether `signature` is the Ed25519 signature of `canonical` under the raw public key.
324
+ * A malformed key or signature is false.
325
+ */
326
+ export async function verifyScopeStoreEnvelope(publicKey, canonical, signature) {
327
+ const keyBytes = base64UrlToBytes(publicKey);
328
+ const sigBytes = base64UrlToBytes(signature);
329
+ if (!keyBytes || !sigBytes || sigBytes.length !== 64)
330
+ return false;
331
+ try {
332
+ const key = await crypto.subtle.importKey('raw', copyBytes(keyBytes), { name: 'Ed25519' }, false, ['verify']);
333
+ return await crypto.subtle.verify('Ed25519', key, copyBytes(sigBytes), new TextEncoder().encode(canonical));
334
+ }
335
+ catch {
336
+ return false;
337
+ }
338
+ }
339
+ /**
340
+ * Build, digest and sign one envelope. `iat` and `nonce` default to now and 16 random bytes.
341
+ * Throws {@link ScopeStoreKeyError} when the key is unusable, and an Error when a field is.
342
+ */
343
+ export async function issueScopeStoreEnvelope(input) {
344
+ const signer = await signingKey(input.privateKey);
345
+ const envelope = {
346
+ v: 1,
347
+ aud: input.aud,
348
+ kid: signer.kid,
349
+ script: input.script,
350
+ name: input.name,
351
+ op: input.op,
352
+ digest: await scopeStoreBodyDigest(input.body),
353
+ iat: input.iat ?? Math.floor(Date.now() / 1000),
354
+ nonce: input.nonce ?? bytesToBase64Url(crypto.getRandomValues(new Uint8Array(16))),
355
+ };
356
+ if (!scopeStoreEnvelopeAdmits(envelope.v, envelope.aud, envelope.op)) {
357
+ throw new Error(`audience '${envelope.aud}' does not send '${envelope.op}'`);
358
+ }
359
+ const canonical = canonicalScopeStoreEnvelope(envelope);
360
+ const signature = await crypto.subtle.sign('Ed25519', signer.key, new TextEncoder().encode(canonical));
361
+ return {
362
+ envelope,
363
+ canonical,
364
+ header: bytesToBase64Url(new TextEncoder().encode(canonical)),
365
+ signature: bytesToBase64Url(new Uint8Array(signature)),
366
+ };
367
+ }
368
+ /**
369
+ * Every envelope check a store makes on a call before the driver's class runs (RFC §10.3
370
+ * checks 1–4, L4, L5), in one place, so a store entry carries no copy. The object binding
371
+ * (check 5: the object's id is `idFromName` of the signed name) is the entry's, because it
372
+ * needs the object's id; so is reading the configured keys and script name.
373
+ *
374
+ * `script` is the store script's own name, compared with the signed line for equality.
375
+ * The body must be JSON naming the signed operation as `operation` and the signed object
376
+ * as `objectName`, so the signed name is the one the driver is asked about.
377
+ */
378
+ export async function verifyScopeStoreCall(input) {
379
+ const refuse = (refusal) => ({ ok: false, refusal });
380
+ if (!input.envelope || !input.signature)
381
+ return refuse('missing');
382
+ const bytes = base64UrlToBytes(input.envelope);
383
+ if (!bytes)
384
+ return refuse('malformed');
385
+ let canonical;
386
+ try {
387
+ canonical = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
388
+ }
389
+ catch {
390
+ return refuse('malformed');
391
+ }
392
+ const envelope = parseScopeStoreEnvelope(canonical);
393
+ if (!envelope)
394
+ return refuse('malformed');
395
+ if (!scopeStoreEnvelopeAdmits(envelope.v, envelope.aud, envelope.op))
396
+ return refuse('audience');
397
+ // Key ids are over the decoded bytes, so two spellings of one key share an id. A key the
398
+ // other audience also lists refuses every call: its holder could sign for either (L16).
399
+ const kidsOf = async (keys) => {
400
+ const kids = new Map();
401
+ for (const key of keys) {
402
+ try {
403
+ kids.set(await scopeStoreKeyId(key), key);
404
+ }
405
+ catch {
406
+ // A malformed listed key verifies nothing.
407
+ }
408
+ }
409
+ return kids;
410
+ };
411
+ const own = await kidsOf(input.keys[envelope.aud]);
412
+ const other = await kidsOf(input.keys[envelope.aud === 'caller' ? 'platform' : 'caller']);
413
+ if ([...own.keys()].some((kid) => other.has(kid)))
414
+ return refuse('keys');
415
+ const publicKey = own.get(envelope.kid);
416
+ if (!publicKey)
417
+ return refuse('kid');
418
+ if (!(await verifyScopeStoreEnvelope(publicKey, canonical, input.signature)))
419
+ return refuse('signature');
420
+ if (envelope.digest !== (await scopeStoreBodyDigest(input.body)))
421
+ return refuse('digest');
422
+ if (!scopeStoreEnvelopeFresh(envelope.iat, input.nowSeconds, input.windowSeconds))
423
+ return refuse('stale');
424
+ if (envelope.script !== input.script)
425
+ return refuse('script');
426
+ let parsed;
427
+ try {
428
+ parsed = JSON.parse(input.body);
429
+ }
430
+ catch {
431
+ return refuse('body');
432
+ }
433
+ const field = (key) => (typeof parsed === 'object' && parsed !== null ? Reflect.get(parsed, key) : undefined);
434
+ if (field('operation') !== envelope.op || field('objectName') !== envelope.name)
435
+ return refuse('body');
436
+ return { ok: true, envelope };
437
+ }
438
+ //# sourceMappingURL=scope-store-envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-store-envelope.js","sourceRoot":"","sources":["../src/scope-store-envelope.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,7 @@ import { z } from 'zod';
5
5
  * A vertical fetches `store.substrat.internal`. It names a binding, an operation
6
6
  * and an input. It does not name a script, an object or a key: the egress worker
7
7
  * hands the call to the router with the dispatch parameters the router set, and
8
- * the router is what signs the object name and addresses the store script.
8
+ * the router is what signs the envelope and addresses the store script.
9
9
  * `*.substrat.internal` is in no DNS zone, so a call from inside a Durable Object
10
10
  * — which an outbound worker does not see — fails instead of leaving the isolate.
11
11
  */
@@ -7,7 +7,7 @@ import { RESERVED_STORE_OPERATIONS, storeOperationName } from './deploy.js';
7
7
  * A vertical fetches `store.substrat.internal`. It names a binding, an operation
8
8
  * and an input. It does not name a script, an object or a key: the egress worker
9
9
  * hands the call to the router with the dispatch parameters the router set, and
10
- * the router is what signs the object name and addresses the store script.
10
+ * the router is what signs the envelope and addresses the store script.
11
11
  * `*.substrat.internal` is in no DNS zone, so a call from inside a Durable Object
12
12
  * — which an outbound worker does not see — fails instead of leaving the isolate.
13
13
  */
@@ -26,7 +26,7 @@ export const storeCallRequest = z
26
26
  .object({
27
27
  scopeId,
28
28
  binding: z.string().regex(/^[A-Z][A-Z0-9_]*$/),
29
- // The same fixed-label rule a log line and a kind's catalog hold (#2245).
29
+ // The same fixed-label rule a log line and a driver's catalog hold (#2245).
30
30
  operation: storeOperationName,
31
31
  input: z.unknown().optional(),
32
32
  })
@@ -1 +1 @@
1
- {"version":3,"file":"scope-store-transport.js","sourceRoot":"","sources":["../src/scope-store-transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAE5E;;;;;;;;;GASG;AAEH,gEAAgE;AAChE,MAAM,CAAC,MAAM,eAAe,GAAG,yBAAyB,CAAC;AAEzD,8FAA8F;AAC9F,MAAM,CAAC,MAAM,cAAc,GAAG,WAAW,eAAe,SAAS,CAAC;AAElE,kFAAkF;AAClF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,QAAgB,EAAW,EAAE,CAC3D,QAAQ,CAAC,WAAW,EAAE,KAAK,eAAe,CAAC;AAE7C;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC;KAC9B,MAAM,CAAC;IACN,OAAO;IACP,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC;IAC9C,0EAA0E;IAC1E,SAAS,EAAE,kBAAkB;IAC7B,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAC9B,CAAC;KACD,MAAM,EAAE,CAAC;AAGZ,wFAAwF;AACxF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;AAGhE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAS,yBAAyB,CAAC,CAAC;AAE5D,uFAAuF;AACvF,MAAM,UAAU,mBAAmB,CAAC,SAAiB,EAAE,QAA2B;IAChF,IAAI,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;QAAE,OAAO,QAAQ,KAAK,UAAU,CAAC;IAC5D,OAAO,QAAQ,KAAK,QAAQ,CAAC;AAC/B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CAAC,UAAyB,EAAE,SAAiB;IAClF,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC7C,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAC1C,OAAO,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3D,CAAC"}
1
+ {"version":3,"file":"scope-store-transport.js","sourceRoot":"","sources":["../src/scope-store-transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAE5E;;;;;;;;;GASG;AAEH,gEAAgE;AAChE,MAAM,CAAC,MAAM,eAAe,GAAG,yBAAyB,CAAC;AAEzD,8FAA8F;AAC9F,MAAM,CAAC,MAAM,cAAc,GAAG,WAAW,eAAe,SAAS,CAAC;AAElE,kFAAkF;AAClF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,QAAgB,EAAW,EAAE,CAC3D,QAAQ,CAAC,WAAW,EAAE,KAAK,eAAe,CAAC;AAE7C;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC;KAC9B,MAAM,CAAC;IACN,OAAO;IACP,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC;IAC9C,4EAA4E;IAC5E,SAAS,EAAE,kBAAkB;IAC7B,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAC9B,CAAC;KACD,MAAM,EAAE,CAAC;AAGZ,wFAAwF;AACxF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;AAGhE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAS,yBAAyB,CAAC,CAAC;AAE5D,uFAAuF;AACvF,MAAM,UAAU,mBAAmB,CAAC,SAAiB,EAAE,QAA2B;IAChF,IAAI,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;QAAE,OAAO,QAAQ,KAAK,UAAU,CAAC;IAC5D,OAAO,QAAQ,KAAK,QAAQ,CAAC;AAC/B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CAAC,UAAyB,EAAE,SAAiB;IAClF,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC7C,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAC1C,OAAO,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3D,CAAC"}
@@ -29,22 +29,33 @@ export declare function verticalScriptStem(slug: string): string;
29
29
  * prefix or starts with it, which covers its stable, jurisdictional and per-version scripts.
30
30
  */
31
31
  export declare const SCOPE_STORE_SCRIPT_PREFIX = "substrat-store-";
32
- /** A store kind id (L20). No `-` and no `_`, which is what keeps {@link scopeStoreScriptName} injective. */
33
- export declare const STORE_KIND_ID: RegExp;
32
+ /** A store driver id (L20). No `-` and no `_`, which is what keeps {@link scopeStoreScriptName} injective. */
33
+ export declare const STORE_DRIVER_ID: RegExp;
34
34
  /**
35
- * The script a scope-store kind is uploaded as, for one vertical (#2210).
35
+ * The script a scope-store driver is uploaded as, for one vertical (#2210).
36
36
  *
37
- * Stable across releases and across the vertical's own pushes: a new release of the kind
37
+ * Stable across releases and across the vertical's own pushes: a new release of the driver
38
38
  * replaces this script in place, and the objects stay where `scopeStoreObjectName` addresses
39
39
  * them, since that carries no version either.
40
40
  *
41
- * Injective over (kind, vertical) (L20): `substrat-store-<kind>-<vertical>`, with the `/` of a
42
- * `<tenant>/<name>` slug written as `_`. A slug never contains `_` and a kind never contains `-`,
43
- * so the kind ends at the first `-` after the prefix and the rest maps back to exactly one slug.
41
+ * Injective over (driver, vertical) (L20): `substrat-store-<driver>-<vertical>`, with the `/` of a
42
+ * `<tenant>/<name>` slug written as `_`. A slug never contains `_` and a driver never contains `-`,
43
+ * so the driver ends at the first `-` after the prefix and the rest maps back to exactly one slug.
44
44
  * A vertical's own stem flattens `/` to `-`, which is not injective; this name does not reuse it.
45
45
  * Anything outside those two grammars is refused rather than flattened.
46
46
  */
47
- export declare function scopeStoreScriptName(vertical: string, kind: string): string;
47
+ export declare function scopeStoreScriptName(vertical: string, driver: string): string;
48
+ /**
49
+ * The vertical segment of the platform's canary script and objects (D-63, #2300). It starts with
50
+ * `-`, which no vertical slug does, so no vertical's store script or store object is named with it.
51
+ */
52
+ export declare const SCOPE_STORE_CANARY = "-canary";
53
+ /**
54
+ * The script a driver's release is canaried in before any vertical runs it (D-63, #2300): the
55
+ * platform's own, `substrat-store-<driver>--canary`. {@link scopeStoreScriptName} cannot produce it,
56
+ * because the part after the driver would be a slug starting with `-`.
57
+ */
58
+ export declare function scopeStoreCanaryScriptName(driver: string): string;
48
59
  /**
49
60
  * The platform script name a vertical with this slug would deploy under, or `null`. Checks the
50
61
  * stable script and its jurisdictional variants. A per-version script ends in a 26-character
@@ -1 +1 @@
1
- {"version":3,"file":"script-names.d.ts","sourceRoot":"","sources":["../src/script-names.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,iFAAiF;AACjF,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAAgD,CAAC;AAElG,uEAAuE;AACvE,eAAO,MAAM,qBAAqB,EAAE,WAAW,CAAC,MAAM,CAapD,CAAC;AAKH;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,oBAAoB,CAAC;AAE3D,4GAA4G;AAC5G,eAAO,MAAM,aAAa,QAAgB,CAAC;AAK3C;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ3E;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOnE;AAED,wFAAwF;AACxF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE7E"}
1
+ {"version":3,"file":"script-names.d.ts","sourceRoot":"","sources":["../src/script-names.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,iFAAiF;AACjF,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAAgD,CAAC;AAElG,uEAAuE;AACvE,eAAO,MAAM,qBAAqB,EAAE,WAAW,CAAC,MAAM,CAapD,CAAC;AAKH;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,oBAAoB,CAAC;AAE3D,8GAA8G;AAC9G,eAAO,MAAM,eAAe,QAAgB,CAAC;AAK7C;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAQ7E;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAE5C;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKjE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOnE;AAED,wFAAwF;AACxF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE7E"}
@@ -46,31 +46,47 @@ export function verticalScriptStem(slug) {
46
46
  * prefix or starts with it, which covers its stable, jurisdictional and per-version scripts.
47
47
  */
48
48
  export const SCOPE_STORE_SCRIPT_PREFIX = 'substrat-store-';
49
- /** A store kind id (L20). No `-` and no `_`, which is what keeps {@link scopeStoreScriptName} injective. */
50
- export const STORE_KIND_ID = /^[a-z0-9]+$/;
49
+ /** A store driver id (L20). No `-` and no `_`, which is what keeps {@link scopeStoreScriptName} injective. */
50
+ export const STORE_DRIVER_ID = /^[a-z0-9]+$/;
51
51
  /** The registry id grammar `verticalSlug` parses (ids.ts), repeated so this file imports nothing. */
52
52
  const VERTICAL_SLUG = /^([a-z0-9](?:[a-z0-9-]*[a-z0-9])?\/)?[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
53
53
  /**
54
- * The script a scope-store kind is uploaded as, for one vertical (#2210).
54
+ * The script a scope-store driver is uploaded as, for one vertical (#2210).
55
55
  *
56
- * Stable across releases and across the vertical's own pushes: a new release of the kind
56
+ * Stable across releases and across the vertical's own pushes: a new release of the driver
57
57
  * replaces this script in place, and the objects stay where `scopeStoreObjectName` addresses
58
58
  * them, since that carries no version either.
59
59
  *
60
- * Injective over (kind, vertical) (L20): `substrat-store-<kind>-<vertical>`, with the `/` of a
61
- * `<tenant>/<name>` slug written as `_`. A slug never contains `_` and a kind never contains `-`,
62
- * so the kind ends at the first `-` after the prefix and the rest maps back to exactly one slug.
60
+ * Injective over (driver, vertical) (L20): `substrat-store-<driver>-<vertical>`, with the `/` of a
61
+ * `<tenant>/<name>` slug written as `_`. A slug never contains `_` and a driver never contains `-`,
62
+ * so the driver ends at the first `-` after the prefix and the rest maps back to exactly one slug.
63
63
  * A vertical's own stem flattens `/` to `-`, which is not injective; this name does not reuse it.
64
64
  * Anything outside those two grammars is refused rather than flattened.
65
65
  */
66
- export function scopeStoreScriptName(vertical, kind) {
67
- if (!STORE_KIND_ID.test(kind)) {
68
- throw new Error(`not a scope-store kind id: '${kind}' (expected [a-z0-9]+)`);
66
+ export function scopeStoreScriptName(vertical, driver) {
67
+ if (!STORE_DRIVER_ID.test(driver)) {
68
+ throw new Error(`not a scope-store driver id: '${driver}' (expected [a-z0-9]+)`);
69
69
  }
70
70
  if (!VERTICAL_SLUG.test(vertical)) {
71
71
  throw new Error(`not a vertical slug: '${vertical}'`);
72
72
  }
73
- return `${SCOPE_STORE_SCRIPT_PREFIX}${kind}-${vertical.replace('/', '_')}`;
73
+ return `${SCOPE_STORE_SCRIPT_PREFIX}${driver}-${vertical.replace('/', '_')}`;
74
+ }
75
+ /**
76
+ * The vertical segment of the platform's canary script and objects (D-63, #2300). It starts with
77
+ * `-`, which no vertical slug does, so no vertical's store script or store object is named with it.
78
+ */
79
+ export const SCOPE_STORE_CANARY = '-canary';
80
+ /**
81
+ * The script a driver's release is canaried in before any vertical runs it (D-63, #2300): the
82
+ * platform's own, `substrat-store-<driver>--canary`. {@link scopeStoreScriptName} cannot produce it,
83
+ * because the part after the driver would be a slug starting with `-`.
84
+ */
85
+ export function scopeStoreCanaryScriptName(driver) {
86
+ if (!STORE_DRIVER_ID.test(driver)) {
87
+ throw new Error(`not a scope-store driver id: '${driver}' (expected [a-z0-9]+)`);
88
+ }
89
+ return `${SCOPE_STORE_SCRIPT_PREFIX}${driver}-${SCOPE_STORE_CANARY}`;
74
90
  }
75
91
  /**
76
92
  * The platform script name a vertical with this slug would deploy under, or `null`. Checks the
@@ -1 +1 @@
1
- {"version":3,"file":"script-names.js","sourceRoot":"","sources":["../src/script-names.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,iFAAiF;AACjF,MAAM,CAAC,MAAM,mBAAmB,GAAsB,CAAC,iBAAiB,EAAE,sBAAsB,CAAC,CAAC;AAElG,uEAAuE;AACvE,MAAM,CAAC,MAAM,qBAAqB,GAAwB,IAAI,GAAG,CAAC;IAChE,GAAG,mBAAmB;IACtB,sBAAsB;IACtB,kBAAkB;IAClB,wBAAwB;IACxB,6BAA6B;IAC7B,oBAAoB;IACpB,yBAAyB;IACzB,eAAe;IACf,uBAAuB;IACvB,4BAA4B;IAC5B,0BAA0B;IAC1B,+BAA+B;CAChC,CAAC,CAAC;AAEH,sGAAsG;AACtG,MAAM,qBAAqB,GAAG,CAAC,IAAI,EAAE,IAAI,CAAU,CAAC;AAEpD;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;AAClF,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,iBAAiB,CAAC;AAE3D,4GAA4G;AAC5G,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAC;AAE3C,qGAAqG;AACrG,MAAM,aAAa,GAAG,uEAAuE,CAAC;AAE9F;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAgB,EAAE,IAAY;IACjE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,wBAAwB,CAAC,CAAC;IAC/E,CAAC;IACD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,yBAAyB,QAAQ,GAAG,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,GAAG,yBAAyB,GAAG,IAAI,IAAI,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;AAC7E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,yBAAyB,CAAC;QAAE,OAAO,IAAI,CAAC;IAClE,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAC/E,IAAI,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IACnD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,qBAAqB,CAAC,IAAY,EAAE,SAAiB;IACnE,OAAO,kBAAkB,IAAI,yBAAyB,SAAS,iDAAiD,CAAC;AACnH,CAAC"}
1
+ {"version":3,"file":"script-names.js","sourceRoot":"","sources":["../src/script-names.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,iFAAiF;AACjF,MAAM,CAAC,MAAM,mBAAmB,GAAsB,CAAC,iBAAiB,EAAE,sBAAsB,CAAC,CAAC;AAElG,uEAAuE;AACvE,MAAM,CAAC,MAAM,qBAAqB,GAAwB,IAAI,GAAG,CAAC;IAChE,GAAG,mBAAmB;IACtB,sBAAsB;IACtB,kBAAkB;IAClB,wBAAwB;IACxB,6BAA6B;IAC7B,oBAAoB;IACpB,yBAAyB;IACzB,eAAe;IACf,uBAAuB;IACvB,4BAA4B;IAC5B,0BAA0B;IAC1B,+BAA+B;CAChC,CAAC,CAAC;AAEH,sGAAsG;AACtG,MAAM,qBAAqB,GAAG,CAAC,IAAI,EAAE,IAAI,CAAU,CAAC;AAEpD;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;AAClF,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,iBAAiB,CAAC;AAE3D,8GAA8G;AAC9G,MAAM,CAAC,MAAM,eAAe,GAAG,aAAa,CAAC;AAE7C,qGAAqG;AACrG,MAAM,aAAa,GAAG,uEAAuE,CAAC;AAE9F;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAgB,EAAE,MAAc;IACnE,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,iCAAiC,MAAM,wBAAwB,CAAC,CAAC;IACnF,CAAC;IACD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,yBAAyB,QAAQ,GAAG,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,GAAG,yBAAyB,GAAG,MAAM,IAAI,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;AAC/E,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,SAAS,CAAC;AAE5C;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CAAC,MAAc;IACvD,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,iCAAiC,MAAM,wBAAwB,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,GAAG,yBAAyB,GAAG,MAAM,IAAI,kBAAkB,EAAE,CAAC;AACvE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,yBAAyB,CAAC;QAAE,OAAO,IAAI,CAAC;IAClE,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAC/E,IAAI,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IACnD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,qBAAqB,CAAC,IAAY,EAAE,SAAiB;IACnE,OAAO,kBAAkB,IAAI,yBAAyB,SAAS,iDAAiD,CAAC;AACnH,CAAC"}
@@ -22,6 +22,13 @@ export interface SqlToken {
22
22
  readonly text: string;
23
23
  /** A quoted identifier or string literal — never read as a keyword. */
24
24
  readonly quoted: boolean;
25
+ /**
26
+ * The name's parts as SQLite reads them, each unquoted: `main.n` and `"main"."n"` are
27
+ * `['main', 'n']`, a schema and a name; `"main.n"` is `['main.n']`, ONE identifier that holds a
28
+ * dot. `text` joins them and cannot tell the two apart, so a reader deciding which schema a name
29
+ * is in reads this. Absent on punctuation.
30
+ */
31
+ readonly parts?: readonly string[];
25
32
  /**
26
33
  * One of `( ) , = ;`, present only when asked for (`{ punctuation: true }`). A reader that
27
34
  * has to know WHERE in a statement a name sits — an assignment target, a column list — needs
@@ -1 +1 @@
1
- {"version":3,"file":"sql-tokens.d.ts","sourceRoot":"","sources":["../src/sql-tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,YAAY,cAAc,CAAC;AAExC,MAAM,WAAW,QAAQ;IACvB,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;CACvB;AAID,4FAA4F;AAC5F,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,QAAQ,EAAE,CAsGjG;AAED,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAEtD;AAED,gGAAgG;AAChG,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,GAAG,MAAM,EAAE,CAOxE"}
1
+ {"version":3,"file":"sql-tokens.d.ts","sourceRoot":"","sources":["../src/sql-tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,YAAY,cAAc,CAAC;AAExC,MAAM,WAAW,QAAQ;IACvB,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;CACvB;AAID,4FAA4F;AAC5F,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,QAAQ,EAAE,CAsGjG;AAED,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAEtD;AAED,gGAAgG;AAChG,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,GAAG,MAAM,EAAE,CAOxE"}