feat(truapi): wire observe seam, wire debugger, and headless mock/forward debug host#295
Draft
decrypto21 wants to merge 3 commits into
Draft
feat(truapi): wire observe seam, wire debugger, and headless mock/forward debug host#295decrypto21 wants to merge 3 commits into
decrypto21 wants to merge 3 commits into
Conversation
createTransport accepts an optional observe callback surfacing every frame as an ObservedFrame (direction, requestId, frameId, lifecycle role, byteLength, timestamp — never the decoded payload). Frames are observed before provider.postMessage so traces stay causally ordered even over a synchronous in-memory provider, and an attempted-but-failed send is still observed. A throwing observer is swallowed; the hook is zero-cost unset. createWireDebugger groups frames into per-requestId WireTraces (LRU-capped) with sink/forward relays isolated from the transport. createMethodNameMap derives a frameId → "service.method" reverse map from the generated wire-table plus the client's service names, so debug lines read account.getAccount instead of id=22. Because every frame carries the transport-minted requestId, a product-side telemetry span (sdk-team#28) adopts that id and product → wire → host becomes one correlated trace. Tests: outbound/inbound roles, subscription lifecycle (start/receive/stop under one id), name mapping across the full wire-table, payload-blindness key-set check, observer/sink/forward failure isolation, e2e span↔trace correlation.
examples/wire-debug-demo.mjs fires a real account.getAccount round trip over an in-memory provider and prints the readable observe/wire-debugger trace, so the observe hook (sdk-team#26 C1) is demoable with no host or network. README's observability section gains a Try it out block pointing at it.
…ported to the current core createDebugHost routes product frames by wire id: ids claimed by a mock entry dispatch locally (payloads encoded by the caller with the generated codecs, marked tier="mock"); everything else forwards byte-verbatim down an optional pipe to a real host — including a WASM-backed mock host — with answers relayed back, requestId untouched. Without a forward pipe it is the headless responder: unclaimed and undecodable frames warn by default. Dispose sends stop frames upstream for live forwarded subscriptions so a real host never streams into a detached pipe. Mock entries are byte-level (the generated TS host server this previously composed onto was removed with the truapi-host codegen pipeline); a typed per-method surface returns when codegen emits a codec table.
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.
Adds the TrUAPI wire-debugging primitives in
@parity/truapi: a payload-blind observe seam on the transport, an in-process wire debugger, and a headless mock/forward debug host. Together they let one product↔host operation be followed end to end under the single wirerequestId.Draft. This touches the
client.tstransport surface that the in-flight versioned-wrapper work also edits; it is kept as a draft and rebased ontomainonce that lands. Not for merge before then.What
createTransport(provider, { observe })- surfaces every outbound and inbound frame as anObservedFrame(direction,requestId,frameId, lifecyclerole,byteLength,timestamp) and never the decoded payload. Frames are observed beforepostMessage, so traces stay causally ordered even over a synchronous provider; a throwing observer is swallowed; the hook is zero-cost when unset.createWireDebugger- groups frames into per-requestIdWireTraces (LRU-capped), with sink and forward relays isolated from the transport.createMethodNameMap- resolvesframeId → "account.getAccount"from the generated wire-table, so traces read as method names.createDebugHost- a headless host that answers scripted mock entries through the real generated codecs and forwards every other frame verbatim to a real host (requestIduntouched, so correlation holds across the hop). With no forward pipe it is a pure headless responder; unclaimed and undecodable frames warn by default. Dispose sends stop frames upstream for live forwarded subscriptions.Why
One correlation id: every frame carries the transport-minted
requestId- the id the host dispatcher carries and the product-sdk telemetry span adopts as itscorrelationId- so product → wire → host is one correlated trace with no second correlation scheme. Because the seam carries no payload bytes and no key material, the same recorder is safe to leave on in production.Try it out
cd js/packages/truapi bun examples/wire-debug-demo.mjs