protoc-gen-drpc-ts (in tools/protoc-gen-drpc-ts) is a protoc/buf plugin that generates a
typed client, a server interface, and a service description from a .proto. Port of
cmd/protoc-gen-go-drpc.
Build the plugin, then invoke via protoc (or buf):
cd tools/protoc-gen-drpc-ts && npm install && npm run build
protoc \
--plugin=protoc-gen-drpc-ts=tools/protoc-gen-drpc-ts/dist/plugin.js \
--drpc-ts_out=./gen \
chat.protoFor each .proto with services it emits a <file>_drpc.ts.
For service Chat { rpc Say(Msg) returns (Msg); rpc Stream(stream Msg) returns (stream Msg); }:
ChatClient— takes aConnand the codecs;say(req, signal?, metadata?)callsconn.invoke,stream()returns a per-method wrapper exposing only the methods valid for that RPC's direction (send/recv/closeAndRecv/sendAndClose,[Symbol.asyncIterator]where the peer streams, plusgetStream()), mirroring Go's generated surface.ChatHandler— a server interface with a method per RPC. A unary method issay(ctx, req, metadata): Promise<Res>—metadatais the peer's request metadata (D6's replacement for Go's ctx-carried metadata; a handler declaring only(ctx, req)still satisfies the interface). A streaming method isstream(ctx, stream): Promise<void>and reaches metadata viastream.getStream().metadata.ChatUnimplementedServerimplements the interface with every method failing as code 12 (Unimplemented), like Go's.ChatDescription(codecs)— aDRPCDescription, somux.register(handler, ChatDescription(codecs))wires it up.
Generated code imports only types from @hyvmind/drpc and your message module — never a protobuf
runtime. The codecs (Encoding<T> per message type) are injected into the client constructor and
the description factory. So @hyvmind/drpc stays zero-dependency, and a consumer brings their own
protobuf runtime (protobuf-es, ts-proto, or hand-written). @bufbuild/protobuf is a dependency of
the generator process only.
Generated files load under Node 26's native type-stripping — the emitter uses explicit fields, not
constructor parameter-property shorthand, which strip-only mode rejects. No build step is needed to
import a generated _drpc.ts directly.