@nimbus-sh/worker 0.12.0 → 0.13.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/dist/esbuild-cli-artifact.generated.d.ts +1 -1
- package/dist/esbuild-cli-artifact.generated.js +4 -4
- package/dist/esbuild-wasm-bundle.generated.d.ts +11 -10
- package/dist/esbuild-wasm-bundle.generated.d.ts.map +1 -1
- package/dist/esbuild-wasm-bundle.generated.js +11 -10
- package/dist/facets/build-facet.d.ts +53 -0
- package/dist/facets/build-facet.d.ts.map +1 -0
- package/dist/facets/build-facet.js +346 -0
- package/dist/facets/cirrus-real.d.ts +3 -0
- package/dist/facets/cirrus-real.d.ts.map +1 -1
- package/dist/facets/cirrus-real.js +1 -2
- package/dist/facets/compose.d.ts +1 -0
- package/dist/facets/compose.d.ts.map +1 -1
- package/dist/facets/compose.js +3 -0
- package/dist/facets/data-plan.d.ts +14 -30
- package/dist/facets/data-plan.d.ts.map +1 -1
- package/dist/facets/data-plan.js +153 -13
- package/dist/facets/dev-stylesheet.d.ts +27 -0
- package/dist/facets/dev-stylesheet.d.ts.map +1 -0
- package/dist/facets/dev-stylesheet.js +65 -0
- package/dist/facets/esbuild-transform.d.ts +23 -18
- package/dist/facets/esbuild-transform.d.ts.map +1 -1
- package/dist/facets/esbuild-transform.js +63 -109
- package/dist/facets/manager.d.ts +49 -9
- package/dist/facets/manager.d.ts.map +1 -1
- package/dist/facets/manager.js +238 -69
- package/dist/facets/oxc-transform.d.ts +29 -0
- package/dist/facets/oxc-transform.d.ts.map +1 -0
- package/dist/facets/oxc-transform.js +198 -0
- package/dist/facets/prebundle-pool.d.ts +23 -0
- package/dist/facets/prebundle-pool.d.ts.map +1 -0
- package/dist/facets/prebundle-pool.js +55 -0
- package/dist/facets/process.d.ts +13 -6
- package/dist/facets/process.d.ts.map +1 -1
- package/dist/facets/process.js +37 -31
- package/dist/facets/transform-store.d.ts +4 -4
- package/dist/facets/transform-store.js +4 -4
- package/dist/facets/vite-dev-server.d.ts +89 -12
- package/dist/facets/vite-dev-server.d.ts.map +1 -1
- package/dist/facets/vite-dev-server.js +66 -43
- package/dist/hosted/commands.d.ts.map +1 -1
- package/dist/hosted/commands.js +20 -4
- package/dist/hosted/runtime.d.ts.map +1 -1
- package/dist/hosted/runtime.js +7 -2
- package/dist/hosted/services.d.ts +3 -3
- package/dist/hosted/services.d.ts.map +1 -1
- package/dist/hosted/services.js +102 -95
- package/dist/hosted/session.d.ts +1 -0
- package/dist/hosted/session.d.ts.map +1 -1
- package/dist/loaders/generated-workers.d.ts +3 -0
- package/dist/loaders/generated-workers.d.ts.map +1 -1
- package/dist/loaders/generated-workers.js +3 -0
- package/dist/napi-wasm-artifacts.generated.js +2 -2
- package/dist/node-shims-artifact.generated.d.ts +14 -1
- package/dist/node-shims-artifact.generated.d.ts.map +1 -1
- package/dist/node-shims-artifact.generated.js +23 -10
- package/dist/npm/bin-links.d.ts +7 -4
- package/dist/npm/bin-links.d.ts.map +1 -1
- package/dist/npm/bin-links.js +14 -55
- package/dist/npm/cache.d.ts +6 -0
- package/dist/npm/cache.d.ts.map +1 -1
- package/dist/npm/cache.js +26 -4
- package/dist/npm/installer.d.ts +1 -1
- package/dist/npm/installer.d.ts.map +1 -1
- package/dist/npm/installer.js +26 -52
- package/dist/npm/pre-bundle-facet.d.ts +15 -117
- package/dist/npm/pre-bundle-facet.d.ts.map +1 -1
- package/dist/npm/pre-bundle-facet.js +13 -511
- package/dist/oxc-facet-artifact.generated.d.ts +18 -0
- package/dist/oxc-facet-artifact.generated.d.ts.map +1 -0
- package/dist/oxc-facet-artifact.generated.js +17 -0
- package/dist/oxc-wasm-artifact.generated.d.ts +20 -0
- package/dist/oxc-wasm-artifact.generated.d.ts.map +1 -0
- package/dist/oxc-wasm-artifact.generated.js +19 -0
- package/dist/rolldown-facet-artifact.generated.d.ts +18 -0
- package/dist/rolldown-facet-artifact.generated.d.ts.map +1 -0
- package/dist/rolldown-facet-artifact.generated.js +17 -0
- package/dist/router/remote-api.d.ts.map +1 -1
- package/dist/router/remote-api.js +9 -0
- package/dist/runtime/bash-repl.d.ts.map +1 -1
- package/dist/runtime/bash-repl.js +1 -4
- package/dist/runtime/cpython-resident.d.ts.map +1 -1
- package/dist/runtime/cpython-resident.js +1 -0
- package/dist/runtime/esbuild-wasm-bytes.d.ts +25 -23
- package/dist/runtime/esbuild-wasm-bytes.d.ts.map +1 -1
- package/dist/runtime/esbuild-wasm-bytes.js +30 -25
- package/dist/runtime/facet-loader-host.d.ts +5 -4
- package/dist/runtime/facet-loader-host.d.ts.map +1 -1
- package/dist/runtime/facet-loader-host.js +5 -4
- package/dist/runtime/node-runner.d.ts +2 -0
- package/dist/runtime/node-runner.d.ts.map +1 -1
- package/dist/runtime/node-runner.js +1 -0
- package/dist/runtime/node-shims-artifact.d.ts +8 -1
- package/dist/runtime/node-shims-artifact.d.ts.map +1 -1
- package/dist/runtime/node-shims-artifact.js +32 -4
- package/dist/runtime/node-shims.d.ts.map +1 -1
- package/dist/runtime/node-shims.js +145 -109
- package/dist/runtime/opencode-facet-runner.d.ts.map +1 -1
- package/dist/runtime/opencode-facet-runner.js +6 -2
- package/dist/runtime/oxc-wasm-bytes.d.ts +19 -0
- package/dist/runtime/oxc-wasm-bytes.d.ts.map +1 -0
- package/dist/runtime/oxc-wasm-bytes.js +39 -0
- package/dist/runtime/package-manager.js +1 -1
- package/dist/runtime/process-logs-api.d.ts.map +1 -1
- package/dist/runtime/process-logs-api.js +2 -0
- package/dist/runtime/project-fs.d.ts +8 -1
- package/dist/runtime/project-fs.d.ts.map +1 -1
- package/dist/runtime/project-fs.js +15 -1
- package/dist/runtime/python-repl.d.ts +40 -1
- package/dist/runtime/python-repl.d.ts.map +1 -1
- package/dist/runtime/python-repl.js +19 -11
- package/dist/runtime/ruby-repl.d.ts +38 -0
- package/dist/runtime/ruby-repl.d.ts.map +1 -1
- package/dist/runtime/ruby-repl.js +24 -5
- package/dist/runtime/ruby-resident.d.ts.map +1 -1
- package/dist/runtime/ruby-resident.js +2 -0
- package/dist/session/nimbus-session.d.ts +13 -8
- package/dist/session/nimbus-session.d.ts.map +1 -1
- package/dist/session/nimbus-session.js +11 -5
- package/dist/session/programmatic.d.ts +25 -30
- package/dist/session/programmatic.d.ts.map +1 -1
- package/dist/session/programmatic.js +65 -93
- package/dist/session/routes.d.ts.map +1 -1
- package/dist/session/routes.js +23 -7
- package/dist/session/rpc.d.ts +16 -6
- package/dist/session/rpc.d.ts.map +1 -1
- package/dist/session/rpc.js +53 -13
- package/dist/session/start-real-vite.d.ts +24 -9
- package/dist/session/start-real-vite.d.ts.map +1 -1
- package/dist/session/start-real-vite.js +40 -4
- package/dist/session/supervisor-op.d.ts +14 -0
- package/dist/session/supervisor-op.d.ts.map +1 -1
- package/dist/session/supervisor-op.js +49 -0
- package/dist/session/supervisor-rpc.d.ts +11 -0
- package/dist/session/supervisor-rpc.d.ts.map +1 -1
- package/dist/session/supervisor-rpc.js +18 -0
- package/dist/session/vite-command.d.ts.map +1 -1
- package/dist/session/vite-command.js +23 -19
- package/dist/session/ws-relay.d.ts.map +1 -1
- package/dist/session/ws-relay.js +13 -1
- package/dist/shell/npm-bin-entrypoints.d.ts +3 -1
- package/dist/shell/npm-bin-entrypoints.d.ts.map +1 -1
- package/dist/shell/npm-bin-entrypoints.js +53 -25
- package/dist/vfs/facet-resident-store.d.ts.map +1 -1
- package/dist/vfs/facet-resident-store.js +11 -5
- package/dist/wrangler/nimbus-wrangler.d.ts +8 -0
- package/dist/wrangler/nimbus-wrangler.d.ts.map +1 -1
- package/dist/wrangler/nimbus-wrangler.js +54 -57
- package/package.json +6 -4
- package/public/_assets/esbuild-0.24.2.wasm +0 -0
- package/public/_assets/napi-wasm/loader/{99efae93dd1dcc2b → ab7e57fe9e8750c2}/napi-wasm-loader.mjs +4 -4
- package/public/_assets/napi-wasm/loader/{99efae93dd1dcc2b → ab7e57fe9e8750c2}/provenance.json +2 -2
- package/public/_assets/oxc/nimbus-oxc-1aa8c4c7057c6c28.provenance.json +72 -0
- package/public/_assets/oxc/nimbus-oxc-1aa8c4c7057c6c28.wasm +0 -0
- package/public/_assets/runtime/esbuild-cli-f13e6a112b03ac07.js +1143 -0
- package/public/_assets/runtime/js-interpreter-3c37c48024f0f651.js +23 -0
- package/public/_assets/runtime/js-interpreter-ops-2f4dfec6798e70fc.js +290 -0
- package/public/_assets/runtime/js-interpreter-primordials-e620a61b7e9800fa.js +1 -0
- package/public/_assets/runtime/{node-shims-f92f16c7d7c532e9.js → node-shims-e3adc4576da31e6e.js} +651 -103
- package/public/_assets/runtime/{esbuild-cli-b7aecffd4c6a36fe.js → oxc-facet-fd86fefcdf16bf9c.js} +217 -1047
- package/public/_assets/runtime/{resident-store-92386265e8b306dc.js → resident-store-009f39539ac989fc.js} +11 -5
- package/public/_assets/runtime/rolldown-facet-09983434e2dbe93e.js +15165 -0
- package/public/_assets/runtime/{vfs-write-ledger-d33ee0034446c3e0.js → vfs-write-ledger-9e9594591425a9b8.js} +4 -1
- package/scripts/acorn-primordials.mjs +637 -0
- package/scripts/bundle-esbuild-wasm.mjs +42 -50
- package/scripts/bundle-facet-workers.mjs +247 -18
- package/scripts/bundle-node-shims.mjs +29 -2
- package/scripts/bundle-oxc-wasm.mjs +105 -0
- package/scripts/interpreter-bundle.mjs +105 -0
- package/scripts/napi-wasm/build.mjs +4 -1
- package/scripts/napi-wasm/loader/napi-wasm-loader.ts +38 -3
- package/scripts/oxc-wasm/Cargo.lock +1246 -0
- package/scripts/oxc-wasm/Cargo.toml +30 -0
- package/scripts/oxc-wasm/build.mjs +249 -0
- package/scripts/oxc-wasm/examples/memory.rs +51 -0
- package/scripts/oxc-wasm/examples/transform.rs +20 -0
- package/scripts/oxc-wasm/inputs.mjs +32 -0
- package/scripts/oxc-wasm/rust-toolchain.toml +5 -0
- package/scripts/oxc-wasm/src/abi.rs +136 -0
- package/scripts/oxc-wasm/src/diagnostics.rs +49 -0
- package/scripts/oxc-wasm/src/helpers.rs +139 -0
- package/scripts/oxc-wasm/src/lib.rs +247 -0
- package/scripts/oxc-wasm/src/module.rs +978 -0
- package/scripts/oxc-wasm/src/names.rs +175 -0
- package/scripts/oxc-wasm/src/options.rs +154 -0
- package/scripts/parser-audit.mjs +492 -0
- package/scripts/rolldown-facet/entry.mjs +21 -0
- package/scripts/rolldown-facet/shims.mjs +64 -0
- package/dist/facets/esbuild-bundle-pool.d.ts +0 -43
- package/dist/facets/esbuild-bundle-pool.d.ts.map +0 -1
- package/dist/facets/esbuild-bundle-pool.js +0 -80
- package/dist/loaders/pre-bundle-preamble.d.ts +0 -44
- package/dist/loaders/pre-bundle-preamble.d.ts.map +0 -1
- package/dist/loaders/pre-bundle-preamble.js +0 -116
- package/dist/runtime/host-wasm.d.ts +0 -8
- package/dist/runtime/host-wasm.d.ts.map +0 -1
- package/dist/runtime/host-wasm.js +0 -33
- /package/public/_assets/napi-wasm/loader/{99efae93dd1dcc2b → ab7e57fe9e8750c2}/wasi-trampoline.wasm +0 -0
package/dist/facets/manager.js
CHANGED
|
@@ -15,23 +15,25 @@
|
|
|
15
15
|
* Long-running processes use a dynamic Worker entrypoint that stays
|
|
16
16
|
* registered in ProcessTable and PortRegistry until exit or kill.
|
|
17
17
|
*/
|
|
18
|
-
import { COMMONJS_CELL_IMPORTS, COMMONJS_CELL_RUNTIME_SOURCE, commonJsCellModuleName, commonJsCellReadsBack, commonJsEntryModuleName, declaresWrapperBinding, runtimeCodeModuleName, runtimeFunctionModule, wrapCommonJsCell, } from '@nimbus-sh/core/_shared/commonjs-cell.js';
|
|
18
|
+
import { COMMONJS_CELL_IMPORTS, COMMONJS_CELL_RUNTIME_SOURCE, commonJsCellModuleName, commonJsCellReadsBack, commonJsEntryModuleName, declaresWrapperBinding, RUNTIME_INTERPRETER_MODULE, RUNTIME_INTERPRETER_OPS_MODULE, RUNTIME_INTERPRETER_PRIMORDIALS_MODULE, runtimeCodeModuleName, runtimeExpressionModule, runtimeFunctionModule, wrapCommonJsCell, } from '@nimbus-sh/core/_shared/commonjs-cell.js';
|
|
19
19
|
import { ReadAheadBudget, STDIN_SYNC_READ_BYTES } from '@nimbus-sh/core/runtime/stdin-read.js';
|
|
20
|
+
import { execIdField } from '@nimbus-sh/core/runtime/process-table.js';
|
|
20
21
|
import { exitCodeForSignal } from '@nimbus-sh/core/substrate/lifo/shell/signals.js';
|
|
21
22
|
import { fetchNodeFacetSources } from '../runtime/node-shims-artifact.js';
|
|
22
23
|
import { generateSqliteFacetPreamble } from '../runtime/sqlite-shim.js';
|
|
23
24
|
import { getRealNodeImportsCode } from '@nimbus-sh/core/_shared/real-node-imports.js';
|
|
24
25
|
import { VFS_CURSOR_SEED_SOURCE, serializeFacetVfsCursor, } from '@nimbus-sh/core/_shared/facet-vfs-cursor.js';
|
|
25
|
-
import { stripLeadingSlashes, vfsPathExtension } from '@nimbus-sh/core/vfs/path.js';
|
|
26
|
+
import { normalizeVfsPath, stripLeadingSlashes, vfsPathExtension } from '@nimbus-sh/core/vfs/path.js';
|
|
27
|
+
import { direntTypeOf } from '@nimbus-sh/core/vfs/dirent-type.js';
|
|
26
28
|
import { clearPortCapability, listPortReservations, readPortReservation, readPortReservationByOwner, releasePortReservation, restoreReservedPortCapability, } from '../session/port-capability.js';
|
|
27
29
|
import { deriveResidentOwner } from './resident-identity.js';
|
|
28
30
|
import { z } from 'zod/v4';
|
|
29
31
|
import { RESIDENT_OWNER_KEY_PREFIX, DURABLE_IMAGES_KEY_PREFIX } from '../session/keys.js';
|
|
30
32
|
import { PORT_CAPABILITY_KEY_PREFIX } from '../session/keys.js';
|
|
31
33
|
import { sessionIdentity, unbindPublicPortCapability } from '../router/public-directory.js';
|
|
32
|
-
import { prefetchForRequire, requireFsOverBridge, ClosureBoundExceededError } from '@nimbus-sh/core/runtime/require-resolver.js';
|
|
34
|
+
import { prefetchForRequire, requireFsOverBridge, resolveDeferredImport, ClosureBoundExceededError, } from '@nimbus-sh/core/runtime/require-resolver.js';
|
|
33
35
|
import { findStaticFsReferences } from '@nimbus-sh/core/runtime/static-fs-refs.js';
|
|
34
|
-
import { planFacetData } from './data-plan.js';
|
|
36
|
+
import { linkTargetOf, packageRootOf, planFacetData } from './data-plan.js';
|
|
35
37
|
import { principalTag, profilePrincipal, ReadProfile, verifiedEvidence, } from './read-profile.js';
|
|
36
38
|
/** What the shared read profile may add to one launch: an eighth of its module map's bytes. */
|
|
37
39
|
const READ_PROFILE_LAUNCH_BYTES = Math.floor(VFS_BUNDLE_MAX_BYTES / 8);
|
|
@@ -49,6 +51,7 @@ import { DEFAULT_CJS_CONDITIONS, DEFAULT_ESM_CONDITIONS, resolvePackageEntry, pa
|
|
|
49
51
|
import { isExecDiagEnabled, recordExecTelemetry } from './exec-telemetry.js';
|
|
50
52
|
import { LaunchLearningStore } from './launch-learning-store.js';
|
|
51
53
|
import { disposeRpcResource, disposeRpcResources } from '@nimbus-sh/platform/rpc-dispose.js';
|
|
54
|
+
import { SUPERVISOR_ANSWERING_SRC } from '@nimbus-sh/core/runtime/supervisor-answering.generated.js';
|
|
52
55
|
import { sqliteWasmModuleEntry } from './opencode-staging.js';
|
|
53
56
|
import { FACET_IMAGE_WRITE_SLICE_BYTES, ImageStore, } from '@nimbus-sh/fabric/image-store.js';
|
|
54
57
|
import { fetchStagedBindingAsset, NAPI_WASM_LOADER, NAPI_WASM_TRAMPOLINE, STAGED_BINDING_LOADER_MODULE, STAGED_BINDING_TRAMPOLINE_MODULE, stagedBinding, stagedBindingsFacetImport, stagedBindingsRequiredBy, } from '../runtime/staged-bindings.js';
|
|
@@ -69,6 +72,10 @@ import { supervisorBindingProps } from '@nimbus-sh/fabric/supervisor-props.js';
|
|
|
69
72
|
import { streamedWasmImageDigest, wasmImageDigest } from './wasm-image-digest.js';
|
|
70
73
|
import { prefetchBundleStart, prefetchBundleEnd, setPrefetchCacheBytes, } from '@nimbus-sh/platform/diag-counters.js';
|
|
71
74
|
const launchAdapters = new WeakMap();
|
|
75
|
+
/** The exact type of `entry` in `dir` on a launch's fs, lstat'ing it where its listing could not type it. */
|
|
76
|
+
function launchEntryType(vfs, dir, entry) {
|
|
77
|
+
return direntTypeOf(entry, () => vfs.stat(`${dir}/${entry.name}`, { followSymlinks: false }));
|
|
78
|
+
}
|
|
72
79
|
function filesOf(fs) {
|
|
73
80
|
let files = launchAdapters.get(fs);
|
|
74
81
|
if (files === undefined) {
|
|
@@ -536,6 +543,19 @@ export function findInlineWasmImages(bundle) {
|
|
|
536
543
|
const SQLITE_FACET_IMPORT = `import __nimbusSqliteWasmModule from "${SQLITE_WASM_MODULE_NAME}";\n` +
|
|
537
544
|
`globalThis.__nimbusSqliteWasmModule = __nimbusSqliteWasmModule;\n` +
|
|
538
545
|
generateSqliteFacetPreamble();
|
|
546
|
+
/**
|
|
547
|
+
* The runtime-code interpreter, its primordials and its host module, in every
|
|
548
|
+
* launch's map: the primordials load at the launch's start, the other two
|
|
549
|
+
* only when the program first produces code no launch staged
|
|
550
|
+
* (core/_shared/commonjs-cell.ts, RUNTIME CODE).
|
|
551
|
+
*/
|
|
552
|
+
function interpreterModules(sources) {
|
|
553
|
+
return {
|
|
554
|
+
[RUNTIME_INTERPRETER_PRIMORDIALS_MODULE]: sources.interpreterPrimordials,
|
|
555
|
+
[RUNTIME_INTERPRETER_MODULE]: sources.interpreter,
|
|
556
|
+
[RUNTIME_INTERPRETER_OPS_MODULE]: sources.interpreterOps,
|
|
557
|
+
};
|
|
558
|
+
}
|
|
539
559
|
/**
|
|
540
560
|
* The entry code as a module of the map, named for the script it came from so
|
|
541
561
|
* its stack frames carry that path; `-e` code is `[eval]`. The runtime may
|
|
@@ -565,6 +585,9 @@ ${usesSqlite ? SQLITE_FACET_IMPORT : ''}
|
|
|
565
585
|
${stagedBindingsFacetImport(vfsState.stagedBindings)}
|
|
566
586
|
${facetWasmImportsSource(wasmImports)}
|
|
567
587
|
const __NimbusHostResponse = globalThis.Response;
|
|
588
|
+
// The SUPERVISOR binding's filesystem calls answer a refusal as a value
|
|
589
|
+
// (core vfs-supervisor.ts answeringSupervisor).
|
|
590
|
+
${SUPERVISOR_ANSWERING_SRC}
|
|
568
591
|
|
|
569
592
|
// The process's code: a module per cell, compiled when first required.
|
|
570
593
|
const __NIMBUS_CODE_CELLS = ${bundleSource.codeCells};
|
|
@@ -601,7 +624,7 @@ ${VFS_CURSOR_SEED_SOURCE}
|
|
|
601
624
|
// ends it early.
|
|
602
625
|
const __entryBudgetMs = Infinity;
|
|
603
626
|
let __drainPasses = 0;
|
|
604
|
-
const __supervisor = workerEnv?.SUPERVISOR
|
|
627
|
+
const __supervisor = workerEnv?.SUPERVISOR ? globalThis.__nimbusAnsweringSupervisor(workerEnv.SUPERVISOR) : null;
|
|
605
628
|
// The same store, namespace and data plan a resident boots on, backed by
|
|
606
629
|
// this run's heap (runOnce hosts no SQLite; vfs/facet-resident-store.ts).
|
|
607
630
|
// Declared inside the request, beside the shims, so a loader that reuses
|
|
@@ -688,6 +711,7 @@ ${RESIDENCY_MISS_REPORT}
|
|
|
688
711
|
} catch {}
|
|
689
712
|
|
|
690
713
|
const mod = { exports: {} };
|
|
714
|
+
Object.defineProperty(mod, "__nimbusImportMeta", { value: __nimbusFileImportMeta(filename || "/home/user/script.js") });
|
|
691
715
|
// G2 (runtime-pkg wave): see corresponding comment in NodeProcess.run.
|
|
692
716
|
__require.main = mod;
|
|
693
717
|
try {
|
|
@@ -706,7 +730,6 @@ ${RESIDENCY_MISS_REPORT}
|
|
|
706
730
|
} catch (e) {
|
|
707
731
|
if (e instanceof __ProcessExit) { exitCode = e.code; }
|
|
708
732
|
else {
|
|
709
|
-
globalThis.__nimbusRuntimeCode.noteFailure(e);
|
|
710
733
|
const trace = (e && e.stack) || (e && e.message) || String(e);
|
|
711
734
|
stderr += trace + "\\n";
|
|
712
735
|
exitCode = 1;
|
|
@@ -745,14 +768,6 @@ ${RESIDENCY_MISS_REPORT}
|
|
|
745
768
|
if (exitCode === 0) exitCode = 1;
|
|
746
769
|
if (__supervisor && !captureOutput) __queueRpcWrite("stderr", __nimbusOutEnc.encode(__residencyReport));
|
|
747
770
|
}
|
|
748
|
-
// A failed launch stages the Function-constructor text its failure is
|
|
749
|
-
// attributable to (commonjs-cell.ts, stageFailedLaunch).
|
|
750
|
-
const __stagedCode = exitCode !== 0 ? globalThis.__nimbusRuntimeCode.stageFailedLaunch() : "";
|
|
751
|
-
if (__stagedCode) {
|
|
752
|
-
stderr += __stagedCode + "\\n";
|
|
753
|
-
if (__supervisor && !captureOutput) __queueRpcWrite("stderr", __nimbusOutEnc.encode(__stagedCode + "\\n"));
|
|
754
|
-
}
|
|
755
|
-
|
|
756
771
|
await __drainPendingIO();
|
|
757
772
|
|
|
758
773
|
if (__supervisor) {
|
|
@@ -810,7 +825,7 @@ ${RESIDENCY_MISS_REPORT}
|
|
|
810
825
|
};
|
|
811
826
|
`,
|
|
812
827
|
modules: bundleSource.modules,
|
|
813
|
-
codeModules: { ...bundleSource.codeModules, [entry.name]: entry.text },
|
|
828
|
+
codeModules: { ...bundleSource.codeModules, ...interpreterModules(sources), [entry.name]: entry.text },
|
|
814
829
|
};
|
|
815
830
|
}
|
|
816
831
|
/**
|
|
@@ -905,6 +920,9 @@ ${stagedBindingsFacetImport(vfsState.stagedBindings)}
|
|
|
905
920
|
${facetWasmImportsSource(opts.wasmImports ?? [])}
|
|
906
921
|
const __NIMBUS_ARGS = ${safeArgs};
|
|
907
922
|
const __NimbusHostResponse = globalThis.Response;
|
|
923
|
+
// The SUPERVISOR binding's filesystem calls answer a refusal as a value
|
|
924
|
+
// (core vfs-supervisor.ts answeringSupervisor).
|
|
925
|
+
${SUPERVISOR_ANSWERING_SRC}
|
|
908
926
|
|
|
909
927
|
// The process's code: a module per cell, compiled when first required. The
|
|
910
928
|
// only other way a string becomes code in a Worker is \`new Function\` at
|
|
@@ -1006,7 +1024,7 @@ async function __nimbusEnsureStarted(workerEnv, workerCtx, __startArgs) {
|
|
|
1006
1024
|
// time. Same reason argv/env/pid want to move here.
|
|
1007
1025
|
const __MODULE_VFS_CURSOR = (__startArgs && __startArgs.vfsCursor) || null;
|
|
1008
1026
|
${VFS_CURSOR_SEED_SOURCE}
|
|
1009
|
-
const __supervisor = workerEnv?.SUPERVISOR
|
|
1027
|
+
const __supervisor = workerEnv?.SUPERVISOR ? globalThis.__nimbusAnsweringSupervisor(workerEnv.SUPERVISOR) : null;
|
|
1010
1028
|
__nimbusRuntimeCodeReporter = () => {
|
|
1011
1029
|
const report = __nimbusFlushRuntimeCode(__supervisor).catch(async (error) => {
|
|
1012
1030
|
await __nimbusReportLearningFailure(__supervisor, error);
|
|
@@ -1138,6 +1156,7 @@ ${RESIDENCY_MISS_REPORT}
|
|
|
1138
1156
|
}
|
|
1139
1157
|
|
|
1140
1158
|
const mod = { exports: {} };
|
|
1159
|
+
Object.defineProperty(mod, "__nimbusImportMeta", { value: __nimbusFileImportMeta(filename || "/home/user/script.js") });
|
|
1141
1160
|
__require.main = mod;
|
|
1142
1161
|
let __attachedCompletion = null;
|
|
1143
1162
|
let __attachedExplicitExit = false;
|
|
@@ -1174,7 +1193,6 @@ ${RESIDENCY_MISS_REPORT}
|
|
|
1174
1193
|
__attachedExplicitExit = true;
|
|
1175
1194
|
exitCode = e.code;
|
|
1176
1195
|
} else {
|
|
1177
|
-
globalThis.__nimbusRuntimeCode.noteFailure(e);
|
|
1178
1196
|
const trace = (e && e.stack) || (e && e.message) || String(e);
|
|
1179
1197
|
stderr += trace + "\\n";
|
|
1180
1198
|
exitCode = 1;
|
|
@@ -1210,13 +1228,6 @@ ${RESIDENCY_MISS_REPORT}
|
|
|
1210
1228
|
if (Number(code ?? 0) === 0) code = 1;
|
|
1211
1229
|
try { await __supervisor.stderr(__nimbusOutEnc.encode(__residencyReport)); } catch {}
|
|
1212
1230
|
}
|
|
1213
|
-
// A failed launch stages the Function-constructor text its failure is
|
|
1214
|
-
// attributable to (commonjs-cell.ts, stageFailedLaunch).
|
|
1215
|
-
const __stagedCode = Number(code ?? 0) !== 0 ? globalThis.__nimbusRuntimeCode.stageFailedLaunch() : "";
|
|
1216
|
-
if (__stagedCode) {
|
|
1217
|
-
stderr += __stagedCode + "\\n";
|
|
1218
|
-
try { await __supervisor.stderr(__nimbusOutEnc.encode(__stagedCode + "\\n")); } catch {}
|
|
1219
|
-
}
|
|
1220
1231
|
await __supervisor.reportExit(code, reason || "", __nimbusDataReadMisses(), [...(globalThis.__nimbusProfileStaged || [])], __nimbusRuntimeCodeLedger(), __nimbusExecutedModuleMisses());
|
|
1221
1232
|
__nimbusProcessExitReported = true;
|
|
1222
1233
|
};
|
|
@@ -1336,7 +1347,7 @@ export class NimbusProcess extends DurableObject {
|
|
|
1336
1347
|
}
|
|
1337
1348
|
`,
|
|
1338
1349
|
modules: bundleSource.modules,
|
|
1339
|
-
codeModules: { ...bundleSource.codeModules, [entry.name]: entry.text },
|
|
1350
|
+
codeModules: { ...bundleSource.codeModules, ...interpreterModules(sources), [entry.name]: entry.text },
|
|
1340
1351
|
};
|
|
1341
1352
|
}
|
|
1342
1353
|
/**
|
|
@@ -2019,6 +2030,8 @@ export async function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requir
|
|
|
2019
2030
|
if (!((await filesOf(vfs).exists(nmDir)) && (await filesOf(vfs).isDirectory(nmDir))))
|
|
2020
2031
|
return { added, groups };
|
|
2021
2032
|
const exts = ['', '.js', '.cjs', '.mjs', '/index.js', '/index.cjs'];
|
|
2033
|
+
// What the admitted groups defer with `import()`; a group does not walk them.
|
|
2034
|
+
const deferred = [];
|
|
2022
2035
|
async function addOne(path) {
|
|
2023
2036
|
const stripped = path.replace(/^\/+/, '');
|
|
2024
2037
|
if ((isBundleModuleCandidate(stripped) || stripped.endsWith('.cjs')) && !isNativeBinPath(stripped)) {
|
|
@@ -2033,6 +2046,9 @@ export async function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requir
|
|
|
2033
2046
|
});
|
|
2034
2047
|
if ('kind' in closure || closure.bundle[stripped] === undefined)
|
|
2035
2048
|
return false;
|
|
2049
|
+
for (const deferral of closure.deferred ?? [])
|
|
2050
|
+
if (deferral.alternatives === 1)
|
|
2051
|
+
deferred.push(deferral);
|
|
2036
2052
|
for (const [member, cell] of Object.entries(closure.bundle)) {
|
|
2037
2053
|
if (bundle[member] !== undefined)
|
|
2038
2054
|
continue;
|
|
@@ -2190,7 +2206,7 @@ export async function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requir
|
|
|
2190
2206
|
{
|
|
2191
2207
|
const sibs = await (async () => vfs.readdir(entryDir))().catch(() => []);
|
|
2192
2208
|
for (const sib of sibs) {
|
|
2193
|
-
if (sib
|
|
2209
|
+
if ((await launchEntryType(vfs, entryDir, sib)) !== 'file')
|
|
2194
2210
|
continue;
|
|
2195
2211
|
// Hash-chunk pattern: <name>.<hash>.<cjs|mjs|js>. Hash must
|
|
2196
2212
|
// be 6+ chars AND look like a hash, not an English word —
|
|
@@ -2218,7 +2234,7 @@ export async function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requir
|
|
|
2218
2234
|
const sharedStripped = sharedDir.replace(/^\/+/, '');
|
|
2219
2235
|
if (await (async () => filesOf(vfs).isDirectory(sharedStripped))().catch(() => false)) {
|
|
2220
2236
|
for (const sh of await (async () => vfs.readdir(sharedDir))().catch(() => [])) {
|
|
2221
|
-
if (sh
|
|
2237
|
+
if ((await launchEntryType(vfs, sharedDir, sh)) !== 'file')
|
|
2222
2238
|
continue;
|
|
2223
2239
|
if (!/\.(cjs|mjs|js)$/.test(sh.name))
|
|
2224
2240
|
continue;
|
|
@@ -2232,6 +2248,28 @@ export async function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requir
|
|
|
2232
2248
|
}
|
|
2233
2249
|
for (const pkgDir of (await speculativePackageDirs(vfs, cwdStripped, bundle)))
|
|
2234
2250
|
(await addPkgEntry(pkgDir));
|
|
2251
|
+
// Then the one `import()` a guessed module defers, when it defers only one
|
|
2252
|
+
// and it is a file of its own package, as a guess of its own with its static
|
|
2253
|
+
// closure; what that defers joins the queue. That is how a package proxies
|
|
2254
|
+
// or splits its own code, and it loads whenever the deferring code runs:
|
|
2255
|
+
// vinext imports @vitejs/plugin-rsc by a computed URL (a guess here, as a
|
|
2256
|
+
// project dependency); plugin-rsc imports vitefu, whose CommonJS entry loads
|
|
2257
|
+
// its ESM build with `import('./index.js')`. A module that defers several
|
|
2258
|
+
// chooses among them, and a deferral of another package is an optional
|
|
2259
|
+
// dependency (@vercel/og's `import("sharp")`, caught when absent, whose
|
|
2260
|
+
// 9.2 MB wasm image the launch would compile): a guess does not guess those.
|
|
2261
|
+
const followed = new Set();
|
|
2262
|
+
for (let i = 0; i < deferred.length; i++) {
|
|
2263
|
+
if (rawBytes >= bound || budgetState.fileCount >= VFS_BUNDLE_MAX_FILES)
|
|
2264
|
+
break;
|
|
2265
|
+
const target = await resolveDeferredImport(requireFsOverBridge(vfs), deferred[i], options.pacer?.spend.bind(options.pacer));
|
|
2266
|
+
// Its own package: where the deferral lands, not how it is spelled.
|
|
2267
|
+
const own = packageRootOf(deferred[i].fromDir.replace(/^\/+/, '') + '/_');
|
|
2268
|
+
if (target === null || own === null || packageRootOf(target) !== own || followed.has(target))
|
|
2269
|
+
continue;
|
|
2270
|
+
followed.add(target);
|
|
2271
|
+
await addOne(target);
|
|
2272
|
+
}
|
|
2235
2273
|
return { added, groups };
|
|
2236
2274
|
}
|
|
2237
2275
|
/**
|
|
@@ -2760,7 +2798,7 @@ export async function addBinTargetSiblings(vfs, scriptPath, bundle, budgetState,
|
|
|
2760
2798
|
if (e.name === '.git')
|
|
2761
2799
|
continue;
|
|
2762
2800
|
const child = dir + '/' + e.name;
|
|
2763
|
-
if (e
|
|
2801
|
+
if ((await launchEntryType(vfs, dir, e)) === 'directory') {
|
|
2764
2802
|
if (!shouldVisitBinPackageDirectory(pkgRoot, child, bundleProfile))
|
|
2765
2803
|
continue;
|
|
2766
2804
|
queue.push(child);
|
|
@@ -3120,10 +3158,11 @@ async function addCwdProjectFiles(vfs, cwd, bundle, budgetState) {
|
|
|
3120
3158
|
visited++;
|
|
3121
3159
|
if (e.name === '.' || e.name === '..')
|
|
3122
3160
|
continue;
|
|
3123
|
-
|
|
3161
|
+
const isDirectory = (await launchEntryType(vfs, dir, e)) === 'directory';
|
|
3162
|
+
if (isDirectory && SKIP_DIRS.has(e.name))
|
|
3124
3163
|
continue;
|
|
3125
3164
|
const child = dir + '/' + e.name;
|
|
3126
|
-
if (
|
|
3165
|
+
if (isDirectory) {
|
|
3127
3166
|
queue.push(child);
|
|
3128
3167
|
continue;
|
|
3129
3168
|
}
|
|
@@ -3316,6 +3355,61 @@ async function transformEsmInBundle(bundle, emits, lowered, esbuild, pacer, stor
|
|
|
3316
3355
|
lowered.add(path);
|
|
3317
3356
|
});
|
|
3318
3357
|
}
|
|
3358
|
+
/** A tool's config file: `<tool>.config.js|ts|mjs|cjs|mts|cts` (vite.config.ts, astro.config.mjs). */
|
|
3359
|
+
const TOOL_CONFIG = /^(.+)\.config\.(?:c|m)?(?:j|t)s$/;
|
|
3360
|
+
/**
|
|
3361
|
+
* The working dir's config files of the tool a launch runs. The tool
|
|
3362
|
+
* executes them (Vite bundles vite.config.ts and imports the result), so
|
|
3363
|
+
* what they import is code that nothing in the program's own graph names,
|
|
3364
|
+
* and a first run would miss it. They are optional roots: a command may
|
|
3365
|
+
* never read its config (`vite --version`), so a config graph past the
|
|
3366
|
+
* map's bound is cut, never a refusal. A config is the tool's when it is
|
|
3367
|
+
* named for the launched package or a package that one depends on (Astro
|
|
3368
|
+
* runs Vite, Vite runs PostCSS); a config of a tool the launch does not run
|
|
3369
|
+
* (eslint.config.js beside Vite) is not. What a config names by a string
|
|
3370
|
+
* (PostCSS's plugins) the tool loads by name: those join the walk's phase 2.
|
|
3371
|
+
*/
|
|
3372
|
+
export async function toolConfigRoots(vfs, cwd, scriptPath) {
|
|
3373
|
+
if (scriptPath === undefined)
|
|
3374
|
+
return [];
|
|
3375
|
+
// A bin is usually launched by its node_modules/.bin link.
|
|
3376
|
+
let script;
|
|
3377
|
+
try {
|
|
3378
|
+
script = await vfs.realpath(scriptPath);
|
|
3379
|
+
}
|
|
3380
|
+
catch {
|
|
3381
|
+
return [];
|
|
3382
|
+
}
|
|
3383
|
+
const root = packageRootOf(script.replace(/^\/+/, ''));
|
|
3384
|
+
if (root === null)
|
|
3385
|
+
return [];
|
|
3386
|
+
let manifest;
|
|
3387
|
+
try {
|
|
3388
|
+
manifest = JSON.parse(await filesOf(vfs).readFileString(root + '/package.json'));
|
|
3389
|
+
}
|
|
3390
|
+
catch {
|
|
3391
|
+
return [];
|
|
3392
|
+
}
|
|
3393
|
+
const tools = new Set(typeof manifest.name === 'string' ? [manifest.name] : []);
|
|
3394
|
+
for (const field of ['dependencies', 'peerDependencies', 'optionalDependencies']) {
|
|
3395
|
+
const named = manifest[field];
|
|
3396
|
+
if (named && typeof named === 'object')
|
|
3397
|
+
for (const name of Object.keys(named))
|
|
3398
|
+
tools.add(name);
|
|
3399
|
+
}
|
|
3400
|
+
let entries;
|
|
3401
|
+
try {
|
|
3402
|
+
entries = await vfs.readdir(cwd);
|
|
3403
|
+
}
|
|
3404
|
+
catch {
|
|
3405
|
+
return [];
|
|
3406
|
+
}
|
|
3407
|
+
const dir = cwd.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
3408
|
+
return entries.flatMap((entry) => {
|
|
3409
|
+
const tool = entry.type === 'file' ? TOOL_CONFIG.exec(entry.name)?.[1] : undefined;
|
|
3410
|
+
return tool !== undefined && tools.has(tool) ? [{ path: (dir ? dir + '/' : '') + entry.name, config: true }] : [];
|
|
3411
|
+
});
|
|
3412
|
+
}
|
|
3319
3413
|
/**
|
|
3320
3414
|
* W2.6a: build the prefetch bundle for FacetManager.exec.
|
|
3321
3415
|
*
|
|
@@ -3360,8 +3454,10 @@ async function _buildPrefetchBundle(vfs, { scriptPath, cwd, entryCode, esbuild,
|
|
|
3360
3454
|
// executable map. A module that arrives with its text (Vite unlinks its
|
|
3361
3455
|
// temporary config after loading it) is walked from that text. Files runs
|
|
3362
3456
|
// only READ are observed reads below: data, never roots, whatever their
|
|
3363
|
-
// extension (Tailwind scans .js/.ts content files as text).
|
|
3364
|
-
|
|
3457
|
+
// extension (Tailwind scans .js/.ts content files as text). The tool's
|
|
3458
|
+
// configs ride along, as optional roots (RequiredModuleRoot.config).
|
|
3459
|
+
const requiredRoots = [...await toolConfigRoots(vfs, cwd, scriptPath), ...executedModules ?? []];
|
|
3460
|
+
const prefetch = (await prefetchForRequire(requireFsOverBridge(vfs), entryCode || '', cwd, scriptPath, maxBundleBytes, pacer?.spend.bind(pacer), undefined, requiredRoots.length > 0 ? requiredRoots : undefined));
|
|
3365
3461
|
if ('kind' in prefetch) {
|
|
3366
3462
|
// A required closure larger than the bound can never launch as a
|
|
3367
3463
|
// snapshot. Surface it as the process's own failure rather than a
|
|
@@ -3772,9 +3868,10 @@ export class FacetManager {
|
|
|
3772
3868
|
/** Per resident pid: the shared read profile's entries its launch staged, settled at its exit. */
|
|
3773
3869
|
residentProfileOffers = new Map();
|
|
3774
3870
|
/**
|
|
3775
|
-
* The
|
|
3871
|
+
* The service the bundle's ESM→CJS pass transforms with. composeFacetManager
|
|
3776
3872
|
* sets it: the host's own, or one whose transforms run in the session's
|
|
3777
|
-
*
|
|
3873
|
+
* transform facet. Never one of this isolate: a transform engine's wasm
|
|
3874
|
+
* memory only grows.
|
|
3778
3875
|
*/
|
|
3779
3876
|
esbuild = null;
|
|
3780
3877
|
/**
|
|
@@ -3879,8 +3976,11 @@ export class FacetManager {
|
|
|
3879
3976
|
+ `"${record.command}" was ${residentLaunchDoing(record)} — restarting it]\x1b[0m\r\n`),
|
|
3880
3977
|
onAbandoned: (record) => this.hooks.notify?.('\x1b[2m[nimbus: the session restarted again while '
|
|
3881
3978
|
+ `"${record.command}" was ${residentLaunchDoing(record)} — leaving it stopped]\x1b[0m\r\n`),
|
|
3882
|
-
onRedriveFailed: (record, e) =>
|
|
3883
|
-
|
|
3979
|
+
onRedriveFailed: (record, e) => {
|
|
3980
|
+
console.warn(`[facet-manager] resident pid ${record.pid} ("${record.command}") not re-driven: ${errorMessage(e)}`);
|
|
3981
|
+
this.hooks.notify?.(`\x1b[2m[nimbus: "${record.command}" could not be restarted: `
|
|
3982
|
+
+ `${errorMessage(e)}]\x1b[0m\r\n`);
|
|
3983
|
+
},
|
|
3884
3984
|
});
|
|
3885
3985
|
this.launchPump = new PacedWork(ctx, {
|
|
3886
3986
|
requestTurn: hooks.requestLaunchTurn?.bind(hooks),
|
|
@@ -4064,7 +4164,7 @@ export class FacetManager {
|
|
|
4064
4164
|
* The entry script as the facet compiles it: each dynamic `import()` routed
|
|
4065
4165
|
* to the process's ESM loader, with the entry's own URL as the parent (Node
|
|
4066
4166
|
* names `-e` code `<cwd>/[eval]` and stdin `<cwd>/[stdin]`). The parse runs
|
|
4067
|
-
* in the
|
|
4167
|
+
* in the transform facet like every cell's, and its result is kept by content
|
|
4068
4168
|
* in the session's transform store. The module-map walk reads the script as
|
|
4069
4169
|
* written, before this.
|
|
4070
4170
|
*/
|
|
@@ -4316,15 +4416,7 @@ export class FacetManager {
|
|
|
4316
4416
|
return null;
|
|
4317
4417
|
}
|
|
4318
4418
|
},
|
|
4319
|
-
|
|
4320
|
-
readlink: async (path) => {
|
|
4321
|
-
try {
|
|
4322
|
-
return await vfs.readlink(path);
|
|
4323
|
-
}
|
|
4324
|
-
catch {
|
|
4325
|
-
return null;
|
|
4326
|
-
}
|
|
4327
|
-
},
|
|
4419
|
+
linkTarget: (path) => linkTargetOf(vfs, path),
|
|
4328
4420
|
stat: async (path) => {
|
|
4329
4421
|
const st = await filesOf(vfs).stat(path).catch(() => null);
|
|
4330
4422
|
return st && { kind: st.type, size: st.size };
|
|
@@ -4349,6 +4441,49 @@ export class FacetManager {
|
|
|
4349
4441
|
const storageBytes = Math.ceil(plan.bytes * 1.01) + rows * LEDGER_ROW_BYTES + moduleBytes + 65_536;
|
|
4350
4442
|
return { paths: plan.paths, storageBytes };
|
|
4351
4443
|
}
|
|
4444
|
+
/**
|
|
4445
|
+
* A one-shot's data plan: what its closure reads synchronously by a path its
|
|
4446
|
+
* code spells out (static-fs-refs.ts; readFileSync, or a read-only openSync),
|
|
4447
|
+
* any size, through any links on it, that the module map does not hold. It
|
|
4448
|
+
* is data-plan.ts's `static` rule for synchronous reads, which needs the
|
|
4449
|
+
* closure and a stat per path but no listing. The store fetches it at boot,
|
|
4450
|
+
* so it is held beside the module map rather than carried in it: `vite
|
|
4451
|
+
* build` reads lightningcss's 15.8 MB image with readFileSync(new
|
|
4452
|
+
* URL('lightningcss_node.wasm', import.meta.url)), which as a map cell
|
|
4453
|
+
* left the closure no room under the map's bound.
|
|
4454
|
+
*/
|
|
4455
|
+
async _staticReadPlan(entry, vfsState, cwd, pacer) {
|
|
4456
|
+
if (!this.filesystem)
|
|
4457
|
+
return [];
|
|
4458
|
+
const vfs = this.filesystem.bind({ pid: entry.pid, cred: entry.cred });
|
|
4459
|
+
const held = new Set(vfsState.bundlePaths ?? []);
|
|
4460
|
+
const dir = stripLeadingSlashes(cwd).replace(/\/+$/, '');
|
|
4461
|
+
const reads = new Set();
|
|
4462
|
+
for (const refs of await this._closureStaticRefs(vfs, vfsState.bundlePaths ?? [], pacer)) {
|
|
4463
|
+
for (const ref of refs.exact)
|
|
4464
|
+
if (ref.sync)
|
|
4465
|
+
reads.add(stripLeadingSlashes(ref.path));
|
|
4466
|
+
for (const ref of refs.cwdRelative)
|
|
4467
|
+
if (ref.sync)
|
|
4468
|
+
reads.add(normalizeVfsPath((dir ? dir + '/' : '') + ref.path));
|
|
4469
|
+
}
|
|
4470
|
+
const plan = new Set();
|
|
4471
|
+
for (const path of reads) {
|
|
4472
|
+
let target;
|
|
4473
|
+
try {
|
|
4474
|
+
target = stripLeadingSlashes(await vfs.realpath('/' + path));
|
|
4475
|
+
}
|
|
4476
|
+
catch {
|
|
4477
|
+
continue;
|
|
4478
|
+
}
|
|
4479
|
+
if (held.has(target))
|
|
4480
|
+
continue;
|
|
4481
|
+
const stat = await filesOf(vfs).stat(target).catch(() => null);
|
|
4482
|
+
if (stat?.type === 'file')
|
|
4483
|
+
plan.add(target);
|
|
4484
|
+
}
|
|
4485
|
+
return [...plan];
|
|
4486
|
+
}
|
|
4352
4487
|
/**
|
|
4353
4488
|
* Paths earlier launches of the same build missed in this session. Other
|
|
4354
4489
|
* sessions' misses (the shared read profile) join the module map instead,
|
|
@@ -4652,6 +4787,10 @@ export class FacetManager {
|
|
|
4652
4787
|
async _stagedRuntimeCode(learning, pacer) {
|
|
4653
4788
|
const modules = new Map();
|
|
4654
4789
|
for (const [codeKey, entry] of learning.code) {
|
|
4790
|
+
if (entry.kind === 'expression') {
|
|
4791
|
+
modules.set(codeKey, runtimeExpressionModule(entry.code));
|
|
4792
|
+
continue;
|
|
4793
|
+
}
|
|
4655
4794
|
if (entry.kind !== 'module') {
|
|
4656
4795
|
modules.set(codeKey, runtimeFunctionModule(entry.kind, entry.params, entry.body));
|
|
4657
4796
|
continue;
|
|
@@ -4849,8 +4988,12 @@ export class FacetManager {
|
|
|
4849
4988
|
entry = found;
|
|
4850
4989
|
}
|
|
4851
4990
|
else {
|
|
4852
|
-
this.processes.reap();
|
|
4853
|
-
|
|
4991
|
+
await this.processes.reap();
|
|
4992
|
+
// A child of the command that ran it, so under its credential: the
|
|
4993
|
+
// program's syscalls answer under the credential the table holds for
|
|
4994
|
+
// its pid. At the top of the table it ran as the session user whoever
|
|
4995
|
+
// started it.
|
|
4996
|
+
entry = this.processes.spawn(command, opts.argv || [], opts.cwd || '/home/user', { parentPid: opts.invokerPid });
|
|
4854
4997
|
// Short foreground `node -e ...` helpers are quiet by design — only
|
|
4855
4998
|
// notify for user-facing `node <file>` invocations, which covers the
|
|
4856
4999
|
// real user intent (running scripts, wrangler, etc.).
|
|
@@ -4928,10 +5071,12 @@ export class FacetManager {
|
|
|
4928
5071
|
opts.signal?.addEventListener('abort', onShellAbort, { once: true });
|
|
4929
5072
|
try {
|
|
4930
5073
|
// A one-shot holds its module map and what it was seen to read (both in
|
|
4931
|
-
// the bundle), and plans
|
|
4932
|
-
//
|
|
4933
|
-
//
|
|
4934
|
-
|
|
5074
|
+
// the bundle), and plans no listing of the namespace (§2.8: the
|
|
5075
|
+
// principal's image is where that comes from). What its closure reads
|
|
5076
|
+
// synchronously by a path its code spells out needs no listing, and is
|
|
5077
|
+
// its data plan.
|
|
5078
|
+
const dataPlan = await this._staticReadPlan(entry, vfsState, cwd, pacer);
|
|
5079
|
+
const result = await this._execViaLoader(code, opts, entry, vfsState, dataPlan, abortController.signal, pacer, diagSink);
|
|
4935
5080
|
await this._recordLaunchLearning(vfsState.bundleKey, {
|
|
4936
5081
|
code: result.runtimeCode, executedModules: result.moduleMisses, dataReads: result.residencyMisses,
|
|
4937
5082
|
}).catch((error) => this._learningLost(entry.pid, error));
|
|
@@ -5252,7 +5397,7 @@ export class FacetManager {
|
|
|
5252
5397
|
}
|
|
5253
5398
|
const command = opts.command || `opencode ${opts.argv.join(' ')}`.trim();
|
|
5254
5399
|
const attached = mode === 'attached';
|
|
5255
|
-
const entry = this.processes.spawn(command, ['opencode', ...opts.argv], opts.cwd);
|
|
5400
|
+
const entry = this.processes.spawn(command, ['opencode', ...opts.argv], opts.cwd, { parentPid: opts.invokerPid });
|
|
5256
5401
|
const pid = entry.pid;
|
|
5257
5402
|
// attached TUI + headless serve are resident long-running processes; only the
|
|
5258
5403
|
// attached TUI grabs the terminal (raw-mode stdin + live geometry).
|
|
@@ -5400,6 +5545,7 @@ export class FacetManager {
|
|
|
5400
5545
|
env: opts.env,
|
|
5401
5546
|
cwd: opts.cwd,
|
|
5402
5547
|
command: `opencode serve --port ${port}`,
|
|
5548
|
+
invokerPid: opts.invokerPid,
|
|
5403
5549
|
}, 'server');
|
|
5404
5550
|
const servePid = serveStaged.pid;
|
|
5405
5551
|
try {
|
|
@@ -5425,6 +5571,9 @@ export class FacetManager {
|
|
|
5425
5571
|
stdin: '',
|
|
5426
5572
|
command: opts.command || 'opencode',
|
|
5427
5573
|
attachedTty: true,
|
|
5574
|
+
// The pair's exec id, from the serve: the command that ran `opencode`
|
|
5575
|
+
// may have ended while the serve booted, and been reaped since.
|
|
5576
|
+
invokerPid: servePid,
|
|
5428
5577
|
});
|
|
5429
5578
|
}
|
|
5430
5579
|
catch (e) {
|
|
@@ -5732,14 +5881,20 @@ export class FacetManager {
|
|
|
5732
5881
|
}
|
|
5733
5882
|
/**
|
|
5734
5883
|
* Re-drive a journalled launch after an instance reset. What the journal
|
|
5735
|
-
* row carries is the recipe and
|
|
5736
|
-
* written to storage, so a worker
|
|
5737
|
-
* through
|
|
5884
|
+
* row carries is the recipe, and who the launch ran as (its credential and
|
|
5885
|
+
* exec id); env and secrets are never written to storage, so a worker
|
|
5886
|
+
* launch's are re-resolved by the embedder through
|
|
5887
|
+
* `hooks.resolveWorkerLaunch`.
|
|
5738
5888
|
*/
|
|
5739
5889
|
async _redrive(record, attempt) {
|
|
5740
5890
|
const { recipe } = record;
|
|
5891
|
+
if (record.cred === undefined) {
|
|
5892
|
+
// Reported through onRedriveFailed, and the row is superseded.
|
|
5893
|
+
throw new Error('its journal entry predates the credential a re-drive runs under, so it is not started as anyone else');
|
|
5894
|
+
}
|
|
5895
|
+
const identity = { cred: record.cred, ...(record.execId === undefined ? {} : { execId: record.execId }) };
|
|
5741
5896
|
switch (recipe.kind) {
|
|
5742
|
-
case 'node': return this._spawnResident(recipe.code, recipe.opts, attempt);
|
|
5897
|
+
case 'node': return this._spawnResident(recipe.code, recipe.opts, attempt, identity);
|
|
5743
5898
|
case 'worker': {
|
|
5744
5899
|
// Which resolver a worker recipe re-drives through is decided by
|
|
5745
5900
|
// `recipe.resident`, and it is not a flag: it is the interpreter
|
|
@@ -5771,7 +5926,7 @@ export class FacetManager {
|
|
|
5771
5926
|
vfsTextModules: resolved.vfsTextModules,
|
|
5772
5927
|
mainModule,
|
|
5773
5928
|
durable: { owner: residentOwner(record) ?? recipe.owner, image: recipe.image },
|
|
5774
|
-
}, attempt);
|
|
5929
|
+
}, attempt, identity);
|
|
5775
5930
|
}
|
|
5776
5931
|
}
|
|
5777
5932
|
}
|
|
@@ -5792,10 +5947,12 @@ export class FacetManager {
|
|
|
5792
5947
|
/**
|
|
5793
5948
|
* `attempt` distinguishes the launch the user asked for from the one re-drive
|
|
5794
5949
|
* an instance reset earns it, and is carried in the journal rather than in
|
|
5795
|
-
* the caller's options because no caller has an opinion about it.
|
|
5950
|
+
* the caller's options because no caller has an opinion about it. So is a
|
|
5951
|
+
* re-drive's credential and exec id, from the row: the process that invoked
|
|
5952
|
+
* the launch went with the instance.
|
|
5796
5953
|
*/
|
|
5797
|
-
async _spawnResident(code, opts, attempt) {
|
|
5798
|
-
this.processes.reap();
|
|
5954
|
+
async _spawnResident(code, opts, attempt, redriven) {
|
|
5955
|
+
await this.processes.reap();
|
|
5799
5956
|
const command = opts.command || (opts.filename ? `node ${opts.filename}` : 'node <script>');
|
|
5800
5957
|
const cwd = opts.cwd || '/home/user';
|
|
5801
5958
|
let entry;
|
|
@@ -5807,7 +5964,9 @@ export class FacetManager {
|
|
|
5807
5964
|
entry = found;
|
|
5808
5965
|
}
|
|
5809
5966
|
else {
|
|
5810
|
-
|
|
5967
|
+
// A child of its invoker, under its credential, as exec's. A re-drive has
|
|
5968
|
+
// no invoker (the journal never holds one): it runs as the row says.
|
|
5969
|
+
entry = this.processes.spawn(command, opts.argv || [], cwd, { parentPid: opts.invokerPid, ...redriven });
|
|
5811
5970
|
}
|
|
5812
5971
|
this.processes.setLongRunning(entry.pid);
|
|
5813
5972
|
if (opts.attachedTty)
|
|
@@ -5888,10 +6047,16 @@ export class FacetManager {
|
|
|
5888
6047
|
owner = declared.owner;
|
|
5889
6048
|
}
|
|
5890
6049
|
}
|
|
6050
|
+
// The recipe is the launch's inputs; the invoker is a pid of this
|
|
6051
|
+
// instance, which a re-drive outlives, so the row carries who it ran as.
|
|
6052
|
+
const { invokerPid: _invokerPid, ...inputs } = opts;
|
|
6053
|
+
const recipe = { kind: 'node', code, opts: { ...inputs, skipSpawn: undefined, callerPid: undefined } };
|
|
6054
|
+
const ranAs = { cred: entry.cred, ...(entry.execId === undefined ? {} : { execId: entry.execId }) };
|
|
5891
6055
|
const initial = {
|
|
5892
6056
|
pid: entry.pid, command, attempt, phase: 'starting', owner,
|
|
5893
|
-
recipe
|
|
6057
|
+
recipe,
|
|
5894
6058
|
restart: residentRestartPolicy(opts.env),
|
|
6059
|
+
...ranAs,
|
|
5895
6060
|
};
|
|
5896
6061
|
let duplicateOf;
|
|
5897
6062
|
try {
|
|
@@ -5930,10 +6095,11 @@ export class FacetManager {
|
|
|
5930
6095
|
command,
|
|
5931
6096
|
attempt,
|
|
5932
6097
|
phase: 'starting',
|
|
5933
|
-
recipe
|
|
6098
|
+
recipe,
|
|
5934
6099
|
owner,
|
|
5935
6100
|
...(held !== null ? { port: held.port, injectedPort: held.port } : {}),
|
|
5936
6101
|
restart: residentRestartPolicy(opts.env),
|
|
6102
|
+
...ranAs,
|
|
5937
6103
|
};
|
|
5938
6104
|
try {
|
|
5939
6105
|
if (!ephemeral)
|
|
@@ -6236,15 +6402,15 @@ export class FacetManager {
|
|
|
6236
6402
|
async spawnWorker(workerCode, command, cwd, opts = {}) {
|
|
6237
6403
|
return this._spawnWorker(workerCode, command, cwd, opts, 0);
|
|
6238
6404
|
}
|
|
6239
|
-
/** `attempt` is the journal's re-drive budget, as `_spawnResident` carries
|
|
6240
|
-
async _spawnWorker(workerCode, command, cwd, opts, attempt) {
|
|
6405
|
+
/** `attempt` is the journal's re-drive budget, and `redriven` who a re-drive runs as, as `_spawnResident` carries them. */
|
|
6406
|
+
async _spawnWorker(workerCode, command, cwd, opts, attempt, redriven) {
|
|
6241
6407
|
if (opts.resident && !opts.durable) {
|
|
6242
6408
|
opts = { ...opts, durable: { owner: await deriveResidentOwner(cwd, opts.resident.argv) } };
|
|
6243
6409
|
}
|
|
6244
|
-
this.processes.reap();
|
|
6410
|
+
await this.processes.reap();
|
|
6245
6411
|
// The table entry carries the same argv the identity is derived from, so
|
|
6246
6412
|
// a runtime resident reads the same way through either path.
|
|
6247
|
-
const entry = this.processes.spawn(command, opts.resident?.argv ?? [], cwd);
|
|
6413
|
+
const entry = this.processes.spawn(command, opts.resident?.argv ?? [], cwd, { parentPid: opts.invokerPid, ...redriven });
|
|
6248
6414
|
// Stamp the process-table entry so /api/processes exposes this as a
|
|
6249
6415
|
// long-running process.
|
|
6250
6416
|
this.processes.setLongRunning(entry.pid);
|
|
@@ -6334,6 +6500,8 @@ export class FacetManager {
|
|
|
6334
6500
|
owner: opts.durable.owner,
|
|
6335
6501
|
restart: opts.restart ?? 'never',
|
|
6336
6502
|
...(opts.port !== undefined && opts.port > 0 ? { port: opts.port } : {}),
|
|
6503
|
+
cred: entry.cred,
|
|
6504
|
+
...(entry.execId !== undefined ? { execId: entry.execId } : {}),
|
|
6337
6505
|
};
|
|
6338
6506
|
// The durable facet name is claimed once, ever, from DO storage — a
|
|
6339
6507
|
// re-drive after a reset, an eviction's re-attach and a relaunch all
|
|
@@ -6674,7 +6842,8 @@ export class FacetManager {
|
|
|
6674
6842
|
app.status = 'running';
|
|
6675
6843
|
apps.set(identity.owner, app);
|
|
6676
6844
|
}
|
|
6677
|
-
|
|
6845
|
+
// The live pid's exec id, read from its process: the one place it lives.
|
|
6846
|
+
return [...apps.values()].map((app) => (app.pid === null ? app : { ...app, ...execIdField(this.processes.get(app.pid)) }));
|
|
6678
6847
|
}
|
|
6679
6848
|
async registerPort(pid, port) {
|
|
6680
6849
|
if (port > 0 && port < 65536) {
|