@nimbus-sh/worker 0.9.0 → 0.11.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.
- package/NOTICE.md +5 -0
- package/README.md +10 -0
- package/dist/_shared/session-router.d.ts +7 -0
- package/dist/_shared/session-router.d.ts.map +1 -1
- package/dist/_shared/session-router.js +7 -0
- package/dist/bindings/body.d.ts +6 -0
- package/dist/bindings/body.d.ts.map +1 -0
- package/dist/bindings/body.js +37 -0
- package/dist/bindings/kv.d.ts +0 -2
- package/dist/bindings/kv.d.ts.map +1 -1
- package/dist/bindings/kv.js +3 -42
- package/dist/bindings/r2.d.ts +0 -2
- package/dist/bindings/r2.d.ts.map +1 -1
- package/dist/bindings/r2.js +4 -44
- package/dist/esbuild-cli-artifact.generated.d.ts +18 -0
- package/dist/esbuild-cli-artifact.generated.d.ts.map +1 -0
- package/dist/esbuild-cli-artifact.generated.js +17 -0
- package/dist/esbuild-wasm-bundle.generated.d.ts +24 -24
- package/dist/esbuild-wasm-bundle.generated.d.ts.map +1 -1
- package/dist/esbuild-wasm-bundle.generated.js +24 -24
- package/dist/facets/cirrus-real.d.ts.map +1 -1
- package/dist/facets/cirrus-real.js +11 -6
- package/dist/facets/compose.d.ts +11 -7
- package/dist/facets/compose.d.ts.map +1 -1
- package/dist/facets/compose.js +8 -31
- package/dist/facets/data-plan.d.ts +79 -0
- package/dist/facets/data-plan.d.ts.map +1 -0
- package/dist/facets/data-plan.js +477 -0
- package/dist/facets/esbuild-bundle-pool.d.ts +1 -1
- package/dist/facets/esbuild-bundle-pool.js +3 -3
- package/dist/facets/esbuild-transform.d.ts +38 -8
- package/dist/facets/esbuild-transform.d.ts.map +1 -1
- package/dist/facets/esbuild-transform.js +219 -19
- package/dist/facets/exec-telemetry.d.ts +7 -3
- package/dist/facets/exec-telemetry.d.ts.map +1 -1
- package/dist/facets/manager.d.ts +198 -69
- package/dist/facets/manager.d.ts.map +1 -1
- package/dist/facets/manager.js +1276 -652
- package/dist/facets/opencode-staging.d.ts +0 -2
- package/dist/facets/opencode-staging.d.ts.map +1 -1
- package/dist/facets/opencode-staging.js +5 -11
- package/dist/facets/process.d.ts +4 -0
- package/dist/facets/process.d.ts.map +1 -1
- package/dist/facets/process.js +3 -0
- package/dist/facets/read-profile.d.ts +149 -0
- package/dist/facets/read-profile.d.ts.map +1 -0
- package/dist/facets/read-profile.js +483 -0
- package/dist/facets/real-vite-hmr.d.ts +2 -0
- package/dist/facets/real-vite-hmr.d.ts.map +1 -1
- package/dist/facets/real-vite-hmr.js +3 -2
- package/dist/facets/resident-identity.d.ts +0 -1
- package/dist/facets/resident-identity.d.ts.map +1 -1
- package/dist/facets/resident-identity.js +0 -3
- package/dist/facets/wasm-swap-registry.d.ts +34 -25
- package/dist/facets/wasm-swap-registry.d.ts.map +1 -1
- package/dist/facets/wasm-swap-registry.js +62 -56
- package/dist/facets/ws-terminal.d.ts +4 -4
- package/dist/facets/ws-terminal.d.ts.map +1 -1
- package/dist/facets/ws-terminal.js +4 -5
- package/dist/git/commands.d.ts +33 -10
- package/dist/git/commands.d.ts.map +1 -1
- package/dist/git/commands.js +1891 -197
- package/dist/git/network-facet.d.ts +12 -2
- package/dist/git/network-facet.d.ts.map +1 -1
- package/dist/git/network-facet.js +69 -18
- package/dist/git/unified-diff.d.ts +74 -0
- package/dist/git/unified-diff.d.ts.map +1 -0
- package/dist/git/unified-diff.js +676 -0
- package/dist/git-bundle.generated.d.ts +7 -11
- package/dist/git-bundle.generated.d.ts.map +1 -1
- package/dist/git-bundle.generated.js +7 -11
- package/dist/hosted/commands.d.ts.map +1 -1
- package/dist/hosted/commands.js +64 -245
- package/dist/hosted/runtime.d.ts +22 -15
- package/dist/hosted/runtime.d.ts.map +1 -1
- package/dist/hosted/runtime.js +72 -14
- package/dist/hosted/services.d.ts +8 -1
- package/dist/hosted/services.d.ts.map +1 -1
- package/dist/hosted/services.js +12 -13
- package/dist/hosted/session.d.ts +165 -0
- package/dist/hosted/session.d.ts.map +1 -0
- package/dist/hosted/session.js +132 -0
- package/dist/loaders/generated-workers.d.ts +6 -3
- package/dist/loaders/generated-workers.d.ts.map +1 -1
- package/dist/loaders/generated-workers.js +8 -5
- package/dist/loaders/npm-resolve-preamble.d.ts.map +1 -1
- package/dist/loaders/npm-resolve-preamble.js +0 -27
- package/dist/loaders/pre-bundle-preamble.d.ts +6 -3
- package/dist/loaders/pre-bundle-preamble.d.ts.map +1 -1
- package/dist/loaders/pre-bundle-preamble.js +13 -8
- package/dist/node-shims-artifact.generated.d.ts +13 -4
- package/dist/node-shims-artifact.generated.d.ts.map +1 -1
- package/dist/node-shims-artifact.generated.js +16 -7
- package/dist/npm/bin-links.d.ts +3 -1
- package/dist/npm/bin-links.d.ts.map +1 -1
- package/dist/npm/bin-links.js +32 -8
- package/dist/npm/cache.d.ts +11 -1
- package/dist/npm/cache.d.ts.map +1 -1
- package/dist/npm/cache.js +21 -7
- package/dist/npm/install-batch-facet.d.ts +4 -2
- package/dist/npm/install-batch-facet.d.ts.map +1 -1
- package/dist/npm/install-batch-facet.js +32 -18
- package/dist/npm/installer.d.ts +23 -3
- package/dist/npm/installer.d.ts.map +1 -1
- package/dist/npm/installer.js +330 -131
- package/dist/npm/npx-install.d.ts +3 -1
- package/dist/npm/npx-install.d.ts.map +1 -1
- package/dist/npm/npx-install.js +4 -1
- package/dist/npm/package-lock.d.ts +32 -0
- package/dist/npm/package-lock.d.ts.map +1 -0
- package/dist/npm/package-lock.js +65 -0
- package/dist/npm/placement.d.ts +16 -0
- package/dist/npm/placement.d.ts.map +1 -0
- package/dist/npm/placement.js +33 -0
- package/dist/npm/pre-bundle-facet.d.ts +1 -30
- package/dist/npm/pre-bundle-facet.d.ts.map +1 -1
- package/dist/npm/pre-bundle-facet.js +3 -5
- package/dist/npm/r2-cache.d.ts +12 -6
- package/dist/npm/r2-cache.d.ts.map +1 -1
- package/dist/npm/r2-cache.js +34 -16
- package/dist/npm/resolve-one-facet.d.ts +3 -0
- package/dist/npm/resolve-one-facet.d.ts.map +1 -1
- package/dist/npm/resolve-one-facet.js +15 -3
- package/dist/npm/resolver.d.ts +11 -13
- package/dist/npm/resolver.d.ts.map +1 -1
- package/dist/npm/resolver.js +12 -25
- package/dist/opencode-artifact.generated.js +2 -2
- package/dist/replica/routing.d.ts +2 -38
- package/dist/replica/routing.d.ts.map +1 -1
- package/dist/replica/routing.js +3 -55
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +15 -2
- package/dist/router/public-directory.d.ts +18 -0
- package/dist/router/public-directory.d.ts.map +1 -1
- package/dist/router/public-directory.js +1 -1
- package/dist/router/remote-api.d.ts +3 -1
- package/dist/router/remote-api.d.ts.map +1 -1
- package/dist/router/remote-api.js +42 -79
- package/dist/runtime/bash-repl.js +2 -2
- package/dist/runtime/bun-repl.d.ts.map +1 -1
- package/dist/runtime/bun-repl.js +2 -13
- package/dist/runtime/cpython-resident.d.ts.map +1 -1
- package/dist/runtime/cpython-resident.js +2 -10
- package/dist/runtime/esbuild-wasm-bytes.d.ts +37 -18
- package/dist/runtime/esbuild-wasm-bytes.d.ts.map +1 -1
- package/dist/runtime/esbuild-wasm-bytes.js +66 -92
- package/dist/runtime/facet-loader-host.d.ts.map +1 -1
- package/dist/runtime/facet-loader-host.js +0 -7
- package/dist/runtime/git-bundle-artifact.d.ts +17 -0
- package/dist/runtime/git-bundle-artifact.d.ts.map +1 -0
- package/dist/runtime/git-bundle-artifact.js +25 -0
- package/dist/runtime/node-repl.d.ts.map +1 -1
- package/dist/runtime/node-repl.js +2 -13
- package/dist/runtime/node-shims-artifact.d.ts +22 -23
- package/dist/runtime/node-shims-artifact.d.ts.map +1 -1
- package/dist/runtime/node-shims-artifact.js +48 -78
- package/dist/runtime/node-shims.d.ts.map +1 -1
- package/dist/runtime/node-shims.js +2358 -996
- package/dist/runtime/opencode-artifact.d.ts.map +1 -1
- package/dist/runtime/opencode-artifact.js +17 -53
- package/dist/runtime/opencode-facet-runner.d.ts +3 -6
- package/dist/runtime/opencode-facet-runner.d.ts.map +1 -1
- package/dist/runtime/opencode-facet-runner.js +45 -10
- package/dist/runtime/opentui-wasm-bytes.d.ts.map +1 -1
- package/dist/runtime/opentui-wasm-bytes.js +16 -49
- package/dist/runtime/package-manager.d.ts +0 -2
- package/dist/runtime/package-manager.d.ts.map +1 -1
- package/dist/runtime/package-manager.js +0 -3
- package/dist/runtime/python-repl.d.ts.map +1 -1
- package/dist/runtime/python-repl.js +4 -35
- package/dist/runtime/repl-session.d.ts +10 -0
- package/dist/runtime/repl-session.d.ts.map +1 -1
- package/dist/runtime/repl-session.js +7 -0
- package/dist/runtime/ruby-repl.d.ts.map +1 -1
- package/dist/runtime/ruby-repl.js +2 -2
- package/dist/runtime/ruby-resident.d.ts.map +1 -1
- package/dist/runtime/ruby-resident.js +41 -51
- package/dist/runtime/runtime-catalog.d.ts +10 -3
- package/dist/runtime/runtime-catalog.d.ts.map +1 -1
- package/dist/runtime/runtime-catalog.js +125 -15
- package/dist/runtime/sqlite-wasm-bytes.d.ts +4 -4
- package/dist/runtime/sqlite-wasm-bytes.d.ts.map +1 -1
- package/dist/runtime/sqlite-wasm-bytes.js +21 -57
- package/dist/runtime/staged-source.d.ts +67 -0
- package/dist/runtime/staged-source.d.ts.map +1 -0
- package/dist/runtime/staged-source.js +113 -0
- package/dist/runtime/wasi/preamble.d.ts +0 -22
- package/dist/runtime/wasi/preamble.d.ts.map +1 -1
- package/dist/runtime/wasi/preamble.js +98 -1425
- package/dist/runtime-catalog.generated.js +1 -1
- package/dist/session/agent.d.ts +14 -2
- package/dist/session/agent.d.ts.map +1 -1
- package/dist/session/agent.js +57 -19
- package/dist/session/ai.d.ts +0 -11
- package/dist/session/ai.d.ts.map +1 -1
- package/dist/session/ai.js +0 -4
- package/dist/session/fs-watch.d.ts +0 -11
- package/dist/session/fs-watch.d.ts.map +1 -1
- package/dist/session/fs-watch.js +0 -21
- package/dist/session/hibernation.d.ts +68 -2
- package/dist/session/hibernation.d.ts.map +1 -1
- package/dist/session/hibernation.js +95 -1
- package/dist/session/init-phases.d.ts +1 -2
- package/dist/session/init-phases.d.ts.map +1 -1
- package/dist/session/init-phases.js +1 -2
- package/dist/session/init.d.ts.map +1 -1
- package/dist/session/init.js +7 -20
- package/dist/session/keys.d.ts +0 -3
- package/dist/session/keys.d.ts.map +1 -1
- package/dist/session/keys.js +0 -3
- package/dist/session/legacy-reset.d.ts +11 -0
- package/dist/session/legacy-reset.d.ts.map +1 -0
- package/dist/session/legacy-reset.js +16 -0
- package/dist/session/nimbus-session.d.ts +50 -16
- package/dist/session/nimbus-session.d.ts.map +1 -1
- package/dist/session/nimbus-session.js +77 -71
- package/dist/session/npm-install-port.d.ts.map +1 -1
- package/dist/session/npm-install-port.js +2 -0
- package/dist/session/programmatic.d.ts +13 -18
- package/dist/session/programmatic.d.ts.map +1 -1
- package/dist/session/programmatic.js +53 -39
- package/dist/session/replica-routes.d.ts +2 -3
- package/dist/session/replica-routes.d.ts.map +1 -1
- package/dist/session/replica-routes.js +3 -10
- package/dist/session/routes.d.ts.map +1 -1
- package/dist/session/routes.js +11 -12
- package/dist/session/rpc.d.ts +108 -21
- package/dist/session/rpc.d.ts.map +1 -1
- package/dist/session/rpc.js +194 -39
- package/dist/session/start-real-vite.js +2 -2
- package/dist/session/state-store.d.ts +1 -17
- package/dist/session/state-store.d.ts.map +1 -1
- package/dist/session/state-store.js +3 -53
- package/dist/session/supervisor-op.d.ts +7 -0
- package/dist/session/supervisor-op.d.ts.map +1 -1
- package/dist/session/supervisor-op.js +6 -1
- package/dist/session/supervisor-rpc.d.ts +116 -19
- package/dist/session/supervisor-rpc.d.ts.map +1 -1
- package/dist/session/supervisor-rpc.js +194 -84
- package/dist/session/vite-command.d.ts.map +1 -1
- package/dist/session/vite-command.js +17 -14
- package/dist/session/ws.d.ts.map +1 -1
- package/dist/session/ws.js +20 -8
- package/dist/shell/npm-bin-entrypoints.d.ts.map +1 -1
- package/dist/shell/npm-bin-entrypoints.js +30 -5
- package/dist/vfs/facet-resident-limits.d.ts +33 -0
- package/dist/vfs/facet-resident-limits.d.ts.map +1 -0
- package/dist/vfs/facet-resident-limits.js +33 -0
- package/dist/vfs/facet-resident-store.d.ts +2 -10
- package/dist/vfs/facet-resident-store.d.ts.map +1 -1
- package/dist/vfs/facet-resident-store.js +1594 -219
- package/dist/workspace-host.d.ts +3 -1
- package/dist/workspace-host.d.ts.map +1 -1
- package/dist/workspace-host.js +2 -0
- package/dist/wrangler/nimbus-wrangler.d.ts +0 -2
- package/dist/wrangler/nimbus-wrangler.d.ts.map +1 -1
- package/dist/wrangler/nimbus-wrangler.js +8 -22
- package/package.json +34 -7
- package/public/_assets/esbuild-0.24.2.js +2380 -0
- package/public/_assets/opencode/1.16.2/index-attach.js +2 -2
- package/public/_assets/runtime/esbuild-cli-c4fda380d52befc1.js +6892 -0
- package/public/_assets/runtime/git-de3e60c9f3ff006a.js +103 -0
- package/public/_assets/runtime/{node-shims-acaa037e6d26ec0d.js → node-shims-06565b121555c194.js} +2879 -992
- package/public/_assets/runtime/resident-store-6ffb1939c53d982f.js +2264 -0
- package/public/_assets/runtime/vfs-write-ledger-e501e8fc793bc2c1.js +889 -0
- package/scripts/build-opencode-attach-entry.mjs +51 -1
- package/scripts/bundle-esbuild-wasm.mjs +55 -39
- package/scripts/bundle-facet-workers.mjs +159 -10
- package/scripts/bundle-git.mjs +88 -27
- package/scripts/bundle-node-shims.mjs +72 -46
- package/scripts/bundle-runtime.mjs +18 -421
- package/scripts/cf-git-patch.mjs +137 -0
- package/scripts/patch-install-deps.mjs +49 -96
- package/scripts/runtime-specs.mjs +435 -0
- package/vendor/git-http.generated.d.ts +82 -0
- package/vendor/git-upstream.generated.d.ts +4378 -0
- package/vendor/git.LICENSE +7 -0
- package/vendor/git.generated.d.mts +21 -0
- package/vendor/git.generated.mjs +103 -0
- package/dist/replica/suspension.d.ts +0 -36
- package/dist/replica/suspension.d.ts.map +0 -1
- package/dist/replica/suspension.js +0 -49
- package/dist/runtime/static-server.d.ts +0 -3
- package/dist/runtime/static-server.d.ts.map +0 -1
- package/dist/runtime/static-server.js +0 -133
- package/scripts/clean-dist.mjs +0 -7
|
@@ -4,10 +4,15 @@
|
|
|
4
4
|
* Exported from index.ts. Facets receive `env.SUPERVISOR` service binding
|
|
5
5
|
* pointing to this class via ctx.exports loopback binding.
|
|
6
6
|
*
|
|
7
|
-
* Props: { doId: string, pid: number, writerId: string }
|
|
7
|
+
* Props: { doId: string, pid: number, writerId: string, route: HostRoute, hostIncarnation?: string }
|
|
8
8
|
* doId — the supervisor DO's durable object ID (for routing)
|
|
9
9
|
* pid — the process ID (for stdout/stderr routing)
|
|
10
10
|
* writerId — the active append-writer incarnation for this process
|
|
11
|
+
* route — the host namespace and dispatch method, minted with the binding
|
|
12
|
+
* in the host's isolate; this entrypoint may answer from another
|
|
13
|
+
* hostIncarnation — the host instance that minted the binding, present
|
|
14
|
+
* when that host applies delivered mutations once
|
|
15
|
+
* (@nimbus-sh/core/workspace/supervisor-delivery.js)
|
|
11
16
|
*
|
|
12
17
|
* Methods callable by facets via RPC:
|
|
13
18
|
* readFile(path) → string | null
|
|
@@ -20,16 +25,29 @@
|
|
|
20
25
|
* fsOpen/fsRead/fsWrite/fsClose/readlink/symlink/rename/rmdir/fsRevision
|
|
21
26
|
* fsReadRange/fsWriteRange/fsAppend/fsAppendAck/fsTruncate
|
|
22
27
|
* → shared RuntimeFsBridge operations
|
|
23
|
-
* fsReadBatch(requests) → per-
|
|
28
|
+
* fsReadBatch(requests) → per-request results (many reads and lstats, one round trip)
|
|
24
29
|
* fsList(after, limit) → one page of what EXISTS, with per-path revisions
|
|
25
30
|
* writeBatch(payload) → { inodes, chunks } (bulk atomic write)
|
|
26
31
|
* stdout(data) → void (pushed to WebSocket + ring buffer)
|
|
27
32
|
* stderr(data) → void
|
|
28
33
|
* reportExit(code, tail?) → void (called from facet's finally block)
|
|
29
34
|
* prefetch(cwd, entryCode) → Record<string, string>
|
|
35
|
+
*
|
|
36
|
+
* Delivery: every call reaches the session over a Durable Object stub the
|
|
37
|
+
* platform can drop ("Network connection lost.", `retryable`). Reads are
|
|
38
|
+
* re-sent on a fresh stub, and hedged: one unanswered after
|
|
39
|
+
* SUPERVISOR_READ_HEDGE_AFTER_MS is sent again while it stays in flight.
|
|
40
|
+
* Filesystem mutations, on a binding that names its
|
|
41
|
+
* host's incarnation, are re-sent under one delivery id that host applies at
|
|
42
|
+
* most once (`_fsMutation`); on any other binding they are sent once.
|
|
43
|
+
* Appends are re-sent under the append ledger's identity. Everything else is
|
|
44
|
+
* sent once and a drop surfaces.
|
|
30
45
|
*/
|
|
31
46
|
import { WorkerEntrypoint } from 'cloudflare:workers';
|
|
32
|
-
import {
|
|
47
|
+
import { hostNamespaceBinding, hostOpDispatch } from '@nimbus-sh/fabric/host-dispatch.js';
|
|
48
|
+
import { idempotent } from '@nimbus-sh/fabric/do-calls.js';
|
|
49
|
+
import { SUPERVISOR_DELIVER_OP, } from '@nimbus-sh/core/workspace/supervisor-delivery.js';
|
|
50
|
+
import { VFS_DELIVERY_RETRY_WINDOW_MS } from '@nimbus-sh/core/constants.js';
|
|
33
51
|
// W5: OOM discriminator — record last-known RPC frame on writeBatch entry
|
|
34
52
|
import { setLastRpcFrame } from '@nimbus-sh/platform/oom-discriminator.js';
|
|
35
53
|
// Phase 2 A'.2 — supervisor in-flight RPC payload byte tracking.
|
|
@@ -37,6 +55,7 @@ import { rpcPayloadStart, rpcPayloadEnd } from '@nimbus-sh/platform/diag-counter
|
|
|
37
55
|
// W4: R2 cross-tenant npm cache (tarballs + packuments)
|
|
38
56
|
import { R2CacheClient, MAX_R2_TARBALL_BYTES } from '../npm/r2-cache.js';
|
|
39
57
|
import { useRpcResource } from '@nimbus-sh/platform/rpc-dispose.js';
|
|
58
|
+
import { fsReadBatchRequestBytes } from './rpc.js';
|
|
40
59
|
import { W7_MAX_RECORD_BYTES } from '@nimbus-sh/platform/w7-frame.js';
|
|
41
60
|
/**
|
|
42
61
|
* Drain the per-call event list captured by R2CacheClient during this
|
|
@@ -78,39 +97,104 @@ function _estimateWriteBatchBytes(payload) {
|
|
|
78
97
|
// The fabric mints `env.SUPERVISOR` bindings for the programs it hosts; the
|
|
79
98
|
// worker's composition root (src/index.ts) names this class to the fabric
|
|
80
99
|
// with composeFabric.
|
|
100
|
+
// A process's filesystem read (SupervisorRPC → session) still unanswered
|
|
101
|
+
// after this long is sent again on a fresh stub, the first left running and
|
|
102
|
+
// the first answer taken (fabric do-calls `hedgeAfterMs`). Measured on a
|
|
103
|
+
// throwaway under three concurrent sessions, 2026-09-28: none of the 521
|
|
104
|
+
// read batches that answered took more than 5 s at the facet's side, the
|
|
105
|
+
// session served each read it received without waiting on I/O, and the 11
|
|
106
|
+
// attempts that stalled — none of which reached the session — were still
|
|
107
|
+
// pending 110–560 s later. So an attempt past 5 s is one that is not coming
|
|
108
|
+
// back, and a hedge then costs a duplicate read only when that measurement
|
|
109
|
+
// was wrong.
|
|
110
|
+
export const SUPERVISOR_READ_HEDGE_AFTER_MS = 5_000;
|
|
81
111
|
export class SupervisorRPC extends WorkerEntrypoint {
|
|
82
|
-
/**
|
|
83
|
-
|
|
112
|
+
/**
|
|
113
|
+
* A fresh stub for the host, by the route the binding carries, per call.
|
|
114
|
+
* The platform serves this entrypoint from whichever isolate it likes; the
|
|
115
|
+
* props were minted in the host's.
|
|
116
|
+
*/
|
|
117
|
+
_host() {
|
|
84
118
|
const doId = this.ctx.props?.doId;
|
|
85
119
|
if (typeof doId !== 'string' || doId.length === 0) {
|
|
86
120
|
throw new Error('SupervisorRPC: missing doId in props');
|
|
87
121
|
}
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
const stub = namespace.get(namespace.idFromString(doId));
|
|
95
|
-
const method = hostDispatchMethod();
|
|
96
|
-
const dispatch = Reflect.get(stub, method);
|
|
97
|
-
if (typeof dispatch !== 'function') {
|
|
98
|
-
throw new Error(`SupervisorRPC: the workspace host mounts no ${method}(); `
|
|
99
|
-
+ 'a host forwards one method to workspace.supervisorOp(op)');
|
|
100
|
-
}
|
|
101
|
-
// Never `.call(stub, …)` on an RpcStub: the proxy treats `call` as a
|
|
102
|
-
// property get, which becomes an RPC to a method literally named "call".
|
|
103
|
-
// `Reflect.apply` reaches the proxied member's apply trap instead, and on
|
|
104
|
-
// a plain-object host it still invokes the method with the stub as `this`.
|
|
105
|
-
return (envelope) => Reflect.apply(dispatch, stub, [envelope]);
|
|
122
|
+
const namespace = hostNamespaceBinding(this.env, 'SupervisorRPC', this._route());
|
|
123
|
+
return namespace.get(namespace.idFromString(doId));
|
|
124
|
+
}
|
|
125
|
+
_route() {
|
|
126
|
+
return this.ctx.props?.route;
|
|
106
127
|
}
|
|
107
128
|
_op(op, args = [], extra = {}) {
|
|
108
|
-
return this.
|
|
129
|
+
return hostOpDispatch(this._host(), 'SupervisorRPC', this._route())({ op, args, ...extra });
|
|
109
130
|
}
|
|
110
131
|
/** Stamp filesystem credentials from the binding, not the supplied arguments. */
|
|
111
132
|
_fsOp(op, args = []) {
|
|
112
133
|
return this._op(op, args, { pid: this._pid() });
|
|
113
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* A filesystem read changes nothing on the host, so a call the platform
|
|
137
|
+
* dropped on the way to it is repeated on a fresh stub. Measured: the
|
|
138
|
+
* host's `stat` failing with "Network connection lost." (`retryable`) is
|
|
139
|
+
* what failed CPython's start in about one fresh session in twenty.
|
|
140
|
+
*
|
|
141
|
+
* A read can also never answer: under concurrent sessions a burst of reads
|
|
142
|
+
* from one facet left some attempts pending for minutes without reaching
|
|
143
|
+
* the host, and the program waiting on them never exited
|
|
144
|
+
* (preview/new/lucide-barrel-cache-widens). So a read still unanswered
|
|
145
|
+
* after SUPERVISOR_READ_HEDGE_AFTER_MS is hedged: sent again on a fresh
|
|
146
|
+
* stub, the first attempt left running, the first answer taken.
|
|
147
|
+
*
|
|
148
|
+
* A read can equally be slow at the session — queued behind the read
|
|
149
|
+
* budget, a lazy import, a busy input gate — and a hedge must not make it
|
|
150
|
+
* read again there. So every attempt carries the one read id minted here,
|
|
151
|
+
* and the session joins a repeat to the read it is still serving
|
|
152
|
+
* (`SupervisorDeliveries.joinRead`): a hedge that did arrive costs the
|
|
153
|
+
* session nothing but a second copy of the answer. Mutations are not
|
|
154
|
+
* hedged: their repeats stay bounded by the delivery retry window.
|
|
155
|
+
*/
|
|
156
|
+
_fsRead(op, args = []) {
|
|
157
|
+
return this._resent({ op, args, pid: this._pid(), readId: crypto.randomUUID() }, { hedgeAfterMs: SUPERVISOR_READ_HEDGE_AFTER_MS });
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* A filesystem mutation, delivered exactly once. The platform drops this
|
|
161
|
+
* hop too — measured: pip's `fsWrite` of a wheel member and a FileHandle
|
|
162
|
+
* write loop, each failing "Network connection lost." (`retryable`) as
|
|
163
|
+
* EIO — and a dropped mutation may or may not have run.
|
|
164
|
+
*
|
|
165
|
+
* So on a binding whose host names its incarnation, every attempt carries
|
|
166
|
+
* the one delivery id minted here, under SUPERVISOR_DELIVER_OP, and that
|
|
167
|
+
* host instance applies the id at most once: a repeat of a mutation that
|
|
168
|
+
* ran is answered from its receipt and never applied again, even over
|
|
169
|
+
* another writer's newer write; one that never arrived applies on the
|
|
170
|
+
* repeat. Any other instance, and any host that predates delivery, refuses
|
|
171
|
+
* the envelope outright, and that refusal is never repeated. Repeats stop
|
|
172
|
+
* VFS_DELIVERY_RETRY_WINDOW_MS after the first attempt, inside the host's
|
|
173
|
+
* receipt retention.
|
|
174
|
+
*
|
|
175
|
+
* A binding minted by a host that dedupes nothing names no incarnation,
|
|
176
|
+
* and its mutations are sent once.
|
|
177
|
+
*
|
|
178
|
+
* The id is random because this entrypoint keeps nothing between calls and
|
|
179
|
+
* may answer from any isolate; the pid still comes from the binding.
|
|
180
|
+
*/
|
|
181
|
+
_fsMutation(op, args) {
|
|
182
|
+
const hostIncarnation = this._hostIncarnation();
|
|
183
|
+
if (hostIncarnation === undefined)
|
|
184
|
+
return this._fsOp(op, args);
|
|
185
|
+
return this._resent({ op: SUPERVISOR_DELIVER_OP, args, pid: this._pid(), delivery: { op, id: crypto.randomUUID(), hostIncarnation } }, { retryWindowMs: VFS_DELIVERY_RETRY_WINDOW_MS });
|
|
186
|
+
}
|
|
187
|
+
/** `envelope`, re-sent as it is on a fresh stub while the platform drops it retryably. */
|
|
188
|
+
_resent(envelope, policy) {
|
|
189
|
+
return idempotent(envelope.delivery?.op ?? envelope.op, () => this._host(), (host) => hostOpDispatch(host, 'SupervisorRPC', this._route())(envelope), policy);
|
|
190
|
+
}
|
|
191
|
+
_hostIncarnation() {
|
|
192
|
+
const props = this.ctx.props;
|
|
193
|
+
if (typeof props !== 'object' || props === null || !('hostIncarnation' in props))
|
|
194
|
+
return undefined;
|
|
195
|
+
const incarnation = props.hostIncarnation;
|
|
196
|
+
return typeof incarnation === 'string' && incarnation.length > 0 ? incarnation : undefined;
|
|
197
|
+
}
|
|
114
198
|
_reportingPid() {
|
|
115
199
|
const pid = this.ctx.props?.pid;
|
|
116
200
|
return typeof pid === 'number' && Number.isInteger(pid) && pid > 0 ? pid : 0;
|
|
@@ -134,14 +218,14 @@ export class SupervisorRPC extends WorkerEntrypoint {
|
|
|
134
218
|
}
|
|
135
219
|
// ── Filesystem RPC ────────────────────────────────────────────────────
|
|
136
220
|
async readFile(path) {
|
|
137
|
-
return this._call(this.
|
|
221
|
+
return this._call(this._fsRead('readFile', [path]));
|
|
138
222
|
}
|
|
139
223
|
/**
|
|
140
224
|
* Read a file as raw bytes. Used by the git network facet for binary
|
|
141
225
|
* object/pack files where the text readFile would corrupt content.
|
|
142
226
|
*/
|
|
143
227
|
async readFileBytes(path) {
|
|
144
|
-
return this._call(this.
|
|
228
|
+
return this._call(this._fsRead('readFileBytes', [path]));
|
|
145
229
|
}
|
|
146
230
|
async writeFile(path, content) {
|
|
147
231
|
// binary-fs wave: accept Uint8Array natively. Pre-fix this RPC was
|
|
@@ -149,55 +233,55 @@ export class SupervisorRPC extends WorkerEntrypoint {
|
|
|
149
233
|
// decode every Uint8Array write — mangling bytes ≥ 0x80 to U+FFFD
|
|
150
234
|
// and corrupting binary content. RPC structured-clone handles
|
|
151
235
|
// Uint8Array transparently; downstream _rpcWriteFile also accepts
|
|
152
|
-
return this._call(this.
|
|
236
|
+
return this._call(this._fsMutation('writeFile', [path, content]));
|
|
153
237
|
}
|
|
154
238
|
async stat(path, options) {
|
|
155
|
-
return this._call(this.
|
|
239
|
+
return this._call(this._fsRead('stat', [path, options]));
|
|
156
240
|
}
|
|
157
241
|
async lstat(path) {
|
|
158
|
-
return this._call(this.
|
|
242
|
+
return this._call(this._fsRead('lstat', [path]));
|
|
159
243
|
}
|
|
160
244
|
async hasLegacySymlinkUnder(path) {
|
|
161
|
-
return this._call(this.
|
|
245
|
+
return this._call(this._fsRead('hasLegacySymlinkUnder', [path]));
|
|
162
246
|
}
|
|
163
247
|
async utimes(path, atimeMs, mtimeMs) {
|
|
164
|
-
return this._call(this.
|
|
248
|
+
return this._call(this._fsMutation('utimes', [path, atimeMs, mtimeMs]));
|
|
165
249
|
}
|
|
166
250
|
async chmod(path, mode) {
|
|
167
|
-
return this._call(this.
|
|
251
|
+
return this._call(this._fsMutation('chmod', [path, mode]));
|
|
168
252
|
}
|
|
169
253
|
async access(path, mode) {
|
|
170
|
-
return this._call(this.
|
|
254
|
+
return this._call(this._fsRead('access', [path, mode]));
|
|
171
255
|
}
|
|
172
256
|
async chown(path, uid, gid, options) {
|
|
173
|
-
return this._call(this.
|
|
257
|
+
return this._call(this._fsMutation('chown', [path, uid, gid, options]));
|
|
174
258
|
}
|
|
175
259
|
async setUmask(mask) {
|
|
176
260
|
return this._call(this._fsOp('setUmask', [mask]));
|
|
177
261
|
}
|
|
178
262
|
async readdir(path) {
|
|
179
|
-
return this._call(this.
|
|
263
|
+
return this._call(this._fsRead('readdir', [path]));
|
|
180
264
|
}
|
|
181
265
|
async exists(path) {
|
|
182
|
-
return this._call(this.
|
|
266
|
+
return this._call(this._fsRead('exists', [path]));
|
|
183
267
|
}
|
|
184
268
|
async mkdir(path, options) {
|
|
185
|
-
return this._call(this.
|
|
269
|
+
return this._call(this._fsMutation('mkdir', [path, options]));
|
|
186
270
|
}
|
|
187
271
|
async rmdir(path) {
|
|
188
|
-
return this._call(this.
|
|
272
|
+
return this._call(this._fsMutation('rmdir', [path]));
|
|
189
273
|
}
|
|
190
274
|
async rename(from, to) {
|
|
191
|
-
return this._call(this.
|
|
275
|
+
return this._call(this._fsMutation('rename', [from, to]));
|
|
192
276
|
}
|
|
193
277
|
async unlink(path) {
|
|
194
|
-
return this._call(this.
|
|
278
|
+
return this._call(this._fsMutation('unlink', [path]));
|
|
195
279
|
}
|
|
196
280
|
async readlink(path) {
|
|
197
|
-
return this._call(this.
|
|
281
|
+
return this._call(this._fsRead('readlink', [path]));
|
|
198
282
|
}
|
|
199
283
|
async symlink(target, path) {
|
|
200
|
-
return this._call(this.
|
|
284
|
+
return this._call(this._fsMutation('symlink', [target, path]));
|
|
201
285
|
}
|
|
202
286
|
/**
|
|
203
287
|
* ACQUIRE: the paths mutated since the facet's cursor, plus a fresh
|
|
@@ -208,13 +292,14 @@ export class SupervisorRPC extends WorkerEntrypoint {
|
|
|
208
292
|
* SupervisorRPC runs in a different isolate from the DO that owns the
|
|
209
293
|
* revision clock, so stamping here would cost its own round trip anyway,
|
|
210
294
|
* and enveloping the existing returns would break `useRpcResource`
|
|
211
|
-
* disposal, which targets the returned value.
|
|
295
|
+
* disposal, which targets the returned value. It only reads the
|
|
296
|
+
* invalidation log, so a dropped call is repeated like any other read.
|
|
212
297
|
*/
|
|
213
|
-
async fsAcquire(epoch, cursor) {
|
|
214
|
-
return this._call(this.
|
|
298
|
+
async fsAcquire(epoch, cursor, options) {
|
|
299
|
+
return this._call(this._fsRead('fsAcquire', options === undefined ? [epoch, cursor] : [epoch, cursor, options]));
|
|
215
300
|
}
|
|
216
301
|
async fsRevision(path) {
|
|
217
|
-
return this._call(this.
|
|
302
|
+
return this._call(this._fsRead('fsRevision', [path]));
|
|
218
303
|
}
|
|
219
304
|
/**
|
|
220
305
|
* Enumerate the session filesystem, one bounded page at a time.
|
|
@@ -233,8 +318,12 @@ export class SupervisorRPC extends WorkerEntrypoint {
|
|
|
233
318
|
* enumerating. `next === null` marks the final page, so a short page is
|
|
234
319
|
* never mistaken for a complete listing.
|
|
235
320
|
*/
|
|
321
|
+
/** N18: `bytes` more for this process's facet store, reporting what it measures. */
|
|
322
|
+
async fsStorageGrant(facet, bytes, databaseSize) {
|
|
323
|
+
return this._call(this._fsOp('fsStorageGrant', [facet, bytes, databaseSize]));
|
|
324
|
+
}
|
|
236
325
|
async fsList(after, limit) {
|
|
237
|
-
return this._call(this.
|
|
326
|
+
return this._call(this._fsRead('fsList', [after ?? null, limit ?? null]));
|
|
238
327
|
}
|
|
239
328
|
/**
|
|
240
329
|
* WebSocket relay. A facet does not open its own sockets: the supervisor
|
|
@@ -257,61 +346,65 @@ export class SupervisorRPC extends WorkerEntrypoint {
|
|
|
257
346
|
return this._call(this._fsOp('wsClose', [id, code, reason]));
|
|
258
347
|
}
|
|
259
348
|
async fsOpen(path, flags) {
|
|
260
|
-
return this._call(this.
|
|
349
|
+
return this._call(this._fsMutation('fsOpen', [path, flags]));
|
|
261
350
|
}
|
|
262
351
|
async fsRead(handleId, offset, length) {
|
|
263
352
|
return this._call(this._fsOp('fsRead', [handleId, offset, length]));
|
|
264
353
|
}
|
|
265
354
|
async fsWrite(handleId, offset, bytes) {
|
|
266
|
-
return this._call(this.
|
|
355
|
+
return this._call(this._fsMutation('fsWrite', [handleId, offset, bytes]));
|
|
267
356
|
}
|
|
357
|
+
/** A descriptor's stat and its directory listing move nothing: re-sent like any read. */
|
|
268
358
|
async fsFstat(...args) {
|
|
269
|
-
return this._call(this.
|
|
359
|
+
return this._call(this._fsRead('fsFstat', args));
|
|
270
360
|
}
|
|
271
361
|
async fsDup(...args) {
|
|
272
|
-
return this._call(this.
|
|
362
|
+
return this._call(this._fsMutation('fsDup', args));
|
|
273
363
|
}
|
|
274
364
|
async fsSeek(...args) {
|
|
275
|
-
return this._call(this.
|
|
365
|
+
return this._call(this._fsMutation('fsSeek', args));
|
|
276
366
|
}
|
|
277
367
|
async fsSetStatus(...args) {
|
|
278
|
-
return this._call(this.
|
|
368
|
+
return this._call(this._fsMutation('fsSetStatus', args));
|
|
279
369
|
}
|
|
280
370
|
async fsReaddirHandle(...args) {
|
|
281
|
-
return this._call(this.
|
|
371
|
+
return this._call(this._fsRead('fsReaddirHandle', args));
|
|
282
372
|
}
|
|
283
373
|
async fsFtruncate(...args) {
|
|
284
|
-
return this._call(this.
|
|
374
|
+
return this._call(this._fsMutation('fsFtruncate', args));
|
|
285
375
|
}
|
|
286
376
|
async fsFchmod(...args) {
|
|
287
|
-
return this._call(this.
|
|
377
|
+
return this._call(this._fsMutation('fsFchmod', args));
|
|
288
378
|
}
|
|
289
379
|
async fsFchown(...args) {
|
|
290
|
-
return this._call(this.
|
|
380
|
+
return this._call(this._fsMutation('fsFchown', args));
|
|
291
381
|
}
|
|
292
382
|
async fsFutimes(...args) {
|
|
293
|
-
return this._call(this.
|
|
383
|
+
return this._call(this._fsMutation('fsFutimes', args));
|
|
294
384
|
}
|
|
295
385
|
async fsSync(...args) {
|
|
296
|
-
return this._call(this.
|
|
386
|
+
return this._call(this._fsMutation('fsSync', args));
|
|
297
387
|
}
|
|
298
388
|
async fsRealpath(...args) {
|
|
299
|
-
return this._call(this.
|
|
389
|
+
return this._call(this._fsRead('fsRealpath', args));
|
|
300
390
|
}
|
|
301
391
|
async fsRemove(...args) {
|
|
302
|
-
return this._call(this.
|
|
392
|
+
return this._call(this._fsMutation('fsRemove', args));
|
|
303
393
|
}
|
|
304
394
|
async fsCopyFile(...args) {
|
|
305
|
-
return this._call(this.
|
|
395
|
+
return this._call(this._fsMutation('fsCopyFile', args));
|
|
396
|
+
}
|
|
397
|
+
async fsCopyTree(...args) {
|
|
398
|
+
return this._call(this._fsMutation('fsCopyTree', args));
|
|
306
399
|
}
|
|
307
400
|
async fsAcquireExclusiveMutation(...args) {
|
|
308
|
-
return this._call(this.
|
|
401
|
+
return this._call(this._fsMutation('fsAcquireExclusiveMutation', args));
|
|
309
402
|
}
|
|
310
403
|
async fsReleaseExclusiveMutation(...args) {
|
|
311
|
-
return this._call(this.
|
|
404
|
+
return this._call(this._fsMutation('fsReleaseExclusiveMutation', args));
|
|
312
405
|
}
|
|
313
406
|
async fsClose(handleId) {
|
|
314
|
-
return this._call(this.
|
|
407
|
+
return this._call(this._fsMutation('fsClose', [handleId]));
|
|
315
408
|
}
|
|
316
409
|
/**
|
|
317
410
|
* Stateless ranged ops. Unlike fsOpen/fsRead/fsWrite they carry no
|
|
@@ -319,7 +412,7 @@ export class SupervisorRPC extends WorkerEntrypoint {
|
|
|
319
412
|
* hibernation and never rewrite whole files for partial updates.
|
|
320
413
|
*/
|
|
321
414
|
async fsReadRange(path, offset, length) {
|
|
322
|
-
return this._call(this.
|
|
415
|
+
return this._call(this._fsRead('fsReadRange', [path, offset, length]));
|
|
323
416
|
}
|
|
324
417
|
/**
|
|
325
418
|
* The same read with the session's content cache bypassed, for a boot spec's
|
|
@@ -328,7 +421,7 @@ export class SupervisorRPC extends WorkerEntrypoint {
|
|
|
328
421
|
* session's heap for the rest of its life.
|
|
329
422
|
*/
|
|
330
423
|
async fsReadRangeUncached(path, offset, length) {
|
|
331
|
-
return this._call(this.
|
|
424
|
+
return this._call(this._fsRead('fsReadRangeUncached', [path, offset, length]));
|
|
332
425
|
}
|
|
333
426
|
/**
|
|
334
427
|
* Read many ranges in ONE round trip — the read-side counterpart to
|
|
@@ -337,8 +430,11 @@ export class SupervisorRPC extends WorkerEntrypoint {
|
|
|
337
430
|
* A file the caller knows is small is one entry; a large one is a run of
|
|
338
431
|
* entries over the same path.
|
|
339
432
|
*
|
|
433
|
+
* A request may instead ask for a path's lstat, so a process learning the
|
|
434
|
+
* metadata of many paths pays one round trip, not one per path.
|
|
435
|
+
*
|
|
340
436
|
* Entries come back positionally, each carrying exactly what the
|
|
341
|
-
* equivalent fsReadRange would have returned. The batch is bounded by
|
|
437
|
+
* equivalent fsReadRange or lstat would have returned. The batch is bounded by
|
|
342
438
|
* FS_READ_BATCH_PATH_LIMIT paths and FS_READ_BATCH_REQUEST_BYTES of
|
|
343
439
|
* requested range, and the supervisor rejects anything past either — never
|
|
344
440
|
* a short result, which a caller could mistake for a short file.
|
|
@@ -348,27 +444,33 @@ export class SupervisorRPC extends WorkerEntrypoint {
|
|
|
348
444
|
// returns at most the range asked for. Counting it keeps the
|
|
349
445
|
// supervisor's heap estimate honest for the duration of the await, the
|
|
350
446
|
// same accounting writeBatch does for its inbound payload.
|
|
351
|
-
const payloadBytes = requests.reduce((total, request) => total + request
|
|
447
|
+
const payloadBytes = requests.reduce((total, request) => total + fsReadBatchRequestBytes(request), 0);
|
|
352
448
|
setLastRpcFrame('fsReadBatch', payloadBytes);
|
|
353
449
|
rpcPayloadStart(payloadBytes);
|
|
354
450
|
try {
|
|
355
|
-
return await this._call(this.
|
|
451
|
+
return await this._call(this._fsRead('fsReadBatch', [requests]));
|
|
356
452
|
}
|
|
357
453
|
finally {
|
|
358
454
|
rpcPayloadEnd(payloadBytes);
|
|
359
455
|
}
|
|
360
456
|
}
|
|
361
457
|
async fsWriteRange(path, offset, bytes) {
|
|
362
|
-
return this._call(this.
|
|
458
|
+
return this._call(this._fsMutation('fsWriteRange', [path, offset, bytes]));
|
|
363
459
|
}
|
|
460
|
+
/**
|
|
461
|
+
* An append and its acknowledgement carry the append ledger's own identity
|
|
462
|
+
* (writer, module incarnation, operation sequence), whose receipt the host
|
|
463
|
+
* keeps until the acknowledgement: a repeat of either applies nothing twice,
|
|
464
|
+
* so a dropped one is simply re-sent.
|
|
465
|
+
*/
|
|
364
466
|
async fsAppend(path, moduleId, operationId, bytes) {
|
|
365
|
-
return this._call(this.
|
|
467
|
+
return this._call(this._resent({ op: 'fsAppend', args: [path, moduleId, operationId, bytes], pid: this._pid(), writerId: this._writerId() }));
|
|
366
468
|
}
|
|
367
469
|
async fsAppendAck(moduleId, operationId) {
|
|
368
|
-
return this._call(this.
|
|
470
|
+
return this._call(this._resent({ op: 'fsAppendAck', args: [moduleId, operationId], pid: this._pid(), writerId: this._writerId() }));
|
|
369
471
|
}
|
|
370
472
|
async fsTruncate(path, size) {
|
|
371
|
-
return this._call(this.
|
|
473
|
+
return this._call(this._fsMutation('fsTruncate', [path, size]));
|
|
372
474
|
}
|
|
373
475
|
/**
|
|
374
476
|
* Bulk-write all inodes + chunks in ONE transactionSync on the supervisor.
|
|
@@ -391,7 +493,7 @@ export class SupervisorRPC extends WorkerEntrypoint {
|
|
|
391
493
|
setLastRpcFrame('writeBatch', payloadBytes);
|
|
392
494
|
rpcPayloadStart(payloadBytes);
|
|
393
495
|
try {
|
|
394
|
-
return await this._call(this.
|
|
496
|
+
return await this._call(this._fsMutation('writeBatch', [payload]));
|
|
395
497
|
}
|
|
396
498
|
finally {
|
|
397
499
|
rpcPayloadEnd(payloadBytes);
|
|
@@ -534,7 +636,8 @@ export class SupervisorRPC extends WorkerEntrypoint {
|
|
|
534
636
|
* it, so a caller-supplied `put` would be a cross-tenant
|
|
535
637
|
* code-execution primitive for anyone holding a supervisor stub. No
|
|
536
638
|
* such RPC exists: the only bytes that reach `pc/<name>.json` are the
|
|
537
|
-
* ones registry.npmjs.org served for that exact name
|
|
639
|
+
* ones registry.npmjs.org served for that exact name; another registry
|
|
640
|
+
* (`options.registry`, the install's `NPM_REGISTRY`) has its own keys.
|
|
538
641
|
*/
|
|
539
642
|
async getPackument(name, options) {
|
|
540
643
|
const r2 = this._r2();
|
|
@@ -561,8 +664,8 @@ export class SupervisorRPC extends WorkerEntrypoint {
|
|
|
561
664
|
* has error state it couldn't stream in-band (rare; main path drains
|
|
562
665
|
* via __pendingIO first).
|
|
563
666
|
*/
|
|
564
|
-
async reportExit(code, tail) {
|
|
565
|
-
return this._call(this._op('reportExit', [code, tail || ''], { pid: this._reportingPid() }));
|
|
667
|
+
async reportExit(code, tail, residencyMisses, profileUnread) {
|
|
668
|
+
return this._call(this._op('reportExit', [code, tail || '', residencyMisses ?? [], profileUnread ?? null], { pid: this._reportingPid() }));
|
|
566
669
|
}
|
|
567
670
|
// ── Prefetch ──────────────────────────────────────────────────────────
|
|
568
671
|
async prefetch(cwd, entryCode) {
|
|
@@ -609,11 +712,18 @@ export class SupervisorRPC extends WorkerEntrypoint {
|
|
|
609
712
|
async cpStdinEnd(childPid) {
|
|
610
713
|
return this._call(this._op('cpStdinEnd', [childPid]));
|
|
611
714
|
}
|
|
612
|
-
|
|
613
|
-
|
|
715
|
+
/**
|
|
716
|
+
* The three long polls that deliver to a process — its stdin, and a
|
|
717
|
+
* child's output and exit — carry the process's ACQUIRE arguments, and a
|
|
718
|
+
* reply that delivers anything carries the answer for them (`acquired`,
|
|
719
|
+
* session/rpc.ts `_acquireOnDelivery`), so the process applies it without
|
|
720
|
+
* asking. The caller's pid names whose credential answers it.
|
|
721
|
+
*/
|
|
722
|
+
async cpReadStdin(childPid, waitMs, acquire) {
|
|
723
|
+
return this._call(this._op('cpReadStdin', [childPid, waitMs, acquire ?? null], { pid: this._reportingPid() }));
|
|
614
724
|
}
|
|
615
|
-
async cpReadOutput(childPid, fd, sinceSeq, waitMs) {
|
|
616
|
-
return this._call(this._op('cpReadOutput', [childPid, fd, sinceSeq, waitMs]));
|
|
725
|
+
async cpReadOutput(childPid, fd, sinceSeq, waitMs, acquire) {
|
|
726
|
+
return this._call(this._op('cpReadOutput', [childPid, fd, sinceSeq, waitMs, acquire ?? null], { pid: this._reportingPid() }));
|
|
617
727
|
}
|
|
618
728
|
async cpDrainOutput(childPid) {
|
|
619
729
|
return this._call(this._op('cpDrainOutput', [childPid]));
|
|
@@ -621,8 +731,8 @@ export class SupervisorRPC extends WorkerEntrypoint {
|
|
|
621
731
|
async cpKill(childPid, signal) {
|
|
622
732
|
return this._call(this._op('cpKill', [childPid, signal]));
|
|
623
733
|
}
|
|
624
|
-
async cpWait(childPid, waitMs) {
|
|
625
|
-
return this._call(this._op('cpWait', [childPid, waitMs]));
|
|
734
|
+
async cpWait(childPid, waitMs, acquire) {
|
|
735
|
+
return this._call(this._op('cpWait', [childPid, waitMs, acquire ?? null], { pid: this._reportingPid() }));
|
|
626
736
|
}
|
|
627
737
|
/**
|
|
628
738
|
* child-process isolation gap #1: dispatch a single cp.spawn request inline using
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite-command.d.ts","sourceRoot":"","sources":["../../src/session/vite-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAyBH,KAAK,QAAQ,GAAG,GAAG,CAAC;AAEpB,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,IAChC,KAAK,GAAG,KAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"vite-command.d.ts","sourceRoot":"","sources":["../../src/session/vite-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAyBH,KAAK,QAAQ,GAAG,GAAG,CAAC;AAEpB,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,IAChC,KAAK,GAAG,KAAG,OAAO,CAAC,MAAM,CAAC,CAslBzC"}
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
import { normalizeVfsPath, parentVfsPath, resolveVfsPath, stripLeadingSlashes } from '@nimbus-sh/core/vfs/path.js';
|
|
16
16
|
import { errorText } from '@nimbus-sh/core/_shared/error-text.js';
|
|
17
17
|
import { CRED_KERNEL } from '@nimbus-sh/core/runtime/os-contracts.js';
|
|
18
|
-
import { parseViteConfigSource, viteBuildBlockingPlugins, unhandledVitePlugins } from '@nimbus-sh/core/runtime/vite-config-parser.js';
|
|
18
|
+
import { parseViteConfigSource, parseViteConfigTypeScript, viteBuildBlockingPlugins, unhandledVitePlugins } from '@nimbus-sh/core/runtime/vite-config-parser.js';
|
|
19
19
|
import { findHtmlScriptEntrypoint, rewriteViteBuildHtml } from '../runtime/html-entrypoint.js';
|
|
20
|
-
import {
|
|
20
|
+
import { supervisorEsbuildService } from '../facets/esbuild-transform.js';
|
|
21
21
|
import { ViteDevServer } from '../facets/vite-dev-server.js';
|
|
22
22
|
import { shouldUseRealVite } from '../facets/cirrus-real.js';
|
|
23
23
|
import { makeLongRunningPortStub, resolveLongRunningPort, expandArgvShellDefaults, } from '@nimbus-sh/core/runtime/long-running-handle.js';
|
|
@@ -49,15 +49,18 @@ export function createViteCommand(self) {
|
|
|
49
49
|
const cfgPath = cwd + '/' + cfgName;
|
|
50
50
|
if (kernelFs.exists(cfgPath)) {
|
|
51
51
|
try {
|
|
52
|
-
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
const cfgCode = kernelFs.readFileString(cfgPath);
|
|
53
|
+
// A .ts config needs esbuild only when it holds type syntax
|
|
54
|
+
// (parseViteConfigTypeScript); a plain one is read as is, so a
|
|
55
|
+
// fresh session's `vite` does not wait on the esbuild facet.
|
|
56
|
+
const parsed = cfgName.endsWith('.ts')
|
|
57
|
+
? await parseViteConfigTypeScript(cfgCode, async (source) => {
|
|
58
|
+
if (!self.esbuildService)
|
|
59
|
+
self.esbuildService = supervisorEsbuildService(self.ctx, self.env, self.getFilesystemAuthority().namespaceFs(CRED_KERNEL));
|
|
60
|
+
return (await self.esbuildService.transform(source, { loader: 'ts', format: 'esm' })).code;
|
|
61
|
+
})
|
|
62
|
+
: parseViteConfigSource(cfgCode);
|
|
63
|
+
Object.assign(viteConfig, parsed);
|
|
61
64
|
}
|
|
62
65
|
catch (e) {
|
|
63
66
|
ctx.stderr.write(`Warning: could not parse ${cfgName}: ${e?.message}\n`);
|
|
@@ -89,7 +92,7 @@ export function createViteCommand(self) {
|
|
|
89
92
|
' (' + buildSkippedPlugins.join(', ') + '); output is the plain-Vite bundle.\n');
|
|
90
93
|
}
|
|
91
94
|
if (!self.esbuildService)
|
|
92
|
-
self.esbuildService =
|
|
95
|
+
self.esbuildService = supervisorEsbuildService(self.ctx, self.env, self.getFilesystemAuthority().namespaceFs(CRED_KERNEL));
|
|
93
96
|
const htmlPath = cwd + '/index.html';
|
|
94
97
|
let entryPoint = cwd + '/src/main.tsx';
|
|
95
98
|
let origHtml = '';
|
|
@@ -295,7 +298,7 @@ export function createViteCommand(self) {
|
|
|
295
298
|
}
|
|
296
299
|
// Start vite on the dist directory
|
|
297
300
|
if (!self.esbuildService)
|
|
298
|
-
self.esbuildService =
|
|
301
|
+
self.esbuildService = supervisorEsbuildService(self.ctx, self.env, self.getFilesystemAuthority().namespaceFs(CRED_KERNEL));
|
|
299
302
|
if (self.viteDevServer?.isRunning)
|
|
300
303
|
self.viteDevServer.stop();
|
|
301
304
|
const previewBasePath = self.viteBasePath;
|
|
@@ -502,7 +505,7 @@ export function createViteCommand(self) {
|
|
|
502
505
|
' (' + devSkipped.join(', ') + '); serving the plain-Vite app.\n');
|
|
503
506
|
}
|
|
504
507
|
if (!self.esbuildService)
|
|
505
|
-
self.esbuildService =
|
|
508
|
+
self.esbuildService = supervisorEsbuildService(self.ctx, self.env, self.getFilesystemAuthority().namespaceFs(CRED_KERNEL));
|
|
506
509
|
const previewBasePath = self.viteBasePath;
|
|
507
510
|
const viteDefine = viteConfig.define;
|
|
508
511
|
// Vite dev servers are represented as long-running process-table
|
package/dist/session/ws.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../../src/session/ws.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAQH,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,eAAe,CAAC;AAIvB,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uDAAuD,CAAC;AACtG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,yCAAyC,CAAC;AAG7E;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,QAAQ,EAAE,SAAS,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACnC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,mBAAmB,EAAE,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACnD;;;;8DAI0D;IAC1D,YAAY,CAAC,EAAE,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;IAC5C,SAAS,EAAE,wBAAwB,CAAC;IACpC,wBAAwB,EAAE,OAAO,CAAC;IAClC,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,GAAG,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,GAAG,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,qEAAqE;IACrE,QAAQ,EAAE,OAAO,0CAA0C,EAAE,YAAY,GAAG,IAAI,CAAC;IACjF,+EAA+E;IAC/E,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACvC,eAAe,IAAI,IAAI,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAoBnF;AAsDD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAStE;AAED;;;;;;;GAOG;AACH,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA6CD,wBAAgB,MAAM,CAAC,EAAE,EAAE,SAAS,GAAG,YAAY,CAElD;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../../src/session/ws.ts"],"names":[],"mappings":"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"}
|
package/dist/session/ws.js
CHANGED
|
@@ -316,15 +316,27 @@ export async function wsMessage(self, ws, message) {
|
|
|
316
316
|
return;
|
|
317
317
|
}
|
|
318
318
|
const terminalMessage = TerminalMessageSchema.safeParse(value);
|
|
319
|
-
if (self.terminal && terminalMessage.success)
|
|
320
|
-
self.terminal
|
|
319
|
+
if (self.terminal && terminalMessage.success) {
|
|
320
|
+
const terminal = self.terminal;
|
|
321
|
+
const completion = terminal.handleMessage(terminalMessage.data);
|
|
322
|
+
if (completion) {
|
|
323
|
+
const task = completion.catch((error) => {
|
|
324
|
+
console.error('[nimbus] terminal input failed:', errorText(error));
|
|
325
|
+
terminal.writeln(`terminal input failed: ${errorText(error)}`);
|
|
326
|
+
}).finally(() => snapshotShellState(self));
|
|
327
|
+
const ctx = self.ctx;
|
|
328
|
+
// Hand the command's completion to waitUntil so its failure is observed and
|
|
329
|
+
// the final snapshot runs, without holding the WebSocket event open or
|
|
330
|
+
// serializing later input. DurableObjectState.waitUntil does not extend the
|
|
331
|
+
// object's lifetime (Cloudflare docs, api/state/#waituntil).
|
|
332
|
+
if (ctx?.waitUntil)
|
|
333
|
+
ctx.waitUntil(task);
|
|
334
|
+
else
|
|
335
|
+
await task;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
321
338
|
// ── B'.1 snapshot ───────────────────────────────────────────────
|
|
322
|
-
//
|
|
323
|
-
// the user's keystroke. The Shell builtin `cd` mutates this.cwd
|
|
324
|
-
// synchronously inside executeLine, so by the time we reach this
|
|
325
|
-
// line a `cd example-app\r` has already taken effect and we capture the
|
|
326
|
-
// new cwd. Cheap when nothing has changed; SESSION_ENV_MAX_BYTES
|
|
327
|
-
// is the only failure mode and is logged, not thrown.
|
|
339
|
+
// Capture immediate keystroke changes; async input completion takes a final snapshot above.
|
|
328
340
|
snapshotShellState(self);
|
|
329
341
|
}
|
|
330
342
|
catch (e) {
|