Skip to content
TypeWire

@tahanabavi/typefetch-grpc

documents v0.0.0

gRPC transport for TypeFetch contracts — Connect unary JSON out of the box, binary grpc-web behind a codec seam, zero dependencies.

Binary grpc-web

Reach for this only when you need protobuf on the wire. Connect JSON is debuggable in a way binary frames never are.

ts
import { grpcTransport } from "@tahanabavi/typefetch-grpc";
import { GetUserRequest, GetUserResponse } from "./gen/user_pb";

grpcTransport({
codec: {
encode: (message) => GetUserRequest.toBinary(message),
decode: (bytes) => GetUserResponse.fromBinary(bytes),
},
});

The codec deals only in message bytes. This package owns the 5-byte length-prefix framing, the 0x80 trailer frame, percent-decoding of grpc-message, and trailers-only responses — protocol concerns, not schema ones. That boundary is what keeps protobuf out of everything published here.

Set a codec per endpoint to mix binary and JSON RPCs on one client.

The failure everyone hits first

A browser calling a cross-origin grpc-web server needs the server to expose the trailer:

txt
Access-Control-Expose-Headers: grpc-status, grpc-message

Without it the trailer is invisible to the client even though it was sent, and every call fails. This transport detects that exact case and says so in the error message rather than reporting a generic parse failure.

Binary grpc-web also generally needs a proxy (Envoy, or a server with grpc-web support built in) in front of a plain gRPC server. grpc-web-text (base64) is not supported.

Capabilities

onUploadProgress and onDownloadProgress do nothing here — a unary RPC is one message in and one message out. The client warns rather than silently never calling your handler, because a progress bar frozen at zero reads as a hung app.

Streaming (server, client, bidi) is deliberately out of scope: it cannot return Promise<T>, so it would change the shape of every generated method. Use @tahanabavi/typesocket for streams.