@@ -36,16 +36,23 @@ import { createProcessConfigForExecution } from "./bridge-setup.js";
3636
3737export { NodeExecutionDriverOptions } ;
3838
39+ // Module-level cache for the static bridge IIFE (identical across all sessions)
40+ let staticBridgeCodeCache : string | null = null ;
41+
3942/**
40- * Compose the default bridge code for snapshot warm-up.
41- * Uses timingMitigation='none' and default budget values so the snapshot
42- * is ready for the most common session configuration.
43+ * Compose the config-independent bridge IIFE. Output is byte-for-byte
44+ * identical regardless of session options — uses DEFAULT values for all
45+ * config that gets overridden by the post-restore script.
46+ * Used for snapshot creation and as the base of every session's bridge code.
4347 */
44- export function composeBridgeCodeForWarmup ( ) : string {
48+ export function composeStaticBridgeCode ( ) : string {
49+ if ( staticBridgeCodeCache ) return staticBridgeCodeCache ;
50+
4551 const parts : string [ ] = [ ] ;
4652
4753 parts . push ( getIvmCompatShimSource ( ) ) ;
4854
55+ // Default budget values — overridden per-session by post-restore script
4956 parts . push ( `globalThis._maxTimers = ${ DEFAULT_MAX_TIMERS } ;` ) ;
5057 parts . push ( `globalThis._maxHandles = ${ DEFAULT_MAX_HANDLES } ;` ) ;
5158 parts . push ( `globalThis.__runtimeBridgeSetupConfig = ${ JSON . stringify ( {
@@ -61,7 +68,7 @@ export function composeBridgeCodeForWarmup(): string {
6168 parts . push ( getRawBridgeCode ( ) ) ;
6269 parts . push ( getBridgeAttachCode ( ) ) ;
6370
64- // Default: no timing mitigation
71+ // Default: no timing mitigation (freeze applied via post-restore script)
6572 parts . push ( getIsolateRuntimeSource ( "applyTimingMitigationOff" ) ) ;
6673
6774 parts . push ( getRequireSetupCode ( ) ) ;
@@ -73,16 +80,64 @@ export function composeBridgeCodeForWarmup(): string {
7380 } ) } ;`) ;
7481 parts . push ( getIsolateRuntimeSource ( "applyCustomGlobalPolicy" ) ) ;
7582
76- // Apply default config via __runtimeApplyConfig (no timing freeze for warmup)
83+ staticBridgeCodeCache = parts . join ( "\n" ) ;
84+ return staticBridgeCodeCache ;
85+ }
86+
87+ /**
88+ * Compose the per-session post-restore script. Overrides default config
89+ * values from the static IIFE with session-specific values, applies timing
90+ * mitigation, and handles polyfill loading.
91+ */
92+ export function composePostRestoreScript ( config : {
93+ timingMitigation : TimingMitigation ;
94+ frozenTimeMs : number ;
95+ maxTimers ?: number ;
96+ maxHandles ?: number ;
97+ initialCwd ?: string ;
98+ payloadLimitBytes ?: number ;
99+ payloadLimitErrorCode ?: string ;
100+ } ) : string {
101+ const parts : string [ ] = [ ] ;
102+
103+ // Override per-session budget values if they differ from defaults
104+ if ( config . maxTimers !== undefined ) {
105+ parts . push ( `globalThis._maxTimers = ${ config . maxTimers } ;` ) ;
106+ }
107+ if ( config . maxHandles !== undefined ) {
108+ parts . push ( `globalThis._maxHandles = ${ config . maxHandles } ;` ) ;
109+ }
110+
111+ // Override initial cwd for module resolution
112+ if ( config . initialCwd && config . initialCwd !== DEFAULT_SANDBOX_CWD ) {
113+ parts . push ( `if (globalThis._currentModule) globalThis._currentModule.dirname = ${ JSON . stringify ( config . initialCwd ) } ;` ) ;
114+ }
115+
116+ // Apply config (timing mitigation, payload limits) via __runtimeApplyConfig
77117 parts . push ( `globalThis.__runtimeApplyConfig(${ JSON . stringify ( {
78- timingMitigation : "none" ,
79- payloadLimitBytes : DEFAULT_ISOLATE_JSON_PAYLOAD_BYTES ,
80- payloadLimitErrorCode : PAYLOAD_LIMIT_ERROR_CODE ,
118+ timingMitigation : config . timingMitigation ,
119+ frozenTimeMs : config . timingMitigation === "freeze" ? config . frozenTimeMs : undefined ,
120+ payloadLimitBytes : config . payloadLimitBytes ,
121+ payloadLimitErrorCode : config . payloadLimitErrorCode ,
81122 } ) } );`) ;
82123
83124 return parts . join ( "\n" ) ;
84125}
85126
127+ /**
128+ * Compose the default bridge code for snapshot warm-up.
129+ * Uses timingMitigation='none' and default budget values so the snapshot
130+ * is ready for the most common session configuration.
131+ */
132+ export function composeBridgeCodeForWarmup ( ) : string {
133+ return composeStaticBridgeCode ( ) + "\n" + composePostRestoreScript ( {
134+ timingMitigation : "off" ,
135+ frozenTimeMs : 0 ,
136+ payloadLimitBytes : DEFAULT_ISOLATE_JSON_PAYLOAD_BYTES ,
137+ payloadLimitErrorCode : PAYLOAD_LIMIT_ERROR_CODE ,
138+ } ) ;
139+ }
140+
86141const MAX_ERROR_MESSAGE_CHARS = 8192 ;
87142
88143function boundErrorMessage ( message : string ) : string {
@@ -100,9 +155,6 @@ export class NodeExecutionDriver implements RuntimeDriver {
100155 private v8InitPromise : Promise < void > | null = null ;
101156 private v8RuntimeOverride : V8Runtime | null ;
102157
103- // Cached bridge code (same across executions)
104- private bridgeCodeCache : string | null = null ;
105-
106158 constructor ( options : NodeExecutionDriverOptions ) {
107159 this . v8RuntimeOverride = options . v8Runtime ?? null ;
108160 this . memoryLimit = options . memoryLimit ?? 128 ;
@@ -222,81 +274,20 @@ export class NodeExecutionDriver implements RuntimeDriver {
222274 } ) ;
223275 }
224276
225- /** Build the config-independent bridge IIFE (cached across executions). */
226- private getBridgeIIFE ( ) : string {
227- if ( this . bridgeCodeCache ) return this . bridgeCodeCache ;
228-
229- const parts : string [ ] = [ ] ;
230-
231- // 1. ivm-compat shim (wraps bridge functions with .applySync/.applySyncPromise)
232- parts . push ( getIvmCompatShimSource ( ) ) ;
233-
234- // 2. Config value injections
235- if ( this . deps . maxTimers !== undefined ) {
236- parts . push ( `globalThis._maxTimers = ${ this . deps . maxTimers } ;` ) ;
237- }
238- if ( this . deps . maxHandles !== undefined ) {
239- parts . push ( `globalThis._maxHandles = ${ this . deps . maxHandles } ;` ) ;
240- }
241- parts . push ( `globalThis.__runtimeBridgeSetupConfig = ${ JSON . stringify ( {
242- initialCwd : this . deps . processConfig . cwd ?? "/" ,
243- jsonPayloadLimitBytes : this . deps . isolateJsonPayloadLimitBytes ,
244- payloadLimitErrorCode : PAYLOAD_LIMIT_ERROR_CODE ,
245- } ) } ;`) ;
246-
247- // 3. Global exposure helpers
248- parts . push ( getIsolateRuntimeSource ( "globalExposureHelpers" ) ) ;
249-
250- // 4. Initial bridge globals setup (defines __runtimeApplyConfig)
251- parts . push ( getInitialBridgeGlobalsSetupCode ( ) ) ;
252-
253- // 5. Console setup (hooks into _log/_error)
254- parts . push ( getConsoleSetupCode ( ) ) ;
255-
256- // 5b. Filesystem facade (_fs object wrapping individual _fs* bridge functions)
257- parts . push ( getIsolateRuntimeSource ( "setupFsFacade" ) ) ;
258-
259- // 6. Bridge bundle IIFE
260- parts . push ( getRawBridgeCode ( ) ) ;
261-
262- // 7. Bridge attach
263- parts . push ( getBridgeAttachCode ( ) ) ;
264-
265- // 8. Timing mitigation — default performance polyfill (freeze applied via __runtimeApplyConfig)
266- parts . push ( getIsolateRuntimeSource ( "applyTimingMitigationOff" ) ) ;
267-
268- // 9. Require setup
269- parts . push ( getRequireSetupCode ( ) ) ;
270-
271- // 10. CJS module/exports globals (for run() and exec() with filePath)
272- parts . push ( getIsolateRuntimeSource ( "initCommonjsModuleGlobals" ) ) ;
273-
274- // 11. Harden custom globals (non-writable/configurable for hardened, mutable for mutable)
275- parts . push ( `globalThis.__runtimeCustomGlobalPolicy = ${ JSON . stringify ( {
276- hardenedGlobals : HARDENED_NODE_CUSTOM_GLOBALS ,
277- mutableGlobals : MUTABLE_NODE_CUSTOM_GLOBALS ,
278- } ) } ;`) ;
279- parts . push ( getIsolateRuntimeSource ( "applyCustomGlobalPolicy" ) ) ;
280-
281- this . bridgeCodeCache = parts . join ( "\n" ) ;
282- return this . bridgeCodeCache ;
283- }
284-
285- /** Compose the full bridge code: cached IIFE + per-execution __runtimeApplyConfig call. */
277+ /** Compose the full bridge code: static IIFE + per-execution post-restore script. */
286278 private composeBridgeCode (
287279 timingMitigation : TimingMitigation ,
288280 frozenTimeMs : number ,
289281 ) : string {
290- const iife = this . getBridgeIIFE ( ) ;
291-
292- // Append per-execution config application via __runtimeApplyConfig
293- const configCall = `globalThis.__runtimeApplyConfig(${ JSON . stringify ( {
282+ return composeStaticBridgeCode ( ) + "\n" + composePostRestoreScript ( {
294283 timingMitigation,
295- frozenTimeMs : timingMitigation === "freeze" ? frozenTimeMs : undefined ,
284+ frozenTimeMs,
285+ maxTimers : this . deps . maxTimers ,
286+ maxHandles : this . deps . maxHandles ,
287+ initialCwd : this . deps . processConfig . cwd ?? DEFAULT_SANDBOX_CWD ,
296288 payloadLimitBytes : this . deps . isolateJsonPayloadLimitBytes ,
297289 payloadLimitErrorCode : PAYLOAD_LIMIT_ERROR_CODE ,
298- } ) } );`;
299- return iife + "\n" + configCall ;
290+ } ) ;
300291 }
301292
302293 private async executeInternal < T = unknown > ( options : {
0 commit comments