@volter/tabnode 0.2.14-volter.88
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/LICENSE +22 -0
- package/README.md +78 -0
- package/THIRD-PARTY-NOTICES.md +12 -0
- package/dist/__sw__.js +526 -0
- package/dist/assets/runtime-worker-4MKaHFVb.js +75221 -0
- package/dist/assets/runtime-worker-4MKaHFVb.js.map +1 -0
- package/dist/code-transforms.d.ts +21 -0
- package/dist/code-transforms.d.ts.map +1 -0
- package/dist/config/cdn.d.ts +12 -0
- package/dist/config/cdn.d.ts.map +1 -0
- package/dist/create-runtime.d.ts +22 -0
- package/dist/create-runtime.d.ts.map +1 -0
- package/dist/host-globals.d.ts +62 -0
- package/dist/host-globals.d.ts.map +1 -0
- package/dist/index.cjs +36021 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +127 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +36020 -0
- package/dist/index.mjs.map +1 -0
- package/dist/node-internals.d.ts +68 -0
- package/dist/node-internals.d.ts.map +1 -0
- package/dist/node-lib/binding/blob.d.ts +12 -0
- package/dist/node-lib/binding/blob.d.ts.map +1 -0
- package/dist/node-lib/binding/buffer.d.ts +144 -0
- package/dist/node-lib/binding/buffer.d.ts.map +1 -0
- package/dist/node-lib/binding/cares_wrap.d.ts +14 -0
- package/dist/node-lib/binding/cares_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/fds.d.ts +30 -0
- package/dist/node-lib/binding/fds.d.ts.map +1 -0
- package/dist/node-lib/binding/fs.d.ts +157 -0
- package/dist/node-lib/binding/fs.d.ts.map +1 -0
- package/dist/node-lib/binding/handles.d.ts +81 -0
- package/dist/node-lib/binding/handles.d.ts.map +1 -0
- package/dist/node-lib/binding/http_parser.d.ts +122 -0
- package/dist/node-lib/binding/http_parser.d.ts.map +1 -0
- package/dist/node-lib/binding/index.d.ts +3 -0
- package/dist/node-lib/binding/index.d.ts.map +1 -0
- package/dist/node-lib/binding/llhttp-wasm.d.ts +22 -0
- package/dist/node-lib/binding/llhttp-wasm.d.ts.map +1 -0
- package/dist/node-lib/binding/misc.d.ts +123 -0
- package/dist/node-lib/binding/misc.d.ts.map +1 -0
- package/dist/node-lib/binding/pipe_wrap.d.ts +84 -0
- package/dist/node-lib/binding/pipe_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/process_wrap.d.ts +173 -0
- package/dist/node-lib/binding/process_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/spawn_sync.d.ts +30 -0
- package/dist/node-lib/binding/spawn_sync.d.ts.map +1 -0
- package/dist/node-lib/binding/stream_wrap.d.ts +191 -0
- package/dist/node-lib/binding/stream_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/stubs.d.ts +23 -0
- package/dist/node-lib/binding/stubs.d.ts.map +1 -0
- package/dist/node-lib/binding/tcp_wrap.d.ts +98 -0
- package/dist/node-lib/binding/tcp_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/tty_wrap.d.ts +36 -0
- package/dist/node-lib/binding/tty_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/util.d.ts +126 -0
- package/dist/node-lib/binding/util.d.ts.map +1 -0
- package/dist/node-lib/binding/uv.d.ts +32 -0
- package/dist/node-lib/binding/uv.d.ts.map +1 -0
- package/dist/node-lib/binding/zlib-pako.d.ts +22 -0
- package/dist/node-lib/binding/zlib-pako.d.ts.map +1 -0
- package/dist/node-lib/binding/zlib.d.ts +38 -0
- package/dist/node-lib/binding/zlib.d.ts.map +1 -0
- package/dist/node-lib/buffer-module.d.ts +51 -0
- package/dist/node-lib/buffer-module.d.ts.map +1 -0
- package/dist/node-lib/child-process-module.d.ts +26 -0
- package/dist/node-lib/child-process-module.d.ts.map +1 -0
- package/dist/node-lib/events-module.d.ts +58 -0
- package/dist/node-lib/events-module.d.ts.map +1 -0
- package/dist/node-lib/fs-module.d.ts +5 -0
- package/dist/node-lib/fs-module.d.ts.map +1 -0
- package/dist/node-lib/http-bridge.d.ts +43 -0
- package/dist/node-lib/http-bridge.d.ts.map +1 -0
- package/dist/node-lib/http-module.d.ts +35 -0
- package/dist/node-lib/http-module.d.ts.map +1 -0
- package/dist/node-lib/internals/addresses.d.ts +40 -0
- package/dist/node-lib/internals/addresses.d.ts.map +1 -0
- package/dist/node-lib/internals/buffer-and-streams.d.ts +96 -0
- package/dist/node-lib/internals/buffer-and-streams.d.ts.map +1 -0
- package/dist/node-lib/internals/child-process.d.ts +27 -0
- package/dist/node-lib/internals/child-process.d.ts.map +1 -0
- package/dist/node-lib/internals/events-util.d.ts +83 -0
- package/dist/node-lib/internals/events-util.d.ts.map +1 -0
- package/dist/node-lib/internals/index.d.ts +2 -0
- package/dist/node-lib/internals/index.d.ts.map +1 -0
- package/dist/node-lib/internals/modules.d.ts +67 -0
- package/dist/node-lib/internals/modules.d.ts.map +1 -0
- package/dist/node-lib/internals/readline-access.d.ts +2 -0
- package/dist/node-lib/internals/readline-access.d.ts.map +1 -0
- package/dist/node-lib/internals/runtime.d.ts +150 -0
- package/dist/node-lib/internals/runtime.d.ts.map +1 -0
- package/dist/node-lib/internals/util.d.ts +33 -0
- package/dist/node-lib/internals/util.d.ts.map +1 -0
- package/dist/node-lib/lazy.d.ts +31 -0
- package/dist/node-lib/lazy.d.ts.map +1 -0
- package/dist/node-lib/load.d.ts +27 -0
- package/dist/node-lib/load.d.ts.map +1 -0
- package/dist/node-lib/module-hooks.d.ts +89 -0
- package/dist/node-lib/module-hooks.d.ts.map +1 -0
- package/dist/node-lib/net-module.d.ts +181 -0
- package/dist/node-lib/net-module.d.ts.map +1 -0
- package/dist/node-lib/node-versions.d.ts +27 -0
- package/dist/node-lib/node-versions.d.ts.map +1 -0
- package/dist/node-lib/public-modules.d.ts +2 -0
- package/dist/node-lib/public-modules.d.ts.map +1 -0
- package/dist/node-lib/require-hook.d.ts +15 -0
- package/dist/node-lib/require-hook.d.ts.map +1 -0
- package/dist/node-lib/small-modules.d.ts +16 -0
- package/dist/node-lib/small-modules.d.ts.map +1 -0
- package/dist/node-lib/sources.d.ts +4 -0
- package/dist/node-lib/sources.d.ts.map +1 -0
- package/dist/node-lib/stream-module.d.ts +77 -0
- package/dist/node-lib/stream-module.d.ts.map +1 -0
- package/dist/node-lib/timers.d.ts +19 -0
- package/dist/node-lib/timers.d.ts.map +1 -0
- package/dist/node-lib/util-module.d.ts +76 -0
- package/dist/node-lib/util-module.d.ts.map +1 -0
- package/dist/node-resolution.d.ts +50 -0
- package/dist/node-resolution.d.ts.map +1 -0
- package/dist/node-resolver.d.ts +7 -0
- package/dist/node-resolver.d.ts.map +1 -0
- package/dist/npm/index.d.ts +73 -0
- package/dist/npm/index.d.ts.map +1 -0
- package/dist/npm/registry.d.ts +111 -0
- package/dist/npm/registry.d.ts.map +1 -0
- package/dist/npm/resolver.d.ts +79 -0
- package/dist/npm/resolver.d.ts.map +1 -0
- package/dist/npm/tarball.d.ts +28 -0
- package/dist/npm/tarball.d.ts.map +1 -0
- package/dist/process-tokens.d.ts +77 -0
- package/dist/process-tokens.d.ts.map +1 -0
- package/dist/punycode-source.d.ts +3 -0
- package/dist/punycode-source.d.ts.map +1 -0
- package/dist/runtime-interface.d.ts +74 -0
- package/dist/runtime-interface.d.ts.map +1 -0
- package/dist/runtime.d.ts +144 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/server-bridge.d.ts +147 -0
- package/dist/server-bridge.d.ts.map +1 -0
- package/dist/shims/async_hooks.d.ts +50 -0
- package/dist/shims/async_hooks.d.ts.map +1 -0
- package/dist/shims/child_process.d.ts +104 -0
- package/dist/shims/child_process.d.ts.map +1 -0
- package/dist/shims/cluster.d.ts +52 -0
- package/dist/shims/cluster.d.ts.map +1 -0
- package/dist/shims/command-line.d.ts +43 -0
- package/dist/shims/command-line.d.ts.map +1 -0
- package/dist/shims/constants.d.ts +222 -0
- package/dist/shims/constants.d.ts.map +1 -0
- package/dist/shims/crypto-constants.d.ts +12 -0
- package/dist/shims/crypto-constants.d.ts.map +1 -0
- package/dist/shims/crypto.d.ts +144 -0
- package/dist/shims/crypto.d.ts.map +1 -0
- package/dist/shims/dgram.d.ts +34 -0
- package/dist/shims/dgram.d.ts.map +1 -0
- package/dist/shims/dns.d.ts +91 -0
- package/dist/shims/dns.d.ts.map +1 -0
- package/dist/shims/domain.d.ts +25 -0
- package/dist/shims/domain.d.ts.map +1 -0
- package/dist/shims/esbuild.d.ts +205 -0
- package/dist/shims/esbuild.d.ts.map +1 -0
- package/dist/shims/fs.d.ts +25 -0
- package/dist/shims/fs.d.ts.map +1 -0
- package/dist/shims/http2.d.ts +81 -0
- package/dist/shims/http2.d.ts.map +1 -0
- package/dist/shims/inspector.d.ts +25 -0
- package/dist/shims/inspector.d.ts.map +1 -0
- package/dist/shims/module.d.ts +22 -0
- package/dist/shims/module.d.ts.map +1 -0
- package/dist/shims/os.d.ts +159 -0
- package/dist/shims/os.d.ts.map +1 -0
- package/dist/shims/path.d.ts +52 -0
- package/dist/shims/path.d.ts.map +1 -0
- package/dist/shims/perf_hooks.d.ts +50 -0
- package/dist/shims/perf_hooks.d.ts.map +1 -0
- package/dist/shims/process.d.ts +226 -0
- package/dist/shims/process.d.ts.map +1 -0
- package/dist/shims/rollup.d.ts +71 -0
- package/dist/shims/rollup.d.ts.map +1 -0
- package/dist/shims/string_decoder.d.ts +41 -0
- package/dist/shims/string_decoder.d.ts.map +1 -0
- package/dist/shims/sync-child.d.ts +64 -0
- package/dist/shims/sync-child.d.ts.map +1 -0
- package/dist/shims/tls.d.ts +53 -0
- package/dist/shims/tls.d.ts.map +1 -0
- package/dist/shims/url.d.ts +84 -0
- package/dist/shims/url.d.ts.map +1 -0
- package/dist/shims/v8.d.ts +73 -0
- package/dist/shims/v8.d.ts.map +1 -0
- package/dist/shims/vfs-adapter.d.ts +126 -0
- package/dist/shims/vfs-adapter.d.ts.map +1 -0
- package/dist/shims/vm.d.ts +52 -0
- package/dist/shims/vm.d.ts.map +1 -0
- package/dist/shims/wasi.d.ts +78 -0
- package/dist/shims/wasi.d.ts.map +1 -0
- package/dist/shims/worker_threads.d.ts +66 -0
- package/dist/shims/worker_threads.d.ts.map +1 -0
- package/dist/shims/zlib-constants.d.ts +66 -0
- package/dist/shims/zlib-constants.d.ts.map +1 -0
- package/dist/shims/zlib.d.ts +102 -0
- package/dist/shims/zlib.d.ts.map +1 -0
- package/dist/transform.d.ts +24 -0
- package/dist/transform.d.ts.map +1 -0
- package/dist/types/package-json.d.ts +18 -0
- package/dist/types/package-json.d.ts.map +1 -0
- package/dist/utils/binary-encoding.d.ts +13 -0
- package/dist/utils/binary-encoding.d.ts.map +1 -0
- package/dist/utils/glob.d.ts +19 -0
- package/dist/utils/glob.d.ts.map +1 -0
- package/dist/utils/hash.d.ts +6 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/virtual-fs.d.ts +259 -0
- package/dist/virtual-fs.d.ts.map +1 -0
- package/dist/vite-plugin.cjs +50 -0
- package/dist/vite-plugin.cjs.map +1 -0
- package/dist/vite-plugin.d.ts +36 -0
- package/dist/vite-plugin.d.ts.map +1 -0
- package/dist/vite-plugin.mjs +31 -0
- package/dist/vite-plugin.mjs.map +1 -0
- package/dist/worker/runtime-worker.d.ts +8 -0
- package/dist/worker/runtime-worker.d.ts.map +1 -0
- package/dist/worker-runtime.d.ts +50 -0
- package/dist/worker-runtime.d.ts.map +1 -0
- package/package.json +88 -0
- package/src/code-transforms.ts +560 -0
- package/src/config/cdn.ts +13 -0
- package/src/create-runtime.ts +89 -0
- package/src/host-globals.ts +121 -0
- package/src/index.ts +235 -0
- package/src/node-internals.ts +283 -0
- package/src/node-lib/LICENSE +47 -0
- package/src/node-lib/_http_agent.js +547 -0
- package/src/node-lib/_http_client.js +996 -0
- package/src/node-lib/_http_common.js +269 -0
- package/src/node-lib/_http_incoming.js +453 -0
- package/src/node-lib/_http_outgoing.js +1262 -0
- package/src/node-lib/_http_server.js +1230 -0
- package/src/node-lib/assert/strict.js +3 -0
- package/src/node-lib/assert.js +844 -0
- package/src/node-lib/binding/blob.ts +35 -0
- package/src/node-lib/binding/buffer.ts +465 -0
- package/src/node-lib/binding/cares_wrap.ts +57 -0
- package/src/node-lib/binding/fds.ts +80 -0
- package/src/node-lib/binding/fs.ts +857 -0
- package/src/node-lib/binding/handles.ts +187 -0
- package/src/node-lib/binding/http_parser.ts +536 -0
- package/src/node-lib/binding/index.ts +77 -0
- package/src/node-lib/binding/llhttp-wasm.ts +670 -0
- package/src/node-lib/binding/misc.ts +252 -0
- package/src/node-lib/binding/pipe_wrap.ts +166 -0
- package/src/node-lib/binding/process_wrap.ts +371 -0
- package/src/node-lib/binding/spawn_sync.ts +141 -0
- package/src/node-lib/binding/stream_wrap.ts +413 -0
- package/src/node-lib/binding/stubs.ts +19 -0
- package/src/node-lib/binding/tcp_wrap.ts +254 -0
- package/src/node-lib/binding/tty_wrap.ts +56 -0
- package/src/node-lib/binding/util.ts +274 -0
- package/src/node-lib/binding/uv.ts +102 -0
- package/src/node-lib/binding/zlib-pako.ts +50 -0
- package/src/node-lib/binding/zlib.ts +259 -0
- package/src/node-lib/buffer-module.ts +70 -0
- package/src/node-lib/buffer.js +1373 -0
- package/src/node-lib/child-process-module.ts +58 -0
- package/src/node-lib/child_process.js +1046 -0
- package/src/node-lib/constants.js +41 -0
- package/src/node-lib/diagnostics_channel.js +438 -0
- package/src/node-lib/events-module.ts +80 -0
- package/src/node-lib/events.js +1223 -0
- package/src/node-lib/fs-module.ts +43 -0
- package/src/node-lib/fs.js +3377 -0
- package/src/node-lib/http-bridge.ts +299 -0
- package/src/node-lib/http-module.ts +53 -0
- package/src/node-lib/http.js +198 -0
- package/src/node-lib/https.js +429 -0
- package/src/node-lib/internal/assert/assertion_error.js +417 -0
- package/src/node-lib/internal/assert/calltracker.js +153 -0
- package/src/node-lib/internal/assert/myers_diff.js +177 -0
- package/src/node-lib/internal/assert/utils.js +278 -0
- package/src/node-lib/internal/buffer.js +1120 -0
- package/src/node-lib/internal/child_process/serialization.js +169 -0
- package/src/node-lib/internal/child_process.js +1135 -0
- package/src/node-lib/internal/constants.js +56 -0
- package/src/node-lib/internal/deps/minimatch/index.js +1628 -0
- package/src/node-lib/internal/errors.js +1912 -0
- package/src/node-lib/internal/events/abort_listener.js +54 -0
- package/src/node-lib/internal/events/symbols.js +11 -0
- package/src/node-lib/internal/fixed_queue.js +119 -0
- package/src/node-lib/internal/freelist.js +30 -0
- package/src/node-lib/internal/fs/cp/cp-sync.js +242 -0
- package/src/node-lib/internal/fs/cp/cp.js +382 -0
- package/src/node-lib/internal/fs/dir.js +369 -0
- package/src/node-lib/internal/fs/glob.js +763 -0
- package/src/node-lib/internal/fs/promises.js +1312 -0
- package/src/node-lib/internal/fs/read/context.js +129 -0
- package/src/node-lib/internal/fs/recursive_watch.js +275 -0
- package/src/node-lib/internal/fs/rimraf.js +311 -0
- package/src/node-lib/internal/fs/streams.js +571 -0
- package/src/node-lib/internal/fs/sync_write_stream.js +49 -0
- package/src/node-lib/internal/fs/utils.js +987 -0
- package/src/node-lib/internal/fs/watchers.js +418 -0
- package/src/node-lib/internal/http.js +62 -0
- package/src/node-lib/internal/mime.js +389 -0
- package/src/node-lib/internal/modules/customization_hooks.js +406 -0
- package/src/node-lib/internal/net.js +95 -0
- package/src/node-lib/internal/querystring.js +119 -0
- package/src/node-lib/internal/readline/callbacks.js +132 -0
- package/src/node-lib/internal/readline/emitKeypressEvents.js +99 -0
- package/src/node-lib/internal/readline/interface.js +1418 -0
- package/src/node-lib/internal/readline/promises.js +144 -0
- package/src/node-lib/internal/readline/utils.js +405 -0
- package/src/node-lib/internal/socket_list.js +108 -0
- package/src/node-lib/internal/stream_base_commons.js +280 -0
- package/src/node-lib/internal/streams/add-abort-signal.js +60 -0
- package/src/node-lib/internal/streams/compose.js +257 -0
- package/src/node-lib/internal/streams/destroy.js +361 -0
- package/src/node-lib/internal/streams/duplex.js +203 -0
- package/src/node-lib/internal/streams/duplexify.js +379 -0
- package/src/node-lib/internal/streams/duplexpair.js +62 -0
- package/src/node-lib/internal/streams/end-of-stream.js +331 -0
- package/src/node-lib/internal/streams/from.js +208 -0
- package/src/node-lib/internal/streams/lazy_transform.js +57 -0
- package/src/node-lib/internal/streams/legacy.js +125 -0
- package/src/node-lib/internal/streams/operators.js +436 -0
- package/src/node-lib/internal/streams/passthrough.js +47 -0
- package/src/node-lib/internal/streams/pipeline.js +465 -0
- package/src/node-lib/internal/streams/readable.js +1762 -0
- package/src/node-lib/internal/streams/state.js +51 -0
- package/src/node-lib/internal/streams/transform.js +204 -0
- package/src/node-lib/internal/streams/utils.js +363 -0
- package/src/node-lib/internal/streams/writable.js +1163 -0
- package/src/node-lib/internal/tty.js +260 -0
- package/src/node-lib/internal/util/colors.js +40 -0
- package/src/node-lib/internal/util/comparisons.js +1028 -0
- package/src/node-lib/internal/util/debuglog.js +524 -0
- package/src/node-lib/internal/util/inspect.js +2535 -0
- package/src/node-lib/internal/util/parse_args/parse_args.js +412 -0
- package/src/node-lib/internal/util/parse_args/utils.js +197 -0
- package/src/node-lib/internal/util.js +1003 -0
- package/src/node-lib/internal/validators.js +654 -0
- package/src/node-lib/internals/addresses.ts +159 -0
- package/src/node-lib/internals/buffer-and-streams.ts +224 -0
- package/src/node-lib/internals/child-process.ts +64 -0
- package/src/node-lib/internals/events-util.ts +105 -0
- package/src/node-lib/internals/index.ts +66 -0
- package/src/node-lib/internals/modules.ts +117 -0
- package/src/node-lib/internals/readline-access.ts +16 -0
- package/src/node-lib/internals/runtime.ts +277 -0
- package/src/node-lib/internals/util.ts +98 -0
- package/src/node-lib/lazy.ts +158 -0
- package/src/node-lib/load.ts +390 -0
- package/src/node-lib/module-hooks.ts +281 -0
- package/src/node-lib/net-module.ts +248 -0
- package/src/node-lib/net.js +2540 -0
- package/src/node-lib/node-versions.ts +34 -0
- package/src/node-lib/os.js +356 -0
- package/src/node-lib/path.js +1694 -0
- package/src/node-lib/primordials.js +743 -0
- package/src/node-lib/public-modules.ts +109 -0
- package/src/node-lib/punycode.js +455 -0
- package/src/node-lib/querystring.js +484 -0
- package/src/node-lib/readline/promises.js +73 -0
- package/src/node-lib/readline.js +523 -0
- package/src/node-lib/require-hook.ts +27 -0
- package/src/node-lib/small-modules.ts +35 -0
- package/src/node-lib/sources.ts +200 -0
- package/src/node-lib/stream/promises.js +44 -0
- package/src/node-lib/stream-module.ts +101 -0
- package/src/node-lib/stream.js +152 -0
- package/src/node-lib/timers.ts +33 -0
- package/src/node-lib/tty.js +168 -0
- package/src/node-lib/util-module.ts +104 -0
- package/src/node-lib/util.js +689 -0
- package/src/node-lib/wasi.js +179 -0
- package/src/node-lib/zlib.js +1036 -0
- package/src/node-resolution.ts +241 -0
- package/src/node-resolver.ts +33 -0
- package/src/npm/index.ts +425 -0
- package/src/npm/registry.ts +235 -0
- package/src/npm/resolver.ts +589 -0
- package/src/npm/tarball.ts +246 -0
- package/src/process-tokens.ts +156 -0
- package/src/punycode-source.ts +6 -0
- package/src/runtime-interface.ts +85 -0
- package/src/runtime.ts +3073 -0
- package/src/server-bridge.ts +971 -0
- package/src/shims/async_hooks.ts +181 -0
- package/src/shims/child_process.ts +1591 -0
- package/src/shims/cluster.ts +79 -0
- package/src/shims/command-line.ts +79 -0
- package/src/shims/constants.ts +68 -0
- package/src/shims/crypto-constants.ts +11 -0
- package/src/shims/crypto.ts +1061 -0
- package/src/shims/dgram.ts +47 -0
- package/src/shims/dns.ts +185 -0
- package/src/shims/domain.ts +58 -0
- package/src/shims/esbuild.ts +1638 -0
- package/src/shims/fs.ts +82 -0
- package/src/shims/http2.ts +96 -0
- package/src/shims/inspector.ts +30 -0
- package/src/shims/module.ts +86 -0
- package/src/shims/os.ts +195 -0
- package/src/shims/path.ts +246 -0
- package/src/shims/perf_hooks.ts +92 -0
- package/src/shims/process.ts +804 -0
- package/src/shims/rollup.ts +149 -0
- package/src/shims/string_decoder.ts +396 -0
- package/src/shims/sync-child.ts +469 -0
- package/src/shims/tls.ts +94 -0
- package/src/shims/url.ts +217 -0
- package/src/shims/v8.ts +113 -0
- package/src/shims/vfs-adapter.ts +408 -0
- package/src/shims/vm.ts +132 -0
- package/src/shims/wasi.ts +1440 -0
- package/src/shims/worker_threads.ts +114 -0
- package/src/shims/zlib-constants.ts +65 -0
- package/src/shims/zlib.ts +228 -0
- package/src/transform.ts +324 -0
- package/src/types/external.d.ts +55 -0
- package/src/types/package-json.ts +17 -0
- package/src/types/pako-zlib.d.ts +30 -0
- package/src/types/sha.js.d.ts +14 -0
- package/src/utils/binary-encoding.ts +43 -0
- package/src/utils/glob.ts +54 -0
- package/src/utils/hash.ts +12 -0
- package/src/virtual-fs.ts +1048 -0
- package/src/vite-plugin.ts +76 -0
- package/src/worker/runtime-worker.ts +128 -0
- package/src/worker-runtime.ts +145 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 almostnode contributors
|
|
4
|
+
Copyright (c) 2026 tabnode contributors
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# tabnode
|
|
2
|
+
|
|
3
|
+
**Node's own library, in a browser tab.**
|
|
4
|
+
|
|
5
|
+
tabnode runs Node programs in the browser. Its builtins are Node's own files, vendored unmodified from Node v22.18.0, on a binding layer that answers what libuv and V8's C++ would have answered: sockets, children, files, TTYs, the HTTP parser, zlib. Node's own test suite measures each module, and the numbers are in [`BUILTINS.md`](BUILTINS.md). Where Node's own module is native and the tab has no twin, the module is the engine's, with the reason at its site.
|
|
6
|
+
|
|
7
|
+
It is the Node engine of [`volter-ai/browser-substrate`](https://github.com/volter-ai/browser-substrate), which consumes it from npm by version. This repository is a fork of `macaly/almostnode`; [`FORK.md`](FORK.md) names the upstream and holds the rules for changing, releasing and measuring it.
|
|
8
|
+
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## What is here
|
|
14
|
+
|
|
15
|
+
The engine is a library, not an application. It has one consumer, the substrate, and its surface is what that consumer embeds:
|
|
16
|
+
|
|
17
|
+
| Door | What it is |
|
|
18
|
+
|---|---|
|
|
19
|
+
| `createContainer()` | a filesystem, a runtime, an npm client and a server bridge as one object, with `run`, `execute` and the process questions a host asks about a named run |
|
|
20
|
+
| `VirtualFS` | the in-memory tree every builtin's `fs` binding reads and writes |
|
|
21
|
+
| `Runtime` | one guest realm: `require`, the module table of builtins, ESM lowered to CommonJS |
|
|
22
|
+
| `createRuntime()` | the same on the caller's thread or on a worker of the engine's own |
|
|
23
|
+
| `ServerBridge` | a page request answered by a guest's own `http` server, through the service worker |
|
|
24
|
+
| `createNodeResolver()` | Node's module resolution as a function over any filesystem |
|
|
25
|
+
| `esbuild`, `rollup` | the bundlers' own wasm builds, for a host that builds outside a run |
|
|
26
|
+
|
|
27
|
+
A guest's builtins are not here. A guest reaches them through the runtime's own module table (`src/runtime.ts`), which serves Node's vendored files from `src/node-lib/` and, for the modules Node writes in C++, the engine's own from `src/shims/`.
|
|
28
|
+
|
|
29
|
+
What the engine does not answer: a package it does not ship. `ws`, `chokidar`, `readdirp` and `fsevents` were imitated here once; each is an ordinary package over a builtin that is Node's own now, so a project installs it and it runs unchanged.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Using it
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install @volter/tabnode
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The `release` branch carries the same build for an install by git tag, `github:volter-ai/tabnode#v0.2.14-volter.<n>`.
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { createContainer } from '@volter/tabnode';
|
|
43
|
+
|
|
44
|
+
const container = createContainer();
|
|
45
|
+
container.vfs.writeFileSync('/hello.js', `
|
|
46
|
+
const fs = require('fs');
|
|
47
|
+
fs.writeFileSync('/out.txt', 'from a tab');
|
|
48
|
+
console.log(fs.readFileSync('/out.txt', 'utf8'));
|
|
49
|
+
`);
|
|
50
|
+
const { stdout, exitCode } = await container.run('node /hello.js');
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
A guest server is reached through the bridge, at `/__virtual__/{port}/`, once the page has registered the service worker this package ships as `dist/__sw__.js`. A Vite host gets that route from the plugin:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// vite.config.ts
|
|
57
|
+
import { tabnodePlugin } from '@volter/tabnode/vite';
|
|
58
|
+
export default { plugins: [tabnodePlugin()] };
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Working on it
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install
|
|
67
|
+
npm run build:lib # the bundle and its declarations, into dist/
|
|
68
|
+
npm run type-check # tsc over src and tests
|
|
69
|
+
npm test # the engine's own checks, vitest over tests/
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
A fix is a source commit on `main` that states which Node behaviour it restores, general to every program, never a fix that recognises a package or a framework. What measures it is Node's own suite, run against a build by `scripts/node-tests.mjs` (`scripts/NODE-TESTS.md`); `FORK.md` holds the release procedure and the module-by-module table of what still fails.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
MIT, [`LICENSE`](LICENSE). Node's own library files under `src/node-lib/` are Node's, under Node's MIT licence beside them; what else is carried from elsewhere is listed in [`THIRD-PARTY-NOTICES.md`](THIRD-PARTY-NOTICES.md).
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
What this repository carries that is someone else's, each under its own
|
|
4
|
+
licence, reproduced where it sits. Dependencies fetched by npm carry their
|
|
5
|
+
licences in `node_modules` and are not listed here.
|
|
6
|
+
|
|
7
|
+
| What | Where | Origin | Licence |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| Node.js's own library files, unmodified | `src/node-lib/**/*.js` | `nodejs/node` v22.18.0, `lib/` | MIT, `src/node-lib/LICENSE` |
|
|
10
|
+
| llhttp compiled to WebAssembly, the build undici ships | `src/node-lib/binding/llhttp-wasm.ts` | undici 6.28.0, `lib/llhttp/llhttp-wasm.js` (`nodejs/llhttp`, `nodejs/undici`) | MIT |
|
|
11
|
+
| punycode 2.3.1, the library Node ships as its `punycode` builtin | `src/punycode-source.ts` | Mathias Bynens, `mathiasbynens/punycode.js` | MIT |
|
|
12
|
+
| The engine this repository is a fork of | the tree | `macaly/almostnode` 0.2.14 | MIT, `LICENSE` |
|
package/dist/__sw__.js
ADDED
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Worker for Mini WebContainers
|
|
3
|
+
* Intercepts fetch requests and routes them to virtual servers
|
|
4
|
+
* Version: 15 - cleanup: extract helpers, gate debug logs, remove test endpoints
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const DEBUG = false;
|
|
8
|
+
|
|
9
|
+
// Communication port with main thread
|
|
10
|
+
let mainPort = null;
|
|
11
|
+
|
|
12
|
+
// Pending requests waiting for response
|
|
13
|
+
const pendingRequests = new Map();
|
|
14
|
+
let requestId = 0;
|
|
15
|
+
|
|
16
|
+
// Registered virtual server ports
|
|
17
|
+
const registeredPorts = new Set();
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Decode base64 string to Uint8Array
|
|
21
|
+
*/
|
|
22
|
+
function base64ToBytes(base64) {
|
|
23
|
+
const binary = atob(base64);
|
|
24
|
+
const bytes = new Uint8Array(binary.length);
|
|
25
|
+
for (let i = 0; i < binary.length; i++) {
|
|
26
|
+
bytes[i] = binary.charCodeAt(i);
|
|
27
|
+
}
|
|
28
|
+
return bytes;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Handle messages from main thread
|
|
33
|
+
*/
|
|
34
|
+
self.addEventListener('message', (event) => {
|
|
35
|
+
const { type, data } = event.data;
|
|
36
|
+
|
|
37
|
+
DEBUG && console.log('[SW] Received message:', type, 'hasPort in event.ports:', event.ports?.length > 0);
|
|
38
|
+
|
|
39
|
+
// When a MessagePort is transferred, it's in event.ports[0], not event.data.port
|
|
40
|
+
if (type === 'init' && event.ports && event.ports[0]) {
|
|
41
|
+
// Initialize communication channel
|
|
42
|
+
mainPort = event.ports[0];
|
|
43
|
+
mainPort.onmessage = handleMainMessage;
|
|
44
|
+
if (data && Array.isArray(data.ownDocuments)) ownDocuments = new Set(data.ownDocuments.map((path) => ownPath(String(path))));
|
|
45
|
+
DEBUG && console.log('[SW] Initialized communication channel with transferred port');
|
|
46
|
+
// Re-claim clients so that pages opened after SW activation get controlled.
|
|
47
|
+
// Without this, controllerchange never fires for late-arriving pages.
|
|
48
|
+
self.clients.claim();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (type === 'server-registered' && data) {
|
|
52
|
+
registeredPorts.add(data.port);
|
|
53
|
+
if (data.primary) primaryPort = data.port;
|
|
54
|
+
DEBUG && console.log(`[SW] Server registered on port ${data.port}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (type === 'server-unregistered' && data) {
|
|
58
|
+
registeredPorts.delete(data.port);
|
|
59
|
+
if (primaryPort === data.port) primaryPort = null;
|
|
60
|
+
DEBUG && console.log(`[SW] Server unregistered from port ${data.port}`);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Handle response messages from main thread
|
|
66
|
+
*/
|
|
67
|
+
function handleMainMessage(event) {
|
|
68
|
+
const { type, id, data, error } = event.data;
|
|
69
|
+
|
|
70
|
+
// The page's bridge speaks over this port: which servers it holds, which
|
|
71
|
+
// is the preview's, and which documents are the page's own frames.
|
|
72
|
+
if (type === 'server-registered' && data) {
|
|
73
|
+
registeredPorts.add(data.port);
|
|
74
|
+
if (data.primary) primaryPort = data.port;
|
|
75
|
+
else if (primaryPort === data.port) primaryPort = null;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (type === 'server-unregistered' && data) {
|
|
79
|
+
registeredPorts.delete(data.port);
|
|
80
|
+
if (primaryPort === data.port) primaryPort = null;
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (type === 'own-documents' && data && Array.isArray(data.paths)) {
|
|
84
|
+
ownDocuments = new Set(data.paths.map((path) => ownPath(String(path))));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
DEBUG && console.log('[SW] Received message from main:', type, 'id:', id);
|
|
89
|
+
|
|
90
|
+
if (type === 'response') {
|
|
91
|
+
const pending = pendingRequests.get(id);
|
|
92
|
+
DEBUG && console.log('[SW] Looking for pending request:', id, 'found:', !!pending);
|
|
93
|
+
|
|
94
|
+
if (pending) {
|
|
95
|
+
pendingRequests.delete(id);
|
|
96
|
+
|
|
97
|
+
if (error) {
|
|
98
|
+
DEBUG && console.log('[SW] Response error:', error);
|
|
99
|
+
pending.reject(new Error(error));
|
|
100
|
+
} else {
|
|
101
|
+
DEBUG && console.log('[SW] Response data:', {
|
|
102
|
+
statusCode: data?.statusCode,
|
|
103
|
+
statusMessage: data?.statusMessage,
|
|
104
|
+
headers: data?.headers,
|
|
105
|
+
bodyType: data?.body?.constructor?.name,
|
|
106
|
+
bodyLength: data?.body?.length || data?.body?.byteLength,
|
|
107
|
+
});
|
|
108
|
+
pending.resolve(data);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Handle streaming responses
|
|
114
|
+
if (type === 'stream-start') {
|
|
115
|
+
DEBUG && console.log('[SW] stream-start received, id:', id);
|
|
116
|
+
const pending = pendingRequests.get(id);
|
|
117
|
+
if (pending && pending.streamController) {
|
|
118
|
+
// Store headers/status for the streaming response
|
|
119
|
+
pending.streamData = data;
|
|
120
|
+
pending.resolveHeaders(data);
|
|
121
|
+
DEBUG && console.log('[SW] headers resolved for stream', id);
|
|
122
|
+
} else {
|
|
123
|
+
DEBUG && console.log('[SW] No pending request or controller for stream-start', id, !!pending, pending?.streamController);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (type === 'stream-chunk') {
|
|
128
|
+
DEBUG && console.log('[SW] stream-chunk received, id:', id, 'size:', data?.chunkBase64?.length);
|
|
129
|
+
const pending = pendingRequests.get(id);
|
|
130
|
+
if (pending && pending.streamController) {
|
|
131
|
+
try {
|
|
132
|
+
// Decode base64 chunk and enqueue
|
|
133
|
+
if (data.chunkBase64) {
|
|
134
|
+
const bytes = base64ToBytes(data.chunkBase64);
|
|
135
|
+
pending.streamController.enqueue(bytes);
|
|
136
|
+
DEBUG && console.log('[SW] chunk enqueued, bytes:', bytes.length);
|
|
137
|
+
}
|
|
138
|
+
} catch (e) {
|
|
139
|
+
console.error('[SW] Error enqueueing chunk:', e);
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
DEBUG && console.log('[SW] No pending request or controller for stream-chunk', id);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (type === 'stream-end') {
|
|
147
|
+
DEBUG && console.log('[SW] stream-end received, id:', id);
|
|
148
|
+
const pending = pendingRequests.get(id);
|
|
149
|
+
if (pending && pending.streamController) {
|
|
150
|
+
try {
|
|
151
|
+
pending.streamController.close();
|
|
152
|
+
DEBUG && console.log('[SW] stream closed');
|
|
153
|
+
} catch (e) {
|
|
154
|
+
DEBUG && console.log('[SW] stream already closed');
|
|
155
|
+
}
|
|
156
|
+
pendingRequests.delete(id);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Send request to main thread and wait for response
|
|
163
|
+
*/
|
|
164
|
+
async function sendRequest(port, method, url, headers, body) {
|
|
165
|
+
DEBUG && console.log('[SW] sendRequest called, mainPort:', !!mainPort, 'url:', url);
|
|
166
|
+
|
|
167
|
+
if (!mainPort) {
|
|
168
|
+
// Ask all clients to re-send the init message
|
|
169
|
+
const allClients = await self.clients.matchAll({ type: 'window' });
|
|
170
|
+
for (const client of allClients) {
|
|
171
|
+
client.postMessage({ type: 'sw-needs-init' });
|
|
172
|
+
}
|
|
173
|
+
// Wait up to 5s for a client to re-initialize the port
|
|
174
|
+
// (main thread may be busy with heavy operations like CLI execution)
|
|
175
|
+
await new Promise(resolve => {
|
|
176
|
+
const check = setInterval(() => { if (mainPort) { clearInterval(check); resolve(); } }, 50);
|
|
177
|
+
setTimeout(() => { clearInterval(check); resolve(); }, 5000);
|
|
178
|
+
});
|
|
179
|
+
if (!mainPort) {
|
|
180
|
+
throw new Error('Service Worker not initialized - no connection to main thread');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const id = ++requestId;
|
|
185
|
+
|
|
186
|
+
return new Promise((resolve, reject) => {
|
|
187
|
+
pendingRequests.set(id, { resolve, reject });
|
|
188
|
+
|
|
189
|
+
// Set timeout for request
|
|
190
|
+
setTimeout(() => {
|
|
191
|
+
if (pendingRequests.has(id)) {
|
|
192
|
+
pendingRequests.delete(id);
|
|
193
|
+
reject(new Error('Request timeout'));
|
|
194
|
+
}
|
|
195
|
+
}, 30000);
|
|
196
|
+
|
|
197
|
+
mainPort.postMessage({
|
|
198
|
+
type: 'request',
|
|
199
|
+
id,
|
|
200
|
+
data: { port, method, url, headers, body },
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Send streaming request to main thread
|
|
207
|
+
* Returns a ReadableStream that receives chunks from main thread
|
|
208
|
+
*/
|
|
209
|
+
async function sendStreamingRequest(port, method, url, headers, body) {
|
|
210
|
+
DEBUG && console.log('[SW] sendStreamingRequest called, url:', url);
|
|
211
|
+
|
|
212
|
+
if (!mainPort) {
|
|
213
|
+
// Ask all clients to re-send the init message
|
|
214
|
+
const allClients = await self.clients.matchAll({ type: 'window' });
|
|
215
|
+
for (const client of allClients) {
|
|
216
|
+
client.postMessage({ type: 'sw-needs-init' });
|
|
217
|
+
}
|
|
218
|
+
await new Promise(resolve => {
|
|
219
|
+
const check = setInterval(() => { if (mainPort) { clearInterval(check); resolve(); } }, 50);
|
|
220
|
+
setTimeout(() => { clearInterval(check); resolve(); }, 5000);
|
|
221
|
+
});
|
|
222
|
+
if (!mainPort) {
|
|
223
|
+
throw new Error('Service Worker not initialized');
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const id = ++requestId;
|
|
228
|
+
|
|
229
|
+
let streamController;
|
|
230
|
+
let resolveHeaders;
|
|
231
|
+
const headersPromise = new Promise(resolve => { resolveHeaders = resolve; });
|
|
232
|
+
|
|
233
|
+
const stream = new ReadableStream({
|
|
234
|
+
start(controller) {
|
|
235
|
+
streamController = controller;
|
|
236
|
+
|
|
237
|
+
// Store in pending requests so handleMainMessage can find it
|
|
238
|
+
pendingRequests.set(id, {
|
|
239
|
+
resolve: () => {},
|
|
240
|
+
reject: (err) => controller.error(err),
|
|
241
|
+
streamController: controller,
|
|
242
|
+
resolveHeaders,
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// Send request to main thread with streaming flag
|
|
246
|
+
mainPort.postMessage({
|
|
247
|
+
type: 'request',
|
|
248
|
+
id,
|
|
249
|
+
data: { port, method, url, headers, body, streaming: true },
|
|
250
|
+
});
|
|
251
|
+
},
|
|
252
|
+
cancel() {
|
|
253
|
+
pendingRequests.delete(id);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
return { stream, headersPromise, id };
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// The preview's server, whose documents are served at this origin's root as
|
|
261
|
+
// they would be at their own origin: an app reads its routes from
|
|
262
|
+
// `location.pathname`, and a document under /__virtual__/<port>/ is not at
|
|
263
|
+
// the path its router expects.
|
|
264
|
+
let primaryPort = null;
|
|
265
|
+
// The page's own documents that are frames of it, told by `init`, so a
|
|
266
|
+
// nested document at one of these paths is the page's and not the preview's.
|
|
267
|
+
let ownDocuments = new Set();
|
|
268
|
+
// The documents and workers served from a virtual server at the root, by
|
|
269
|
+
// client id, so their requests reach that server without a prefix to read.
|
|
270
|
+
const rootedClients = new Map();
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* The virtual server a request outside /__virtual__/ is for, if any: the
|
|
274
|
+
* one a document under /__virtual__/<port>/ was served from (`prefix` set),
|
|
275
|
+
* or the one a document at the root was served from (`prefix` null). A
|
|
276
|
+
* frame's navigation to a path of this origin is the preview's server's
|
|
277
|
+
* when the path is not one of the page's own frame documents, which the
|
|
278
|
+
* page names at `init`. A request from a document
|
|
279
|
+
* or worker served at the root is remembered by its client id; after the
|
|
280
|
+
* worker restarts, a nested document at a path that is not the page's own
|
|
281
|
+
* is the preview's.
|
|
282
|
+
*/
|
|
283
|
+
async function virtualContext(event) {
|
|
284
|
+
const url = new URL(event.request.url);
|
|
285
|
+
let client = null;
|
|
286
|
+
if (event.clientId) {
|
|
287
|
+
try { client = await self.clients.get(event.clientId); } catch (e) { /* no client */ }
|
|
288
|
+
}
|
|
289
|
+
// A worker that restarted remembers no primary server and no rooted
|
|
290
|
+
// document. A request that could be the preview's, from a nested document
|
|
291
|
+
// or a frame's navigation, asks the page for its registrations first, as a
|
|
292
|
+
// virtual request asks for its port, so a restart does not send the
|
|
293
|
+
// preview's own requests to the network.
|
|
294
|
+
if (primaryPort === null && !mainPort && ((client && client.frameType === 'nested') || (event.request.mode === 'navigate' && (event.request.destination === 'iframe' || event.request.destination === 'frame')))) {
|
|
295
|
+
await askForInit();
|
|
296
|
+
}
|
|
297
|
+
const contextUrl = event.request.referrer || (client ? client.url : '');
|
|
298
|
+
if (contextUrl) {
|
|
299
|
+
try {
|
|
300
|
+
const contextMatch = new URL(contextUrl).pathname.match(/^\/__virtual__\/(\d+)/);
|
|
301
|
+
if (contextMatch) return { prefix: contextMatch[0], port: parseInt(contextMatch[1], 10) };
|
|
302
|
+
} catch (e) { /* not a URL */ }
|
|
303
|
+
}
|
|
304
|
+
if (event.clientId && rootedClients.has(event.clientId)) return { prefix: null, port: rootedClients.get(event.clientId) };
|
|
305
|
+
if (primaryPort === null) return null;
|
|
306
|
+
if (event.request.mode === 'navigate') {
|
|
307
|
+
if (event.request.destination !== 'iframe' && event.request.destination !== 'frame') return null;
|
|
308
|
+
if (ownDocuments.has(ownPath(url.pathname))) return null;
|
|
309
|
+
return { prefix: null, port: primaryPort };
|
|
310
|
+
}
|
|
311
|
+
if (client && client.frameType === 'nested' && !ownDocuments.has(ownPath(new URL(client.url).pathname))) return { prefix: null, port: primaryPort };
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/** A path as the page names its own documents: without a trailing slash. */
|
|
316
|
+
function ownPath(pathname) {
|
|
317
|
+
return pathname.length > 1 && pathname.endsWith('/') ? pathname.slice(0, -1) : pathname;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/** Asks every window for the page's registrations and waits for them, as a request waits for its port. */
|
|
321
|
+
async function askForInit() {
|
|
322
|
+
const allClients = await self.clients.matchAll({ type: 'window' });
|
|
323
|
+
for (const client of allClients) client.postMessage({ type: 'sw-needs-init' });
|
|
324
|
+
await new Promise((resolve) => {
|
|
325
|
+
const check = setInterval(() => { if (mainPort) { clearInterval(check); resolve(); } }, 50);
|
|
326
|
+
setTimeout(() => { clearInterval(check); resolve(); }, 5000);
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/** Answers a request for a virtual server at the root, remembering the document or worker it makes. */
|
|
331
|
+
function handleRootedRequest(event, port, path) {
|
|
332
|
+
if (event.resultingClientId) {
|
|
333
|
+
rootedClients.set(event.resultingClientId, port);
|
|
334
|
+
if (rootedClients.size > 256) pruneRootedClients();
|
|
335
|
+
}
|
|
336
|
+
return handleVirtualRequest(event.request, port, path, true);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/** Forgets the documents and workers that are gone. */
|
|
340
|
+
async function pruneRootedClients() {
|
|
341
|
+
const alive = new Set((await self.clients.matchAll({ type: 'all' })).map((client) => client.id));
|
|
342
|
+
for (const id of [...rootedClients.keys()]) if (!alive.has(id)) rootedClients.delete(id);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Intercept fetch requests
|
|
347
|
+
*/
|
|
348
|
+
self.addEventListener('fetch', (event) => {
|
|
349
|
+
const url = new URL(event.request.url);
|
|
350
|
+
|
|
351
|
+
DEBUG && console.log('[SW] Fetch:', url.pathname, 'mainPort:', !!mainPort);
|
|
352
|
+
|
|
353
|
+
// Check if this is a virtual server request
|
|
354
|
+
const match = url.pathname.match(/^\/__virtual__\/(\d+)(\/.*)?$/);
|
|
355
|
+
|
|
356
|
+
if (!match) {
|
|
357
|
+
// Not a virtual request, but perhaps from a virtual document: a plain
|
|
358
|
+
// <a href="/about">, an <img src="/x">, a fetch("/api/x") from a page
|
|
359
|
+
// under /__virtual__/<port>/ is that server's. The document is found by
|
|
360
|
+
// the request's client id, which every request from a document carries;
|
|
361
|
+
// the referrer, which a document sent with no referrer never has, is
|
|
362
|
+
// the fallback. A document at the root is the preview's server's, and
|
|
363
|
+
// its own requests are that server's with it.
|
|
364
|
+
if (event.request.referrer || event.clientId || (event.request.mode === 'navigate' && primaryPort !== null)) {
|
|
365
|
+
event.respondWith((async () => {
|
|
366
|
+
const context = await virtualContext(event);
|
|
367
|
+
if (!context) return fetch(event.request);
|
|
368
|
+
const targetPath = url.pathname + url.search;
|
|
369
|
+
if (context.prefix === null) {
|
|
370
|
+
DEBUG && console.log('[SW] Answering a root request from the virtual server:', url.pathname);
|
|
371
|
+
return handleRootedRequest(event, context.port, targetPath);
|
|
372
|
+
}
|
|
373
|
+
if (event.request.mode === 'navigate') {
|
|
374
|
+
DEBUG && console.log('[SW] Redirecting navigation from virtual context:', url.pathname);
|
|
375
|
+
return Response.redirect(url.origin + context.prefix + targetPath, 302);
|
|
376
|
+
}
|
|
377
|
+
DEBUG && console.log('[SW] Forwarding resource from virtual context:', url.pathname);
|
|
378
|
+
return handleVirtualRequest(event.request, context.port, targetPath);
|
|
379
|
+
})());
|
|
380
|
+
}
|
|
381
|
+
// Not a virtual request, let it pass through
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
DEBUG && console.log('[SW] Virtual request:', url.pathname);
|
|
386
|
+
|
|
387
|
+
const port = parseInt(match[1], 10);
|
|
388
|
+
const path = match[2] || '/';
|
|
389
|
+
|
|
390
|
+
event.respondWith(handleVirtualRequest(event.request, port, path + url.search));
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Handle a request to a virtual server
|
|
395
|
+
*/
|
|
396
|
+
async function handleVirtualRequest(request, port, path, rooted = false) {
|
|
397
|
+
try {
|
|
398
|
+
// Build headers object
|
|
399
|
+
const headers = {};
|
|
400
|
+
request.headers.forEach((value, key) => {
|
|
401
|
+
headers[key] = value;
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
// Get body if present
|
|
405
|
+
let body = null;
|
|
406
|
+
if (request.method !== 'GET' && request.method !== 'HEAD') {
|
|
407
|
+
body = await request.arrayBuffer();
|
|
408
|
+
// A body's length is a header Node's server always has, content-length
|
|
409
|
+
// or a chunked transfer-encoding; a fetch's headers carry neither, and
|
|
410
|
+
// Express 5's body parser takes their absence for no body at all.
|
|
411
|
+
if (body && body.byteLength > 0 && headers['content-length'] === undefined && headers['transfer-encoding'] === undefined) {
|
|
412
|
+
headers['content-length'] = String(body.byteLength);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Check if this is an API route that might stream (POST to /api/*)
|
|
417
|
+
const isStreamingCandidate = request.method === 'POST' && path.startsWith('/api/');
|
|
418
|
+
|
|
419
|
+
if (isStreamingCandidate) {
|
|
420
|
+
DEBUG && console.log('[SW] Using streaming mode for:', path);
|
|
421
|
+
return handleStreamingRequest(port, request.method, path, headers, body);
|
|
422
|
+
}
|
|
423
|
+
DEBUG && console.log('[SW] Using non-streaming mode for:', request.method, path);
|
|
424
|
+
|
|
425
|
+
// Send to main thread
|
|
426
|
+
const response = await sendRequest(port, request.method, path, headers, body);
|
|
427
|
+
|
|
428
|
+
DEBUG && console.log('[SW] Got response from main thread:', {
|
|
429
|
+
statusCode: response.statusCode,
|
|
430
|
+
headersKeys: response.headers ? Object.keys(response.headers) : [],
|
|
431
|
+
bodyBase64Length: response.bodyBase64?.length,
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// Decode base64 body and create response
|
|
435
|
+
let finalResponse;
|
|
436
|
+
if (response.bodyBase64 && response.bodyBase64.length > 0) {
|
|
437
|
+
try {
|
|
438
|
+
const bytes = base64ToBytes(response.bodyBase64);
|
|
439
|
+
DEBUG && console.log('[SW] Decoded body length:', bytes.length);
|
|
440
|
+
|
|
441
|
+
// Use Blob to ensure proper body handling
|
|
442
|
+
const blob = new Blob([bytes], { type: response.headers['Content-Type'] || 'application/octet-stream' });
|
|
443
|
+
DEBUG && console.log('[SW] Created blob size:', blob.size);
|
|
444
|
+
|
|
445
|
+
// Merge response headers with CORP/COEP headers to allow iframe embedding
|
|
446
|
+
// The parent page has COEP: credentialless, so we need matching headers
|
|
447
|
+
const respHeaders = new Headers(response.headers);
|
|
448
|
+
respHeaders.set('Cross-Origin-Embedder-Policy', 'credentialless');
|
|
449
|
+
respHeaders.set('Cross-Origin-Opener-Policy', 'same-origin');
|
|
450
|
+
respHeaders.set('Cross-Origin-Resource-Policy', 'cross-origin');
|
|
451
|
+
// Remove any headers that might block iframe loading
|
|
452
|
+
respHeaders.delete('X-Frame-Options');
|
|
453
|
+
|
|
454
|
+
finalResponse = new Response(blob, {
|
|
455
|
+
status: response.statusCode,
|
|
456
|
+
statusText: response.statusMessage,
|
|
457
|
+
headers: respHeaders,
|
|
458
|
+
});
|
|
459
|
+
} catch (decodeError) {
|
|
460
|
+
console.error('[SW] Failed to decode base64 body:', decodeError);
|
|
461
|
+
finalResponse = new Response(`Decode error: ${decodeError.message}`, {
|
|
462
|
+
status: 500,
|
|
463
|
+
headers: { 'Content-Type': 'text/plain' },
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
} else {
|
|
467
|
+
finalResponse = new Response(null, {
|
|
468
|
+
status: response.statusCode,
|
|
469
|
+
statusText: response.statusMessage,
|
|
470
|
+
headers: response.headers,
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
DEBUG && console.log('[SW] Final Response created, status:', finalResponse.status);
|
|
475
|
+
|
|
476
|
+
return finalResponse;
|
|
477
|
+
} catch (error) {
|
|
478
|
+
console.error('[SW] Error handling virtual request:', error);
|
|
479
|
+
return new Response(`Service Worker Error: ${error.message}`, {
|
|
480
|
+
status: 500,
|
|
481
|
+
statusText: 'Internal Server Error',
|
|
482
|
+
headers: { 'Content-Type': 'text/plain' },
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Handle a streaming request
|
|
489
|
+
*/
|
|
490
|
+
async function handleStreamingRequest(port, method, path, headers, body) {
|
|
491
|
+
const { stream, headersPromise, id } = await sendStreamingRequest(port, method, path, headers, body);
|
|
492
|
+
|
|
493
|
+
// Wait for headers to arrive
|
|
494
|
+
const responseData = await headersPromise;
|
|
495
|
+
|
|
496
|
+
DEBUG && console.log('[SW] Streaming response started:', responseData?.statusCode);
|
|
497
|
+
|
|
498
|
+
// Build response headers
|
|
499
|
+
const respHeaders = new Headers(responseData?.headers || {});
|
|
500
|
+
respHeaders.set('Cross-Origin-Embedder-Policy', 'credentialless');
|
|
501
|
+
respHeaders.set('Cross-Origin-Opener-Policy', 'same-origin');
|
|
502
|
+
respHeaders.set('Cross-Origin-Resource-Policy', 'cross-origin');
|
|
503
|
+
respHeaders.delete('X-Frame-Options');
|
|
504
|
+
|
|
505
|
+
return new Response(stream, {
|
|
506
|
+
status: responseData?.statusCode || 200,
|
|
507
|
+
statusText: responseData?.statusMessage || 'OK',
|
|
508
|
+
headers: respHeaders,
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Activate immediately
|
|
514
|
+
*/
|
|
515
|
+
self.addEventListener('install', (event) => {
|
|
516
|
+
DEBUG && console.log('[SW] Installing...');
|
|
517
|
+
event.waitUntil(self.skipWaiting());
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Claim all clients immediately
|
|
522
|
+
*/
|
|
523
|
+
self.addEventListener('activate', (event) => {
|
|
524
|
+
DEBUG && console.log('[SW] Activated');
|
|
525
|
+
event.waitUntil(self.clients.claim());
|
|
526
|
+
});
|