@@ -412,13 +412,16 @@ impl SandboxBuilderWrapper {
412412 ) -> napi:: Result < & Self > {
413413 self . with_inner ( |b| {
414414 // Blocking mode is intentional: the guest's print/console.log call
415- // is synchronous — the guest must wait for the print to complete
416- // before continuing execution. Unlike host functions (which use
417- // NonBlocking + oneshot channel for async Promise resolution),
418- // print is fire-and-forget with no return value to await.
415+ // blocks until the print has been dispatched to JS via the
416+ // ThreadsafeFunction. However, the current JS/TS wrapper may invoke
417+ // the user-provided callback via a Promise microtask, so user code
418+ // can still run *after* guest execution resumes. From the guest's
419+ // perspective, print is effectively fire-and-forget with no return
420+ // value to await, unlike host functions (which use NonBlocking +
421+ // oneshot channel for async Promise resolution).
419422 //
420- // **Reentrancy note:** The print callback runs while the sandbox
421- // Mutex is held (inside `call_handler`'s `spawn_blocking`).
423+ // **Reentrancy note:** The print callback ultimately runs while the
424+ // sandbox Mutex is held (inside `call_handler`'s `spawn_blocking`).
422425 // Calling Hyperlight APIs that acquire the same lock from within
423426 // the callback (e.g. `snapshot()`, `restore()`, `unload()`) will
424427 // deadlock. Keep print callbacks simple — logging only.
0 commit comments