class GrpcService
implements IGrpcService

The gRPC service applications use to register Connect/gRPC services.

The default basePath is the root (DEFAULT_BASE_PATH): a gRPC-family client derives its path from the method name alone and has no prefix option, so a prefixed default serves every procedure at an address no such client asks for. At the root, claims() reports only registered procedure paths, so the kernel consults this service before route matching without shadowing ordinary routes. Connect and gRPC-Web are then served at their natural addresses; native application/grpc is refused with a Trailers-Only UNIMPLEMENTED. Pass basePath: '/grpc' to restore the pre-M70i prefix.

Examples

Example 1

const grpc = app.services.get<IGrpcService>(CAPABILITIES.GRPC);
grpc.addService(EchoService, { echo: (req) => ({ text: req.text }) });

Constructors

GrpcService(init: GrpcServiceOptions)

Properties

readonly
available: boolean

Whether gRPC dispatch is available. Always true since the kernel now resolves IGrpcService from the service registry and dispatches after the middleware pipeline (M70a). The previous adapter-based seam is retired.

readonly
serviceCount: number

Number of application services registered. Read by the health indicator.

Methods

addService<TDef extends GrpcServiceDefinition>(
definition: TDef,
implementation?: unknown
): void

Registers a gRPC service definition with an optional implementation.

Since 0.3.0
claims(request: Request): boolean

Whether this service claims the request's path — that is, whether the path lies inside the configured basePath.

The kernel calls this before GrpcService.handleRequest, which answers 404 for a claimed path with no matching procedure and therefore cannot itself be used to tell "not mine" from "mine, but unknown". Without this guard every unmatched route in the application would be answered by gRPC's plain-text 404 instead of the kernel's JSON one.

A root basePath is the exception, and it is load-bearing: '' contains every path, so a prefix test would claim the entire application. The kernel consults claims before route matching, so that would 404 every ordinary route. At the root this therefore claims only paths it can actually serve, mirroring the asymmetry dispatchRequest already documents — "not a known procedure" and "an ordinary application route" are indistinguishable there, so both fall through.

Inside a non-root base path the prefix IS the claim, so an unknown procedure under /grpc answers gRPC's 404 rather than falling through to the application — the M49 behaviour.

close(): void

Releases the built router and its handlers. Afterwards the plugin's own procedures answer 503 instead of rebuilding a router for an application that is shutting down, while every other path falls through untouched.

The handler that used to be installed into IHttpAdapter.setRpcHandler. Returns null for any request outside basePath.

handleRequest(request: Request): Promise<Response>

Handles an RPC request directly.

Returns a 404 response when the request does not match any registered service path. Callers routing traffic should consult GrpcService.claims first.

Since 0.6.0
refuses(request: Request): Response | null

Refuses a native application/grpc request from its HEADERS alone.

The refusal itself is M70i's and unchanged: the fetch Response cannot carry the HTTP/2 trailers the native wire format signals completion with, so a Trailers-Only UNIMPLEMENTED is the protocol's own way to say so. What changed is WHEN it is reachable.

The kernel used to buffer the request body before dispatching, and a client-streaming or bidirectional call holds its request stream OPEN — so that read never resolved and the caller got no frames at all instead of the refusal (V5-5). grpcurl opens a bidirectional reflection stream first, which is why it hung on every request while a unary probe with the stream closed received the refusal correctly.

Deciding this from headers costs nothing: the content type is all the answer depends on, and the path check is the same claims already made.