/** * WebSocket v2 Subscription Manager * * This module implements multiplexed subscriptions over a single WebSocket connection. * It maintains the same external API as v1 but uses the new v2 protocol internally. */ import { SubscriptionOptions } from '../types'; /** * Live subscriptions the SDK puts on ONE socket before opening another. * * The realtime worker refuses the 51st distinct subscribe on a connection with * `{ code: 'subscription_limit', status: 429 }` - see * `packages/cdk/cloudflare/realtime-worker/src/subscriptions.ts` * (`attachment.subscriptions.length >= 50`). The cap is structural there: every * subscription spec has to fit the 16KB Durable Object hibernation attachment, * and each write fans out across the whole set of one socket. * * 45 leaves deliberate headroom under that 50: two concurrent subscribeV2 calls * can both see room and overshoot by a frame or two, and another tab may already * hold subscriptions on the same DO. A refusal that happens anyway is treated as * backpressure, not a failure (see rehomeRefusedSubscription). */ export declare const SHARD_CAP = 45; /** * Sockets one routing target (app, room, or wallet identity) may hold. Past this * a subscribe fails loudly with `subscription_limit` instead of opening * connections without end - 8 * 45 = 360 concurrent live subscriptions per * target, far beyond any legitimate UI. */ export declare const MAX_SHARDS_PER_KEY = 8; /** * Every idle client on a stalled object hits its dead timer at about the same * moment, so the replacement waits out the wrapper's own first-attempt delay * with the same jitter, instead of every client reopening in one instant. */ export declare const HEARTBEAT_RECONNECT_DELAY_MAX_MS: number; /** * Subscribe to data at a path using WebSocket v2. * Returns an unsubscribe function. */ /** * @param roomRoutePath INTERNAL ONLY. A `/` room path * used by `live.subscribeView` to route this subscription's connection to the * per-room DO (where live view fan-out lives). It is NOT part of the public * subscribe API — app code never passes routing; the worker remains the * authority on the destination DO (it derives the room from the `?path=` we * attach). This argument only tells the client which connection to multiplex * the subscription onto, since a WS connection routes to a single DO. */ export declare function subscribeV2(path: string, subscriptionOptions: SubscriptionOptions, roomRoutePath?: string): Promise<() => Promise>; /** * Close all v2 subscriptions. */ export declare function closeAllSubscriptionsV2(): Promise; /** * Clear the v2 cache. */ export declare function clearCacheV2(path?: string): void; /** * Get cached data for a path (v2). */ export declare function getCachedDataV2(path: string, prompt?: string): any | null; /** * Reconnect all v2 WebSocket connections with fresh authentication. * Call this when the user's auth state changes (login/logout). * * This will: * 1. Close existing connections * 2. Re-establish with new auth token * 3. Re-subscribe to all active paths * * Note: Existing subscriptions will receive new initial data after reconnection. */ export declare function reconnectWithNewAuthV2(): Promise; /** * Force close and reconnect all connections. * This is more aggressive than reconnectWithNewAuthV2() and ensures * a complete teardown and rebuild of connections. */ export declare function forceReconnectV2(): Promise; /** * Returns true if there is an active v2 WebSocket connection open. */ export declare function hasActiveConnection(): boolean; /** * v2 socket-when-warm transport for named/computed query polls (subscribeQuery / * runQuery). Runs `queries` over the ambient per-app authenticated socket instead * of HTTP `POST /queries`, but ONLY when that is observably safe and identity-correct: * - a warm, OPEN, non-authenticating app socket already exists (never opens one); * - the server advertised `capabilities.runQuery` on the authenticated ack; * - the socket's authenticated principal matches the caller's CURRENT identity * (else read rules would evaluate for the wrong user) - reuses the same gate as * reliable live intents; * - the serialized frame fits the WS message limit. * Returns the per-row array on a clean socket success; returns null - meaning * "fall back to HTTP" - for every miss/refusal (no socket, no capability, identity * skew, oversized batch, the server's own `{ useHttp: true }` deferral, or any * timeout / disconnect / error frame). The rows are byte-identical to POST /queries, * so the caller is transport-agnostic and never observes which transport won. */ export declare function runNamedQueriesOverSocket(appId: string, queries: Array<{ path: string; queryName: string; queryArgs: any; }>, isServer: boolean): Promise; /** * Send a live-room intent over the EXISTING per-room socket (fire-and-forget). * Returns true if it was sent over an open connection, false if there is no * live socket for this room yet (caller falls back to HTTP). The worker is the * room authority — the connection is already routed to the room DO, so the * client never names a destination. */ export declare function wsIntent(appId: string, roomRoutePath: string, intent: unknown, isServer: boolean): Promise; /** True when an OPEN room socket exists for this room path. */ export declare function hasOpenRoomConnection(appId: string, roomRoutePath: string): boolean; /** * Send a live-room intent over the EXISTING per-room socket and AWAIT the server * ack — so a policy/auth denial (401/403/404/503) REJECTS instead of being * silently dropped (the fire-and-forget `wsIntent` discards request-less error * frames). Use for semantically important intents (join/ready/leave). Returns a * Promise that resolves on ack / rejects on error, or `undefined` if no live * socket exists yet (caller falls back to HTTP, which also surfaces errors). */ export declare function wsIntentReliable(appId: string, roomRoutePath: string, intent: unknown, isServer: boolean): Promise<{ ok: true; } | undefined>;