@nimbus-sh/worker 0.1.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/README.md +219 -0
- package/dist/_shared/bytes.d.ts +18 -0
- package/dist/_shared/bytes.d.ts.map +1 -0
- package/dist/_shared/bytes.js +17 -0
- package/dist/_shared/cache-stats.d.ts +146 -0
- package/dist/_shared/cache-stats.d.ts.map +1 -0
- package/dist/_shared/cache-stats.js +162 -0
- package/dist/_shared/exports-resolver.d.ts +76 -0
- package/dist/_shared/exports-resolver.d.ts.map +1 -0
- package/dist/_shared/exports-resolver.js +284 -0
- package/dist/_shared/install-phase.d.ts +47 -0
- package/dist/_shared/install-phase.d.ts.map +1 -0
- package/dist/_shared/install-phase.js +1 -0
- package/dist/_shared/real-node-imports.d.ts +38 -0
- package/dist/_shared/real-node-imports.d.ts.map +1 -0
- package/dist/_shared/real-node-imports.js +46 -0
- package/dist/_shared/retry.d.ts +93 -0
- package/dist/_shared/retry.d.ts.map +1 -0
- package/dist/_shared/retry.js +161 -0
- package/dist/_shared/session-id.d.ts +39 -0
- package/dist/_shared/session-id.d.ts.map +1 -0
- package/dist/_shared/session-id.js +127 -0
- package/dist/_shared/session-router.d.ts +104 -0
- package/dist/_shared/session-router.d.ts.map +1 -0
- package/dist/_shared/session-router.js +165 -0
- package/dist/_shared/w7-frame.d.ts +93 -0
- package/dist/_shared/w7-frame.d.ts.map +1 -0
- package/dist/_shared/w7-frame.js +402 -0
- package/dist/auth/index.d.ts +16 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +15 -0
- package/dist/auth/middleware.d.ts +85 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +150 -0
- package/dist/auth/token.d.ts +96 -0
- package/dist/auth/token.d.ts.map +1 -0
- package/dist/auth/token.js +226 -0
- package/dist/auth/types.d.ts +141 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +114 -0
- package/dist/bindings/d1.d.ts +102 -0
- package/dist/bindings/d1.d.ts.map +1 -0
- package/dist/bindings/d1.js +549 -0
- package/dist/bindings/kv.d.ts +82 -0
- package/dist/bindings/kv.d.ts.map +1 -0
- package/dist/bindings/kv.js +290 -0
- package/dist/bindings/r2.d.ts +137 -0
- package/dist/bindings/r2.d.ts.map +1 -0
- package/dist/bindings/r2.js +379 -0
- package/dist/cirrus-npm-cjs.generated.d.ts +17 -0
- package/dist/cirrus-npm-cjs.generated.d.ts.map +1 -0
- package/dist/cirrus-npm-cjs.generated.js +41 -0
- package/dist/cirrus-plugin-react.generated.d.ts +34 -0
- package/dist/cirrus-plugin-react.generated.d.ts.map +1 -0
- package/dist/cirrus-plugin-react.generated.js +33 -0
- package/dist/constants.d.ts +34 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +116 -0
- package/dist/esbuild-wasm-bundle.generated.d.ts +41 -0
- package/dist/esbuild-wasm-bundle.generated.d.ts.map +1 -0
- package/dist/esbuild-wasm-bundle.generated.js +40 -0
- package/dist/facets/cirrus-real.d.ts +147 -0
- package/dist/facets/cirrus-real.d.ts.map +1 -0
- package/dist/facets/cirrus-real.js +981 -0
- package/dist/facets/inner-do-registry.d.ts +41 -0
- package/dist/facets/inner-do-registry.d.ts.map +1 -0
- package/dist/facets/inner-do-registry.js +51 -0
- package/dist/facets/manager.d.ts +314 -0
- package/dist/facets/manager.d.ts.map +1 -0
- package/dist/facets/manager.js +2681 -0
- package/dist/facets/process.d.ts +318 -0
- package/dist/facets/process.d.ts.map +1 -0
- package/dist/facets/process.js +567 -0
- package/dist/facets/real-vite-fs-shim.d.ts +151 -0
- package/dist/facets/real-vite-fs-shim.d.ts.map +1 -0
- package/dist/facets/real-vite-fs-shim.js +1279 -0
- package/dist/facets/real-vite-hmr.d.ts +142 -0
- package/dist/facets/real-vite-hmr.d.ts.map +1 -0
- package/dist/facets/real-vite-hmr.js +476 -0
- package/dist/facets/vite-dev-server.d.ts +293 -0
- package/dist/facets/vite-dev-server.d.ts.map +1 -0
- package/dist/facets/vite-dev-server.js +2580 -0
- package/dist/facets/wasm-swap-registry.d.ts +261 -0
- package/dist/facets/wasm-swap-registry.d.ts.map +1 -0
- package/dist/facets/wasm-swap-registry.js +551 -0
- package/dist/facets/ws-terminal.d.ts +107 -0
- package/dist/facets/ws-terminal.d.ts.map +1 -0
- package/dist/facets/ws-terminal.js +207 -0
- package/dist/git/commands.d.ts +13 -0
- package/dist/git/commands.d.ts.map +1 -0
- package/dist/git/commands.js +633 -0
- package/dist/git/network-facet.d.ts +61 -0
- package/dist/git/network-facet.d.ts.map +1 -0
- package/dist/git/network-facet.js +700 -0
- package/dist/git-bundle.generated.d.ts +16 -0
- package/dist/git-bundle.generated.d.ts.map +1 -0
- package/dist/git-bundle.generated.js +15 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/loaders/child-process/spawn-facet.d.ts +90 -0
- package/dist/loaders/child-process/spawn-facet.d.ts.map +1 -0
- package/dist/loaders/child-process/spawn-facet.js +103 -0
- package/dist/loaders/child-process/spawn-pool.d.ts +110 -0
- package/dist/loaders/child-process/spawn-pool.d.ts.map +1 -0
- package/dist/loaders/child-process/spawn-pool.js +161 -0
- package/dist/loaders/fanout-pool.d.ts +195 -0
- package/dist/loaders/fanout-pool.d.ts.map +1 -0
- package/dist/loaders/fanout-pool.js +326 -0
- package/dist/loaders/generated-workers.d.ts +26 -0
- package/dist/loaders/generated-workers.d.ts.map +1 -0
- package/dist/loaders/generated-workers.js +25 -0
- package/dist/loaders/index.d.ts +15 -0
- package/dist/loaders/index.d.ts.map +1 -0
- package/dist/loaders/index.js +13 -0
- package/dist/loaders/loader-pool.d.ts +273 -0
- package/dist/loaders/loader-pool.d.ts.map +1 -0
- package/dist/loaders/loader-pool.js +624 -0
- package/dist/loaders/npm-resolve-preamble.d.ts +34 -0
- package/dist/loaders/npm-resolve-preamble.d.ts.map +1 -0
- package/dist/loaders/npm-resolve-preamble.js +237 -0
- package/dist/loaders/pre-bundle-preamble.d.ts +41 -0
- package/dist/loaders/pre-bundle-preamble.d.ts.map +1 -0
- package/dist/loaders/pre-bundle-preamble.js +114 -0
- package/dist/loaders/vendor/codegen.d.ts +24 -0
- package/dist/loaders/vendor/codegen.d.ts.map +1 -0
- package/dist/loaders/vendor/codegen.js +44 -0
- package/dist/loaders/vendor/errors.d.ts +24 -0
- package/dist/loaders/vendor/errors.d.ts.map +1 -0
- package/dist/loaders/vendor/errors.js +46 -0
- package/dist/loaders/vendor/index.d.ts +16 -0
- package/dist/loaders/vendor/index.d.ts.map +1 -0
- package/dist/loaders/vendor/index.js +11 -0
- package/dist/loaders/vendor/pool.d.ts +88 -0
- package/dist/loaders/vendor/pool.d.ts.map +1 -0
- package/dist/loaders/vendor/pool.js +353 -0
- package/dist/loaders/vendor/primitives.d.ts +11 -0
- package/dist/loaders/vendor/primitives.d.ts.map +1 -0
- package/dist/loaders/vendor/primitives.js +33 -0
- package/dist/loaders/vendor/serialize.d.ts +3 -0
- package/dist/loaders/vendor/serialize.d.ts.map +1 -0
- package/dist/loaders/vendor/serialize.js +25 -0
- package/dist/loaders/vendor/types.d.ts +60 -0
- package/dist/loaders/vendor/types.d.ts.map +1 -0
- package/dist/loaders/vendor/types.js +4 -0
- package/dist/npm/cache.d.ts +136 -0
- package/dist/npm/cache.d.ts.map +1 -0
- package/dist/npm/cache.js +429 -0
- package/dist/npm/install-batch-facet.d.ts +129 -0
- package/dist/npm/install-batch-facet.d.ts.map +1 -0
- package/dist/npm/install-batch-facet.js +598 -0
- package/dist/npm/install-facet.d.ts +29 -0
- package/dist/npm/install-facet.d.ts.map +1 -0
- package/dist/npm/install-facet.js +9 -0
- package/dist/npm/installer.d.ts +239 -0
- package/dist/npm/installer.d.ts.map +1 -0
- package/dist/npm/installer.js +2022 -0
- package/dist/npm/npx-install.d.ts +74 -0
- package/dist/npm/npx-install.d.ts.map +1 -0
- package/dist/npm/npx-install.js +302 -0
- package/dist/npm/pre-bundle-facet.d.ts +168 -0
- package/dist/npm/pre-bundle-facet.d.ts.map +1 -0
- package/dist/npm/pre-bundle-facet.js +653 -0
- package/dist/npm/r2-cache.d.ts +286 -0
- package/dist/npm/r2-cache.d.ts.map +1 -0
- package/dist/npm/r2-cache.js +506 -0
- package/dist/npm/resolve-facet.d.ts +202 -0
- package/dist/npm/resolve-facet.d.ts.map +1 -0
- package/dist/npm/resolve-facet.js +833 -0
- package/dist/npm/resolve-one-facet.d.ts +204 -0
- package/dist/npm/resolve-one-facet.d.ts.map +1 -0
- package/dist/npm/resolve-one-facet.js +437 -0
- package/dist/npm/resolver.d.ts +109 -0
- package/dist/npm/resolver.d.ts.map +1 -0
- package/dist/npm/resolver.js +899 -0
- package/dist/npm/tarball-stream.d.ts +85 -0
- package/dist/npm/tarball-stream.d.ts.map +1 -0
- package/dist/npm/tarball-stream.js +205 -0
- package/dist/npm/tarball.d.ts +51 -0
- package/dist/npm/tarball.d.ts.map +1 -0
- package/dist/npm/tarball.js +185 -0
- package/dist/observability/diag-counters.d.ts +292 -0
- package/dist/observability/diag-counters.d.ts.map +1 -0
- package/dist/observability/diag-counters.js +302 -0
- package/dist/observability/heap-estimate.d.ts +166 -0
- package/dist/observability/heap-estimate.d.ts.map +1 -0
- package/dist/observability/heap-estimate.js +192 -0
- package/dist/observability/heavy-alloc-coord.d.ts +95 -0
- package/dist/observability/heavy-alloc-coord.d.ts.map +1 -0
- package/dist/observability/heavy-alloc-coord.js +149 -0
- package/dist/observability/oom-classify.d.ts +56 -0
- package/dist/observability/oom-classify.d.ts.map +1 -0
- package/dist/observability/oom-classify.js +118 -0
- package/dist/observability/oom-discriminator.d.ts +192 -0
- package/dist/observability/oom-discriminator.d.ts.map +1 -0
- package/dist/observability/oom-discriminator.js +233 -0
- package/dist/real-vite-bundle.generated.d.ts +46 -0
- package/dist/real-vite-bundle.generated.d.ts.map +1 -0
- package/dist/real-vite-bundle.generated.js +53 -0
- package/dist/replica/routing.d.ts +171 -0
- package/dist/replica/routing.d.ts.map +1 -0
- package/dist/replica/routing.js +288 -0
- package/dist/replica/suspension.d.ts +36 -0
- package/dist/replica/suspension.d.ts.map +1 -0
- package/dist/replica/suspension.js +49 -0
- package/dist/router/index.d.ts +156 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +220 -0
- package/dist/runtime/assets-loader.d.ts +71 -0
- package/dist/runtime/assets-loader.d.ts.map +1 -0
- package/dist/runtime/assets-loader.js +128 -0
- package/dist/runtime/barrel-detect.d.ts +46 -0
- package/dist/runtime/barrel-detect.d.ts.map +1 -0
- package/dist/runtime/barrel-detect.js +73 -0
- package/dist/runtime/barrel-synthesizer.d.ts +181 -0
- package/dist/runtime/barrel-synthesizer.d.ts.map +1 -0
- package/dist/runtime/barrel-synthesizer.js +541 -0
- package/dist/runtime/bun-repl.d.ts +46 -0
- package/dist/runtime/bun-repl.d.ts.map +1 -0
- package/dist/runtime/bun-repl.js +326 -0
- package/dist/runtime/bun-runner.d.ts +66 -0
- package/dist/runtime/bun-runner.d.ts.map +1 -0
- package/dist/runtime/bun-runner.js +219 -0
- package/dist/runtime/clang-runner.d.ts +38 -0
- package/dist/runtime/clang-runner.d.ts.map +1 -0
- package/dist/runtime/clang-runner.js +1033 -0
- package/dist/runtime/comment-strip.d.ts +37 -0
- package/dist/runtime/comment-strip.d.ts.map +1 -0
- package/dist/runtime/comment-strip.js +74 -0
- package/dist/runtime/esbuild-service.d.ts +201 -0
- package/dist/runtime/esbuild-service.d.ts.map +1 -0
- package/dist/runtime/esbuild-service.js +1444 -0
- package/dist/runtime/esbuild-wasm-bytes.d.ts +87 -0
- package/dist/runtime/esbuild-wasm-bytes.d.ts.map +1 -0
- package/dist/runtime/esbuild-wasm-bytes.js +131 -0
- package/dist/runtime/framework-detect.d.ts +71 -0
- package/dist/runtime/framework-detect.d.ts.map +1 -0
- package/dist/runtime/framework-detect.js +178 -0
- package/dist/runtime/long-running-handle.d.ts +133 -0
- package/dist/runtime/long-running-handle.d.ts.map +1 -0
- package/dist/runtime/long-running-handle.js +192 -0
- package/dist/runtime/node-repl.d.ts +36 -0
- package/dist/runtime/node-repl.d.ts.map +1 -0
- package/dist/runtime/node-repl.js +293 -0
- package/dist/runtime/node-runner.d.ts +111 -0
- package/dist/runtime/node-runner.d.ts.map +1 -0
- package/dist/runtime/node-runner.js +194 -0
- package/dist/runtime/node-shims.d.ts +24 -0
- package/dist/runtime/node-shims.d.ts.map +1 -0
- package/dist/runtime/node-shims.js +3019 -0
- package/dist/runtime/package-manager.d.ts +118 -0
- package/dist/runtime/package-manager.d.ts.map +1 -0
- package/dist/runtime/package-manager.js +420 -0
- package/dist/runtime/port-registry.d.ts +80 -0
- package/dist/runtime/port-registry.d.ts.map +1 -0
- package/dist/runtime/port-registry.js +166 -0
- package/dist/runtime/process-logs-api.d.ts +102 -0
- package/dist/runtime/process-logs-api.d.ts.map +1 -0
- package/dist/runtime/process-logs-api.js +253 -0
- package/dist/runtime/process-logs.d.ts +311 -0
- package/dist/runtime/process-logs.d.ts.map +1 -0
- package/dist/runtime/process-logs.js +656 -0
- package/dist/runtime/process-table.d.ts +65 -0
- package/dist/runtime/process-table.d.ts.map +1 -0
- package/dist/runtime/process-table.js +107 -0
- package/dist/runtime/project-detect.d.ts +21 -0
- package/dist/runtime/project-detect.d.ts.map +1 -0
- package/dist/runtime/project-detect.js +46 -0
- package/dist/runtime/python-repl.d.ts +66 -0
- package/dist/runtime/python-repl.d.ts.map +1 -0
- package/dist/runtime/python-repl.js +563 -0
- package/dist/runtime/python-runner.d.ts +50 -0
- package/dist/runtime/python-runner.d.ts.map +1 -0
- package/dist/runtime/python-runner.js +870 -0
- package/dist/runtime/repl-session.d.ts +160 -0
- package/dist/runtime/repl-session.d.ts.map +1 -0
- package/dist/runtime/repl-session.js +393 -0
- package/dist/runtime/require-resolver.d.ts +52 -0
- package/dist/runtime/require-resolver.d.ts.map +1 -0
- package/dist/runtime/require-resolver.js +690 -0
- package/dist/runtime/router-basename.d.ts +36 -0
- package/dist/runtime/router-basename.d.ts.map +1 -0
- package/dist/runtime/router-basename.js +310 -0
- package/dist/runtime/ruby-repl.d.ts +43 -0
- package/dist/runtime/ruby-repl.d.ts.map +1 -0
- package/dist/runtime/ruby-repl.js +229 -0
- package/dist/runtime/ruby-runner.d.ts +62 -0
- package/dist/runtime/ruby-runner.d.ts.map +1 -0
- package/dist/runtime/ruby-runner.js +737 -0
- package/dist/runtime/runtime-catalog.d.ts +99 -0
- package/dist/runtime/runtime-catalog.d.ts.map +1 -0
- package/dist/runtime/runtime-catalog.js +183 -0
- package/dist/runtime/runtime-registry.d.ts +136 -0
- package/dist/runtime/runtime-registry.d.ts.map +1 -0
- package/dist/runtime/runtime-registry.js +318 -0
- package/dist/runtime/streams.d.ts +13 -0
- package/dist/runtime/streams.d.ts.map +1 -0
- package/dist/runtime/streams.js +402 -0
- package/dist/runtime/wasi-instance.d.ts +190 -0
- package/dist/runtime/wasi-instance.d.ts.map +1 -0
- package/dist/runtime/wasi-instance.js +2044 -0
- package/dist/runtime/wasm-runner.d.ts +117 -0
- package/dist/runtime/wasm-runner.d.ts.map +1 -0
- package/dist/runtime/wasm-runner.js +705 -0
- package/dist/session/bindings.d.ts +168 -0
- package/dist/session/bindings.d.ts.map +1 -0
- package/dist/session/bindings.js +524 -0
- package/dist/session/ctx-exports.d.ts +16 -0
- package/dist/session/ctx-exports.d.ts.map +1 -0
- package/dist/session/ctx-exports.js +22 -0
- package/dist/session/diag.d.ts +62 -0
- package/dist/session/diag.d.ts.map +1 -0
- package/dist/session/diag.js +118 -0
- package/dist/session/fs-watch.d.ts +132 -0
- package/dist/session/fs-watch.d.ts.map +1 -0
- package/dist/session/fs-watch.js +255 -0
- package/dist/session/helpers.d.ts +150 -0
- package/dist/session/helpers.d.ts.map +1 -0
- package/dist/session/helpers.js +472 -0
- package/dist/session/hibernation.d.ts +145 -0
- package/dist/session/hibernation.d.ts.map +1 -0
- package/dist/session/hibernation.js +385 -0
- package/dist/session/init-phases.d.ts +87 -0
- package/dist/session/init-phases.d.ts.map +1 -0
- package/dist/session/init-phases.js +137 -0
- package/dist/session/init.d.ts +46 -0
- package/dist/session/init.d.ts.map +1 -0
- package/dist/session/init.js +3579 -0
- package/dist/session/keys.d.ts +56 -0
- package/dist/session/keys.d.ts.map +1 -0
- package/dist/session/keys.js +55 -0
- package/dist/session/nimbus-session.d.ts +434 -0
- package/dist/session/nimbus-session.d.ts.map +1 -0
- package/dist/session/nimbus-session.js +1084 -0
- package/dist/session/programmatic.d.ts +105 -0
- package/dist/session/programmatic.d.ts.map +1 -0
- package/dist/session/programmatic.js +326 -0
- package/dist/session/replica-routes.d.ts +68 -0
- package/dist/session/replica-routes.d.ts.map +1 -0
- package/dist/session/replica-routes.js +77 -0
- package/dist/session/routes.d.ts +29 -0
- package/dist/session/routes.d.ts.map +1 -0
- package/dist/session/routes.js +1331 -0
- package/dist/session/rpc.d.ts +323 -0
- package/dist/session/rpc.d.ts.map +1 -0
- package/dist/session/rpc.js +808 -0
- package/dist/session/state-store.d.ts +210 -0
- package/dist/session/state-store.d.ts.map +1 -0
- package/dist/session/state-store.js +459 -0
- package/dist/session/supervisor-rpc.d.ts +269 -0
- package/dist/session/supervisor-rpc.d.ts.map +1 -0
- package/dist/session/supervisor-rpc.js +437 -0
- package/dist/session/ws-hibernation-config.d.ts +64 -0
- package/dist/session/ws-hibernation-config.d.ts.map +1 -0
- package/dist/session/ws-hibernation-config.js +89 -0
- package/dist/session/ws.d.ts +95 -0
- package/dist/session/ws.d.ts.map +1 -0
- package/dist/session/ws.js +395 -0
- package/dist/shell/features.d.ts +410 -0
- package/dist/shell/features.d.ts.map +1 -0
- package/dist/shell/features.js +1885 -0
- package/dist/shell/unix-commands.d.ts +15 -0
- package/dist/shell/unix-commands.d.ts.map +1 -0
- package/dist/shell/unix-commands.js +3703 -0
- package/dist/stubs/lifo-ui.d.ts +10 -0
- package/dist/stubs/lifo-ui.d.ts.map +1 -0
- package/dist/stubs/lifo-ui.js +1 -0
- package/dist/tailwind-play.generated.d.ts +19 -0
- package/dist/tailwind-play.generated.d.ts.map +1 -0
- package/dist/tailwind-play.generated.js +18 -0
- package/dist/vfs/dev-provider.d.ts +64 -0
- package/dist/vfs/dev-provider.d.ts.map +1 -0
- package/dist/vfs/dev-provider.js +191 -0
- package/dist/vfs/events.d.ts +51 -0
- package/dist/vfs/events.d.ts.map +1 -0
- package/dist/vfs/events.js +127 -0
- package/dist/vfs/path.d.ts +30 -0
- package/dist/vfs/path.d.ts.map +1 -0
- package/dist/vfs/path.js +41 -0
- package/dist/vfs/seed-project.d.ts +62 -0
- package/dist/vfs/seed-project.d.ts.map +1 -0
- package/dist/vfs/seed-project.js +1045 -0
- package/dist/vfs/sqlite-vfs.d.ts +435 -0
- package/dist/vfs/sqlite-vfs.d.ts.map +1 -0
- package/dist/vfs/sqlite-vfs.js +1670 -0
- package/dist/vfs/symlink-registry.d.ts +64 -0
- package/dist/vfs/symlink-registry.d.ts.map +1 -0
- package/dist/vfs/symlink-registry.js +137 -0
- package/dist/wrangler/nimbus-wrangler.d.ts +157 -0
- package/dist/wrangler/nimbus-wrangler.d.ts.map +1 -0
- package/dist/wrangler/nimbus-wrangler.js +931 -0
- package/package.json +77 -0
- package/public/_assets/cirrus-plugin-react.bundle.js +70740 -0
- package/public/_assets/esbuild-0.24.2.wasm +0 -0
- package/public/_assets/real-vite-bundle.js +101478 -0
- package/public/_assets/rollup.wasm +0 -0
- package/public/favicon.svg +8 -0
- package/public/index.html +565 -0
- package/public/s/index.html +2379 -0
- package/scripts/bundle-esbuild-wasm.mjs +244 -0
- package/scripts/bundle-facet-workers.mjs +137 -0
- package/scripts/bundle-git.mjs +118 -0
- package/scripts/bundle-npm-cjs.mjs +363 -0
- package/scripts/bundle-plugin-react.mjs +480 -0
- package/scripts/bundle-real-vite.mjs +959 -0
- package/scripts/bundle-runtime.mjs +600 -0
- package/scripts/bundle-tailwind-play.mjs +130 -0
- package/scripts/patch-lifo-ui.mjs +131 -0
|
@@ -0,0 +1,3019 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* node-shims.ts — Nimbus v2.0 Node.js runtime shims for dynamic workers.
|
|
3
|
+
*
|
|
4
|
+
* Generates a raw JS string embedded in facet code. Provides:
|
|
5
|
+
* - fs: full sync/async/promises/streams VFS-backed filesystem
|
|
6
|
+
* - path: complete POSIX path operations
|
|
7
|
+
* - os/process: Linux edge environment simulation
|
|
8
|
+
* - Buffer: Uint8Array wrapper with encoding support
|
|
9
|
+
* - events: full EventEmitter
|
|
10
|
+
* - stream: real Readable/Writable/Transform/Duplex with backpressure
|
|
11
|
+
* - crypto: createHash (FNV-1a sync, SubtleCrypto async), randomBytes/UUID
|
|
12
|
+
* - zlib: real gzip/gunzip/deflate via CompressionStream/DecompressionStream
|
|
13
|
+
* - dns: real DNS resolution via Cloudflare DNS-over-HTTPS
|
|
14
|
+
* - http: virtual server with port registry for supervisor routing
|
|
15
|
+
* - https: fetch()-backed request/get
|
|
16
|
+
* - net: Socket/Server with connect/write/end
|
|
17
|
+
* - child_process: ChildProcess objects (execution requires supervisor RPC)
|
|
18
|
+
* - assert, util, url, querystring, string_decoder, readline, tty, timers
|
|
19
|
+
*
|
|
20
|
+
* VFS access: reads from __vfsBundle (pre-bundled by FacetManager),
|
|
21
|
+
* writes to __vfsWrites (flushed back to VFS on completion).
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Generate the shared shim block that goes inside both the DO-facet and
|
|
25
|
+
* entrypoint runner code. The returned string is raw JS (no wrapping).
|
|
26
|
+
*
|
|
27
|
+
* At runtime the following variables must exist in scope:
|
|
28
|
+
* - __vfsBundle: Record<string, string> (path→utf8 content)
|
|
29
|
+
* - __vfsWrites: Record<string, string> (written files, returned in result)
|
|
30
|
+
* - __vfsDirs: Record<string, boolean> (dirs created)
|
|
31
|
+
* - __vfsBaseUrl: string (supervisor URL for lazy VFS reads)
|
|
32
|
+
* - cwd: string
|
|
33
|
+
* - argv, env, filename, dirname: from args
|
|
34
|
+
* - stdout, stderr, exitCode: capture variables
|
|
35
|
+
*/
|
|
36
|
+
import { generateStreamsCode } from './streams.js';
|
|
37
|
+
import { getExportsResolverJS } from '../_shared/exports-resolver.js';
|
|
38
|
+
import { NODE_VERSION, NODE_VERSIONS } from '../constants.js';
|
|
39
|
+
const STREAMS_CODE = generateStreamsCode();
|
|
40
|
+
const EXPORTS_RESOLVER_JS = getExportsResolverJS();
|
|
41
|
+
// Node version fingerprint. Single source of truth in constants.ts.
|
|
42
|
+
// Interpolated as JS literals into the emitted process shim. See
|
|
43
|
+
// constants.ts for the rationale (create-astro preflight, etc.).
|
|
44
|
+
const NODE_VERSION_LITERAL = JSON.stringify(NODE_VERSION);
|
|
45
|
+
const NODE_VERSIONS_LITERAL = JSON.stringify(NODE_VERSIONS);
|
|
46
|
+
export function generateShimsCode() {
|
|
47
|
+
return `
|
|
48
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
49
|
+
// ── Format helper ──────────────────────────────────────────────────
|
|
50
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
51
|
+
function __fmt(v) {
|
|
52
|
+
if (v === null) return "null";
|
|
53
|
+
if (v === undefined) return "undefined";
|
|
54
|
+
if (typeof v === "object") {
|
|
55
|
+
try { return JSON.stringify(v); } catch { return String(v); }
|
|
56
|
+
}
|
|
57
|
+
return String(v);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
61
|
+
// ── path module ────────────────────────────────────────────────────
|
|
62
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
63
|
+
const __pathMod = (() => {
|
|
64
|
+
function normalize(p) {
|
|
65
|
+
const parts = p.split("/");
|
|
66
|
+
const out = [];
|
|
67
|
+
for (const s of parts) {
|
|
68
|
+
if (s === "..") { if (out.length && out[out.length-1] !== "..") out.pop(); else out.push(s); }
|
|
69
|
+
else if (s !== "." && s !== "") out.push(s);
|
|
70
|
+
}
|
|
71
|
+
return (p.startsWith("/") ? "/" : "") + out.join("/");
|
|
72
|
+
}
|
|
73
|
+
function join(...p) { return normalize(p.join("/")); }
|
|
74
|
+
function resolve(...p) {
|
|
75
|
+
let r = "";
|
|
76
|
+
for (let i = p.length - 1; i >= 0; i--) {
|
|
77
|
+
r = p[i] + (r ? "/" + r : "");
|
|
78
|
+
if (r.startsWith("/")) break;
|
|
79
|
+
}
|
|
80
|
+
if (!r.startsWith("/")) r = (cwd || "/home/user") + "/" + r;
|
|
81
|
+
return normalize(r);
|
|
82
|
+
}
|
|
83
|
+
function dirname(p) { const i = p.lastIndexOf("/"); return i > 0 ? p.substring(0, i) : i === 0 ? "/" : "."; }
|
|
84
|
+
function basename(p, ext) { const b = p.split("/").pop() || ""; return ext && b.endsWith(ext) ? b.slice(0, -ext.length) : b; }
|
|
85
|
+
function extname(p) { const b = basename(p); const i = b.lastIndexOf("."); return i > 0 ? b.substring(i) : ""; }
|
|
86
|
+
function isAbsolute(p) { return p.startsWith("/"); }
|
|
87
|
+
function relative(from, to) {
|
|
88
|
+
const f = resolve(from).split("/").filter(Boolean);
|
|
89
|
+
const t = resolve(to).split("/").filter(Boolean);
|
|
90
|
+
let c = 0;
|
|
91
|
+
while (c < f.length && c < t.length && f[c] === t[c]) c++;
|
|
92
|
+
return [...Array(f.length - c).fill(".."), ...t.slice(c)].join("/") || ".";
|
|
93
|
+
}
|
|
94
|
+
return { join, resolve, dirname, basename, extname, normalize, isAbsolute, relative, sep: "/", delimiter: ":", posix: null, win32: null };
|
|
95
|
+
})();
|
|
96
|
+
__pathMod.posix = __pathMod;
|
|
97
|
+
// X.5-Z5 §3 follow-on: enhanced-resolve (transitive via @tailwindcss/vite
|
|
98
|
+
// → vite → enhanced-resolve) reads path.win32.normalize / .dirname at
|
|
99
|
+
// import time. We have no real win32 paths in workerd's VFS, so the
|
|
100
|
+
// posix implementation is functionally correct for any path content the
|
|
101
|
+
// workers will ever see. Aliasing posix to win32 satisfies the structural
|
|
102
|
+
// contract without spawning a separate code path. See
|
|
103
|
+
// audit/sections/X5Z5-build-retro.md §3.
|
|
104
|
+
__pathMod.win32 = __pathMod;
|
|
105
|
+
|
|
106
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
107
|
+
// ── Buffer shim ────────────────────────────────────────────────────
|
|
108
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
109
|
+
const __BufferMod = (() => {
|
|
110
|
+
const _enc = new TextEncoder();
|
|
111
|
+
const _dec = new TextDecoder();
|
|
112
|
+
|
|
113
|
+
function from(d, encoding) {
|
|
114
|
+
if (typeof d === "string") {
|
|
115
|
+
if (encoding === "base64") {
|
|
116
|
+
const bin = atob(d); const a = new Uint8Array(bin.length);
|
|
117
|
+
for (let i = 0; i < bin.length; i++) a[i] = bin.charCodeAt(i);
|
|
118
|
+
return _wrap(a);
|
|
119
|
+
}
|
|
120
|
+
if (encoding === "hex") {
|
|
121
|
+
const a = new Uint8Array(d.length / 2);
|
|
122
|
+
for (let i = 0; i < a.length; i++) a[i] = parseInt(d.substr(i*2, 2), 16);
|
|
123
|
+
return _wrap(a);
|
|
124
|
+
}
|
|
125
|
+
return _wrap(_enc.encode(d));
|
|
126
|
+
}
|
|
127
|
+
if (d instanceof Uint8Array) return _wrap(new Uint8Array(d));
|
|
128
|
+
if (d instanceof ArrayBuffer) return _wrap(new Uint8Array(d));
|
|
129
|
+
if (Array.isArray(d)) return _wrap(new Uint8Array(d));
|
|
130
|
+
return _wrap(new Uint8Array(0));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function alloc(n, fill) { const a = new Uint8Array(n); if (fill !== undefined) a.fill(typeof fill === "number" ? fill : 0); return _wrap(a); }
|
|
134
|
+
function isBuffer(o) { return o instanceof Uint8Array && typeof o.toString === "function" && o.__isBuffer; }
|
|
135
|
+
function concat(bufs, len) {
|
|
136
|
+
const total = len ?? bufs.reduce((s, b) => s + b.length, 0);
|
|
137
|
+
const r = new Uint8Array(total); let off = 0;
|
|
138
|
+
for (const b of bufs) { r.set(b.subarray(0, Math.min(b.length, total - off)), off); off += b.length; if (off >= total) break; }
|
|
139
|
+
return _wrap(r);
|
|
140
|
+
}
|
|
141
|
+
function _wrap(u8) {
|
|
142
|
+
u8.__isBuffer = true;
|
|
143
|
+
u8.toString = function(encoding) {
|
|
144
|
+
if (!encoding || encoding === "utf8" || encoding === "utf-8") return _dec.decode(this);
|
|
145
|
+
if (encoding === "base64") { let s = ""; for (const b of this) s += String.fromCharCode(b); return btoa(s); }
|
|
146
|
+
if (encoding === "hex") { let s = ""; for (const b of this) s += b.toString(16).padStart(2, "0"); return s; }
|
|
147
|
+
return _dec.decode(this);
|
|
148
|
+
};
|
|
149
|
+
u8.write = function(str, off, len, enc) { const b = _enc.encode(str); this.set(b.subarray(0, len || b.length), off || 0); return Math.min(b.length, len || b.length); };
|
|
150
|
+
u8.slice = function(s, e) { return _wrap(this.subarray(s, e)); };
|
|
151
|
+
u8.copy = function(t, tOff, sOff, sEnd) { t.set(this.subarray(sOff || 0, sEnd), tOff || 0); };
|
|
152
|
+
u8.equals = function(o) { if (this.length !== o.length) return false; for (let i = 0; i < this.length; i++) if (this[i] !== o[i]) return false; return true; };
|
|
153
|
+
u8.toJSON = function() { return { type: "Buffer", data: Array.from(this) }; };
|
|
154
|
+
u8.indexOf = function(v) { if (typeof v === "number") return Uint8Array.prototype.indexOf.call(this, v); const b = typeof v === "string" ? _enc.encode(v) : v; outer: for (let i = 0; i <= this.length - b.length; i++) { for (let j = 0; j < b.length; j++) if (this[i+j] !== b[j]) continue outer; return i; } return -1; };
|
|
155
|
+
return u8;
|
|
156
|
+
}
|
|
157
|
+
const B = Object.assign(from, { from, alloc, isBuffer, concat, byteLength: (s, e) => _enc.encode(s).length });
|
|
158
|
+
return B;
|
|
159
|
+
})();
|
|
160
|
+
|
|
161
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
162
|
+
// ── fs shim (VFS-backed) ───────────────────────────────────────────
|
|
163
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
164
|
+
const __fsMod = (() => {
|
|
165
|
+
const _enc = new TextEncoder();
|
|
166
|
+
const _dec = new TextDecoder();
|
|
167
|
+
|
|
168
|
+
// ── byte-shape helpers (binary-fs wave) ──
|
|
169
|
+
// __vfsWrites + __vfsBundle now carry \`Uint8Array | string\`. Strings
|
|
170
|
+
// are the hot path (module source, package.json, user JS); bytes are
|
|
171
|
+
// the binary-fs path (wasm modules, images, binary protocol payloads).
|
|
172
|
+
// Pre-fix the Uint8Array branch UTF-8-decoded the bytes to a string,
|
|
173
|
+
// which mangled every byte ≥ 0x80 to U+FFFD (3-byte EF BF BD on the
|
|
174
|
+
// re-encode), corrupting all binary fs writes. See
|
|
175
|
+
// /workspace/.seal-internal/2026-05-10-binary-fs/.
|
|
176
|
+
function _isBytes(v) { return v instanceof Uint8Array; }
|
|
177
|
+
// Length in bytes regardless of shape — used by statSync's size field
|
|
178
|
+
// and the bundle-cap accounting on the host side.
|
|
179
|
+
function _byteLen(v) {
|
|
180
|
+
if (_isBytes(v)) return v.byteLength;
|
|
181
|
+
if (typeof v === "string") return _enc.encode(v).length;
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
// Coerce to bytes for binary-write paths. Strings are UTF-8-encoded
|
|
185
|
+
// (lossless for valid Unicode); bytes pass through.
|
|
186
|
+
function _asBytes(v) {
|
|
187
|
+
if (_isBytes(v)) return v;
|
|
188
|
+
if (typeof v === "string") return _enc.encode(v);
|
|
189
|
+
return new Uint8Array(0);
|
|
190
|
+
}
|
|
191
|
+
// Coerce to string for text-read paths. Bytes are UTF-8-decoded
|
|
192
|
+
// (lossy for invalid sequences — same caveat as Node's
|
|
193
|
+
// \`Buffer.toString('utf8')\`); strings pass through.
|
|
194
|
+
function _asString(v) {
|
|
195
|
+
if (typeof v === "string") return v;
|
|
196
|
+
if (_isBytes(v)) return _dec.decode(v);
|
|
197
|
+
return "";
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ── helpers ──
|
|
201
|
+
function _strip(p) { return String(p).replace(/^\\/+/, ""); }
|
|
202
|
+
function _resolve(p) {
|
|
203
|
+
// X.5-O: WHATWG-URL → POSIX path coercion. Pre-fix String(p) on
|
|
204
|
+
// a URL instance or 'file://' string produced 'file:///package.json';
|
|
205
|
+
// that failed the startsWith('/') guard below and got misrouted via
|
|
206
|
+
// path.resolve(cwd, 'file:///…') → corrupt path → ENOENT (verify-90993b3
|
|
207
|
+
// §3 bucket O: vite). Strip 'file://' and unwrap URL instances first.
|
|
208
|
+
// See audit/probes/x5npqo/functional/o-fs-url.mjs.
|
|
209
|
+
let s;
|
|
210
|
+
if (p && typeof p === "object" && p.protocol === "file:" && typeof p.pathname === "string") {
|
|
211
|
+
// URL instance — pathname is already a POSIX path with leading /
|
|
212
|
+
try { s = decodeURIComponent(p.pathname); } catch { s = p.pathname; }
|
|
213
|
+
} else {
|
|
214
|
+
s = String(p);
|
|
215
|
+
if (s.startsWith("file://")) {
|
|
216
|
+
// 'file:///abs' → '/abs', 'file://host/abs' → '/abs'
|
|
217
|
+
const tail = s.slice(7);
|
|
218
|
+
const slashIdx = tail.indexOf("/");
|
|
219
|
+
const pathPart = tail.startsWith("/") ? tail : (slashIdx >= 0 ? tail.slice(slashIdx) : "/" + tail);
|
|
220
|
+
try { s = decodeURIComponent(pathPart); } catch { s = pathPart; }
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (s.startsWith("/")) return __pathMod.normalize(s);
|
|
224
|
+
return __pathMod.resolve(cwd || "/home/user", s);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ── VFS bundle lookup (fast path — in-memory) ──
|
|
228
|
+
function _bundleLookup(absPath) {
|
|
229
|
+
const k = _strip(absPath);
|
|
230
|
+
if (__vfsBundle && k in __vfsBundle) return __vfsBundle[k];
|
|
231
|
+
// Also check writes
|
|
232
|
+
if (__vfsWrites && k in __vfsWrites) return __vfsWrites[k];
|
|
233
|
+
return undefined;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// ── readFileSync ──
|
|
237
|
+
// Returns a Buffer when no encoding requested, a string otherwise.
|
|
238
|
+
// The cell shape (string vs Uint8Array) drives conversion:
|
|
239
|
+
// - text encoding requested + string cell → return string as-is
|
|
240
|
+
// - text encoding requested + bytes cell → UTF-8 decode bytes
|
|
241
|
+
// - no encoding + string cell → wrap _enc.encode(...) as Buffer
|
|
242
|
+
// - no encoding + bytes cell → wrap bytes as Buffer (no copy)
|
|
243
|
+
function readFileSync(p, opts) {
|
|
244
|
+
const absPath = _resolve(p);
|
|
245
|
+
const content = _bundleLookup(absPath);
|
|
246
|
+
if (content === undefined) {
|
|
247
|
+
const err = new Error("ENOENT: no such file or directory, open '" + p + "'");
|
|
248
|
+
err.code = "ENOENT";
|
|
249
|
+
err.errno = -2;
|
|
250
|
+
throw err;
|
|
251
|
+
}
|
|
252
|
+
const encoding = typeof opts === "string" ? opts : opts?.encoding;
|
|
253
|
+
if (encoding) {
|
|
254
|
+
// text encoding requested — produce a string regardless of cell shape.
|
|
255
|
+
return _asString(content);
|
|
256
|
+
}
|
|
257
|
+
// No encoding requested — produce a Buffer-shaped Uint8Array.
|
|
258
|
+
if (_isBytes(content)) return __BufferMod.from(content);
|
|
259
|
+
return __BufferMod.from(content);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// ── writeFileSync ──
|
|
263
|
+
// Uint8Array is preserved as bytes (no UTF-8 round-trip → no
|
|
264
|
+
// EF-BF-BD mangling on bytes ≥ 0x80). String is preserved as string
|
|
265
|
+
// (the hot path for source code / package.json / user JS).
|
|
266
|
+
// Anything else is stringified (Node's behaviour for e.g. numbers).
|
|
267
|
+
function writeFileSync(p, data, opts) {
|
|
268
|
+
const absPath = _resolve(p);
|
|
269
|
+
const k = _strip(absPath);
|
|
270
|
+
let cell;
|
|
271
|
+
if (data instanceof Uint8Array) cell = data;
|
|
272
|
+
else if (typeof data === "string") cell = data;
|
|
273
|
+
else cell = String(data);
|
|
274
|
+
__vfsWrites[k] = cell;
|
|
275
|
+
// Also update bundle so subsequent reads see the write
|
|
276
|
+
if (__vfsBundle) __vfsBundle[k] = cell;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// ── appendFileSync ──
|
|
280
|
+
// Concat semantics: if EITHER existing or new data is bytes, the
|
|
281
|
+
// combined cell is bytes (lossless for both). When both are strings,
|
|
282
|
+
// stay string (avoids re-encoding ASCII through TextEncoder).
|
|
283
|
+
function appendFileSync(p, data, opts) {
|
|
284
|
+
const absPath = _resolve(p);
|
|
285
|
+
const k = _strip(absPath);
|
|
286
|
+
const existing = _bundleLookup(absPath);
|
|
287
|
+
const existingDefined = existing !== undefined;
|
|
288
|
+
const dataIsBytes = data instanceof Uint8Array;
|
|
289
|
+
const existingIsBytes = existingDefined && _isBytes(existing);
|
|
290
|
+
|
|
291
|
+
let cell;
|
|
292
|
+
if (!existingDefined) {
|
|
293
|
+
// No prior content — same shape as a writeFileSync.
|
|
294
|
+
if (dataIsBytes) cell = data;
|
|
295
|
+
else if (typeof data === "string") cell = data;
|
|
296
|
+
else cell = String(data);
|
|
297
|
+
} else if (dataIsBytes || existingIsBytes) {
|
|
298
|
+
// Promote both to bytes and concat.
|
|
299
|
+
const a = _asBytes(existing);
|
|
300
|
+
const b = _asBytes(dataIsBytes ? data : (typeof data === "string" ? data : String(data)));
|
|
301
|
+
const out = new Uint8Array(a.byteLength + b.byteLength);
|
|
302
|
+
out.set(a, 0);
|
|
303
|
+
out.set(b, a.byteLength);
|
|
304
|
+
cell = out;
|
|
305
|
+
} else {
|
|
306
|
+
// Both strings — string concat.
|
|
307
|
+
cell = existing + (typeof data === "string" ? data : String(data));
|
|
308
|
+
}
|
|
309
|
+
__vfsWrites[k] = cell;
|
|
310
|
+
if (__vfsBundle) __vfsBundle[k] = cell;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// ── existsSync ──
|
|
314
|
+
function existsSync(p) {
|
|
315
|
+
const absPath = _resolve(p);
|
|
316
|
+
const k = _strip(absPath);
|
|
317
|
+
if (__vfsBundle && k in __vfsBundle) return true;
|
|
318
|
+
if (__vfsWrites && k in __vfsWrites) return true;
|
|
319
|
+
if (__vfsDirs && k in __vfsDirs) return true;
|
|
320
|
+
// W2.5b root-cause fix: consult the manifest BEFORE falling back to
|
|
321
|
+
// the O(N) bundle-prefix scan. The manifest is uncapped and always
|
|
322
|
+
// reflects the real directory shape, even when the file content for
|
|
323
|
+
// a directory's contents was excluded by the 4 MiB / 500-file content
|
|
324
|
+
// bundle cap. (facet-manager.ts:453, audit/sections/W2.5-rootcause.md)
|
|
325
|
+
if (__vfsManifest) {
|
|
326
|
+
if (k in __vfsManifest) return true;
|
|
327
|
+
// Path may be a file listed by its parent's manifest entry.
|
|
328
|
+
const slash = k.lastIndexOf("/");
|
|
329
|
+
const parent = slash >= 0 ? k.slice(0, slash) : "";
|
|
330
|
+
const name = slash >= 0 ? k.slice(slash + 1) : k;
|
|
331
|
+
const sib = __vfsManifest[parent];
|
|
332
|
+
if (sib && sib.indexOf(name) !== -1) return true;
|
|
333
|
+
}
|
|
334
|
+
// Last-resort: bundle dir entries
|
|
335
|
+
if (__vfsBundle) {
|
|
336
|
+
const prefix = k + "/";
|
|
337
|
+
for (const bk in __vfsBundle) { if (bk.startsWith(prefix) || bk === k) return true; }
|
|
338
|
+
}
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// ── statSync ──
|
|
343
|
+
function statSync(p) {
|
|
344
|
+
const absPath = _resolve(p);
|
|
345
|
+
const k = _strip(absPath);
|
|
346
|
+
// Check if it's a known directory written this exec session
|
|
347
|
+
if (__vfsDirs && k in __vfsDirs) {
|
|
348
|
+
return { isFile: () => false, isDirectory: () => true, isSymbolicLink: () => false, size: 0, mtime: new Date(), mode: 0o755 };
|
|
349
|
+
}
|
|
350
|
+
// W2.5b: consult uncapped manifest first for directory shape.
|
|
351
|
+
if (__vfsManifest && k in __vfsManifest) {
|
|
352
|
+
return { isFile: () => false, isDirectory: () => true, isSymbolicLink: () => false, size: 0, mtime: new Date(), mode: 0o755 };
|
|
353
|
+
}
|
|
354
|
+
// File with content embedded?
|
|
355
|
+
const content = _bundleLookup(absPath);
|
|
356
|
+
if (content !== undefined) {
|
|
357
|
+
// _byteLen handles both string (UTF-8 encode) and Uint8Array
|
|
358
|
+
// (byteLength) — fixes binary writes from reporting the
|
|
359
|
+
// post-corruption byte count.
|
|
360
|
+
const size = _byteLen(content);
|
|
361
|
+
return { isFile: () => true, isDirectory: () => false, isSymbolicLink: () => false, size, mtime: new Date(), mode: 0o644 };
|
|
362
|
+
}
|
|
363
|
+
// File listed in parent's manifest but content was capped out — return
|
|
364
|
+
// a zero-size file stat so callers like fs.stat / fs.statSync see the
|
|
365
|
+
// file as present (downstream readFileSync will surface ENOENT if it
|
|
366
|
+
// actually tries to read content; many consumers only need stat).
|
|
367
|
+
if (__vfsManifest) {
|
|
368
|
+
const slash = k.lastIndexOf("/");
|
|
369
|
+
const parent = slash >= 0 ? k.slice(0, slash) : "";
|
|
370
|
+
const name = slash >= 0 ? k.slice(slash + 1) : k;
|
|
371
|
+
const sib = __vfsManifest[parent];
|
|
372
|
+
if (sib && sib.indexOf(name) !== -1) {
|
|
373
|
+
return { isFile: () => true, isDirectory: () => false, isSymbolicLink: () => false, size: 0, mtime: new Date(), mode: 0o644 };
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
// Last-resort: bundle prefix scan (legacy path).
|
|
377
|
+
if (__vfsBundle) {
|
|
378
|
+
const prefix = k + "/";
|
|
379
|
+
for (const bk in __vfsBundle) {
|
|
380
|
+
if (bk.startsWith(prefix)) {
|
|
381
|
+
return { isFile: () => false, isDirectory: () => true, isSymbolicLink: () => false, size: 0, mtime: new Date(), mode: 0o755 };
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
const err = new Error("ENOENT: no such file or directory, stat '" + p + "'");
|
|
386
|
+
err.code = "ENOENT"; err.errno = -2;
|
|
387
|
+
throw err;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// ── lstatSync (alias for statSync in our VFS — no symlinks) ──
|
|
391
|
+
function lstatSync(p) { return statSync(p); }
|
|
392
|
+
|
|
393
|
+
// ── readdirSync ──
|
|
394
|
+
// W2.5b root-cause fix: prefer the uncapped __vfsManifest for directory
|
|
395
|
+
// listings. The legacy bundle-prefix scan is kept as a fallback for paths
|
|
396
|
+
// not in the manifest (e.g. dirs created at exec time via mkdirSync) and
|
|
397
|
+
// is unioned with __vfsWrites so newly-written files become visible.
|
|
398
|
+
// (facet-manager.ts:453, audit/sections/W2.5-rootcause.md)
|
|
399
|
+
function readdirSync(p, opts) {
|
|
400
|
+
const absPath = _resolve(p);
|
|
401
|
+
const k = _strip(absPath);
|
|
402
|
+
const prefix = k ? k + "/" : "";
|
|
403
|
+
const names = new Set();
|
|
404
|
+
// 1. Manifest-supplied children (the authoritative source for installed pkgs).
|
|
405
|
+
if (__vfsManifest && k in __vfsManifest) {
|
|
406
|
+
for (const n of __vfsManifest[k]) names.add(n);
|
|
407
|
+
}
|
|
408
|
+
// 2. Bundle-prefix fallback (covers older paths or runtime-mkdir'd ones
|
|
409
|
+
// that aren't in the manifest yet).
|
|
410
|
+
if (__vfsBundle) {
|
|
411
|
+
for (const bk in __vfsBundle) {
|
|
412
|
+
if (bk.startsWith(prefix)) {
|
|
413
|
+
const rest = bk.substring(prefix.length);
|
|
414
|
+
const seg = rest.split("/")[0];
|
|
415
|
+
if (seg) names.add(seg);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
// 3. Files written during this exec session.
|
|
420
|
+
if (__vfsWrites) {
|
|
421
|
+
for (const wk in __vfsWrites) {
|
|
422
|
+
if (wk.startsWith(prefix)) {
|
|
423
|
+
const rest = wk.substring(prefix.length);
|
|
424
|
+
const seg = rest.split("/")[0];
|
|
425
|
+
if (seg) names.add(seg);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
// 4. Dirs created during this exec session.
|
|
430
|
+
if (__vfsDirs) {
|
|
431
|
+
for (const dk in __vfsDirs) {
|
|
432
|
+
if (dk.startsWith(prefix)) {
|
|
433
|
+
const rest = dk.substring(prefix.length);
|
|
434
|
+
const seg = rest.split("/")[0];
|
|
435
|
+
if (seg) names.add(seg);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
const arr = [...names].sort();
|
|
440
|
+
if (opts?.withFileTypes) {
|
|
441
|
+
return arr.map(n => {
|
|
442
|
+
const fp = prefix + n;
|
|
443
|
+
// Manifest is the definitive isDir source; fall back to bundle scan.
|
|
444
|
+
const isDir =
|
|
445
|
+
(!!__vfsManifest && fp in __vfsManifest) ||
|
|
446
|
+
(!!__vfsDirs && fp in __vfsDirs) ||
|
|
447
|
+
(!!__vfsBundle && Object.keys(__vfsBundle).some(bk => bk.startsWith(fp + "/")));
|
|
448
|
+
return { name: n, isFile: () => !isDir, isDirectory: () => isDir, isSymbolicLink: () => false };
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
return arr;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// ── mkdirSync ──
|
|
455
|
+
function mkdirSync(p, opts) {
|
|
456
|
+
const absPath = _resolve(p);
|
|
457
|
+
const k = _strip(absPath);
|
|
458
|
+
if (opts?.recursive) {
|
|
459
|
+
const parts = k.split("/").filter(Boolean);
|
|
460
|
+
let cur = "";
|
|
461
|
+
for (const part of parts) { cur = cur ? cur + "/" + part : part; __vfsDirs[cur] = true; }
|
|
462
|
+
} else {
|
|
463
|
+
__vfsDirs[k] = true;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// ── unlinkSync ──
|
|
468
|
+
function unlinkSync(p) {
|
|
469
|
+
const absPath = _resolve(p);
|
|
470
|
+
const k = _strip(absPath);
|
|
471
|
+
if (__vfsBundle) delete __vfsBundle[k];
|
|
472
|
+
if (__vfsWrites) delete __vfsWrites[k];
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// ── rmdirSync ──
|
|
476
|
+
function rmdirSync(p) {
|
|
477
|
+
const absPath = _resolve(p);
|
|
478
|
+
const k = _strip(absPath);
|
|
479
|
+
if (__vfsDirs) delete __vfsDirs[k];
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// ── renameSync ──
|
|
483
|
+
function renameSync(oldP, newP) {
|
|
484
|
+
const oldK = _strip(_resolve(oldP));
|
|
485
|
+
const newK = _strip(_resolve(newP));
|
|
486
|
+
const content = __vfsBundle?.[oldK] ?? __vfsWrites?.[oldK];
|
|
487
|
+
if (content !== undefined) {
|
|
488
|
+
__vfsWrites[newK] = content;
|
|
489
|
+
if (__vfsBundle) { __vfsBundle[newK] = content; delete __vfsBundle[oldK]; }
|
|
490
|
+
if (__vfsWrites) delete __vfsWrites[oldK];
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// ── copyFileSync ──
|
|
495
|
+
function copyFileSync(src, dest) {
|
|
496
|
+
writeFileSync(dest, readFileSync(src, "utf8"));
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// ── realpathSync (X.5-T per X5Z5-plan §4.3 + X526b-retro §3.1) ──
|
|
500
|
+
// VFS has no symlinks; identity-resolve to the absolute path. The
|
|
501
|
+
// .native static is required by TypeScript's getNodeSystem at
|
|
502
|
+
// typescript.js:8291 (see audit/probes/x5t/functional/realpath-native-defined.mjs).
|
|
503
|
+
function realpathSync(p, opts) { return _resolve(String(p)); }
|
|
504
|
+
realpathSync.native = realpathSync;
|
|
505
|
+
|
|
506
|
+
// ── Async variants (thin wrappers returning via callback) ──
|
|
507
|
+
function readFile(p, opts, cb) {
|
|
508
|
+
if (typeof opts === "function") { cb = opts; opts = undefined; }
|
|
509
|
+
try { const r = readFileSync(p, opts); if (cb) cb(null, r); } catch (e) { if (cb) cb(e); }
|
|
510
|
+
}
|
|
511
|
+
function writeFile(p, d, opts, cb) {
|
|
512
|
+
if (typeof opts === "function") { cb = opts; opts = undefined; }
|
|
513
|
+
try { writeFileSync(p, d, opts); if (cb) cb(null); } catch (e) { if (cb) cb(e); }
|
|
514
|
+
}
|
|
515
|
+
function stat(p, cb) { try { cb(null, statSync(p)); } catch (e) { cb(e); } }
|
|
516
|
+
function readdir(p, opts, cb) {
|
|
517
|
+
if (typeof opts === "function") { cb = opts; opts = undefined; }
|
|
518
|
+
try { cb(null, readdirSync(p, opts)); } catch (e) { cb(e); }
|
|
519
|
+
}
|
|
520
|
+
function exists(p, cb) { cb(existsSync(p)); }
|
|
521
|
+
function mkdir(p, opts, cb) {
|
|
522
|
+
if (typeof opts === "function") { cb = opts; opts = undefined; }
|
|
523
|
+
try { mkdirSync(p, opts); if (cb) cb(null); } catch (e) { if (cb) cb(e); }
|
|
524
|
+
}
|
|
525
|
+
function unlink(p, cb) { try { unlinkSync(p); if (cb) cb(null); } catch (e) { if (cb) cb(e); } }
|
|
526
|
+
function access(p, mode, cb) {
|
|
527
|
+
if (typeof mode === "function") { cb = mode; mode = undefined; }
|
|
528
|
+
if (existsSync(p)) cb(null); else { const e = new Error("ENOENT"); e.code = "ENOENT"; cb(e); }
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// ── FileHandle (W3) — returned from fs.promises.open ──
|
|
532
|
+
// VFS-backed minimal impl: read, write, readFile, writeFile, stat,
|
|
533
|
+
// truncate, close, asyncDispose. Sufficient for puppeteer-core,
|
|
534
|
+
// graceful-fs, and most module-level fs.promises.open patterns.
|
|
535
|
+
class __FileHandle {
|
|
536
|
+
constructor(path, flags) { this._path = path; this._flags = flags || 'r'; this._closed = false; this.fd = 0; }
|
|
537
|
+
async read(buffer, offset, length, position) {
|
|
538
|
+
const absPath = _resolve(this._path);
|
|
539
|
+
const data = _bundleLookup(absPath);
|
|
540
|
+
if (data === undefined) {
|
|
541
|
+
const e = new Error("ENOENT: no such file, read '" + this._path + "'");
|
|
542
|
+
e.code = "ENOENT"; throw e;
|
|
543
|
+
}
|
|
544
|
+
// _bundleLookup may return string OR Uint8Array (binary-fs wave).
|
|
545
|
+
const buf = _isBytes(data) ? data : _enc.encode(data);
|
|
546
|
+
const start = position || 0;
|
|
547
|
+
const slice = buf.subarray(start, start + (length || (buf.length - start)));
|
|
548
|
+
buffer.set(slice, offset || 0);
|
|
549
|
+
return { bytesRead: slice.length, buffer };
|
|
550
|
+
}
|
|
551
|
+
async write(buffer, offset, length, position) {
|
|
552
|
+
// binary-fs: keep bytes as bytes through the write. Pre-fix this
|
|
553
|
+
// path UTF-8-decoded the chunk to a string, mangling non-ASCII
|
|
554
|
+
// bytes. Use appendFileSync's polymorphic concat so the existing
|
|
555
|
+
// cell's shape (string vs bytes) drives the merged shape.
|
|
556
|
+
let chunkBytesWritten;
|
|
557
|
+
if (typeof buffer === "string") {
|
|
558
|
+
const o = offset || 0;
|
|
559
|
+
const l = length === undefined ? buffer.length - o : length;
|
|
560
|
+
const sub = buffer.substr(o, l);
|
|
561
|
+
appendFileSync(this._path, sub);
|
|
562
|
+
chunkBytesWritten = _enc.encode(sub).length;
|
|
563
|
+
} else {
|
|
564
|
+
const o = offset || 0;
|
|
565
|
+
const l = length === undefined ? buffer.length - o : length;
|
|
566
|
+
const sub = buffer.subarray(o, o + l);
|
|
567
|
+
appendFileSync(this._path, sub);
|
|
568
|
+
chunkBytesWritten = sub.byteLength;
|
|
569
|
+
}
|
|
570
|
+
return { bytesWritten: chunkBytesWritten, buffer };
|
|
571
|
+
}
|
|
572
|
+
async readFile(opts) { return readFileSync(this._path, opts); }
|
|
573
|
+
async writeFile(data, opts) { writeFileSync(this._path, data, opts); }
|
|
574
|
+
async appendFile(data, opts) { appendFileSync(this._path, data, opts); }
|
|
575
|
+
async stat() { return statSync(this._path); }
|
|
576
|
+
async truncate(len) {
|
|
577
|
+
const cur = readFileSync(this._path, "utf8");
|
|
578
|
+
writeFileSync(this._path, cur.slice(0, len || 0));
|
|
579
|
+
}
|
|
580
|
+
async chmod() {} async chown() {} async utimes() {} async sync() {} async datasync() {}
|
|
581
|
+
async close() { this._closed = true; }
|
|
582
|
+
[Symbol.asyncDispose]() { return this.close(); }
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// ── promises namespace (W3: full surface, VFS-backed) ──
|
|
586
|
+
// We can't forward to workerd's node:fs/promises because that operates
|
|
587
|
+
// on a real-host filesystem, not our VFS. So every method is shim'd
|
|
588
|
+
// against the same underlying readFileSync/writeFileSync/etc.
|
|
589
|
+
const promises = {
|
|
590
|
+
// pre-W3 surface:
|
|
591
|
+
readFile: (p, o) => new Promise((res, rej) => readFile(p, o, (e, d) => e ? rej(e) : res(d))),
|
|
592
|
+
writeFile: (p, d, o) => new Promise((res, rej) => writeFile(p, d, o, (e) => e ? rej(e) : res())),
|
|
593
|
+
stat: (p) => new Promise((res, rej) => stat(p, (e, s) => e ? rej(e) : res(s))),
|
|
594
|
+
readdir: (p, o) => new Promise((res, rej) => readdir(p, o, (e, d) => e ? rej(e) : res(d))),
|
|
595
|
+
mkdir: (p, o) => new Promise((res, rej) => mkdir(p, o, (e) => e ? rej(e) : res())),
|
|
596
|
+
unlink: (p) => new Promise((res, rej) => unlink(p, (e) => e ? rej(e) : res())),
|
|
597
|
+
access: (p, m) => new Promise((res, rej) => access(p, m, (e) => e ? rej(e) : res())),
|
|
598
|
+
|
|
599
|
+
// W3 additions:
|
|
600
|
+
appendFile: async (p, d, o) => { appendFileSync(p, d, o); },
|
|
601
|
+
lstat: (p) => new Promise((res, rej) => stat(p, (e, s) => e ? rej(e) : res(s))),
|
|
602
|
+
rm: async (p, opts) => {
|
|
603
|
+
const o = opts || {};
|
|
604
|
+
const k = _strip(_resolve(p));
|
|
605
|
+
const prefix = k + "/";
|
|
606
|
+
if (o.recursive) {
|
|
607
|
+
if (__vfsBundle) for (const bk of Object.keys(__vfsBundle)) if (bk === k || bk.startsWith(prefix)) delete __vfsBundle[bk];
|
|
608
|
+
if (__vfsWrites) for (const wk of Object.keys(__vfsWrites)) if (wk === k || wk.startsWith(prefix)) delete __vfsWrites[wk];
|
|
609
|
+
if (__vfsDirs) for (const dk of Object.keys(__vfsDirs)) if (dk === k || dk.startsWith(prefix)) delete __vfsDirs[dk];
|
|
610
|
+
} else {
|
|
611
|
+
try { unlinkSync(p); } catch (e) { if (!o.force) throw e; }
|
|
612
|
+
}
|
|
613
|
+
},
|
|
614
|
+
cp: async (src, dest, opts) => {
|
|
615
|
+
const o = opts || {};
|
|
616
|
+
const srcAbs = _resolve(src);
|
|
617
|
+
const srcK = _strip(srcAbs);
|
|
618
|
+
const destK = _strip(_resolve(dest));
|
|
619
|
+
const content = _bundleLookup(srcAbs);
|
|
620
|
+
if (content !== undefined) { writeFileSync(dest, content); return; }
|
|
621
|
+
if (!o.recursive) {
|
|
622
|
+
const err = new Error("EISDIR: cp without recursive on directory: " + src);
|
|
623
|
+
err.code = "EISDIR"; throw err;
|
|
624
|
+
}
|
|
625
|
+
// Recursive: copy every key under srcK/ to destK/
|
|
626
|
+
const prefix = srcK + "/";
|
|
627
|
+
const entries = [];
|
|
628
|
+
if (__vfsBundle) for (const bk in __vfsBundle) if (bk.startsWith(prefix)) entries.push([bk, __vfsBundle[bk]]);
|
|
629
|
+
if (__vfsWrites) for (const wk in __vfsWrites) if (wk.startsWith(prefix)) entries.push([wk, __vfsWrites[wk]]);
|
|
630
|
+
// Ensure destination directory tree
|
|
631
|
+
__vfsDirs[destK] = true;
|
|
632
|
+
for (const [bk, v] of entries) {
|
|
633
|
+
const newK = destK + "/" + bk.slice(prefix.length);
|
|
634
|
+
__vfsWrites[newK] = v;
|
|
635
|
+
if (__vfsBundle) __vfsBundle[newK] = v;
|
|
636
|
+
}
|
|
637
|
+
},
|
|
638
|
+
copyFile: async (src, dest) => { copyFileSync(src, dest); },
|
|
639
|
+
rename: async (oldP, newP) => { renameSync(oldP, newP); },
|
|
640
|
+
rmdir: async (p) => { rmdirSync(p); },
|
|
641
|
+
realpath: async (p) => __pathMod.resolve(String(p)),
|
|
642
|
+
truncate: async (p, len) => {
|
|
643
|
+
const cur = (() => { try { return readFileSync(p, "utf8"); } catch { return ""; } })();
|
|
644
|
+
writeFileSync(p, cur.slice(0, len || 0));
|
|
645
|
+
},
|
|
646
|
+
chmod: async () => {}, chown: async () => {}, lchmod: async () => {}, lchown: async () => {},
|
|
647
|
+
utimes: async () => {}, lutimes: async () => {},
|
|
648
|
+
symlink: async () => {}, link: async () => {},
|
|
649
|
+
readlink: async (p) => String(p),
|
|
650
|
+
mkdtemp: async (prefix) => {
|
|
651
|
+
const name = String(prefix) + Math.random().toString(36).slice(2, 10);
|
|
652
|
+
mkdirSync(name, { recursive: true });
|
|
653
|
+
return name;
|
|
654
|
+
},
|
|
655
|
+
open: async (path, flags, mode) => new __FileHandle(path, flags || 'r'),
|
|
656
|
+
watch: async function* (filename, opts) {
|
|
657
|
+
// Minimal async iter — polls _bundleLookup every 500ms and yields
|
|
658
|
+
// a single \`change\` event when content differs. Adequate for
|
|
659
|
+
// "wait for file to change" patterns; not a complete fsevents.
|
|
660
|
+
const absPath = _resolve(filename);
|
|
661
|
+
let last = _bundleLookup(absPath);
|
|
662
|
+
while (true) {
|
|
663
|
+
await new Promise(r => setTimeout(r, 500));
|
|
664
|
+
const cur = _bundleLookup(absPath);
|
|
665
|
+
if (cur !== last) {
|
|
666
|
+
last = cur;
|
|
667
|
+
yield { eventType: cur === undefined ? 'rename' : 'change', filename: __pathMod.basename(String(filename)) };
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
},
|
|
671
|
+
glob: async function* (pattern, opts) {
|
|
672
|
+
// Minimal — yield matching files via prefix scan. Not full glob.
|
|
673
|
+
// Sufficient for "**/*.js" style patterns; documented limitation.
|
|
674
|
+
const root = (opts && opts.cwd) ? _strip(_resolve(opts.cwd)) : _strip(_resolve('.'));
|
|
675
|
+
const re = (() => {
|
|
676
|
+
// Convert simple glob to regex: ** -> .*, * -> [^/]*, ? -> .
|
|
677
|
+
let r = '^' + (root ? root + '/' : '');
|
|
678
|
+
let g = pattern.replace(/\\\\/g, '/');
|
|
679
|
+
for (let i = 0; i < g.length; i++) {
|
|
680
|
+
const c = g[i];
|
|
681
|
+
if (c === '*') {
|
|
682
|
+
if (g[i+1] === '*') { r += '.*'; i++; if (g[i+1] === '/') i++; }
|
|
683
|
+
else r += '[^/]*';
|
|
684
|
+
} else if (c === '?') r += '.';
|
|
685
|
+
else if (/[.+^$(){}|[\\]\\\\]/.test(c)) r += '\\\\' + c;
|
|
686
|
+
else r += c;
|
|
687
|
+
}
|
|
688
|
+
r += '$';
|
|
689
|
+
return new RegExp(r);
|
|
690
|
+
})();
|
|
691
|
+
const seen = new Set();
|
|
692
|
+
if (__vfsBundle) for (const bk in __vfsBundle) if (re.test(bk)) seen.add(bk);
|
|
693
|
+
if (__vfsWrites) for (const wk in __vfsWrites) if (re.test(wk)) seen.add(wk);
|
|
694
|
+
for (const m of [...seen].sort()) yield '/' + m;
|
|
695
|
+
},
|
|
696
|
+
};
|
|
697
|
+
|
|
698
|
+
// ── constants ──
|
|
699
|
+
const constants = { F_OK: 0, R_OK: 4, W_OK: 2, X_OK: 1 };
|
|
700
|
+
|
|
701
|
+
return {
|
|
702
|
+
readFileSync, writeFileSync, appendFileSync, existsSync, statSync, lstatSync,
|
|
703
|
+
readdirSync, mkdirSync, unlinkSync, rmdirSync, renameSync, copyFileSync,
|
|
704
|
+
realpathSync,
|
|
705
|
+
readFile, writeFile, stat, readdir, exists, mkdir, unlink, access,
|
|
706
|
+
promises, constants,
|
|
707
|
+
createReadStream: (p, opts) => {
|
|
708
|
+
const rs = new __streamMod.Readable({
|
|
709
|
+
read() {
|
|
710
|
+
try {
|
|
711
|
+
const data = readFileSync(p, opts);
|
|
712
|
+
this.push(data);
|
|
713
|
+
this.push(null);
|
|
714
|
+
} catch (e) {
|
|
715
|
+
this.destroy(e);
|
|
716
|
+
}
|
|
717
|
+
},
|
|
718
|
+
});
|
|
719
|
+
return rs;
|
|
720
|
+
},
|
|
721
|
+
createWriteStream: (p, opts) => {
|
|
722
|
+
// binary-fs: chunks may arrive as Uint8Array OR string. Keep
|
|
723
|
+
// each chunk in its native shape; on final, if any chunk is
|
|
724
|
+
// bytes the merged write is bytes; otherwise string-concat
|
|
725
|
+
// (the hot path for ASCII text streams).
|
|
726
|
+
const chunks = [];
|
|
727
|
+
let anyBytes = false;
|
|
728
|
+
const ws = new __streamMod.Writable({
|
|
729
|
+
write(chunk, enc, cb) {
|
|
730
|
+
if (chunk instanceof Uint8Array) { anyBytes = true; chunks.push(chunk); }
|
|
731
|
+
else chunks.push(typeof chunk === "string" ? chunk : String(chunk));
|
|
732
|
+
cb();
|
|
733
|
+
},
|
|
734
|
+
final(cb) {
|
|
735
|
+
if (anyBytes) {
|
|
736
|
+
// Sum byteLength across mixed chunks; concat to one Uint8Array.
|
|
737
|
+
let total = 0;
|
|
738
|
+
for (const c of chunks) total += (c instanceof Uint8Array) ? c.byteLength : _enc.encode(c).length;
|
|
739
|
+
const out = new Uint8Array(total);
|
|
740
|
+
let off = 0;
|
|
741
|
+
for (const c of chunks) {
|
|
742
|
+
const b = (c instanceof Uint8Array) ? c : _enc.encode(c);
|
|
743
|
+
out.set(b, off);
|
|
744
|
+
off += b.byteLength;
|
|
745
|
+
}
|
|
746
|
+
writeFileSync(p, out);
|
|
747
|
+
} else {
|
|
748
|
+
writeFileSync(p, chunks.join(""));
|
|
749
|
+
}
|
|
750
|
+
cb();
|
|
751
|
+
},
|
|
752
|
+
});
|
|
753
|
+
return ws;
|
|
754
|
+
},
|
|
755
|
+
// fs.watch() — returns a watcher object that emits 'change' events.
|
|
756
|
+
// In the facet context, changes to __vfsBundle/Writes are detected
|
|
757
|
+
// via polling since we don't have the supervisor's event emitter.
|
|
758
|
+
// For the supervisor context, real VFS events are wired separately.
|
|
759
|
+
watch: (filename, opts, listener) => {
|
|
760
|
+
if (typeof opts === "function") { listener = opts; opts = {}; }
|
|
761
|
+
const watcher = new __eventsMod();
|
|
762
|
+
watcher.close = () => { watcher._closed = true; watcher.removeAllListeners(); };
|
|
763
|
+
watcher._closed = false;
|
|
764
|
+
if (listener) watcher.on("change", listener);
|
|
765
|
+
// Poll for changes every 500ms (simple but functional)
|
|
766
|
+
const absPath = _resolve(filename);
|
|
767
|
+
const key = _strip(absPath);
|
|
768
|
+
let lastContent = _bundleLookup(absPath);
|
|
769
|
+
const interval = setInterval(() => {
|
|
770
|
+
if (watcher._closed) { clearInterval(interval); return; }
|
|
771
|
+
const current = _bundleLookup(absPath);
|
|
772
|
+
if (current !== lastContent) {
|
|
773
|
+
lastContent = current;
|
|
774
|
+
const eventType = current === undefined ? "rename" : "change";
|
|
775
|
+
watcher.emit("change", eventType, __pathMod.basename(filename));
|
|
776
|
+
}
|
|
777
|
+
}, 500);
|
|
778
|
+
return watcher;
|
|
779
|
+
},
|
|
780
|
+
watchFile: (filename, opts, listener) => {
|
|
781
|
+
if (typeof opts === "function") { listener = opts; opts = {}; }
|
|
782
|
+
// No-op but accept the API
|
|
783
|
+
return { unref: () => {} };
|
|
784
|
+
},
|
|
785
|
+
unwatchFile: () => {},
|
|
786
|
+
};
|
|
787
|
+
})();
|
|
788
|
+
|
|
789
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
790
|
+
// ── constants module (framework-fixes-F1) ───────────────────────────
|
|
791
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
792
|
+
//
|
|
793
|
+
// require('node:constants') (and the legacy bare require('constants'))
|
|
794
|
+
// expose a FLAT object of POSIX/Linux/OpenSSL constants. Real Node ships
|
|
795
|
+
// ~234 constants; we ship the ones that actually get touched by:
|
|
796
|
+
// - create-next-app (touches UV_FS_O_FILEMAP — verified via grep on
|
|
797
|
+
// unpkg.com/create-next-app@latest/dist/index.js)
|
|
798
|
+
// - typical fs.openSync flag composition (O_RDONLY, O_WRONLY, O_RDWR,
|
|
799
|
+
// O_CREAT, O_EXCL, O_TRUNC, O_APPEND, O_DIRECTORY, etc.)
|
|
800
|
+
// - typical fs.access mode composition (F_OK, R_OK, W_OK, X_OK)
|
|
801
|
+
// - typical fs.copyFile mode composition (COPYFILE_EXCL etc.)
|
|
802
|
+
// - signal/errno tables (shared shape with __osMod.constants.signals
|
|
803
|
+
// etc. — flat here, nested there; both shapes are real-Node-accurate
|
|
804
|
+
// and we expose both via the right module).
|
|
805
|
+
// - dlopen flags (RTLD_*) for libraries that probe defined-ness.
|
|
806
|
+
// - SSL_OP_* / TLS_*_VERSION for libs that probe TLS options
|
|
807
|
+
// (vanilla openssl numeric values — semantic match real Node's).
|
|
808
|
+
//
|
|
809
|
+
// Values match real Node v20 on Linux exactly. Verified via
|
|
810
|
+
// node -e 'console.log(require("node:constants"))'.
|
|
811
|
+
//
|
|
812
|
+
// History: F1 root cause in framework-fixes wave. Pre-fix create-next-app
|
|
813
|
+
// errored with "Cannot find module 'node:constants'" at module init.
|
|
814
|
+
const __constantsMod = {
|
|
815
|
+
// ── dlopen flags ──────────────────────────────────────────────────
|
|
816
|
+
RTLD_LAZY: 1, RTLD_NOW: 2, RTLD_GLOBAL: 256, RTLD_LOCAL: 0, RTLD_DEEPBIND: 8,
|
|
817
|
+
// ── errno (Linux ABI) ─────────────────────────────────────────────
|
|
818
|
+
E2BIG: 7, EACCES: 13, EADDRINUSE: 98, EADDRNOTAVAIL: 99, EAFNOSUPPORT: 97,
|
|
819
|
+
EAGAIN: 11, EALREADY: 114, EBADF: 9, EBADMSG: 74, EBUSY: 16,
|
|
820
|
+
ECANCELED: 125, ECHILD: 10, ECONNABORTED: 103, ECONNREFUSED: 111,
|
|
821
|
+
ECONNRESET: 104, EDEADLK: 35, EDESTADDRREQ: 89, EDOM: 33, EDQUOT: 122,
|
|
822
|
+
EEXIST: 17, EFAULT: 14, EFBIG: 27, EHOSTUNREACH: 113, EIDRM: 43,
|
|
823
|
+
EILSEQ: 84, EINPROGRESS: 115, EINTR: 4, EINVAL: 22, EIO: 5,
|
|
824
|
+
EISCONN: 106, EISDIR: 21, ELOOP: 40, EMFILE: 24, EMLINK: 31,
|
|
825
|
+
EMSGSIZE: 90, EMULTIHOP: 72, ENAMETOOLONG: 36, ENETDOWN: 100,
|
|
826
|
+
ENETRESET: 102, ENETUNREACH: 101, ENFILE: 23, ENOBUFS: 105,
|
|
827
|
+
ENODATA: 61, ENODEV: 19, ENOENT: 2, ENOEXEC: 8, ENOLCK: 37,
|
|
828
|
+
ENOLINK: 67, ENOMEM: 12, ENOMSG: 42, ENOPROTOOPT: 92, ENOSPC: 28,
|
|
829
|
+
ENOSR: 63, ENOSTR: 60, ENOSYS: 38, ENOTCONN: 107, ENOTDIR: 20,
|
|
830
|
+
ENOTEMPTY: 39, ENOTSOCK: 88, ENOTSUP: 95, ENOTTY: 25, ENXIO: 6,
|
|
831
|
+
EOPNOTSUPP: 95, EOVERFLOW: 75, EPERM: 1, EPIPE: 32, EPROTO: 71,
|
|
832
|
+
EPROTONOSUPPORT: 93, EPROTOTYPE: 91, ERANGE: 34, EROFS: 30,
|
|
833
|
+
ESPIPE: 29, ESRCH: 3, ESTALE: 116, ETIME: 62, ETIMEDOUT: 110,
|
|
834
|
+
ETXTBSY: 26, EWOULDBLOCK: 11, EXDEV: 18,
|
|
835
|
+
// ── Process priority (os.setPriority / os.getPriority) ────────────
|
|
836
|
+
PRIORITY_LOW: 19, PRIORITY_BELOW_NORMAL: 10, PRIORITY_NORMAL: 0,
|
|
837
|
+
PRIORITY_ABOVE_NORMAL: -7, PRIORITY_HIGH: -14, PRIORITY_HIGHEST: -20,
|
|
838
|
+
// ── Signals (POSIX + Linux) ───────────────────────────────────────
|
|
839
|
+
SIGHUP: 1, SIGINT: 2, SIGQUIT: 3, SIGILL: 4, SIGTRAP: 5,
|
|
840
|
+
SIGABRT: 6, SIGIOT: 6, SIGBUS: 7, SIGFPE: 8, SIGKILL: 9,
|
|
841
|
+
SIGUSR1: 10, SIGSEGV: 11, SIGUSR2: 12, SIGPIPE: 13, SIGALRM: 14,
|
|
842
|
+
SIGTERM: 15, SIGCHLD: 17, SIGSTKFLT: 16, SIGCONT: 18, SIGSTOP: 19,
|
|
843
|
+
SIGTSTP: 20, SIGTTIN: 21, SIGTTOU: 22, SIGURG: 23, SIGXCPU: 24,
|
|
844
|
+
SIGXFSZ: 25, SIGVTALRM: 26, SIGPROF: 27, SIGWINCH: 28, SIGIO: 29,
|
|
845
|
+
SIGPOLL: 29, SIGPWR: 30, SIGSYS: 31,
|
|
846
|
+
// ── File-type bits (stat.mode masks) ──────────────────────────────
|
|
847
|
+
S_IFMT: 61440, S_IFREG: 32768, S_IFDIR: 16384, S_IFCHR: 8192,
|
|
848
|
+
S_IFBLK: 24576, S_IFIFO: 4096, S_IFLNK: 40960, S_IFSOCK: 49152,
|
|
849
|
+
// ── File-open flags (fs.openSync / fs.constants.O_*) ──────────────
|
|
850
|
+
O_RDONLY: 0, O_WRONLY: 1, O_RDWR: 2,
|
|
851
|
+
O_CREAT: 64, O_EXCL: 128, O_NOCTTY: 256, O_TRUNC: 512, O_APPEND: 1024,
|
|
852
|
+
O_DIRECTORY: 65536, O_NOATIME: 262144, O_NOFOLLOW: 131072,
|
|
853
|
+
O_SYNC: 1052672, O_DSYNC: 4096, O_DIRECT: 16384, O_NONBLOCK: 2048,
|
|
854
|
+
// libuv-specific fs flag — create-next-app touches this directly.
|
|
855
|
+
UV_FS_O_FILEMAP: 0,
|
|
856
|
+
// ── File-permission bits (chmod / stat.mode user/group/other) ─────
|
|
857
|
+
S_IRWXU: 448, S_IRUSR: 256, S_IWUSR: 128, S_IXUSR: 64,
|
|
858
|
+
S_IRWXG: 56, S_IRGRP: 32, S_IWGRP: 16, S_IXGRP: 8,
|
|
859
|
+
S_IRWXO: 7, S_IROTH: 4, S_IWOTH: 2, S_IXOTH: 1,
|
|
860
|
+
// ── fs.access mode constants ──────────────────────────────────────
|
|
861
|
+
F_OK: 0, R_OK: 4, W_OK: 2, X_OK: 1,
|
|
862
|
+
// ── fs.copyFile mode constants (libuv shape + Node alias) ─────────
|
|
863
|
+
UV_FS_COPYFILE_EXCL: 1, COPYFILE_EXCL: 1,
|
|
864
|
+
UV_FS_COPYFILE_FICLONE: 2, COPYFILE_FICLONE: 2,
|
|
865
|
+
UV_FS_COPYFILE_FICLONE_FORCE: 4, COPYFILE_FICLONE_FORCE: 4,
|
|
866
|
+
// ── OpenSSL / TLS option flags ────────────────────────────────────
|
|
867
|
+
// Numeric values from real Node v20. Libraries probe defined-ness;
|
|
868
|
+
// we ship the surface so constants.SSL_OP_* doesn't undefined-throw.
|
|
869
|
+
OPENSSL_VERSION_NUMBER: 810549328,
|
|
870
|
+
SSL_OP_ALL: 2147485776, SSL_OP_ALLOW_NO_DHE_KEX: 1024,
|
|
871
|
+
SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: 262144,
|
|
872
|
+
SSL_OP_CIPHER_SERVER_PREFERENCE: 4194304,
|
|
873
|
+
SSL_OP_CISCO_ANYCONNECT: 32768, SSL_OP_COOKIE_EXCHANGE: 8192,
|
|
874
|
+
SSL_OP_CRYPTOPRO_TLSEXT_BUG: 2147483648,
|
|
875
|
+
SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: 2048,
|
|
876
|
+
SSL_OP_LEGACY_SERVER_CONNECT: 4, SSL_OP_NO_COMPRESSION: 131072,
|
|
877
|
+
SSL_OP_NO_ENCRYPT_THEN_MAC: 524288, SSL_OP_NO_QUERY_MTU: 4096,
|
|
878
|
+
SSL_OP_NO_RENEGOTIATION: 1073741824,
|
|
879
|
+
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION: 65536,
|
|
880
|
+
SSL_OP_NO_SSLv2: 0, SSL_OP_NO_SSLv3: 33554432,
|
|
881
|
+
SSL_OP_NO_TICKET: 16384, SSL_OP_NO_TLSv1: 67108864,
|
|
882
|
+
SSL_OP_NO_TLSv1_1: 268435456, SSL_OP_NO_TLSv1_2: 134217728,
|
|
883
|
+
SSL_OP_NO_TLSv1_3: 536870912, SSL_OP_PRIORITIZE_CHACHA: 2097152,
|
|
884
|
+
SSL_OP_TLS_ROLLBACK_BUG: 8388608,
|
|
885
|
+
// ── TLS version numbers ───────────────────────────────────────────
|
|
886
|
+
TLS1_VERSION: 769, TLS1_1_VERSION: 770,
|
|
887
|
+
TLS1_2_VERSION: 771, TLS1_3_VERSION: 772,
|
|
888
|
+
// ── crypto engine method flags ────────────────────────────────────
|
|
889
|
+
ENGINE_METHOD_RSA: 1, ENGINE_METHOD_DSA: 2, ENGINE_METHOD_DH: 4,
|
|
890
|
+
ENGINE_METHOD_RAND: 8, ENGINE_METHOD_EC: 2048,
|
|
891
|
+
ENGINE_METHOD_CIPHERS: 64, ENGINE_METHOD_DIGESTS: 128,
|
|
892
|
+
ENGINE_METHOD_PKEY_METHS: 512, ENGINE_METHOD_PKEY_ASN1_METHS: 1024,
|
|
893
|
+
ENGINE_METHOD_ALL: 65535, ENGINE_METHOD_NONE: 0,
|
|
894
|
+
// ── DH / RSA padding ──────────────────────────────────────────────
|
|
895
|
+
DH_CHECK_P_NOT_SAFE_PRIME: 2, DH_CHECK_P_NOT_PRIME: 1,
|
|
896
|
+
DH_UNABLE_TO_CHECK_GENERATOR: 4, DH_NOT_SUITABLE_GENERATOR: 8,
|
|
897
|
+
RSA_PKCS1_PADDING: 1, RSA_NO_PADDING: 3,
|
|
898
|
+
RSA_PKCS1_OAEP_PADDING: 4, RSA_X931_PADDING: 5,
|
|
899
|
+
RSA_PKCS1_PSS_PADDING: 6,
|
|
900
|
+
RSA_PSS_SALTLEN_DIGEST: -1, RSA_PSS_SALTLEN_MAX_SIGN: -2,
|
|
901
|
+
RSA_PSS_SALTLEN_AUTO: -2,
|
|
902
|
+
};
|
|
903
|
+
|
|
904
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
905
|
+
// ── os module ──────────────────────────────────────────────────────
|
|
906
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
907
|
+
const __osMod = {
|
|
908
|
+
platform: () => "linux", arch: () => "x64", type: () => "Linux",
|
|
909
|
+
release: () => "6.0.0-nimbus", tmpdir: () => "/tmp", homedir: () => "/home/user",
|
|
910
|
+
hostname: () => "nimbus", userInfo: () => ({ uid: 1000, gid: 1000, username: "user", homedir: "/home/user", shell: "/bin/sh" }),
|
|
911
|
+
cpus: () => [{ model: "DO vCPU", speed: 3000, times: { user: 0, nice: 0, sys: 0, idle: 0, irq: 0 } }],
|
|
912
|
+
totalmem: () => 128 * 1024 * 1024, freemem: () => 64 * 1024 * 1024,
|
|
913
|
+
loadavg: () => [0, 0, 0], uptime: () => 3600,
|
|
914
|
+
networkInterfaces: () => ({ lo: [{ address: "127.0.0.1", netmask: "255.0.0.0", family: "IPv4", internal: true }] }),
|
|
915
|
+
EOL: "\\n", endianness: () => "LE",
|
|
916
|
+
// os.constants — signals + errno + priority. Used by human-signals,
|
|
917
|
+
// signal-exit, cross-spawn, exit-hook, and a long tail of "graceful
|
|
918
|
+
// shutdown" / "child-process plumbing" libraries that real Node ships.
|
|
919
|
+
//
|
|
920
|
+
// human-signals's main.js (v2+) does:
|
|
921
|
+
// import { constants } from 'node:os'
|
|
922
|
+
// ...
|
|
923
|
+
// const findSignalByNumber = (number, signals) =>
|
|
924
|
+
// signals.find(({ name }) => constants.signals[name] === number)
|
|
925
|
+
//
|
|
926
|
+
// Pre-fix, __osMod had no \`constants\` field → \`constants.signals\`
|
|
927
|
+
// was undefined → \`signals[name]\` throws TypeError → caller's
|
|
928
|
+
// \`getSignalsByName\` blows up at module init time. Surfaced by
|
|
929
|
+
// create-react-router (transitively depends on human-signals via
|
|
930
|
+
// execa / cross-spawn).
|
|
931
|
+
//
|
|
932
|
+
// Values mirror real Node v20+ on Linux (verified against \`node -e
|
|
933
|
+
// "console.log(require('os').constants)"\`). The shape is stable;
|
|
934
|
+
// pinning POSIX signal numbers per the LSB / glibc table.
|
|
935
|
+
constants: {
|
|
936
|
+
// ── Signals ──────────────────────────────────────────────────
|
|
937
|
+
// Standard POSIX + Linux-specific signals as Node exposes them.
|
|
938
|
+
// Numbers match the Linux ABI; portable signal-name lookups
|
|
939
|
+
// (which is what 100% of npm consumers do) work regardless of
|
|
940
|
+
// platform.
|
|
941
|
+
signals: {
|
|
942
|
+
SIGHUP: 1, SIGINT: 2, SIGQUIT: 3, SIGILL: 4, SIGTRAP: 5,
|
|
943
|
+
SIGABRT: 6, SIGIOT: 6, SIGBUS: 7, SIGFPE: 8, SIGKILL: 9,
|
|
944
|
+
SIGUSR1: 10, SIGSEGV: 11, SIGUSR2: 12, SIGPIPE: 13, SIGALRM: 14,
|
|
945
|
+
SIGTERM: 15, SIGCHLD: 17, SIGSTKFLT: 16, SIGCONT: 18, SIGSTOP: 19,
|
|
946
|
+
SIGTSTP: 20, SIGTTIN: 21, SIGTTOU: 22, SIGURG: 23, SIGXCPU: 24,
|
|
947
|
+
SIGXFSZ: 25, SIGVTALRM: 26, SIGPROF: 27, SIGWINCH: 28, SIGIO: 29,
|
|
948
|
+
SIGPOLL: 29, SIGPWR: 30, SIGSYS: 31,
|
|
949
|
+
},
|
|
950
|
+
// ── Errno ────────────────────────────────────────────────────
|
|
951
|
+
// Standard Linux errno codes. fs/network libraries (e.g.
|
|
952
|
+
// graceful-fs, retry layers in node-fetch wrappers) probe these
|
|
953
|
+
// to decide retry strategy. Subset matches Node's exposed surface.
|
|
954
|
+
errno: {
|
|
955
|
+
E2BIG: 7, EACCES: 13, EADDRINUSE: 98, EADDRNOTAVAIL: 99,
|
|
956
|
+
EAFNOSUPPORT: 97, EAGAIN: 11, EALREADY: 114, EBADF: 9,
|
|
957
|
+
EBADMSG: 74, EBUSY: 16, ECANCELED: 125, ECHILD: 10,
|
|
958
|
+
ECONNABORTED: 103, ECONNREFUSED: 111, ECONNRESET: 104,
|
|
959
|
+
EDEADLK: 35, EDESTADDRREQ: 89, EDOM: 33, EDQUOT: 122,
|
|
960
|
+
EEXIST: 17, EFAULT: 14, EFBIG: 27, EHOSTUNREACH: 113,
|
|
961
|
+
EIDRM: 43, EILSEQ: 84, EINPROGRESS: 115, EINTR: 4, EINVAL: 22,
|
|
962
|
+
EIO: 5, EISCONN: 106, EISDIR: 21, ELOOP: 40, EMFILE: 24,
|
|
963
|
+
EMLINK: 31, EMSGSIZE: 90, EMULTIHOP: 72, ENAMETOOLONG: 36,
|
|
964
|
+
ENETDOWN: 100, ENETRESET: 102, ENETUNREACH: 101, ENFILE: 23,
|
|
965
|
+
ENOBUFS: 105, ENODATA: 61, ENODEV: 19, ENOENT: 2, ENOEXEC: 8,
|
|
966
|
+
ENOLCK: 37, ENOLINK: 67, ENOMEM: 12, ENOMSG: 42, ENOPROTOOPT: 92,
|
|
967
|
+
ENOSPC: 28, ENOSR: 63, ENOSTR: 60, ENOSYS: 38, ENOTCONN: 107,
|
|
968
|
+
ENOTDIR: 20, ENOTEMPTY: 39, ENOTSOCK: 88, ENOTSUP: 95,
|
|
969
|
+
ENOTTY: 25, ENXIO: 6, EOPNOTSUPP: 95, EOVERFLOW: 75, EPERM: 1,
|
|
970
|
+
EPIPE: 32, EPROTO: 71, EPROTONOSUPPORT: 93, EPROTOTYPE: 91,
|
|
971
|
+
ERANGE: 34, EROFS: 30, ESPIPE: 29, ESRCH: 3, ESTALE: 116,
|
|
972
|
+
ETIME: 62, ETIMEDOUT: 110, ETXTBSY: 26, EWOULDBLOCK: 11, EXDEV: 18,
|
|
973
|
+
},
|
|
974
|
+
// ── Priority ────────────────────────────────────────────────
|
|
975
|
+
// Process priority constants for os.setPriority / os.getPriority.
|
|
976
|
+
// Not used by anything we've observed, but Node exposes them and
|
|
977
|
+
// some libs check defined-ness before falling through.
|
|
978
|
+
priority: {
|
|
979
|
+
PRIORITY_LOW: 19,
|
|
980
|
+
PRIORITY_BELOW_NORMAL: 10,
|
|
981
|
+
PRIORITY_NORMAL: 0,
|
|
982
|
+
PRIORITY_ABOVE_NORMAL: -7,
|
|
983
|
+
PRIORITY_HIGH: -14,
|
|
984
|
+
PRIORITY_HIGHEST: -20,
|
|
985
|
+
},
|
|
986
|
+
// ── dlopen flags ────────────────────────────────────────────
|
|
987
|
+
// Documented for completeness; Nimbus has no real dlopen.
|
|
988
|
+
dlopen: { RTLD_LAZY: 1, RTLD_NOW: 2, RTLD_GLOBAL: 256, RTLD_LOCAL: 0 },
|
|
989
|
+
},
|
|
990
|
+
};
|
|
991
|
+
|
|
992
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
993
|
+
// ── events module ──────────────────────────────────────────────────
|
|
994
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
995
|
+
const __eventsMod = (() => {
|
|
996
|
+
// X.5-Z5 (Z5 §1 follow-on): every method that reads/writes \`this._e\`
|
|
997
|
+
// lazy-initializes it. Userland (notably express's createApplication
|
|
998
|
+
// — express/lib/express.js:36-42) mixin-copies EventEmitter.prototype
|
|
999
|
+
// onto a plain function via merge-descriptors; the EE constructor
|
|
1000
|
+
// never runs on that target so \`_e\` is undefined. The lazy guard
|
|
1001
|
+
// \`(this._e ??= {})\` matches Node's behaviour (Node initializes
|
|
1002
|
+
// _events on first use too) and makes mixin-copy patterns safe.
|
|
1003
|
+
// See audit/sections/X5Z5-build-retro.md §3.
|
|
1004
|
+
class EE {
|
|
1005
|
+
constructor() { this._e = {}; this._maxListeners = 10; }
|
|
1006
|
+
on(n, fn) { const e = (this._e ??= {}); (e[n] = e[n] || []).push(fn); return this; }
|
|
1007
|
+
addListener(n, fn) { return this.on(n, fn); }
|
|
1008
|
+
once(n, fn) { const w = (...a) => { this.off(n, w); fn(...a); }; w.__orig = fn; return this.on(n, w); }
|
|
1009
|
+
off(n, fn) { const e = (this._e ??= {}); if (e[n]) e[n] = e[n].filter(f => f !== fn && f.__orig !== fn); return this; }
|
|
1010
|
+
removeListener(n, fn) { return this.off(n, fn); }
|
|
1011
|
+
removeAllListeners(n) { if (n) { const e = (this._e ??= {}); delete e[n]; } else this._e = {}; return this; }
|
|
1012
|
+
emit(n, ...a) { const e = (this._e ??= {}); const fns = e[n]; if (!fns || !fns.length) return false; for (const fn of [...fns]) fn(...a); return true; }
|
|
1013
|
+
listeners(n) { const e = (this._e ??= {}); return (e[n] || []).map(f => f.__orig || f); }
|
|
1014
|
+
listenerCount(n) { const e = (this._e ??= {}); return (e[n] || []).length; }
|
|
1015
|
+
eventNames() { const e = (this._e ??= {}); return Object.keys(e).filter(k => e[k].length > 0); }
|
|
1016
|
+
setMaxListeners(n) { this._maxListeners = n; return this; }
|
|
1017
|
+
getMaxListeners() { return this._maxListeners; }
|
|
1018
|
+
prependListener(n, fn) { const e = (this._e ??= {}); (e[n] = e[n] || []).unshift(fn); return this; }
|
|
1019
|
+
rawListeners(n) { const e = (this._e ??= {}); return e[n] || []; }
|
|
1020
|
+
}
|
|
1021
|
+
EE.EventEmitter = EE;
|
|
1022
|
+
EE.defaultMaxListeners = 10;
|
|
1023
|
+
return EE;
|
|
1024
|
+
})();
|
|
1025
|
+
|
|
1026
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1027
|
+
// ── stream module (real, with backpressure) ────────────────────────
|
|
1028
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1029
|
+
${STREAMS_CODE}
|
|
1030
|
+
|
|
1031
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1032
|
+
// ── util module ────────────────────────────────────────────────────
|
|
1033
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1034
|
+
const __utilMod = {
|
|
1035
|
+
inspect: (o, opts) => { try { return JSON.stringify(o, null, 2); } catch { return String(o); } },
|
|
1036
|
+
format: (fmt, ...a) => {
|
|
1037
|
+
if (typeof fmt !== "string") return [fmt, ...a].map(__fmt).join(" ");
|
|
1038
|
+
let i = 0;
|
|
1039
|
+
return fmt.replace(/%[sdifjoO%]/g, (m) => {
|
|
1040
|
+
if (m === "%%") return "%";
|
|
1041
|
+
if (i >= a.length) return m;
|
|
1042
|
+
const v = a[i++];
|
|
1043
|
+
if (m === "%s") return String(v);
|
|
1044
|
+
if (m === "%d" || m === "%i" || m === "%f") return Number(v).toString();
|
|
1045
|
+
if (m === "%j") { try { return JSON.stringify(v); } catch { return "[Circular]"; } }
|
|
1046
|
+
if (m === "%o" || m === "%O") { try { return JSON.stringify(v, null, 2); } catch { return String(v); } }
|
|
1047
|
+
return String(v);
|
|
1048
|
+
}) + (i < a.length ? " " + a.slice(i).map(__fmt).join(" ") : "");
|
|
1049
|
+
},
|
|
1050
|
+
promisify: (fn) => (...a) => new Promise((res, rej) => fn(...a, (e, r) => e ? rej(e) : res(r))),
|
|
1051
|
+
callbackify: (fn) => (...a) => { const cb = a.pop(); fn(...a).then(r => cb(null, r), e => cb(e)); },
|
|
1052
|
+
// X.5-Q: util.types polyfill expansion. The pre-X.5-Q 3-method shape
|
|
1053
|
+
// (isDate, isRegExp, isPromise) was insufficient for jsdom's bundled
|
|
1054
|
+
// undici, which dereferences isUint8Array (lib/web/fetch/util.js +
|
|
1055
|
+
// body.js), isArrayBuffer (lib/web/websocket/websocket.js), and
|
|
1056
|
+
// util.types.isProxy (lib/web/fetch/headers.js). Expanding to the
|
|
1057
|
+
// 17-method shape below mirrors Node.js's util.types surface for the
|
|
1058
|
+
// common cases; isProxy returns false (no userland Proxy detection).
|
|
1059
|
+
// See audit/probes/x5npqo/investigate/Q-undici-types-survey.md and
|
|
1060
|
+
// audit/probes/x5npqo/functional/q-util-types.mjs.
|
|
1061
|
+
types: {
|
|
1062
|
+
isDate: (v) => v instanceof Date,
|
|
1063
|
+
isRegExp: (v) => v instanceof RegExp,
|
|
1064
|
+
isPromise: (v) => v instanceof Promise,
|
|
1065
|
+
isUint8Array: (v) => v instanceof Uint8Array,
|
|
1066
|
+
isArrayBuffer: (v) => v instanceof ArrayBuffer,
|
|
1067
|
+
isAnyArrayBuffer: (v) => v instanceof ArrayBuffer
|
|
1068
|
+
|| (typeof SharedArrayBuffer !== "undefined" && v instanceof SharedArrayBuffer),
|
|
1069
|
+
isArrayBufferView: (v) => ArrayBuffer.isView(v),
|
|
1070
|
+
isTypedArray: (v) => ArrayBuffer.isView(v) && !(v instanceof DataView),
|
|
1071
|
+
isMap: (v) => v instanceof Map,
|
|
1072
|
+
isSet: (v) => v instanceof Set,
|
|
1073
|
+
isWeakMap: (v) => v instanceof WeakMap,
|
|
1074
|
+
isWeakSet: (v) => v instanceof WeakSet,
|
|
1075
|
+
isNativeError: (v) => v instanceof Error,
|
|
1076
|
+
isAsyncFunction: (v) => v && v.constructor && v.constructor.name === "AsyncFunction",
|
|
1077
|
+
isGeneratorFunction: (v) => v && v.constructor && v.constructor.name === "GeneratorFunction",
|
|
1078
|
+
isProxy: (v) => false,
|
|
1079
|
+
isBoxedPrimitive: (v) => v instanceof Boolean || v instanceof Number
|
|
1080
|
+
|| v instanceof String || (typeof v === "object" && v !== null && (v.constructor === Symbol || v.constructor === BigInt)),
|
|
1081
|
+
},
|
|
1082
|
+
inherits: (c, s) => {
|
|
1083
|
+
// X.5-Z5 Defect-B fix: guard against null/undefined superCtor or a
|
|
1084
|
+
// superCtor whose .prototype is null/undefined. Without this guard,
|
|
1085
|
+
// Object.create(undefined.prototype, ...) and Object.create(null, ...)
|
|
1086
|
+
// both throw 'Object prototype may only be an Object or null: undefined'
|
|
1087
|
+
// — same surface as Defect A but for shim namespaces with no synthetic
|
|
1088
|
+
// .prototype. Mirrors the canonical inherits_browser.js fallback.
|
|
1089
|
+
// See audit/sections/X5Z5-plan.md §1.3 Defensive fix.
|
|
1090
|
+
if (s == null || s.prototype == null) return;
|
|
1091
|
+
c.super_ = s;
|
|
1092
|
+
c.prototype = Object.create(s.prototype, { constructor: { value: c, enumerable: false, writable: true, configurable: true } });
|
|
1093
|
+
},
|
|
1094
|
+
deprecate: (fn, msg) => fn,
|
|
1095
|
+
debuglog: () => () => {},
|
|
1096
|
+
isDeepStrictEqual: (a, b) => JSON.stringify(a) === JSON.stringify(b),
|
|
1097
|
+
TextEncoder: globalThis.TextEncoder,
|
|
1098
|
+
TextDecoder: globalThis.TextDecoder,
|
|
1099
|
+
// util.stripVTControlCharacters(str) — Node 16.11+. Strips ANSI
|
|
1100
|
+
// escape sequences from a string. Used by sv (svelte CLI), modern
|
|
1101
|
+
// log libraries, and any CLI that wants to measure displayed-width
|
|
1102
|
+
// independent of color codes. Pre-fix, sv's engine module imported
|
|
1103
|
+
// this from 'node:util' and crashed at module-init with
|
|
1104
|
+
// "stripVTControlCharacters is not a function".
|
|
1105
|
+
//
|
|
1106
|
+
// Real-Node impl strips C0/C1 ANSI escapes via a single regex.
|
|
1107
|
+
// Standard CSI sequence pattern: ESC + '[' + parameter bytes + final byte.
|
|
1108
|
+
stripVTControlCharacters: (str) => {
|
|
1109
|
+
if (typeof str !== "string") return str;
|
|
1110
|
+
// Covers most common ANSI sequences: CSI (\x1b[...m, \x1b[...K, etc.),
|
|
1111
|
+
// OSC, simple ESC sequences. Mirrors the regex Node's lib/internal/
|
|
1112
|
+
// util/inspect.js uses (slightly relaxed).
|
|
1113
|
+
return str.replace(/\\x1b\\[[0-9;?]*[A-Za-z]|\\x1b[\\(\\)\\*\\+][AB012]|\\x1b\\][^\\x07\\x1b]*[\\x07\\x1b]|\\x1b[=>]/g, "");
|
|
1114
|
+
},
|
|
1115
|
+
// util.styleText(format, text [, opts]) — Node 20.12+. Returns text
|
|
1116
|
+
// wrapped in ANSI escape sequences for terminal styling. Used by
|
|
1117
|
+
// create-vite and many modern CLIs.
|
|
1118
|
+
//
|
|
1119
|
+
// Surface: format may be a single style string or an array of style
|
|
1120
|
+
// strings; in either case we apply each style's open code, then the
|
|
1121
|
+
// text, then the closing code. The Nimbus terminal renders ANSI;
|
|
1122
|
+
// unrecognised formats pass through as plain text (Node's docs say
|
|
1123
|
+
// it throws TypeError in strict mode, but our facet code may emit
|
|
1124
|
+
// styled error messages even for unrecognised foreground colors
|
|
1125
|
+
// — choose the lenient pass-through to keep CLIs functioning).
|
|
1126
|
+
styleText: (format, text /*, _opts */) => {
|
|
1127
|
+
// ANSI lookup. Mirrors Node's util.inspect.colors keys.
|
|
1128
|
+
const codes = {
|
|
1129
|
+
reset: [0, 0],
|
|
1130
|
+
bold: [1, 22],
|
|
1131
|
+
italic: [3, 23],
|
|
1132
|
+
underline: [4, 24],
|
|
1133
|
+
strikethrough: [9, 29],
|
|
1134
|
+
hidden: [8, 28],
|
|
1135
|
+
dim: [2, 22],
|
|
1136
|
+
overlined: [53, 55],
|
|
1137
|
+
blink: [5, 25],
|
|
1138
|
+
inverse: [7, 27],
|
|
1139
|
+
doubleunderline: [21, 24],
|
|
1140
|
+
framed: [51, 54],
|
|
1141
|
+
black: [30, 39], red: [31, 39], green: [32, 39],
|
|
1142
|
+
yellow: [33, 39], blue: [34, 39], magenta: [35, 39],
|
|
1143
|
+
cyan: [36, 39], white: [37, 39], gray: [90, 39],
|
|
1144
|
+
grey: [90, 39],
|
|
1145
|
+
blackBright: [90, 39], redBright: [91, 39], greenBright: [92, 39],
|
|
1146
|
+
yellowBright: [93, 39], blueBright: [94, 39], magentaBright: [95, 39],
|
|
1147
|
+
cyanBright: [96, 39], whiteBright: [97, 39],
|
|
1148
|
+
bgBlack: [40, 49], bgRed: [41, 49], bgGreen: [42, 49],
|
|
1149
|
+
bgYellow: [43, 49], bgBlue: [44, 49], bgMagenta: [45, 49],
|
|
1150
|
+
bgCyan: [46, 49], bgWhite: [47, 49], bgGray: [100, 49],
|
|
1151
|
+
bgGrey: [100, 49],
|
|
1152
|
+
bgBlackBright: [100, 49], bgRedBright: [101, 49], bgGreenBright: [102, 49],
|
|
1153
|
+
bgYellowBright: [103, 49], bgBlueBright: [104, 49], bgMagentaBright: [105, 49],
|
|
1154
|
+
bgCyanBright: [106, 49], bgWhiteBright: [107, 49],
|
|
1155
|
+
};
|
|
1156
|
+
const formats = Array.isArray(format) ? format : [format];
|
|
1157
|
+
let opens = "";
|
|
1158
|
+
let closes = "";
|
|
1159
|
+
for (const f of formats) {
|
|
1160
|
+
const c = codes[f];
|
|
1161
|
+
if (c) {
|
|
1162
|
+
opens += "\\x1b[" + c[0] + "m";
|
|
1163
|
+
closes = "\\x1b[" + c[1] + "m" + closes;
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
return opens + String(text) + closes;
|
|
1167
|
+
},
|
|
1168
|
+
};
|
|
1169
|
+
|
|
1170
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1171
|
+
// ── url module ─────────────────────────────────────────────────────
|
|
1172
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1173
|
+
// X.5-M (M-3): lenient URL constructor for rolldown-bundled CJS packages.
|
|
1174
|
+
//
|
|
1175
|
+
// Rolldown/rollup-bundled CJS packages (vite v7, esbuild plugins, …)
|
|
1176
|
+
// emit at module top-level:
|
|
1177
|
+
//
|
|
1178
|
+
// const X = new URL("../../../src/node/constants.ts", import.meta.url);
|
|
1179
|
+
//
|
|
1180
|
+
// where the rolldown-CJS polyfill for import.meta.url evaluates to literal
|
|
1181
|
+
// null (the bare word) in our facet (no document, no location, polyfill doesn't reach
|
|
1182
|
+
// __filename for CJS-loaded modules — see audit/sections/X5M-plan.md §1
|
|
1183
|
+
// M-3 + audit/probes/x5m/investigate/vite-url-stack{5,A,B,D}.txt).
|
|
1184
|
+
//
|
|
1185
|
+
// workerd's URL constructor strict-rejects null/undefined base, throwing
|
|
1186
|
+
// "Invalid URL string." at module top-level eval — breaks require('vite').
|
|
1187
|
+
//
|
|
1188
|
+
// Fix: wrap globalThis.URL so null/undefined base for a string input
|
|
1189
|
+
// defaults to "file:///" (after first trying the input as an absolute
|
|
1190
|
+
// URL). All other URL behaviour is passthrough; instanceof checks and
|
|
1191
|
+
// static methods (canParse, parse, createObjectURL, ...) preserved.
|
|
1192
|
+
//
|
|
1193
|
+
// Stage A (this commit): vite no longer throws at the URL constructor;
|
|
1194
|
+
// it now progresses to a deeper fs-URL composition gap (vite passes URL
|
|
1195
|
+
// instances / file:// strings to fs.readFileSync, which our fs shim
|
|
1196
|
+
// doesn't strip) — that's out-of-charter, see X5M-retro §3.
|
|
1197
|
+
//
|
|
1198
|
+
// X.5-M3 (this section): when esbuild ESM-to-CJS pre-compile substitutes
|
|
1199
|
+
// import.meta.url with undefined (its documented empty-import-meta
|
|
1200
|
+
// warning behavior), new URL(rel, undefined) falls into the null-base
|
|
1201
|
+
// branch below. Pre-M3 the fallback was a literal "file:///", which
|
|
1202
|
+
// resolved every new URL("../foo", import.meta.url) to root-relative
|
|
1203
|
+
// file:///foo — wrong for vite/dist/node/chunks/logger.js:75 et al.
|
|
1204
|
+
//
|
|
1205
|
+
// M3 plumbs the currently-loading module's path via globalThis.__currentModulePath
|
|
1206
|
+
// (set+restored by __loadModule per call). When set, the fallback becomes
|
|
1207
|
+
// "file:///" + __currentModulePath so relative URLs resolve against
|
|
1208
|
+
// the real on-VFS module location — restoring proper import.meta.url
|
|
1209
|
+
// semantics for ESM-transformed CJS. See audit/sections/X5M3-plan.md §3.
|
|
1210
|
+
(() => {
|
|
1211
|
+
const _Orig = globalThis.URL;
|
|
1212
|
+
class _Shim extends _Orig {
|
|
1213
|
+
constructor(input, base) {
|
|
1214
|
+
if (base == null && typeof input === "string") {
|
|
1215
|
+
try { super(input); return; }
|
|
1216
|
+
catch {
|
|
1217
|
+
// X.5-M3: prefer current module path when known, so
|
|
1218
|
+
// new URL(rel, undefined) === new URL(rel, "file:///" + __filename)
|
|
1219
|
+
// matches real ESM import-meta-url resolution.
|
|
1220
|
+
const cur = globalThis.__currentModulePath;
|
|
1221
|
+
const fallback = (typeof cur === "string" && cur.length > 0)
|
|
1222
|
+
? "file:///" + cur.replace(/^\\/+/, "")
|
|
1223
|
+
: "file:///";
|
|
1224
|
+
super(input, fallback);
|
|
1225
|
+
return;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
super(input, base);
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
for (const k of Object.getOwnPropertyNames(_Orig)) {
|
|
1232
|
+
if (typeof _Orig[k] === "function" && !(k in _Shim)) {
|
|
1233
|
+
try { _Shim[k] = _Orig[k].bind(_Orig); } catch (_e) {}
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
// NOTE: cannot reassign _Shim.prototype = _Orig.prototype — workerd treats
|
|
1237
|
+
// class.prototype as read-only. Inheritance via "extends _Orig" is enough:
|
|
1238
|
+
// _Shim instances are instanceof _Orig, and _Shim.prototype's __proto__ is
|
|
1239
|
+
// _Orig.prototype (so all native URL methods are reachable via the chain).
|
|
1240
|
+
globalThis.URL = _Shim;
|
|
1241
|
+
})();
|
|
1242
|
+
const __urlMod = {
|
|
1243
|
+
URL: globalThis.URL, URLSearchParams: globalThis.URLSearchParams,
|
|
1244
|
+
parse: (s) => { try { const u = new URL(s); return { protocol: u.protocol, hostname: u.hostname, port: u.port, pathname: u.pathname, search: u.search, hash: u.hash, href: u.href, host: u.host }; } catch { return { href: s }; } },
|
|
1245
|
+
format: (o) => { if (typeof o === "string") return o; if (o instanceof URL) return o.href; return (o.protocol || "http:") + "//" + (o.hostname || "") + (o.port ? ":" + o.port : "") + (o.pathname || "/") + (o.search || ""); },
|
|
1246
|
+
resolve: (from, to) => new URL(to, from).href,
|
|
1247
|
+
pathToFileURL: (p) => new URL("file://" + p),
|
|
1248
|
+
fileURLToPath: (u) => (typeof u === "string" ? u : u.pathname).replace(/^file:\\/\\//, ""),
|
|
1249
|
+
};
|
|
1250
|
+
__urlMod.URL = globalThis.URL;
|
|
1251
|
+
|
|
1252
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1253
|
+
// ── crypto module (W3: forward to workerd's real node:crypto) ──────
|
|
1254
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1255
|
+
//
|
|
1256
|
+
// Pre-W3 this was a hand-rolled FNV-1a fake that returned a 16-byte
|
|
1257
|
+
// FNV state repeated as a 32-byte "sha256" hash — silent correctness
|
|
1258
|
+
// disaster (sha256("hello") = abdd62852c5bd7fc9fa116d64f0254ec × 2
|
|
1259
|
+
// instead of 2cf24dba...). W3 forwards to workerd's real
|
|
1260
|
+
// node:crypto, which has been stable since CF changelog 2025-04-08.
|
|
1261
|
+
// __real_crypto comes from the static import block at the top of the
|
|
1262
|
+
// generated facet file (see src/_shared/real-node-imports.ts).
|
|
1263
|
+
//
|
|
1264
|
+
// The forward is exhaustive — Node 20 surface (createHash, createHmac,
|
|
1265
|
+
// pbkdf2/Sync, scrypt/Sync, createCipheriv/Decipheriv, createSign/
|
|
1266
|
+
// Verify, KeyObject, generateKeyPair/Sync, createPublic/PrivateKey,
|
|
1267
|
+
// timingSafeEqual, randomBytes/UUID/Int/Fill, getHashes/Ciphers/Curves,
|
|
1268
|
+
// constants, webcrypto, subtle) is all on the workerd module.
|
|
1269
|
+
const __cryptoMod = (() => {
|
|
1270
|
+
const real = (typeof __real_crypto !== 'undefined') ? (__real_crypto.default ?? __real_crypto) : null;
|
|
1271
|
+
if (real && typeof real.createHash === 'function') return real;
|
|
1272
|
+
// Defensive fallback: if for some reason the static import didn't
|
|
1273
|
+
// materialise (e.g. compat-flag drift), surface honest-error rather
|
|
1274
|
+
// than silently shipping a fake hash. Anything beyond randomBytes/
|
|
1275
|
+
// randomUUID throws a NIMBUS-flavoured error.
|
|
1276
|
+
function _unavail(name) {
|
|
1277
|
+
return () => {
|
|
1278
|
+
const e = new Error('crypto.' + name + ': workerd node:crypto not available. Check facet compat date >= 2025-04-08.');
|
|
1279
|
+
e.code = 'ERR_CRYPTO_UNAVAILABLE';
|
|
1280
|
+
throw e;
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
return {
|
|
1284
|
+
randomBytes: (n) => { const a = new Uint8Array(n); crypto.getRandomValues(a); return __BufferMod.from(a); },
|
|
1285
|
+
randomUUID: () => crypto.randomUUID(),
|
|
1286
|
+
randomInt: (min, max) => { if (max === undefined) { max = min; min = 0; } return min + Math.floor(Math.random() * (max - min)); },
|
|
1287
|
+
randomFillSync: (buf) => { crypto.getRandomValues(buf); return buf; },
|
|
1288
|
+
createHash: _unavail('createHash'),
|
|
1289
|
+
createHmac: _unavail('createHmac'),
|
|
1290
|
+
pbkdf2: _unavail('pbkdf2'),
|
|
1291
|
+
pbkdf2Sync: _unavail('pbkdf2Sync'),
|
|
1292
|
+
timingSafeEqual: (a, b) => { if (a.length !== b.length) return false; let r = 0; for (let i = 0; i < a.length; i++) r |= a[i] ^ b[i]; return r === 0; },
|
|
1293
|
+
constants: {},
|
|
1294
|
+
webcrypto: globalThis.crypto,
|
|
1295
|
+
subtle: globalThis.crypto?.subtle,
|
|
1296
|
+
};
|
|
1297
|
+
})();
|
|
1298
|
+
|
|
1299
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1300
|
+
// ── vm module (W3: hybrid — forward surface, honest-error on eval) ──
|
|
1301
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1302
|
+
//
|
|
1303
|
+
// Workerd's node:vm provides the API surface (constants, classes,
|
|
1304
|
+
// runInContext as a function) BUT every code-running method throws
|
|
1305
|
+
// ERR_METHOD_NOT_IMPLEMENTED at request-handler time. New Function
|
|
1306
|
+
// is also blocked at request time. So we forward the surface (so
|
|
1307
|
+
// jsdom's static-load checks pass) and wrap the eval methods with
|
|
1308
|
+
// a honest Nimbus error so callers know it's the workerd block.
|
|
1309
|
+
//
|
|
1310
|
+
// Acceptance limitation: jsdom static-load works; jsdom HTML-script
|
|
1311
|
+
// execution does not. Documented in W3 retro for W3.5 follow-up
|
|
1312
|
+
// (a parser-based vm fallback, or pre-bundle vm-using scripts at
|
|
1313
|
+
// install time).
|
|
1314
|
+
const __vmMod = (() => {
|
|
1315
|
+
const real = (typeof __real_vm !== 'undefined') ? (__real_vm.default ?? __real_vm) : null;
|
|
1316
|
+
function honestError(method, originalErr) {
|
|
1317
|
+
const e = new Error(
|
|
1318
|
+
'vm.' + method + ': workerd does not implement runtime eval. ' +
|
|
1319
|
+
'Pre-bundle vm-using scripts at install time, or wait for W3.5 ' +
|
|
1320
|
+
'parser-based fallback. (Original: ' +
|
|
1321
|
+
((originalErr && originalErr.message) || 'no underlying error') + ')'
|
|
1322
|
+
);
|
|
1323
|
+
e.code = 'ERR_VM_DYNAMIC_EVAL_DISALLOWED';
|
|
1324
|
+
return e;
|
|
1325
|
+
}
|
|
1326
|
+
function wrapRuntimeEval(method) {
|
|
1327
|
+
return (...args) => {
|
|
1328
|
+
if (!real || typeof real[method] !== 'function') {
|
|
1329
|
+
throw honestError(method, null);
|
|
1330
|
+
}
|
|
1331
|
+
try { return real[method](...args); } catch (e) {
|
|
1332
|
+
// Workerd surfaces ERR_METHOD_NOT_IMPLEMENTED;
|
|
1333
|
+
// \`new Function\` surfaces "Code generation from strings disallowed".
|
|
1334
|
+
if (e && (e.code === 'ERR_METHOD_NOT_IMPLEMENTED'
|
|
1335
|
+
|| /not implemented|disallowed|Code generation/i.test(e.message || ''))) {
|
|
1336
|
+
throw honestError(method, e);
|
|
1337
|
+
}
|
|
1338
|
+
throw e;
|
|
1339
|
+
}
|
|
1340
|
+
};
|
|
1341
|
+
}
|
|
1342
|
+
return {
|
|
1343
|
+
constants: real?.constants ?? {},
|
|
1344
|
+
createContext: (sandbox, opts) => {
|
|
1345
|
+
if (!real || typeof real.createContext !== 'function') return sandbox || {};
|
|
1346
|
+
try { return real.createContext(sandbox, opts); }
|
|
1347
|
+
catch { return sandbox || {}; }
|
|
1348
|
+
},
|
|
1349
|
+
isContext: real?.isContext ?? ((o) => !!o),
|
|
1350
|
+
runInContext: wrapRuntimeEval('runInContext'),
|
|
1351
|
+
runInNewContext: wrapRuntimeEval('runInNewContext'),
|
|
1352
|
+
runInThisContext: wrapRuntimeEval('runInThisContext'),
|
|
1353
|
+
compileFunction: wrapRuntimeEval('compileFunction'),
|
|
1354
|
+
Script: real?.Script ?? class { constructor() { throw honestError('Script', null); } },
|
|
1355
|
+
Module: real?.Module,
|
|
1356
|
+
SourceTextModule: real?.SourceTextModule,
|
|
1357
|
+
SyntheticModule: real?.SyntheticModule,
|
|
1358
|
+
measureMemory: real?.measureMemory ?? (async () => ({ total: { jsMemoryEstimate: 0 } })),
|
|
1359
|
+
};
|
|
1360
|
+
})();
|
|
1361
|
+
|
|
1362
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1363
|
+
// ── http2 module (W3: stub — non-throwing load, honest connect err) ─
|
|
1364
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1365
|
+
//
|
|
1366
|
+
// axios's dist/node code does \`var http2 = require('http2')\` at top
|
|
1367
|
+
// level, unconditionally. Without this stub the require fails →
|
|
1368
|
+
// axios fails to load. The actual HTTP/2 transport is only invoked
|
|
1369
|
+
// when user opts in (\`httpVersion: 2\`); otherwise this shim is dormant.
|
|
1370
|
+
const __http2Mod = (() => {
|
|
1371
|
+
function _err(op) {
|
|
1372
|
+
const e = new Error('http2.' + op + ': not implemented in Nimbus. Use fetch() or HTTP/1.1.');
|
|
1373
|
+
e.code = 'ERR_HTTP2_NOT_SUPPORTED';
|
|
1374
|
+
return e;
|
|
1375
|
+
}
|
|
1376
|
+
class Http2Session extends __eventsMod {
|
|
1377
|
+
constructor() { super(); this.destroyed = false; }
|
|
1378
|
+
request() { throw _err('request'); }
|
|
1379
|
+
close() { this.destroyed = true; this.emit('close'); }
|
|
1380
|
+
destroy(err) { this.destroyed = true; if (err) this.emit('error', err); this.emit('close'); }
|
|
1381
|
+
settings() {}
|
|
1382
|
+
}
|
|
1383
|
+
function connect(/* authority, opts, listener */) {
|
|
1384
|
+
const session = new Http2Session();
|
|
1385
|
+
queueMicrotask(() => session.emit('error', _err('connect')));
|
|
1386
|
+
return session;
|
|
1387
|
+
}
|
|
1388
|
+
function createServer() { throw _err('createServer'); }
|
|
1389
|
+
return {
|
|
1390
|
+
connect, createServer,
|
|
1391
|
+
createSecureServer: createServer,
|
|
1392
|
+
Http2Session,
|
|
1393
|
+
constants: {
|
|
1394
|
+
NGHTTP2_NO_ERROR: 0, NGHTTP2_PROTOCOL_ERROR: 1,
|
|
1395
|
+
HTTP2_HEADER_PATH: ':path', HTTP2_HEADER_METHOD: ':method',
|
|
1396
|
+
HTTP2_HEADER_STATUS: ':status', HTTP2_HEADER_AUTHORITY: ':authority',
|
|
1397
|
+
HTTP2_HEADER_SCHEME: ':scheme',
|
|
1398
|
+
},
|
|
1399
|
+
sensitiveHeaders: Symbol('nodejs.http2.sensitiveHeaders'),
|
|
1400
|
+
};
|
|
1401
|
+
})();
|
|
1402
|
+
|
|
1403
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1404
|
+
// ── repl module (W3: forward to workerd) ───────────────────────────
|
|
1405
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1406
|
+
// ts-node imports repl. Workerd has it (stub since 2026-03-17).
|
|
1407
|
+
const __replMod = (() => {
|
|
1408
|
+
const real = (typeof __real_repl !== 'undefined') ? (__real_repl.default ?? __real_repl) : null;
|
|
1409
|
+
if (real && typeof real.start === 'function') return real;
|
|
1410
|
+
// Fallback if static import didn't materialise.
|
|
1411
|
+
class REPLServer extends __eventsMod {
|
|
1412
|
+
close() { this.emit('exit'); }
|
|
1413
|
+
displayPrompt() {} pause() {} resume() {}
|
|
1414
|
+
setupHistory(p, cb) { if (cb) cb(null, this); }
|
|
1415
|
+
defineCommand() {}
|
|
1416
|
+
}
|
|
1417
|
+
return { start: (opts) => new REPLServer(), REPLServer, REPL_MODE_SLOPPY: 0, REPL_MODE_STRICT: 1 };
|
|
1418
|
+
})();
|
|
1419
|
+
|
|
1420
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1421
|
+
// ── diagnostics_channel (W3: forward to workerd) ───────────────────
|
|
1422
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1423
|
+
// fastify uses Channel.runStores at request-handler time — workerd's
|
|
1424
|
+
// real impl includes this. Forward whole module.
|
|
1425
|
+
const __diagChannelMod = (() => {
|
|
1426
|
+
const real = (typeof __real_diagnostics_channel !== 'undefined') ? (__real_diagnostics_channel.default ?? __real_diagnostics_channel) : null;
|
|
1427
|
+
if (real && typeof real.channel === 'function') return real;
|
|
1428
|
+
// Fallback: tiny pure-JS impl (no runStores; fastify will fail loud).
|
|
1429
|
+
const channels = new Map();
|
|
1430
|
+
class Channel {
|
|
1431
|
+
constructor(name) { this.name = name; this._subs = []; }
|
|
1432
|
+
get hasSubscribers() { return this._subs.length > 0; }
|
|
1433
|
+
subscribe(fn) { this._subs.push(fn); }
|
|
1434
|
+
unsubscribe(fn) { const i = this._subs.indexOf(fn); if (i >= 0) { this._subs.splice(i, 1); return true; } return false; }
|
|
1435
|
+
publish(msg) { for (const fn of [...this._subs]) { try { fn(msg, this.name); } catch {} } }
|
|
1436
|
+
runStores(_store, fn, thisArg, ...args) { return fn.apply(thisArg, args); }
|
|
1437
|
+
bindStore() {} unbindStore() {}
|
|
1438
|
+
}
|
|
1439
|
+
function channel(name) {
|
|
1440
|
+
let c = channels.get(name);
|
|
1441
|
+
if (!c) { c = new Channel(name); channels.set(name, c); }
|
|
1442
|
+
return c;
|
|
1443
|
+
}
|
|
1444
|
+
return {
|
|
1445
|
+
channel,
|
|
1446
|
+
hasSubscribers: (name) => { const c = channels.get(name); return !!(c && c.hasSubscribers); },
|
|
1447
|
+
subscribe: (name, fn) => channel(name).subscribe(fn),
|
|
1448
|
+
unsubscribe: (name, fn) => channel(name).unsubscribe(fn),
|
|
1449
|
+
tracingChannel: (n) => ({
|
|
1450
|
+
start: channel('tracing:' + n + ':start'),
|
|
1451
|
+
end: channel('tracing:' + n + ':end'),
|
|
1452
|
+
asyncStart: channel('tracing:' + n + ':asyncStart'),
|
|
1453
|
+
asyncEnd: channel('tracing:' + n + ':asyncEnd'),
|
|
1454
|
+
error: channel('tracing:' + n + ':error'),
|
|
1455
|
+
traceSync(fn) { return fn(); },
|
|
1456
|
+
tracePromise(fn) { return Promise.resolve().then(fn); },
|
|
1457
|
+
traceCallback(fn, _pos, _ctx, thisArg, ...args) { return fn.apply(thisArg, args); },
|
|
1458
|
+
}),
|
|
1459
|
+
Channel,
|
|
1460
|
+
};
|
|
1461
|
+
})();
|
|
1462
|
+
|
|
1463
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1464
|
+
// ── tls module (W3: forward to workerd, override createServer) ─────
|
|
1465
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1466
|
+
const __tlsMod = (() => {
|
|
1467
|
+
const real = (typeof __real_tls !== 'undefined') ? (__real_tls.default ?? __real_tls) : null;
|
|
1468
|
+
if (!real) {
|
|
1469
|
+
return { connect: () => { throw new Error('tls: workerd node:tls not available'); } };
|
|
1470
|
+
}
|
|
1471
|
+
// tls.createServer in workerd would bind a real port; in a facet we want
|
|
1472
|
+
// routing through __portRegistry, so override that one method.
|
|
1473
|
+
return new Proxy(real, {
|
|
1474
|
+
get(t, p) {
|
|
1475
|
+
if (p === 'createServer') {
|
|
1476
|
+
return () => {
|
|
1477
|
+
const e = new Error('tls.createServer: not supported in Nimbus facet. Use http.createServer for routing.');
|
|
1478
|
+
e.code = 'ERR_NET_SERVER_NOT_AVAILABLE';
|
|
1479
|
+
throw e;
|
|
1480
|
+
};
|
|
1481
|
+
}
|
|
1482
|
+
return t[p];
|
|
1483
|
+
}
|
|
1484
|
+
});
|
|
1485
|
+
})();
|
|
1486
|
+
|
|
1487
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1488
|
+
// ── async_hooks module (W3: forward to workerd) ────────────────────
|
|
1489
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1490
|
+
// AsyncLocalStorage is the 90% case; workerd has it via nodejs_als
|
|
1491
|
+
// (auto-on at compat date 2026-04-01). createHook is also present
|
|
1492
|
+
// in workerd as a non-functional stub.
|
|
1493
|
+
const __asyncHooksMod = (() => {
|
|
1494
|
+
const real = (typeof __real_async_hooks !== 'undefined') ? (__real_async_hooks.default ?? __real_async_hooks) : null;
|
|
1495
|
+
if (real && typeof real.AsyncLocalStorage === 'function') return real;
|
|
1496
|
+
// Defensive fallback.
|
|
1497
|
+
return {
|
|
1498
|
+
AsyncLocalStorage: class { run(_s, fn, ...args) { return fn(...args); } getStore() { return undefined; } enterWith() {} disable() {} exit(fn, ...args) { return fn(...args); } },
|
|
1499
|
+
AsyncResource: class { runInAsyncScope(fn, thisArg, ...args) { return fn.apply(thisArg, args); } bind(fn) { return fn; } asyncId() { return 0; } triggerAsyncId() { return 0; } emitDestroy() {} },
|
|
1500
|
+
createHook: () => ({ enable() { return this; }, disable() { return this; } }),
|
|
1501
|
+
executionAsyncId: () => 0,
|
|
1502
|
+
executionAsyncResource: () => null,
|
|
1503
|
+
triggerAsyncId: () => 0,
|
|
1504
|
+
};
|
|
1505
|
+
})();
|
|
1506
|
+
|
|
1507
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1508
|
+
// ── assert module ──────────────────────────────────────────────────
|
|
1509
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1510
|
+
const __assertMod = Object.assign(
|
|
1511
|
+
(v, m) => { if (!v) { const e = new Error(m || "AssertionError"); e.code = "ERR_ASSERTION"; throw e; } },
|
|
1512
|
+
{
|
|
1513
|
+
ok: (v, m) => { if (!v) { const e = new Error(m || "The expression evaluated to a falsy value"); e.code = "ERR_ASSERTION"; throw e; } },
|
|
1514
|
+
equal: (a, b, m) => { if (a != b) { const e = new Error(m || __fmt(a) + " != " + __fmt(b)); e.code = "ERR_ASSERTION"; throw e; } },
|
|
1515
|
+
notEqual: (a, b, m) => { if (a == b) { const e = new Error(m || __fmt(a) + " == " + __fmt(b)); e.code = "ERR_ASSERTION"; throw e; } },
|
|
1516
|
+
strictEqual: (a, b, m) => { if (a !== b) { const e = new Error(m || __fmt(a) + " !== " + __fmt(b)); e.code = "ERR_ASSERTION"; throw e; } },
|
|
1517
|
+
notStrictEqual: (a, b, m) => { if (a === b) { const e = new Error(m || "Values are strictly equal"); e.code = "ERR_ASSERTION"; throw e; } },
|
|
1518
|
+
deepEqual: (a, b, m) => { if (JSON.stringify(a) !== JSON.stringify(b)) { const e = new Error(m || "deepEqual failed"); e.code = "ERR_ASSERTION"; throw e; } },
|
|
1519
|
+
deepStrictEqual: (a, b, m) => __assertMod.deepEqual(a, b, m),
|
|
1520
|
+
throws: (fn, m) => { try { fn(); } catch { return; } const e = new Error(m || "Missing expected exception"); e.code = "ERR_ASSERTION"; throw e; },
|
|
1521
|
+
doesNotThrow: (fn, m) => { try { fn(); } catch (ex) { const e = new Error(m || "Got unwanted exception: " + ex.message); e.code = "ERR_ASSERTION"; throw e; } },
|
|
1522
|
+
ifError: (v) => { if (v) throw v; },
|
|
1523
|
+
fail: (m) => { const e = new Error(m || "Failed"); e.code = "ERR_ASSERTION"; throw e; },
|
|
1524
|
+
}
|
|
1525
|
+
);
|
|
1526
|
+
|
|
1527
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1528
|
+
// ── querystring, string_decoder, child_process (stubs) ─────────────
|
|
1529
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1530
|
+
const __qsMod = {
|
|
1531
|
+
stringify: (o, sep, eq) => Object.entries(o || {}).map(([k,v]) => encodeURIComponent(k) + (eq||"=") + encodeURIComponent(String(v))).join(sep||"&"),
|
|
1532
|
+
parse: (s, sep, eq) => Object.fromEntries(new URLSearchParams(s)),
|
|
1533
|
+
escape: encodeURIComponent,
|
|
1534
|
+
unescape: decodeURIComponent,
|
|
1535
|
+
};
|
|
1536
|
+
|
|
1537
|
+
const __stringDecoderMod = {
|
|
1538
|
+
StringDecoder: class { constructor(enc) { this.enc = enc || "utf8"; this._dec = new TextDecoder(this.enc); } write(buf) { return this._dec.decode(buf, { stream: true }); } end(buf) { return buf ? this._dec.decode(buf) : ""; } },
|
|
1539
|
+
};
|
|
1540
|
+
|
|
1541
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1542
|
+
// ── child_process — W8 facet-mapped impl ──────────────────────────
|
|
1543
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
1544
|
+
//
|
|
1545
|
+
// Routes through __supervisor.cp{Spawn,StdinWrite,StdinEnd,ReadOutput,
|
|
1546
|
+
// DrainOutput,Kill,Wait}. When __supervisor is unavailable (rare — the
|
|
1547
|
+
// facet is normally instantiated with one), every API surfaces a clean
|
|
1548
|
+
// ERR_CHILD_PROCESS_UNAVAILABLE error rather than silently returning
|
|
1549
|
+
// success.
|
|
1550
|
+
//
|
|
1551
|
+
// Key differences from the pre-W8 stub:
|
|
1552
|
+
// 1. spawn() actually spawns. Returns a ChildProcess emitter whose
|
|
1553
|
+
// stdio streams are real workerd Readable/Writable instances.
|
|
1554
|
+
// 2. exec/execFile route through spawn (Node-doc semantics). The
|
|
1555
|
+
// callback fires (err, stdout, stderr) once the child exits.
|
|
1556
|
+
// 3. fork() establishes a JSON-newline IPC channel via the stdin
|
|
1557
|
+
// queue. ChildProcess.send(msg)→cpStdinWrite of JSON.stringify(msg)+'\\n'.
|
|
1558
|
+
// Phase 1 limit: messages are JSON, NOT v8.serialize. Buffer/Date
|
|
1559
|
+
// project to their JSON shapes ({type:'Buffer',data:[...]} and
|
|
1560
|
+
// ISO strings respectively). Documented in cp-fork-ipc.mjs probe.
|
|
1561
|
+
// 4. spawnSync/execSync are FAKE-SYNC: they kick off the async spawn
|
|
1562
|
+
// and return a sentinel that resolves under a normal microtask
|
|
1563
|
+
// drain. The facet's existing __pendingIO drain handles the rest.
|
|
1564
|
+
// cross-spawn.sync uses execSync; husky uses spawnSync for git
|
|
1565
|
+
// config queries — both rely on this fake-sync working.
|
|
1566
|
+
// 5. Live children are tracked in __cpChildren so the facet's exit-
|
|
1567
|
+
// time drain (see __cpDrainAllChildren below) can issue a
|
|
1568
|
+
// cpDrainOutput RPC for each before reportExit fires. This is
|
|
1569
|
+
// the BLOCKER-1 fix from W8-plan §8.5: without it, output from
|
|
1570
|
+
// unawaited children dies between the last 'data' poll and the
|
|
1571
|
+
// facet's reportExit.
|
|
1572
|
+
const __cpChildren = new Map(); // pid → ChildProcess (for exit-time drain)
|
|
1573
|
+
|
|
1574
|
+
const __childProcessMod = (() => {
|
|
1575
|
+
const HAS_SUPERVISOR = !!(__supervisor && typeof __supervisor.cpSpawn === "function");
|
|
1576
|
+
|
|
1577
|
+
/**
|
|
1578
|
+
* Create a workerd-PassThrough that auto-resumes when a 'data' listener
|
|
1579
|
+
* is attached. Nimbus's __streamMod.Readable does NOT auto-resume on
|
|
1580
|
+
* addListener('data') the way real Node does, so we patch in the
|
|
1581
|
+
* behaviour by overriding addListener/on for 'data'. Without this,
|
|
1582
|
+
* cross-spawn-style consumers that call .on('data', cb) never see
|
|
1583
|
+
* chunks (the Readable buffer fills, flowing stays null).
|
|
1584
|
+
*/
|
|
1585
|
+
function _makeReadable() {
|
|
1586
|
+
const r = new __streamMod.PassThrough();
|
|
1587
|
+
// Default encoding to utf8 so consumers see strings (matches the
|
|
1588
|
+
// common cross-spawn / husky pattern of reading text). Callers can
|
|
1589
|
+
// override via .setEncoding('hex'), .setEncoding(null), etc.
|
|
1590
|
+
let _encoding = "utf8";
|
|
1591
|
+
r.setEncoding = function(enc) { _encoding = enc; return r; };
|
|
1592
|
+
const origOn = r.on.bind(r);
|
|
1593
|
+
function patched(event, listener) {
|
|
1594
|
+
// Wrap data listener to decode bytes per current encoding.
|
|
1595
|
+
if (event === "data" && typeof listener === "function") {
|
|
1596
|
+
const wrapped = (chunk) => {
|
|
1597
|
+
let out = chunk;
|
|
1598
|
+
if (_encoding && (chunk instanceof Uint8Array)) {
|
|
1599
|
+
try { out = new TextDecoder(_encoding === "buffer" ? "utf-8" : _encoding).decode(chunk); }
|
|
1600
|
+
catch { out = chunk; }
|
|
1601
|
+
}
|
|
1602
|
+
return listener(out);
|
|
1603
|
+
};
|
|
1604
|
+
// Stash so removeListener still works against the original.
|
|
1605
|
+
listener.__wrapped = wrapped;
|
|
1606
|
+
const result = origOn("data", wrapped);
|
|
1607
|
+
if (typeof r.resume === "function") {
|
|
1608
|
+
try { r.resume(); } catch {}
|
|
1609
|
+
}
|
|
1610
|
+
return result;
|
|
1611
|
+
}
|
|
1612
|
+
return origOn(event, listener);
|
|
1613
|
+
}
|
|
1614
|
+
r.on = patched;
|
|
1615
|
+
r.addListener = patched;
|
|
1616
|
+
return r;
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
/**
|
|
1620
|
+
* Create a workerd-Writable backed by cpStdinWrite RPC.
|
|
1621
|
+
* Decodes Uint8Array chunks to UTF-8 strings before pushing to RPC
|
|
1622
|
+
* (workerd's Writable encodes string→bytes internally; we need to
|
|
1623
|
+
* round-trip back to a string for the supervisor's stdin queue).
|
|
1624
|
+
*/
|
|
1625
|
+
function _toUtf8(chunk) {
|
|
1626
|
+
if (typeof chunk === "string") return chunk;
|
|
1627
|
+
if (chunk instanceof Uint8Array) {
|
|
1628
|
+
try { return new TextDecoder("utf-8").decode(chunk); } catch { return String(chunk); }
|
|
1629
|
+
}
|
|
1630
|
+
return String(chunk);
|
|
1631
|
+
}
|
|
1632
|
+
function _makeWritable(child) {
|
|
1633
|
+
const w = new __streamMod.Writable({
|
|
1634
|
+
write(chunk, enc, cb) {
|
|
1635
|
+
const s = _toUtf8(chunk);
|
|
1636
|
+
if (!child.pid) {
|
|
1637
|
+
// Child not yet spawned — buffer until pid available.
|
|
1638
|
+
child._pendingStdin = child._pendingStdin || [];
|
|
1639
|
+
child._pendingStdin.push(s);
|
|
1640
|
+
cb();
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1643
|
+
if (!HAS_SUPERVISOR) { cb(new Error("ERR_CHILD_PROCESS_UNAVAILABLE")); return; }
|
|
1644
|
+
Promise.resolve(__supervisor.cpStdinWrite(child.pid, s))
|
|
1645
|
+
.then(() => cb())
|
|
1646
|
+
.catch((e) => cb(e));
|
|
1647
|
+
},
|
|
1648
|
+
final(cb) {
|
|
1649
|
+
if (!child.pid) { cb(); return; }
|
|
1650
|
+
if (!HAS_SUPERVISOR) { cb(); return; }
|
|
1651
|
+
Promise.resolve(__supervisor.cpStdinEnd(child.pid))
|
|
1652
|
+
.then(() => cb())
|
|
1653
|
+
.catch(() => cb()); // best-effort end
|
|
1654
|
+
},
|
|
1655
|
+
});
|
|
1656
|
+
return w;
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
/** Normalize stdio config to a 3-tuple of 'pipe'|'ignore'|'inherit'. */
|
|
1660
|
+
function _normalizeStdio(stdio) {
|
|
1661
|
+
if (!stdio) return ["pipe", "pipe", "pipe"];
|
|
1662
|
+
if (Array.isArray(stdio)) {
|
|
1663
|
+
const a = stdio.slice(0, 3);
|
|
1664
|
+
while (a.length < 3) a.push("pipe");
|
|
1665
|
+
return a.map((v) => (v === "ignore" || v === "inherit" || v === "pipe") ? v : "pipe");
|
|
1666
|
+
}
|
|
1667
|
+
if (stdio === "ignore" || stdio === "inherit" || stdio === "pipe") return [stdio, stdio, stdio];
|
|
1668
|
+
return ["pipe", "pipe", "pipe"];
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
/** Build a fresh ChildProcess emitter with real streams. */
|
|
1672
|
+
function _makeChild(opts) {
|
|
1673
|
+
const stdio = _normalizeStdio((opts || {}).stdio);
|
|
1674
|
+
const child = new __eventsMod();
|
|
1675
|
+
child.pid = 0;
|
|
1676
|
+
child.connected = false;
|
|
1677
|
+
child.killed = false;
|
|
1678
|
+
child.exitCode = null;
|
|
1679
|
+
child.signalCode = null;
|
|
1680
|
+
// For 'inherit' or 'ignore', set the corresponding stream to null
|
|
1681
|
+
// (Node-doc semantics). 'inherit' → parent's stdio; we don't have
|
|
1682
|
+
// one, so null is the closest honest value. Consumers that try to
|
|
1683
|
+
// attach .on('data', ...) on null will throw — same as real Node.
|
|
1684
|
+
child.stdin = stdio[0] === "pipe" ? _makeWritable(child) : null;
|
|
1685
|
+
child.stdout = stdio[1] === "pipe" ? _makeReadable() : null;
|
|
1686
|
+
child.stderr = stdio[2] === "pipe" ? _makeReadable() : null;
|
|
1687
|
+
child.stdio = [child.stdin, child.stdout, child.stderr];
|
|
1688
|
+
child._pendingKill = null; // {signal} if kill called before pid
|
|
1689
|
+
child._exitFired = false;
|
|
1690
|
+
child._closeFired = false;
|
|
1691
|
+
// For non-piped fds, treat them as already-ended so 'close' can
|
|
1692
|
+
// fire after exit without waiting for end events that never come.
|
|
1693
|
+
child._stdoutEnded = stdio[1] !== "pipe";
|
|
1694
|
+
child._stderrEnded = stdio[2] !== "pipe";
|
|
1695
|
+
// Listen to the underlying streams' 'end' events so 'close' fires
|
|
1696
|
+
// only after actual data has flushed.
|
|
1697
|
+
if (child.stdout) {
|
|
1698
|
+
child.stdout.on("end", () => { child._stdoutEnded = true; _maybeFireClose(child); });
|
|
1699
|
+
}
|
|
1700
|
+
if (child.stderr) {
|
|
1701
|
+
child.stderr.on("end", () => { child._stderrEnded = true; _maybeFireClose(child); });
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
child.kill = function(signal) {
|
|
1705
|
+
// Node semantics: kill() returns true even on already-exited
|
|
1706
|
+
// children (it's a best-effort syscall). Reserve false for "no
|
|
1707
|
+
// pid known" (kill called before spawn settled and we have
|
|
1708
|
+
// nothing to queue).
|
|
1709
|
+
const sig = signal || "SIGTERM";
|
|
1710
|
+
child.killed = true;
|
|
1711
|
+
if (child._exitFired) return true;
|
|
1712
|
+
if (!child.pid) { child._pendingKill = { signal: sig }; return true; }
|
|
1713
|
+
if (!HAS_SUPERVISOR) return true;
|
|
1714
|
+
__pendingIO.push(
|
|
1715
|
+
Promise.resolve(__supervisor.cpKill(child.pid, sig)).catch(() => {}),
|
|
1716
|
+
);
|
|
1717
|
+
return true;
|
|
1718
|
+
};
|
|
1719
|
+
child.ref = function() { return child; };
|
|
1720
|
+
child.unref = function() { return child; };
|
|
1721
|
+
child.disconnect = function() {
|
|
1722
|
+
child.connected = false;
|
|
1723
|
+
try { child.emit("disconnect"); } catch {}
|
|
1724
|
+
};
|
|
1725
|
+
|
|
1726
|
+
return child;
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
/**
|
|
1730
|
+
* Coalesce the close event: emit only after exit AND both streams
|
|
1731
|
+
* have ended. Once close fires, evict the child from __cpChildren so
|
|
1732
|
+
* a long-running parent that spawns thousands of children doesn't
|
|
1733
|
+
* leak ChildProcess emitters + PassThrough buffers into memory.
|
|
1734
|
+
*/
|
|
1735
|
+
function _maybeFireClose(child) {
|
|
1736
|
+
if (child._exitFired && child._stdoutEnded && child._stderrEnded && !child._closeFired) {
|
|
1737
|
+
child._closeFired = true;
|
|
1738
|
+
try { child.emit("close", child.exitCode, child.signalCode); } catch {}
|
|
1739
|
+
// Evict from the live-children map after a microtask so any
|
|
1740
|
+
// close listeners that re-read child state see consistent values.
|
|
1741
|
+
queueMicrotask(() => {
|
|
1742
|
+
try { if (child.pid) __cpChildren.delete(child.pid); } catch {}
|
|
1743
|
+
});
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
/**
|
|
1748
|
+
* Read-loop for a single fd. Long-polls cpReadOutput, pushes chunks
|
|
1749
|
+
* into the Readable via .push, handles closure.
|
|
1750
|
+
*/
|
|
1751
|
+
async function _runReadLoop(child, fd, stream, sinceSeqRef) {
|
|
1752
|
+
// Exponential backoff for idle children: start at 100ms, double up
|
|
1753
|
+
// to 1500ms cap. Reset to 100ms whenever a chunk arrives. Caps
|
|
1754
|
+
// workerd subrequest budget consumption for many concurrent
|
|
1755
|
+
// children — a 30-way 'concurrently' would otherwise sustain 60
|
|
1756
|
+
// in-flight RPCs at 250ms intervals.
|
|
1757
|
+
let backoff = 100;
|
|
1758
|
+
const BACKOFF_MAX = 1500;
|
|
1759
|
+
while (HAS_SUPERVISOR && child.pid && !child._streamsClosed) {
|
|
1760
|
+
try {
|
|
1761
|
+
const r = await __supervisor.cpReadOutput(child.pid, fd, sinceSeqRef.value, backoff);
|
|
1762
|
+
if (r && Array.isArray(r.chunks) && r.chunks.length > 0) {
|
|
1763
|
+
backoff = 100; // reset — child is producing
|
|
1764
|
+
for (const c of r.chunks) {
|
|
1765
|
+
stream.write(c.data);
|
|
1766
|
+
if (typeof c.seq === "number" && c.seq > sinceSeqRef.value) {
|
|
1767
|
+
sinceSeqRef.value = c.seq;
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
} else {
|
|
1771
|
+
backoff = Math.min(backoff * 2, BACKOFF_MAX);
|
|
1772
|
+
}
|
|
1773
|
+
if (r && r.closed) {
|
|
1774
|
+
stream.end();
|
|
1775
|
+
// _stdoutEnded / _stderrEnded flag is set in the stream's
|
|
1776
|
+
// 'end' listener (see _makeChild) so 'close' fires AFTER
|
|
1777
|
+
// actual data flushes.
|
|
1778
|
+
break;
|
|
1779
|
+
}
|
|
1780
|
+
} catch (e) {
|
|
1781
|
+
// RPC failure → close the stream and bail.
|
|
1782
|
+
stream.end();
|
|
1783
|
+
break;
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
/**
|
|
1789
|
+
* Wait-loop: long-poll cpWait until the child reports exit. Emits
|
|
1790
|
+
* 'exit' once stamped.
|
|
1791
|
+
*/
|
|
1792
|
+
async function _runWaitLoop(child) {
|
|
1793
|
+
while (HAS_SUPERVISOR && child.pid && !child._exitFired) {
|
|
1794
|
+
try {
|
|
1795
|
+
const r = await __supervisor.cpWait(child.pid, 1000);
|
|
1796
|
+
if (r && r.done) {
|
|
1797
|
+
child.exitCode = r.exitCode;
|
|
1798
|
+
child.signalCode = r.signal;
|
|
1799
|
+
child._exitFired = true;
|
|
1800
|
+
try { child.emit("exit", r.exitCode, r.signal || null); } catch {}
|
|
1801
|
+
_maybeFireClose(child);
|
|
1802
|
+
break;
|
|
1803
|
+
}
|
|
1804
|
+
} catch (e) {
|
|
1805
|
+
// Couldn't wait — synthesize an error exit.
|
|
1806
|
+
child.exitCode = 1;
|
|
1807
|
+
child._exitFired = true;
|
|
1808
|
+
try { child.emit("exit", 1, null); } catch {}
|
|
1809
|
+
_maybeFireClose(child);
|
|
1810
|
+
break;
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
/**
|
|
1816
|
+
* Internal spawn primitive. Always returns a ChildProcess emitter;
|
|
1817
|
+
* any failure (no supervisor, bad cmd) surfaces via 'error' + 'exit'
|
|
1818
|
+
* events, never a synchronous throw.
|
|
1819
|
+
*/
|
|
1820
|
+
function _spawn(cmd, args, opts) {
|
|
1821
|
+
if (args && typeof args === "object" && !Array.isArray(args)) { opts = args; args = []; }
|
|
1822
|
+
args = args || [];
|
|
1823
|
+
opts = opts || {};
|
|
1824
|
+
const child = _makeChild(opts);
|
|
1825
|
+
|
|
1826
|
+
if (!HAS_SUPERVISOR) {
|
|
1827
|
+
queueMicrotask(() => {
|
|
1828
|
+
const err = Object.assign(new Error("ERR_CHILD_PROCESS_UNAVAILABLE"), {
|
|
1829
|
+
code: "ERR_CHILD_PROCESS_UNAVAILABLE", cmd,
|
|
1830
|
+
});
|
|
1831
|
+
try { child.emit("error", err); } catch {}
|
|
1832
|
+
child._exitFired = true;
|
|
1833
|
+
try { child.emit("exit", 1, null); } catch {}
|
|
1834
|
+
// End the streams synchronously; their 'end' listeners flip the
|
|
1835
|
+
// _stdoutEnded/_stderrEnded flags and trigger _maybeFireClose.
|
|
1836
|
+
try { child.stdout && child.stdout.end(); } catch {}
|
|
1837
|
+
try { child.stderr && child.stderr.end(); } catch {}
|
|
1838
|
+
_maybeFireClose(child);
|
|
1839
|
+
});
|
|
1840
|
+
return child;
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1843
|
+
// Issue cpSpawn asynchronously. Return the emitter immediately so
|
|
1844
|
+
// callers can attach 'data' listeners before any chunk arrives.
|
|
1845
|
+
__pendingIO.push((async () => {
|
|
1846
|
+
try {
|
|
1847
|
+
const r = await __supervisor.cpSpawn({
|
|
1848
|
+
command: cmd,
|
|
1849
|
+
args,
|
|
1850
|
+
env: { ...(__processMod.env || {}), ...(opts.env || {}) },
|
|
1851
|
+
cwd: opts.cwd || cwd || "/home/user",
|
|
1852
|
+
stdio: opts.stdio || ["pipe", "pipe", "pipe"],
|
|
1853
|
+
detached: !!opts.detached,
|
|
1854
|
+
shell: opts.shell || false,
|
|
1855
|
+
});
|
|
1856
|
+
child.pid = r.childPid;
|
|
1857
|
+
child.connected = true;
|
|
1858
|
+
__cpChildren.set(child.pid, child);
|
|
1859
|
+
try { child.emit("spawn"); } catch {}
|
|
1860
|
+
|
|
1861
|
+
// Flush any stdin written before pid was known.
|
|
1862
|
+
if (child._pendingStdin && child._pendingStdin.length > 0) {
|
|
1863
|
+
for (const d of child._pendingStdin) {
|
|
1864
|
+
__pendingIO.push(__supervisor.cpStdinWrite(child.pid, d).catch(() => {}));
|
|
1865
|
+
}
|
|
1866
|
+
child._pendingStdin = null;
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
// Flush a queued kill if .kill() was called before pid landed.
|
|
1870
|
+
if (child._pendingKill) {
|
|
1871
|
+
const sig = child._pendingKill.signal;
|
|
1872
|
+
child._pendingKill = null;
|
|
1873
|
+
__pendingIO.push(__supervisor.cpKill(child.pid, sig).catch(() => {}));
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
// Start the loops. Each of these is its own async task pushed
|
|
1877
|
+
// onto __pendingIO so the facet's main drain knows to await.
|
|
1878
|
+
// For non-piped fds (stdio: 'inherit' or 'ignore'), the stream
|
|
1879
|
+
// is null and we skip the read-loop entirely.
|
|
1880
|
+
const stdoutSeq = { value: 0 };
|
|
1881
|
+
const stderrSeq = { value: 0 };
|
|
1882
|
+
if (child.stdout) __pendingIO.push(_runReadLoop(child, 1, child.stdout, stdoutSeq));
|
|
1883
|
+
if (child.stderr) __pendingIO.push(_runReadLoop(child, 2, child.stderr, stderrSeq));
|
|
1884
|
+
__pendingIO.push(_runWaitLoop(child));
|
|
1885
|
+
} catch (e) {
|
|
1886
|
+
try { child.emit("error", e); } catch {}
|
|
1887
|
+
child._exitFired = true;
|
|
1888
|
+
try { child.emit("exit", 1, null); } catch {}
|
|
1889
|
+
try { child.stdout && child.stdout.end(); } catch {}
|
|
1890
|
+
try { child.stderr && child.stderr.end(); } catch {}
|
|
1891
|
+
_maybeFireClose(child);
|
|
1892
|
+
}
|
|
1893
|
+
})());
|
|
1894
|
+
|
|
1895
|
+
return child;
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
/**
|
|
1899
|
+
* exec(cmd, opts, cb) — Node semantics: passes cmd to a shell
|
|
1900
|
+
* (we use 'sh -c'). Buffers stdout/stderr; cb fires once on exit.
|
|
1901
|
+
*/
|
|
1902
|
+
function exec(cmd, opts, cb) {
|
|
1903
|
+
if (typeof opts === "function") { cb = opts; opts = {}; }
|
|
1904
|
+
opts = opts || {};
|
|
1905
|
+
// Use sh -c so shell metacharacters work for husky/concurrently/etc.
|
|
1906
|
+
const child = _spawn("sh", ["-c", cmd], { ...opts, shell: true });
|
|
1907
|
+
let stdout = "", stderr = "";
|
|
1908
|
+
child.stdout.on("data", (d) => { stdout += String(d); });
|
|
1909
|
+
child.stderr.on("data", (d) => { stderr += String(d); });
|
|
1910
|
+
// Use 'close' (fires after exit AND both stdio streams ended) so all
|
|
1911
|
+
// chunks have landed before cb resolves.
|
|
1912
|
+
child.on("close", (code) => {
|
|
1913
|
+
if (cb) {
|
|
1914
|
+
if (code === 0) cb(null, stdout, stderr);
|
|
1915
|
+
else {
|
|
1916
|
+
const err = Object.assign(new Error("Command failed: " + cmd), {
|
|
1917
|
+
code, cmd, stdout, stderr,
|
|
1918
|
+
});
|
|
1919
|
+
cb(err, stdout, stderr);
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
});
|
|
1923
|
+
return child;
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
/**
|
|
1927
|
+
* execFile(file, args, opts, cb) — like exec but no shell.
|
|
1928
|
+
*/
|
|
1929
|
+
function execFile(file, args, opts, cb) {
|
|
1930
|
+
if (typeof args === "function") { cb = args; args = []; opts = {}; }
|
|
1931
|
+
if (typeof opts === "function") { cb = opts; opts = {}; }
|
|
1932
|
+
opts = opts || {};
|
|
1933
|
+
const child = _spawn(file, args || [], { ...opts, shell: false });
|
|
1934
|
+
let stdout = "", stderr = "";
|
|
1935
|
+
child.stdout.on("data", (d) => { stdout += String(d); });
|
|
1936
|
+
child.stderr.on("data", (d) => { stderr += String(d); });
|
|
1937
|
+
child.on("close", (code) => {
|
|
1938
|
+
if (cb) {
|
|
1939
|
+
if (code === 0) cb(null, stdout, stderr);
|
|
1940
|
+
else {
|
|
1941
|
+
const err = Object.assign(new Error("Command failed: " + file), {
|
|
1942
|
+
code, stdout, stderr,
|
|
1943
|
+
});
|
|
1944
|
+
cb(err, stdout, stderr);
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
});
|
|
1948
|
+
return child;
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
/**
|
|
1952
|
+
* Fake-sync spawn. Phase-1 limit: V8/Workers can't truly block JS
|
|
1953
|
+
* execution. We approximate "synchronous" semantics by:
|
|
1954
|
+
* 1. Issuing the underlying _spawn (which queues async work onto
|
|
1955
|
+
* __pendingIO).
|
|
1956
|
+
* 2. Returning a result object that LAZILY accumulates fields as
|
|
1957
|
+
* stdout/stderr/exit events fire. Callers like cross-spawn.sync
|
|
1958
|
+
* that read result.status get null until the spawn settles.
|
|
1959
|
+
* 3. When the parent facet's main drain settles __pendingIO before
|
|
1960
|
+
* reportExit (facet-manager.ts), the result object's fields are
|
|
1961
|
+
* filled in by the time the supervisor sees the parent exit.
|
|
1962
|
+
*
|
|
1963
|
+
* Cross-spawn.sync's typical pattern is "const r = spawnSync(...);
|
|
1964
|
+
* if (r.status !== 0) throw". To make THIS work synchronously, we
|
|
1965
|
+
* also expose a .__deferred promise; idiomatic Nimbus consumers
|
|
1966
|
+
* await r.__deferred to get a fully-populated result. Probes test
|
|
1967
|
+
* both shapes.
|
|
1968
|
+
*
|
|
1969
|
+
* Real Node spawnSync truly blocks the event loop via libuv; matching
|
|
1970
|
+
* that semantic in workerd would require Atomics.wait on shared state
|
|
1971
|
+
* which workerd doesn't expose to userland. Phase 1 documents this.
|
|
1972
|
+
*/
|
|
1973
|
+
function spawnSync(cmd, args, opts) {
|
|
1974
|
+
if (args && typeof args === "object" && !Array.isArray(args)) { opts = args; args = []; }
|
|
1975
|
+
args = args || []; opts = opts || {};
|
|
1976
|
+
const child = _spawn(cmd, args, opts);
|
|
1977
|
+
let stdout = "", stderr = "";
|
|
1978
|
+
if (child.stdout) child.stdout.on("data", (d) => { stdout += String(d); });
|
|
1979
|
+
if (child.stderr) child.stderr.on("data", (d) => { stderr += String(d); });
|
|
1980
|
+
|
|
1981
|
+
const result = { pid: 0, stdout: "", stderr: "", status: null, signal: null, output: [null, "", ""] };
|
|
1982
|
+
let _done = false;
|
|
1983
|
+
result.__deferred = new Promise((resolve) => {
|
|
1984
|
+
child.on("close", (code, signal) => {
|
|
1985
|
+
result.pid = child.pid;
|
|
1986
|
+
result.stdout = stdout;
|
|
1987
|
+
result.stderr = stderr;
|
|
1988
|
+
result.status = code;
|
|
1989
|
+
result.signal = signal;
|
|
1990
|
+
result.output = [null, stdout, stderr];
|
|
1991
|
+
_done = true;
|
|
1992
|
+
resolve(result);
|
|
1993
|
+
});
|
|
1994
|
+
});
|
|
1995
|
+
// Best-effort eager population: as 'data' events flow we already
|
|
1996
|
+
// mutate stdout/stderr above; once 'exit' fires we also populate
|
|
1997
|
+
// .status synchronously (before 'close' which fires after streams
|
|
1998
|
+
// drain). This narrows the window where a sync caller sees
|
|
1999
|
+
// status=null.
|
|
2000
|
+
child.on("exit", (code, signal) => {
|
|
2001
|
+
if (result.status === null) result.status = code;
|
|
2002
|
+
if (result.signal === null) result.signal = signal;
|
|
2003
|
+
});
|
|
2004
|
+
return result;
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
function execSync(cmd, opts) {
|
|
2008
|
+
opts = opts || {};
|
|
2009
|
+
const r = spawnSync("sh", ["-c", cmd], { ...opts, shell: true });
|
|
2010
|
+
// Caller awaits __deferred under normal drain.
|
|
2011
|
+
return r;
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
function execFileSync(file, args, opts) {
|
|
2015
|
+
args = args || []; opts = opts || {};
|
|
2016
|
+
return spawnSync(file, args, opts);
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
/**
|
|
2020
|
+
* fork(modulePath, args, opts) — spawn a child node facet with an IPC
|
|
2021
|
+
* channel. IPC is JSON-newline over the stdin queue. Phase-1 limits:
|
|
2022
|
+
* - Buffer → {type:'Buffer', data:[...]} (JSON.stringify projection)
|
|
2023
|
+
* - Date → ISO string
|
|
2024
|
+
* - Map/Set lose all entries (become {})
|
|
2025
|
+
* Documented + asserted in cp-fork-ipc.mjs.
|
|
2026
|
+
*/
|
|
2027
|
+
function fork(modulePath, args, opts) {
|
|
2028
|
+
if (args && typeof args === "object" && !Array.isArray(args)) { opts = args; args = []; }
|
|
2029
|
+
args = args || []; opts = opts || {};
|
|
2030
|
+
// The child runs the requested module with __NIMBUS_FORK_IPC=1 in env
|
|
2031
|
+
// so a corresponding fork-aware runtime in the child knows to listen
|
|
2032
|
+
// on stdin for IPC frames.
|
|
2033
|
+
const childEnv = { ...(__processMod.env || {}), ...(opts.env || {}), NIMBUS_FORK_IPC: "1" };
|
|
2034
|
+
const child = _spawn("node", [modulePath, ...args], { ...opts, env: childEnv });
|
|
2035
|
+
child.connected = true;
|
|
2036
|
+
child.send = function(msg) {
|
|
2037
|
+
if (!child.connected) return false;
|
|
2038
|
+
if (!child.stdin) return false;
|
|
2039
|
+
try {
|
|
2040
|
+
const line = JSON.stringify(msg) + "\\n";
|
|
2041
|
+
child.stdin.write(line);
|
|
2042
|
+
return true;
|
|
2043
|
+
} catch (e) {
|
|
2044
|
+
return false;
|
|
2045
|
+
}
|
|
2046
|
+
};
|
|
2047
|
+
// 'message' events: parent listens to child.stdout newline-
|
|
2048
|
+
// delimited and parses each as JSON. Real Node IPC uses a side-
|
|
2049
|
+
// channel fd; Phase 1 multiplexes through stdout. Any well-formed
|
|
2050
|
+
// JSON line counts as a message — non-JSON lines are dropped
|
|
2051
|
+
// silently (real fork would route them to stderr-style handling).
|
|
2052
|
+
// No __nimbusIpc envelope: round-trip is symmetric with the
|
|
2053
|
+
// parent's child.send which writes raw JSON.stringify(msg)+'\\n'.
|
|
2054
|
+
child.stdout.on("data", (d) => {
|
|
2055
|
+
const lines = String(d).split("\\n");
|
|
2056
|
+
for (const line of lines) {
|
|
2057
|
+
const trimmed = line.trim();
|
|
2058
|
+
if (!trimmed) continue;
|
|
2059
|
+
let msg;
|
|
2060
|
+
try { msg = JSON.parse(trimmed); }
|
|
2061
|
+
catch { continue; }
|
|
2062
|
+
try { child.emit("message", msg); } catch {}
|
|
2063
|
+
}
|
|
2064
|
+
});
|
|
2065
|
+
child.on("exit", () => {
|
|
2066
|
+
child.connected = false;
|
|
2067
|
+
try { child.emit("disconnect"); } catch {}
|
|
2068
|
+
});
|
|
2069
|
+
return child;
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
/**
|
|
2073
|
+
* Exit-time drain: walk __cpChildren and issue cpDrainOutput RPCs so
|
|
2074
|
+
* any unawaited children's stdout lands before the facet's reportExit.
|
|
2075
|
+
* Called automatically by the facet's exit path AND exposed for tests.
|
|
2076
|
+
*/
|
|
2077
|
+
async function __cpDrainAllChildren() {
|
|
2078
|
+
if (!HAS_SUPERVISOR) return;
|
|
2079
|
+
const drains = [];
|
|
2080
|
+
for (const [pid, child] of __cpChildren) {
|
|
2081
|
+
drains.push((async () => {
|
|
2082
|
+
try {
|
|
2083
|
+
const r = await __supervisor.cpDrainOutput(pid);
|
|
2084
|
+
if (r && r.stdout && child.stdout) {
|
|
2085
|
+
try { child.stdout.write(r.stdout); } catch {}
|
|
2086
|
+
}
|
|
2087
|
+
if (r && r.stderr && child.stderr) {
|
|
2088
|
+
try { child.stderr.write(r.stderr); } catch {}
|
|
2089
|
+
}
|
|
2090
|
+
// Force-close streams so listeners receive 'end'. The 'end'
|
|
2091
|
+
// event listeners in _makeChild flip _stdoutEnded/_stderrEnded.
|
|
2092
|
+
try { child.stdout && child.stdout.end(); } catch {}
|
|
2093
|
+
try { child.stderr && child.stderr.end(); } catch {}
|
|
2094
|
+
if (!child._exitFired) {
|
|
2095
|
+
// No exit reported yet — wait briefly, then synthesize.
|
|
2096
|
+
try {
|
|
2097
|
+
const w = await __supervisor.cpWait(pid, 500);
|
|
2098
|
+
if (w && w.done) {
|
|
2099
|
+
child.exitCode = w.exitCode;
|
|
2100
|
+
child.signalCode = w.signal;
|
|
2101
|
+
} else {
|
|
2102
|
+
child.exitCode = child.exitCode == null ? 0 : child.exitCode;
|
|
2103
|
+
}
|
|
2104
|
+
} catch {
|
|
2105
|
+
child.exitCode = child.exitCode == null ? 0 : child.exitCode;
|
|
2106
|
+
}
|
|
2107
|
+
child._exitFired = true;
|
|
2108
|
+
try { child.emit("exit", child.exitCode, child.signalCode); } catch {}
|
|
2109
|
+
}
|
|
2110
|
+
_maybeFireClose(child);
|
|
2111
|
+
} catch { /* best-effort */ }
|
|
2112
|
+
})());
|
|
2113
|
+
}
|
|
2114
|
+
await Promise.allSettled(drains);
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
return {
|
|
2118
|
+
spawn: _spawn,
|
|
2119
|
+
spawnSync,
|
|
2120
|
+
exec,
|
|
2121
|
+
execSync,
|
|
2122
|
+
execFile,
|
|
2123
|
+
execFileSync,
|
|
2124
|
+
fork,
|
|
2125
|
+
ChildProcess: __eventsMod,
|
|
2126
|
+
__cpDrainAllChildren, // exposed for the facet exit hook + tests
|
|
2127
|
+
};
|
|
2128
|
+
})();
|
|
2129
|
+
|
|
2130
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
2131
|
+
// ── console shim ───────────────────────────────────────────────────
|
|
2132
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
2133
|
+
const __consoleMod = {
|
|
2134
|
+
log: (...a) => { stdout += __utilMod.format(...a) + "\\n"; },
|
|
2135
|
+
error: (...a) => { stderr += __utilMod.format(...a) + "\\n"; },
|
|
2136
|
+
warn: (...a) => { stderr += __utilMod.format(...a) + "\\n"; },
|
|
2137
|
+
info: (...a) => { stdout += __utilMod.format(...a) + "\\n"; },
|
|
2138
|
+
debug: (...a) => { stdout += __utilMod.format(...a) + "\\n"; },
|
|
2139
|
+
dir: (o, opts) => { stdout += __utilMod.inspect(o, opts) + "\\n"; },
|
|
2140
|
+
trace: (...a) => { stderr += "Trace: " + __utilMod.format(...a) + "\\n"; },
|
|
2141
|
+
assert: (c, ...a) => { if (!c) stderr += "Assertion failed: " + __utilMod.format(...a) + "\\n"; },
|
|
2142
|
+
time: () => {}, timeEnd: () => {}, timeLog: () => {}, clear: () => {},
|
|
2143
|
+
count: () => {}, countReset: () => {}, group: () => {}, groupEnd: () => {},
|
|
2144
|
+
table: (d) => { stdout += __utilMod.inspect(d) + "\\n"; },
|
|
2145
|
+
};
|
|
2146
|
+
|
|
2147
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
2148
|
+
// ── process shim ───────────────────────────────────────────────────
|
|
2149
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
2150
|
+
const __processMod = {
|
|
2151
|
+
argv: ["node", ...(argv || [])],
|
|
2152
|
+
env: env || {},
|
|
2153
|
+
cwd: () => cwd || "/home/user",
|
|
2154
|
+
chdir: (d) => { cwd = __pathMod.resolve(cwd || "/home/user", d); },
|
|
2155
|
+
exit: (code) => { exitCode = code ?? 0; throw new __ProcessExit(exitCode); },
|
|
2156
|
+
platform: "linux", arch: "x64",
|
|
2157
|
+
version: ${NODE_VERSION_LITERAL}, versions: ${NODE_VERSIONS_LITERAL},
|
|
2158
|
+
pid: 1, ppid: 0, title: "node",
|
|
2159
|
+
stdout: { write: (d) => { stdout += String(d); return true; }, isTTY: false },
|
|
2160
|
+
stderr: { write: (d) => { stderr += String(d); return true; }, isTTY: false },
|
|
2161
|
+
stdin: { read: () => null, on: () => __processMod.stdin, isTTY: false },
|
|
2162
|
+
hrtime: Object.assign(
|
|
2163
|
+
(prev) => { const n = Date.now(); const s = Math.floor(n / 1000); const ns = (n % 1000) * 1e6; if (!prev) return [s, ns]; return [s - prev[0], ns - prev[1]]; },
|
|
2164
|
+
{ bigint: () => BigInt(Date.now()) * 1000000n }
|
|
2165
|
+
),
|
|
2166
|
+
memoryUsage: () => ({ rss: 0, heapTotal: 0, heapUsed: 0, external: 0, arrayBuffers: 0 }),
|
|
2167
|
+
nextTick: (fn, ...a) => queueMicrotask(() => fn(...a)),
|
|
2168
|
+
on: () => __processMod, once: () => __processMod, emit: () => false,
|
|
2169
|
+
removeListener: () => __processMod, removeAllListeners: () => __processMod,
|
|
2170
|
+
uptime: () => 0, kill: () => {},
|
|
2171
|
+
umask: () => 0o022,
|
|
2172
|
+
binding: () => { throw new Error("process.binding is not supported"); },
|
|
2173
|
+
};
|
|
2174
|
+
|
|
2175
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
2176
|
+
// ── Builtins initialization (MUST come before require) ─────────────
|
|
2177
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
2178
|
+
const builtins = {};
|
|
2179
|
+
builtins.fs = __fsMod;
|
|
2180
|
+
builtins.path = __pathMod;
|
|
2181
|
+
builtins.os = __osMod;
|
|
2182
|
+
// framework-fixes-F1 (2026-05-12): 'node:constants' (legacy 'constants').
|
|
2183
|
+
// Pre-fix require('node:constants') threw "Cannot find module" because
|
|
2184
|
+
// the table didn't include it. create-next-app touches
|
|
2185
|
+
// constants.UV_FS_O_FILEMAP at module init; that crash blocked the entire
|
|
2186
|
+
// scaffold flow. See __constantsMod definition above for the full shape.
|
|
2187
|
+
builtins.constants = __constantsMod;
|
|
2188
|
+
// Also register under the 'node:'-prefixed key. __requireFrom (this
|
|
2189
|
+
// file ~line 2900) has a fast-path strip but the explicit registration
|
|
2190
|
+
// matches the dns/promises + util/types convention.
|
|
2191
|
+
builtins["node:constants"] = __constantsMod;
|
|
2192
|
+
builtins.events = __eventsMod;
|
|
2193
|
+
builtins.stream = __streamMod;
|
|
2194
|
+
// X.5-R: real Node's \`require('stream')\` re-exports EventEmitter
|
|
2195
|
+
// (verified: \`require('stream').EventEmitter === require('events').EventEmitter\`
|
|
2196
|
+
// in Node 20). Older CJS code reads EE off the stream module instead of
|
|
2197
|
+
// events — e.g., @redis/client/dist/lib/client/cache.js:301:
|
|
2198
|
+
// \`class ClientSideCacheProvider extends stream_1.EventEmitter {}\` where
|
|
2199
|
+
// \`stream_1 = require("stream")\`. Without this re-export, \`stream_1.EventEmitter\`
|
|
2200
|
+
// is undefined and \`class … extends undefined\` throws "Class extends value
|
|
2201
|
+
// undefined is not a constructor or null". See audit/sections/X5R-plan.md §3
|
|
2202
|
+
// + audit/probes/x5r/functional/r-stream-eventemitter-shape.mjs.
|
|
2203
|
+
// Idempotent guard so a future streams.ts revision that already exposes
|
|
2204
|
+
// EventEmitter doesn't get clobbered.
|
|
2205
|
+
if (!__streamMod.EventEmitter) __streamMod.EventEmitter = __eventsMod;
|
|
2206
|
+
builtins.buffer = { Buffer: __BufferMod };
|
|
2207
|
+
builtins.util = __utilMod;
|
|
2208
|
+
builtins.url = __urlMod;
|
|
2209
|
+
builtins.crypto = __cryptoMod;
|
|
2210
|
+
builtins.assert = __assertMod;
|
|
2211
|
+
builtins.querystring = __qsMod;
|
|
2212
|
+
builtins.string_decoder = __stringDecoderMod;
|
|
2213
|
+
builtins.child_process = __childProcessMod;
|
|
2214
|
+
builtins.process = __processMod;
|
|
2215
|
+
builtins.console = __consoleMod;
|
|
2216
|
+
builtins.http = (() => {
|
|
2217
|
+
if (!globalThis.__portRegistry) globalThis.__portRegistry = new Map();
|
|
2218
|
+
class ServerResponse extends __eventsMod {
|
|
2219
|
+
constructor() { super(); this.statusCode = 200; this.headers = {}; this._body = []; this._ended = false; }
|
|
2220
|
+
writeHead(code, hdrs) { this.statusCode = code; if (hdrs) Object.assign(this.headers, hdrs); return this; }
|
|
2221
|
+
setHeader(k, v) { this.headers[k.toLowerCase()] = v; return this; }
|
|
2222
|
+
getHeader(k) { return this.headers[k.toLowerCase()]; }
|
|
2223
|
+
write(chunk) { this._body.push(typeof chunk === "string" ? chunk : String(chunk)); return true; }
|
|
2224
|
+
end(data) { if (data) this.write(data); this._ended = true; this.emit("finish"); }
|
|
2225
|
+
get headersSent() { return this._ended; }
|
|
2226
|
+
}
|
|
2227
|
+
class IncomingMessage extends __eventsMod {
|
|
2228
|
+
constructor(u, m, h) { super(); this.url = u || "/"; this.method = m || "GET"; this.headers = h || {}; this.httpVersion = "1.1"; }
|
|
2229
|
+
}
|
|
2230
|
+
class Server extends __eventsMod {
|
|
2231
|
+
constructor(handler) { super(); if (handler) this.on("request", handler); this._port = 0; this._listening = false; }
|
|
2232
|
+
listen(port, host, cb) { if (typeof host === "function") { cb = host; } this._port = port || 0; this._listening = true; globalThis.__portRegistry.set(this._port, this); if (cb) queueMicrotask(cb); this.emit("listening"); return this; }
|
|
2233
|
+
close(cb) { this._listening = false; globalThis.__portRegistry.delete(this._port); if (cb) cb(); this.emit("close"); }
|
|
2234
|
+
get listening() { return this._listening; }
|
|
2235
|
+
// X.5-M (M-1): http.Server.setTimeout no-op for fastify.
|
|
2236
|
+
// fastify's lib/server.js calls server.setTimeout(connectionTimeout)
|
|
2237
|
+
// immediately after createServer(). Pre-X5M the Server class lacked
|
|
2238
|
+
// this method → "TypeError: server.setTimeout is not a function".
|
|
2239
|
+
// Mirror the net.Socket.setTimeout pattern at the bottom of this file
|
|
2240
|
+
// (same builtins/net IIFE): no-op + chainable. Idle timeouts have no
|
|
2241
|
+
// facet-side meaning (we don't own outbound TCP), but we honour the
|
|
2242
|
+
// 1-arg callback form so listeners that emit on 'timeout' still run.
|
|
2243
|
+
setTimeout(ms, cb) { if (typeof ms === "function") { cb = ms; } if (cb) this.on("timeout", cb); return this; }
|
|
2244
|
+
setKeepAlive() { return this; }
|
|
2245
|
+
address() { return { address: "0.0.0.0", port: this._port, family: "IPv4" }; }
|
|
2246
|
+
_handleRequest(u, m, h, b) { const req = new IncomingMessage(u, m, h); const res = new ServerResponse(); this.emit("request", req, res); if (b) { req.emit("data", b); req.emit("end"); } else { req.emit("end"); } return res; }
|
|
2247
|
+
}
|
|
2248
|
+
function createServer(o, h) { if (typeof o === "function") { h = o; } return new Server(h); }
|
|
2249
|
+
return { createServer, Server, IncomingMessage, ServerResponse, Agent: class {}, STATUS_CODES: {}, METHODS: ["GET","POST","PUT","DELETE","PATCH","HEAD","OPTIONS"], request: () => { throw new Error("Use fetch()"); }, get: () => { throw new Error("Use fetch()"); } };
|
|
2250
|
+
})();
|
|
2251
|
+
builtins.https = (() => {
|
|
2252
|
+
const hm = builtins.http;
|
|
2253
|
+
return {
|
|
2254
|
+
createServer: hm.createServer, Server: hm.Server, Agent: class {}, globalAgent: {},
|
|
2255
|
+
request: (url, opts, cb) => { if (typeof url === "string") url = new URL(url); if (typeof opts === "function") { cb = opts; opts = {}; } const req = new __eventsMod(); req.end = (body) => { fetch(url.href || url, { method: opts?.method || "GET", headers: opts?.headers, body }).then(async (resp) => { const res = new __eventsMod(); res.statusCode = resp.status; res.headers = Object.fromEntries(resp.headers); if (cb) cb(res); const text = await resp.text(); res.emit("data", text); res.emit("end"); }).catch((e) => req.emit("error", e)); }; req.write = () => req; req.on = (...a) => { __eventsMod.prototype.on.apply(req, a); return req; }; return req; },
|
|
2256
|
+
get: (url, opts, cb) => { const req = builtins.https.request(url, opts, cb); req.end(); return req; },
|
|
2257
|
+
};
|
|
2258
|
+
})();
|
|
2259
|
+
// W3 — net.Socket honest-error mode.
|
|
2260
|
+
//
|
|
2261
|
+
// Pre-W3 behaviour: \`new net.Socket().connect(443, 'example.com')\`
|
|
2262
|
+
// immediately fired the 'connect' event without any I/O — silent lie.
|
|
2263
|
+
// Anything attempting raw TCP from a facet (pg, mysql2, redis wire
|
|
2264
|
+
// protocols) thought it succeeded but produced no I/O.
|
|
2265
|
+
//
|
|
2266
|
+
// W3 behaviour: connect() emits 'error' with code
|
|
2267
|
+
// ERR_NET_SOCKET_NOT_AVAILABLE so callers fail loud. W8 will route
|
|
2268
|
+
// raw outbound TCP through supervisor RPC.
|
|
2269
|
+
builtins.net = (() => {
|
|
2270
|
+
class Socket extends __eventsMod {
|
|
2271
|
+
constructor() {
|
|
2272
|
+
super();
|
|
2273
|
+
this.connecting = false;
|
|
2274
|
+
this.destroyed = false;
|
|
2275
|
+
// Honest: we cannot send/receive bytes from a facet today.
|
|
2276
|
+
this.writable = false;
|
|
2277
|
+
this.readable = false;
|
|
2278
|
+
this.remoteAddress = null;
|
|
2279
|
+
this.remotePort = null;
|
|
2280
|
+
this.localAddress = "0.0.0.0";
|
|
2281
|
+
this.localPort = 0;
|
|
2282
|
+
}
|
|
2283
|
+
connect(port, host, cb) {
|
|
2284
|
+
if (typeof host === "function") { cb = host; host = "127.0.0.1"; }
|
|
2285
|
+
this.remoteAddress = host || "127.0.0.1";
|
|
2286
|
+
this.remotePort = port;
|
|
2287
|
+
const self = this;
|
|
2288
|
+
queueMicrotask(() => {
|
|
2289
|
+
const err = new Error(
|
|
2290
|
+
"net.Socket: outbound TCP from Nimbus facet not yet supported. " +
|
|
2291
|
+
"Use fetch() for HTTP/HTTPS. (W8 will route via supervisor RPC.)"
|
|
2292
|
+
);
|
|
2293
|
+
err.code = "ERR_NET_SOCKET_NOT_AVAILABLE";
|
|
2294
|
+
self.destroyed = true;
|
|
2295
|
+
self.emit("error", err);
|
|
2296
|
+
if (cb) cb(err);
|
|
2297
|
+
});
|
|
2298
|
+
return this;
|
|
2299
|
+
}
|
|
2300
|
+
write() { return false; }
|
|
2301
|
+
end(data, enc, cb) {
|
|
2302
|
+
if (typeof data === "function") { cb = data; data = undefined; }
|
|
2303
|
+
const self = this;
|
|
2304
|
+
queueMicrotask(() => { self.emit("end"); self.emit("close"); if (cb) cb(); });
|
|
2305
|
+
return this;
|
|
2306
|
+
}
|
|
2307
|
+
destroy(err) { this.destroyed = true; if (err) this.emit("error", err); this.emit("close"); return this; }
|
|
2308
|
+
setEncoding() { return this; }
|
|
2309
|
+
setTimeout() { return this; }
|
|
2310
|
+
setNoDelay() { return this; }
|
|
2311
|
+
setKeepAlive() { return this; }
|
|
2312
|
+
ref() { return this; }
|
|
2313
|
+
unref() { return this; }
|
|
2314
|
+
address() { return null; }
|
|
2315
|
+
}
|
|
2316
|
+
return {
|
|
2317
|
+
Socket,
|
|
2318
|
+
Server: builtins.http.Server,
|
|
2319
|
+
createServer: (o, h) => { if (typeof o === "function") { h = o; } return builtins.http.createServer(h); },
|
|
2320
|
+
createConnection: (p, h, cb) => new Socket().connect(p, h, cb),
|
|
2321
|
+
connect: (p, h, cb) => new Socket().connect(p, h, cb),
|
|
2322
|
+
isIP: (s) => /^\\d+\\.\\d+\\.\\d+\\.\\d+$/.test(s) ? 4 : 0,
|
|
2323
|
+
isIPv4: (s) => /^\\d+\\.\\d+\\.\\d+\\.\\d+$/.test(s),
|
|
2324
|
+
isIPv6: () => false,
|
|
2325
|
+
};
|
|
2326
|
+
})();
|
|
2327
|
+
builtins.dns = (() => {
|
|
2328
|
+
async function _doh(h, t) { try { const r = await fetch("https://cloudflare-dns.com/dns-query?name="+encodeURIComponent(h)+"&type="+(t||"A"),{headers:{"Accept":"application/dns-json"}}); const d = await r.json(); return (d.Answer||[]).map(a=>a.data).filter(Boolean); } catch { return []; } }
|
|
2329
|
+
return { resolve: (h,t,cb) => { if (typeof t==="function"){cb=t;t="A";} _doh(h,t).then(a=>cb(null,a.length?a:["127.0.0.1"])).catch(e=>cb(e)); }, resolve4: (h,cb) => _doh(h,"A").then(a=>cb(null,a.length?a:["127.0.0.1"])).catch(e=>cb(e)), resolve6: (h,cb) => _doh(h,"AAAA").then(a=>cb(null,a)).catch(e=>cb(e)), lookup: (h,o,cb) => { if(typeof o==="function"){cb=o;} if(h==="localhost"){cb(null,"127.0.0.1",4);return;} _doh(h,"A").then(a=>cb(null,a[0]||"127.0.0.1",4)).catch(e=>cb(e)); }, promises: { resolve: (h,t) => _doh(h,t||"A"), resolve4: (h) => _doh(h,"A"), lookup: async(h) => { if(h==="localhost") return {address:"127.0.0.1",family:4}; const a=await _doh(h,"A"); return {address:a[0]||"127.0.0.1",family:4}; } } };
|
|
2330
|
+
})();
|
|
2331
|
+
builtins.tty = { isatty: () => false, ReadStream: class extends __streamMod.Readable { constructor() { super(); this.isTTY = false; } }, WriteStream: class extends __streamMod.Writable { constructor() { super(); this.isTTY = false; this.columns = 80; this.rows = 24; } } };
|
|
2332
|
+
builtins.module = { get builtinModules() { return Object.keys(builtins); }, createRequire: () => __require, _resolveFilename: (id) => id, _cache: {} };
|
|
2333
|
+
builtins.timers = { setTimeout: globalThis.setTimeout, setInterval: globalThis.setInterval, clearTimeout: globalThis.clearTimeout, clearInterval: globalThis.clearInterval, setImmediate: (fn,...a) => setTimeout(fn,0,...a), clearImmediate: clearTimeout };
|
|
2334
|
+
builtins.zlib = (() => {
|
|
2335
|
+
function _c(d,a) { const i=typeof d==="string"?new TextEncoder().encode(d):d; return new Response(new Blob([i]).stream().pipeThrough(new CompressionStream(a))).arrayBuffer().then(ab=>__BufferMod.from(new Uint8Array(ab))); }
|
|
2336
|
+
function _d(d,a) { const i=d instanceof Uint8Array?d:new Uint8Array(d); return new Response(new Blob([i]).stream().pipeThrough(new DecompressionStream(a))).arrayBuffer().then(ab=>__BufferMod.from(new Uint8Array(ab))); }
|
|
2337
|
+
return { gzip:(d,o,cb)=>{if(typeof o==="function")cb=o;_c(d,"gzip").then(r=>cb(null,r)).catch(e=>cb(e));}, gunzip:(d,o,cb)=>{if(typeof o==="function")cb=o;_d(d,"gzip").then(r=>cb(null,r)).catch(e=>cb(e));}, deflate:(d,o,cb)=>{if(typeof o==="function")cb=o;_c(d,"deflate").then(r=>cb(null,r)).catch(e=>cb(e));}, inflate:(d,o,cb)=>{if(typeof o==="function")cb=o;_d(d,"deflate").then(r=>cb(null,r)).catch(e=>cb(e));}, gzipSync:()=>{throw new Error("use async gzip()");}, gunzipSync:()=>{throw new Error("use async gunzip()");}, createGzip:()=>new __streamMod.Transform({transform(c,e,cb){_c(c,"gzip").then(r=>cb(null,r)).catch(e=>cb(e));}}), createGunzip:()=>new __streamMod.Transform({transform(c,e,cb){_d(c,"gzip").then(r=>cb(null,r)).catch(e=>cb(e));}}), createDeflate:()=>new __streamMod.Transform({transform(c,e,cb){_c(c,"deflate").then(r=>cb(null,r)).catch(e=>cb(e));}}), createInflate:()=>new __streamMod.Transform({transform(c,e,cb){_d(c,"deflate").then(r=>cb(null,r)).catch(e=>cb(e));}}), constants:{Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1} };
|
|
2338
|
+
})();
|
|
2339
|
+
builtins.readline = (() => {
|
|
2340
|
+
function createInterface(opts) { const inp=typeof opts==="object"&&!opts.input?opts:{input:opts?.input,output:opts?.output}; const rl=new __eventsMod(); rl.close=()=>{rl.emit("close");}; rl.question=(q,o,cb)=>{if(typeof o==="function")cb=o;if(inp.output?.write)inp.output.write(q);if(cb)queueMicrotask(()=>cb(""));}; rl.prompt=()=>{if(inp.output?.write)inp.output.write("> ");}; rl.on=(...a)=>{__eventsMod.prototype.on.apply(rl,a);return rl;}; rl.setPrompt=()=>rl; rl[Symbol.asyncIterator]=async function*(){}; return rl; }
|
|
2341
|
+
return { createInterface, Interface: __eventsMod };
|
|
2342
|
+
})();
|
|
2343
|
+
builtins.perf_hooks = { performance: globalThis.performance || { now:()=>Date.now(), mark:()=>{}, measure:()=>{}, getEntriesByName:()=>[], clearMarks:()=>{}, clearMeasures:()=>{} } };
|
|
2344
|
+
// X.5-Z5 §3 follow-on: minimal v8 stub for jiti (used transitively by
|
|
2345
|
+
// @tailwindcss/vite). jiti reads v8.startupSnapshot.isBuildingSnapshot()
|
|
2346
|
+
// to decide whether to skip JIT compilation; workerd never builds v8
|
|
2347
|
+
// snapshots, so 'false' is the correct answer. Other v8 introspection
|
|
2348
|
+
// APIs (cachedDataVersionTag, getHeapStatistics, etc.) return inert
|
|
2349
|
+
// values that satisfy the shape contract without offering real data.
|
|
2350
|
+
// See audit/sections/X5Z5-build-retro.md §3.
|
|
2351
|
+
builtins.v8 = {
|
|
2352
|
+
startupSnapshot: {
|
|
2353
|
+
isBuildingSnapshot: () => false,
|
|
2354
|
+
addSerializeCallback: () => {},
|
|
2355
|
+
addDeserializeCallback: () => {},
|
|
2356
|
+
setDeserializeMainFunction: () => {},
|
|
2357
|
+
setDeserializeData: () => {},
|
|
2358
|
+
},
|
|
2359
|
+
cachedDataVersionTag: () => 0,
|
|
2360
|
+
getHeapStatistics: () => ({ total_heap_size: 0, used_heap_size: 0, heap_size_limit: 0, malloced_memory: 0 }),
|
|
2361
|
+
getHeapSpaceStatistics: () => [],
|
|
2362
|
+
setFlagsFromString: () => {},
|
|
2363
|
+
serialize: (v) => __BufferMod.from(JSON.stringify(v)),
|
|
2364
|
+
deserialize: (b) => JSON.parse(__BufferMod.from(b).toString()),
|
|
2365
|
+
writeHeapSnapshot: () => "",
|
|
2366
|
+
};
|
|
2367
|
+
builtins.worker_threads = { isMainThread:true, parentPort:null, workerData:null, threadId:0, Worker: class extends __eventsMod { constructor(){super();} terminate(){return Promise.resolve(0);} postMessage(){} } };
|
|
2368
|
+
|
|
2369
|
+
// ── W3 additions: builtins forwarded/shimmed for axios/jsdom/fastify/
|
|
2370
|
+
// puppeteer-core/ts-node + Node 20 surface completeness.
|
|
2371
|
+
builtins.vm = __vmMod;
|
|
2372
|
+
builtins.http2 = __http2Mod;
|
|
2373
|
+
builtins.repl = __replMod;
|
|
2374
|
+
builtins.diagnostics_channel = __diagChannelMod;
|
|
2375
|
+
builtins.tls = __tlsMod;
|
|
2376
|
+
builtins.async_hooks = __asyncHooksMod;
|
|
2377
|
+
// Subpath-style require() — the shim's __requireFrom strips a 'node:'
|
|
2378
|
+
// prefix to look up bare names, so we expose both bare and prefixed
|
|
2379
|
+
// keys explicitly for grep-friendliness and to handle any future call
|
|
2380
|
+
// site that bypasses the strip path.
|
|
2381
|
+
builtins["fs/promises"] = __fsMod.promises;
|
|
2382
|
+
builtins["node:fs/promises"] = __fsMod.promises;
|
|
2383
|
+
|
|
2384
|
+
// stream/promises — promise-wrapped versions of pipeline + finished.
|
|
2385
|
+
// Surfaced by sv (svelte CLI, the new replacement for create-svelte
|
|
2386
|
+
// v6.x) at /tmp/.npx-cache/node_modules/sv/dist/bin.mjs — it imports
|
|
2387
|
+
// 'node:stream/promises' for promise-style pipeline composition.
|
|
2388
|
+
// signal-exit, gulp's vinyl streams, tar-fs, and many node-only build
|
|
2389
|
+
// scripts use this subpath too.
|
|
2390
|
+
//
|
|
2391
|
+
// Real Node's stream/promises wraps the callback-style pipeline/
|
|
2392
|
+
// finished from 'stream' into Promise-returning variants. The
|
|
2393
|
+
// __streamMod above already ships pipeline() and finished() in their
|
|
2394
|
+
// callback form (src/runtime/streams.ts:339/361); the promise wrapper
|
|
2395
|
+
// is a thin shim that returns a Promise resolving on success +
|
|
2396
|
+
// rejecting on the callback's err arg.
|
|
2397
|
+
builtins["stream/promises"] = (() => {
|
|
2398
|
+
const promisifyOp = (op) => (...args) => new Promise((res, rej) => {
|
|
2399
|
+
// op signature: op(...streamsOrTarget, callback)
|
|
2400
|
+
op(...args, (err, value) => {
|
|
2401
|
+
if (err) rej(err);
|
|
2402
|
+
else res(value);
|
|
2403
|
+
});
|
|
2404
|
+
});
|
|
2405
|
+
return {
|
|
2406
|
+
pipeline: promisifyOp(__streamMod.pipeline),
|
|
2407
|
+
finished: promisifyOp(__streamMod.finished),
|
|
2408
|
+
};
|
|
2409
|
+
})();
|
|
2410
|
+
builtins["node:stream/promises"] = builtins["stream/promises"];
|
|
2411
|
+
|
|
2412
|
+
// stream/consumers — Promise-returning helpers that drain a Readable.
|
|
2413
|
+
// Node 16.7+. Used by undici, tar-stream, multiple "consume the whole
|
|
2414
|
+
// body" patterns. Each helper takes a readable stream and returns a
|
|
2415
|
+
// Promise<Buffer | string | object | array>.
|
|
2416
|
+
builtins["stream/consumers"] = (() => {
|
|
2417
|
+
function readAll(stream) {
|
|
2418
|
+
return new Promise((res, rej) => {
|
|
2419
|
+
const chunks = [];
|
|
2420
|
+
stream.on('data', (chunk) => chunks.push(chunk));
|
|
2421
|
+
stream.on('end', () => res(chunks));
|
|
2422
|
+
stream.on('error', rej);
|
|
2423
|
+
});
|
|
2424
|
+
}
|
|
2425
|
+
return {
|
|
2426
|
+
buffer: async (stream) => {
|
|
2427
|
+
const chunks = await readAll(stream);
|
|
2428
|
+
// Concat Buffers / Uint8Arrays / strings.
|
|
2429
|
+
if (chunks.length === 0) return __BufferMod.alloc(0);
|
|
2430
|
+
if (typeof chunks[0] === 'string') {
|
|
2431
|
+
return __BufferMod.from(chunks.join(''));
|
|
2432
|
+
}
|
|
2433
|
+
return __BufferMod.concat(chunks);
|
|
2434
|
+
},
|
|
2435
|
+
text: async (stream) => {
|
|
2436
|
+
const chunks = await readAll(stream);
|
|
2437
|
+
if (chunks.length === 0) return '';
|
|
2438
|
+
if (typeof chunks[0] === 'string') return chunks.join('');
|
|
2439
|
+
return __BufferMod.concat(chunks).toString('utf8');
|
|
2440
|
+
},
|
|
2441
|
+
json: async (stream) => {
|
|
2442
|
+
const chunks = await readAll(stream);
|
|
2443
|
+
const text = typeof chunks[0] === 'string'
|
|
2444
|
+
? chunks.join('')
|
|
2445
|
+
: __BufferMod.concat(chunks).toString('utf8');
|
|
2446
|
+
return JSON.parse(text);
|
|
2447
|
+
},
|
|
2448
|
+
arrayBuffer: async (stream) => {
|
|
2449
|
+
const chunks = await readAll(stream);
|
|
2450
|
+
const buf = __BufferMod.concat(chunks);
|
|
2451
|
+
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
2452
|
+
},
|
|
2453
|
+
blob: async () => {
|
|
2454
|
+
throw new Error('stream/consumers.blob not implemented');
|
|
2455
|
+
},
|
|
2456
|
+
};
|
|
2457
|
+
})();
|
|
2458
|
+
builtins["node:stream/consumers"] = builtins["stream/consumers"];
|
|
2459
|
+
|
|
2460
|
+
// stream/web — Web Streams API namespace. Node 17+. Userland CLIs
|
|
2461
|
+
// occasionally pull \`ReadableStream\` from here for portability. The
|
|
2462
|
+
// platform exposes these globals already; we just re-export them.
|
|
2463
|
+
builtins["stream/web"] = {
|
|
2464
|
+
ReadableStream: globalThis.ReadableStream,
|
|
2465
|
+
WritableStream: globalThis.WritableStream,
|
|
2466
|
+
TransformStream: globalThis.TransformStream,
|
|
2467
|
+
ByteLengthQueuingStrategy: globalThis.ByteLengthQueuingStrategy,
|
|
2468
|
+
CountQueuingStrategy: globalThis.CountQueuingStrategy,
|
|
2469
|
+
ReadableStreamDefaultReader: globalThis.ReadableStreamDefaultReader,
|
|
2470
|
+
ReadableStreamDefaultController: globalThis.ReadableStreamDefaultController,
|
|
2471
|
+
WritableStreamDefaultWriter: globalThis.WritableStreamDefaultWriter,
|
|
2472
|
+
};
|
|
2473
|
+
builtins["node:stream/web"] = builtins["stream/web"];
|
|
2474
|
+
builtins["timers/promises"] = (() => {
|
|
2475
|
+
return {
|
|
2476
|
+
setTimeout: (ms, value) => new Promise(res => setTimeout(() => res(value), ms || 0)),
|
|
2477
|
+
setImmediate: (value) => new Promise(res => queueMicrotask(() => res(value))),
|
|
2478
|
+
setInterval: async function* (ms, value) {
|
|
2479
|
+
while (true) { await new Promise(r => setTimeout(r, ms || 0)); yield value; }
|
|
2480
|
+
},
|
|
2481
|
+
};
|
|
2482
|
+
})();
|
|
2483
|
+
builtins["node:timers/promises"] = builtins["timers/promises"];
|
|
2484
|
+
|
|
2485
|
+
// X.5-M (M-2): dns/promises subpath registration for redis.
|
|
2486
|
+
// @redis/client/dist/lib/client does require('dns/promises') to do
|
|
2487
|
+
// hostname → IP resolution. Pre-fix the only exposure was
|
|
2488
|
+
// builtins.dns.promises (an object property of the parent dns shim);
|
|
2489
|
+
// __requireFrom matches keys exactly, so 'dns/promises' missed.
|
|
2490
|
+
// Mirror the timers/promises pattern above. builtins.dns.promises is
|
|
2491
|
+
// already a complete object (DoH-backed lookup/resolve/resolve4) —
|
|
2492
|
+
// re-exposing it as a subpath builtin is a 2-line registration.
|
|
2493
|
+
builtins["dns/promises"] = builtins.dns.promises;
|
|
2494
|
+
builtins["node:dns/promises"] = builtins["dns/promises"];
|
|
2495
|
+
|
|
2496
|
+
// X.5-Q: util/types subpath registration for jsdom's bundled undici.
|
|
2497
|
+
// undici@7.x calls require('node:util/types').{isUint8Array,isArrayBuffer}
|
|
2498
|
+
// directly from lib/web/fetch/util.js + body.js + websocket/websocket.js.
|
|
2499
|
+
// __requireFrom matches keys exactly; pre-fix the only exposure was
|
|
2500
|
+
// builtins.util.types (object property of parent util shim), so the
|
|
2501
|
+
// subpath missed. Mirror the dns/promises (M-2) pattern. The
|
|
2502
|
+
// builtins.util.types object is the X.5-Q-expanded 17-method polyfill
|
|
2503
|
+
// (see line 707), sufficient for undici@7.25.0 + undici@8.2.0.
|
|
2504
|
+
// See audit/probes/x5npqo/investigate/Q-undici-types-survey.md.
|
|
2505
|
+
builtins["util/types"] = builtins.util.types;
|
|
2506
|
+
builtins["node:util/types"] = builtins["util/types"];
|
|
2507
|
+
|
|
2508
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
2509
|
+
// ── require() — full Node.js module resolution ─────────────────────
|
|
2510
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
2511
|
+
const __moduleCache = new Map();
|
|
2512
|
+
|
|
2513
|
+
/**
|
|
2514
|
+
* Direct VFS bundle access for module resolution.
|
|
2515
|
+
* These bypass the fs shim's _resolve() (which prepends cwd)
|
|
2516
|
+
* because resolver paths are already in VFS format (no leading /).
|
|
2517
|
+
*/
|
|
2518
|
+
function __readFileOr(path, fallback) {
|
|
2519
|
+
const k = path.replace(/^\\/+/, "");
|
|
2520
|
+
// binary-fs: bundle/writes cells may be Uint8Array; module-resolution
|
|
2521
|
+
// callers (package.json parse, source compile) want strings. Decode
|
|
2522
|
+
// bytes lossily — same as Node's Buffer.toString('utf8').
|
|
2523
|
+
function _coerceStr(v) {
|
|
2524
|
+
if (typeof v === "string") return v;
|
|
2525
|
+
if (v instanceof Uint8Array) {
|
|
2526
|
+
try { return new TextDecoder().decode(v); } catch { return fallback; }
|
|
2527
|
+
}
|
|
2528
|
+
return fallback;
|
|
2529
|
+
}
|
|
2530
|
+
if (__vfsBundle && k in __vfsBundle) return _coerceStr(__vfsBundle[k]);
|
|
2531
|
+
if (__vfsWrites && k in __vfsWrites) return _coerceStr(__vfsWrites[k]);
|
|
2532
|
+
// Fallback: try through fs shim (handles _resolve for user-facing paths)
|
|
2533
|
+
try { return __fsMod.readFileSync("/" + k, "utf8"); } catch { return fallback; }
|
|
2534
|
+
}
|
|
2535
|
+
function __fileExists(path) {
|
|
2536
|
+
const k = path.replace(/^\\/+/, "");
|
|
2537
|
+
if (__vfsBundle && k in __vfsBundle) return true;
|
|
2538
|
+
if (__vfsWrites && k in __vfsWrites) return true;
|
|
2539
|
+
if (__vfsDirs && k in __vfsDirs) return true;
|
|
2540
|
+
// Check for directory by looking for any key with this prefix
|
|
2541
|
+
if (__vfsBundle) {
|
|
2542
|
+
const prefix = k + "/";
|
|
2543
|
+
for (const bk in __vfsBundle) { if (bk.startsWith(prefix)) return true; }
|
|
2544
|
+
}
|
|
2545
|
+
return false;
|
|
2546
|
+
}
|
|
2547
|
+
// W3.5 Fix A: strict-file membership probe. __fileExists also returns true for
|
|
2548
|
+
// directories (it has to — __resolveNodeModule and __resolveImportsField call
|
|
2549
|
+
// it to check whether a node_modules/<pkg> directory exists). __resolveFile's
|
|
2550
|
+
// empty-extension probe needs the inverse: "is this an actual file?" — so the
|
|
2551
|
+
// loop falls through to /index.js when "base" is a directory rather than
|
|
2552
|
+
// short-circuiting and returning the directory path (which __loadModule then
|
|
2553
|
+
// can't read, throwing "Cannot read module: <dir>"). See W3 retro §S3 for
|
|
2554
|
+
// the fastify ret/dist/types failure.
|
|
2555
|
+
function __pathIsFile(path) {
|
|
2556
|
+
const k = path.replace(/^\\/+/, "");
|
|
2557
|
+
if (__vfsBundle && k in __vfsBundle) return true;
|
|
2558
|
+
if (__vfsWrites && k in __vfsWrites) return true;
|
|
2559
|
+
// Deliberately does NOT consult __vfsDirs nor do the prefix scan.
|
|
2560
|
+
return false;
|
|
2561
|
+
}
|
|
2562
|
+
function __resolveFile(base) {
|
|
2563
|
+
// Mirrors Node's LOAD_AS_FILE + LOAD_AS_DIRECTORY (require_2 spec):
|
|
2564
|
+
//
|
|
2565
|
+
// 1. LOAD_AS_FILE -- try base, base.js, base.mjs, base.cjs, base.json
|
|
2566
|
+
// as a regular file. The empty-ext probe uses __pathIsFile (not
|
|
2567
|
+
// __fileExists) so a directory at "base" does NOT short-circuit
|
|
2568
|
+
// here; it falls through to the LOAD_AS_DIRECTORY block below.
|
|
2569
|
+
// See W3.5-plan.md §1 Failure 1.
|
|
2570
|
+
//
|
|
2571
|
+
// 2. LOAD_AS_DIRECTORY -- if "base" resolves to a directory:
|
|
2572
|
+
// a. If <base>/package.json has a "main" field -- recurse on it.
|
|
2573
|
+
// (Bug class C, audit 2026-05-11: this branch was missing,
|
|
2574
|
+
// so require("./mod") where mod/package.json#main="entry.js"
|
|
2575
|
+
// and no mod/index.js -- "Cannot find module ./mod".)
|
|
2576
|
+
// b. Else fall through to <base>/index.{js,cjs,mjs,json}.
|
|
2577
|
+
//
|
|
2578
|
+
// Must mirror the install-time pre-bundler at require-resolver.ts:
|
|
2579
|
+
// resolveFile so prefetch + runtime agree on which file a given
|
|
2580
|
+
// require() will load.
|
|
2581
|
+
const fileExts = ["", ".js", ".mjs", ".cjs", ".json"];
|
|
2582
|
+
for (const ext of fileExts) {
|
|
2583
|
+
const cand = base + ext;
|
|
2584
|
+
if (ext === "") {
|
|
2585
|
+
if (__pathIsFile(cand)) return cand;
|
|
2586
|
+
continue;
|
|
2587
|
+
}
|
|
2588
|
+
if (__fileExists(cand)) return cand;
|
|
2589
|
+
}
|
|
2590
|
+
// LOAD_AS_DIRECTORY: prefer package.json#main over index.*
|
|
2591
|
+
const pkgJsonPath = base.replace(/\\/+$/, "") + "/package.json";
|
|
2592
|
+
if (__pathIsFile(pkgJsonPath)) {
|
|
2593
|
+
let pkg = null;
|
|
2594
|
+
try { pkg = JSON.parse(__readFileOr(pkgJsonPath, "null")); } catch { /* fall through */ }
|
|
2595
|
+
if (pkg && typeof pkg.main === "string" && pkg.main.length > 0) {
|
|
2596
|
+
const mainStripped = pkg.main.replace(/^\\.\\/+/, "").replace(/^\\/+/, "");
|
|
2597
|
+
const mainBase = base.replace(/\\/+$/, "") + "/" + mainStripped;
|
|
2598
|
+
// Recurse: main itself may be a directory (e.g. main: "lib") or
|
|
2599
|
+
// a file without extension. Guard against pkg.main === "." which
|
|
2600
|
+
// would re-enter this same base and stack-overflow.
|
|
2601
|
+
if (mainBase !== base && mainBase !== base.replace(/\\/+$/, "")) {
|
|
2602
|
+
const resolved = __resolveFile(mainBase);
|
|
2603
|
+
if (resolved) return resolved;
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
const indexExts = ["/index.js", "/index.cjs", "/index.mjs", "/index.json"];
|
|
2608
|
+
for (const ext of indexExts) {
|
|
2609
|
+
const cand = base + ext;
|
|
2610
|
+
if (__fileExists(cand)) return cand;
|
|
2611
|
+
}
|
|
2612
|
+
return null;
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2615
|
+
// __compiledModules is defined at MODULE TOP LEVEL in the generator code
|
|
2616
|
+
// (facet-manager.ts) so new Function() runs during module evaluation.
|
|
2617
|
+
|
|
2618
|
+
// ── Single-source-of-truth exports/imports resolver (W2) ───────────────
|
|
2619
|
+
// Emitted from src/_shared/exports-resolver.ts via getExportsResolverJS().
|
|
2620
|
+
// Declares: resolveExports, resolveConditionValue, resolvePackageEntry,
|
|
2621
|
+
// DEFAULT_ESM_CONDITIONS, DEFAULT_CJS_CONDITIONS.
|
|
2622
|
+
// See audit/sections/03-resolver-gaps.md §3.1 for the bug this fixes:
|
|
2623
|
+
// the prior hand-rolled __resolvePkgEntry only honoured top-level
|
|
2624
|
+
// require|default|import and dropped subpath maps, wildcards, nested
|
|
2625
|
+
// conditions, the imports field, and null-target enforcement.
|
|
2626
|
+
${EXPORTS_RESOLVER_JS}
|
|
2627
|
+
|
|
2628
|
+
/** Conditions for runtime CJS resolution (user-shell node). */
|
|
2629
|
+
const __NIMBUS_CJS_CONDITIONS = ["require", "node", "default"];
|
|
2630
|
+
|
|
2631
|
+
/**
|
|
2632
|
+
* Read and parse a package.json from VFS. Returns null on miss/parse-fail.
|
|
2633
|
+
*/
|
|
2634
|
+
function __readPkgJson(pkgDir) {
|
|
2635
|
+
const s = __readFileOr(pkgDir + "/package.json", null);
|
|
2636
|
+
if (!s) return null;
|
|
2637
|
+
try { return JSON.parse(s); } catch { return null; }
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2640
|
+
/**
|
|
2641
|
+
* Resolve a single subpath inside an installed package (pkgDir).
|
|
2642
|
+
* - subpath: '.' for root entry, './foo' for explicit subpath, etc.
|
|
2643
|
+
* - Honours pkg.exports (subpath maps, wildcards, conditions).
|
|
2644
|
+
* - Falls back to module/main for root, raw subpath probing otherwise.
|
|
2645
|
+
* - Final filesystem probe via __resolveFile (extension list).
|
|
2646
|
+
*
|
|
2647
|
+
* Returns a VFS-relative path to the resolved file, or null.
|
|
2648
|
+
*/
|
|
2649
|
+
function __resolvePkgSubpath(pkgDir, pkg, subpath) {
|
|
2650
|
+
if (!pkg) pkg = __readPkgJson(pkgDir);
|
|
2651
|
+
if (!pkg) {
|
|
2652
|
+
// No package.json — try direct probe
|
|
2653
|
+
if (subpath === ".") return __resolveFile(pkgDir + "/index");
|
|
2654
|
+
return __resolveFile(pkgDir + "/" + subpath.replace(/^\\.\\/+/, ""));
|
|
2655
|
+
}
|
|
2656
|
+
let entry = resolvePackageEntry(pkg, subpath, __NIMBUS_CJS_CONDITIONS);
|
|
2657
|
+
// X.5-F R3: ESM-condition fallback for pure-ESM packages whose
|
|
2658
|
+
// dist/.mjs files were transformed to CJS by transformEsmInBundle
|
|
2659
|
+
// at install time (facet-manager.ts:842, W3.5 Fix B). Without this,
|
|
2660
|
+
// packages like nuxt — whose exports map only contains
|
|
2661
|
+
// {types, import} for the root subpath — return null from the CJS
|
|
2662
|
+
// walk and dead-end with "Cannot find module 'nuxt'" even though
|
|
2663
|
+
// dist/index.mjs is in the bundle and runnable as CJS. We only fall
|
|
2664
|
+
// back when the package actually declares an exports map (so we
|
|
2665
|
+
// don't shadow legit "package not installed" misses).
|
|
2666
|
+
if (entry == null && pkg.exports != null) {
|
|
2667
|
+
entry = resolvePackageEntry(pkg, subpath, DEFAULT_ESM_CONDITIONS);
|
|
2668
|
+
}
|
|
2669
|
+
if (entry != null) {
|
|
2670
|
+
// Strip leading ./ from the resolver result
|
|
2671
|
+
const stripped = entry.replace(/^\\.\\/+/, "");
|
|
2672
|
+
const resolved = __resolveFile(pkgDir + "/" + stripped);
|
|
2673
|
+
if (resolved) return resolved;
|
|
2674
|
+
// W2.6a D2: exports/main yielded a target but the file doesn't exist
|
|
2675
|
+
// in the bundle (capped out, or the package mis-declares its main).
|
|
2676
|
+
// Fall through to the direct-probe path so we get index.js when the
|
|
2677
|
+
// declared entry is missing. Without this fallback, packages whose
|
|
2678
|
+
// exports point at a file evicted by the content cap return null and
|
|
2679
|
+
// the require chain dead-ends with "Cannot find module" — even though
|
|
2680
|
+
// a perfectly good index.js sits next to it.
|
|
2681
|
+
}
|
|
2682
|
+
// Fallback: probe the directory for a usable entry. This catches
|
|
2683
|
+
// (a) exports map yielded null (forbidden / no condition matched)
|
|
2684
|
+
// (b) exports map yielded a path whose file isn't on disk
|
|
2685
|
+
// (c) main yielded a path whose file isn't on disk
|
|
2686
|
+
if (subpath === ".") {
|
|
2687
|
+
// Try main again under the extension-list resolver, then fall through
|
|
2688
|
+
// to /index probing. The shared resolvePackageEntry already prefers
|
|
2689
|
+
// exports → module → main, so re-probing main here only triggers when
|
|
2690
|
+
// entry was null OR entry's file was missing.
|
|
2691
|
+
if (typeof pkg.main === 'string') {
|
|
2692
|
+
const mainStripped = pkg.main.replace(/^\\.\\/+/, "");
|
|
2693
|
+
const r = __resolveFile(pkgDir + "/" + mainStripped);
|
|
2694
|
+
if (r) return r;
|
|
2695
|
+
}
|
|
2696
|
+
return __resolveFile(pkgDir + "/index");
|
|
2697
|
+
}
|
|
2698
|
+
const rel = subpath.replace(/^\\.\\/+/, "");
|
|
2699
|
+
return __resolveFile(pkgDir + "/" + rel);
|
|
2700
|
+
}
|
|
2701
|
+
|
|
2702
|
+
/** Back-compat name used elsewhere in this file. */
|
|
2703
|
+
function __resolvePkgEntry(pkgDir) {
|
|
2704
|
+
return __resolvePkgSubpath(pkgDir, null, ".");
|
|
2705
|
+
}
|
|
2706
|
+
|
|
2707
|
+
/**
|
|
2708
|
+
* Resolve a bare specifier (e.g. "react", "@scope/pkg", "pkg/sub/path")
|
|
2709
|
+
* by walking up node_modules from fromDir. Returns the resolved file or null.
|
|
2710
|
+
*/
|
|
2711
|
+
function __resolveNodeModule(name, fromDir) {
|
|
2712
|
+
// Split into pkgName + subpath
|
|
2713
|
+
let pkgName, subpath;
|
|
2714
|
+
if (name.startsWith("@")) {
|
|
2715
|
+
const parts = name.split("/");
|
|
2716
|
+
if (parts.length < 2) return null;
|
|
2717
|
+
pkgName = parts.slice(0, 2).join("/");
|
|
2718
|
+
subpath = parts.length > 2 ? "./" + parts.slice(2).join("/") : ".";
|
|
2719
|
+
} else {
|
|
2720
|
+
const slashIdx = name.indexOf("/");
|
|
2721
|
+
if (slashIdx > 0) {
|
|
2722
|
+
pkgName = name.substring(0, slashIdx);
|
|
2723
|
+
subpath = "./" + name.substring(slashIdx + 1);
|
|
2724
|
+
} else {
|
|
2725
|
+
pkgName = name;
|
|
2726
|
+
subpath = ".";
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
|
|
2730
|
+
// Walk up directories looking for node_modules/<pkgName>.
|
|
2731
|
+
// Audit §3.7 (P7 fastify case): the prior loop was right, but the
|
|
2732
|
+
// visited-set keyed on dir-with-leading-slash-stripped while node_modules
|
|
2733
|
+
// existence checks used the same form, so iteration COULD terminate early
|
|
2734
|
+
// when hitting "" (empty string) at the root. Explicit termination on
|
|
2735
|
+
// empty string + always-also-check root node_modules covers both.
|
|
2736
|
+
let dir = (fromDir || "").replace(/^\\/+/, "");
|
|
2737
|
+
const visited = new Set();
|
|
2738
|
+
while (true) {
|
|
2739
|
+
if (visited.has(dir)) break;
|
|
2740
|
+
visited.add(dir);
|
|
2741
|
+
const nmDir = (dir ? dir + "/" : "") + "node_modules/" + pkgName;
|
|
2742
|
+
if (__fileExists(nmDir)) {
|
|
2743
|
+
const resolved = __resolvePkgSubpath(nmDir, null, subpath);
|
|
2744
|
+
if (resolved) return resolved;
|
|
2745
|
+
}
|
|
2746
|
+
if (!dir) break;
|
|
2747
|
+
const lastSlash = dir.lastIndexOf("/");
|
|
2748
|
+
dir = lastSlash > 0 ? dir.substring(0, lastSlash) : "";
|
|
2749
|
+
}
|
|
2750
|
+
return null;
|
|
2751
|
+
}
|
|
2752
|
+
|
|
2753
|
+
/**
|
|
2754
|
+
* Resolve a #name imports-field specifier from the nearest enclosing
|
|
2755
|
+
* package.json. Returns the resolved file or null.
|
|
2756
|
+
*/
|
|
2757
|
+
function __resolveImportsField(name, fromDir) {
|
|
2758
|
+
// Walk up looking for the nearest package.json. Stop at the first one
|
|
2759
|
+
// (Node spec: imports field of the importing module's package).
|
|
2760
|
+
let dir = (fromDir || "").replace(/^\\/+/, "");
|
|
2761
|
+
while (true) {
|
|
2762
|
+
const pkgJsonPath = (dir ? dir + "/" : "") + "package.json";
|
|
2763
|
+
if (__fileExists(pkgJsonPath)) {
|
|
2764
|
+
const pkg = __readPkgJson(dir);
|
|
2765
|
+
if (pkg && pkg.imports) {
|
|
2766
|
+
const target = resolveExports(pkg.imports, name, __NIMBUS_CJS_CONDITIONS);
|
|
2767
|
+
if (target) {
|
|
2768
|
+
// Imports targets are relative to the package root (dir)
|
|
2769
|
+
if (target.startsWith("./")) {
|
|
2770
|
+
return __resolveFile((dir ? dir + "/" : "") + target.slice(2));
|
|
2771
|
+
}
|
|
2772
|
+
if (target.startsWith("/")) {
|
|
2773
|
+
return __resolveFile(target.slice(1));
|
|
2774
|
+
}
|
|
2775
|
+
// Bare specifier — re-resolve as a node_module from this dir
|
|
2776
|
+
return __resolveNodeModule(target, dir);
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
return null; // first package.json wins, even if no imports field
|
|
2780
|
+
}
|
|
2781
|
+
if (!dir) return null;
|
|
2782
|
+
const lastSlash = dir.lastIndexOf("/");
|
|
2783
|
+
dir = lastSlash > 0 ? dir.substring(0, lastSlash) : "";
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2787
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
2788
|
+
// ── X.5-S: __mkCompiledFn — conditional-param-rename wrap for new Function
|
|
2789
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
2790
|
+
//
|
|
2791
|
+
// vite's chunks/node.js (transitive bundle of open@10.2.0) contains the
|
|
2792
|
+
// ESM idiom \`const __dirname = path.dirname(fileURLToPath(import.meta.url))\`.
|
|
2793
|
+
// W3.5 Fix B's esbuild ESM→CJS transform preserves that line verbatim
|
|
2794
|
+
// while substituting \`import.meta\` with \`const import_meta = {}\`. Wrapping
|
|
2795
|
+
// the body in \`new Function("exports","require","module","__filename","__dirname", code)\`
|
|
2796
|
+
// then collides at parse time:
|
|
2797
|
+
//
|
|
2798
|
+
// SyntaxError: Identifier '__dirname' has already been declared
|
|
2799
|
+
//
|
|
2800
|
+
// (VERIFY-23417C5 §4 #1 / X5M3-retro §"Next bucket".) The helper RENAMES
|
|
2801
|
+
// the conflicting param to a placeholder name so the body's own
|
|
2802
|
+
// \`const __dirname\` becomes the single declarer. We rename rather than
|
|
2803
|
+
// drop because callers pass 5 positional arguments and dropping a slot
|
|
2804
|
+
// would mis-align downstream slots (e.g. the USER_CODE wrap appends
|
|
2805
|
+
// \`console\` / \`process\` / etc. after \`__dirname\`). Renaming preserves
|
|
2806
|
+
// slot alignment while letting the body's binding win.
|
|
2807
|
+
//
|
|
2808
|
+
// Symmetric for \`__filename\` because open@10's idiom often emits both.
|
|
2809
|
+
// See audit/sections/X5S-plan.md §3, audit/probes/x5s/investigation/repro.mjs.
|
|
2810
|
+
function __mkCompiledFn(code) {
|
|
2811
|
+
const reFn = /(?:^|\\n|;)\\s*(?:const|let|var)\\s+__filename\\s*=/m;
|
|
2812
|
+
const reDn = /(?:^|\\n|;)\\s*(?:const|let|var)\\s+__dirname\\s*=/m;
|
|
2813
|
+
const fnName = reFn.test(code) ? "__filename__nimbus_unused" : "__filename";
|
|
2814
|
+
const dnName = reDn.test(code) ? "__dirname__nimbus_unused" : "__dirname";
|
|
2815
|
+
return new Function("exports", "require", "module", fnName, dnName, code);
|
|
2816
|
+
}
|
|
2817
|
+
|
|
2818
|
+
/**
|
|
2819
|
+
* Load and execute a JS/JSON module from VFS.
|
|
2820
|
+
* Returns the module.exports value.
|
|
2821
|
+
*/
|
|
2822
|
+
function __loadModule(resolvedPath) {
|
|
2823
|
+
if (__moduleCache.has(resolvedPath)) return __moduleCache.get(resolvedPath);
|
|
2824
|
+
|
|
2825
|
+
// Prevent circular require: set empty exports before executing
|
|
2826
|
+
const mod = { exports: {} };
|
|
2827
|
+
__moduleCache.set(resolvedPath, mod.exports);
|
|
2828
|
+
|
|
2829
|
+
const code = __readFileOr(resolvedPath, null);
|
|
2830
|
+
if (code === null) throw new Error("Cannot read module: " + resolvedPath);
|
|
2831
|
+
|
|
2832
|
+
// JSON
|
|
2833
|
+
if (resolvedPath.endsWith(".json")) {
|
|
2834
|
+
mod.exports = JSON.parse(code);
|
|
2835
|
+
__moduleCache.set(resolvedPath, mod.exports);
|
|
2836
|
+
return mod.exports;
|
|
2837
|
+
}
|
|
2838
|
+
|
|
2839
|
+
// JS — wrap in function and execute with scoped require
|
|
2840
|
+
const modDir = resolvedPath.includes("/") ? resolvedPath.substring(0, resolvedPath.lastIndexOf("/")) : ".";
|
|
2841
|
+
const scopedRequire = (id) => __requireFrom(id, modDir);
|
|
2842
|
+
scopedRequire.resolve = (id) => {
|
|
2843
|
+
const r = __resolveFrom(id, modDir);
|
|
2844
|
+
if (!r) throw new Error("Cannot resolve '" + id + "'");
|
|
2845
|
+
return r;
|
|
2846
|
+
};
|
|
2847
|
+
scopedRequire.cache = __moduleCache;
|
|
2848
|
+
// G2 (runtime-pkg wave): scopedRequire.main mirrors the top-level
|
|
2849
|
+
// __require.main (set to the entry module by the runner). Pre-fix
|
|
2850
|
+
// it was hardcoded null, so:
|
|
2851
|
+
// - 'require.main' inside a sub-module returned null
|
|
2852
|
+
// - 'require.main === module' was false for the entry too
|
|
2853
|
+
// (because in the entry, require.main was null too)
|
|
2854
|
+
//
|
|
2855
|
+
// Post-fix: in the ENTRY, __require.main === entry's module ⇒
|
|
2856
|
+
// require.main === module is true. In a SUB-MODULE (loaded via
|
|
2857
|
+
// __loadModule), scopedRequire.main === entry's module, but
|
|
2858
|
+
// module === sub-module's mod, so require.main === module is
|
|
2859
|
+
// FALSE — exactly the canonical 'is this file being executed
|
|
2860
|
+
// directly?' semantics.
|
|
2861
|
+
scopedRequire.main = __require.main;
|
|
2862
|
+
|
|
2863
|
+
// X.5-M3: thread currently-loading module path through globalThis so the
|
|
2864
|
+
// URL shim null-base fallback (in node-shims url module) can compose
|
|
2865
|
+
// relative URLs against the real module location — synthesizing
|
|
2866
|
+
// import.meta.url semantics for ESM that esbuild CJS-emit reduced to
|
|
2867
|
+
// const import_meta = {}. Save+restore for recursive __loadModule.
|
|
2868
|
+
// See audit/sections/X5M3-plan.md §3.
|
|
2869
|
+
const __prevModulePath = globalThis.__currentModulePath;
|
|
2870
|
+
globalThis.__currentModulePath = resolvedPath;
|
|
2871
|
+
try {
|
|
2872
|
+
// Use pre-compiled function from startup (new Function allowed at module eval time)
|
|
2873
|
+
// Normalize path to match VFS bundle key format (no leading /)
|
|
2874
|
+
const normalizedPath = resolvedPath.replace(/^\\/+/, "");
|
|
2875
|
+
const precompiled = __compiledModules.get(normalizedPath) || __compiledModules.get(resolvedPath);
|
|
2876
|
+
// G2/G3 (runtime-pkg wave): pass console/process/Buffer + timer
|
|
2877
|
+
// shims into every sub-module so process.exit() inside a required
|
|
2878
|
+
// file routes through __processMod (NOT workerd's real process,
|
|
2879
|
+
// which crashes with 'Canceling the request'). Pre-fix call site
|
|
2880
|
+
// passed only 5 params; sub-modules' references to these globals
|
|
2881
|
+
// resolved up the V8 scope chain to workerd's real bindings.
|
|
2882
|
+
//
|
|
2883
|
+
// The compile-time params list at manager.ts already added the
|
|
2884
|
+
// extras; here we provide them at call time. Order MUST match
|
|
2885
|
+
// the params list at manager.ts:225+.
|
|
2886
|
+
if (precompiled) {
|
|
2887
|
+
precompiled(
|
|
2888
|
+
mod.exports, scopedRequire, mod, "/" + resolvedPath, "/" + modDir,
|
|
2889
|
+
__consoleMod, __processMod, __BufferMod,
|
|
2890
|
+
globalThis.setTimeout, globalThis.setInterval, globalThis.clearTimeout, globalThis.clearInterval,
|
|
2891
|
+
);
|
|
2892
|
+
} else {
|
|
2893
|
+
// Fallback: try new Function at request time (works if eval is permitted)
|
|
2894
|
+
// X.5-S: conditional-param-rename via __mkCompiledFn — see helper
|
|
2895
|
+
// comment above. Without this, esbuild-transformed ESM that declares
|
|
2896
|
+
// \`const __dirname = …\` at top level (e.g. vite's chunks/node.js)
|
|
2897
|
+
// collides with the previously hardcoded \`__dirname\` parameter.
|
|
2898
|
+
try {
|
|
2899
|
+
// G2/G3: same extra-params extension on the fallback path.
|
|
2900
|
+
const fn = __mkCompiledFn(code, [
|
|
2901
|
+
"console", "process", "Buffer",
|
|
2902
|
+
"setTimeout", "setInterval", "clearTimeout", "clearInterval",
|
|
2903
|
+
]);
|
|
2904
|
+
fn(
|
|
2905
|
+
mod.exports, scopedRequire, mod, "/" + resolvedPath, "/" + modDir,
|
|
2906
|
+
__consoleMod, __processMod, __BufferMod,
|
|
2907
|
+
globalThis.setTimeout, globalThis.setInterval, globalThis.clearTimeout, globalThis.clearInterval,
|
|
2908
|
+
);
|
|
2909
|
+
} catch (evalErr) {
|
|
2910
|
+
// W3.5 Fix C: if the file was in the bundle but its pre-compile
|
|
2911
|
+
// failed at facet startup, surface the original SyntaxError
|
|
2912
|
+
// instead of the misleading "file was not pre-bundled" text.
|
|
2913
|
+
// See audit/sections/W3.5-plan.md §1 Failure 2.
|
|
2914
|
+
const normalizedPath2 = resolvedPath.replace(/^\\/+/, "");
|
|
2915
|
+
const compileErr =
|
|
2916
|
+
(typeof __compileFailures !== "undefined" && __compileFailures &&
|
|
2917
|
+
(__compileFailures.get(normalizedPath2) || __compileFailures.get(resolvedPath))) || null;
|
|
2918
|
+
if (compileErr) {
|
|
2919
|
+
throw new Error(
|
|
2920
|
+
"Cannot load module '" + resolvedPath +
|
|
2921
|
+
"': pre-compile failed at facet startup: " + compileErr,
|
|
2922
|
+
);
|
|
2923
|
+
}
|
|
2924
|
+
if (evalErr.message && evalErr.message.includes("Code generation from strings disallowed")) {
|
|
2925
|
+
throw new Error("Cannot load module '" + resolvedPath + "': file was not pre-bundled. Add it to the VFS bundle.");
|
|
2926
|
+
}
|
|
2927
|
+
throw evalErr;
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
} catch (e) {
|
|
2931
|
+
__moduleCache.delete(resolvedPath);
|
|
2932
|
+
throw e;
|
|
2933
|
+
} finally {
|
|
2934
|
+
globalThis.__currentModulePath = __prevModulePath;
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2937
|
+
// Update cache with final exports (module.exports may have been reassigned)
|
|
2938
|
+
__moduleCache.set(resolvedPath, mod.exports);
|
|
2939
|
+
return mod.exports;
|
|
2940
|
+
}
|
|
2941
|
+
|
|
2942
|
+
/**
|
|
2943
|
+
* Resolve a module ID from a given directory.
|
|
2944
|
+
* Returns the resolved VFS path, or null.
|
|
2945
|
+
*/
|
|
2946
|
+
function __resolveFrom(id, fromDir) {
|
|
2947
|
+
// X.5-P: literal "." / ".." are CommonJS aliases for "./" / "../".
|
|
2948
|
+
// Pre-fix they slipped past the startsWith("./")/("../") guards (which
|
|
2949
|
+
// require >= 3 / >= 4 chars respectively) and fell into the bare-spec
|
|
2950
|
+
// branch — querying __resolveNodeModule for a package literally named
|
|
2951
|
+
// "." → "Cannot find module '.'" (verify-90993b3 §3 bucket P:
|
|
2952
|
+
// fastify via ajv/dist/compile/jtd, redis via @redis/client/dist/lib/client).
|
|
2953
|
+
// Normalize so they take the relative-resolve branch (which then probes
|
|
2954
|
+
// index.js / package.json#main via __resolveFile). See
|
|
2955
|
+
// audit/probes/x5npqo/functional/p-parent-dir.mjs.
|
|
2956
|
+
if (id === ".") id = "./";
|
|
2957
|
+
else if (id === "..") id = "../";
|
|
2958
|
+
// Relative path
|
|
2959
|
+
if (id.startsWith("./") || id.startsWith("../") || id.startsWith("/")) {
|
|
2960
|
+
let base;
|
|
2961
|
+
if (id.startsWith("/")) {
|
|
2962
|
+
base = id.replace(/^\\/+/, "");
|
|
2963
|
+
} else {
|
|
2964
|
+
// VFS paths are stored without leading /. __pathMod.resolve treats
|
|
2965
|
+
// a non-absolute fromDir as relative-to-cwd which would corrupt the
|
|
2966
|
+
// result (audit §3.7-bug). Force-absolutise fromDir before resolving,
|
|
2967
|
+
// then strip the leading / again.
|
|
2968
|
+
const absFromDir = fromDir.startsWith("/") ? fromDir : "/" + fromDir;
|
|
2969
|
+
base = __pathMod.resolve(absFromDir, id).replace(/^\\/+/, "");
|
|
2970
|
+
}
|
|
2971
|
+
return __resolveFile(base);
|
|
2972
|
+
}
|
|
2973
|
+
// imports field (#name)
|
|
2974
|
+
if (id.startsWith("#")) {
|
|
2975
|
+
return __resolveImportsField(id, fromDir);
|
|
2976
|
+
}
|
|
2977
|
+
// Bare specifier → node_modules resolution
|
|
2978
|
+
return __resolveNodeModule(id, fromDir);
|
|
2979
|
+
}
|
|
2980
|
+
|
|
2981
|
+
/**
|
|
2982
|
+
* require() from a specific directory context.
|
|
2983
|
+
* This is what each loaded module gets as its require function.
|
|
2984
|
+
*/
|
|
2985
|
+
function __requireFrom(id, fromDir) {
|
|
2986
|
+
// Check builtins first (always takes priority)
|
|
2987
|
+
if (builtins[id]) return builtins[id];
|
|
2988
|
+
if (id.startsWith("node:")) {
|
|
2989
|
+
const bare = id.substring(5);
|
|
2990
|
+
if (builtins[bare]) return builtins[bare];
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
const resolved = __resolveFrom(id, fromDir);
|
|
2994
|
+
if (!resolved) throw new Error("Cannot find module '" + id + "' (from " + fromDir + ")");
|
|
2995
|
+
|
|
2996
|
+
return __loadModule(resolved);
|
|
2997
|
+
}
|
|
2998
|
+
|
|
2999
|
+
/**
|
|
3000
|
+
* Top-level require() — resolves from cwd/dirname.
|
|
3001
|
+
* This is the require passed to the user's entry script.
|
|
3002
|
+
*/
|
|
3003
|
+
function __require(id) {
|
|
3004
|
+
return __requireFrom(id, dirname || cwd || "/home/user");
|
|
3005
|
+
}
|
|
3006
|
+
__require.resolve = (id) => {
|
|
3007
|
+
const r = __resolveFrom(id, dirname || cwd || "/home/user");
|
|
3008
|
+
if (!r) throw new Error("Cannot resolve '" + id + "'");
|
|
3009
|
+
return "/" + r;
|
|
3010
|
+
};
|
|
3011
|
+
__require.cache = __moduleCache;
|
|
3012
|
+
__require.main = null;
|
|
3013
|
+
|
|
3014
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
3015
|
+
// ── END OF GENERATED SHIMS — closing marker ─────────────────────────
|
|
3016
|
+
// (builtins block has been moved above the resolver functions)
|
|
3017
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
3018
|
+
`;
|
|
3019
|
+
}
|