Skip to content

Commit c83789d

Browse files
committed
fix: readline named exports, process.env in ESM run mode, ESM exec mode detection, grace period. Remaining: V8 run mode event loop
1 parent 936eb1e commit c83789d

4 files changed

Lines changed: 21 additions & 6 deletions

File tree

packages/nodejs/src/builtin-modules.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ const KNOWN_BUILTIN_MODULES = new Set([
138138
* `import { readFile } from 'fs'` works inside the isolate.
139139
*/
140140
export const BUILTIN_NAMED_EXPORTS: Record<string, string[]> = {
141+
readline: [
142+
"createInterface",
143+
"promises",
144+
],
141145
fs: [
142146
"promises",
143147
"readFileSync",

packages/nodejs/src/execution-driver.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,7 @@ export class NodeExecutionDriver implements RuntimeDriver {
902902
}
903903

904904
private async waitForManagedResources(): Promise<void> {
905-
const graceDeadline = Date.now() + 100;
905+
const graceDeadline = Date.now() + 5000;
906906

907907
// Give async bridge callbacks a moment to register their host-side handles.
908908
while (!this.disposed && !this.hasManagedResources() && Date.now() < graceDeadline) {
@@ -1330,7 +1330,7 @@ export class NodeExecutionDriver implements RuntimeDriver {
13301330
},
13311331
});
13321332

1333-
if (options.mode === "exec" && !result.error) {
1333+
if (!result.error) {
13341334
await this.waitForManagedResources();
13351335
}
13361336

packages/nodejs/src/kernel-runtime.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -905,14 +905,24 @@ class NodeRuntimeDriver implements RuntimeDriver {
905905
// where the CJS transform succeeds, return transformed CJS code instead.
906906
if (this._isOverlayEsmEntry(hostPath)) {
907907
const transformed = transformSourceForRequireSync(content, scriptPath);
908-
// Check if the transform actually converted ESM to CJS (not just stripped shebang).
909-
// The require-setup marker indicates a successful ESM→CJS conversion.
910908
const REQUIRE_ESM_MARKER = "/*__secure_exec_require_esm__*/";
911909
if (transformed.startsWith(REQUIRE_ESM_MARKER)) {
912910
console.error(`[_resolveEntry] ESM→CJS transform OK: ${scriptPath} (${content.length}${transformed.length})`);
913911
return { code: transformed, filePath: scriptPath };
914912
}
915-
console.error(`[_resolveEntry] ESM→CJS transform skipped: ${scriptPath} (${content.length} bytes, no marker), using V8 ESM`);
913+
// CJS transform failed (e.g., top-level await). Wrap in a CJS
914+
// async launcher that imports the module and then waits for active
915+
// handles (event loop pump). This runs in exec mode with full
916+
// event loop support via _waitForActiveHandles.
917+
console.error(`[_resolveEntry] ESM async launcher: ${scriptPath} (${content.length} bytes)`);
918+
const launcher = [
919+
`/*__secure_exec_require_esm__*/`,
920+
`(async function() {`,
921+
` try { await __dynamicImport(${JSON.stringify(scriptPath)}, ${JSON.stringify(scriptPath)}); }`,
922+
` catch(e) { process.stderr.write(String(e.stack || e.message) + "\\n"); process.exit(1); }`,
923+
`})();`,
924+
].join("\n");
925+
return { code: launcher, filePath: scriptPath };
916926
}
917927
return { code: content, filePath: scriptPath };
918928
} catch {

packages/nodejs/src/module-source.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,8 @@ export function transformSourceForRequireSync(
265265

266266
try {
267267
return transformSync(normalizedSource, getRequireTransformOptions(filePath, syntax)).code;
268-
} catch {
268+
} catch (e) {
269+
console.error(`[transformSourceForRequireSync] FAILED for ${filePath}: ${(e as Error).message?.slice(0, 200)}`);
269270
return normalizedSource;
270271
}
271272
}

0 commit comments

Comments
 (0)