@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,705 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wasm-runner.ts — native-WASM runner via the LOADER-modules transport.
|
|
3
|
+
*
|
|
4
|
+
* Re-introduced after the multi-runtime wave's revert. The previous
|
|
5
|
+
* version relied on direct `WebAssembly.instantiate(bytes)` at request
|
|
6
|
+
* time — workerd's CSP blocks that path inside both the supervisor
|
|
7
|
+
* and facet isolates (verified in the multi-runtime feasibility
|
|
8
|
+
* memo). The new version routes through the LOADER's modules map:
|
|
9
|
+
* bytes ride INSIDE the worker code blob, workerd compiles them
|
|
10
|
+
* during the inner worker's MODULE-LOAD phase (the one phase where
|
|
11
|
+
* wasm code generation IS allowed), and the resulting
|
|
12
|
+
* WebAssembly.Module is exposed to the user fn via the
|
|
13
|
+
* NimbusLoaderPool's `globalThis.__NIMBUS_WASM[<name>]` table.
|
|
14
|
+
*
|
|
15
|
+
* The validation that this works on the deployed Cloudflare fleet
|
|
16
|
+
* lives at /workspace/.seal-internal/2026-05-10-wasm-csp/findings.md
|
|
17
|
+
* (`add(3,4) === 7` returned in 11ms warm, 113ms cold).
|
|
18
|
+
*
|
|
19
|
+
* Shell command shape
|
|
20
|
+
* ───────────────────
|
|
21
|
+
*
|
|
22
|
+
* wasm-runner --version
|
|
23
|
+
* wasm-runner <file.wasm> <exportName> [int args...]
|
|
24
|
+
*
|
|
25
|
+
* Each invocation:
|
|
26
|
+
* 1. Reads bytes from VFS (or any caller-supplied source).
|
|
27
|
+
* 2. Allocates a PID via processTable (Process tab integration).
|
|
28
|
+
* 3. NimbusLoaderPool.submit() with wasmModules: { 'user.wasm': bytes }
|
|
29
|
+
* — pool merges per-call wasm with constructor-time entries,
|
|
30
|
+
* generates a worker.js that imports './user.wasm', and ships
|
|
31
|
+
* the modules map to env.LOADER.get(...).
|
|
32
|
+
* 4. The submitted fn runs inside the inner facet:
|
|
33
|
+
* - reads globalThis.__NIMBUS_WASM['user.wasm'] (the precompiled
|
|
34
|
+
* Module the pool registered)
|
|
35
|
+
* - WebAssembly.instantiate(module, {}) — allowed because the
|
|
36
|
+
* Module is precompiled
|
|
37
|
+
* - looks up the export, calls with parsed integer args, returns
|
|
38
|
+
* the result + the export list
|
|
39
|
+
* 5. Supervisor formats and writes stdout/stderr; exit code 0/1.
|
|
40
|
+
*
|
|
41
|
+
* Limitations (documented in --help):
|
|
42
|
+
* - Function args are integers only (parseInt). Float / string /
|
|
43
|
+
* multi-arg-shapes need a wrapper module.
|
|
44
|
+
* - Only WebAssembly.Memory and integer return values are surfaced.
|
|
45
|
+
* - WASI imports are NOT provided. Modules expecting wasi_snapshot
|
|
46
|
+
* won't instantiate (fail at the in-facet instantiate step).
|
|
47
|
+
*
|
|
48
|
+
* Anti-requirements
|
|
49
|
+
* ─────────────────
|
|
50
|
+
* - NO setTimeout / NO retry / NO defensive-catch in the dispatch
|
|
51
|
+
* path. The pool's resilience options handle retries.
|
|
52
|
+
* - The try/catch around vfs.readFile is a legitimate I/O boundary;
|
|
53
|
+
* the diagnostic propagates as exitCode 1 + stderr line.
|
|
54
|
+
* - NO direct WebAssembly.instantiate(bytes) at request time —
|
|
55
|
+
* that's the architectural mistake from the prior wave.
|
|
56
|
+
*/
|
|
57
|
+
import { WASI_INSTANCE_PREAMBLE_SRC, WASI_WAVE1_FNS } from './wasi-instance.js';
|
|
58
|
+
export const WASM_RUNNER_VERSION = '0.3.0';
|
|
59
|
+
export const WASM_RUNNER_HELP = 'Usage: wasm-runner [options] <file.wasm> [exportName] [int args...]\n' +
|
|
60
|
+
' wasm-runner --version\n' +
|
|
61
|
+
' wasm-runner --wasi-info\n' +
|
|
62
|
+
'\n' +
|
|
63
|
+
'Loads a .wasm module and runs it. Two modes auto-detected from the\n' +
|
|
64
|
+
'module\'s imports:\n' +
|
|
65
|
+
'\n' +
|
|
66
|
+
' WASI mode (imports wasi_snapshot_preview1): invokes _start with a\n' +
|
|
67
|
+
' Wave-1 WASI shim. stdout/stderr stream to the Process tab.\n' +
|
|
68
|
+
' exportName argument is optional; defaults to _start.\n' +
|
|
69
|
+
' Direct mode (no WASI imports): calls the named export with integer\n' +
|
|
70
|
+
' args and prints the return value.\n' +
|
|
71
|
+
'\n' +
|
|
72
|
+
'Examples:\n' +
|
|
73
|
+
' wasm-runner ./hello.wasm # WASI, runs _start\n' +
|
|
74
|
+
' wasm-runner ./hello.wasm a b c # WASI, args [a,b,c]\n' +
|
|
75
|
+
' wasm-runner ./add.wasm add 3 4 # direct, → 7\n' +
|
|
76
|
+
' wasm-runner ./fib.wasm fib 10 # direct, → 55\n' +
|
|
77
|
+
'\n' +
|
|
78
|
+
'Limitations (direct mode):\n' +
|
|
79
|
+
' - Function args are integers only (parseInt). Float / string /\n' +
|
|
80
|
+
' multi-arg-shapes need a wrapper module.\n' +
|
|
81
|
+
' - Only integer return values are surfaced.\n' +
|
|
82
|
+
'\n' +
|
|
83
|
+
'Limitations (WASI mode, Wave-1):\n' +
|
|
84
|
+
' - 16 fns implemented: ' + WASI_WAVE1_FNS.join(', ') + '.\n' +
|
|
85
|
+
' - path_*, fd_readdir, fd_filestat_*, fd_pread, fd_pwrite, poll_oneoff,\n' +
|
|
86
|
+
' sock_* return ENOSYS (Wave-2 will add SqliteFS-backed paths).\n' +
|
|
87
|
+
' - fd 0 (stdin) returns EOF immediately.\n' +
|
|
88
|
+
' - Transport: bytes ship via the LOADER modules map, NOT\n' +
|
|
89
|
+
' WebAssembly.instantiate(bytes) at request time (CSP-blocked).';
|
|
90
|
+
/**
|
|
91
|
+
* Cheap supervisor-side WASI-detect: scan the wasm import section
|
|
92
|
+
* header bytes for the literal `wasi_snapshot_preview1` module name.
|
|
93
|
+
* No full parser — we just walk the import section and check the
|
|
94
|
+
* module-name string of each entry. False positives are not possible
|
|
95
|
+
* because import-section module names are length-prefixed UTF-8
|
|
96
|
+
* blocks; a substring match against the raw bytes is sufficient
|
|
97
|
+
* (the literal "wasi_snapshot_preview1" doesn't appear inside any
|
|
98
|
+
* other section's well-formed payload at the import position).
|
|
99
|
+
*
|
|
100
|
+
* This avoids `WebAssembly.Module.imports(mod)` which can only run
|
|
101
|
+
* inside a context that holds a precompiled Module — we don't yet
|
|
102
|
+
* have one in the supervisor (CSP blocks request-time compile).
|
|
103
|
+
*/
|
|
104
|
+
function hasWasiImports(bytes) {
|
|
105
|
+
// Recognise BOTH 'wasi_snapshot_preview1' (modern) AND
|
|
106
|
+
// 'wasi_unstable' (older WASI ABI, binji-linked binaries use this).
|
|
107
|
+
// Either substring in the wasm bytes is sufficient — WASI module-
|
|
108
|
+
// name strings are length-prefixed UTF-8 in the import section; a
|
|
109
|
+
// substring match against the raw bytes can't false-positive at the
|
|
110
|
+
// import position. False-positives elsewhere (e.g. in a data
|
|
111
|
+
// section that happens to contain "wasi_unstable" as a string
|
|
112
|
+
// literal) are harmless — the WASI shim won't be invoked unless
|
|
113
|
+
// the wasm actually has `_start` and the imports the shim provides.
|
|
114
|
+
const enc = new TextEncoder();
|
|
115
|
+
const needles = [
|
|
116
|
+
enc.encode('wasi_snapshot_preview1'),
|
|
117
|
+
enc.encode('wasi_unstable'),
|
|
118
|
+
];
|
|
119
|
+
for (const needle of needles) {
|
|
120
|
+
if (bytes.length < needle.length)
|
|
121
|
+
continue;
|
|
122
|
+
outer: for (let i = 0; i <= bytes.length - needle.length; i++) {
|
|
123
|
+
for (let j = 0; j < needle.length; j++) {
|
|
124
|
+
if (bytes[i + j] !== needle[j])
|
|
125
|
+
continue outer;
|
|
126
|
+
}
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Convert a Uint8Array to a base64 string. Used to encode VFS file
|
|
134
|
+
* contents into the JSON-serializable `context` field of the loader
|
|
135
|
+
* pool. Workerd's btoa is the standard one; we use it directly rather
|
|
136
|
+
* than depending on Node's Buffer (which works in workerd via the
|
|
137
|
+
* nodejs_compat polyfill but adds an import dependency).
|
|
138
|
+
*/
|
|
139
|
+
function bytesToB64(bytes) {
|
|
140
|
+
let s = '';
|
|
141
|
+
for (let i = 0; i < bytes.length; i++)
|
|
142
|
+
s += String.fromCharCode(bytes[i]);
|
|
143
|
+
return btoa(s);
|
|
144
|
+
}
|
|
145
|
+
function b64ToBytes(b64) {
|
|
146
|
+
const bin = atob(b64);
|
|
147
|
+
const out = new Uint8Array(bin.length);
|
|
148
|
+
for (let i = 0; i < bin.length; i++)
|
|
149
|
+
out[i] = bin.charCodeAt(i);
|
|
150
|
+
return out;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Snapshot a VFS subtree rooted at `vfsRoot` into a JSON-serializable
|
|
154
|
+
* `WasiFsSnapshot`. Used by the WASI runner to ship the user's session
|
|
155
|
+
* filesystem into the facet isolate.
|
|
156
|
+
*
|
|
157
|
+
* Bounded by:
|
|
158
|
+
* - 32 MiB total bytes (hard cap — bigger sessions need a per-call
|
|
159
|
+
* RPC dispatch architecture; defer to Wave-3).
|
|
160
|
+
* - 5000 file count.
|
|
161
|
+
*
|
|
162
|
+
* Returns null + a diagnostic if bounds are exceeded so the caller
|
|
163
|
+
* can surface a clear error to the user.
|
|
164
|
+
*/
|
|
165
|
+
function snapshotVfs(vfs, vfsRoot) {
|
|
166
|
+
const MAX_BYTES = 32 * 1024 * 1024;
|
|
167
|
+
const MAX_FILES = 5000;
|
|
168
|
+
const root = vfsRoot.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
169
|
+
const files = {};
|
|
170
|
+
const dirs = [];
|
|
171
|
+
let totalBytes = 0;
|
|
172
|
+
let fileCount = 0;
|
|
173
|
+
const stack = [root];
|
|
174
|
+
if (!vfs.exists(root)) {
|
|
175
|
+
return { snapshot: { root, preopens: [], files: {}, dirs: [root] }, bytes: 0, files: 0 };
|
|
176
|
+
}
|
|
177
|
+
dirs.push(root);
|
|
178
|
+
// Directory prefixes to skip during snapshot. The user's `~/.nimbus`
|
|
179
|
+
// install root holds nimbus-managed runtime bundles (clang.wasm,
|
|
180
|
+
// lld.wasm, sysroot.tar, Pyodide, …) that easily exceed the
|
|
181
|
+
// 32 MiB per-snapshot cap and don't belong in the WASI sandbox
|
|
182
|
+
// anyway. node_modules is similar — large, irrelevant to user
|
|
183
|
+
// wasm execution.
|
|
184
|
+
const skipSubdirs = new Set(['.nimbus', 'node_modules', '.cache', '.npm']);
|
|
185
|
+
while (stack.length > 0) {
|
|
186
|
+
const dir = stack.pop();
|
|
187
|
+
let entries;
|
|
188
|
+
try {
|
|
189
|
+
entries = vfs.readdir(dir);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
for (const e of entries) {
|
|
195
|
+
const childPath = dir + '/' + e.name;
|
|
196
|
+
if (e.type === 'directory') {
|
|
197
|
+
// Skip well-known large/irrelevant subdirs.
|
|
198
|
+
if (skipSubdirs.has(e.name))
|
|
199
|
+
continue;
|
|
200
|
+
dirs.push(childPath);
|
|
201
|
+
stack.push(childPath);
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
let bytes;
|
|
205
|
+
try {
|
|
206
|
+
bytes = vfs.readFile(childPath);
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
totalBytes += bytes.length;
|
|
212
|
+
fileCount++;
|
|
213
|
+
if (totalBytes > MAX_BYTES) {
|
|
214
|
+
return { error: `WASI snapshot exceeded 32 MiB cap (current dir: ${dir})` };
|
|
215
|
+
}
|
|
216
|
+
if (fileCount > MAX_FILES) {
|
|
217
|
+
return { error: `WASI snapshot exceeded 5000 file cap` };
|
|
218
|
+
}
|
|
219
|
+
files[childPath] = bytesToB64(bytes);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
snapshot: { root, preopens: [], files, dirs },
|
|
224
|
+
bytes: totalBytes,
|
|
225
|
+
files: fileCount,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Apply a WasiFsDiff produced by the facet back into the supervisor's
|
|
230
|
+
* SqliteFS. Each operation is independent; failures on one path don't
|
|
231
|
+
* abort the rest (we log to stderr and continue).
|
|
232
|
+
*/
|
|
233
|
+
function flushVfsDiff(vfs, diff) {
|
|
234
|
+
let written = 0, deleted = 0, mkdirs = 0, rmdirs = 0;
|
|
235
|
+
let timesTouched = 0, symlinks = 0;
|
|
236
|
+
for (const path of diff.dirsCreated) {
|
|
237
|
+
try {
|
|
238
|
+
vfs.mkdir(path, { recursive: true });
|
|
239
|
+
mkdirs++;
|
|
240
|
+
}
|
|
241
|
+
catch { }
|
|
242
|
+
}
|
|
243
|
+
for (const [path, b64] of Object.entries(diff.filesWritten)) {
|
|
244
|
+
try {
|
|
245
|
+
const bytes = b64ToBytes(b64);
|
|
246
|
+
// ensure parent dirs exist
|
|
247
|
+
const lastSlash = path.lastIndexOf('/');
|
|
248
|
+
if (lastSlash > 0) {
|
|
249
|
+
const parent = path.substring(0, lastSlash);
|
|
250
|
+
try {
|
|
251
|
+
vfs.mkdir(parent, { recursive: true });
|
|
252
|
+
}
|
|
253
|
+
catch { }
|
|
254
|
+
}
|
|
255
|
+
vfs.writeFile(path, bytes);
|
|
256
|
+
written++;
|
|
257
|
+
}
|
|
258
|
+
catch { }
|
|
259
|
+
}
|
|
260
|
+
for (const path of diff.filesDeleted) {
|
|
261
|
+
try {
|
|
262
|
+
vfs.unlink(path);
|
|
263
|
+
deleted++;
|
|
264
|
+
}
|
|
265
|
+
catch { }
|
|
266
|
+
}
|
|
267
|
+
for (const path of diff.dirsDeleted) {
|
|
268
|
+
try {
|
|
269
|
+
vfs.rmdir(path);
|
|
270
|
+
rmdirs++;
|
|
271
|
+
}
|
|
272
|
+
catch { }
|
|
273
|
+
}
|
|
274
|
+
// Stream-B B1+B3: count timesChanged / symlinks for diagnostics. The
|
|
275
|
+
// current SqliteVFS doesn't expose utime() or symlink() on its public
|
|
276
|
+
// surface, so we don't persist these across calls — they live only
|
|
277
|
+
// within the call (mtimes are read back correctly via stat→filestat_get
|
|
278
|
+
// before the snapshot returns). This is a documented v1 limitation.
|
|
279
|
+
if (diff.timesChanged) {
|
|
280
|
+
timesTouched = Object.keys(diff.timesChanged).length;
|
|
281
|
+
// Future hook: when SqliteVFS gains a utime() method, call it here:
|
|
282
|
+
// for (const [path, t] of Object.entries(diff.timesChanged)) {
|
|
283
|
+
// try { vfs.utime(path, Number(t.atime) / 1e9, Number(t.mtime) / 1e9); } catch {}
|
|
284
|
+
// }
|
|
285
|
+
}
|
|
286
|
+
if (diff.symlinksCreated) {
|
|
287
|
+
symlinks = Object.keys(diff.symlinksCreated).length;
|
|
288
|
+
// Future hook: when SqliteVFS gains a symlink() method, call it here.
|
|
289
|
+
}
|
|
290
|
+
return { written, deleted, mkdirs, rmdirs, timesTouched, symlinks };
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Build a `run` function suitable for RuntimeSpec.run(). Parameterised
|
|
294
|
+
* over the VFS, env (for env.LOADER), ctx (for the pool's doId-scoped
|
|
295
|
+
* cache key), and processTable + processLogs (for `ps` / `logs <pid>` /
|
|
296
|
+
* Process tab integration). Returns a fn that matches the runtime-
|
|
297
|
+
* registry's contract.
|
|
298
|
+
*/
|
|
299
|
+
export function makeWasmRunner(deps) {
|
|
300
|
+
return async function runWasm(_facetMgr, _code, opts) {
|
|
301
|
+
// opts.filename is the resolved .wasm path (absolute, /-prefixed
|
|
302
|
+
// by the registry's bypassesScriptRead path).
|
|
303
|
+
// opts.argv is:
|
|
304
|
+
// WASI mode: [<extra-args-to-program>...] (or empty)
|
|
305
|
+
// direct mode: [exportName, intArg1, intArg2, ...]
|
|
306
|
+
const wasmPath = (opts.filename || '').replace(/^\/+/, '');
|
|
307
|
+
const argv = opts.argv || [];
|
|
308
|
+
if (!deps.vfs.exists(wasmPath)) {
|
|
309
|
+
return {
|
|
310
|
+
exitCode: 1,
|
|
311
|
+
stdout: '',
|
|
312
|
+
stderr: `wasm-runner: cannot find module '${opts.filename}'\n`,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
let bytes;
|
|
316
|
+
try {
|
|
317
|
+
bytes = deps.vfs.readFile(wasmPath);
|
|
318
|
+
}
|
|
319
|
+
catch (e) {
|
|
320
|
+
return {
|
|
321
|
+
exitCode: 1,
|
|
322
|
+
stdout: '',
|
|
323
|
+
stderr: `wasm-runner: cannot read '${opts.filename}': ${e?.message || e}\n`,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
// Detect WASI imports BEFORE parsing argv as direct-mode integers.
|
|
327
|
+
// WASI mode treats every argv token as a string passed to the
|
|
328
|
+
// program; direct mode treats argv[0] as export name and the rest
|
|
329
|
+
// as integers.
|
|
330
|
+
const isWasi = hasWasiImports(bytes);
|
|
331
|
+
let exportName;
|
|
332
|
+
let parsedArgs = [];
|
|
333
|
+
let wasiArgv = [];
|
|
334
|
+
if (isWasi) {
|
|
335
|
+
// WASI argv convention: argv[0] is the program name. Use the
|
|
336
|
+
// module's filename (without leading slashes) so getopt-style
|
|
337
|
+
// libraries see something sensible.
|
|
338
|
+
const progName = (opts.filename || 'wasm').replace(/^\/+/, '').split('/').pop() || 'wasm';
|
|
339
|
+
wasiArgv = [progName, ...argv];
|
|
340
|
+
// Allow the user to pass `wasm-runner file.wasm _start` as a
|
|
341
|
+
// hint that they really want the _start entry (matches the
|
|
342
|
+
// existing direct-mode invocation shape so probes can be the
|
|
343
|
+
// same). _start is the default for WASI anyway.
|
|
344
|
+
if (argv.length > 0 && argv[0] === '_start') {
|
|
345
|
+
wasiArgv = [progName, ...argv.slice(1)];
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
exportName = argv[0];
|
|
350
|
+
const intArgs = argv.slice(1);
|
|
351
|
+
if (!exportName) {
|
|
352
|
+
return {
|
|
353
|
+
exitCode: 1,
|
|
354
|
+
stdout: '',
|
|
355
|
+
stderr: 'wasm-runner: missing export name\n' +
|
|
356
|
+
`Usage: wasm-runner ${opts.filename} <exportName> [int args...]\n`,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
// Parse integer args. Non-integer values are reported as a clear
|
|
360
|
+
// diagnostic rather than silently coerced (Number() would map
|
|
361
|
+
// 'foo' → NaN which the wasm fn would treat as 0 — confusing).
|
|
362
|
+
for (let i = 0; i < intArgs.length; i++) {
|
|
363
|
+
const n = parseInt(intArgs[i], 10);
|
|
364
|
+
if (!Number.isFinite(n)) {
|
|
365
|
+
return {
|
|
366
|
+
exitCode: 1,
|
|
367
|
+
stdout: '',
|
|
368
|
+
stderr: `wasm-runner: argument ${i + 1} ('${intArgs[i]}') is not an integer\n`,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
parsedArgs.push(n);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
// Convert Uint8Array (SqliteVFS native) into ArrayBuffer.
|
|
375
|
+
// structuredClone-safe ArrayBuffer is required by the pool's
|
|
376
|
+
// wasmModules contract; sub-views aren't accepted by workerd's
|
|
377
|
+
// modules map either. The slice() call always returns a fresh
|
|
378
|
+
// ArrayBuffer regardless of whether bytes.buffer was originally
|
|
379
|
+
// a Shared variant — TS's overload-resolution narrowing here is
|
|
380
|
+
// overly conservative; cast to ArrayBuffer is correct.
|
|
381
|
+
const buf = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
382
|
+
// Load the pool lazily — its constructor reaches into env.LOADER
|
|
383
|
+
// which we may not have at every wasm-runner construction site
|
|
384
|
+
// (e.g. unit tests that mock the registry). Lazy import keeps
|
|
385
|
+
// module load cheap.
|
|
386
|
+
const { NimbusLoaderPool } = await import('../loaders/loader-pool.js');
|
|
387
|
+
const pool = new NimbusLoaderPool(deps.env, deps.ctx, {
|
|
388
|
+
tag: isWasi ? 'wasm-runner-wasi' : 'wasm-runner',
|
|
389
|
+
concurrency: 1,
|
|
390
|
+
// No SUPERVISOR binding required for compute-only workloads,
|
|
391
|
+
// and omitting it keeps the bindings table minimal so the
|
|
392
|
+
// facet isolate boots fast.
|
|
393
|
+
omitSupervisor: true,
|
|
394
|
+
// WASI mode: ship the WASI shim source as a module-init preamble
|
|
395
|
+
// so `__wasiMakeImports` is in scope when the facet fn runs.
|
|
396
|
+
// Direct mode: no preamble (saves a few KB per submit).
|
|
397
|
+
preamble: isWasi ? WASI_INSTANCE_PREAMBLE_SRC : undefined,
|
|
398
|
+
});
|
|
399
|
+
const facetFn = async function wasmFacetCall(args) {
|
|
400
|
+
const wasmTable = globalThis.__NIMBUS_WASM || {};
|
|
401
|
+
const mod = wasmTable['user.wasm'];
|
|
402
|
+
if (!mod) {
|
|
403
|
+
return {
|
|
404
|
+
ok: false,
|
|
405
|
+
mode: args.mode,
|
|
406
|
+
error: 'globalThis.__NIMBUS_WASM[\'user.wasm\'] not found — the pool ' +
|
|
407
|
+
'did not register the module. Internal error.',
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
// ── WASI mode ──
|
|
411
|
+
if (args.mode === 'wasi') {
|
|
412
|
+
const mk = __wasiMakeImports;
|
|
413
|
+
const runStart = __wasiRunStart;
|
|
414
|
+
// Stream-B P3 / prod-verify-fix: bare lexical reference, matching
|
|
415
|
+
// the runStart pattern above. The earlier `(globalThis as any)
|
|
416
|
+
// .__wasiRunStartAsync` lookup returned undefined at runtime
|
|
417
|
+
// because top-level `function` declarations in the preamble's
|
|
418
|
+
// ES-module scope do NOT auto-attach to globalThis. The result
|
|
419
|
+
// was that sock_*/poll_oneoff (wrapped in WebAssembly.Suspending)
|
|
420
|
+
// were invoked from a sync `_start` call stack → V8 trapped with
|
|
421
|
+
// "trying to suspend without WebAssembly.promising". The 11
|
|
422
|
+
// sync-only Stream-B probes worked because they never hit a
|
|
423
|
+
// Suspending import; the 7 async probes failed because they did.
|
|
424
|
+
// The preamble is statically prepended to this same module body
|
|
425
|
+
// (loader-pool.ts:523-530), so the symbol is guaranteed in
|
|
426
|
+
// scope. typeof guard handles the impossible case of a preamble
|
|
427
|
+
// pre-dating Stream-B (defensive only).
|
|
428
|
+
const runStartAsync = typeof __wasiRunStartAsync === 'function'
|
|
429
|
+
? __wasiRunStartAsync
|
|
430
|
+
: null;
|
|
431
|
+
const initFS = __wasiInitFS;
|
|
432
|
+
const snapshotFS = __wasiSnapshotFS;
|
|
433
|
+
if (!mk || !runStart || !initFS || !snapshotFS) {
|
|
434
|
+
return {
|
|
435
|
+
ok: false,
|
|
436
|
+
mode: 'wasi',
|
|
437
|
+
error: 'WASI preamble missing: __wasi* helpers not defined. ' +
|
|
438
|
+
'Pool preamble may have failed to load.',
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
// Install the snapshotted VFS state into the WASI shim's
|
|
442
|
+
// virtual filesystem. fd 3 = the user's session root preopen.
|
|
443
|
+
// The shim's fd table is reset by initFS each call.
|
|
444
|
+
if (args.wasiFs) {
|
|
445
|
+
initFS({
|
|
446
|
+
root: args.wasiFs.root,
|
|
447
|
+
preopens: args.wasiFs.preopens,
|
|
448
|
+
files: args.wasiFs.files,
|
|
449
|
+
dirs: args.wasiFs.dirs,
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
// Minimal FS so __wasiFS isn't null when WASI fns are called.
|
|
454
|
+
initFS({ root: '', preopens: [], files: {}, dirs: [] });
|
|
455
|
+
}
|
|
456
|
+
const memRef = { mem: null };
|
|
457
|
+
const wasi = mk({
|
|
458
|
+
argv: args.wasiArgv || [],
|
|
459
|
+
env: args.wasiEnv || {},
|
|
460
|
+
getMemory: () => memRef.mem,
|
|
461
|
+
});
|
|
462
|
+
let inst;
|
|
463
|
+
try {
|
|
464
|
+
// Both modern `wasi_snapshot_preview1` and older
|
|
465
|
+
// `wasi_unstable` namespaces point at the SAME shim
|
|
466
|
+
// import object. The WASI ABIs are near-identical in
|
|
467
|
+
// function signatures (preview1 fixed fd_seek's offset
|
|
468
|
+
// width to i64 and the `filestat` struct layout); our
|
|
469
|
+
// shim implements preview1 and the older binji-linked
|
|
470
|
+
// binaries are tolerant of the wider types via JS
|
|
471
|
+
// BigInt coercion at the wasm boundary.
|
|
472
|
+
const result = await WebAssembly.instantiate(mod, {
|
|
473
|
+
wasi_snapshot_preview1: wasi.wasiImport,
|
|
474
|
+
wasi_unstable: wasi.wasiImport,
|
|
475
|
+
});
|
|
476
|
+
inst = (result instanceof WebAssembly.Instance ? result : result.instance);
|
|
477
|
+
}
|
|
478
|
+
catch (e) {
|
|
479
|
+
return {
|
|
480
|
+
ok: false,
|
|
481
|
+
mode: 'wasi',
|
|
482
|
+
error: `instantiate failed: ${e?.message || e}`,
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
memRef.mem = inst.exports.memory;
|
|
486
|
+
if (!memRef.mem) {
|
|
487
|
+
return {
|
|
488
|
+
ok: false,
|
|
489
|
+
mode: 'wasi',
|
|
490
|
+
error: 'wasm module did not export a `memory` — WASI requires one.',
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
// Stream-B P3: use async runStart when available so any
|
|
494
|
+
// suspending socket imports can complete via JSPI. The async
|
|
495
|
+
// wrapper falls back to sync invocation internally when
|
|
496
|
+
// WebAssembly.promising isn't available, so this is safe for
|
|
497
|
+
// non-suspending programs too. Legacy preambles (pre-Stream-B)
|
|
498
|
+
// that ship without __wasiRunStartAsync still work via the
|
|
499
|
+
// sync runStart path.
|
|
500
|
+
const r = runStartAsync
|
|
501
|
+
? await runStartAsync(inst, { memory: memRef.mem })
|
|
502
|
+
: runStart(inst, { memory: memRef.mem });
|
|
503
|
+
const fsDiff = snapshotFS();
|
|
504
|
+
return {
|
|
505
|
+
ok: r.exitCode === 0 && !r.error,
|
|
506
|
+
mode: 'wasi',
|
|
507
|
+
stdout: wasi.getStdout(),
|
|
508
|
+
stderr: wasi.getStderr(),
|
|
509
|
+
exitCode: r.exitCode,
|
|
510
|
+
exports: Object.keys(inst.exports),
|
|
511
|
+
error: r.error,
|
|
512
|
+
fsDiff: fsDiff || undefined,
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
// ── Direct mode ──
|
|
516
|
+
let inst;
|
|
517
|
+
try {
|
|
518
|
+
// Single-arg instantiate against a precompiled Module — this
|
|
519
|
+
// is the form workerd's CSP DOES allow. The dynamic-bytes
|
|
520
|
+
// form (instantiate(ArrayBuffer)) is what's blocked.
|
|
521
|
+
const result = await WebAssembly.instantiate(mod, {});
|
|
522
|
+
inst = (result instanceof WebAssembly.Instance ? result : result.instance);
|
|
523
|
+
}
|
|
524
|
+
catch (e) {
|
|
525
|
+
return {
|
|
526
|
+
ok: false,
|
|
527
|
+
mode: 'direct',
|
|
528
|
+
error: `instantiate failed: ${e?.message || e}`,
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
const exportNames = Object.keys(inst.exports);
|
|
532
|
+
const fn = inst.exports[args.exportName];
|
|
533
|
+
if (typeof fn !== 'function') {
|
|
534
|
+
return {
|
|
535
|
+
ok: false,
|
|
536
|
+
mode: 'direct',
|
|
537
|
+
exports: exportNames,
|
|
538
|
+
error: `export '${args.exportName}' is not a function (or not exported). ` +
|
|
539
|
+
`Available exports: ${exportNames.join(', ')}`,
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
let out;
|
|
543
|
+
try {
|
|
544
|
+
out = fn(...(args.intArgs || []));
|
|
545
|
+
}
|
|
546
|
+
catch (e) {
|
|
547
|
+
return {
|
|
548
|
+
ok: false,
|
|
549
|
+
mode: 'direct',
|
|
550
|
+
exports: exportNames,
|
|
551
|
+
error: `${args.exportName}(${(args.intArgs || []).join(', ')}) threw: ${e?.message || e}`,
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
// BigInt (i64) → string; everything else → as-is.
|
|
555
|
+
if (typeof out === 'bigint')
|
|
556
|
+
return { ok: true, mode: 'direct', result: out.toString(), exports: exportNames };
|
|
557
|
+
return { ok: true, mode: 'direct', result: out, exports: exportNames };
|
|
558
|
+
};
|
|
559
|
+
// PID + log integration. The runtime-registry's contract is
|
|
560
|
+
// runtime-agnostic at the PID layer; node + bun get this for
|
|
561
|
+
// free via runFresh → facetMgr.exec which calls
|
|
562
|
+
// processTable.spawn. wasm-runner uses NimbusLoaderPool directly
|
|
563
|
+
// (compute-only, no SUPERVISOR binding needed) so we have to
|
|
564
|
+
// allocate the PID + log entries by hand.
|
|
565
|
+
const cmdLabel = 'wasm-runner ' +
|
|
566
|
+
(opts.filename || '').replace(/^\/+/, '/') +
|
|
567
|
+
' ' +
|
|
568
|
+
argv.join(' ');
|
|
569
|
+
const procEntry = deps.processTable.spawn(cmdLabel.trim(), ['wasm-runner', ...argv], opts.cwd || '/home/user');
|
|
570
|
+
const pid = procEntry.pid;
|
|
571
|
+
// Pass-through env vars (Nimbus shell sets HOME/USER/PATH/etc.). The
|
|
572
|
+
// runtime-registry's RuntimeRunOpts carries env on the way in; we
|
|
573
|
+
// forward to the WASI shim. Direct mode doesn't use env.
|
|
574
|
+
const wasiEnv = isWasi ? (opts.env || {}) : {};
|
|
575
|
+
// ── Wave-2: snapshot user's session VFS for WASI mode ──
|
|
576
|
+
//
|
|
577
|
+
// The user's cwd at invocation time is our session-root preopen
|
|
578
|
+
// anchor. WASI programs see this as fd 3 mapped to '/'. We
|
|
579
|
+
// snapshot the subtree, ship via the loader-pool `context`, and
|
|
580
|
+
// flush mutations back after _start returns.
|
|
581
|
+
//
|
|
582
|
+
// For direct mode there's no FS exposure — wasm runs in pure
|
|
583
|
+
// compute-only mode, no preopens.
|
|
584
|
+
let wasiFs;
|
|
585
|
+
let wasiFsBytes = 0;
|
|
586
|
+
let wasiFsFiles = 0;
|
|
587
|
+
if (isWasi) {
|
|
588
|
+
// Session root = cwd of the shell invocation. Falls back to /home/user.
|
|
589
|
+
const cwd = (opts.cwd || '/home/user').replace(/^\/+/, '');
|
|
590
|
+
const snap = snapshotVfs(deps.vfs, cwd);
|
|
591
|
+
if ('error' in snap) {
|
|
592
|
+
return {
|
|
593
|
+
exitCode: 1,
|
|
594
|
+
stdout: '',
|
|
595
|
+
stderr: `wasm-runner: ${snap.error}\n`,
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
wasiFs = {
|
|
599
|
+
root: snap.snapshot.root,
|
|
600
|
+
preopens: [
|
|
601
|
+
// fd 3 → '/' mapping (covers the user's session subtree).
|
|
602
|
+
{ wasiPath: '/', vfsPath: snap.snapshot.root },
|
|
603
|
+
],
|
|
604
|
+
files: snap.snapshot.files,
|
|
605
|
+
dirs: snap.snapshot.dirs,
|
|
606
|
+
};
|
|
607
|
+
wasiFsBytes = snap.bytes;
|
|
608
|
+
wasiFsFiles = snap.files;
|
|
609
|
+
}
|
|
610
|
+
let outcome;
|
|
611
|
+
try {
|
|
612
|
+
const submitArgs = isWasi
|
|
613
|
+
? { mode: 'wasi', wasiArgv, wasiEnv, wasiFs }
|
|
614
|
+
: { mode: 'direct', exportName: exportName, intArgs: parsedArgs };
|
|
615
|
+
outcome = (await pool.submit(facetFn, submitArgs, {
|
|
616
|
+
wasmModules: { 'user.wasm': buf },
|
|
617
|
+
// 30s ceiling for compute. Most wasm calls return in
|
|
618
|
+
// microseconds; runaway loops hit this and the pool returns
|
|
619
|
+
// a TimeoutError that surfaces as exitCode 1 + stderr.
|
|
620
|
+
timeoutMs: 30_000,
|
|
621
|
+
}));
|
|
622
|
+
}
|
|
623
|
+
catch (e) {
|
|
624
|
+
outcome = { ok: false, error: `dispatch failed: ${e?.message || e}` };
|
|
625
|
+
}
|
|
626
|
+
// ── Wave-2: flush mutated FS state back into SqliteFS ──
|
|
627
|
+
if (outcome.mode === 'wasi' && outcome.ok && outcome.fsDiff) {
|
|
628
|
+
try {
|
|
629
|
+
flushVfsDiff(deps.vfs, outcome.fsDiff);
|
|
630
|
+
}
|
|
631
|
+
catch (e) {
|
|
632
|
+
// Flush failure is non-fatal; the wasm ran, the user saw stdout.
|
|
633
|
+
// But surface a diagnostic so they know the FS didn't persist.
|
|
634
|
+
console.warn('wasm-runner: FS flush failed:', e?.message || e);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
let exitCode;
|
|
638
|
+
let stdout;
|
|
639
|
+
let stderr;
|
|
640
|
+
// The facet's `ok` field encodes "clean exit (code 0, no trap)" — but
|
|
641
|
+
// for WASI mode, a non-zero proc_exit IS legitimate program output,
|
|
642
|
+
// not a wasm-runner error. Branch on `mode` first so we surface the
|
|
643
|
+
// program's exit code unchanged.
|
|
644
|
+
if (outcome.mode === 'wasi') {
|
|
645
|
+
// WASI mode: pass through stdout/stderr the wasm wrote via
|
|
646
|
+
// fd_write. Exit code from proc_exit (or 0 on natural fall-through).
|
|
647
|
+
// If runStart reported an `error` (wasm trapped, _start missing,
|
|
648
|
+
// …), append it to stderr but still surface its exitCode (default
|
|
649
|
+
// 1 from runStart on trap) so callers can distinguish.
|
|
650
|
+
const wasiOut = outcome;
|
|
651
|
+
// Either branch carries optional stdout/stderr/exitCode/error.
|
|
652
|
+
stdout = wasiOut.stdout || '';
|
|
653
|
+
stderr = wasiOut.stderr || '';
|
|
654
|
+
if (wasiOut.error) {
|
|
655
|
+
stderr = (stderr ? stderr : '') +
|
|
656
|
+
`wasm-runner: wasi trap: ${wasiOut.error}\n`;
|
|
657
|
+
}
|
|
658
|
+
exitCode = wasiOut.exitCode ?? (wasiOut.ok ? 0 : 1);
|
|
659
|
+
}
|
|
660
|
+
else if (!outcome.ok) {
|
|
661
|
+
// Direct-mode failure or pre-instantiate dispatch failure — shell
|
|
662
|
+
// sees rc=1 + stderr.
|
|
663
|
+
exitCode = 1;
|
|
664
|
+
stdout = '';
|
|
665
|
+
stderr = `wasm-runner: ${outcome.error}\n`;
|
|
666
|
+
}
|
|
667
|
+
else {
|
|
668
|
+
// Direct mode success: surface the result on stdout. void-return
|
|
669
|
+
// is success with no output; callers chain `&& echo OK` to detect.
|
|
670
|
+
stdout =
|
|
671
|
+
outcome.result === undefined || outcome.result === null
|
|
672
|
+
? ''
|
|
673
|
+
: String(outcome.result) + '\n';
|
|
674
|
+
stderr = '';
|
|
675
|
+
exitCode = 0;
|
|
676
|
+
}
|
|
677
|
+
// Mirror stdout/stderr into the per-PID ring so `logs <pid>`
|
|
678
|
+
// and the Process tab WS log stream see the output. The
|
|
679
|
+
// append-then-markExit ordering matches what shellExecuteTracked
|
|
680
|
+
// does in init.ts:1559+ (Fix 5 contract).
|
|
681
|
+
if (stdout) {
|
|
682
|
+
try {
|
|
683
|
+
deps.processLogs.append(pid, 'stdout', stdout);
|
|
684
|
+
}
|
|
685
|
+
catch { }
|
|
686
|
+
}
|
|
687
|
+
if (stderr) {
|
|
688
|
+
try {
|
|
689
|
+
deps.processLogs.append(pid, 'stderr', stderr);
|
|
690
|
+
}
|
|
691
|
+
catch { }
|
|
692
|
+
}
|
|
693
|
+
try {
|
|
694
|
+
deps.processTable.exit(pid, exitCode);
|
|
695
|
+
}
|
|
696
|
+
catch { }
|
|
697
|
+
try {
|
|
698
|
+
if (!deps.processLogs.getExit(pid)) {
|
|
699
|
+
deps.processLogs.markExit(pid, exitCode);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
catch { }
|
|
703
|
+
return { exitCode, stdout, stderr };
|
|
704
|
+
};
|
|
705
|
+
}
|