@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/src/runtime.ts
ADDED
|
@@ -0,0 +1,3073 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime - Execute user code with shimmed Node.js globals
|
|
3
|
+
*
|
|
4
|
+
* ESM to CJS transformation is now handled during npm install by transform.ts
|
|
5
|
+
* using esbuild-wasm. This runtime just executes the pre-transformed CJS code.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { VirtualFS } from './virtual-fs';
|
|
9
|
+
import { forGuestRealm, installGuestRealm, takeFromHost, defineOnHost, heldWork } from './host-globals';
|
|
10
|
+
import type { IRuntime, IExecuteResult, IRuntimeOptions } from './runtime-interface';
|
|
11
|
+
import type { PackageJson } from './types/package-json';
|
|
12
|
+
import { simpleHash } from './utils/hash';
|
|
13
|
+
import { uint8ToBase64, uint8ToHex } from './utils/binary-encoding';
|
|
14
|
+
import { createFsShim, FsShim } from './shims/fs';
|
|
15
|
+
import * as pathShim from './shims/path';
|
|
16
|
+
import { createProcess, Process, __reportUncaughtException } from './shims/process';
|
|
17
|
+
import {
|
|
18
|
+
httpModule, httpsModule, httpCommonModule, httpIncomingModule, httpOutgoingModule,
|
|
19
|
+
httpServerModule, httpClientModule, httpAgentModule,
|
|
20
|
+
} from './node-lib/http-module';
|
|
21
|
+
import { netModule as netShim } from './node-lib/net-module';
|
|
22
|
+
import { errname as __uvErrname } from './node-lib/binding/uv';
|
|
23
|
+
import { nodeTimeout, timerHandleOf } from './node-lib/timers';
|
|
24
|
+
import eventsShim from './node-lib/events-module';
|
|
25
|
+
import { streamModule as streamShim, streamPromisesModule as streamPromises } from './node-lib/stream-module';
|
|
26
|
+
import * as urlShim from './shims/url';
|
|
27
|
+
import utilShim from './node-lib/util-module';
|
|
28
|
+
import * as cryptoShim from './shims/crypto';
|
|
29
|
+
import * as stringDecoderShim from './shims/string_decoder';
|
|
30
|
+
import * as dnsShim from './shims/dns';
|
|
31
|
+
import { bufferModule as bufferShim } from './node-lib/buffer-module';
|
|
32
|
+
import { initChildProcess } from './shims/child_process';
|
|
33
|
+
import { childProcessModule as childProcessShim } from './node-lib/child-process-module';
|
|
34
|
+
import { getServerBridge } from './server-bridge';
|
|
35
|
+
import * as moduleShim from './shims/module';
|
|
36
|
+
import { RunModuleHooks, CJS_CONDITIONS } from './node-lib/module-hooks';
|
|
37
|
+
import { kRunFilesystem } from './node-lib/binding/fs';
|
|
38
|
+
import { esmNamespaceOf, syncBuiltinESMExports } from './node-lib/load';
|
|
39
|
+
import { fsModule, fsModuleFor } from './node-lib/fs-module';
|
|
40
|
+
import {
|
|
41
|
+
assertModule, querystringModule, punycodeModule, constantsModule,
|
|
42
|
+
diagnosticsChannelModule, osModule, ttyModule, readlineModule, readlinePromisesModule, zlibModule,
|
|
43
|
+
} from './node-lib/small-modules';
|
|
44
|
+
import { recordedProxies } from './node-lib/internals/util';
|
|
45
|
+
import { __nodeResolverFor } from './node-resolver';
|
|
46
|
+
import { Buffer as BufferPolyfill } from './node-lib/buffer-module';
|
|
47
|
+
import { PUNYCODE_SOURCE } from './punycode-source';
|
|
48
|
+
import * as perfHooksShim from './shims/perf_hooks';
|
|
49
|
+
import * as workerThreadsShim from './shims/worker_threads';
|
|
50
|
+
import * as esbuildShim from './shims/esbuild';
|
|
51
|
+
import * as rollupShim from './shims/rollup';
|
|
52
|
+
import * as v8Shim from './shims/v8';
|
|
53
|
+
import * as tlsShim from './shims/tls';
|
|
54
|
+
import * as http2Shim from './shims/http2';
|
|
55
|
+
import * as clusterShim from './shims/cluster';
|
|
56
|
+
import * as dgramShim from './shims/dgram';
|
|
57
|
+
import * as vmShim from './shims/vm';
|
|
58
|
+
import * as inspectorShim from './shims/inspector';
|
|
59
|
+
import * as asyncHooksShim from './shims/async_hooks';
|
|
60
|
+
import * as domainShim from './shims/domain';
|
|
61
|
+
import { createWasiModule, type WasiHostFs, type WasiModule } from './shims/wasi';
|
|
62
|
+
|
|
63
|
+
import { resolve as resolveExports, imports as resolveImports } from 'resolve.exports';
|
|
64
|
+
import { transformEsmToCjsSimple, setNodeLowering, __cjsExports, __substrateHasEsmSyntax } from './code-transforms';
|
|
65
|
+
import * as acorn from 'acorn';
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Walk an acorn AST recursively, calling the callback for every node.
|
|
69
|
+
*/
|
|
70
|
+
function walkAst(node: any, callback: (node: any) => void): void {
|
|
71
|
+
if (!node || typeof node !== 'object') return;
|
|
72
|
+
if (typeof node.type === 'string') {
|
|
73
|
+
callback(node);
|
|
74
|
+
}
|
|
75
|
+
for (const key of Object.keys(node)) {
|
|
76
|
+
if (key === 'type' || key === 'start' || key === 'end' || key === 'loc' || key === 'range') continue;
|
|
77
|
+
const child = node[key];
|
|
78
|
+
if (child && typeof child === 'object') {
|
|
79
|
+
if (Array.isArray(child)) {
|
|
80
|
+
for (const item of child) {
|
|
81
|
+
if (item && typeof item === 'object' && typeof item.type === 'string') {
|
|
82
|
+
walkAst(item, callback);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} else if (typeof child.type === 'string') {
|
|
86
|
+
walkAst(child, callback);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* On the in-page lane a guest module runs where the page's `document`,
|
|
94
|
+
* `window`, and `location` are in scope, so a package that asks
|
|
95
|
+
* `typeof document` to tell a browser from Node takes the browser path and
|
|
96
|
+
* fails on Node work. A Node program sees none of them; the module wrapper
|
|
97
|
+
* shadows them, and the guest's `globalThis` is a proxy over the host's that
|
|
98
|
+
* answers for them.
|
|
99
|
+
*/
|
|
100
|
+
const __substrateGuestGlobals = new WeakMap<Process, Record<string, unknown>>();
|
|
101
|
+
/**
|
|
102
|
+
* The timers a guest process has pending: what Node's loop counts to decide
|
|
103
|
+
* a program is done. A timer the guest sets through its global view is
|
|
104
|
+
* held here until it fires, is cleared, or is unref'd, and the `node`
|
|
105
|
+
* command's end-of-program rule asks how many remain.
|
|
106
|
+
*/
|
|
107
|
+
const __substratePendingTimers = new WeakMap<Process, Set<unknown>>();
|
|
108
|
+
export function pendingGuestTimers(process: Process): number {
|
|
109
|
+
return __substratePendingTimers.get(process)?.size ?? 0;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Clear every timer a guest still holds, as ending a Node process clears the
|
|
113
|
+
* ones its loop was waiting on. The ids were made by the host's own
|
|
114
|
+
* `setTimeout`/`setInterval` through the guest's global view, so the host's
|
|
115
|
+
* own clears end them; a `Timeout` is cleared by either in Node, and either
|
|
116
|
+
* refusing an id of the other kind is not an error here.
|
|
117
|
+
*/
|
|
118
|
+
export function stopGuestTimers(process: Process): void {
|
|
119
|
+
const held = __substratePendingTimers.get(process);
|
|
120
|
+
if (!held) return;
|
|
121
|
+
const host = globalThis as unknown as Record<string, unknown>;
|
|
122
|
+
const clearOnce = host.clearTimeout as ((id: unknown) => void) | undefined;
|
|
123
|
+
const clearRepeating = host.clearInterval as ((id: unknown) => void) | undefined;
|
|
124
|
+
for (const id of [...held]) {
|
|
125
|
+
try { clearOnce?.call(host, id); } catch {}
|
|
126
|
+
try { clearRepeating?.call(host, id); } catch {}
|
|
127
|
+
}
|
|
128
|
+
held.clear();
|
|
129
|
+
}
|
|
130
|
+
function __substrateTimerFunctions(process: Process, host: Record<string, unknown>): Record<string, unknown> {
|
|
131
|
+
let pending = __substratePendingTimers.get(process);
|
|
132
|
+
if (!pending) { pending = new Set(); __substratePendingTimers.set(process, pending); }
|
|
133
|
+
const held = pending;
|
|
134
|
+
const hostSetTimeout = host.setTimeout as (fn: (...a: unknown[]) => void, ms?: number, ...rest: unknown[]) => unknown;
|
|
135
|
+
const hostSetInterval = host.setInterval as (fn: (...a: unknown[]) => void, ms?: number, ...rest: unknown[]) => unknown;
|
|
136
|
+
const hostClearTimeout = host.clearTimeout as (id: unknown) => void;
|
|
137
|
+
const hostClearInterval = host.clearInterval as (id: unknown) => void;
|
|
138
|
+
// Node's timers answer a `Timeout`: an object with `ref`, `unref`,
|
|
139
|
+
// `hasRef` and `refresh`, which vitest and many packages call. A browser's
|
|
140
|
+
// answer a number. The engine used to correct this by replacing the realm's
|
|
141
|
+
// `setTimeout`, which in a Node host replaced the host's own; the
|
|
142
|
+
// correction belongs to the guest that reads Node's shape, so it is made
|
|
143
|
+
// here, on the guest's timer, and a host that already answers a `Timeout`
|
|
144
|
+
// keeps its own. The shape itself is `src/node-lib/timers.ts`: Node's own
|
|
145
|
+
// files take their timers from `require('timers')` rather than from the
|
|
146
|
+
// realm, and a timer made through one is cleared through the other.
|
|
147
|
+
const handleOf = timerHandleOf;
|
|
148
|
+
// An exception a timer callback throws is that program's uncaught
|
|
149
|
+
// exception: Node gives it to the process's `uncaughtException` listeners,
|
|
150
|
+
// else prints the stack to that process's stderr and exits it 1, and every
|
|
151
|
+
// other process is untouched. The engine's timers are the realm's own, so
|
|
152
|
+
// an uncaught throw left the guest's frames and reached the realm's global
|
|
153
|
+
// `error` event — in the tab the worker's, which the substrate's container
|
|
154
|
+
// reads as a dead host and disposes, killing openvscode-server's extension
|
|
155
|
+
// host and every other program in the tab along with the one that threw.
|
|
156
|
+
// A callback with no owning program (the engine imported as a library) is
|
|
157
|
+
// rethrown, so the host reports it as it always did.
|
|
158
|
+
const inProcess = (fn: (...a: unknown[]) => void) => (...args: unknown[]): void => {
|
|
159
|
+
try { fn(...args); }
|
|
160
|
+
catch (error) { if (!__reportUncaughtException(process, error)) throw error; }
|
|
161
|
+
};
|
|
162
|
+
const track = (id: unknown): unknown => {
|
|
163
|
+
held.add(id);
|
|
164
|
+
if (id && typeof id === "object" && typeof (id as { unref?: unknown }).unref === "function") {
|
|
165
|
+
const handle = id as { unref: () => unknown; ref: () => unknown };
|
|
166
|
+
const unref = handle.unref.bind(handle);
|
|
167
|
+
const ref = handle.ref.bind(handle);
|
|
168
|
+
handle.unref = () => { held.delete(id); return unref(); };
|
|
169
|
+
handle.ref = () => { held.add(id); return ref(); };
|
|
170
|
+
}
|
|
171
|
+
return id;
|
|
172
|
+
};
|
|
173
|
+
return {
|
|
174
|
+
setTimeout(fn: (...a: unknown[]) => void, ms?: number, ...rest: unknown[]) {
|
|
175
|
+
let id: unknown;
|
|
176
|
+
const call = inProcess(fn);
|
|
177
|
+
id = nodeTimeout(hostSetTimeout.call(host, (...args: unknown[]) => { held.delete(id); call(...args); }, ms, ...rest));
|
|
178
|
+
return track(id);
|
|
179
|
+
},
|
|
180
|
+
setInterval(fn: (...a: unknown[]) => void, ms?: number, ...rest: unknown[]) {
|
|
181
|
+
return track(nodeTimeout(hostSetInterval.call(host, inProcess(fn), ms, ...rest)));
|
|
182
|
+
},
|
|
183
|
+
clearTimeout(id: unknown) { held.delete(id); return hostClearTimeout.call(host, handleOf(id)); },
|
|
184
|
+
clearInterval(id: unknown) { held.delete(id); return hostClearInterval.call(host, handleOf(id)); },
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const __substrateAsyncFunction = (async function() {}).constructor;
|
|
188
|
+
const __substrateFunctionScope = Function("__substrateFunctionGlobals", "__substrateFunctionSource", "with (__substrateFunctionGlobals) { return eval('(' + __substrateFunctionSource + ')'); }");
|
|
189
|
+
function __substrateGuestConstructor(Constructor: unknown, process: Process): unknown {
|
|
190
|
+
if (Constructor !== Function && Constructor !== __substrateAsyncFunction) return Constructor;
|
|
191
|
+
return new Proxy(Constructor as object, { construct(target, args) {
|
|
192
|
+
const compiled = Reflect.construct(target as new (...args: unknown[]) => unknown, args);
|
|
193
|
+
return __substrateFunctionScope(__substrateGuestGlobal(process), String(compiled));
|
|
194
|
+
} });
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* The name the script of a module's body carries.
|
|
198
|
+
*
|
|
199
|
+
* Node compiles a module from its file, so every frame of its body names the
|
|
200
|
+
* file and counts the file's own lines. The engine evaluates a module's body,
|
|
201
|
+
* and V8 names an eval'd script only when the script says so: a
|
|
202
|
+
* `//# sourceURL=` directive at its end is the whole of it. Without one every
|
|
203
|
+
* stack a guest printed read `at eval (eval at runModuleBody (.../node-execution-worker.js:84621:17), <anonymous>:96:613)`
|
|
204
|
+
* — no file, and a line offset by the wrapper.
|
|
205
|
+
*
|
|
206
|
+
* A `file:` URL is named by the path it points at. A name a directive cannot
|
|
207
|
+
* hold — a `data:` module whose URL carries a line break — names nothing,
|
|
208
|
+
* since a broken directive would be read as code.
|
|
209
|
+
*/
|
|
210
|
+
function __substrateSourceURL(resolvedPath: string): string {
|
|
211
|
+
let name = resolvedPath;
|
|
212
|
+
if (name.startsWith('file://')) {
|
|
213
|
+
try { name = decodeURIComponent(new URL(name).pathname); } catch { /* a URL that will not parse names itself */ }
|
|
214
|
+
}
|
|
215
|
+
return /[\n\r]/u.test(name) ? '' : `\n//# sourceURL=${name}`;
|
|
216
|
+
}
|
|
217
|
+
function __substrateScopeConstructors(code: string): string {
|
|
218
|
+
if (!/\bnew\s/u.test(code)) return code;
|
|
219
|
+
let ast;
|
|
220
|
+
try { ast = acorn.parse(code, { ecmaVersion: "latest", sourceType: "module", allowReturnOutsideFunction: true }); }
|
|
221
|
+
catch { return code; }
|
|
222
|
+
const positions: Array<[number, number]> = [];
|
|
223
|
+
walkAst(ast, node => {
|
|
224
|
+
if (node.type === "NewExpression" && node.callee.type === "Identifier") positions.push([node.callee.start, node.callee.end]);
|
|
225
|
+
});
|
|
226
|
+
for (const [start, end] of positions.sort((a,b) => b[0] - a[0])) code = code.slice(0,start) + "(__substrateGuestConstructor(" + code.slice(start,end) + ",$process))" + code.slice(end);
|
|
227
|
+
return code;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Work the host is doing for a guest, counted while it is outstanding.
|
|
231
|
+
*
|
|
232
|
+
* Node keeps a process alive for its outstanding requests, not for its
|
|
233
|
+
* promises: `new Promise(() => {})` alone exits, while an awaited file read
|
|
234
|
+
* or a compile does not, because a request is pending underneath. The engine
|
|
235
|
+
* counts a guest's timers and its held work the same way, and a run ends when
|
|
236
|
+
* nothing is pending. What it never counted is the work the host does on a
|
|
237
|
+
* guest's behalf behind a promise, so a guest that wrote the ordinary thing,
|
|
238
|
+
* `await WebAssembly.instantiate(bytes)`, was ended mid-await and the line
|
|
239
|
+
* after it never ran: the shape every one of Node's WASI tests is written in,
|
|
240
|
+
* and the shape a napi-rs wasm loader uses. Such a call is this engine's
|
|
241
|
+
* analogue of one of those requests, and it holds the run while it is in
|
|
242
|
+
* flight, exactly as the engine's own esbuild and rollup work already does.
|
|
243
|
+
*/
|
|
244
|
+
function __substrateHeldAsync<T extends (...args: never[]) => Promise<unknown>>(call: T, host: unknown): T {
|
|
245
|
+
return function (this: unknown, ...args: Parameters<T>) {
|
|
246
|
+
const held = heldWork();
|
|
247
|
+
held.count += 1;
|
|
248
|
+
let settled: Promise<unknown>;
|
|
249
|
+
try { settled = call.apply(this === undefined ? host : this, args); }
|
|
250
|
+
catch (error) { held.count -= 1; throw error; }
|
|
251
|
+
if (!(settled instanceof Promise)) { held.count -= 1; return settled; }
|
|
252
|
+
return settled.finally(() => { held.count -= 1; });
|
|
253
|
+
} as T;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** The host namespaces whose asynchronous calls are work the guest is waiting on. */
|
|
257
|
+
const __substrateHeldNamespaces: Record<string, readonly string[]> = {
|
|
258
|
+
WebAssembly: ['compile', 'compileStreaming', 'instantiate', 'instantiateStreaming'],
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
function __substrateGuestGlobal(process: Process): Record<string, unknown> {
|
|
262
|
+
let guest = __substrateGuestGlobals.get(process);
|
|
263
|
+
if (guest) return guest;
|
|
264
|
+
const host = globalThis as unknown as Record<string, unknown>;
|
|
265
|
+
let fetch = host.fetch;
|
|
266
|
+
// The guest's `Buffer` is the one `require('buffer')` answers with, read
|
|
267
|
+
// when the guest asks rather than when this closure is made: the name in
|
|
268
|
+
// this file stands for the class until the loader has built it, and a guest
|
|
269
|
+
// that compared the two found two objects.
|
|
270
|
+
let buffer: unknown;
|
|
271
|
+
const boundGlobals = new Map<string | symbol, { original: unknown; bound: unknown }>();
|
|
272
|
+
// A key the guest defined that the host would not take (a name the host
|
|
273
|
+
// holds non-configurable, `navigator` under a worker's authority) lives on
|
|
274
|
+
// the proxy's own target, and is this guest's from then on.
|
|
275
|
+
const shadowed = (target: object, key: string | symbol): boolean => Reflect.getOwnPropertyDescriptor(target, key) !== undefined;
|
|
276
|
+
guest = new Proxy(Object.create(null), {
|
|
277
|
+
get(target, key) {
|
|
278
|
+
if (["document", "window", "location", "self"].includes(key as string)) return undefined;
|
|
279
|
+
if (key === "fetch") return fetch;
|
|
280
|
+
if (key === "Buffer") return buffer ?? bufferShim.Buffer;
|
|
281
|
+
if (key === "process") return process;
|
|
282
|
+
if (key === "globalThis" || key === "global") return guest;
|
|
283
|
+
if (shadowed(target, key)) return Reflect.get(target, key, guest);
|
|
284
|
+
const value = Reflect.get(host, key, host);
|
|
285
|
+
if (["setTimeout", "clearTimeout", "setInterval", "clearInterval"].includes(key as string) && typeof value === "function") {
|
|
286
|
+
// The guest's timers, counted for it; rebuilt if the host's own change.
|
|
287
|
+
if (boundGlobals.get(key)?.original !== value) {
|
|
288
|
+
const timers = __substrateTimerFunctions(process, host);
|
|
289
|
+
for (const name of ["setTimeout", "clearTimeout", "setInterval", "clearInterval"]) boundGlobals.set(name, { original: Reflect.get(host, name, host), bound: timers[name] });
|
|
290
|
+
}
|
|
291
|
+
return boundGlobals.get(key)!.bound;
|
|
292
|
+
}
|
|
293
|
+
// A namespace whose asynchronous calls the guest waits on: the calls are
|
|
294
|
+
// wrapped, everything else passes through, so `instanceof` and the
|
|
295
|
+
// synchronous constructors are the host's own.
|
|
296
|
+
const held = __substrateHeldNamespaces[key as string];
|
|
297
|
+
if (held !== undefined && value !== null && typeof value === "object") {
|
|
298
|
+
if (boundGlobals.get(key)?.original !== value) {
|
|
299
|
+
const namespace = value as Record<string, unknown>;
|
|
300
|
+
boundGlobals.set(key, { original: value, bound: new Proxy(namespace, {
|
|
301
|
+
get(target, name, receiver) {
|
|
302
|
+
const member = Reflect.get(target, name, receiver);
|
|
303
|
+
if (!held.includes(name as string) || typeof member !== "function") return member;
|
|
304
|
+
return __substrateHeldAsync(member as (...args: never[]) => Promise<unknown>, target);
|
|
305
|
+
},
|
|
306
|
+
}) });
|
|
307
|
+
}
|
|
308
|
+
return boundGlobals.get(key)!.bound;
|
|
309
|
+
}
|
|
310
|
+
if (["atob", "btoa", "structuredClone", "queueMicrotask"].includes(key as string) && typeof value === "function") {
|
|
311
|
+
if (boundGlobals.get(key)?.original !== value) boundGlobals.set(key, { original: value, bound: value.bind(host) });
|
|
312
|
+
return boundGlobals.get(key)!.bound;
|
|
313
|
+
}
|
|
314
|
+
return value;
|
|
315
|
+
},
|
|
316
|
+
set(target, key, value) {
|
|
317
|
+
if (key === "fetch") { fetch = value; return true; }
|
|
318
|
+
if (key === "Buffer") { buffer = value; return true; }
|
|
319
|
+
if (shadowed(target, key)) return Reflect.set(target, key, value, target);
|
|
320
|
+
return Reflect.set(host, key, value, host);
|
|
321
|
+
},
|
|
322
|
+
has(target, key) { return key === "global" || shadowed(target, key) || key in host; },
|
|
323
|
+
ownKeys(target) {
|
|
324
|
+
const keys = Reflect.ownKeys(target);
|
|
325
|
+
for (const key of Reflect.ownKeys(host)) if (!keys.includes(key)) keys.push(key);
|
|
326
|
+
return keys;
|
|
327
|
+
},
|
|
328
|
+
getOwnPropertyDescriptor(target, key) {
|
|
329
|
+
if (key === "fetch") return { value: fetch, writable: true, configurable: true, enumerable: true };
|
|
330
|
+
if (key === "Buffer") return { value: buffer ?? bufferShim.Buffer, writable: true, configurable: true, enumerable: true };
|
|
331
|
+
// A key the guest defined non-configurable lives on the proxy's own
|
|
332
|
+
// target as well, and is reported from there, as the proxy's
|
|
333
|
+
// invariants require.
|
|
334
|
+
const own = Reflect.getOwnPropertyDescriptor(target, key);
|
|
335
|
+
if (own) return own;
|
|
336
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(host, key);
|
|
337
|
+
return descriptor ? { ...descriptor, configurable: true } : undefined;
|
|
338
|
+
},
|
|
339
|
+
defineProperty(target, key, descriptor) {
|
|
340
|
+
if (key === "fetch") { if (!("value" in descriptor)) return false; fetch = descriptor.value; return true; }
|
|
341
|
+
if (key === "Buffer") { if (!("value" in descriptor)) return false; buffer = descriptor.value; return true; }
|
|
342
|
+
// A non-configurable define, undici's of its global dispatcher symbol,
|
|
343
|
+
// is defined on the proxy's own target too: a proxy may only claim a
|
|
344
|
+
// non-configurable property its target holds non-configurable, and
|
|
345
|
+
// the host global keeps every key configurable so a later guest can
|
|
346
|
+
// redefine it.
|
|
347
|
+
if (descriptor.configurable === false) {
|
|
348
|
+
if (!Reflect.defineProperty(target, key, descriptor)) return false;
|
|
349
|
+
Reflect.defineProperty(host, key, { ...descriptor, configurable: true });
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
if (Reflect.defineProperty(host, key, descriptor)) return true;
|
|
353
|
+
// The host refused (a name it holds non-configurable): the define is
|
|
354
|
+
// still the guest's to make on its own global, so the target takes it.
|
|
355
|
+
return Reflect.defineProperty(target, key, descriptor);
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
__substrateGuestGlobals.set(process, guest!);
|
|
359
|
+
return guest!;
|
|
360
|
+
}
|
|
361
|
+
// Node compiles a CommonJS body as sloppy script code: an assignment to a
|
|
362
|
+
// getter-only property is ignored rather than thrown, an undeclared assignment
|
|
363
|
+
// makes a global, and `this` at the top is `module.exports`. A direct `eval`
|
|
364
|
+
// from this module, and a module is always strict, made every guest body
|
|
365
|
+
// strict: lightningcss's `node/index.js` assigns three names onto the wasm
|
|
366
|
+
// build's namespace it had just re-exported, and the assignment threw where
|
|
367
|
+
// Node ignores it, so Tailwind's PostCSS plugin died under Next. The wrapper is
|
|
368
|
+
// compiled through this alias, which is an indirect eval: global scope, sloppy.
|
|
369
|
+
// The guest helpers are then out of scope by name, so they are arguments.
|
|
370
|
+
const __substrateSloppyEval = eval;
|
|
371
|
+
// An ES module stays strict, as Node keeps one: the lowering marks its output.
|
|
372
|
+
const __substrateModuleMarker = '/*__substrate_module__*/';
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Transform dynamic imports in code: import('x') -> __dynamicImport('x')
|
|
376
|
+
* Regex-based fallback for when AST parsing fails.
|
|
377
|
+
*/
|
|
378
|
+
function transformDynamicImportsRegex(code: string): string {
|
|
379
|
+
// A `#` before the word makes it a private name, never an import expression:
|
|
380
|
+
// happy-dom's module loader declares `#import()` and calls it, the declaration
|
|
381
|
+
// was renamed and the calls were not, and the class no longer declared the
|
|
382
|
+
// field its body used.
|
|
383
|
+
return code.replace(/(?<![.$\w#])import\s*\(/g, '__dynamicImport(');
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* All-in-one ESM to CJS transform using AST.
|
|
388
|
+
* Handles import/export declarations, import.meta, and dynamic imports in a single pass.
|
|
389
|
+
* Falls back to regex-based transforms if acorn can't parse the code.
|
|
390
|
+
*/
|
|
391
|
+
/**
|
|
392
|
+
* `import()` in a CommonJS module is Node's way of loading an ES module from
|
|
393
|
+
* one, and Next's server loads a project's config exactly so. The engine rewrote
|
|
394
|
+
* `import()` to its own loader only inside modules it lowered from ESM, so a
|
|
395
|
+
* CommonJS `.js` module's `import()` ran the host's, which has no view of the
|
|
396
|
+
* engine's filesystem. Every module the engine compiles gets the rewrite, and it
|
|
397
|
+
* is made from the module's syntax tree, never from its text: an `import(`
|
|
398
|
+
* inside a string is not an import, and Next's app loader writes
|
|
399
|
+
* `() => import("...")` into a template string that a text rewrite turned into
|
|
400
|
+
* the engine's loader call inside webpack's generated entry, where webpack then
|
|
401
|
+
* saw no import at all.
|
|
402
|
+
*/
|
|
403
|
+
function __substrateRewriteDynamicImportsInScript(code: string): string {
|
|
404
|
+
if (!/(?<![.$\w#])import\s*\(/.test(code)) return code;
|
|
405
|
+
let ast;
|
|
406
|
+
try {
|
|
407
|
+
ast = acorn.parse(code, { ecmaVersion: "latest", sourceType: "script", allowReturnOutsideFunction: true, allowHashBang: true, allowAwaitOutsideFunction: true });
|
|
408
|
+
} catch {
|
|
409
|
+
return code;
|
|
410
|
+
}
|
|
411
|
+
const replacements: Array<[number, number]> = [];
|
|
412
|
+
walkAst(ast, (node: any) => {
|
|
413
|
+
if (node.type === "ImportExpression") replacements.push([node.start, node.start + 6]);
|
|
414
|
+
});
|
|
415
|
+
if (replacements.length === 0) return code;
|
|
416
|
+
replacements.sort((a, b) => b[0] - a[0]);
|
|
417
|
+
let out = code;
|
|
418
|
+
for (const [start, end] of replacements) out = out.slice(0, start) + "__dynamicImport" + out.slice(end);
|
|
419
|
+
return out;
|
|
420
|
+
}
|
|
421
|
+
function transformEsmToCjs(code: string, filename: string): string {
|
|
422
|
+
// Quick check: does the code have any ESM-like patterns?
|
|
423
|
+
const maybeEsm = __substrateHasEsmSyntax(code);
|
|
424
|
+
if (!maybeEsm) return __substrateRewriteDynamicImportsInScript(code);
|
|
425
|
+
|
|
426
|
+
setNodeLowering(true);
|
|
427
|
+
try {
|
|
428
|
+
return transformEsmToCjsAst(code, filename);
|
|
429
|
+
} catch {
|
|
430
|
+
// Acorn can't parse — fall back to regex transforms
|
|
431
|
+
return transformEsmToCjsRegexFallback(code, filename);
|
|
432
|
+
} finally {
|
|
433
|
+
setNodeLowering(false);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* AST-based ESM to CJS transform. Parses once with acorn, then:
|
|
439
|
+
* 1. Replaces import.meta with import_meta (the wrapper-provided variable)
|
|
440
|
+
* 2. Replaces dynamic import() with __dynamicImport()
|
|
441
|
+
* 3. Transforms import/export declarations to require/exports
|
|
442
|
+
*
|
|
443
|
+
* Steps 1 & 2 use a deep AST walk (handles nodes inside functions/classes).
|
|
444
|
+
* Step 3 re-parses the modified code via transformEsmToCjsSimple.
|
|
445
|
+
*/
|
|
446
|
+
function transformEsmToCjsAst(code: string, filename: string): string {
|
|
447
|
+
const ast = acorn.parse(code, { ecmaVersion: 'latest', sourceType: 'module' }) as any;
|
|
448
|
+
|
|
449
|
+
// Collect deep replacements: import.meta → import_meta, import() → __dynamicImport()
|
|
450
|
+
const deepReplacements: Array<[number, number, string]> = [];
|
|
451
|
+
|
|
452
|
+
walkAst(ast, (node: any) => {
|
|
453
|
+
// import.meta → import_meta (variable provided by module wrapper)
|
|
454
|
+
if (node.type === 'MetaProperty' && node.meta?.name === 'import' && node.property?.name === 'meta') {
|
|
455
|
+
deepReplacements.push([node.start, node.end, 'import_meta']);
|
|
456
|
+
}
|
|
457
|
+
// import('x') → __dynamicImport('x')
|
|
458
|
+
if (node.type === 'ImportExpression') {
|
|
459
|
+
// Replace just the 'import' keyword, preserving the (...) part
|
|
460
|
+
deepReplacements.push([node.start, node.start + 6, '__dynamicImport']);
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
// Check for actual import/export declarations
|
|
465
|
+
const hasImportDecl = ast.body.some((n: any) => n.type === 'ImportDeclaration');
|
|
466
|
+
const hasExportDecl = ast.body.some((n: any) => n.type?.startsWith('Export'));
|
|
467
|
+
|
|
468
|
+
// Apply deep replacements from end to start (preserves earlier positions)
|
|
469
|
+
let transformed = code;
|
|
470
|
+
deepReplacements.sort((a, b) => b[0] - a[0]);
|
|
471
|
+
for (const [start, end, replacement] of deepReplacements) {
|
|
472
|
+
transformed = transformed.slice(0, start) + replacement + transformed.slice(end);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Transform import/export declarations (re-parses the modified code)
|
|
476
|
+
if (hasImportDecl || hasExportDecl) {
|
|
477
|
+
transformed = transformEsmToCjsSimple(transformed);
|
|
478
|
+
|
|
479
|
+
if (hasExportDecl) {
|
|
480
|
+
transformed = `Object.defineProperty(${__cjsExports()}, "__esModule", { value: true });\n` + transformed;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
return transformed;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Regex-based fallback for ESM to CJS transform (when acorn can't parse).
|
|
489
|
+
*/
|
|
490
|
+
function transformEsmToCjsRegexFallback(code: string, filename: string): string {
|
|
491
|
+
let transformed = code;
|
|
492
|
+
|
|
493
|
+
// Replace import.meta (regex — may match in strings, but this is the fallback)
|
|
494
|
+
transformed = transformed.replace(/\bimport\.meta\.url\b/g, `"file://${filename}"`);
|
|
495
|
+
transformed = transformed.replace(/\bimport\.meta\.dirname\b/g, `"${pathShim.dirname(filename)}"`);
|
|
496
|
+
transformed = transformed.replace(/\bimport\.meta\.filename\b/g, `"${filename}"`);
|
|
497
|
+
transformed = transformed.replace(/\bimport\.meta\b/g, `({ url: "file://${filename}", dirname: "${pathShim.dirname(filename)}", filename: "${filename}" })`);
|
|
498
|
+
|
|
499
|
+
// Replace dynamic imports
|
|
500
|
+
transformed = transformDynamicImportsRegex(transformed);
|
|
501
|
+
|
|
502
|
+
// Transform import/export (AST with its own regex fallback)
|
|
503
|
+
const hasImport = /\bimport\s+[\w{*'"]/m.test(code);
|
|
504
|
+
const hasExport = /\bexport\s+(?:default|const|let|var|function|class|{|\*)/m.test(code);
|
|
505
|
+
if (hasImport || hasExport) {
|
|
506
|
+
transformed = transformEsmToCjsSimple(transformed);
|
|
507
|
+
if (hasExport) {
|
|
508
|
+
transformed = `Object.defineProperty(${__cjsExports()}, "__esModule", { value: true });\n` + transformed;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
return transformed;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Create a dynamic import function for a module context
|
|
517
|
+
* Returns a function that wraps require() in a Promise
|
|
518
|
+
*/
|
|
519
|
+
/**
|
|
520
|
+
* A module whose body is still settling: one with a top-level `await`, or one
|
|
521
|
+
* importing such a module. Node evaluates a module graph in order and an
|
|
522
|
+
* importer's body runs after what it imports has settled; `import()` of it
|
|
523
|
+
* settles when it has. The loader runs such a body as an async function and
|
|
524
|
+
* keeps its promise on the exports under this symbol until it settles, where
|
|
525
|
+
* an importer's lowered import awaits it and a dynamic import does too. A
|
|
526
|
+
* synchronous `require` of a settling module still answers its exports as
|
|
527
|
+
* they are, where Node throws ERR_REQUIRE_ASYNC_MODULE.
|
|
528
|
+
*/
|
|
529
|
+
/**
|
|
530
|
+
* A `data:` URL whose media type is JavaScript is a module, as Node imports
|
|
531
|
+
* one: its payload evaluated as a module whose `import.meta.url` is the URL
|
|
532
|
+
* itself, cached by URL. Packages that compile a file in memory and import
|
|
533
|
+
* the result, import-from-string under vite-plugin-fake-server, depend on it.
|
|
534
|
+
*/
|
|
535
|
+
function __substrateDataModuleSource(url: string): string | undefined {
|
|
536
|
+
const match = /^data:([^,;]*)((?:;[^,]*)*),(.*)$/su.exec(url);
|
|
537
|
+
if (!match) return undefined;
|
|
538
|
+
const type = (match[1] || 'text/plain').toLowerCase();
|
|
539
|
+
if (!/^(?:text|application)\/(?:javascript|ecmascript|x-javascript)$/u.test(type)) {
|
|
540
|
+
throw Object.assign(new Error(`Unknown module format for data: URL of type ${type}`), { code: 'ERR_UNKNOWN_MODULE_FORMAT' });
|
|
541
|
+
}
|
|
542
|
+
const payload = match[3]!;
|
|
543
|
+
return /;base64/iu.test(match[2] ?? '')
|
|
544
|
+
? new TextDecoder().decode(Uint8Array.from(atob(payload), (character) => character.charCodeAt(0)))
|
|
545
|
+
: decodeURIComponent(payload);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
const __substratePending = Symbol.for('substrate.pending');
|
|
549
|
+
export function __substratePendingOf(value: unknown): Promise<void> | undefined {
|
|
550
|
+
if (value === null || (typeof value !== 'object' && typeof value !== 'function')) return undefined;
|
|
551
|
+
const pending = (value as Record<symbol, unknown>)[__substratePending];
|
|
552
|
+
return pending instanceof Promise ? pending : undefined;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* The module's body promise, kept on its exports until it settles; a body
|
|
556
|
+
* that failed forgets the module. Nothing here handles the rejection: an
|
|
557
|
+
* importer, a dynamic import or the program's runner awaits it, and a body
|
|
558
|
+
* nobody awaits fails as an unhandled rejection, which a program's runner
|
|
559
|
+
* reports, where Node prints the error and exits 1.
|
|
560
|
+
*/
|
|
561
|
+
function __substrateKeepPending(module: Module, body: Promise<unknown>, forget: () => void): void {
|
|
562
|
+
const exports = module.exports as Record<symbol, unknown>;
|
|
563
|
+
const holds = exports !== null && (typeof exports === 'object' || typeof exports === 'function');
|
|
564
|
+
const settled: Promise<void> = body.then(
|
|
565
|
+
() => { module.loaded = true; if (holds) delete exports[__substratePending]; },
|
|
566
|
+
(error: unknown) => { forget(); if (holds) delete exports[__substratePending]; throw error; },
|
|
567
|
+
);
|
|
568
|
+
if (holds) Object.defineProperty(exports, __substratePending, { value: settled, configurable: true, enumerable: false, writable: true });
|
|
569
|
+
}
|
|
570
|
+
const __substrateAwaitMarker = '/*__substrate_await__*/(';
|
|
571
|
+
/**
|
|
572
|
+
* A lowered ES module body runs as a generator: each import marker yields
|
|
573
|
+
* what the imported module is still settling on, if anything. The loader
|
|
574
|
+
* drives it synchronously, so a body whose imports have all settled runs
|
|
575
|
+
* through in one go, and a synchronous throw is thrown from the load, as
|
|
576
|
+
* Node's would be; a body that meets a settling import is continued once it
|
|
577
|
+
* has settled, and its own settling is what its importers await. The body's
|
|
578
|
+
* imports evaluate where they stand, once, in the body's own order.
|
|
579
|
+
*/
|
|
580
|
+
function __substrateGeneratorBody(wrappedCode: string): string {
|
|
581
|
+
return wrappedCode.replace('return (function() {', 'return (function* () {').replaceAll(__substrateAwaitMarker, 'yield (');
|
|
582
|
+
}
|
|
583
|
+
/** A body V8 refuses as a generator, a top-level `await` of its own, runs as an async function; the end of the body says it ran through. */
|
|
584
|
+
function __substrateAsyncBody(wrappedCode: string): string {
|
|
585
|
+
const at = wrappedCode.lastIndexOf('\n}).call(');
|
|
586
|
+
if (at < 0) throw new Error('module wrapper changed');
|
|
587
|
+
return wrappedCode.slice(0, at).replace('return (function() {', 'return (async function() {').replaceAll(__substrateAwaitMarker, 'await (')
|
|
588
|
+
+ '\n;$module.__substrateBodyDone = true;' + wrappedCode.slice(at);
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Drives a body: a generator runs until an import is still settling or the
|
|
592
|
+
* body is done; an async body's promise is its own. Returns what is still
|
|
593
|
+
* settling, or undefined when the body ran through.
|
|
594
|
+
*/
|
|
595
|
+
function __substrateDriveBody(kind: 'sync' | 'generator' | 'async', body: unknown, module: Module): Promise<unknown> | undefined {
|
|
596
|
+
if (kind === 'sync') return undefined;
|
|
597
|
+
if (kind === 'async') return (module as { __substrateBodyDone?: boolean }).__substrateBodyDone ? undefined : body as Promise<unknown>;
|
|
598
|
+
const iterator = body as Iterator<unknown>;
|
|
599
|
+
let step: IteratorResult<unknown> = iterator.next();
|
|
600
|
+
while (!step.done && !step.value) step = iterator.next();
|
|
601
|
+
if (step.done) return undefined;
|
|
602
|
+
return (async () => {
|
|
603
|
+
let current: IteratorResult<unknown> = step;
|
|
604
|
+
while (!current.done) {
|
|
605
|
+
await current.value;
|
|
606
|
+
current = iterator.next();
|
|
607
|
+
while (!current.done && !current.value) current = iterator.next();
|
|
608
|
+
}
|
|
609
|
+
})();
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* A dynamic import through the chain `module.register` built.
|
|
614
|
+
*
|
|
615
|
+
* This is where an asynchronous hook is consulted, because this is where the
|
|
616
|
+
* engine can await one: `import()` answers a promise in Node too. A static
|
|
617
|
+
* `import` is lowered to a synchronous `require` and never arrives here, so a
|
|
618
|
+
* hook that must see every specifier is registered with `registerHooks`,
|
|
619
|
+
* whose chain is synchronous and runs at both seams.
|
|
620
|
+
*/
|
|
621
|
+
async function __substrateImportThroughHooks(
|
|
622
|
+
hooks: RunModuleHooks,
|
|
623
|
+
id: string,
|
|
624
|
+
parentURL: string | undefined,
|
|
625
|
+
moduleRequire: RequireFunction,
|
|
626
|
+
): Promise<unknown> {
|
|
627
|
+
// A run with a module resolution outstanding is not idle. The chain can
|
|
628
|
+
// wait on anything -- VS Code's hook asks the main thread over a
|
|
629
|
+
// `MessagePort` and waits for the answer -- and the engine ends a run that
|
|
630
|
+
// holds no timer and no handle. It ended this one between the hook's
|
|
631
|
+
// question and its answer, so `import('vscode')` never settled and nothing
|
|
632
|
+
// said why. Node keeps its loop alive for a pending import; the engine
|
|
633
|
+
// holds the run for the same reason, and lets go however the chain ends.
|
|
634
|
+
const held = heldWork();
|
|
635
|
+
held.count += 1;
|
|
636
|
+
try {
|
|
637
|
+
return await __substrateImportChain(hooks, id, parentURL, moduleRequire);
|
|
638
|
+
} finally {
|
|
639
|
+
held.count -= 1;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
async function __substrateImportChain(
|
|
644
|
+
hooks: RunModuleHooks,
|
|
645
|
+
id: string,
|
|
646
|
+
parentURL: string | undefined,
|
|
647
|
+
moduleRequire: RequireFunction,
|
|
648
|
+
): Promise<unknown> {
|
|
649
|
+
const doors = moduleRequire as unknown as {
|
|
650
|
+
__resolveToURL: (specifier: string) => string;
|
|
651
|
+
__loadFromURL: (url: string, format?: string, source?: string | ArrayBuffer | ArrayBufferView | null) => unknown;
|
|
652
|
+
__readFromURL: (url: string) => string | null;
|
|
653
|
+
};
|
|
654
|
+
const resolved = hooks.hasAsyncResolve
|
|
655
|
+
? await hooks.resolve(id, parentURL, void 0, (specifier: string) => ({ url: doors.__resolveToURL(specifier) }))
|
|
656
|
+
: { url: doors.__resolveToURL(id), format: void 0 as string | undefined };
|
|
657
|
+
if (!hooks.hasAsyncLoad) return doors.__loadFromURL(resolved.url, resolved.format);
|
|
658
|
+
const loaded = await hooks.load(resolved.url, resolved.format, void 0, (url: string, context: { format?: string }) => ({
|
|
659
|
+
source: doors.__readFromURL(url),
|
|
660
|
+
format: context.format,
|
|
661
|
+
}));
|
|
662
|
+
return doors.__loadFromURL(resolved.url, loaded.format ?? resolved.format, loaded.source ?? void 0);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
function createDynamicImport(moduleRequire: RequireFunction, parentURL?: string): (specifier: unknown) => Promise<unknown> {
|
|
666
|
+
return async (specifier: unknown): Promise<unknown> => {
|
|
667
|
+
try {
|
|
668
|
+
// The specifier of `import()` undergoes ToString, as Node's does. ESLint's
|
|
669
|
+
// `loadFormatter` imports `pathToFileURL(formatterPath)` — a URL object —
|
|
670
|
+
// and the engine handed the object to require untouched, so the
|
|
671
|
+
// installed-wins check called `.startsWith` on it and `vite --host` died at
|
|
672
|
+
// `initializeESLint` with "id4.startsWith is not a function". A value whose
|
|
673
|
+
// conversion throws rejects the import, which is Node's answer too.
|
|
674
|
+
const id = typeof specifier === 'string' ? specifier : String(specifier);
|
|
675
|
+
// A dynamic import of a `file://` URL loads the file. Node takes a file
|
|
676
|
+
// URL in `import()`, and Vite loads a project's config by bundling it to
|
|
677
|
+
// a file beside it and importing that file by URL; handing the URL to
|
|
678
|
+
// require found no module by that name. `String(new URL(...))` is the
|
|
679
|
+
// href, so a URL object arrives at that branch as the same `file://` string.
|
|
680
|
+
const hooks = (moduleRequire as unknown as { __moduleHooks?: () => RunModuleHooks | undefined }).__moduleHooks?.();
|
|
681
|
+
const mod = hooks && (hooks.hasAsyncResolve || hooks.hasAsyncLoad)
|
|
682
|
+
? await __substrateImportThroughHooks(hooks, id, parentURL, moduleRequire)
|
|
683
|
+
: moduleRequire(id.startsWith('file://') ? decodeURIComponent(new URL(id).pathname) : id);
|
|
684
|
+
// A module still settling settles the import, as Node's does.
|
|
685
|
+
const pending = __substratePendingOf(mod);
|
|
686
|
+
if (pending) await pending;
|
|
687
|
+
|
|
688
|
+
// A lowered ES module already carries its named exports and `__esModule`.
|
|
689
|
+
// A CommonJS builtin does not: Node's ESM namespace is built from the
|
|
690
|
+
// module's own keys with `default` the module object. Spread of a lazy
|
|
691
|
+
// proxy copied none of those keys, so `(await import("https")).request`
|
|
692
|
+
// was undefined.
|
|
693
|
+
if (mod && typeof mod === 'object' && '__esModule' in (mod as object)) {
|
|
694
|
+
return mod;
|
|
695
|
+
}
|
|
696
|
+
return esmNamespaceOf(mod);
|
|
697
|
+
} catch (error) {
|
|
698
|
+
// Re-throw as a rejected promise (which is what dynamic import does)
|
|
699
|
+
throw error;
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
export interface Module {
|
|
705
|
+
id: string;
|
|
706
|
+
filename: string;
|
|
707
|
+
exports: unknown;
|
|
708
|
+
loaded: boolean;
|
|
709
|
+
children: Module[];
|
|
710
|
+
paths: string[];
|
|
711
|
+
/** The module that first required this one; null for the entry, as Node's is. */
|
|
712
|
+
parent?: Module | null;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
export interface RuntimeOptions {
|
|
716
|
+
cwd?: string;
|
|
717
|
+
env?: Record<string, string>;
|
|
718
|
+
onConsole?: (method: string, args: unknown[]) => void;
|
|
719
|
+
onStdout?: (data: string) => void;
|
|
720
|
+
onStderr?: (data: string) => void;
|
|
721
|
+
/** What is on the guest's fd 0, the way a shell puts the left of a pipe there. */
|
|
722
|
+
stdin?: string;
|
|
723
|
+
/** The runner can still write to fd 0, so standard input has not ended. */
|
|
724
|
+
stdinHeld?: boolean;
|
|
725
|
+
/** The run was given a TTY; a pipe child is not one. */
|
|
726
|
+
tty?: boolean;
|
|
727
|
+
/** This run's process number and its parent's; minted where neither is given. */
|
|
728
|
+
pid?: number;
|
|
729
|
+
ppid?: number;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
export interface RequireFunction {
|
|
733
|
+
(id: string): unknown;
|
|
734
|
+
resolve: (id: string) => string;
|
|
735
|
+
cache: Record<string, Module>;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* Create a basic timers module
|
|
740
|
+
*/
|
|
741
|
+
function createTimersModule() {
|
|
742
|
+
// Node's legacy timer list API, deprecated (DEP0095) and still exported:
|
|
743
|
+
// an object with `_onTimeout` is enrolled for a duration, made active to
|
|
744
|
+
// start or restart its countdown, and unenrolled to stop it.
|
|
745
|
+
type Enrolled = { _onTimeout?: () => void; _idleTimeout?: number; _idleTimeoutId?: ReturnType<typeof setTimeout> | null };
|
|
746
|
+
const unenroll = (item: Enrolled): void => {
|
|
747
|
+
if (item._idleTimeoutId) globalThis.clearTimeout(item._idleTimeoutId);
|
|
748
|
+
item._idleTimeoutId = null;
|
|
749
|
+
item._idleTimeout = -1;
|
|
750
|
+
};
|
|
751
|
+
const enroll = (item: Enrolled, msecs: number): void => {
|
|
752
|
+
if (item._idleTimeoutId) globalThis.clearTimeout(item._idleTimeoutId);
|
|
753
|
+
item._idleTimeoutId = null;
|
|
754
|
+
item._idleTimeout = msecs;
|
|
755
|
+
};
|
|
756
|
+
const active = (item: Enrolled): void => {
|
|
757
|
+
const msecs = item._idleTimeout;
|
|
758
|
+
if (typeof msecs !== 'number' || msecs < 0) return;
|
|
759
|
+
if (item._idleTimeoutId) globalThis.clearTimeout(item._idleTimeoutId);
|
|
760
|
+
item._idleTimeoutId = globalThis.setTimeout(() => { item._idleTimeoutId = null; if (typeof item._onTimeout === 'function') item._onTimeout(); }, msecs);
|
|
761
|
+
};
|
|
762
|
+
return {
|
|
763
|
+
setTimeout: globalThis.setTimeout,
|
|
764
|
+
setInterval: globalThis.setInterval,
|
|
765
|
+
setImmediate: (fn: () => void) => setTimeout(fn, 0),
|
|
766
|
+
clearTimeout: globalThis.clearTimeout,
|
|
767
|
+
clearInterval: globalThis.clearInterval,
|
|
768
|
+
clearImmediate: globalThis.clearTimeout,
|
|
769
|
+
active,
|
|
770
|
+
enroll,
|
|
771
|
+
unenroll,
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* Minimal prettier shim - just returns input unchanged
|
|
777
|
+
* This is needed because prettier uses createRequire which conflicts with our runtime
|
|
778
|
+
*/
|
|
779
|
+
const prettierShim = {
|
|
780
|
+
format: (source: string, _options?: unknown) => Promise.resolve(source),
|
|
781
|
+
formatWithCursor: (source: string, _options?: unknown) => Promise.resolve({ formatted: source, cursorOffset: 0 }),
|
|
782
|
+
check: (_source: string, _options?: unknown) => Promise.resolve(true),
|
|
783
|
+
resolveConfig: () => Promise.resolve(null),
|
|
784
|
+
resolveConfigFile: () => Promise.resolve(null),
|
|
785
|
+
clearConfigCache: () => {},
|
|
786
|
+
getFileInfo: () => Promise.resolve({ ignored: false, inferredParser: null }),
|
|
787
|
+
getSupportInfo: () => Promise.resolve({ languages: [], options: [] }),
|
|
788
|
+
version: '3.0.0',
|
|
789
|
+
doc: {
|
|
790
|
+
builders: {},
|
|
791
|
+
printer: {},
|
|
792
|
+
utils: {},
|
|
793
|
+
},
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
/**
|
|
797
|
+
* Create a mutable copy of a module for packages that need to patch it
|
|
798
|
+
* (e.g., Sentry needs to patch http.request/http.get)
|
|
799
|
+
*/
|
|
800
|
+
function makeMutable(mod: Record<string, unknown>): Record<string, unknown> {
|
|
801
|
+
const mutable: Record<string, unknown> = {};
|
|
802
|
+
for (const key of Object.keys(mod)) {
|
|
803
|
+
mutable[key] = mod[key];
|
|
804
|
+
}
|
|
805
|
+
return mutable;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
/**
|
|
809
|
+
* Built-in modules registry
|
|
810
|
+
*/
|
|
811
|
+
// Node's old `constants` module, and the groups `process.binding("constants")`
|
|
812
|
+
// serves it from, are one table in `shims/constants.ts`.
|
|
813
|
+
const __browserRuntimePunycode = (() => { const module = { exports: {} }; new Function("module", "exports", PUNYCODE_SOURCE)(module, module.exports); return module.exports; })();
|
|
814
|
+
/**
|
|
815
|
+
* Node's `stream/web` is the web streams the worker already has as globals; the
|
|
816
|
+
* table had no entry, so `file-type`, on Dub's middleware path, was "Cannot
|
|
817
|
+
* find module 'stream/web'". The module is those globals.
|
|
818
|
+
*/
|
|
819
|
+
/**
|
|
820
|
+
* Where a page registers the native side of an installed package for one
|
|
821
|
+
* filesystem: `vfs[__substrateNativeModules]` is a `Map` from a file the
|
|
822
|
+
* package's own exports name to a factory the guest's `require` calls with the
|
|
823
|
+
* asking process. The engine keeps resolution, the manifest and the version
|
|
824
|
+
* check with the installed package; the registration replaces only the module
|
|
825
|
+
* the resolved file would have produced, and only on the filesystem it was made
|
|
826
|
+
* for.
|
|
827
|
+
*/
|
|
828
|
+
const __substrateNativeModules = Symbol.for("@volter/browser-node/rolldown-modules");
|
|
829
|
+
/** `pkg:<name>@<version>/<path within the package>` for a file, from the nearest package.json above it; undefined outside a package. */
|
|
830
|
+
const __substrateIdentityCache = new WeakMap<object, Map<string, string | null>>();
|
|
831
|
+
function __substratePackageIdentity(vfs: VirtualFS, file: string): string | undefined {
|
|
832
|
+
let cache = __substrateIdentityCache.get(vfs);
|
|
833
|
+
if (!cache) { cache = new Map(); __substrateIdentityCache.set(vfs, cache); }
|
|
834
|
+
let directory = file.slice(0, file.lastIndexOf('/'));
|
|
835
|
+
const walked: string[] = [];
|
|
836
|
+
let found: string | null = null;
|
|
837
|
+
while (directory) {
|
|
838
|
+
const cached = cache.get(directory);
|
|
839
|
+
if (cached !== undefined) { found = cached; break; }
|
|
840
|
+
walked.push(directory);
|
|
841
|
+
const manifest = `${directory}/package.json`;
|
|
842
|
+
if (vfs.existsSync(manifest)) {
|
|
843
|
+
try {
|
|
844
|
+
const parsed = JSON.parse(vfs.readFileSync(manifest, 'utf8') as string) as { name?: unknown; version?: unknown };
|
|
845
|
+
if (typeof parsed.name === 'string' && typeof parsed.version === 'string') { found = `${directory}\u0000${parsed.name}@${parsed.version}`; break; }
|
|
846
|
+
} catch { /* not a package manifest */ }
|
|
847
|
+
}
|
|
848
|
+
if (directory.endsWith('/node_modules')) { found = null; break; }
|
|
849
|
+
directory = directory.slice(0, directory.lastIndexOf('/'));
|
|
850
|
+
}
|
|
851
|
+
for (const seen of walked) cache.set(seen, found);
|
|
852
|
+
if (!found) return undefined;
|
|
853
|
+
const [root, identity] = found.split('\u0000');
|
|
854
|
+
return `pkg:${identity}/${file.slice(root!.length + 1)}`;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
function __webStreamsModule(): Record<string, unknown> {
|
|
858
|
+
const module: Record<string, unknown> = {};
|
|
859
|
+
for (const name of ["ReadableStream", "ReadableStreamDefaultReader", "ReadableStreamBYOBReader", "ReadableStreamBYOBRequest", "ReadableByteStreamController", "ReadableStreamDefaultController", "TransformStream", "TransformStreamDefaultController", "WritableStream", "WritableStreamDefaultWriter", "WritableStreamDefaultController", "ByteLengthQueuingStrategy", "CountQueuingStrategy", "TextEncoderStream", "TextDecoderStream", "CompressionStream", "DecompressionStream"]) {
|
|
860
|
+
if (typeof (globalThis as Record<string, unknown>)[name] !== "undefined") module[name] = (globalThis as Record<string, unknown>)[name];
|
|
861
|
+
}
|
|
862
|
+
return module;
|
|
863
|
+
}
|
|
864
|
+
const builtinModules: Record<string, unknown> = {
|
|
865
|
+
constants: constantsModule,
|
|
866
|
+
punycode: punycodeModule,
|
|
867
|
+
"stream/web": __webStreamsModule(),
|
|
868
|
+
// Node's `path` is its posix object itself (path.js exports posix, and
|
|
869
|
+
// posix.posix === posix), so require('path') === require('path/posix').
|
|
870
|
+
path: pathShim.posix,
|
|
871
|
+
// Make http/https mutable so packages like Sentry can patch them
|
|
872
|
+
http: httpModule,
|
|
873
|
+
https: httpsModule,
|
|
874
|
+
_http_common: httpCommonModule,
|
|
875
|
+
_http_incoming: httpIncomingModule,
|
|
876
|
+
_http_outgoing: httpOutgoingModule,
|
|
877
|
+
_http_server: httpServerModule,
|
|
878
|
+
_http_client: httpClientModule,
|
|
879
|
+
_http_agent: httpAgentModule,
|
|
880
|
+
net: netShim,
|
|
881
|
+
events: eventsShim,
|
|
882
|
+
stream: streamShim,
|
|
883
|
+
// `stream/promises` is the promise form of pipeline and finished, as Node's.
|
|
884
|
+
'stream/promises': streamPromises,
|
|
885
|
+
buffer: bufferShim,
|
|
886
|
+
url: urlShim,
|
|
887
|
+
querystring: querystringModule,
|
|
888
|
+
util: utilShim,
|
|
889
|
+
tty: ttyModule,
|
|
890
|
+
os: osModule,
|
|
891
|
+
crypto: cryptoShim,
|
|
892
|
+
zlib: zlibModule,
|
|
893
|
+
dns: dnsShim,
|
|
894
|
+
child_process: childProcessShim,
|
|
895
|
+
assert: assertModule,
|
|
896
|
+
string_decoder: stringDecoderShim,
|
|
897
|
+
timers: createTimersModule(),
|
|
898
|
+
// `chokidar`, `readdirp`, `fsevents` and `ws` are not the engine's to
|
|
899
|
+
// answer. Each is an ordinary package over a builtin that is Node's own
|
|
900
|
+
// now, so a project installs it and it runs unchanged: a watcher over
|
|
901
|
+
// `fs.watch`, a WebSocket server over the `upgrade` a real socket carries.
|
|
902
|
+
// The engine's imitations answered those names before, and a program got a
|
|
903
|
+
// watcher and a server that were not the ones it had installed. `fsevents`
|
|
904
|
+
// is absent as it is on a Linux host, which is what chokidar checks for.
|
|
905
|
+
module: moduleShim,
|
|
906
|
+
perf_hooks: perfHooksShim,
|
|
907
|
+
worker_threads: workerThreadsShim,
|
|
908
|
+
esbuild: esbuildShim,
|
|
909
|
+
rollup: rollupShim,
|
|
910
|
+
v8: v8Shim,
|
|
911
|
+
readline: readlineModule,
|
|
912
|
+
tls: tlsShim,
|
|
913
|
+
http2: http2Shim,
|
|
914
|
+
cluster: clusterShim,
|
|
915
|
+
dgram: dgramShim,
|
|
916
|
+
vm: vmShim,
|
|
917
|
+
inspector: inspectorShim,
|
|
918
|
+
'inspector/promises': inspectorShim,
|
|
919
|
+
async_hooks: asyncHooksShim,
|
|
920
|
+
// `domain` stays the engine's own. Node's `domain.js` is a consumer of the
|
|
921
|
+
// async-hooks machinery -- it installs a trampoline the C++ layer calls to
|
|
922
|
+
// enter and leave a domain around every async callback -- and the engine
|
|
923
|
+
// has no such machinery, so the vendored file loads and then catches
|
|
924
|
+
// nothing, which is worse than an imitation that says what it is.
|
|
925
|
+
domain: domainShim,
|
|
926
|
+
diagnostics_channel: diagnosticsChannelModule,
|
|
927
|
+
// prettier uses createRequire which doesn't work in our runtime, so we shim it
|
|
928
|
+
prettier: prettierShim,
|
|
929
|
+
// Some packages explicitly require 'console' (with Console constructor)
|
|
930
|
+
console: {
|
|
931
|
+
...console,
|
|
932
|
+
Console: class Console {
|
|
933
|
+
private _stdout: { write: (s: string) => void } | null;
|
|
934
|
+
private _stderr: { write: (s: string) => void } | null;
|
|
935
|
+
constructor(options?: unknown) {
|
|
936
|
+
// Node's Console accepts (stdout, stderr) or { stdout, stderr }
|
|
937
|
+
const opts = options as Record<string, unknown> | undefined;
|
|
938
|
+
if (opts && typeof opts === 'object' && 'write' in opts) {
|
|
939
|
+
// new Console(stdout, stderr) — first arg is stdout stream
|
|
940
|
+
this._stdout = opts as unknown as { write: (s: string) => void };
|
|
941
|
+
this._stderr = (arguments[1] as { write: (s: string) => void }) || this._stdout;
|
|
942
|
+
} else if (opts && typeof opts === 'object' && 'stdout' in opts) {
|
|
943
|
+
// new Console({ stdout, stderr })
|
|
944
|
+
this._stdout = opts.stdout as { write: (s: string) => void } || null;
|
|
945
|
+
this._stderr = (opts.stderr as { write: (s: string) => void }) || this._stdout;
|
|
946
|
+
} else {
|
|
947
|
+
this._stdout = null;
|
|
948
|
+
this._stderr = null;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
private _write(stream: 'out' | 'err', args: unknown[]) {
|
|
952
|
+
const msg = args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ') + '\n';
|
|
953
|
+
const target = stream === 'err' ? this._stderr : this._stdout;
|
|
954
|
+
if (target) target.write(msg);
|
|
955
|
+
else if (stream === 'err') console.error(...args);
|
|
956
|
+
else console.log(...args);
|
|
957
|
+
}
|
|
958
|
+
log(...args: unknown[]) { this._write('out', args); }
|
|
959
|
+
error(...args: unknown[]) { this._write('err', args); }
|
|
960
|
+
warn(...args: unknown[]) { this._write('err', args); }
|
|
961
|
+
info(...args: unknown[]) { this._write('out', args); }
|
|
962
|
+
debug(...args: unknown[]) { this._write('out', args); }
|
|
963
|
+
trace(...args: unknown[]) { this._write('err', args); }
|
|
964
|
+
dir(obj: unknown) { this._write('out', [obj]); }
|
|
965
|
+
time(_label?: string) {}
|
|
966
|
+
timeEnd(_label?: string) {}
|
|
967
|
+
timeLog(_label?: string) {}
|
|
968
|
+
assert(value: unknown, ...args: unknown[]) { if (!value) this._write('err', ['Assertion failed:', ...args]); }
|
|
969
|
+
clear() {}
|
|
970
|
+
count(_label?: string) {}
|
|
971
|
+
countReset(_label?: string) {}
|
|
972
|
+
group(..._args: unknown[]) {}
|
|
973
|
+
groupCollapsed(..._args: unknown[]) {}
|
|
974
|
+
groupEnd() {}
|
|
975
|
+
table(data: unknown) { this._write('out', [data]); }
|
|
976
|
+
},
|
|
977
|
+
},
|
|
978
|
+
// util/types is accessed as a subpath
|
|
979
|
+
'util/types': utilShim.types,
|
|
980
|
+
// path subpaths: Node's own two flavours, the very objects path.posix and
|
|
981
|
+
// path.win32 name (Node's test-path-posix-exists.js asserts that identity).
|
|
982
|
+
'path/posix': pathShim.posix,
|
|
983
|
+
'path/win32': pathShim.win32,
|
|
984
|
+
// timers subpaths
|
|
985
|
+
'timers/promises': {
|
|
986
|
+
setTimeout: (ms: number) => new Promise(resolve => setTimeout(resolve, ms)),
|
|
987
|
+
setInterval: globalThis.setInterval,
|
|
988
|
+
setImmediate: (value?: unknown) => new Promise(resolve => setTimeout(() => resolve(value), 0)),
|
|
989
|
+
scheduler: { wait: (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) },
|
|
990
|
+
},
|
|
991
|
+
};
|
|
992
|
+
// Node's `assert/strict` is the module's own `strict` property, read when
|
|
993
|
+
// a guest asks rather than when this table is built -- `assert` is a lazy
|
|
994
|
+
// export and loading it here is a cycle with the loader.
|
|
995
|
+
Object.defineProperty(builtinModules, 'assert/strict', {
|
|
996
|
+
configurable: true,
|
|
997
|
+
enumerable: true,
|
|
998
|
+
get(): unknown { return (assertModule as { strict: unknown }).strict; },
|
|
999
|
+
});
|
|
1000
|
+
// Node's builtin module objects are ordinary mutable objects: a program can
|
|
1001
|
+
// patch `vm.runInContext` or `crypto.randomUUID`, and Next's environment
|
|
1002
|
+
// extensions and its error inspector do. Most shims are frozen module
|
|
1003
|
+
// namespaces, so the assignment threw. Every builtin the table holds is handed
|
|
1004
|
+
// out as a mutable copy, the way http and https already were.
|
|
1005
|
+
for (const __substrateName of Object.keys(builtinModules)) {
|
|
1006
|
+
const __substrateModule = builtinModules[__substrateName];
|
|
1007
|
+
if (__substrateModule && typeof __substrateModule === "object" && Object.isFrozen(__substrateModule)) builtinModules[__substrateName] = makeMutable(__substrateModule as Record<string, unknown>);
|
|
1008
|
+
}
|
|
1009
|
+
/** Every proxy the engine's realm made, so `util.types.isProxy` can name one. */
|
|
1010
|
+
function __browserRuntimeFillModules(table: Record<string, any>) {
|
|
1011
|
+
// A frozen shim cannot take the names it is missing, so the table gets a
|
|
1012
|
+
// copy carrying them; the shim's own mutable default object takes them too,
|
|
1013
|
+
// so an ESM default import and a require answer the same surface.
|
|
1014
|
+
const extend = (name: string, fills: Record<string, any>): any => {
|
|
1015
|
+
const base = table[name];
|
|
1016
|
+
if (!base) return null;
|
|
1017
|
+
const next = Object.assign({}, base, fills);
|
|
1018
|
+
if (base.default && typeof base.default === "object") {
|
|
1019
|
+
Object.assign(base.default, fills);
|
|
1020
|
+
next.default = base.default;
|
|
1021
|
+
}
|
|
1022
|
+
table[name] = next;
|
|
1023
|
+
return next;
|
|
1024
|
+
};
|
|
1025
|
+
const abortError = () => {
|
|
1026
|
+
const error = new Error("The operation was aborted") as Error & { code?: string };
|
|
1027
|
+
error.name = "AbortError";
|
|
1028
|
+
error.code = "ABORT_ERR";
|
|
1029
|
+
return error;
|
|
1030
|
+
};
|
|
1031
|
+
|
|
1032
|
+
// `path` needs no fills: Node's own lib/path.js carries toNamespacedPath,
|
|
1033
|
+
// matchesGlob, and the posix/win32 cross-links, and the module table points
|
|
1034
|
+
// at those objects directly so require("path/posix") === require("path").posix.
|
|
1035
|
+
|
|
1036
|
+
// `assert`'s loose half, its `strict` half, `AssertionError`,
|
|
1037
|
+
// `partialDeepStrictEqual` and the `assert/strict` module were written out
|
|
1038
|
+
// here over the engine's hand-written assert. `assert` is Node's own file
|
|
1039
|
+
// now and every one of them is Node's own code; `assert/strict` is the
|
|
1040
|
+
// module's own `strict` property, as it is in Node.
|
|
1041
|
+
|
|
1042
|
+
// The statics Node hangs off `EventEmitter` -- `errorMonitor`,
|
|
1043
|
+
// `captureRejections`, `defaultMaxListeners`, `setMaxListeners`,
|
|
1044
|
+
// `getMaxListeners`, `addAbortListener`, `EventEmitterAsyncResource` --
|
|
1045
|
+
// used to be written out here, over the engine's hand-written emitter.
|
|
1046
|
+
// `events` is Node's own file now and every one of them is Node's own code.
|
|
1047
|
+
|
|
1048
|
+
// `util.types` is Node's own now -- `util.js` exports the same
|
|
1049
|
+
// `internal/util/types` this engine binds -- so the forty-three predicates
|
|
1050
|
+
// that used to be written out here live in `node-lib/internals/util.ts`,
|
|
1051
|
+
// beside the reason each one answers the way it does. What stays here is
|
|
1052
|
+
// the realm's business: a guest's `Proxy` records what it makes, because
|
|
1053
|
+
// `isProxy` is the one predicate no tag can answer.
|
|
1054
|
+
forGuestRealm(() => {
|
|
1055
|
+
const NativeProxy = globalThis.Proxy as any;
|
|
1056
|
+
if (NativeProxy.__substrateProxies) return;
|
|
1057
|
+
const RecordedProxy = function Proxy(target: any, handler: any) {
|
|
1058
|
+
if (!new.target) throw new TypeError("Constructor Proxy requires 'new'");
|
|
1059
|
+
const proxy = new NativeProxy(target, handler);
|
|
1060
|
+
recordedProxies.add(proxy);
|
|
1061
|
+
return proxy;
|
|
1062
|
+
};
|
|
1063
|
+
RecordedProxy.revocable = (target: any, handler: any) => {
|
|
1064
|
+
const revocable = NativeProxy.revocable(target, handler);
|
|
1065
|
+
recordedProxies.add(revocable.proxy);
|
|
1066
|
+
return revocable;
|
|
1067
|
+
};
|
|
1068
|
+
Object.defineProperty(RecordedProxy, "__substrateProxies", { value: recordedProxies });
|
|
1069
|
+
takeFromHost(globalThis, "Proxy", RecordedProxy);
|
|
1070
|
+
});
|
|
1071
|
+
|
|
1072
|
+
// Node names a system error by its negative errno; the engine's constants
|
|
1073
|
+
// table already holds those numbers, so the map is read off it rather than
|
|
1074
|
+
// written down a second time.
|
|
1075
|
+
const errorNames = new Map();
|
|
1076
|
+
for (const [name, value] of Object.entries(table.constants || {})) {
|
|
1077
|
+
if (typeof value === "number" && /^E[A-Z0-9]+$/.test(name) && !errorNames.has(-value)) errorNames.set(-value, name);
|
|
1078
|
+
}
|
|
1079
|
+
// A number the constants table does not name is still one libuv names, and
|
|
1080
|
+
// the binding holds that table: `spawnSync` past `maxBuffer` reports
|
|
1081
|
+
// `ENOBUFS`, which the engine's own constants never carried.
|
|
1082
|
+
const systemErrorName = (errno: any) => errorNames.get(errno) || errorNames.get(-errno) || __uvErrname(errno);
|
|
1083
|
+
|
|
1084
|
+
// `util.parseArgs`, `util.isDeepStrictEqual`, `util.getSystemErrorName`,
|
|
1085
|
+
// `getSystemErrorMessage`, `getSystemErrorMap`, `toUSVString`, `aborted`
|
|
1086
|
+
// and `util.types` were all written out here, over the engine's
|
|
1087
|
+
// hand-written `util`. `util` is Node's own file now and every one of them
|
|
1088
|
+
// is Node's own code; `errorNames` above stays, because the engine's own
|
|
1089
|
+
// parts still name an errno.
|
|
1090
|
+
|
|
1091
|
+
// timers/promises.setInterval was the global setInterval, which answers a
|
|
1092
|
+
// handle rather than the async generator Node does, so "for await" over it
|
|
1093
|
+
// never yielded; setTimeout dropped the value it was given, and neither took
|
|
1094
|
+
// a signal.
|
|
1095
|
+
const timersPromises = {
|
|
1096
|
+
setTimeout: (delay: any, value: any, options: any) => new Promise((resolve, reject) => {
|
|
1097
|
+
const signal = options && options.signal;
|
|
1098
|
+
if (signal && signal.aborted) { reject(abortError()); return; }
|
|
1099
|
+
const onAbort = () => { clearTimeout(handle); reject(abortError()); };
|
|
1100
|
+
const handle = setTimeout(() => {
|
|
1101
|
+
if (signal) signal.removeEventListener("abort", onAbort);
|
|
1102
|
+
resolve(value);
|
|
1103
|
+
}, delay);
|
|
1104
|
+
if (signal) signal.addEventListener("abort", onAbort, { once: true });
|
|
1105
|
+
}),
|
|
1106
|
+
setImmediate: (value: any, options: any) => timersPromises.setTimeout(0, value, options),
|
|
1107
|
+
setInterval: async function* setInterval(delay: any, value: any, options: any) {
|
|
1108
|
+
const signal = options && options.signal;
|
|
1109
|
+
for (;;) {
|
|
1110
|
+
await timersPromises.setTimeout(delay, void 0, options);
|
|
1111
|
+
if (signal && signal.aborted) return;
|
|
1112
|
+
yield value;
|
|
1113
|
+
}
|
|
1114
|
+
},
|
|
1115
|
+
scheduler: {
|
|
1116
|
+
wait: (delay: any, options: any) => timersPromises.setTimeout(delay, void 0, options),
|
|
1117
|
+
yield: () => timersPromises.setTimeout(0, void 0, void 0)
|
|
1118
|
+
}
|
|
1119
|
+
};
|
|
1120
|
+
table["timers/promises"] = timersPromises;
|
|
1121
|
+
table.timers.promises = timersPromises;
|
|
1122
|
+
|
|
1123
|
+
// Node's punycode decoder, RFC 3492, so domainToUnicode answers the name a
|
|
1124
|
+
// person reads rather than the xn-- label: the engine dropped the punycode
|
|
1125
|
+
// module Node retired, and nothing else in a tab decodes one.
|
|
1126
|
+
const punycodeDecode = (input: any) => {
|
|
1127
|
+
const base = 36, tMin = 1, tMax = 26, skew = 38, damp = 700;
|
|
1128
|
+
const output = [];
|
|
1129
|
+
let index = input.lastIndexOf("-");
|
|
1130
|
+
if (index > 0) { for (let i = 0; i < index; i++) output.push(input.charCodeAt(i)); index++; } else index = 0;
|
|
1131
|
+
let n = 128, bias = 72, i = 0;
|
|
1132
|
+
while (index < input.length) {
|
|
1133
|
+
const start = i;
|
|
1134
|
+
for (let weight = 1, k = base; ; k += base) {
|
|
1135
|
+
if (index >= input.length) throw new RangeError("Invalid punycode input");
|
|
1136
|
+
const code = input.charCodeAt(index++);
|
|
1137
|
+
let digit;
|
|
1138
|
+
if (code >= 0x30 && code <= 0x39) digit = code - 0x30 + 26;
|
|
1139
|
+
else if (code >= 0x61 && code <= 0x7a) digit = code - 0x61;
|
|
1140
|
+
else if (code >= 0x41 && code <= 0x5a) digit = code - 0x41;
|
|
1141
|
+
else throw new RangeError("Invalid punycode input");
|
|
1142
|
+
i += digit * weight;
|
|
1143
|
+
const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
|
|
1144
|
+
if (digit < t) break;
|
|
1145
|
+
weight *= base - t;
|
|
1146
|
+
}
|
|
1147
|
+
const out = output.length + 1;
|
|
1148
|
+
let delta = i - start;
|
|
1149
|
+
delta = start === 0 ? Math.floor(delta / damp) : delta >> 1;
|
|
1150
|
+
delta += Math.floor(delta / out);
|
|
1151
|
+
let k = 0;
|
|
1152
|
+
for (; delta > ((base - tMin) * tMax) >> 1; k += base) delta = Math.floor(delta / (base - tMin));
|
|
1153
|
+
bias = Math.floor(k + ((base - tMin + 1) * delta) / (delta + skew));
|
|
1154
|
+
n += Math.floor(i / out);
|
|
1155
|
+
i %= out;
|
|
1156
|
+
output.splice(i++, 0, n);
|
|
1157
|
+
}
|
|
1158
|
+
return String.fromCodePoint(...output);
|
|
1159
|
+
};
|
|
1160
|
+
const urlModule = table.url;
|
|
1161
|
+
const URLClass = urlModule.URL || globalThis.URL;
|
|
1162
|
+
const domainToASCII = (domain: any) => {
|
|
1163
|
+
try { return new URLClass("http://" + String(domain)).hostname; } catch (error) { return ""; }
|
|
1164
|
+
};
|
|
1165
|
+
const domainToUnicode = (domain: any) => {
|
|
1166
|
+
const ascii = domainToASCII(domain);
|
|
1167
|
+
if (!ascii) return "";
|
|
1168
|
+
return ascii.split(".").map((label: any) => {
|
|
1169
|
+
if (!/^xn--/i.test(label)) return label;
|
|
1170
|
+
try { return punycodeDecode(label.slice(4)); } catch (error) { return label; }
|
|
1171
|
+
}).join(".");
|
|
1172
|
+
};
|
|
1173
|
+
function Url(this: any) {
|
|
1174
|
+
this.protocol = null; this.slashes = null; this.auth = null; this.host = null;
|
|
1175
|
+
this.port = null; this.hostname = null; this.hash = null; this.search = null;
|
|
1176
|
+
this.query = null; this.pathname = null; this.path = null; this.href = null;
|
|
1177
|
+
}
|
|
1178
|
+
const resolveObject = (from: any, to: any) => Object.assign(new (Url as any)(), urlModule.parse(urlModule.resolve(from, to)));
|
|
1179
|
+
Url.prototype.parse = function (this: any, input: any, parseQueryString: any, slashesDenoteHost: any) {
|
|
1180
|
+
return Object.assign(this, urlModule.parse(input, parseQueryString, slashesDenoteHost));
|
|
1181
|
+
};
|
|
1182
|
+
Url.prototype.format = function () { return urlModule.format(this); };
|
|
1183
|
+
Url.prototype.resolve = function (relative: any) { return urlModule.resolve(urlModule.format(this), relative); };
|
|
1184
|
+
Url.prototype.resolveObject = function (relative: any) { return resolveObject(urlModule.format(this), relative); };
|
|
1185
|
+
const urlFills: Record<string, any> = {
|
|
1186
|
+
Url,
|
|
1187
|
+
resolveObject,
|
|
1188
|
+
domainToASCII,
|
|
1189
|
+
domainToUnicode,
|
|
1190
|
+
urlToHttpOptions: (url: any) => {
|
|
1191
|
+
const hostname = typeof url.hostname === "string" && url.hostname.startsWith("[") ? url.hostname.slice(1, -1) : url.hostname;
|
|
1192
|
+
const options = {
|
|
1193
|
+
protocol: url.protocol,
|
|
1194
|
+
hostname,
|
|
1195
|
+
hash: url.hash,
|
|
1196
|
+
search: url.search,
|
|
1197
|
+
pathname: url.pathname,
|
|
1198
|
+
path: (url.pathname || "") + (url.search || ""),
|
|
1199
|
+
href: url.href
|
|
1200
|
+
} as Record<string, any>;
|
|
1201
|
+
if (url.port !== "" && url.port !== void 0 && url.port !== null) options.port = Number(url.port);
|
|
1202
|
+
if (url.username || url.password) options.auth = decodeURIComponent(url.username || "") + ":" + decodeURIComponent(url.password || "");
|
|
1203
|
+
return options;
|
|
1204
|
+
}
|
|
1205
|
+
};
|
|
1206
|
+
if (typeof URLPattern !== "undefined") urlFills.URLPattern = URLPattern;
|
|
1207
|
+
extend("url", urlFills);
|
|
1208
|
+
|
|
1209
|
+
extend("querystring", {
|
|
1210
|
+
// Node's unescapeBuffer answers the bytes behind the percent escapes, not
|
|
1211
|
+
// a string, so a caller decoding a body that is not UTF-8 keeps them.
|
|
1212
|
+
unescapeBuffer: (text: any, decodeSpaces: any) => {
|
|
1213
|
+
const bytes = [];
|
|
1214
|
+
const encoder = new TextEncoder();
|
|
1215
|
+
for (let i = 0; i < text.length; i++) {
|
|
1216
|
+
const ch = text[i];
|
|
1217
|
+
if (ch === "+" && decodeSpaces) { bytes.push(32); continue; }
|
|
1218
|
+
if (ch === "%" && i + 2 < text.length) {
|
|
1219
|
+
const value = parseInt(text.slice(i + 1, i + 3), 16);
|
|
1220
|
+
if (!Number.isNaN(value)) { bytes.push(value); i += 2; continue; }
|
|
1221
|
+
}
|
|
1222
|
+
for (const byte of encoder.encode(ch)) bytes.push(byte);
|
|
1223
|
+
}
|
|
1224
|
+
return BufferPolyfill.from(bytes);
|
|
1225
|
+
}
|
|
1226
|
+
});
|
|
1227
|
+
|
|
1228
|
+
// The buffer module's Blob and File are the tab's own; isUtf8 and isAscii
|
|
1229
|
+
// read the bytes, which is all Node's do.
|
|
1230
|
+
const bufferModule = table.buffer;
|
|
1231
|
+
bufferModule.Blob = globalThis.Blob;
|
|
1232
|
+
if (typeof globalThis.File !== "undefined") bufferModule.File = globalThis.File;
|
|
1233
|
+
bufferModule.kStringMaxLength = (bufferModule.constants && bufferModule.constants.MAX_STRING_LENGTH) || 536870888;
|
|
1234
|
+
bufferModule.isUtf8 = (input: any) => {
|
|
1235
|
+
const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
1236
|
+
try { new TextDecoder("utf-8", { fatal: true }).decode(bytes); return true; } catch (error) { return false; }
|
|
1237
|
+
};
|
|
1238
|
+
bufferModule.isAscii = (input: any) => {
|
|
1239
|
+
const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
1240
|
+
for (let i = 0; i < bytes.length; i++) if (bytes[i] > 127) return false;
|
|
1241
|
+
return true;
|
|
1242
|
+
};
|
|
1243
|
+
|
|
1244
|
+
extend("os", {
|
|
1245
|
+
// A tab reports the parallelism the browser gives it; a worker with no
|
|
1246
|
+
// navigator answers one, as Node does on a machine it cannot ask.
|
|
1247
|
+
availableParallelism: () => (typeof navigator === "object" && navigator && Number(navigator.hardwareConcurrency)) || 1
|
|
1248
|
+
});
|
|
1249
|
+
|
|
1250
|
+
// dns's error codes are the names a guest compares err.code against; the
|
|
1251
|
+
// engine had none of them, and dns/promises was not a module at all.
|
|
1252
|
+
const dnsCodes = {
|
|
1253
|
+
NODATA: "ENODATA", FORMERR: "EFORMERR", SERVFAIL: "ESERVFAIL", NOTFOUND: "ENOTFOUND",
|
|
1254
|
+
NOTIMP: "ENOTIMP", REFUSED: "EREFUSED", BADQUERY: "EBADQUERY", BADNAME: "EBADNAME",
|
|
1255
|
+
BADFAMILY: "EBADFAMILY", BADRESP: "EBADRESP", CONNREFUSED: "ECONNREFUSED", TIMEOUT: "ETIMEOUT",
|
|
1256
|
+
EOF: "EOF", FILE: "EFILE", NOMEM: "ENOMEM", DESTRUCTION: "EDESTRUCTION", BADSTR: "EBADSTR",
|
|
1257
|
+
BADFLAGS: "EBADFLAGS", NONAME: "ENONAME", BADHINTS: "EBADHINTS", NOTINITIALIZED: "ENOTINITIALIZED",
|
|
1258
|
+
LOADIPHLPAPI: "ELOADIPHLPAPI", ADDRGETNETWORKPARAMS: "EADDRGETNETWORKPARAMS", CANCELLED: "ECANCELLED"
|
|
1259
|
+
};
|
|
1260
|
+
const dnsModule = extend("dns", dnsCodes);
|
|
1261
|
+
const dnsPromises = Object.assign({}, dnsModule.promises, dnsCodes);
|
|
1262
|
+
dnsPromises.default = dnsPromises;
|
|
1263
|
+
dnsModule.promises = dnsPromises;
|
|
1264
|
+
table["dns/promises"] = dnsPromises;
|
|
1265
|
+
|
|
1266
|
+
// readline/promises was not a module, and the engine's readline.promises
|
|
1267
|
+
// answered an object with only createInterface on it whose async iterator
|
|
1268
|
+
// yielded nothing, so "for await (const line of rl)" ended at once.
|
|
1269
|
+
const readlineModule = table.readline;
|
|
1270
|
+
class PromisesInterface {
|
|
1271
|
+
[key: string]: any;
|
|
1272
|
+
constructor(options: any) {
|
|
1273
|
+
this.input = options && options.input;
|
|
1274
|
+
this.output = options && options.output;
|
|
1275
|
+
this._interface = readlineModule.createInterface(options);
|
|
1276
|
+
}
|
|
1277
|
+
question(query: any, options: any) {
|
|
1278
|
+
const signal = options && options.signal;
|
|
1279
|
+
return new Promise((resolve, reject) => {
|
|
1280
|
+
if (signal && signal.aborted) { reject(abortError()); return; }
|
|
1281
|
+
if (signal) signal.addEventListener("abort", () => reject(abortError()), { once: true });
|
|
1282
|
+
this._interface.question(query, resolve);
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1285
|
+
close() { return this._interface.close(); }
|
|
1286
|
+
pause() { if (typeof this._interface.pause === "function") this._interface.pause(); return this; }
|
|
1287
|
+
resume() { if (typeof this._interface.resume === "function") this._interface.resume(); return this; }
|
|
1288
|
+
write(data: any, key: any) { return this._interface.write(data, key); }
|
|
1289
|
+
getCursorPos() { return this._interface.getCursorPos(); }
|
|
1290
|
+
on(event: any, listener: any) { this._interface.on(event, listener); return this; }
|
|
1291
|
+
once(event: any, listener: any) { this._interface.once(event, listener); return this; }
|
|
1292
|
+
off(event: any, listener: any) { this._interface.removeListener(event, listener); return this; }
|
|
1293
|
+
removeListener(event: any, listener: any) { this._interface.removeListener(event, listener); return this; }
|
|
1294
|
+
[Symbol.asyncIterator]() {
|
|
1295
|
+
const lines: any[] = [];
|
|
1296
|
+
let closed = false;
|
|
1297
|
+
let wake: any = null;
|
|
1298
|
+
const bump = () => { const resume = wake; wake = null; if (resume) resume(); };
|
|
1299
|
+
this._interface.on("line", (line: any) => { lines.push(line); bump(); });
|
|
1300
|
+
this._interface.on("close", () => { closed = true; bump(); });
|
|
1301
|
+
return {
|
|
1302
|
+
[Symbol.asyncIterator]() { return this; },
|
|
1303
|
+
async next() {
|
|
1304
|
+
for (;;) {
|
|
1305
|
+
if (lines.length > 0) return { value: lines.shift(), done: false };
|
|
1306
|
+
if (closed) return { value: void 0, done: true };
|
|
1307
|
+
await new Promise((resolve) => { wake = resolve; });
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
// Node's Readline queues its cursor and clear escapes and writes them on commit.
|
|
1314
|
+
class Readline {
|
|
1315
|
+
[key: string]: any;
|
|
1316
|
+
constructor(stream: any, options: any) {
|
|
1317
|
+
this._stream = stream;
|
|
1318
|
+
this._autoCommit = !!(options && options.autoCommit);
|
|
1319
|
+
this._queue = [];
|
|
1320
|
+
}
|
|
1321
|
+
_queueEscape(text: any) {
|
|
1322
|
+
this._queue.push(text);
|
|
1323
|
+
return this._autoCommit ? this.commit() : this;
|
|
1324
|
+
}
|
|
1325
|
+
clearLine(dir: any) { return this._queueEscape("\u001b[" + (dir < 0 ? "1K" : dir > 0 ? "0K" : "2K")); }
|
|
1326
|
+
clearScreenDown() { return this._queueEscape("\u001b[0J"); }
|
|
1327
|
+
cursorTo(x: any, y: any) { return this._queueEscape(y === void 0 ? "\u001b[" + (x + 1) + "G" : "\u001b[" + (y + 1) + ";" + (x + 1) + "H"); }
|
|
1328
|
+
moveCursor(dx: any, dy: any) {
|
|
1329
|
+
let text = "";
|
|
1330
|
+
if (dx < 0) text += "\u001b[" + -dx + "D"; else if (dx > 0) text += "\u001b[" + dx + "C";
|
|
1331
|
+
if (dy < 0) text += "\u001b[" + -dy + "A"; else if (dy > 0) text += "\u001b[" + dy + "B";
|
|
1332
|
+
return this._queueEscape(text);
|
|
1333
|
+
}
|
|
1334
|
+
rollback() { this._queue = []; return this; }
|
|
1335
|
+
async commit() {
|
|
1336
|
+
const text = this._queue.join("");
|
|
1337
|
+
this._queue = [];
|
|
1338
|
+
if (text && this._stream && typeof this._stream.write === "function") this._stream.write(text);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
const readlinePromises = {
|
|
1342
|
+
Interface: PromisesInterface,
|
|
1343
|
+
Readline,
|
|
1344
|
+
createInterface: (options: any) => new PromisesInterface(options)
|
|
1345
|
+
} as Record<string, any>;
|
|
1346
|
+
readlinePromises.default = readlinePromises;
|
|
1347
|
+
table["readline/promises"] = readlinePromises;
|
|
1348
|
+
extend("readline", { promises: readlinePromises });
|
|
1349
|
+
|
|
1350
|
+
// `zlib`'s streaming classes were written out here, over the engine's
|
|
1351
|
+
// one-shot functions: each gathered its whole input and ran the one-shot at
|
|
1352
|
+
// flush, so the bytes were right and the streaming was not. `zlib` is
|
|
1353
|
+
// Node's own file now, on zlib's own inflate and deflate, and every class
|
|
1354
|
+
// it exports is a real streaming codec.
|
|
1355
|
+
|
|
1356
|
+
}
|
|
1357
|
+
/**
|
|
1358
|
+
* `stream/consumers`: the one module beside `stream` that Node ships and this
|
|
1359
|
+
* lane did not vendor -- four functions that read a whole stream into a
|
|
1360
|
+
* string, a Buffer, JSON or a Blob. Everything else the engine used to fill in
|
|
1361
|
+
* here (`pipeline`, `finished`, `stream/promises`, the `toWeb` statics, an
|
|
1362
|
+
* async iterator on a Readable, `duplexPair`, `isDisturbed`, the high-water
|
|
1363
|
+
* marks) is Node's own file's now and is gone.
|
|
1364
|
+
*/
|
|
1365
|
+
function __browserRuntimeFillStreams(table: Record<string, any>) {
|
|
1366
|
+
const Bytes = BufferPolyfill;
|
|
1367
|
+
const collect = async (source: any) => {
|
|
1368
|
+
const chunks: any[] = [];
|
|
1369
|
+
if (source && typeof source.getReader === "function") {
|
|
1370
|
+
const reader = source.getReader();
|
|
1371
|
+
for (;;) {
|
|
1372
|
+
const step = await reader.read();
|
|
1373
|
+
if (step.done) break;
|
|
1374
|
+
chunks.push(Bytes.from(step.value));
|
|
1375
|
+
}
|
|
1376
|
+
} else if (source && typeof source[Symbol.asyncIterator] === "function") {
|
|
1377
|
+
for await (const chunk of source) chunks.push(typeof chunk === "string" ? Bytes.from(chunk) : Bytes.from(chunk));
|
|
1378
|
+
} else if (source && typeof source[Symbol.iterator] === "function") {
|
|
1379
|
+
for (const chunk of source) chunks.push(typeof chunk === "string" ? Bytes.from(chunk) : Bytes.from(chunk));
|
|
1380
|
+
} else {
|
|
1381
|
+
throw new TypeError("The stream argument must be a stream or an iterable");
|
|
1382
|
+
}
|
|
1383
|
+
return Bytes.concat(chunks);
|
|
1384
|
+
};
|
|
1385
|
+
table["stream/consumers"] = {
|
|
1386
|
+
arrayBuffer: async (source: any) => {
|
|
1387
|
+
const bytes = await collect(source);
|
|
1388
|
+
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
1389
|
+
},
|
|
1390
|
+
blob: async (source: any) => new Blob([new Uint8Array(await collect(source))]),
|
|
1391
|
+
buffer: collect,
|
|
1392
|
+
bytes: async (source: any) => new Uint8Array(await collect(source)),
|
|
1393
|
+
json: async (source: any) => JSON.parse((await collect(source)).toString("utf8")),
|
|
1394
|
+
text: async (source: any) => (await collect(source)).toString("utf8")
|
|
1395
|
+
};
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
__browserRuntimeFillStreams(builtinModules);
|
|
1399
|
+
|
|
1400
|
+
__browserRuntimeFillModules(builtinModules);
|
|
1401
|
+
|
|
1402
|
+
/**
|
|
1403
|
+
* A shared esbuild or rollup shim must use the calling guest's cwd, even after
|
|
1404
|
+
* awaits. One shim instance serves every guest in the tab, so a build the guest
|
|
1405
|
+
* started with a relative entry resolved that entry against whatever directory
|
|
1406
|
+
* the tab happened to be in once the await resumed, and the build failed on a
|
|
1407
|
+
* file that was right there. Each guest process gets its own bound copy.
|
|
1408
|
+
*/
|
|
1409
|
+
type RollupInput = string | string[] | Record<string, string> | undefined;
|
|
1410
|
+
type RollupOptions = { input?: RollupInput; fs?: unknown; [key: string]: unknown };
|
|
1411
|
+
type RollupOutputOptions = { dir?: string; file?: string; [key: string]: unknown };
|
|
1412
|
+
type RollupBundle = Record<string, (output?: RollupOutputOptions) => unknown>;
|
|
1413
|
+
type RollupModule = { rollup: (options: RollupOptions) => Promise<RollupBundle>; [key: string]: unknown };
|
|
1414
|
+
type EsbuildOptions = { absWorkingDir?: string; tsconfig?: string; tsconfigRaw?: string; [key: string]: unknown };
|
|
1415
|
+
type EsbuildModule = { [key: string]: unknown };
|
|
1416
|
+
|
|
1417
|
+
const __substrateGuestBundlers = new WeakMap<Process, EsbuildModule>();
|
|
1418
|
+
// `wasi` is a per-guest builtin, as fs and process are: its WASI class runs a
|
|
1419
|
+
// wasm program over the guest's own filesystem and stdio, so each guest
|
|
1420
|
+
// process gets Node's `lib/wasi.js` evaluated once on a binding to its own.
|
|
1421
|
+
const __substrateGuestWasis = new WeakMap<Process, WasiModule>();
|
|
1422
|
+
function __substrateGuestWasi(fsShim: FsShim, process: Process): WasiModule {
|
|
1423
|
+
let module = __substrateGuestWasis.get(process);
|
|
1424
|
+
if (module === undefined) {
|
|
1425
|
+
module = createWasiModule(fsShim as unknown as WasiHostFs, process);
|
|
1426
|
+
__substrateGuestWasis.set(process, module);
|
|
1427
|
+
}
|
|
1428
|
+
return module;
|
|
1429
|
+
}
|
|
1430
|
+
const __substrateGuestRollups = new WeakMap<Process, RollupModule>();
|
|
1431
|
+
let currentVfs: VirtualFS | null = null;
|
|
1432
|
+
function __substrateGuestRollup(process: Process): RollupModule {
|
|
1433
|
+
let bound = __substrateGuestRollups.get(process);
|
|
1434
|
+
if (bound) return bound;
|
|
1435
|
+
const original = builtinModules.rollup as RollupModule;
|
|
1436
|
+
bound = { ...original, rollup: async (options: RollupOptions = {}) => {
|
|
1437
|
+
const cwd = process.cwd();
|
|
1438
|
+
const resolve = (path: string) => {
|
|
1439
|
+
if (path.startsWith(String.fromCharCode(0))) return path;
|
|
1440
|
+
const parts: string[] = [];
|
|
1441
|
+
for (const part of (path.startsWith("/") ? path : cwd + "/" + path).split("/")) {
|
|
1442
|
+
if (part === "..") parts.pop(); else if (part && part !== ".") parts.push(part);
|
|
1443
|
+
}
|
|
1444
|
+
return "/" + parts.join("/");
|
|
1445
|
+
};
|
|
1446
|
+
const input = typeof options.input === "string" ? resolve(options.input)
|
|
1447
|
+
: Array.isArray(options.input) ? options.input.map(resolve)
|
|
1448
|
+
: options.input ? Object.fromEntries(Object.entries(options.input).map(([name,path]) => [name,resolve(path)])) : options.input;
|
|
1449
|
+
const fs = options.fs ?? (globalThis as { __browserRuntimeRollupFs?: unknown }).__browserRuntimeRollupFs;
|
|
1450
|
+
const bundle = await original.rollup({ ...options, input, ...(fs ? { fs } : {}) });
|
|
1451
|
+
for (const name of ["generate", "write"]) {
|
|
1452
|
+
const action = bundle[name].bind(bundle);
|
|
1453
|
+
bundle[name] = (output: RollupOutputOptions = {}) => action({ ...output, ...(output.dir ? { dir: resolve(output.dir) } : {}), ...(output.file ? { file: resolve(output.file) } : {}) });
|
|
1454
|
+
}
|
|
1455
|
+
return bundle;
|
|
1456
|
+
} };
|
|
1457
|
+
bound.default = bound;
|
|
1458
|
+
__substrateGuestRollups.set(process,bound);
|
|
1459
|
+
return bound;
|
|
1460
|
+
}
|
|
1461
|
+
function __substrateGuestEsbuild(process: Process): EsbuildModule {
|
|
1462
|
+
let bound = __substrateGuestBundlers.get(process);
|
|
1463
|
+
if (bound) return bound;
|
|
1464
|
+
const original = builtinModules.esbuild as Record<string, (options: EsbuildOptions) => unknown>;
|
|
1465
|
+
bound = { ...original };
|
|
1466
|
+
// esbuild reads the nearest tsconfig.json above the working directory from
|
|
1467
|
+
// disk; the tab's esbuild has none, so it is read from the tab's filesystem
|
|
1468
|
+
// here and handed over, as esbuild takes it.
|
|
1469
|
+
const nearestTsconfig = (directory: string) => {
|
|
1470
|
+
const fs2 = typeof currentVfs !== "undefined" ? currentVfs : null;
|
|
1471
|
+
if (!fs2) return void 0;
|
|
1472
|
+
let dir = directory;
|
|
1473
|
+
for (let hops = 0; hops < 32; hops += 1) {
|
|
1474
|
+
const candidate = (dir === "/" ? "" : dir) + "/tsconfig.json";
|
|
1475
|
+
try { if (fs2.existsSync(candidate)) return fs2.readFileSync(candidate, "utf8") as string; } catch {}
|
|
1476
|
+
if (dir === "/" || !dir) return void 0;
|
|
1477
|
+
dir = dir.slice(0, dir.lastIndexOf("/")) || "/";
|
|
1478
|
+
}
|
|
1479
|
+
return void 0;
|
|
1480
|
+
};
|
|
1481
|
+
for (const name of ["build", "context"]) {
|
|
1482
|
+
bound[name] = (options: EsbuildOptions = {}) => {
|
|
1483
|
+
const absWorkingDir = options.absWorkingDir ?? process.cwd();
|
|
1484
|
+
const tsconfigRaw = options.tsconfigRaw ?? (options.tsconfig ? void 0 : nearestTsconfig(absWorkingDir));
|
|
1485
|
+
return original[name]({ ...options, absWorkingDir, ...(tsconfigRaw !== void 0 ? { tsconfigRaw } : {}) });
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
bound.default = bound;
|
|
1489
|
+
__substrateGuestBundlers.set(process, bound);
|
|
1490
|
+
return bound;
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
type GuestProcess = Process & { getBuiltinModule?: (name: string) => unknown };
|
|
1494
|
+
|
|
1495
|
+
/**
|
|
1496
|
+
* A package the project has installed is the one a require of it loads, as Node
|
|
1497
|
+
* loads it. The engine answered `rollup`, `esbuild` and `prettier` with shims of
|
|
1498
|
+
* its own before looking in `node_modules`, so a real Vite could not reach the
|
|
1499
|
+
* esbuild the project carries (the vendor's wasm build, as a pack), and its
|
|
1500
|
+
* config loader died in the engine's shim reaching for a CDN. An installed
|
|
1501
|
+
* esbuild wins only when it can run here, which is when its package directory
|
|
1502
|
+
* holds the wasm binary; one that would spawn a native binary is still answered
|
|
1503
|
+
* by the engine's own service for it, as is a package that is not installed.
|
|
1504
|
+
*/
|
|
1505
|
+
// Whether the esbuild a file belongs to runs in a tab: its package directory
|
|
1506
|
+
// holds the wasm binary, as esbuild-wasm's does and esbuild's does not.
|
|
1507
|
+
function __substrateEsbuildRunsHere(vfs: VirtualFS, file: string): boolean {
|
|
1508
|
+
let dir = file;
|
|
1509
|
+
for (let hops = 0; hops < 6; hops += 1) {
|
|
1510
|
+
dir = dir.slice(0, dir.lastIndexOf("/"));
|
|
1511
|
+
if (!dir) return false;
|
|
1512
|
+
if (vfs.existsSync(dir + "/package.json")) return vfs.existsSync(dir + "/esbuild.wasm");
|
|
1513
|
+
}
|
|
1514
|
+
return false;
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
/**
|
|
1518
|
+
* Node's `module` builtin is the `Module` class: every module's `require` is
|
|
1519
|
+
* `Module.prototype.require`, and resolution goes through
|
|
1520
|
+
* `Module._resolveFilename`, so a program that replaces either, Next's require
|
|
1521
|
+
* hook among them, sees every later require. A plain object answered
|
|
1522
|
+
* `require("module")` and resolution went through closures no program could
|
|
1523
|
+
* reach, so the hook read `undefined.require` and died. The class here is one
|
|
1524
|
+
* per module cache (one per container), and each `require` the engine creates
|
|
1525
|
+
* consults it before its own path.
|
|
1526
|
+
*/
|
|
1527
|
+
const __substrateModuleClasses = new WeakMap<Record<string, Module>, any>();
|
|
1528
|
+
// The directory a module resolves from: its file's, or, for the stand-in
|
|
1529
|
+
// parent a require without a module names, the directory itself, which it
|
|
1530
|
+
// carries with a trailing slash that dirname would otherwise climb out of.
|
|
1531
|
+
function __substrateModuleDir(parent: any, currentDir: string): string {
|
|
1532
|
+
if (!parent || typeof parent.filename !== "string" || parent.filename === "") return currentDir;
|
|
1533
|
+
if (parent.filename.endsWith("/")) return parent.filename.length > 1 ? parent.filename.slice(0, -1) : "/";
|
|
1534
|
+
return pathShim.dirname(parent.filename);
|
|
1535
|
+
}
|
|
1536
|
+
function __substrateModuleClassFor(moduleCache: Record<string, Module>, requireFor: (parent: any) => any): any {
|
|
1537
|
+
let Module = __substrateModuleClasses.get(moduleCache);
|
|
1538
|
+
if (Module) return Module;
|
|
1539
|
+
Module = function Module(this: any, id = "", parent?: any) {
|
|
1540
|
+
this.id = id; this.filename = id; this.exports = {}; this.loaded = false; this.children = []; this.paths = []; this.parent = parent;
|
|
1541
|
+
};
|
|
1542
|
+
// Node's chain, and the one a program patches into: a module's `require`
|
|
1543
|
+
// calls `Module._load`, and `_load` does the resolving and the loading.
|
|
1544
|
+
// openvscode-server's extension host answers an extension's
|
|
1545
|
+
// `require('vscode')` by replacing `_load` (`NodeModuleRequireInterceptor`),
|
|
1546
|
+
// which is how ts-node, pirates, module-alias and proxyquire all work too;
|
|
1547
|
+
// the engine's require went straight to its own loader, so every such patch
|
|
1548
|
+
// was installed and never called. Measured in the tab: after
|
|
1549
|
+
// `module._load = fn`, a `require('fs')` never reached `fn`.
|
|
1550
|
+
Module.prototype.require = function (this: any, id: string) { return Module._load(id, this, false); };
|
|
1551
|
+
Module.__substrateRequire = Module.prototype.require;
|
|
1552
|
+
// `Module.prototype._compile(content, filename)` is the seam every loader
|
|
1553
|
+
// that transpiles a file uses: require.extensions hooks, ts-node, and
|
|
1554
|
+
// Next's TypeScript config loader, which compiles a string into a bare
|
|
1555
|
+
// `new Module(...)`. Node also takes ES module source here (require(esm),
|
|
1556
|
+
// Node >= 22.12), so the content goes through the engine's own loader.
|
|
1557
|
+
Module.prototype._compile = function (this: any, content: string, filename: string) {
|
|
1558
|
+
const file = typeof filename === 'string' && filename ? filename : (this.filename || this.id || '');
|
|
1559
|
+
this.filename = file;
|
|
1560
|
+
if (!Array.isArray(this.paths) || this.paths.length === 0) this.paths = Module._nodeModulePaths(pathShim.dirname(file));
|
|
1561
|
+
requireFor(this).__compileRaw(this, String(content), file, pathShim.dirname(file));
|
|
1562
|
+
return this.exports;
|
|
1563
|
+
};
|
|
1564
|
+
Module._resolveFilename = function (request: string, parent: any) { return requireFor(parent).__resolveRaw(request); };
|
|
1565
|
+
Module.__substrateResolveFilename = Module._resolveFilename;
|
|
1566
|
+
// `Module._load(request, null, true)` runs a module as the main module, the
|
|
1567
|
+
// way Node starts the entry it was given: the module it loads is
|
|
1568
|
+
// `process.mainModule` and every `require.main` from the moment its body runs.
|
|
1569
|
+
Module._load = function (request: string, parent: any, isMain: boolean) {
|
|
1570
|
+
const from = parent || new Module();
|
|
1571
|
+
if (isMain) (process as any).__substrateMainPending = Module._resolveFilename(request, from, true, void 0);
|
|
1572
|
+
return requireFor(from).__requireRaw(request);
|
|
1573
|
+
};
|
|
1574
|
+
Module.__substrateLoad = Module._load;
|
|
1575
|
+
Module._cache = moduleCache;
|
|
1576
|
+
// Node's extension loaders, what require.extensions names. A loader here
|
|
1577
|
+
// runs the file through the engine; the engine's own loader does not yet
|
|
1578
|
+
// consult these, so a program that wraps one to transpile is honored only
|
|
1579
|
+
// where it calls the loader itself.
|
|
1580
|
+
Module._extensions = Object.assign(Object.create(null), {
|
|
1581
|
+
".js": (module: any, filename: string) => { module.exports = requireFor(module).__requireRaw(filename); module.loaded = true; },
|
|
1582
|
+
".json": (module: any, filename: string) => { module.exports = requireFor(module).__requireRaw(filename); module.loaded = true; },
|
|
1583
|
+
".node": (module: any, filename: string) => { throw Object.assign(new Error(`Cannot load native addon ${filename} in a tab.`), { code: "ERR_DLOPEN_FAILED" }); },
|
|
1584
|
+
});
|
|
1585
|
+
Module._pathCache = Object.create(null);
|
|
1586
|
+
Module.builtinModules = moduleShim.builtinModules;
|
|
1587
|
+
Module.isBuiltin = moduleShim.isBuiltin;
|
|
1588
|
+
Module.syncBuiltinESMExports = syncBuiltinESMExports;
|
|
1589
|
+
Module.globalPaths = ["/node_modules"];
|
|
1590
|
+
Module._nodeModulePaths = (directory: string) => {
|
|
1591
|
+
const result = [];
|
|
1592
|
+
for (let current = directory.replace(/\/$/u, "") || "/";;) {
|
|
1593
|
+
if (!current.endsWith("/node_modules")) result.push((current === "/" ? "" : current) + "/node_modules");
|
|
1594
|
+
if (current === "/") return result;
|
|
1595
|
+
current = current.slice(0, current.lastIndexOf("/")) || "/";
|
|
1596
|
+
}
|
|
1597
|
+
};
|
|
1598
|
+
Module.wrapper = ["(function (exports, require, module, __filename, __dirname) { ", "\n});"];
|
|
1599
|
+
Module.wrap = (code: string) => Module.wrapper[0] + code + Module.wrapper[1];
|
|
1600
|
+
Module.createRequire = (filenameOrUrl: string) => {
|
|
1601
|
+
let fromPath = String(filenameOrUrl);
|
|
1602
|
+
if (fromPath.startsWith("file://")) {
|
|
1603
|
+
fromPath = fromPath.slice(7);
|
|
1604
|
+
if (fromPath.startsWith("/") && fromPath[2] === ":") fromPath = fromPath.slice(1);
|
|
1605
|
+
}
|
|
1606
|
+
const made = requireFor({ id: fromPath, filename: fromPath, paths: [] });
|
|
1607
|
+
made.cache = moduleCache;
|
|
1608
|
+
return made;
|
|
1609
|
+
};
|
|
1610
|
+
Module.findSourceMap = () => undefined;
|
|
1611
|
+
// The module-customization hooks of this run, built on the first call and
|
|
1612
|
+
// nowhere else: a run that registers none never pays for the chain, which is
|
|
1613
|
+
// the fast path Node keeps too. They hang off the Module class because that
|
|
1614
|
+
// class is this run's -- one per module cache -- and Node's are per process.
|
|
1615
|
+
Module.__substrateHooks = void 0;
|
|
1616
|
+
const __substrateHooksOf = (): RunModuleHooks => (Module.__substrateHooks ??= new RunModuleHooks());
|
|
1617
|
+
Module.registerHooks = (hooks: { resolve?: unknown; load?: unknown }) => __substrateHooksOf().sync.registerHooks(hooks);
|
|
1618
|
+
Module.register = (specifier: unknown, parentURL?: unknown, options?: { parentURL?: unknown; data?: unknown; transferList?: unknown }) =>
|
|
1619
|
+
__substrateHooksOf().register(specifier, parentURL, options, (url: string, from: string) => Module.createRequire(from)(url));
|
|
1620
|
+
Module.Module = Module;
|
|
1621
|
+
Module.default = Module;
|
|
1622
|
+
__substrateModuleClasses.set(moduleCache, Module);
|
|
1623
|
+
return Module;
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
/**
|
|
1627
|
+
* Create a require function for a specific module context
|
|
1628
|
+
*/
|
|
1629
|
+
function createRequire(
|
|
1630
|
+
vfs: VirtualFS,
|
|
1631
|
+
fsShim: FsShim,
|
|
1632
|
+
process: Process,
|
|
1633
|
+
currentDir: string,
|
|
1634
|
+
moduleCache: Record<string, Module>,
|
|
1635
|
+
options: RuntimeOptions,
|
|
1636
|
+
processedCodeCache?: Map<string, string>,
|
|
1637
|
+
parentModule?: Module | null
|
|
1638
|
+
): RequireFunction {
|
|
1639
|
+
currentVfs = vfs;
|
|
1640
|
+
// Whether a name the engine has a shim for is answered by an installed
|
|
1641
|
+
// package instead: one is installed, and, for esbuild, one that runs here.
|
|
1642
|
+
// Names the engine's table answers that are not Node's: a package the project
|
|
1643
|
+
// installed wins over each; and one that stands for a native watcher,
|
|
1644
|
+
// fsevents, chokidar's use of it, is not answered at all when it is not
|
|
1645
|
+
// installed, as it is not on a Linux host.
|
|
1646
|
+
const __substrateInstalledWins = (id: string): boolean => {
|
|
1647
|
+
const shimmed = id === 'rollup' || id.startsWith('rollup/') || id.startsWith('@rollup/') ? 'rollup'
|
|
1648
|
+
: id === 'esbuild' || id.startsWith('esbuild/') || id.startsWith('@esbuild/') ? 'esbuild'
|
|
1649
|
+
: id === 'prettier' || id.startsWith('prettier/') ? 'prettier'
|
|
1650
|
+
: id === 'ws' || id.startsWith('ws/') ? 'ws'
|
|
1651
|
+
: id === 'chokidar' || id.startsWith('chokidar/') ? 'chokidar'
|
|
1652
|
+
: id === 'readdirp' || id.startsWith('readdirp/') ? 'readdirp'
|
|
1653
|
+
: id === 'fsevents' ? 'fsevents' : void 0;
|
|
1654
|
+
if (!shimmed) return false;
|
|
1655
|
+
try {
|
|
1656
|
+
const file = resolveModule(id, currentDir);
|
|
1657
|
+
return shimmed !== 'esbuild' || __substrateEsbuildRunsHere(vfs, file);
|
|
1658
|
+
} catch {
|
|
1659
|
+
return false;
|
|
1660
|
+
}
|
|
1661
|
+
};
|
|
1662
|
+
const __substrateModule = () => __substrateModuleClassFor(moduleCache, (parent: any) => createRequire(vfs, fsShim, process, __substrateModuleDir(parent, currentDir), moduleCache, options, processedCodeCache, parent));
|
|
1663
|
+
/** The hooks this run has registered, and undefined while it has registered none. */
|
|
1664
|
+
const __substrateHooks = (): RunModuleHooks | undefined => __substrateModule().__substrateHooks as RunModuleHooks | undefined;
|
|
1665
|
+
const __substrateResolve = (id: string): string => {
|
|
1666
|
+
const Module = __substrateModule();
|
|
1667
|
+
return Module._resolveFilename === Module.__substrateResolveFilename
|
|
1668
|
+
? resolveModule(id, currentDir)
|
|
1669
|
+
: Module._resolveFilename(id, parentModule || { id: currentDir, filename: currentDir + '/', paths: [] }, false, undefined);
|
|
1670
|
+
};
|
|
1671
|
+
// Module resolution cache for faster repeated imports
|
|
1672
|
+
const resolutionCache: Map<string, string | null> = new Map();
|
|
1673
|
+
|
|
1674
|
+
// Package.json parsing cache
|
|
1675
|
+
const packageJsonCache: Map<string, PackageJson | null> = new Map();
|
|
1676
|
+
|
|
1677
|
+
const getParsedPackageJson = (pkgPath: string): PackageJson | null => {
|
|
1678
|
+
if (packageJsonCache.has(pkgPath)) {
|
|
1679
|
+
return packageJsonCache.get(pkgPath)!;
|
|
1680
|
+
}
|
|
1681
|
+
try {
|
|
1682
|
+
const content = vfs.readFileSync(pkgPath, 'utf8');
|
|
1683
|
+
const parsed = JSON.parse(content) as PackageJson;
|
|
1684
|
+
packageJsonCache.set(pkgPath, parsed);
|
|
1685
|
+
return parsed;
|
|
1686
|
+
} catch {
|
|
1687
|
+
packageJsonCache.set(pkgPath, null);
|
|
1688
|
+
return null;
|
|
1689
|
+
}
|
|
1690
|
+
};
|
|
1691
|
+
|
|
1692
|
+
const resolveModule = (id: string, fromDir: string): string => {
|
|
1693
|
+
// Handle node: protocol prefix (Node.js 16+)
|
|
1694
|
+
if (id.startsWith('node:')) {
|
|
1695
|
+
id = id.slice(5);
|
|
1696
|
+
}
|
|
1697
|
+
// A file URL is read as its path here too, behind a lowered import.
|
|
1698
|
+
if (id.startsWith('file://')) {
|
|
1699
|
+
id = decodeURIComponent(new URL(id).pathname);
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
// A package the engine stands in for resolves to the installed file. The
|
|
1703
|
+
// engine answers `require("rollup")` and `require("esbuild")` with its own
|
|
1704
|
+
// builds, and this resolver gave their bare names back, as it does for
|
|
1705
|
+
// Node's builtins; Vite's Node API resolves rollup to read the package.json
|
|
1706
|
+
// beside it, and read `<cwd>/rollup/../../package.json` instead, which is
|
|
1707
|
+
// nowhere, so vue3-ssr's server died importing Vite. Node's builtins still
|
|
1708
|
+
// resolve to their names; a stand-in resolves to the file the project
|
|
1709
|
+
// installed, and to its name only where the project has no such package.
|
|
1710
|
+
const __standInPaths = (globalThis as Record<string, unknown>).__browserRuntimeStandInPaths as Record<string, string> | undefined;
|
|
1711
|
+
if (__standInPaths && Object.prototype.hasOwnProperty.call(__standInPaths, id) && vfs.existsSync(__standInPaths[id])) {
|
|
1712
|
+
return __standInPaths[id];
|
|
1713
|
+
}
|
|
1714
|
+
if (id === 'fs' || id === 'process' || id === 'url' || id === 'querystring' || id === 'util' || moduleShim.builtinModules.includes(id)) {
|
|
1715
|
+
return id;
|
|
1716
|
+
}
|
|
1717
|
+
const __standIn = Boolean(builtinModules[id]);
|
|
1718
|
+
|
|
1719
|
+
// The engine's own `#imports` walk stopped one directory short of the root,
|
|
1720
|
+
// so a root package's imports map never answered; the shared resolver takes
|
|
1721
|
+
// the `#` names too.
|
|
1722
|
+
if (id.startsWith('#')) {
|
|
1723
|
+
const __resolvedImport = __nodeResolverFor(vfs, 'runtime').resolve(id, fromDir);
|
|
1724
|
+
if (__resolvedImport) return __resolvedImport;
|
|
1725
|
+
throw Object.assign(new Error(`Cannot find module '${id}'`), { code: 'MODULE_NOT_FOUND' });
|
|
1726
|
+
}
|
|
1727
|
+
const cacheKey = `${fromDir}|${id}`;
|
|
1728
|
+
const cached = resolutionCache.get(cacheKey);
|
|
1729
|
+
if (cached !== undefined) {
|
|
1730
|
+
if (cached === null) {
|
|
1731
|
+
throw Object.assign(new Error(`Cannot find module '${id}'`), { code: 'MODULE_NOT_FOUND' });
|
|
1732
|
+
}
|
|
1733
|
+
return cached;
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
// One resolver for every name the engine resolves: this require, the simple
|
|
1737
|
+
// loader's, and the bundler's plugin. Each had a hand-rolled subset of
|
|
1738
|
+
// Node's algorithm; they disagreed with each other and with Node, and every
|
|
1739
|
+
// app found a new gap. This site keeps only its edges — the cache, the
|
|
1740
|
+
// builtins, the stand-ins — and calls the shared resolver.
|
|
1741
|
+
{
|
|
1742
|
+
const __resolved = __nodeResolverFor(vfs, 'runtime').resolve(id, fromDir);
|
|
1743
|
+
if (__resolved) {
|
|
1744
|
+
resolutionCache.set(cacheKey, __resolved);
|
|
1745
|
+
return __resolved;
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
// A name the tree does not answer is put to the module stand-ins before it
|
|
1750
|
+
// is "not found": a registered stand-in may answer with a module it computes
|
|
1751
|
+
// from the project, what a generator would have written. The registry is
|
|
1752
|
+
// `globalThis.__browserRuntimeModuleStandIns`, installed by the toolchain.
|
|
1753
|
+
const __standIns = (globalThis as Record<string, unknown>).__browserRuntimeModuleStandIns as { resolve: (id: string, from: string) => string | null } | undefined;
|
|
1754
|
+
const __answered = __standIns ? __standIns.resolve(id, fromDir) : null;
|
|
1755
|
+
if (__answered) {
|
|
1756
|
+
resolutionCache.set(cacheKey, __answered);
|
|
1757
|
+
return __answered;
|
|
1758
|
+
}
|
|
1759
|
+
resolutionCache.set(cacheKey, null);
|
|
1760
|
+
if (__standIn) return id;
|
|
1761
|
+
throw Object.assign(new Error(`Cannot find module '${id}'`), { code: 'MODULE_NOT_FOUND' });
|
|
1762
|
+
};
|
|
1763
|
+
|
|
1764
|
+
/**
|
|
1765
|
+
* What a resolve step already decided about a module: the URL the hooks
|
|
1766
|
+
* chain settled on, the format it named, and, where a load hook replaced a
|
|
1767
|
+
* builtin's source, that source. Node carries the same three on the module
|
|
1768
|
+
* record (`kURL`, `kFormat`, `kModuleSource`).
|
|
1769
|
+
*/
|
|
1770
|
+
type ResolvedAs = { url?: string; format?: string; source?: string | ArrayBuffer | ArrayBufferView | null };
|
|
1771
|
+
const loadModule = (resolvedPath: string, resolvedAs?: ResolvedAs): Module => {
|
|
1772
|
+
// A path into a package the host stands in for loads the host's file
|
|
1773
|
+
// too, from the same table the resolver reads by name
|
|
1774
|
+
// (`globalThis.__browserRuntimeStandInPaths`, package name -> file): Vite's
|
|
1775
|
+
// bundled config imports its plugins by the file paths its own resolver
|
|
1776
|
+
// found, `node_modules/<package>/dist/index.mjs`, never by name. The
|
|
1777
|
+
// engine names no package here; the table is the host's.
|
|
1778
|
+
const __hostStandIns = (globalThis as Record<string, unknown>).__browserRuntimeStandInPaths as Record<string, string> | undefined;
|
|
1779
|
+
if (__hostStandIns) {
|
|
1780
|
+
for (const [__name, __file] of Object.entries(__hostStandIns)) {
|
|
1781
|
+
if (resolvedPath.includes('/node_modules/' + __name + '/') && vfs.existsSync(__file)) { resolvedPath = __file; break; }
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
// Return cached module
|
|
1785
|
+
// A native addon cannot load in a tab. Node answers a `require` of a `.node`
|
|
1786
|
+
// file that cannot be loaded with `ERR_DLOPEN_FAILED`, and a package that
|
|
1787
|
+
// probes for its addon, chokidar for fsevents, takes its portable path on
|
|
1788
|
+
// that error. Reading the binary as a module and parsing it took the process
|
|
1789
|
+
// with it.
|
|
1790
|
+
if (resolvedPath.endsWith('.node')) {
|
|
1791
|
+
// A native addon whose surface the holder answers in JavaScript, named
|
|
1792
|
+
// by the package the addon belongs to (`bcrypt` -> a module with the
|
|
1793
|
+
// binding's exports): the addon's bytes are never read and the stand-in
|
|
1794
|
+
// loads in its place. Every other addon fails as Node's dlopen would.
|
|
1795
|
+
const __native = (globalThis as { __browserRuntimeNativeStandIns?: Record<string, string> }).__browserRuntimeNativeStandIns;
|
|
1796
|
+
const __package = __native ? Object.keys(__native).find((name) => resolvedPath.includes('/node_modules/' + name + '/')) : undefined;
|
|
1797
|
+
const __answer = __package !== undefined && __native ? __native[__package] : undefined;
|
|
1798
|
+
if (__answer && vfs.existsSync(__answer)) {
|
|
1799
|
+
resolvedPath = __answer;
|
|
1800
|
+
} else {
|
|
1801
|
+
throw Object.assign(new Error('Cannot load native addon ' + resolvedPath + ': a tab runs no native code.'), { code: 'ERR_DLOPEN_FAILED' });
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
if (moduleCache[resolvedPath]) {
|
|
1805
|
+
return moduleCache[resolvedPath];
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
// A module knows its parent. Node's `module.parent` is the module that
|
|
1809
|
+
// first required this one, null for the entry; with no parent, nodemon,
|
|
1810
|
+
// which reads its own version from the package.json above
|
|
1811
|
+
// `module.parent.filename`, died in a callback with nothing said.
|
|
1812
|
+
const module: Module = {
|
|
1813
|
+
id: resolvedPath,
|
|
1814
|
+
filename: resolvedPath,
|
|
1815
|
+
exports: {},
|
|
1816
|
+
loaded: false,
|
|
1817
|
+
children: [],
|
|
1818
|
+
paths: [],
|
|
1819
|
+
parent: parentModule || null,
|
|
1820
|
+
};
|
|
1821
|
+
if (parentModule && Array.isArray(parentModule.children)) parentModule.children.push(module);
|
|
1822
|
+
|
|
1823
|
+
// Cache before loading to handle circular dependencies
|
|
1824
|
+
moduleCache[resolvedPath] = module;
|
|
1825
|
+
// The entry module is the main module: `process.mainModule` and
|
|
1826
|
+
// `require.main` name it, and its id is ".", as Node has them, so a program
|
|
1827
|
+
// that runs only when it is the entry (`require.main === module`, which the
|
|
1828
|
+
// Prisma CLI and every bin script written that way tests) runs.
|
|
1829
|
+
if ((process as any).__substrateMainPending === resolvedPath) {
|
|
1830
|
+
delete (process as any).__substrateMainPending;
|
|
1831
|
+
(process as any).mainModule = module;
|
|
1832
|
+
module.id = '.';
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
// Node keeps every loaded module for the life of the process; so does a tab.
|
|
1836
|
+
// A cap of 2000 meant a program that requires more, as a Next application's
|
|
1837
|
+
// Server Action does with its middleware, saw its earliest modules load a
|
|
1838
|
+
// second time: two live copies of a module that holds state, such as Next's
|
|
1839
|
+
// request store, and the second copy empty.
|
|
1840
|
+
|
|
1841
|
+
// A module's source, and the format it is compiled in, are the load step.
|
|
1842
|
+
// Where a run has registered load hooks the chain answers both and this
|
|
1843
|
+
// read is its last link, which is where Node's `loadSource` calls
|
|
1844
|
+
// `loadWithHooks`; where it has none, nothing here changes.
|
|
1845
|
+
const __hooks = __substrateHooks();
|
|
1846
|
+
const defaultSource = (): string => resolvedPath.startsWith('data:')
|
|
1847
|
+
? __substrateDataModuleSource(resolvedPath)!
|
|
1848
|
+
: vfs.readFileSync(resolvedPath, 'utf8');
|
|
1849
|
+
let format = resolvedAs?.format;
|
|
1850
|
+
let source = resolvedAs?.source;
|
|
1851
|
+
if (__hooks && __hooks.hasSyncLoad && source === undefined) {
|
|
1852
|
+
const url = resolvedAs?.url ?? __hooks.sync.convertCJSFilenameToURL(resolvedPath);
|
|
1853
|
+
const loaded = __hooks.sync.loadWithHooks(url, format, void 0, CJS_CONDITIONS, (urlFromHook, context) => ({
|
|
1854
|
+
// Node's `getDefaultLoad`: a URL the chain changed is read from the
|
|
1855
|
+
// file it names, not from the one the loader started with.
|
|
1856
|
+
source: urlFromHook === url ? defaultSource() : vfs.readFileSync(__hooks.sync.convertURLToCJSFilename(urlFromHook), 'utf8'),
|
|
1857
|
+
format: context.format,
|
|
1858
|
+
}));
|
|
1859
|
+
format = loaded.format;
|
|
1860
|
+
source = loaded.source;
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
if (format === 'json' || (format === undefined && resolvedPath.endsWith('.json'))) {
|
|
1864
|
+
module.exports = JSON.parse(source === undefined || source === null ? vfs.readFileSync(resolvedPath, 'utf8') : String(source));
|
|
1865
|
+
module.loaded = true;
|
|
1866
|
+
return module;
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
// Read and execute JS file; a data: URL carries its own source.
|
|
1870
|
+
const rawCode = source === undefined || source === null ? defaultSource() : String(source);
|
|
1871
|
+
const dirname = resolvedPath.startsWith('data:') ? currentDir : pathShim.dirname(resolvedPath);
|
|
1872
|
+
|
|
1873
|
+
runModuleBody(module, prepareModuleCode(rawCode, resolvedPath, format), resolvedPath, dirname);
|
|
1874
|
+
return module;
|
|
1875
|
+
};
|
|
1876
|
+
|
|
1877
|
+
/**
|
|
1878
|
+
* A file's source made a body: shebang stripped, types stripped, ESM
|
|
1879
|
+
* lowered, dynamic imports rewritten; cached by content.
|
|
1880
|
+
*
|
|
1881
|
+
* `format` is what a load hook named, and it decides the same three things
|
|
1882
|
+
* the file's extension decides without one: whether the source carries
|
|
1883
|
+
* types, whether it is lowered as an ES module, and whether it is JSON. A
|
|
1884
|
+
* run with no hooks never passes one, and the extension rules below are
|
|
1885
|
+
* what they always were.
|
|
1886
|
+
*/
|
|
1887
|
+
const prepareModuleCode = (rawCode: string, resolvedPath: string, format?: string): string => {
|
|
1888
|
+
// Check processed code cache (useful for HMR when module cache is cleared but code hasn't changed)
|
|
1889
|
+
// Use a simple hash of the content for cache key to handle content changes
|
|
1890
|
+
const codeCacheKey = `${resolvedPath}|${format ?? ''}|${simpleHash(rawCode)}`;
|
|
1891
|
+
let code = processedCodeCache?.get(codeCacheKey);
|
|
1892
|
+
|
|
1893
|
+
if (!code) {
|
|
1894
|
+
code = rawCode;
|
|
1895
|
+
|
|
1896
|
+
// Strip shebang line if present (e.g. #!/usr/bin/env node)
|
|
1897
|
+
if (code.startsWith('#!')) {
|
|
1898
|
+
code = code.slice(code.indexOf('\n') + 1);
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
// A `.ts`, `.mts` or `.cts` file runs with its types stripped, as Node
|
|
1902
|
+
// runs one since 22.18: the source goes to the type stripper the realm
|
|
1903
|
+
// loaded, amaro, before the module's imports are read. A realm without one
|
|
1904
|
+
// runs the file as it is.
|
|
1905
|
+
const __typescript = format === undefined
|
|
1906
|
+
? /[.](?:ts|mts|cts)$/u.test(resolvedPath) && !resolvedPath.endsWith('.d.ts')
|
|
1907
|
+
: format === 'typescript' || format === 'commonjs-typescript' || format === 'module-typescript';
|
|
1908
|
+
if (__typescript && typeof (globalThis as any).__substrateStripTypes === 'function') {
|
|
1909
|
+
code = (globalThis as any).__substrateStripTypes(code, resolvedPath) as string;
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
// Transform ESM to CJS if needed (for .mjs files or ESM that wasn't pre-transformed)
|
|
1913
|
+
// transformEsmToCjs uses AST to handle import/export, import.meta, and dynamic imports
|
|
1914
|
+
// It also handles already-CJS files safely (AST finds no ESM nodes → no-op)
|
|
1915
|
+
const __commonjs = format === 'commonjs' || format === 'commonjs-typescript'
|
|
1916
|
+
? true
|
|
1917
|
+
: format === 'module' || format === 'module-typescript'
|
|
1918
|
+
? false
|
|
1919
|
+
: resolvedPath.endsWith('.cjs');
|
|
1920
|
+
if (!__commonjs) {
|
|
1921
|
+
// An ES module is strict wherever it runs; the mark says so to the
|
|
1922
|
+
// compile below, which is otherwise sloppy as a CommonJS body is.
|
|
1923
|
+
const lowered = transformEsmToCjs(code, resolvedPath);
|
|
1924
|
+
code = lowered === code ? code : `${__substrateModuleMarker}"use strict";\n${lowered}`;
|
|
1925
|
+
} else {
|
|
1926
|
+
// A `.cjs` module skips the ESM transform, and with it the rewrite of
|
|
1927
|
+
// `import(...)` to the engine's dynamic import, so its
|
|
1928
|
+
// `import("fs/promises")` reached the browser's own import and failed on
|
|
1929
|
+
// the bare specifier. The dynamic-import rewrite applies to `.cjs` too.
|
|
1930
|
+
code = transformDynamicImportsRegex(code);
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
// Cache the processed code
|
|
1934
|
+
processedCodeCache?.set(codeCacheKey, code);
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
return code;
|
|
1938
|
+
};
|
|
1939
|
+
|
|
1940
|
+
/**
|
|
1941
|
+
* Runs a body as the module, on the module's own require and console, and
|
|
1942
|
+
* keeps it settling where it must. Node compiles a body in place through
|
|
1943
|
+
* `Module.prototype._compile`, and a loader that transpiles a file
|
|
1944
|
+
* (require.extensions hooks, ts-node, Next's TypeScript config loader)
|
|
1945
|
+
* hands the result to it; the engine's own pipeline is what makes the
|
|
1946
|
+
* body Node-shaped here.
|
|
1947
|
+
*/
|
|
1948
|
+
const runModuleBody = (module: Module, prepared: string, resolvedPath: string, dirname: string): void => {
|
|
1949
|
+
let code = prepared;
|
|
1950
|
+
// Create require for this module
|
|
1951
|
+
const moduleRequire = createRequire(
|
|
1952
|
+
vfs,
|
|
1953
|
+
fsShim,
|
|
1954
|
+
process,
|
|
1955
|
+
dirname,
|
|
1956
|
+
moduleCache,
|
|
1957
|
+
options,
|
|
1958
|
+
processedCodeCache,
|
|
1959
|
+
module
|
|
1960
|
+
);
|
|
1961
|
+
moduleRequire.cache = moduleCache;
|
|
1962
|
+
|
|
1963
|
+
// Create console wrapper
|
|
1964
|
+
const consoleWrapper = createConsoleWrapper(options.onConsole);
|
|
1965
|
+
|
|
1966
|
+
// Execute module code
|
|
1967
|
+
// We use an outer/inner function pattern to avoid conflicts:
|
|
1968
|
+
// - Outer function receives parameters and sets up vars
|
|
1969
|
+
// - Inner function runs the code, allowing let/const to shadow without "already declared" errors
|
|
1970
|
+
// - import.meta is provided for ESM code that uses it
|
|
1971
|
+
try {
|
|
1972
|
+
const importMetaUrl = resolvedPath.startsWith('data:') ? resolvedPath : 'file://' + resolvedPath;
|
|
1973
|
+
const strictBody = code.startsWith(__substrateModuleMarker);
|
|
1974
|
+
code = __substrateScopeConstructors(code);
|
|
1975
|
+
// The wrapper is one line and the body begins on it, as Node's
|
|
1976
|
+
// `Module.wrap` is one line, so a module's line N is line N of the
|
|
1977
|
+
// script V8 compiles and a stack names the module's own lines. The
|
|
1978
|
+
// header's `var` statements are the module's scope, `globalThis` and
|
|
1979
|
+
// `global` among them for code that reads the process off them
|
|
1980
|
+
// directly; the inner function is what lets the body's own `let` and
|
|
1981
|
+
// `const` shadow that scope. `__substrateSourceURL` names the script.
|
|
1982
|
+
const wrappedCode = `(function($exports, $require, $module, $filename, $dirname, $process, $console, $importMeta, $dynamicImport, __substrateGuestGlobal, __substrateGuestConstructor) { var exports = $exports; var require = $require; var module = $module; var __filename = $filename; var __dirname = $dirname; var process = $process; var console = $console; var import_meta = $importMeta; var __dynamicImport = $dynamicImport; var document = void 0, window = void 0, location = void 0, self = void 0; var globalThis = __substrateGuestGlobal($process); var global = globalThis; var Buffer = globalThis.Buffer; var queueMicrotask = globalThis.queueMicrotask, atob = globalThis.atob, btoa = globalThis.btoa, structuredClone = globalThis.structuredClone, setTimeout = globalThis.setTimeout, clearTimeout = globalThis.clearTimeout, setInterval = globalThis.setInterval, clearInterval = globalThis.clearInterval; globalThis.process = $process; global.process = $process; return (function() {${code}
|
|
1983
|
+
}).call(${strictBody ? 'void 0' : '$module.exports'});
|
|
1984
|
+
})${__substrateSourceURL(resolvedPath)}`;
|
|
1985
|
+
|
|
1986
|
+
// A lowered ES module body is a generator that yields at each import
|
|
1987
|
+
// still settling; a body that must wait, on a top-level `await` of its
|
|
1988
|
+
// own, runs as an async function. Either way its settling is what its
|
|
1989
|
+
// importers await.
|
|
1990
|
+
let bodyKind: 'sync' | 'generator' | 'async' = code.includes(__substrateAwaitMarker) ? 'generator' : 'sync';
|
|
1991
|
+
let fn;
|
|
1992
|
+
try {
|
|
1993
|
+
fn = __substrateSloppyEval(bodyKind === 'generator' ? __substrateGeneratorBody(wrappedCode) : wrappedCode);
|
|
1994
|
+
} catch (evalError) {
|
|
1995
|
+
const msg = evalError instanceof Error ? evalError.message : String(evalError);
|
|
1996
|
+
// A module with top-level await runs. Node runs a `.js` file of a package
|
|
1997
|
+
// with `"type": "module"` as a module, where `await` is valid at the top;
|
|
1998
|
+
// a module lowered to a function body made V8 refuse vue3-ssr's server at
|
|
1999
|
+
// its first top-level `await`. A body V8 refuses for that reason runs as
|
|
2000
|
+
// an async function body instead.
|
|
2001
|
+
if (!(evalError instanceof SyntaxError)) throw evalError;
|
|
2002
|
+
bodyKind = 'async';
|
|
2003
|
+
try { fn = __substrateSloppyEval(__substrateAsyncBody(wrappedCode)); }
|
|
2004
|
+
catch { throw new SyntaxError(`${msg} (in ${resolvedPath})`); }
|
|
2005
|
+
}
|
|
2006
|
+
// Create dynamic import function for this module context
|
|
2007
|
+
const dynamicImport = createDynamicImport(moduleRequire, importMetaUrl);
|
|
2008
|
+
|
|
2009
|
+
const body = fn(
|
|
2010
|
+
module.exports,
|
|
2011
|
+
moduleRequire,
|
|
2012
|
+
module,
|
|
2013
|
+
resolvedPath,
|
|
2014
|
+
dirname,
|
|
2015
|
+
process,
|
|
2016
|
+
consoleWrapper,
|
|
2017
|
+
{ url: importMetaUrl, dirname, filename: resolvedPath },
|
|
2018
|
+
dynamicImport,
|
|
2019
|
+
__substrateGuestGlobal,
|
|
2020
|
+
__substrateGuestConstructor
|
|
2021
|
+
);
|
|
2022
|
+
|
|
2023
|
+
const settling = __substrateDriveBody(bodyKind, body, module);
|
|
2024
|
+
if (settling) __substrateKeepPending(module, settling, () => { delete moduleCache[resolvedPath]; });
|
|
2025
|
+
else module.loaded = true;
|
|
2026
|
+
} catch (error) {
|
|
2027
|
+
// Remove from cache on error
|
|
2028
|
+
delete moduleCache[resolvedPath];
|
|
2029
|
+
// Enhance runtime errors with the module path for easier debugging
|
|
2030
|
+
// A module error names the module it happened in and, as it climbs, each
|
|
2031
|
+
// module that required it, the way Node prints a require stack; the engine
|
|
2032
|
+
// named the innermost alone, so a native module deep in a tree could not
|
|
2033
|
+
// say which package had asked for it.
|
|
2034
|
+
if (error instanceof Error) {
|
|
2035
|
+
if (!error.message.includes('(in /')) error.message = `${error.message} (in ${resolvedPath})`;
|
|
2036
|
+
else if (!error.message.includes(`\n required by ${resolvedPath}`)) error.message = `${error.message}\n required by ${resolvedPath}`;
|
|
2037
|
+
}
|
|
2038
|
+
throw error;
|
|
2039
|
+
}
|
|
2040
|
+
};
|
|
2041
|
+
|
|
2042
|
+
const require: RequireFunction = (id: string): unknown => {
|
|
2043
|
+
const Module = __substrateModule();
|
|
2044
|
+
if (Module.prototype.require !== Module.__substrateRequire) {
|
|
2045
|
+
return Module.prototype.require.call(parentModule || { id: currentDir, filename: currentDir + '/', paths: [] }, id);
|
|
2046
|
+
}
|
|
2047
|
+
// A program that replaced `Module._load` sees every require from here on,
|
|
2048
|
+
// as it would in Node; with the engine's own still in place, the fast
|
|
2049
|
+
// path below is the whole of a require, as it is for `_resolveFilename`.
|
|
2050
|
+
if (Module._load !== Module.__substrateLoad) {
|
|
2051
|
+
return Module._load(id, parentModule || { id: currentDir, filename: currentDir + '/', paths: [] }, false);
|
|
2052
|
+
}
|
|
2053
|
+
return requireRaw(id);
|
|
2054
|
+
};
|
|
2055
|
+
/**
|
|
2056
|
+
* A require through the hooks this run registered, and, where it has
|
|
2057
|
+
* registered none, the require the engine has always done.
|
|
2058
|
+
*
|
|
2059
|
+
* Node resolves a request before it decides whether the request names a
|
|
2060
|
+
* builtin (`Module._load` calls `resolveForCJSWithHooks` first), so a
|
|
2061
|
+
* resolve hook can send `require("zlib")` to a file on disk and a load hook
|
|
2062
|
+
* can replace a builtin's source. Node keeps a fast path for the ordinary
|
|
2063
|
+
* case and so does this: with no hook registered, `requirePlain` is the
|
|
2064
|
+
* whole of a require and nothing below it runs.
|
|
2065
|
+
*/
|
|
2066
|
+
const requireRaw = (id: string): unknown => {
|
|
2067
|
+
// A data: URL is a module of its own, loaded at that URL.
|
|
2068
|
+
if (id.startsWith('data:')) return loadModule(id).exports;
|
|
2069
|
+
// A hook is handed the specifier as it was written, `node:` prefix and
|
|
2070
|
+
// all: the prefix is stripped for the engine's own lookup and nowhere
|
|
2071
|
+
// else, which is the rule Node states in its own test -- "the one with
|
|
2072
|
+
// the prefix stripped for internal lookups should not get passed into
|
|
2073
|
+
// the hooks". A hook that answers `node:assert` never saw it otherwise.
|
|
2074
|
+
// Only the synchronous chain: a hook installed with `module.register` is
|
|
2075
|
+
// Node's ESM customization and does not apply to a `require` there
|
|
2076
|
+
// either, so a run that registered one alone resolves exactly as it did.
|
|
2077
|
+
const hooks = __substrateHooks();
|
|
2078
|
+
if (hooks && (hooks.hasSyncResolve || hooks.hasSyncLoad)) return requireHooked(id, hooks);
|
|
2079
|
+
// Handle node: protocol prefix (Node.js 16+)
|
|
2080
|
+
if (id.startsWith('node:')) {
|
|
2081
|
+
id = id.slice(5);
|
|
2082
|
+
}
|
|
2083
|
+
return requirePlain(id);
|
|
2084
|
+
};
|
|
2085
|
+
|
|
2086
|
+
/**
|
|
2087
|
+
* A name the engine answers with a module of its own rather than a file:
|
|
2088
|
+
* Node's builtins, and the packages the engine stands in for. Handing one
|
|
2089
|
+
* to the file resolver would look for a file that is not there.
|
|
2090
|
+
*/
|
|
2091
|
+
const __substrateNamedModule = (specifier: string): string | undefined => {
|
|
2092
|
+
const name = specifier.startsWith('node:') ? specifier.slice(5) : specifier;
|
|
2093
|
+
if (moduleShim.isBuiltin(name) || name === 'fs/promises') return name;
|
|
2094
|
+
if (Object.prototype.hasOwnProperty.call(builtinModules, name) && !__substrateInstalledWins(name)) return name;
|
|
2095
|
+
return void 0;
|
|
2096
|
+
};
|
|
2097
|
+
|
|
2098
|
+
const requireHooked = (id: string, hooks: RunModuleHooks): unknown => {
|
|
2099
|
+
let defaultURL: string | undefined;
|
|
2100
|
+
let defaultFilename: string | undefined;
|
|
2101
|
+
// The bottom of the chain: the engine's own resolution, in the URL terms
|
|
2102
|
+
// a hook speaks. A builtin keeps its name, as Node's `defaultResolveImpl`
|
|
2103
|
+
// returns the normalized id rather than a path.
|
|
2104
|
+
const defaultResolve = (specifier: string): { url: string } => {
|
|
2105
|
+
defaultFilename = __substrateNamedModule(specifier) ?? __substrateResolve(specifier);
|
|
2106
|
+
defaultURL = hooks.sync.convertCJSFilenameToURL(defaultFilename);
|
|
2107
|
+
return { url: defaultURL };
|
|
2108
|
+
};
|
|
2109
|
+
const parent = parentModule && typeof parentModule.filename === 'string' && parentModule.filename
|
|
2110
|
+
? hooks.sync.convertCJSFilenameToURL(parentModule.filename)
|
|
2111
|
+
: void 0;
|
|
2112
|
+
const resolved = hooks.hasSyncResolve
|
|
2113
|
+
? hooks.sync.resolveWithHooks(id, parent, void 0, CJS_CONDITIONS, defaultResolve)
|
|
2114
|
+
: defaultResolve(id);
|
|
2115
|
+
const url = resolved.url;
|
|
2116
|
+
const format = (resolved as { format?: string }).format;
|
|
2117
|
+
const filename = url === defaultURL ? defaultFilename! : hooks.sync.convertURLToCJSFilename(url);
|
|
2118
|
+
|
|
2119
|
+
// A builtin still goes through the load chain, as Node's
|
|
2120
|
+
// `loadBuiltinWithHooks` runs it, and the source a hook returns for one is
|
|
2121
|
+
// ignored -- unless the hook also moved the format off `builtin`, which is
|
|
2122
|
+
// how a program puts a file of its own in a builtin's place.
|
|
2123
|
+
if (moduleShim.isBuiltin(filename)) {
|
|
2124
|
+
if (hooks.hasSyncLoad) {
|
|
2125
|
+
const loaded = hooks.sync.loadWithHooks(url, format || 'builtin', void 0, CJS_CONDITIONS, (_urlFromHook, context) => ({ source: null, format: context.format }));
|
|
2126
|
+
if (loaded.format && loaded.format !== 'builtin') {
|
|
2127
|
+
return loadModule(filename, { url, format: loaded.format, source: loaded.source }).exports;
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
return requirePlain(filename);
|
|
2131
|
+
}
|
|
2132
|
+
// Nothing moved: the engine's own require, with every stand-in and
|
|
2133
|
+
// installed-package rule it carries. The load chain runs inside loadModule.
|
|
2134
|
+
if (url === defaultURL && format === undefined) return requirePlain(id);
|
|
2135
|
+
return loadModule(filename, { url, format }).exports;
|
|
2136
|
+
};
|
|
2137
|
+
|
|
2138
|
+
/**
|
|
2139
|
+
* Node appends each builtin a process loads to `process.moduleLoadList`, in
|
|
2140
|
+
* the order it first loaded each, and a program reads that list to tell
|
|
2141
|
+
* whether a module is already in memory. The engine answers a builtin from a
|
|
2142
|
+
* table rather than compiling one, so the record is made here, where the
|
|
2143
|
+
* name is first answered.
|
|
2144
|
+
*/
|
|
2145
|
+
const __substrateRecordBuiltin = (id: string): void => {
|
|
2146
|
+
const list = (process as unknown as { moduleLoadList?: string[] }).moduleLoadList;
|
|
2147
|
+
if (!Array.isArray(list)) return;
|
|
2148
|
+
const entry = `NativeModule ${id}`;
|
|
2149
|
+
if (!list.includes(entry)) list.push(entry);
|
|
2150
|
+
};
|
|
2151
|
+
|
|
2152
|
+
const requirePlain = (id: string): unknown => {
|
|
2153
|
+
// Handle node: protocol prefix (Node.js 16+)
|
|
2154
|
+
if (id.startsWith('node:')) {
|
|
2155
|
+
id = id.slice(5);
|
|
2156
|
+
}
|
|
2157
|
+
// A data: URL is a module of its own, loaded at that URL.
|
|
2158
|
+
if (id.startsWith('data:')) return loadModule(id).exports;
|
|
2159
|
+
if (moduleShim.isBuiltin(id)) __substrateRecordBuiltin(id);
|
|
2160
|
+
|
|
2161
|
+
// Built-in modules
|
|
2162
|
+
if (id === 'fs') {
|
|
2163
|
+
return fsModuleFor(process);
|
|
2164
|
+
}
|
|
2165
|
+
if (id === 'fs/promises') {
|
|
2166
|
+
return (fsModuleFor(process) as { promises: unknown }).promises;
|
|
2167
|
+
}
|
|
2168
|
+
if (id === 'internal/fs/promises') {
|
|
2169
|
+
return (fsModuleFor(process) as { promises: unknown }).promises;
|
|
2170
|
+
}
|
|
2171
|
+
if (id === 'process') {
|
|
2172
|
+
return process;
|
|
2173
|
+
}
|
|
2174
|
+
// Worker threads run where a thread host is installed, a worker the
|
|
2175
|
+
// page owns per thread; the shim alone refuses to run one. The host
|
|
2176
|
+
// registers itself under this symbol and answers the module for a guest.
|
|
2177
|
+
if (id === 'worker_threads') {
|
|
2178
|
+
const bridge = (globalThis as Record<symbol, unknown>)[Symbol.for("@volter/browser-node/threads")] as { module?: (vfs: VirtualFS, process: unknown, shim: unknown) => unknown } | undefined;
|
|
2179
|
+
const module = bridge && typeof bridge.module === "function" ? bridge.module(vfs, process, builtinModules.worker_threads) : undefined;
|
|
2180
|
+
if (module) return module;
|
|
2181
|
+
}
|
|
2182
|
+
if (id === 'module') {
|
|
2183
|
+
return __substrateModule();
|
|
2184
|
+
}
|
|
2185
|
+
if (id === 'wasi') {
|
|
2186
|
+
return __substrateGuestWasi(fsShim, process);
|
|
2187
|
+
}
|
|
2188
|
+
if (builtinModules[id] && !__substrateInstalledWins(id) && !(id === 'fsevents' || id === 'chokidar' || id === 'readdirp')) {
|
|
2189
|
+
return id === 'esbuild' ? __substrateGuestEsbuild(process) : id === 'rollup' ? __substrateGuestRollup(process) : builtinModules[id];
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
if (!__substrateInstalledWins(id)) {
|
|
2193
|
+
// Intercept rollup and esbuild - always use our shims
|
|
2194
|
+
// These packages have native binaries that don't work in browser
|
|
2195
|
+
if (id === 'rollup' || id.startsWith('rollup/') || id.startsWith('@rollup/rollup-')) {
|
|
2196
|
+
console.log('[runtime] Intercepted rollup:', id);
|
|
2197
|
+
return __substrateGuestRollup(process);
|
|
2198
|
+
}
|
|
2199
|
+
if (id === 'esbuild' || id.startsWith('esbuild/') || id.startsWith('@esbuild/')) {
|
|
2200
|
+
console.log('[runtime] Intercepted esbuild:', id);
|
|
2201
|
+
return __substrateGuestEsbuild(process);
|
|
2202
|
+
}
|
|
2203
|
+
// Intercept prettier - uses createRequire which doesn't work in our runtime
|
|
2204
|
+
if (id === 'prettier' || id.startsWith('prettier/')) {
|
|
2205
|
+
return builtinModules['prettier'];
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
const resolved = __substrateResolve(id);
|
|
2209
|
+
|
|
2210
|
+
// If resolved to a built-in name (shouldn't happen but safety check)
|
|
2211
|
+
if (builtinModules[resolved] && !(resolved === 'fsevents' || resolved === 'chokidar' || resolved === 'readdirp')) {
|
|
2212
|
+
return resolved === 'esbuild' ? __substrateGuestEsbuild(process) : resolved === 'rollup' ? __substrateGuestRollup(process) : builtinModules[resolved];
|
|
2213
|
+
}
|
|
2214
|
+
|
|
2215
|
+
// Also check if resolved path is to rollup, esbuild, or prettier in node_modules
|
|
2216
|
+
if (resolved.includes('/node_modules/rollup/') ||
|
|
2217
|
+
resolved.includes('/node_modules/@rollup/rollup-')) {
|
|
2218
|
+
return __substrateGuestRollup(process);
|
|
2219
|
+
}
|
|
2220
|
+
if ((resolved.includes('/node_modules/esbuild/') ||
|
|
2221
|
+
resolved.includes('/node_modules/@esbuild/')) && !__substrateEsbuildRunsHere(vfs, resolved)) {
|
|
2222
|
+
return __substrateGuestEsbuild(process);
|
|
2223
|
+
}
|
|
2224
|
+
if (resolved.includes('/node_modules/prettier/')) {
|
|
2225
|
+
return builtinModules['prettier'];
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
// A page that can run a package's native side in the browser -- Rolldown's
|
|
2229
|
+
// wasm binding is the one that does -- registers it on the filesystem the
|
|
2230
|
+
// package is installed in, under this symbol: a map from the installed
|
|
2231
|
+
// export file to the module to answer with, made for the process that is
|
|
2232
|
+
// asking. Nothing else about the package changes: it is resolved the
|
|
2233
|
+
// installed way, so `require.resolve` still names the file on disk and its
|
|
2234
|
+
// manifest still says the version; a filesystem with no registration, and
|
|
2235
|
+
// an export path the registration does not name, load the file as before.
|
|
2236
|
+
// The registry was a text patch over the engine's build, which read the
|
|
2237
|
+
// same symbol at the same point; a guest that required the package on an
|
|
2238
|
+
// unpatched build got the installed stub instead of the binding, and every
|
|
2239
|
+
// filesystem in the tab shared whichever binding was loaded last.
|
|
2240
|
+
const registered = (vfs as unknown as Record<symbol, unknown>)[__substrateNativeModules] as
|
|
2241
|
+
| Map<string, (process: unknown) => unknown>
|
|
2242
|
+
| undefined;
|
|
2243
|
+
if (registered && typeof registered.has === 'function') {
|
|
2244
|
+
if (registered.has(resolved)) return registered.get(resolved)!(process);
|
|
2245
|
+
// A registration by package identity, `pkg:<name>@<version>/<file>`,
|
|
2246
|
+
// answers every copy of that version in the tree: a nested copy under
|
|
2247
|
+
// another package, or one pnpm placed in its store, is the same package.
|
|
2248
|
+
const identity = __substratePackageIdentity(vfs, resolved);
|
|
2249
|
+
if (identity && registered.has(identity)) return registered.get(identity)!(process);
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
return loadModule(resolved).exports;
|
|
2253
|
+
};
|
|
2254
|
+
|
|
2255
|
+
require.resolve = (id: string): string => {
|
|
2256
|
+
if (id === 'fs' || id === 'process' || id.startsWith('node:') || moduleShim.builtinModules.includes(id)) {
|
|
2257
|
+
return id;
|
|
2258
|
+
}
|
|
2259
|
+
return resolveModule(id, currentDir);
|
|
2260
|
+
};
|
|
2261
|
+
|
|
2262
|
+
require.cache = moduleCache;
|
|
2263
|
+
(require as any).__requireRaw = requireRaw;
|
|
2264
|
+
(require as any).__compileRaw = (module: Module, content: string, filename: string, dir: string): void => runModuleBody(module, prepareModuleCode(content, filename), filename, dir);
|
|
2265
|
+
(require as any).__resolveRaw = (id: string) => resolveModule(id, currentDir);
|
|
2266
|
+
// The doors `module.register`'s chain reaches this loader through: the run's
|
|
2267
|
+
// hooks, the engine's own resolution in the URL terms a hook speaks, the
|
|
2268
|
+
// read that is the bottom of a load chain, and the load of a module whose
|
|
2269
|
+
// URL, format and source the chain has already settled.
|
|
2270
|
+
(require as any).__moduleHooks = __substrateHooks;
|
|
2271
|
+
(require as any).__resolveToURL = (specifier: string): string => {
|
|
2272
|
+
const hooks = __substrateHooks()!;
|
|
2273
|
+
return hooks.sync.convertCJSFilenameToURL(__substrateNamedModule(specifier) ?? __substrateResolve(specifier));
|
|
2274
|
+
};
|
|
2275
|
+
(require as any).__readFromURL = (url: string): string | null => {
|
|
2276
|
+
// A builtin has no source of its own, and Node's default load answers null
|
|
2277
|
+
// for one rather than reading a file named after it.
|
|
2278
|
+
if (url.startsWith('node:')) return null;
|
|
2279
|
+
if (url.startsWith('data:')) return __substrateDataModuleSource(url)!;
|
|
2280
|
+
return vfs.readFileSync(__substrateHooks()!.sync.convertURLToCJSFilename(url), 'utf8');
|
|
2281
|
+
};
|
|
2282
|
+
(require as any).__loadFromURL = (url: string, format?: string, source?: string | ArrayBuffer | ArrayBufferView | null): unknown => {
|
|
2283
|
+
if (url.startsWith('data:')) return loadModule(url, { url, format, source }).exports;
|
|
2284
|
+
const filename = __substrateHooks()!.sync.convertURLToCJSFilename(url);
|
|
2285
|
+
if (source === undefined && moduleShim.isBuiltin(filename)) return requirePlain(filename);
|
|
2286
|
+
return loadModule(filename, { url, format, source }).exports;
|
|
2287
|
+
};
|
|
2288
|
+
(require as any).extensions = __substrateModule()._extensions;
|
|
2289
|
+
Object.defineProperty(require, 'main', { get: () => (process as any).mainModule, set: (value: unknown) => { (process as any).mainModule = value; }, enumerable: true, configurable: true });
|
|
2290
|
+
|
|
2291
|
+
// A bundle built for Node reaches its builtins through
|
|
2292
|
+
// `process.getBuiltinModule("node:http")` rather than a static import, so that
|
|
2293
|
+
// one call is the first thing it makes of the engine; the guest process had no
|
|
2294
|
+
// such method and the bundle died on its first line. It answers the engine's
|
|
2295
|
+
// own module for a builtin name with or without the `node:` prefix, and
|
|
2296
|
+
// undefined for a name that is not a builtin, as Node does.
|
|
2297
|
+
if (process && typeof process === 'object' && typeof (process as GuestProcess).getBuiltinModule !== 'function') {
|
|
2298
|
+
(process as GuestProcess).getBuiltinModule = (name: string) => {
|
|
2299
|
+
if (typeof name !== 'string') return void 0;
|
|
2300
|
+
const id = name.startsWith('node:') ? name.slice(5) : name;
|
|
2301
|
+
if (id !== 'fs' && id !== 'fs/promises' && id !== 'process' && id !== 'module' && id !== 'wasi' && !Object.prototype.hasOwnProperty.call(builtinModules, id)) return void 0;
|
|
2302
|
+
try { return require(id); } catch (error) { return void 0; }
|
|
2303
|
+
};
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
return require;
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
/**
|
|
2310
|
+
* Create a console wrapper that can capture output
|
|
2311
|
+
*/
|
|
2312
|
+
function createConsoleWrapper(
|
|
2313
|
+
onConsole?: (method: string, args: unknown[]) => void
|
|
2314
|
+
): Console {
|
|
2315
|
+
const wrapper = {
|
|
2316
|
+
log: (...args: unknown[]) => {
|
|
2317
|
+
console.log(...args);
|
|
2318
|
+
onConsole?.('log', args);
|
|
2319
|
+
},
|
|
2320
|
+
error: (...args: unknown[]) => {
|
|
2321
|
+
console.error(...args);
|
|
2322
|
+
onConsole?.('error', args);
|
|
2323
|
+
},
|
|
2324
|
+
warn: (...args: unknown[]) => {
|
|
2325
|
+
console.warn(...args);
|
|
2326
|
+
onConsole?.('warn', args);
|
|
2327
|
+
},
|
|
2328
|
+
info: (...args: unknown[]) => {
|
|
2329
|
+
console.info(...args);
|
|
2330
|
+
onConsole?.('info', args);
|
|
2331
|
+
},
|
|
2332
|
+
debug: (...args: unknown[]) => {
|
|
2333
|
+
console.debug(...args);
|
|
2334
|
+
onConsole?.('debug', args);
|
|
2335
|
+
},
|
|
2336
|
+
trace: (...args: unknown[]) => {
|
|
2337
|
+
console.trace(...args);
|
|
2338
|
+
onConsole?.('trace', args);
|
|
2339
|
+
},
|
|
2340
|
+
dir: (obj: unknown) => {
|
|
2341
|
+
console.dir(obj);
|
|
2342
|
+
onConsole?.('dir', [obj]);
|
|
2343
|
+
},
|
|
2344
|
+
time: console.time.bind(console),
|
|
2345
|
+
timeEnd: console.timeEnd.bind(console),
|
|
2346
|
+
timeLog: console.timeLog.bind(console),
|
|
2347
|
+
assert: console.assert.bind(console),
|
|
2348
|
+
clear: console.clear.bind(console),
|
|
2349
|
+
count: console.count.bind(console),
|
|
2350
|
+
countReset: console.countReset.bind(console),
|
|
2351
|
+
group: console.group.bind(console),
|
|
2352
|
+
groupCollapsed: console.groupCollapsed.bind(console),
|
|
2353
|
+
groupEnd: console.groupEnd.bind(console),
|
|
2354
|
+
table: console.table.bind(console),
|
|
2355
|
+
};
|
|
2356
|
+
|
|
2357
|
+
return wrapper as unknown as Console;
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2360
|
+
/**
|
|
2361
|
+
* Runtime class for executing code in virtual environment
|
|
2362
|
+
* Note: This class has sync methods for backward compatibility.
|
|
2363
|
+
* Use createRuntime() factory for IRuntime interface compliance.
|
|
2364
|
+
*/
|
|
2365
|
+
export class Runtime {
|
|
2366
|
+
private vfs: VirtualFS;
|
|
2367
|
+
private fsShim: FsShim;
|
|
2368
|
+
private process: Process;
|
|
2369
|
+
private moduleCache: Record<string, Module> = {};
|
|
2370
|
+
private options: RuntimeOptions;
|
|
2371
|
+
/** Cache for pre-processed code (after ESM transform) before eval */
|
|
2372
|
+
private processedCodeCache: Map<string, string> = new Map();
|
|
2373
|
+
|
|
2374
|
+
constructor(vfs: VirtualFS, options: RuntimeOptions = {}) {
|
|
2375
|
+
this.vfs = vfs;
|
|
2376
|
+
// Create process first so we can get cwd for fs shim
|
|
2377
|
+
this.process = createProcess({
|
|
2378
|
+
cwd: options.cwd || '/',
|
|
2379
|
+
env: options.env,
|
|
2380
|
+
onStdout: options.onStdout,
|
|
2381
|
+
onStderr: options.onStderr,
|
|
2382
|
+
...(typeof options.stdin === 'string' ? { stdin: options.stdin } : {}),
|
|
2383
|
+
...(options.stdinHeld ? { stdinHeld: true } : {}),
|
|
2384
|
+
...(options.tty ? { tty: true } : {}),
|
|
2385
|
+
...(typeof options.pid === 'number' ? { pid: options.pid } : {}),
|
|
2386
|
+
...(typeof options.ppid === 'number' ? { ppid: options.ppid } : {}),
|
|
2387
|
+
});
|
|
2388
|
+
// The filesystem of this run, on this run's own process. Node's `fs` is
|
|
2389
|
+
// one module for the whole engine and the engine holds one tree per run,
|
|
2390
|
+
// so the binding reads the tree off the process whose code is executing --
|
|
2391
|
+
// the same door every vendored file gets its `process` through.
|
|
2392
|
+
(this.process as unknown as Record<symbol, unknown>)[kRunFilesystem] = vfs;
|
|
2393
|
+
// Create fs shim with cwd getter for relative path resolution
|
|
2394
|
+
this.fsShim = createFsShim(vfs, () => this.process.cwd());
|
|
2395
|
+
this.options = options;
|
|
2396
|
+
|
|
2397
|
+
// Initialize child_process with VFS for bash command support
|
|
2398
|
+
initChildProcess(vfs);
|
|
2399
|
+
|
|
2400
|
+
// Initialize file watcher shims with VFS
|
|
2401
|
+
|
|
2402
|
+
// Initialize esbuild shim with VFS for file access
|
|
2403
|
+
esbuildShim.setVFS(vfs);
|
|
2404
|
+
|
|
2405
|
+
// The realm's own corrections — the ones a guest can only reach through
|
|
2406
|
+
// the realm — are installed here, when a guest is first asked for, and
|
|
2407
|
+
// not when this module is loaded. Importing the engine into someone
|
|
2408
|
+
// else's Node process leaves that process's globals alone;
|
|
2409
|
+
// `restoreHostGlobals()` hands back what a runtime took.
|
|
2410
|
+
installGuestRealm();
|
|
2411
|
+
}
|
|
2412
|
+
|
|
2413
|
+
/**
|
|
2414
|
+
* Execute code as a module (synchronous - backward compatible)
|
|
2415
|
+
*/
|
|
2416
|
+
execute(
|
|
2417
|
+
code: string,
|
|
2418
|
+
filename: string = '/index.js'
|
|
2419
|
+
): { exports: unknown; module: Module } {
|
|
2420
|
+
const dirname = pathShim.dirname(filename);
|
|
2421
|
+
|
|
2422
|
+
// The tree holds the file the run names; it is written only when the
|
|
2423
|
+
// text differs. Every run wrote it, and a file run as it stands in the
|
|
2424
|
+
// tree was rewritten with itself, which fired its watcher (a dev server
|
|
2425
|
+
// watching the project restarted on its own entry being run) and
|
|
2426
|
+
// touched its mtime for nothing.
|
|
2427
|
+
let held: string | undefined;
|
|
2428
|
+
try { held = this.vfs.readFileSync(filename, 'utf8') as string; } catch { held = undefined; }
|
|
2429
|
+
if (held !== code) this.vfs.writeFileSync(filename, code);
|
|
2430
|
+
|
|
2431
|
+
// Create require function
|
|
2432
|
+
const require = createRequire(
|
|
2433
|
+
this.vfs,
|
|
2434
|
+
this.fsShim,
|
|
2435
|
+
this.process,
|
|
2436
|
+
dirname,
|
|
2437
|
+
this.moduleCache,
|
|
2438
|
+
this.options,
|
|
2439
|
+
this.processedCodeCache
|
|
2440
|
+
);
|
|
2441
|
+
|
|
2442
|
+
// Create module object
|
|
2443
|
+
const module: Module = {
|
|
2444
|
+
id: filename,
|
|
2445
|
+
filename,
|
|
2446
|
+
exports: {},
|
|
2447
|
+
loaded: false,
|
|
2448
|
+
children: [],
|
|
2449
|
+
paths: [],
|
|
2450
|
+
};
|
|
2451
|
+
|
|
2452
|
+
// Cache the module
|
|
2453
|
+
this.moduleCache[filename] = module;
|
|
2454
|
+
// The entry module is the main module: `process.mainModule` and
|
|
2455
|
+
// `require.main` name it, and its id is ".", as Node has them, so a program
|
|
2456
|
+
// that runs only when it is the entry (`require.main === module`, which the
|
|
2457
|
+
// Prisma CLI and every bin script written that way tests) runs.
|
|
2458
|
+
if (!(this.process as any).mainModule) {
|
|
2459
|
+
(this.process as any).mainModule = module;
|
|
2460
|
+
module.id = '.';
|
|
2461
|
+
}
|
|
2462
|
+
|
|
2463
|
+
// Create console wrapper
|
|
2464
|
+
const consoleWrapper = createConsoleWrapper(this.options.onConsole);
|
|
2465
|
+
|
|
2466
|
+
// Transform code the same way loadModule does
|
|
2467
|
+
// Strip shebang line if present (e.g. #!/usr/bin/env node)
|
|
2468
|
+
if (code.startsWith('#!')) {
|
|
2469
|
+
code = code.slice(code.indexOf('\n') + 1);
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
// Transform ESM to CJS if needed (AST-based, handles import.meta and dynamic imports too)
|
|
2473
|
+
if (!filename.endsWith('.cjs')) {
|
|
2474
|
+
const lowered = transformEsmToCjs(code, filename);
|
|
2475
|
+
code = lowered === code ? code : `${__substrateModuleMarker}"use strict";\n${lowered}`;
|
|
2476
|
+
} else {
|
|
2477
|
+
// A `.cjs` module skips the ESM transform, and with it the rewrite of
|
|
2478
|
+
// `import(...)` to the engine's dynamic import, so its
|
|
2479
|
+
// `import("fs/promises")` reached the browser's own import and failed on
|
|
2480
|
+
// the bare specifier. The dynamic-import rewrite applies to `.cjs` too.
|
|
2481
|
+
code = transformDynamicImportsRegex(code);
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2484
|
+
// Execute code
|
|
2485
|
+
// Use the same wrapper pattern as loadModule for consistency
|
|
2486
|
+
try {
|
|
2487
|
+
const importMetaUrl = 'file://' + filename;
|
|
2488
|
+
const strictBody = code.startsWith(__substrateModuleMarker);
|
|
2489
|
+
code = __substrateScopeConstructors(code);
|
|
2490
|
+
// The wrapper is one line and the body begins on it, as Node's
|
|
2491
|
+
// `Module.wrap` is one line, so a module's line N is line N of the
|
|
2492
|
+
// script V8 compiles and a stack names the module's own lines. The
|
|
2493
|
+
// header's `var` statements are the module's scope, `globalThis` and
|
|
2494
|
+
// `global` among them for code that reads the process off them
|
|
2495
|
+
// directly; the inner function is what lets the body's own `let` and
|
|
2496
|
+
// `const` shadow that scope. `__substrateSourceURL` names the script.
|
|
2497
|
+
const wrappedCode = `(function($exports, $require, $module, $filename, $dirname, $process, $console, $importMeta, $dynamicImport, __substrateGuestGlobal, __substrateGuestConstructor) { var exports = $exports; var require = $require; var module = $module; var __filename = $filename; var __dirname = $dirname; var process = $process; var console = $console; var import_meta = $importMeta; var __dynamicImport = $dynamicImport; var document = void 0, window = void 0, location = void 0, self = void 0; var globalThis = __substrateGuestGlobal($process); var global = globalThis; var Buffer = globalThis.Buffer; var queueMicrotask = globalThis.queueMicrotask, atob = globalThis.atob, btoa = globalThis.btoa, structuredClone = globalThis.structuredClone, setTimeout = globalThis.setTimeout, clearTimeout = globalThis.clearTimeout, setInterval = globalThis.setInterval, clearInterval = globalThis.clearInterval; globalThis.process = $process; global.process = $process; return (function() {${code}
|
|
2498
|
+
}).call(${strictBody ? 'void 0' : '$module.exports'});
|
|
2499
|
+
})${__substrateSourceURL(filename)}`;
|
|
2500
|
+
|
|
2501
|
+
// Create dynamic import function for this module context
|
|
2502
|
+
const dynamicImport = createDynamicImport(require, filename.startsWith('data:') ? filename : `file://${filename}`);
|
|
2503
|
+
|
|
2504
|
+
// A module with top-level await runs. Node runs a `.js` file of a package
|
|
2505
|
+
// with `"type": "module"` as a module, where `await` is valid at the top;
|
|
2506
|
+
// a module lowered to a function body made V8 refuse vue3-ssr's server at
|
|
2507
|
+
// its first top-level `await`. A body V8 refuses for that reason runs as
|
|
2508
|
+
// an async function body instead.
|
|
2509
|
+
let bodyKind: 'sync' | 'generator' | 'async' = code.includes(__substrateAwaitMarker) ? 'generator' : 'sync';
|
|
2510
|
+
let fn;
|
|
2511
|
+
try {
|
|
2512
|
+
fn = __substrateSloppyEval(bodyKind === 'generator' ? __substrateGeneratorBody(wrappedCode) : wrappedCode);
|
|
2513
|
+
} catch (syntaxError) {
|
|
2514
|
+
if (!(syntaxError instanceof SyntaxError)) throw syntaxError;
|
|
2515
|
+
bodyKind = 'async';
|
|
2516
|
+
try { fn = __substrateSloppyEval(__substrateAsyncBody(wrappedCode)); }
|
|
2517
|
+
catch { throw syntaxError; }
|
|
2518
|
+
}
|
|
2519
|
+
const body = fn(
|
|
2520
|
+
module.exports,
|
|
2521
|
+
require,
|
|
2522
|
+
module,
|
|
2523
|
+
filename,
|
|
2524
|
+
dirname,
|
|
2525
|
+
this.process,
|
|
2526
|
+
consoleWrapper,
|
|
2527
|
+
{ url: importMetaUrl, dirname, filename },
|
|
2528
|
+
dynamicImport,
|
|
2529
|
+
__substrateGuestGlobal,
|
|
2530
|
+
__substrateGuestConstructor
|
|
2531
|
+
);
|
|
2532
|
+
|
|
2533
|
+
const settling = __substrateDriveBody(bodyKind, body, module);
|
|
2534
|
+
if (settling) __substrateKeepPending(module, settling, () => { delete this.moduleCache[filename]; });
|
|
2535
|
+
else module.loaded = true;
|
|
2536
|
+
} catch (error) {
|
|
2537
|
+
delete this.moduleCache[filename];
|
|
2538
|
+
throw error;
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
return { exports: module.exports, module };
|
|
2542
|
+
}
|
|
2543
|
+
|
|
2544
|
+
/**
|
|
2545
|
+
* Execute code as a module (async version for IRuntime interface)
|
|
2546
|
+
* Alias: executeSync() is the same as execute() for backward compatibility
|
|
2547
|
+
*/
|
|
2548
|
+
executeSync = this.execute;
|
|
2549
|
+
|
|
2550
|
+
/**
|
|
2551
|
+
* Execute code as a module (async - for IRuntime interface)
|
|
2552
|
+
*/
|
|
2553
|
+
async executeAsync(
|
|
2554
|
+
code: string,
|
|
2555
|
+
filename: string = '/index.js'
|
|
2556
|
+
): Promise<IExecuteResult> {
|
|
2557
|
+
const result = this.execute(code, filename);
|
|
2558
|
+
const pending = __substratePendingOf(result.exports);
|
|
2559
|
+
if (pending) await pending;
|
|
2560
|
+
return result;
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
/**
|
|
2564
|
+
* Run a file from the virtual file system (synchronous - backward compatible)
|
|
2565
|
+
*/
|
|
2566
|
+
runFile(filename: string): { exports: unknown; module: Module } {
|
|
2567
|
+
// An entry runs at its real path, as Node runs one: Node resolves an
|
|
2568
|
+
// entry's symlinks before loading it (unless --preserve-symlinks), so a
|
|
2569
|
+
// program run through its `.bin` link reads its relative imports and its
|
|
2570
|
+
// package's `type` from where the file is. Run at the link, paraglide's
|
|
2571
|
+
// `.bin` entry resolved `../lib` beside `.bin` and found nothing.
|
|
2572
|
+
let real = filename;
|
|
2573
|
+
try { real = this.vfs.realpathSync(filename) as string; } catch { /* the read below reports it */ }
|
|
2574
|
+
const code = this.vfs.readFileSync(real, 'utf8');
|
|
2575
|
+
return this.execute(code, real);
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2578
|
+
/**
|
|
2579
|
+
* Alias for runFile (backward compatibility)
|
|
2580
|
+
*/
|
|
2581
|
+
runFileSync = this.runFile;
|
|
2582
|
+
|
|
2583
|
+
/**
|
|
2584
|
+
* Run a file from the virtual file system (async - for IRuntime interface)
|
|
2585
|
+
*/
|
|
2586
|
+
async runFileAsync(filename: string): Promise<IExecuteResult> {
|
|
2587
|
+
const result = this.runFile(filename);
|
|
2588
|
+
// An entry still settling, a top-level `await` in it or in what it
|
|
2589
|
+
// imports, has run when it has settled.
|
|
2590
|
+
const pending = __substratePendingOf(result.exports);
|
|
2591
|
+
if (pending) await pending;
|
|
2592
|
+
return result;
|
|
2593
|
+
}
|
|
2594
|
+
|
|
2595
|
+
/**
|
|
2596
|
+
* Clear the module cache
|
|
2597
|
+
*/
|
|
2598
|
+
clearCache(): void {
|
|
2599
|
+
// Clear contents in-place so closures that captured the reference still see the cleared cache
|
|
2600
|
+
for (const key of Object.keys(this.moduleCache)) {
|
|
2601
|
+
delete this.moduleCache[key];
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
|
|
2605
|
+
/**
|
|
2606
|
+
* Get the virtual file system
|
|
2607
|
+
*/
|
|
2608
|
+
getVFS(): VirtualFS {
|
|
2609
|
+
return this.vfs;
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
/**
|
|
2613
|
+
* Get the process object
|
|
2614
|
+
*/
|
|
2615
|
+
getProcess(): Process {
|
|
2616
|
+
return this.process;
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2619
|
+
/**
|
|
2620
|
+
* Create a REPL context that evaluates expressions and persists state.
|
|
2621
|
+
*
|
|
2622
|
+
* Returns an object with an `eval` method that:
|
|
2623
|
+
* - Returns the value of the last expression (unlike `execute` which returns module.exports)
|
|
2624
|
+
* - Persists variables between calls (`var x = 1` then `x` works)
|
|
2625
|
+
* - Has access to `require`, `console`, `process`, `Buffer` (same as execute)
|
|
2626
|
+
*
|
|
2627
|
+
* Security: The eval runs inside a Generator's local scope via direct eval,
|
|
2628
|
+
* NOT in the global scope. Only the runtime's own require/console/process are
|
|
2629
|
+
* exposed — the same sandbox boundary as execute(). Variables created in the
|
|
2630
|
+
* REPL are confined to the generator's closure and cannot leak to the page.
|
|
2631
|
+
*
|
|
2632
|
+
* Note: `const`/`let` are transformed to `var` so they persist across calls
|
|
2633
|
+
* (var hoists to the generator's function scope, const/let are block-scoped
|
|
2634
|
+
* to each eval call and would be lost).
|
|
2635
|
+
*/
|
|
2636
|
+
createREPL(): { eval: (code: string) => unknown } {
|
|
2637
|
+
const require = createRequire(
|
|
2638
|
+
this.vfs,
|
|
2639
|
+
this.fsShim,
|
|
2640
|
+
this.process,
|
|
2641
|
+
'/',
|
|
2642
|
+
this.moduleCache,
|
|
2643
|
+
this.options,
|
|
2644
|
+
this.processedCodeCache
|
|
2645
|
+
);
|
|
2646
|
+
const consoleWrapper = createConsoleWrapper(this.options.onConsole);
|
|
2647
|
+
const process = this.process;
|
|
2648
|
+
const buffer = bufferShim.Buffer;
|
|
2649
|
+
|
|
2650
|
+
// Use a Generator to maintain a persistent eval scope.
|
|
2651
|
+
// Generator functions preserve their local scope across yields, so
|
|
2652
|
+
// var declarations from eval() persist between calls. Direct eval
|
|
2653
|
+
// runs in the generator's scope (not global), providing isolation.
|
|
2654
|
+
const GeneratorFunction = Object.getPrototypeOf(function* () {}).constructor;
|
|
2655
|
+
const replGen = new GeneratorFunction(
|
|
2656
|
+
'require',
|
|
2657
|
+
'console',
|
|
2658
|
+
'process',
|
|
2659
|
+
'Buffer',
|
|
2660
|
+
`var __code, __result;
|
|
2661
|
+
while (true) {
|
|
2662
|
+
__code = yield;
|
|
2663
|
+
try {
|
|
2664
|
+
__result = eval(__code);
|
|
2665
|
+
yield { value: __result, error: null };
|
|
2666
|
+
} catch (e) {
|
|
2667
|
+
yield { value: undefined, error: e };
|
|
2668
|
+
}
|
|
2669
|
+
}`
|
|
2670
|
+
)(require, consoleWrapper, process, buffer);
|
|
2671
|
+
replGen.next(); // prime the generator
|
|
2672
|
+
|
|
2673
|
+
return {
|
|
2674
|
+
eval(code: string): unknown {
|
|
2675
|
+
// Transform const/let to var for persistence across REPL calls.
|
|
2676
|
+
// var declarations in direct eval are added to the enclosing function
|
|
2677
|
+
// scope (the generator), so they survive across yields.
|
|
2678
|
+
const transformed = code.replace(/^\s*(const|let)\s+/gm, 'var ');
|
|
2679
|
+
|
|
2680
|
+
// Try as expression first (wrapping in parens), fall back to statement.
|
|
2681
|
+
// replGen.next(code) sends code to the generator, which evals it and
|
|
2682
|
+
// yields the result — so the result is in the return value of .next().
|
|
2683
|
+
const exprResult = replGen.next('(' + transformed + ')').value as { value: unknown; error: unknown };
|
|
2684
|
+
if (!exprResult.error) {
|
|
2685
|
+
// Advance past the wait-for-code yield so it's ready for next call
|
|
2686
|
+
replGen.next();
|
|
2687
|
+
return exprResult.value;
|
|
2688
|
+
}
|
|
2689
|
+
|
|
2690
|
+
// Expression parse failed — advance past wait-for-code, then try as statement
|
|
2691
|
+
replGen.next();
|
|
2692
|
+
const stmtResult = replGen.next(transformed).value as { value: unknown; error: unknown };
|
|
2693
|
+
if (stmtResult.error) {
|
|
2694
|
+
replGen.next(); // advance past wait-for-code yield
|
|
2695
|
+
throw stmtResult.error;
|
|
2696
|
+
}
|
|
2697
|
+
replGen.next(); // advance past wait-for-code yield
|
|
2698
|
+
return stmtResult.value;
|
|
2699
|
+
},
|
|
2700
|
+
};
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
/**
|
|
2705
|
+
* Create and execute code in a new runtime (synchronous - backward compatible)
|
|
2706
|
+
*/
|
|
2707
|
+
export function execute(
|
|
2708
|
+
code: string,
|
|
2709
|
+
vfs: VirtualFS,
|
|
2710
|
+
options?: RuntimeOptions
|
|
2711
|
+
): { exports: unknown; module: Module } {
|
|
2712
|
+
const runtime = new Runtime(vfs, options);
|
|
2713
|
+
return runtime.execute(code);
|
|
2714
|
+
}
|
|
2715
|
+
|
|
2716
|
+
// Re-export types
|
|
2717
|
+
export type { IRuntime, IExecuteResult, IRuntimeOptions } from './runtime-interface';
|
|
2718
|
+
|
|
2719
|
+
export default Runtime;
|
|
2720
|
+
|
|
2721
|
+
/**
|
|
2722
|
+
* The corrections a guest needs from the realm itself, rather than from its
|
|
2723
|
+
* own global: a constructor it reads by bare name, a prototype it inherits.
|
|
2724
|
+
* Each is registered here when this module loads and installed by the first
|
|
2725
|
+
* `Runtime`, so that a host that only imported the engine keeps its own.
|
|
2726
|
+
*/
|
|
2727
|
+
// Polyfill setImmediate/clearImmediate (Node.js globals not available in browsers)
|
|
2728
|
+
forGuestRealm(() => {
|
|
2729
|
+
if (typeof globalThis.setImmediate === 'undefined') {
|
|
2730
|
+
takeFromHost(globalThis, 'setImmediate', (fn: (...args: unknown[]) => void, ...args: unknown[]) => setTimeout(fn, 0, ...args));
|
|
2731
|
+
takeFromHost(globalThis, 'clearImmediate', (id: number) => clearTimeout(id));
|
|
2732
|
+
}
|
|
2733
|
+
});
|
|
2734
|
+
|
|
2735
|
+
// Node's timers answer a `Timeout` object and a browser's answer a number.
|
|
2736
|
+
// That correction used to be made on the realm, which replaced the
|
|
2737
|
+
// `setTimeout` of any Node process that imported the engine. It is the
|
|
2738
|
+
// guest's, and it is made on the guest's own timers, in
|
|
2739
|
+
// `__substrateTimerFunctions`.
|
|
2740
|
+
|
|
2741
|
+
forGuestRealm(() => {
|
|
2742
|
+
// Node's `fetch` does not apply the fetch specification's
|
|
2743
|
+
// forbidden-request-header guard, and a browser's `Request` constructor
|
|
2744
|
+
// does: `new Request(url, { headers: { host } })` keeps the header on
|
|
2745
|
+
// Node and silently loses it here, along with `connection`,
|
|
2746
|
+
// `content-length`, `origin` and the `sec-`/`proxy-` families. Any
|
|
2747
|
+
// program that wraps a request it was handed in a web `Request` then
|
|
2748
|
+
// reads `null` where Node shows a value. Next's middleware adapter and
|
|
2749
|
+
// its app-router `headers()` both do exactly that, so Dub's middleware
|
|
2750
|
+
// died on its first line reading the authority the request arrived on.
|
|
2751
|
+
//
|
|
2752
|
+
// A request keeps the headers it was built with, as Node keeps them.
|
|
2753
|
+
// What the browser will not *send* is still its own business: this
|
|
2754
|
+
// restores what a program can read, which is what Node's own behaviour
|
|
2755
|
+
// is measured on.
|
|
2756
|
+
if (typeof globalThis.Request === 'function' && !(globalThis.Request as unknown as { __substrateHeaderGuard?: boolean }).__substrateHeaderGuard) {
|
|
2757
|
+
const Native = globalThis.Request;
|
|
2758
|
+
const kept = new WeakMap<object, Headers>();
|
|
2759
|
+
class NodeRequest extends Native {
|
|
2760
|
+
constructor(input: RequestInfo | URL, init?: RequestInit) {
|
|
2761
|
+
super(input as RequestInfo, init);
|
|
2762
|
+
const asked = new Headers(init?.headers ?? (input instanceof Native ? (input as Request).headers : undefined));
|
|
2763
|
+
const headers = new Headers(super.headers);
|
|
2764
|
+
asked.forEach((value, name) => { if (!headers.has(name)) headers.set(name, value); });
|
|
2765
|
+
kept.set(this, headers);
|
|
2766
|
+
}
|
|
2767
|
+
get headers(): Headers {
|
|
2768
|
+
return kept.get(this) ?? super.headers;
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
Object.defineProperty(NodeRequest, '__substrateHeaderGuard', { value: true });
|
|
2772
|
+
Object.defineProperty(NodeRequest, 'name', { value: 'Request', configurable: true });
|
|
2773
|
+
takeFromHost(globalThis, 'Request', NodeRequest);
|
|
2774
|
+
}
|
|
2775
|
+
});
|
|
2776
|
+
|
|
2777
|
+
// Polyfill Error.captureStackTrace/prepareStackTrace for Safari/WebKit
|
|
2778
|
+
// (V8-specific API used by Express's depd and other npm packages)
|
|
2779
|
+
forGuestRealm(__substrateStackTracePolyfill);
|
|
2780
|
+
|
|
2781
|
+
// A call site of a module's body names the module's file, as Node's does.
|
|
2782
|
+
forGuestRealm(__substrateCallSiteFileNames);
|
|
2783
|
+
|
|
2784
|
+
// Polyfill TextDecoder to handle base64/base64url/hex gracefully
|
|
2785
|
+
// (Some CLI tools incorrectly try to use TextDecoder for these)
|
|
2786
|
+
forGuestRealm(__substrateTextDecoderPolyfill);
|
|
2787
|
+
|
|
2788
|
+
/**
|
|
2789
|
+
* Set up a polyfilled TextDecoder that handles binary encodings
|
|
2790
|
+
*/
|
|
2791
|
+
function __substrateTextDecoderPolyfill(): void {
|
|
2792
|
+
const OriginalTextDecoder = globalThis.TextDecoder;
|
|
2793
|
+
// Installed once: wrapping the wrapper would decode through two decoders.
|
|
2794
|
+
if ((OriginalTextDecoder as unknown as { __substrateBinaryEncodings?: boolean }).__substrateBinaryEncodings) return;
|
|
2795
|
+
|
|
2796
|
+
class PolyfillTextDecoder {
|
|
2797
|
+
private encoding: string;
|
|
2798
|
+
private decoder: TextDecoder | null = null;
|
|
2799
|
+
|
|
2800
|
+
constructor(encoding: string = 'utf-8', options?: TextDecoderOptions) {
|
|
2801
|
+
this.encoding = encoding.toLowerCase();
|
|
2802
|
+
|
|
2803
|
+
// For valid text encodings, use the real TextDecoder
|
|
2804
|
+
const validTextEncodings = [
|
|
2805
|
+
'utf-8', 'utf8', 'utf-16le', 'utf-16be', 'utf-16',
|
|
2806
|
+
'ascii', 'iso-8859-1', 'latin1', 'windows-1252'
|
|
2807
|
+
];
|
|
2808
|
+
|
|
2809
|
+
if (validTextEncodings.includes(this.encoding)) {
|
|
2810
|
+
try {
|
|
2811
|
+
this.decoder = new OriginalTextDecoder(encoding, options);
|
|
2812
|
+
} catch {
|
|
2813
|
+
// Fall back to utf-8
|
|
2814
|
+
this.decoder = new OriginalTextDecoder('utf-8', options);
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
// For binary encodings (base64, base64url, hex), decoder stays null
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2820
|
+
decode(input?: BufferSource, options?: TextDecodeOptions): string {
|
|
2821
|
+
if (this.decoder) {
|
|
2822
|
+
return this.decoder.decode(input, options);
|
|
2823
|
+
}
|
|
2824
|
+
|
|
2825
|
+
// Handle binary encodings manually
|
|
2826
|
+
if (!input) return '';
|
|
2827
|
+
|
|
2828
|
+
const bytes = input instanceof ArrayBuffer
|
|
2829
|
+
? new Uint8Array(input)
|
|
2830
|
+
: new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
|
|
2831
|
+
|
|
2832
|
+
if (this.encoding === 'base64') {
|
|
2833
|
+
return uint8ToBase64(bytes);
|
|
2834
|
+
}
|
|
2835
|
+
|
|
2836
|
+
if (this.encoding === 'base64url') {
|
|
2837
|
+
return uint8ToBase64(bytes).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2840
|
+
if (this.encoding === 'hex') {
|
|
2841
|
+
return uint8ToHex(bytes);
|
|
2842
|
+
}
|
|
2843
|
+
|
|
2844
|
+
// Fallback: decode as utf-8
|
|
2845
|
+
return new OriginalTextDecoder('utf-8').decode(input, options);
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2848
|
+
get fatal(): boolean {
|
|
2849
|
+
return this.decoder?.fatal ?? false;
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
get ignoreBOM(): boolean {
|
|
2853
|
+
return this.decoder?.ignoreBOM ?? false;
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
|
|
2857
|
+
Object.defineProperty(PolyfillTextDecoder, '__substrateBinaryEncodings', { value: true });
|
|
2858
|
+
takeFromHost(globalThis, 'TextDecoder', PolyfillTextDecoder);
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2861
|
+
/**
|
|
2862
|
+
* Polyfill V8's Error.captureStackTrace and Error.prepareStackTrace for Safari/WebKit.
|
|
2863
|
+
* Express's `depd` and other npm packages use these V8-specific APIs which don't
|
|
2864
|
+
* exist in Safari, causing "callSite.getFileName is not a function" errors.
|
|
2865
|
+
*/
|
|
2866
|
+
function __substrateStackTracePolyfill(): void {
|
|
2867
|
+
// Only polyfill if not already available (i.e., not V8/Chrome)
|
|
2868
|
+
if (typeof (Error as any).captureStackTrace === 'function') return;
|
|
2869
|
+
|
|
2870
|
+
// Set a default stackTraceLimit so Math.max(10, undefined) doesn't produce NaN
|
|
2871
|
+
// (depd and other packages read this value)
|
|
2872
|
+
if ((Error as any).stackTraceLimit === undefined) {
|
|
2873
|
+
takeFromHost(Error, 'stackTraceLimit', 10);
|
|
2874
|
+
}
|
|
2875
|
+
|
|
2876
|
+
// Parse a stack trace string into structured frames
|
|
2877
|
+
function parseStack(stack: string): Array<{fn: string, file: string, line: number, col: number}> {
|
|
2878
|
+
if (!stack) return [];
|
|
2879
|
+
const frames: Array<{fn: string, file: string, line: number, col: number}> = [];
|
|
2880
|
+
const lines = stack.split('\n');
|
|
2881
|
+
|
|
2882
|
+
for (const raw of lines) {
|
|
2883
|
+
const line = raw.trim();
|
|
2884
|
+
if (!line || line.startsWith('Error') || line.startsWith('TypeError')) continue;
|
|
2885
|
+
|
|
2886
|
+
let fn = '', file = '', lineNo = 0, colNo = 0;
|
|
2887
|
+
|
|
2888
|
+
// Safari format: "functionName@file:line:col" or "@file:line:col"
|
|
2889
|
+
const safariMatch = line.match(/^(.*)@(.*?):(\d+):(\d+)$/);
|
|
2890
|
+
if (safariMatch) {
|
|
2891
|
+
fn = safariMatch[1] || '';
|
|
2892
|
+
file = safariMatch[2];
|
|
2893
|
+
lineNo = parseInt(safariMatch[3], 10);
|
|
2894
|
+
colNo = parseInt(safariMatch[4], 10);
|
|
2895
|
+
frames.push({ fn, file, line: lineNo, col: colNo });
|
|
2896
|
+
continue;
|
|
2897
|
+
}
|
|
2898
|
+
|
|
2899
|
+
// Chrome format: "at functionName (file:line:col)" or "at file:line:col"
|
|
2900
|
+
const chromeMatch = line.match(/^at\s+(?:(.+?)\s+\()?(.*?):(\d+):(\d+)\)?$/);
|
|
2901
|
+
if (chromeMatch) {
|
|
2902
|
+
fn = chromeMatch[1] || '';
|
|
2903
|
+
file = chromeMatch[2];
|
|
2904
|
+
lineNo = parseInt(chromeMatch[3], 10);
|
|
2905
|
+
colNo = parseInt(chromeMatch[4], 10);
|
|
2906
|
+
frames.push({ fn, file, line: lineNo, col: colNo });
|
|
2907
|
+
continue;
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
return frames;
|
|
2911
|
+
}
|
|
2912
|
+
|
|
2913
|
+
// Create a mock CallSite object from a parsed frame
|
|
2914
|
+
function createCallSite(frame: {fn: string, file: string, line: number, col: number}) {
|
|
2915
|
+
return {
|
|
2916
|
+
getFileName: () => frame.file || null,
|
|
2917
|
+
getLineNumber: () => frame.line || null,
|
|
2918
|
+
getColumnNumber: () => frame.col || null,
|
|
2919
|
+
getFunctionName: () => frame.fn || null,
|
|
2920
|
+
getMethodName: () => frame.fn || null,
|
|
2921
|
+
getTypeName: () => null,
|
|
2922
|
+
getThis: () => undefined,
|
|
2923
|
+
getFunction: () => undefined,
|
|
2924
|
+
getEvalOrigin: () => undefined,
|
|
2925
|
+
isNative: () => false,
|
|
2926
|
+
isConstructor: () => false,
|
|
2927
|
+
isToplevel: () => !frame.fn,
|
|
2928
|
+
isEval: () => false,
|
|
2929
|
+
toString: () => frame.fn
|
|
2930
|
+
? `${frame.fn} (${frame.file}:${frame.line}:${frame.col})`
|
|
2931
|
+
: `${frame.file}:${frame.line}:${frame.col}`,
|
|
2932
|
+
};
|
|
2933
|
+
}
|
|
2934
|
+
|
|
2935
|
+
// Helper: parse stack and create CallSite objects, used by both captureStackTrace and .stack getter
|
|
2936
|
+
function buildCallSites(stack: string, constructorOpt?: Function) {
|
|
2937
|
+
const frames = parseStack(stack);
|
|
2938
|
+
let startIdx = 0;
|
|
2939
|
+
if (constructorOpt && constructorOpt.name) {
|
|
2940
|
+
for (let i = 0; i < frames.length; i++) {
|
|
2941
|
+
if (frames[i].fn === constructorOpt.name) {
|
|
2942
|
+
startIdx = i + 1;
|
|
2943
|
+
break;
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2947
|
+
return frames.slice(startIdx).map(createCallSite);
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2950
|
+
// Symbol to store raw stack string, used by the .stack getter
|
|
2951
|
+
const stackSymbol = Symbol('rawStack');
|
|
2952
|
+
|
|
2953
|
+
// Intercept .stack on Error.prototype so that packages using the V8 pattern
|
|
2954
|
+
// "Error.prepareStackTrace = fn; new Error().stack" also get CallSite objects.
|
|
2955
|
+
// In V8, reading .stack lazily triggers prepareStackTrace; Safari doesn't do this.
|
|
2956
|
+
defineOnHost(Error.prototype, 'stack', {
|
|
2957
|
+
get() {
|
|
2958
|
+
const rawStack = (this as any)[stackSymbol];
|
|
2959
|
+
if (rawStack !== undefined && typeof (Error as any).prepareStackTrace === 'function') {
|
|
2960
|
+
const callSites = buildCallSites(rawStack);
|
|
2961
|
+
try {
|
|
2962
|
+
return (Error as any).prepareStackTrace(this, callSites);
|
|
2963
|
+
} catch {
|
|
2964
|
+
return rawStack;
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2967
|
+
return rawStack;
|
|
2968
|
+
},
|
|
2969
|
+
set(value: string) {
|
|
2970
|
+
(this as any)[stackSymbol] = value;
|
|
2971
|
+
},
|
|
2972
|
+
configurable: true,
|
|
2973
|
+
enumerable: false,
|
|
2974
|
+
});
|
|
2975
|
+
|
|
2976
|
+
// Polyfill Error.captureStackTrace
|
|
2977
|
+
const captureStackTrace = function(target: any, constructorOpt?: Function) {
|
|
2978
|
+
// Temporarily clear prepareStackTrace to get the raw stack string
|
|
2979
|
+
// (otherwise our .stack getter would call prepareStackTrace recursively)
|
|
2980
|
+
const savedPrepare = (Error as any).prepareStackTrace;
|
|
2981
|
+
(Error as any).prepareStackTrace = undefined;
|
|
2982
|
+
const err = new Error();
|
|
2983
|
+
const rawStack = err.stack || '';
|
|
2984
|
+
(Error as any).prepareStackTrace = savedPrepare;
|
|
2985
|
+
|
|
2986
|
+
// If prepareStackTrace is set, provide structured call sites
|
|
2987
|
+
if (typeof savedPrepare === 'function') {
|
|
2988
|
+
const callSites = buildCallSites(rawStack, constructorOpt);
|
|
2989
|
+
try {
|
|
2990
|
+
target.stack = savedPrepare(target, callSites);
|
|
2991
|
+
} catch (e) {
|
|
2992
|
+
console.warn('[tabnode] Error.prepareStackTrace threw:', e);
|
|
2993
|
+
target.stack = rawStack;
|
|
2994
|
+
}
|
|
2995
|
+
} else {
|
|
2996
|
+
target.stack = rawStack;
|
|
2997
|
+
}
|
|
2998
|
+
};
|
|
2999
|
+
takeFromHost(Error, 'captureStackTrace', captureStackTrace);
|
|
3000
|
+
}
|
|
3001
|
+
|
|
3002
|
+
/**
|
|
3003
|
+
* A call site of a module's body answers `getFileName()` with the module's
|
|
3004
|
+
* file, as a call site of a file Node compiled does.
|
|
3005
|
+
*
|
|
3006
|
+
* The engine evaluates a module's body, and the `//# sourceURL=` directive the
|
|
3007
|
+
* wrapper carries names that script in the stack's text and in
|
|
3008
|
+
* `getScriptNameOrSourceURL()` — but V8 leaves `getFileName()` null for an
|
|
3009
|
+
* eval'd frame whatever the script is named. The `bindings` package, how
|
|
3010
|
+
* `@vscode/spdlog` and `@vscode/native-watchdog` find their `.node` file, sets
|
|
3011
|
+
* `Error.prepareStackTrace`, reads its caller's `getFileName()` and calls
|
|
3012
|
+
* `.indexOf` on it, so openvscode-server's extension host died in
|
|
3013
|
+
* `TypeError: Cannot read properties of undefined (reading 'indexOf')` at
|
|
3014
|
+
* `bindings.getFileName`.
|
|
3015
|
+
*
|
|
3016
|
+
* V8 reads `Error.prepareStackTrace` as an ordinary property, so the realm
|
|
3017
|
+
* holds the guest's function and hands V8 one that names the frames first. A
|
|
3018
|
+
* frame V8 names itself is passed through untouched, and so is a frame of a
|
|
3019
|
+
* guest's own `eval`, which carries no name to give. The guest reads back one
|
|
3020
|
+
* function per function it set, so the save-and-restore every package writes
|
|
3021
|
+
* around `prepareStackTrace` restores what it saved.
|
|
3022
|
+
*/
|
|
3023
|
+
function __substrateCallSiteFileNames(): void {
|
|
3024
|
+
// Safari has no V8 call sites; there the engine builds them itself from the
|
|
3025
|
+
// stack's text, where the script's name is already all there is.
|
|
3026
|
+
if (typeof (Error as { captureStackTrace?: unknown }).captureStackTrace !== 'function') return;
|
|
3027
|
+
interface CallSite { getFileName(): string | null; getScriptNameOrSourceURL?(): string | null }
|
|
3028
|
+
type Prepare = (error: unknown, sites: CallSite[]) => unknown;
|
|
3029
|
+
const held = Object.getOwnPropertyDescriptor(Error, 'prepareStackTrace');
|
|
3030
|
+
if ((held?.get as { __substrateNamesFrames?: boolean } | undefined)?.__substrateNamesFrames) return;
|
|
3031
|
+
// A guest may pin `Error.prepareStackTrace` on the realm -- a source-map
|
|
3032
|
+
// package defines it without `configurable` -- and the realm's `Error` is
|
|
3033
|
+
// shared by every run the engine holds. Naming frames is a nicety; a
|
|
3034
|
+
// process that cannot install it still runs. The define threw instead, and
|
|
3035
|
+
// in the tab every run started after the one that pinned it died before its
|
|
3036
|
+
// first line with `node: Cannot redefine property: prepareStackTrace` --
|
|
3037
|
+
// measured through the page's shell on v0.2.14-volter.63, where it made the
|
|
3038
|
+
// shell unusable while openvscode-server kept running.
|
|
3039
|
+
if (held !== undefined && held.configurable === false) return;
|
|
3040
|
+
|
|
3041
|
+
const named = (site: CallSite): CallSite => new Proxy(site, {
|
|
3042
|
+
get(target, key) {
|
|
3043
|
+
if (key === 'getFileName') return () => target.getFileName() ?? (target.getScriptNameOrSourceURL?.() || null);
|
|
3044
|
+
const value = Reflect.get(target, key) as unknown;
|
|
3045
|
+
// A call site's methods read the frame off their own receiver, which a
|
|
3046
|
+
// proxy is not: each is handed back bound to the frame itself.
|
|
3047
|
+
return typeof value === 'function' ? (value as (...args: unknown[]) => unknown).bind(target) : value;
|
|
3048
|
+
},
|
|
3049
|
+
});
|
|
3050
|
+
|
|
3051
|
+
let guestPrepare: unknown = held && !held.get && !held.set ? held.value : undefined;
|
|
3052
|
+
const namers = new WeakMap<object, Prepare>();
|
|
3053
|
+
const guests = new WeakMap<object, unknown>();
|
|
3054
|
+
const namerFor = (prepare: Prepare): Prepare => {
|
|
3055
|
+
let namer = namers.get(prepare);
|
|
3056
|
+
if (!namer) {
|
|
3057
|
+
namer = (error, sites) => prepare(error, sites.map(named));
|
|
3058
|
+
namers.set(prepare, namer);
|
|
3059
|
+
guests.set(namer, prepare);
|
|
3060
|
+
}
|
|
3061
|
+
return namer;
|
|
3062
|
+
};
|
|
3063
|
+
const get = () => (typeof guestPrepare === 'function' ? namerFor(guestPrepare as Prepare) : guestPrepare);
|
|
3064
|
+
(get as { __substrateNamesFrames?: boolean }).__substrateNamesFrames = true;
|
|
3065
|
+
defineOnHost(Error, 'prepareStackTrace', {
|
|
3066
|
+
get,
|
|
3067
|
+
set(prepare: unknown) {
|
|
3068
|
+
guestPrepare = typeof prepare === 'function' && guests.has(prepare as object) ? guests.get(prepare as object) : prepare;
|
|
3069
|
+
},
|
|
3070
|
+
configurable: true,
|
|
3071
|
+
enumerable: false,
|
|
3072
|
+
});
|
|
3073
|
+
}
|