@substrat-run/adapter-cloudflare 0.158.0 → 0.160.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.
@@ -87,8 +87,9 @@ export interface PlatformSweeperDo {
87
87
  * sweep: (env) =>
88
88
  * runPlatformSweep(hostFor(env), {
89
89
  * actor: SWEEP_ACTOR,
90
- * // bound: workerd refuses the bare global called as `opts.fetch(…)`
91
- * fetch: globalThis.fetch.bind(globalThis) as unknown as FetchLike,
90
+ * // the kernel's: called on its global (workerd refuses another receiver), and a sized
91
+ * // stream body is sent at its length rather than as "[object Object]" (#2498)
92
+ * fetch: globalFetch,
92
93
  * sweepers: { scrive: sweepScriveReconciliations },
93
94
  * }),
94
95
  * });
@@ -1 +1 @@
1
- {"version":3,"file":"platform-sweeper-do.d.ts","sourceRoot":"","sources":["../src/platform-sweeper-do.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AAExD,2EAA2E;AAC3E,MAAM,MAAM,oBAAoB,GAAG,mBAAmB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3E,MAAM,WAAW,uBAAuB,CAAC,GAAG;IAC1C;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;;;;OASG;IACH,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC9C,kFAAkF;IAClF,MAAM,CAAC,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC;CACxD;AAED,+EAA+E;AAC/E,MAAM,WAAW,iBAAiB;IAChC,2EAA2E;IAC3E,WAAW,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5D,gEAAgE;IAChE,QAAQ,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC3C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EACzC,MAAM,EAAE,uBAAuB,CAAC,GAAG,CAAC,GACnC,KAAK,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,GAAG,KAAK,aAAa,CAAC,GAAG,CAAC,GAAG,iBAAiB,CAqDnF"}
1
+ {"version":3,"file":"platform-sweeper-do.d.ts","sourceRoot":"","sources":["../src/platform-sweeper-do.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AAExD,2EAA2E;AAC3E,MAAM,MAAM,oBAAoB,GAAG,mBAAmB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3E,MAAM,WAAW,uBAAuB,CAAC,GAAG;IAC1C;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;;;;OASG;IACH,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC9C,kFAAkF;IAClF,MAAM,CAAC,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC;CACxD;AAED,+EAA+E;AAC/E,MAAM,WAAW,iBAAiB;IAChC,2EAA2E;IAC3E,WAAW,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5D,gEAAgE;IAChE,QAAQ,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC3C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EACzC,MAAM,EAAE,uBAAuB,CAAC,GAAG,CAAC,GACnC,KAAK,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,GAAG,KAAK,aAAa,CAAC,GAAG,CAAC,GAAG,iBAAiB,CAqDnF"}
@@ -50,8 +50,9 @@ export const PLATFORM_SWEEPER_NAME = 'platform-sweeper';
50
50
  * sweep: (env) =>
51
51
  * runPlatformSweep(hostFor(env), {
52
52
  * actor: SWEEP_ACTOR,
53
- * // bound: workerd refuses the bare global called as `opts.fetch(…)`
54
- * fetch: globalThis.fetch.bind(globalThis) as unknown as FetchLike,
53
+ * // the kernel's: called on its global (workerd refuses another receiver), and a sized
54
+ * // stream body is sent at its length rather than as "[object Object]" (#2498)
55
+ * fetch: globalFetch,
55
56
  * sweepers: { scrive: sweepScriveReconciliations },
56
57
  * }),
57
58
  * });
@@ -1 +1 @@
1
- {"version":3,"file":"platform-sweeper-do.js","sourceRoot":"","sources":["../src/platform-sweeper-do.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AAoCxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,MAAM,UAAU,uBAAuB,CACrC,MAAoC;IAEpC,OAAO,MAAM,iBAAkB,SAAQ,aAAkB;QACvD,mEAAmE;QACnE,KAAK,GAAyC,IAAI,CAAC;QAEnD;;;WAGG;QACH,KAAK,CAAC,WAAW;YACf,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACnD,IAAI,QAAQ,KAAK,IAAI;gBAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;YAClE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC;YAC/C,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACzC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAClC,CAAC;QAED;;;;WAIG;QACH,KAAK,CAAC,QAAQ;YACZ,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;QACrB,CAAC;QAED,yEAAyE;QACzE,KAAK,CAAC,KAAK;YACT,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QACpB,CAAC;QAED,KAAK,CAAC,IAAI;YACR,IAAI,IAAI,CAAC,KAAK;gBAAE,OAAO,IAAI,CAAC,KAAK,CAAC;YAClC,IAAI,CAAC,KAAK,GAAG,CAAC,KAAK,IAAmC,EAAE;gBACtD,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBAC5C,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;oBAClC,OAAO,MAAM,CAAC;gBAChB,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC5E,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;oBACnC,OAAO,OAAO,CAAC;gBACjB,CAAC;YACH,CAAC,CAAC,EAAE,CAAC;YACL,IAAI,CAAC;gBACH,OAAO,MAAM,IAAI,CAAC,KAAK,CAAC;YAC1B,CAAC;oBAAS,CAAC;gBACT,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;gBAClB,yEAAyE;gBACzE,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;YAClE,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"platform-sweeper-do.js","sourceRoot":"","sources":["../src/platform-sweeper-do.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AAoCxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,MAAM,UAAU,uBAAuB,CACrC,MAAoC;IAEpC,OAAO,MAAM,iBAAkB,SAAQ,aAAkB;QACvD,mEAAmE;QACnE,KAAK,GAAyC,IAAI,CAAC;QAEnD;;;WAGG;QACH,KAAK,CAAC,WAAW;YACf,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACnD,IAAI,QAAQ,KAAK,IAAI;gBAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;YAClE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC;YAC/C,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACzC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAClC,CAAC;QAED;;;;WAIG;QACH,KAAK,CAAC,QAAQ;YACZ,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;QACrB,CAAC;QAED,yEAAyE;QACzE,KAAK,CAAC,KAAK;YACT,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QACpB,CAAC;QAED,KAAK,CAAC,IAAI;YACR,IAAI,IAAI,CAAC,KAAK;gBAAE,OAAO,IAAI,CAAC,KAAK,CAAC;YAClC,IAAI,CAAC,KAAK,GAAG,CAAC,KAAK,IAAmC,EAAE;gBACtD,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBAC5C,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;oBAClC,OAAO,MAAM,CAAC;gBAChB,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC5E,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;oBACnC,OAAO,OAAO,CAAC;gBACjB,CAAC;YACH,CAAC,CAAC,EAAE,CAAC;YACL,IAAI,CAAC;gBACH,OAAO,MAAM,IAAI,CAAC,KAAK,CAAC;YAC1B,CAAC;oBAAS,CAAC;gBACT,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;gBAClB,yEAAyE;gBACzE,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;YAClE,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
package/dist/r2.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type FetchLike, type TenantBlobStore } from '@substrat-run/kernel';
1
+ import { type FetchLike, type IncrementalSha256, type TenantBlobStore } from '@substrat-run/kernel';
2
2
  /**
3
3
  * The live R2 side of per-tenant blob stores (#473): a minimal client over Cloudflare's
4
4
  * R2 REST API — create and delete buckets. Pure web-standard `fetch`, injected for tests,
@@ -40,6 +40,12 @@ export interface R2BlobStoresOptions {
40
40
  */
41
41
  export declare function blobStoreBucketName(tenantId: string, vertical: string, binding: string): Promise<string>;
42
42
  export declare function createR2BlobStores(opts: R2BlobStoresOptions): R2BlobStores;
43
+ /**
44
+ * workerd's running SHA-256 (#2498): `crypto.DigestStream`, fed chunk by chunk as a streamed
45
+ * upload passes, so its sha256 is known when the last byte lands without the body ever being
46
+ * held. The kernel's `putAttachmentBytes` takes it.
47
+ */
48
+ export declare function workerdSha256(): IncrementalSha256;
43
49
  /**
44
50
  * The WORKER-side open (#473): wrap the tenant's real `r2_bucket` binding — looked up as
45
51
  * `env[blobStoreBindingName(binding, tenantId)]` — in the kernel's `TenantBlobStore`
package/dist/r2.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"r2.d.ts","sourceRoot":"","sources":["../src/r2.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,KAAK,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEjH;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACtC,8EAA8E;IAC9E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,0FAA0F;IAC1F,QAAQ,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAaD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAYjB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,mBAAmB,GAAG,YAAY,CA2D1E;AAqBD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,eAAe,CA2BlE"}
1
+ {"version":3,"file":"r2.d.ts","sourceRoot":"","sources":["../src/r2.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,SAAS,EACd,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACrB,MAAM,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACtC,8EAA8E;IAC9E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,0FAA0F;IAC1F,QAAQ,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAaD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAYjB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,mBAAmB,GAAG,YAAY,CA2D1E;AAED;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,iBAAiB,CAUjD;AAsBD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,eAAe,CA6BlE"}
package/dist/r2.js CHANGED
@@ -1,4 +1,4 @@
1
- import { globalFetch } from '@substrat-run/kernel';
1
+ import { globalFetch, isSizedByteStream, knownLengthStream, } from '@substrat-run/kernel';
2
2
  /** Bound an untrusted upstream body for an error message, marking the cut (#307). */
3
3
  function bounded(body, max = 2000) {
4
4
  return body.length <= max ? body : `${body.slice(0, max)} … [truncated, ${body.length - max} chars omitted]`;
@@ -84,6 +84,22 @@ export function createR2BlobStores(opts) {
84
84
  },
85
85
  };
86
86
  }
87
+ /**
88
+ * workerd's running SHA-256 (#2498): `crypto.DigestStream`, fed chunk by chunk as a streamed
89
+ * upload passes, so its sha256 is known when the last byte lands without the body ever being
90
+ * held. The kernel's `putAttachmentBytes` takes it.
91
+ */
92
+ export function workerdSha256() {
93
+ const digest = new crypto.DigestStream('SHA-256');
94
+ const writer = digest.getWriter();
95
+ return {
96
+ update: (chunk) => writer.write(chunk),
97
+ hex: async () => {
98
+ await writer.close();
99
+ return [...new Uint8Array(await digest.digest)].map((b) => b.toString(16).padStart(2, '0')).join('');
100
+ },
101
+ };
102
+ }
87
103
  /**
88
104
  * The WORKER-side open (#473): wrap the tenant's real `r2_bucket` binding — looked up as
89
105
  * `env[blobStoreBindingName(binding, tenantId)]` — in the kernel's `TenantBlobStore`
@@ -94,7 +110,9 @@ export function r2TenantBlobStore(bucket) {
94
110
  const r2 = bucket;
95
111
  return {
96
112
  put: async (key, body, opts) => {
97
- await r2.put(key, body, opts?.contentType ? { httpMetadata: { contentType: opts.contentType } } : undefined);
113
+ // #2498: a stream goes in as it is read, at the length it declared.
114
+ const value = isSizedByteStream(body) ? knownLengthStream(body) : body;
115
+ await r2.put(key, value, opts?.contentType ? { httpMetadata: { contentType: opts.contentType } } : undefined);
98
116
  },
99
117
  get: async (key) => {
100
118
  const obj = await r2.get(key);
package/dist/r2.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"r2.js","sourceRoot":"","sources":["../src/r2.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAgE,MAAM,sBAAsB,CAAC;AAoCjH,qFAAqF;AACrF,SAAS,OAAO,CAAC,IAAY,EAAE,GAAG,GAAG,IAAI;IACvC,OAAO,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,kBAAkB,IAAI,CAAC,MAAM,GAAG,GAAG,iBAAiB,CAAC;AAC/G,CAAC;AAQD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,QAAgB,EAChB,QAAgB,EAChB,OAAe;IAEf,MAAM,GAAG,GAAG,QAAQ,QAAQ,IAAI,OAAO,IAAI,QAAQ,EAAE;SAClD,WAAW,EAAE;SACb,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC;SAC5B,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACvB,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IACjC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACpF,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;SACrC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;SAC3C,IAAI,CAAC,EAAE,CAAC,CAAC;IACZ,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAyB;IAC1D,MAAM,SAAS,GAAc,IAAI,CAAC,KAAK,IAAI,WAAW,CAAC;IACvD,MAAM,IAAI,GAAG,iDAAiD,IAAI,CAAC,SAAS,aAAa,CAAC;IAC1F,MAAM,IAAI,GAAG,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;IAE1D,MAAM,YAAY,GAAG,KAAK,EAAK,GAAsB,EAAE,IAAY,EAA0B,EAAE;QAC7F,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9C,IAAI,GAA8B,CAAC;QACnC,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAmB,CAAC,CAAC,CAAC,SAAS,CAAC;QAC/D,CAAC;QAAC,MAAM,CAAC;YACP,yEAAyE;QAC3E,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;YAC3F,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,cAAc,IAAI,YAAY,GAAG,CAAC,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC,CAAC;YAC7F,GAA2B,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;YACjD,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,IAAI;YACf,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE;gBAChC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,GAAG,IAAI,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBACxD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC;aAC/B,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,kFAAkF;gBAClF,+EAA+E;gBAC/E,yDAAyD;gBACzD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;oBACvB,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,kBAAkB,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;oBACxF,IAAI,KAAK,CAAC,EAAE,EAAE,CAAC;wBACb,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;wBACnC,OAAO,IAAI,CAAC;oBACd,CAAC;gBACH,CAAC;gBACD,MAAM,YAAY,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC,CAAC,kCAAkC;YACjF,CAAC;iBAAM,CAAC;gBACN,MAAM,YAAY,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;YAC9C,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,GAAG;YACd,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,EAAE;gBAChE,MAAM,EAAE,QAAQ;gBAChB,OAAO,EAAE,IAAI;aACd,CAAC,CAAC;YACH,mDAAmD;YACnD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBACvB,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;gBACjC,OAAO;YACT,CAAC;YACD,MAAM,YAAY,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;QAC9C,CAAC;KACF,CAAC;AACJ,CAAC;AAqBD;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAe;IAC/C,MAAM,EAAE,GAAG,MAAsB,CAAC;IAClC,OAAO;QACL,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;YAC7B,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC/G,CAAC;QACD,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACjB,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC9B,IAAI,CAAC,GAAG;gBAAE,OAAO,IAAI,CAAC;YACtB,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;YACrD,MAAM,WAAW,GAAG,GAAG,CAAC,YAAY,EAAE,WAAW,CAAC;YAClD,OAAO,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACtE,CAAC;QACD,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACpB,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC;QACD,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YACrB,MAAM,IAAI,GAAa,EAAE,CAAC;YAC1B,IAAI,MAA0B,CAAC;YAC/B,GAAG,CAAC;gBACF,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBACtE,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC7C,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;YACpD,CAAC,QAAQ,MAAM,EAAE;YACjB,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;QACrB,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"r2.js","sourceRoot":"","sources":["../src/r2.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"scope-do.d.ts","sourceRoot":"","sources":["../src/scope-do.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAgEnD,OAAO,EAwDL,KAAK,mBAAmB,EASxB,KAAK,SAAS,EAsBd,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EAkHtB,MAAM,sBAAsB,CAAC;AAoD9B,OAAO,EAAW,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAwBL,kBAAkB,EAgFnB,MAAM,sBAAsB,CAAC;AA2B9B;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC;AAoFD,oFAAoF;AACpF,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AA2rB5E;;;GAGG;AACH,MAAM,MAAM,yBAAyB,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;AAmBtD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,SAAS,CAOxD;AAED,gHAAgH;AAChH,OAAO,EAAE,kBAAkB,EAAE,CAAC;AA2B9B,wBAAgB,aAAa,CAC3B,OAAO,EAAE,kBAAkB,EAAE,EAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AACzD;;;;GAIG;AACH,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,mBAAmB,CAAA;CAAO,GAClD,KAAK,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,UAAU,KAAK,aAAa,CAAC,UAAU,CAAC,CAwpP7E"}
1
+ {"version":3,"file":"scope-do.d.ts","sourceRoot":"","sources":["../src/scope-do.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAgEnD,OAAO,EA0DL,KAAK,mBAAmB,EASxB,KAAK,SAAS,EAsBd,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EAmHtB,MAAM,sBAAsB,CAAC;AAoD9B,OAAO,EAAW,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAwBL,kBAAkB,EAiFnB,MAAM,sBAAsB,CAAC;AA2B9B;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC;AAoFD,oFAAoF;AACpF,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AA2rB5E;;;GAGG;AACH,MAAM,MAAM,yBAAyB,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;AAmBtD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,SAAS,CAOxD;AAED,gHAAgH;AAChH,OAAO,EAAE,kBAAkB,EAAE,CAAC;AA2B9B,wBAAgB,aAAa,CAC3B,OAAO,EAAE,kBAAkB,EAAE,EAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AACzD;;;;GAIG;AACH,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,mBAAmB,CAAA;CAAO,GAClD,KAAK,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,UAAU,KAAK,aAAa,CAAC,UAAU,CAAC,CAuuP7E"}
package/dist/scope-do.js CHANGED
@@ -2,12 +2,12 @@ import { REWIND_REFUSED } from './rewind-refusal.js';
2
2
  import { SYSTEM_DOOR_MOVED } from './system-door.js';
3
3
  import { DurableObject } from 'cloudflare:workers';
4
4
  import { ATTACHMENT_ADDED, ATTACHMENT_REMOVED, attachmentRecord, domainEvent, domainEventInput, eventId, instant, objectRef, entityObjectRef, assertModuleEmittableType, assertKernelAuthoredType, toWireFailure, grantRefFromProof, principalId, principalBecomeCapabilityInput, scopeId as scopeIdOf, tenantId as tenantIdOf, platformRequestInput, platformRequestId, MAX_PENDING_PLATFORM_REQUESTS, MAX_PENDING_SWEEP_RUNS, SWEEP_RUNS_KIND, SCOPE_DUMP_PAGE_MAX_BYTES, SCOPE_TABLE_PAGE_MAX, SCOPE_QUERY_ROW_MAX, listLimitOf, pageOf, countedPageOf, requestFingerprint, substratError, errorCodeOf, assertReplayableDump, REDRAIN_BATCH, } from '@substrat-run/contracts';
5
- import { ulid, DO_SQL_LIMITS, unknownRoleError, createUlid, assertAllowed, ConnectionSealingKeyUnavailableError, noSealingKeyMessage, sealTo, assertReadOnlyQuery, entitlementDenial, platformRequestHistoryQuery, platformRequestOf, PLATFORM_REQUEST_COLUMNS, PLATFORM_REQUEST_REDACTION_SQL, platformRequestRedactionParams, platformRequestRedactionQuery, intentPayloadCarriesSubject, redactSubjectJobRuns, eraseSubjectFromModules, moduleErasurePlan, redactSubjectScopeText, assertRowLimit, assertRowOffset, JOB_RUN_PATCH_SQL, JOB_RUN_CLAIM_SQL, JOB_RUN_RENEW_SQL, JOB_RUN_BEGIN_SQL, JOB_RUN_MISS_SQL, JOB_RUN_MISS_SETTLE_SQL, admissionMissOutcome, JOB_LEASE_EXPIRED_NOTE, JOB_STEP_RECORD_SQL, DELIVERY_ERROR_REDACTION_SQL, REDACTED_DELIVERY_NOTE, seatScopeTuple, delegatedRevokeSql, writeExplicitTupleIn, grantEntityShapeIn, topUpEntityGrantShapes, applyScopeRoleChange, changeScopeRole, revokeScopeRoles, scopeRoleHolders, assertModuleDeclared, noteReservedKeys, reservedGrantRefusal, reservedRoleRefusal, reservedShapeRefusal, effectiveRoleGrantQuery, switchRecordedOff, switchSystemSchedules, peerGrantsStatus, systemGrantsStatus, systemScheduleState, systemSwitchedOff, denialListQuery, refusalListQuery, mapRefusalRow, denialSummaryQuery, denialTotalsQuery, DENIAL_WINDOW_QUERY, mapDenialRow, mapDenialSummaryBuckets, PermissionDenied, assertImpersonationWrites, assertModuleEnqueueableKind, impersonationStampOf, createAtomic, NotSearchable, isSearchIndexTable, searchIndexPlans, NotListable, listIndexPlans, moduleMigrations, MIGRATION_DIGEST_FENCE_DDL, MIGRATION_DIGEST_MARK_LEGACY, assertJournalDumpCoherent, assertMigrationSql, migrationDivergence, migrationFailedError, migrationSetDivergence, migrationSteps, planMigrations, listQuery, cursorOf, searchLimit, searchMatchExpression, searchQuery, ATTACHMENT_TEXT_DDL, ATTACHMENT_CONDEMNED_DDL, ATTACHMENT_SWEEP_LICENCE_DDL, ATTACHMENT_SWEEP_LICENCE_TABLE, clearOrphanSweepLicence, condemnLicensedOrphanAttachments, consumeOrphanSweepLicence, licensedOrphanIds, recordOrphanSweepLicence, refuseUnlicensedOrphanSweep, refuseCondemnedAttachment, refuseCondemnedInDump, rowlessAttachmentIds, attachmentRecordOfRow, enqueueAttachmentText, reconcileAttachmentText, queueAttachmentTextBackfill, startAttachmentTextBackfill, recordAttachmentText, searchAttachments, IDEMPOTENCY_DDL, REFUSALS_TABLE_DDL, REFUSALS_INDEX, refusalInsert, refusalOf, markGuardRefusal, REFUSALS_REBUILD, refusalsAdmitGuards, assertIdempotencyKey, assertPermissionKey, idempotencyLookupQuery, idempotencyPruneStatement, idempotencyRecordStatement, idempotencyOptedOutMessage, replayFor, entityVersionQuery, entityVersionOf, assertIfMatch, OUTBOX_ENTITY_INDEX, SCHEDULE_STATE_DDL, SCHEDULE_STATE_REBUILD, scheduleStateHasKind, VERTICAL_EVENTS_DDL, EXPORT_HOPS_SQL, emptyImportResult, IMPORT_CURSORS_SQL, IMPORT_CURSOR_OF_SQL, OUTBOX_MARK_SQL, exportedSinceQuery, emittedSinceQuery, emittedReportOf, EMITTED_REPORT_CAP, IMPORT_CURSOR_ADVANCE_SQL, IMPORT_RECORD_SQL, moveImportCursor, CrossVerticalRegistry, exportReadPlan, exportReadQuery, planExportBatch, withheldNote, JOB_RUN_DDL, JOB_RUN_DUE_AT, jobRunListLimit, SYSTEM_DOOR_WAIT, ancestorsWithin, } from '@substrat-run/kernel';
5
+ import { ulid, DO_SQL_LIMITS, unknownRoleError, createUlid, assertAllowed, ConnectionSealingKeyUnavailableError, noSealingKeyMessage, sealTo, assertReadOnlyQuery, entitlementDenial, platformRequestHistoryQuery, platformRequestOf, PLATFORM_REQUEST_COLUMNS, PLATFORM_REQUEST_REDACTION_SQL, platformRequestRedactionParams, platformRequestRedactionQuery, intentPayloadCarriesSubject, redactSubjectJobRuns, eraseSubjectFromModules, moduleErasurePlan, redactSubjectScopeText, assertRowLimit, assertRowOffset, JOB_RUN_PATCH_SQL, JOB_RUN_CLAIM_SQL, JOB_RUN_RENEW_SQL, JOB_RUN_BEGIN_SQL, JOB_RUN_MISS_SQL, JOB_RUN_MISS_SETTLE_SQL, admissionMissOutcome, JOB_LEASE_EXPIRED_NOTE, JOB_STEP_RECORD_SQL, DELIVERY_ERROR_REDACTION_SQL, REDACTED_DELIVERY_NOTE, seatScopeTuple, delegatedRevokeSql, writeExplicitTupleIn, grantEntityShapeIn, topUpEntityGrantShapes, applyScopeRoleChange, changeScopeRole, revokeScopeRoles, scopeRoleHolders, assertModuleDeclared, noteDeclaredKeys, noteReservedKeys, SCOPE_SEATED_ROLES_SQL, reservedGrantRefusal, reservedRoleRefusal, reservedShapeRefusal, effectiveRoleGrantQuery, switchRecordedOff, switchSystemSchedules, peerGrantsStatus, systemGrantsStatus, systemScheduleState, systemSwitchedOff, denialListQuery, refusalListQuery, mapRefusalRow, denialSummaryQuery, denialTotalsQuery, DENIAL_WINDOW_QUERY, mapDenialRow, mapDenialSummaryBuckets, PermissionDenied, assertImpersonationWrites, assertModuleEnqueueableKind, impersonationStampOf, createAtomic, NotSearchable, isSearchIndexTable, searchIndexPlans, NotListable, listIndexPlans, moduleMigrations, MIGRATION_DIGEST_FENCE_DDL, MIGRATION_DIGEST_MARK_LEGACY, assertJournalDumpCoherent, assertMigrationSql, migrationDivergence, migrationFailedError, migrationSetDivergence, migrationSteps, planMigrations, listQuery, cursorOf, searchLimit, searchMatchExpression, searchQuery, ATTACHMENT_TEXT_DDL, ATTACHMENT_BYTES_SQL, ATTACHMENT_CONDEMNED_DDL, ATTACHMENT_SWEEP_LICENCE_DDL, ATTACHMENT_SWEEP_LICENCE_TABLE, clearOrphanSweepLicence, condemnLicensedOrphanAttachments, consumeOrphanSweepLicence, licensedOrphanIds, recordOrphanSweepLicence, refuseUnlicensedOrphanSweep, refuseCondemnedAttachment, refuseCondemnedInDump, rowlessAttachmentIds, attachmentRecordOfRow, enqueueAttachmentText, reconcileAttachmentText, queueAttachmentTextBackfill, startAttachmentTextBackfill, recordAttachmentText, searchAttachments, IDEMPOTENCY_DDL, REFUSALS_TABLE_DDL, REFUSALS_INDEX, refusalInsert, refusalOf, markGuardRefusal, REFUSALS_REBUILD, refusalsAdmitGuards, assertIdempotencyKey, assertPermissionKey, idempotencyLookupQuery, idempotencyPruneStatement, idempotencyRecordStatement, idempotencyOptedOutMessage, replayFor, entityVersionQuery, entityVersionOf, assertIfMatch, OUTBOX_ENTITY_INDEX, SCHEDULE_STATE_DDL, SCHEDULE_STATE_REBUILD, scheduleStateHasKind, VERTICAL_EVENTS_DDL, EXPORT_HOPS_SQL, emptyImportResult, IMPORT_CURSORS_SQL, IMPORT_CURSOR_OF_SQL, OUTBOX_MARK_SQL, exportedSinceQuery, emittedSinceQuery, emittedReportOf, EMITTED_REPORT_CAP, IMPORT_CURSOR_ADVANCE_SQL, IMPORT_RECORD_SQL, moveImportCursor, CrossVerticalRegistry, exportReadPlan, exportReadQuery, planExportBatch, withheldNote, JOB_RUN_DDL, JOB_RUN_DUE_AT, jobRunListLimit, SYSTEM_DOOR_WAIT, ancestorsWithin, } from '@substrat-run/kernel';
6
6
  import { isUpgradeRequest, readSubscription, LIVE_DECIDE_ATTEMPTS, LIVE_FANOUT_LIMIT, LIVE_PRINCIPAL_HEADER, LIVE_SCOPE_HEADER, LIVE_SUBSCRIBE_PATH, LIVE_TENANT_HEADER, LIVE_WITHIN_HEADER, LIVE_EXPIRES_HEADER, LIVE_CLOSE, LIVE_SOCKETS_PER_PRINCIPAL, decodeLiveWithin, liveInstant, liveRefusal, liveRefusalStatus, } from './live-reads.js';
7
7
  import { replyOf } from './do-reply.js';
8
8
  import { OperationQueue } from './serialization.js';
9
9
  import { assertNoWorkerdStorage, doScopedSql, doBuiltColumnsOf, doRedactionSql, doSpineSql } from './sql.js';
10
- import { actorOf, admitPeer, boundToPeerDeclarations, collectPeers, switchPeer, peerSubjectRef, subjectGrantState, assertNoSecret, CAPABILITY_DDL, UPLOAD_LINK_DDL, createAttachmentVerbs, inspectUploadLink, redeemUploadLinkInTransaction, COPY_ORIGIN_DDL, ENTITY_STATE_MOVES_DDL, SWITCH_FENCES_DDL, TABLE_OWNERS_DDL, assertMigrationLeavesLedgerAlone, recordOwnershipSteps, runMigrationStatements, splitSqlStatements, executableSqlStatements, blankSqlComments, CAPABILITY_EXCHANGE_OPERATION, CAPABILITY_BECOME_MINT_OPERATION, becomeMintCheck, mintBecomeCapabilityAsPrincipal, revokeBecomeCapabilityAsPrincipal, readBecomeLinkStates, ENTITY_UNBIND_OPERATION, allowedFor, unbindEntityHolderBounded, capabilityAttachmentWriteRefused, createCapabilityVerbs, createEntityEdgeVerbs, createEntityStateVerbs, createTrashedReads, CONTINUATION_POSITION_CAP, visibleContinuation, searchStateWhere, uncheckedView, addStatePlans, addUpdatedStampPlans, watchUpdatedStamps, assertNoCallerPurge, isUnreachableParent, PURGE_BATCH, heldPurgePass, lifecycleRefusal, purgeHeldBy, purgeDueOf, purgeOnlyKeysOf, runPurgePass, refuseTrashedTarget, assertBoundOperations, checkHeldOperationsOf, countChecks, noteUncheckedCompletion, registerTrashTargets, withheldKeysFor, statefulTablesOf, afterMigration, afterRuntimeDdl, derivesAnything, repairDerivedObjects, StateColumnLost, exchangeCapability, guardSecrets, mintBecomeCapability, redactSecrets, redactSecretText, moduleLog, asyncInvocationId, asyncLinePass, resolveCapabilitySession, revokeCapabilityAsPlatform, readCapabilityPage, domainEventOf, facetEvents, readDeadLetters, readLifecycleFlow, readOperationSeries, readHistory, readInvocation, readUndrainedOutbox, walkEventCause, walkEventEffects, } from '@substrat-run/kernel';
10
+ import { actorOf, admitPeer, boundToPeerDeclarations, collectPeers, switchPeer, peerSubjectRef, subjectGrantState, assertNoSecret, CAPABILITY_DDL, UPLOAD_LINK_DDL, createAttachmentVerbs, inspectUploadLink, redeemUploadLinkInTransaction, COPY_ORIGIN_DDL, ENTITY_STATE_MOVES_DDL, SWITCH_FENCES_DDL, TABLE_OWNERS_DDL, assertMigrationLeavesLedgerAlone, recordOwnershipSteps, runMigrationStatements, splitSqlStatements, executableSqlStatements, blankSqlComments, CAPABILITY_EXCHANGE_OPERATION, CAPABILITY_BECOME_MINT_OPERATION, becomeMintCheck, mintBecomeCapabilityAsPrincipal, revokeBecomeCapabilityAsPrincipal, readBecomeLinkStates, ENTITY_UNBIND_OPERATION, allowedFor, unbindEntityHolderBounded, capabilityAttachmentWriteRefused, createCapabilityVerbs, createEntityEdgeVerbs, createEntityStateVerbs, createTrashedReads, CONTINUATION_POSITION_CAP, visibleContinuation, searchStateWhere, uncheckedView, addStatePlans, addUpdatedStampPlans, watchUpdatedStamps, assertNoCallerPurge, isUnreachableParent, PURGE_BATCH, heldPurgePass, lifecycleRefusal, purgeHeldBy, assertPlatformRequestRoom, purgeDueOf, purgeOnlyKeysOf, runPurgePass, refuseTrashedTarget, assertBoundOperations, checkHeldOperationsOf, countChecks, noteUncheckedCompletion, registerTrashTargets, withheldKeysFor, statefulTablesOf, afterMigration, afterRuntimeDdl, derivesAnything, repairDerivedObjects, StateColumnLost, exchangeCapability, guardSecrets, mintBecomeCapability, redactSecrets, redactSecretText, moduleLog, asyncInvocationId, asyncLinePass, resolveCapabilitySession, revokeCapabilityAsPlatform, readCapabilityPage, domainEventOf, facetEvents, readDeadLetters, readLifecycleFlow, readOperationSeries, readHistory, readInvocation, readUndrainedOutbox, walkEventCause, walkEventEffects, } from '@substrat-run/kernel';
11
11
  import { COPY_RESTORE_FENCE_LAPSED, copyRestoreFenceLapsed, orphanSweepVersionRefusal } from '@substrat-run/kernel';
12
12
  import { createDoTupleChecker, createLocalControlPlaneReader, scopeTupleReader } from './checker.js';
13
13
  import { settlePlatformRequestIn } from '@substrat-run/kernel';
@@ -762,8 +762,11 @@ options = {}) {
762
762
  assertModuleDeclared(options.permissions, registration.manifest.id);
763
763
  // What the declared surface reserves holds in every instance too, whatever registers under its ids.
764
764
  const declaredReserved = new Set();
765
- for (const m of options.permissions?.modules ?? [])
765
+ const declaredListed = new Set();
766
+ for (const m of options.permissions?.modules ?? []) {
766
767
  noteReservedKeys(declaredReserved, m.manifest);
768
+ noteDeclaredKeys(declaredListed, m.manifest);
769
+ }
767
770
  return class ScopeDO extends DurableObject {
768
771
  sql;
769
772
  continuationOrder = 0;
@@ -825,6 +828,8 @@ options = {}) {
825
828
  * `holder: 'system'` — the role and grant doors' refusals read it.
826
829
  */
827
830
  reservedKeys = new Set(declaredReserved);
831
+ /** #2447: every key those modules declare, marked or not — a role definition projected here reads it. */
832
+ declaredKeys = new Set(declaredListed);
828
833
  /** #1705: what this deployment exports to other verticals and imports from them. */
829
834
  crossVertical = new CrossVerticalRegistry();
830
835
  /**
@@ -1004,6 +1009,7 @@ options = {}) {
1004
1009
  })),
1005
1010
  });
1006
1011
  noteReservedKeys(this.reservedKeys, manifest);
1012
+ noteDeclaredKeys(this.declaredKeys, manifest);
1007
1013
  if (erasure)
1008
1014
  this.erasurePlans.push(erasure);
1009
1015
  for (const [name, handler] of Object.entries(registration.predicates ?? {})) {
@@ -1198,6 +1204,14 @@ options = {}) {
1198
1204
  databaseSize() {
1199
1205
  return this.sql.databaseSize;
1200
1206
  }
1207
+ /**
1208
+ * This scope's attachment bytes (#2501): what its attachment rows sum to
1209
+ * (`ATTACHMENT_BYTES_SQL`). Read without migrating, as `databaseSize` is. The constructor lays
1210
+ * the spine, so the table is always there, and a copy wiped of its rows reads 0.
1211
+ */
1212
+ attachmentBytes() {
1213
+ return this.sql.exec(ATTACHMENT_BYTES_SQL).toArray()[0].bytes;
1214
+ }
1201
1215
  /**
1202
1216
  * The PITR bookmarks this scope recorded before migration passes (#286),
1203
1217
  * newest first — what a backout UI offers as rewind points. Rows taken after
@@ -1209,11 +1223,21 @@ options = {}) {
1209
1223
  * written since this table shipped and selected by nobody — the frontier
1210
1224
  * readers want `(module_id, version)` only — so "when did this scope's
1211
1225
  * schema change" had no answer. A pre-column row reads null, a fact.
1226
+ *
1227
+ * Every row, never a page (#2553): the caller treats the list as the scope's whole
1228
+ * migration history, and a cap truncated it silently once a scope passed 100 rows.
1229
+ * A row is a few short columns (~150 B on the wire) and every row is an authored
1230
+ * migration a push shipped, so the set is bounded by authored migrations × pushes:
1231
+ * hundreds of rows, tens of KB, far under the RPC and response limits.
1232
+ *
1233
+ * `rowid DESC` breaks a tie: each migration reads its own clock, so neighbours can
1234
+ * share a millisecond, and the rowid is the order they were written in. `module_id,
1235
+ * version` ascending would read those oldest-first.
1212
1236
  */
1213
- appliedMigrations(limit = 100) {
1237
+ appliedMigrations() {
1214
1238
  return this.sql
1215
1239
  .exec(`SELECT module_id, version, applied_at, duration_ms, rows_changed FROM _substrat_migrations
1216
- ORDER BY applied_at DESC, module_id, version LIMIT ?`, limit)
1240
+ ORDER BY applied_at DESC, rowid DESC`)
1217
1241
  .toArray()
1218
1242
  .map((r) => ({
1219
1243
  moduleId: r.module_id,
@@ -1348,6 +1372,34 @@ options = {}) {
1348
1372
  const { verdict } = this.tenantVerdict(tenantId);
1349
1373
  return verdict === 'recorded' || verdict === 'inferred';
1350
1374
  }
1375
+ /**
1376
+ * #2541: this scope's database size, or null when the deployment does not hold it. The held
1377
+ * check and the read are ONE call: a reap or wipe cannot land between them, so a scope that
1378
+ * stopped being held is answered "not held", never with a number.
1379
+ */
1380
+ async databaseSizeIfHeld() {
1381
+ return (await this.holdsScope()) ? this.databaseSize() : null;
1382
+ }
1383
+ /** #2541: this scope's attachment bytes, or null when the deployment does not hold it; one call, as the size is. */
1384
+ async attachmentBytesIfHeld() {
1385
+ return (await this.holdsScope()) ? this.attachmentBytes() : null;
1386
+ }
1387
+ /**
1388
+ * #2541: whether this object is a scope the deployment holds, asked by a read that names only a
1389
+ * scope id. False for a DO nothing provisioned or loaded here (never provisioned), for a reaped
1390
+ * scope's name addressed again (its tombstone), and for a copy a carry wiped, whose rows went
1391
+ * with the wipe. Held otherwise: a provision receipt or role rows, or state (`holdsData`). Read
1392
+ * without migrating, so a refusal leaves the DO as it found it.
1393
+ */
1394
+ async holdsScope() {
1395
+ if (this.carriedAwayCopy || (await this.isReaped()))
1396
+ return false;
1397
+ return this.provisionedFor() !== null || this.holdsRoles() || this.holdsData();
1398
+ }
1399
+ /** Whether the scope holds any role row, of whichever tenant; read without migrating. */
1400
+ holdsRoles() {
1401
+ return this.hasTable('_substrat_roles') && this.sql.exec('SELECT 1 FROM _substrat_roles LIMIT 1').toArray().length > 0;
1402
+ }
1351
1403
  /**
1352
1404
  * #2016: what one door into this scope needs from its storage on a CP-less host, in ONE call —
1353
1405
  * how `tenantId` reads against the scope (`tenantVerdict`), and the lifecycle the platform
@@ -3170,6 +3222,29 @@ options = {}) {
3170
3222
  return parsed;
3171
3223
  });
3172
3224
  }
3225
+ /**
3226
+ * The upload's write gate and nothing else (#2516): asked by the host before a streamed body is
3227
+ * read, so a connection that may not write costs no object. Checked and recorded exactly as
3228
+ * `addAttachment` does, which still checks again when the row is written.
3229
+ */
3230
+ async checkAttachmentWrite(entity, principal, tenantId, scopeId, connectionId) {
3231
+ await this.ensureMigrations();
3232
+ const gate = this.attachmentGate(entity.entityType);
3233
+ try {
3234
+ const ctx = this.operationContext(principal, tenantId, scopeId, undefined, connectionId, undefined, undefined, undefined, 'attachments.upload');
3235
+ assertAllowed(await ctx.check(gate.write, entity));
3236
+ }
3237
+ catch (err) {
3238
+ if (err instanceof PermissionDenied) {
3239
+ this.recordDenial(attachSubject(principal, connectionId), tenantId, 'attachments.upload', err, null);
3240
+ }
3241
+ throw err;
3242
+ }
3243
+ return null;
3244
+ }
3245
+ attachmentCheckWriteReply(...args) {
3246
+ return replyOf(() => this.checkAttachmentWrite(...args));
3247
+ }
3173
3248
  /** Records for one entity, newest first — read gate first. */
3174
3249
  async listAttachments(entity, principal, tenantId, scopeId, connectionId) {
3175
3250
  await this.ensureMigrations();
@@ -3664,10 +3739,15 @@ options = {}) {
3664
3739
  /**
3665
3740
  * #2430: why `roleKey` may not be conferred through `door` here, or null — the tenant's role as
3666
3741
  * the checker expands it (`controlPlaneReader`), against the keys this class's modules reserve.
3667
- * A role the tenant does not define is left to the door's own answer for it.
3742
+ * A role the tenant does not define is left to the door's own answer for it. A person's door reads
3743
+ * the role even when this class reserves nothing (#2447): a role stored `holder: 'system'` is
3744
+ * never a person's, whatever this class knows. Accepted cost: on a class that reserves nothing, an
3745
+ * invite, a role change and a `canAssign` read the role here and again for the bound, which on a
3746
+ * scope still reading the shared directory is one more ControlPlaneDO round trip per call. These
3747
+ * doors are a person acting, not a hot path, so one read is not threaded through both.
3668
3748
  */
3669
3749
  async reservedRoleRefusalFor(tenantId, roleKey, door) {
3670
- if (this.reservedKeys.size === 0)
3750
+ if (door === 'platform' && this.reservedKeys.size === 0)
3671
3751
  return null;
3672
3752
  const role = await this.controlPlaneReader().getRole(tenantId, roleKey);
3673
3753
  return role ? reservedRoleRefusal(role, this.reservedKeys, door) : null;
@@ -3686,7 +3766,7 @@ options = {}) {
3686
3766
  * door cannot know, so it refuses.
3687
3767
  */
3688
3768
  async reservedRoleRefusalHere(roleKey, door) {
3689
- if (this.reservedKeys.size === 0)
3769
+ if (door === 'platform' && this.reservedKeys.size === 0)
3690
3770
  return null;
3691
3771
  const tenantId = this.provisionedFor();
3692
3772
  if (tenantId)
@@ -3699,7 +3779,8 @@ options = {}) {
3699
3779
  if (refusal)
3700
3780
  return refusal;
3701
3781
  }
3702
- if (tenants.length === 0 && this.permissionSourceIsRemote()) {
3782
+ // A class that reserves nothing has nothing to rule out here, at either door (#2447 keeps that).
3783
+ if (tenants.length === 0 && this.reservedKeys.size > 0 && this.permissionSourceIsRemote()) {
3703
3784
  return (`role '${roleKey}' cannot be judged here: this scope has no provisioning receipt and no projected role, and its ` +
3704
3785
  "checks read roles from the control plane, so which tenant's definition a check expands is unknown and a key " +
3705
3786
  'reserved to a system principal cannot be ruled out. Provision the scope first.');
@@ -3714,6 +3795,27 @@ options = {}) {
3714
3795
  async reservedShapeRefusalFor(shapes) {
3715
3796
  return reservedShapeRefusal(shapes, this.reservedKeys);
3716
3797
  }
3798
+ /**
3799
+ * #2447: the tenant's roles as this scope stores them, and the role keys anyone but a system
3800
+ * principal holds a live scope-level seat in here — what a role
3801
+ * set defined on this scope, or a role definition fanned out to it, is judged against.
3802
+ */
3803
+ async roleStateHere(tenantId) {
3804
+ // Spine tables only (built in the constructor), so no module migration runs ahead of a provision's.
3805
+ const now = new Date().toISOString();
3806
+ const roles = this.hasTable('_substrat_roles')
3807
+ ? this.sql.exec('SELECT role_key, permissions, holder FROM _substrat_roles WHERE tenant_id = ? AND revoked_at IS NULL', tenantId).toArray().map((r) => ({ key: r.role_key, permissions: JSON.parse(r.permissions), ...(r.holder ? { holder: r.holder } : {}) }))
3808
+ : [];
3809
+ // Scope-level seats only. The tenant-level ones are the directory's (the ControlPlaneDO reads
3810
+ // them in its own unit), and this scope's projected copy can be stale: a fan-out skips an
3811
+ // archived scope, and a CP-less projection carries none.
3812
+ const seated = new Set(this.sql.exec(SCOPE_SEATED_ROLES_SQL, now).toArray().map((r) => r.role_key));
3813
+ return { roles, seated: [...seated] };
3814
+ }
3815
+ /** #2447: what this class's modules reserve and declare — a coordinator judging a role definition joins its own. */
3816
+ async reservationHere() {
3817
+ return { reserved: [...this.reservedKeys], declared: [...this.declaredKeys] };
3818
+ }
3717
3819
  /** #2430: which of `permissions` this class's modules reserve to a system principal. */
3718
3820
  async reservedAmong(permissions) {
3719
3821
  return permissions.filter((p) => this.reservedKeys.has(p));
@@ -4100,7 +4202,12 @@ options = {}) {
4100
4202
  * positional-RPC reason `recordExecutorAttempt` gives; a coordinator without it gets a fresh
4101
4203
  * id per purge, as before.
4102
4204
  */
4103
- runInvocationId) {
4205
+ runInvocationId,
4206
+ /**
4207
+ * #2517: platform requests the purge runs earlier in the same tick enqueued. LAST and optional
4208
+ * for the same reason; absent means none, so a refused head is a failure as before.
4209
+ */
4210
+ earlierPurgeRequests) {
4104
4211
  await this.ensureMigrations();
4105
4212
  const schedule = this.purgeSchedules.get(operation);
4106
4213
  if (!schedule)
@@ -4120,9 +4227,14 @@ options = {}) {
4120
4227
  if (held !== null)
4121
4228
  return heldPurgePass(held);
4122
4229
  const due = purgeDueOf(doSpineSql(this.sql), this.statePlans, this.operationTarget, operation, schedule.entityType, new Date().toISOString(), PURGE_BATCH);
4123
- return runPurgePass(operation, due, async (entityId) => {
4124
- await this.#invokeOrThrow(operation, { [due.idFrom]: entityId }, schedule.moduleId, tenantId, scopeId, undefined, undefined, schedule.moduleId, { invocationId: runInvocationId ?? ulid() }, undefined, undefined, undefined, systemDoorInstance, true);
4125
- }, (write) => write(doSpineSql(this.sql)));
4230
+ // #2440: what each committed purge enqueued, from the same envelope an ordinary invoke's
4231
+ // caller reads. A purge that threw rolled back, and its intents with it.
4232
+ let platformRequests = 0;
4233
+ const pass = await runPurgePass(operation, due, async (entityId) => {
4234
+ const envelope = await this.#invokeOrThrow(operation, { [due.idFrom]: entityId }, schedule.moduleId, tenantId, scopeId, undefined, undefined, schedule.moduleId, { invocationId: runInvocationId ?? ulid() }, undefined, undefined, undefined, systemDoorInstance, true);
4235
+ platformRequests += envelope.platformRequests;
4236
+ }, (write) => write(doSpineSql(this.sql)), earlierPurgeRequests ?? 0);
4237
+ return platformRequests > 0 ? { ...pass, platformRequests } : pass;
4126
4238
  }
4127
4239
  /**
4128
4240
  * #119: the purge gate's facts (`PurgeGateFacts`), from this scope's own storage: the module's
@@ -4911,9 +5023,7 @@ options = {}) {
4911
5023
  const pending = Number(this.sql
4912
5024
  .exec(`SELECT COUNT(*) AS c FROM _substrat_platform_requests WHERE status = 'pending'`)
4913
5025
  .toArray()[0].c);
4914
- if (pending >= MAX_PENDING_PLATFORM_REQUESTS) {
4915
- throw new Error(`too many pending platform requests (${pending}); the delivery retries once some have drained`);
4916
- }
5026
+ assertPlatformRequestRoom(pending, 'the delivery retries once some have drained');
4917
5027
  const id = platformRequestId.parse(ulid());
4918
5028
  // K-42: the intent inherits the SOURCE EVENT's stamp rather than being written
4919
5029
  // unstamped. Nobody is impersonating at this moment — the drain runs long after
@@ -6551,9 +6661,7 @@ options = {}) {
6551
6661
  const pending = Number(sql
6552
6662
  .exec(`SELECT COUNT(*) AS c FROM _substrat_platform_requests WHERE status = 'pending'`)
6553
6663
  .toArray()[0].c);
6554
- if (pending >= MAX_PENDING_PLATFORM_REQUESTS) {
6555
- throw new Error(`too many pending platform requests (${pending}); retry once some have drained`);
6556
- }
6664
+ assertPlatformRequestRoom(pending);
6557
6665
  const id = platformRequestId.parse(ulid());
6558
6666
  const requestedBy = systemActor ?? derivedActor;
6559
6667
  sql.exec(`INSERT INTO _substrat_platform_requests
@@ -6838,27 +6946,9 @@ options = {}) {
6838
6946
  // The write side of the local reader: the coordinator fans role/tuple changes
6839
6947
  // into a scope's own storage (Phase 2), then flips the source to 'local'. Public
6840
6948
  // RPC methods so `CloudflareScopeHost` (and the projection sweep) can call them.
6841
- /** Project (upsert) a role definition into this scope. */
6842
- async projectRole(tenantId, role) {
6843
- await this.queue.enqueue(() => {
6844
- this.sql.exec(`INSERT OR REPLACE INTO _substrat_roles (tenant_id, role_key, permissions, source, holder, revoked_at)
6845
- VALUES (?, ?, ?, ?, ?, NULL)`, tenantId, role.key, JSON.stringify(role.permissions), role.source, role.holder ?? null);
6846
- });
6847
- }
6848
- /** Tombstone a projected role — it stops granting but stays as evidence (K-21). */
6849
- async revokeProjectedRole(tenantId, key, revokedAt) {
6850
- await this.queue.enqueue(() => {
6851
- this.sql.exec(`UPDATE _substrat_roles SET revoked_at = ? WHERE tenant_id = ? AND role_key = ?`, revokedAt, tenantId, key);
6852
- });
6853
- }
6854
- /** Project (upsert) a tenant-level tuple into this scope. `revokedAt` tombstones it. */
6855
- async projectTenantTuple(tenantId, subject, relation, object, expiresAt, revokedAt = null) {
6856
- await this.queue.enqueue(() => {
6857
- this.sql.exec(`INSERT OR REPLACE INTO _substrat_tenant_tuples
6858
- (tenant_id, subject, relation, object, expires_at, revoked_at)
6859
- VALUES (?, ?, ?, ?, ?, ?)`, tenantId, subject, relation, object, expiresAt, revokedAt);
6860
- });
6861
- }
6949
+ // #2531: no per-row role or tenant-tuple projection RPC. Every projected row arrives through
6950
+ // `applyProjection`, whose callers judge what they project (or fan out definitions already
6951
+ // judged), so no RPC writes a role row unjudged.
6862
6952
  /** Flip which reader the checker uses. 'local' makes projections authoritative. */
6863
6953
  async setPermissionSource(source) {
6864
6954
  await this.queue.enqueue(() => {