@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
@@ -0,0 +1,83 @@
1
+ /**
2
+ * inner-do-env.ts — a classic Durable Object binding inside an inner Worker.
3
+ *
4
+ * `nimbus wrangler dev` loads the user's Worker as a dynamic worker, and its
5
+ * Durable Object bindings run as facets of the session Durable Object. The
6
+ * binding the loader passes (`NimbusDurableObjectNamespace`, an entrypoint of
7
+ * the session's isolate) answers RPC, so it cannot be the inner Worker's
8
+ * namespace: a DurableObjectNamespace's API is synchronous (`env.P.get(
9
+ * env.P.idFromName('x'))` takes no await), and an RpcPromise cannot travel as
10
+ * an argument ("Could not serialize object of type RpcPromise").
11
+ *
12
+ * So a module the inner Worker runs before any of its own code (its main
13
+ * module's first import, `innerWorkerModules`) replaces each such binding in
14
+ * the isolate's env, which every handler, entrypoint and Durable Object of the
15
+ * isolate sees, with a local namespace. Ids are made locally, and `get`
16
+ * answers at once an RPC stub (`new RpcStub(target)`) of a local target that
17
+ * relays each member the stub's caller reaches (a call, a read, or a path
18
+ * through members, fetch included) to the binding's `callOn` or `getOn`,
19
+ * which the session runs on the object's facet. An RPC stub is what a
20
+ * Durable Object stub is to the runtime: callable by any method name, read by
21
+ * any property name, pipelined, bound to its request, and transferable, as an
22
+ * argument or an answer, where an entrypoint of a dynamically-loaded Worker
23
+ * is not. Arguments and answers cross natively, stubs, functions and streams
24
+ * included.
25
+ *
26
+ * Its prototype is not RpcStub's but one shaped as a Durable Object stub's:
27
+ * its constructor is a class `DurableObject` that cannot be constructed, its
28
+ * tag is 'DurableObject', and it has no `dup` or Symbol.dispose of its own,
29
+ * so `dup` is a member, which the runtime refuses as on Cloudflare. It
30
+ * differs from a Durable Object stub in two ways the runtime fixes. `typeof`
31
+ * is 'function'. And it is not persistent, so a Worker Loader env cannot carry
32
+ * it ("RpcStub cannot be serialized in this context because it is not a
33
+ * persistent stub"): the loader shim (NimbusLoaderRPC) keeps a child's code
34
+ * and loads it again in each later request, so the child's env can carry
35
+ * nothing made in one request, the session's own stubs included.
36
+ */
37
+ import type { RpcStub, WorkerEntrypoint } from 'cloudflare:workers';
38
+ /**
39
+ * The id string a name gives: deterministic (FNV-style, 64-bit hex), with the
40
+ * prefix `name:` so it never collides with a `uniq:` id. Self-contained: its
41
+ * source also runs in the inner isolate (innerDoAdapter).
42
+ */
43
+ export declare function innerDoIdFromName(name: string): string;
44
+ /** What the binding the loader passes answers: one access to one object. */
45
+ export interface InnerDoRemote {
46
+ /** The member of object `id` at `path` (names from the object down), called with `args`. */
47
+ callOn(id: string, path: string[], args: unknown[]): Promise<unknown>;
48
+ /** The member of object `id` at `path`, read. */
49
+ getOn(id: string, path: string[]): Promise<unknown>;
50
+ }
51
+ /** What the adapter runs over: the inner isolate's `cloudflare:workers`. */
52
+ export interface InnerDoRuntime {
53
+ env: object;
54
+ WorkerEntrypoint: typeof WorkerEntrypoint;
55
+ RpcStub: typeof RpcStub;
56
+ }
57
+ /**
58
+ * The adapter, as it runs in the inner isolate: it replaces each of `names`
59
+ * in `runtime.env` that holds the binding with a local DurableObjectNamespace,
60
+ * and answers the class check the main module exports. `main` is the main
61
+ * module's namespace. Self-contained (serialized with toString): it reaches
62
+ * nothing outside itself but its arguments.
63
+ */
64
+ export declare function innerDoAdapter(idFromName: (name: string) => string, names: readonly string[], main: object, runtime: InnerDoRuntime): {
65
+ NimbusDurableObjectClasses: unknown;
66
+ };
67
+ /**
68
+ * The modules an inner Worker runs with Durable Object bindings `names`: its
69
+ * bundle as the main module, whose first import is the adapter (so the
70
+ * adapter has run before any of the Worker's code) and which exports the
71
+ * class check as `classesEntrypoint`, and the adapter. The import shares the
72
+ * bundle's first line, so line numbers stay the bundle's. A Worker with no
73
+ * such binding runs its bundle as it is, and has no class check (null).
74
+ *
75
+ * `classesEntrypoint` is a name the bundle never spells, so it exports no
76
+ * such name itself (a bundler prints an ASCII name as it is).
77
+ */
78
+ export declare function innerWorkerModules(bundle: string, names: readonly string[]): {
79
+ mainModule: string;
80
+ modules: Record<string, string>;
81
+ classesEntrypoint: string | null;
82
+ };
83
+ //# sourceMappingURL=inner-do-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inner-do-env.d.ts","sourceRoot":"","sources":["../src/inner-do-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGpE;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAWtD;AAED,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,4FAA4F;IAC5F,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtE,iDAAiD;IACjD,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACrD;AAED,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,gBAAgB,EAAE,OAAO,gBAAgB,CAAC;IAC1C,OAAO,EAAE,OAAO,OAAO,CAAC;CACzB;AAID;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EACpC,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,cAAc,GACtB;IAAE,0BAA0B,EAAE,OAAO,CAAA;CAAE,CAuFzC;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC,CAiBA"}
@@ -0,0 +1,181 @@
1
+ /**
2
+ * inner-do-env.ts — a classic Durable Object binding inside an inner Worker.
3
+ *
4
+ * `nimbus wrangler dev` loads the user's Worker as a dynamic worker, and its
5
+ * Durable Object bindings run as facets of the session Durable Object. The
6
+ * binding the loader passes (`NimbusDurableObjectNamespace`, an entrypoint of
7
+ * the session's isolate) answers RPC, so it cannot be the inner Worker's
8
+ * namespace: a DurableObjectNamespace's API is synchronous (`env.P.get(
9
+ * env.P.idFromName('x'))` takes no await), and an RpcPromise cannot travel as
10
+ * an argument ("Could not serialize object of type RpcPromise").
11
+ *
12
+ * So a module the inner Worker runs before any of its own code (its main
13
+ * module's first import, `innerWorkerModules`) replaces each such binding in
14
+ * the isolate's env, which every handler, entrypoint and Durable Object of the
15
+ * isolate sees, with a local namespace. Ids are made locally, and `get`
16
+ * answers at once an RPC stub (`new RpcStub(target)`) of a local target that
17
+ * relays each member the stub's caller reaches (a call, a read, or a path
18
+ * through members, fetch included) to the binding's `callOn` or `getOn`,
19
+ * which the session runs on the object's facet. An RPC stub is what a
20
+ * Durable Object stub is to the runtime: callable by any method name, read by
21
+ * any property name, pipelined, bound to its request, and transferable, as an
22
+ * argument or an answer, where an entrypoint of a dynamically-loaded Worker
23
+ * is not. Arguments and answers cross natively, stubs, functions and streams
24
+ * included.
25
+ *
26
+ * Its prototype is not RpcStub's but one shaped as a Durable Object stub's:
27
+ * its constructor is a class `DurableObject` that cannot be constructed, its
28
+ * tag is 'DurableObject', and it has no `dup` or Symbol.dispose of its own,
29
+ * so `dup` is a member, which the runtime refuses as on Cloudflare. It
30
+ * differs from a Durable Object stub in two ways the runtime fixes. `typeof`
31
+ * is 'function'. And it is not persistent, so a Worker Loader env cannot carry
32
+ * it ("RpcStub cannot be serialized in this context because it is not a
33
+ * persistent stub"): the loader shim (NimbusLoaderRPC) keeps a child's code
34
+ * and loads it again in each later request, so the child's env can carry
35
+ * nothing made in one request, the session's own stubs included.
36
+ */
37
+ import { ESBUILD_NAME_MODULE_SHIM } from '@nimbus-sh/core/_shared/esbuild-facet-shim.js';
38
+ /**
39
+ * The id string a name gives: deterministic (FNV-style, 64-bit hex), with the
40
+ * prefix `name:` so it never collides with a `uniq:` id. Self-contained: its
41
+ * source also runs in the inner isolate (innerDoAdapter).
42
+ */
43
+ export function innerDoIdFromName(name) {
44
+ let h1 = 0xdeadbeef ^ name.length;
45
+ let h2 = 0x41c6ce57 ^ name.length;
46
+ for (let i = 0; i < name.length; i++) {
47
+ const ch = name.charCodeAt(i);
48
+ h1 = Math.imul(h1 ^ ch, 2654435761);
49
+ h2 = Math.imul(h2 ^ ch, 1597334677);
50
+ }
51
+ h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
52
+ h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
53
+ return 'name:' + (h1 >>> 0).toString(16).padStart(8, '0') + (h2 >>> 0).toString(16).padStart(8, '0');
54
+ }
55
+ /** The entrypoint a build asks which Durable Object classes are missing, unless the bundle spells it. */
56
+ const CLASSES_ENTRYPOINT = 'NimbusDurableObjectClasses';
57
+ /**
58
+ * The adapter, as it runs in the inner isolate: it replaces each of `names`
59
+ * in `runtime.env` that holds the binding with a local DurableObjectNamespace,
60
+ * and answers the class check the main module exports. `main` is the main
61
+ * module's namespace. Self-contained (serialized with toString): it reaches
62
+ * nothing outside itself but its arguments.
63
+ */
64
+ export function innerDoAdapter(idFromName, names, main, runtime) {
65
+ /** A Durable Object id: its string, and the name it was made from. */
66
+ class DurableObjectId {
67
+ name;
68
+ #id;
69
+ constructor(id, name) {
70
+ this.#id = id;
71
+ if (name !== undefined)
72
+ this.name = name;
73
+ }
74
+ toString() { return this.#id; }
75
+ equals(other) { return other instanceof DurableObjectId && String(other) === this.#id; }
76
+ }
77
+ /** Whether `value` is the binding the loader passes (an RPC stub's methods are its properties). */
78
+ function isRemote(value) {
79
+ return value !== null && (typeof value === 'object' || typeof value === 'function')
80
+ && typeof Reflect.get(value, 'callOn') === 'function' && typeof Reflect.get(value, 'getOn') === 'function';
81
+ }
82
+ /**
83
+ * The member of object `id` at `path`, as the runtime reaches it in an RPC
84
+ * to the stub: called, read (it is thenable, and the runtime awaits what a
85
+ * read answers), or walked through to one of its own members (the runtime
86
+ * walks a path through own properties only, so every name is reported as
87
+ * one). At the empty path it is the stub's target.
88
+ */
89
+ function member(remote, id, path) {
90
+ const next = (name) => member(remote, id, [...path, name]);
91
+ return new Proxy((..._args) => undefined, {
92
+ apply: (_target, _self, args) => remote.callOn(id, [...path], args),
93
+ get: (target, name) => {
94
+ if (name === 'then') {
95
+ return (resolve, reject) => remote.getOn(id, [...path]).then(resolve, reject);
96
+ }
97
+ return typeof name === 'string' ? next(name) : Reflect.get(target, name);
98
+ },
99
+ getOwnPropertyDescriptor: (target, name) => (typeof name === 'string' && name !== 'then'
100
+ ? { value: next(name), writable: true, enumerable: true, configurable: true }
101
+ : Reflect.getOwnPropertyDescriptor(target, name)),
102
+ });
103
+ }
104
+ /**
105
+ * A stub's prototype, as a Durable Object stub's shows: its constructor
106
+ * cannot be called or constructed, and it is tagged 'DurableObject'.
107
+ */
108
+ const stubPrototype = Object.create(Object.prototype, {
109
+ constructor: {
110
+ value: function DurableObject() { throw new TypeError('Illegal constructor'); },
111
+ writable: true,
112
+ configurable: true,
113
+ },
114
+ [Symbol.toStringTag]: { value: 'DurableObject', configurable: true },
115
+ });
116
+ /** Asked once by a build: which classes the main module does not export. */
117
+ class NimbusDurableObjectClasses extends runtime.WorkerEntrypoint {
118
+ missing(classNames) {
119
+ return classNames.filter((name) => typeof Reflect.get(main, name) !== 'function');
120
+ }
121
+ }
122
+ /** env.MY_DO: the namespace, made locally; its stubs relay to `remote`. */
123
+ class DurableObjectNamespace {
124
+ #remote;
125
+ constructor(remote) { this.#remote = remote; }
126
+ idFromName(name) { return new DurableObjectId(idFromName(String(name)), String(name)); }
127
+ newUniqueId() { return new DurableObjectId('uniq:' + crypto.randomUUID().replaceAll('-', '')); }
128
+ idFromString(id) { return new DurableObjectId(String(id)); }
129
+ get(id) {
130
+ const at = id instanceof DurableObjectId ? id : new DurableObjectId(String(id));
131
+ const stub = Object.setPrototypeOf(new runtime.RpcStub(member(this.#remote, String(at), [])), stubPrototype);
132
+ // As a Durable Object stub has them: its own, enumerable, in this order.
133
+ return Object.defineProperties(stub, {
134
+ name: { value: at.name, enumerable: true },
135
+ id: { value: at, enumerable: true },
136
+ });
137
+ }
138
+ getByName(name) { return this.get(this.idFromName(name)); }
139
+ jurisdiction() { return this; }
140
+ }
141
+ for (const name of names) {
142
+ const remote = Reflect.get(runtime.env, name);
143
+ if (isRemote(remote))
144
+ Reflect.set(runtime.env, name, new DurableObjectNamespace(remote));
145
+ }
146
+ return { NimbusDurableObjectClasses };
147
+ }
148
+ /** The inner Worker's own module, as bundled, and the adapter's. */
149
+ const MAIN_MODULE = 'worker.js';
150
+ const ADAPTER_MODULE = 'nimbus-do-env.js';
151
+ /**
152
+ * The modules an inner Worker runs with Durable Object bindings `names`: its
153
+ * bundle as the main module, whose first import is the adapter (so the
154
+ * adapter has run before any of the Worker's code) and which exports the
155
+ * class check as `classesEntrypoint`, and the adapter. The import shares the
156
+ * bundle's first line, so line numbers stay the bundle's. A Worker with no
157
+ * such binding runs its bundle as it is, and has no class check (null).
158
+ *
159
+ * `classesEntrypoint` is a name the bundle never spells, so it exports no
160
+ * such name itself (a bundler prints an ASCII name as it is).
161
+ */
162
+ export function innerWorkerModules(bundle, names) {
163
+ if (names.length === 0)
164
+ return { mainModule: MAIN_MODULE, modules: { [MAIN_MODULE]: bundle }, classesEntrypoint: null };
165
+ let classesEntrypoint = CLASSES_ENTRYPOINT;
166
+ for (let n = 2; bundle.includes(classesEntrypoint); n++)
167
+ classesEntrypoint = `${CLASSES_ENTRYPOINT}_${n}`;
168
+ const head = `export { ${CLASSES_ENTRYPOINT} as ${classesEntrypoint} } from './${ADAPTER_MODULE}';`;
169
+ // A hashbang must stay first.
170
+ const at = bundle.startsWith('#!') ? bundle.indexOf('\n') + 1 : 0;
171
+ const main = bundle.slice(0, at) + head + bundle.slice(at);
172
+ const adapter = [
173
+ "import { env, RpcStub, WorkerEntrypoint } from 'cloudflare:workers';",
174
+ `import * as main from './${MAIN_MODULE}';`,
175
+ // The functions below are serialized from the bundled worker, which wraps them in __name.
176
+ ESBUILD_NAME_MODULE_SHIM,
177
+ `const { ${CLASSES_ENTRYPOINT} } = (${innerDoAdapter.toString()})(${innerDoIdFromName.toString()}, ${JSON.stringify(names)}, main, { env, RpcStub, WorkerEntrypoint });`,
178
+ `export { ${CLASSES_ENTRYPOINT} };`,
179
+ ].join('\n');
180
+ return { mainModule: MAIN_MODULE, modules: { [MAIN_MODULE]: main, [ADAPTER_MODULE]: adapter }, classesEntrypoint };
181
+ }
@@ -7,9 +7,9 @@
7
7
  * running 67 npm tarball extractions (cold-start dominates). We pin
8
8
  * each job to `slot = cursor % concurrency` and use stable loader
9
9
  * IDs `nfp:${fnHash}:slot-${i}:g${generation}`, so a pool of
10
- * concurrency=4 keeps at most 4 warm isolates rather than N fresh ones.
10
+ * concurrency=N keeps at most N warm isolates rather than one per job.
11
11
  * 2. **Nimbus defaults**: compatibilityDate = CF_COMPAT_DATE (matches
12
- * the supervisor worker), compatibilityFlags = ['nodejs_compat'],
12
+ * the supervisor worker), compatibilityFlags = GUEST_COMPAT_FLAGS,
13
13
  * globalOutbound = undefined (inherit parent network so the facet can
14
14
  * reach https://registry.npmjs.org without a proxy binding).
15
15
  * 3. **Supervisor autoinjection**. The pool grabs the embedder's
@@ -24,6 +24,7 @@
24
24
  * and binding types used by this implementation.
25
25
  */
26
26
  import { type HostRoute } from './composition.js';
27
+ import { type DynamicWorkerClaim } from './budgets.js';
27
28
  import type { FacetBindings } from '@nimbus-sh/core/runtime/facet-host.js';
28
29
  import type { WorkerLoader } from './vendor/types.js';
29
30
  /**
@@ -44,8 +45,18 @@ export interface IsolatePoolEnv {
44
45
  }
45
46
  /** Options handed to IsolatePool's constructor. */
46
47
  export interface IsolatePoolOptions {
47
- /** Maximum concurrent in-flight facets. Default 4. */
48
+ /**
49
+ * Maximum concurrent in-flight facets, each a distinct Dynamic Worker
50
+ * spent from the hosting DO's `DO_DYNAMIC_WORKER_LIMIT`. Default 1; a
51
+ * caller that wants more sizes it against that budget (Fanout does).
52
+ */
48
53
  concurrency?: number;
54
+ /**
55
+ * The width the caller claimed for this pool's dispatches
56
+ * (`claimDynamicWorkers`): they are held inside it rather than on top of
57
+ * it, and a refused one waits for a slot of the claim.
58
+ */
59
+ claim?: DynamicWorkerClaim;
49
60
  /** Per-task timeout in ms. Default 60_000. */
50
61
  timeoutMs?: number;
51
62
  /**
@@ -139,15 +150,19 @@ export interface IsolatePoolOptions {
139
150
  /**
140
151
  * WebAssembly modules to ship into the facet via the LOADER's
141
152
  * `modules` map. Map keys are module specifier paths (e.g.
142
- * `'esbuild.wasm'`); values are the raw bytes.
153
+ * `'esbuild.wasm'`); values are the raw bytes, or a module the host
154
+ * already holds compiled.
143
155
  *
144
- * Workerd registers each entry as `{ wasm: ArrayBuffer }` in the
145
- * worker's modules map. The pool prepends a static
156
+ * Workerd registers each entry as `{ wasm }` in the worker's modules
157
+ * map. The pool prepends a static
146
158
  * `import __NIMBUS_WASM_<id> from './<key>';` to the generated
147
- * worker.js so workerd compiles each at module-load (startup phase,
148
- * where wasm code generation is permitted). The compiled Modules
149
- * are exposed via `globalThis.__NIMBUS_WASM[<key>]` for the user
150
- * function to read at request time.
159
+ * worker.js; bytes are compiled at the facet's module-load (startup
160
+ * phase, where wasm code generation is permitted), and a compiled
161
+ * module is shared with the facet as is, its compiled code included
162
+ * (workerd src/workerd/api/worker-loader.c++,
163
+ * extractWasmModuleContent). The Modules are exposed via
164
+ * `globalThis.__NIMBUS_WASM[<key>]` for the user function to read at
165
+ * request time.
151
166
  *
152
167
  * Why this works when other paths don't:
153
168
  * - request-time `WebAssembly.compile()` — disallowed by workerd
@@ -156,15 +171,15 @@ export interface IsolatePoolOptions {
156
171
  * structured-clone refuses ("Unable to deserialize cloned data").
157
172
  * - inlining bytes in the preamble — 16 MiB string per dispatch
158
173
  * OOMs the supervisor at module-source allocation time.
159
- * - LOADER modules-map (this) — bytes ride INSIDE the worker code
160
- * blob; workerd compiles wasm during its own startup pipeline,
161
- * never crossing structured-clone, never executing JS eval.
174
+ * - LOADER modules-map (this) — the module rides INSIDE the worker
175
+ * code blob, never crossing structured-clone, never executing JS
176
+ * eval.
162
177
  *
163
- * The bytes ARE part of the loader-cache key (workerd hashes the
164
- * whole WorkerCode), so changing the wasm bytes invalidates warm
165
- * slots — desirable when the bundled wasm version changes.
178
+ * A compiled module must be described (host-wasm.ts describeHostWasm):
179
+ * its identity keys warm slots, as the bytes' fingerprint does, and its
180
+ * size counts toward the dynamic-worker code limit.
166
181
  */
167
- wasmModules?: Record<string, ArrayBuffer>;
182
+ wasmModules?: Record<string, ArrayBuffer | WebAssembly.Module>;
168
183
  }
169
184
  /** Per-call override (merged with pool defaults). */
170
185
  export interface IsolateCallOptions {
@@ -233,7 +248,7 @@ export declare function assembleLoaderWorkerModuleSource(options: LoaderWorkerMo
233
248
  * Typical use:
234
249
  *
235
250
  * const pool = new IsolatePool(env, ctx, {
236
- * concurrency: 4,
251
+ * concurrency: 2,
237
252
  * tag: 'npm-install',
238
253
  * });
239
254
  * const results = await pool.map(
@@ -246,6 +261,8 @@ export declare class IsolatePool {
246
261
  private readonly loader;
247
262
  /** The hosting actor, as the loader budget ledger's per-DO key. */
248
263
  private readonly ctx;
264
+ /** The width this pool's dispatches are held inside (IsolatePoolOptions.claim). */
265
+ private readonly claim;
249
266
  private readonly concurrency;
250
267
  private readonly defaultTimeoutMs;
251
268
  private readonly defaultRetries;
@@ -273,11 +290,11 @@ export declare class IsolatePool {
273
290
  * across pool dispatches (cache-key stability).
274
291
  */
275
292
  private readonly wasmModules;
276
- /** Hash of (name + byte length + first/last bytes) of every wasm
277
- * module, folded into the loader cache key so changes invalidate
278
- * warm slots. Hashing the FULL bytes would be O(20+ MiB) per dispatch
279
- * and is unnecessary — wasm bytes are pinned at deploy time, the
280
- * length+endpoints are a strong-enough fingerprint. */
293
+ /** Hash of every constructor-time wasm module, folded into the loader
294
+ * cache key so changes invalidate warm slots: a compiled module by the
295
+ * identity its host described, bytes by name + length + first/last
296
+ * byte. Hashing the FULL bytes would be O(20+ MiB) per dispatch and is
297
+ * unnecessary — they are pinned at deploy time. */
281
298
  private readonly wasmHash;
282
299
  /**
283
300
  * Short prefix of the owning DO's id, baked into the loader.get()
@@ -1 +1 @@
1
- {"version":3,"file":"isolate-pool.d.ts","sourceRoot":"","sources":["../src/isolate-pool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"isolate-pool.d.ts","sourceRoot":"","sources":["../src/isolate-pool.ts"],"names":[],"mappings":"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"}