Files
skills/docs/api-stack/api/api-ws-bun/src/handshake/subprotocol.md
2026-05-29 08:20:56 +01:00

2.2 KiB

subprotocol

Purpose

Implements RFC 6455 §4.1 subprotocol negotiation as a tiny pure function. The server is supplied the client's requested protocols and the server-supported list; the function returns the first server-supported protocol the client requested, or null when the client requested nothing.

This is exposed as a public utility because callers occasionally need to short-circuit the full handshake — for example, an OpenAPI documentation route advertising the engine's supported subprotocols before any actual upgrade.

Features

  • Strict RFC 6455 ordering — server-supported list determines priority, NOT the client's preference list.
  • Throws WS_BUN.SUBPROTOCOL_UNSUPPORTED when the client requested any subprotocol but none match.
  • Returns null for the common "client requested nothing" case.

Usage: Basic

import { resolveSubprotocol } from "@suaveplan/api-ws-bun";

const chosen = resolveSubprotocol(
    ["graphql-transport-ws"],
    ["suaveplan.v1", "graphql-transport-ws"]
);
// chosen === "graphql-transport-ws"

Usage: Advanced

import { WS_BUN_CODES, resolveSubprotocol } from "@suaveplan/api-ws-bun";

try {
    resolveSubprotocol(["unknown"], ["suaveplan.v1"]);
} catch (err) {
    if ((err as { code?: string }).code === WS_BUN_CODES.SUBPROTOCOL_UNSUPPORTED) {
        // respond 400 with `Sec-WebSocket-Protocol: <server's list>`
    }
}

API Reference

  • resolveSubprotocol(requested, supported): string | null — pure negotiation function.

Implementation Notes

Server-priority ordering matters: a client might list ["graphql-ws", "graphql-transport-ws"] expecting the older protocol, but if the server prefers the newer one and lists it first, the function returns "graphql-transport-ws". That matches the RFC and matches the behaviour Bun's native Server.upgrade would apply if the negotiation were delegated to Bun itself.

The empty-requested short-circuit returns null rather than throwing because RFC 6455 explicitly permits handshakes with no Sec-WebSocket-Protocol header — the connection is valid, it just has no negotiated subprotocol. This is the default state for a Bun client written against the foundation's plain-JSON envelope wire format.