Repository navigation
computer: Pass isolate capability calls as native RPC values - #183
Open
mattzcarey wants to merge 3 commits into
Open
mattzcarey wants to merge 3 commits into
mattzcarey wants to merge 3 commits into
Conversation
🦋 Changeset detectedLatest commit: 039f65c The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
mattzcarey
force-pushed
the
feat/native-rpc-modules
branch
from
October 1, 2026 11:01
5d1931c to
aa38a8f
Compare
Base automatically changed from
fix/exec-tool-review
to
feat/ws-container-module
October 1, 2026 11:02
mattzcarey
force-pushed
the
feat/ws-container-module
branch
from
October 1, 2026 11:23
1adc1e6 to
0970232
Compare
mattzcarey
force-pushed
the
feat/native-rpc-modules
branch
3 times, most recently
from
October 1, 2026 13:28
5828e04 to
2040d21
Compare
This was referenced Oct 1, 2026
mattzcarey
force-pushed
the
feat/native-rpc-modules
branch
from
October 6, 2026 17:54
2040d21 to
c091b72
Compare
mattzcarey
force-pushed
the
feat/ws-container-module
branch
from
October 6, 2026 17:54
0e2e978 to
1a90515
Compare
mattzcarey
force-pushed
the
feat/native-rpc-modules
branch
from
October 6, 2026 17:56
c091b72 to
3829d7b
Compare
mattzcarey
force-pushed
the
feat/ws-container-module
branch
3 times, most recently
from
October 6, 2026 21:22
9290816 to
ba4b679
Compare
mattzcarey
force-pushed
the
feat/native-rpc-modules
branch
2 times, most recently
from
October 6, 2026 21:37
039f65c to
08ef2ea
Compare
The Dynamic Worker already received a real RPC object, the runtime
bridge, but every node:fs and host module call was JSON-encoded on top
of it: arguments became a string with a custom codec for bytes,
arrays, and objects, and results came back the same way. Bytes
travelled as arrays of numbers, roughly four times their size against
the capability byte limit, and both sides carried an encoder and a
decoder.
Arguments and results now cross as Workers RPC values. The isolate
passes its argument list straight to host.call, and the bridge answers
with { result } or a bounded { error } carrying code and path for
node:fs. The bridge stays the single proxy for every call, so its
controls are unchanged: cancellation, concurrent and total call
counts, per-call deadlines with abort, and draining accepted calls
before an execution ends.
Byte budgets now measure the values themselves: UTF-8 bytes of strings
and keys, raw bytes of byte arrays, and a fixed cost per scalar. The
same walk rejects anything that is not plain data, including functions
and RPC stubs that Workers RPC would otherwise carry into the host as
live callbacks, and cycles.
- Error responses now count against the cumulative response budget. - An error's path and code are kept only if the whole error still fits the payload limit; the message is cut to what is left. - Every value costs at least one byte, so many empty strings or objects can no longer reach the host past the request limit. - Host module arguments and results follow JSON again: undefined object fields are left out and undefined array items become null, so a host value with an optional field no longer fails the execution.
mattzcarey
force-pushed
the
feat/native-rpc-modules
branch
from
October 6, 2026 22:59
08ef2ea to
2aa11a6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #172, after #182 merged into it.
The Dynamic Worker already gets a real RPC object, the runtime bridge. Even so, every
node:fsand host module call was JSON-encoded on top of it:Bytes travelled as arrays of numbers, about four times their real size against
maxCapabilityBytes, and both sides carried an encoder and a decoder.Values now cross as Workers RPC values:
sequenceDiagram participant Code as Isolate code participant Bridge as Host bridge (proxy) participant Host as node:fs / host module Code->>Bridge: call("fs.writeFile", ["/a.bin", Uint8Array]) Note over Bridge: cancelled? concurrency, call count,<br/>measure bytes, reject non-plain data Bridge->>Host: run with deadline and abort signal Host-->>Bridge: value Note over Bridge: measure response, response budget Bridge-->>Code: { result } or { error }The bridge stays the one proxy every call goes through, so its controls are unchanged:
Byte budgets now measure the values themselves: UTF-8 bytes of strings and keys, raw bytes of byte arrays, and a fixed cost per scalar. The same walk rejects anything that is not plain data, including cycles. That includes functions and RPC stubs, which Workers RPC would otherwise carry into the Durable Object as live callbacks. The isolate keeps a rough size check so an obviously oversized request skips the round trip.
What changes for callers: bytes count at their real size, so a 900-byte write now fits under a 1024-byte limit where it used to be rejected. A new script runner test shows this; it fails on the old codec with "capability request exceeds 1024 bytes". Host module arguments and results are still JSON-compatible plain data, normalized as JSON would: an
undefinedobject field is left out and anundefinedarray item becomesnull.Every response counts against the per-execution response budget, errors included. An error keeps its
codeandpathonly if the whole error still fitsmaxPayloadBytes. Every value costs at least one byte, so a request of many empty strings or objects is bounded by the byte limit too. Allowing byte arrays or streams there, for example to streamws:containeroutput, is now a small follow-up rather than a codec change.The script runner suite runs every path through a real Dynamic Worker:
node:fsbytes and errors with codes, host modules, the call, concurrency, and byte limits, and oversized errors. The bridge unit tests add plain-value pass-through, rejection of functions, class instances, and cycles, and UTF-8 sizing.