@nimbus-sh/fabric 0.8.0 → 0.10.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 (51) hide show
  1. package/README.md +98 -11
  2. package/dist/bindings.d.ts +31 -33
  3. package/dist/bindings.d.ts.map +1 -1
  4. package/dist/bindings.js +108 -97
  5. package/dist/budgets.d.ts +102 -29
  6. package/dist/budgets.d.ts.map +1 -1
  7. package/dist/budgets.js +266 -44
  8. package/dist/do-calls.d.ts +20 -0
  9. package/dist/do-calls.d.ts.map +1 -1
  10. package/dist/do-calls.js +24 -11
  11. package/dist/fanout.d.ts +40 -32
  12. package/dist/fanout.d.ts.map +1 -1
  13. package/dist/fanout.js +48 -51
  14. package/dist/fenced-work.d.ts +3 -3
  15. package/dist/fenced-work.js +3 -3
  16. package/dist/host-wasm.d.ts +29 -0
  17. package/dist/host-wasm.d.ts.map +1 -0
  18. package/dist/host-wasm.js +31 -0
  19. package/dist/image-store.d.ts +1 -1
  20. package/dist/image-store.d.ts.map +1 -1
  21. package/dist/image-store.js +33 -1
  22. package/dist/inner-do-env.d.ts +83 -0
  23. package/dist/inner-do-env.d.ts.map +1 -0
  24. package/dist/inner-do-env.js +181 -0
  25. package/dist/isolate-pool.d.ts +40 -23
  26. package/dist/isolate-pool.d.ts.map +1 -1
  27. package/dist/isolate-pool.js +105 -55
  28. package/dist/process-fabric.d.ts +26 -11
  29. package/dist/process-fabric.d.ts.map +1 -1
  30. package/dist/process-fabric.js +44 -0
  31. package/dist/timers.d.ts +12 -0
  32. package/dist/timers.d.ts.map +1 -1
  33. package/dist/timers.js +44 -9
  34. package/dist/vendor/types.d.ts +11 -5
  35. package/dist/vendor/types.d.ts.map +1 -1
  36. package/dist/workerd-facet-host.d.ts.map +1 -1
  37. package/dist/workerd-facet-host.js +35 -30
  38. package/package.json +4 -4
  39. package/src/bindings.ts +121 -98
  40. package/src/budgets.ts +311 -53
  41. package/src/do-calls.ts +45 -11
  42. package/src/fanout.ts +62 -53
  43. package/src/fenced-work.ts +3 -3
  44. package/src/host-wasm.ts +41 -0
  45. package/src/image-store.ts +29 -2
  46. package/src/inner-do-env.ts +213 -0
  47. package/src/isolate-pool.ts +145 -75
  48. package/src/process-fabric.ts +55 -13
  49. package/src/timers.ts +45 -9
  50. package/src/vendor/types.ts +11 -5
  51. package/src/workerd-facet-host.ts +36 -31
package/dist/timers.js CHANGED
@@ -103,6 +103,7 @@ export class Timers {
103
103
  arms.push({ reason, whenMs });
104
104
  return Promise.resolve(true);
105
105
  }
106
+ const epoch = host._timerEpoch ?? 0;
106
107
  // Serialize every read-modify-write of the reasons map through one
107
108
  // per-instance chain: two schedulers firing back-to-back from one activity
108
109
  // hook would otherwise interleave their get→put cycles and silently drop
@@ -113,15 +114,21 @@ export class Timers {
113
114
  if (typeof setAlarmFn !== 'function')
114
115
  return false;
115
116
  const existing = (await ctx.storage.get(TIMER_REASONS_KEY));
117
+ // Requested before a reset: it belongs to the timers the reset voided.
118
+ if ((host._timerEpoch ?? 0) !== epoch)
119
+ return false;
116
120
  const map = { ...(existing || {}) };
117
121
  // Earliest-deadline-first: only update if new request is sooner or
118
122
  // this reason has no pending entry.
123
+ let written;
119
124
  if (!(reason in map) || whenMs < map[reason]) {
120
125
  map[reason] = whenMs;
121
- await ctx.storage.put(TIMER_REASONS_KEY, map);
126
+ written = ctx.storage.put(TIMER_REASONS_KEY, map);
122
127
  }
123
- const earliest = Math.min(...Object.values(map));
124
- setAlarmFn.call(ctx.storage, earliest);
128
+ // Issued in the turn the epoch was checked in: a reset after this
129
+ // point wipes and disarms after these, never before.
130
+ setAlarmFn.call(ctx.storage, Math.min(...Object.values(map)));
131
+ await written;
125
132
  return true;
126
133
  }
127
134
  catch (e) {
@@ -133,6 +140,17 @@ export class Timers {
133
140
  host._timerChain = chained;
134
141
  return chained;
135
142
  }
143
+ /**
144
+ * Void every timer of this instance: a schedule or dispatch already
145
+ * requested — still queued on the chain, or a dispatch whose handlers are
146
+ * running — writes no reason and arms no alarm from here on. For a
147
+ * deliberate end of the actor's state (a session destroy): call it before
148
+ * wiping storage and deleting the alarm, so nothing in flight writes the
149
+ * map back or re-arms after the wipe. Requests made after it proceed.
150
+ */
151
+ reset() {
152
+ this.host._timerEpoch = (this.host._timerEpoch ?? 0) + 1;
153
+ }
136
154
  /**
137
155
  * Multi-reason timer dispatcher. Called from the DO's `alarm()` handler
138
156
  * with the embedder's handler map.
@@ -155,14 +173,22 @@ export class Timers {
155
173
  */
156
174
  dispatch(handlers, onLegacyAlarm, alarmInfo) {
157
175
  const { host, ctx } = this;
176
+ const epoch = host._timerEpoch ?? 0;
177
+ const current = () => (host._timerEpoch ?? 0) === epoch;
158
178
  // Same serialization as schedule: the dispatcher's read→handlers→write
159
179
  // cycle must not interleave with an activity-hook schedule.
160
- const chained = (host._timerChain ?? Promise.resolve()).then(() => dispatchBody(ctx, handlers, onLegacyAlarm, alarmInfo), () => dispatchBody(ctx, handlers, onLegacyAlarm, alarmInfo));
180
+ const chained = (host._timerChain ?? Promise.resolve()).then(() => dispatchBody(ctx, current, handlers, onLegacyAlarm, alarmInfo), () => dispatchBody(ctx, current, handlers, onLegacyAlarm, alarmInfo));
161
181
  host._timerChain = chained;
162
182
  return chained;
163
183
  }
164
184
  }
165
- async function dispatchBody(ctx, handlers, onLegacyAlarm, alarmInfo) {
185
+ /**
186
+ * One dispatch. `current` answers whether the epoch it was requested in still
187
+ * stands: once a reset voids it, no further handler runs and nothing is
188
+ * written or armed — the reset's caller is wiping this state, and a write
189
+ * after the wipe would outlive it.
190
+ */
191
+ async function dispatchBody(ctx, current, handlers, onLegacyAlarm, alarmInfo) {
166
192
  // Collect schedule requests made inside handler context (see
167
193
  // dispatchArms) and fold them into the map below, so an in-dispatch arm
168
194
  // neither deadlocks on the chain nor races the write.
@@ -170,6 +196,8 @@ async function dispatchBody(ctx, handlers, onLegacyAlarm, alarmInfo) {
170
196
  try {
171
197
  const now = Date.now();
172
198
  const existing = (await ctx?.storage?.get?.(TIMER_REASONS_KEY));
199
+ if (!current())
200
+ return;
173
201
  const map = { ...(existing || {}) };
174
202
  const hadMap = Object.keys(map).length > 0;
175
203
  if (!hadMap) {
@@ -185,6 +213,8 @@ async function dispatchBody(ctx, handlers, onLegacyAlarm, alarmInfo) {
185
213
  fired.push(reason);
186
214
  }
187
215
  for (const reason of fired) {
216
+ if (!current())
217
+ return;
188
218
  delete map[reason];
189
219
  const handler = handlers[reason];
190
220
  // Unknown reasons silently dropped (forward-compat).
@@ -201,20 +231,25 @@ async function dispatchBody(ctx, handlers, onLegacyAlarm, alarmInfo) {
201
231
  }
202
232
  }
203
233
  }
234
+ // A reset while the handlers ran: the map read above is gone, and
235
+ // writing it back — or arming for it — would revive what was ended.
236
+ if (!current())
237
+ return;
204
238
  // Fold the in-dispatch arms, earliest-deadline-first per reason.
205
239
  for (const arm of arms) {
206
240
  if (!(arm.reason in map) || arm.whenMs < map[arm.reason]) {
207
241
  map[arm.reason] = arm.whenMs;
208
242
  }
209
243
  }
210
- // Re-arm or clear.
244
+ // Re-arm or clear, issued in the turn the epoch was checked in: a reset
245
+ // after this point wipes and disarms after these, never before.
211
246
  const setAlarmFn = ctx?.storage?.setAlarm;
212
247
  if (Object.keys(map).length > 0) {
213
- await ctx.storage.put(TIMER_REASONS_KEY, map);
214
- const earliest = Math.min(...Object.values(map));
248
+ const written = ctx.storage.put(TIMER_REASONS_KEY, map);
215
249
  if (typeof setAlarmFn === 'function') {
216
- setAlarmFn.call(ctx.storage, earliest);
250
+ setAlarmFn.call(ctx.storage, Math.min(...Object.values(map)));
217
251
  }
252
+ await written;
218
253
  }
219
254
  else if (hadMap) {
220
255
  try {
@@ -17,13 +17,19 @@ export interface JsonModule {
17
17
  json: unknown;
18
18
  }
19
19
  /**
20
- * A compiled WebAssembly module, importable from a facet by module name.
21
- * Nimbus ships these on every path — sql.js for node:sqlite, the interpreter
22
- * images for python and ruby — so the omission here was the type lagging the
23
- * API, not a kind the loader lacks.
20
+ * A WebAssembly module, importable from a facet by module name. Nimbus ships
21
+ * these on every path — sql.js for node:sqlite, the interpreter images for
22
+ * python and ruby — so the omission here was the type lagging the API, not a
23
+ * kind the loader lacks. The loader takes either the bytes, which it
24
+ * compiles, or a module the caller holds compiled already, whose compiled
25
+ * code the dynamic worker then shares (workerd src/workerd/api/
26
+ * worker-loader.c++, extractWasmModuleContent). A module handed over this
27
+ * way should be described with describeHostWasm (host-wasm.ts): the
28
+ * code-size budget and the loader cache key cannot read a Module's size or
29
+ * identity from JS.
24
30
  */
25
31
  export interface WasmModule {
26
- wasm: ArrayBuffer;
32
+ wasm: ArrayBuffer | WebAssembly.Module;
27
33
  }
28
34
  /** Plain string = type inferred from file extension (.js or .py). */
29
35
  export type ModuleContent = string | JsModule | CjsModule | PyModule | TextModule | DataModule | JsonModule | WasmModule;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/vendor/types.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,QAAQ;IAAG,EAAE,EAAE,MAAM,CAAA;CAAE;AACxC,MAAM,WAAW,SAAS;IAAG,GAAG,EAAE,MAAM,CAAA;CAAE;AAC1C,MAAM,WAAW,QAAQ;IAAG,EAAE,EAAE,MAAM,CAAA;CAAE;AACxC,MAAM,WAAW,UAAU;IAAG,IAAI,EAAE,MAAM,CAAA;CAAE;AAC5C,MAAM,WAAW,UAAU;IAAG,IAAI,EAAE,WAAW,CAAA;CAAE;AACjD,MAAM,WAAW,UAAU;IAAG,IAAI,EAAE,OAAO,CAAA;CAAE;AAC7C;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAAG,IAAI,EAAE,WAAW,CAAA;CAAE;AAEjD,qEAAqE;AACrE,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,UAAU,GACV,UAAU,GACV,UAAU,GACV,UAAU,CAAC;AAEf,MAAM,WAAW,UAAU;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE9B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACpC,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAClE;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,UAAU;IACzB,aAAa,IAAI,cAAc,CAAC;IAChC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,iBAAiB,GAAG,cAAc,CAAC;CACvE;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjE,OAAO,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC/C;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;AAExD,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,eAAe,GAAG,UAAU,CAAC;CAC/D"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/vendor/types.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,QAAQ;IAAG,EAAE,EAAE,MAAM,CAAA;CAAE;AACxC,MAAM,WAAW,SAAS;IAAG,GAAG,EAAE,MAAM,CAAA;CAAE;AAC1C,MAAM,WAAW,QAAQ;IAAG,EAAE,EAAE,MAAM,CAAA;CAAE;AACxC,MAAM,WAAW,UAAU;IAAG,IAAI,EAAE,MAAM,CAAA;CAAE;AAC5C,MAAM,WAAW,UAAU;IAAG,IAAI,EAAE,WAAW,CAAA;CAAE;AACjD,MAAM,WAAW,UAAU;IAAG,IAAI,EAAE,OAAO,CAAA;CAAE;AAC7C;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,UAAU;IAAG,IAAI,EAAE,WAAW,GAAG,WAAW,CAAC,MAAM,CAAA;CAAE;AAEtE,qEAAqE;AACrE,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,UAAU,GACV,UAAU,GACV,UAAU,GACV,UAAU,CAAC;AAEf,MAAM,WAAW,UAAU;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE9B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACpC,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAClE;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,UAAU;IACzB,aAAa,IAAI,cAAc,CAAC;IAChC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,iBAAiB,GAAG,cAAc,CAAC;CACvE;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjE,OAAO,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC/C;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;AAExD,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,eAAe,GAAG,UAAU,CAAC;CAC/D"}
@@ -1 +1 @@
1
- {"version":3,"file":"workerd-facet-host.d.ts","sourceRoot":"","sources":["../src/workerd-facet-host.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workerd-facet-host.d.ts","sourceRoot":"","sources":["../src/workerd-facet-host.ts"],"names":[],"mappings":"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"}
@@ -15,7 +15,7 @@
15
15
  import { disposeRpcResource } from '@nimbus-sh/platform/rpc-dispose.js';
16
16
  import { StorageLedger, forgetFacetStorage } from '@nimbus-sh/core/runtime/storage-ledger.js';
17
17
  import { getCtxExports, stagedBootAssembler, supervisorEntrypoint, supervisorEntrypointName, } from './composition.js';
18
- import { assertModuleMapWithinCodeLimit, beginLoaderFetch, facetNameCount, facetNameCountDurable, recordFacetNameMinted, recordLoaderId, withDynamicWorkerCapNamed, withFacetBudgetNamed, } from './budgets.js';
18
+ import { assertModuleMapWithinCodeLimit, beginLoaderFetch, facetNameCount, facetNameCountDurable, recordFacetNameMinted, withDynamicWorkerCapNamed, withFacetBudgetNamed, } from './budgets.js';
19
19
  import { RESIDENT_PROCESS_CLASS, residentLoaderConfig, } from './process-fabric.js';
20
20
  import { supervisorLoaderKey } from './supervisor-props.js';
21
21
  export function getNimbusCtxExports() {
@@ -87,7 +87,7 @@ export async function cloneStorage(ctx, clone) {
87
87
  const facets = facetContainer(ctx);
88
88
  if (typeof facets.clone !== 'function') {
89
89
  throw new Error('Nimbus: ctx.facets.clone is unavailable in this runtime; the reflink image '
90
- + 'path needs deployed Cloudflare workerd (local workerd <= 1.20260603.1 lacks it)');
90
+ + 'path needs workerd 1.20260926.1 or later, or deployed Cloudflare workerd');
91
91
  }
92
92
  const { src, dst } = clone;
93
93
  if (!(await clone.populated(src))) {
@@ -292,10 +292,13 @@ function spawnResident(ctx, env, disk, supervisor, params) {
292
292
  + 'it is not restarted');
293
293
  }
294
294
  evaluated = true;
295
- return { class: residentProcessClass(ctx, env, disk, supervisor, params) };
295
+ return { class: residentProcessClass(env, disk, supervisor, params, loaderKey) };
296
296
  };
297
297
  const book = slotBook(ctx);
298
298
  const ledger = sessionLedger(ctx);
299
+ // A warm worker keeps the SUPERVISOR binding it was built with, and the
300
+ // loader outlives this instance.
301
+ const loaderKey = supervisorLoaderKey(params.workerKey, supervisor);
299
302
  let facet;
300
303
  try {
301
304
  // N18: the fill is admitted, and recorded under the facet's name, before
@@ -315,6 +318,12 @@ function spawnResident(ctx, env, disk, supervisor, params) {
315
318
  }
316
319
  if (explicit)
317
320
  book.live.add(name);
321
+ // The facet's worker is one Dynamic Worker in flight for as long as the
322
+ // process is resident, not only while a call is open: its WebSockets and
323
+ // streamed responses outlive the calls the ledger could bracket, and a
324
+ // request can reach it at any moment. Held from here to `release`, so no
325
+ // fan-out spends the slot a running process needs.
326
+ const endResidency = beginLoaderFetch(ctx, loaderKey);
318
327
  facetOfPid(ctx).set(params.pid, name);
319
328
  let disposed = false;
320
329
  const release = async () => {
@@ -323,6 +332,7 @@ function spawnResident(ctx, env, disk, supervisor, params) {
323
332
  disposed = true;
324
333
  released = true;
325
334
  facetOfPid(ctx).delete(params.pid);
335
+ endResidency();
326
336
  try {
327
337
  facets.abort(name, new Error('Nimbus: resident process released'));
328
338
  }
@@ -396,25 +406,15 @@ function spawnResident(ctx, env, disk, supervisor, params) {
396
406
  * assembles its module map at most once and the bytes never stay resident in
397
407
  * the hosting DO's heap.
398
408
  */
399
- function residentProcessClass(ctx, env, disk, supervisor, params) {
409
+ function residentProcessClass(env, disk, supervisor, params, loaderKey) {
400
410
  const loader = env.LOADER;
401
411
  if (!loader || typeof loader.get !== 'function') {
402
412
  throw new Error('Nimbus: env.LOADER binding missing or invalid. Resident processes require '
403
413
  + 'the Worker Loader binding; add it via worker_loaders in wrangler.jsonc.');
404
414
  }
405
- // A warm worker keeps the SUPERVISOR binding it was built with, and the
406
- // loader outlives this instance.
407
- const loaderKey = supervisorLoaderKey(params.workerKey, supervisor);
408
- try {
409
- const worker = loader
410
- .get(loaderKey, () => residentWorkerConfig(env, disk, supervisor, params.boot))
411
- .getDurableObjectClass(RESIDENT_PROCESS_CLASS);
412
- recordLoaderId(ctx, loaderKey);
413
- return worker;
414
- }
415
- catch (error) {
416
- throw withDynamicWorkerCapNamed(ctx, error);
417
- }
415
+ return loader
416
+ .get(loaderKey, () => residentWorkerConfig(env, disk, supervisor, params.boot))
417
+ .getDurableObjectClass(RESIDENT_PROCESS_CLASS);
418
418
  }
419
419
  async function runOneShot(ctx, env, supervisor, params, consume) {
420
420
  const loader = env.LOADER;
@@ -455,23 +455,28 @@ async function runOneShot(ctx, env, supervisor, params, consume) {
455
455
  throw new Error('Nimbus: one-shot runtime entrypoint has no fetch method');
456
456
  }
457
457
  params.onLoaded?.();
458
- // The unkeyed worker is a live dynamic worker for exactly this call, so
459
- // the run is a Loader fetch on the hosting actor's ledger — bracketed,
460
- // never wrapped: see beginLoaderFetch for the measured DO-poisoning
461
- // hazard, and the pipelined-`fetch.call` note above for its sibling.
462
- const endFetch = beginLoaderFetch(ctx);
463
- let response;
458
+ // The unkeyed worker is one distinct dynamic worker in flight until its
459
+ // response is consumed (the body streams from it), keyed by this run's
460
+ // writer id — bracketed, never wrapped: see beginLoaderFetch for the
461
+ // measured DO-poisoning hazard, and the pipelined-`fetch.call` note above
462
+ // for its sibling.
463
+ const endFetch = beginLoaderFetch(ctx, `one-shot:${params.writerId}`);
464
464
  try {
465
- response = await ep.fetch(params.request);
466
- }
467
- finally {
468
- endFetch();
465
+ const response = await ep.fetch(params.request);
466
+ try {
467
+ return await consume(response);
468
+ }
469
+ finally {
470
+ disposeRpcResource(response);
471
+ }
469
472
  }
470
- try {
471
- return await consume(response);
473
+ catch (error) {
474
+ // A limit refusal pauses the ledger's admissions (beginLoaderFetchWhenFree).
475
+ endFetch(error);
476
+ throw error;
472
477
  }
473
478
  finally {
474
- disposeRpcResource(response);
479
+ endFetch();
475
480
  }
476
481
  }
477
482
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nimbus-sh/fabric",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "The Cloudflare half of Nimbus \u2014 Durable Object facet hosting, dynamic-worker loader pools, the resident-process fabric, and DO alarm/hibernation machinery.",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -50,12 +50,12 @@
50
50
  "typecheck": "tsc --noEmit"
51
51
  },
52
52
  "dependencies": {
53
- "@nimbus-sh/core": "^0.13.0",
54
- "@nimbus-sh/platform": "^0.6.0",
53
+ "@nimbus-sh/core": "^0.15.0",
54
+ "@nimbus-sh/platform": "^0.7.0",
55
55
  "zod": "^4.4.3"
56
56
  },
57
57
  "devDependencies": {
58
- "@cloudflare/workers-types": "^4.20250327.0",
58
+ "@cloudflare/workers-types": "^5.20260928.1",
59
59
  "typescript": "^5.7.0"
60
60
  },
61
61
  "publishConfig": {
package/src/bindings.ts CHANGED
@@ -29,6 +29,7 @@ import { disposeRpcResource, useRpcResource } from '@nimbus-sh/platform/rpc-disp
29
29
  import { hostNamespace, supervisorEntrypoint, supervisorEntrypointName, stagedBootAssembler } from './composition.js';
30
30
  import type { HostRoute } from './composition.js';
31
31
  import { hostNamespaceBinding, hostOpDispatch, type HostOpDispatch } from './host-dispatch.js';
32
+ import { innerDoIdFromName } from './inner-do-env.js';
32
33
  import { assertModuleMapWithinCodeLimit } from './budgets.js';
33
34
  import type { EntrypointLoopbackFactory } from './composition.js';
34
35
  import type { WorkerCode } from './vendor/types.js';
@@ -708,46 +709,23 @@ interface NimbusDoNamespaceProps {
708
709
  }
709
710
 
710
711
  /**
711
- * `env.MY_DO` shim — a DurableObjectNamespace-like WorkerEntrypoint.
712
+ * The binding the loader passes for `env.MY_DO` (a WorkerEntrypoint of the
713
+ * session's isolate). The inner Worker does not use it as its namespace: a
714
+ * DurableObjectNamespace's API is synchronous, and this one's answers are
715
+ * RpcPromises, which cannot travel as arguments. The inner Worker replaces it
716
+ * with a local namespace (inner-do-env.ts, innerWorkerModules) that makes ids
717
+ * and stubs itself, and relays each member a stub's caller reaches, its
718
+ * fetch included, to `callOn` or `getOn`.
712
719
  *
713
- * Usage from inner Worker:
714
- * const id = await env.MY_DO.idFromName('x'); // AWAIT required
715
- * const stub = env.MY_DO.get(id);
716
- * await stub.fetch(request);
717
- *
718
- * IMPORTANT: unlike the real DurableObjectNamespace, idFromName /
719
- * newUniqueId / idFromString here return **Promises**, because they're
720
- * RPC-backed WorkerEntrypoint methods. The inner caller MUST `await`
721
- * them before passing the result to `.get()`. Workers RPC pipelining
722
- * does not currently allow passing an RpcPromise as a method argument
723
- * — the no-await form fails with:
724
- * "Could not serialize object of type \"RpcPromise\"."
725
- *
726
- * Typical real-Worker code written for Cloudflare's synchronous
727
- * DurableObjectNamespace needs a one-word change (add `await`).
728
- *
729
- * idFromName produces prefix `name:` (deterministic FNV-style hash);
730
- * newUniqueId uses `uniq:` (random). The prefixes keep the two id
731
- * spaces distinct so a name-derived id can't collide with a random
732
- * one.
720
+ * `idFromName`, `newUniqueId`, `idFromString` and `get` answer as before, for
721
+ * a caller that awaits them. idFromName produces prefix `name:` (a
722
+ * deterministic hash, innerDoIdFromName); newUniqueId uses `uniq:`; the
723
+ * prefixes keep the two id spaces distinct.
733
724
  */
734
- export class NimbusDurableObjectNamespace extends WorkerEntrypoint<unknown, NimbusDoNamespaceProps> {
725
+ export class NimbusDurableObjectNamespace extends WorkerEntrypoint<object, NimbusDoNamespaceProps> {
735
726
  /** Stable string id derived from a name. Hash is deterministic. */
736
727
  idFromName(name: string): string {
737
- // Simple 64-bit-ish FNV-style hash → hex. Stable across runs;
738
- // distinct names → distinct strings; same name → same string.
739
- let h1 = 0xdeadbeef ^ name.length;
740
- let h2 = 0x41c6ce57 ^ name.length;
741
- for (let i = 0; i < name.length; i++) {
742
- const ch = name.charCodeAt(i);
743
- h1 = Math.imul(h1 ^ ch, 2654435761);
744
- h2 = Math.imul(h2 ^ ch, 1597334677);
745
- }
746
- h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
747
- h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
748
- const high = (h1 >>> 0).toString(16).padStart(8, '0');
749
- const low = (h2 >>> 0).toString(16).padStart(8, '0');
750
- return 'name:' + high + low;
728
+ return innerDoIdFromName(name);
751
729
  }
752
730
 
753
731
  /** Fresh random id (matches DurableObjectNamespace.newUniqueId()). */
@@ -774,6 +752,19 @@ export class NimbusDurableObjectNamespace extends WorkerEntrypoint<unknown, Nimb
774
752
  },
775
753
  });
776
754
  }
755
+
756
+ /**
757
+ * The member of object `id` at `path` (names from the object down), called
758
+ * with `args`: its answer, or what it throws, as the object gave it.
759
+ */
760
+ callOn(id: string, path: string[], args: unknown[]): Promise<unknown> {
761
+ return innerDoMember(this.env, { ...(this.ctx.props || {}), id: String(id) }, path, args);
762
+ }
763
+
764
+ /** The member of object `id` at `path`, read. */
765
+ getOn(id: string, path: string[]): Promise<unknown> {
766
+ return innerDoMember(this.env, { ...(this.ctx.props || {}), id: String(id) }, path, null);
767
+ }
777
768
  }
778
769
 
779
770
  /** Props the DO stub carries: which binding, which supervisor, which id. */
@@ -782,70 +773,102 @@ interface NimbusDoStubProps extends NimbusDoNamespaceProps {
782
773
  }
783
774
 
784
775
  /**
785
- * A Durable-Object-namespace-stub for a specific id. Exposes fetch()
786
- * and will, if we later need it, forward RPC method calls through a
787
- * dispatch helper. The important invariant: EVERY call resolves the
788
- * inner DO class via getInnerDoClass() (./inner-do-registry.js) and
789
- * spins up / attaches to a facet via the supervisor's ctx.facets in
790
- * the SAME outer request context — never reusing stubs across requests.
776
+ * The session Durable Object, through the composed host namespace, and its
777
+ * one supervisorOp entrypoint: a host forwards envelopes, not private _rpc*
778
+ * methods. Throws when the binding cannot reach it; `release` drops the stub.
791
779
  */
792
- export class NimbusDOStub extends WorkerEntrypoint<object, NimbusDoStubProps> {
793
- /**
794
- * Resolve the supervisor DO through the composed host namespace and
795
- * dispatch the innerDoFetch op through its one supervisorOp entrypoint —
796
- * a host forwards envelopes, not private _rpc* methods.
797
- */
798
- async fetch(request: Request): Promise<Response> {
799
- const props: NimbusDoStubProps = this.ctx.props || {};
800
- const supervisorDoId = String(props.supervisorDoId || '');
801
- if (!supervisorDoId) return new Response('Nimbus: supervisorDoId missing', { status: 500 });
802
- const bindingName = String(props.bindingName || '');
803
- const id = String(props.id || '');
804
- let stub: DurableObjectStub | null = null;
805
- let dispatch: HostOpDispatch;
806
- try {
807
- const ns = hostNamespaceBinding(this.env ?? {}, 'NimbusDOStub', props.route);
808
- stub = ns.get(ns.idFromString(supervisorDoId));
809
- dispatch = hostOpDispatch(stub, 'NimbusDOStub', props.route);
810
- } catch (e) {
811
- disposeRpcResource(stub);
812
- return new Response(`Nimbus: ${e instanceof Error ? e.message : String(e)}`, { status: 500 });
813
- }
814
- // Forward the full request (method, body, headers preserved) by
815
- // serializing what's needed and reconstructing on the other side.
816
- // The supervisor reconstitutes the Request from these fields and
817
- // invokes the facet.
818
- const body = request.method !== 'GET' && request.method !== 'HEAD'
819
- ? await request.arrayBuffer()
820
- : null;
780
+ function supervisorOf(env: object | undefined, props: NimbusDoStubProps): { dispatch: HostOpDispatch; release(): void } {
781
+ const supervisorDoId = String(props.supervisorDoId || '');
782
+ if (!supervisorDoId) throw new Error('supervisorDoId missing');
783
+ let stub: DurableObjectStub | null = null;
784
+ try {
785
+ const ns = hostNamespaceBinding(env ?? {}, 'NimbusDOStub', props.route);
786
+ stub = ns.get(ns.idFromString(supervisorDoId));
787
+ const held = stub;
788
+ return { dispatch: hostOpDispatch(stub, 'NimbusDOStub', props.route), release: () => disposeRpcResource(held) };
789
+ } catch (e) {
790
+ disposeRpcResource(stub);
791
+ throw e;
792
+ }
793
+ }
794
+
795
+ /** What the session's innerDoFetch answers: the object's response, as fields. */
796
+ export interface InnerDoFetchAnswer {
797
+ status: number;
798
+ statusText: string;
799
+ headers: [string, string][];
800
+ body: ArrayBuffer | null;
801
+ }
802
+
803
+ function isInnerDoFetchAnswer(value: unknown): value is InnerDoFetchAnswer {
804
+ return value !== null && typeof value === 'object'
805
+ && 'status' in value && typeof value.status === 'number'
806
+ && 'statusText' in value && typeof value.statusText === 'string'
807
+ && 'headers' in value && Array.isArray(value.headers)
808
+ && 'body' in value && (value.body === null || value.body instanceof ArrayBuffer);
809
+ }
810
+
811
+ /**
812
+ * The inner object's fetch: the request forwarded whole (method, body,
813
+ * headers) as fields the session reconstructs, and its response rebuilt here
814
+ * from the fields the session answers. A binding that cannot reach the
815
+ * session answers 500.
816
+ */
817
+ async function innerDoFetch(env: object | undefined, props: NimbusDoStubProps, request: Request): Promise<Response> {
818
+ let supervisor: ReturnType<typeof supervisorOf>;
819
+ try {
820
+ supervisor = supervisorOf(env, props);
821
+ } catch (e) {
822
+ return new Response(`Nimbus: ${e instanceof Error ? e.message : String(e)}`, { status: 500 });
823
+ }
824
+ try {
825
+ const body = request.method !== 'GET' && request.method !== 'HEAD' ? await request.arrayBuffer() : null;
821
826
  const headerList: [string, string][] = [];
822
827
  request.headers.forEach((v, k) => { headerList.push([k, v]); });
823
- try {
824
- return await useRpcResource(
825
- dispatch({
826
- op: 'innerDoFetch',
827
- args: [{
828
- bindingName,
829
- id,
830
- method: request.method,
831
- url: request.url,
832
- headers: headerList,
833
- body,
834
- }],
835
- }),
836
- (res) => {
837
- if (!(res instanceof Response)) {
838
- return new Response('Nimbus: innerDoFetch returned an invalid result', { status: 502 });
839
- }
840
- return new Response(res.body, {
841
- status: res.status,
842
- statusText: res.statusText,
843
- headers: res.headers,
844
- });
845
- },
846
- );
847
- } finally {
848
- disposeRpcResource(stub);
849
- }
828
+ return await useRpcResource(
829
+ supervisor.dispatch({
830
+ op: 'innerDoFetch',
831
+ args: [{ bindingName: String(props.bindingName || ''), id: String(props.id || ''), method: request.method, url: request.url, headers: headerList, body }],
832
+ }),
833
+ (res) => {
834
+ if (!isInnerDoFetchAnswer(res)) {
835
+ return new Response('Nimbus: innerDoFetch returned an invalid result', { status: 502 });
836
+ }
837
+ return new Response(res.body, { status: res.status, statusText: res.statusText, headers: res.headers });
838
+ },
839
+ );
840
+ } finally {
841
+ supervisor.release();
842
+ }
843
+ }
844
+
845
+ /**
846
+ * A member of the inner object, called with `args` or read (`args` null): the
847
+ * session reaches it on the object's facet and answers what it answered (a
848
+ * stub, function or stream travels as one) or rejects with what it threw,
849
+ * type and message kept.
850
+ */
851
+ async function innerDoMember(env: object | undefined, props: NimbusDoStubProps, path: string[], args: unknown[] | null): Promise<unknown> {
852
+ const supervisor = supervisorOf(env, props);
853
+ try {
854
+ return await supervisor.dispatch({
855
+ op: 'innerDoCall',
856
+ args: [{ bindingName: String(props.bindingName || ''), id: String(props.id || ''), path, args }],
857
+ });
858
+ } finally {
859
+ supervisor.release();
860
+ }
861
+ }
862
+
863
+ /**
864
+ * A Durable-Object-namespace-stub for a specific id, for a caller of the
865
+ * binding's own `get`: its fetch. The important invariant: EVERY call
866
+ * resolves the inner DO class via getInnerDoClass() (./inner-do-registry.js)
867
+ * and spins up / attaches to a facet via the supervisor's ctx.facets in the
868
+ * SAME outer request context — never reusing stubs across requests.
869
+ */
870
+ export class NimbusDOStub extends WorkerEntrypoint<object, NimbusDoStubProps> {
871
+ async fetch(request: Request): Promise<Response> {
872
+ return innerDoFetch(this.env, this.ctx.props || {}, request);
850
873
  }
851
874
  }