@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
@@ -5,7 +5,7 @@
5
5
  * Why this exists
6
6
  * ───────────────
7
7
  * Pre-bundling npm packages (the `Pre-bundling N modules…` step in
8
- * src/npm/installer.ts) runs inside NimbusLoaderPool isolates so each
8
+ * src/npm/installer.ts) runs inside NimbusIsolatePool isolates so each
9
9
  * `esbuild.build()` allocation hits a fresh 128 MiB envelope rather
10
10
  * than the supervisor's. The facet needs two pieces of esbuild-wasm
11
11
  * at module-load time:
@@ -175,7 +175,7 @@ async function main() {
175
175
  * esbuild-wasm-bundle.generated.ts — AUTO-GENERATED by scripts/bundle-esbuild-wasm.mjs
176
176
  * DO NOT EDIT.
177
177
  *
178
- * Bundled esbuild-wasm ${version} adapter for use inside NimbusLoaderPool
178
+ * Bundled esbuild-wasm ${version} adapter for use inside NimbusIsolatePool
179
179
  * isolates. Only the JS adapter is bundled here (~117 KiB); the wasm
180
180
  * binary itself lives in the static-assets layer at
181
181
  * public/_assets/esbuild-${version}.wasm and is fetched on demand by
@@ -4,7 +4,7 @@
4
4
  * injects into dynamic workers.
5
5
  *
6
6
  * WHY this exists:
7
- * Dynamic workers (NimbusFacetPool / NimbusLoaderPool) receive their
7
+ * Dynamic workers (NimbusFacetPool / NimbusIsolatePool) receive their
8
8
  * module source as strings — they cannot import supervisor modules,
9
9
  * and user functions cannot capture supervisor closure variables. Any
10
10
  * TypeScript the injected code needs must therefore be esbuild-bundled
@@ -51,6 +51,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
51
51
  const __dirname = dirname(fileURLToPath(import.meta.url));
52
52
  const root = join(__dirname, '..');
53
53
  const coreRoot = join(root, '..', 'core');
54
+ const platformRoot = join(root, '..', 'platform');
54
55
 
55
56
  /**
56
57
  * Bundle one TS source into a self-contained ESM string suitable for
@@ -273,11 +274,8 @@ async function main() {
273
274
  // facet has no access to the encoder symbol (cloudflare-parallel
274
275
  // serialises via fn.toString() — no runtime imports).
275
276
  //
276
- // The W7-frame module imports a TypeScript type from sqlite-vfs,
277
- // which esbuild's type-stripping handles transparently. The
278
- // runtime output has no imports.
279
277
  const w7Stripped = await bundleAsPreamble(
280
- join(coreRoot, 'src', '_shared', 'w7-frame.ts'),
278
+ join(platformRoot, 'src', 'w7-frame.ts'),
281
279
  'w7-frame',
282
280
  );
283
281
 
@@ -291,7 +289,7 @@ async function main() {
291
289
  ' *',
292
290
  ' * Produced by scripts/bundle-facet-workers.mjs from:',
293
291
  ' * - @nimbus-sh/core src/_shared/tarball-stream.ts (streaming tar primitives)',
294
- ' * - @nimbus-sh/core src/_shared/w7-frame.ts (W7 streaming bulk-write encoder)',
292
+ ' * - @nimbus-sh/platform src/w7-frame.ts (W7 streaming bulk-write encoder)',
295
293
  ' *',
296
294
  ' * Consumed by src/loaders/loader-pool.ts callers via the `preamble`',
297
295
  ' * option. The preamble is injected at the top of every generated',
@@ -327,7 +325,7 @@ async function main() {
327
325
  ' *',
328
326
  ' * Self-contained IIFE that installs globalThis.__nimbusVirtualSockets.',
329
327
  ' * Consumed by python-runner.ts and ruby-runner.ts: spliced into the',
330
- ' * socket process worker module source passed to NimbusLoaderPool.',
328
+ ' * socket process worker module source passed to NimbusIsolatePool.',
331
329
  ' *',
332
330
  ` * Size: ${(kernelSrc.length / 1024).toFixed(2)} KiB`,
333
331
  ' */',
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Why this exists
7
7
  * ───────────────
8
- * `import { DatabaseSync } from "node:sqlite"` runs inside NimbusLoaderPool
8
+ * `import { DatabaseSync } from "node:sqlite"` runs inside NimbusIsolatePool
9
9
  * facet isolates. sql.js (Emscripten SQLite) needs two pieces at facet
10
10
  * runtime:
11
11
  *
@@ -1,41 +0,0 @@
1
- /**
2
- * inner-do-registry.ts — Module-level registry of inner DO classes.
3
- *
4
- * `nimbus-wrangler` populates this on each successful buildAndLoad()
5
- * with the DurableObject classes extracted from the freshly-loaded
6
- * inner Worker via `worker.getDurableObjectClass(name)`. The supervisor
7
- * DO (`NimbusSession`) reads it on each inner-DO fetch to synthesize a
8
- * NimbusDurableObjectNamespace stub for `env.MY_DO`.
9
- *
10
- * Why a separate leaf module:
11
- * Before this extraction, the registry lived inside nimbus-session.ts,
12
- * which forced nimbus-wrangler.ts to import from nimbus-session.ts —
13
- * producing the cycle
14
- * index.ts -> nimbus-session.ts -> nimbus-wrangler.ts -> nimbus-session.ts
15
- * Promoting the registry to its own leaf breaks that cycle without
16
- * changing any semantics. The Map identity is preserved across the
17
- * isolate (it's still process-scoped — module-level state — survives
18
- * across DO instances in the same workerd process).
19
- *
20
- * Key shape:
21
- * `<supervisor-DO-id>:<binding-name>` — both halves are required to
22
- * prevent multiple supervisor DOs in the same isolate from clobbering
23
- * each other's registrations.
24
- *
25
- * The values are DurableObject class constructors. `any` here is
26
- * deliberate: the inner DO's class shape is whatever the user defines
27
- * in their inner Worker, and we only need to invoke it via
28
- * `ctx.facets.get(name, { class: cls, id })` — workerd does the rest.
29
- */
30
- /** Look up a registered inner-DO class. Returns undefined if not found. */
31
- export declare function getInnerDoClass(supervisorDoId: string, bindingName: string): any | undefined;
32
- /**
33
- * Register an inner DO class for synthesis. Called by nimbus-wrangler.ts
34
- * after each successful buildAndLoad() with the class extracted from
35
- * the fresh worker stub. Keys are `<doId>:<bindingName>` so multiple
36
- * supervisor DOs don't collide.
37
- */
38
- export declare function registerInnerDoClass(supervisorDoId: string, bindingName: string, cls: any): void;
39
- /** Clear all registrations belonging to a supervisor DO (called on rebuild). */
40
- export declare function clearInnerDoClasses(supervisorDoId: string): void;
41
- //# sourceMappingURL=inner-do-registry.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"inner-do-registry.d.ts","sourceRoot":"","sources":["../../src/facets/inner-do-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAE5F;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,GAAG,GACP,IAAI,CAEN;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAKhE"}
@@ -1,51 +0,0 @@
1
- /**
2
- * inner-do-registry.ts — Module-level registry of inner DO classes.
3
- *
4
- * `nimbus-wrangler` populates this on each successful buildAndLoad()
5
- * with the DurableObject classes extracted from the freshly-loaded
6
- * inner Worker via `worker.getDurableObjectClass(name)`. The supervisor
7
- * DO (`NimbusSession`) reads it on each inner-DO fetch to synthesize a
8
- * NimbusDurableObjectNamespace stub for `env.MY_DO`.
9
- *
10
- * Why a separate leaf module:
11
- * Before this extraction, the registry lived inside nimbus-session.ts,
12
- * which forced nimbus-wrangler.ts to import from nimbus-session.ts —
13
- * producing the cycle
14
- * index.ts -> nimbus-session.ts -> nimbus-wrangler.ts -> nimbus-session.ts
15
- * Promoting the registry to its own leaf breaks that cycle without
16
- * changing any semantics. The Map identity is preserved across the
17
- * isolate (it's still process-scoped — module-level state — survives
18
- * across DO instances in the same workerd process).
19
- *
20
- * Key shape:
21
- * `<supervisor-DO-id>:<binding-name>` — both halves are required to
22
- * prevent multiple supervisor DOs in the same isolate from clobbering
23
- * each other's registrations.
24
- *
25
- * The values are DurableObject class constructors. `any` here is
26
- * deliberate: the inner DO's class shape is whatever the user defines
27
- * in their inner Worker, and we only need to invoke it via
28
- * `ctx.facets.get(name, { class: cls, id })` — workerd does the rest.
29
- */
30
- const _NIMBUS_INNER_DO_CLASSES = new Map();
31
- /** Look up a registered inner-DO class. Returns undefined if not found. */
32
- export function getInnerDoClass(supervisorDoId, bindingName) {
33
- return _NIMBUS_INNER_DO_CLASSES.get(supervisorDoId + ':' + bindingName);
34
- }
35
- /**
36
- * Register an inner DO class for synthesis. Called by nimbus-wrangler.ts
37
- * after each successful buildAndLoad() with the class extracted from
38
- * the fresh worker stub. Keys are `<doId>:<bindingName>` so multiple
39
- * supervisor DOs don't collide.
40
- */
41
- export function registerInnerDoClass(supervisorDoId, bindingName, cls) {
42
- _NIMBUS_INNER_DO_CLASSES.set(supervisorDoId + ':' + bindingName, cls);
43
- }
44
- /** Clear all registrations belonging to a supervisor DO (called on rebuild). */
45
- export function clearInnerDoClasses(supervisorDoId) {
46
- const prefix = supervisorDoId + ':';
47
- for (const k of _NIMBUS_INNER_DO_CLASSES.keys()) {
48
- if (k.startsWith(prefix))
49
- _NIMBUS_INNER_DO_CLASSES.delete(k);
50
- }
51
- }
@@ -1,111 +0,0 @@
1
- /**
2
- * launch-pacer.ts — spreading a resident launch across Durable Object turns.
3
- *
4
- * Building a resident process is the largest single span of computation this
5
- * session performs: for pi it walks a 17 MB source tree through eight
6
- * enrichment passes, serializes a 22.9 MB module map, and writes that map into
7
- * the image store. Done in one turn it occupied the session DO's only thread
8
- * for 15-35 s, and a session that cannot reach its thread cannot service the
9
- * terminal WebSocket — the launch turn finished `outcome=ok` and the terminal
10
- * died anyway, painting "[process terminal closed]" over a process that was
11
- * still running.
12
- *
13
- * A faster launch does not fix that. A launch half the length still blocks the
14
- * thread for as long as it runs, and the socket is dropped inside that window
15
- * whether or not the work succeeds. What fixes it is never holding the thread
16
- * for long in the first place, which means suspending the launch at bounded
17
- * intervals and resuming it on a fresh turn. Responsiveness stops depending on
18
- * how long the total work takes.
19
- *
20
- * A fresh turn is also a fresh CPU budget. The same launches that dropped the
21
- * socket were also being killed with `exceededCpu` at 31.8 s and 32.5 s
22
- * against a 30 s ceiling, and no amount of yielding *within* one invocation
23
- * moves that: CPU accrues to the invocation, not to the pause. Only genuinely
24
- * re-entering the object resets it.
25
- *
26
- * Progress is measured in bytes rather than milliseconds because workerd's
27
- * clock does not advance without I/O — a wall-clock guard inside a span of
28
- * pure computation reads zero however many seconds it burns, which is why the
29
- * phase costs behind this module had to be recovered from per-turn `cpuTime`
30
- * rather than measured in place. Bytes are what the work is actually
31
- * proportional to, and they are exact. The same reasoning is why
32
- * `git/network-facet.ts` bounds its checkout chunks by entries and decoded
33
- * bytes and treats its wall guard as coarse.
34
- */
35
- /** How a paced launch gets back onto a fresh Durable Object turn. */
36
- export interface LaunchTurnScheduler {
37
- /**
38
- * Suspend until a fresh turn is running this launch again.
39
- *
40
- * `chunkEnded` settles when the resumed launch reaches its next suspension
41
- * point or finishes, so whoever grants the turn can await the work it just
42
- * released rather than letting it run detached in a handler's microtask
43
- * drain.
44
- */
45
- nextTurn(chunkEnded: Promise<void>): Promise<void>;
46
- }
47
- /**
48
- * Bytes of launch work one turn may perform before it must yield.
49
- *
50
- * Sized so a chunk stays far below both the CPU ceiling and the span in which
51
- * a terminal socket is at risk, while keeping the number of turn handoffs —
52
- * each an alarm round trip — small enough not to dominate a launch. pi's
53
- * 22.9 MB map crosses this about a dozen times per phase that handles it.
54
- */
55
- export declare const LAUNCH_CHUNK_MAX_BYTES = 2000000;
56
- /**
57
- * Accounts launch progress and ends the turn when a chunk's worth has been
58
- * spent.
59
- *
60
- * Callers report the work they are about to do or have just done and await
61
- * the result; a pacer that is not yielding returns without suspending, so the
62
- * one-shot exec path — which passes no pacer at all — keeps its exact
63
- * behaviour and cost. Nothing here decides WHAT the launch does, only where it
64
- * is allowed to stop.
65
- */
66
- export declare class LaunchPacer {
67
- private readonly scheduler;
68
- private readonly maxChunkBytes;
69
- private readonly stillWanted?;
70
- /** Turn handoffs this launch has taken. Reported with the launch. */
71
- chunks: number;
72
- /** Total work accounted, for the same report. */
73
- bytes: number;
74
- private spent;
75
- private chunkEnded;
76
- /**
77
- * @param stillWanted Checked every time the launch resumes. A launch spans
78
- * many turns, so anything may have happened to what it is building for
79
- * while it was suspended; throwing from here is how a launch stops instead
80
- * of spending turn after turn on work nothing will use. Checked at the one
81
- * place a launch can be interrupted, rather than at whichever phases
82
- * remembered to ask.
83
- */
84
- constructor(scheduler: LaunchTurnScheduler, maxChunkBytes?: number, stillWanted?: (() => void) | undefined);
85
- /**
86
- * Account `bytes` of completed work, ending the turn if a chunk is full.
87
- *
88
- * Safe to call anywhere the launch holds no state that a concurrent turn
89
- * could invalidate — which is why the image store registers its whole root
90
- * set before the first call rather than one entry at a time.
91
- */
92
- spend(bytes: number): Promise<void>;
93
- /**
94
- * The launch has finished (or failed). Releases the turn still waiting on
95
- * the chunk it resumed, so a launch that ends mid-chunk does not strand the
96
- * handler that granted it.
97
- */
98
- settle(): void;
99
- }
100
- /**
101
- * Chunk bound for this session, honouring the verification knob.
102
- *
103
- * `NIMBUS_LAUNCH_CHUNK_BYTES` forces a small bound so an ordinary launch —
104
- * not just a pathological one — crosses several turns and exercises every
105
- * suspension point. Without it the multi-turn path would only ever be
106
- * reached by the largest programs, which is the same reason
107
- * `git/commands.ts` carries `NIMBUS_GIT_CHECKOUT_CHUNK_ENTRIES`. Unset in
108
- * production, where the default applies.
109
- */
110
- export declare function launchChunkMaxBytes(env: unknown): number;
111
- //# sourceMappingURL=launch-pacer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"launch-pacer.d.ts","sourceRoot":"","sources":["../../src/facets/launch-pacer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,qEAAqE;AACrE,MAAM,WAAW,mBAAmB;IAClC;;;;;;;OAOG;IACH,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,UAAY,CAAC;AAEhD;;;;;;;;;GASG;AACH,qBAAa,WAAW;IAkBpB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAnB/B,qEAAqE;IACrE,MAAM,SAAK;IACX,iDAAiD;IACjD,KAAK,SAAK;IAEV,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,UAAU,CAA8D;IAEhF;;;;;;;OAOG;gBAEgB,SAAS,EAAE,mBAAmB,EAC9B,aAAa,GAAE,MAA+B,EAC9C,WAAW,CAAC,GAAE,MAAM,IAAI,aAAA;IAG3C;;;;;;OAMG;IACG,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAczC;;;;OAIG;IACH,MAAM,IAAI,IAAI;CAIf;AAQD;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAMxD"}
@@ -1,130 +0,0 @@
1
- /**
2
- * launch-pacer.ts — spreading a resident launch across Durable Object turns.
3
- *
4
- * Building a resident process is the largest single span of computation this
5
- * session performs: for pi it walks a 17 MB source tree through eight
6
- * enrichment passes, serializes a 22.9 MB module map, and writes that map into
7
- * the image store. Done in one turn it occupied the session DO's only thread
8
- * for 15-35 s, and a session that cannot reach its thread cannot service the
9
- * terminal WebSocket — the launch turn finished `outcome=ok` and the terminal
10
- * died anyway, painting "[process terminal closed]" over a process that was
11
- * still running.
12
- *
13
- * A faster launch does not fix that. A launch half the length still blocks the
14
- * thread for as long as it runs, and the socket is dropped inside that window
15
- * whether or not the work succeeds. What fixes it is never holding the thread
16
- * for long in the first place, which means suspending the launch at bounded
17
- * intervals and resuming it on a fresh turn. Responsiveness stops depending on
18
- * how long the total work takes.
19
- *
20
- * A fresh turn is also a fresh CPU budget. The same launches that dropped the
21
- * socket were also being killed with `exceededCpu` at 31.8 s and 32.5 s
22
- * against a 30 s ceiling, and no amount of yielding *within* one invocation
23
- * moves that: CPU accrues to the invocation, not to the pause. Only genuinely
24
- * re-entering the object resets it.
25
- *
26
- * Progress is measured in bytes rather than milliseconds because workerd's
27
- * clock does not advance without I/O — a wall-clock guard inside a span of
28
- * pure computation reads zero however many seconds it burns, which is why the
29
- * phase costs behind this module had to be recovered from per-turn `cpuTime`
30
- * rather than measured in place. Bytes are what the work is actually
31
- * proportional to, and they are exact. The same reasoning is why
32
- * `git/network-facet.ts` bounds its checkout chunks by entries and decoded
33
- * bytes and treats its wall guard as coarse.
34
- */
35
- /**
36
- * Bytes of launch work one turn may perform before it must yield.
37
- *
38
- * Sized so a chunk stays far below both the CPU ceiling and the span in which
39
- * a terminal socket is at risk, while keeping the number of turn handoffs —
40
- * each an alarm round trip — small enough not to dominate a launch. pi's
41
- * 22.9 MB map crosses this about a dozen times per phase that handles it.
42
- */
43
- export const LAUNCH_CHUNK_MAX_BYTES = 2_000_000;
44
- /**
45
- * Accounts launch progress and ends the turn when a chunk's worth has been
46
- * spent.
47
- *
48
- * Callers report the work they are about to do or have just done and await
49
- * the result; a pacer that is not yielding returns without suspending, so the
50
- * one-shot exec path — which passes no pacer at all — keeps its exact
51
- * behaviour and cost. Nothing here decides WHAT the launch does, only where it
52
- * is allowed to stop.
53
- */
54
- export class LaunchPacer {
55
- scheduler;
56
- maxChunkBytes;
57
- stillWanted;
58
- /** Turn handoffs this launch has taken. Reported with the launch. */
59
- chunks = 0;
60
- /** Total work accounted, for the same report. */
61
- bytes = 0;
62
- spent = 0;
63
- chunkEnded;
64
- /**
65
- * @param stillWanted Checked every time the launch resumes. A launch spans
66
- * many turns, so anything may have happened to what it is building for
67
- * while it was suspended; throwing from here is how a launch stops instead
68
- * of spending turn after turn on work nothing will use. Checked at the one
69
- * place a launch can be interrupted, rather than at whichever phases
70
- * remembered to ask.
71
- */
72
- constructor(scheduler, maxChunkBytes = LAUNCH_CHUNK_MAX_BYTES, stillWanted) {
73
- this.scheduler = scheduler;
74
- this.maxChunkBytes = maxChunkBytes;
75
- this.stillWanted = stillWanted;
76
- }
77
- /**
78
- * Account `bytes` of completed work, ending the turn if a chunk is full.
79
- *
80
- * Safe to call anywhere the launch holds no state that a concurrent turn
81
- * could invalidate — which is why the image store registers its whole root
82
- * set before the first call rather than one entry at a time.
83
- */
84
- async spend(bytes) {
85
- this.bytes += bytes;
86
- this.spent += bytes;
87
- if (this.spent < this.maxChunkBytes)
88
- return;
89
- this.spent = 0;
90
- this.chunks++;
91
- // Release the turn that resumed us before asking for the next one.
92
- this.chunkEnded?.resolve();
93
- const ended = withResolvers();
94
- this.chunkEnded = ended;
95
- await this.scheduler.nextTurn(ended.promise);
96
- this.stillWanted?.();
97
- }
98
- /**
99
- * The launch has finished (or failed). Releases the turn still waiting on
100
- * the chunk it resumed, so a launch that ends mid-chunk does not strand the
101
- * handler that granted it.
102
- */
103
- settle() {
104
- this.chunkEnded?.resolve();
105
- this.chunkEnded = undefined;
106
- }
107
- }
108
- function withResolvers() {
109
- let resolve;
110
- const promise = new Promise((r) => { resolve = r; });
111
- return { promise, resolve };
112
- }
113
- /**
114
- * Chunk bound for this session, honouring the verification knob.
115
- *
116
- * `NIMBUS_LAUNCH_CHUNK_BYTES` forces a small bound so an ordinary launch —
117
- * not just a pathological one — crosses several turns and exercises every
118
- * suspension point. Without it the multi-turn path would only ever be
119
- * reached by the largest programs, which is the same reason
120
- * `git/commands.ts` carries `NIMBUS_GIT_CHECKOUT_CHUNK_ENTRIES`. Unset in
121
- * production, where the default applies.
122
- */
123
- export function launchChunkMaxBytes(env) {
124
- const raw = env
125
- ?.NIMBUS_LAUNCH_CHUNK_BYTES;
126
- if (!raw)
127
- return LAUNCH_CHUNK_MAX_BYTES;
128
- const parsed = Number(raw);
129
- return Number.isFinite(parsed) && parsed > 0 ? parsed : LAUNCH_CHUNK_MAX_BYTES;
130
- }
@@ -1,207 +0,0 @@
1
- /**
2
- * Two-tier fan-out primitive for work that must execute in Worker Loader
3
- * facets without tripping workerd's per-DO dynamic-worker ceiling.
4
- *
5
- * A single Durable Object method can drive at most four concurrent
6
- * Worker Loader fetches before extra dispatches serialize or fail. Small
7
- * batches therefore run in the coordinator DO through NimbusLoaderPool.
8
- * Wider batches are sharded across sibling NimbusSession DOs, each of
9
- * which owns its own four-loader budget.
10
- *
11
- * Routing is deterministic: each task has a stable key, and the key maps
12
- * to a sibling DO shard. There is no silent fallback to width-1 execution;
13
- * missing LOADER or NIMBUS_SESSION bindings fail loudly so install and
14
- * runtime operations do not appear successful after partial dispatch.
15
- */
16
- /**
17
- * Threshold at which routing switches from coordinator-local loaders to
18
- * sibling Durable Objects.
19
- *
20
- * Set to **5** so the in-DO path stays below the V8 4-loaders-per-method
21
- * cap by construction. width < 5 stays local; width >= 5 uses sibling DOs.
22
- */
23
- export declare const IN_DO_THRESHOLD = 5;
24
- /**
25
- * Hard cap on concurrent peer DOs per single submitMany call. Throughput stays
26
- * flat through this width while keeping per-request scheduler pressure bounded.
27
- */
28
- export declare const MAX_PEER_FANOUT = 32;
29
- /**
30
- * Bounded retries for a peer-DO shard dispatch that rejects with a
31
- * transient platform reset (code roll-over, storage cold-start hiccup).
32
- * Sibling DOs are addressed by stable name, so the retry re-dispatches
33
- * the SAME shard to the re-provisioning object; the fanned-out work
34
- * (packument resolution, tarball materialisation) is idempotent, so
35
- * re-running a shard is safe. Budget mirrors the resolve-facet's own
36
- * per-fetch retry policy so a single flaky cold start no longer fails a
37
- * whole install. The same budget covers an overloaded peer, on the longer
38
- * schedule below. Non-transient rejections (OOM, count mismatch, genuine
39
- * task throw) are NOT retried — they propagate on the first hit.
40
- */
41
- export declare const PEER_TRANSIENT_RESET_RETRIES = 3;
42
- export declare const PEER_RETRY_BACKOFF_MS: number[];
43
- /**
44
- * Backoff for a shard whose peer DO was shed as overloaded. The object is
45
- * alive and the shard never ran; what it needs is time for the input-gate
46
- * queue to drain, so the schedule is an order of magnitude longer than the
47
- * reset schedule. A whole-batch abort here used to fail an entire install.
48
- */
49
- export declare const PEER_OVERLOAD_BACKOFF_MS: number[];
50
- /**
51
- * Peer shards dispatched per phase. Each phase is a barrier that costs its
52
- * slowest member, so a wide fan-out pays ⌈shards / FANOUT_PHASE_SIZE⌉ serial
53
- * round-trips; the size trades that serialization against simultaneous cold
54
- * sibling DO starts.
55
- *
56
- * The six-barrier profile once measured on a 123-package install (21 shards of
57
- * ~6 packages, 10.6/6.8/21.8/7.9/34.6/4.8 s) came from the shard count, not
58
- * from this width. Capping install shards at INSTALL_PEER_CAP fixed it at the
59
- * source and that install now clears in two phases. Widening to 8 on top of
60
- * that bought one further barrier and doubled the simultaneous cold sibling-DO
61
- * starts, which is the account-level pressure the phasing exists for: twelve
62
- * concurrent Markflow installs went from 48 simultaneous peer starts to 96 and
63
- * began timing out. Phasing does not change how many peers start, only how
64
- * many start at once, so this width is set by the burst the scheduler
65
- * tolerates rather than by the barrier count.
66
- */
67
- export declare const FANOUT_PHASE_SIZE = 4;
68
- /** Argument shape for `submitMany`. */
69
- export interface FanoutTask<A> {
70
- /**
71
- * Routing key for the stable-id router. Same key → same peer DO
72
- * (when on the peer-DO path). Tests use this to predict placement.
73
- */
74
- key: string;
75
- /** Argument passed to the user fn. */
76
- args: A;
77
- }
78
- /** Options handed to NimbusFanoutPool's constructor. */
79
- export interface NimbusFanoutPoolOptions {
80
- /**
81
- * Tag prepended to peer-DO ids and in-DO loader ids for debugging
82
- * (e.g. "npm-install-batch"). Affects neither isolate identity (in-DO
83
- * path uses the existing NimbusLoaderPool's tag-fold) nor peer-DO
84
- * deterministic placement (peer ids fold tag + key).
85
- */
86
- tag: string;
87
- /**
88
- * Per-task timeout in ms. Default 60_000. Forwarded to the in-DO
89
- * NimbusLoaderPool's submit calls and to the peer-DO RPC's own
90
- * NimbusLoaderPool.
91
- */
92
- timeoutMs?: number;
93
- /**
94
- * Preamble bundled into every facet (in-DO and inside each peer
95
- * DO). Same semantics as NimbusLoaderPool's preamble option.
96
- */
97
- preamble?: string;
98
- /**
99
- * Wasm modules forwarded to every facet. Same semantics as
100
- * NimbusLoaderPool's wasmModules option.
101
- */
102
- wasmModules?: Record<string, ArrayBuffer>;
103
- /**
104
- * Extra bindings forwarded to every facet. Same semantics as
105
- * NimbusLoaderPool's extraBindings option.
106
- */
107
- extraBindings?: Record<string, unknown>;
108
- /**
109
- * If set, skip the supervisor-RPC binding injection (mirrors
110
- * NimbusLoaderPool's omitSupervisor flag).
111
- */
112
- omitSupervisor?: boolean;
113
- /**
114
- * Invoking process pid, baked into each facet's SUPERVISOR binding so
115
- * filesystem RPCs (writeBatchStream) are authorized under the caller's
116
- * credential (mirrors NimbusLoaderPool's supervisorPid). Threaded to both
117
- * the in-DO loader pool and, via `_rpcFanoutExecute`, the peer-DO pools.
118
- * npm install passes the shell command's `ctx.pid`; resolve leaves it 0.
119
- */
120
- supervisorPid?: number;
121
- /**
122
- * Called once per completed peer-DO dispatch phase with that phase's shard
123
- * count and elapsed ms. Phases are barriers, so this is what tells a caller
124
- * whether its fan-out is bounded by shard work or by the number of barriers.
125
- * Not called on the in-DO path, which has no phases.
126
- */
127
- onDispatchPhase?: (width: number, elapsedMs: number) => void;
128
- /**
129
- * Cap on peer DOs this pool will spread one submitMany across. Defaults to
130
- * MAX_PEER_FANOUT. Tasks beyond the cap bucket into the peers that exist and
131
- * run through their in-peer pool, so lowering it trades peers for barriers
132
- * without lowering total concurrency: each peer runs its bucket at
133
- * concurrency 4, so N peers still resolve 4N tasks at once.
134
- *
135
- * A caller sets this when its per-task work is small enough that a peer per
136
- * task buys nothing but round-trips — one task per peer costs ⌈tasks/
137
- * FANOUT_PHASE_SIZE⌉ barriers, and each barrier costs a cold sibling start.
138
- */
139
- maxPeers?: number;
140
- }
141
- /**
142
- * Two-tier fan-out pool. Constructed by the supervisor DO; routes
143
- * each `submitMany` call automatically based on width.
144
- *
145
- * Lifetime: cheap to construct (no async init). Multiple submitMany
146
- * calls share NO state — each is dispatched fresh. The class
147
- * exists primarily as a clean API surface; per-call dispatch state
148
- * lives only inside submitMany's promise.
149
- */
150
- export declare class NimbusFanoutPool {
151
- private readonly env;
152
- private readonly ctx;
153
- private readonly opts;
154
- private readonly coordDoId;
155
- private readonly coordDoIdShort;
156
- constructor(env: any, ctx: DurableObjectState, opts: NimbusFanoutPoolOptions);
157
- /**
158
- * Dispatch `tasks` across the appropriate topology and return
159
- * results in input order.
160
- *
161
- * Routing:
162
- * tasks.length < 5 -> coordinator-local NimbusLoaderPool
163
- * tasks.length >= 5 -> sibling NimbusSession DOs
164
- *
165
- * Backpressure: if `tasks.length > MAX_PEER_FANOUT (32)`, tasks
166
- * are sharded modulo `MAX_PEER_FANOUT` and each shard's bucket
167
- * runs serially inside its assigned peer DO via the in-peer
168
- * NimbusLoaderPool's concurrency (capped at 4 there too). A
169
- * single submitMany call returns when ALL tasks complete (or any
170
- * throws).
171
- *
172
- * `fn` is the user function executed per task. It runs INSIDE a
173
- * Worker Loader isolate (in the in-DO path) or inside a peer DO's
174
- * Worker Loader isolate (in the peer-DO path); same trust posture
175
- * as NimbusLoaderPool.submit. The function is serialized via
176
- * the vendored serializeFunction (same as NimbusLoaderPool#prepare).
177
- */
178
- submitMany<A, R>(tasks: FanoutTask<A>[], fn: (item: A, env: any) => R | Promise<R>): Promise<R[]>;
179
- /** Report which topology a task count uses without dispatching. */
180
- topologyFor(taskCount: number): 'in-do' | 'peer-do' | 'empty';
181
- /**
182
- * Compute the deterministic peer-DO id for a task key and peer count.
183
- *
184
- * Shape: `nbf:${tag}:${coordDoIdShort}:${shard}` where
185
- * `shard = hash(key) mod peerCount`. Peer count is
186
- * `min(tasks.length, MAX_PEER_FANOUT)`.
187
- */
188
- peerSiblingId(key: string, peerCount: number): string;
189
- private _dispatchInDo;
190
- private _dispatchPeerDo;
191
- }
192
- /**
193
- * Stable hash → shard. Uses a fresh djb2 over the key (NOT
194
- * hashSource) and modulos by peerCount.
195
- *
196
- * Why not reuse hashSource: hashSource returns a base-36 string,
197
- * NOT hex — its alphabet is `[0-9a-z]`. parseInt(str, 16) on a
198
- * base-36 string aborts at the first non-hex char (any of g-z),
199
- * which produces extremely poor distribution: keys with the same
200
- * leading-hex-prefix collide regardless of their suffix. (Seen in
201
- * the wild: `task-0 .. task-7` all collided onto shard 4.)
202
- *
203
- * Deterministic: same key + same peerCount → same shard, every run.
204
- * Tests use this to predict placement.
205
- */
206
- export declare function hashKeyToShard(key: string, peerCount: number): number;
207
- //# sourceMappingURL=fanout-pool.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fanout-pool.d.ts","sourceRoot":"","sources":["../../src/loaders/fanout-pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAQH;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,IAAI,CAAC;AAEjC;;;GAGG;AACH,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAC9C,eAAO,MAAM,qBAAqB,UAAmB,CAAC;AAEtD;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,UAAqB,CAAC;AAE3D;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,uCAAuC;AACvC,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,sCAAsC;IACtC,IAAI,EAAE,CAAC,CAAC;CACT;AAED,wDAAwD;AACxD,MAAM,WAAW,uBAAuB;IACtC;;;;;OAKG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC1C;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA4BD;;;;;;;;GAQG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;IAC1B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAqB;IACzC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAE5B,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,kBAAkB,EAAE,IAAI,EAAE,uBAAuB;IAiB5E;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,UAAU,CAAC,CAAC,EAAE,CAAC,EACnB,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,EACtB,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACxC,OAAO,CAAC,CAAC,EAAE,CAAC;IASf,mEAAmE;IACnE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO;IAK7D;;;;;;OAMG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;YAOvC,aAAa;YAoCb,eAAe;CAyJ9B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAUrE"}