@nimbus-sh/platform 0.5.1 → 0.6.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.
@@ -0,0 +1,19 @@
1
+ /**
2
+ * CRC-32 (IEEE 802.3, the zip/gzip/PNG polynomial), the one implementation
3
+ * every Nimbus caller uses: the W7 write-batch framing and zip archives.
4
+ *
5
+ * `crc32(bytes, previous)` has node:zlib's contract: `previous` is the
6
+ * finished CRC of the bytes before these, so a checksum computed in pieces
7
+ * equals the checksum of the whole.
8
+ *
9
+ * Measured 2026-09-24 (5k files x 2 KiB; 64 MiB in 1 MiB buffers):
10
+ * node:zlib's crc32 is 5-40x faster than any JavaScript loop in bun, node and
11
+ * workerd (compat 2026-04-01, nodejs_compat), but each call costs ~0.14 us in
12
+ * workerd, so below 128 bytes the table loop wins there. It is reached through
13
+ * `process.getBuiltinModule`, like core's incremental SHA-256, so this module
14
+ * imports nothing and still loads where node:zlib is absent (a browser,
15
+ * workerd without nodejs_compat). The JavaScript path is slicing-by-8: 2-3x
16
+ * the byte-at-a-time table loop in bun and node, and level with it in workerd.
17
+ */
18
+ export declare function crc32(bytes: Uint8Array, previous?: number): number;
19
+ //# sourceMappingURL=crc32.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crc32.d.ts","sourceRoot":"","sources":["../src/crc32.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAqCH,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,SAAI,GAAG,MAAM,CAiB7D"}
package/dist/crc32.js ADDED
@@ -0,0 +1,67 @@
1
+ /**
2
+ * CRC-32 (IEEE 802.3, the zip/gzip/PNG polynomial), the one implementation
3
+ * every Nimbus caller uses: the W7 write-batch framing and zip archives.
4
+ *
5
+ * `crc32(bytes, previous)` has node:zlib's contract: `previous` is the
6
+ * finished CRC of the bytes before these, so a checksum computed in pieces
7
+ * equals the checksum of the whole.
8
+ *
9
+ * Measured 2026-09-24 (5k files x 2 KiB; 64 MiB in 1 MiB buffers):
10
+ * node:zlib's crc32 is 5-40x faster than any JavaScript loop in bun, node and
11
+ * workerd (compat 2026-04-01, nodejs_compat), but each call costs ~0.14 us in
12
+ * workerd, so below 128 bytes the table loop wins there. It is reached through
13
+ * `process.getBuiltinModule`, like core's incremental SHA-256, so this module
14
+ * imports nothing and still loads where node:zlib is absent (a browser,
15
+ * workerd without nodejs_compat). The JavaScript path is slicing-by-8: 2-3x
16
+ * the byte-at-a-time table loop in bun and node, and level with it in workerd.
17
+ */
18
+ /** Below this many bytes the native call's overhead exceeds the JavaScript loop's work (workerd). */
19
+ const CRC_NATIVE_MIN_BYTES = 128;
20
+ const nativeCrc32 = (() => {
21
+ try {
22
+ const crc32 = globalThis.process?.getBuiltinModule?.('node:zlib')?.crc32;
23
+ return typeof crc32 === 'function' ? crc32 : null;
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ })();
29
+ /** Eight 256-entry tables: table k maps a byte to its CRC after k further zero bytes. */
30
+ let crcTables = null;
31
+ function createCrcTables() {
32
+ const table = new Uint32Array(256 * 8);
33
+ for (let index = 0; index < 256; index++) {
34
+ let value = index;
35
+ for (let bit = 0; bit < 8; bit++)
36
+ value = (value & 1) !== 0 ? 0xedb8_8320 ^ (value >>> 1) : value >>> 1;
37
+ table[index] = value;
38
+ }
39
+ for (let index = 0; index < 256; index++) {
40
+ let value = table[index];
41
+ for (let k = 1; k < 8; k++) {
42
+ value = table[value & 0xff] ^ (value >>> 8);
43
+ table[k * 256 + index] = value;
44
+ }
45
+ }
46
+ return table;
47
+ }
48
+ export function crc32(bytes, previous = 0) {
49
+ if (nativeCrc32 !== null && bytes.length >= CRC_NATIVE_MIN_BYTES)
50
+ return nativeCrc32(bytes, previous) >>> 0;
51
+ const t = crcTables ??= createCrcTables();
52
+ let value = ~previous;
53
+ const length = bytes.length;
54
+ const whole = length - (length & 7);
55
+ let i = 0;
56
+ for (; i < whole; i += 8) {
57
+ const low = value ^ (bytes[i] | (bytes[i + 1] << 8) | (bytes[i + 2] << 16) | (bytes[i + 3] << 24));
58
+ const high = bytes[i + 4] | (bytes[i + 5] << 8) | (bytes[i + 6] << 16) | (bytes[i + 7] << 24);
59
+ value = t[1792 + (low & 0xff)] ^ t[1536 + ((low >>> 8) & 0xff)]
60
+ ^ t[1280 + ((low >>> 16) & 0xff)] ^ t[1024 + (low >>> 24)]
61
+ ^ t[768 + (high & 0xff)] ^ t[512 + ((high >>> 8) & 0xff)]
62
+ ^ t[256 + ((high >>> 16) & 0xff)] ^ t[high >>> 24];
63
+ }
64
+ for (; i < length; i++)
65
+ value = t[(value ^ bytes[i]) & 0xff] ^ (value >>> 8);
66
+ return ~value >>> 0;
67
+ }
@@ -6,7 +6,7 @@
6
6
  * `process.memoryUsage()` returns 0 for every field inside a Durable
7
7
  * Object class context (only dynamic-worker isolates under nodejs_compat
8
8
  * get the real implementation). The previous `readNodeMem` /
9
- * `sampleMemory` helpers in nimbus-session-diag.ts called it anyway and
9
+ * `sampleMemory` helpers in session/diag.ts called it anyway and
10
10
  * therefore reported zero forever — useless for verifying memory-
11
11
  * containment work in plan §3 Track A'.
12
12
  *
@@ -6,7 +6,7 @@
6
6
  * `process.memoryUsage()` returns 0 for every field inside a Durable
7
7
  * Object class context (only dynamic-worker isolates under nodejs_compat
8
8
  * get the real implementation). The previous `readNodeMem` /
9
- * `sampleMemory` helpers in nimbus-session-diag.ts called it anyway and
9
+ * `sampleMemory` helpers in session/diag.ts called it anyway and
10
10
  * therefore reported zero forever — useless for verifying memory-
11
11
  * containment work in plan §3 Track A'.
12
12
  *
package/dist/limits.d.ts CHANGED
@@ -38,6 +38,7 @@ export declare const SQL_MAX_BOUND_PARAMETERS = 100;
38
38
  * clone, with reserve.
39
39
  */
40
40
  export declare const DO_STORAGE_LIMIT_BYTES = 10000000000;
41
+ export declare const HYDRATION_DEADLINE_MS = 30000;
41
42
  /**
42
43
  * Maximum SQL statement text per exec. Documented "100 KB"; read as binary
43
44
  * KiB because the value is SQLite's compile-time SQLITE_MAX_SQL_LENGTH
@@ -103,7 +104,9 @@ export declare const RESIDENT_KEEPALIVE_DETACHED_MS = 60000;
103
104
  */
104
105
  export declare const WS_ATTACHMENT_LIMIT_BYTES = 16384;
105
106
  export declare const MAX_RPC_SAFE_PAYLOAD_BYTES: number;
107
+ export declare const ONE_SHOT_MODULE_MAP_MAX_BYTES: number;
106
108
  export declare const SUPERVISOR_HEAP_CEILING_BYTES: number;
109
+ export declare const FACET_OWN_WRITE_MEMORY_BYTES: number;
107
110
  export declare const SUPERVISOR_IN_FLIGHT_ALLOCATION_BUDGET_BYTES: number;
108
111
  export declare const SUPERVISOR_READ_RESERVE_BYTES: number;
109
112
  export declare const MAX_GLOBAL_WRITE_STREAM_CREDIT_BYTES: number;
@@ -1 +1 @@
1
- {"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,QAAS,CAAC;AAEjC,eAAO,MAAM,iBAAiB,QAAkB,CAAC;AACjD,eAAO,MAAM,mBAAmB,MAAM,CAAC;AACvC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAI5C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,cAAiB,CAAC;AAErD;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,QAAa,CAAC;AAErD;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,UAAY,CAAC;AAI9C;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAIlD;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,OAAQ,CAAC;AAE3C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,8BAA8B,QAAS,CAAC;AAIrD;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAOhD,eAAO,MAAM,0BAA0B,QAAmB,CAAC;AA6B3D,eAAO,MAAM,6BAA6B,QAAmB,CAAC;AAO9D,eAAO,MAAM,4CAA4C,QAAmB,CAAC;AAY7E,eAAO,MAAM,6BAA6B,QAAc,CAAC;AAKzD,eAAO,MAAM,oCAAoC,QAAkB,CAAC;AAQpE,eAAO,MAAM,0BAA0B,QAA6B,CAAC;AACrE,eAAO,MAAM,sBAAsB,IAAI,CAAC"}
1
+ {"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,QAAS,CAAC;AAEjC,eAAO,MAAM,iBAAiB,QAAkB,CAAC;AACjD,eAAO,MAAM,mBAAmB,MAAM,CAAC;AACvC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAI5C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,cAAiB,CAAC;AAMrD,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAE5C;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,QAAa,CAAC;AAErD;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,UAAY,CAAC;AAI9C;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAIlD;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,OAAQ,CAAC;AAE3C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,8BAA8B,QAAS,CAAC;AAIrD;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAOhD,eAAO,MAAM,0BAA0B,QAAmB,CAAC;AAmB3D,eAAO,MAAM,6BAA6B,QAAmB,CAAC;AA6B9D,eAAO,MAAM,6BAA6B,QAAmB,CAAC;AAM9D,eAAO,MAAM,4BAA4B,QAAmB,CAAC;AAO7D,eAAO,MAAM,4CAA4C,QAAmB,CAAC;AAY7E,eAAO,MAAM,6BAA6B,QAAc,CAAC;AAKzD,eAAO,MAAM,oCAAoC,QAAkB,CAAC;AAQpE,eAAO,MAAM,0BAA0B,QAA6B,CAAC;AACrE,eAAO,MAAM,sBAAsB,IAAI,CAAC"}
package/dist/limits.js CHANGED
@@ -45,6 +45,11 @@ export const SQL_MAX_BOUND_PARAMETERS = 100;
45
45
  * clone, with reserve.
46
46
  */
47
47
  export const DO_STORAGE_LIMIT_BYTES = 10_000_000_000;
48
+ // N17: how long a launch that reads synchronously (WASI) waits for the paths
49
+ // it names to hydrate out of a lazy import before it fails with EIO naming
50
+ // the first that is not local. Bounded so a fetch that never resolves cannot
51
+ // hold a launch forever.
52
+ export const HYDRATION_DEADLINE_MS = 30_000;
48
53
  /**
49
54
  * Maximum SQL statement text per exec. Documented "100 KB"; read as binary
50
55
  * KiB because the value is SQLite's compile-time SQLITE_MAX_SQL_LENGTH
@@ -117,6 +122,24 @@ export const WS_ATTACHMENT_LIMIT_BYTES = 16_384;
117
122
  // The platform limit is 32 MiB; 28 MiB leaves room for structured-clone
118
123
  // metadata and matches the proven on-demand facet transfer envelope.
119
124
  export const MAX_RPC_SAFE_PAYLOAD_BYTES = 28 * 1024 * 1024;
125
+ // ── A one-shot's module map [#13] ───────────────────────────────────────
126
+ //
127
+ // The largest one-shot module map (its closure's raw bytes) the session DO
128
+ // builds and hands to the Worker Loader. What limits it is the DO, not the
129
+ // loader (whose documented limits are concurrency only): the map is built,
130
+ // serialized and passed on from the DO's 128 MB isolate.
131
+ //
132
+ // Measured on a throwaway (2026-09-26; session DO max memoryUsageBytes from
133
+ // GraphQL durableObjectsPeriodicGroups, one launch per minute; a package of
134
+ // 256 KiB distinct modules required whole, verify/release/do-headroom.md),
135
+ // with the map serialized one side module at a time:
136
+ // 4 MiB 64 MB, 8 MiB 81 MB, 12 MiB 97 MB, 16 MiB 110 MB, 20 MiB 126 MB,
137
+ // 24 MiB 145 MB, 28 MiB 164 MB, over an idle 40-55 MB.
138
+ // That is about 4.5 MB of DO per MiB of map. 18 MiB, about 118 MB, is the
139
+ // largest size that leaves about 10 MB of the 128 MB for the rest of the
140
+ // session's work. (Before the single-copy build it was 6-7 MB per MiB: 24 MiB
141
+ // reset the DO.)
142
+ export const ONE_SHOT_MODULE_MAP_MAX_BYTES = 18 * 1024 * 1024;
120
143
  // ── Supervisor heap budget [C'.1] ───────────────────────────────────────
121
144
  //
122
145
  // Three distinct memory regimes, not one shared pool:
@@ -145,6 +168,11 @@ export const MAX_RPC_SAFE_PAYLOAD_BYTES = 28 * 1024 * 1024;
145
168
  // sites known to be missing are listed in HEAP_BLIND_SPOTS. Read a low
146
169
  // percentOfCeiling accordingly.
147
170
  export const SUPERVISOR_HEAP_CEILING_BYTES = 64 * 1024 * 1024;
171
+ // A process facet's own writes its store could not hold (N18: the session's
172
+ // storage is full) are kept in its heap instead, so a write-then-read still
173
+ // works: at most this many bytes, least recently used out first. An eighth
174
+ // of a facet's measured ~208-256 MiB, the rest left to the program.
175
+ export const FACET_OWN_WRITE_MEMORY_BYTES = 32 * 1024 * 1024;
148
176
  // Shared allowance for transient allocations in the supervisor DO. With the
149
177
  // VFS LRU shrunk to 8 MiB during an active reservation, 40 MiB of admitted
150
178
  // payload plus the 9 MiB bundle baseline stays below the 64 MiB soft ceiling
@@ -123,7 +123,7 @@ export declare function isTransientDoReset(input: unknown): boolean;
123
123
  export declare function isDoOverloaded(input: unknown): boolean;
124
124
  /**
125
125
  * How one failed Durable Object call relates to a retry. The taxonomy
126
- * Proteus hand-wrote in `cf-backend/src/lib/do-rpc.ts:71-79` because the
126
+ * Proteus originally hand-wrote in `cf-backend/src/lib/do-rpc.ts` because the
127
127
  * Agents SDK does not export its own, plus the `overloaded` class both
128
128
  * consumers need: Cloudflare documents that errors carry `.retryable` and
129
129
  * `.overloaded`, that a retryable error should be retried with backoff on a
@@ -1 +1 @@
1
- {"version":3,"file":"oom-classify.d.ts","sourceRoot":"","sources":["../src/oom-classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AAEH,QAAA,MAAM,UAAU,kLAYN,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;AAEjD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAItD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAkErD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAO1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEtD;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW;AACrB,8CAA8C;AAC5C,oBAAoB;AACtB,8CAA8C;GAC5C,iBAAiB;AACnB,uEAAuE;GACrE,eAAe;AACjB,wDAAwD;GACtD,gBAAgB;AAClB;kDACkD;GAChD,YAAY;AACd,kEAAkE;GAChE,WAAW,CAAC;AAEhB;2DAC2D;AAC3D,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAK7D;AAmBD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAsB1D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAgBpD"}
1
+ {"version":3,"file":"oom-classify.d.ts","sourceRoot":"","sources":["../src/oom-classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AAEH,QAAA,MAAM,UAAU,kLAYN,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;AAEjD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAItD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAkErD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAO1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEtD;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW;AACrB,8CAA8C;AAC5C,oBAAoB;AACtB,8CAA8C;GAC5C,iBAAiB;AACnB,uEAAuE;GACrE,eAAe;AACjB,wDAAwD;GACtD,gBAAgB;AAClB;kDACkD;GAChD,YAAY;AACd,kEAAkE;GAChE,WAAW,CAAC;AAEhB;2DAC2D;AAC3D,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAK7D;AAmBD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAsB1D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAiBpD"}
@@ -311,7 +311,8 @@ export function describeError(input) {
311
311
  const suffix = cause !== 'unknown' ? ` [${cause}]`
312
312
  : isTransientDoReset(input) ? ' [transient-do-reset]'
313
313
  : isDoOverloaded(input) ? ' [do-overloaded]'
314
- : '';
314
+ : classifyDoCall(input) === 'retryable_flag' ? ' [retryable]'
315
+ : '';
315
316
  return `${name}${message}${suffix}`;
316
317
  }
317
318
  function readMessage(input) {
@@ -1 +1 @@
1
- {"version":3,"file":"w7-frame.d.ts","sourceRoot":"","sources":["../src/w7-frame.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"w7-frame.d.ts","sourceRoot":"","sources":["../src/w7-frame.ts"],"names":[],"mappings":"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"}
package/dist/w7-frame.js CHANGED
@@ -2,6 +2,7 @@
2
2
  * W7 v3 — incremental typed records for streamed bulk filesystem writes.
3
3
  * The format is internal: every producer and consumer deploys together.
4
4
  */
5
+ import { crc32 } from './crc32.js';
5
6
  import { CHUNK_SIZE } from './limits.js';
6
7
  export const W7_MAGIC = new Uint8Array([0x4e, 0x57, 0x37, 0x03]);
7
8
  const ENCODER_QUEUE_HWM = 0;
@@ -101,7 +102,7 @@ export async function decodeWriteBatchStream(stream, options = {}) {
101
102
  }
102
103
  const beginPayload = await buffer.readExact(beginEnvelope.length, 'batch-begin payload');
103
104
  const begin = parseBatchBegin(beginPayload);
104
- const initialCheck = updateRecordCheck(CRC_SEED, beginEnvelope.header, beginPayload);
105
+ const initialCheck = updateRecordCheck(0, beginEnvelope.header, beginPayload);
105
106
  handedOff = true;
106
107
  return {
107
108
  batchId: begin.id,
@@ -180,7 +181,7 @@ async function* decodeRecords(stream, reader, buffer, options, initialCheck) {
180
181
  throwIfAborted(options.signal);
181
182
  const data = await buffer.readExact(dataLength, 'file-chunk data');
182
183
  batchCheck = updateRecordCheck(batchCheck, envelope.header, headerPayload, data);
183
- active.check = crc32Update(active.check, data);
184
+ active.check = crc32(data, active.check);
184
185
  active.nextChunkId++;
185
186
  active.receivedBytes += dataLength;
186
187
  summary.recordCount++;
@@ -242,7 +243,7 @@ async function* decodeRecords(stream, reader, buffer, options, initialCheck) {
242
243
  inode,
243
244
  nextChunkId: 0,
244
245
  receivedBytes: 0,
245
- check: CRC_SEED,
246
+ check: 0,
246
247
  };
247
248
  yield { type: 'file-begin', streamContentId: metadata.contentId, inode };
248
249
  break;
@@ -251,7 +252,7 @@ async function* decodeRecords(stream, reader, buffer, options, initialCheck) {
251
252
  if (!active)
252
253
  throw new Error('w7-frame: file-end without active file');
253
254
  const metadata = parseFileEnd(payload);
254
- const actualCheck = crc32Finish(active.check);
255
+ const actualCheck = active.check;
255
256
  if (metadata.contentId !== active.metadata.contentId) {
256
257
  throw new Error(`w7-frame: file-end content id mismatch for ${active.inode.path}`);
257
258
  }
@@ -281,7 +282,7 @@ async function* decodeRecords(stream, reader, buffer, options, initialCheck) {
281
282
  if (active)
282
283
  throw new Error(`w7-frame: batch-end while file ${active.inode.path} is active`);
283
284
  const actual = parseBatchEnd(payload);
284
- const expected = { ...summary, check: crc32Finish(batchCheck) };
285
+ const expected = { ...summary, check: batchCheck };
285
286
  if (!sameSummary(actual, expected)) {
286
287
  throw new Error(`w7-frame: batch-end summary mismatch; expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);
287
288
  }
@@ -315,7 +316,7 @@ async function* decodeRecords(stream, reader, buffer, options, initialCheck) {
315
316
  }
316
317
  function* encodeRecords(batchId, deletes, directories, files) {
317
318
  const state = {
318
- batchCheck: CRC_SEED,
319
+ batchCheck: 0,
319
320
  summary: {
320
321
  recordCount: 0,
321
322
  pathCount: 0,
@@ -350,7 +351,7 @@ function* encodeRecords(batchId, deletes, directories, files) {
350
351
  size: file.inode.size,
351
352
  chunkCount: file.inode.chunkCount,
352
353
  }, state);
353
- let fileCheck = CRC_SEED;
354
+ let fileCheck = 0;
354
355
  for (const chunk of file.chunks) {
355
356
  const data = chunk.data;
356
357
  const contentBytes = new TextEncoder().encode(file.contentId);
@@ -364,19 +365,19 @@ function* encodeRecords(batchId, deletes, directories, files) {
364
365
  state.summary.recordCount++;
365
366
  state.summary.chunkCount++;
366
367
  state.summary.byteCount += data.byteLength;
367
- fileCheck = crc32Update(fileCheck, data);
368
+ fileCheck = crc32(data, fileCheck);
368
369
  yield [concatBytes(header, prefix), data];
369
370
  }
370
371
  yield encodeMetadataRecord(RecordTag.FileEnd, {
371
372
  contentId: file.contentId,
372
373
  size: file.inode.size,
373
374
  chunkCount: file.inode.chunkCount,
374
- check: crc32Finish(fileCheck),
375
+ check: fileCheck,
375
376
  }, state);
376
377
  }
377
378
  const end = {
378
379
  ...state.summary,
379
- check: crc32Finish(state.batchCheck),
380
+ check: state.batchCheck,
380
381
  };
381
382
  yield encodeMetadataRecord(RecordTag.BatchEnd, end);
382
383
  }
@@ -718,33 +719,9 @@ function readU32LE(bytes, offset) {
718
719
  function updateRecordCheck(seed, ...parts) {
719
720
  let check = seed;
720
721
  for (const part of parts)
721
- check = crc32Update(check, part);
722
+ check = crc32(part, check);
722
723
  return check;
723
724
  }
724
- const CRC_SEED = 0xffff_ffff;
725
- let crcTable = null;
726
- function crc32Update(check, bytes) {
727
- crcTable ??= createCrcTable();
728
- const table = crcTable;
729
- let value = check;
730
- for (const byte of bytes)
731
- value = table[(value ^ byte) & 0xff] ^ (value >>> 8);
732
- return value >>> 0;
733
- }
734
- function crc32Finish(check) {
735
- return (check ^ 0xffff_ffff) >>> 0;
736
- }
737
- function createCrcTable() {
738
- const table = new Uint32Array(256);
739
- for (let index = 0; index < table.length; index++) {
740
- let value = index;
741
- for (let bit = 0; bit < 8; bit++) {
742
- value = (value & 1) !== 0 ? 0xedb8_8320 ^ (value >>> 1) : value >>> 1;
743
- }
744
- table[index] = value >>> 0;
745
- }
746
- return table;
747
- }
748
725
  function noopRetention(bytes) {
749
726
  return { bytes, release() { } };
750
727
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nimbus-sh/platform",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "The measured Cloudflare platform truths Nimbus is built on \u2014 error taxonomy, limits tables, budget coordination, and wire-format primitives, with zero runtime dependencies.",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -43,8 +43,8 @@
43
43
  "LICENSE"
44
44
  ],
45
45
  "scripts": {
46
- "build": "tsc -p tsconfig.json --noCheck --noEmit false --declaration true --declarationMap true --outDir dist --rootDir src",
47
- "prepack": "npm run build",
46
+ "build": "node ../../scripts/clean-dist.mjs && tsc -p tsconfig.json --noCheck --noEmit false --declaration true --declarationMap true --outDir dist --rootDir src",
47
+ "prepublishOnly": "bun ../../scripts/dist-integrity.mjs --publish",
48
48
  "typecheck": "tsc --noEmit"
49
49
  },
50
50
  "devDependencies": {
package/src/crc32.ts ADDED
@@ -0,0 +1,71 @@
1
+ /**
2
+ * CRC-32 (IEEE 802.3, the zip/gzip/PNG polynomial), the one implementation
3
+ * every Nimbus caller uses: the W7 write-batch framing and zip archives.
4
+ *
5
+ * `crc32(bytes, previous)` has node:zlib's contract: `previous` is the
6
+ * finished CRC of the bytes before these, so a checksum computed in pieces
7
+ * equals the checksum of the whole.
8
+ *
9
+ * Measured 2026-09-24 (5k files x 2 KiB; 64 MiB in 1 MiB buffers):
10
+ * node:zlib's crc32 is 5-40x faster than any JavaScript loop in bun, node and
11
+ * workerd (compat 2026-04-01, nodejs_compat), but each call costs ~0.14 us in
12
+ * workerd, so below 128 bytes the table loop wins there. It is reached through
13
+ * `process.getBuiltinModule`, like core's incremental SHA-256, so this module
14
+ * imports nothing and still loads where node:zlib is absent (a browser,
15
+ * workerd without nodejs_compat). The JavaScript path is slicing-by-8: 2-3x
16
+ * the byte-at-a-time table loop in bun and node, and level with it in workerd.
17
+ */
18
+
19
+ type NodeZlib = { crc32?(data: Uint8Array, value?: number): number };
20
+ type BuiltinModules = { process?: { getBuiltinModule?(id: 'node:zlib'): NodeZlib | undefined } };
21
+
22
+ /** Below this many bytes the native call's overhead exceeds the JavaScript loop's work (workerd). */
23
+ const CRC_NATIVE_MIN_BYTES = 128;
24
+
25
+ const nativeCrc32 = (() => {
26
+ try {
27
+ const crc32 = (globalThis as BuiltinModules).process?.getBuiltinModule?.('node:zlib')?.crc32;
28
+ return typeof crc32 === 'function' ? crc32 : null;
29
+ } catch {
30
+ return null;
31
+ }
32
+ })();
33
+
34
+ /** Eight 256-entry tables: table k maps a byte to its CRC after k further zero bytes. */
35
+ let crcTables: Uint32Array | null = null;
36
+
37
+ function createCrcTables(): Uint32Array {
38
+ const table = new Uint32Array(256 * 8);
39
+ for (let index = 0; index < 256; index++) {
40
+ let value = index;
41
+ for (let bit = 0; bit < 8; bit++) value = (value & 1) !== 0 ? 0xedb8_8320 ^ (value >>> 1) : value >>> 1;
42
+ table[index] = value;
43
+ }
44
+ for (let index = 0; index < 256; index++) {
45
+ let value = table[index];
46
+ for (let k = 1; k < 8; k++) {
47
+ value = table[value & 0xff] ^ (value >>> 8);
48
+ table[k * 256 + index] = value;
49
+ }
50
+ }
51
+ return table;
52
+ }
53
+
54
+ export function crc32(bytes: Uint8Array, previous = 0): number {
55
+ if (nativeCrc32 !== null && bytes.length >= CRC_NATIVE_MIN_BYTES) return nativeCrc32(bytes, previous) >>> 0;
56
+ const t = crcTables ??= createCrcTables();
57
+ let value = ~previous;
58
+ const length = bytes.length;
59
+ const whole = length - (length & 7);
60
+ let i = 0;
61
+ for (; i < whole; i += 8) {
62
+ const low = value ^ (bytes[i] | (bytes[i + 1] << 8) | (bytes[i + 2] << 16) | (bytes[i + 3] << 24));
63
+ const high = bytes[i + 4] | (bytes[i + 5] << 8) | (bytes[i + 6] << 16) | (bytes[i + 7] << 24);
64
+ value = t[1792 + (low & 0xff)] ^ t[1536 + ((low >>> 8) & 0xff)]
65
+ ^ t[1280 + ((low >>> 16) & 0xff)] ^ t[1024 + (low >>> 24)]
66
+ ^ t[768 + (high & 0xff)] ^ t[512 + ((high >>> 8) & 0xff)]
67
+ ^ t[256 + ((high >>> 16) & 0xff)] ^ t[high >>> 24];
68
+ }
69
+ for (; i < length; i++) value = t[(value ^ bytes[i]) & 0xff] ^ (value >>> 8);
70
+ return ~value >>> 0;
71
+ }
@@ -6,7 +6,7 @@
6
6
  * `process.memoryUsage()` returns 0 for every field inside a Durable
7
7
  * Object class context (only dynamic-worker isolates under nodejs_compat
8
8
  * get the real implementation). The previous `readNodeMem` /
9
- * `sampleMemory` helpers in nimbus-session-diag.ts called it anyway and
9
+ * `sampleMemory` helpers in session/diag.ts called it anyway and
10
10
  * therefore reported zero forever — useless for verifying memory-
11
11
  * containment work in plan §3 Track A'.
12
12
  *
package/src/limits.ts CHANGED
@@ -52,6 +52,12 @@ export const SQL_MAX_BOUND_PARAMETERS = 100;
52
52
  */
53
53
  export const DO_STORAGE_LIMIT_BYTES = 10_000_000_000;
54
54
 
55
+ // N17: how long a launch that reads synchronously (WASI) waits for the paths
56
+ // it names to hydrate out of a lazy import before it fails with EIO naming
57
+ // the first that is not local. Bounded so a fetch that never resolves cannot
58
+ // hold a launch forever.
59
+ export const HYDRATION_DEADLINE_MS = 30_000;
60
+
55
61
  /**
56
62
  * Maximum SQL statement text per exec. Documented "100 KB"; read as binary
57
63
  * KiB because the value is SQLite's compile-time SQLITE_MAX_SQL_LENGTH
@@ -136,6 +142,25 @@ export const WS_ATTACHMENT_LIMIT_BYTES = 16_384;
136
142
  // metadata and matches the proven on-demand facet transfer envelope.
137
143
  export const MAX_RPC_SAFE_PAYLOAD_BYTES = 28 * 1024 * 1024;
138
144
 
145
+ // ── A one-shot's module map [#13] ───────────────────────────────────────
146
+ //
147
+ // The largest one-shot module map (its closure's raw bytes) the session DO
148
+ // builds and hands to the Worker Loader. What limits it is the DO, not the
149
+ // loader (whose documented limits are concurrency only): the map is built,
150
+ // serialized and passed on from the DO's 128 MB isolate.
151
+ //
152
+ // Measured on a throwaway (2026-09-26; session DO max memoryUsageBytes from
153
+ // GraphQL durableObjectsPeriodicGroups, one launch per minute; a package of
154
+ // 256 KiB distinct modules required whole, verify/release/do-headroom.md),
155
+ // with the map serialized one side module at a time:
156
+ // 4 MiB 64 MB, 8 MiB 81 MB, 12 MiB 97 MB, 16 MiB 110 MB, 20 MiB 126 MB,
157
+ // 24 MiB 145 MB, 28 MiB 164 MB, over an idle 40-55 MB.
158
+ // That is about 4.5 MB of DO per MiB of map. 18 MiB, about 118 MB, is the
159
+ // largest size that leaves about 10 MB of the 128 MB for the rest of the
160
+ // session's work. (Before the single-copy build it was 6-7 MB per MiB: 24 MiB
161
+ // reset the DO.)
162
+ export const ONE_SHOT_MODULE_MAP_MAX_BYTES = 18 * 1024 * 1024;
163
+
139
164
  // ── Supervisor heap budget [C'.1] ───────────────────────────────────────
140
165
  //
141
166
  // Three distinct memory regimes, not one shared pool:
@@ -165,6 +190,12 @@ export const MAX_RPC_SAFE_PAYLOAD_BYTES = 28 * 1024 * 1024;
165
190
  // percentOfCeiling accordingly.
166
191
  export const SUPERVISOR_HEAP_CEILING_BYTES = 64 * 1024 * 1024;
167
192
 
193
+ // A process facet's own writes its store could not hold (N18: the session's
194
+ // storage is full) are kept in its heap instead, so a write-then-read still
195
+ // works: at most this many bytes, least recently used out first. An eighth
196
+ // of a facet's measured ~208-256 MiB, the rest left to the program.
197
+ export const FACET_OWN_WRITE_MEMORY_BYTES = 32 * 1024 * 1024;
198
+
168
199
  // Shared allowance for transient allocations in the supervisor DO. With the
169
200
  // VFS LRU shrunk to 8 MiB during an active reservation, 40 MiB of admitted
170
201
  // payload plus the 9 MiB bundle baseline stays below the 64 MiB soft ceiling
@@ -224,7 +224,7 @@ export function isDoOverloaded(input: unknown): boolean {
224
224
 
225
225
  /**
226
226
  * How one failed Durable Object call relates to a retry. The taxonomy
227
- * Proteus hand-wrote in `cf-backend/src/lib/do-rpc.ts:71-79` because the
227
+ * Proteus originally hand-wrote in `cf-backend/src/lib/do-rpc.ts` because the
228
228
  * Agents SDK does not export its own, plus the `overloaded` class both
229
229
  * consumers need: Cloudflare documents that errors carry `.retryable` and
230
230
  * `.overloaded`, that a retryable error should be retried with backoff on a
@@ -329,6 +329,7 @@ export function describeError(input: unknown): string {
329
329
  const suffix = cause !== 'unknown' ? ` [${cause}]`
330
330
  : isTransientDoReset(input) ? ' [transient-do-reset]'
331
331
  : isDoOverloaded(input) ? ' [do-overloaded]'
332
+ : classifyDoCall(input) === 'retryable_flag' ? ' [retryable]'
332
333
  : '';
333
334
  return `${name}${message}${suffix}`;
334
335
  }
package/src/w7-frame.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  * The format is internal: every producer and consumer deploys together.
4
4
  */
5
5
 
6
+ import { crc32 } from './crc32.js';
6
7
  import { CHUNK_SIZE } from './limits.js';
7
8
 
8
9
  // The batch payload types live WITH the wire format that encodes them: every
@@ -246,7 +247,7 @@ export async function decodeWriteBatchStream(
246
247
  }
247
248
  const beginPayload = await buffer.readExact(beginEnvelope.length, 'batch-begin payload');
248
249
  const begin = parseBatchBegin(beginPayload);
249
- const initialCheck = updateRecordCheck(CRC_SEED, beginEnvelope.header, beginPayload);
250
+ const initialCheck = updateRecordCheck(0, beginEnvelope.header, beginPayload);
250
251
  handedOff = true;
251
252
  return {
252
253
  batchId: begin.id,
@@ -343,7 +344,7 @@ async function* decodeRecords(
343
344
  throwIfAborted(options.signal);
344
345
  const data = await buffer.readExact(dataLength, 'file-chunk data');
345
346
  batchCheck = updateRecordCheck(batchCheck, envelope.header, headerPayload, data);
346
- active.check = crc32Update(active.check, data);
347
+ active.check = crc32(data, active.check);
347
348
  active.nextChunkId++;
348
349
  active.receivedBytes += dataLength;
349
350
  summary.recordCount++;
@@ -406,7 +407,7 @@ async function* decodeRecords(
406
407
  inode,
407
408
  nextChunkId: 0,
408
409
  receivedBytes: 0,
409
- check: CRC_SEED,
410
+ check: 0,
410
411
  };
411
412
  yield { type: 'file-begin', streamContentId: metadata.contentId, inode };
412
413
  break;
@@ -414,7 +415,7 @@ async function* decodeRecords(
414
415
  case RecordTag.FileEnd: {
415
416
  if (!active) throw new Error('w7-frame: file-end without active file');
416
417
  const metadata = parseFileEnd(payload);
417
- const actualCheck = crc32Finish(active.check);
418
+ const actualCheck = active.check;
418
419
  if (metadata.contentId !== active.metadata.contentId) {
419
420
  throw new Error(`w7-frame: file-end content id mismatch for ${active.inode.path}`);
420
421
  }
@@ -443,7 +444,7 @@ async function* decodeRecords(
443
444
  case RecordTag.BatchEnd: {
444
445
  if (active) throw new Error(`w7-frame: batch-end while file ${active.inode.path} is active`);
445
446
  const actual = parseBatchEnd(payload);
446
- const expected = { ...summary, check: crc32Finish(batchCheck) };
447
+ const expected = { ...summary, check: batchCheck };
447
448
  if (!sameSummary(actual, expected)) {
448
449
  throw new Error(
449
450
  `w7-frame: batch-end summary mismatch; expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`,
@@ -479,7 +480,7 @@ function* encodeRecords(
479
480
  files: EncoderFile[],
480
481
  ): Generator<Uint8Array[]> {
481
482
  const state: EncoderState = {
482
- batchCheck: CRC_SEED,
483
+ batchCheck: 0,
483
484
  summary: {
484
485
  recordCount: 0,
485
486
  pathCount: 0,
@@ -514,7 +515,7 @@ function* encodeRecords(
514
515
  size: file.inode.size,
515
516
  chunkCount: file.inode.chunkCount,
516
517
  }, state);
517
- let fileCheck = CRC_SEED;
518
+ let fileCheck = 0;
518
519
  for (const chunk of file.chunks) {
519
520
  const data = chunk.data;
520
521
  const contentBytes = new TextEncoder().encode(file.contentId);
@@ -528,19 +529,19 @@ function* encodeRecords(
528
529
  state.summary.recordCount++;
529
530
  state.summary.chunkCount++;
530
531
  state.summary.byteCount += data.byteLength;
531
- fileCheck = crc32Update(fileCheck, data);
532
+ fileCheck = crc32(data, fileCheck);
532
533
  yield [concatBytes(header, prefix), data];
533
534
  }
534
535
  yield encodeMetadataRecord(RecordTag.FileEnd, {
535
536
  contentId: file.contentId,
536
537
  size: file.inode.size,
537
538
  chunkCount: file.inode.chunkCount,
538
- check: crc32Finish(fileCheck),
539
+ check: fileCheck,
539
540
  }, state);
540
541
  }
541
542
  const end: W7BatchSummary = {
542
543
  ...state.summary,
543
- check: crc32Finish(state.batchCheck),
544
+ check: state.batchCheck,
544
545
  };
545
546
  yield encodeMetadataRecord(RecordTag.BatchEnd, end);
546
547
  }
@@ -916,37 +917,10 @@ function readU32LE(bytes: Uint8Array, offset: number): number {
916
917
 
917
918
  function updateRecordCheck(seed: number, ...parts: Uint8Array[]): number {
918
919
  let check = seed;
919
- for (const part of parts) check = crc32Update(check, part);
920
+ for (const part of parts) check = crc32(part, check);
920
921
  return check;
921
922
  }
922
923
 
923
- const CRC_SEED = 0xffff_ffff;
924
- let crcTable: Uint32Array | null = null;
925
-
926
- function crc32Update(check: number, bytes: Uint8Array): number {
927
- crcTable ??= createCrcTable();
928
- const table = crcTable;
929
- let value = check;
930
- for (const byte of bytes) value = table[(value ^ byte) & 0xff] ^ (value >>> 8);
931
- return value >>> 0;
932
- }
933
-
934
- function crc32Finish(check: number): number {
935
- return (check ^ 0xffff_ffff) >>> 0;
936
- }
937
-
938
- function createCrcTable(): Uint32Array {
939
- const table = new Uint32Array(256);
940
- for (let index = 0; index < table.length; index++) {
941
- let value = index;
942
- for (let bit = 0; bit < 8; bit++) {
943
- value = (value & 1) !== 0 ? 0xedb8_8320 ^ (value >>> 1) : value >>> 1;
944
- }
945
- table[index] = value >>> 0;
946
- }
947
- return table;
948
- }
949
-
950
924
  function noopRetention(bytes: number): W7ChunkRetention {
951
925
  return { bytes, release() {} };
952
926
  }