@nimbus-sh/worker 0.2.3 → 0.4.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 (146) hide show
  1. package/dist/_shared/session-router.d.ts +8 -0
  2. package/dist/_shared/session-router.d.ts.map +1 -1
  3. package/dist/_shared/session-router.js +8 -0
  4. package/dist/esbuild-wasm-bundle.generated.d.ts +1 -1
  5. package/dist/esbuild-wasm-bundle.generated.js +1 -1
  6. package/dist/facets/cirrus-real.js +1 -1
  7. package/dist/facets/manager.d.ts +43 -129
  8. package/dist/facets/manager.d.ts.map +1 -1
  9. package/dist/facets/manager.js +107 -318
  10. package/dist/facets/opencode-staging.d.ts +1 -1
  11. package/dist/facets/opencode-staging.d.ts.map +1 -1
  12. package/dist/facets/opencode-staging.js +3 -0
  13. package/dist/facets/real-vite-hmr.js +1 -1
  14. package/dist/facets/vite-dev-server.d.ts +4 -4
  15. package/dist/facets/vite-dev-server.js +5 -5
  16. package/dist/git/commands.d.ts +8 -0
  17. package/dist/git/commands.d.ts.map +1 -1
  18. package/dist/git/commands.js +41 -9
  19. package/dist/git/network-facet.d.ts +1 -1
  20. package/dist/git/network-facet.d.ts.map +1 -1
  21. package/dist/git/network-facet.js +39 -15
  22. package/dist/git-bundle.generated.d.ts +2 -2
  23. package/dist/git-bundle.generated.d.ts.map +1 -1
  24. package/dist/git-bundle.generated.js +3 -3
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +9 -1
  27. package/dist/loaders/child-process/spawn-facet.js +1 -1
  28. package/dist/loaders/child-process/spawn-pool.d.ts.map +1 -1
  29. package/dist/loaders/child-process/spawn-pool.js +2 -2
  30. package/dist/loaders/generated-workers.d.ts +2 -2
  31. package/dist/loaders/generated-workers.d.ts.map +1 -1
  32. package/dist/loaders/generated-workers.js +3 -3
  33. package/dist/loaders/npm-resolve-preamble.d.ts +3 -3
  34. package/dist/loaders/npm-resolve-preamble.js +3 -3
  35. package/dist/loaders/pre-bundle-preamble.d.ts +5 -5
  36. package/dist/loaders/pre-bundle-preamble.js +6 -6
  37. package/dist/loaders/process-host.d.ts +6 -107
  38. package/dist/loaders/process-host.d.ts.map +1 -1
  39. package/dist/loaders/process-host.js +6 -405
  40. package/dist/npm/install-batch-facet.d.ts +1 -1
  41. package/dist/npm/install-batch-facet.js +1 -1
  42. package/dist/npm/installer.d.ts +6 -6
  43. package/dist/npm/installer.d.ts.map +1 -1
  44. package/dist/npm/installer.js +28 -27
  45. package/dist/npm/pre-bundle-facet.d.ts +2 -2
  46. package/dist/npm/pre-bundle-facet.js +5 -5
  47. package/dist/npm/r2-cache.d.ts +1 -1
  48. package/dist/npm/resolve-facet.d.ts +1 -1
  49. package/dist/npm/resolve-facet.js +1 -1
  50. package/dist/npm/resolve-one-facet.d.ts +5 -5
  51. package/dist/npm/resolve-one-facet.js +5 -5
  52. package/dist/router/index.js +2 -2
  53. package/dist/router/remote-api.js +9 -1
  54. package/dist/runtime/bun-repl.d.ts +1 -1
  55. package/dist/runtime/bun-repl.js +3 -3
  56. package/dist/runtime/esbuild-wasm-bytes.js +1 -1
  57. package/dist/runtime/facet-loader-host.d.ts +5 -8
  58. package/dist/runtime/facet-loader-host.d.ts.map +1 -1
  59. package/dist/runtime/facet-loader-host.js +7 -11
  60. package/dist/runtime/node-repl.js +2 -2
  61. package/dist/runtime/node-shims-artifact.js +1 -1
  62. package/dist/runtime/node-shims.js +2 -1
  63. package/dist/runtime/opencode-artifact.js +1 -1
  64. package/dist/runtime/opentui-wasm-bytes.js +1 -1
  65. package/dist/runtime/python-repl.js +3 -3
  66. package/dist/runtime/ruby-repl.js +2 -2
  67. package/dist/runtime/ruby-resident.js +1 -1
  68. package/dist/runtime/sqlite-wasm-bytes.js +1 -1
  69. package/dist/session/diag.js +1 -1
  70. package/dist/session/hibernation.d.ts +20 -53
  71. package/dist/session/hibernation.d.ts.map +1 -1
  72. package/dist/session/hibernation.js +57 -194
  73. package/dist/session/init-phases.d.ts +2 -3
  74. package/dist/session/init-phases.d.ts.map +1 -1
  75. package/dist/session/init-phases.js +3 -2
  76. package/dist/session/init.d.ts.map +1 -1
  77. package/dist/session/init.js +8 -4
  78. package/dist/session/keys.d.ts +14 -37
  79. package/dist/session/keys.d.ts.map +1 -1
  80. package/dist/session/keys.js +18 -37
  81. package/dist/session/nimbus-session.d.ts +10 -15
  82. package/dist/session/nimbus-session.d.ts.map +1 -1
  83. package/dist/session/nimbus-session.js +28 -31
  84. package/dist/session/port-capability.d.ts +43 -0
  85. package/dist/session/port-capability.d.ts.map +1 -0
  86. package/dist/session/port-capability.js +49 -0
  87. package/dist/session/programmatic.d.ts +39 -5
  88. package/dist/session/programmatic.d.ts.map +1 -1
  89. package/dist/session/programmatic.js +150 -19
  90. package/dist/session/routes.d.ts +2 -0
  91. package/dist/session/routes.d.ts.map +1 -1
  92. package/dist/session/routes.js +96 -20
  93. package/dist/session/rpc.d.ts +36 -9
  94. package/dist/session/rpc.d.ts.map +1 -1
  95. package/dist/session/rpc.js +84 -24
  96. package/dist/session/start-real-vite.d.ts.map +1 -1
  97. package/dist/session/start-real-vite.js +3 -1
  98. package/dist/session/state-store.d.ts +3 -2
  99. package/dist/session/state-store.d.ts.map +1 -1
  100. package/dist/session/state-store.js +3 -2
  101. package/dist/session/supervisor-rpc.d.ts.map +1 -1
  102. package/dist/session/supervisor-rpc.js +7 -4
  103. package/dist/session/ws.d.ts +1 -3
  104. package/dist/session/ws.d.ts.map +1 -1
  105. package/dist/session/ws.js +4 -3
  106. package/dist/wrangler/nimbus-wrangler.js +1 -1
  107. package/package.json +4 -2
  108. package/scripts/bundle-esbuild-wasm.mjs +2 -2
  109. package/scripts/bundle-facet-workers.mjs +5 -7
  110. package/scripts/bundle-sqlite-wasm.mjs +1 -1
  111. package/dist/facets/inner-do-registry.d.ts +0 -41
  112. package/dist/facets/inner-do-registry.d.ts.map +0 -1
  113. package/dist/facets/inner-do-registry.js +0 -51
  114. package/dist/facets/launch-pacer.d.ts +0 -111
  115. package/dist/facets/launch-pacer.d.ts.map +0 -1
  116. package/dist/facets/launch-pacer.js +0 -130
  117. package/dist/loaders/fanout-pool.d.ts +0 -207
  118. package/dist/loaders/fanout-pool.d.ts.map +0 -1
  119. package/dist/loaders/fanout-pool.js +0 -363
  120. package/dist/loaders/loader-pool.d.ts +0 -294
  121. package/dist/loaders/loader-pool.d.ts.map +0 -1
  122. package/dist/loaders/loader-pool.js +0 -642
  123. package/dist/loaders/process-fabric.d.ts +0 -509
  124. package/dist/loaders/process-fabric.d.ts.map +0 -1
  125. package/dist/loaders/process-fabric.js +0 -360
  126. package/dist/loaders/vendor/errors.d.ts +0 -24
  127. package/dist/loaders/vendor/errors.d.ts.map +0 -1
  128. package/dist/loaders/vendor/errors.js +0 -46
  129. package/dist/loaders/vendor/serialize.d.ts +0 -3
  130. package/dist/loaders/vendor/serialize.d.ts.map +0 -1
  131. package/dist/loaders/vendor/serialize.js +0 -25
  132. package/dist/loaders/vendor/types.d.ts +0 -69
  133. package/dist/loaders/vendor/types.d.ts.map +0 -1
  134. package/dist/loaders/vendor/types.js +0 -4
  135. package/dist/loaders/workerd-facet-host.d.ts +0 -141
  136. package/dist/loaders/workerd-facet-host.d.ts.map +0 -1
  137. package/dist/loaders/workerd-facet-host.js +0 -284
  138. package/dist/session/bindings.d.ts +0 -209
  139. package/dist/session/bindings.d.ts.map +0 -1
  140. package/dist/session/bindings.js +0 -680
  141. package/dist/session/ctx-exports.d.ts +0 -16
  142. package/dist/session/ctx-exports.d.ts.map +0 -1
  143. package/dist/session/ctx-exports.js +0 -22
  144. package/dist/session/ws-hibernation-config.d.ts +0 -64
  145. package/dist/session/ws-hibernation-config.d.ts.map +0 -1
  146. package/dist/session/ws-hibernation-config.js +0 -89
@@ -1,69 +1,9 @@
1
1
  /**
2
- * process-host.ts — the two substrates a resident process can run on, and the
3
- * one value that picks between them.
4
- *
5
- * `loaders/process-fabric.ts` owns what a resident process IS. This module
6
- * owns only where it lives, behind `ProcessHost`:
7
- *
8
- * facet — the process is a named child actor of the user's own session DO.
9
- * peer — the process is a named child actor of a SIBLING session DO, and
10
- * the coordinator reaches it over one held-open RPC.
11
- *
12
- * Both call the same `openResidentFacet`. The peer leg is not a second process
13
- * implementation; it is the same call made on a different actor, which is why
14
- * the runner, the boot spec, the class name, the writer handshake, the start
15
- * contract and the lifecycle are shared code rather than parallel paths.
16
- *
17
- * Choosing between them
18
- * ─────────────────────
19
- * `NIMBUS_PROCESS_HOST`, one var for the whole deployment. No spawn site
20
- * chooses; no program name, mode or payload size reaches the choice. If a
21
- * decision about a particular process ever appears here, the heavy/light
22
- * classifier has grown back and should be deleted again.
23
- *
24
- * | | spawn | memory | CPU | SQLite |
25
- * |----------|------------|-------------|------------|--------|
26
- * | facet | 8-16 ms | independent | SHARED | own |
27
- * | peer | 242-359 ms | independent | independent| own |
28
- *
29
- * Facet CPU is shared because facets are separate isolates inside ONE actor
30
- * thread: awaiting I/O yields it completely (measured 0 ms of sibling impact),
31
- * but a non-yielding loop stalls every sibling for its full duration
32
- * (measured 6,852 ms). A peer pays ~20x the spawn cost to buy that back.
33
- *
34
- * What the peer leg has to do differently, and why none of it reaches the
35
- * process
36
- * ────────────────────────────────────────────────────────────────────────
37
- * payloads — a whole structured-clone RPC value is capped at 32 MiB, and
38
- * pi's node snapshot alone serializes to 44,252,709 bytes. Boot
39
- * specs name their large members BY PATH, so what crosses is a
40
- * path and the host reads the bytes off the coordinator's disk in
41
- * 4 MiB ranges through the supervisor. Nothing large is ever an
42
- * RPC argument, so nothing has to be streamed or replayed.
43
- * requests — workerd refuses to transfer an object owned by a
44
- * dynamically-loaded worker across a sibling-DO hop, so a request
45
- * travels to the peer as PARTS and the response comes back as
46
- * parts, both with plain `ReadableStream` bodies that RPC carries
47
- * with flow control. A live SSE body still streams; nothing is
48
- * buffered.
49
- * liveness — the host leg is held open for the process's whole life, which
50
- * is also what keeps the hosting DO resident. A peer therefore
51
- * never outlives its coordinator: the coordinator dying cancels
52
- * the inbound call and the facet dies with it. Nothing in this
53
- * fabric arms an alarm, on either substrate.
54
- *
55
- * WebSockets are NOT in that list, because a resident process never receives
56
- * one. `RouteableFacetTarget` is `handleHttpRequest(Request): Promise<Response>`
57
- * and nothing else; no runner returns a 101 with a `webSocket` member; every
58
- * inbound socket Nimbus serves — the shell terminal, `/api/logs/<pid>`, vite
59
- * HMR — terminates on the session DO and reaches the process, if at all, as
60
- * events on a supervisor poll. That is substrate-independent by construction.
2
+ * process-host.ts — which substrate this deployment runs resident processes
3
+ * on. The substrates themselves live in `@nimbus-sh/fabric/process-host.js`;
4
+ * this module owns only the deployment config that picks between them.
61
5
  */
62
- import { disposeRpcResource } from '@nimbus-sh/core/_shared/rpc-dispose.js';
63
- import { isTransientDoReset } from '@nimbus-sh/core/observability/oom-classify.js';
64
- import { PEER_RETRY_BACKOFF_MS, PEER_TRANSIENT_RESET_RETRIES } from './fanout-pool.js';
65
- import { DYNAMIC_WORKER_CODE_LIMIT_BYTES, openResidentFacet, residentFacetName, runOneShotWorker, } from './workerd-facet-host.js';
66
- import { BindingError } from './vendor/errors.js';
6
+ import { createProcessHost, } from '@nimbus-sh/fabric/process-host.js';
67
7
  /**
68
8
  * The var that picks the substrate, and the only place its name appears.
69
9
  * Unset means `facet`; an unrecognized value is refused rather than defaulted,
@@ -80,346 +20,7 @@ export function processHostMode(env) {
80
20
  return 'peer';
81
21
  throw new Error(`Nimbus: NIMBUS_PROCESS_HOST must be 'facet' or 'peer' (got '${String(raw)}')`);
82
22
  }
83
- /**
84
- * The substrate for this deployment, resolved once. `disk` is the
85
- * coordinator's own filesystem reader; the peer host does not take it, because
86
- * a peer reads the same disk through the supervisor instead.
87
- */
23
+ /** The substrate for this deployment, resolved once. */
88
24
  export function processHostFor(ctx, env, disk) {
89
- return processHostMode(env) === 'peer'
90
- ? new PeerProcessHost(ctx, env)
91
- : new FacetProcessHost(ctx, env, disk);
92
- }
93
- // ── facet: the process is a child of the user's own session DO ──────────────
94
- class FacetProcessHost {
95
- ctx;
96
- disk;
97
- /**
98
- * The process shares its session's Durable Object, so the session's own
99
- * store is reachable by copy-on-write — and its storage budget is the same
100
- * budget. Both halves of that follow from the one fact, and neither is
101
- * optional.
102
- */
103
- imageDelivery = {
104
- reflink: 'same-object',
105
- moduleCeilingBytes: DYNAMIC_WORKER_CODE_LIMIT_BYTES,
106
- storageSharedWithSession: true,
107
- };
108
- env;
109
- coordDoId;
110
- constructor(ctx, env, disk) {
111
- this.ctx = ctx;
112
- this.disk = disk;
113
- this.env = (env ?? {});
114
- this.coordDoId = ctx.id.toString();
115
- }
116
- runOnce(params, consume) {
117
- return runOneShotWorker(this.env, { doId: this.coordDoId, pid: params.pid, writerId: params.writerId }, params, consume);
118
- }
119
- async open(params) {
120
- const supervisor = {
121
- doId: this.coordDoId,
122
- pid: params.pid,
123
- writerId: params.writerId,
124
- };
125
- const { slot, ...facet } = openResidentFacet(this.ctx, this.env, this.disk, supervisor, params);
126
- return {
127
- ...facet,
128
- describe: () => `facet '${residentFacetName(slot)}' (pid ${params.pid})`
129
- + ` of session ${this.coordDoId.slice(-12)}`
130
- + `; ${describeImageDelivery(this.imageDelivery)}`,
131
- };
132
- }
133
- }
134
- /**
135
- * The operator-facing half of the substrate difference, on the one line an
136
- * operator actually reads. A comment in this file would not have told anyone
137
- * who flipped the config that the image path changed under them.
138
- */
139
- function describeImageDelivery(delivery) {
140
- return `fs image: reflink ${delivery.reflink}, module map ≤ ${delivery.moduleCeilingBytes}B, `
141
- + `storage ${delivery.storageSharedWithSession ? 'shared with the session' : 'its own'}`;
142
- }
143
- // ── peer: the process is a child of a sibling session DO ────────────────────
144
- /**
145
- * How many sibling names to try before accepting one that co-located with a
146
- * process already running. Measured: 1 shared pair in 24 fresh peers.
147
- */
148
- const PEER_PLACEMENT_MAX_ATTEMPTS = 4;
149
- /**
150
- * This workerd process's identity. Module scope, so two Durable Objects
151
- * reporting the same token are in the same process — which is exactly the CPU
152
- * sharing a peer exists to avoid, and the only way to detect it.
153
- */
154
- let _isolateToken = null;
155
- export function isolateToken() {
156
- if (!_isolateToken)
157
- _isolateToken = crypto.randomUUID();
158
- return _isolateToken;
159
- }
160
- /**
161
- * Every method a hosting sibling must answer. Checked as a set at first
162
- * contact: a stub that has the probe but not the router is a deployment skew,
163
- * and finding that out mid-process is finding it out too late.
164
- */
165
- const PROCESS_PEER_METHODS = [
166
- '_rpcProcessHostProbe',
167
- '_rpcHostProcess',
168
- '_rpcAwaitHostedOpen',
169
- '_rpcAwaitHostedBoot',
170
- '_rpcRouteHostedHttp',
171
- '_rpcCancelHostProcess',
172
- ];
173
- function peerNamespace(env) {
174
- const ns = (typeof env === 'object' || typeof env === 'function') && env !== null
175
- ? Reflect.get(env, 'NIMBUS_SESSION')
176
- : undefined;
177
- if ((typeof ns !== 'object' && typeof ns !== 'function') || ns === null
178
- || typeof Reflect.get(ns, 'idFromName') !== 'function'
179
- || typeof Reflect.get(ns, 'get') !== 'function') {
180
- throw new BindingError('ProcessFabric: env.NIMBUS_SESSION binding missing or invalid. '
181
- + "NIMBUS_PROCESS_HOST='peer' hosts every resident process on a sibling "
182
- + 'Durable Object; add the binding via durable_objects.bindings in wrangler.jsonc.');
183
- }
184
- return ns;
185
- }
186
- function processPeerStub(value, peerName) {
187
- if ((typeof value !== 'object' && typeof value !== 'function') || value === null) {
188
- throw new BindingError(`ProcessFabric: NIMBUS_SESSION.get() returned no stub for peer '${peerName}'.`);
189
- }
190
- for (const method of PROCESS_PEER_METHODS) {
191
- if (typeof Reflect.get(value, method) !== 'function') {
192
- throw new BindingError(`ProcessFabric: peer '${peerName}' does not expose ${method}(). `
193
- + 'A sibling that answers some of the host-process surface and not the rest '
194
- + 'would fail somewhere inside a running process instead of here.');
195
- }
196
- }
197
- return value;
198
- }
199
- class PeerProcessHost {
200
- ctx;
201
- /**
202
- * A peer buys independent CPU and its own storage budget, and pays for both
203
- * with the image path: nothing crosses a Durable Object boundary by
204
- * reference, so the whole session filesystem has to travel as bytes.
205
- */
206
- imageDelivery = {
207
- reflink: 'impossible',
208
- moduleCeilingBytes: DYNAMIC_WORKER_CODE_LIMIT_BYTES,
209
- storageSharedWithSession: false,
210
- };
211
- ns;
212
- env;
213
- coordDoId;
214
- /** pid → the isolate token of the peer currently hosting that process. */
215
- tokensInUse = new Map();
216
- constructor(ctx, env) {
217
- this.ctx = ctx;
218
- this.ns = peerNamespace(env);
219
- this.env = (env ?? {});
220
- this.coordDoId = ctx.id.toString();
221
- }
222
- /**
223
- * Not placed on a sibling, and that is not a gap in this substrate.
224
- * `peer` exists to buy a resident process independent CPU; a program that
225
- * ends with the call it was started by has no residency to place, and its
226
- * map is fully inline — so a hop would meet the RPC ceiling that by-path
227
- * boot specs exist to avoid while buying nothing. It runs as a dynamic
228
- * worker of the coordinator here exactly as it does on `facet`.
229
- */
230
- runOnce(params, consume) {
231
- return runOneShotWorker(this.env, { doId: this.coordDoId, pid: params.pid, writerId: params.writerId }, params, consume);
232
- }
233
- async open(params) {
234
- const placement = await this._place(params.pid);
235
- this.tokensInUse.set(params.pid, placement.isolateToken);
236
- // Held open for the process's whole life: it is the lifecycle, and it is
237
- // also what keeps the hosting DO resident. It settles when a `lifetime`
238
- // runner exits or when a `boot` runner's host is cancelled, and rejects if
239
- // the peer dies under either.
240
- const hostLeg = placement.stub._rpcHostProcess(params.boot, {
241
- coordinatorDoId: this.coordDoId,
242
- pid: params.pid,
243
- writerId: params.writerId,
244
- workerKey: params.workerKey,
245
- startArgs: params.startArgs,
246
- });
247
- hostLeg.catch(() => { });
248
- // The peer starts the runner as part of hosting it; this reads back that
249
- // one boot payload without re-running anything, so `started` means exactly
250
- // what it means on a facet. Racing the host leg is what turns a peer that
251
- // died before the boot landed into a rejection rather than a hang — the
252
- // peer that would have answered is the thing that is gone.
253
- const booted = placement.stub._rpcAwaitHostedBoot(params.workerKey).then((r) => r.payload);
254
- booted.catch(() => { });
255
- const started = Promise.race([booted, hostLeg.then(() => booted)]);
256
- started.catch(() => { });
257
- // Do not return a handle for a process that was never opened. Opening a
258
- // facet of one's own DO either throws or does not, before any handle
259
- // exists; this is that same moment, one hop away.
260
- try {
261
- await Promise.race([
262
- placement.stub._rpcAwaitHostedOpen(params.workerKey),
263
- hostLeg.then(() => ({ ok: true })),
264
- ]);
265
- }
266
- catch (error) {
267
- this.tokensInUse.delete(params.pid);
268
- // Awaited, not fired off: a spawn that rejects must mean nothing was
269
- // left running, which is what a throw from `openResidentFacet` means on
270
- // the other substrate.
271
- try {
272
- await this._cancel(params.workerKey, placement.peerName);
273
- }
274
- finally {
275
- disposeRpcResource(placement.stub);
276
- }
277
- throw error;
278
- }
279
- let released = false;
280
- return {
281
- started,
282
- // The held leg IS the process's residency here. It settles cleanly when
283
- // the coordinator releases; anything else is the host going away under a
284
- // process that was up, and the fabric ends the process on it.
285
- lost: hostLeg.then(() => new Promise(() => { })),
286
- handleHttpRequest: (request) => routeThroughPeer(placement.stub, params.workerKey, request),
287
- release: async () => {
288
- if (released)
289
- return;
290
- released = true;
291
- this.tokensInUse.delete(params.pid);
292
- try {
293
- await this._cancel(params.workerKey, placement.peerName);
294
- }
295
- finally {
296
- disposeRpcResource(placement.stub);
297
- }
298
- },
299
- describe: () => `peer '${placement.peerName}' (isolate ${placement.isolateToken.slice(0, 8)})`
300
- + `; ${describeImageDelivery(this.imageDelivery)}`,
301
- };
302
- }
303
- /**
304
- * Probe successive sibling names until one reports an isolate token distinct
305
- * from this coordinator's and from every peer already hosting a process. A
306
- * peer that co-located bought nothing — it shares the CPU it was chosen to
307
- * escape — so placement verifies rather than assumes.
308
- */
309
- async _place(pid) {
310
- const denied = new Set([isolateToken(), ...this.tokensInUse.values()]);
311
- for (let attempt = 0; attempt < PEER_PLACEMENT_MAX_ATTEMPTS - 1; attempt++) {
312
- const candidate = await this._probePlacement(pid, attempt);
313
- if (!denied.has(candidate.isolateToken))
314
- return candidate;
315
- disposeRpcResource(candidate.stub);
316
- }
317
- // Every attempt co-located, which happens in single-process topologies. Use
318
- // the last one anyway: it runs the process correctly, it just shares the
319
- // CPU it was chosen to escape, and the placement line names the isolate it
320
- // landed in so that is visible rather than assumed.
321
- return this._probePlacement(pid, PEER_PLACEMENT_MAX_ATTEMPTS - 1);
322
- }
323
- /** One sibling name, resolved and probed. Leaks nothing on failure. */
324
- async _probePlacement(pid, attempt) {
325
- const peerName = `${this.coordDoId}:proc:${pid}:${attempt}`;
326
- let resource;
327
- try {
328
- resource = this.ns.get(this.ns.idFromName(peerName));
329
- const stub = processPeerStub(resource, peerName);
330
- const probe = await this._probe(stub, peerName);
331
- return { stub, peerName, isolateToken: probe.isolateToken };
332
- }
333
- catch (error) {
334
- disposeRpcResource(resource);
335
- throw error;
336
- }
337
- }
338
- /**
339
- * First contact with a possibly-cold sibling DO: retry transient platform
340
- * resets with the same bounded policy the fanout peers ship. Non-transient
341
- * failures propagate on the first hit.
342
- */
343
- async _probe(stub, peerName) {
344
- for (let attempt = 0;; attempt++) {
345
- try {
346
- const probe = await stub._rpcProcessHostProbe();
347
- if (!probe || typeof probe.isolateToken !== 'string' || probe.isolateToken.length === 0) {
348
- throw new Error(`ProcessFabric: peer '${peerName}' returned no isolate token`);
349
- }
350
- return probe;
351
- }
352
- catch (err) {
353
- if (attempt < PEER_TRANSIENT_RESET_RETRIES && isTransientDoReset(err)) {
354
- await new Promise((r) => setTimeout(r, PEER_RETRY_BACKOFF_MS[Math.min(attempt, PEER_RETRY_BACKOFF_MS.length - 1)]));
355
- continue;
356
- }
357
- throw err;
358
- }
359
- }
360
- }
361
- /**
362
- * A fresh stub to the hosting peer fires `_rpcCancelHostProcess`, which
363
- * releases the peer's facet — the exact teardown a local facet gets — and
364
- * only answers once it has. Awaiting it is what makes "released" mean the
365
- * same thing on both substrates, so the writer identity is retired at the
366
- * same point in the process's life either way. Also handed to `waitUntil`,
367
- * so a kill nobody awaited still completes.
368
- */
369
- _cancel(workerKey, peerName) {
370
- let stub;
371
- try {
372
- stub = processPeerStub(this.ns.get(this.ns.idFromName(peerName)), peerName);
373
- }
374
- catch {
375
- return Promise.resolve();
376
- }
377
- const cancelled = Promise.resolve(stub._rpcCancelHostProcess(workerKey))
378
- .then(() => undefined)
379
- .catch(() => { })
380
- .finally(() => disposeRpcResource(stub));
381
- this.ctx.waitUntil(cancelled);
382
- return cancelled;
383
- }
384
- }
385
- async function routeThroughPeer(stub, workerKey, request) {
386
- const result = await stub._rpcRouteHostedHttp(workerKey, {
387
- method: request.method,
388
- url: request.url,
389
- headers: headerPairs(request.headers),
390
- body: request.method === 'GET' || request.method === 'HEAD' ? null : request.body,
391
- });
392
- const responseHeaders = new Headers();
393
- for (const [key, value] of result.headers)
394
- responseHeaders.append(key, value);
395
- return new Response(result.body, {
396
- status: result.status,
397
- statusText: result.statusText,
398
- headers: responseHeaders,
399
- });
400
- }
401
- /**
402
- * Headers as pairs, with every `Set-Cookie` kept separate.
403
- *
404
- * Iterating a `Headers` combines same-named fields into one comma-joined
405
- * value, and for `Set-Cookie` that is not reversible — `append` cannot split
406
- * `a=1; Path=/, b=2; Path=/` back into two cookies, and a browser reading the
407
- * merged form sets one malformed cookie instead of two. Every other field
408
- * combines by comma legally, so only this one needs the separate accessor.
409
- * A user's server setting two cookies must not depend on which substrate its
410
- * process happened to run on.
411
- */
412
- export function headerPairs(headers) {
413
- const pairs = [];
414
- headers.forEach((value, key) => {
415
- if (key.toLowerCase() !== 'set-cookie')
416
- pairs.push([key, value]);
417
- });
418
- const getSetCookie = headers.getSetCookie;
419
- const cookies = typeof getSetCookie === 'function'
420
- ? getSetCookie.call(headers)
421
- : (headers.get('set-cookie') ? [headers.get('set-cookie')] : []);
422
- for (const cookie of cookies)
423
- pairs.push(['set-cookie', cookie]);
424
- return pairs;
25
+ return createProcessHost(processHostMode(env), ctx, env, disk);
425
26
  }
@@ -67,7 +67,7 @@ export interface InstallBatchResult {
67
67
  perPackage: InstallBatchPerPackage[];
68
68
  /** Wall-clock ms inside the facet (whole batch). */
69
69
  elapsed: number;
70
- /** Counter snapshot at end of batch. Mirrors src/observability/diag-counters.ts shape
70
+ /** Counter snapshot at end of batch. Mirrors @nimbus-sh/platform/diag-counters.js shape
71
71
  * for the install-facet subset (commit 3 surfaces these in /api/_diag/memory). */
72
72
  facetCounters: {
73
73
  tarballsCompleted: number;
@@ -38,7 +38,7 @@
38
38
  */
39
39
  // ── Facet function ──────────────────────────────────────────────────────
40
40
  //
41
- // Runs inside a NimbusLoaderPool isolate. Serialised via fn.toString();
41
+ // Runs inside a IsolatePool isolate. Serialised via fn.toString();
42
42
  // the helpers it references at top-level scope (streamTarEntries,
43
43
  // readableStreamToAsyncIterable, MAX_FILE_BYTES) are NOT in the facet's
44
44
  // lexical scope — the pool injects them via the preamble. No static
@@ -24,7 +24,7 @@ import type { EsbuildService } from '@nimbus-sh/core/runtime/esbuild-service.js'
24
24
  import { NpmCache } from './cache.js';
25
25
  import { type FetchFn } from './resolver.js';
26
26
  import { type NpmLogEmitter } from './npm-log.js';
27
- import type { InstallPhase } from '@nimbus-sh/core/_shared/install-phase.js';
27
+ import type { InstallPhase } from '@nimbus-sh/platform/install-phase.js';
28
28
  export interface InstallProgress {
29
29
  phase: InstallPhase;
30
30
  resolved: number;
@@ -91,7 +91,7 @@ export declare class NpmInstaller {
91
91
  /**
92
92
  * F-2 frontier-coordinator path. Replaces the single-resolve-facet
93
93
  * dispatch with a per-package fanout: each BFS layer becomes ONE
94
- * `NimbusFanoutPool.submitMany` call, layer N+1 builds from the
94
+ * `Fanout.submitMany` call, layer N+1 builds from the
95
95
  * resolved metadata of layer N.
96
96
  *
97
97
  * Topology auto-routes per layer:
@@ -115,12 +115,12 @@ export declare class NpmInstaller {
115
115
  */
116
116
  private resolveTreeViaFanout;
117
117
  /**
118
- * Batch install via two-tier fan-out (NimbusFanoutPool).
118
+ * Batch install via two-tier fan-out (Fanout).
119
119
  *
120
120
  * Shard count is `min(specs.length, INSTALL_PEER_CAP)`, and the topology
121
121
  * follows from it:
122
122
  * shardCount < IN_DO_THRESHOLD (5) → in-DO fanout in-DO
123
- * 1 NimbusLoaderPool with concurrency = shardCount, capped at
123
+ * 1 IsolatePool with concurrency = shardCount, capped at
124
124
  * 4 by V8 invariant. Each shard is one facet running its own
125
125
  * installPackagesInFacet.
126
126
  * shardCount >= IN_DO_THRESHOLD → peer-DO fanout peer-DO
@@ -132,7 +132,7 @@ export declare class NpmInstaller {
132
132
  * `shard-${i}` task key deterministically (tests can predict
133
133
  * placement).
134
134
  *
135
- * Pre-fix lineage: this site previously ran ONE NimbusLoaderPool
135
+ * Pre-fix lineage: this site previously ran ONE IsolatePool
136
136
  * with concurrency=1, internal pLimit(3) — the explicit "collapses
137
137
  * what was 4 concurrent dynamic workers (pool.map slots) into 1"
138
138
  * Two-tier topology re-expands the fan-out without re-introducing
@@ -225,7 +225,7 @@ export declare class NpmInstaller {
225
225
  /**
226
226
  * P5 (production reliability) — deterministic supervisor-heap estimate in MiB.
227
227
  *
228
- * Routes through observability/heap-estimate.ts which sums KNOWN
228
+ * Routes through @nimbus-sh/platform/heap-estimate.js which sums KNOWN
229
229
  * supervisor heap allocation sources from runtime counters that
230
230
  * ARE accurate inside a DO context (DiagCounters singleton +
231
231
  * SqliteVFS.getStats()). This replaces a previous use of
@@ -1 +1 @@
1
- {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../src/npm/installer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../src/npm/installer.ts"],"names":[],"mappings":"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"}