API reference

yatta/grpcweb

gRPC-Web unary calls: protobuf codec, framing, handler, client.

38 exported symbols and 18 members, read from src/func/grpcweb.ts.

Construct

concat

function

Join byte arrays in order. The result is a copy, so it is safe to keep.

concat(...parts: Uint8Array[]): Uint8Array

createGrpcWebHandler

function

Build the HTTP handler for gRPC-Web unary calls.

Mount it on `options.basePath` and give it a service map. Anything that is not a `POST` to `<basePath>/<Service>/<Method>` is answered before a service is consulted.

createGrpcWebHandler(services?: GrpcServices, options?: GrpcWebOptions): (req: Request) => Promise<Response>
services
The methods to expose. Defaults to the health check and an echo, which are useful for a smoke test and harmless otherwise.

Returns A `(req) => Promise<Response>` to hand to a router or `Bun.serve`.

decodeFrames

function

Split a gRPC-Web body into its frames.

decodeFrames(data: Uint8Array, maxFrameBytes?: ): GrpcFrame[]
maxFrameBytes
Refuse a frame above this size before reading it. The length comes from the caller, so a 5-byte header can otherwise announce four gigabytes and have the server try to find them.

decodeMessage

function

Split one encoded message into its fields, in wire order.

Every length is checked against the bytes actually present before it is used, so a truncated message is an error rather than a short read.

decodeMessage(data: Uint8Array): ProtoField[]

decodeVarint

function

Read one varint that starts at `offset`.

decodeVarint(data: Uint8Array, offset: number): { value: bigint; next: number; }

Returns `value`, and `next` — the offset just past the varint, so a caller can keep walking a message.

decodeZigZag

function

Undo .

decodeZigZag(n: bigint): bigint

encodeBooleanField

function

Wire type 0 with 1 or 0. Protobuf has no boolean on the wire.

encodeBooleanField(field: number, value: boolean): Uint8Array

encodeBytesField

function

Wire type 2: tag, length, then the bytes untouched.

encodeBytesField(field: number, body: Uint8Array): Uint8Array

encodeDoubleField

function

Wire type 1: eight bytes, little-endian.

encodeDoubleField(field: number, value: number): Uint8Array

encodeFloatField

function

Wire type 5: four bytes, little-endian, as protobuf requires.

encodeFloatField(field: number, value: number): Uint8Array

encodeFrame

function

Frame a payload: one flag byte, a 4-byte big-endian length, then the bytes.

encodeFrame(data: Uint8Array, trailer?: ): Uint8Array

encodeMessageField

function

Wire type 2 with a message the caller has already encoded.

encodeMessageField(field: number, messageBytes: Uint8Array): Uint8Array

encodeStringField

function

Wire type 2, with the string encoded as UTF-8.

encodeStringField(field: number, value: string): Uint8Array

encodeVarint

function

Encode an integer as a base-128 varint.

A negative value becomes its 64-bit two's complement, which is how protobuf writes `int64` — ten bytes every time. Use for `sint*` fields to avoid that.

encodeVarint(value: bigint | number): Uint8Array

encodeVarintField

function

Wire type 0: tag then varint.

encodeVarintField(field: number, value: number | bigint): Uint8Array

encodeZigZag

function

ZigZag-encode a signed value for a `sint32`/`sint64` field.

Without it a small negative number is ten bytes of sign extension; with it, -1 is one byte.

encodeZigZag(n: bigint | number): bigint

fieldBoolean

function

A varint field read as a boolean: anything other than 0 is true.

fieldBoolean(fields: ProtoField[], field: number): boolean | null

fieldBytes

function

The last length-delimited field with this number, as raw bytes.

fieldBytes(fields: ProtoField[], field: number): Uint8Array | null

Returns null when the field is absent. The bytes are a view into the decoded message, so copy them before keeping them.

fieldDouble

function

A 64-bit float field (wire type 1). Null when absent or the wrong width.

fieldDouble(fields: ProtoField[], field: number): number | null

fieldFloat

function

A 32-bit float field (wire type 5). Null when absent or the wrong width.

fieldFloat(fields: ProtoField[], field: number): number | null

fieldMessage

function

A nested message, already decoded. Null when the field is absent.

fieldMessage(fields: ProtoField[], field: number): ProtoField[] | null

fieldNumber

function

as a JavaScript number.

Loses precision past 2^53, so read ids and timestamps with instead.

fieldNumber(fields: ProtoField[], field: number): number | null

fieldRepeatedBytes

function

Every value of a repeated bytes field, in order.

fieldRepeatedBytes(fields: ProtoField[], field: number): Uint8Array[]

fieldRepeatedMessage

function

Every value of a repeated message field, decoded.

fieldRepeatedMessage(fields: ProtoField[], field: number): ProtoField[][]

fieldRepeatedString

function

Every value of a repeated string field, in order.

fieldRepeatedString(fields: ProtoField[], field: number): string[]

fieldRepeatedVarint

function

Every value of a repeated varint field, in order.

Proto3 packs them into one length-delimited field (wire type 2) and proto2 repeats the tag (wire type 0). Both appear in real traffic, so both are read rather than assuming the sender's proto version.

fieldRepeatedVarint(fields: ProtoField[], field: number): bigint[]

fieldString

function

The last length-delimited field with this number, read as text.

fieldString(fields: ProtoField[], field: number): string | null

Returns null when the field is absent — an absent field and an empty string are different answers, and callers rely on that.

fieldVarint

function

The last varint field with this number.

fieldVarint(fields: ProtoField[], field: number): bigint | null

Returns null when absent, so a legitimate 0 is not mistaken for "no field".

grpcWebCall

async function

Call a unary gRPC-Web method and return the raw reply message.

Works in a browser and in Bun/Node, because it goes through `fetch`. The reply is unwrapped for you: trailers are parsed and the message bytes are returned.

grpcWebCall(endpoint: string, service: string, method: string, message: Uint8Array, options?: GrpcWebCallOptions): Promise<Uint8Array>
endpoint
Base URL, like `"https://api.example.com/grpc-web"`.

GrpcError

class

An error carrying a gRPC status code.

Throw one from a service to choose what the client sees. Anything else is logged and answered as `INTERNAL`, so an unexpected failure does not put its message on the wire.

class GrpcError extends Error

2 members

  • codeproperty
    code: number
  • grpcStatusgetter
    grpcStatus: number

Types

GrpcContext

interface

What a service gets besides the request message.

interface GrpcContext

2 members

  • reqproperty
    req: Request

    The original HTTP request: headers, cookies, and the caller's identity.

  • signalproperty
    signal?: AbortSignal

GrpcFrame

interface

One frame of a gRPC-Web body.

`trailer` marks the final frame, which carries `grpc-status` as text instead of a message. `compressed` is the flag this server never sets: it negotiates no compression, and refusing the flag is clearer than silently handing back bytes nobody decompressed.

interface GrpcFrame

3 members

  • trailerproperty
    trailer: boolean
  • compressedproperty
    compressed: boolean
  • dataproperty
    data: Uint8Array

GrpcWebCallOptions

interface

4 members

  • headersproperty
    headers?: Record<string, string>

    Extra headers, for example `{ authorization: "Bearer …" }`.

  • signalproperty
    signal?: AbortSignal

    Abort the call from the caller's side.

  • formatproperty
    format?: "binary" | "text"

    `"text"` sends base64 over `application/grpc-web-text`, which is what

  • timeoutMsproperty
    timeoutMs?: number

    Sent as a `grpc-timeout` header. The server is free to ignore it.

GrpcWebOptions

interface
interface GrpcWebOptions

3 members

  • basePathproperty
    basePath?: string

    Where the handler is mounted. Default `/grpc-web`; a trailing slash is ignored.

  • maxMessageBytesproperty
    maxMessageBytes?: number

    Largest message accepted, in bytes. Default 4 MB. A reply is not

  • corsOriginsproperty
    corsOrigins?: string[]

    Browser origins allowed to call this endpoint, like

    Unset means no CORS headers, so a browser on another origin is refused by the browser itself. An `OPTIONS` from an origin not on the list gets a 403 rather than a permissive preflight.

ProtoField

interface

One decoded protobuf field.

`varint` is set for wire type 0, `bytes` for 1 (fixed64), 2 (length-delimited) and 5 (fixed32). Values are `bigint`, not `number`, so a real 64-bit id survives the round trip.

interface ProtoField

4 members

  • fieldproperty
    field: number
  • wireTypeproperty
    wireType: 0 | 1 | 2 | 5
  • varintproperty
    varint?: bigint
  • bytesproperty
    bytes?: Uint8Array

GrpcServiceFn

type

One unary method: request message in, reply message out.

Return bytes, not a `Response` — framing, trailers and status codes are the handler's job. Throw to pick the status code.

type GrpcServiceFn = (request: Uint8Array, ctx: GrpcContext) => Promise<Uint8Array> | Uint8Array

GrpcServices

type

Methods keyed `"package.Service/Method"`, the same string the client

type GrpcServices = Record<string, GrpcServiceFn>

GrpcStatusCode

type

Any of the numeric values in .

type GrpcStatusCode = (typeof GrpcStatus)[keyof typeof GrpcStatus]
Tip
Most of the types above are inferred. You rarely import AuthConfig or JobPayload — declaring your schema once is enough for the rest to follow. See Typed keys.