You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
<stub>.map(fn) already records fn locally, emits a ["remap", …] instruction, and replays it on the receiver. This generalizes the mechanism so any user-defined method on an RpcTarget can accept callbacks that serialize the same way.
Motivation: I'm building typegres which uses capnweb to expose a capability-based query builder:
The callbacks should be interpreted server-side (not exported as a stub and sent back to client).
Key design decisions
Backward compatibility: Plain functions passed over RPC today are exported as stubs (pass-by-reference). To keep that unchanged, the draft only routes functions through record-replay when they're passed inside a .map() callback — where creating a new stub is already forbidden. (No new opt-in flags needed).
Sharing between map and general closures: I chose to re-use the most code possible but maintain distinct wire formats for remap and closure.
Potential follow-ons (not in this PR):
Sync replay for closures -- the receiver's replay fn currently returns a Promise because RpcPayload.deliverResolve always wraps in one, even when nothing needs awaiting. Async closures are already rejected at serialize time.
Why this matters: Typegres's query builder is synchronous -- without sync replay, every callback-taking method has to become async, infecting the call chain.
Stub identity preservation: independent of closures: round-tripping a stub back to its owner currently yields a proxy, not the raw target.
Why this matters: server may need to do things like validate the type of the object, access non-exposed fields, etc. which are impossible to do if its own object is wrapped behind a stub
(Opening as a draft to get your read on the design -- happy to rework anything.)
Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.
This PR includes no changesets
When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types
Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution. You can sign the CLA by just posting a Pull Request Comment same as the below format.
I have read the CLA Document and I hereby sign the CLA
You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.
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
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.
<stub>.map(fn)already recordsfnlocally, emits a["remap", …]instruction, and replays it on the receiver. This generalizes the mechanism so any user-defined method on anRpcTargetcan accept callbacks that serialize the same way.Motivation: I'm building typegres which uses capnweb to expose a capability-based query builder:
The callbacks should be interpreted server-side (not exported as a stub and sent back to client).
Key design decisions
mapand general closures: I chose to re-use the most code possible but maintain distinct wire formats forremapandclosure.Potential follow-ons (not in this PR):
RpcPayload.deliverResolvealways wraps in one, even when nothing needs awaiting. Async closures are already rejected at serialize time.(Opening as a draft to get your read on the design -- happy to rework anything.)