@substrat-run/control-plane-api 0.147.0 → 0.148.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 (57) hide show
  1. package/dist/api.d.ts +56 -1
  2. package/dist/api.d.ts.map +1 -1
  3. package/dist/api.js +801 -379
  4. package/dist/api.js.map +1 -1
  5. package/dist/deploy.d.ts +4 -3
  6. package/dist/deploy.d.ts.map +1 -1
  7. package/dist/deploy.js +3 -3
  8. package/dist/deploy.js.map +1 -1
  9. package/dist/errors.d.ts +19 -1
  10. package/dist/errors.d.ts.map +1 -1
  11. package/dist/errors.js +18 -4
  12. package/dist/errors.js.map +1 -1
  13. package/dist/index.d.ts +10 -2
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +6 -2
  16. package/dist/index.js.map +1 -1
  17. package/dist/lake-gateway.d.ts +54 -0
  18. package/dist/lake-gateway.d.ts.map +1 -0
  19. package/dist/lake-gateway.js +158 -0
  20. package/dist/lake-gateway.js.map +1 -0
  21. package/dist/platform-entry.generated.d.ts +1 -1
  22. package/dist/platform-entry.generated.d.ts.map +1 -1
  23. package/dist/platform-entry.generated.js +2 -2
  24. package/dist/platform-entry.generated.js.map +1 -1
  25. package/dist/platform-scope-stores.d.ts +59 -6
  26. package/dist/platform-scope-stores.d.ts.map +1 -1
  27. package/dist/platform-scope-stores.js +117 -16
  28. package/dist/platform-scope-stores.js.map +1 -1
  29. package/dist/r2-sql-engine.d.ts +50 -0
  30. package/dist/r2-sql-engine.d.ts.map +1 -0
  31. package/dist/r2-sql-engine.js +126 -0
  32. package/dist/r2-sql-engine.js.map +1 -0
  33. package/dist/scope-copy-cleanup.d.ts +12 -0
  34. package/dist/scope-copy-cleanup.d.ts.map +1 -1
  35. package/dist/scope-copy-cleanup.js +14 -3
  36. package/dist/scope-copy-cleanup.js.map +1 -1
  37. package/dist/store-entry.d.ts +90 -0
  38. package/dist/store-entry.d.ts.map +1 -0
  39. package/dist/store-entry.generated.d.ts +60 -0
  40. package/dist/store-entry.generated.d.ts.map +1 -0
  41. package/dist/store-entry.generated.js +62 -0
  42. package/dist/store-entry.generated.js.map +1 -0
  43. package/dist/store-entry.js +178 -0
  44. package/dist/store-entry.js.map +1 -0
  45. package/dist/store-releases.d.ts +147 -0
  46. package/dist/store-releases.d.ts.map +1 -0
  47. package/dist/store-releases.js +298 -0
  48. package/dist/store-releases.js.map +1 -0
  49. package/dist/store-script.d.ts +80 -0
  50. package/dist/store-script.d.ts.map +1 -0
  51. package/dist/store-script.js +173 -0
  52. package/dist/store-script.js.map +1 -0
  53. package/dist/vertical-client.d.ts +4 -0
  54. package/dist/vertical-client.d.ts.map +1 -1
  55. package/dist/vertical-client.js +10 -1
  56. package/dist/vertical-client.js.map +1 -1
  57. package/package.json +7 -7
@@ -9,8 +9,8 @@
9
9
  export const PLATFORM_ENTRY_MODULE = 'substrat-platform-entry.js';
10
10
  /** The import specifier the uploader replaces with `./<the bundle's entry>`. */
11
11
  export const PLATFORM_ENTRY_PLACEHOLDER = '__SUBSTRAT_VERTICAL_ENTRY__';
12
- /** The entry itself — 12744 bytes of ESM. */
13
- export const PLATFORM_ENTRY_SOURCE = "// substrat-platform-entry.ts\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\n// packages/contracts/dist/invocation-record.js\nvar INVOCATION_RECORD_HEADER = \"x-substrat-invocation-record\";\nvar REQUEST_ID_HEADER = \"x-substrat-request-id\";\nvar INVOCATION_RECORD_FIELD_MAX = 128;\nvar FIELDS = [\"operation\", \"problemCode\", \"principalKind\"];\nfunction encodeInvocationRecord(record) {\n const params = new URLSearchParams();\n for (const key of FIELDS) {\n const v = record[key];\n if (typeof v === \"string\" && v !== \"\")\n params.set(key, v.slice(0, INVOCATION_RECORD_FIELD_MAX));\n }\n const value = params.toString();\n return value === \"\" ? null : value;\n}\nvar FIELD_COVERAGE_HEADER = \"x-substrat-field-coverage\";\nfunction invocationLevelOf(status, threw, problemCode) {\n if (threw || status === null || status >= 500)\n return \"error\";\n if (status >= 400)\n return \"warn\";\n if (problemCode)\n return \"warn\";\n return \"info\";\n}\n\n// packages/kernel/dist/invocation-line.js\nfunction invocationLine(f) {\n const emitted = f.emitted;\n return {\n substrat: \"invocation\",\n ...f.kind ? { kind: f.kind } : {},\n tenantId: f.tenantId,\n scopeId: f.scopeId,\n vertical: f.vertical ?? null,\n surface: f.surface ?? null,\n method: f.method ?? null,\n path: f.path ?? null,\n status: f.status ?? null,\n threw: f.threw,\n durationMs: f.durationMs,\n invocationId: f.invocationId,\n level: f.level,\n operation: f.operation ?? null,\n problemCode: f.problemCode ?? null,\n principalKind: f.principalKind ?? null,\n eventCount: emitted ? emitted.total : null,\n eventTypes: emitted ? distinct(emitted.events.map((e) => e.type)) : [],\n entities: emitted && f.withEntities !== false ? distinct(emitted.events.map((e) => e.entity)) : [],\n versionId: f.versionId ?? null,\n ...f.outputFields ? { outputFields: f.outputFields, ...f.fieldCoverageId ? { fieldCoverageId: f.fieldCoverageId } : {} } : {},\n ...f.storeCalls && f.storeCalls.length > 0 ? { storeCalls: f.storeCalls } : {},\n ...f.storeCallsDropped ? { storeCallsDropped: f.storeCallsDropped } : {},\n ...f.async ?? {}\n };\n}\nvar STORE_CALL_LOG_CAP = 16;\nfunction tallyStoreCall(tally, call) {\n const calls = tally.storeCalls ?? (tally.storeCalls = []);\n if (calls.length < STORE_CALL_LOG_CAP) {\n calls.push({ binding: call.binding, operation: call.operation, outcome: call.outcome, durationMs: call.durationMs });\n } else {\n tally.storeCallsDropped = (tally.storeCallsDropped ?? 0) + 1;\n }\n}\nvar STORE_CALL_SINK_KEY = \"substrat.store-call-sink\";\nfunction distinct(values) {\n return [...new Set(values)];\n}\n\n// packages/kernel/dist/ulid.js\nvar B32 = \"0123456789ABCDEFGHJKMNPQRSTVWXYZ\";\nvar MAX_ULID_TIME = 2 ** 48 - 1;\nvar ULID_SHAPE = /^[0-9A-HJKMNP-TV-Z]{26}$/;\nvar unencodable = (t) => `not an encodable ULID instant: ${t} (want 0..${MAX_ULID_TIME})`;\nfunction encodeTime(time) {\n let ts = \"\";\n let t = time;\n for (let i = 0; i < 10; i++) {\n ts = B32[t % 32] + ts;\n t = Math.floor(t / 32);\n }\n return ts;\n}\nfunction createUlid() {\n let lastTime = -1;\n const lastRand = new Array(16).fill(0);\n function freshRandom() {\n const bytes = crypto.getRandomValues(new Uint8Array(16));\n for (let i = 0; i < 16; i++)\n lastRand[i] = bytes[i] % 32;\n }\n function incrementRandom() {\n for (let i = 15; i >= 0; i--) {\n if (lastRand[i] < 31) {\n lastRand[i]++;\n return true;\n }\n lastRand[i] = 0;\n }\n return false;\n }\n const mint = ((now = Date.now()) => {\n if (!Number.isSafeInteger(now))\n throw new RangeError(unencodable(now));\n let time = now;\n if (time <= lastTime) {\n time = lastTime;\n if (!incrementRandom()) {\n time = lastTime + 1;\n freshRandom();\n }\n } else {\n freshRandom();\n }\n if (time < 0 || time > MAX_ULID_TIME)\n throw new RangeError(unencodable(time));\n lastTime = time;\n let r = \"\";\n for (const d of lastRand)\n r += B32[d];\n return encodeTime(time) + r;\n });\n mint.seedFrom = (id) => {\n const time = ulidTime(id);\n if (time < lastTime)\n return;\n const rand = [];\n for (const ch of id.slice(10))\n rand.push(B32.indexOf(ch));\n if (time === lastTime) {\n let ahead = false;\n for (let i = 0; i < 16; i++) {\n if (rand[i] !== lastRand[i]) {\n ahead = rand[i] > lastRand[i];\n break;\n }\n }\n if (!ahead)\n return;\n }\n lastTime = time;\n for (let i = 0; i < 16; i++)\n lastRand[i] = rand[i];\n };\n return mint;\n}\nvar processUlid = createUlid();\nfunction ulid(now = Date.now()) {\n return processUlid(now);\n}\nfunction ulidTime(id) {\n if (!ULID_SHAPE.test(id))\n throw new Error(`not a ULID: ${id}`);\n let t = 0;\n for (const ch of id.slice(0, 10))\n t = t * 32 + B32.indexOf(ch);\n if (t > MAX_ULID_TIME)\n throw new Error(`not a ULID: ${id}`);\n return t;\n}\n\n// packages/contracts/dist/wire-auth.js\nfunction secretMatches(presented, expected) {\n const given = presented ?? \"\";\n let diff = given.length ^ expected.length | (given.length === 0 ? 1 : 0);\n for (let i = 0; i < expected.length; i++) {\n diff |= (i < given.length ? given.charCodeAt(i) : 0) ^ expected.charCodeAt(i);\n }\n return diff === 0;\n}\n\n// packages/vertical-host/src/routed-node.ts\nvar ROUTED_ID = /^[0-9A-HJKMNP-TV-Z]{26}$/;\nvar RouterAssertionError = class extends Error {\n};\nfunction readRoutedNode(headers, options = {}) {\n const rawTenant = headers.get(\"x-substrat-tenant\");\n const rawScope = headers.get(\"x-substrat-scope\");\n if (!rawTenant && !rawScope) return null;\n const { expectedSecret, allowUnsigned = false } = options;\n if (expectedSecret) {\n if (!secretMatches(headers.get(\"x-substrat-router\"), expectedSecret)) {\n throw new RouterAssertionError(\"router assertion is not signed by a known router\");\n }\n } else if (!allowUnsigned) {\n throw new RouterAssertionError(\n \"router assertion cannot be verified: this worker has no ROUTER_SECRET configured\"\n );\n }\n if (!rawTenant || !rawScope) {\n throw new RouterAssertionError(\"router assertion is incomplete\");\n }\n if (!ROUTED_ID.test(rawTenant) || !ROUTED_ID.test(rawScope)) {\n throw new RouterAssertionError(\"router assertion carries a malformed id\");\n }\n return {\n tenantId: rawTenant,\n scopeId: rawScope,\n surface: headers.get(\"x-substrat-surface\") ?? \"app\",\n verticalSlug: headers.get(\"x-substrat-vertical\")\n };\n}\n\n// packages/vertical-host/src/invocation-log.ts\nfunction builtinAsyncLocalStorage() {\n try {\n const proc = globalThis.process;\n const mod = proc?.getBuiltinModule?.(\"node:async_hooks\");\n return typeof mod?.AsyncLocalStorage === \"function\" ? mod.AsyncLocalStorage : void 0;\n } catch {\n return void 0;\n }\n}\nfunction storeCallSlot(provided) {\n try {\n const g = globalThis;\n const key = Symbol.for(STORE_CALL_SINK_KEY);\n const existing = g[key];\n if (typeof existing?.run === \"function\" && typeof existing.current === \"function\") return existing;\n const Als = provided ?? builtinAsyncLocalStorage();\n if (!Als) return void 0;\n const storage = new Als();\n const slot = {\n current() {\n const tally = storage.getStore();\n return tally ? (call) => tallyStoreCall(tally, call) : void 0;\n },\n run: (tally, fn) => storage.run(tally, fn)\n };\n g[key] = slot;\n return slot;\n } catch {\n return void 0;\n }\n}\nfunction runRecordingStoreCalls(record, provided, fn) {\n const slot = storeCallSlot(provided);\n return slot ? slot.run(record, fn) : fn();\n}\nfunction versionIdOf(env) {\n const v = env?.SUBSTRAT_VERSION_ID;\n return typeof v === \"string\" && v.length > 0 ? v : null;\n}\nfunction pathOf(url) {\n try {\n return new URL(url).pathname;\n } catch {\n return \"/\";\n }\n}\nvar STAMPS = /* @__PURE__ */ Symbol.for(\"substrat.invocation-stamp\");\nfunction stamps() {\n const g = globalThis;\n return g[STAMPS] ??= /* @__PURE__ */ new WeakMap();\n}\nfunction invocationStampOf(request) {\n return stamps().get(request);\n}\nfunction withRequestId(response, id) {\n const headers = response?.headers;\n try {\n headers?.set?.(REQUEST_ID_HEADER, id);\n return response;\n } catch {\n }\n try {\n const r = response;\n if (r.status === 101) return response;\n const copy = new Response(r.body, r);\n copy.headers.set(REQUEST_ID_HEADER, id);\n return copy;\n } catch {\n return response;\n }\n}\nfunction beginStamp(request, env, options) {\n const stamp = { invocationId: ulid(), record: {} };\n const fieldCoverageId = armedFieldCoverageId(request.headers, env, options);\n if (fieldCoverageId) stamp.fieldCoverageId = fieldCoverageId;\n stamps().set(request, stamp);\n return stamp;\n}\nfunction armedFieldCoverageId(headers, env, options) {\n let id;\n try {\n id = headers.get(FIELD_COVERAGE_HEADER);\n } catch {\n return void 0;\n }\n if (id === null || !ROUTED_ID.test(id)) return void 0;\n return routedNodeOrNull(headers, env, options) !== null ? id : void 0;\n}\nfunction writeInvocationLine(stamp, done, options) {\n try {\n writeLineOrThrow(stamp, done, options);\n } catch (e) {\n try {\n console.log(JSON.stringify({ substrat: \"invocation-log-fault\", detail: String(e) }));\n } catch {\n }\n }\n}\nfunction writeLineOrThrow(stamp, done, options) {\n const node = routedNodeOrNull(done.request.headers, done.env, options);\n if (!node) return;\n const { record, invocationId } = stamp;\n const line = invocationLine({\n tenantId: node.tenantId,\n scopeId: node.scopeId,\n vertical: node.verticalSlug,\n surface: node.surface,\n method: done.request.method,\n path: pathOf(done.request.url),\n status: done.status,\n threw: done.threw,\n durationMs: Date.now() - done.started,\n invocationId,\n level: invocationLevelOf(done.status, done.threw, record.problemCode),\n operation: record.operation,\n problemCode: record.problemCode,\n principalKind: record.principalKind,\n ...record.emitted ? { emitted: record.emitted } : {},\n versionId: versionIdOf(done.env),\n ...record.outputFields ? { outputFields: record.outputFields } : {},\n ...stamp.fieldCoverageId ? { fieldCoverageId: stamp.fieldCoverageId } : {},\n ...record.storeCalls && record.storeCalls.length > 0 ? { storeCalls: record.storeCalls } : {},\n ...record.storeCallsDropped ? { storeCallsDropped: record.storeCallsDropped } : {}\n });\n console.log(JSON.stringify(line));\n}\nvar OTHER_HANDLERS = [\"scheduled\", \"queue\", \"email\", \"tail\", \"trace\", \"alarm\", \"test\"];\nfunction withInvocationLog(worker, options = {}) {\n const inner = worker?.fetch;\n if (typeof inner !== \"function\") return worker;\n const wrapped = {\n async fetch(request, env, ctx) {\n if (invocationStampOf(request)) return inner.call(worker, request, env, ctx);\n const started = Date.now();\n const stamp = beginStamp(request, env, options);\n let status = null;\n let threw = false;\n try {\n const response = withRequestId(\n await runRecordingStoreCalls(stamp.record, options.asyncLocalStorage, () => inner.call(worker, request, env, ctx)),\n stamp.invocationId\n );\n status = response.status;\n handRecordToRouter(response, stamp.record, request, env, options);\n return response;\n } catch (e) {\n threw = true;\n throw e;\n } finally {\n writeInvocationLine(stamp, { request, env, status, threw, started }, options);\n }\n }\n };\n for (const name of OTHER_HANDLERS) {\n const h = worker[name];\n if (typeof h === \"function\") wrapped[name] = h.bind(worker);\n }\n return wrapped;\n}\nfunction handRecordToRouter(response, record, request, env, options) {\n try {\n const value = encodeInvocationRecord(record);\n if (value === null || !routedNodeOrNull(request.headers, env, options)) return;\n response.headers?.set?.(\n INVOCATION_RECORD_HEADER,\n value\n );\n } catch {\n }\n}\nfunction routedNodeOrNull(headers, env, options) {\n try {\n return readRoutedNode(headers, {\n expectedSecret: options.routerSecret?.(env),\n allowUnsigned: options.allowUnsigned?.(env) ?? false\n });\n } catch (e) {\n if (!(e instanceof RouterAssertionError)) console.log(JSON.stringify({ substrat: \"invocation-log-fault\", detail: String(e) }));\n return null;\n }\n}\n\n// substrat-platform-entry.ts\nimport * as vertical from \"__SUBSTRAT_VERTICAL_ENTRY__\";\nexport * from \"__SUBSTRAT_VERTICAL_ENTRY__\";\nvar substrat_platform_entry_default = withInvocationLog(vertical.default, {\n routerSecret: (env) => env.ROUTER_SECRET,\n allowUnsigned: (env) => env.ALLOW_DEV_NODE === \"true\",\n asyncLocalStorage: AsyncLocalStorage\n});\nexport {\n substrat_platform_entry_default as default\n};\n";
12
+ /** The entry itself — 12959 bytes of ESM. */
13
+ export const PLATFORM_ENTRY_SOURCE = "// substrat-platform-entry.ts\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\n// packages/contracts/dist/invocation-record.js\nvar INVOCATION_RECORD_HEADER = \"x-substrat-invocation-record\";\nvar REQUEST_ID_HEADER = \"x-substrat-request-id\";\nvar INVOCATION_RECORD_FIELD_MAX = 128;\nvar FIELDS = [\"operation\", \"problemCode\", \"principalKind\"];\nfunction encodeInvocationRecord(record) {\n const params = new URLSearchParams();\n for (const key of FIELDS) {\n const v = record[key];\n if (typeof v === \"string\" && v !== \"\")\n params.set(key, v.slice(0, INVOCATION_RECORD_FIELD_MAX));\n }\n const value = params.toString();\n return value === \"\" ? null : value;\n}\nvar FIELD_COVERAGE_HEADER = \"x-substrat-field-coverage\";\nfunction invocationLevelOf(status, threw, problemCode) {\n if (threw || status === null || status >= 500)\n return \"error\";\n if (status >= 400)\n return \"warn\";\n if (problemCode)\n return \"warn\";\n return \"info\";\n}\n\n// packages/kernel/dist/invocation-line.js\nfunction invocationLine(f) {\n const emitted = f.emitted;\n return {\n substrat: \"invocation\",\n ...f.kind ? { kind: f.kind } : {},\n tenantId: f.tenantId,\n scopeId: f.scopeId,\n vertical: f.vertical ?? null,\n surface: f.surface ?? null,\n method: f.method ?? null,\n path: f.path ?? null,\n status: f.status ?? null,\n threw: f.threw,\n durationMs: f.durationMs,\n invocationId: f.invocationId,\n level: f.level,\n operation: f.operation ?? null,\n problemCode: f.problemCode ?? null,\n principalKind: f.principalKind ?? null,\n eventCount: emitted ? emitted.total : null,\n eventTypes: emitted ? distinct(emitted.events.map((e) => e.type)) : [],\n entities: emitted && f.withEntities !== false ? distinct(emitted.events.map((e) => e.entity)) : [],\n versionId: f.versionId ?? null,\n ...f.outputFields ? { outputFields: f.outputFields, ...f.fieldCoverageId ? { fieldCoverageId: f.fieldCoverageId } : {} } : {},\n ...f.storeCalls && f.storeCalls.length > 0 ? { storeCalls: f.storeCalls } : {},\n ...f.storeCallsDropped ? { storeCallsDropped: f.storeCallsDropped } : {},\n ...f.async ?? {}\n };\n}\nvar STORE_CALL_LOG_CAP = 16;\nfunction tallyStoreCall(tally, call) {\n const calls = tally.storeCalls ?? (tally.storeCalls = []);\n if (calls.length < STORE_CALL_LOG_CAP) {\n calls.push({ binding: call.binding, operation: call.operation, outcome: call.outcome, durationMs: call.durationMs });\n } else {\n tally.storeCallsDropped = (tally.storeCallsDropped ?? 0) + 1;\n }\n}\nvar STORE_CALL_SINK_KEY = \"substrat.store-call-sink\";\nfunction distinct(values) {\n return [...new Set(values)];\n}\n\n// packages/kernel/dist/ulid.js\nvar B32 = \"0123456789ABCDEFGHJKMNPQRSTVWXYZ\";\nvar MAX_ULID_TIME = 2 ** 48 - 1;\nvar ULID_SHAPE = /^[0-9A-HJKMNP-TV-Z]{26}$/;\nvar unencodable = (t) => `not an encodable ULID instant: ${t} (want 0..${MAX_ULID_TIME})`;\nfunction encodeTime(time) {\n let ts = \"\";\n let t = time;\n for (let i = 0; i < 10; i++) {\n ts = B32[t % 32] + ts;\n t = Math.floor(t / 32);\n }\n return ts;\n}\nfunction createUlid() {\n let lastTime = -1;\n const lastRand = new Array(16).fill(0);\n function freshRandom() {\n const bytes = crypto.getRandomValues(new Uint8Array(16));\n for (let i = 0; i < 16; i++)\n lastRand[i] = bytes[i] % 32;\n }\n function incrementRandom() {\n for (let i = 15; i >= 0; i--) {\n if (lastRand[i] < 31) {\n lastRand[i]++;\n return true;\n }\n lastRand[i] = 0;\n }\n return false;\n }\n const mint = ((now = Date.now()) => {\n if (!Number.isSafeInteger(now))\n throw new RangeError(unencodable(now));\n let time = now;\n if (time <= lastTime) {\n time = lastTime;\n if (!incrementRandom()) {\n time = lastTime + 1;\n freshRandom();\n }\n } else {\n freshRandom();\n }\n if (time < 0 || time > MAX_ULID_TIME)\n throw new RangeError(unencodable(time));\n lastTime = time;\n let r = \"\";\n for (const d of lastRand)\n r += B32[d];\n return encodeTime(time) + r;\n });\n mint.seedFrom = (id) => {\n const time = ulidTime(id);\n if (time < lastTime)\n return;\n const rand = [];\n for (const ch of id.slice(10))\n rand.push(B32.indexOf(ch));\n if (time === lastTime) {\n let ahead = false;\n for (let i = 0; i < 16; i++) {\n if (rand[i] !== lastRand[i]) {\n ahead = rand[i] > lastRand[i];\n break;\n }\n }\n if (!ahead)\n return;\n }\n lastTime = time;\n for (let i = 0; i < 16; i++)\n lastRand[i] = rand[i];\n };\n return mint;\n}\nvar processUlid = createUlid();\nfunction ulid(now = Date.now()) {\n return processUlid(now);\n}\nfunction ulidTime(id) {\n if (!ULID_SHAPE.test(id))\n throw new Error(`not a ULID: ${id}`);\n let t = 0;\n for (const ch of id.slice(0, 10))\n t = t * 32 + B32.indexOf(ch);\n if (t > MAX_ULID_TIME)\n throw new Error(`not a ULID: ${id}`);\n return t;\n}\n\n// packages/contracts/dist/wire-auth.js\nfunction secretMatches(presented, expected) {\n const given = presented ?? \"\";\n let diff = given.length ^ expected.length | (given.length === 0 ? 1 : 0);\n for (let i = 0; i < expected.length; i++) {\n diff |= (i < given.length ? given.charCodeAt(i) : 0) ^ expected.charCodeAt(i);\n }\n return diff === 0;\n}\n\n// packages/vertical-host/src/routed-node.ts\nvar ROUTED_ID = /^[0-9A-HJKMNP-TV-Z]{26}$/;\nvar RouterAssertionError = class extends Error {\n};\nfunction readRoutedNode(headers, options = {}) {\n const rawTenant = headers.get(\"x-substrat-tenant\");\n const rawScope = headers.get(\"x-substrat-scope\");\n if (!rawTenant && !rawScope) return null;\n const { expectedSecret, allowUnsigned = false } = options;\n if (expectedSecret) {\n if (!secretMatches(headers.get(\"x-substrat-router\"), expectedSecret)) {\n throw new RouterAssertionError(\"router assertion is not signed by a known router\");\n }\n } else if (!allowUnsigned) {\n throw new RouterAssertionError(\n \"router assertion cannot be verified: this worker has no ROUTER_SECRET configured\"\n );\n }\n if (!rawTenant || !rawScope) {\n throw new RouterAssertionError(\"router assertion is incomplete\");\n }\n if (!ROUTED_ID.test(rawTenant) || !ROUTED_ID.test(rawScope)) {\n throw new RouterAssertionError(\"router assertion carries a malformed id\");\n }\n return {\n tenantId: rawTenant,\n scopeId: rawScope,\n surface: headers.get(\"x-substrat-surface\") ?? \"app\",\n verticalSlug: headers.get(\"x-substrat-vertical\")\n };\n}\n\n// packages/vertical-host/src/invocation-log.ts\nfunction builtinAsyncLocalStorage() {\n try {\n const proc = globalThis.process;\n const mod = proc?.getBuiltinModule?.(\"node:async_hooks\");\n return typeof mod?.AsyncLocalStorage === \"function\" ? mod.AsyncLocalStorage : void 0;\n } catch {\n return void 0;\n }\n}\nfunction storeCallSlot(provided) {\n try {\n const g = globalThis;\n const key = Symbol.for(STORE_CALL_SINK_KEY);\n const existing = g[key];\n if (typeof existing?.run === \"function\" && typeof existing.current === \"function\") return existing;\n const Als = provided ?? builtinAsyncLocalStorage();\n if (!Als) return void 0;\n const storage = new Als();\n const slot = {\n current() {\n const tally = storage.getStore();\n return tally ? (call) => tallyStoreCall(tally, call) : void 0;\n },\n run: (tally, fn) => storage.run(tally, fn)\n };\n g[key] = slot;\n return slot;\n } catch {\n return void 0;\n }\n}\nfunction runRecordingStoreCalls(record, provided, fn) {\n const slot = storeCallSlot(provided);\n return slot ? slot.run(record, fn) : fn();\n}\nfunction versionIdOf(env) {\n const v = env?.SUBSTRAT_VERSION_ID;\n return typeof v === \"string\" && v.length > 0 ? v : null;\n}\nvar UPLOAD_LINK_SECRET_SEGMENT = /^(\\/api\\/attachment-uploads\\/[^/]+\\/[^/]+\\/)[^/]+/;\nvar redactUploadLinkSecret = (pathname) => pathname.replace(UPLOAD_LINK_SECRET_SEGMENT, \"$1[redacted]\");\nfunction pathOf(url) {\n try {\n return redactUploadLinkSecret(new URL(url).pathname);\n } catch {\n return \"/\";\n }\n}\nvar STAMPS = /* @__PURE__ */ Symbol.for(\"substrat.invocation-stamp\");\nfunction stamps() {\n const g = globalThis;\n return g[STAMPS] ??= /* @__PURE__ */ new WeakMap();\n}\nfunction invocationStampOf(request) {\n return stamps().get(request);\n}\nfunction withRequestId(response, id) {\n const headers = response?.headers;\n try {\n headers?.set?.(REQUEST_ID_HEADER, id);\n return response;\n } catch {\n }\n try {\n const r = response;\n if (r.status === 101) return response;\n const copy = new Response(r.body, r);\n copy.headers.set(REQUEST_ID_HEADER, id);\n return copy;\n } catch {\n return response;\n }\n}\nfunction beginStamp(request, env, options) {\n const stamp = { invocationId: ulid(), record: {} };\n const fieldCoverageId = armedFieldCoverageId(request.headers, env, options);\n if (fieldCoverageId) stamp.fieldCoverageId = fieldCoverageId;\n stamps().set(request, stamp);\n return stamp;\n}\nfunction armedFieldCoverageId(headers, env, options) {\n let id;\n try {\n id = headers.get(FIELD_COVERAGE_HEADER);\n } catch {\n return void 0;\n }\n if (id === null || !ROUTED_ID.test(id)) return void 0;\n return routedNodeOrNull(headers, env, options) !== null ? id : void 0;\n}\nfunction writeInvocationLine(stamp, done, options) {\n try {\n writeLineOrThrow(stamp, done, options);\n } catch (e) {\n try {\n console.log(JSON.stringify({ substrat: \"invocation-log-fault\", detail: String(e) }));\n } catch {\n }\n }\n}\nfunction writeLineOrThrow(stamp, done, options) {\n const node = routedNodeOrNull(done.request.headers, done.env, options);\n if (!node) return;\n const { record, invocationId } = stamp;\n const line = invocationLine({\n tenantId: node.tenantId,\n scopeId: node.scopeId,\n vertical: node.verticalSlug,\n surface: node.surface,\n method: done.request.method,\n path: pathOf(done.request.url),\n status: done.status,\n threw: done.threw,\n durationMs: Date.now() - done.started,\n invocationId,\n level: invocationLevelOf(done.status, done.threw, record.problemCode),\n operation: record.operation,\n problemCode: record.problemCode,\n principalKind: record.principalKind,\n ...record.emitted ? { emitted: record.emitted } : {},\n versionId: versionIdOf(done.env),\n ...record.outputFields ? { outputFields: record.outputFields } : {},\n ...stamp.fieldCoverageId ? { fieldCoverageId: stamp.fieldCoverageId } : {},\n ...record.storeCalls && record.storeCalls.length > 0 ? { storeCalls: record.storeCalls } : {},\n ...record.storeCallsDropped ? { storeCallsDropped: record.storeCallsDropped } : {}\n });\n console.log(JSON.stringify(line));\n}\nvar OTHER_HANDLERS = [\"scheduled\", \"queue\", \"email\", \"tail\", \"trace\", \"alarm\", \"test\"];\nfunction withInvocationLog(worker, options = {}) {\n const inner = worker?.fetch;\n if (typeof inner !== \"function\") return worker;\n const wrapped = {\n async fetch(request, env, ctx) {\n if (invocationStampOf(request)) return inner.call(worker, request, env, ctx);\n const started = Date.now();\n const stamp = beginStamp(request, env, options);\n let status = null;\n let threw = false;\n try {\n const response = withRequestId(\n await runRecordingStoreCalls(stamp.record, options.asyncLocalStorage, () => inner.call(worker, request, env, ctx)),\n stamp.invocationId\n );\n status = response.status;\n handRecordToRouter(response, stamp.record, request, env, options);\n return response;\n } catch (e) {\n threw = true;\n throw e;\n } finally {\n writeInvocationLine(stamp, { request, env, status, threw, started }, options);\n }\n }\n };\n for (const name of OTHER_HANDLERS) {\n const h = worker[name];\n if (typeof h === \"function\") wrapped[name] = h.bind(worker);\n }\n return wrapped;\n}\nfunction handRecordToRouter(response, record, request, env, options) {\n try {\n const value = encodeInvocationRecord(record);\n if (value === null || !routedNodeOrNull(request.headers, env, options)) return;\n response.headers?.set?.(\n INVOCATION_RECORD_HEADER,\n value\n );\n } catch {\n }\n}\nfunction routedNodeOrNull(headers, env, options) {\n try {\n return readRoutedNode(headers, {\n expectedSecret: options.routerSecret?.(env),\n allowUnsigned: options.allowUnsigned?.(env) ?? false\n });\n } catch (e) {\n if (!(e instanceof RouterAssertionError)) console.log(JSON.stringify({ substrat: \"invocation-log-fault\", detail: String(e) }));\n return null;\n }\n}\n\n// substrat-platform-entry.ts\nimport * as vertical from \"__SUBSTRAT_VERTICAL_ENTRY__\";\nexport * from \"__SUBSTRAT_VERTICAL_ENTRY__\";\nvar substrat_platform_entry_default = withInvocationLog(vertical.default, {\n routerSecret: (env) => env.ROUTER_SECRET,\n allowUnsigned: (env) => env.ALLOW_DEV_NODE === \"true\",\n asyncLocalStorage: AsyncLocalStorage\n});\nexport {\n substrat_platform_entry_default as default\n};\n";
14
14
  /**
15
15
  * #2245: the entry's `node:async_hooks` import, as it appears in `PLATFORM_ENTRY_SOURCE`, and
16
16
  * the line the uploader puts in its place for a script that can have no `AsyncLocalStorage`
@@ -1 +1 @@
1
- {"version":3,"file":"platform-entry.generated.js","sourceRoot":"","sources":["../src/platform-entry.generated.ts"],"names":[],"mappings":"AAAA,8KAA8K;AAC9K,sEAAsE;AAEtE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,4BAA4B,CAAC;AAElE,gFAAgF;AAChF,MAAM,CAAC,MAAM,0BAA0B,GAAG,6BAA6B,CAAC;AAExE,6CAA6C;AAC7C,MAAM,CAAC,MAAM,qBAAqB,GAAW,i8ZAAi8Z,CAAC;AAE/+Z;;;;;GAKG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,yDAAyD,CAAC;AACnG,MAAM,CAAC,MAAM,2BAA2B,GAAG,sCAAsC,CAAC;AAElF;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,8BAA8B,CAAC;AAEtE,8CAA8C;AAC9C,MAAM,CAAC,MAAM,uBAAuB,GAAW,o0TAAo0T,CAAC"}
1
+ {"version":3,"file":"platform-entry.generated.js","sourceRoot":"","sources":["../src/platform-entry.generated.ts"],"names":[],"mappings":"AAAA,8KAA8K;AAC9K,sEAAsE;AAEtE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,4BAA4B,CAAC;AAElE,gFAAgF;AAChF,MAAM,CAAC,MAAM,0BAA0B,GAAG,6BAA6B,CAAC;AAExE,6CAA6C;AAC7C,MAAM,CAAC,MAAM,qBAAqB,GAAW,iqaAAiqa,CAAC;AAE/sa;;;;;GAKG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,yDAAyD,CAAC;AACnG,MAAM,CAAC,MAAM,2BAA2B,GAAG,sCAAsC,CAAC;AAElF;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,8BAA8B,CAAC;AAEtE,8CAA8C;AAC9C,MAAM,CAAC,MAAM,uBAAuB,GAAW,o0TAAo0T,CAAC"}
@@ -3,11 +3,12 @@ import { type HostAdmin } from '@substrat-run/kernel';
3
3
  /**
4
4
  * A reserved scope-store call, made by the control plane straight at the store
5
5
  * script (#2207). The vertical is not on this path: it holds neither the
6
- * namespace nor the key. The key signs the object name here, and the audience
7
- * is `platform`, which is the only audience a `substrat.*` operation accepts.
6
+ * namespace nor the key. The key signs the envelope here, audience `platform`,
7
+ * which is the only audience a `substrat.*` operation accepts.
8
8
  */
9
9
  export interface PlatformScopeStoreDispatch {
10
- readonly hmacKey: string;
10
+ /** PKCS8 Ed25519 private key, base64url. Signs audience `platform`. */
11
+ readonly platformKey: string;
11
12
  fetch(scriptName: string, request: Request): Promise<Response>;
12
13
  }
13
14
  export interface PlatformScopeStoreTarget {
@@ -71,10 +72,34 @@ export interface PlatformScopeStores {
71
72
  }
72
73
  /** Bindings a version manifest declares. Missing JSON is none. Unreadable JSON fails closed. */
73
74
  export declare function declaredStoresOf(manifestJson: string | null): DeclaredScopeStore[];
75
+ /**
76
+ * The version a scope's deployment runs, read once (#2207, L14). A scope with a serving pin runs
77
+ * the serving pointer's version when the pointer's ref is its pin, and an unknown one otherwise;
78
+ * a scope with no pin runs its bound version. `servingPointer` is the pointer as read, for a scope
79
+ * with a pin: the pair a subject-erasure claim requires to still hold (#2285). A pointer that
80
+ * cannot be read refuses (503): neither the version nor the fence can be named.
81
+ */
82
+ export interface RunningVersion {
83
+ readonly versionId: string | null;
84
+ readonly servingPointer?: {
85
+ ref: string;
86
+ versionId: string;
87
+ } | null;
88
+ }
89
+ export declare function runningVersionOf(admin: Pick<HostAdmin, 'verticalServing'>, actor: PlatformActorId, scope: Pick<Scope, 'vertical' | 'verticalVersionId' | 'servingRef'>): Promise<RunningVersion>;
90
+ /**
91
+ * Stop the router serving a scope, before its stores are wiped (#2285, L6). The router admits a
92
+ * scope only while one of its hostnames is `active`, and it reads that row on every request, so
93
+ * unbinding is immediate. Unbind is idempotent: a retry after a failed wipe finds nothing left
94
+ * to remove. A hostname set merely non-active would not hold — the issuance reconcile heals a
95
+ * platform hostname back to `active`.
96
+ */
97
+ export declare function unrouteScope(admin: Pick<HostAdmin, 'listHostnames' | 'unbindHostname'>, actor: PlatformActorId, scope: Pick<Scope, 'tenantId' | 'id'>): Promise<void>;
74
98
  /**
75
99
  * The scope stores of the version a scope's deployment runs (#2207). A scope on its vertical's
76
100
  * serving pin runs the serving pointer's version, and any other scope its bound version; this
77
- * is the version the router reads a scope's stores from (`READ_ROUTE_SQL`). Provisioning sets the
101
+ * is the version the router reads a scope's stores from (`READ_ROUTE_SQL`), and the one a restore
102
+ * may import into (L8). The lifecycle reaches more: `scopeStoresOf`. Provisioning sets the
78
103
  * serving pin and no bound version, so reading the bound version alone answers "no store" for an
79
104
  * ordinary install whose store the router serves. A pin that names another script than the
80
105
  * pointer's is unknown, as #2242's erasure gate has it.
@@ -83,10 +108,38 @@ export declare function declaredStoresOf(manifestJson: string | null): DeclaredS
83
108
  * answer is none. Otherwise a version that cannot be named, a manifest that cannot be read, or one
84
109
  * the gate says may hold a store without naming it refuses (503), rather than let a backup, a
85
110
  * wipe, a replay or an erasure skip a store that may hold data.
111
+ *
112
+ * `running` is a resolution the caller already holds (`runningVersionOf`), so a caller that fences
113
+ * on the version reads it once and judges the stores against the same read.
86
114
  */
87
- export declare function scopeStoresOf(admin: Pick<HostAdmin, 'verticalServing' | 'versionManifest'>, actor: PlatformActorId, scope: Pick<Scope, 'id' | 'vertical' | 'verticalVersionId' | 'servingRef'>, kinds?: readonly StoreKindRegistration[]): Promise<DeclaredScopeStore[]>;
88
- /** Sign `objectName` and POST the reserved operation at that kind's script. */
115
+ export declare function runningVersionStoresOf(admin: Pick<HostAdmin, 'verticalServing' | 'versionManifest'>, actor: PlatformActorId, scope: Pick<Scope, 'id' | 'vertical' | 'verticalVersionId' | 'servingRef'>, kinds?: readonly StoreKindRegistration[], running?: RunningVersion): Promise<DeclaredScopeStore[]>;
116
+ /**
117
+ * What the lifecycle reaches for a scope (#2286, L17): the running version's stores
118
+ * (`runningVersionStoresOf`, which still fails closed first), and every binding any version of its
119
+ * vertical has declared (`HostAdmin.verticalScopeStores`, read by its keys). Export, wipe, erasure
120
+ * and the meter reach `all`, so an object under a binding a later version dropped is still
121
+ * reached. A restore imports only into `running` (L8).
122
+ *
123
+ * A binding keeps its kind for the life of the vertical, since publish refuses a re-kind; a
124
+ * running version whose kind disagrees with the record, or a record that cannot be read,
125
+ * refuses (503).
126
+ */
127
+ export declare function scopeStoreReachOf(admin: Pick<HostAdmin, 'verticalServing' | 'versionManifest' | 'verticalScopeStores'>, actor: PlatformActorId, scope: Pick<Scope, 'id' | 'vertical' | 'verticalVersionId' | 'servingRef'>, kinds?: readonly StoreKindRegistration[], running?: RunningVersion): Promise<{
128
+ running: DeclaredScopeStore[];
129
+ all: DeclaredScopeStore[];
130
+ }>;
131
+ /** `scopeStoreReachOf`'s `all`: every store the lifecycle reaches for a scope (#2286). */
132
+ export declare function scopeStoresOf(admin: Pick<HostAdmin, 'verticalServing' | 'versionManifest' | 'verticalScopeStores'>, actor: PlatformActorId, scope: Pick<Scope, 'id' | 'vertical' | 'verticalVersionId' | 'servingRef'>, kinds?: readonly StoreKindRegistration[], running?: RunningVersion): Promise<DeclaredScopeStore[]>;
133
+ /** Sign the envelope and POST the reserved operation at that kind's script. */
89
134
  export declare function callPlatformScopeStore(dispatch: PlatformScopeStoreDispatch, target: PlatformScopeStoreTarget, operation: ReservedStoreOperation, input?: unknown): Promise<unknown>;
135
+ /**
136
+ * The same call at a named script and object: the platform's canary (#2300), which no
137
+ * (vertical, scope) names. Its answer is parsed as every reserved answer is.
138
+ */
139
+ export declare function callPlatformScopeStoreAt(dispatch: PlatformScopeStoreDispatch, target: {
140
+ readonly scriptName: string;
141
+ readonly objectName: string;
142
+ }, operation: ReservedStoreOperation, input?: unknown): Promise<unknown>;
90
143
  /** The five reserved operations, one call per declared binding. */
91
144
  export declare function platformScopeStoresFor(dispatch: PlatformScopeStoreDispatch): PlatformScopeStores;
92
145
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"platform-scope-stores.d.ts","sourceRoot":"","sources":["../src/platform-scope-stores.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"platform-scope-stores.d.ts","sourceRoot":"","sources":["../src/platform-scope-stores.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { mayHoldScopeStores, scopeStoresDeclaredIn, STORE_KINDS, scopeStoreObjectName, scopeStoreScriptName, signScopeStoreName, storeEraseResult, storeExportResult, storeSizeResult, StoreError, } from '@substrat-run/contracts';
1
+ import { LIST_PAGE_MAX, mayHoldScopeStores, scopeStoresDeclaredIn, STORE_KINDS, issueScopeStoreEnvelope, SCOPE_STORE_ENVELOPE_HEADER, SCOPE_STORE_SIGNATURE_HEADER, ScopeStoreKeyError, scopeStoreObjectName, scopeStoreScriptName, storeEraseResult, storeExportResult, storeSizeResult, StoreError, } from '@substrat-run/contracts';
2
2
  import { callReservedStoreOperation } from '@substrat-run/kernel';
3
3
  import { ControlPlaneError } from '@substrat-run/control-plane-client';
4
4
  import { storedDeployManifest } from './deploy.js';
@@ -19,10 +19,48 @@ export function declaredStoresOf(manifestJson) {
19
19
  }
20
20
  return parsed.data.scopeStores;
21
21
  }
22
+ export async function runningVersionOf(admin, actor, scope) {
23
+ if (!scope.vertical || !scope.servingRef)
24
+ return { versionId: scope.verticalVersionId };
25
+ let pointer;
26
+ try {
27
+ pointer = await admin.verticalServing(actor, scope.vertical);
28
+ }
29
+ catch {
30
+ throw new ControlPlaneError(503, `the serving pointer of '${scope.vertical}' could not be read`);
31
+ }
32
+ const servingPointer = pointer ? { ref: pointer.ref, versionId: pointer.versionId } : null;
33
+ return { versionId: servingPointer?.ref === scope.servingRef ? servingPointer.versionId : null, servingPointer };
34
+ }
35
+ /**
36
+ * Stop the router serving a scope, before its stores are wiped (#2285, L6). The router admits a
37
+ * scope only while one of its hostnames is `active`, and it reads that row on every request, so
38
+ * unbinding is immediate. Unbind is idempotent: a retry after a failed wipe finds nothing left
39
+ * to remove. A hostname set merely non-active would not hold — the issuance reconcile heals a
40
+ * platform hostname back to `active`.
41
+ */
42
+ export async function unrouteScope(admin, actor, scope) {
43
+ // Every page: an unbind deletes the row, so each read starts again from the first hostname left.
44
+ // A row still listed after its unbind would loop forever, so it refuses instead.
45
+ const unbound = new Set();
46
+ for (;;) {
47
+ const page = await admin.listHostnames(actor, { tenantId: scope.tenantId, scopeId: scope.id, limit: LIST_PAGE_MAX });
48
+ if (page.length === 0)
49
+ return;
50
+ for (const { hostname } of page) {
51
+ if (unbound.has(hostname))
52
+ throw new Error(`hostname '${hostname}' is still bound after its unbind`);
53
+ // Only while the row still names this scope: a name rebound elsewhere since the list stays bound.
54
+ await admin.unbindHostname(actor, hostname, { tenantId: scope.tenantId, scopeId: scope.id });
55
+ unbound.add(hostname);
56
+ }
57
+ }
58
+ }
22
59
  /**
23
60
  * The scope stores of the version a scope's deployment runs (#2207). A scope on its vertical's
24
61
  * serving pin runs the serving pointer's version, and any other scope its bound version; this
25
- * is the version the router reads a scope's stores from (`READ_ROUTE_SQL`). Provisioning sets the
62
+ * is the version the router reads a scope's stores from (`READ_ROUTE_SQL`), and the one a restore
63
+ * may import into (L8). The lifecycle reaches more: `scopeStoresOf`. Provisioning sets the
26
64
  * serving pin and no bound version, so reading the bound version alone answers "no store" for an
27
65
  * ordinary install whose store the router serves. A pin that names another script than the
28
66
  * pointer's is unknown, as #2242's erasure gate has it.
@@ -31,15 +69,14 @@ export function declaredStoresOf(manifestJson) {
31
69
  * answer is none. Otherwise a version that cannot be named, a manifest that cannot be read, or one
32
70
  * the gate says may hold a store without naming it refuses (503), rather than let a backup, a
33
71
  * wipe, a replay or an erasure skip a store that may hold data.
72
+ *
73
+ * `running` is a resolution the caller already holds (`runningVersionOf`), so a caller that fences
74
+ * on the version reads it once and judges the stores against the same read.
34
75
  */
35
- export async function scopeStoresOf(admin, actor, scope, kinds = STORE_KINDS) {
76
+ export async function runningVersionStoresOf(admin, actor, scope, kinds = STORE_KINDS, running) {
36
77
  if (!scope.vertical || !mayHoldScopeStores(undefined, kinds))
37
78
  return [];
38
- let versionId = scope.verticalVersionId;
39
- if (scope.servingRef) {
40
- const pointer = await admin.verticalServing(actor, scope.vertical).catch(() => null);
41
- versionId = pointer?.ref === scope.servingRef ? pointer.versionId : null;
42
- }
79
+ const { versionId } = running ?? await runningVersionOf(admin, actor, scope);
43
80
  const manifestJson = versionId
44
81
  ? await admin.versionManifest(actor, scope.vertical, versionId).catch(() => undefined)
45
82
  : undefined;
@@ -50,29 +87,93 @@ export async function scopeStoresOf(admin, actor, scope, kinds = STORE_KINDS) {
50
87
  return declared;
51
88
  throw new ControlPlaneError(503, `scope ${scope.id} may hold scope stores, and the version it runs cannot say which`);
52
89
  }
90
+ /**
91
+ * What the lifecycle reaches for a scope (#2286, L17): the running version's stores
92
+ * (`runningVersionStoresOf`, which still fails closed first), and every binding any version of its
93
+ * vertical has declared (`HostAdmin.verticalScopeStores`, read by its keys). Export, wipe, erasure
94
+ * and the meter reach `all`, so an object under a binding a later version dropped is still
95
+ * reached. A restore imports only into `running` (L8).
96
+ *
97
+ * A binding keeps its kind for the life of the vertical, since publish refuses a re-kind; a
98
+ * running version whose kind disagrees with the record, or a record that cannot be read,
99
+ * refuses (503).
100
+ */
101
+ export async function scopeStoreReachOf(admin, actor, scope, kinds = STORE_KINDS, running) {
102
+ const current = await runningVersionStoresOf(admin, actor, scope, kinds, running);
103
+ if (!scope.vertical || !mayHoldScopeStores(undefined, kinds))
104
+ return { running: current, all: current };
105
+ let declared;
106
+ try {
107
+ declared = await admin.verticalScopeStores(actor, scope.vertical);
108
+ }
109
+ catch {
110
+ throw new ControlPlaneError(503, `the scope stores '${scope.vertical}' has declared could not be read`);
111
+ }
112
+ const all = new Map(declared.map((store) => [store.binding, store.kind]));
113
+ for (const store of current) {
114
+ const kind = all.get(store.binding);
115
+ if (kind !== undefined && kind !== store.kind) {
116
+ throw new ControlPlaneError(503, `scope store '${store.binding}' is declared as both '${kind}' and '${store.kind}'`);
117
+ }
118
+ all.set(store.binding, store.kind);
119
+ }
120
+ return { running: current, all: [...all].map(([binding, kind]) => ({ binding, kind })) };
121
+ }
122
+ /** `scopeStoreReachOf`'s `all`: every store the lifecycle reaches for a scope (#2286). */
123
+ export async function scopeStoresOf(admin, actor, scope, kinds = STORE_KINDS, running) {
124
+ return (await scopeStoreReachOf(admin, actor, scope, kinds, running)).all;
125
+ }
53
126
  function asControlPlane(error) {
54
127
  if (error instanceof StoreError) {
55
128
  throw new ControlPlaneError(error.storeStatus, error.message);
56
129
  }
57
130
  throw error;
58
131
  }
59
- /** Sign `objectName` and POST the reserved operation at that kind's script. */
132
+ /** Sign the envelope and POST the reserved operation at that kind's script. */
60
133
  export async function callPlatformScopeStore(dispatch, target, operation, input) {
61
- if (!dispatch.hmacKey) {
134
+ return callPlatformScopeStoreAt(dispatch, {
135
+ scriptName: scopeStoreScriptName(target.vertical, target.kind),
136
+ objectName: scopeStoreObjectName(target.tenantId, target.vertical, target.scopeId, target.binding),
137
+ }, operation, input);
138
+ }
139
+ /**
140
+ * The same call at a named script and object: the platform's canary (#2300), which no
141
+ * (vertical, scope) names. Its answer is parsed as every reserved answer is.
142
+ */
143
+ export async function callPlatformScopeStoreAt(dispatch, target, operation, input) {
144
+ if (!dispatch.platformKey) {
62
145
  throw new ControlPlaneError(503, 'this control plane holds no scope-store key');
63
146
  }
147
+ const { scriptName, objectName } = target;
64
148
  try {
65
149
  return await callReservedStoreOperation(async (request) => {
66
- const objectName = scopeStoreObjectName(target.tenantId, target.vertical, target.scopeId, target.binding);
67
- const mac = await signScopeStoreName(dispatch.hmacKey, objectName);
68
- const response = await dispatch.fetch(scopeStoreScriptName(target.vertical, target.kind), new Request('https://scope-store/invoke', {
150
+ const body = JSON.stringify({ ...request, objectName });
151
+ let issued;
152
+ try {
153
+ issued = await issueScopeStoreEnvelope({
154
+ privateKey: dispatch.platformKey,
155
+ aud: 'platform',
156
+ script: scriptName,
157
+ name: objectName,
158
+ op: request.operation,
159
+ body,
160
+ });
161
+ }
162
+ catch (error) {
163
+ if (!(error instanceof ScopeStoreKeyError))
164
+ throw error;
165
+ // Set but unusable, e.g. a raw key where PKCS8 belongs. The message never carries the key.
166
+ console.warn(`scope store call refused: STORE_PLATFORM_KEY is set but unusable (${error.message})`);
167
+ throw new ControlPlaneError(503, 'this control plane holds no usable scope-store key');
168
+ }
169
+ const response = await dispatch.fetch(scriptName, new Request('https://scope-store/invoke', {
69
170
  method: 'POST',
70
171
  headers: {
71
172
  'content-type': 'application/json',
72
- 'x-substrat-store-mac': mac,
73
- 'x-substrat-store-audience': 'platform',
173
+ [SCOPE_STORE_ENVELOPE_HEADER]: issued.header,
174
+ [SCOPE_STORE_SIGNATURE_HEADER]: issued.signature,
74
175
  },
75
- body: JSON.stringify({ ...request, objectName }),
176
+ body,
76
177
  }));
77
178
  try {
78
179
  return await response.json();
@@ -1 +1 @@
1
- {"version":3,"file":"platform-scope-stores.js","sourceRoot":"","sources":["../src/platform-scope-stores.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"platform-scope-stores.js","sourceRoot":"","sources":["../src/platform-scope-stores.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import type { LakeQueryEngine } from './lake-gateway.js';
2
+ export interface R2SqlEngineOptions {
3
+ accountId: string;
4
+ /** The lake's bucket — `LAKE.bucket` in `scripts/lake-provision.mjs`. */
5
+ bucket: string;
6
+ /** The query token the secrets tooling pushes as `R2_SQL_TOKEN` (`secrets/README.md`). */
7
+ token: string;
8
+ /** Injected for tests. */
9
+ fetchImpl?: typeof fetch;
10
+ /** Injected for tests; `LAKE_QUERY_TIMEOUT_MS` otherwise. */
11
+ timeoutMs?: number;
12
+ /** Injected for tests; `LAKE_RESPONSE_MAX_BYTES` otherwise. */
13
+ maxResponseBytes?: number;
14
+ }
15
+ /**
16
+ * How long one lake query may take, request and body together. R2 SQL is open beta and
17
+ * names heavy queries as a timeout risk; without a bound, a stalled answer holds the
18
+ * control-plane request open until the platform cuts it, and the caller gets a generic
19
+ * failure instead of the gateway's 502.
20
+ */
21
+ export declare const LAKE_QUERY_TIMEOUT_MS = 30000;
22
+ /**
23
+ * The largest answer the engine will read. A page is at most `LAKE_EVENTS_LIMIT_MAX` + 1
24
+ * envelope rows, around a kilobyte each, so 4 MiB is far above any honest answer. Anything
25
+ * bigger is refused before it is parsed, never parsed and then trimmed.
26
+ */
27
+ export declare const LAKE_RESPONSE_MAX_BYTES: number;
28
+ /** A query R2 SQL refused or could not run. The message is Cloudflare's, never a row. */
29
+ export declare class LakeQueryError extends Error {
30
+ constructor(message: string);
31
+ }
32
+ /**
33
+ * The R2 SQL implementation of `LakeQueryEngine` — the Cloudflare row of kernel-design's
34
+ * adapter table ("Query gateway engine | R2 SQL").
35
+ *
36
+ * **Unverified against the real lake.** The endpoint and the response envelope below are
37
+ * written from Cloudflare's documented shape (`POST …/r2-sql/query/<bucket>` with
38
+ * `{ query }`, answering `{ success, errors, result: { rows } }`), and no run in this repo
39
+ * has exercised them. Until a human has, the control plane is deployed without the bucket
40
+ * var that turns this on, and the gateway's route answers 501.
41
+ *
42
+ * **Which permissions the token needs is unverified too.** It is provisioned today as an R2
43
+ * "Admin Read only" token scoped to the lake bucket. Cloudflare's R2 SQL docs list catalog,
44
+ * storage and R2 SQL permissions for a query token, and their example grants storage read
45
+ * and write, so whether read-only is enough has not been checked. The smoke test that turns
46
+ * this engine on establishes the smallest set that works. This client never writes; the
47
+ * gateway only ever sends the SELECT it compiled.
48
+ */
49
+ export declare function createR2SqlEngine(opts: R2SqlEngineOptions): LakeQueryEngine;
50
+ //# sourceMappingURL=r2-sql-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"r2-sql-engine.d.ts","sourceRoot":"","sources":["../src/r2-sql-engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,0FAA0F;IAC1F,KAAK,EAAE,MAAM,CAAC;IACd,0BAA0B;IAC1B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAE5C;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,QAAkB,CAAC;AAEvD,yFAAyF;AACzF,qBAAa,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAqCD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,kBAAkB,GAAG,eAAe,CAiD3E"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * How long one lake query may take, request and body together. R2 SQL is open beta and
3
+ * names heavy queries as a timeout risk; without a bound, a stalled answer holds the
4
+ * control-plane request open until the platform cuts it, and the caller gets a generic
5
+ * failure instead of the gateway's 502.
6
+ */
7
+ export const LAKE_QUERY_TIMEOUT_MS = 30_000;
8
+ /**
9
+ * The largest answer the engine will read. A page is at most `LAKE_EVENTS_LIMIT_MAX` + 1
10
+ * envelope rows, around a kilobyte each, so 4 MiB is far above any honest answer. Anything
11
+ * bigger is refused before it is parsed, never parsed and then trimmed.
12
+ */
13
+ export const LAKE_RESPONSE_MAX_BYTES = 4 * 1024 * 1024;
14
+ /** A query R2 SQL refused or could not run. The message is Cloudflare's, never a row. */
15
+ export class LakeQueryError extends Error {
16
+ constructor(message) {
17
+ super(message);
18
+ this.name = 'LakeQueryError';
19
+ }
20
+ }
21
+ /**
22
+ * The response body as text, refused once it passes `maxBytes`: up front when the
23
+ * `content-length` says so, and while streaming when it does not (a chunked answer has none),
24
+ * cancelling the rest rather than reading it.
25
+ */
26
+ async function readCapped(res, maxBytes) {
27
+ const tooLarge = () => new LakeQueryError(`R2 SQL answer exceeds ${maxBytes} bytes; refused before parsing`);
28
+ const declared = Number(res.headers.get('content-length'));
29
+ if (Number.isFinite(declared) && declared > maxBytes) {
30
+ await res.body?.cancel();
31
+ throw tooLarge();
32
+ }
33
+ if (!res.body)
34
+ return '';
35
+ const reader = res.body.getReader();
36
+ const chunks = [];
37
+ let total = 0;
38
+ for (;;) {
39
+ const { done, value } = await reader.read();
40
+ if (done)
41
+ break;
42
+ total += value.byteLength;
43
+ if (total > maxBytes) {
44
+ await reader.cancel();
45
+ throw tooLarge();
46
+ }
47
+ chunks.push(value);
48
+ }
49
+ const all = new Uint8Array(total);
50
+ let at = 0;
51
+ for (const c of chunks) {
52
+ all.set(c, at);
53
+ at += c.byteLength;
54
+ }
55
+ return new TextDecoder().decode(all);
56
+ }
57
+ /**
58
+ * The R2 SQL implementation of `LakeQueryEngine` — the Cloudflare row of kernel-design's
59
+ * adapter table ("Query gateway engine | R2 SQL").
60
+ *
61
+ * **Unverified against the real lake.** The endpoint and the response envelope below are
62
+ * written from Cloudflare's documented shape (`POST …/r2-sql/query/<bucket>` with
63
+ * `{ query }`, answering `{ success, errors, result: { rows } }`), and no run in this repo
64
+ * has exercised them. Until a human has, the control plane is deployed without the bucket
65
+ * var that turns this on, and the gateway's route answers 501.
66
+ *
67
+ * **Which permissions the token needs is unverified too.** It is provisioned today as an R2
68
+ * "Admin Read only" token scoped to the lake bucket. Cloudflare's R2 SQL docs list catalog,
69
+ * storage and R2 SQL permissions for a query token, and their example grants storage read
70
+ * and write, so whether read-only is enough has not been checked. The smoke test that turns
71
+ * this engine on establishes the smallest set that works. This client never writes; the
72
+ * gateway only ever sends the SELECT it compiled.
73
+ */
74
+ export function createR2SqlEngine(opts) {
75
+ const fetchImpl = opts.fetchImpl ?? fetch;
76
+ const timeoutMs = opts.timeoutMs ?? LAKE_QUERY_TIMEOUT_MS;
77
+ const maxBytes = opts.maxResponseBytes ?? LAKE_RESPONSE_MAX_BYTES;
78
+ const url = `https://api.sql.cloudflarestorage.com/api/v1/accounts/${encodeURIComponent(opts.accountId)}` +
79
+ `/r2-sql/query/${encodeURIComponent(opts.bucket)}`;
80
+ return {
81
+ async query(sql) {
82
+ let res;
83
+ let text;
84
+ try {
85
+ // One signal for the request AND the body read: a server that answers its headers
86
+ // promptly and then stalls the body is the same stall.
87
+ res = await fetchImpl(url, {
88
+ method: 'POST',
89
+ headers: { authorization: `Bearer ${opts.token}`, 'content-type': 'application/json' },
90
+ body: JSON.stringify({ query: sql }),
91
+ signal: AbortSignal.timeout(timeoutMs),
92
+ });
93
+ text = await readCapped(res, maxBytes);
94
+ }
95
+ catch (err) {
96
+ if (err instanceof LakeQueryError)
97
+ throw err;
98
+ const name = err?.name;
99
+ if (name === 'TimeoutError' || name === 'AbortError') {
100
+ throw new LakeQueryError(`R2 SQL query timed out after ${timeoutMs} ms`);
101
+ }
102
+ throw new LakeQueryError(`R2 SQL request failed: ${err?.message ?? String(err)}`);
103
+ }
104
+ let body;
105
+ try {
106
+ body = JSON.parse(text);
107
+ }
108
+ catch {
109
+ body = null;
110
+ }
111
+ if (!res.ok || !body || body.success === false) {
112
+ const reason = body?.errors?.map((e) => e.message).filter(Boolean).join('; ') || 'no error detail';
113
+ throw new LakeQueryError(`R2 SQL query failed (${res.status}): ${reason}`);
114
+ }
115
+ const rows = body.result?.rows;
116
+ if (!Array.isArray(rows) || !rows.every((r) => typeof r === 'object' && r !== null && !Array.isArray(r))) {
117
+ // A shape this client does not know is refused, not guessed at: the gateway's
118
+ // tenant check reads `tenant_id` off each row, and a row it cannot read is not one
119
+ // it can vouch for.
120
+ throw new LakeQueryError('R2 SQL answered without a rows array of objects');
121
+ }
122
+ return rows;
123
+ },
124
+ };
125
+ }
126
+ //# sourceMappingURL=r2-sql-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"r2-sql-engine.js","sourceRoot":"","sources":["../src/r2-sql-engine.ts"],"names":[],"mappings":"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"}
@@ -83,4 +83,16 @@ export declare function recordStrandedStorage(admin: HostAdmin, actor: PlatformA
83
83
  export declare function reapScopeScriptCopies(input: ScopeCopyCleanup, tenantId: TenantId, scopeId: ScopeId): Promise<{
84
84
  storageStranded: boolean;
85
85
  }>;
86
+ /**
87
+ * The reap claim. The directory claim and new move records serialize on one store. A carry that
88
+ * already began refuses the reap (412) and keeps it retryable; one starting later cannot restore
89
+ * bytes after the scripts have been drained and the row removed. A reap that unroutes the scope
90
+ * takes this before it destroys anything (#2285), so a refusal leaves the scope routed and whole.
91
+ * Taking a claim already held resumes it.
92
+ */
93
+ export declare function claimScopeScriptReap(input: Pick<ScopeCopyCleanup, 'admin' | 'actor'>, tenantId: TenantId, scopeId: ScopeId): Promise<void>;
94
+ /** `reapScopeScriptCopies` past its claim: delete through every named script, then settle the ledger. */
95
+ export declare function drainScopeScriptCopies(input: ScopeCopyCleanup, tenantId: TenantId, scopeId: ScopeId): Promise<{
96
+ storageStranded: boolean;
97
+ }>;
86
98
  //# sourceMappingURL=scope-copy-cleanup.d.ts.map