@finalai/websockets 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of @finalai/websockets might be problematic. Click here for more details.

@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/index.ts"],
4
+ "sourcesContent": ["import {\n compareWebsocketGatewayCursors,\n websocketGatewayDataSchema,\n websocketGatewayProtocolVersion,\n websocketGatewayServerFrameSchema,\n type WebsocketGatewayAction as WebsocketsAction,\n type WebsocketGatewayCapability as WebsocketsCapability,\n type WebsocketGatewayClientFrame as WebsocketsClientFrame,\n type WebsocketGatewayData as WebsocketsData,\n type WebsocketGatewayMessage as WebsocketsMessage,\n type WebsocketGatewayPresenceMember as WebsocketsPresenceMember,\n type WebsocketGatewayProxyPayload as WebsocketsProxyPayload,\n type WebsocketGatewayProxyUpstreamDescriptor as WebsocketsProxyUpstreamDescriptor,\n type WebsocketGatewayRealtimeMessage as WebsocketsRealtimeMessage,\n type WebsocketGatewayServerFrame as WebsocketsServerFrame,\n} from '@finalai/websocket-gateway-protocol';\nimport { WebSocket as PartySocketWebSocket } from 'partysocket';\n\nexport type {\n WebsocketGatewayAction as WebsocketsAction,\n WebsocketGatewayCapability as WebsocketsCapability,\n WebsocketGatewayClientFrame as WebsocketsClientFrame,\n WebsocketGatewayData as WebsocketsData,\n WebsocketGatewayMessage as WebsocketsMessage,\n WebsocketGatewayPresenceMember as WebsocketsPresenceMember,\n WebsocketGatewayProxyPayload as WebsocketsProxyPayload,\n WebsocketGatewayProxyUpstreamDescriptor as WebsocketsProxyUpstreamDescriptor,\n WebsocketGatewayRealtimeMessage as WebsocketsRealtimeMessage,\n WebsocketGatewayServerFrame as WebsocketsServerFrame,\n} from '@finalai/websocket-gateway-protocol';\n\nexport type GatewayAuthProvider = string | (() => string | Promise<string>);\nexport type GatewayFrameHandler = (frame: WebsocketsServerFrame) => void;\nexport type WebsocketsProxyTarget = string | Pick<WebsocketsProxyUpstreamDescriptor, 'id'>;\nexport type WebsocketsProxySendData = string | ArrayBuffer | ArrayBufferView;\nexport type WebsocketsErrorFrame = Extract<WebsocketsServerFrame, { type: 'error' }>;\nexport interface WebsocketsProxyHandlers {\n onOpen?: (upstream: string) => void;\n onMessage?: (data: string | ArrayBuffer) => void;\n onClose?: (event: { code?: number; reason?: string }) => void;\n}\n\nexport interface WebsocketsChannelPublishOptions {\n name?: string;\n idempotencyKey?: string;\n retain?: boolean;\n}\n\nexport interface WebsocketsChannelSubscribeOptionsIface {\n afterCursor?: string;\n onError?: (error: WebsocketsErrorFrame) => void;\n onSubscribed?: () => void;\n}\n\nexport interface WebsocketsRealtimeSubscribeOptionsIface {\n afterCursor?: string;\n onError?: (error: { code: string; message: string; retryable: boolean }) => void;\n onResyncRequired?: () => void;\n onSubscribed?: () => void;\n}\n\nexport interface WebsocketsRealtimePresenceEventIface {\n action: 'enter' | 'update' | 'leave';\n member: WebsocketsPresenceMember;\n topic: string;\n}\n\nexport interface WebsocketsRealtimePresenceIface {\n enter: (data?: WebsocketsData) => void;\n update: (data?: WebsocketsData) => void;\n leave: () => void;\n get: (options?: WebsocketsPresenceGetOptionsIface) => Promise<WebsocketsPresenceMember[]>;\n subscribe: (handler: (event: WebsocketsRealtimePresenceEventIface) => void) => () => void;\n}\n\nexport interface WebsocketsPresenceGetOptionsIface {\n signal?: AbortSignal;\n}\n\nexport interface WebsocketsClientOptions {\n url: string;\n auth: GatewayAuthProvider;\n WebSocketCtor?: typeof WebSocket;\n reconnect?: boolean;\n onReconnect?: () => void;\n heartbeatIntervalMs?: number;\n ackTimeoutMs?: number;\n maxQueuedFrames?: number;\n}\n\nexport interface WebsocketsChannelSubscriptionDiagnosticsIface {\n bufferedBytes: number;\n bufferedBytesHighWater: number;\n bufferedFrames: number;\n bufferedFramesHighWater: number;\n channel: string;\n pendingGapFill: boolean;\n pendingSubscribeAck: boolean;\n receivedBytes: number;\n receivedFrames: number;\n}\n\nexport interface WebsocketsConnectionDiagnosticsIface {\n bufferedBytes: number;\n bufferedBytesHighWater: number;\n bufferedFrames: number;\n bufferedFramesHighWater: number;\n bufferLimitFlushes: number;\n channelMessageBytes: number;\n channelMessageFrames: number;\n channelStreams: WebsocketsChannelSubscriptionDiagnosticsIface[];\n channelSubscriptions: number;\n gapFillErrors: number;\n gapFillRequests: number;\n gapFillResponses: number;\n gapFillSendErrors: number;\n gapFillTimeouts: number;\n frameHandlers: number;\n frameHandlersHighWater: number;\n lastCloseCode: number | null;\n lastCloseReason: string | null;\n pendingGapFills: number;\n pendingSubscribeAcks: number;\n queuedBytes: number;\n queuedFrames: number;\n realtimeMessageBytes: number;\n realtimeMessageFrames: number;\n realtimeSubscriptions: number;\n receivedBytes: number;\n receivedFrames: number;\n reconnects: number;\n rpcCallBytes: number;\n rpcCallFrames: number;\n sentBytes: number;\n sentFrames: number;\n socketBufferedBytes: number;\n socketBufferedBytesHighWater: number;\n socketCloses: number;\n socketOpens: number;\n subscribeAcks: number;\n subscribeErrors: number;\n subscribeRequests: number;\n subscribeSuperseded: number;\n subscribeTimeouts: number;\n}\n\nconst openReadyState = 1;\nconst defaultAckTimeoutMs = 30_000;\nconst defaultMaxQueuedFrames = 256;\nconst randomId = (): string =>\n typeof globalThis.crypto?.randomUUID === 'function'\n ? globalThis.crypto.randomUUID()\n : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;\n\nconst bytesToBase64 = (bytes: Uint8Array): string => {\n let binary = '';\n const chunkSize = 0x8000;\n for (let offset = 0; offset < bytes.length; offset += chunkSize) {\n const chunk = bytes.subarray(offset, offset + chunkSize);\n binary += String.fromCharCode(...chunk);\n }\n return btoa(binary);\n};\n\nconst base64ToArrayBuffer = (data: string): ArrayBuffer => {\n const binary = atob(data);\n const bytes = new Uint8Array(binary.length);\n for (let index = 0; index < binary.length; index += 1) {\n bytes[index] = binary.charCodeAt(index);\n }\n return bytes.buffer;\n};\n\nconst encodeProxyPayload = (data: WebsocketsProxySendData): WebsocketsProxyPayload => {\n if (typeof data === 'string') return data;\n const bytes =\n data instanceof ArrayBuffer\n ? new Uint8Array(data)\n : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n return { encoding: 'base64', data: bytesToBase64(bytes) };\n};\n\nconst decodeProxyPayload = (data: WebsocketsProxyPayload): string | ArrayBuffer =>\n typeof data === 'string' ? data : base64ToArrayBuffer(data.data);\n\nconst resolveAuth = async (auth: GatewayAuthProvider): Promise<string> =>\n typeof auth === 'function' ? auth() : auth;\n\nconst compareCursors = compareWebsocketGatewayCursors;\n\nconst utf8ByteLength = (value: string): number => {\n let bytes = 0;\n for (let index = 0; index < value.length; index += 1) {\n const codePoint = value.charCodeAt(index);\n if (codePoint < 0x80) {\n bytes += 1;\n } else if (codePoint < 0x800) {\n bytes += 2;\n } else if (codePoint >= 0xd800 && codePoint <= 0xdbff && index + 1 < value.length) {\n const trailing = value.charCodeAt(index + 1);\n if (trailing >= 0xdc00 && trailing <= 0xdfff) {\n bytes += 4;\n index += 1;\n } else {\n bytes += 3;\n }\n } else {\n bytes += 3;\n }\n }\n return bytes;\n};\n\nconst maxBufferedChannelFrames = 10_000;\n\ninterface CursorMessageIface {\n cursor: string | null;\n}\n\ninterface SubscriptionDeliveryIface<Message extends CursorMessageIface> {\n message: Message;\n prevCursor?: string;\n}\n\ninterface SubscriptionBufferDiagnosticsIface {\n bytes: number;\n frames: number;\n}\n\ninterface SubscriptionStreamStateIface<Message extends CursorMessageIface> {\n afterCursor?: string;\n lastCursor?: string;\n gapFillRequestId: string | null;\n gapFillTimer: ReturnType<typeof setTimeout> | null;\n buffered: SubscriptionDeliveryIface<Message>[];\n bufferedBytes: number;\n bufferedBytesHighWater: number;\n bufferedFramesHighWater: number;\n}\n\ninterface ChannelSubscriptionStateIface extends SubscriptionStreamStateIface<WebsocketsMessage> {\n // Set between channel.subscribe and its ack: live frames buffer so history\n // replay (which the server sends before the ack) dispatches first, merged\n // by cursor.\n pendingAckId: string | null;\n pendingAckTimer: ReturnType<typeof setTimeout> | null;\n receivedBytes: number;\n receivedFrames: number;\n // Set while a prevCursor mismatch is being gap-filled via channel.history.\n onError: ((error: WebsocketsErrorFrame) => void) | null;\n onSubscribed: (() => void) | null;\n}\n\ninterface RegisterChannelSubscriptionArgsIface {\n afterCursor?: string;\n channel: string;\n onError?: (error: WebsocketsErrorFrame) => void;\n onSubscribed?: () => void;\n}\n\ninterface QueuedFrameIface {\n encoded: string;\n frame: WebsocketsClientFrame;\n sizeBytes: number;\n}\n\ninterface RealtimeSubscriptionStateIface extends SubscriptionStreamStateIface<WebsocketsRealtimeMessage> {\n topic: string;\n pendingSubscribe: boolean;\n handler: (message: WebsocketsRealtimeMessage) => void;\n onError: ((error: { code: string; message: string; retryable: boolean }) => void) | null;\n onResyncRequired: (() => void) | null;\n onSubscribed: (() => void) | null;\n}\n\nexport class WebsocketsConnection {\n private socket: PartySocketWebSocket | null = null;\n private handlers = new Set<GatewayFrameHandler>();\n private replayRegistrations = new Map<string, () => void>();\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private channelSubscriptions = new Map<string, ChannelSubscriptionStateIface>();\n private realtimeSubscriptions = new Map<string, RealtimeSubscriptionStateIface>();\n private realtimeSubscribeQueue = new Set<string>();\n private realtimeSubscribeQueued = false;\n private realtimeUnsubscribeQueue = new Set<string>();\n private realtimeUnsubscribeQueued = false;\n private socketAuthToken: string | null = null;\n private authenticated = false;\n private queuedFrames: QueuedFrameIface[] = [];\n private queuedBytes = 0;\n private manuallyClosed = false;\n private hasAuthenticated = false;\n private diagnostics: WebsocketsConnectionDiagnosticsIface = {\n bufferedBytes: 0,\n bufferedBytesHighWater: 0,\n bufferedFrames: 0,\n bufferedFramesHighWater: 0,\n bufferLimitFlushes: 0,\n channelMessageBytes: 0,\n channelMessageFrames: 0,\n channelStreams: [],\n channelSubscriptions: 0,\n gapFillErrors: 0,\n gapFillRequests: 0,\n gapFillResponses: 0,\n gapFillSendErrors: 0,\n gapFillTimeouts: 0,\n frameHandlers: 0,\n frameHandlersHighWater: 0,\n lastCloseCode: null,\n lastCloseReason: null,\n pendingGapFills: 0,\n pendingSubscribeAcks: 0,\n queuedBytes: 0,\n queuedFrames: 0,\n realtimeMessageBytes: 0,\n realtimeMessageFrames: 0,\n realtimeSubscriptions: 0,\n receivedBytes: 0,\n receivedFrames: 0,\n reconnects: 0,\n rpcCallBytes: 0,\n rpcCallFrames: 0,\n sentBytes: 0,\n sentFrames: 0,\n socketBufferedBytes: 0,\n socketBufferedBytesHighWater: 0,\n socketCloses: 0,\n socketOpens: 0,\n subscribeAcks: 0,\n subscribeErrors: 0,\n subscribeRequests: 0,\n subscribeSuperseded: 0,\n subscribeTimeouts: 0,\n };\n\n constructor(private readonly options: WebsocketsClientOptions) {}\n\n async connect(): Promise<void> {\n this.manuallyClosed = false;\n await this.openSocket();\n }\n\n private async openSocket(): Promise<void> {\n const WebSocketCtor = this.options.WebSocketCtor ?? globalThis.WebSocket;\n if (WebSocketCtor == null) {\n throw new Error('WebSocket is not available in this runtime');\n }\n const socket = new PartySocketWebSocket(() => this.resolveSocketUrlAndAuth(), undefined, {\n WebSocket: WebSocketCtor,\n minReconnectionDelay: 500,\n maxReconnectionDelay: 15_000,\n reconnectionDelayGrowFactor: 2,\n maxRetries: this.options.reconnect === false ? 0 : Infinity,\n });\n this.socket = socket;\n socket.addEventListener('message', (event) => {\n const rawText = String(event.data);\n let raw: unknown;\n try {\n raw = JSON.parse(rawText);\n } catch {\n return;\n }\n const parsed = websocketGatewayServerFrameSchema.safeParse(raw);\n if (!parsed.success) return;\n const frameByteLength = utf8ByteLength(rawText);\n this.diagnostics.receivedFrames += 1;\n this.diagnostics.receivedBytes += frameByteLength;\n if (parsed.data.type === 'channel.message') {\n this.diagnostics.channelMessageFrames += 1;\n this.diagnostics.channelMessageBytes += frameByteLength;\n }\n if (parsed.data.type === 'realtime.message') {\n this.diagnostics.realtimeMessageFrames += 1;\n this.diagnostics.realtimeMessageBytes += frameByteLength;\n }\n for (const frame of this.routeIncomingFrame(parsed.data, frameByteLength)) {\n for (const handler of this.handlers) handler(frame);\n }\n });\n socket.addEventListener('close', (event) => {\n this.clearHeartbeat();\n this.authenticated = false;\n this.diagnostics.socketCloses += 1;\n this.diagnostics.lastCloseCode = event.code;\n this.diagnostics.lastCloseReason = event.reason;\n });\n await new Promise<void>((resolve, reject) => {\n let settled = false;\n socket.addEventListener('open', () => {\n this.diagnostics.socketOpens += 1;\n this.authenticated = false;\n void this.authenticateInitialSocket()\n .then(() => {\n this.authenticated = true;\n this.startHeartbeat();\n this.resubscribeChannels();\n this.resubscribeRealtimeTopics();\n this.replayRegistrations.forEach((replay) => replay());\n this.flushQueuedFrames();\n if (this.hasAuthenticated) {\n this.diagnostics.reconnects += 1;\n this.options.onReconnect?.();\n }\n this.hasAuthenticated = true;\n if (!settled) {\n settled = true;\n resolve();\n }\n })\n .catch((cause) => {\n this.clearHeartbeat();\n this.authenticated = false;\n if (!settled && this.socket === socket) {\n this.socket = null;\n }\n if (!settled) {\n socket.close(4001, 'websockets auth failed');\n settled = true;\n reject(cause instanceof Error ? cause : new Error('Websockets auth failed'));\n } else {\n socket.reconnect(4001, 'websockets auth failed');\n }\n });\n });\n socket.addEventListener('error', () => {\n if (!settled) {\n settled = true;\n reject(new Error('Websockets open failed'));\n }\n });\n });\n }\n\n private async resolveSocketUrlAndAuth(): Promise<string> {\n this.socketAuthToken = await resolveAuth(this.options.auth);\n const url = new URL(this.options.url);\n url.searchParams.set('protocolVersion', String(websocketGatewayProtocolVersion));\n return url.toString();\n }\n\n private authenticateInitialSocket(): Promise<void> {\n const token = this.socketAuthToken;\n this.socketAuthToken = null;\n if (token == null) {\n return Promise.reject(new Error('Websockets auth token was not resolved'));\n }\n return this.auth.authorize({ token });\n }\n\n private startHeartbeat(): void {\n this.clearHeartbeat();\n const intervalMs = this.options.heartbeatIntervalMs;\n if (intervalMs == null || intervalMs <= 0) return;\n this.heartbeatTimer = setInterval(() => {\n if (this.socket == null || this.socket.readyState !== openReadyState) return;\n this.send({ type: 'ping', nonce: randomId() });\n }, intervalMs);\n }\n\n private clearHeartbeat(): void {\n if (this.heartbeatTimer == null) return;\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n\n // Per-channel frame routing: dedupes replay/live overlap by cursor, buffers\n // live frames until the subscribe ack so replay dispatches first, and\n // gap-fills skipped messages when a frame's prevCursor doesn't chain.\n private routeIncomingFrame(\n frame: WebsocketsServerFrame,\n frameByteLength: number,\n ): WebsocketsServerFrame[] {\n if (frame.type === 'realtime.subscribed') {\n const state = this.realtimeSubscriptions.get(frame.topic);\n if (state != null) {\n state.pendingSubscribe = false;\n if (frame.resyncRequired) state.lastCursor = undefined;\n if (frame.cursor != null) state.lastCursor = frame.cursor;\n if (frame.resyncRequired) state.onResyncRequired?.();\n state.onSubscribed?.();\n const buffered = this.settleSubscriptionBuffer(state, []);\n queueMicrotask(() => {\n if (this.realtimeSubscriptions.get(frame.topic) !== state) return;\n this.dispatchRealtimeDeliveries(state, buffered);\n });\n }\n return [frame];\n }\n if (frame.type === 'realtime.error') {\n this.realtimeSubscriptions.get(frame.topic)?.onError?.({\n code: frame.code,\n message: frame.message,\n retryable: frame.retryable,\n });\n return [frame];\n }\n if (frame.type === 'realtime.history') {\n const state = this.realtimeSubscriptions.get(frame.topic);\n if (state != null && state.gapFillRequestId === frame.requestId) {\n this.diagnostics.gapFillResponses += 1;\n this.clearSubscriptionGapFill(state);\n this.dispatchRealtimeDeliveries(\n state,\n this.settleSubscriptionBuffer(\n state,\n frame.messages.map((message) => ({ message })),\n ),\n );\n }\n return [frame];\n }\n if (frame.type === 'realtime.presence.event') return [frame];\n if (frame.type === 'realtime.message') {\n const state = this.realtimeSubscriptions.get(frame.topic);\n if (state == null) return [frame];\n if (state.pendingSubscribe || state.gapFillRequestId != null) {\n this.bufferSubscriptionDelivery(state, frame, frameByteLength);\n if (state.buffered.length >= maxBufferedChannelFrames) {\n this.diagnostics.bufferLimitFlushes += 1;\n state.pendingSubscribe = false;\n state.onResyncRequired?.();\n this.dispatchRealtimeDeliveries(state, this.settleSubscriptionBuffer(state, []));\n }\n return [];\n }\n const cursor = frame.message.cursor;\n if (\n frame.prevCursor != null &&\n state.lastCursor != null &&\n cursor != null &&\n frame.prevCursor !== state.lastCursor &&\n compareCursors(frame.prevCursor, state.lastCursor) > 0\n ) {\n this.beginRealtimeGapFill(state, frame, frameByteLength);\n return [];\n }\n const dispatchable = this.dispatchableSubscriptionDeliveries(state, [frame]);\n this.dispatchRealtimeDeliveries(state, dispatchable);\n return dispatchable.length === 0 ? [] : [frame];\n }\n if (frame.type === 'channel.message') {\n const state = this.channelSubscriptions.get(frame.message.channel);\n if (state == null) return [frame];\n state.receivedFrames += 1;\n state.receivedBytes += frameByteLength;\n if (state.pendingAckId != null || state.gapFillRequestId != null) {\n this.bufferSubscriptionDelivery(state, frame, frameByteLength);\n if (state.buffered.length >= maxBufferedChannelFrames) {\n this.diagnostics.bufferLimitFlushes += 1;\n return this.channelFrames(this.settleSubscriptionBuffer(state, []));\n }\n return [];\n }\n if (\n frame.prevCursor != null &&\n state.lastCursor != null &&\n frame.message.cursor != null &&\n frame.prevCursor !== state.lastCursor &&\n compareCursors(frame.prevCursor, state.lastCursor) > 0\n ) {\n this.beginChannelGapFill(frame.message.channel, state, frame, frameByteLength);\n return [];\n }\n return this.channelFrames(this.dispatchableSubscriptionDeliveries(state, [frame]));\n }\n if (frame.type === 'ack' || frame.type === 'error') {\n const state = [...this.channelSubscriptions.values()].find(\n (candidate) => candidate.pendingAckId != null && candidate.pendingAckId === frame.requestId,\n );\n if (state != null) {\n if (frame.type === 'error') {\n this.diagnostics.subscribeErrors += 1;\n } else {\n this.diagnostics.subscribeAcks += 1;\n }\n state.pendingAckId = null;\n if (state.pendingAckTimer != null) {\n clearTimeout(state.pendingAckTimer);\n state.pendingAckTimer = null;\n }\n const settled = this.channelFrames(this.settleSubscriptionBuffer(state, []));\n // A live subscription that has seen no message resumes from here after a\n // reconnect instead of from live, so it replays what it missed meanwhile.\n if (frame.type === 'ack' && frame.cursor != null && state.lastCursor == null) {\n state.lastCursor = frame.cursor;\n }\n if (frame.type === 'error') {\n state.onError?.(frame);\n } else {\n state.onSubscribed?.();\n }\n return [...settled, frame];\n }\n if (frame.type === 'error') {\n const realtimeGapFillState = [...this.realtimeSubscriptions.values()].find(\n (candidate) => candidate.gapFillRequestId === frame.requestId,\n );\n if (realtimeGapFillState != null) {\n this.diagnostics.gapFillErrors += 1;\n this.clearSubscriptionGapFill(realtimeGapFillState);\n this.dispatchRealtimeDeliveries(\n realtimeGapFillState,\n this.settleSubscriptionBuffer(realtimeGapFillState, []),\n );\n realtimeGapFillState.onError?.({\n code: frame.code,\n message: frame.message,\n retryable: true,\n });\n return [frame];\n }\n const gapFillState = [...this.channelSubscriptions.values()].find(\n (candidate) =>\n candidate.gapFillRequestId != null && candidate.gapFillRequestId === frame.requestId,\n );\n if (gapFillState != null) {\n this.diagnostics.gapFillErrors += 1;\n this.clearSubscriptionGapFill(gapFillState);\n const settled = this.channelFrames(this.settleSubscriptionBuffer(gapFillState, []));\n gapFillState.onError?.(frame);\n return [...settled, frame];\n }\n }\n return [frame];\n }\n if (frame.type === 'channel.history') {\n const state = [...this.channelSubscriptions.values()].find(\n (candidate) =>\n candidate.gapFillRequestId != null && candidate.gapFillRequestId === frame.requestId,\n );\n if (state == null) return [frame];\n this.diagnostics.gapFillResponses += 1;\n this.clearSubscriptionGapFill(state);\n // The internal gap-fill response is consumed here, not forwarded.\n return this.channelFrames(\n this.settleSubscriptionBuffer(\n state,\n frame.messages.map((message) => ({ message })),\n ),\n );\n }\n return [frame];\n }\n\n private dispatchableSubscriptionDeliveries<Message extends CursorMessageIface>(\n state: SubscriptionStreamStateIface<Message>,\n deliveries: SubscriptionDeliveryIface<Message>[],\n ): SubscriptionDeliveryIface<Message>[] {\n const dispatchable: SubscriptionDeliveryIface<Message>[] = [];\n for (const delivery of deliveries) {\n const cursor = delivery.message.cursor;\n if (cursor != null) {\n if (state.lastCursor != null && compareCursors(cursor, state.lastCursor) <= 0) continue;\n state.lastCursor = cursor;\n }\n dispatchable.push(delivery);\n }\n return dispatchable;\n }\n\n private settleSubscriptionBuffer<Message extends CursorMessageIface>(\n state: SubscriptionStreamStateIface<Message>,\n fetched: SubscriptionDeliveryIface<Message>[],\n ): SubscriptionDeliveryIface<Message>[] {\n const buffered = state.buffered;\n state.buffered = [];\n state.bufferedBytes = 0;\n const retained = [\n ...fetched.filter((delivery) => delivery.message.cursor != null),\n ...buffered.filter((delivery) => delivery.message.cursor != null),\n ].sort((left, right) =>\n compareCursors(left.message.cursor ?? '0-0', right.message.cursor ?? '0-0'),\n );\n const ephemeral = buffered.filter((delivery) => delivery.message.cursor == null);\n return this.dispatchableSubscriptionDeliveries(state, [...retained, ...ephemeral]);\n }\n\n private bufferSubscriptionDelivery<Message extends CursorMessageIface>(\n state: SubscriptionStreamStateIface<Message>,\n delivery: SubscriptionDeliveryIface<Message>,\n byteLength: number,\n ): void {\n state.buffered.push(delivery);\n state.bufferedBytes += byteLength;\n state.bufferedFramesHighWater = Math.max(state.bufferedFramesHighWater, state.buffered.length);\n state.bufferedBytesHighWater = Math.max(state.bufferedBytesHighWater, state.bufferedBytes);\n const diagnostics = this.currentBufferDiagnostics();\n this.diagnostics.bufferedFramesHighWater = Math.max(\n this.diagnostics.bufferedFramesHighWater,\n diagnostics.frames,\n );\n this.diagnostics.bufferedBytesHighWater = Math.max(\n this.diagnostics.bufferedBytesHighWater,\n diagnostics.bytes,\n );\n }\n\n private currentBufferDiagnostics(): SubscriptionBufferDiagnosticsIface {\n let bytes = 0;\n let frames = 0;\n for (const state of this.channelSubscriptions.values()) {\n bytes += state.bufferedBytes;\n frames += state.buffered.length;\n }\n for (const state of this.realtimeSubscriptions.values()) {\n bytes += state.bufferedBytes;\n frames += state.buffered.length;\n }\n return { bytes, frames };\n }\n\n private clearSubscriptionGapFill<Message extends CursorMessageIface>(\n state: SubscriptionStreamStateIface<Message>,\n ): void {\n state.gapFillRequestId = null;\n if (state.gapFillTimer != null) clearTimeout(state.gapFillTimer);\n state.gapFillTimer = null;\n }\n\n private beginSubscriptionGapFill<Message extends CursorMessageIface>(\n state: SubscriptionStreamStateIface<Message>,\n delivery: SubscriptionDeliveryIface<Message>,\n deliveryByteLength: number,\n sendHistory: (requestId: string) => void,\n onUnavailable: (deliveries: SubscriptionDeliveryIface<Message>[]) => void,\n ): void {\n const requestId = randomId();\n this.diagnostics.gapFillRequests += 1;\n state.gapFillRequestId = requestId;\n this.bufferSubscriptionDelivery(state, delivery, deliveryByteLength);\n const recoverWithoutHistory = (): void => {\n if (state.gapFillRequestId !== requestId) return;\n this.clearSubscriptionGapFill(state);\n onUnavailable(this.settleSubscriptionBuffer(state, []));\n };\n state.gapFillTimer = setTimeout(() => {\n this.diagnostics.gapFillTimeouts += 1;\n recoverWithoutHistory();\n }, this.options.ackTimeoutMs ?? defaultAckTimeoutMs);\n try {\n sendHistory(requestId);\n } catch {\n this.diagnostics.gapFillSendErrors += 1;\n recoverWithoutHistory();\n }\n }\n\n private channelFrames(\n deliveries: SubscriptionDeliveryIface<WebsocketsMessage>[],\n ): Extract<WebsocketsServerFrame, { type: 'channel.message' }>[] {\n return deliveries.map((delivery) => ({ type: 'channel.message', ...delivery }));\n }\n\n private dispatchRealtimeDeliveries(\n state: RealtimeSubscriptionStateIface,\n deliveries: SubscriptionDeliveryIface<WebsocketsRealtimeMessage>[],\n ): void {\n for (const delivery of deliveries) state.handler(delivery.message);\n }\n\n private beginRealtimeGapFill(\n state: RealtimeSubscriptionStateIface,\n frame: Extract<WebsocketsServerFrame, { type: 'realtime.message' }>,\n frameByteLength: number,\n ): void {\n this.beginSubscriptionGapFill(\n state,\n frame,\n frameByteLength,\n (requestId) => {\n this.send({\n type: 'realtime.history',\n id: requestId,\n topic: state.topic,\n afterCursor: state.lastCursor,\n limit: 1000,\n });\n },\n (deliveries) => {\n this.dispatchRealtimeDeliveries(state, deliveries);\n state.onResyncRequired?.();\n },\n );\n }\n\n private beginChannelGapFill(\n channel: string,\n state: ChannelSubscriptionStateIface,\n frame: Extract<WebsocketsServerFrame, { type: 'channel.message' }>,\n frameByteLength: number,\n ): void {\n this.beginSubscriptionGapFill(\n state,\n frame,\n frameByteLength,\n (requestId) => {\n this.send({\n type: 'channel.history',\n id: requestId,\n channel,\n afterCursor: state.lastCursor,\n limit: 1000,\n });\n },\n (deliveries) => {\n for (const flushed of this.channelFrames(deliveries)) {\n for (const handler of this.handlers) handler(flushed);\n }\n },\n );\n }\n\n private resubscribeChannels(): void {\n for (const [channel, subscription] of this.channelSubscriptions) {\n this.sendSubscribeFrame(channel, subscription);\n }\n }\n\n private resubscribeRealtimeTopics(): void {\n this.realtimeSubscribeQueue.clear();\n this.realtimeSubscribeQueued = false;\n this.realtimeUnsubscribeQueue.clear();\n this.realtimeUnsubscribeQueued = false;\n this.queuedFrames = this.queuedFrames.filter(\n (queued) =>\n queued.frame.type !== 'realtime.subscribe' && queued.frame.type !== 'realtime.unsubscribe',\n );\n this.queuedBytes = this.queuedFrames.reduce((total, queued) => total + queued.sizeBytes, 0);\n this.sendRealtimeSubscribeBatches([...this.realtimeSubscriptions.values()]);\n }\n\n private queueRealtimeSubscribe(topic: string): void {\n this.realtimeSubscribeQueue.add(topic);\n if (this.realtimeSubscribeQueued) return;\n this.realtimeSubscribeQueued = true;\n queueMicrotask(() => {\n this.realtimeSubscribeQueued = false;\n const states = [...this.realtimeSubscribeQueue].flatMap((queuedTopic) => {\n const state = this.realtimeSubscriptions.get(queuedTopic);\n return state == null ? [] : [state];\n });\n this.realtimeSubscribeQueue.clear();\n if (states.length > 0 && !this.manuallyClosed) this.sendRealtimeSubscribeBatches(states);\n });\n }\n\n private sendRealtimeSubscribeBatches(states: RealtimeSubscriptionStateIface[]): void {\n for (let offset = 0; offset < states.length; offset += 64) {\n const batch = states.slice(offset, offset + 64);\n for (const state of batch) state.pendingSubscribe = true;\n this.send({\n type: 'realtime.subscribe',\n id: randomId(),\n subscriptions: batch.map((state) => ({\n topic: state.topic,\n afterCursor: state.lastCursor ?? state.afterCursor ?? '$',\n })),\n });\n }\n }\n\n private queueRealtimeUnsubscribe(topic: string): void {\n this.realtimeUnsubscribeQueue.add(topic);\n if (this.realtimeUnsubscribeQueued) return;\n this.realtimeUnsubscribeQueued = true;\n queueMicrotask(() => {\n this.realtimeUnsubscribeQueued = false;\n const topics = [...this.realtimeUnsubscribeQueue];\n this.realtimeUnsubscribeQueue.clear();\n if (this.manuallyClosed) return;\n for (let offset = 0; offset < topics.length; offset += 64) {\n this.send({ type: 'realtime.unsubscribe', topics: topics.slice(offset, offset + 64) });\n }\n });\n }\n\n private sendSubscribeFrame(channel: string, subscription: ChannelSubscriptionStateIface): void {\n const requestId = randomId();\n this.diagnostics.subscribeRequests += 1;\n if (subscription.pendingAckId != null) this.diagnostics.subscribeSuperseded += 1;\n subscription.pendingAckId = requestId;\n if (subscription.pendingAckTimer != null) clearTimeout(subscription.pendingAckTimer);\n subscription.pendingAckTimer = setTimeout(() => {\n if (subscription.pendingAckId !== requestId) return;\n this.diagnostics.subscribeTimeouts += 1;\n subscription.pendingAckId = null;\n subscription.pendingAckTimer = null;\n for (const flushed of this.channelFrames(this.settleSubscriptionBuffer(subscription, []))) {\n for (const handler of this.handlers) handler(flushed);\n }\n }, this.options.ackTimeoutMs ?? defaultAckTimeoutMs);\n this.send({\n type: 'channel.subscribe',\n id: requestId,\n channel,\n afterCursor: subscription.lastCursor ?? subscription.afterCursor ?? '$',\n });\n }\n\n auth = {\n authorize: (args: { token: string }): Promise<void> => {\n const requestId = randomId();\n const result = this.waitForAck(requestId, 'auth');\n this.sendAuthFrame({ id: requestId, type: 'auth', token: args.token });\n return result;\n },\n };\n\n onFrame(handler: GatewayFrameHandler): () => void {\n this.handlers.add(handler);\n this.diagnostics.frameHandlersHighWater = Math.max(\n this.diagnostics.frameHandlersHighWater,\n this.handlers.size,\n );\n return () => this.handlers.delete(handler);\n }\n\n registerReplay(key: string, replay: () => void): () => void {\n this.replayRegistrations.set(key, replay);\n return () => this.replayRegistrations.delete(key);\n }\n\n waitForAck(requestId: string, operation: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n unsubscribe();\n reject(new Error(`Websockets ${operation} acknowledgement timed out`));\n }, this.options.ackTimeoutMs ?? defaultAckTimeoutMs);\n const unsubscribe = this.onFrame((frame) => {\n if (\n frame.type === 'ack' &&\n frame.requestId === requestId &&\n frame.operation === operation\n ) {\n unsubscribe();\n clearTimeout(timeout);\n resolve();\n }\n if (frame.type === 'error' && frame.requestId === requestId) {\n unsubscribe();\n clearTimeout(timeout);\n reject(new Error(frame.message));\n }\n });\n });\n }\n\n channel(name: string): WebsocketsChannel {\n return new WebsocketsChannel(this, name);\n }\n\n realtime(topic: string): WebsocketsRealtimeTopic {\n return new WebsocketsRealtimeTopic(this, topic);\n }\n\n registerRealtimeSubscription(args: {\n topic: string;\n handler: (message: WebsocketsRealtimeMessage) => void;\n options?: WebsocketsRealtimeSubscribeOptionsIface;\n }): () => void {\n this.realtimeUnsubscribeQueue.delete(args.topic);\n const state: RealtimeSubscriptionStateIface = {\n topic: args.topic,\n pendingSubscribe: true,\n afterCursor: args.options?.afterCursor,\n gapFillRequestId: null,\n gapFillTimer: null,\n buffered: [],\n bufferedBytes: 0,\n bufferedBytesHighWater: 0,\n bufferedFramesHighWater: 0,\n handler: args.handler,\n onError: args.options?.onError ?? null,\n onResyncRequired: args.options?.onResyncRequired ?? null,\n onSubscribed: args.options?.onSubscribed ?? null,\n };\n this.realtimeSubscriptions.set(args.topic, state);\n this.queueRealtimeSubscribe(args.topic);\n return () => {\n if (this.realtimeSubscriptions.get(args.topic) !== state) return;\n this.clearSubscriptionGapFill(state);\n this.realtimeSubscriptions.delete(args.topic);\n this.realtimeSubscribeQueue.delete(args.topic);\n this.queueRealtimeUnsubscribe(args.topic);\n };\n }\n\n registerChannelSubscription(args: RegisterChannelSubscriptionArgsIface): () => void {\n const subscription: ChannelSubscriptionStateIface = {\n afterCursor: args.afterCursor,\n pendingAckId: null,\n pendingAckTimer: null,\n gapFillRequestId: null,\n gapFillTimer: null,\n buffered: [],\n bufferedBytes: 0,\n bufferedBytesHighWater: 0,\n bufferedFramesHighWater: 0,\n onError: args.onError ?? null,\n onSubscribed: args.onSubscribed ?? null,\n receivedBytes: 0,\n receivedFrames: 0,\n };\n this.channelSubscriptions.set(args.channel, subscription);\n this.sendSubscribeFrame(args.channel, subscription);\n return () => {\n if (subscription.pendingAckTimer != null) clearTimeout(subscription.pendingAckTimer);\n this.clearSubscriptionGapFill(subscription);\n this.channelSubscriptions.delete(args.channel);\n this.send({ type: 'channel.unsubscribe', channel: args.channel });\n };\n }\n\n rpc(name: string): WebsocketsRpc {\n return new WebsocketsRpc(this, name);\n }\n\n bridge(name: string): WebsocketsBridge {\n return new WebsocketsBridge(this, name);\n }\n\n proxy(upstream: WebsocketsProxyTarget): WebsocketsProxy {\n return new WebsocketsProxy(this, upstream);\n }\n\n send(frame: WebsocketsClientFrame): void {\n if (this.socket == null) {\n throw new Error('Websockets connection is not open');\n }\n if (this.manuallyClosed) {\n throw new Error('Websockets connection is not open');\n }\n const encoded = JSON.stringify(frame);\n const sizeBytes = utf8ByteLength(encoded);\n if (!this.authenticated && frame.type !== 'auth') {\n if (this.socket.readyState !== openReadyState && this.options.reconnect === false) {\n throw new Error('Websockets connection is not open');\n }\n if (this.queuedFrames.length >= (this.options.maxQueuedFrames ?? defaultMaxQueuedFrames)) {\n throw new Error('Websockets queued frame limit exceeded');\n }\n this.queuedFrames.push({ encoded, frame, sizeBytes });\n this.queuedBytes += sizeBytes;\n return;\n }\n if (this.socket.readyState !== openReadyState) {\n throw new Error('Websockets connection is not open');\n }\n this.sendEncodedFrame(frame, encoded, sizeBytes);\n }\n\n getDiagnostics(): WebsocketsConnectionDiagnosticsIface {\n const buffers = this.currentBufferDiagnostics();\n let pendingGapFills = 0;\n let pendingSubscribeAcks = 0;\n for (const state of this.channelSubscriptions.values()) {\n if (state.gapFillRequestId != null) pendingGapFills += 1;\n if (state.pendingAckId != null) pendingSubscribeAcks += 1;\n }\n for (const state of this.realtimeSubscriptions.values()) {\n if (state.gapFillRequestId != null) pendingGapFills += 1;\n }\n return {\n ...this.diagnostics,\n bufferedBytes: buffers.bytes,\n bufferedFrames: buffers.frames,\n channelStreams: [...this.channelSubscriptions.entries()].map(([channel, state]) => ({\n bufferedBytes: state.bufferedBytes,\n bufferedBytesHighWater: state.bufferedBytesHighWater,\n bufferedFrames: state.buffered.length,\n bufferedFramesHighWater: state.bufferedFramesHighWater,\n channel,\n pendingGapFill: state.gapFillRequestId != null,\n pendingSubscribeAck: state.pendingAckId != null,\n receivedBytes: state.receivedBytes,\n receivedFrames: state.receivedFrames,\n })),\n channelSubscriptions: this.channelSubscriptions.size,\n frameHandlers: this.handlers.size,\n pendingGapFills,\n pendingSubscribeAcks,\n queuedBytes: this.queuedBytes,\n queuedFrames: this.queuedFrames.length,\n realtimeSubscriptions: this.realtimeSubscriptions.size,\n socketBufferedBytes: this.socket?.bufferedAmount ?? 0,\n };\n }\n\n private sendAuthFrame(frame: Extract<WebsocketsClientFrame, { type: 'auth' }>): void {\n if (this.socket == null || this.socket.readyState !== openReadyState) {\n throw new Error('Websockets connection is not open');\n }\n const encoded = JSON.stringify(frame);\n this.sendEncodedFrame(frame, encoded, utf8ByteLength(encoded));\n }\n\n private sendEncodedFrame(frame: WebsocketsClientFrame, encoded: string, sizeBytes: number): void {\n if (this.socket == null || this.socket.readyState !== openReadyState) {\n throw new Error('Websockets connection is not open');\n }\n this.socket.send(encoded);\n this.diagnostics.sentFrames += 1;\n this.diagnostics.sentBytes += sizeBytes;\n if (frame.type === 'rpc.call') {\n this.diagnostics.rpcCallFrames += 1;\n this.diagnostics.rpcCallBytes += sizeBytes;\n }\n const socketBufferedBytes = this.socket.bufferedAmount;\n this.diagnostics.socketBufferedBytesHighWater = Math.max(\n this.diagnostics.socketBufferedBytesHighWater,\n socketBufferedBytes,\n );\n }\n\n private flushQueuedFrames(): void {\n if (this.socket == null || this.socket.readyState !== openReadyState || !this.authenticated) {\n return;\n }\n const frames = this.queuedFrames;\n this.queuedFrames = [];\n this.queuedBytes = 0;\n for (const queued of frames) {\n this.sendEncodedFrame(queued.frame, queued.encoded, queued.sizeBytes);\n }\n }\n\n ping(nonce = randomId()): void {\n this.send({ type: 'ping', nonce });\n }\n\n close(code?: number, reason?: string): void {\n this.manuallyClosed = true;\n this.queuedFrames = [];\n this.queuedBytes = 0;\n this.realtimeSubscribeQueue.clear();\n this.realtimeSubscribeQueued = false;\n this.realtimeUnsubscribeQueue.clear();\n this.realtimeUnsubscribeQueued = false;\n this.clearHeartbeat();\n this.socket?.close(code, reason);\n }\n}\n\nexport class WebsocketsChannel {\n constructor(\n private readonly connection: WebsocketsConnection,\n private readonly name: string,\n ) {}\n\n subscribe(\n handler: (message: WebsocketsMessage) => void,\n options?: string | WebsocketsChannelSubscribeOptionsIface,\n ): () => void {\n const unsubscribe = this.connection.onFrame((frame) => {\n if (frame.type === 'channel.message' && frame.message.channel === this.name) {\n handler(frame.message);\n }\n });\n const unregisterSubscription = this.connection.registerChannelSubscription({\n channel: this.name,\n afterCursor: typeof options === 'string' ? options : options?.afterCursor,\n onError: typeof options === 'string' ? undefined : options?.onError,\n onSubscribed: typeof options === 'string' ? undefined : options?.onSubscribed,\n });\n return () => {\n unsubscribe();\n unregisterSubscription();\n };\n }\n\n publish(data: WebsocketsData, options: string | WebsocketsChannelPublishOptions = {}): void {\n const publishOptions = typeof options === 'string' ? { name: options } : options;\n this.connection.send({\n type: 'channel.publish',\n channel: this.name,\n name: publishOptions.name ?? 'message',\n data,\n idempotencyKey: publishOptions.idempotencyKey,\n retain: publishOptions.retain,\n });\n }\n\n history(args: { afterCursor?: string; limit?: number } = {}): Promise<WebsocketsMessage[]> {\n const requestId = randomId();\n this.connection.send({\n type: 'channel.history',\n id: requestId,\n channel: this.name,\n afterCursor: args.afterCursor,\n limit: args.limit ?? 100,\n });\n return new Promise((resolve, reject) => {\n const unsubscribe = this.connection.onFrame((frame) => {\n if (frame.type === 'channel.history' && frame.requestId === requestId) {\n unsubscribe();\n resolve(frame.messages);\n }\n if (frame.type === 'error' && frame.requestId === requestId) {\n unsubscribe();\n reject(new Error(frame.message));\n }\n });\n });\n }\n\n presence(): WebsocketsPresence {\n return new WebsocketsPresence(this.connection, this.name);\n }\n}\n\nexport class WebsocketsRealtimeTopic {\n constructor(\n private readonly connection: WebsocketsConnection,\n private readonly topic: string,\n ) {}\n\n subscribe(\n handler: (message: WebsocketsRealtimeMessage) => void,\n options?: WebsocketsRealtimeSubscribeOptionsIface,\n ): () => void {\n return this.connection.registerRealtimeSubscription({ topic: this.topic, handler, options });\n }\n\n presence(): WebsocketsRealtimePresenceIface {\n let data: WebsocketsData | undefined;\n let unregisterReplay: (() => void) | null = null;\n return {\n enter: (nextData?: WebsocketsData): void => {\n data = nextData;\n unregisterReplay?.();\n unregisterReplay = this.connection.registerReplay(`realtime-presence:${this.topic}`, () => {\n this.connection.send({\n type: 'realtime.presence.enter',\n topic: this.topic,\n data,\n });\n });\n this.connection.send({\n type: 'realtime.presence.enter',\n topic: this.topic,\n data: nextData,\n });\n },\n update: (nextData?: WebsocketsData): void => {\n data = nextData;\n this.connection.send({\n type: 'realtime.presence.update',\n topic: this.topic,\n data: nextData,\n });\n },\n leave: (): void => {\n unregisterReplay?.();\n unregisterReplay = null;\n this.connection.send({ type: 'realtime.presence.leave', topic: this.topic });\n },\n get: (\n options: WebsocketsPresenceGetOptionsIface = {},\n ): Promise<WebsocketsPresenceMember[]> => {\n const requestId = randomId();\n return new Promise((resolve, reject) => {\n let unsubscribe = (): void => undefined;\n const cleanup = (): void => {\n unsubscribe();\n options.signal?.removeEventListener('abort', handleAbort);\n };\n const handleAbort = (): void => {\n cleanup();\n reject(options.signal?.reason ?? new Error('Presence snapshot request aborted'));\n };\n if (options.signal?.aborted === true) {\n handleAbort();\n return;\n }\n unsubscribe = this.connection.onFrame((frame) => {\n if (\n frame.type === 'realtime.presence.snapshot' &&\n frame.requestId === requestId &&\n frame.topic === this.topic\n ) {\n cleanup();\n resolve(frame.members);\n }\n if (\n frame.type === 'realtime.error' &&\n frame.requestId === requestId &&\n frame.topic === this.topic\n ) {\n cleanup();\n reject(new Error(frame.message));\n }\n });\n options.signal?.addEventListener('abort', handleAbort, { once: true });\n try {\n this.connection.send({\n id: requestId,\n type: 'realtime.presence.get',\n topic: this.topic,\n });\n } catch (error) {\n cleanup();\n reject(error);\n }\n });\n },\n subscribe: (handler: (event: WebsocketsRealtimePresenceEventIface) => void): (() => void) =>\n this.connection.onFrame((frame) => {\n if (frame.type !== 'realtime.presence.event' || frame.topic !== this.topic) return;\n handler(frame);\n }),\n };\n }\n}\n\nexport class WebsocketsPresence {\n private unregisterPresenceReplay: (() => void) | null = null;\n private data: WebsocketsData | undefined;\n\n constructor(\n private readonly connection: WebsocketsConnection,\n private readonly channel: string,\n ) {}\n\n enter(data?: WebsocketsData): void {\n this.data = data;\n this.unregisterPresenceReplay?.();\n this.unregisterPresenceReplay = this.connection.registerReplay(\n `presence:${this.channel}`,\n () => {\n this.connection.send({ type: 'presence.enter', channel: this.channel, data: this.data });\n },\n );\n this.connection.send({ type: 'presence.enter', channel: this.channel, data });\n }\n\n update(data?: WebsocketsData): void {\n this.data = data;\n this.connection.send({ type: 'presence.update', channel: this.channel, data });\n }\n\n leave(): void {\n this.unregisterPresenceReplay?.();\n this.unregisterPresenceReplay = null;\n this.connection.send({ type: 'presence.leave', channel: this.channel });\n }\n\n get(options: WebsocketsPresenceGetOptionsIface = {}): Promise<WebsocketsPresenceMember[]> {\n const requestId = randomId();\n return new Promise((resolve, reject) => {\n let unsubscribe = (): void => undefined;\n const cleanup = (): void => {\n unsubscribe();\n options.signal?.removeEventListener('abort', handleAbort);\n };\n const handleAbort = (): void => {\n cleanup();\n reject(options.signal?.reason ?? new Error('Presence snapshot request aborted'));\n };\n if (options.signal?.aborted === true) {\n handleAbort();\n return;\n }\n unsubscribe = this.connection.onFrame((frame) => {\n if (frame.type === 'presence.snapshot' && frame.requestId === requestId) {\n cleanup();\n resolve(frame.members);\n }\n if (frame.type === 'error' && frame.requestId === requestId) {\n cleanup();\n reject(new Error(frame.message));\n }\n });\n options.signal?.addEventListener('abort', handleAbort, { once: true });\n try {\n this.connection.send({\n type: 'presence.get',\n id: requestId,\n channel: this.channel,\n });\n } catch (error) {\n cleanup();\n reject(error);\n }\n });\n }\n\n subscribe(\n handler: (event: {\n channel: string;\n action: 'enter' | 'update' | 'leave';\n member: WebsocketsPresenceMember;\n }) => void,\n ): () => void {\n return this.connection.onFrame((frame) => {\n if (frame.type === 'presence.event' && frame.channel === this.channel) {\n handler({ channel: frame.channel, action: frame.action, member: frame.member });\n }\n });\n }\n}\n\nexport class WebsocketsRpc {\n constructor(\n private readonly connection: WebsocketsConnection,\n private readonly name: string,\n ) {}\n\n connect(handler: (data: WebsocketsData) => WebsocketsData | Promise<WebsocketsData>): () => void {\n this.connection.send({ type: 'rpc.register', name: this.name });\n const unregisterReplay = this.connection.registerReplay(`rpc:${this.name}`, () => {\n this.connection.send({ type: 'rpc.register', name: this.name });\n });\n const unsubscribe = this.connection.onFrame((frame) => {\n if (frame.type !== 'rpc.call' || frame.name !== this.name) return;\n Promise.resolve(handler(websocketGatewayDataSchema.parse(frame.data)))\n .then((data) => {\n this.connection.send({ type: 'rpc.respond', correlationId: frame.correlationId, data });\n })\n .catch((cause) => {\n this.connection.send({\n type: 'rpc.respond',\n correlationId: frame.correlationId,\n error: {\n code: 'handler_failed',\n message: cause instanceof Error ? cause.message : String(cause),\n },\n });\n });\n });\n return () => {\n unsubscribe();\n unregisterReplay();\n };\n }\n\n call(\n data: WebsocketsData,\n timeoutMs = 30_000,\n signal?: AbortSignal,\n ): Promise<WebsocketsData | undefined> {\n const correlationId = randomId();\n return new Promise((resolve, reject) => {\n if (signal?.aborted === true) {\n reject(signal.reason);\n return;\n }\n const cleanup = () => {\n clearTimeout(timer);\n unsubscribe();\n signal?.removeEventListener('abort', abort);\n };\n const abort = () => {\n cleanup();\n reject(signal?.reason ?? new Error('Websockets RPC aborted'));\n };\n const timer = setTimeout(() => {\n cleanup();\n reject(new Error('Websockets RPC timed out'));\n }, timeoutMs);\n const unsubscribe = this.connection.onFrame((frame) => {\n if (frame.type !== 'rpc.response' || frame.correlationId !== correlationId) return;\n cleanup();\n if (frame.error != null) reject(new Error(frame.error.message));\n else\n resolve(\n frame.data === undefined ? undefined : websocketGatewayDataSchema.parse(frame.data),\n );\n });\n signal?.addEventListener('abort', abort, { once: true });\n try {\n this.connection.send({ type: 'rpc.call', name: this.name, correlationId, data, timeoutMs });\n } catch (cause) {\n cleanup();\n reject(cause);\n }\n });\n }\n}\n\nexport class WebsocketsBridge {\n constructor(\n private readonly connection: WebsocketsConnection,\n private readonly name: string,\n ) {}\n\n join(role: string, handler?: (data: WebsocketsData) => void): () => void {\n this.connection.send({ type: 'bridge.join', bridge: this.name, role });\n const unregisterReplay = this.connection.registerReplay(`bridge:${this.name}`, () => {\n this.connection.send({ type: 'bridge.join', bridge: this.name, role });\n });\n const unsubscribe = this.connection.onFrame((frame) => {\n if (frame.type === 'bridge.message' && frame.bridge === this.name) {\n handler?.(websocketGatewayDataSchema.parse(frame.data));\n }\n });\n return () => {\n unsubscribe();\n unregisterReplay();\n this.connection.send({ type: 'bridge.leave', bridge: this.name });\n };\n }\n\n async joinReady(role: string, handler?: (data: WebsocketsData) => void): Promise<() => void> {\n const requestId = randomId();\n const acknowledged = this.connection.waitForAck(requestId, 'bridge.join');\n const unsubscribe = this.connection.onFrame((frame) => {\n if (frame.type === 'bridge.message' && frame.bridge === this.name) {\n handler?.(websocketGatewayDataSchema.parse(frame.data));\n }\n });\n const unregisterReplay = this.connection.registerReplay(`bridge:${this.name}`, () => {\n this.connection.send({ type: 'bridge.join', bridge: this.name, role });\n });\n this.connection.send({\n id: requestId,\n type: 'bridge.join',\n bridge: this.name,\n role,\n });\n try {\n await acknowledged;\n } catch (error) {\n unsubscribe();\n unregisterReplay();\n throw error;\n }\n return () => {\n unsubscribe();\n unregisterReplay();\n this.connection.send({ type: 'bridge.leave', bridge: this.name });\n };\n }\n\n send(data: WebsocketsData): void {\n this.connection.send({ type: 'bridge.send', bridge: this.name, data });\n }\n}\n\nexport class WebsocketsProxy {\n private readonly upstreamId: string;\n\n constructor(\n private readonly connection: WebsocketsConnection,\n upstream: WebsocketsProxyTarget,\n ) {\n this.upstreamId = typeof upstream === 'string' ? upstream : upstream.id;\n }\n\n connect(handlers: WebsocketsProxyHandlers = {}): () => void {\n const unsubscribe = this.connection.onFrame((frame) => {\n switch (frame.type) {\n case 'proxy.open':\n if (frame.upstreamId === this.upstreamId) {\n handlers.onOpen?.(frame.upstreamId);\n }\n return;\n case 'proxy.message':\n handlers.onMessage?.(decodeProxyPayload(frame.data));\n return;\n case 'proxy.closed':\n handlers.onClose?.({ code: frame.code, reason: frame.reason });\n return;\n }\n });\n this.connection.send({ type: 'proxy.connect', upstreamId: this.upstreamId });\n return unsubscribe;\n }\n\n send(data: WebsocketsProxySendData): void {\n this.connection.send({ type: 'proxy.send', data: encodeProxyPayload(data) });\n }\n\n close(code?: number, reason?: string): void {\n this.connection.send({ type: 'proxy.close', code, reason });\n }\n}\n\nexport class WebsocketsWorker {\n private helloArgs: {\n workerId: string;\n namespace?: string;\n appVersion?: string;\n queues: string[];\n maxConcurrency: number;\n inFlightLeaseIds: string[];\n } | null = null;\n private inFlightLeases = new Map<string, string>();\n private pendingTerminalLeaseOperations = new Map<\n string,\n {\n operation: 'work.complete' | 'work.fail';\n requestId: string;\n result?: WebsocketsData;\n error?: string;\n unsubscribe: () => void;\n }\n >();\n private unregisterHelloReplay: (() => void) | null = null;\n private unregisterTerminalOperationReplay: (() => void) | null = null;\n\n constructor(private readonly connection: WebsocketsConnection) {}\n\n hello(args: {\n workerId: string;\n namespace?: string;\n appVersion?: string;\n queues: string[];\n maxConcurrency?: number;\n inFlightLeaseIds?: string[];\n inFlightLeases?: Array<{ leaseId: string; queue: string }>;\n }): void {\n this.helloArgs = {\n workerId: args.workerId,\n namespace: args.namespace,\n appVersion: args.appVersion,\n queues: args.queues,\n maxConcurrency: args.maxConcurrency ?? 1,\n inFlightLeaseIds: args.inFlightLeaseIds ?? [],\n };\n this.inFlightLeases.clear();\n for (const lease of args.inFlightLeases ?? []) {\n this.inFlightLeases.set(lease.leaseId, lease.queue);\n }\n if (\n (args.inFlightLeases == null || args.inFlightLeases.length === 0) &&\n args.queues.length === 1\n ) {\n for (const leaseId of args.inFlightLeaseIds ?? []) {\n this.inFlightLeases.set(leaseId, args.queues[0]!);\n }\n }\n this.unregisterHelloReplay?.();\n this.unregisterHelloReplay = this.connection.registerReplay(`worker:${args.workerId}`, () => {\n this.sendHello();\n });\n this.unregisterTerminalOperationReplay?.();\n this.unregisterTerminalOperationReplay = this.connection.registerReplay(\n `worker:${args.workerId}:terminal-lease-operations`,\n () => {\n this.replayPendingTerminalLeaseOperations();\n },\n );\n this.sendHello();\n }\n\n private sendHello(): void {\n if (this.helloArgs == null) return;\n this.connection.send({\n type: 'worker.hello',\n workerId: this.helloArgs.workerId,\n namespace: this.helloArgs.namespace,\n appVersion: this.helloArgs.appVersion,\n queues: this.helloArgs.queues,\n ...(() => {\n if (!(this.helloArgs.maxConcurrency === 1))\n return { maxConcurrency: this.helloArgs.maxConcurrency };\n return {};\n })(),\n inFlightLeaseIds: this.helloArgs.inFlightLeaseIds,\n inFlightLeases: [...this.inFlightLeases.entries()].map(([leaseId, queue]) => ({\n leaseId,\n queue,\n })),\n });\n }\n\n onOffer(\n handler: (offer: { queue: string; leaseId: string; payload: WebsocketsData }) => void,\n ): () => void {\n return this.connection.onFrame((frame) => {\n if (frame.type !== 'work.offer') return;\n this.inFlightLeases.set(frame.leaseId, frame.queue);\n handler({\n queue: frame.queue,\n leaseId: frame.leaseId,\n payload: websocketGatewayDataSchema.parse(frame.payload),\n });\n });\n }\n\n accept(leaseId: string): Promise<void> {\n return this.sendLeaseOperation('work.accept', leaseId);\n }\n\n heartbeat(leaseId: string): Promise<void> {\n return this.sendLeaseOperation('work.heartbeat', leaseId);\n }\n\n complete(leaseId: string, result?: WebsocketsData): Promise<void> {\n return this.sendTerminalLeaseOperation('work.complete', leaseId, { result }).then(() => {\n this.inFlightLeases.delete(leaseId);\n });\n }\n\n fail(leaseId: string, error: string): Promise<void> {\n return this.sendTerminalLeaseOperation('work.fail', leaseId, { error }).then(() => {\n this.inFlightLeases.delete(leaseId);\n });\n }\n\n drain(reason?: string): Promise<void> {\n const requestId = randomId();\n const result = this.connection.waitForAck(requestId, 'work.drain');\n this.connection.send({ id: requestId, type: 'work.drain', reason });\n return result;\n }\n\n close(code?: number, reason?: string): void {\n this.unregisterHelloReplay?.();\n this.unregisterTerminalOperationReplay?.();\n this.connection.close(code, reason);\n }\n\n private sendTerminalLeaseOperation(\n operation: 'work.complete' | 'work.fail',\n leaseId: string,\n extra: { result?: WebsocketsData; error?: string } = {},\n ): Promise<void> {\n this.pendingTerminalLeaseOperations.get(leaseId)?.unsubscribe();\n const requestId = randomId();\n const unsubscribe = this.connection.onFrame((frame) => {\n if (frame.type === 'ack' && frame.requestId === requestId && frame.operation === operation) {\n this.clearPendingTerminalLeaseOperation(leaseId);\n this.inFlightLeases.delete(leaseId);\n }\n if (frame.type === 'error' && frame.requestId === requestId) {\n this.clearPendingTerminalLeaseOperation(leaseId);\n this.inFlightLeases.delete(leaseId);\n }\n });\n this.pendingTerminalLeaseOperations.set(leaseId, {\n operation,\n requestId,\n result: extra.result,\n error: extra.error,\n unsubscribe,\n });\n const result = this.connection.waitForAck(requestId, operation).then(() => {\n this.clearPendingTerminalLeaseOperation(leaseId);\n });\n this.sendTerminalLeaseOperationFrame(leaseId);\n return result;\n }\n\n private clearPendingTerminalLeaseOperation(leaseId: string): void {\n const pending = this.pendingTerminalLeaseOperations.get(leaseId);\n pending?.unsubscribe();\n this.pendingTerminalLeaseOperations.delete(leaseId);\n }\n\n private replayPendingTerminalLeaseOperations(): void {\n for (const leaseId of this.pendingTerminalLeaseOperations.keys()) {\n this.sendTerminalLeaseOperationFrame(leaseId);\n }\n }\n\n private sendTerminalLeaseOperationFrame(leaseId: string): void {\n const pending = this.pendingTerminalLeaseOperations.get(leaseId);\n if (pending == null) return;\n switch (pending.operation) {\n case 'work.complete':\n this.connection.send({\n id: pending.requestId,\n type: 'work.complete',\n leaseId,\n result: pending.result,\n });\n break;\n case 'work.fail':\n this.connection.send({\n id: pending.requestId,\n type: 'work.fail',\n leaseId,\n error: pending.error ?? 'Worker failed',\n });\n break;\n }\n }\n\n private sendLeaseOperation(\n operation: 'work.accept' | 'work.heartbeat' | 'work.complete' | 'work.fail',\n leaseId: string,\n extra: { result?: WebsocketsData; error?: string } = {},\n ): Promise<void> {\n const requestId = randomId();\n const result = this.connection.waitForAck(requestId, operation);\n switch (operation) {\n case 'work.accept':\n this.connection.send({ id: requestId, type: 'work.accept', leaseId });\n break;\n case 'work.heartbeat':\n this.connection.send({ id: requestId, type: 'work.heartbeat', leaseId });\n break;\n case 'work.complete':\n this.connection.send({\n id: requestId,\n type: 'work.complete',\n leaseId,\n result: extra.result,\n });\n break;\n case 'work.fail':\n this.connection.send({\n id: requestId,\n type: 'work.fail',\n leaseId,\n error: extra.error ?? 'Worker failed',\n });\n break;\n }\n return result;\n }\n}\n\nexport const client = {\n connect: async (options: WebsocketsClientOptions): Promise<WebsocketsConnection> => {\n const connection = new WebsocketsConnection(options);\n await connection.connect();\n return connection;\n },\n};\n\nexport const worker = {\n connect: async (options: WebsocketsClientOptions): Promise<WebsocketsWorker> => {\n const connection = new WebsocketsConnection(options);\n await connection.connect();\n return new WebsocketsWorker(connection);\n },\n};\n\nexport const capability = (\n channels: string[],\n actions: WebsocketsAction[],\n): WebsocketsCapability => ({\n channels,\n actions,\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,27 @@
1
+ import type { LookupFunction } from 'node:net';
2
+ export interface NodeClientTlsIface {
3
+ cert: string;
4
+ key: string;
5
+ ca?: string;
6
+ }
7
+ export interface NodeClientTlsFetchOptionsIface {
8
+ tls: NodeClientTlsIface;
9
+ lookup?: LookupFunction;
10
+ validateUrl?: (url: string) => Promise<void>;
11
+ }
12
+ export interface NodeClientTlsSessionIface {
13
+ fetch: typeof fetch;
14
+ close: () => Promise<void>;
15
+ }
16
+ export declare const createNodeClientTlsSession: (args: NodeClientTlsFetchOptionsIface) => NodeClientTlsSessionIface;
17
+ export declare const createNodeClientTlsFetch: (args: NodeClientTlsFetchOptionsIface) => typeof fetch;
18
+ export interface NodeClientWebSocketConstructorIface<T extends object> {
19
+ new (url: string, protocols?: string | string[], options?: {
20
+ headers?: Record<string, string>;
21
+ }): T;
22
+ }
23
+ export declare const configureNodeClientWebSocket: <T extends object>(args: {
24
+ constructor: NodeClientWebSocketConstructorIface<T>;
25
+ tls?: NodeClientTlsIface;
26
+ lookup?: LookupFunction;
27
+ }) => NodeClientWebSocketConstructorIface<T>;
@@ -0,0 +1,54 @@
1
+ import * as z from "zod";
2
+ import { Agent } from "undici";
3
+ const tlsDispatcher = (args) => {
4
+ const dispatcher = new Agent({ allowH2: false, connect: { ...args.tls, lookup: args.lookup } });
5
+ const tlsFetch = async (input, init) => {
6
+ const request = new Request(input, init);
7
+ if (new URL(request.url).protocol !== "https:") throw new Error("Client TLS requires HTTPS");
8
+ await args.validateUrl?.(request.url);
9
+ const options = { dispatcher, redirect: "manual" };
10
+ const response = await fetch(request, options);
11
+ if (response.status >= 300 && response.status < 400) {
12
+ await response.body?.cancel();
13
+ throw new Error("Client TLS redirects are not allowed");
14
+ }
15
+ return response;
16
+ };
17
+ return { fetch: tlsFetch, finish: () => dispatcher.close(), close: () => dispatcher.destroy() };
18
+ };
19
+ const createNodeClientTlsSession = (args) => {
20
+ const session = tlsDispatcher(args);
21
+ return { fetch: session.fetch, close: session.close };
22
+ };
23
+ const createNodeClientTlsFetch = (args) => async (input, init) => {
24
+ const session = tlsDispatcher(args);
25
+ try {
26
+ return await session.fetch(input, init);
27
+ } finally {
28
+ void session.finish().catch(() => void 0);
29
+ }
30
+ };
31
+ const configureNodeClientWebSocket = (args) => new Proxy(args.constructor, {
32
+ construct: (target, raw) => {
33
+ const [url, protocols, options] = z.tuple([
34
+ z.string(),
35
+ z.union([z.string(), z.array(z.string())]).optional(),
36
+ z.looseObject({ headers: z.record(z.string(), z.string()).optional() }).optional()
37
+ ]).parse(raw);
38
+ if (args.tls != null && new URL(url).protocol !== "wss:")
39
+ throw new Error("Client TLS requires WSS");
40
+ const socketOptions = {
41
+ ...options,
42
+ ...args.tls,
43
+ lookup: args.lookup,
44
+ followRedirects: false
45
+ };
46
+ return new target(url, protocols, socketOptions);
47
+ }
48
+ });
49
+ export {
50
+ configureNodeClientWebSocket,
51
+ createNodeClientTlsFetch,
52
+ createNodeClientTlsSession
53
+ };
54
+ //# sourceMappingURL=node-client-tls.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/node-client-tls.ts"],
4
+ "sourcesContent": ["import type { LookupFunction } from 'node:net';\nimport * as z from 'zod';\nimport { Agent, type Dispatcher } from 'undici';\n\nexport interface NodeClientTlsIface {\n cert: string;\n key: string;\n ca?: string;\n}\n\nexport interface NodeClientTlsFetchOptionsIface {\n tls: NodeClientTlsIface;\n lookup?: LookupFunction;\n validateUrl?: (url: string) => Promise<void>;\n}\n\nconst tlsDispatcher = (args: NodeClientTlsFetchOptionsIface) => {\n const dispatcher = new Agent({ allowH2: false, connect: { ...args.tls, lookup: args.lookup } });\n const tlsFetch: typeof fetch = async (input, init) => {\n const request = new Request(input, init);\n if (new URL(request.url).protocol !== 'https:') throw new Error('Client TLS requires HTTPS');\n await args.validateUrl?.(request.url);\n const options: RequestInit & { dispatcher: Dispatcher } = { dispatcher, redirect: 'manual' };\n const response = await fetch(request, options);\n if (response.status >= 300 && response.status < 400) {\n await response.body?.cancel();\n throw new Error('Client TLS redirects are not allowed');\n }\n return response;\n };\n return { fetch: tlsFetch, finish: () => dispatcher.close(), close: () => dispatcher.destroy() };\n};\n\n// A stream owns the connection pool and closes it with its ACP session.\nexport interface NodeClientTlsSessionIface {\n fetch: typeof fetch;\n close: () => Promise<void>;\n}\nexport const createNodeClientTlsSession = (\n args: NodeClientTlsFetchOptionsIface,\n): NodeClientTlsSessionIface => {\n const session = tlsDispatcher(args);\n return { fetch: session.fetch, close: session.close };\n};\n\n// A request-scoped dispatcher closes after the response body finishes, including\n// streaming ACP responses. Client credentials never follow redirects.\nexport const createNodeClientTlsFetch =\n (args: NodeClientTlsFetchOptionsIface): typeof fetch =>\n async (input, init) => {\n const session = tlsDispatcher(args);\n try {\n return await session.fetch(input, init);\n } finally {\n void session.finish().catch(() => undefined);\n }\n };\n\nexport interface NodeClientWebSocketConstructorIface<T extends object> {\n new (\n url: string,\n protocols?: string | string[],\n options?: { headers?: Record<string, string> },\n ): T;\n}\n\nexport const configureNodeClientWebSocket = <T extends object>(args: {\n constructor: NodeClientWebSocketConstructorIface<T>;\n tls?: NodeClientTlsIface;\n lookup?: LookupFunction;\n}): NodeClientWebSocketConstructorIface<T> =>\n new Proxy(args.constructor, {\n construct: (target, raw) => {\n const [url, protocols, options] = z\n .tuple([\n z.string(),\n z.union([z.string(), z.array(z.string())]).optional(),\n z.looseObject({ headers: z.record(z.string(), z.string()).optional() }).optional(),\n ])\n .parse(raw);\n if (args.tls != null && new URL(url).protocol !== 'wss:')\n throw new Error('Client TLS requires WSS');\n const socketOptions = {\n ...options,\n ...args.tls,\n lookup: args.lookup,\n followRedirects: false,\n };\n return new target(url, protocols, socketOptions);\n },\n });\n"],
5
+ "mappings": "AACA,YAAY,OAAO;AACnB,SAAS,aAA8B;AAcvC,MAAM,gBAAgB,CAAC,SAAyC;AAC9D,QAAM,aAAa,IAAI,MAAM,EAAE,SAAS,OAAO,SAAS,EAAE,GAAG,KAAK,KAAK,QAAQ,KAAK,OAAO,EAAE,CAAC;AAC9F,QAAM,WAAyB,OAAO,OAAO,SAAS;AACpD,UAAM,UAAU,IAAI,QAAQ,OAAO,IAAI;AACvC,QAAI,IAAI,IAAI,QAAQ,GAAG,EAAE,aAAa,SAAU,OAAM,IAAI,MAAM,2BAA2B;AAC3F,UAAM,KAAK,cAAc,QAAQ,GAAG;AACpC,UAAM,UAAoD,EAAE,YAAY,UAAU,SAAS;AAC3F,UAAM,WAAW,MAAM,MAAM,SAAS,OAAO;AAC7C,QAAI,SAAS,UAAU,OAAO,SAAS,SAAS,KAAK;AACnD,YAAM,SAAS,MAAM,OAAO;AAC5B,YAAM,IAAI,MAAM,sCAAsC;AAAA,IACxD;AACA,WAAO;AAAA,EACT;AACA,SAAO,EAAE,OAAO,UAAU,QAAQ,MAAM,WAAW,MAAM,GAAG,OAAO,MAAM,WAAW,QAAQ,EAAE;AAChG;AAOO,MAAM,6BAA6B,CACxC,SAC8B;AAC9B,QAAM,UAAU,cAAc,IAAI;AAClC,SAAO,EAAE,OAAO,QAAQ,OAAO,OAAO,QAAQ,MAAM;AACtD;AAIO,MAAM,2BACX,CAAC,SACD,OAAO,OAAO,SAAS;AACrB,QAAM,UAAU,cAAc,IAAI;AAClC,MAAI;AACF,WAAO,MAAM,QAAQ,MAAM,OAAO,IAAI;AAAA,EACxC,UAAE;AACA,SAAK,QAAQ,OAAO,EAAE,MAAM,MAAM,MAAS;AAAA,EAC7C;AACF;AAUK,MAAM,+BAA+B,CAAmB,SAK7D,IAAI,MAAM,KAAK,aAAa;AAAA,EAC1B,WAAW,CAAC,QAAQ,QAAQ;AAC1B,UAAM,CAAC,KAAK,WAAW,OAAO,IAAI,EAC/B,MAAM;AAAA,MACL,EAAE,OAAO;AAAA,MACT,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,SAAS;AAAA,MACpD,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS;AAAA,IACnF,CAAC,EACA,MAAM,GAAG;AACZ,QAAI,KAAK,OAAO,QAAQ,IAAI,IAAI,GAAG,EAAE,aAAa;AAChD,YAAM,IAAI,MAAM,yBAAyB;AAC3C,UAAM,gBAAgB;AAAA,MACpB,GAAG;AAAA,MACH,GAAG,KAAK;AAAA,MACR,QAAQ,KAAK;AAAA,MACb,iBAAiB;AAAA,IACnB;AACA,WAAO,IAAI,OAAO,KAAK,WAAW,aAAa;AAAA,EACjD;AACF,CAAC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,15 @@
1
+ export declare const createClientTlsFixture: () => {
2
+ tls: {
3
+ cert: string;
4
+ key: string;
5
+ ca: string;
6
+ };
7
+ server: {
8
+ cert: string;
9
+ key: string;
10
+ ca: string;
11
+ requestCert: boolean;
12
+ rejectUnauthorized: boolean;
13
+ };
14
+ cleanup: () => void;
15
+ };
@@ -0,0 +1,85 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ const createClientTlsFixture = () => {
6
+ const directory = mkdtempSync(join(tmpdir(), "final-client-tls-"));
7
+ const openssl = (args) => execFileSync("openssl", args, { cwd: directory, stdio: "ignore" });
8
+ try {
9
+ openssl([
10
+ "req",
11
+ "-x509",
12
+ "-newkey",
13
+ "ec",
14
+ "-pkeyopt",
15
+ "ec_paramgen_curve:prime256v1",
16
+ "-nodes",
17
+ "-keyout",
18
+ "ca.key",
19
+ "-out",
20
+ "ca.crt",
21
+ "-subj",
22
+ "/CN=Final test CA",
23
+ "-days",
24
+ "1"
25
+ ]);
26
+ for (const name of ["server", "client"]) {
27
+ openssl([
28
+ "req",
29
+ "-new",
30
+ "-newkey",
31
+ "ec",
32
+ "-pkeyopt",
33
+ "ec_paramgen_curve:prime256v1",
34
+ "-nodes",
35
+ "-keyout",
36
+ `${name}.key`,
37
+ "-out",
38
+ `${name}.csr`,
39
+ "-subj",
40
+ `/CN=${name === "server" ? "localhost" : "Final test client"}`
41
+ ]);
42
+ writeFileSync(
43
+ join(directory, `${name}.ext`),
44
+ name === "server" ? "subjectAltName=DNS:localhost,IP:127.0.0.1\nextendedKeyUsage=serverAuth\n" : "extendedKeyUsage=clientAuth\n"
45
+ );
46
+ openssl([
47
+ "x509",
48
+ "-req",
49
+ "-in",
50
+ `${name}.csr`,
51
+ "-CA",
52
+ "ca.crt",
53
+ "-CAkey",
54
+ "ca.key",
55
+ "-CAcreateserial",
56
+ "-out",
57
+ `${name}.crt`,
58
+ "-days",
59
+ "1",
60
+ "-extfile",
61
+ `${name}.ext`
62
+ ]);
63
+ }
64
+ const read = (name) => readFileSync(join(directory, name), "utf8");
65
+ const ca = read("ca.crt");
66
+ return {
67
+ tls: { cert: read("client.crt"), key: read("client.key"), ca },
68
+ server: {
69
+ cert: read("server.crt"),
70
+ key: read("server.key"),
71
+ ca,
72
+ requestCert: true,
73
+ rejectUnauthorized: true
74
+ },
75
+ cleanup: () => rmSync(directory, { recursive: true, force: true })
76
+ };
77
+ } catch (error) {
78
+ rmSync(directory, { recursive: true, force: true });
79
+ throw error;
80
+ }
81
+ };
82
+ export {
83
+ createClientTlsFixture
84
+ };
85
+ //# sourceMappingURL=client-tls-fixture.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/testing/client-tls-fixture.ts"],
4
+ "sourcesContent": ["import { execFileSync } from 'node:child_process';\nimport { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\n\n// Ephemeral certificates for real HTTPS/WSS tests; no keys are committed.\nexport const createClientTlsFixture = () => {\n const directory = mkdtempSync(join(tmpdir(), 'final-client-tls-'));\n const openssl = (args: string[]) =>\n execFileSync('openssl', args, { cwd: directory, stdio: 'ignore' });\n try {\n openssl([\n 'req',\n '-x509',\n '-newkey',\n 'ec',\n '-pkeyopt',\n 'ec_paramgen_curve:prime256v1',\n '-nodes',\n '-keyout',\n 'ca.key',\n '-out',\n 'ca.crt',\n '-subj',\n '/CN=Final test CA',\n '-days',\n '1',\n ]);\n for (const name of ['server', 'client']) {\n openssl([\n 'req',\n '-new',\n '-newkey',\n 'ec',\n '-pkeyopt',\n 'ec_paramgen_curve:prime256v1',\n '-nodes',\n '-keyout',\n `${name}.key`,\n '-out',\n `${name}.csr`,\n '-subj',\n `/CN=${name === 'server' ? 'localhost' : 'Final test client'}`,\n ]);\n writeFileSync(\n join(directory, `${name}.ext`),\n name === 'server'\n ? 'subjectAltName=DNS:localhost,IP:127.0.0.1\\nextendedKeyUsage=serverAuth\\n'\n : 'extendedKeyUsage=clientAuth\\n',\n );\n openssl([\n 'x509',\n '-req',\n '-in',\n `${name}.csr`,\n '-CA',\n 'ca.crt',\n '-CAkey',\n 'ca.key',\n '-CAcreateserial',\n '-out',\n `${name}.crt`,\n '-days',\n '1',\n '-extfile',\n `${name}.ext`,\n ]);\n }\n const read = (name: string) => readFileSync(join(directory, name), 'utf8');\n const ca = read('ca.crt');\n return {\n tls: { cert: read('client.crt'), key: read('client.key'), ca },\n server: {\n cert: read('server.crt'),\n key: read('server.key'),\n ca,\n requestCert: true,\n rejectUnauthorized: true,\n },\n cleanup: () => rmSync(directory, { recursive: true, force: true }),\n };\n } catch (error) {\n rmSync(directory, { recursive: true, force: true });\n throw error;\n }\n};\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,aAAa,cAAc,QAAQ,qBAAqB;AACjE,SAAS,cAAc;AACvB,SAAS,YAAY;AAGd,MAAM,yBAAyB,MAAM;AAC1C,QAAM,YAAY,YAAY,KAAK,OAAO,GAAG,mBAAmB,CAAC;AACjE,QAAM,UAAU,CAAC,SACf,aAAa,WAAW,MAAM,EAAE,KAAK,WAAW,OAAO,SAAS,CAAC;AACnE,MAAI;AACF,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AACD,eAAW,QAAQ,CAAC,UAAU,QAAQ,GAAG;AACvC,cAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,GAAG,IAAI;AAAA,QACP;AAAA,QACA,GAAG,IAAI;AAAA,QACP;AAAA,QACA,OAAO,SAAS,WAAW,cAAc,mBAAmB;AAAA,MAC9D,CAAC;AACD;AAAA,QACE,KAAK,WAAW,GAAG,IAAI,MAAM;AAAA,QAC7B,SAAS,WACL,6EACA;AAAA,MACN;AACA,cAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA,GAAG,IAAI;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,GAAG,IAAI;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA,GAAG,IAAI;AAAA,MACT,CAAC;AAAA,IACH;AACA,UAAM,OAAO,CAAC,SAAiB,aAAa,KAAK,WAAW,IAAI,GAAG,MAAM;AACzE,UAAM,KAAK,KAAK,QAAQ;AACxB,WAAO;AAAA,MACL,KAAK,EAAE,MAAM,KAAK,YAAY,GAAG,KAAK,KAAK,YAAY,GAAG,GAAG;AAAA,MAC7D,QAAQ;AAAA,QACN,MAAM,KAAK,YAAY;AAAA,QACvB,KAAK,KAAK,YAAY;AAAA,QACtB;AAAA,QACA,aAAa;AAAA,QACb,oBAAoB;AAAA,MACtB;AAAA,MACA,SAAS,MAAM,OAAO,WAAW,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IACnE;AAAA,EACF,SAAS,OAAO;AACd,WAAO,WAAW,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAClD,UAAM;AAAA,EACR;AACF;",
6
+ "names": []
7
+ }
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@finalai/websockets",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "description": "Client for Final WebSockets channels, realtime, presence, and RPC.",
6
+ "license": "UNLICENSED",
7
+ "files": [
8
+ "dist",
9
+ "README.md",
10
+ "THIRD_PARTY_NOTICES.md"
11
+ ],
12
+ "type": "module",
13
+ "sideEffects": false,
14
+ "types": "./dist/modules/index.d.mts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/modules/index.d.mts",
18
+ "import": "./dist/modules/index.mjs",
19
+ "default": "./dist/modules/index.mjs"
20
+ },
21
+ "./package.json": "./package.json",
22
+ "./node-client-tls": {
23
+ "types": "./dist/modules/node-client-tls.d.mts",
24
+ "import": "./dist/modules/node-client-tls.mjs",
25
+ "default": "./dist/modules/node-client-tls.mjs"
26
+ },
27
+ "./channel-transport": {
28
+ "types": "./dist/modules/channel-transport.d.mts",
29
+ "import": "./dist/modules/channel-transport.mjs",
30
+ "default": "./dist/modules/channel-transport.mjs"
31
+ },
32
+ "./testing/client-tls-fixture": {
33
+ "types": "./dist/modules/testing/client-tls-fixture.d.mts",
34
+ "import": "./dist/modules/testing/client-tls-fixture.mjs",
35
+ "default": "./dist/modules/testing/client-tls-fixture.mjs"
36
+ }
37
+ },
38
+ "publishConfig": {
39
+ "access": "restricted",
40
+ "registry": "https://registry.npmjs.org/"
41
+ },
42
+ "dependencies": {
43
+ "@finalai/websocket-gateway-protocol": "0.1.0",
44
+ "partysocket": "1.2.0",
45
+ "undici": "^8.10",
46
+ "zod": "4.6.5"
47
+ },
48
+ "engines": {
49
+ "node": ">=26"
50
+ },
51
+ "repository": {
52
+ "type": "git",
53
+ "url": "git+https://github.com/final-company/packages-typescript.git",
54
+ "directory": "packages/@finalai/websockets"
55
+ }
56
+ }