@scelar/nodepod 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/LICENSE +43 -0
  2. package/README.md +240 -0
  3. package/dist/child_process-BJOMsZje.js +8233 -0
  4. package/dist/child_process-BJOMsZje.js.map +1 -0
  5. package/dist/child_process-Cj8vOcuc.cjs +7434 -0
  6. package/dist/child_process-Cj8vOcuc.cjs.map +1 -0
  7. package/dist/index-Cb1Cgdnd.js +35308 -0
  8. package/dist/index-Cb1Cgdnd.js.map +1 -0
  9. package/dist/index-DsMGS-xc.cjs +37195 -0
  10. package/dist/index-DsMGS-xc.cjs.map +1 -0
  11. package/dist/index.cjs +65 -0
  12. package/dist/index.cjs.map +1 -0
  13. package/dist/index.mjs +59 -0
  14. package/dist/index.mjs.map +1 -0
  15. package/package.json +95 -0
  16. package/src/__tests__/smoke.test.ts +11 -0
  17. package/src/constants/cdn-urls.ts +18 -0
  18. package/src/constants/config.ts +236 -0
  19. package/src/cross-origin.ts +26 -0
  20. package/src/engine-factory.ts +176 -0
  21. package/src/engine-types.ts +56 -0
  22. package/src/helpers/byte-encoding.ts +39 -0
  23. package/src/helpers/digest.ts +9 -0
  24. package/src/helpers/event-loop.ts +96 -0
  25. package/src/helpers/wasm-cache.ts +133 -0
  26. package/src/iframe-sandbox.ts +141 -0
  27. package/src/index.ts +192 -0
  28. package/src/isolation-helpers.ts +148 -0
  29. package/src/memory-volume.ts +941 -0
  30. package/src/module-transformer.ts +368 -0
  31. package/src/packages/archive-extractor.ts +248 -0
  32. package/src/packages/browser-bundler.ts +284 -0
  33. package/src/packages/installer.ts +396 -0
  34. package/src/packages/registry-client.ts +131 -0
  35. package/src/packages/version-resolver.ts +411 -0
  36. package/src/polyfills/assert.ts +384 -0
  37. package/src/polyfills/async_hooks.ts +144 -0
  38. package/src/polyfills/buffer.ts +628 -0
  39. package/src/polyfills/child_process.ts +2288 -0
  40. package/src/polyfills/chokidar.ts +336 -0
  41. package/src/polyfills/cluster.ts +106 -0
  42. package/src/polyfills/console.ts +136 -0
  43. package/src/polyfills/constants.ts +123 -0
  44. package/src/polyfills/crypto.ts +885 -0
  45. package/src/polyfills/dgram.ts +87 -0
  46. package/src/polyfills/diagnostics_channel.ts +76 -0
  47. package/src/polyfills/dns.ts +134 -0
  48. package/src/polyfills/domain.ts +68 -0
  49. package/src/polyfills/esbuild.ts +854 -0
  50. package/src/polyfills/events.ts +276 -0
  51. package/src/polyfills/fs.ts +2888 -0
  52. package/src/polyfills/fsevents.ts +79 -0
  53. package/src/polyfills/http.ts +1449 -0
  54. package/src/polyfills/http2.ts +199 -0
  55. package/src/polyfills/https.ts +76 -0
  56. package/src/polyfills/inspector.ts +62 -0
  57. package/src/polyfills/lightningcss.ts +105 -0
  58. package/src/polyfills/module.ts +191 -0
  59. package/src/polyfills/net.ts +353 -0
  60. package/src/polyfills/os.ts +238 -0
  61. package/src/polyfills/path.ts +206 -0
  62. package/src/polyfills/perf_hooks.ts +102 -0
  63. package/src/polyfills/process.ts +690 -0
  64. package/src/polyfills/punycode.ts +159 -0
  65. package/src/polyfills/querystring.ts +93 -0
  66. package/src/polyfills/quic.ts +118 -0
  67. package/src/polyfills/readdirp.ts +229 -0
  68. package/src/polyfills/readline.ts +692 -0
  69. package/src/polyfills/repl.ts +134 -0
  70. package/src/polyfills/rollup.ts +119 -0
  71. package/src/polyfills/sea.ts +33 -0
  72. package/src/polyfills/sqlite.ts +78 -0
  73. package/src/polyfills/stream.ts +1620 -0
  74. package/src/polyfills/string_decoder.ts +25 -0
  75. package/src/polyfills/tailwindcss-oxide.ts +309 -0
  76. package/src/polyfills/test.ts +197 -0
  77. package/src/polyfills/timers.ts +32 -0
  78. package/src/polyfills/tls.ts +105 -0
  79. package/src/polyfills/trace_events.ts +50 -0
  80. package/src/polyfills/tty.ts +71 -0
  81. package/src/polyfills/url.ts +174 -0
  82. package/src/polyfills/util.ts +559 -0
  83. package/src/polyfills/v8.ts +126 -0
  84. package/src/polyfills/vm.ts +132 -0
  85. package/src/polyfills/volume-registry.ts +15 -0
  86. package/src/polyfills/wasi.ts +44 -0
  87. package/src/polyfills/worker_threads.ts +326 -0
  88. package/src/polyfills/ws.ts +595 -0
  89. package/src/polyfills/zlib.ts +881 -0
  90. package/src/request-proxy.ts +716 -0
  91. package/src/script-engine.ts +3375 -0
  92. package/src/sdk/nodepod-fs.ts +93 -0
  93. package/src/sdk/nodepod-process.ts +86 -0
  94. package/src/sdk/nodepod-terminal.ts +350 -0
  95. package/src/sdk/nodepod.ts +509 -0
  96. package/src/sdk/types.ts +70 -0
  97. package/src/shell/commands/bun.ts +121 -0
  98. package/src/shell/commands/directory.ts +297 -0
  99. package/src/shell/commands/file-ops.ts +525 -0
  100. package/src/shell/commands/git.ts +2142 -0
  101. package/src/shell/commands/node.ts +80 -0
  102. package/src/shell/commands/npm.ts +198 -0
  103. package/src/shell/commands/pm-types.ts +45 -0
  104. package/src/shell/commands/pnpm.ts +82 -0
  105. package/src/shell/commands/search.ts +264 -0
  106. package/src/shell/commands/shell-env.ts +352 -0
  107. package/src/shell/commands/text-processing.ts +1152 -0
  108. package/src/shell/commands/yarn.ts +84 -0
  109. package/src/shell/shell-builtins.ts +19 -0
  110. package/src/shell/shell-helpers.ts +250 -0
  111. package/src/shell/shell-interpreter.ts +514 -0
  112. package/src/shell/shell-parser.ts +429 -0
  113. package/src/shell/shell-types.ts +85 -0
  114. package/src/syntax-transforms.ts +561 -0
  115. package/src/threading/engine-worker.ts +64 -0
  116. package/src/threading/inline-worker.ts +372 -0
  117. package/src/threading/offload-types.ts +112 -0
  118. package/src/threading/offload-worker.ts +383 -0
  119. package/src/threading/offload.ts +271 -0
  120. package/src/threading/process-context.ts +92 -0
  121. package/src/threading/process-handle.ts +275 -0
  122. package/src/threading/process-manager.ts +956 -0
  123. package/src/threading/process-worker-entry.ts +854 -0
  124. package/src/threading/shared-vfs.ts +352 -0
  125. package/src/threading/sync-channel.ts +135 -0
  126. package/src/threading/task-queue.ts +177 -0
  127. package/src/threading/vfs-bridge.ts +231 -0
  128. package/src/threading/worker-pool.ts +233 -0
  129. package/src/threading/worker-protocol.ts +358 -0
  130. package/src/threading/worker-vfs.ts +218 -0
  131. package/src/types/externals.d.ts +38 -0
  132. package/src/types/fs-streams.ts +142 -0
  133. package/src/types/manifest.ts +17 -0
  134. package/src/worker-sandbox.ts +90 -0
@@ -0,0 +1,3375 @@
1
+ // ScriptEngine — JS execution engine with require(), module resolution,
2
+ // ESM-to-CJS conversion, and Node.js polyfills. Runs in the browser.
3
+
4
+ import { MemoryVolume } from "./memory-volume";
5
+ import type {
6
+ IScriptEngine,
7
+ ExecutionOutcome,
8
+ EngineConfig,
9
+ LoadedModule,
10
+ } from "./engine-types";
11
+ import type { PackageManifest } from "./types/manifest";
12
+ import { quickDigest } from "./helpers/digest";
13
+ import { bytesToBase64, bytesToHex } from "./helpers/byte-encoding";
14
+ import { buildFileSystemBridge, FsBridge } from "./polyfills/fs";
15
+ import * as pathPolyfill from "./polyfills/path";
16
+ import {
17
+ RESOLVE_EXTENSIONS,
18
+ MAIN_FIELD_EXTENSIONS,
19
+ INDEX_FILES,
20
+ IMPORTS_FIELD_EXTENSIONS,
21
+ LIMITS,
22
+ } from "./constants/config";
23
+ import { buildProcessEnv, ProcessObject } from "./polyfills/process";
24
+ import * as httpPolyfill from "./polyfills/http";
25
+ import * as httpsPolyfill from "./polyfills/https";
26
+ import * as tcpPolyfill from "./polyfills/net";
27
+ import eventBusPolyfill from "./polyfills/events";
28
+ import streamPolyfill from "./polyfills/stream";
29
+ import * as urlPolyfill from "./polyfills/url";
30
+ import * as qsPolyfill from "./polyfills/querystring";
31
+ import * as helpersPolyfill from "./polyfills/util";
32
+ import * as ttyPolyfill from "./polyfills/tty";
33
+ import * as osPolyfill from "./polyfills/os";
34
+ import * as hashingPolyfill from "./polyfills/crypto";
35
+ import * as compressionPolyfill from "./polyfills/zlib";
36
+ import * as dnsPolyfill from "./polyfills/dns";
37
+ import bufferPolyfill from "./polyfills/buffer";
38
+ // child_process is lazy-loaded to avoid pulling in the shell at import time
39
+ let _shellExecPolyfill: any = null;
40
+ let _initShellExec: ((vol: any) => void) | null = null;
41
+ const shellExecProxy = new Proxy({} as any, {
42
+ get(_target, prop) {
43
+ if (!_shellExecPolyfill) return undefined;
44
+ return _shellExecPolyfill[prop];
45
+ },
46
+ ownKeys() {
47
+ if (!_shellExecPolyfill) return [];
48
+ return Reflect.ownKeys(_shellExecPolyfill);
49
+ },
50
+ getOwnPropertyDescriptor(_target, prop) {
51
+ if (!_shellExecPolyfill) return undefined;
52
+ return Object.getOwnPropertyDescriptor(_shellExecPolyfill, prop);
53
+ },
54
+ has(_target, prop) {
55
+ if (!_shellExecPolyfill) return false;
56
+ return prop in _shellExecPolyfill;
57
+ },
58
+ });
59
+
60
+ // Set eagerly so require('child_process') works sync in workers.
61
+ // The async .then() in the constructor fires too late for top-level require() calls.
62
+ export function setChildProcessPolyfill(mod: any): void {
63
+ _shellExecPolyfill = mod;
64
+ _initShellExec = mod.initShellExec;
65
+ }
66
+ import { getProxyInstance } from "./request-proxy";
67
+ import * as watcherPolyfill from "./polyfills/chokidar";
68
+ import * as wsPolyfill from "./polyfills/ws";
69
+ import * as macEventsPolyfill from "./polyfills/fsevents";
70
+ import * as scannerPolyfill from "./polyfills/readdirp";
71
+ import * as moduleSysPolyfill from "./polyfills/module";
72
+ import * as perfPolyfill from "./polyfills/perf_hooks";
73
+ import * as threadPoolPolyfill from "./polyfills/worker_threads";
74
+ import * as esbuildPolyfill from "./polyfills/esbuild";
75
+ import * as rollupPolyfill from "./polyfills/rollup";
76
+ import * as v8Polyfill from "./polyfills/v8";
77
+ import * as lineReaderPolyfill from "./polyfills/readline";
78
+ import * as tlsPolyfill from "./polyfills/tls";
79
+ import * as http2Polyfill from "./polyfills/http2";
80
+ import * as clusterPolyfill from "./polyfills/cluster";
81
+ import * as udpPolyfill from "./polyfills/dgram";
82
+ import * as vmPolyfill from "./polyfills/vm";
83
+ import * as debugPolyfill from "./polyfills/inspector";
84
+ import * as asyncCtxPolyfill from "./polyfills/async_hooks";
85
+ import * as domainPolyfill from "./polyfills/domain";
86
+ import * as tracePolyfill from "./polyfills/diagnostics_channel";
87
+ import * as consolePolyfill from "./polyfills/console";
88
+ import * as replPolyfill from "./polyfills/repl";
89
+ import * as testPolyfill from "./polyfills/test";
90
+ import * as traceEventsPolyfill from "./polyfills/trace_events";
91
+ import * as wasiPolyfill from "./polyfills/wasi";
92
+ import * as seaPolyfill from "./polyfills/sea";
93
+ import * as sqlitePolyfill from "./polyfills/sqlite";
94
+ import * as quicPolyfill from "./polyfills/quic";
95
+ import * as lightningcssPolyfill from "./polyfills/lightningcss";
96
+ import * as tailwindOxidePolyfill from "./polyfills/tailwindcss-oxide";
97
+ import {
98
+ promises as streamPromises,
99
+ Readable,
100
+ Writable,
101
+ Duplex,
102
+ Transform,
103
+ PassThrough,
104
+ } from "./polyfills/stream";
105
+ import { promises as dnsPromises } from "./polyfills/dns";
106
+ import { promises as readlinePromises } from "./polyfills/readline";
107
+
108
+ import assertPolyfill from "./polyfills/assert";
109
+ import stringDecoderPolyfill from "./polyfills/string_decoder";
110
+ import timersPolyfill from "./polyfills/timers";
111
+ import { promises as timersPromises } from "./polyfills/timers";
112
+ import * as punycodePolyfill from "./polyfills/punycode";
113
+ import constantsPolyfill from "./polyfills/constants";
114
+ import {
115
+ resolve as resolveExports,
116
+ imports as resolveImports,
117
+ } from "resolve.exports";
118
+ import {
119
+ esmToCjs,
120
+ stripTopLevelAwait,
121
+ hasTopLevelAwait,
122
+ } from "./syntax-transforms";
123
+ import { getCachedModule, precompileWasm, compileWasmInWorker } from "./helpers/wasm-cache";
124
+ import * as acorn from "acorn";
125
+
126
+ // ── TypeScript type stripper ──
127
+ // Regex-based stripping of TS syntax so acorn/eval can handle it at runtime.
128
+
129
+ function stripTypeScript(source: string): string {
130
+ let s = source;
131
+
132
+ s = s.replace(
133
+ /^\s*declare\s+(module|namespace|global)\s+[^{]*\{[^}]*(?:\{[^}]*\}[^}]*)*\}/gm,
134
+ "",
135
+ );
136
+ s = s.replace(
137
+ /^\s*declare\s+(?:const|let|var|function|class|enum|type|interface)\s+[^;\n]+[;\n]/gm,
138
+ "",
139
+ );
140
+
141
+ s = s.replace(
142
+ /^\s*(?:export\s+)?interface\s+\w+(?:\s+extends\s+[^{]+)?\s*\{[^}]*(?:\{[^}]*\}[^}]*)*\}/gm,
143
+ "",
144
+ );
145
+
146
+ s = s.replace(/^\s*(?:export\s+)?type\s+\w+(?:<[^>]*>)?\s*=\s*[^;]+;/gm, "");
147
+
148
+ s = s.replace(
149
+ /^\s*export\s+type\s*\{[^}]*\}\s*(?:from\s*['"][^'"]*['"])?\s*;?/gm,
150
+ "",
151
+ );
152
+ s = s.replace(
153
+ /^\s*import\s+type\s+(?:\{[^}]*\}|\w+)\s*(?:from\s*['"][^'"]*['"])?\s*;?/gm,
154
+ "",
155
+ );
156
+
157
+ s = s.replace(/\bas\s+const\b/g, "");
158
+ s = s.replace(/\s+as\s+(?:[A-Z][\w.<>,\s|&\[\]]*)/g, "");
159
+
160
+ s = s.replace(
161
+ /(function\s+\w+|(?:const|let|var)\s+\w+\s*=\s*(?:async\s+)?(?:function\s*)?)\s*<[^(]*?>\s*\(/g,
162
+ "$1(",
163
+ );
164
+
165
+ // Strip type annotations from params and return types
166
+ s = s.replace(
167
+ /:\s*(?:readonly\s+)?(?:[A-Z][\w.<>,\s|&\[\]]*|string|number|boolean|void|any|never|unknown|null|undefined|object|bigint)(?:\s*\|\s*(?:[A-Z][\w.<>,\s|&\[\]]*|string|number|boolean|void|any|never|unknown|null|undefined|object|bigint))*/g,
168
+ (match, offset) => {
169
+ // Heuristic: only strip if we're in a signature context, not object literals
170
+ const before = s.slice(Math.max(0, offset - 40), offset);
171
+ if (/[,(?]\s*\w+\s*\??$/.test(before)) return "";
172
+ if (/\)\s*$/.test(before)) return "";
173
+ if (/\(\s*\w+\s*\??$/.test(before)) return "";
174
+ if (/\b(?:const|let|var)\s+\w+$/.test(before)) return "";
175
+ return match;
176
+ },
177
+ );
178
+
179
+ s = s.replace(/(\w)!\./g, "$1.");
180
+ s = s.replace(/(\w)!\)/g, "$1)");
181
+ s = s.replace(/(\w)!\,/g, "$1,");
182
+
183
+ s = s.replace(
184
+ /(?<!=)\s*<(?:string|number|boolean|any|unknown|never|void|object|bigint|Record|Partial|Required|Readonly|Pick|Omit|Extract|Exclude|Array|Promise|Set|Map)\b[^>]*>/g,
185
+ "",
186
+ );
187
+
188
+ // Convert enums to plain objects
189
+ s = s.replace(
190
+ /^\s*(?:export\s+)?(?:const\s+)?enum\s+(\w+)\s*\{([^}]*)\}/gm,
191
+ (_, name, body) => {
192
+ const entries = body
193
+ .split(",")
194
+ .map((e: string) => e.trim())
195
+ .filter(Boolean);
196
+ const obj: string[] = [];
197
+ let autoVal = 0;
198
+ for (const entry of entries) {
199
+ const eqIdx = entry.indexOf("=");
200
+ if (eqIdx !== -1) {
201
+ const key = entry.slice(0, eqIdx).trim();
202
+ const val = entry.slice(eqIdx + 1).trim();
203
+ obj.push(`${JSON.stringify(key)}: ${val}`);
204
+ const numVal = Number(val);
205
+ if (!isNaN(numVal)) autoVal = numVal + 1;
206
+ } else {
207
+ obj.push(`${JSON.stringify(entry)}: ${autoVal}`);
208
+ autoVal++;
209
+ }
210
+ }
211
+ return `var ${name} = {${obj.join(", ")}};`;
212
+ },
213
+ );
214
+
215
+ s = s.replace(/^\s*(public|private|protected)?\s*readonly\s+/gm, "$1 ");
216
+ s = s.replace(/\b(public|private|protected)\s+(?=\w+[\s,):])/g, "");
217
+ s = s.replace(/\babstract\s+(class|extends)/g, "$1");
218
+ s = s.replace(/\bimplements\s+[\w.,\s<>]+(?=\s*\{)/g, "");
219
+ s = s.replace(/\boverride\s+(?=\w)/g, "");
220
+
221
+ return s;
222
+ }
223
+
224
+ function isTypeScriptFile(filename: string): boolean {
225
+ const clean = filename.split("?")[0];
226
+ if (
227
+ clean.endsWith(".ts") ||
228
+ clean.endsWith(".tsx") ||
229
+ clean.endsWith(".mts")
230
+ ) return true;
231
+ // Vite SFC query params like ?type=script&lang.ts
232
+ if (filename.includes("lang.ts") || filename.includes("lang=ts")) return true;
233
+ return false;
234
+ }
235
+
236
+ // CSS files must never go through stripTypeScript
237
+ function isCSSFile(filename: string): boolean {
238
+ const clean = filename.split("?")[0];
239
+ if (
240
+ clean.endsWith(".css") ||
241
+ clean.endsWith(".scss") ||
242
+ clean.endsWith(".sass") ||
243
+ clean.endsWith(".less") ||
244
+ clean.endsWith(".styl") ||
245
+ clean.endsWith(".stylus") ||
246
+ clean.endsWith(".postcss")
247
+ ) return true;
248
+ if (filename.includes("type=style")) return true;
249
+ if (/lang[.=](?:css|scss|sass|less|styl|stylus|postcss)/.test(filename)) return true;
250
+ return false;
251
+ }
252
+
253
+ // Fallback heuristic when filename doesn't indicate TS
254
+ function looksLikeTypeScript(source: string): boolean {
255
+ return (
256
+ /\b(?:interface|type)\s+\w+/.test(source) ||
257
+ /:\s*(?:string|number|boolean|void|any|never|unknown|Record|Array|Promise)\b/.test(source) ||
258
+ /(?:as\s+(?:string|number|boolean|any|const)\b)/.test(source)
259
+ );
260
+ }
261
+
262
+ // ── AST walk helper ──
263
+ function traverseAst(node: any, visitor: (n: any) => void): void {
264
+ if (!node || typeof node !== "object") return;
265
+ if (typeof node.type === "string") visitor(node);
266
+ for (const key of Object.keys(node)) {
267
+ if (
268
+ key === "type" ||
269
+ key === "start" ||
270
+ key === "end" ||
271
+ key === "loc" ||
272
+ key === "range"
273
+ )
274
+ continue;
275
+ const val = node[key];
276
+ if (val && typeof val === "object") {
277
+ if (Array.isArray(val)) {
278
+ for (const item of val) {
279
+ if (item && typeof item === "object" && typeof item.type === "string")
280
+ traverseAst(item, visitor);
281
+ }
282
+ } else if (typeof val.type === "string") {
283
+ traverseAst(val, visitor);
284
+ }
285
+ }
286
+ }
287
+ }
288
+
289
+ // ── Dynamic import regex fallback ──
290
+ function rewriteDynamicImportsRegex(source: string): string {
291
+ return source.replace(/(?<![.$\w])import\s*\(/g, "__asyncLoad(");
292
+ }
293
+
294
+ // ── ESM → CJS conversion ──
295
+ function convertModuleSyntax(source: string, filePath: string): string {
296
+ if (!/\bimport\b|\bexport\b/.test(source)) return source;
297
+ try {
298
+ return convertViaAst(source, filePath);
299
+ } catch (astErr) {
300
+ _nativeConsole.warn("[convertModuleSyntax] AST parse failed for", filePath, "falling back to regex:", astErr instanceof Error ? astErr.message : String(astErr));
301
+ return convertViaRegex(source, filePath);
302
+ }
303
+ }
304
+
305
+ function convertViaAst(source: string, filePath: string): string {
306
+ const ast = acorn.parse(source, {
307
+ ecmaVersion: "latest",
308
+ sourceType: "module",
309
+ }) as any;
310
+ const patches: Array<[number, number, string]> = [];
311
+
312
+ traverseAst(ast, (node: any) => {
313
+ if (
314
+ node.type === "MetaProperty" &&
315
+ node.meta?.name === "import" &&
316
+ node.property?.name === "meta"
317
+ ) {
318
+ patches.push([node.start, node.end, "import_meta"]);
319
+ }
320
+ if (node.type === "ImportExpression") {
321
+ patches.push([node.start, node.start + 6, "__asyncLoad"]);
322
+ }
323
+ });
324
+
325
+ const hasImportDecl = ast.body.some(
326
+ (n: any) => n.type === "ImportDeclaration",
327
+ );
328
+ const hasExportDecl = ast.body.some((n: any) => n.type?.startsWith("Export"));
329
+
330
+ let output = source;
331
+ patches.sort((a, b) => b[0] - a[0]);
332
+ for (const [s, e, r] of patches)
333
+ output = output.slice(0, s) + r + output.slice(e);
334
+
335
+ if (hasImportDecl || hasExportDecl) {
336
+ output = esmToCjs(output);
337
+ if (hasExportDecl) {
338
+ output =
339
+ 'Object.defineProperty(exports, "__esModule", { value: true });\n' +
340
+ output;
341
+ }
342
+ }
343
+
344
+ // .mjs files with `const require = createRequire(...)` hit TDZ after esmToCjs
345
+ output = demoteLexicalRequire(output);
346
+
347
+ return output;
348
+ }
349
+
350
+ // Demote `const/let require =` to plain assignment to avoid TDZ with esmToCjs-generated require() calls
351
+ function demoteLexicalRequire(code: string): string {
352
+ if (!/\b(?:const|let)\s+require\s*=/.test(code)) return code;
353
+ return code.replace(
354
+ /\b(const|let)\s+(require)\s*=/g,
355
+ "require =",
356
+ );
357
+ }
358
+
359
+ // Builds the IIFE wrapper that sandboxes user code with shimmed globals
360
+ function buildModuleWrapper(
361
+ code: string,
362
+ opts: {
363
+ async?: boolean;
364
+ useNativePromise?: boolean;
365
+ includeViteVars?: boolean;
366
+ hideBrowserGlobals?: boolean;
367
+ wasmHelpers?: boolean;
368
+ } = {},
369
+ ): string {
370
+ const {
371
+ async: isAsync = false,
372
+ useNativePromise = false,
373
+ includeViteVars = true,
374
+ hideBrowserGlobals = true,
375
+ wasmHelpers = false,
376
+ } = opts;
377
+
378
+ const promiseVar = useNativePromise ? "globalThis.Promise" : "$SyncPromise";
379
+ const fnKeyword = isAsync ? "async function" : "function";
380
+
381
+ let vars = `var exports = $exports;
382
+ var require = $require;
383
+ var module = $module;
384
+ var __filename = $filename;
385
+ var __dirname = $dirname;
386
+ `;
387
+ if (includeViteVars) {
388
+ vars += `var __vite_injected_original_filename = $filename;
389
+ var __vite_injected_original_dirname = $dirname;
390
+ var __vite_injected_original_import_meta_url = "file://" + $filename;
391
+ `;
392
+ }
393
+ vars += `var process = $process;
394
+ var console = $console;
395
+ var import_meta = $importMeta;
396
+ var __asyncLoad = $asyncLoad;
397
+ var __syncAwait = $syncAwait;
398
+ var Promise = ${promiseVar};
399
+ var global = globalThis;
400
+ `;
401
+ if (hideBrowserGlobals) {
402
+ vars += `var document = undefined;
403
+ var window = undefined;
404
+ var HTMLElement = undefined;
405
+ `;
406
+ }
407
+ vars += `globalThis.process = $process;
408
+ globalThis.console = $console;
409
+ globalThis.require = $require;
410
+ global.process = $process;
411
+ global.console = $console;
412
+ global.require = $require;
413
+ `;
414
+ if (wasmHelpers) {
415
+ vars += `async function __wasmCompile(bytes) { return WebAssembly.compile(bytes); }
416
+ async function __wasmInstantiate(moduleOrBytes, imports) {
417
+ var mod = moduleOrBytes;
418
+ if (moduleOrBytes instanceof ArrayBuffer || ArrayBuffer.isView(moduleOrBytes)) {
419
+ mod = await WebAssembly.compile(moduleOrBytes);
420
+ }
421
+ var result = await WebAssembly.instantiate(mod, imports);
422
+ return result.instance || result;
423
+ }
424
+ `;
425
+ }
426
+
427
+ return `(function($exports, $require, $module, $filename, $dirname, $process, $console, $importMeta, $asyncLoad, $syncAwait, $SyncPromise) {
428
+ ${vars}return (${fnKeyword}() {
429
+ ${code}
430
+ }).call(this);
431
+ })`;
432
+ }
433
+
434
+ function convertViaRegex(source: string, filePath: string): string {
435
+ let output = source;
436
+ output = output.replace(/\bimport\.meta\.url\b/g, `"file://${filePath}"`);
437
+ output = output.replace(
438
+ /\bimport\.meta\.dirname\b/g,
439
+ `"${pathPolyfill.dirname(filePath)}"`,
440
+ );
441
+ output = output.replace(/\bimport\.meta\.filename\b/g, `"${filePath}"`);
442
+ output = output.replace(
443
+ /\bimport\.meta\b/g,
444
+ `({ url: "file://${filePath}", dirname: "${pathPolyfill.dirname(filePath)}", filename: "${filePath}" })`,
445
+ );
446
+ output = rewriteDynamicImportsRegex(output);
447
+
448
+ const hasImport = /\bimport\s+[\w{*'"]/m.test(source);
449
+ const hasExport =
450
+ /\bexport\s+(?:default|const|let|var|function|class|{|\*)/m.test(source);
451
+ if (hasImport || hasExport) {
452
+ output = esmToCjs(output);
453
+ if (hasExport) {
454
+ output =
455
+ 'Object.defineProperty(exports, "__esModule", { value: true });\n' +
456
+ output;
457
+ }
458
+ }
459
+
460
+ output = demoteLexicalRequire(output);
461
+
462
+ return output;
463
+ }
464
+
465
+ // ── Sync promise infrastructure ──
466
+ // SyncThenable and SyncPromise let __syncAwait unwrap values without hitting
467
+ // the microtask queue. This is how require() can work synchronously even when
468
+ // modules use async patterns internally.
469
+
470
+ // .then() fires synchronously when value is already resolved
471
+ class SyncThenable<T> {
472
+ private _value: T;
473
+ constructor(value: T) {
474
+ this._value = value;
475
+ }
476
+ then<R>(
477
+ onFulfilled?: ((v: T) => R) | null,
478
+ _onRejected?: ((e: any) => R) | null,
479
+ ): SyncThenable<R> | this {
480
+ if (onFulfilled) return new SyncThenable(onFulfilled(this._value));
481
+ return this;
482
+ }
483
+ catch(_onRejected?: ((e: any) => unknown) | null): this {
484
+ return this;
485
+ }
486
+ finally(onFinally?: (() => void) | null): this {
487
+ if (onFinally) onFinally();
488
+ return this;
489
+ }
490
+ }
491
+
492
+ // Try to synchronously unwrap a thenable. Returns the value if .then() fires sync,
493
+ // otherwise returns the original value (possibly a native Promise).
494
+ function syncAwait(val: unknown): unknown {
495
+ if (val && typeof (val as any).then === "function") {
496
+ let resolved: unknown;
497
+ let gotSync = false;
498
+ (val as any).then((v: unknown) => {
499
+ resolved = v;
500
+ gotSync = true;
501
+ });
502
+ if (gotSync) return resolved;
503
+ }
504
+ return val;
505
+ }
506
+
507
+ // Promise subclass that resolves .then() synchronously when the executor resolves sync.
508
+ // Needed because async functions always return native Promises, but when their body
509
+ // resolves synchronously we want __syncAwait to unwrap the result.
510
+ // Injected as `Promise` inside module wrappers.
511
+ function createSyncPromise(): typeof Promise {
512
+ const NativePromise = Promise;
513
+
514
+ class SyncPromise<T> extends NativePromise<T> {
515
+ private _syncValue: T | undefined;
516
+ private _syncResolved = false;
517
+ private _syncRejected = false;
518
+ private _syncError: any;
519
+
520
+ constructor(
521
+ executor: (
522
+ resolve: (value: T | PromiseLike<T>) => void,
523
+ reject: (reason?: any) => void,
524
+ ) => void,
525
+ ) {
526
+ let syncVal: T | undefined;
527
+ let syncResolved = false;
528
+ let syncRejected = false;
529
+ let syncErr: any;
530
+
531
+ super((resolve, reject) => {
532
+ executor(
533
+ (value) => {
534
+ // Try sync unwrap. If it can't resolve sync, let native handle it.
535
+ // Without this, p-limit's resolve(asyncPromise) gets treated as
536
+ // sync-resolved with the Promise object as the value.
537
+ if (
538
+ value &&
539
+ typeof value === "object" &&
540
+ typeof (value as any).then === "function"
541
+ ) {
542
+ let innerResolved = false;
543
+ let innerVal: T | undefined;
544
+ let innerRejected = false;
545
+ let innerErr: any;
546
+ (value as any).then(
547
+ (v: T) => {
548
+ innerVal = v;
549
+ innerResolved = true;
550
+ },
551
+ (e: any) => {
552
+ innerErr = e;
553
+ innerRejected = true;
554
+ },
555
+ );
556
+ if (innerResolved) {
557
+ syncVal = innerVal;
558
+ syncResolved = true;
559
+ resolve(innerVal!);
560
+ return;
561
+ }
562
+ if (innerRejected) {
563
+ syncRejected = true;
564
+ syncErr = innerErr;
565
+ reject(innerErr);
566
+ return;
567
+ }
568
+ resolve(value);
569
+ return;
570
+ }
571
+ syncVal = value as T;
572
+ syncResolved = true;
573
+ resolve(value);
574
+ },
575
+ (reason) => {
576
+ syncRejected = true;
577
+ syncErr = reason;
578
+ reject(reason);
579
+ },
580
+ );
581
+ });
582
+
583
+ this._syncValue = syncVal;
584
+ this._syncResolved = syncResolved;
585
+ this._syncRejected = syncRejected;
586
+ this._syncError = syncErr;
587
+
588
+ // Suppress native unhandledrejection — our .then() handles these sync
589
+ if (syncRejected) {
590
+ NativePromise.prototype.catch.call(this, () => {});
591
+ }
592
+ }
593
+
594
+ then<TResult1 = T, TResult2 = never>(
595
+ onFulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
596
+ onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null,
597
+ ): Promise<TResult1 | TResult2> {
598
+ if (this._syncResolved && onFulfilled) {
599
+ try {
600
+ const result = onFulfilled(this._syncValue as T);
601
+ if (
602
+ result &&
603
+ typeof result === "object" &&
604
+ typeof (result as any).then === "function"
605
+ ) {
606
+ let innerVal: any;
607
+ let innerResolved = false;
608
+ let innerRejected = false;
609
+ let innerErr: any;
610
+ (result as any).then(
611
+ (v: any) => {
612
+ innerVal = v;
613
+ innerResolved = true;
614
+ },
615
+ (e: any) => {
616
+ innerErr = e;
617
+ innerRejected = true;
618
+ },
619
+ );
620
+ if (innerResolved) {
621
+ return new SyncPromise<TResult1>((res) => res(innerVal)) as any;
622
+ }
623
+ if (innerRejected) {
624
+ if (onRejected) {
625
+ return new SyncPromise<TResult2>((res) =>
626
+ res(onRejected(innerErr) as TResult2),
627
+ ) as any;
628
+ }
629
+ return new SyncPromise<TResult2>((_, rej) => rej(innerErr)) as any;
630
+ }
631
+ return NativePromise.resolve(result).then(null, onRejected) as any;
632
+ }
633
+ return new SyncPromise<TResult1>((res) =>
634
+ res(result as TResult1),
635
+ ) as any;
636
+ } catch (e) {
637
+ if (onRejected) {
638
+ return new SyncPromise<TResult2>((res) =>
639
+ res(onRejected(e) as TResult2),
640
+ ) as any;
641
+ }
642
+ // Must be SyncPromise so downstream .catch() fires sync (p-locate depends on this)
643
+ return new SyncPromise<TResult2>((_, rej) => rej(e)) as any;
644
+ }
645
+ }
646
+ if (this._syncRejected && onRejected) {
647
+ try {
648
+ const result = onRejected(this._syncError);
649
+ return new SyncPromise<TResult2>((res) =>
650
+ res(result as TResult2),
651
+ ) as any;
652
+ } catch (e) {
653
+ return new SyncPromise<TResult2>((_, rej) => rej(e)) as any;
654
+ }
655
+ }
656
+ if (this._syncRejected && !onRejected) {
657
+ return new SyncPromise<TResult2>((_, rej) =>
658
+ rej(this._syncError),
659
+ ) as any;
660
+ }
661
+ return super.then(onFulfilled, onRejected);
662
+ }
663
+ }
664
+
665
+ // instanceof must work for native Promises too since we inject SyncPromise as `Promise`
666
+ Object.defineProperty(SyncPromise, Symbol.hasInstance, {
667
+ value: (instance: any) =>
668
+ instance instanceof NativePromise,
669
+ configurable: true,
670
+ });
671
+
672
+ (SyncPromise as any).resolve = (value: any) => {
673
+ if (
674
+ value &&
675
+ typeof value === "object" &&
676
+ typeof (value as any).then === "function"
677
+ ) {
678
+ return new SyncPromise((res) => res(value));
679
+ }
680
+ return new SyncPromise((res) => res(value));
681
+ };
682
+ (SyncPromise as any).reject = (reason: any) =>
683
+ new SyncPromise((_, rej) => rej(reason));
684
+
685
+ // all/race/allSettled/any return SyncPromise so __syncAwait can unwrap them
686
+ (SyncPromise as any).all = (iterable: Iterable<any>) => {
687
+ const arr = Array.from(iterable);
688
+ const results: any[] = new Array(arr.length);
689
+ let allSync = true;
690
+ for (let i = 0; i < arr.length; i++) {
691
+ const v = arr[i];
692
+ if (v instanceof SyncPromise) {
693
+ if ((v as any)._syncResolved) {
694
+ results[i] = (v as any)._syncValue;
695
+ } else if ((v as any)._syncRejected) {
696
+ return new SyncPromise((_, rej) => rej((v as any)._syncError));
697
+ } else {
698
+ allSync = false;
699
+ break;
700
+ }
701
+ } else if (
702
+ v && typeof v === "object" && typeof v.then === "function"
703
+ ) {
704
+ let probed = false, pVal: any;
705
+ v.then((x: any) => { pVal = x; probed = true; });
706
+ if (probed) {
707
+ results[i] = pVal;
708
+ } else {
709
+ allSync = false;
710
+ break;
711
+ }
712
+ } else {
713
+ results[i] = v;
714
+ }
715
+ }
716
+ if (allSync) {
717
+ return new SyncPromise((res: any) => res(results));
718
+ }
719
+ return new SyncPromise((res: any, rej: any) => {
720
+ NativePromise.all(arr).then(res, rej);
721
+ });
722
+ };
723
+
724
+ (SyncPromise as any).allSettled = (iterable: Iterable<any>) => {
725
+ const arr = Array.from(iterable);
726
+ const results: any[] = new Array(arr.length);
727
+ let allSync = true;
728
+ for (let i = 0; i < arr.length; i++) {
729
+ const v = arr[i];
730
+ if (v instanceof SyncPromise) {
731
+ if ((v as any)._syncResolved) {
732
+ results[i] = { status: "fulfilled", value: (v as any)._syncValue };
733
+ } else if ((v as any)._syncRejected) {
734
+ results[i] = { status: "rejected", reason: (v as any)._syncError };
735
+ } else {
736
+ allSync = false;
737
+ break;
738
+ }
739
+ } else if (
740
+ v && typeof v === "object" && typeof v.then === "function"
741
+ ) {
742
+ allSync = false;
743
+ break;
744
+ } else {
745
+ results[i] = { status: "fulfilled", value: v };
746
+ }
747
+ }
748
+ if (allSync) {
749
+ return new SyncPromise((res: any) => res(results));
750
+ }
751
+ return new SyncPromise((res: any, rej: any) => {
752
+ NativePromise.allSettled(arr).then(res, rej);
753
+ });
754
+ };
755
+
756
+ (SyncPromise as any).race = (iterable: Iterable<any>) => {
757
+ const arr = Array.from(iterable);
758
+ for (const v of arr) {
759
+ if (v instanceof SyncPromise) {
760
+ if ((v as any)._syncResolved) {
761
+ return new SyncPromise((res: any) => res((v as any)._syncValue));
762
+ }
763
+ if ((v as any)._syncRejected) {
764
+ return new SyncPromise((_, rej: any) => rej((v as any)._syncError));
765
+ }
766
+ } else if (
767
+ !(v && typeof v === "object" && typeof v.then === "function")
768
+ ) {
769
+ return new SyncPromise((res: any) => res(v));
770
+ }
771
+ }
772
+ return new SyncPromise((res: any, rej: any) => {
773
+ NativePromise.race(arr).then(res, rej);
774
+ });
775
+ };
776
+
777
+ (SyncPromise as any).any = (iterable: Iterable<any>) => {
778
+ const arr = Array.from(iterable);
779
+ for (const v of arr) {
780
+ if (v instanceof SyncPromise && (v as any)._syncResolved) {
781
+ return new SyncPromise((res: any) => res((v as any)._syncValue));
782
+ }
783
+ if (
784
+ !(v && typeof v === "object" && typeof v.then === "function")
785
+ ) {
786
+ return new SyncPromise((res: any) => res(v));
787
+ }
788
+ }
789
+ let allSyncRejected = true;
790
+ const errors: any[] = [];
791
+ for (const v of arr) {
792
+ if (v instanceof SyncPromise && (v as any)._syncRejected) {
793
+ errors.push((v as any)._syncError);
794
+ } else {
795
+ allSyncRejected = false;
796
+ break;
797
+ }
798
+ }
799
+ if (allSyncRejected && arr.length > 0) {
800
+ return new SyncPromise((_, rej: any) =>
801
+ rej(new AggregateError(errors, "All promises were rejected")),
802
+ );
803
+ }
804
+ return new SyncPromise((res: any, rej: any) => {
805
+ NativePromise.any(arr).then(res, rej);
806
+ });
807
+ };
808
+
809
+ return SyncPromise as any;
810
+ }
811
+
812
+ const SyncPromiseClass = createSyncPromise();
813
+
814
+ function makeDynamicLoader(
815
+ resolver: ResolverFn,
816
+ ): (specifier: string) => SyncThenable<unknown> {
817
+ return (specifier: string): SyncThenable<unknown> => {
818
+ const loaded = resolver(specifier);
819
+ // Functions can have named exports as properties (e.g. Module.createRequire)
820
+ if (
821
+ loaded &&
822
+ (typeof loaded === "object" || typeof loaded === "function") &&
823
+ ("default" in (loaded as object) || "__esModule" in (loaded as object))
824
+ ) {
825
+ return new SyncThenable(loaded);
826
+ }
827
+ const spread = loaded && (typeof loaded === "object" || typeof loaded === "function")
828
+ ? Object.getOwnPropertyNames(loaded as object).reduce((acc, key) => {
829
+ acc[key] = (loaded as any)[key];
830
+ return acc;
831
+ }, {} as Record<string, unknown>)
832
+ : {};
833
+ return new SyncThenable({
834
+ default: loaded,
835
+ ...spread,
836
+ });
837
+ };
838
+ }
839
+
840
+ // ── Types ──
841
+ export interface ModuleRecord {
842
+ id: string;
843
+ filename: string;
844
+ exports: unknown;
845
+ loaded: boolean;
846
+ children: ModuleRecord[];
847
+ paths: string[];
848
+ }
849
+
850
+ export interface EngineOptions {
851
+ cwd?: string;
852
+ env?: Record<string, string>;
853
+ onConsole?: (method: string, args: unknown[]) => void;
854
+ onStdout?: (data: string) => void;
855
+ onStderr?: (data: string) => void;
856
+ workerThreadsOverride?: {
857
+ isMainThread: boolean;
858
+ parentPort: unknown;
859
+ workerData: unknown;
860
+ threadId: number;
861
+ };
862
+ }
863
+
864
+ export interface ResolverFn {
865
+ (id: string): unknown;
866
+ resolve: (id: string, options?: { paths?: string[] }) => string;
867
+ cache: Record<string, ModuleRecord>;
868
+ extensions: Record<string, unknown>;
869
+ main: ModuleRecord | null;
870
+ }
871
+
872
+ // Mutable copy so packages can monkey-patch frozen polyfill namespaces
873
+ function shallowCopy(source: Record<string, unknown>): Record<string, unknown> {
874
+ const copy: Record<string, unknown> = {};
875
+ for (const k of Object.keys(source)) copy[k] = source[k];
876
+ return copy;
877
+ }
878
+
879
+ // ── Core module registry ──
880
+ const CORE_MODULES: Record<string, unknown> = {
881
+ path: pathPolyfill,
882
+ http: shallowCopy(httpPolyfill as unknown as Record<string, unknown>),
883
+ https: shallowCopy(httpsPolyfill as unknown as Record<string, unknown>),
884
+ net: tcpPolyfill,
885
+ events: eventBusPolyfill,
886
+ stream: streamPolyfill,
887
+ buffer: bufferPolyfill,
888
+ url: urlPolyfill,
889
+ querystring: qsPolyfill,
890
+ util: helpersPolyfill,
891
+ tty: ttyPolyfill,
892
+ os: osPolyfill,
893
+ crypto: shallowCopy(hashingPolyfill as unknown as Record<string, unknown>),
894
+ zlib: compressionPolyfill,
895
+ dns: dnsPolyfill,
896
+ child_process: shellExecProxy,
897
+ assert: assertPolyfill,
898
+ string_decoder: stringDecoderPolyfill,
899
+ timers: timersPolyfill,
900
+ constants: constantsPolyfill,
901
+ punycode: punycodePolyfill,
902
+ _http_common: {},
903
+ _http_incoming: {},
904
+ _http_outgoing: {},
905
+ chokidar: watcherPolyfill,
906
+ ws: wsPolyfill,
907
+ fsevents: macEventsPolyfill,
908
+ readdirp: scannerPolyfill,
909
+ module: moduleSysPolyfill.Module,
910
+ perf_hooks: perfPolyfill,
911
+ worker_threads: threadPoolPolyfill,
912
+ esbuild: esbuildPolyfill,
913
+ rollup: rollupPolyfill,
914
+ v8: v8Polyfill,
915
+ readline: lineReaderPolyfill,
916
+ tls: tlsPolyfill,
917
+ http2: http2Polyfill,
918
+ cluster: clusterPolyfill,
919
+ dgram: udpPolyfill,
920
+ vm: vmPolyfill,
921
+ inspector: debugPolyfill,
922
+ "inspector/promises": debugPolyfill,
923
+ async_hooks: asyncCtxPolyfill,
924
+ domain: domainPolyfill,
925
+ diagnostics_channel: tracePolyfill,
926
+ console: { ...console, Console: consolePolyfill.Console },
927
+ repl: replPolyfill,
928
+ test: testPolyfill,
929
+ trace_events: traceEventsPolyfill,
930
+ wasi: wasiPolyfill,
931
+ sea: seaPolyfill,
932
+ sqlite: sqlitePolyfill,
933
+ quic: quicPolyfill,
934
+ lightningcss: lightningcssPolyfill,
935
+ "@tailwindcss/oxide": tailwindOxidePolyfill,
936
+ sys: helpersPolyfill,
937
+ "util/types": helpersPolyfill.types,
938
+ "path/posix": pathPolyfill,
939
+ "path/win32": pathPolyfill.win32,
940
+ "timers/promises": timersPromises,
941
+ "stream/promises": streamPromises,
942
+ "stream/web": {
943
+ ReadableStream: globalThis.ReadableStream,
944
+ WritableStream: globalThis.WritableStream,
945
+ TransformStream: globalThis.TransformStream,
946
+ ByteLengthQueuingStrategy: globalThis.ByteLengthQueuingStrategy,
947
+ CountQueuingStrategy: globalThis.CountQueuingStrategy,
948
+ },
949
+ "stream/consumers": {
950
+ async arrayBuffer(stream: any): Promise<ArrayBuffer> {
951
+ const chunks: Uint8Array[] = [];
952
+ for await (const chunk of stream) {
953
+ chunks.push(
954
+ typeof chunk === "string" ? new TextEncoder().encode(chunk) : chunk,
955
+ );
956
+ }
957
+ let len = 0;
958
+ for (const c of chunks) len += c.byteLength;
959
+ const buf = new Uint8Array(len);
960
+ let off = 0;
961
+ for (const c of chunks) {
962
+ buf.set(c, off);
963
+ off += c.byteLength;
964
+ }
965
+ return buf.buffer;
966
+ },
967
+ async blob(stream: any): Promise<Blob> {
968
+ const chunks: Uint8Array[] = [];
969
+ for await (const chunk of stream) {
970
+ chunks.push(
971
+ typeof chunk === "string" ? new TextEncoder().encode(chunk) : chunk,
972
+ );
973
+ }
974
+ return new Blob(chunks as unknown as BlobPart[]);
975
+ },
976
+ async buffer(stream: any): Promise<Uint8Array> {
977
+ const chunks: Uint8Array[] = [];
978
+ for await (const chunk of stream) {
979
+ chunks.push(
980
+ typeof chunk === "string" ? new TextEncoder().encode(chunk) : chunk,
981
+ );
982
+ }
983
+ let len = 0;
984
+ for (const c of chunks) len += c.byteLength;
985
+ const buf = new Uint8Array(len);
986
+ let off = 0;
987
+ for (const c of chunks) {
988
+ buf.set(c, off);
989
+ off += c.byteLength;
990
+ }
991
+ return buf;
992
+ },
993
+ async json(stream: any): Promise<unknown> {
994
+ const chunks: string[] = [];
995
+ for await (const chunk of stream) {
996
+ chunks.push(
997
+ typeof chunk === "string" ? chunk : new TextDecoder().decode(chunk),
998
+ );
999
+ }
1000
+ return JSON.parse(chunks.join(""));
1001
+ },
1002
+ async text(stream: any): Promise<string> {
1003
+ const chunks: string[] = [];
1004
+ for await (const chunk of stream) {
1005
+ chunks.push(
1006
+ typeof chunk === "string" ? chunk : new TextDecoder().decode(chunk),
1007
+ );
1008
+ }
1009
+ return chunks.join("");
1010
+ },
1011
+ },
1012
+ "dns/promises": dnsPromises,
1013
+ "assert/strict": assertPolyfill,
1014
+ "readline/promises": readlinePromises,
1015
+ _stream_readable: Readable,
1016
+ _stream_writable: Writable,
1017
+ _stream_duplex: Duplex,
1018
+ _stream_transform: Transform,
1019
+ _stream_passthrough: PassThrough,
1020
+ // Vite imports rollup/parseAst which normally uses native bindings
1021
+ "rollup/parseAst": {
1022
+ parseAst: rollupPolyfill.parseAst,
1023
+ parseAstAsync: rollupPolyfill.parseAstAsync,
1024
+ },
1025
+ };
1026
+
1027
+ // ── Console wrapper ──
1028
+ // Captured at module load time to avoid infinite recursion when globalThis.console is overridden
1029
+ const _nativeConsole = console;
1030
+
1031
+ function wrapConsole(
1032
+ onConsole?: (method: string, args: unknown[]) => void,
1033
+ ): Console {
1034
+ // Route through onConsole callback exclusively when provided, else fall back to browser console
1035
+ const nc = _nativeConsole;
1036
+ const wrapped = {
1037
+ log: (...args: unknown[]) => {
1038
+ if (onConsole) onConsole("log", args);
1039
+ else nc.log(...args);
1040
+ },
1041
+ error: (...args: unknown[]) => {
1042
+ if (onConsole) onConsole("error", args);
1043
+ else nc.error(...args);
1044
+ },
1045
+ warn: (...args: unknown[]) => {
1046
+ if (onConsole) onConsole("warn", args);
1047
+ else nc.warn(...args);
1048
+ },
1049
+ info: (...args: unknown[]) => {
1050
+ if (onConsole) onConsole("info", args);
1051
+ else nc.info(...args);
1052
+ },
1053
+ debug: (...args: unknown[]) => {
1054
+ if (onConsole) onConsole("debug", args);
1055
+ else nc.debug(...args);
1056
+ },
1057
+ trace: (...args: unknown[]) => {
1058
+ if (onConsole) onConsole("trace", args);
1059
+ else nc.trace(...args);
1060
+ },
1061
+ dir: (obj: unknown) => {
1062
+ if (onConsole) onConsole("dir", [obj]);
1063
+ else nc.dir(obj);
1064
+ },
1065
+ time: nc.time.bind(nc),
1066
+ timeEnd: nc.timeEnd.bind(nc),
1067
+ timeLog: nc.timeLog.bind(nc),
1068
+ assert: (...args: unknown[]) => {
1069
+ const [v, ...rest] = args;
1070
+ if (!v) {
1071
+ if (onConsole) onConsole("error", ["Assertion failed:", ...rest]);
1072
+ else nc.assert(v as boolean, ...rest);
1073
+ }
1074
+ },
1075
+ clear: nc.clear.bind(nc),
1076
+ count: nc.count.bind(nc),
1077
+ countReset: nc.countReset.bind(nc),
1078
+ group: nc.group.bind(nc),
1079
+ groupCollapsed: nc.groupCollapsed.bind(nc),
1080
+ groupEnd: nc.groupEnd.bind(nc),
1081
+ table: (...args: unknown[]) => {
1082
+ if (onConsole) onConsole("log", args);
1083
+ else nc.table(...args);
1084
+ },
1085
+ timeStamp: nc.timeStamp ? nc.timeStamp.bind(nc) : () => {},
1086
+ profile: nc.profile ? nc.profile.bind(nc) : () => {},
1087
+ profileEnd: nc.profileEnd ? nc.profileEnd.bind(nc) : () => {},
1088
+ };
1089
+ return wrapped as unknown as Console;
1090
+ }
1091
+
1092
+ // ── Module resolver & loader ──
1093
+ function buildResolver(
1094
+ vol: MemoryVolume,
1095
+ fsBridge: FsBridge,
1096
+ proc: ProcessObject,
1097
+ baseDir: string,
1098
+ cache: Record<string, ModuleRecord>,
1099
+ opts: EngineOptions,
1100
+ codeCache?: Map<string, string>,
1101
+ deAsyncImports = false,
1102
+ ): ResolverFn {
1103
+ const resolveCache = new Map<string, string | null>();
1104
+ const manifestCache = new Map<string, PackageManifest | null>();
1105
+ // Shared across all resolvers — deduplicates same-version packages from nested node_modules
1106
+ const _pkgIdentityMap: Record<string, string> =
1107
+ (cache as any).__pkgIdentityMap ?? ((cache as any).__pkgIdentityMap = {});
1108
+
1109
+ const readManifest = (manifestPath: string): PackageManifest | null => {
1110
+ if (manifestCache.has(manifestPath))
1111
+ return manifestCache.get(manifestPath)!;
1112
+ try {
1113
+ const raw = vol.readFileSync(manifestPath, "utf8");
1114
+ const parsed = JSON.parse(raw) as PackageManifest;
1115
+ manifestCache.set(manifestPath, parsed);
1116
+ return parsed;
1117
+ } catch {
1118
+ manifestCache.set(manifestPath, null);
1119
+ return null;
1120
+ }
1121
+ };
1122
+
1123
+ const resolveId = (
1124
+ id: string,
1125
+ fromDir: string,
1126
+ preferEsm: boolean = false,
1127
+ ): string => {
1128
+ if (typeof id !== "string") {
1129
+ throw new TypeError(
1130
+ `The "id" argument must be of type string. Received ${typeof id}`,
1131
+ );
1132
+ }
1133
+ if (id.startsWith("node:")) id = id.slice(5);
1134
+
1135
+ if (id.startsWith("file:///")) {
1136
+ id = decodeURIComponent(id.slice(7));
1137
+ if (/^[A-Za-z]:[\\/]/.test(id)) {
1138
+ id = "/" + id.slice(2).replace(/\\/g, "/");
1139
+ }
1140
+ } else if (id.startsWith("file://")) {
1141
+ id = decodeURIComponent(id.slice(7));
1142
+ if (/^[A-Za-z]:[\\/]/.test(id)) {
1143
+ id = "/" + id.slice(2).replace(/\\/g, "/");
1144
+ }
1145
+ }
1146
+
1147
+ const qIdx = id.indexOf("?");
1148
+ if (qIdx !== -1) id = id.slice(0, qIdx);
1149
+
1150
+ const hashIdx = id.indexOf("#");
1151
+ if (hashIdx !== -1 && !id.startsWith("#")) id = id.slice(0, hashIdx);
1152
+
1153
+ if (id.includes("\\")) id = id.replace(/\\/g, "/");
1154
+
1155
+ if (
1156
+ CORE_MODULES[id] ||
1157
+ id === "fs" ||
1158
+ id === "process" ||
1159
+ id === "url" ||
1160
+ id === "querystring" ||
1161
+ id === "util"
1162
+ ) {
1163
+ return id;
1164
+ }
1165
+
1166
+ // Native Rust bindings can't run in browser — provide JS stubs
1167
+ if (id.startsWith("@rollup/rollup-")) {
1168
+ if (!CORE_MODULES[id]) {
1169
+ CORE_MODULES[id] = {
1170
+ parse: rollupPolyfill.parseAst,
1171
+ parseAsync: rollupPolyfill.parseAstAsync,
1172
+ };
1173
+ }
1174
+ return id;
1175
+ }
1176
+
1177
+ if (id.startsWith("@rolldown/binding-")) {
1178
+ if (!CORE_MODULES[id]) {
1179
+ const makeParseResult = (source: string, opts?: any) => {
1180
+ const lang = opts?.lang || "js";
1181
+ const useJsx = lang === "jsx" || lang === "tsx";
1182
+ const ast = rollupPolyfill.parseAst(source, { jsx: useJsx });
1183
+ return {
1184
+ program: JSON.stringify({ node: ast, fixes: [] }),
1185
+ module: {
1186
+ hasModuleSyntax: false,
1187
+ staticImports: [],
1188
+ staticExports: [],
1189
+ dynamicImports: [],
1190
+ importMetas: [],
1191
+ },
1192
+ comments: [],
1193
+ errors: [],
1194
+ };
1195
+ };
1196
+ const applyDefineReplacements = (
1197
+ code: string,
1198
+ define?: Record<string, string>,
1199
+ ): string => {
1200
+ if (!define || typeof define !== "object") return code;
1201
+ for (const [key, value] of Object.entries(define)) {
1202
+ if (!key) continue;
1203
+ const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1204
+ const re = new RegExp(`\\b${escaped}\\b`, "g");
1205
+ code = code.replace(re, value);
1206
+ }
1207
+ return code;
1208
+ };
1209
+ const noop = () => {};
1210
+ const noopAsync = async () => {};
1211
+ CORE_MODULES[id] = {
1212
+ // Parser
1213
+ parseSync: (_filename: string, source: string, opts?: any) =>
1214
+ makeParseResult(source, opts),
1215
+ parse: async (_filename: string, source: string, opts?: any) =>
1216
+ makeParseResult(source, opts),
1217
+ initTraceSubscriber: noop,
1218
+ shutdownAsyncRuntime: noop,
1219
+ startAsyncRuntime: noop,
1220
+ createTokioRuntime: noop,
1221
+ registerPlugins: noop,
1222
+ rawTransferSupported: () => false,
1223
+ sync: noop,
1224
+ transform: async (filename: string, code: string, opts?: any) => {
1225
+ code = applyDefineReplacements(code, opts?.define);
1226
+ if (!isCSSFile(filename) && (isTypeScriptFile(filename) || looksLikeTypeScript(code)))
1227
+ code = stripTypeScript(code);
1228
+ return { code, map: null, errors: [], warnings: [] };
1229
+ },
1230
+ transformSync: (filename: string, code: string, opts?: any) => {
1231
+ code = applyDefineReplacements(code, opts?.define);
1232
+ if (!isCSSFile(filename) && (isTypeScriptFile(filename) || looksLikeTypeScript(code)))
1233
+ code = stripTypeScript(code);
1234
+ return { code, map: null, errors: [], warnings: [] };
1235
+ },
1236
+ enhancedTransform: async (
1237
+ filename: string,
1238
+ code: string,
1239
+ opts?: any,
1240
+ ) => {
1241
+ code = applyDefineReplacements(code, opts?.define);
1242
+ if (!isCSSFile(filename) && (isTypeScriptFile(filename) || looksLikeTypeScript(code)))
1243
+ code = stripTypeScript(code);
1244
+ return {
1245
+ code,
1246
+ map: null,
1247
+ errors: [],
1248
+ warnings: [],
1249
+ helpersUsed: {},
1250
+ tsconfigFilePaths: [],
1251
+ };
1252
+ },
1253
+ enhancedTransformSync: (
1254
+ filename: string,
1255
+ code: string,
1256
+ opts?: any,
1257
+ ) => {
1258
+ code = applyDefineReplacements(code, opts?.define);
1259
+ if (!isCSSFile(filename) && (isTypeScriptFile(filename) || looksLikeTypeScript(code)))
1260
+ code = stripTypeScript(code);
1261
+ return {
1262
+ code,
1263
+ map: null,
1264
+ errors: [],
1265
+ warnings: [],
1266
+ helpersUsed: {},
1267
+ tsconfigFilePaths: [],
1268
+ };
1269
+ },
1270
+ minify: async (_filename: string, code: string) => ({
1271
+ code,
1272
+ map: null,
1273
+ errors: [],
1274
+ warnings: [],
1275
+ }),
1276
+ minifySync: (_filename: string, code: string) => ({
1277
+ code,
1278
+ map: null,
1279
+ errors: [],
1280
+ warnings: [],
1281
+ }),
1282
+ isolatedDeclaration: async (_filename: string, code: string) => ({
1283
+ code,
1284
+ map: null,
1285
+ errors: [],
1286
+ warnings: [],
1287
+ }),
1288
+ isolatedDeclarationSync: (_filename: string, code: string) => ({
1289
+ code,
1290
+ map: null,
1291
+ errors: [],
1292
+ warnings: [],
1293
+ }),
1294
+ moduleRunnerTransform: async (filename: string, code: string) => {
1295
+ if (!isCSSFile(filename) && (isTypeScriptFile(filename) || looksLikeTypeScript(code)))
1296
+ code = stripTypeScript(code);
1297
+ return { code, map: null, deps: [], dynamicDeps: [], errors: [] };
1298
+ },
1299
+ moduleRunnerTransformSync: (filename: string, code: string) => {
1300
+ if (!isCSSFile(filename) && (isTypeScriptFile(filename) || looksLikeTypeScript(code)))
1301
+ code = stripTypeScript(code);
1302
+ return { code, map: null, deps: [], dynamicDeps: [], errors: [] };
1303
+ },
1304
+ Severity: { Error: "Error", Warning: "Warning", Advice: "Advice" },
1305
+ ParseResult: class {},
1306
+ ResolverFactory: class {},
1307
+ EnforceExtension: { Auto: 0, Enabled: 1, Disabled: 2 },
1308
+ ModuleType: {},
1309
+ HelperMode: {},
1310
+ TraceSubscriberGuard: class {},
1311
+ BindingBundler: class {
1312
+ closed = false;
1313
+ #watchFiles: string[] = [];
1314
+ async generate(opts: any) {
1315
+ return this.#bundle(opts);
1316
+ }
1317
+ async write(opts: any) {
1318
+ const result = await this.#bundle(opts);
1319
+ const outputOpts = opts?.outputOptions ?? {};
1320
+ const dir = outputOpts.dir || "/dist";
1321
+ try {
1322
+ if (!vol.existsSync(dir)) {
1323
+ vol.mkdirSync(dir, { recursive: true });
1324
+ }
1325
+ } catch {
1326
+ /* best effort */
1327
+ }
1328
+ for (const chunk of result.chunks) {
1329
+ const outPath = pathPolyfill.join(dir, chunk.getFileName());
1330
+ try {
1331
+ const outDir = pathPolyfill.dirname(outPath);
1332
+ if (!vol.existsSync(outDir)) {
1333
+ vol.mkdirSync(outDir, { recursive: true });
1334
+ }
1335
+ const code = chunk.getCode();
1336
+ vol.writeFileSync(outPath, code);
1337
+ } catch {
1338
+ /* best effort */
1339
+ }
1340
+ }
1341
+ return result;
1342
+ }
1343
+ // Dependency scanning for Vite's dep optimizer — invokes plugin resolveId hooks
1344
+ // so Vite's scan plugin discovers bare imports to pre-bundle
1345
+ async scan(opts?: any) {
1346
+ try {
1347
+ const inputOpts = opts?.inputOptions ?? {};
1348
+ const plugins: any[] = (inputOpts.plugins ?? []).filter(
1349
+ Boolean,
1350
+ );
1351
+ const entries: { name?: string; import: string }[] =
1352
+ Array.isArray(inputOpts.input) ? inputOpts.input : [];
1353
+ const cwd = inputOpts.cwd || "/";
1354
+ if (!entries.length || !plugins.length) return;
1355
+
1356
+ const mockCtx = {
1357
+ resolve: async () => null,
1358
+ load: async () => ({}),
1359
+ emitFile: () => "",
1360
+ getFileName: () => "",
1361
+ getModuleInfo: () => null,
1362
+ getModuleIds: () => [],
1363
+ addWatchFile: () => {},
1364
+ parse: (code: string) =>
1365
+ acorn.parse(code, {
1366
+ ecmaVersion: "latest" as any,
1367
+ sourceType: "module",
1368
+ }),
1369
+ };
1370
+
1371
+ const extractImports = (code: string): string[] => {
1372
+ const specs: string[] = [];
1373
+ try {
1374
+ const ast: any = acorn.parse(code, {
1375
+ ecmaVersion: "latest" as any,
1376
+ sourceType: "module",
1377
+ allowImportExportEverywhere: true,
1378
+ });
1379
+ for (const node of ast.body) {
1380
+ if (
1381
+ node.type === "ImportDeclaration" &&
1382
+ node.source?.value
1383
+ )
1384
+ specs.push(node.source.value);
1385
+ if (
1386
+ node.type === "ExportNamedDeclaration" &&
1387
+ node.source?.value
1388
+ )
1389
+ specs.push(node.source.value);
1390
+ if (
1391
+ node.type === "ExportAllDeclaration" &&
1392
+ node.source?.value
1393
+ )
1394
+ specs.push(node.source.value);
1395
+ }
1396
+ } catch { /* fallback to regex */ }
1397
+ const dynRe = /\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
1398
+ let m;
1399
+ while ((m = dynRe.exec(code)) !== null) specs.push(m[1]);
1400
+ return [...new Set(specs)];
1401
+ };
1402
+
1403
+ for (const p of plugins) {
1404
+ if (p.buildStart) {
1405
+ try {
1406
+ await p.buildStart(mockCtx, {});
1407
+ } catch (hookErr) {
1408
+ const msg = hookErr instanceof Error ? hookErr.message : String(hookErr);
1409
+ _nativeConsole.warn("[rolldown scan] buildStart hook error:", msg);
1410
+ }
1411
+ }
1412
+ }
1413
+
1414
+ // BFS: load files, extract imports, call resolveId, follow local files
1415
+ const visitedSpecs = new Set<string>();
1416
+ const visitedFiles = new Set<string>();
1417
+ const queue: string[] = [];
1418
+
1419
+ for (const entry of entries) {
1420
+ const ep = entry.import?.startsWith("/")
1421
+ ? entry.import
1422
+ : pathPolyfill.resolve(cwd, entry.import);
1423
+ queue.push(ep);
1424
+ }
1425
+
1426
+ const loadFile = async (
1427
+ filePath: string,
1428
+ usePlugins: boolean,
1429
+ ): Promise<string> => {
1430
+ if (usePlugins) {
1431
+ for (const p of plugins) {
1432
+ if (p.load) {
1433
+ try {
1434
+ const r = await p.load(mockCtx, filePath);
1435
+ if (r && typeof r === "object" && r.code)
1436
+ return r.code;
1437
+ } catch (loadErr) {
1438
+ const msg = loadErr instanceof Error ? loadErr.message : String(loadErr);
1439
+ _nativeConsole.warn("[rolldown scan] load hook error:", filePath, msg);
1440
+ }
1441
+ }
1442
+ }
1443
+ }
1444
+ return vol.readFileSync(filePath, "utf8");
1445
+ };
1446
+
1447
+ const MAX_DEPTH = LIMITS.MAX_RESOLVE_DEPTH;
1448
+ let processed = 0;
1449
+ const entryPaths = new Set(queue);
1450
+ while (queue.length > 0 && processed < MAX_DEPTH) {
1451
+ const filePath = queue.shift()!;
1452
+ if (visitedFiles.has(filePath)) continue;
1453
+ visitedFiles.add(filePath);
1454
+ processed++;
1455
+
1456
+ let code: string;
1457
+ try {
1458
+ code = await loadFile(filePath, entryPaths.has(filePath));
1459
+ } catch {
1460
+ continue;
1461
+ }
1462
+
1463
+ const specifiers = extractImports(code);
1464
+
1465
+ for (const spec of specifiers) {
1466
+ const key = `${spec}\0${filePath}`;
1467
+ if (visitedSpecs.has(key)) continue;
1468
+ visitedSpecs.add(key);
1469
+
1470
+ for (const p of plugins) {
1471
+ if (p.resolveId) {
1472
+ try {
1473
+ await p.resolveId(mockCtx, spec, filePath, {
1474
+ isEntry: false,
1475
+ kind: "import-statement",
1476
+ custom: undefined,
1477
+ });
1478
+ } catch (resolveErr) {
1479
+ const msg = resolveErr instanceof Error ? resolveErr.message : String(resolveErr);
1480
+ _nativeConsole.warn("[rolldown scan] resolveId hook error:", spec, msg);
1481
+ }
1482
+ }
1483
+ }
1484
+
1485
+ // Follow local files to discover deeper imports
1486
+ if (spec.startsWith(".") || spec.startsWith("/")) {
1487
+ const dir = pathPolyfill.dirname(filePath);
1488
+ let resolved = "";
1489
+ try {
1490
+ resolved = resolveId(spec, dir, true);
1491
+ } catch {
1492
+ /* not found */
1493
+ }
1494
+ // Vite treats absolute paths as project-root-relative
1495
+ if (!resolved && spec.startsWith("/")) {
1496
+ try {
1497
+ const cwdSpec = pathPolyfill.join(cwd, spec);
1498
+ resolved = resolveId(cwdSpec, cwd, true);
1499
+ } catch {
1500
+ /* not found */
1501
+ }
1502
+ }
1503
+ if (
1504
+ resolved &&
1505
+ !resolved.includes("/node_modules/") &&
1506
+ !visitedFiles.has(resolved)
1507
+ ) {
1508
+ queue.push(resolved);
1509
+ }
1510
+ }
1511
+ }
1512
+ }
1513
+
1514
+ for (const p of plugins) {
1515
+ if (p.buildEnd) {
1516
+ try {
1517
+ await p.buildEnd(mockCtx);
1518
+ } catch (endErr) {
1519
+ const msg = endErr instanceof Error ? endErr.message : String(endErr);
1520
+ _nativeConsole.warn("[rolldown scan] buildEnd hook error:", msg);
1521
+ }
1522
+ }
1523
+ }
1524
+ } catch (scanErr) {
1525
+ const msg = scanErr instanceof Error ? scanErr.message : String(scanErr);
1526
+ const detail = scanErr instanceof Error && scanErr.stack ? `\n${scanErr.stack}` : "";
1527
+ _nativeConsole.warn("[rolldown scan]", msg);
1528
+ }
1529
+ }
1530
+ async close() {
1531
+ this.closed = true;
1532
+ }
1533
+ getWatchFiles() {
1534
+ return this.#watchFiles;
1535
+ }
1536
+ async #bundle(opts: any) {
1537
+ const inputOpts = opts?.inputOptions ?? {};
1538
+ const entries: { name: string; import: string }[] = Array.isArray(
1539
+ inputOpts.input,
1540
+ )
1541
+ ? inputOpts.input
1542
+ : [];
1543
+ const cwd = inputOpts.cwd || "/";
1544
+ const outputOpts = opts?.outputOptions ?? {};
1545
+ const format = outputOpts.format ?? "esm";
1546
+ const entryFileNames = outputOpts.entryFileNames || "[name].js";
1547
+
1548
+ const extractExports = (src: string): string[] => {
1549
+ try {
1550
+ const ast = acorn.parse(src, {
1551
+ ecmaVersion: "latest",
1552
+ sourceType: "module",
1553
+ allowImportExportEverywhere: true,
1554
+ }) as any;
1555
+ const names: string[] = [];
1556
+ for (const node of ast.body) {
1557
+ if (
1558
+ node.type === "ExportNamedDeclaration" &&
1559
+ node.specifiers
1560
+ ) {
1561
+ for (const s of node.specifiers) {
1562
+ if (s.exported?.name) names.push(s.exported.name);
1563
+ }
1564
+ if (node.declaration) {
1565
+ if (node.declaration.id?.name) {
1566
+ names.push(node.declaration.id.name);
1567
+ } else if (node.declaration.declarations) {
1568
+ for (const d of node.declaration.declarations) {
1569
+ if (d.id?.name) names.push(d.id.name);
1570
+ }
1571
+ }
1572
+ }
1573
+ } else if (node.type === "ExportDefaultDeclaration") {
1574
+ names.push("default");
1575
+ } else if (node.type === "ExportAllDeclaration") {
1576
+ // Can't statically enumerate re-exports
1577
+ }
1578
+ }
1579
+ return names;
1580
+ } catch {
1581
+ return [];
1582
+ }
1583
+ };
1584
+
1585
+ // Re-resolve using browser ESM conditions when esbuild produces empty output
1586
+ // (happens with thin ESM re-exports pointing at CJS like vue/index.mjs)
1587
+ const reResolveEntry = (origPath: string): string | null => {
1588
+ // Only applicable inside node_modules
1589
+ const nmIdx = origPath.lastIndexOf("/node_modules/");
1590
+ if (nmIdx === -1) return null;
1591
+ const afterNm = origPath.slice(nmIdx + "/node_modules/".length);
1592
+ const parts = afterNm.split("/");
1593
+ const scoped = parts[0].startsWith("@");
1594
+ const pkgName = scoped ? parts.slice(0, 2).join("/") : parts[0];
1595
+ const pkgRoot = origPath.slice(0, nmIdx) + "/node_modules/" + pkgName;
1596
+ const pkgJsonPath = pkgRoot + "/package.json";
1597
+ try {
1598
+ if (!vol.existsSync(pkgJsonPath)) return null;
1599
+ const manifest = JSON.parse(vol.readFileSync(pkgJsonPath, "utf8"));
1600
+ for (const conds of [
1601
+ { browser: true, import: true },
1602
+ { import: true },
1603
+ ] as const) {
1604
+ try {
1605
+ const resolved = resolveExports(manifest, ".", conds);
1606
+ if (resolved?.length) {
1607
+ const full = pathPolyfill.join(pkgRoot, resolved[0]);
1608
+ if (vol.existsSync(full) && full !== origPath) return full;
1609
+ }
1610
+ } catch { /* try next */ }
1611
+ }
1612
+ } catch { /* can't re-resolve */ }
1613
+ return null;
1614
+ };
1615
+
1616
+ const esbuildMod = CORE_MODULES["esbuild"] as any;
1617
+ const chunks: any[] = [];
1618
+ for (const entry of entries) {
1619
+ let entryPath = entry.import.startsWith("/")
1620
+ ? entry.import
1621
+ : pathPolyfill.resolve(cwd, entry.import);
1622
+ let code: string;
1623
+ const esbuildPlatform =
1624
+ inputOpts.platform === "browser" ? "browser" : "node";
1625
+ const esbuildFormat = format === "cjs" ? "cjs" : "esm";
1626
+
1627
+ const doBuild = async (ep: string) => {
1628
+ const result = await esbuildMod.build({
1629
+ entryPoints: [ep],
1630
+ bundle: true,
1631
+ write: false,
1632
+ format: esbuildFormat,
1633
+ platform: esbuildPlatform,
1634
+ sourcemap: outputOpts.sourcemap ? "inline" : false,
1635
+ target: "esnext",
1636
+ logLevel: "warning",
1637
+ });
1638
+ return result.outputFiles?.[0]?.text ?? vol.readFileSync(ep, "utf8");
1639
+ };
1640
+
1641
+ try {
1642
+ code = await doBuild(entryPath);
1643
+
1644
+ // Empty output = thin ESM re-export of CJS; try browser-ESM re-resolve
1645
+ if (
1646
+ esbuildFormat === "esm" &&
1647
+ esbuildPlatform === "browser" &&
1648
+ code.length < 300 &&
1649
+ extractExports(code).length === 0
1650
+ ) {
1651
+ const alt = reResolveEntry(entryPath);
1652
+ if (alt) {
1653
+ const altCode = await doBuild(alt);
1654
+ if (altCode.length > code.length) {
1655
+ code = altCode;
1656
+ entryPath = alt;
1657
+ }
1658
+ }
1659
+ }
1660
+ } catch (buildErr) {
1661
+ const buildMsg = buildErr instanceof Error ? buildErr.message : String(buildErr);
1662
+ _nativeConsole.warn("[rolldown bundle] esbuild failed for", entryPath, buildMsg);
1663
+ try {
1664
+ code = vol.readFileSync(entryPath, "utf8");
1665
+ } catch {
1666
+ code = "";
1667
+ }
1668
+ }
1669
+ const name =
1670
+ entry.name ||
1671
+ pathPolyfill.basename(
1672
+ entryPath,
1673
+ pathPolyfill.extname(entryPath),
1674
+ );
1675
+ const fileName =
1676
+ typeof entryFileNames === "string"
1677
+ ? entryFileNames.replace("[name]", name)
1678
+ : name + ".js";
1679
+ const exports = extractExports(code);
1680
+ this.#watchFiles.push(entryPath);
1681
+ chunks.push({
1682
+ dropInner: () => ({ freed: true }),
1683
+ getFileName: () => fileName,
1684
+ getName: () => name,
1685
+ getCode: () => code,
1686
+ getExports: () => exports,
1687
+ getIsEntry: () => true,
1688
+ getIsDynamicEntry: () => false,
1689
+ getFacadeModuleId: () => entryPath,
1690
+ getSourcemapFileName: () => null,
1691
+ getPreliminaryFileName: () => fileName,
1692
+ getModules: () => ({ values: [], keys: [] }),
1693
+ getImports: () => [],
1694
+ getDynamicImports: () => [],
1695
+ getModuleIds: () => [entryPath],
1696
+ getMap: () => null,
1697
+ });
1698
+ }
1699
+ return { chunks, assets: [] };
1700
+ }
1701
+ },
1702
+ // Constructor (not class) so methods are own-enumerable — Vite iterates with for...in
1703
+ BindingCallableBuiltinPlugin: function (this: any, _opts: any) {
1704
+ this.resolveId = async function (
1705
+ specifier: string,
1706
+ importer?: string | null,
1707
+ ) {
1708
+ if (!specifier || typeof specifier !== "string") return null;
1709
+ if (specifier.startsWith("\0")) return null;
1710
+ if (
1711
+ specifier.includes(":") &&
1712
+ !specifier.startsWith("/") &&
1713
+ !specifier.startsWith(".")
1714
+ )
1715
+ return null;
1716
+
1717
+ // Preserve query/hash (Vue SFC virtual modules need them)
1718
+ let cleanSpec = specifier;
1719
+ let querySuffix = "";
1720
+ const qIdx = cleanSpec.indexOf("?");
1721
+ if (qIdx !== -1) {
1722
+ querySuffix = cleanSpec.slice(qIdx);
1723
+ cleanSpec = cleanSpec.slice(0, qIdx);
1724
+ }
1725
+ const hIdx = cleanSpec.indexOf("#");
1726
+ if (hIdx !== -1) {
1727
+ querySuffix = cleanSpec.slice(hIdx) + querySuffix;
1728
+ cleanSpec = cleanSpec.slice(0, hIdx);
1729
+ }
1730
+
1731
+ // Strip Vite dev server prefixes like /@fs/ and /@id/
1732
+ let stripped = cleanSpec;
1733
+ if (
1734
+ stripped.startsWith("/@") &&
1735
+ stripped.length > 2 &&
1736
+ stripped[2] !== "/"
1737
+ ) {
1738
+ const secondSlash = stripped.indexOf("/", 2);
1739
+ if (secondSlash !== -1) {
1740
+ stripped = stripped.slice(secondSlash);
1741
+ }
1742
+ }
1743
+
1744
+ const fromDir = importer
1745
+ ? pathPolyfill.dirname(
1746
+ importer.startsWith("/@")
1747
+ ? importer.slice(importer.indexOf("/", 2))
1748
+ : importer,
1749
+ )
1750
+ : (typeof globalThis !== "undefined" &&
1751
+ (globalThis as any).process?.cwd?.()) ||
1752
+ "/";
1753
+
1754
+ for (const candidate of stripped !== cleanSpec
1755
+ ? [stripped, cleanSpec]
1756
+ : [cleanSpec]) {
1757
+ try {
1758
+ const resolved = resolveId(candidate, fromDir, true);
1759
+ if (resolved) {
1760
+ return { id: resolved + querySuffix };
1761
+ }
1762
+ } catch (_e) { /* not found */ }
1763
+
1764
+ if (candidate.startsWith("/")) {
1765
+ if (vol.existsSync(candidate)) return { id: candidate + querySuffix };
1766
+ const cwd =
1767
+ (typeof globalThis !== "undefined" &&
1768
+ (globalThis as any).process?.cwd?.()) ||
1769
+ "/";
1770
+ if (cwd !== "/") {
1771
+ const abs = cwd + candidate;
1772
+ if (vol.existsSync(abs)) return { id: abs + querySuffix };
1773
+ for (const ext of RESOLVE_EXTENSIONS) {
1774
+ if (vol.existsSync(abs + ext)) return { id: abs + ext + querySuffix };
1775
+ }
1776
+ }
1777
+ }
1778
+ }
1779
+ return null;
1780
+ };
1781
+ this.load = async function () {
1782
+ return null;
1783
+ };
1784
+ this.transform = async function () {
1785
+ return null;
1786
+ };
1787
+ this.watchChange = async function () {};
1788
+ this.buildStart = function () {};
1789
+ this.buildEnd = function () {};
1790
+ this.renderChunk = function () {
1791
+ return null;
1792
+ };
1793
+ this.generateBundle = function () {};
1794
+ this.moduleParsed = function () {};
1795
+ },
1796
+ resolveTsconfig: () => ({
1797
+ tsconfig: {
1798
+ compilerOptions: {},
1799
+ },
1800
+ tsconfigFilePaths: [],
1801
+ }),
1802
+ collapseSourcemaps: () => null,
1803
+ freeExternalMemory: noop,
1804
+ scan: noopAsync,
1805
+ BindingWatcher: class {
1806
+ constructor(_options?: any, _notifyOption?: any) {}
1807
+ async close() {}
1808
+ async start(_listener: any) {}
1809
+ },
1810
+ BindingWatcherBundler: class {
1811
+ async close() {}
1812
+ },
1813
+ BindingDevEngine: class {
1814
+ constructor(_options?: any, _devOptions?: any) {}
1815
+ async run() {}
1816
+ async ensureCurrentBuildFinish() {}
1817
+ async getBundleState() {
1818
+ return { lastFullBuildFailed: false, hasStaleOutput: false };
1819
+ }
1820
+ async ensureLatestBuildOutput() {}
1821
+ async invalidate() {
1822
+ return [];
1823
+ }
1824
+ async registerModules() {}
1825
+ async removeClient() {}
1826
+ async close() {}
1827
+ async compileEntry() {
1828
+ return "";
1829
+ }
1830
+ },
1831
+ BindingPluginContext: class {},
1832
+ BindingTransformPluginContext: class {},
1833
+ BindingLoadPluginContext: class {},
1834
+ BindingChunkingContext: class {},
1835
+ BindingOutputChunk: class {},
1836
+ BindingOutputAsset: class {},
1837
+ BindingRenderedChunk: class {},
1838
+ BindingRenderedChunkMeta: class {},
1839
+ BindingRenderedModule: class {},
1840
+ BindingModuleInfo: class {},
1841
+ BindingNormalizedOptions: class {},
1842
+ BindingSourceMap: class {},
1843
+ BindingDecodedMap: class {},
1844
+ BindingBundleEndEventData: class {},
1845
+ BindingBundleErrorEventData: class {},
1846
+ BindingWatcherChangeData: class {},
1847
+ BindingWatcherEvent: class {},
1848
+ TsconfigCache: class {},
1849
+ ParallelJsPluginRegistry: class {},
1850
+ ScheduledBuild: class {},
1851
+ ExportExportNameKind: {},
1852
+ ExportImportNameKind: {},
1853
+ ExportLocalNameKind: {},
1854
+ ImportNameKind: {},
1855
+ FilterTokenKind: {},
1856
+ BindingChunkModuleOrderBy: { ModuleId: 0, ExecOrder: 1 },
1857
+ BindingPluginOrder: { Pre: 0, Post: 1 },
1858
+ BindingAttachDebugInfo: { None: 0, Simple: 1, Full: 2 },
1859
+ BindingLogLevel: { Silent: 0, Debug: 1, Warn: 2, Info: 3 },
1860
+ BindingPropertyReadSideEffects: { Always: 0, False: 1 },
1861
+ BindingPropertyWriteSideEffects: { Always: 0, False: 1 },
1862
+ BindingBuiltinPluginName: {},
1863
+ BindingRebuildStrategy: { Always: 0, Auto: 1, Never: 2 },
1864
+ BindingMagicString: class {
1865
+ _str: string;
1866
+ _original: string;
1867
+ _changed: boolean;
1868
+ _filename: string | null;
1869
+ constructor(source?: string, opts?: any) {
1870
+ this._str = source ?? "";
1871
+ this._original = this._str;
1872
+ this._changed = false;
1873
+ this._filename = opts?.filename ?? null;
1874
+ }
1875
+ get filename() {
1876
+ return this._filename;
1877
+ }
1878
+ replace(from: string, to: string) {
1879
+ this._str = this._str.replace(from, to);
1880
+ if (this._str !== this._original) this._changed = true;
1881
+ return this;
1882
+ }
1883
+ replaceAll(from: string, to: string) {
1884
+ this._str = this._str.split(from).join(to);
1885
+ if (this._str !== this._original) this._changed = true;
1886
+ return this;
1887
+ }
1888
+ prepend(content: string) {
1889
+ this._str = content + this._str;
1890
+ this._changed = true;
1891
+ return this;
1892
+ }
1893
+ append(content: string) {
1894
+ this._str += content;
1895
+ this._changed = true;
1896
+ return this;
1897
+ }
1898
+ prependLeft(idx: number, content: string) {
1899
+ this._str =
1900
+ this._str.slice(0, idx) + content + this._str.slice(idx);
1901
+ this._changed = true;
1902
+ return this;
1903
+ }
1904
+ prependRight(idx: number, content: string) {
1905
+ this._str =
1906
+ this._str.slice(0, idx) + content + this._str.slice(idx);
1907
+ this._changed = true;
1908
+ return this;
1909
+ }
1910
+ appendLeft(idx: number, content: string) {
1911
+ this._str =
1912
+ this._str.slice(0, idx) + content + this._str.slice(idx);
1913
+ this._changed = true;
1914
+ return this;
1915
+ }
1916
+ appendRight(idx: number, content: string) {
1917
+ this._str =
1918
+ this._str.slice(0, idx) + content + this._str.slice(idx);
1919
+ this._changed = true;
1920
+ return this;
1921
+ }
1922
+ overwrite(start: number, end: number, content: string) {
1923
+ this._str =
1924
+ this._str.slice(0, start) + content + this._str.slice(end);
1925
+ this._changed = true;
1926
+ return this;
1927
+ }
1928
+ update(start: number, end: number, content: string) {
1929
+ return this.overwrite(start, end, content);
1930
+ }
1931
+ remove(start: number, end: number) {
1932
+ return this.overwrite(start, end, "");
1933
+ }
1934
+ toString() {
1935
+ return this._str;
1936
+ }
1937
+ hasChanged() {
1938
+ return this._changed;
1939
+ }
1940
+ length() {
1941
+ return this._str.length;
1942
+ }
1943
+ isEmpty() {
1944
+ return this._str.length === 0;
1945
+ }
1946
+ insert(_index: number, _content: string): never {
1947
+ throw new Error(
1948
+ "magicString.insert(...) is deprecated. Use prependRight(...) or appendLeft(...) instead",
1949
+ );
1950
+ }
1951
+ indent(indentor?: string) {
1952
+ const ind = indentor ?? "\t";
1953
+ this._str = this._str.replace(/^/gm, ind);
1954
+ this._changed = true;
1955
+ return this;
1956
+ }
1957
+ trim(_charType?: string) {
1958
+ this._str = this._str.trim();
1959
+ if (this._str !== this._original) this._changed = true;
1960
+ return this;
1961
+ }
1962
+ trimStart(_charType?: string) {
1963
+ this._str = this._str.trimStart();
1964
+ if (this._str !== this._original) this._changed = true;
1965
+ return this;
1966
+ }
1967
+ trimEnd(_charType?: string) {
1968
+ this._str = this._str.trimEnd();
1969
+ if (this._str !== this._original) this._changed = true;
1970
+ return this;
1971
+ }
1972
+ trimLines() {
1973
+ this._str = this._str.replace(/^\n+/, "").replace(/\n+$/, "");
1974
+ if (this._str !== this._original) this._changed = true;
1975
+ return this;
1976
+ }
1977
+ clone() {
1978
+ const c = new (this.constructor as any)(this._str);
1979
+ c._original = this._original;
1980
+ c._changed = this._changed;
1981
+ return c;
1982
+ }
1983
+ lastChar() {
1984
+ return this._str[this._str.length - 1] || "";
1985
+ }
1986
+ lastLine() {
1987
+ const idx = this._str.lastIndexOf("\n");
1988
+ return idx === -1 ? this._str : this._str.slice(idx + 1);
1989
+ }
1990
+ snip(start: number, end: number) {
1991
+ return new (this.constructor as any)(this._str.slice(start, end));
1992
+ }
1993
+ reset(start: number, end: number) {
1994
+ const s = start < 0 ? this._original.length + start : start;
1995
+ const e = end < 0 ? this._original.length + end : end;
1996
+ const original = this._original.slice(s, e);
1997
+ this._str = this._str.slice(0, s) + original + this._str.slice(e);
1998
+ return this;
1999
+ }
2000
+ slice(start?: number, end?: number) {
2001
+ return this._str.slice(start, end);
2002
+ }
2003
+ relocate(start: number, end: number, to: number) {
2004
+ const chunk = this._str.slice(start, end);
2005
+ const without = this._str.slice(0, start) + this._str.slice(end);
2006
+ const adjustedTo = to > end ? to - (end - start) : to;
2007
+ this._str =
2008
+ without.slice(0, adjustedTo) +
2009
+ chunk +
2010
+ without.slice(adjustedTo);
2011
+ this._changed = true;
2012
+ return this;
2013
+ }
2014
+ move(start: number, end: number, index: number) {
2015
+ return this.relocate(start, end, index);
2016
+ }
2017
+ generateMap(_opts?: any) {
2018
+ return { version: 3, sources: [], mappings: "", names: [] };
2019
+ }
2020
+ generateDecodedMap(_opts?: any) {
2021
+ return { version: 3, sources: [], mappings: [], names: [] };
2022
+ }
2023
+ },
2024
+ };
2025
+ }
2026
+ return id;
2027
+ }
2028
+
2029
+ if (id.startsWith("#")) {
2030
+ let dir = fromDir;
2031
+ while (dir !== "/" && dir) {
2032
+ const mf = readManifest(pathPolyfill.join(dir, "package.json"));
2033
+ if (mf?.imports) {
2034
+ for (const conds of [
2035
+ { browser: true, require: true },
2036
+ { require: true },
2037
+ { browser: true, import: true },
2038
+ {},
2039
+ ] as const) {
2040
+ try {
2041
+ const resolved = resolveImports(mf, id, conds);
2042
+ if (resolved?.length) {
2043
+ const full = pathPolyfill.join(dir, resolved[0]);
2044
+ if (vol.existsSync(full)) return full;
2045
+ for (const ext of IMPORTS_FIELD_EXTENSIONS) {
2046
+ if (vol.existsSync(full + ext)) return full + ext;
2047
+ }
2048
+ }
2049
+ } catch {
2050
+ /* try next condition set */
2051
+ }
2052
+ }
2053
+ }
2054
+ const parent = pathPolyfill.dirname(dir);
2055
+ if (parent === dir) break;
2056
+ dir = parent;
2057
+ }
2058
+ // Unresolvable # imports get a stub (many are just feature-detection flags)
2059
+ const stubPath = `/node_modules/.nodepod-stubs/${id.slice(1)}.js`;
2060
+ if (!vol.existsSync(stubPath)) {
2061
+ vol.mkdirSync(pathPolyfill.dirname(stubPath), { recursive: true });
2062
+ vol.writeFileSync(stubPath, "module.exports = {};");
2063
+ }
2064
+ return stubPath;
2065
+ }
2066
+
2067
+ const cacheKey = `${fromDir}|${id}`;
2068
+ const cached = resolveCache.get(cacheKey);
2069
+ if (cached !== undefined) {
2070
+ if (cached === null) {
2071
+ const e = new Error(`Cannot find module '${id}'`) as Error & { code: string };
2072
+ e.code = "MODULE_NOT_FOUND";
2073
+ throw e;
2074
+ }
2075
+ return cached;
2076
+ }
2077
+
2078
+ const tryFile = (base: string): string | null => {
2079
+ if (vol.existsSync(base)) {
2080
+ const s = vol.statSync(base);
2081
+ if (s.isFile()) return base;
2082
+ const localMf = readManifest(pathPolyfill.join(base, "package.json"));
2083
+ if (localMf?.main) {
2084
+ const mainPath = pathPolyfill.join(base, localMf.main);
2085
+ if (vol.existsSync(mainPath)) {
2086
+ const ms = vol.statSync(mainPath);
2087
+ if (ms.isFile()) return mainPath;
2088
+ }
2089
+ for (const ext of MAIN_FIELD_EXTENSIONS) {
2090
+ const withExt = mainPath + ext;
2091
+ if (vol.existsSync(withExt)) return withExt;
2092
+ }
2093
+ }
2094
+ for (const idx of INDEX_FILES) {
2095
+ const idxPath = pathPolyfill.join(base, idx);
2096
+ if (vol.existsSync(idxPath)) return idxPath;
2097
+ }
2098
+ }
2099
+ for (const ext of [...MAIN_FIELD_EXTENSIONS, ".node"]) {
2100
+ const withExt = base + ext;
2101
+ if (vol.existsSync(withExt)) return withExt;
2102
+ }
2103
+ return null;
2104
+ };
2105
+
2106
+ if (id === "." || id === "..") id = id + "/";
2107
+ if (id.startsWith("./") || id.startsWith("../") || id.startsWith("/")) {
2108
+ const abs = id.startsWith("/") ? id : pathPolyfill.resolve(fromDir, id);
2109
+ const found = tryFile(abs);
2110
+ if (found) {
2111
+ resolveCache.set(cacheKey, found);
2112
+ return found;
2113
+ }
2114
+
2115
+ resolveCache.set(cacheKey, null);
2116
+ const e = new Error(`Cannot find module '${id}' from '${fromDir}'`) as Error & { code: string };
2117
+ e.code = "MODULE_NOT_FOUND";
2118
+ throw e;
2119
+ }
2120
+
2121
+ const applyBrowserRemap = (
2122
+ resolved: string,
2123
+ manifest: PackageManifest,
2124
+ pkgRoot: string,
2125
+ ): string | null => {
2126
+ if (!manifest.browser || typeof manifest.browser !== "object")
2127
+ return resolved;
2128
+ const map = manifest.browser as Record<string, string | false>;
2129
+ const rel = "./" + pathPolyfill.relative(pkgRoot, resolved);
2130
+ const relNoExt = rel.replace(/\.(js|json|cjs|mjs)$/, "");
2131
+ for (const k of [rel, relNoExt]) {
2132
+ if (k in map) {
2133
+ if (map[k] === false) return null;
2134
+ return tryFile(pathPolyfill.join(pkgRoot, map[k] as string));
2135
+ }
2136
+ }
2137
+ return resolved;
2138
+ };
2139
+
2140
+ const tryNodeModules = (nmDir: string, moduleId: string): string | null => {
2141
+ const parts = moduleId.split("/");
2142
+ const pkgName =
2143
+ parts[0].startsWith("@") && parts.length > 1
2144
+ ? `${parts[0]}/${parts[1]}`
2145
+ : parts[0];
2146
+
2147
+ const pkgRoot = pathPolyfill.join(nmDir, pkgName);
2148
+ const mfPath = pathPolyfill.join(pkgRoot, "package.json");
2149
+ const manifest = readManifest(mfPath);
2150
+
2151
+ if (manifest) {
2152
+ let exportsResolved = false;
2153
+ if (manifest.exports) {
2154
+ const subpath =
2155
+ moduleId === pkgName
2156
+ ? "."
2157
+ : "./" + moduleId.slice(pkgName.length + 1);
2158
+
2159
+ // Custom export conditions from --conditions flag / NODE_OPTIONS
2160
+ const extraConditions: string[] = [];
2161
+ const execArgv: string[] = proc.execArgv || [];
2162
+ for (let ai = 0; ai < execArgv.length; ai++) {
2163
+ const arg = execArgv[ai];
2164
+ if (arg === "--conditions" || arg === "-C") {
2165
+ if (ai + 1 < execArgv.length) extraConditions.push(execArgv[++ai]);
2166
+ } else if (arg.startsWith("--conditions=")) {
2167
+ extraConditions.push(arg.slice("--conditions=".length));
2168
+ }
2169
+ }
2170
+ const nodeOpts = proc.env?.NODE_OPTIONS || "";
2171
+ const condMatch = nodeOpts.matchAll(/(?:--conditions[= ]|-C )(\S+)/g);
2172
+ for (const m of condMatch) extraConditions.push(m[1]);
2173
+ const condExtra = extraConditions.length > 0
2174
+ ? { conditions: extraConditions }
2175
+ : {};
2176
+
2177
+ const baseSets: Record<string, unknown>[] = preferEsm
2178
+ ? [
2179
+ { node: true, import: true, ...condExtra },
2180
+ { browser: true, import: true, ...condExtra },
2181
+ { import: true, ...condExtra },
2182
+ { node: true, require: true, ...condExtra },
2183
+ { browser: true, require: true, ...condExtra },
2184
+ { require: true, ...condExtra },
2185
+ ]
2186
+ : [
2187
+ { node: true, require: true, ...condExtra },
2188
+ { browser: true, require: true, ...condExtra },
2189
+ { require: true, ...condExtra },
2190
+ { node: true, import: true, ...condExtra },
2191
+ { browser: true, import: true, ...condExtra },
2192
+ { import: true, ...condExtra },
2193
+ ];
2194
+
2195
+ for (const conds of baseSets) {
2196
+ try {
2197
+ const resolved = resolveExports(manifest, subpath, conds);
2198
+ if (resolved?.length) {
2199
+ const full = pathPolyfill.join(pkgRoot, resolved[0]);
2200
+ const found = tryFile(full);
2201
+ if (found) {
2202
+ if (found.endsWith(".cjs")) {
2203
+ try {
2204
+ const content = vol.readFileSync(found, "utf8");
2205
+ if (content.trimStart().startsWith("throw ")) continue;
2206
+ } catch {
2207
+ /* proceed */
2208
+ }
2209
+ }
2210
+ exportsResolved = true;
2211
+ return found;
2212
+ }
2213
+ }
2214
+ } catch {
2215
+ /* try next */
2216
+ }
2217
+ }
2218
+ }
2219
+
2220
+ if (!exportsResolved && pkgName === moduleId) {
2221
+ let entry: string | undefined;
2222
+ if (typeof manifest.browser === "string") entry = manifest.browser;
2223
+ if (!entry && manifest.module) entry = manifest.module as string;
2224
+ if (!entry) entry = manifest.main || "index.js";
2225
+ const found = tryFile(pathPolyfill.join(pkgRoot, entry));
2226
+ if (found) return found;
2227
+ }
2228
+ }
2229
+
2230
+ const directPath = pathPolyfill.join(nmDir, moduleId);
2231
+ return tryFile(directPath);
2232
+ };
2233
+
2234
+ let searchDir = fromDir;
2235
+ while (searchDir !== "/") {
2236
+ const nmDir = pathPolyfill.join(searchDir, "node_modules");
2237
+ const found = tryNodeModules(nmDir, id);
2238
+ if (found) {
2239
+ resolveCache.set(cacheKey, found);
2240
+ return found;
2241
+ }
2242
+ searchDir = pathPolyfill.dirname(searchDir);
2243
+ }
2244
+
2245
+ const rootFound = tryNodeModules("/node_modules", id);
2246
+ if (rootFound) {
2247
+ resolveCache.set(cacheKey, rootFound);
2248
+ return rootFound;
2249
+ }
2250
+
2251
+ // Fallback: resolve from cwd (handles modules loaded from temp/bundled locations)
2252
+ const cwd = proc.cwd();
2253
+ if (cwd !== fromDir && cwd !== "/") {
2254
+ let fallbackDir = cwd;
2255
+ while (fallbackDir !== "/" && fallbackDir !== fromDir) {
2256
+ const nmDir = pathPolyfill.join(fallbackDir, "node_modules");
2257
+ const found = tryNodeModules(nmDir, id);
2258
+ if (found) {
2259
+ resolveCache.set(cacheKey, found);
2260
+ return found;
2261
+ }
2262
+ fallbackDir = pathPolyfill.dirname(fallbackDir);
2263
+ }
2264
+ }
2265
+
2266
+ resolveCache.set(cacheKey, null);
2267
+ const e = new Error(`Cannot find module '${id}' from '${fromDir}'`) as Error & { code: string };
2268
+ e.code = "MODULE_NOT_FOUND";
2269
+ throw e;
2270
+ };
2271
+
2272
+ const loadModule = (resolved: string): ModuleRecord => {
2273
+ if (cache[resolved]) return cache[resolved];
2274
+
2275
+ // Package dedup: reuse first instance of name@version:path to prevent
2276
+ // "Cannot use X from another module or realm" errors
2277
+ const nmIdx = resolved.lastIndexOf("/node_modules/");
2278
+ if (nmIdx !== -1) {
2279
+ const afterNm = resolved.slice(nmIdx + "/node_modules/".length);
2280
+ const parts = afterNm.split("/");
2281
+ const pkgName = parts[0].startsWith("@") ? parts[0] + "/" + parts[1] : parts[0];
2282
+ const pkgDir = resolved.slice(0, nmIdx) + "/node_modules/" + pkgName;
2283
+ try {
2284
+ const pkgJson = JSON.parse(vol.readFileSync(pkgDir + "/package.json", "utf8"));
2285
+ // Include file path so different subpath exports (svelte vs svelte/compiler) aren't deduped
2286
+ const identity = pkgName + "@" + (pkgJson.version || "0.0.0") + ":" + afterNm;
2287
+ if (!_pkgIdentityMap[identity]) {
2288
+ _pkgIdentityMap[identity] = resolved;
2289
+ } else if (_pkgIdentityMap[identity] !== resolved) {
2290
+ // Only reuse fully-loaded modules — returning mid-execution ones causes "X is not a function"
2291
+ const canonical = _pkgIdentityMap[identity];
2292
+ if (cache[canonical] && cache[canonical].loaded) {
2293
+ cache[resolved] = cache[canonical];
2294
+ return cache[canonical];
2295
+ }
2296
+ }
2297
+ } catch { /* no package.json */ }
2298
+ }
2299
+
2300
+ const _loadDepth = ((globalThis as any).__loadModuleDepth ?? 0) + 1;
2301
+ (globalThis as any).__loadModuleDepth = _loadDepth;
2302
+
2303
+ const record: ModuleRecord = {
2304
+ id: resolved,
2305
+ filename: resolved,
2306
+ exports: {},
2307
+ loaded: false,
2308
+ children: [],
2309
+ paths: [],
2310
+ };
2311
+
2312
+ cache[resolved] = record;
2313
+
2314
+ const keys = Object.keys(cache);
2315
+ if (keys.length > LIMITS.MODULE_CACHE_MAX) delete cache[keys[0]];
2316
+
2317
+ if (resolved.endsWith(".json")) {
2318
+ const raw = vol.readFileSync(resolved, "utf8");
2319
+ record.exports = JSON.parse(raw);
2320
+ record.loaded = true;
2321
+ return record;
2322
+ }
2323
+
2324
+ // Native addons can't run in browser — return empty module for fallback
2325
+ if (resolved.endsWith(".node")) {
2326
+ record.exports = {};
2327
+ record.loaded = true;
2328
+ return record;
2329
+ }
2330
+
2331
+ const rawSource = vol.readFileSync(resolved, "utf8");
2332
+ const dir = pathPolyfill.dirname(resolved);
2333
+
2334
+ const codeCacheKey = `${resolved}|${quickDigest(rawSource)}`;
2335
+ let processedCode = codeCache?.get(codeCacheKey);
2336
+
2337
+ if (!processedCode) {
2338
+ processedCode = rawSource;
2339
+ if (processedCode.startsWith("#!")) {
2340
+ processedCode = processedCode.slice(processedCode.indexOf("\n") + 1);
2341
+ }
2342
+ if (isTypeScriptFile(resolved)) {
2343
+ processedCode = stripTypeScript(processedCode);
2344
+ }
2345
+ if (resolved.endsWith(".cjs")) {
2346
+ // CJS: only rewrite import()/import.meta via AST, skip full ESM conversion
2347
+ try {
2348
+ const cjsAst = acorn.parse(processedCode, {
2349
+ ecmaVersion: "latest",
2350
+ sourceType: "script",
2351
+ allowImportExportEverywhere: true,
2352
+ });
2353
+ const cjsPatches: Array<[number, number, string]> = [];
2354
+ const walkCjs = (node: any) => {
2355
+ if (!node || typeof node !== "object") return;
2356
+ if (Array.isArray(node)) { for (const c of node) walkCjs(c); return; }
2357
+ if (typeof node.type !== "string") return;
2358
+ if (node.type === "ImportExpression") {
2359
+ cjsPatches.push([node.start, node.start + 6, "__asyncLoad"]);
2360
+ }
2361
+ if (node.type === "MetaProperty" && node.meta?.name === "import" && node.property?.name === "meta") {
2362
+ cjsPatches.push([
2363
+ node.start,
2364
+ node.end,
2365
+ `({ url: "file://${resolved}", dirname: "${pathPolyfill.dirname(resolved)}", filename: "${resolved}" })`,
2366
+ ]);
2367
+ }
2368
+ for (const key of Object.keys(node)) {
2369
+ if (key === "type" || key === "start" || key === "end") continue;
2370
+ const val = node[key];
2371
+ if (val && typeof val === "object") walkCjs(val);
2372
+ }
2373
+ };
2374
+ walkCjs(cjsAst);
2375
+ if (cjsPatches.length > 0) {
2376
+ cjsPatches.sort((a, b) => b[0] - a[0]);
2377
+ for (const [start, end, replacement] of cjsPatches) {
2378
+ processedCode = processedCode.slice(0, start) + replacement + processedCode.slice(end);
2379
+ }
2380
+ }
2381
+ } catch { /* can't parse — leave untransformed */ }
2382
+ } else {
2383
+ processedCode = convertModuleSyntax(processedCode, resolved);
2384
+ }
2385
+ codeCache?.set(codeCacheKey, processedCode);
2386
+ }
2387
+
2388
+ // "full" de-async strips async from all functions so cross-module calls work with __syncAwait
2389
+ // "topLevelOnly" preserves genuine async behavior for non-TLA modules
2390
+ const moduleHasTLA = resolved.endsWith(".cjs") ? false : hasTopLevelAwait(processedCode);
2391
+ const useFullDeAsync = deAsyncImports || moduleHasTLA;
2392
+
2393
+ const childResolver = buildResolver(
2394
+ vol,
2395
+ fsBridge,
2396
+ proc,
2397
+ dir,
2398
+ cache,
2399
+ opts,
2400
+ codeCache,
2401
+ useFullDeAsync,
2402
+ );
2403
+ childResolver.cache = cache;
2404
+
2405
+ const wrappedConsole = wrapConsole(opts.onConsole);
2406
+
2407
+ try {
2408
+ const metaUrl = "file://" + resolved;
2409
+ // CJS files: skip — would corrupt await inside async functions
2410
+ if (!resolved.endsWith(".cjs")) {
2411
+ processedCode = stripTopLevelAwait(
2412
+ processedCode,
2413
+ useFullDeAsync ? "full" : "topLevelOnly",
2414
+ );
2415
+ }
2416
+ const wrapper = buildModuleWrapper(processedCode);
2417
+
2418
+ let fn;
2419
+ try {
2420
+ fn = (0, eval)(wrapper);
2421
+ } catch (syntaxErr) {
2422
+ const msg =
2423
+ syntaxErr instanceof Error ? syntaxErr.message : String(syntaxErr);
2424
+ throw new SyntaxError(`${msg} (in ${resolved})`);
2425
+ }
2426
+
2427
+ {
2428
+ const srcMap = (globalThis as any).__dbgSrcMap || ((globalThis as any).__dbgSrcMap = new Map());
2429
+ srcMap.set(resolved, wrapper);
2430
+ }
2431
+
2432
+ const asyncLoader = makeDynamicLoader(childResolver);
2433
+ fn(
2434
+ record.exports,
2435
+ childResolver,
2436
+ record,
2437
+ resolved,
2438
+ dir,
2439
+ proc,
2440
+ wrappedConsole,
2441
+ { url: metaUrl, dirname: dir, filename: resolved },
2442
+ asyncLoader,
2443
+ syncAwait,
2444
+ SyncPromiseClass,
2445
+ );
2446
+
2447
+ record.loaded = true;
2448
+ (globalThis as any).__loadModuleDepth = _loadDepth - 1;
2449
+ } catch (err) {
2450
+ (globalThis as any).__loadModuleDepth = _loadDepth - 1;
2451
+ delete cache[resolved];
2452
+ // >8MB WASM: retry with async compilation APIs
2453
+ const errMsg = err instanceof Error ? err.message : String(err);
2454
+ if (
2455
+ errMsg.includes("disallowed on the main thread") ||
2456
+ errMsg.includes("buffer size is larger than") ||
2457
+ errMsg.includes("__WASM_COMPILE_PENDING__")
2458
+ ) {
2459
+ let asyncCode = processedCode!;
2460
+ asyncCode = asyncCode.replace(
2461
+ /new\s+WebAssembly\.Module\b/g,
2462
+ "await __wasmCompile",
2463
+ );
2464
+ asyncCode = asyncCode.replace(
2465
+ /new\s+WebAssembly\.Instance\b/g,
2466
+ "await __wasmInstantiate",
2467
+ );
2468
+
2469
+ const asyncWrapper = buildModuleWrapper(asyncCode, {
2470
+ async: true,
2471
+ useNativePromise: true,
2472
+ includeViteVars: false,
2473
+ hideBrowserGlobals: false,
2474
+ wasmHelpers: true,
2475
+ });
2476
+ try {
2477
+ const asyncFn = (0, eval)(asyncWrapper);
2478
+ const asyncLoader = makeDynamicLoader(childResolver);
2479
+ const wasmReady = asyncFn(
2480
+ record.exports,
2481
+ childResolver,
2482
+ record,
2483
+ resolved,
2484
+ dir,
2485
+ proc,
2486
+ wrappedConsole,
2487
+ { url: "file://" + resolved, dirname: dir, filename: resolved },
2488
+ asyncLoader,
2489
+ syncAwait,
2490
+ SyncPromiseClass,
2491
+ );
2492
+ record.loaded = true;
2493
+ (record as any).__wasmReady = wasmReady;
2494
+ cache[resolved] = record;
2495
+ } catch (retryErr) {
2496
+ if (err instanceof Error && !err.message.includes("(in /")) {
2497
+ err.message = `${err.message} (in ${resolved})`;
2498
+ }
2499
+ throw err;
2500
+ }
2501
+ return record;
2502
+ }
2503
+
2504
+ if (err instanceof Error && !err.message.includes("(in /")) {
2505
+ err.message = `${err.message} (in ${resolved})`;
2506
+ }
2507
+ throw err;
2508
+ }
2509
+
2510
+ return record;
2511
+ };
2512
+
2513
+ const resolver: ResolverFn = (id: string): unknown => {
2514
+ if (typeof id !== "string") {
2515
+ // Match real Node.js error: TypeError with ERR_INVALID_ARG_TYPE code
2516
+ const err: any = new TypeError(
2517
+ `The "id" argument must be of type string. Received ${id === null ? "null" : typeof id}`
2518
+ );
2519
+ err.code = "ERR_INVALID_ARG_TYPE";
2520
+ throw err;
2521
+ }
2522
+ if (id.startsWith("node:")) id = id.slice(5);
2523
+
2524
+ if (id === "fs") return fsBridge;
2525
+ if (id === "fs/promises") return fsBridge.promises;
2526
+ if (id === "process") return proc;
2527
+ if (id === "console") return wrapConsole(opts.onConsole);
2528
+ if (id === "worker_threads") {
2529
+ if (opts.workerThreadsOverride) {
2530
+ const base = CORE_MODULES["worker_threads"];
2531
+ const override = Object.assign(Object.create(null), base, opts.workerThreadsOverride);
2532
+ override.default = override;
2533
+ return override;
2534
+ }
2535
+ return CORE_MODULES["worker_threads"];
2536
+ }
2537
+ if (id === "module") {
2538
+ // Per-engine Module so fork() doesn't clobber parent's _resolveFilename
2539
+ const OrigModule = moduleSysPolyfill.Module;
2540
+
2541
+ function PerEngineModule(this: any, mid?: string, parent?: any) {
2542
+ OrigModule.call(this, mid, parent);
2543
+ }
2544
+ PerEngineModule.prototype = OrigModule.prototype;
2545
+
2546
+ const liveCreateRequire = (from: string) => {
2547
+ let fromPath = from;
2548
+ if (from.startsWith("file://")) {
2549
+ fromPath = decodeURIComponent(from.slice(7));
2550
+ if (fromPath.startsWith("/") && fromPath[2] === ":")
2551
+ fromPath = fromPath.slice(1);
2552
+ }
2553
+ const childDir = pathPolyfill.dirname(fromPath);
2554
+ const child = buildResolver(vol, fsBridge, proc, childDir, cache, opts, codeCache, deAsyncImports);
2555
+ child.cache = cache;
2556
+ return child;
2557
+ };
2558
+
2559
+ PerEngineModule.createRequire = liveCreateRequire;
2560
+ PerEngineModule._cache = cache;
2561
+ PerEngineModule._resolveFilename = (
2562
+ request: string,
2563
+ parent?: any,
2564
+ isMain?: boolean,
2565
+ options?: any,
2566
+ ) => {
2567
+ if (typeof request !== "string") {
2568
+ const err: any = new Error(
2569
+ `Cannot find module '${request}'`,
2570
+ );
2571
+ err.code = "MODULE_NOT_FOUND";
2572
+ throw err;
2573
+ }
2574
+ if (options?.paths && Array.isArray(options.paths)) {
2575
+ for (const p of options.paths) {
2576
+ try {
2577
+ return resolveId(request, p);
2578
+ } catch {
2579
+ /* try next */
2580
+ }
2581
+ }
2582
+ }
2583
+ if (parent?.paths && Array.isArray(parent.paths)) {
2584
+ for (const p of parent.paths) {
2585
+ try {
2586
+ const dir = p.endsWith("/node_modules")
2587
+ ? pathPolyfill.dirname(p)
2588
+ : p;
2589
+ return resolveId(request, dir);
2590
+ } catch {
2591
+ /* try next */
2592
+ }
2593
+ }
2594
+ }
2595
+ const fromDir = parent?.filename
2596
+ ? pathPolyfill.dirname(parent.filename)
2597
+ : baseDir;
2598
+ try {
2599
+ return resolveId(request, fromDir);
2600
+ } catch {
2601
+ const err: any = new Error(
2602
+ `Cannot find module '${request}'`,
2603
+ );
2604
+ err.code = "MODULE_NOT_FOUND";
2605
+ throw err;
2606
+ }
2607
+ };
2608
+ PerEngineModule._load = (request: string, parent?: any, isMain?: boolean) => {
2609
+ try {
2610
+ return resolver(request);
2611
+ } catch {
2612
+ return moduleSysPolyfill._load(request, parent, isMain);
2613
+ }
2614
+ };
2615
+
2616
+ PerEngineModule.builtinModules = moduleSysPolyfill.builtinModules;
2617
+ PerEngineModule.isBuiltin = moduleSysPolyfill.isBuiltin;
2618
+ PerEngineModule._extensions = moduleSysPolyfill._extensions;
2619
+ PerEngineModule._pathCache = moduleSysPolyfill._pathCache;
2620
+ PerEngineModule._nodeModulePaths = moduleSysPolyfill._nodeModulePaths;
2621
+ PerEngineModule._findPath = moduleSysPolyfill._findPath;
2622
+ PerEngineModule.syncBuiltinESMExports =
2623
+ moduleSysPolyfill.syncBuiltinESMExports;
2624
+ PerEngineModule.wrap = moduleSysPolyfill.wrap;
2625
+ PerEngineModule.wrapper = moduleSysPolyfill.wrapper;
2626
+ PerEngineModule.Module = PerEngineModule;
2627
+ PerEngineModule.runMain = OrigModule.runMain;
2628
+ PerEngineModule._preloadModules = OrigModule._preloadModules;
2629
+ PerEngineModule._initPaths = OrigModule._initPaths;
2630
+ PerEngineModule.globalPaths = OrigModule.globalPaths;
2631
+ (PerEngineModule as any).default = PerEngineModule;
2632
+ return PerEngineModule;
2633
+ }
2634
+ if (CORE_MODULES[id]) return CORE_MODULES[id];
2635
+
2636
+ const resolved = resolveId(id, baseDir);
2637
+ if (CORE_MODULES[resolved]) return CORE_MODULES[resolved];
2638
+
2639
+ const rec = loadModule(resolved);
2640
+ // Proxy for async WASM — reads from rec.exports at access time so
2641
+ // reassigned module.exports is picked up after compilation finishes
2642
+ if ((rec as any).__wasmReady) {
2643
+ return new Proxy(Object.create(null), {
2644
+ get(_t, prop) {
2645
+ const ex = rec.exports as any;
2646
+ if (ex && prop in ex) return ex[prop];
2647
+ return undefined;
2648
+ },
2649
+ set(_t, prop, val) {
2650
+ (rec.exports as any)[prop] = val;
2651
+ return true;
2652
+ },
2653
+ has(_t, prop) {
2654
+ return rec.exports ? prop in (rec.exports as any) : false;
2655
+ },
2656
+ ownKeys() {
2657
+ return rec.exports ? Reflect.ownKeys(rec.exports as any) : [];
2658
+ },
2659
+ getOwnPropertyDescriptor(_t, prop) {
2660
+ if (!rec.exports) return undefined;
2661
+ return Object.getOwnPropertyDescriptor(rec.exports as any, prop);
2662
+ },
2663
+ });
2664
+ }
2665
+ return rec.exports;
2666
+ };
2667
+
2668
+ resolver.resolve = (id: string, options?: { paths?: string[] }): string => {
2669
+ if (id === "fs" || id === "process" || CORE_MODULES[id]) return id;
2670
+ if (options?.paths && Array.isArray(options.paths)) {
2671
+ for (const p of options.paths) {
2672
+ try {
2673
+ return resolveId(id, p);
2674
+ } catch {
2675
+ /* try next */
2676
+ }
2677
+ }
2678
+ }
2679
+ return resolveId(id, baseDir);
2680
+ };
2681
+
2682
+ resolver.cache = cache;
2683
+ resolver.extensions = {
2684
+ ".js": () => {},
2685
+ ".json": () => {},
2686
+ ".node": () => {},
2687
+ ".ts": () => {},
2688
+ ".tsx": () => {},
2689
+ ".mjs": () => {},
2690
+ ".cjs": () => {},
2691
+ };
2692
+ resolver.main = null;
2693
+ return resolver;
2694
+ }
2695
+
2696
+ // ── ScriptEngine class ──
2697
+ export class ScriptEngine {
2698
+ private vol: MemoryVolume;
2699
+ private fsBridge: FsBridge;
2700
+ private proc: ProcessObject;
2701
+ private moduleRegistry: Record<string, ModuleRecord> = {};
2702
+ private opts: EngineOptions;
2703
+ private transformCache: Map<string, string> = new Map();
2704
+
2705
+ constructor(vol: MemoryVolume, opts: EngineOptions = {}) {
2706
+ this.vol = vol;
2707
+ this.proc = buildProcessEnv({
2708
+ cwd: opts.cwd || "/",
2709
+ env: opts.env,
2710
+ onStdout: opts.onStdout,
2711
+ onStderr: opts.onStderr,
2712
+ });
2713
+ this.fsBridge = buildFileSystemBridge(vol, () => this.proc.cwd());
2714
+ this.opts = opts;
2715
+
2716
+ // Don't call initShellExec here — Nodepod.boot() sets up the shell with correct cwd
2717
+ import("./polyfills/child_process")
2718
+ .then((mod) => {
2719
+ _shellExecPolyfill = mod;
2720
+ _initShellExec = mod.initShellExec;
2721
+ })
2722
+ .catch(() => {
2723
+ /* shell unavailable in this environment */
2724
+ });
2725
+ watcherPolyfill.setVolume(vol);
2726
+ scannerPolyfill.setVolume(vol);
2727
+ esbuildPolyfill.setVolume(vol);
2728
+
2729
+ (globalThis as any).__nodepodVolume = vol;
2730
+
2731
+ if (typeof globalThis.setImmediate === "undefined") {
2732
+ (globalThis as any).setImmediate = (
2733
+ fn: (...a: unknown[]) => void,
2734
+ ...a: unknown[]
2735
+ ) => setTimeout(fn, 0, ...a);
2736
+ (globalThis as any).clearImmediate = (id: number) => clearTimeout(id);
2737
+ }
2738
+
2739
+ // Browsers disallow sync WebAssembly.Module() for >8MB buffers — serve from cache
2740
+ if (
2741
+ typeof WebAssembly !== "undefined" &&
2742
+ !(WebAssembly.Module as any).__nodepodPatched
2743
+ ) {
2744
+ const OrigModule = WebAssembly.Module;
2745
+ const PatchedModule = function WebAssemblyModule(
2746
+ this: any,
2747
+ bytes: BufferSource,
2748
+ ) {
2749
+ const cached = getCachedModule(bytes);
2750
+ if (cached) return cached;
2751
+ try {
2752
+ return new OrigModule(bytes);
2753
+ } catch (e: any) {
2754
+ if (
2755
+ e &&
2756
+ (e.message?.includes("disallowed on the main thread") ||
2757
+ e.message?.includes("buffer size is larger than"))
2758
+ ) {
2759
+ const cached2 = getCachedModule(bytes);
2760
+ if (cached2) return cached2;
2761
+ const compilePromise = compileWasmInWorker(
2762
+ bytes instanceof ArrayBuffer ? new Uint8Array(bytes) : bytes as Uint8Array,
2763
+ );
2764
+ (globalThis as any).__wasmCompilePromise = compilePromise;
2765
+ }
2766
+ throw e;
2767
+ }
2768
+ } as any;
2769
+ PatchedModule.prototype = OrigModule.prototype;
2770
+ PatchedModule.__nodepodPatched = true;
2771
+ PatchedModule.imports = OrigModule.imports?.bind(OrigModule);
2772
+ PatchedModule.exports = OrigModule.exports?.bind(OrigModule);
2773
+ PatchedModule.customSections =
2774
+ OrigModule.customSections?.bind(OrigModule);
2775
+ (globalThis as any).WebAssembly.Module = PatchedModule;
2776
+ }
2777
+
2778
+ // Timers need .ref()/.unref() to match Node.js API
2779
+ if (!(globalThis.setTimeout as any).__nodepodPatched) {
2780
+ const origST = globalThis.setTimeout.bind(globalThis);
2781
+ const origSI = globalThis.setInterval.bind(globalThis);
2782
+ const origCT = globalThis.clearTimeout.bind(globalThis);
2783
+ const origCI = globalThis.clearInterval.bind(globalThis);
2784
+
2785
+ const wrapTimeout = (id: ReturnType<typeof origST>) => {
2786
+ const obj = {
2787
+ _id: id,
2788
+ _ref: true,
2789
+ ref() { obj._ref = true; return obj; },
2790
+ unref() { obj._ref = false; return obj; },
2791
+ hasRef() { return obj._ref; },
2792
+ refresh() { return obj; },
2793
+ [Symbol.toPrimitive]() { return id; },
2794
+ };
2795
+ return obj;
2796
+ };
2797
+
2798
+ const wrapInterval = (id: ReturnType<typeof origSI>) => {
2799
+ const obj = {
2800
+ _id: id,
2801
+ _ref: true,
2802
+ ref() { obj._ref = true; return obj; },
2803
+ unref() { obj._ref = false; return obj; },
2804
+ hasRef() { return obj._ref; },
2805
+ refresh() { return obj; },
2806
+ [Symbol.toPrimitive]() { return id; },
2807
+ };
2808
+ return obj;
2809
+ };
2810
+
2811
+ (globalThis as any).setTimeout = Object.assign(
2812
+ (...a: Parameters<typeof origST>) => wrapTimeout(origST(...a)),
2813
+ { __nodepodPatched: true },
2814
+ );
2815
+ (globalThis as any).setInterval = Object.assign(
2816
+ (...a: Parameters<typeof origSI>) => wrapInterval(origSI(...a)),
2817
+ { __nodepodPatched: true },
2818
+ );
2819
+ (globalThis as any).clearTimeout = (t: any) => origCT(t?._id ?? t);
2820
+ (globalThis as any).clearInterval = (t: any) => origCI(t?._id ?? t);
2821
+ }
2822
+
2823
+ this.patchStackTraceApi();
2824
+ this.patchTextDecoder();
2825
+ }
2826
+
2827
+ private patchTextDecoder(): void {
2828
+ const Original = globalThis.TextDecoder;
2829
+
2830
+ class ExtendedDecoder {
2831
+ private enc: string;
2832
+ private inner: TextDecoder | null = null;
2833
+
2834
+ constructor(encoding: string = "utf-8", options?: TextDecoderOptions) {
2835
+ this.enc = encoding.toLowerCase();
2836
+ const textEncodings = [
2837
+ "utf-8",
2838
+ "utf8",
2839
+ "utf-16le",
2840
+ "utf-16be",
2841
+ "utf-16",
2842
+ "ascii",
2843
+ "iso-8859-1",
2844
+ "latin1",
2845
+ "windows-1252",
2846
+ ];
2847
+ if (textEncodings.includes(this.enc)) {
2848
+ try {
2849
+ this.inner = new Original(encoding, options);
2850
+ } catch {
2851
+ this.inner = new Original("utf-8", options);
2852
+ }
2853
+ }
2854
+ }
2855
+
2856
+ decode(input?: BufferSource, options?: TextDecodeOptions): string {
2857
+ if (this.inner) return this.inner.decode(input, options);
2858
+ if (!input) return "";
2859
+ const bytes =
2860
+ input instanceof ArrayBuffer
2861
+ ? new Uint8Array(input)
2862
+ : new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
2863
+
2864
+ if (this.enc === "base64") return bytesToBase64(bytes);
2865
+ if (this.enc === "base64url")
2866
+ return bytesToBase64(bytes)
2867
+ .replace(/\+/g, "-")
2868
+ .replace(/\//g, "_")
2869
+ .replace(/=/g, "");
2870
+ if (this.enc === "hex") return bytesToHex(bytes);
2871
+ return new Original("utf-8").decode(input, options);
2872
+ }
2873
+
2874
+ get fatal(): boolean {
2875
+ return this.inner?.fatal ?? false;
2876
+ }
2877
+ get ignoreBOM(): boolean {
2878
+ return this.inner?.ignoreBOM ?? false;
2879
+ }
2880
+ }
2881
+
2882
+ globalThis.TextDecoder = ExtendedDecoder as unknown as typeof TextDecoder;
2883
+ }
2884
+
2885
+ // Override even in Chrome — eval produces stack frames the native V8 API can't map to VFS paths
2886
+ private patchStackTraceApi(): void {
2887
+ if ((Error as any).stackTraceLimit === undefined)
2888
+ (Error as any).stackTraceLimit = 10;
2889
+
2890
+ function parseFrames(stack: string) {
2891
+ if (!stack) return [];
2892
+ const frames: Array<{
2893
+ fn: string;
2894
+ file: string;
2895
+ line: number;
2896
+ col: number;
2897
+ }> = [];
2898
+ for (const raw of stack.split("\n")) {
2899
+ const trimmed = raw.trim();
2900
+ if (!trimmed) continue;
2901
+ if (/^\w*Error\b/.test(trimmed) && !trimmed.startsWith("at ")) continue;
2902
+
2903
+ const safari = trimmed.match(/^(.*)@(.*?):(\d+):(\d+)$/);
2904
+ if (safari) {
2905
+ frames.push({
2906
+ fn: safari[1] || "",
2907
+ file: safari[2],
2908
+ line: +safari[3],
2909
+ col: +safari[4],
2910
+ });
2911
+ continue;
2912
+ }
2913
+
2914
+ const chrome = trimmed.match(
2915
+ /^at\s+(?:(.+?)\s+\()?(.*?):(\d+):(\d+)\)?$/,
2916
+ );
2917
+ if (chrome) {
2918
+ frames.push({
2919
+ fn: chrome[1] || "",
2920
+ file: chrome[2],
2921
+ line: +chrome[3],
2922
+ col: +chrome[4],
2923
+ });
2924
+ continue;
2925
+ }
2926
+
2927
+ const chromePlain = trimmed.match(/^at\s+(?:(.+?)\s+\()?(.*?)\)?$/);
2928
+ if (chromePlain) {
2929
+ frames.push({
2930
+ fn: chromePlain[1] || "",
2931
+ file: chromePlain[2] || "<anonymous>",
2932
+ line: 0,
2933
+ col: 0,
2934
+ });
2935
+ }
2936
+ }
2937
+ return frames;
2938
+ }
2939
+
2940
+ function makeCallSite(f: {
2941
+ fn: string;
2942
+ file: string;
2943
+ line: number;
2944
+ col: number;
2945
+ }) {
2946
+ return {
2947
+ getFileName: () => f.file || null,
2948
+ getLineNumber: () => f.line || null,
2949
+ getColumnNumber: () => f.col || null,
2950
+ getFunctionName: () => f.fn || null,
2951
+ getMethodName: () => f.fn || null,
2952
+ getTypeName: () => null,
2953
+ getThis: () => undefined,
2954
+ getFunction: () => undefined,
2955
+ getEvalOrigin: () => undefined,
2956
+ isNative: () => false,
2957
+ isConstructor: () => false,
2958
+ isToplevel: () => !f.fn,
2959
+ isEval: () => false,
2960
+ toString: () =>
2961
+ f.fn
2962
+ ? `${f.fn} (${f.file}:${f.line}:${f.col})`
2963
+ : `${f.file}:${f.line}:${f.col}`,
2964
+ };
2965
+ }
2966
+
2967
+ function buildSites(stack: string, ctorOpt?: Function) {
2968
+ const frames = parseFrames(stack);
2969
+ let start = 0;
2970
+ if (ctorOpt?.name) {
2971
+ for (let i = 0; i < frames.length; i++) {
2972
+ if (frames[i].fn === ctorOpt.name) {
2973
+ start = i + 1;
2974
+ break;
2975
+ }
2976
+ }
2977
+ }
2978
+ return frames.slice(start).map(makeCallSite);
2979
+ }
2980
+
2981
+ const sym = Symbol("rawStack");
2982
+ const symProcessed = Symbol("stackProcessed");
2983
+
2984
+ const nativeCapture = (Error as any).captureStackTrace;
2985
+
2986
+ Object.defineProperty(Error.prototype, "stack", {
2987
+ get() {
2988
+ if ((this as any)[symProcessed]) return (this as any)[sym];
2989
+ const raw = (this as any)[sym];
2990
+ if (
2991
+ typeof raw === "string" &&
2992
+ typeof (Error as any).prepareStackTrace === "function"
2993
+ ) {
2994
+ try {
2995
+ const sites = buildSites(raw);
2996
+ if (sites.length > 0) {
2997
+ return (Error as any).prepareStackTrace(this, sites);
2998
+ }
2999
+ } catch {
3000
+ return raw;
3001
+ }
3002
+ }
3003
+ return raw;
3004
+ },
3005
+ set(val: any) {
3006
+ (this as any)[sym] = val;
3007
+ },
3008
+ configurable: true,
3009
+ enumerable: false,
3010
+ });
3011
+
3012
+ (Error as any).captureStackTrace = function (
3013
+ target: any,
3014
+ ctorOpt?: Function,
3015
+ ) {
3016
+ const saved = (Error as any).prepareStackTrace;
3017
+ (Error as any).prepareStackTrace = undefined;
3018
+
3019
+ let raw: string;
3020
+ if (nativeCapture) {
3021
+ const tmp = {} as any;
3022
+ nativeCapture(tmp);
3023
+ raw = tmp.stack || "";
3024
+ } else {
3025
+ raw = new Error().stack || "";
3026
+ }
3027
+ (Error as any).prepareStackTrace = saved;
3028
+
3029
+ if (typeof saved === "function") {
3030
+ try {
3031
+ const result = saved(target, buildSites(raw, ctorOpt));
3032
+ (target as any)[symProcessed] = true;
3033
+ target.stack = result;
3034
+ } catch {
3035
+ target.stack = raw;
3036
+ }
3037
+ } else {
3038
+ target.stack = raw;
3039
+ }
3040
+ };
3041
+ }
3042
+
3043
+ execute(
3044
+ code: string,
3045
+ filename: string = "/index.js",
3046
+ ): { exports: unknown; module: ModuleRecord } {
3047
+ const dir = pathPolyfill.dirname(filename);
3048
+ this.vol.writeFileSync(filename, code);
3049
+
3050
+ const mod: ModuleRecord = {
3051
+ id: filename,
3052
+ filename,
3053
+ exports: {},
3054
+ loaded: false,
3055
+ children: [],
3056
+ paths: [],
3057
+ };
3058
+ this.moduleRegistry[filename] = mod;
3059
+
3060
+ const consoleProxy = wrapConsole(this.opts.onConsole);
3061
+
3062
+ let processed = code;
3063
+ if (processed.startsWith("#!"))
3064
+ processed = processed.slice(processed.indexOf("\n") + 1);
3065
+ if (isTypeScriptFile(filename)) {
3066
+ processed = stripTypeScript(processed);
3067
+ }
3068
+ if (filename.endsWith(".cjs")) {
3069
+ try {
3070
+ const cjsAst = acorn.parse(processed, {
3071
+ ecmaVersion: "latest",
3072
+ sourceType: "script",
3073
+ allowImportExportEverywhere: true,
3074
+ });
3075
+ const cjsPatches: Array<[number, number, string]> = [];
3076
+ const walkCjs = (node: any) => {
3077
+ if (!node || typeof node !== "object") return;
3078
+ if (Array.isArray(node)) { for (const c of node) walkCjs(c); return; }
3079
+ if (typeof node.type !== "string") return;
3080
+ if (node.type === "ImportExpression") {
3081
+ cjsPatches.push([node.start, node.start + 6, "__asyncLoad"]);
3082
+ }
3083
+ if (node.type === "MetaProperty" && node.meta?.name === "import" && node.property?.name === "meta") {
3084
+ cjsPatches.push([
3085
+ node.start,
3086
+ node.end,
3087
+ `({ url: "file://${filename}", dirname: "${pathPolyfill.dirname(filename)}", filename: "${filename}" })`,
3088
+ ]);
3089
+ }
3090
+ for (const key of Object.keys(node)) {
3091
+ if (key === "type" || key === "start" || key === "end") continue;
3092
+ const val = node[key];
3093
+ if (val && typeof val === "object") walkCjs(val);
3094
+ }
3095
+ };
3096
+ walkCjs(cjsAst);
3097
+ if (cjsPatches.length > 0) {
3098
+ cjsPatches.sort((a, b) => b[0] - a[0]);
3099
+ for (const [start, end, replacement] of cjsPatches) {
3100
+ processed = processed.slice(0, start) + replacement + processed.slice(end);
3101
+ }
3102
+ }
3103
+ } catch { /* can't parse */ }
3104
+ } else {
3105
+ processed = convertModuleSyntax(processed, filename);
3106
+ }
3107
+
3108
+ const fileHasTLA = filename.endsWith(".cjs") ? false : hasTopLevelAwait(processed);
3109
+ const resolver = buildResolver(
3110
+ this.vol,
3111
+ this.fsBridge,
3112
+ this.proc,
3113
+ dir,
3114
+ this.moduleRegistry,
3115
+ this.opts,
3116
+ this.transformCache,
3117
+ fileHasTLA,
3118
+ );
3119
+
3120
+ try {
3121
+ const metaUrl = "file://" + filename;
3122
+ if (!filename.endsWith(".cjs")) {
3123
+ processed = stripTopLevelAwait(
3124
+ processed,
3125
+ fileHasTLA ? "full" : "topLevelOnly",
3126
+ );
3127
+ }
3128
+ const wrapper = buildModuleWrapper(processed);
3129
+
3130
+ const asyncLoader = makeDynamicLoader(resolver);
3131
+ let fn;
3132
+ try {
3133
+ fn = (0, eval)(wrapper);
3134
+ } catch (syntaxErr) {
3135
+ throw syntaxErr;
3136
+ }
3137
+
3138
+ fn(
3139
+ mod.exports,
3140
+ resolver,
3141
+ mod,
3142
+ filename,
3143
+ dir,
3144
+ this.proc,
3145
+ consoleProxy,
3146
+ { url: metaUrl, dirname: dir, filename },
3147
+ asyncLoader,
3148
+ syncAwait,
3149
+ SyncPromiseClass,
3150
+ );
3151
+
3152
+ mod.loaded = true;
3153
+ } catch (err) {
3154
+ delete this.moduleRegistry[filename];
3155
+ throw err;
3156
+ }
3157
+
3158
+ return { exports: mod.exports, module: mod };
3159
+ }
3160
+
3161
+ executeSync = this.execute;
3162
+
3163
+ async executeAsync(
3164
+ code: string,
3165
+ filename: string = "/index.js",
3166
+ ): Promise<ExecutionOutcome> {
3167
+ return Promise.resolve(this.execute(code, filename));
3168
+ }
3169
+
3170
+ runFile(filename: string): { exports: unknown; module: ModuleRecord } {
3171
+ const source = this.vol.readFileSync(filename, "utf8");
3172
+ return this.execute(source, filename);
3173
+ }
3174
+
3175
+ runFileSync = this.runFile;
3176
+
3177
+ // Wraps in async IIFE when TLA is detected, falls back to sync otherwise
3178
+ async runFileTLA(
3179
+ filename: string,
3180
+ ): Promise<{ exports: unknown; module: ModuleRecord }> {
3181
+ const source = this.vol.readFileSync(filename, "utf8");
3182
+ const dir = pathPolyfill.dirname(filename);
3183
+ this.vol.writeFileSync(filename, source);
3184
+
3185
+ const mod: ModuleRecord = {
3186
+ id: filename,
3187
+ filename,
3188
+ exports: {},
3189
+ loaded: false,
3190
+ children: [],
3191
+ paths: [],
3192
+ };
3193
+ this.moduleRegistry[filename] = mod;
3194
+
3195
+ const consoleProxy = wrapConsole(this.opts.onConsole);
3196
+
3197
+ let processed = source as string;
3198
+ if (processed.startsWith("#!"))
3199
+ processed = processed.slice(processed.indexOf("\n") + 1);
3200
+ if (isTypeScriptFile(filename)) {
3201
+ processed = stripTypeScript(processed);
3202
+ }
3203
+ if (filename.endsWith(".cjs")) {
3204
+ processed = rewriteDynamicImportsRegex(processed);
3205
+ processed = processed.replace(
3206
+ /\bimport\.meta\.url\b/g,
3207
+ `"file://${filename}"`,
3208
+ );
3209
+ processed = processed.replace(
3210
+ /\bimport\.meta\b/g,
3211
+ `({ url: "file://${filename}" })`,
3212
+ );
3213
+ } else {
3214
+ processed = convertModuleSyntax(processed, filename);
3215
+ }
3216
+ const tla = hasTopLevelAwait(processed);
3217
+
3218
+ // Don't propagate deAsyncImports from entry — it uses native await (async IIFE),
3219
+ // so deps don't need de-async. loadModule handles individual TLA modules.
3220
+ const resolver = buildResolver(
3221
+ this.vol,
3222
+ this.fsBridge,
3223
+ this.proc,
3224
+ dir,
3225
+ this.moduleRegistry,
3226
+ this.opts,
3227
+ this.transformCache,
3228
+ false,
3229
+ );
3230
+
3231
+ if (!tla) {
3232
+ try {
3233
+ processed = stripTopLevelAwait(processed);
3234
+ const wrapper = buildModuleWrapper(processed);
3235
+ const asyncLoader = makeDynamicLoader(resolver);
3236
+ const fn = (0, eval)(wrapper);
3237
+
3238
+ fn(
3239
+ mod.exports,
3240
+ resolver,
3241
+ mod,
3242
+ filename,
3243
+ dir,
3244
+ this.proc,
3245
+ consoleProxy,
3246
+ { url: "file://" + filename, dirname: dir, filename },
3247
+ asyncLoader,
3248
+ syncAwait,
3249
+ SyncPromiseClass,
3250
+ );
3251
+ mod.loaded = true;
3252
+ } catch (err) {
3253
+ delete this.moduleRegistry[filename];
3254
+ throw err;
3255
+ }
3256
+ return { exports: mod.exports, module: mod };
3257
+ }
3258
+
3259
+ try {
3260
+ const metaUrl = "file://" + filename;
3261
+ const wrapper = buildModuleWrapper(processed, { async: true });
3262
+ const asyncLoader = makeDynamicLoader(resolver);
3263
+ const fn = (0, eval)(wrapper);
3264
+ await fn(
3265
+ mod.exports,
3266
+ resolver,
3267
+ mod,
3268
+ filename,
3269
+ dir,
3270
+ this.proc,
3271
+ consoleProxy,
3272
+ { url: metaUrl, dirname: dir, filename },
3273
+ asyncLoader,
3274
+ syncAwait,
3275
+ SyncPromiseClass,
3276
+ );
3277
+ mod.loaded = true;
3278
+ } catch (err) {
3279
+ delete this.moduleRegistry[filename];
3280
+ throw err;
3281
+ }
3282
+ return { exports: mod.exports, module: mod };
3283
+ }
3284
+
3285
+ async runFileAsync(filename: string): Promise<ExecutionOutcome> {
3286
+ return Promise.resolve(this.runFile(filename));
3287
+ }
3288
+
3289
+ clearCache(): void {
3290
+ for (const k of Object.keys(this.moduleRegistry))
3291
+ delete this.moduleRegistry[k];
3292
+ }
3293
+
3294
+ getVolume(): MemoryVolume {
3295
+ return this.vol;
3296
+ }
3297
+ getProcess(): ProcessObject {
3298
+ return this.proc;
3299
+ }
3300
+
3301
+ createREPL(): { eval: (code: string) => unknown } {
3302
+ const resolver = buildResolver(
3303
+ this.vol,
3304
+ this.fsBridge,
3305
+ this.proc,
3306
+ "/",
3307
+ this.moduleRegistry,
3308
+ this.opts,
3309
+ this.transformCache,
3310
+ );
3311
+ const consoleProxy = wrapConsole(this.opts.onConsole);
3312
+ const proc = this.proc;
3313
+ const buf = bufferPolyfill.Buffer;
3314
+
3315
+ const GenFn = Object.getPrototypeOf(function* () {}).constructor;
3316
+ const gen = new GenFn(
3317
+ "require",
3318
+ "console",
3319
+ "process",
3320
+ "Buffer",
3321
+ `var __code, __result;
3322
+ while (true) {
3323
+ __code = yield;
3324
+ try {
3325
+ __result = eval(__code);
3326
+ yield { value: __result, error: null };
3327
+ } catch (e) {
3328
+ yield { value: undefined, error: e };
3329
+ }
3330
+ }`,
3331
+ )(resolver, consoleProxy, proc, buf);
3332
+ gen.next();
3333
+
3334
+ return {
3335
+ eval(code: string): unknown {
3336
+ const normalized = code.replace(/^\s*(const|let)\s+/gm, "var ");
3337
+ const exprResult = gen.next("(" + normalized + ")").value as {
3338
+ value: unknown;
3339
+ error: unknown;
3340
+ };
3341
+ if (!exprResult.error) {
3342
+ gen.next();
3343
+ return exprResult.value;
3344
+ }
3345
+ gen.next();
3346
+ const stmtResult = gen.next(normalized).value as {
3347
+ value: unknown;
3348
+ error: unknown;
3349
+ };
3350
+ if (stmtResult.error) {
3351
+ gen.next();
3352
+ throw stmtResult.error;
3353
+ }
3354
+ gen.next();
3355
+ return stmtResult.value;
3356
+ },
3357
+ };
3358
+ }
3359
+ }
3360
+
3361
+ export function executeCode(
3362
+ code: string,
3363
+ vol: MemoryVolume,
3364
+ opts?: EngineOptions,
3365
+ ): { exports: unknown; module: ModuleRecord } {
3366
+ const engine = new ScriptEngine(vol, opts);
3367
+ return engine.execute(code);
3368
+ }
3369
+
3370
+ export type {
3371
+ IScriptEngine,
3372
+ ExecutionOutcome,
3373
+ EngineConfig,
3374
+ } from "./engine-types";
3375
+ export default ScriptEngine;