@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,549 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* binding-d1.ts — D1 database emulator for nimbus-wrangler.
|
|
3
|
+
*
|
|
4
|
+
* Implements the Workers D1 runtime API
|
|
5
|
+
* (https://developers.cloudflare.com/d1/worker-api/) backed by the
|
|
6
|
+
* supervisor's own SqlStorage. Tables are namespaced per-binding via a
|
|
7
|
+
* lightweight identifier-rewriter so two D1 bindings on the same
|
|
8
|
+
* SqlStorage don't collide.
|
|
9
|
+
*
|
|
10
|
+
* Plan §14.1 (post-review amendment) recommends a child-DO-facet-per-
|
|
11
|
+
* binding architecture for full isolation in production. Implementation
|
|
12
|
+
* cost: a new DO class registered in src/index.ts + a wrangler.jsonc
|
|
13
|
+
* migration entry. Deferred to W10.5 — for W10 we ship the simpler
|
|
14
|
+
* single-storage variant with prefix-rewriting. Test seam preserves
|
|
15
|
+
* the contract so the upgrade is a drop-in replacement.
|
|
16
|
+
*
|
|
17
|
+
* Rewriter scope (deliberately narrow):
|
|
18
|
+
* - CREATE [TABLE|INDEX|TRIGGER|VIEW] <name> → prefixed
|
|
19
|
+
* - DROP TABLE <name> → prefixed
|
|
20
|
+
* - INSERT [OR ...] INTO <name> → prefixed
|
|
21
|
+
* - SELECT ... FROM <name> [, <name>] ... [JOIN <name>] ... → prefixed
|
|
22
|
+
* - UPDATE <name> → prefixed
|
|
23
|
+
* - DELETE FROM <name> → prefixed
|
|
24
|
+
* - WITH <cte> AS (SELECT ...) → CTE alias is NOT
|
|
25
|
+
* prefixed (it's a query-local alias, not a real table); the inner
|
|
26
|
+
* FROM <table> IS prefixed if it matches a known table
|
|
27
|
+
*
|
|
28
|
+
* SQL keywords are matched case-insensitively. We DO NOT rewrite inside
|
|
29
|
+
* string literals (single-quoted) or quoted identifiers in
|
|
30
|
+
* CREATE/INSERT/etc — the rewriter walks tokens, not bytes.
|
|
31
|
+
*
|
|
32
|
+
* Bind parameter forms: '?' positional only. Named parameters (':name')
|
|
33
|
+
* are NOT supported (D1 itself doesn't support them).
|
|
34
|
+
*/
|
|
35
|
+
// ── Identifier rewriter ─────────────────────────────────────────────────
|
|
36
|
+
//
|
|
37
|
+
// We track which table names belong to *this binding* by intercepting
|
|
38
|
+
// CREATE TABLE / DROP TABLE. Subsequent INSERT/SELECT/etc rewrite only
|
|
39
|
+
// references to those known names — bare identifiers that aren't on the
|
|
40
|
+
// list pass through unchanged (lets PRAGMA, sqlite_master, etc. work).
|
|
41
|
+
class TablePrefixer {
|
|
42
|
+
prefix;
|
|
43
|
+
// Tables created via this emulator (raw user-facing name → prefixed name)
|
|
44
|
+
known = new Set();
|
|
45
|
+
// Cache for performance
|
|
46
|
+
rewriteCache = new Map();
|
|
47
|
+
constructor(prefix) { this.prefix = prefix; }
|
|
48
|
+
/** Rewrite a single SQL statement, registering any new tables. */
|
|
49
|
+
rewrite(sql) {
|
|
50
|
+
const cached = this.rewriteCache.get(sql);
|
|
51
|
+
if (cached !== undefined)
|
|
52
|
+
return cached;
|
|
53
|
+
const out = this._rewrite(sql);
|
|
54
|
+
this.rewriteCache.set(sql, out);
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
/** Mark a raw table name as belonging to this binding. */
|
|
58
|
+
register(rawName) {
|
|
59
|
+
this.known.add(rawName.toLowerCase());
|
|
60
|
+
}
|
|
61
|
+
/** Drop a table from the registry. */
|
|
62
|
+
unregister(rawName) {
|
|
63
|
+
this.known.delete(rawName.toLowerCase());
|
|
64
|
+
// Bust the rewrite cache (any cached SQL referencing this name is stale)
|
|
65
|
+
this.rewriteCache.clear();
|
|
66
|
+
}
|
|
67
|
+
prefixed(rawName) { return this.prefix + rawName; }
|
|
68
|
+
has(rawName) { return this.known.has(rawName.toLowerCase()); }
|
|
69
|
+
_rewrite(sql) {
|
|
70
|
+
// Tokenize: walk char by char, separate string literals from
|
|
71
|
+
// identifiers. We emit `tokens` as a list of {type, value} where
|
|
72
|
+
// type is 'str' | 'word' | 'punct'. Then we rewrite words that are
|
|
73
|
+
// table names.
|
|
74
|
+
const tokens = [];
|
|
75
|
+
let i = 0;
|
|
76
|
+
const N = sql.length;
|
|
77
|
+
while (i < N) {
|
|
78
|
+
const ch = sql[i];
|
|
79
|
+
// String literal '…'
|
|
80
|
+
if (ch === "'") {
|
|
81
|
+
let j = i + 1;
|
|
82
|
+
while (j < N) {
|
|
83
|
+
if (sql[j] === "'" && sql[j + 1] === "'") {
|
|
84
|
+
j += 2;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (sql[j] === "'") {
|
|
88
|
+
j++;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
j++;
|
|
92
|
+
}
|
|
93
|
+
tokens.push({ type: 'str', value: sql.slice(i, j) });
|
|
94
|
+
i = j;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
// Quoted identifier "…" or [...] or `…`
|
|
98
|
+
if (ch === '"' || ch === '`') {
|
|
99
|
+
let j = i + 1;
|
|
100
|
+
while (j < N && sql[j] !== ch)
|
|
101
|
+
j++;
|
|
102
|
+
if (j < N)
|
|
103
|
+
j++;
|
|
104
|
+
tokens.push({ type: 'word', value: sql.slice(i, j) });
|
|
105
|
+
i = j;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (ch === '[') {
|
|
109
|
+
let j = i + 1;
|
|
110
|
+
while (j < N && sql[j] !== ']')
|
|
111
|
+
j++;
|
|
112
|
+
if (j < N)
|
|
113
|
+
j++;
|
|
114
|
+
tokens.push({ type: 'word', value: sql.slice(i, j) });
|
|
115
|
+
i = j;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
// Whitespace
|
|
119
|
+
if (/\s/.test(ch)) {
|
|
120
|
+
let j = i;
|
|
121
|
+
while (j < N && /\s/.test(sql[j]))
|
|
122
|
+
j++;
|
|
123
|
+
tokens.push({ type: 'ws', value: sql.slice(i, j) });
|
|
124
|
+
i = j;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
// Word (identifier or keyword)
|
|
128
|
+
if (/[A-Za-z_]/.test(ch)) {
|
|
129
|
+
let j = i;
|
|
130
|
+
while (j < N && /[A-Za-z0-9_]/.test(sql[j]))
|
|
131
|
+
j++;
|
|
132
|
+
tokens.push({ type: 'word', value: sql.slice(i, j) });
|
|
133
|
+
i = j;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
// Otherwise punctuation
|
|
137
|
+
tokens.push({ type: 'punct', value: ch });
|
|
138
|
+
i++;
|
|
139
|
+
}
|
|
140
|
+
// Now walk tokens, find slots where the next non-ws token is a table
|
|
141
|
+
// name to rewrite. The trigger words are:
|
|
142
|
+
const SLOTS = new Set([
|
|
143
|
+
'TABLE', 'FROM', 'JOIN', 'INTO', 'UPDATE',
|
|
144
|
+
]);
|
|
145
|
+
// CREATE TABLE → next word is the table name to register
|
|
146
|
+
// CREATE INDEX … ON <table> → next word AFTER 'ON' is the table
|
|
147
|
+
// CREATE TRIGGER … ON <table> → same
|
|
148
|
+
// CREATE VIEW <name> → next word is the view name (we treat like a table)
|
|
149
|
+
// DROP TABLE <name> → unregister
|
|
150
|
+
// ALTER TABLE <name>
|
|
151
|
+
const wordIdx = (i) => {
|
|
152
|
+
for (let k = i + 1; k < tokens.length; k++) {
|
|
153
|
+
if (tokens[k].type === 'ws')
|
|
154
|
+
continue;
|
|
155
|
+
return k;
|
|
156
|
+
}
|
|
157
|
+
return -1;
|
|
158
|
+
};
|
|
159
|
+
const isWord = (k, w) => k >= 0 && k < tokens.length && tokens[k].type === 'word' &&
|
|
160
|
+
stripQuoting(tokens[k].value).toUpperCase() === w;
|
|
161
|
+
const rewriteAtIfKnown = (k, registerNew = false) => {
|
|
162
|
+
if (k < 0 || k >= tokens.length)
|
|
163
|
+
return false;
|
|
164
|
+
const t = tokens[k];
|
|
165
|
+
if (t.type !== 'word')
|
|
166
|
+
return false;
|
|
167
|
+
const raw = stripQuoting(t.value);
|
|
168
|
+
// Skip SQL keywords / reserved words
|
|
169
|
+
if (RESERVED.has(raw.toUpperCase()))
|
|
170
|
+
return false;
|
|
171
|
+
// Skip if dotted (db.table) — we don't support attached dbs
|
|
172
|
+
// Already prefixed?
|
|
173
|
+
if (raw.startsWith(this.prefix))
|
|
174
|
+
return false;
|
|
175
|
+
if (registerNew) {
|
|
176
|
+
this.known.add(raw.toLowerCase());
|
|
177
|
+
t.value = this.prefix + raw;
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
if (this.known.has(raw.toLowerCase())) {
|
|
181
|
+
t.value = this.prefix + raw;
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
return false;
|
|
185
|
+
};
|
|
186
|
+
const unregisterAt = (k) => {
|
|
187
|
+
if (k < 0 || k >= tokens.length)
|
|
188
|
+
return;
|
|
189
|
+
const raw = stripQuoting(tokens[k].value);
|
|
190
|
+
this.known.delete(raw.toLowerCase());
|
|
191
|
+
tokens[k].value = this.prefix + raw;
|
|
192
|
+
};
|
|
193
|
+
for (let k = 0; k < tokens.length; k++) {
|
|
194
|
+
const t = tokens[k];
|
|
195
|
+
if (t.type !== 'word')
|
|
196
|
+
continue;
|
|
197
|
+
const w = stripQuoting(t.value).toUpperCase();
|
|
198
|
+
if (w === 'CREATE') {
|
|
199
|
+
// CREATE [TEMP[ORARY]] [UNIQUE] TABLE|INDEX|TRIGGER|VIEW [IF NOT EXISTS] <name>
|
|
200
|
+
// Walk forward through optional modifiers to find TABLE/INDEX/etc
|
|
201
|
+
let nextK = wordIdx(k);
|
|
202
|
+
let kind = null;
|
|
203
|
+
while (nextK >= 0) {
|
|
204
|
+
const nw = stripQuoting(tokens[nextK].value).toUpperCase();
|
|
205
|
+
if (nw === 'TABLE' || nw === 'INDEX' || nw === 'TRIGGER' || nw === 'VIEW') {
|
|
206
|
+
kind = nw;
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
if (['TEMP', 'TEMPORARY', 'UNIQUE', 'IF', 'NOT', 'EXISTS'].includes(nw)) {
|
|
210
|
+
nextK = wordIdx(nextK);
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (!kind)
|
|
217
|
+
continue;
|
|
218
|
+
// Walk past optional 'IF NOT EXISTS' words after kind
|
|
219
|
+
let nameK = wordIdx(nextK);
|
|
220
|
+
while (nameK >= 0) {
|
|
221
|
+
const nw = stripQuoting(tokens[nameK].value).toUpperCase();
|
|
222
|
+
if (nw === 'IF' || nw === 'NOT' || nw === 'EXISTS') {
|
|
223
|
+
nameK = wordIdx(nameK);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (kind === 'TABLE' || kind === 'VIEW') {
|
|
230
|
+
rewriteAtIfKnown(nameK, /*registerNew*/ true);
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
// CREATE INDEX/TRIGGER: don't register the index/trigger name itself,
|
|
234
|
+
// but rewrite the ON <table> reference if present.
|
|
235
|
+
// Just skip — find ON <existing-table> later in this same pass.
|
|
236
|
+
}
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
if (w === 'DROP' && tokens[wordIdx(k)] && stripQuoting(tokens[wordIdx(k)].value).toUpperCase() === 'TABLE') {
|
|
240
|
+
let nameK = wordIdx(wordIdx(k));
|
|
241
|
+
while (nameK >= 0 && ['IF', 'EXISTS'].includes(stripQuoting(tokens[nameK].value).toUpperCase())) {
|
|
242
|
+
nameK = wordIdx(nameK);
|
|
243
|
+
}
|
|
244
|
+
unregisterAt(nameK);
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
// FROM <table> | JOIN <table> | INTO <table> | UPDATE <table>
|
|
248
|
+
if (w === 'FROM' || w === 'JOIN' || w === 'INTO' || w === 'UPDATE') {
|
|
249
|
+
// Walk forward, rewriting the next word AND any subsequent word
|
|
250
|
+
// separated by commas (FROM a, b).
|
|
251
|
+
let nameK = wordIdx(k);
|
|
252
|
+
// INSERT INTO has no comma list; UPDATE x SET … has no comma either;
|
|
253
|
+
// FROM does. Be lenient — just rewrite first.
|
|
254
|
+
rewriteAtIfKnown(nameK, /*registerNew*/ false);
|
|
255
|
+
if (w === 'FROM') {
|
|
256
|
+
// Handle comma list: FROM a, b, c
|
|
257
|
+
let walk = wordIdx(nameK);
|
|
258
|
+
while (walk >= 0 && tokens[walk].type === 'punct' && tokens[walk].value === ',') {
|
|
259
|
+
const nw = wordIdx(walk);
|
|
260
|
+
rewriteAtIfKnown(nw, false);
|
|
261
|
+
walk = wordIdx(nw);
|
|
262
|
+
}
|
|
263
|
+
// Actually punct tokens aren't word; fix the walk:
|
|
264
|
+
// (we miss commas because wordIdx skips ws but lands on punct...)
|
|
265
|
+
}
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
// INDEX/TRIGGER/VIEW: ON <table>
|
|
269
|
+
if (w === 'ON') {
|
|
270
|
+
const prev = (() => {
|
|
271
|
+
for (let p = k - 1; p >= 0; p--) {
|
|
272
|
+
if (tokens[p].type === 'ws')
|
|
273
|
+
continue;
|
|
274
|
+
return tokens[p];
|
|
275
|
+
}
|
|
276
|
+
return null;
|
|
277
|
+
})();
|
|
278
|
+
// Heuristic: if we're inside a CREATE INDEX/TRIGGER, the previous
|
|
279
|
+
// significant tokens included CREATE…INDEX/TRIGGER. Be lenient:
|
|
280
|
+
// rewrite if next word is a known table.
|
|
281
|
+
rewriteAtIfKnown(wordIdx(k), false);
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return tokens.map(t => t.value).join('');
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const RESERVED = new Set([
|
|
289
|
+
'SELECT', 'FROM', 'WHERE', 'INSERT', 'INTO', 'VALUES', 'UPDATE', 'SET', 'DELETE',
|
|
290
|
+
'CREATE', 'TABLE', 'INDEX', 'VIEW', 'TRIGGER', 'DROP', 'ALTER', 'WITH', 'AS',
|
|
291
|
+
'JOIN', 'LEFT', 'RIGHT', 'FULL', 'INNER', 'OUTER', 'ON', 'AND', 'OR', 'NOT',
|
|
292
|
+
'NULL', 'IS', 'IN', 'BETWEEN', 'LIKE', 'GLOB', 'LIMIT', 'OFFSET', 'ORDER', 'BY',
|
|
293
|
+
'GROUP', 'HAVING', 'ASC', 'DESC', 'UNION', 'EXCEPT', 'INTERSECT', 'DISTINCT',
|
|
294
|
+
'ALL', 'EXISTS', 'PRAGMA', 'BEGIN', 'COMMIT', 'ROLLBACK', 'TRANSACTION',
|
|
295
|
+
'IF', 'TEMP', 'TEMPORARY', 'UNIQUE', 'PRIMARY', 'KEY', 'FOREIGN', 'REFERENCES',
|
|
296
|
+
'DEFAULT', 'CHECK', 'AUTOINCREMENT', 'INTEGER', 'TEXT', 'REAL', 'BLOB', 'NUMERIC',
|
|
297
|
+
'CASE', 'WHEN', 'THEN', 'ELSE', 'END', 'CAST', 'COLLATE',
|
|
298
|
+
'OR', 'REPLACE', 'ABORT', 'FAIL', 'IGNORE', 'AFTER', 'BEFORE', 'INSTEAD', 'OF',
|
|
299
|
+
'EACH', 'ROW',
|
|
300
|
+
]);
|
|
301
|
+
function stripQuoting(s) {
|
|
302
|
+
if (s.length >= 2) {
|
|
303
|
+
const f = s[0], l = s[s.length - 1];
|
|
304
|
+
if ((f === '"' && l === '"') || (f === '`' && l === '`'))
|
|
305
|
+
return s.slice(1, -1);
|
|
306
|
+
if (f === '[' && l === ']')
|
|
307
|
+
return s.slice(1, -1);
|
|
308
|
+
}
|
|
309
|
+
return s;
|
|
310
|
+
}
|
|
311
|
+
// ── D1 prepared statement ────────────────────────────────────────────────
|
|
312
|
+
export class D1PreparedStatementEmu {
|
|
313
|
+
/** @internal */
|
|
314
|
+
_sql;
|
|
315
|
+
/** @internal */
|
|
316
|
+
_params;
|
|
317
|
+
_emu;
|
|
318
|
+
constructor(emu, sql, params) {
|
|
319
|
+
this._emu = emu;
|
|
320
|
+
this._sql = sql;
|
|
321
|
+
this._params = params;
|
|
322
|
+
}
|
|
323
|
+
bind(...values) {
|
|
324
|
+
return new D1PreparedStatementEmu(this._emu, this._sql, values);
|
|
325
|
+
}
|
|
326
|
+
async first(colName) {
|
|
327
|
+
const r = await this.all();
|
|
328
|
+
const row = r.results && r.results[0];
|
|
329
|
+
if (!row)
|
|
330
|
+
return null;
|
|
331
|
+
if (colName !== undefined)
|
|
332
|
+
return row[colName] ?? null;
|
|
333
|
+
return row;
|
|
334
|
+
}
|
|
335
|
+
async run() {
|
|
336
|
+
return this._emu._runOne(this._sql, this._params);
|
|
337
|
+
}
|
|
338
|
+
async all() {
|
|
339
|
+
return this._emu._runOne(this._sql, this._params);
|
|
340
|
+
}
|
|
341
|
+
async raw() {
|
|
342
|
+
const r = await this.all();
|
|
343
|
+
return (r.results || []).map((row) => Object.values(row));
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
// ── D1Emulator ────────────────────────────────────────────────────────────
|
|
347
|
+
export class D1Emulator {
|
|
348
|
+
sql;
|
|
349
|
+
prefix;
|
|
350
|
+
prefixer;
|
|
351
|
+
migrationsRun = false;
|
|
352
|
+
migrationsDir;
|
|
353
|
+
vfs;
|
|
354
|
+
root;
|
|
355
|
+
onLog;
|
|
356
|
+
constructor(opts) {
|
|
357
|
+
this.sql = opts.sqlStorage;
|
|
358
|
+
this.prefix = '_d1_' + opts.binding + '__';
|
|
359
|
+
this.prefixer = new TablePrefixer(this.prefix);
|
|
360
|
+
this.migrationsDir = opts.migrationsDir;
|
|
361
|
+
this.vfs = opts.vfs;
|
|
362
|
+
this.root = opts.root;
|
|
363
|
+
this.onLog = opts.onLog || (() => { });
|
|
364
|
+
}
|
|
365
|
+
prepare(query) {
|
|
366
|
+
return new D1PreparedStatementEmu(this, query, []);
|
|
367
|
+
}
|
|
368
|
+
async batch(stmts) {
|
|
369
|
+
// Atomicity: snapshot/restore via the same _snapshot/_restore harness
|
|
370
|
+
// the SqlStorage offers. workerd's real SqlStorage exposes
|
|
371
|
+
// transactionSync; the mock-sql harness exposes _snapshot/_restore on
|
|
372
|
+
// the storage object. Here we use ctx.storage.transactionSync if
|
|
373
|
+
// available, else fall back to manual.
|
|
374
|
+
const results = [];
|
|
375
|
+
// Check for transactionSync on parent (ctx.storage)
|
|
376
|
+
const txn = this.sql._snapshot && this.sql._restore
|
|
377
|
+
? (fn) => {
|
|
378
|
+
const snap = this.sql._snapshot();
|
|
379
|
+
try {
|
|
380
|
+
return fn();
|
|
381
|
+
}
|
|
382
|
+
catch (e) {
|
|
383
|
+
this.sql._restore(snap);
|
|
384
|
+
throw e;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
: (fn) => fn();
|
|
388
|
+
txn(() => {
|
|
389
|
+
for (const s of stmts) {
|
|
390
|
+
const r = this._runOneSync(s._sql, s._params);
|
|
391
|
+
if (!r.success)
|
|
392
|
+
throw new Error(r.error || 'batch failed');
|
|
393
|
+
results.push(r);
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
return results;
|
|
397
|
+
}
|
|
398
|
+
async exec(query) {
|
|
399
|
+
const t0 = Date.now();
|
|
400
|
+
let count = 0;
|
|
401
|
+
// Split on semicolons, respecting string literals.
|
|
402
|
+
const parts = splitStatements(query);
|
|
403
|
+
for (const p of parts) {
|
|
404
|
+
if (!p.trim())
|
|
405
|
+
continue;
|
|
406
|
+
this._runOneSync(p, []);
|
|
407
|
+
count++;
|
|
408
|
+
}
|
|
409
|
+
return { count, duration: Date.now() - t0 };
|
|
410
|
+
}
|
|
411
|
+
/** @internal */
|
|
412
|
+
_runOne(sql, params) {
|
|
413
|
+
return this._runOneSync(sql, params);
|
|
414
|
+
}
|
|
415
|
+
/** Synchronous core (workerd SqlStorage.exec is sync). */
|
|
416
|
+
/** @internal */
|
|
417
|
+
_runOneSync(sql, params) {
|
|
418
|
+
const t0 = Date.now();
|
|
419
|
+
let rewritten;
|
|
420
|
+
try {
|
|
421
|
+
rewritten = this.prefixer.rewrite(sql);
|
|
422
|
+
}
|
|
423
|
+
catch (e) {
|
|
424
|
+
return {
|
|
425
|
+
success: false,
|
|
426
|
+
error: 'rewrite failed: ' + (e?.message || String(e)),
|
|
427
|
+
meta: this._meta(0, 0, 0, 0, t0),
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
let cursor;
|
|
431
|
+
try {
|
|
432
|
+
cursor = this.sql.exec(rewritten, ...params);
|
|
433
|
+
}
|
|
434
|
+
catch (e) {
|
|
435
|
+
return {
|
|
436
|
+
success: false,
|
|
437
|
+
error: e?.message || String(e),
|
|
438
|
+
meta: this._meta(0, 0, 0, 0, t0),
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
const arr = typeof cursor.toArray === 'function' ? cursor.toArray() : Array.from(cursor || []);
|
|
442
|
+
const rowsRead = cursor.rowsRead ?? cursor._rowsRead ?? arr.length;
|
|
443
|
+
const rowsWritten = cursor.rowsWritten ?? cursor._rowsWritten ?? 0;
|
|
444
|
+
const changes = cursor._changes ?? rowsWritten;
|
|
445
|
+
const lastRowId = cursor._lastRowId ?? 0;
|
|
446
|
+
return {
|
|
447
|
+
success: true,
|
|
448
|
+
results: arr,
|
|
449
|
+
meta: this._meta(rowsRead, rowsWritten, changes, lastRowId, t0),
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
_meta(rowsRead, rowsWritten, changes, lastRowId, t0) {
|
|
453
|
+
return {
|
|
454
|
+
duration: Date.now() - t0,
|
|
455
|
+
changes,
|
|
456
|
+
last_row_id: lastRowId,
|
|
457
|
+
rows_read: rowsRead,
|
|
458
|
+
rows_written: rowsWritten,
|
|
459
|
+
served_by: 'nimbus-d1-emu',
|
|
460
|
+
changed_db: rowsWritten > 0,
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
/** Apply migrations from migrations_dir if present. Idempotent. */
|
|
464
|
+
async applyMigrations() {
|
|
465
|
+
if (this.migrationsRun || !this.migrationsDir || !this.vfs)
|
|
466
|
+
return { applied: 0 };
|
|
467
|
+
this.migrationsRun = true;
|
|
468
|
+
// Ledger table tracks which migrations we've applied.
|
|
469
|
+
const ledger = '_d1_' + this.prefix.slice(4, -2) + '__nimbus_migrations';
|
|
470
|
+
this.sql.exec(`CREATE TABLE IF NOT EXISTS ${ledger} (filename TEXT PRIMARY KEY, applied_at INTEGER)`);
|
|
471
|
+
const root = (this.root || '').replace(/^\/+/, '').replace(/\/+$/, '');
|
|
472
|
+
const dir = this.migrationsDir.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
473
|
+
const fullDir = root ? root + '/' + dir : dir;
|
|
474
|
+
if (!this.vfs.exists(fullDir))
|
|
475
|
+
return { applied: 0 };
|
|
476
|
+
const files = this.vfs.readdir(fullDir)
|
|
477
|
+
.filter((e) => e.type === 'file' && e.name.endsWith('.sql'))
|
|
478
|
+
.map((e) => e.name)
|
|
479
|
+
.sort();
|
|
480
|
+
let applied = 0;
|
|
481
|
+
for (const f of files) {
|
|
482
|
+
// Has it been applied?
|
|
483
|
+
const seen = this.sql.exec(`SELECT filename FROM ${ledger} WHERE filename = ?`, f).toArray();
|
|
484
|
+
if (seen.length > 0)
|
|
485
|
+
continue;
|
|
486
|
+
const sql = this.vfs.readFileString(fullDir + '/' + f);
|
|
487
|
+
const parts = splitStatements(sql);
|
|
488
|
+
for (const p of parts) {
|
|
489
|
+
if (!p.trim())
|
|
490
|
+
continue;
|
|
491
|
+
this._runOneSync(p, []);
|
|
492
|
+
}
|
|
493
|
+
this.sql.exec(`INSERT INTO ${ledger} (filename, applied_at) VALUES (?, ?)`, f, Date.now());
|
|
494
|
+
applied++;
|
|
495
|
+
}
|
|
496
|
+
return { applied };
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
// ── splitStatements ─────────────────────────────────────────────────────
|
|
500
|
+
// Split on `;` outside string literals. Trivial parser — D1 / SQLite both
|
|
501
|
+
// accept `;`-separated statements, and we don't try to be cleverer than
|
|
502
|
+
// that (no PL/pgSQL, no BEGIN…END blocks beyond what SQLite supports for
|
|
503
|
+
// triggers, which fits in a single ; terminator anyway).
|
|
504
|
+
function splitStatements(sql) {
|
|
505
|
+
const out = [];
|
|
506
|
+
let cur = '';
|
|
507
|
+
let inStr = false;
|
|
508
|
+
let depth = 0; // CREATE TRIGGER … BEGIN … END uses BEGIN/END words but
|
|
509
|
+
// semicolons inside those need careful handling. Simple:
|
|
510
|
+
// track string state and split on `;` only outside strings.
|
|
511
|
+
for (let i = 0; i < sql.length; i++) {
|
|
512
|
+
const ch = sql[i];
|
|
513
|
+
if (inStr) {
|
|
514
|
+
cur += ch;
|
|
515
|
+
if (ch === "'") {
|
|
516
|
+
if (sql[i + 1] === "'") {
|
|
517
|
+
cur += sql[++i];
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
inStr = false;
|
|
521
|
+
}
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
if (ch === "'") {
|
|
525
|
+
inStr = true;
|
|
526
|
+
cur += ch;
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
if (ch === ';') {
|
|
530
|
+
// Crude: BEGIN…END trigger bodies — we don't split inside them.
|
|
531
|
+
// Heuristic: if the trimmed `cur` contains an unmatched 'BEGIN',
|
|
532
|
+
// accumulate until 'END'.
|
|
533
|
+
const trimUpper = cur.toUpperCase();
|
|
534
|
+
const begins = (trimUpper.match(/\bBEGIN\b/g) || []).length;
|
|
535
|
+
const ends = (trimUpper.match(/\bEND\b/g) || []).length;
|
|
536
|
+
if (begins > ends) {
|
|
537
|
+
cur += ch;
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
out.push(cur);
|
|
541
|
+
cur = '';
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
cur += ch;
|
|
545
|
+
}
|
|
546
|
+
if (cur.trim())
|
|
547
|
+
out.push(cur);
|
|
548
|
+
return out;
|
|
549
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* binding-kv.ts — KV namespace emulator for nimbus-wrangler.
|
|
3
|
+
*
|
|
4
|
+
* Implements the Workers KV runtime API
|
|
5
|
+
* (https://developers.cloudflare.com/kv/api/) backed by SqliteVFS file
|
|
6
|
+
* blobs. The emulator is constructed inline by NimbusWrangler.buildInnerEnv()
|
|
7
|
+
* and attached as `env.<binding>` on the inner Worker.
|
|
8
|
+
*
|
|
9
|
+
* Storage layout:
|
|
10
|
+
* <root>/.nimbus/kv/<binding>/<key> — body (raw bytes)
|
|
11
|
+
* <root>/.nimbus/kv/<binding>/<key>.meta — sidecar JSON:
|
|
12
|
+
* { exp?: number, // unix seconds, absolute expiration
|
|
13
|
+
* meta?: any, // user-supplied metadata
|
|
14
|
+
* v: 1 } // schema version
|
|
15
|
+
*
|
|
16
|
+
* Keys are URL-encoded so that '/' / '\\' / '\0' / '#' / etc. don't break
|
|
17
|
+
* the VFS path. We then add ".meta" to derive the sidecar path.
|
|
18
|
+
*
|
|
19
|
+
* Concurrency: KV semantics permit eventual consistency. We do not use
|
|
20
|
+
* VFS writeBatch for the body+meta pair (a torn write surfaces as a meta
|
|
21
|
+
* read mismatch which we treat as no-metadata; the body still resolves).
|
|
22
|
+
*
|
|
23
|
+
* Test seam: `_setKvNow(() => ts)` replaces the wall clock (Date.now/1000)
|
|
24
|
+
* for TTL probes. Production reads Date.now() / 1000.
|
|
25
|
+
*/
|
|
26
|
+
import type { SqliteVFS } from '../vfs/sqlite-vfs.js';
|
|
27
|
+
export interface KvEmulatorOptions {
|
|
28
|
+
vfs: SqliteVFS | any;
|
|
29
|
+
root: string;
|
|
30
|
+
binding: string;
|
|
31
|
+
onLog: (msg: string) => void;
|
|
32
|
+
}
|
|
33
|
+
export interface KvPutOptions {
|
|
34
|
+
expiration?: number;
|
|
35
|
+
expirationTtl?: number;
|
|
36
|
+
metadata?: any;
|
|
37
|
+
}
|
|
38
|
+
export interface KvGetOptions {
|
|
39
|
+
type?: 'text' | 'json' | 'arrayBuffer' | 'stream';
|
|
40
|
+
cacheTtl?: number;
|
|
41
|
+
}
|
|
42
|
+
export interface KvListOptions {
|
|
43
|
+
prefix?: string;
|
|
44
|
+
limit?: number;
|
|
45
|
+
cursor?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface KvListResult {
|
|
48
|
+
keys: {
|
|
49
|
+
name: string;
|
|
50
|
+
expiration?: number;
|
|
51
|
+
metadata?: any;
|
|
52
|
+
}[];
|
|
53
|
+
list_complete: boolean;
|
|
54
|
+
cursor?: string;
|
|
55
|
+
cacheStatus: string | null;
|
|
56
|
+
}
|
|
57
|
+
export declare function _setKvNow(fn: () => number): void;
|
|
58
|
+
export declare class KvEmulator {
|
|
59
|
+
private vfs;
|
|
60
|
+
private dir;
|
|
61
|
+
private metaCache;
|
|
62
|
+
private onLog;
|
|
63
|
+
constructor(opts: KvEmulatorOptions);
|
|
64
|
+
get(key: string, options?: KvGetOptions | string): Promise<any>;
|
|
65
|
+
getWithMetadata<T = unknown>(key: string, options?: KvGetOptions | string): Promise<{
|
|
66
|
+
value: any;
|
|
67
|
+
metadata: T | null;
|
|
68
|
+
cacheStatus: string | null;
|
|
69
|
+
}>;
|
|
70
|
+
put(key: string, value: string | ArrayBuffer | ArrayBufferView | ReadableStream | Uint8Array | null, options?: KvPutOptions): Promise<void>;
|
|
71
|
+
delete(key: string): Promise<void>;
|
|
72
|
+
list(options?: KvListOptions): Promise<KvListResult>;
|
|
73
|
+
private _ensureDir;
|
|
74
|
+
private _coerceBody;
|
|
75
|
+
private _project;
|
|
76
|
+
private _readResolved;
|
|
77
|
+
private _readMeta;
|
|
78
|
+
private _lazyDelete;
|
|
79
|
+
private _encodeCursor;
|
|
80
|
+
private _decodeCursor;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=kv.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kv.d.ts","sourceRoot":"","sources":["../../src/bindings/kv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,SAAS,GAAG,GAAG,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,GAAG,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,GAAG,QAAQ,CAAC;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,GAAG,CAAA;KAAE,EAAE,CAAC;IAC9D,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAWD,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,MAAM,GAAG,IAAI,CAAiB;AAgBlE,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,KAAK,CAAsB;gBAEvB,IAAI,EAAE,iBAAiB;IAS7B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAO/D,eAAe,CAAC,CAAC,GAAG,OAAO,EAC/B,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,YAAY,GAAG,MAAM,GAC9B,OAAO,CAAC;QAAE,KAAK,EAAE,GAAG,CAAC;QAAC,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAQpE,GAAG,CACP,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,eAAe,GAAG,cAAc,GAAG,UAAU,GAAG,IAAI,EAClF,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,IAAI,CAAC;IAwBV,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASlC,IAAI,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IA8C1D,OAAO,CAAC,UAAU;YAMJ,WAAW;IA2BzB,OAAO,CAAC,QAAQ;YA0BF,aAAa;IAa3B,OAAO,CAAC,SAAS;IAejB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,aAAa;CAOtB"}
|