Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Replace Koffi with ffi-rs in the Node SDK - #2643

Closed
stephentoub wants to merge 2 commits into
mainfrom
stephentoub-evaluate-node-ffi
Closed

Replace Koffi with ffi-rs in the Node SDK#2643
stephentoub wants to merge 2 commits into
mainfrom
stephentoub-evaluate-node-ffi

Conversation

@stephentoub

Copy link
Copy Markdown
Collaborator

Why

The Node in-process runtime transport uses a narrow C ABI, but Koffi contributes a relatively large native dependency. ffi-rs supports all runtime targets used by the SDK while reducing the observed Windows x64 installed footprint from approximately 2.73 MB to 1.47 MB and loading its addon faster.

What changed

  • Replace the Koffi dependency and lockfile entries with ffi-rs 1.3.7.
  • Reimplement synchronous and asynchronous native calls, callback registration, pointer decoding, and resource cleanup using ffi-rs.
  • Preserve connection-close retries and callback quarantine behavior, including rollback after partial startup failures.
  • Use a path-specific library key so multiple SDK/runtime copies cannot silently resolve symbols from the wrong native library.
  • Add focused tests for callback ABI descriptors, pointer reconstruction, cleanup retries, disposal during callbacks, partial startup rollback, and cleanup failures.

Validation

  • TypeScript typecheck
  • Prettier and ESLint checks
  • 10/10 focused FFI lifecycle tests
  • 199/199 client regression tests
  • ESM and CJS builds, including a real CJS in-process round trip
  • Real in-process runtime E2E tests on Windows x64 during development
  • Package dry run and dependency installation
  • Sustained callback traffic, which reached a stable RSS plateau after warmup

Tradeoffs and review notes

A trivial native call takes approximately 2.8 microseconds through ffi-rs, compared with approximately 43 nanoseconds through a pre-bound Koffi function. The relative difference is large, but the absolute overhead is negligible compared with JSON-RPC and runtime processing.

ffi-rs 1.3.7 also requires two callback compatibility measures: pointer arguments are transported as lossless BigInt values because native-thread External conversion aborts, and callbacks use an ignored U64 return because Void callbacks corrupt callback-owned data. These paths have targeted tests but need careful cross-platform CI coverage.

One upstream limitation remains: if native close fails permanently or freePointer throws, ffi-rs provides no safe callback unref API, so its referenced thread-safe callback can keep Node alive. The relevant lines are annotated for review.

Generated by Copilot

Migrate the in-process runtime transport to ffi-rs, preserve callback and cleanup lifecycle behavior, and add coverage for callback pointer handling and partial startup rollback.

Co-authored-by: Copilot App <[email protected]>
Copilot AI balanced review requested due to automatic review settings September 13, 2026 18:05
@stephentoub
stephentoub requested a review from a team as a code owner September 13, 2026 18:05
@github-actions

This comment has been minimized.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Synchronous non-void FFI calls are memory-unsafe in the pinned dependency, and the samples lockfile is incomplete.

Get a fresh assessment by requesting another Copilot review.

Review tier: Balanced
Findings: 1 High severity · 1 Medium severity

Open findings (2)
What changed in this PR

Replaces Koffi with ffi-rs for the Node SDK’s in-process native transport.

Changes:

  • Reworks native calls, callbacks, pointer handling, and cleanup.
  • Adds focused FFI lifecycle tests.
  • Updates dependencies and lockfiles.
File Description
nodejs/​src/​ffiRuntimeHost.ts Implements the ffi-rs transport.
nodejs/​src/​client.ts Updates lazy-loading documentation.
nodejs/​test/​ffiRuntimeHost.test.ts Tests callback and cleanup behavior.
nodejs/​package.json Replaces the FFI dependency.
nodejs/​package-lock.json Locks ffi-rs platform packages.
nodejs/​samples/​package-lock.json Partially updates the sample lock graph.
Files not reviewed (2)
  • nodejs/package-lock.json: Generated file
  • nodejs/samples/package-lock.json: Generated file

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread nodejs/src/ffiRuntimeHost.ts
Comment thread nodejs/samples/package-lock.json
Run every non-void ffi-rs call on its worker-thread path, preserve serialized writes, add regression coverage, and complete the samples lock graph.

Co-authored-by: Copilot App <[email protected]>
@github-actions

Copy link
Copy Markdown
Contributor

SDK Consistency Review — PR #2643

Scope of change: This PR only modifies the Node.js SDK's internal in-process FFI runtime host implementation, replacing the koffi native-binding library with ffi-rs (nodejs/src/ffiRuntimeHost.ts, nodejs/src/client.ts comment update, nodejs/package.json/lockfiles, and the corresponding unit test).

Findings:

  • No public API surface changed — CopilotClient's public methods, options, and behavior are unaffected; only the private native-binding implementation used for the in-process transport was swapped.
  • No new feature was introduced, so there's nothing to mirror in other language SDKs.
  • Each other SDK (Java JnaNativeBinding/FfiRuntimeHost, Go internal/ffihost, .NET FfiRuntimeHost.cs, Python _ffi_runtime_host.py, Rust — native runtime itself) already has its own independent, idiomatic native-binding implementation appropriate to that language's FFI ecosystem (JNA, cgo, P/Invoke, ctypes, native Rust). None of these need to change as a result of swapping the Node.js FFI library.
  • The change is a like-for-like internal implementation swap: same public behavior (in-process host start/shutdown, connection open/write/close, outbound callback framing), just re-implemented against ffi-rs's API instead of koffi's.

Conclusion: This PR maintains cross-SDK consistency. It is a Node.js-only internal dependency/implementation change with no observable API or behavioral difference, so no other SDK requires updates.

Generated by SDK Consistency Review Agent for #2643 · copilot · sonnet50 · 29.4 AIC · ⌖ 12.2 AIC · ⊞ 8.3K ·

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants