Add @polyvariant/smithy-ts-runtime: out-of-the-box transports - #2
Merged
Conversation
The codegen emits transport *interfaces* and leaves the implementation to consumers, so every consuming project ends up hand-rolling the same fetch wrapper, and the same ndjson read loop wherever streaming is used. This publishes that as a library. `fetchTransport` implements both halves of the contract: unary requests, plus ndjson and binary framing in both directions for streaming ops. It returns non-2xx as a response rather than throwing, since the generated client needs the status and body to dispatch declared errors; 401 is the exception, and the generated error class can be passed in so existing `instanceof` checks keep working. Middleware (`chain` / `around` / `tap` / `withHeaders`) covers cross-cutting concerns like tracing, auth headers and error reporting, and `interceptorStack` covers the add-and-remove-later case a React effect needs. The per-call options blob the codegen already threads through untouched is what carries framework-specific knobs, so the package needs no HTTP client dependency of its own and stays dependency-free. The library imports nothing from generated code: it declares structural copies of the transport types. typecheck/src/runtimeUsage.ts compiles the two against each other so that pairing can't drift silently. TypeScript moves into a pnpm workspace (runtime/ + typecheck/); nix flake check now builds and unit-tests the library before typechecking the sample. A v* tag publishes the package to npm alongside the JVM artifacts, with the tag as the only source of version truth. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
kubukoz
force-pushed
the
runtime-transports
branch
from
August 19, 2026 14:40
da47ba4 to
d5424dd
Compare
OIDC means no NPM_TOKEN secret to create, store or rotate. The publish step moves from pnpm to npm because the OIDC exchange is implemented in the npm CLI; everything before it still runs under pnpm. Co-Authored-By: Claude Opus 5 <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.
Closes the README TODO: the
Transport/StreamTransportimplementations had to be written by hand in every consuming project — a near-identical fetch wrapper each time, plus a hand-rolled ndjson read loop wherever streaming was used. This publishes that as@polyvariant/smithy-ts-runtime.What ships
fetchTransportimplements both halves of the generated contract from one object:undefined), lowercased response headers, empty/non-JSON body tolerance.duplex: 'half'where the platform supports it and buffers where it doesn't.errors: [...]. 401 is the exception; pass your generated error class viaunauthenticatedto keep existinginstanceofchecks working.chain/around/mapRequest/withHeaders/tap, plusinterceptorStackfor handlers registered and removed after construction (what a React effect needs).encodeNdjson,decodeNdjson, …) are exported for transports this package doesn't ship.The package is zero-dependency and ESM-only.
Type compatibility is checked, not assumed
The library declares its own structural copies of the transport types and imports nothing from generated code, so
generated.tsstays self-contained.typecheck/src/runtimeUsage.tsdrives the real generated clients with the library's transport, so if the codegen changes the contract and the library isn't updated, it stops compiling.Build
TypeScript moves into a pnpm workspace (
runtime/+typecheck/).nix flake checknow builds and unit-tests the library (39node:testcases covering framing round-trips, chunk-split multi-byte characters, laziness, the transport against afetchdouble, and middleware ordering) before typechecking the generated sample.pnpm checkruns the same without nix.Publishing
.github/workflows/npm-publish.ymlpublishes on av*tag, so one tag ships both halves at the same version. The tag is the only source of version truth —runtime/package.jsonkeeps a placeholder0.0.0the workflow overwrites, so there's no version to bump by hand. It runs the full check before publishing, and uses npm provenance.Hand-written rather than folded into
ci.yml, since that file is generated by sbt-typelevel and CI fails if it drifts.Needs an
NPM_TOKENsecret with publish rights on the@polyvariantscope before the first tag.Verification
nix flake checkpasses: library build + typecheck + 39 tests, then the generated-sample typecheck including the compatibility file. Package packs cleanly with no@types/nodeleakage into the published.d.ts.🤖 Generated with Claude Code