Conversation
🦋 Changeset detectedLatest commit: a6de425 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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: |
|
@ask-bonk review this |
There was a problem hiding this comment.
The change is small and well scoped, and I think it's worth adding. Every layer except the transport is real, so tests can catch missing dup() calls and disposal bugs that hand-rolled mocks never would. Swapping the ad-hoc SessionPair in limits.test.ts for this helper also cleans things up.
I traced the abort and disconnect paths and they look right:
- Self-abort: when a session aborts on its own (for example, a limits violation),
RpcSessionImpl.abort()sends theabortmessage before it callstransport.abort(). The message is either handed to the peer's pending receiver or queued, andreceive()drains the queue before rejecting. So the peer sees the original error, not a generic break. disconnect():send()quietly drops messages once the peer is gone, so the abort message each session tries to send when it breaks goes nowhere, which is what you want.- No unhandled rejections: the rejected
#receiverpromise is always inside thereadLoopPromise.race, so rejecting it doesn't leak.
The inline comments are small, non-blocking suggestions.
This comment was marked as outdated.
This comment was marked as outdated.
d8a7fef to
d6d6cca
Compare
|
@ask-bonk review this |
There was a problem hiding this comment.
Re-reviewed at d6d6cca. The earlier review was on d8a7fef, and this push covers all four of its comments:
- Function mains:
PartialMain<T>keeps call signatures, so a function main has to match the whole function type. The@ts-expect-errorcases forFormatterandPublicApitest this. - Client main:
clientMainis now supported, typed byC, andserver.getRemoteMain()returnsRpcStub<C>. - Return type: the function now returns a named
InMemoryRpcSessionPair<T, C>. - After
disconnect(): the test checks that pending calls reject with the samereason, thatonRpcBrokenfires on a stub the server holds, and that a seconddisconnect()doesn't throw.
I checked it locally:
pnpm test:typespasses.- The new
in-memory session pairtests and the rewrittenlimits backwards compatibilitytests pass in thenodevitest project. - Leaving out
Tstill infers correctly, for both anRpcTargetsubclass and a plain object main. For example,newInMemoryRpcSessionPair(new Echo()).stub.echo(1)is typednumber, and calling an unknown method is an error.
The transport logic is still correct:
send()hands the message straight to a waiting receiver, or queues it.receive()delivers any queued messages before it rejects, so anabortmessage sent just beforetransport.abort()still reaches the peer.abort()breaks both ends. A second call does nothing because#peerhas already been cleared.
I have one non-blocking nit, left inline. Looks good to merge from my side.
|
I reviewed the latest commit ( The earlier review's four comments are all addressed. That review looked at an older commit (
What I ran:
Transport logic: I re-checked the transport and it's still correct. An abort message sent just before shutdown still reaches the other side, One small suggestion, not blocking: |
d6d6cca to
b954a5c
Compare
|
thoughts:
|
💪
nah, it already tree-shakes. i bundled a tiny app against dist with esbuild that only imports newWebSocketRpcSession, and none of the pair's code ends up in the output. if you do import it, it's ~600 bytes minified.
i'd hold off on that one. once
fwiw the pair sends JSON strings (since this is the predominate encoding. iirc only MessagePort transport uses structed clone), not structured clones, so structured-clone tests wouldn't go through it anyway. |
b954a5c to
f974469
Compare
f974469 to
a6de425
Compare
In cloudflare-os and even here locally we find ourselves hand-rolling mock/stubs of cap'n web for testing (unless we go a heavier route through workerd). This is especially annoying as cap'n web rejects calls from anything without its symbol/brand, so these almost always have to take the form of fakes.
This introduces an in-memory transport, useful for primarily testing situations. Everything else is real: serialization, deserialization, import/export tables, pipelining, ...
connectrpc takes a similar approach: https://connectrpc.com/docs/node/testing/#testing-against-an-in-memory-server