xxrpc_handler
xxrpc_handler generates Protobuf-ES message sources and abstract TypeScript handler classes for unary, client-streaming, server-streaming, and bidirectional RPC methods. Generation runs during xx run; pass the returned dependency to deps when another task needs the generated files.
Arguments
| Argument | Required | Description |
|---|---|---|
srcs | Yes | Non-empty list of project-relative .proto files. |
out_es | Yes | Project-relative ECMAScript output directory. |
deps | No | Dependencies that provide protoc and protoc-gen-es. Defaults to []. |
Load protoc from an exact @protobuf package. Install @bufbuild/protoc-gen-es version 2 in the project and make node_modules/.bin available through deps. xxRPC checks for protoc-gen-es before invoking protoc and does not install or select a plugin version.
Each generated <source>_xxrpc.ts file exports one abstract <Service>Handler class per Protobuf service. Handler implementations use only standard TypeScript types and generated Protobuf messages:
| Protobuf method | Handler input | Handler result |
|---|---|---|
| Unary | Input | Promise<Output> |
| Server streaming | Input | AsyncIterable<Output> |
| Client streaming | AsyncIterable<Input> | Promise<Output> |
| Bidirectional streaming | AsyncIterable<Input> | AsyncIterable<Output> |
Every method also receives an XXRPCContext containing an AbortSignal. The signal is aborted when the request or WebSocket disconnects or the client cancels. Implementations do not import Node.js, Cloudflare, Vercel, or another server framework.
The generated handle(request: Request) method handles unary calls:
- accepts HTTP
POSTrequests with a raw Protobuf body; - routes with
X-XXRPC-ServiceandX-XXRPC-Methodheaders and requiresX-XXRPC-Streaming: 0; - decodes and encodes messages with
@bufbuild/protobuf; - passes
request.signalthroughXXRPCContext; - returns
400for an invalid Protobuf body,404for an unknown service or method,405for another HTTP method, and413for a body larger than 4 MiB; - catches every implementation throw and returns HTTP
500without exposing the thrown value.
The generated prepareStreaming(request) method validates a WebSocket request before an adapter upgrades it. The request must use xxrpc.streaming.v1, include exactly one xxrpc-service and xxrpc-method URL parameter, and name a streaming method. Requesting a unary method through WebSocket or a streaming method through HTTP returns HTTP 400.
XXRPCPreparedStream accepts a small XXRPCSocket interface. Platform adapters only translate their WebSocket implementation to this interface; Protobuf dispatch, flow control, cancellation, and errors remain in the generated generic core.
Cloudflare Workers
Handler generation also writes <source>_xxrpc_cloudflare.ts. It exports createCloudflareXXRPCHandler, which handles both standard Fetch requests and WebSocketPair upgrades:
import { Greeter } from "./greeter.js";
import { createCloudflareXXRPCHandler } from "./generated/contracts/greeter_xxrpc_cloudflare.js";
const handle = createCloudflareXXRPCHandler(new Greeter());
export default {
fetch(request: Request): Promise<Response> {
return handle(request);
},
};
The adapter is generated separately so the generic handler module contains no Cloudflare APIs or type dependencies. Authentication and origin checks should run before calling the generated adapter.
Example
load("@[email protected]", "npm_install")
load("@os@1", "env_prepend")
load("@[email protected]", "protoc")
load("@xxrpc@1", "xxrpc_handler")
install = npm_install()
rpc_server = xxrpc_handler(
srcs=["contracts/greeter.proto"],
out_es="backend/generated",
deps=[
protoc,
install,
env_prepend("PATH", "node_modules/.bin"),
],
)
Sources retain their path below the project root. contracts/greeter.proto produces these files:
backend/generated/contracts/greeter_pb.jsbackend/generated/contracts/greeter_pb.d.tsbackend/generated/contracts/greeter_xxrpc.tsbackend/generated/contracts/greeter_xxrpc_cloudflare.ts
The output directory is owned by the xxRPC task. Obsolete generated files from preceding generations are removed before generation.