@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,981 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cirrus-real.ts — Real Vite inside a Cloudflare DO facet.
|
|
3
|
+
*
|
|
4
|
+
* Ships alongside the in-process Cirrus shim (src/vite-dev-server.ts,
|
|
5
|
+
* untouched). Users opt into real-vite mode via `NIMBUS_REAL_VITE=1`
|
|
6
|
+
* or `nimbusDevServer: 'real'` in vite.config.ts.
|
|
7
|
+
*
|
|
8
|
+
* Phase status (PHASE2-REAL-VITE-PLAN.md):
|
|
9
|
+
* 0 (import + createServer + listen) — GREEN, shipped
|
|
10
|
+
* 1 (VFS-backed fs shim) — implemented here
|
|
11
|
+
* 2 (HMR over our /ws) — implemented here
|
|
12
|
+
* 3 (real @vitejs/plugin-react) — depends on plugin preload
|
|
13
|
+
* 4 (opt-in polish + boot banner) — implemented in nimbus-session
|
|
14
|
+
*
|
|
15
|
+
* Architecture:
|
|
16
|
+
*
|
|
17
|
+
* NimbusSession (supervisor DO)
|
|
18
|
+
* │
|
|
19
|
+
* │ LOADER.load({
|
|
20
|
+
* │ modules: {
|
|
21
|
+
* │ main.js — facet entrypoint (generated)
|
|
22
|
+
* │ vite.bundle.js — 2.3 MB real Vite (pre-bundled)
|
|
23
|
+
* │ cirrus-fs.js — our fs shim (src/real-vite-fs-shim.ts)
|
|
24
|
+
* │ cirrus-fs-promises.js — ditto (fs/promises)
|
|
25
|
+
* │ cirrus-ws.js — our ws-shim (src/real-vite-hmr.ts)
|
|
26
|
+
* │ cirrus-chokidar.js — our chokidar shim (src/real-vite-hmr.ts)
|
|
27
|
+
* │ real-node-fs.js — raw node:fs re-export
|
|
28
|
+
* │ synthetic.js — seeds globalThis.__cirrusRealFs
|
|
29
|
+
* │ with the VFS snapshot
|
|
30
|
+
* │ user-vite-config.js — pre-bundled vite.config.ts
|
|
31
|
+
* │ }
|
|
32
|
+
* │ })
|
|
33
|
+
* ▼
|
|
34
|
+
* Dynamic Worker (facet)
|
|
35
|
+
* - imports synthetic.js (side-effect: populates globalThis.__cirrusRealFs)
|
|
36
|
+
* - imports vite.bundle.js (evaluates, sees the seeded fs Map)
|
|
37
|
+
* - starts Vite server via `createServer().listen()`
|
|
38
|
+
* - exposes fetch via httpServerHandler({port}) from cloudflare:node
|
|
39
|
+
* - runs a long-poll loop against env.SUPERVISOR.hmrNextEvent
|
|
40
|
+
* that delivers VFS change events to the chokidar shim + HMR
|
|
41
|
+
* client messages to the ws shim
|
|
42
|
+
*
|
|
43
|
+
* All traffic in / out:
|
|
44
|
+
* Browser ──/preview/* ──> DO.fetch ──> facetStub.fetch
|
|
45
|
+
* Browser ──/preview/__nimbus_hmr──> DO.fetch (WS upgrade)
|
|
46
|
+
* │
|
|
47
|
+
* ▼
|
|
48
|
+
* HmrBridge (nimbus-session-side)
|
|
49
|
+
* │ long-poll
|
|
50
|
+
* ▼
|
|
51
|
+
* facet loop ──> chokidar / ws shim
|
|
52
|
+
*/
|
|
53
|
+
// [sdk-phase-1] Large blobs (REAL_VITE_BUNDLE 4.6 MB, ROLLUP_WASM 2.5 MB,
|
|
54
|
+
// CIRRUS_PLUGIN_REACT_BUNDLE 3.0 MB) now ship via the ASSETS binding
|
|
55
|
+
// instead of inline. We import async getters here; start() became async
|
|
56
|
+
// so it can await them. CIRRUS_NPM_CJS_BUNDLES stays inline (1.2 MB,
|
|
57
|
+
// used inside the sync part of start()).
|
|
58
|
+
import { REAL_VITE_VERSION, VITE_CLIENT_MJS, VITE_ENV_MJS, getRealViteBundle, getRollupWasmBase64, } from '../real-vite-bundle.generated.js';
|
|
59
|
+
import { CIRRUS_PLUGIN_REACT_VERSION, getCirrusPluginReactBundle, } from '../cirrus-plugin-react.generated.js';
|
|
60
|
+
import { CIRRUS_NPM_CJS_BUNDLES, CIRRUS_NPM_CJS_VERSIONS } from '../cirrus-npm-cjs.generated.js';
|
|
61
|
+
import { CF_COMPAT_DATE } from '../constants.js';
|
|
62
|
+
import { getCtxExports } from '../session/ctx-exports.js';
|
|
63
|
+
import { buildFsSnapshot, generateFsShimModuleCode, generateFsPromisesShimModuleCode, generateSyntheticModuleCode, } from './real-vite-fs-shim.js';
|
|
64
|
+
import { HmrBridge, registerHmrBridge, generateWsShimModuleCode, generateChokidarShimModuleCode, } from './real-vite-hmr.js';
|
|
65
|
+
/**
|
|
66
|
+
* Compatibility flags for the real-vite facet.
|
|
67
|
+
*
|
|
68
|
+
* nodejs_compat — base Node polyfills
|
|
69
|
+
* enable_nodejs_http_modules — http.get / http.request
|
|
70
|
+
* enable_nodejs_http_server_modules — http.createServer / Server
|
|
71
|
+
*
|
|
72
|
+
* (expose_global_message_channel is not strictly required for our flow
|
|
73
|
+
* since we don't use Worker in FakeWorker mode yet; add later if needed.)
|
|
74
|
+
*/
|
|
75
|
+
const REAL_VITE_COMPAT_FLAGS = [
|
|
76
|
+
'nodejs_compat',
|
|
77
|
+
'enable_nodejs_http_modules',
|
|
78
|
+
'enable_nodejs_http_server_modules',
|
|
79
|
+
];
|
|
80
|
+
/**
|
|
81
|
+
* Resolve opt-in mode.
|
|
82
|
+
*
|
|
83
|
+
* Priority: env var > vite.config.ts regex sniff > default ('cirrus').
|
|
84
|
+
*/
|
|
85
|
+
export function shouldUseRealVite(opts) {
|
|
86
|
+
const env = opts.env || {};
|
|
87
|
+
const v = env.NIMBUS_REAL_VITE;
|
|
88
|
+
if (v != null) {
|
|
89
|
+
const s = String(v).trim().toLowerCase();
|
|
90
|
+
if (s === '1' || s === 'true' || s === 'yes' || s === 'real')
|
|
91
|
+
return true;
|
|
92
|
+
if (s === '0' || s === 'false' || s === 'no' || s === 'cirrus' || s === 'shim')
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
const cfg = opts.viteConfigSource;
|
|
96
|
+
if (cfg) {
|
|
97
|
+
// Regex-only (safe: no eval). Matches `nimbusDevServer: 'real'` /
|
|
98
|
+
// `'shim'` / `'auto'` with either quote style.
|
|
99
|
+
const m = cfg.match(/nimbusDevServer\s*:\s*['"]([a-z-]+)['"]/i);
|
|
100
|
+
if (m) {
|
|
101
|
+
const mode = m[1].toLowerCase();
|
|
102
|
+
if (mode === 'real' || mode === 'real-vite')
|
|
103
|
+
return true;
|
|
104
|
+
if (mode === 'cirrus' || mode === 'shim')
|
|
105
|
+
return false;
|
|
106
|
+
if (mode === 'auto') {
|
|
107
|
+
// Heuristic: if the config imports any @vitejs/* plugin, prefer
|
|
108
|
+
// real-vite; otherwise stick with Cirrus.
|
|
109
|
+
return /@vitejs\/plugin-[\w-]+/.test(cfg);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
// ── Facet entrypoint source generator ─────────────────────────────────
|
|
116
|
+
function generateMainModuleCode(opts) {
|
|
117
|
+
const { port, root, basePath, hasUserViteConfig } = opts;
|
|
118
|
+
const configImportLine = hasUserViteConfig
|
|
119
|
+
? `import __userConfig from './user-vite-config.js';`
|
|
120
|
+
: `const __userConfig = {};`;
|
|
121
|
+
return `
|
|
122
|
+
// ── Facet entrypoint: real Vite in a DO Facet [D'.1] ───────────────
|
|
123
|
+
// Generated by src/cirrus-real.ts.
|
|
124
|
+
//
|
|
125
|
+
// Track D' / D'.1: this module exports a DurableObject class so the
|
|
126
|
+
// supervisor can spawn it via ctx.facets.get('cirrus-real-vite',
|
|
127
|
+
// {class}). The facet has its own SQLite (this.ctx.storage) which we
|
|
128
|
+
// use to persist a per-facet identity cookie — that's what proves
|
|
129
|
+
// the same facet instance is reused across supervisor reconnects vs.
|
|
130
|
+
// being re-created from scratch.
|
|
131
|
+
//
|
|
132
|
+
// Pre-D'.1 the export was \`export default { fetch(req, env, ctx) }\`
|
|
133
|
+
// — a stateless WorkerEntrypoint shape spawned via env.LOADER.load().
|
|
134
|
+
// That worker had no own storage and was rebuilt on every start().
|
|
135
|
+
import { DurableObject } from "cloudflare:workers";
|
|
136
|
+
|
|
137
|
+
globalThis.__cirrusFsDebug = false;
|
|
138
|
+
globalThis.__cirrusResolveDebug = false;
|
|
139
|
+
// CLN-3 (2026-05-11): umbrella debug flag for hot-path HMR / dispatch /
|
|
140
|
+
// memory-snapshot / WS-accept logs in cirrus-real.ts + real-vite-hmr.ts.
|
|
141
|
+
// Default off in prod. Diagnostic users mutate at runtime
|
|
142
|
+
// (globalThis.__cirrusDebug = true) or ship a temp-deploy with the
|
|
143
|
+
// literal "= true" here. Mirrors the __cirrusFsDebug / __cirrusResolveDebug pattern.
|
|
144
|
+
globalThis.__cirrusDebug = false;
|
|
145
|
+
|
|
146
|
+
// ── Phase-A memory telemetry ──────────────────────────────────────
|
|
147
|
+
// Records process.memoryUsage() at key phases so we can measure
|
|
148
|
+
// exactly where heap grows. Numbers go to the supervisor RPC
|
|
149
|
+
// (telemetry.report) AND stdout for the wrangler log.
|
|
150
|
+
let __cirrusPhaseBaseline = null;
|
|
151
|
+
function __cirrusMem(phase) {
|
|
152
|
+
try {
|
|
153
|
+
const mu = process.memoryUsage();
|
|
154
|
+
const cache = globalThis.__cirrusRealFs?.files?.size ?? 0;
|
|
155
|
+
const cacheBytes = globalThis.__cirrusRealFsLruSize ?? 0;
|
|
156
|
+
const row = {
|
|
157
|
+
phase,
|
|
158
|
+
heapUsed: (mu.heapUsed / 1024 / 1024).toFixed(1) + 'MB',
|
|
159
|
+
heapTotal: (mu.heapTotal / 1024 / 1024).toFixed(1) + 'MB',
|
|
160
|
+
rss: (mu.rss / 1024 / 1024).toFixed(1) + 'MB',
|
|
161
|
+
external: (mu.external / 1024 / 1024).toFixed(1) + 'MB',
|
|
162
|
+
cacheEntries: cache,
|
|
163
|
+
cacheKB: (cacheBytes / 1024).toFixed(0) + 'KB',
|
|
164
|
+
};
|
|
165
|
+
if (__cirrusPhaseBaseline == null) __cirrusPhaseBaseline = mu.heapUsed;
|
|
166
|
+
row.delta = '+' + ((mu.heapUsed - __cirrusPhaseBaseline) / 1024 / 1024).toFixed(1) + 'MB';
|
|
167
|
+
if (globalThis.__cirrusDebug) console.log('[cirrus-mem]', JSON.stringify(row));
|
|
168
|
+
} catch (e) {
|
|
169
|
+
if (globalThis.__cirrusDebug) console.log('[cirrus-mem]', phase, 'err:', e?.message || e);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
__cirrusMem('module-top (pre-imports)');
|
|
173
|
+
|
|
174
|
+
// workerd sometimes terminates the isolate without surfacing the
|
|
175
|
+
// failure on stdout — install uncaught handlers so we at least see
|
|
176
|
+
// the event in the wrangler log.
|
|
177
|
+
try {
|
|
178
|
+
globalThis.addEventListener?.('error', (ev) => {
|
|
179
|
+
try { console.error('[cirrus-real uncaught]', ev.error?.stack || ev.error?.message || ev.message); } catch {}
|
|
180
|
+
});
|
|
181
|
+
globalThis.addEventListener?.('unhandledrejection', (ev) => {
|
|
182
|
+
try { console.error('[cirrus-real unhandledrejection]', ev.reason?.stack || ev.reason?.message || ev.reason); } catch {}
|
|
183
|
+
});
|
|
184
|
+
} catch {}
|
|
185
|
+
|
|
186
|
+
import { createRequire as __cirrusCreateRequire } from 'node:module';
|
|
187
|
+
globalThis.__cirrusNodeCreateRequire = __cirrusCreateRequire;
|
|
188
|
+
|
|
189
|
+
import './synthetic.js';
|
|
190
|
+
__cirrusMem('post synthetic.js');
|
|
191
|
+
import './cirrus-ws.js';
|
|
192
|
+
import './cirrus-chokidar.js';
|
|
193
|
+
__cirrusMem('post ws+chokidar shims');
|
|
194
|
+
|
|
195
|
+
${configImportLine}
|
|
196
|
+
__cirrusMem('post user-vite-config.js');
|
|
197
|
+
|
|
198
|
+
import * as vite from './vite.bundle.js';
|
|
199
|
+
__cirrusMem('post vite.bundle.js');
|
|
200
|
+
import { httpServerHandler } from 'cloudflare:node';
|
|
201
|
+
__cirrusMem('all imports complete');
|
|
202
|
+
|
|
203
|
+
const PORT = ${port};
|
|
204
|
+
const ROOT = ${JSON.stringify(root)};
|
|
205
|
+
const BASE = ${JSON.stringify(basePath)};
|
|
206
|
+
|
|
207
|
+
let serverReady = null;
|
|
208
|
+
let readyError = null;
|
|
209
|
+
let boot = null;
|
|
210
|
+
let viteServerInstance = null;
|
|
211
|
+
|
|
212
|
+
// Env bindings — made available to the fs shim + HMR loop via
|
|
213
|
+
// globalThis so modules loaded AFTER the first fetch handler can
|
|
214
|
+
// reach them without needing env passed through.
|
|
215
|
+
let _supervisorBinding = null;
|
|
216
|
+
let _hmrBinding = null;
|
|
217
|
+
|
|
218
|
+
function installBindings(env) {
|
|
219
|
+
const sup = env?.SUPERVISOR;
|
|
220
|
+
if (sup && !_supervisorBinding) {
|
|
221
|
+
_supervisorBinding = sup;
|
|
222
|
+
globalThis.__cirrusRealSupervisor = sup;
|
|
223
|
+
}
|
|
224
|
+
const hmr = env?.CIRRUS_HMR;
|
|
225
|
+
if (hmr && !_hmrBinding) {
|
|
226
|
+
_hmrBinding = hmr;
|
|
227
|
+
globalThis.__cirrusRealHmr = hmr;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Pre-extract HMR controls once vite is ready, so the long-poll loop
|
|
232
|
+
// can dispatch events to the bundled-in chokidar-shim watchers and
|
|
233
|
+
// ws-shim connections.
|
|
234
|
+
function dispatchEvents(events) {
|
|
235
|
+
if (!events || events.length === 0) return;
|
|
236
|
+
if (globalThis.__cirrusDebug) console.log('[cirrus-real dispatch]', events.length, 'events. types:', events.map(e => e.type).join(','));
|
|
237
|
+
for (const ev of events) {
|
|
238
|
+
try {
|
|
239
|
+
if (ev.type === 'connection') {
|
|
240
|
+
const wss = globalThis.__cirrusRealWsServer;
|
|
241
|
+
if (globalThis.__cirrusDebug) console.log('[cirrus-real] connection event, wss?', !!wss);
|
|
242
|
+
if (wss) wss._acceptConnection(ev.clientId);
|
|
243
|
+
} else if (ev.type === 'message') {
|
|
244
|
+
const wss = globalThis.__cirrusRealWsServer;
|
|
245
|
+
if (wss) wss._dispatchMessage(ev.clientId, ev.msg);
|
|
246
|
+
} else if (ev.type === 'disconnect') {
|
|
247
|
+
const wss = globalThis.__cirrusRealWsServer;
|
|
248
|
+
if (wss) wss._disconnect(ev.clientId);
|
|
249
|
+
} else if (ev.type === 'vfs') {
|
|
250
|
+
const ws = globalThis.__cirrusRealWatchers;
|
|
251
|
+
if (ws) for (const w of ws) {
|
|
252
|
+
try { w._dispatch(ev.event, ev.path, ev.oldPath); } catch {}
|
|
253
|
+
}
|
|
254
|
+
// CRITICAL: invalidate the fs-shim snapshot cache so
|
|
255
|
+
// subsequent readFile calls hit SUPERVISOR.readFile and
|
|
256
|
+
// fetch the fresh content. Without this, Vite serves the
|
|
257
|
+
// OLD source on the HMR update cycle → browser reloads
|
|
258
|
+
// but sees the same content → user thinks HMR is broken.
|
|
259
|
+
if (globalThis.__cirrusRealFs) {
|
|
260
|
+
if (ev.event === 'unlink' || ev.event === 'unlinkDir') {
|
|
261
|
+
globalThis.__cirrusRealFs.files.delete(ev.path);
|
|
262
|
+
} else if (ev.event === 'change' || ev.event === 'add') {
|
|
263
|
+
globalThis.__cirrusRealFs.files.delete(ev.path);
|
|
264
|
+
} else if (ev.event === 'rename' && ev.oldPath) {
|
|
265
|
+
globalThis.__cirrusRealFs.files.delete(ev.oldPath);
|
|
266
|
+
globalThis.__cirrusRealFs.files.delete(ev.path);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
} catch (e) {
|
|
271
|
+
console.warn('[cirrus-real] dispatchEvents item threw:', e?.message);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Poll for HMR events — drive the pump off request cycles so we
|
|
277
|
+
// don't leave a long-poll dangling when no request is active
|
|
278
|
+
// (workerd may think the request itself is hung). Each fetch kicks
|
|
279
|
+
// the pump: a short-timeout poll (2s) that dispatches events and
|
|
280
|
+
// returns. If clients are connected, the pump schedules itself again
|
|
281
|
+
// via waitUntil.
|
|
282
|
+
async function pumpHmrOnce(ctx) {
|
|
283
|
+
if (!_hmrBinding) return;
|
|
284
|
+
try {
|
|
285
|
+
// Short timeout so we don't hold a request's waitUntil chain for
|
|
286
|
+
// too long. The supervisor returns immediately if there are
|
|
287
|
+
// pending events, so latency is fine.
|
|
288
|
+
const events = await _hmrBinding.hmrNextEvent(2_000);
|
|
289
|
+
dispatchEvents(events);
|
|
290
|
+
// Reschedule: if we have active WS clients or recent events, keep
|
|
291
|
+
// polling. Otherwise one shot per request is enough.
|
|
292
|
+
if (ctx?.waitUntil && (globalThis.__cirrusRealWsClients?.size > 0)) {
|
|
293
|
+
ctx.waitUntil(pumpHmrOnce(ctx));
|
|
294
|
+
}
|
|
295
|
+
} catch {
|
|
296
|
+
// RPC error (rare) — back off; next request will try again.
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function bootOnce() {
|
|
301
|
+
if (serverReady) return serverReady;
|
|
302
|
+
__cirrusMem('bootOnce.start');
|
|
303
|
+
serverReady = (async () => {
|
|
304
|
+
try {
|
|
305
|
+
const resolvedUserConfig = typeof __userConfig === 'function'
|
|
306
|
+
? await __userConfig({ command: 'serve', mode: 'development', isSsrBuild: false, isPreview: false })
|
|
307
|
+
: (__userConfig && typeof __userConfig === 'object' ? __userConfig : {});
|
|
308
|
+
const cfg = {
|
|
309
|
+
...resolvedUserConfig,
|
|
310
|
+
root: ROOT || '/',
|
|
311
|
+
base: BASE,
|
|
312
|
+
configLoader: 'runner',
|
|
313
|
+
configFile: false, // we already loaded the config above
|
|
314
|
+
logLevel: 'info',
|
|
315
|
+
clearScreen: false,
|
|
316
|
+
optimizeDeps: {
|
|
317
|
+
...(resolvedUserConfig.optimizeDeps || {}),
|
|
318
|
+
noDiscovery: true,
|
|
319
|
+
include: [],
|
|
320
|
+
force: false,
|
|
321
|
+
disabled: true,
|
|
322
|
+
entries: [],
|
|
323
|
+
esbuildOptions: { ...(resolvedUserConfig.optimizeDeps?.esbuildOptions || {}), plugins: [] },
|
|
324
|
+
},
|
|
325
|
+
// legacy.buildSsrCjsExternalHeuristics is a no-op but listed
|
|
326
|
+
// here as a reminder that we want zero esbuild invocations.
|
|
327
|
+
// Disable Vite's esbuild-based TS/JSX transform entirely.
|
|
328
|
+
// esbuild's JS API refuses to run when bundled into another
|
|
329
|
+
// file (it requires spawning a native binary). Plugins like
|
|
330
|
+
// @vitejs/plugin-react handle JSX transforms themselves via
|
|
331
|
+
// Babel, so we don't actually need the built-in esbuild
|
|
332
|
+
// transformer when a plugin is present.
|
|
333
|
+
esbuild: false,
|
|
334
|
+
server: {
|
|
335
|
+
...(resolvedUserConfig.server || {}),
|
|
336
|
+
port: PORT,
|
|
337
|
+
host: '127.0.0.1',
|
|
338
|
+
strictPort: true,
|
|
339
|
+
fs: { strict: false, ...(resolvedUserConfig.server?.fs || {}) },
|
|
340
|
+
// HMR: path tells the browser @vite/client what URL to open
|
|
341
|
+
// (resolved against window.location.origin). We don't set
|
|
342
|
+
// clientPort/host so the browser uses same-origin — which
|
|
343
|
+
// is how the user reached us in the first place.
|
|
344
|
+
hmr: {
|
|
345
|
+
path: '__nimbus_hmr',
|
|
346
|
+
...(typeof resolvedUserConfig.server?.hmr === 'object' ? resolvedUserConfig.server.hmr : {}),
|
|
347
|
+
},
|
|
348
|
+
// Enable file watching — our chokidar shim catches the
|
|
349
|
+
// chokidar.watch() call and returns a CirrusWatcher that
|
|
350
|
+
// delivers events from the HmrBridge long-poll. Disabling
|
|
351
|
+
// polling so the shim doesn't waste cycles.
|
|
352
|
+
watch: {
|
|
353
|
+
usePolling: false,
|
|
354
|
+
...(resolvedUserConfig.server?.watch || {}),
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
appType: resolvedUserConfig.appType || 'spa',
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
__cirrusMem('bootOnce.before createServer');
|
|
361
|
+
const server = await vite.createServer(cfg);
|
|
362
|
+
viteServerInstance = server;
|
|
363
|
+
__cirrusMem('bootOnce.after createServer');
|
|
364
|
+
await server.listen();
|
|
365
|
+
__cirrusMem('bootOnce.after listen');
|
|
366
|
+
return server;
|
|
367
|
+
} catch (e) {
|
|
368
|
+
readyError = e;
|
|
369
|
+
console.error('[cirrus-real] Vite boot failed:', e && e.stack ? e.stack : e);
|
|
370
|
+
throw e;
|
|
371
|
+
}
|
|
372
|
+
})();
|
|
373
|
+
return serverReady;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// ── DurableObject class — the D'.1 entrypoint ───────────────────────
|
|
377
|
+
//
|
|
378
|
+
// Lifecycle:
|
|
379
|
+
// - First ctx.facets.get(...) call: workerd instantiates this class
|
|
380
|
+
// ONCE per facet name. The constructor runs; this.ctx.storage is
|
|
381
|
+
// a fresh empty SQLite. ensureFacetCookie() writes a UUID row.
|
|
382
|
+
// - Subsequent ctx.facets.get(...) calls in the same supervisor
|
|
383
|
+
// isolate (or after hibernation/wake): workerd reuses the same
|
|
384
|
+
// instance; storage rows survive. ensureFacetCookie() reads
|
|
385
|
+
// the existing UUID.
|
|
386
|
+
//
|
|
387
|
+
// The supervisor's CirrusReal controller calls fetch() for every
|
|
388
|
+
// preview request and getDiag() for the /api/_diag/cirrus surface.
|
|
389
|
+
// HMR pump scheduling now lives on this class (each fetch() kicks
|
|
390
|
+
// pumpHmrOnce via this.ctx.waitUntil).
|
|
391
|
+
export class CirrusRealVite extends DurableObject {
|
|
392
|
+
__bootStartedAt;
|
|
393
|
+
__bootCompletedAt;
|
|
394
|
+
__cookie;
|
|
395
|
+
|
|
396
|
+
constructor(state, env) {
|
|
397
|
+
super(state, env);
|
|
398
|
+
this.__bootStartedAt = Date.now();
|
|
399
|
+
this.__bootCompletedAt = 0;
|
|
400
|
+
this.__cookie = '';
|
|
401
|
+
// Ensure schema + cookie row up front. SQLite operations on the
|
|
402
|
+
// facet's own storage; survives hibernation/wake of THIS facet.
|
|
403
|
+
try {
|
|
404
|
+
const sql = state?.storage?.sql;
|
|
405
|
+
if (sql) {
|
|
406
|
+
sql.exec('CREATE TABLE IF NOT EXISTS cirrus_facet_meta (k TEXT PRIMARY KEY, v TEXT NOT NULL)');
|
|
407
|
+
let found = '';
|
|
408
|
+
for (const row of sql.exec('SELECT v FROM cirrus_facet_meta WHERE k = ?', 'cookie')) {
|
|
409
|
+
found = String(row.v);
|
|
410
|
+
break;
|
|
411
|
+
}
|
|
412
|
+
if (found) {
|
|
413
|
+
this.__cookie = found;
|
|
414
|
+
} else {
|
|
415
|
+
// Mint a fresh UUID-shaped cookie and persist. crypto.randomUUID
|
|
416
|
+
// is available in workerd globals.
|
|
417
|
+
const c = (globalThis.crypto?.randomUUID?.() || ('cookie-' + Math.random().toString(16).slice(2)));
|
|
418
|
+
sql.exec('INSERT OR REPLACE INTO cirrus_facet_meta (k, v) VALUES (?, ?)', 'cookie', c);
|
|
419
|
+
this.__cookie = c;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
} catch (e) {
|
|
423
|
+
console.warn('[cirrus-real-facet] cookie-init failed:', e?.message || e);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/** RPC: identity + boot stats so the supervisor can surface them
|
|
428
|
+
* on /api/_diag/cirrus. */
|
|
429
|
+
async getFacetMeta() {
|
|
430
|
+
return {
|
|
431
|
+
cookie: this.__cookie,
|
|
432
|
+
bootMs: this.__bootCompletedAt > 0
|
|
433
|
+
? this.__bootCompletedAt - this.__bootStartedAt
|
|
434
|
+
: 0,
|
|
435
|
+
bootError: readyError ? String(readyError?.message || readyError) : null,
|
|
436
|
+
viteServerListening: viteServerInstance != null,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
async fetch(request) {
|
|
441
|
+
return __cirrusFetchImpl(request, this.env, this.ctx, () => {
|
|
442
|
+
if (this.__bootCompletedAt === 0) this.__bootCompletedAt = Date.now();
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// ── Stateless-fetcher fallback export [d1-fix] ────────────────────────
|
|
448
|
+
// When env.LOADER.get(...) returns a stub WITHOUT
|
|
449
|
+
// getDurableObjectClass (because the \`experimental\` compat flag is
|
|
450
|
+
// absent — the case in production CF deployments since the
|
|
451
|
+
// 2026-05-08 deploy validator change rejecting \$experimental flags
|
|
452
|
+
// for non-CF-team accounts), the supervisor cannot spawn this
|
|
453
|
+
// module as a DO Facet. It falls back to env.LOADER.get(...).
|
|
454
|
+
// getEntrypoint() — a stateless Fetcher.
|
|
455
|
+
//
|
|
456
|
+
// In that mode, the supervisor's fetch() routes here. We share all
|
|
457
|
+
// the module-scope vite-bootstrap state with the DurableObject
|
|
458
|
+
// path (boot, viteServerInstance, readyError, etc.) so the
|
|
459
|
+
// user-visible behavior is identical. The only delta: per-instance
|
|
460
|
+
// state (the cookie + per-instance bootMs) is N/A — the supervisor
|
|
461
|
+
// surfaces \`kind: 'fetcher-fallback'\` in /api/_diag/cirrus and the
|
|
462
|
+
// probe relaxes its assertions accordingly.
|
|
463
|
+
let __statelessBootCompletedAt = 0;
|
|
464
|
+
async function __cirrusFetchImpl(request, env, ctx, onBootComplete) {
|
|
465
|
+
installBindings(env);
|
|
466
|
+
const fetchUrl = request.url;
|
|
467
|
+
const fetchPath = (() => { try { return new URL(fetchUrl).pathname; } catch { return '?'; } })();
|
|
468
|
+
__cirrusMem('fetch.enter ' + fetchPath);
|
|
469
|
+
try {
|
|
470
|
+
await bootOnce();
|
|
471
|
+
if (typeof onBootComplete === 'function') onBootComplete();
|
|
472
|
+
if (__statelessBootCompletedAt === 0) __statelessBootCompletedAt = Date.now();
|
|
473
|
+
} catch {
|
|
474
|
+
// readyError set; fall through to error response.
|
|
475
|
+
}
|
|
476
|
+
if (readyError) {
|
|
477
|
+
const msg = '[cirrus-real] Vite failed to boot:\\n' +
|
|
478
|
+
(readyError && readyError.stack ? readyError.stack : String(readyError));
|
|
479
|
+
return new Response(msg, {
|
|
480
|
+
status: 500,
|
|
481
|
+
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
// HMR pump: kick once per fetch with a short poll. Events may be
|
|
485
|
+
// queued from a browser WS connection that attached between
|
|
486
|
+
// requests, OR VFS events fired since the last pump. We cap at
|
|
487
|
+
// one iteration per request — pumpHmrOnce re-schedules itself
|
|
488
|
+
// via waitUntil when clients are connected.
|
|
489
|
+
if (ctx?.waitUntil && _hmrBinding) {
|
|
490
|
+
ctx.waitUntil(pumpHmrOnce(ctx));
|
|
491
|
+
}
|
|
492
|
+
if (!boot) boot = httpServerHandler({ port: PORT });
|
|
493
|
+
try {
|
|
494
|
+
const resp = await boot.fetch(request, env, ctx);
|
|
495
|
+
__cirrusMem('fetch.exit ' + fetchPath + ' [' + resp.status + ']');
|
|
496
|
+
return resp;
|
|
497
|
+
} catch (e) {
|
|
498
|
+
return new Response('[cirrus-real] httpServerHandler.fetch threw: ' +
|
|
499
|
+
(e && e.stack ? e.stack : String(e)), {
|
|
500
|
+
status: 500,
|
|
501
|
+
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const __cirrusModuleLoadedAt = Date.now();
|
|
507
|
+
|
|
508
|
+
// Default export: stateless Fetcher shape. Used when the supervisor
|
|
509
|
+
// falls back to env.LOADER.get(...).getEntrypoint() because the DO
|
|
510
|
+
// Facet path is unavailable (no \`experimental\` flag).
|
|
511
|
+
//
|
|
512
|
+
// We use a WorkerEntrypoint subclass (instead of a plain
|
|
513
|
+
// default-export object) so the supervisor can call BOTH
|
|
514
|
+
// .fetch(req) and .getFacetMeta() via the same RPC stub —
|
|
515
|
+
// matching the API surface the DO Facet variant exposes.
|
|
516
|
+
import { WorkerEntrypoint } from 'cloudflare:workers';
|
|
517
|
+
export default class CirrusRealStateless extends WorkerEntrypoint {
|
|
518
|
+
async fetch(request) {
|
|
519
|
+
return __cirrusFetchImpl(request, this.env, this.ctx);
|
|
520
|
+
}
|
|
521
|
+
/** Stateless analog of CirrusRealVite.getFacetMeta(). Cookie is
|
|
522
|
+
* N/A in this mode (no per-facet SQLite); we surface bootMs and
|
|
523
|
+
* viteServerListening so the supervisor's diag still has
|
|
524
|
+
* observability. */
|
|
525
|
+
async getFacetMeta() {
|
|
526
|
+
return {
|
|
527
|
+
cookie: null, // N/A in stateless mode
|
|
528
|
+
bootMs: __statelessBootCompletedAt > 0
|
|
529
|
+
? __statelessBootCompletedAt - __cirrusModuleLoadedAt
|
|
530
|
+
: 0,
|
|
531
|
+
bootError: readyError ? String(readyError?.message || readyError) : null,
|
|
532
|
+
viteServerListening: viteServerInstance != null,
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
`.trim();
|
|
537
|
+
}
|
|
538
|
+
// ── Supervisor-side controller class ──────────────────────────────────
|
|
539
|
+
export class CirrusReal {
|
|
540
|
+
env;
|
|
541
|
+
port;
|
|
542
|
+
root;
|
|
543
|
+
basePath;
|
|
544
|
+
vfs;
|
|
545
|
+
vfsEvents;
|
|
546
|
+
userConfigBundle;
|
|
547
|
+
extraSyntheticFiles;
|
|
548
|
+
facetStub = null;
|
|
549
|
+
pid = 0;
|
|
550
|
+
bootError = null;
|
|
551
|
+
_startedAt = 0;
|
|
552
|
+
/** [D'.1] facet name used with ctx.facets.get/delete. Set in start(),
|
|
553
|
+
* cleared in stop(). */
|
|
554
|
+
_facetName = null;
|
|
555
|
+
/** Dispatch shape:
|
|
556
|
+
* - 'do-facet' (post-D'.1, requires `$experimental` compat flag)
|
|
557
|
+
* - 'fetcher-fallback' (D'.1 graceful-degrade, when
|
|
558
|
+
* getDurableObjectClass is unavailable — the prod and the
|
|
559
|
+
* flag-stripped local dev case after the 2026-05-08
|
|
560
|
+
* deploy-flag-fix tightening) [d1-fix]
|
|
561
|
+
* - null (not started, or stop()'d)
|
|
562
|
+
* Surfaced via /api/_diag/cirrus.kind for the probe.
|
|
563
|
+
*/
|
|
564
|
+
_kind = null;
|
|
565
|
+
/** [D'.1] timestamp when the facet stub was successfully obtained
|
|
566
|
+
* (after ctx.facets.get returned). Used to compute the supervisor-
|
|
567
|
+
* side bootMs that includes module compilation + facet binding,
|
|
568
|
+
* but NOT the in-facet vite.createServer.listen() (that's measured
|
|
569
|
+
* separately via getFacetMeta RPC). */
|
|
570
|
+
_bootCompletedAt = 0;
|
|
571
|
+
/** [D'.1] last fetch latency ms — surfaces on diag for warm-reuse
|
|
572
|
+
* perf assertions. */
|
|
573
|
+
_lastFetchMs = 0;
|
|
574
|
+
_snapshotStats = null;
|
|
575
|
+
/** HMR bridge — shared by WS upgrade handler + VFS event pump. */
|
|
576
|
+
hmr = new HmrBridge();
|
|
577
|
+
/** Unsubscribe from vfs events on stop(). */
|
|
578
|
+
_vfsUnsub = null;
|
|
579
|
+
constructor(opts) {
|
|
580
|
+
this.env = opts.env;
|
|
581
|
+
this.port = opts.port;
|
|
582
|
+
this.root = opts.root;
|
|
583
|
+
this.basePath = opts.basePath;
|
|
584
|
+
this.vfs = opts.vfs;
|
|
585
|
+
this.vfsEvents = opts.vfsEvents || null;
|
|
586
|
+
this.userConfigBundle = opts.userConfigBundle || null;
|
|
587
|
+
this.extraSyntheticFiles = opts.extraSyntheticFiles || {};
|
|
588
|
+
}
|
|
589
|
+
get isRunning() {
|
|
590
|
+
return this.facetStub != null && this.bootError == null;
|
|
591
|
+
}
|
|
592
|
+
get stats() {
|
|
593
|
+
return {
|
|
594
|
+
mode: 'real-vite',
|
|
595
|
+
viteVersion: REAL_VITE_VERSION,
|
|
596
|
+
pluginReactVersion: CIRRUS_PLUGIN_REACT_VERSION,
|
|
597
|
+
npmCjsVersions: CIRRUS_NPM_CJS_VERSIONS,
|
|
598
|
+
port: this.port,
|
|
599
|
+
root: this.root,
|
|
600
|
+
basePath: this.basePath,
|
|
601
|
+
bootError: this.bootError,
|
|
602
|
+
uptimeMs: this._startedAt ? Date.now() - this._startedAt : 0,
|
|
603
|
+
snapshot: this._snapshotStats,
|
|
604
|
+
sizeWarning: this._sizeWarning,
|
|
605
|
+
hmrClients: this.hmr.size,
|
|
606
|
+
hmrActive: this.hmr._everAwaitedEvents,
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
/** Soft warning set during start() if the project looks too large
|
|
610
|
+
* for the facet's 128 MB isolate budget. Surfaces in `stats` so
|
|
611
|
+
* the banner printed by nimbus-session.ts can show it. Empty
|
|
612
|
+
* string when the project is in the known-good envelope. */
|
|
613
|
+
_sizeWarning = '';
|
|
614
|
+
async start(ctx, pid) {
|
|
615
|
+
if (this.facetStub)
|
|
616
|
+
return;
|
|
617
|
+
this.pid = pid;
|
|
618
|
+
this._startedAt = Date.now();
|
|
619
|
+
// Build the project snapshot for the facet's sync-fs Map.
|
|
620
|
+
// (Lazy: eagerly seeds user project source + every package.json
|
|
621
|
+
// under node_modules. Source files in node_modules are loaded on
|
|
622
|
+
// demand via SUPERVISOR.readFile and cached in-facet.)
|
|
623
|
+
const snapshot = buildFsSnapshot(this.vfs, this.root);
|
|
624
|
+
this._snapshotStats = {
|
|
625
|
+
fileCount: snapshot.fileCount,
|
|
626
|
+
dirCount: snapshot.dirs.length,
|
|
627
|
+
totalBytes: snapshot.totalBytes,
|
|
628
|
+
skipped: snapshot.skipped,
|
|
629
|
+
packageJsonCount: snapshot.packageJsonCount,
|
|
630
|
+
pathIndexCount: snapshot.pathIndexCount,
|
|
631
|
+
};
|
|
632
|
+
// Size-based soft warning. Empirical findings (CIRRUS-OOM-TRACE.txt):
|
|
633
|
+
// - seed project (6307 post-install files, 2.5 MB snapshot,
|
|
634
|
+
// 203 pkg.json) survived 5 min without OOM
|
|
635
|
+
// - AshishKumar4/personal-website (58033 files, 22 MB snapshot,
|
|
636
|
+
// 945 pkg.json) survived 2 min without OOM
|
|
637
|
+
// - workerd isolate limit: 128 MB
|
|
638
|
+
// - static facet footprint: ~40 MB parsed modules + snapshot
|
|
639
|
+
//
|
|
640
|
+
// Above 100k files OR 60 MB snapshot OR 3000 pkg.json, we warn
|
|
641
|
+
// but don't block. Those are empirical — we haven't actually
|
|
642
|
+
// measured the ceiling because the tests held.
|
|
643
|
+
const warn = [];
|
|
644
|
+
if (snapshot.pathIndexCount > 100_000) {
|
|
645
|
+
warn.push(`${snapshot.pathIndexCount} indexed files in node_modules (above 100k may OOM)`);
|
|
646
|
+
}
|
|
647
|
+
if (snapshot.totalBytes > 60 * 1024 * 1024) {
|
|
648
|
+
warn.push(`snapshot is ${(snapshot.totalBytes / 1024 / 1024).toFixed(1)} MB (>60 MB may OOM)`);
|
|
649
|
+
}
|
|
650
|
+
if (snapshot.packageJsonCount > 3000) {
|
|
651
|
+
warn.push(`${snapshot.packageJsonCount} package.json entries (above 3k strains the resolver)`);
|
|
652
|
+
}
|
|
653
|
+
this._sizeWarning = warn.length > 0
|
|
654
|
+
? 'size warning: ' + warn.join('; ') + '. If vite crashes, fall back to Cirrus (NIMBUS_REAL_VITE=0 vite).'
|
|
655
|
+
: '';
|
|
656
|
+
// Generate all the module sources.
|
|
657
|
+
const mainCode = generateMainModuleCode({
|
|
658
|
+
port: this.port,
|
|
659
|
+
root: '/' + this.root.replace(/^\/+/, ''),
|
|
660
|
+
basePath: this.basePath,
|
|
661
|
+
hasUserViteConfig: this.userConfigBundle != null,
|
|
662
|
+
});
|
|
663
|
+
const fsShim = generateFsShimModuleCode();
|
|
664
|
+
const fsPromisesShim = generateFsPromisesShimModuleCode();
|
|
665
|
+
const wsShim = generateWsShimModuleCode();
|
|
666
|
+
const chokidarShim = generateChokidarShimModuleCode();
|
|
667
|
+
// Merge the extras (plugin-specific asset files the user-config
|
|
668
|
+
// bundler pre-harvested from node_modules) into the snapshot.
|
|
669
|
+
const mergedFiles = { ...snapshot.files, ...this.extraSyntheticFiles };
|
|
670
|
+
// Map CJS bundle specifiers (e.g. "react/jsx-runtime") to the
|
|
671
|
+
// path suffixes Vite produces when resolving a user-project
|
|
672
|
+
// bare import. Vite's resolver walks node_modules and returns
|
|
673
|
+
// e.g. `/<root>/node_modules/react/index.js` or
|
|
674
|
+
// `/<root>/node_modules/react/jsx-runtime.js`. We use the
|
|
675
|
+
// suffix match to intercept those.
|
|
676
|
+
const SPEC_TO_SUFFIXES = {
|
|
677
|
+
'react': ['/node_modules/react/index.js'],
|
|
678
|
+
'react/jsx-runtime': ['/node_modules/react/jsx-runtime.js'],
|
|
679
|
+
'react/jsx-dev-runtime': ['/node_modules/react/jsx-dev-runtime.js'],
|
|
680
|
+
'react-dom': ['/node_modules/react-dom/index.js'],
|
|
681
|
+
'react-dom/client': ['/node_modules/react-dom/client.js'],
|
|
682
|
+
'scheduler': ['/node_modules/scheduler/index.js'],
|
|
683
|
+
};
|
|
684
|
+
const cjsPrebuiltBundles = {};
|
|
685
|
+
for (const [spec, bundle] of Object.entries(CIRRUS_NPM_CJS_BUNDLES)) {
|
|
686
|
+
const suffixes = SPEC_TO_SUFFIXES[spec] || [];
|
|
687
|
+
for (const suffix of suffixes) {
|
|
688
|
+
cjsPrebuiltBundles[suffix] = bundle.code;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
// [sdk-phase-1] Pre-fetch the three large assets from the ASSETS
|
|
692
|
+
// binding before assembling the synthetic module code + loader
|
|
693
|
+
// config. After first call, all three are cached per-isolate, so
|
|
694
|
+
// subsequent start() invocations on the same supervisor pay zero.
|
|
695
|
+
const [realViteBundle, rollupWasmBase64, cirrusPluginReactBundle] = await Promise.all([
|
|
696
|
+
getRealViteBundle(this.env),
|
|
697
|
+
getRollupWasmBase64(this.env),
|
|
698
|
+
getCirrusPluginReactBundle(this.env),
|
|
699
|
+
]);
|
|
700
|
+
const syntheticCode = generateSyntheticModuleCode({
|
|
701
|
+
viteVersion: REAL_VITE_VERSION,
|
|
702
|
+
snapshotFiles: mergedFiles,
|
|
703
|
+
snapshotDirs: snapshot.dirs,
|
|
704
|
+
existingPaths: snapshot.existingPaths,
|
|
705
|
+
rollupWasmBase64,
|
|
706
|
+
cjsPrebuiltBundles,
|
|
707
|
+
viteClientMjs: VITE_CLIENT_MJS,
|
|
708
|
+
viteEnvMjs: VITE_ENV_MJS,
|
|
709
|
+
});
|
|
710
|
+
const ctxExports = getCtxExports();
|
|
711
|
+
const supervisorBinding = ctxExports?.SupervisorRPC
|
|
712
|
+
? ctxExports.SupervisorRPC({ props: { doId: ctx.id.toString(), pid } })
|
|
713
|
+
: undefined;
|
|
714
|
+
// Phase 2: separate HMR binding so we don't need to modify
|
|
715
|
+
// supervisor-rpc.ts (off-limits). The CirrusHmrRPC class lives in
|
|
716
|
+
// src/real-vite-hmr.ts and is re-exported from src/index.ts so
|
|
717
|
+
// ctx.exports can build a Service Binding for it.
|
|
718
|
+
const hmrBinding = ctxExports?.CirrusHmrRPC
|
|
719
|
+
? ctxExports.CirrusHmrRPC({ props: { doId: ctx.id.toString() } })
|
|
720
|
+
: undefined;
|
|
721
|
+
// Register this instance's HmrBridge in the module-level registry
|
|
722
|
+
// so the CirrusHmrRPC service can route facet RPCs back to us.
|
|
723
|
+
registerHmrBridge(ctx.id.toString(), this);
|
|
724
|
+
// [D'.1] Spawn cirrus-real as a DO Facet, not a Worker.
|
|
725
|
+
//
|
|
726
|
+
// Step A: LOADER.get(stableId, configCb) → DynamicWorker stub. The
|
|
727
|
+
// stable ID per-(supervisor-DO + cirrus-real-version) makes the
|
|
728
|
+
// loader cache the bundled vite + plugin code across hibernation.
|
|
729
|
+
// Two restarts within the same supervisor isolate hit the warm
|
|
730
|
+
// cache; a different DO ID gets a fresh slot.
|
|
731
|
+
//
|
|
732
|
+
// Step B: worker.getDurableObjectClass('CirrusRealVite') → the
|
|
733
|
+
// class constructor from the dynamic worker's exports. Same
|
|
734
|
+
// pattern facet-manager.ts uses for NodeProcess.
|
|
735
|
+
//
|
|
736
|
+
// Step C: ctx.facets.get('cirrus-real-vite', { class }) → DO Facet
|
|
737
|
+
// stub. The facet has its own SQLite (used by the cookie row),
|
|
738
|
+
// its own hibernation lifecycle, and is owned by THIS supervisor
|
|
739
|
+
// DO so eviction is coherent. The same name returns the same
|
|
740
|
+
// facet on subsequent calls — that's what makes the cookie
|
|
741
|
+
// persist across supervisor reconnects.
|
|
742
|
+
const stableLoaderId = `${ctx.id.toString()}:cirrus-real-vite:${REAL_VITE_VERSION}`;
|
|
743
|
+
const facetName = 'cirrus-real-vite';
|
|
744
|
+
try {
|
|
745
|
+
const worker = this.env.LOADER.get(stableLoaderId, async () => ({
|
|
746
|
+
compatibilityDate: CF_COMPAT_DATE,
|
|
747
|
+
compatibilityFlags: REAL_VITE_COMPAT_FLAGS,
|
|
748
|
+
mainModule: 'main.js',
|
|
749
|
+
modules: {
|
|
750
|
+
'main.js': mainCode,
|
|
751
|
+
'vite.bundle.js': realViteBundle,
|
|
752
|
+
'synthetic.js': syntheticCode,
|
|
753
|
+
// Phase 1 shims.
|
|
754
|
+
'cirrus-fs.js': fsShim,
|
|
755
|
+
'cirrus-fs-promises.js': fsPromisesShim,
|
|
756
|
+
'real-node-fs.js': `import * as _f from 'node:fs'; export * from 'node:fs'; export default _f.default || _f;`,
|
|
757
|
+
'real-node-fs-promises.js': `import * as _f from 'node:fs/promises'; export * from 'node:fs/promises'; export default _f.default || _f;`,
|
|
758
|
+
// Phase 2 shims.
|
|
759
|
+
'cirrus-ws.js': wsShim,
|
|
760
|
+
'cirrus-chokidar.js': chokidarShim,
|
|
761
|
+
// Phase 3: the user's pre-bundled vite.config.js (if any).
|
|
762
|
+
...(this.userConfigBundle
|
|
763
|
+
? {
|
|
764
|
+
'user-vite-config.js': this.userConfigBundle,
|
|
765
|
+
'vite-config-helper.js': `
|
|
766
|
+
export * from './vite.bundle.js';
|
|
767
|
+
import * as _v from './vite.bundle.js';
|
|
768
|
+
export default _v.default || _v;
|
|
769
|
+
`,
|
|
770
|
+
'cirrus-plugin-react.js': cirrusPluginReactBundle,
|
|
771
|
+
}
|
|
772
|
+
: {}),
|
|
773
|
+
},
|
|
774
|
+
env: {
|
|
775
|
+
...(supervisorBinding ? { SUPERVISOR: supervisorBinding } : {}),
|
|
776
|
+
...(hmrBinding ? { CIRRUS_HMR: hmrBinding } : {}),
|
|
777
|
+
},
|
|
778
|
+
}));
|
|
779
|
+
// [d1-fix] Two-path bind:
|
|
780
|
+
//
|
|
781
|
+
// PRIMARY (DO Facet) — requires `experimental` compat flag:
|
|
782
|
+
// worker.getDurableObjectClass('CirrusRealVite') →
|
|
783
|
+
// ctx.facets.get(name, {class}) → stub with own-SQLite.
|
|
784
|
+
// Provides the cookie-persistence + identity story.
|
|
785
|
+
//
|
|
786
|
+
// FALLBACK (Fetcher) — used when getDurableObjectClass is
|
|
787
|
+
// unavailable (no `experimental` flag — the prod situation
|
|
788
|
+
// since the 2026-05-08 deploy validator change rejecting
|
|
789
|
+
// $experimental flags for non-CF-team accounts):
|
|
790
|
+
// worker.getEntrypoint('CirrusRealStateless') → stateless
|
|
791
|
+
// WorkerEntrypoint stub. Vite still serves /preview/ via
|
|
792
|
+
// the same module-scope state; cookie persistence is N/A
|
|
793
|
+
// (no per-instance SQLite). Probe surfaces this via
|
|
794
|
+
// `kind: 'fetcher-fallback'`.
|
|
795
|
+
//
|
|
796
|
+
// The detection is by *runtime feature probe* — we try
|
|
797
|
+
// getDurableObjectClass first and catch the classic
|
|
798
|
+
// 'is not a function' / facets-related error, mirroring the
|
|
799
|
+
// pattern at facets/manager.ts:1286-1322. NOT by static
|
|
800
|
+
// env-var check (the flag is invisible from JS at runtime).
|
|
801
|
+
let CirrusRealViteClass = null;
|
|
802
|
+
try {
|
|
803
|
+
CirrusRealViteClass = worker.getDurableObjectClass?.('CirrusRealVite');
|
|
804
|
+
}
|
|
805
|
+
catch (cls) {
|
|
806
|
+
// Caller-side throw means the method exists but the class
|
|
807
|
+
// lookup failed — surface as a real bootError so we don't
|
|
808
|
+
// silently fall through.
|
|
809
|
+
this.bootError = 'getDurableObjectClass(CirrusRealVite) threw: ' +
|
|
810
|
+
(cls?.message || String(cls));
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
if (CirrusRealViteClass && typeof ctx.facets?.get === 'function') {
|
|
814
|
+
// PRIMARY: DO Facet path.
|
|
815
|
+
this._facetName = facetName;
|
|
816
|
+
this.facetStub = ctx.facets.get(facetName, async () => ({
|
|
817
|
+
class: CirrusRealViteClass,
|
|
818
|
+
}));
|
|
819
|
+
this._kind = 'do-facet';
|
|
820
|
+
}
|
|
821
|
+
else {
|
|
822
|
+
// FALLBACK: Fetcher path. The default-exported
|
|
823
|
+
// CirrusRealStateless WorkerEntrypoint exposes both
|
|
824
|
+
// `fetch(req)` and `getFacetMeta()` so the supervisor's
|
|
825
|
+
// handleRequest + getDiag logic Just Works without
|
|
826
|
+
// branching on `kind`.
|
|
827
|
+
//
|
|
828
|
+
// No `experimental` compat flag → no DO-Facet API at runtime.
|
|
829
|
+
// This is the prod path (CF rejects the flag) and the
|
|
830
|
+
// local-dev path post-2026-05-08 deploy-flag-fix wave.
|
|
831
|
+
this._facetName = null; // facets.delete() is N/A here
|
|
832
|
+
// Default export → getEntrypoint() with no name argument.
|
|
833
|
+
// Per workerd's WorkerStub semantics: getEntrypoint() →
|
|
834
|
+
// the default export; getEntrypoint(name) → a named export.
|
|
835
|
+
// The fallback main.js export is `export default class
|
|
836
|
+
// CirrusRealStateless extends WorkerEntrypoint { ... }` —
|
|
837
|
+
// resolved as the DEFAULT, not as a named entrypoint.
|
|
838
|
+
this.facetStub = worker.getEntrypoint?.();
|
|
839
|
+
if (!this.facetStub) {
|
|
840
|
+
this.bootError =
|
|
841
|
+
'cirrus-real fallback: worker.getEntrypoint() returned no stub. ' +
|
|
842
|
+
'Worker Loader binding may be missing or incompatible.';
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
this._kind = 'fetcher-fallback';
|
|
846
|
+
}
|
|
847
|
+
this._bootCompletedAt = Date.now();
|
|
848
|
+
}
|
|
849
|
+
catch (e) {
|
|
850
|
+
this.bootError = e?.stack || e?.message || String(e);
|
|
851
|
+
}
|
|
852
|
+
// Wire the VFS event stream into the HMR bridge so the facet's
|
|
853
|
+
// chokidar shim actually sees file changes.
|
|
854
|
+
if (this.vfsEvents) {
|
|
855
|
+
this._vfsUnsub = this.vfsEvents.on((batch) => {
|
|
856
|
+
for (const ev of batch) {
|
|
857
|
+
const absPath = '/' + ev.path.replace(/^\/+/, '');
|
|
858
|
+
// chokidar uses 'addDir'/'unlinkDir' for directory events;
|
|
859
|
+
// VFS emits the same strings, so we can pass through as-is.
|
|
860
|
+
this.hmr.pushVfsEvent(ev.type, absPath, ev.oldPath);
|
|
861
|
+
}
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
stop(ctx) {
|
|
866
|
+
// [D'.1] Tear down the DO Facet via ctx.facets.delete so its own
|
|
867
|
+
// SQLite storage is reclaimed. Pre-D'.1 the worker stub was
|
|
868
|
+
// garbage-collected when facetStub was nulled — facets need an
|
|
869
|
+
// explicit delete (otherwise the cookie row + storage slot leak
|
|
870
|
+
// until the supervisor itself is evicted).
|
|
871
|
+
if (this._facetName && ctx) {
|
|
872
|
+
try {
|
|
873
|
+
ctx.facets.delete(this._facetName);
|
|
874
|
+
}
|
|
875
|
+
catch { }
|
|
876
|
+
}
|
|
877
|
+
this.facetStub = null;
|
|
878
|
+
this._facetName = null;
|
|
879
|
+
this._kind = null;
|
|
880
|
+
this.hmr.closeAll();
|
|
881
|
+
if (this._vfsUnsub) {
|
|
882
|
+
try {
|
|
883
|
+
this._vfsUnsub();
|
|
884
|
+
}
|
|
885
|
+
catch { }
|
|
886
|
+
}
|
|
887
|
+
this._vfsUnsub = null;
|
|
888
|
+
// Note: we deliberately do NOT unregister from the HMR bridge
|
|
889
|
+
// map here — if the user runs `vite stop` then `vite` again, the
|
|
890
|
+
// bridge must still be lookup-able by doId during the brief
|
|
891
|
+
// restart window. Unregister happens on DO teardown, not here.
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* Browser WS upgrade request arrived at /preview/__nimbus_hmr.
|
|
895
|
+
* The DO has already accepted the server-side socket via
|
|
896
|
+
* ctx.acceptWebSocket; we register it with the HmrBridge.
|
|
897
|
+
*/
|
|
898
|
+
attachHmrClient(ws) {
|
|
899
|
+
return this.hmr.attachClient(ws);
|
|
900
|
+
}
|
|
901
|
+
detachHmrClient(id) {
|
|
902
|
+
this.hmr.detachClient(id);
|
|
903
|
+
}
|
|
904
|
+
deliverHmrClientMessage(id, msg) {
|
|
905
|
+
this.hmr.deliverClientMessage(id, msg);
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Route a (non-WS) request into the facet. `pathname` is the path
|
|
909
|
+
* after stripping the session's `/preview` prefix (e.g. `/`,
|
|
910
|
+
* `/@vite/client`, `/src/main.tsx`).
|
|
911
|
+
*/
|
|
912
|
+
async handleRequest(request, pathname) {
|
|
913
|
+
if (this.bootError) {
|
|
914
|
+
return new Response('[cirrus-real] facet spawn failed:\n' + this.bootError, { status: 500, headers: { 'Content-Type': 'text/plain; charset=utf-8' } });
|
|
915
|
+
}
|
|
916
|
+
if (!this.facetStub) {
|
|
917
|
+
return new Response('[cirrus-real] facet not started', {
|
|
918
|
+
status: 503, headers: { 'Content-Type': 'text/plain; charset=utf-8' },
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
// Vite is configured with `base: this.basePath` — forward the
|
|
922
|
+
// base-prefixed path so its middleware matches.
|
|
923
|
+
const origUrl = new URL(request.url);
|
|
924
|
+
const joined = this.basePath.replace(/\/+$/, '') + (pathname.startsWith('/') ? '' : '/') + pathname;
|
|
925
|
+
const forwardUrl = 'http://cirrus-real' + joined + (origUrl.search || '');
|
|
926
|
+
const forwardInit = {
|
|
927
|
+
method: request.method,
|
|
928
|
+
headers: request.headers,
|
|
929
|
+
body: (request.method === 'GET' || request.method === 'HEAD')
|
|
930
|
+
? undefined : await request.arrayBuffer(),
|
|
931
|
+
};
|
|
932
|
+
const forwardReq = new Request(forwardUrl, forwardInit);
|
|
933
|
+
const fetchT0 = Date.now();
|
|
934
|
+
try {
|
|
935
|
+
const resp = await this.facetStub.fetch(forwardReq);
|
|
936
|
+
this._lastFetchMs = Date.now() - fetchT0;
|
|
937
|
+
const out = new Response(resp.body, {
|
|
938
|
+
status: resp.status,
|
|
939
|
+
statusText: resp.statusText,
|
|
940
|
+
headers: resp.headers,
|
|
941
|
+
});
|
|
942
|
+
out.headers.set('Access-Control-Allow-Origin', '*');
|
|
943
|
+
out.headers.set('Cache-Control', 'no-store');
|
|
944
|
+
return out;
|
|
945
|
+
}
|
|
946
|
+
catch (e) {
|
|
947
|
+
return new Response('[cirrus-real] facet.fetch threw: ' + (e?.stack || e?.message || String(e)), { status: 502, headers: { 'Content-Type': 'text/plain; charset=utf-8' } });
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* [D'.1] Diag bundle for /api/_diag/cirrus. Includes the facet's
|
|
952
|
+
* own-SQLite identity cookie (round-tripped via the facet's
|
|
953
|
+
* getFacetMeta RPC), supervisor-side dispatch kind, supervisor-side
|
|
954
|
+
* bootMs, and last-fetch latency. Returns null when cirrus-real
|
|
955
|
+
* is not running.
|
|
956
|
+
*/
|
|
957
|
+
async getDiag() {
|
|
958
|
+
if (!this.facetStub)
|
|
959
|
+
return null;
|
|
960
|
+
let facetMeta = null;
|
|
961
|
+
try {
|
|
962
|
+
facetMeta = await this.facetStub.getFacetMeta();
|
|
963
|
+
}
|
|
964
|
+
catch (e) {
|
|
965
|
+
facetMeta = { rpcError: e?.message || String(e) };
|
|
966
|
+
}
|
|
967
|
+
return {
|
|
968
|
+
kind: this._kind,
|
|
969
|
+
facetName: this._facetName,
|
|
970
|
+
cookie: facetMeta?.cookie ?? null,
|
|
971
|
+
bootMs: this._startedAt > 0 ? this._bootCompletedAt - this._startedAt : 0,
|
|
972
|
+
facetBootMs: facetMeta?.bootMs ?? 0,
|
|
973
|
+
lastFetchMs: this._lastFetchMs,
|
|
974
|
+
bootError: this.bootError,
|
|
975
|
+
facetBootError: facetMeta?.bootError ?? null,
|
|
976
|
+
viteServerListening: facetMeta?.viteServerListening ?? null,
|
|
977
|
+
uptimeMs: this._startedAt ? Date.now() - this._startedAt : 0,
|
|
978
|
+
hmrClients: this.hmr.size,
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
}
|