/** * Binary realtime relay transport (`crowdy-relay-v1`). * * Connects to the game-api's raw-WebSocket relay endpoint and exchanges * complete Buddy wire datagrams as BINARY frames — no GraphQL, JSON, or * base64 on the wire. Owned by {@link RealtimeClient}, which keeps the public * handler/dispatch surface identical across transports. * * Auth: the app token rides as a `bearer.` subprotocol * entry (browsers cannot set WebSocket headers). The server replies with one * TEXT `ready` frame carrying the session's `gameTokenId`, which becomes the * client-side HMAC signing context. */ import type { CrowdyLogger } from './logger.js'; import { CrowdyRealtimeError } from './errors.js'; import type { UdpNotification } from './realtime.js'; import { type RelaySignContext } from './binary-wire.js'; export declare const RELAY_SUBPROTOCOL = "crowdy-relay-v1"; export interface BinaryRelayCallbacks { getToken(): string | null; onNotification(notification: UdpNotification): void; onError(error: CrowdyRealtimeError): void; onStatus(status: 'connecting' | 'connected' | 'reconnecting' | 'disconnected'): void; /** * The relay endpoint looks permanently unavailable (older server, blocked * upgrade). The owner should fall back to the GraphQL transport. */ onUnavailable(): void; /** * The server asked this client to move to another API instance — either it is * rebalancing load, or it is draining. The socket is still open, so this is * advice: acting on it promptly is better for the fleet, but ignoring it only * costs this client its share of an imbalance. */ onReconnectDirective?(target: { httpUrl: string; wsUrl: string; reason: string; }): void; } /** * Would honouring `candidate` keep us on the same site as `current`? * * The directive arrives over an authenticated TLS socket, so the server saying * it is the server we already trust. This guards the next step instead: a * redirect must never be able to move a client onto an origin outside the * estate it is already talking to — otherwise one compromised instance could * walk an entire fleet's clients somewhere else, which is a much worse outcome * than an unbalanced fleet. * * Compares the last two labels, so `ck-api-4.pgc.prod.cp.cks-env.com` and * `ck.prod.cp.cks-env.com` match, and `evil.example.com` does not. */ export declare function isSameEstate(current: string, candidate: string): boolean; export interface BinaryRelayConfig { /** Absolute ws(s) URL of the relay endpoint (e.g. `wss://host/realtime`). */ url: string; retryAttempts?: number; retryInitialDelayMs?: number; retryMaxDelayMs?: number; logger?: CrowdyLogger; } export declare class BinaryRelayTransport { private readonly callbacks; private readonly url; private readonly logger; private readonly retryAttempts; private readonly retryInitialDelayMs; private readonly retryMaxDelayMs; private ws; private signContext; private desired; private appId; private retries; private preReadyFailures; private everReady; private retryTimer; private generation; constructor(config: BinaryRelayConfig, callbacks: BinaryRelayCallbacks); /** True when the socket is open and the `ready` handshake completed. */ isReady(): boolean; /** The session signing context (gameTokenId + HMAC key), once ready. */ getSignContext(): RelaySignContext | null; connect(appId: string): void; disconnect(): void; /** Restart (e.g. after a token refresh) while remaining desired. */ restart(): void; /** Send one pre-serialized Buddy datagram as a BINARY frame. */ sendFrame(frame: Uint8Array): void; private open; private handleControlFrame; /** * The server wants this client on a different instance. * * Refusing a malformed or off-estate target is not a failure worth surfacing * to the application: the current connection is still working, so the correct * behaviour is to stay put and say so in the log. */ private handleReconnectDirective; private maybeRetry; } //# sourceMappingURL=binary-relay.d.ts.map