Skip to content

feat: expose host print function to Node.js API#55

Open
simongdavies wants to merge 1 commit intohyperlight-dev:mainfrom
simongdavies:expose-host-print-to-node-js
Open

feat: expose host print function to Node.js API#55
simongdavies wants to merge 1 commit intohyperlight-dev:mainfrom
simongdavies:expose-host-print-to-node-js

Conversation

@simongdavies
Copy link
Copy Markdown
Contributor

Add setHostPrintFn() to SandboxBuilder allowing Node.js callers to receive guest console.log/print output via a callback.

  • New setHostPrintFn(callback) method on SandboxBuilder (NAPI layer)
  • Uses ThreadsafeFunction in blocking mode for synchronous print semantics
  • Supports method chaining (returns this)
  • Added to lib.js sync wrapper list for error code extraction
  • 4 new vitest tests: chaining, single log, multiple logs, consumed error
  • index.d.ts auto-generated by napi build with correct TypeScript types

@simongdavies simongdavies added the kind/enhancement New feature or improvement label Mar 18, 2026
@simongdavies simongdavies force-pushed the expose-host-print-to-node-js branch from 54b4d31 to 0e553bc Compare March 18, 2026 19:54
@simongdavies simongdavies requested a review from Copilot March 26, 2026 13:21
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR exposes guest console.log/print output to Node.js consumers by adding a setHostPrintFn() callback hook on SandboxBuilder, wiring it through the NAPI layer and JS error-enrichment wrapper, and validating behavior via new Vitest tests.

Changes:

  • Add SandboxBuilder.setHostPrintFn() to the Rust NAPI layer using a blocking ThreadsafeFunction<String> to preserve synchronous print semantics.
  • Add a custom lib.js wrapper for setHostPrintFn that catches exceptions thrown by the user’s callback to avoid unhandled errors.
  • Add Vitest coverage for chaining, single/multi log delivery, callback replacement, callback-throw resilience, and consumed-builder errors.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/js-host-api/src/lib.rs Adds the NAPI set_host_print_fn method that registers a host print callback into the underlying sandbox builder.
src/js-host-api/lib.js Wraps setHostPrintFn to catch callback exceptions and keep error-code enrichment behavior consistent.
src/js-host-api/tests/sandbox.test.js Adds tests ensuring host print callback semantics and builder lifecycle behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Add setHostPrintFn() to SandboxBuilder allowing Node.js callers to
receive guest console.log/print output via a callback.

- New setHostPrintFn(callback) method on SandboxBuilder (NAPI layer)
- Uses ThreadsafeFunction<String> in blocking mode for synchronous
  print semantics
- Supports method chaining (returns this)
- Added to lib.js sync wrapper list for error code extraction
- 4 new vitest tests: chaining, single log, multiple logs, consumed error
- index.d.ts auto-generated by napi build with correct TypeScript types

Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +385 to +390
const loaded = await sandbox.getLoadedSandbox();
await loaded.callHandler('handler', {});

expect(firstMessages.length).toBe(0);
expect(secondMessages.join('')).toContain('which callback?');
});
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test asserts on secondMessages immediately after await loaded.callHandler(...), but the print wrapper defers the user callback via Promise.resolve().then(...) (see other tests here that yield with setTimeout(0)). Without a yield/flush here, this can be timing-dependent and flaky; add the same flush before the assertions (or make the print wrapper synchronous).

Copilot uses AI. Check for mistakes.
Comment on lines +220 to +222
// Forward non-function values to the native method for consistent
// validation errors (the Rust layer rejects non-callable arguments).
return origSetHostPrintFn.call(this, callback);
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The typeof callback !== 'function' branch is redundant/misleading: because the native signature expects a ThreadsafeFunction, non-callables will be rejected by napi argument conversion before Rust validation can run, so you won’t get a project-specific [ERR_*] code either way. Consider validating and throwing a clear JS error here, or remove the branch/comment to avoid implying the Rust layer will handle non-functions.

Suggested change
// Forward non-function values to the native method for consistent
// validation errors (the Rust layer rejects non-callable arguments).
return origSetHostPrintFn.call(this, callback);
throw new TypeError(
`SandboxBuilder.setHostPrintFn expects a function, received ${typeof callback}`
);

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/enhancement New feature or improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants