feat(devframe): jsonSerializable declaration for RPC + per-call wire dispatch#301
Merged
feat(devframe): jsonSerializable declaration for RPC + per-call wire dispatch#301
Conversation
Adds an opt-in `jsonSerializable: boolean` field to RPC function definitions. When true, the WS transport encodes the function's messages as plain JSON via a strict single-pass `JSON.stringify` that throws DF0019 synchronously on Map/Set/Date/BigInt/class instances/ undefined-in-array. When false (default) the function uses structured-clone-es with an `s:` wire prefix, preserving fancy types. The wire dispatcher reads the prefix on decode (no defs lookup needed) and consults local defs on encode, so request and response can independently choose their encoder per channel. Build dumps tag each manifest entry with `serialization: 'json' | 'structured-clone'` and dispatch the matching encoder/decoder; static client revives sc-tagged entries via `scDeserialize`. Agent exposure now requires `jsonSerializable: true` — registration throws DF0018 if `agent` is set without it. Aligns the MCP contract with the wire contract: only JSON-serializable functions are advertised to coding agents. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
commit: |
Adds a `structured-clone dumps` group to `collectStaticRpcDump` tests: - Verifies Map/Set values survive in `files[].data` for default (structured-clone) functions. - Round-trips a Map through scStringify → JSON.parse → scDeserialize to confirm the build-write / client-read pipeline is lossless. - Covers query-mode records and fallback shards both encode as structured-clone when default. - Confirms `jsonSerializable: true` produces plain JSON shards that parse losslessly. - Asserts DF0019 fires at build time when a JSON-flagged handler returns non-JSON data. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Renames the structured-clone-es re-exports for clarity: - scStringify → structuredCloneStringify - scParse → structuredCloneParse - scDeserialize → structuredCloneDeserialize Migrates the leftover DTK0001-DTK0008 codes in `rpc/diagnostics.ts` to DF0020-DF0027. The DTK prefix was misleading — these emit from the devframe package, not @vitejs/devtools, and they shadowed the docs URL space of the genuinely-DTK codes in `packages/core`. Moving them to DF lets `rpc/diagnostics.ts` use a single `defineDiagnostics` block with the correct devframe docsBase, dropping the previous two-block split. Adds DF0020-DF0027 docs pages with their DTK migration mapping; updates `errors/index.md` and the sidebar count. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes `makePerCallChannelOptions` from `rpc/serialization.ts` and inlines the wire dispatch logic directly into `ws-server.ts` and `ws-client.ts`. The helper had only two callers and the abstraction wasn't pulling its weight — a single function name shouldn't need a factory builder. `STRUCTURED_CLONE_PREFIX`, `strictJsonStringify`, and the `structuredClone*` re-exports remain — they're the actual reusable primitives. The unit tests targeting `makePerCallChannelOptions` are dropped; the dispatch behavior is now exercised end-to-end via the existing static-rpc and static-dump tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolves a numbering conflict: main's #302 introduced DF0018 for the `ctx.logs` deprecation warning, so my jsonSerializable diagnostics shift up by one. New numbering on this branch: - DF0018 (main) — `ctx.logs` deprecated. - DF0019 — Agent Requires JSON-Serializable RPC. - DF0020 — Non-JSON Value in JSON-Serializable RPC. - DF0021..DF0028 — migrated from DTK0001..DTK0008. Updates code, callsites, docs pages, sidebar count (28), error index table, and skill / guide references to the new numbers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Turbo had cached a pre-merge kit build, so the previous `-u` ran against stale dist and lost the new exports introduced upstream (`DevToolsDiagnosticsHost`, `DevToolsMessage*`, etc.). CI built fresh and tripped on the mismatch. Forced rebuild + snapshot update brings the kit snapshots in line with the merged code. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- devframe: tinyexec 1.1.1 → 1.1.2 - core: @clack/core + @clack/prompts 1.2.0 → 1.3.0; fast-string-truncated-width 1.2.1 → 3.0.3; fast-string-width 1.1.0 → 3.0.2; fast-wrap-ansi 0.1.6 → 0.2.0 Picked up automatically from the workspace catalog ranges. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Re-export `serialize` from structured-clone-es alongside the existing `structuredCloneDeserialize` / `structuredCloneParse` / `structuredCloneStringify` so callers can build the tagged intermediate representation without going through JSON text — useful when piping into another transport or storage that already accepts plain JSON values. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Description
Adds an opt-in
jsonSerializable: booleanfield onRpcFunctionDefinitionthat declares the on-wire / on-disk shape contract:false(default) — payloads usestructured-clone-es(round-tripsMap,Set,Date,BigInt, cycles, class instances). Status quo behavior.true(opt-in) — payloads use a strict single-passJSON.stringifythat throwsDF0019synchronously at the offending call when it sees a value JSON cannot round-trip. Errors surface in dev right next to the bad return value, not silently coerced to{}later at build time.The WS transport dispatches per-call: outgoing requests choose the encoder from local defs (
msg.m); responses use a per-channelpendingRequestMethodsmap (populated on incoming request) so each direction independently consults its own defs — no birpc change required. The wire is plain JSON when JSON-flagged, structured-clone with ans:prefix otherwise (decode is self-describing via the prefix). Build dumps mirror the same per-function dispatch and tag each manifest entry withserialization: 'json' | 'structured-clone'.agent: {...}now requiresjsonSerializable: true— registration throwsDF0018otherwise. Aligns the MCP contract (JSON-only consumers) with the wire/dump contract.Linked Issues
Additional context
DF0018(registration: agent withoutjsonSerializable: true) andDF0019(runtime: JSON-flagged value contains a non-JSON shape). Both with docs pages + sidebar bump.ConnectionMetagainsjsonSerializableMethods: string[]so the browser-side WS client builds its defs map from the existing.connection.jsonfetch — no extra request, no birpc patch.strictJsonStringifyrejection cases, the prefix dispatcher, registration gating, and structured-clone round-trip through the static client. Existinghost-agent/static-dump/ example tests updated where the new fields are observable.🤖 Generated with Claude Code