Skip to content

Contracts

Type WebSocket messages and upgrade inputs with socketContract and scope.input.

AI generated, pending review Updated 10 days ago · Flare 0.3

WebSocket contracts describe what a route accepts and emits. socketContract is the "ws" kind of the shared contract core, the sibling of httpContract for HTTP routes.

Attach a branded entry with contract: MySocket.chat in route options, or spell the same fields loose in the options object. Do not pass both.

FieldPurposeTyped into
incomingSchema for each inbound messagescope.input.message on message handlers
outgoingSchema for ws.send argumentsOutbound serialization on the connection
paramsUpgrade path params (/chat/:room)scope.input.params at connect time
queryUpgrade URL query primitivesscope.input.query at connect time
subprotocolsAccepted subprotocol tokensHandshake picks the first match

When incoming is omitted, scope.input.message is a FlareWebSocketMessage wrapper (use .text(), .json(), .raw, .isBinary). When outgoing is omitted, send accepts raw string or Uint8Array.

import { socketContract } from "@flare-ts/core";
import { int, schema, str } from "@flare-ts/lib/schema";
const MsgIn = schema({ text: str });
const MsgOut = schema({ text: str });
export const Chat = socketContract({
chat: {
incoming: MsgIn,
outgoing: MsgOut,
params: { room: str },
query: { page: int },
subprotocols: ["chat.v1"],
},
});

Register the entry on a route:

host.ws.route("/chat/:room", { contract: Chat.chat })
.open((_ws, scope) => {
const room = scope.input.params.room;
const page = scope.input.query.page;
})
.message((ws, scope) => {
ws.send({ text: scope.input.message.text });
});

Connect-time input is stable for the connection’s life:

scope.input.params // typed path params
scope.input.query // typed query map (or URLSearchParams when undeclared)

On message, scope.input adds the validated payload:

scope.input.message // validated inbound value, or FlareWebSocketMessage

This mirrors HTTP: per-invocation payload lives on scope.input, not as a separate handler argument shape from HTTP.

  • Params and query parse at upgrade match time. Bad values reject the handshake.
  • Inbound messages validate on each message event before your handler runs. On a typed route, a message that is not valid JSON or fails the incoming schema is logged and the connection closes with code 1008; the handler does not run. Untyped routes wrap the raw message and never reject at decode.
  • Outbound values serialize through outgoing when declared.

Build-time validation catches contract kind mismatches (for example passing an httpContract entry to a WebSocket route).