{"version":3,"file":"BackendWebSocketService.cjs","sourceRoot":"","sources":["../../src/ws/BackendWebSocketService.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TraceCallback } from '@metamask/controller-utils';\nimport { ExponentialBackoff } from '@metamask/controller-utils';\nimport type {\n  KeyringControllerLockEvent,\n  KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { AuthenticationController } from '@metamask/profile-sync-controller';\nimport { getErrorMessage } from '@metamask/utils';\nimport { v4 as uuidV4 } from 'uuid';\n\nimport { projectLogger, createModuleLogger } from '../logger';\nimport type { BackendWebSocketServiceMethodActions } from './BackendWebSocketService-method-action-types';\n\nconst SERVICE_NAME = 'BackendWebSocketService' as const;\n\nconst log = createModuleLogger(projectLogger, SERVICE_NAME);\n\n// WebSocket close codes and reasons for internal operations\nconst MANUAL_DISCONNECT_CODE = 4999 as const;\nconst MANUAL_DISCONNECT_REASON = 'Internal: Manual disconnect' as const;\nconst FORCE_RECONNECT_CODE = 4998 as const;\nconst FORCE_RECONNECT_REASON = 'Internal: Force reconnect' as const;\n\nconst MESSENGER_EXPOSED_METHODS = [\n  'connect',\n  'disconnect',\n  'forceReconnection',\n  'sendMessage',\n  'sendRequest',\n  'subscribe',\n  'getConnectionInfo',\n  'getSubscriptionsByChannel',\n  'channelHasSubscription',\n  'findSubscriptionsByChannelPrefix',\n  'addChannelCallback',\n  'removeChannelCallback',\n  'getChannelCallbacks',\n] as const;\n\n/**\n * Gets human-readable close reason from RFC 6455 close code\n *\n * @param code - WebSocket close code\n * @returns Human-readable close reason\n */\nexport function getCloseReason(code: number): string {\n  switch (code) {\n    case 1000:\n      return 'Normal Closure';\n    case 1001:\n      return 'Going Away';\n    case 1002:\n      return 'Protocol Error';\n    case 1003:\n      return 'Unsupported Data';\n    case 1004:\n      return 'Reserved';\n    case 1005:\n      return 'No Status Received';\n    case 1006:\n      return 'Abnormal Closure';\n    case 1007:\n      return 'Invalid frame payload data';\n    case 1008:\n      return 'Policy Violation';\n    case 1009:\n      return 'Message Too Big';\n    case 1010:\n      return 'Mandatory Extension';\n    case 1011:\n      return 'Internal Server Error';\n    case 1012:\n      return 'Service Restart';\n    case 1013:\n      return 'Try Again Later';\n    case 1014:\n      return 'Bad Gateway';\n    case 1015:\n      return 'TLS Handshake';\n    default:\n      if (code >= 3000 && code <= 3999) {\n        return 'Library/Framework Error';\n      }\n      if (code >= 4000 && code <= 4999) {\n        return 'Application Error';\n      }\n      return 'Unknown';\n  }\n}\n\n/**\n * WebSocket connection states\n */\nexport enum WebSocketState {\n  CONNECTING = 'connecting',\n  CONNECTED = 'connected',\n  /** @deprecated This value is no longer used internally and will be removed in a future major release */\n  DISCONNECTING = 'disconnecting',\n  DISCONNECTED = 'disconnected',\n  /** @deprecated TThis value is no longer used internally and will be removed in a future major release */\n  ERROR = 'error',\n}\n\n/**\n * WebSocket event types\n */\nexport enum WebSocketEventType {\n  CONNECTED = 'connected',\n  DISCONNECTED = 'disconnected',\n  MESSAGE = 'message',\n  ERROR = 'error',\n  RECONNECTING = 'reconnecting',\n  RECONNECTED = 'reconnected',\n}\n\n/**\n * Configuration options for the WebSocket service\n */\nexport type BackendWebSocketServiceOptions = {\n  /** The WebSocket URL to connect to */\n  url: string;\n\n  /** The messenger for inter-service communication */\n  messenger: BackendWebSocketServiceMessenger;\n\n  /** Connection timeout in milliseconds (default: 10000) */\n  timeout?: number;\n\n  /** Initial reconnection delay in milliseconds (default: 10000) */\n  reconnectDelay?: number;\n\n  /** Maximum reconnection delay in milliseconds (default: 60000) */\n  maxReconnectDelay?: number;\n\n  /** Request timeout in milliseconds (default: 30000) */\n  requestTimeout?: number;\n\n  /** Optional callback to determine if connection should be enabled (default: always enabled) */\n  isEnabled?: () => boolean;\n\n  /** Optional callback to trace performance of WebSocket operations (default: no-op) */\n  traceFn?: TraceCallback;\n};\n\n/**\n * Client Request message\n * Used when client sends a request to the server\n */\nexport type ClientRequestMessage = {\n  event: string;\n  data: {\n    requestId: string;\n    channels?: string[];\n    [key: string]: unknown;\n  };\n};\n\n/**\n * Server Response message\n * Used when server responds to a client request\n */\nexport type ServerResponseMessage = {\n  event: string;\n  data: {\n    requestId: string;\n    subscriptionId?: string;\n    succeeded?: string[];\n    failed?: string[];\n    [key: string]: unknown;\n  };\n};\n\n/**\n * Server Notification message\n * Used when server sends unsolicited data to client\n * subscriptionId is optional for system-wide notifications\n */\nexport type ServerNotificationMessage = {\n  event: string;\n  subscriptionId?: string;\n  channel: string;\n  data: Record<string, unknown>;\n  timestamp: number;\n};\n\n/**\n * Union type for all WebSocket messages\n */\nexport type WebSocketMessage =\n  | ClientRequestMessage\n  | ServerResponseMessage\n  | ServerNotificationMessage;\n\n/**\n * Channel-based callback configuration\n */\nexport type ChannelCallback = {\n  /** Channel name to match (also serves as the unique identifier) */\n  channelName: string;\n  /** Callback function */\n  callback: (notification: ServerNotificationMessage) => void;\n};\n\n/**\n * Unified WebSocket subscription object used for both internal storage and external API\n */\nexport type WebSocketSubscription = {\n  /** The subscription ID from the server */\n  subscriptionId: string;\n  /** Channel names for this subscription */\n  channels: string[];\n  /** Channel type with version (e.g., 'account-activity.v1') extracted from first channel */\n  channelType: string;\n  /** Callback function for handling notifications (optional for external use) */\n  callback?: (notification: ServerNotificationMessage) => void;\n  /** Function to unsubscribe and clean up */\n  unsubscribe: (requestId?: string) => Promise<void>;\n};\n\n/**\n * WebSocket connection info\n */\nexport type WebSocketConnectionInfo = {\n  state: WebSocketState;\n  url: string;\n  reconnectAttempts: number;\n  timeout: number;\n  reconnectDelay: number;\n  maxReconnectDelay: number;\n  requestTimeout: number;\n  connectedAt?: number;\n};\n\n// Action types for the messaging system - using generated method actions\nexport type BackendWebSocketServiceActions =\n  BackendWebSocketServiceMethodActions;\n\ntype AllowedActions =\n  AuthenticationController.AuthenticationControllerGetBearerTokenAction;\n\n// Event types for WebSocket connection state changes\nexport type BackendWebSocketServiceConnectionStateChangedEvent = {\n  type: 'BackendWebSocketService:connectionStateChanged';\n  payload: [WebSocketConnectionInfo];\n};\n\ntype AllowedEvents =\n  | AuthenticationController.AuthenticationControllerStateChangeEvent\n  | KeyringControllerLockEvent\n  | KeyringControllerUnlockEvent;\n\nexport type BackendWebSocketServiceEvents =\n  BackendWebSocketServiceConnectionStateChangedEvent;\n\nexport type BackendWebSocketServiceMessenger = Messenger<\n  typeof SERVICE_NAME,\n  BackendWebSocketServiceActions | AllowedActions,\n  BackendWebSocketServiceEvents | AllowedEvents\n>;\n\n/**\n * WebSocket Service with automatic reconnection, session management and direct callback routing\n *\n * Connection Management:\n * - Automatically subscribes to AuthenticationController:stateChange (sign in/out)\n * - Automatically subscribes to KeyringController:lock/unlock events\n * - Idempotent connect() function safe for multiple rapid calls\n * - Auto-reconnects on unexpected disconnects (manualDisconnect = false)\n *\n * Platform Responsibilities:\n * - Call connect() when app opens/foregrounds\n * - Call disconnect() when app closes/backgrounds\n * - Provide isEnabled() callback (feature flag)\n * - Call destroy() on app termination\n *\n * Real-Time Performance Optimizations:\n * - Fast path message routing (zero allocations)\n * - Production mode removes try-catch overhead\n * - Optimized JSON parsing with fail-fast\n * - Direct callback routing bypasses event emitters\n * - Memory cleanup and resource management\n */\nexport class BackendWebSocketService {\n  /**\n   * The name of the service.\n   */\n  readonly name = SERVICE_NAME;\n\n  readonly #messenger: BackendWebSocketServiceMessenger;\n\n  readonly #options: Required<\n    Omit<BackendWebSocketServiceOptions, 'messenger' | 'isEnabled' | 'traceFn'>\n  >;\n\n  readonly #isEnabled: (() => boolean) | undefined;\n\n  readonly #trace: TraceCallback;\n\n  #ws: WebSocket | undefined;\n\n  #state: WebSocketState = WebSocketState.DISCONNECTED;\n\n  #reconnectAttempts = 0;\n\n  #reconnectTimer: NodeJS.Timeout | null = null;\n\n  #connectionTimeout: NodeJS.Timeout | null = null;\n\n  #stableConnectionTimer: NodeJS.Timeout | null = null;\n\n  // Track the current connection promise to handle concurrent connection attempts\n  #connectionPromise: Promise<void> | null = null;\n\n  readonly #pendingRequests = new Map<\n    string,\n    {\n      resolve: (value: unknown) => void;\n      reject: (error: Error) => void;\n      timeout: NodeJS.Timeout;\n    }\n  >();\n\n  #connectedAt: number = 0;\n\n  // Simplified subscription storage (single flat map)\n  // Key: subscription ID string (e.g., 'sub_abc123def456')\n  // Value: WebSocketSubscription object with channels, callback and metadata\n  readonly #subscriptions = new Map<string, WebSocketSubscription>();\n\n  // Channel-based callback storage\n  // Key: channel name (serves as unique identifier)\n  // Value: ChannelCallback configuration\n  readonly #channelCallbacks = new Map<string, ChannelCallback>();\n\n  // Backoff instance for reconnection delays (reset on stable connection)\n  #backoff!: ReturnType<ExponentialBackoff<unknown>['next']>;\n\n  // =============================================================================\n  // 1. CONSTRUCTOR & INITIALIZATION\n  // =============================================================================\n\n  /**\n   * Creates a new WebSocket service instance\n   *\n   * @param options - Configuration options for the WebSocket service\n   */\n  constructor(options: BackendWebSocketServiceOptions) {\n    this.#messenger = options.messenger;\n    this.#isEnabled = options.isEnabled;\n    // Default to no-op trace function to keep core platform-agnostic\n    this.#trace =\n      options.traceFn ??\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      (((_request: any, fn?: any) => fn?.()) as TraceCallback);\n\n    this.#options = {\n      url: options.url,\n      timeout: options.timeout ?? 10000,\n      reconnectDelay: options.reconnectDelay ?? 10000,\n      maxReconnectDelay: options.maxReconnectDelay ?? 60000,\n      requestTimeout: options.requestTimeout ?? 30000,\n    };\n\n    // Initialize backoff for reconnection delays\n    this.#newBackoff();\n\n    // Subscribe to authentication and keyring controller events\n    this.#subscribeEvents();\n\n    // Register action handlers using the method actions pattern\n    this.#messenger.registerMethodActionHandlers(\n      this,\n      MESSENGER_EXPOSED_METHODS,\n    );\n  }\n\n  /**\n   * Setup event handling for authentication and wallet lock state\n   *\n   * Three event sources trigger connection/disconnection:\n   * 1. AuthenticationController:stateChange (sign in/out)\n   * 2. KeyringController:unlock (wallet unlocked)\n   * 3. KeyringController:lock (wallet locked)\n   *\n   * All connect() calls are idempotent and validate all requirements.\n   */\n  #subscribeEvents(): void {\n    // Subscribe to authentication state changes (sign in/out)\n    this.#messenger.subscribe(\n      'AuthenticationController:stateChange',\n      (state: AuthenticationController.AuthenticationControllerState) => {\n        if (state.isSignedIn) {\n          // eslint-disable-next-line @typescript-eslint/no-floating-promises\n          this.connect();\n        } else {\n          this.disconnect();\n        }\n      },\n      (state) => ({ isSignedIn: state.isSignedIn }),\n    );\n\n    // Subscribe to wallet unlock event\n    this.#messenger.subscribe('KeyringController:unlock', () => {\n      // eslint-disable-next-line @typescript-eslint/no-floating-promises\n      this.connect();\n    });\n\n    // Subscribe to wallet lock event\n    this.#messenger.subscribe('KeyringController:lock', () => {\n      this.disconnect();\n    });\n  }\n\n  // =============================================================================\n  // 2. PUBLIC API METHODS\n  // =============================================================================\n\n  /**\n   * Establishes WebSocket connection with smart reconnection behavior\n   *\n   * Connection Requirements (all must be true):\n   * 1. Feature enabled (isEnabled() = true)\n   * 2. Wallet unlocked (checked by getBearerToken)\n   * 3. User signed in (checked by getBearerToken)\n   *\n   * Platform code should call this when app opens/foregrounds.\n   * Automatically called on KeyringController:unlock event.\n   *\n   * @returns Promise that resolves when connection is established\n   */\n  async connect(): Promise<void> {\n    // Priority 1: Check if feature is enabled via callback (feature flag check)\n    // If feature is disabled, stop all connection attempts\n    if (this.#isEnabled && !this.#isEnabled()) {\n      // Clear any pending reconnection attempts since feature is disabled\n      this.#clearTimers();\n      this.#reconnectAttempts = 0;\n      return;\n    }\n\n    // If already connected, return immediately\n    if (this.#state === WebSocketState.CONNECTED) {\n      return;\n    }\n\n    // If already connecting, wait for the existing connection attempt to complete\n    if (this.#connectionPromise) {\n      await this.#connectionPromise;\n      return;\n    }\n\n    // If a reconnect is already scheduled, defer to it to avoid bypassing exponential backoff\n    // This prevents rapid loops when server accepts then immediately closes connections\n    if (this.#reconnectTimer) {\n      return;\n    }\n\n    // Create and store the connection promise IMMEDIATELY (before any async operations)\n    // This ensures subsequent connect() calls will wait for this promise instead of creating new connections\n    this.#connectionPromise = (async (): Promise<void> => {\n      // Priority 2: Check authentication requirements (signed in)\n      let bearerToken: string;\n      try {\n        const token = await this.#messenger.call(\n          'AuthenticationController:getBearerToken',\n        );\n        if (!token) {\n          throw new Error('Authentication required: user not signed in');\n        }\n        bearerToken = token;\n      } catch (error) {\n        log('Failed to check authentication requirements', { error });\n        throw error;\n      }\n\n      // Establish the actual WebSocket connection\n      await this.#establishConnection(bearerToken);\n    })();\n\n    try {\n      await this.#connectionPromise;\n    } catch {\n      // Always schedule reconnect on any failure\n      // Exponential backoff will prevent aggressive retries\n      this.#scheduleReconnect();\n    } finally {\n      // Clear the connection promise when done (success or failure)\n      this.#connectionPromise = null;\n    }\n  }\n\n  /**\n   * Closes WebSocket connection\n   */\n  disconnect(): void {\n    if (this.#state === WebSocketState.DISCONNECTED || !this.#ws) {\n      return;\n    }\n\n    // Close WebSocket with manual disconnect code and reason\n    this.#ws.close(MANUAL_DISCONNECT_CODE, MANUAL_DISCONNECT_REASON);\n\n    log('WebSocket manually disconnected');\n  }\n\n  /**\n   * Forces a WebSocket reconnection to clean up subscription state\n   *\n   * This method is useful when subscription state may be out of sync and needs to be reset.\n   * It performs a controlled disconnect-then-reconnect sequence:\n   * - Disconnects cleanly to trigger subscription cleanup\n   * - Schedules reconnection with exponential backoff to prevent rapid loops\n   * - All subscriptions will be cleaned up automatically on disconnect\n   *\n   * Use cases:\n   * - Recovering from subscription/unsubscription issues\n   * - Cleaning up orphaned subscriptions\n   * - Forcing a fresh subscription state\n   *\n   * @returns Promise that resolves when disconnection is complete (reconnection is scheduled)\n   */\n  async forceReconnection(): Promise<void> {\n    if (this.#state === WebSocketState.DISCONNECTED || !this.#ws) {\n      log('WebSocket already disconnected, scheduling reconnect');\n      this.#scheduleReconnect();\n      return;\n    }\n\n    log('Forcing WebSocket reconnection to clean up subscription state');\n\n    // This ensures ws.onclose will schedule a reconnect (not treat it as manual disconnect)\n    this.#ws.close(FORCE_RECONNECT_CODE, FORCE_RECONNECT_REASON);\n  }\n\n  /**\n   * Sends a message through the WebSocket (fire-and-forget, no response expected)\n   *\n   * This is a low-level method for sending messages without waiting for a response.\n   * Most consumers should use `sendRequest()` instead, which handles request-response\n   * correlation and provides proper error handling with timeouts.\n   *\n   * Use this method only when:\n   * - You don't need a response from the server\n   * - You're implementing custom message protocols\n   * - You need fine-grained control over message timing\n   *\n   * @param message - The message to send\n   * @throws Error if WebSocket is not connected or send fails\n   *\n   * @see sendRequest for request-response pattern with automatic correlation\n   */\n  sendMessage(message: ClientRequestMessage): void {\n    if (this.#state !== WebSocketState.CONNECTED || !this.#ws) {\n      throw new Error(`Cannot send message: WebSocket is ${this.#state}`);\n    }\n\n    try {\n      this.#ws.send(JSON.stringify(message));\n    } catch (error) {\n      const errorMessage = getErrorMessage(error);\n      this.#handleError(new Error(errorMessage));\n      throw new Error(errorMessage);\n    }\n  }\n\n  /**\n   * Sends a request and waits for a correlated response (recommended for most use cases)\n   *\n   * This is the recommended high-level method for request-response communication.\n   * It automatically handles:\n   * - Request ID generation and correlation\n   * - Response matching with timeout protection\n   * - Automatic reconnection on timeout\n   * - Proper cleanup of pending requests\n   *\n   * @param message - The request message (can include optional requestId for testing)\n   * @returns Promise that resolves with the response data\n   * @throws Error if WebSocket is not connected, request times out, or response indicates failure\n   *\n   * @see sendMessage for fire-and-forget messaging without response handling\n   */\n  async sendRequest<Type = ServerResponseMessage['data']>(\n    message: Omit<ClientRequestMessage, 'data'> & {\n      data?: Omit<ClientRequestMessage['data'], 'requestId'> & {\n        requestId?: string;\n      };\n    },\n  ): Promise<Type> {\n    if (this.#state !== WebSocketState.CONNECTED) {\n      throw new Error(`Cannot send request: WebSocket is ${this.#state}`);\n    }\n\n    // Use provided requestId if available, otherwise generate a new one\n    const requestId = message.data?.requestId ?? uuidV4();\n    const requestMessage: ClientRequestMessage = {\n      event: message.event,\n      data: {\n        ...message.data,\n        requestId, // Set after spread to ensure it's not overwritten by undefined\n      },\n    };\n\n    return new Promise((resolve, reject) => {\n      const timeout = setTimeout(() => {\n        this.#pendingRequests.delete(requestId);\n        log('Request timeout - triggering reconnection', {\n          timeout: this.#options.requestTimeout,\n        });\n\n        // Trigger reconnection on request timeout as it may indicate stale connection\n        if (this.#state === WebSocketState.CONNECTED && this.#ws) {\n          // Force close the current connection to trigger reconnection logic\n          this.#ws.close(3000, 'Request timeout - forcing reconnect');\n        }\n\n        reject(\n          new Error(`Request timeout after ${this.#options.requestTimeout}ms`),\n        );\n      }, this.#options.requestTimeout);\n\n      // Store in pending requests for response correlation\n      this.#pendingRequests.set(requestId, {\n        resolve: resolve as (value: unknown) => void,\n        reject,\n        timeout,\n      });\n\n      // Send the request\n      try {\n        this.sendMessage(requestMessage);\n      } catch (error) {\n        this.#pendingRequests.delete(requestId);\n        clearTimeout(timeout);\n        reject(error instanceof Error ? error : new Error(String(error)));\n      }\n    });\n  }\n\n  /**\n   * Gets current connection information\n   *\n   * @returns Current connection status and details\n   */\n  getConnectionInfo(): WebSocketConnectionInfo {\n    return {\n      state: this.#state,\n      url: this.#options.url,\n      timeout: this.#options.timeout,\n      reconnectDelay: this.#options.reconnectDelay,\n      maxReconnectDelay: this.#options.maxReconnectDelay,\n      requestTimeout: this.#options.requestTimeout,\n      reconnectAttempts: this.#reconnectAttempts,\n      connectedAt: this.#connectedAt,\n    };\n  }\n\n  /**\n   * Gets all subscription information for a specific channel\n   *\n   * @param channel - The channel name to look up\n   * @returns Array of subscription details for all subscriptions containing the channel\n   */\n  getSubscriptionsByChannel(channel: string): WebSocketSubscription[] {\n    const matchingSubscriptions: WebSocketSubscription[] = [];\n    for (const [subscriptionId, subscription] of this.#subscriptions) {\n      if (subscription.channels.includes(channel)) {\n        matchingSubscriptions.push({\n          subscriptionId,\n          channels: subscription.channels,\n          channelType: subscription.channelType,\n          unsubscribe: subscription.unsubscribe,\n        });\n      }\n    }\n    return matchingSubscriptions;\n  }\n\n  /**\n   * Checks if a channel has a subscription\n   *\n   * @param channel - The channel name to check\n   * @returns True if the channel has a subscription, false otherwise\n   */\n  channelHasSubscription(channel: string): boolean {\n    for (const subscription of this.#subscriptions.values()) {\n      if (subscription.channels.includes(channel)) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  /**\n   * Finds all subscriptions that have channels starting with the specified prefix\n   *\n   * @param channelPrefix - The channel prefix to search for (e.g., \"account-activity.v1\")\n   * @returns Array of subscription info for matching subscriptions\n   */\n  findSubscriptionsByChannelPrefix(\n    channelPrefix: string,\n  ): WebSocketSubscription[] {\n    const matchingSubscriptions: WebSocketSubscription[] = [];\n\n    for (const [subscriptionId, subscription] of this.#subscriptions) {\n      // Check if any channel in this subscription starts with the prefix\n      const hasMatchingChannel = subscription.channels.some((channel) =>\n        channel.startsWith(channelPrefix),\n      );\n\n      if (hasMatchingChannel) {\n        matchingSubscriptions.push({\n          subscriptionId,\n          channels: subscription.channels,\n          channelType: subscription.channelType,\n          unsubscribe: subscription.unsubscribe,\n        });\n      }\n    }\n\n    return matchingSubscriptions;\n  }\n\n  /**\n   * Register a callback for specific channels (local callback only, no server subscription)\n   *\n   * **Key Difference from `subscribe()`:**\n   * - `addChannelCallback()`: Registers a local callback without creating a server-side subscription.\n   * The callback triggers on ANY message matching the channel name, regardless of subscriptionId.\n   * Useful for system-wide notifications or when you don't control the subscription lifecycle.\n   *\n   * - `subscribe()`: Creates a proper server-side subscription with a subscriptionId.\n   * The callback only triggers for messages with the matching subscriptionId.\n   * Includes proper lifecycle management (unsubscribe, automatic cleanup on disconnect).\n   *\n   * **When to use `addChannelCallback()`:**\n   * - Listening to system-wide notifications (e.g., 'system-notifications.v1')\n   * - Monitoring channels where subscriptions are managed elsewhere\n   * - Debug/logging scenarios where you want to observe all channel messages\n   *\n   * **When to use `subscribe()` instead:**\n   * - Creating new subscriptions that need server-side registration\n   * - When you need proper cleanup via unsubscribe\n   * - Most application use cases (recommended approach)\n   *\n   * @param options - Channel callback configuration\n   * @param options.channelName - Channel name to match exactly\n   * @param options.callback - Function to call when channel matches\n   *\n   * @example\n   * ```typescript\n   * // Listen to system notifications (no server subscription needed)\n   * webSocketService.addChannelCallback({\n   *   channelName: 'system-notifications.v1',\n   *   callback: (notification) => {\n   *     console.log('System notification:', notification.data);\n   *   }\n   * });\n   *\n   * // For account-specific subscriptions, use subscribe() instead:\n   * // const sub = await webSocketService.subscribe({\n   * //   channels: ['account-activity.v1.eip155:0:0x1234...'],\n   * //   callback: (notification) => { ... }\n   * // });\n   * ```\n   *\n   * @see subscribe for creating proper server-side subscriptions with lifecycle management\n   */\n  addChannelCallback(options: {\n    channelName: string;\n    callback: (notification: ServerNotificationMessage) => void;\n  }): void {\n    const channelCallback: ChannelCallback = {\n      channelName: options.channelName,\n      callback: options.callback,\n    };\n\n    // Check if callback already exists for this channel\n    if (this.#channelCallbacks.has(options.channelName)) {\n      return;\n    }\n\n    this.#channelCallbacks.set(options.channelName, channelCallback);\n  }\n\n  /**\n   * Remove a channel callback\n   *\n   * @param channelName - The channel name returned from addChannelCallback\n   * @returns True if callback was found and removed, false otherwise\n   */\n  removeChannelCallback(channelName: string): boolean {\n    return this.#channelCallbacks.delete(channelName);\n  }\n\n  /**\n   * Get all registered channel callbacks (for debugging)\n   *\n   * @returns Array of all registered channel callbacks\n   */\n  getChannelCallbacks(): ChannelCallback[] {\n    return Array.from(this.#channelCallbacks.values());\n  }\n\n  /**\n   * Destroy the service and clean up resources\n   * Called when service is being destroyed or app is terminating\n   */\n  destroy(): void {\n    // Always clear timers first to prevent reconnection attempts after destruction\n    // This handles the case where destroy() is called while DISCONNECTED with a pending reconnect timer\n    this.#clearTimers();\n\n    // Reset reconnect attempts to prevent any future reconnection logic\n    this.#reconnectAttempts = 0;\n\n    // Disconnect the WebSocket if connected (will be no-op if already disconnected)\n    this.disconnect();\n  }\n\n  /**\n   * Create and manage a subscription with server-side registration (recommended for most use cases)\n   *\n   * This is the recommended subscription API for high-level services. It creates a proper\n   * server-side subscription and routes notifications based on subscriptionId.\n   *\n   * **Key Features:**\n   * - Creates server-side subscription with unique subscriptionId\n   * - Callback triggered only for messages with matching subscriptionId\n   * - Automatic lifecycle management (cleanup on disconnect)\n   * - Includes unsubscribe method for proper cleanup\n   * - Request-response pattern with error handling\n   *\n   * **When to use `subscribe()`:**\n   * - Creating new subscriptions (account activity, price updates, etc.)\n   * - When you need proper cleanup/unsubscribe functionality\n   * - Most application use cases\n   *\n   * **When to use `addChannelCallback()` instead:**\n   * - System-wide notifications without server-side subscription\n   * - Observing channels managed elsewhere\n   * - Debug/logging scenarios\n   *\n   * @param options - Subscription configuration\n   * @param options.channels - Array of channel names to subscribe to\n   * @param options.callback - Callback function for handling notifications\n   * @param options.requestId - Optional request ID for testing (will generate UUID if not provided)\n   * @param options.channelType - Channel type identifier\n   * @returns Subscription object with unsubscribe method\n   *\n   * @example\n   * ```typescript\n   * // AccountActivityService usage\n   * const subscription = await webSocketService.subscribe({\n   *   channels: ['account-activity.v1.eip155:0:0x1234...'],\n   *   callback: (notification) => {\n   *     this.handleAccountActivity(notification.data);\n   *   }\n   * });\n   *\n   * // Later, clean up\n   * await subscription.unsubscribe();\n   * ```\n   *\n   * @see addChannelCallback for local callbacks without server-side subscription\n   */\n  async subscribe(options: {\n    /** Channel names to subscribe to */\n    channels: string[];\n    /** Channel type with version (e.g., 'account-activity.v1') for tracing and monitoring */\n    channelType: string;\n    /** Handler for incoming notifications */\n    callback: (notification: ServerNotificationMessage) => void;\n    /** Optional request ID for testing (will generate UUID if not provided) */\n    requestId?: string;\n  }): Promise<WebSocketSubscription> {\n    const { channels, channelType, callback, requestId } = options;\n\n    if (this.#state !== WebSocketState.CONNECTED) {\n      throw new Error(\n        `Cannot create subscription(s) ${channels.join(', ')}: WebSocket is ${this.#state}`,\n      );\n    }\n\n    // Send subscription request and wait for response\n    const subscriptionResponse = await this.sendRequest({\n      event: 'subscribe',\n      data: { channels, requestId },\n    });\n\n    if (!subscriptionResponse?.subscriptionId) {\n      throw new Error('Invalid subscription response: missing subscription ID');\n    }\n\n    const { subscriptionId } = subscriptionResponse;\n\n    // Create unsubscribe function\n    const unsubscribe = async (unsubRequestId?: string): Promise<void> => {\n      // Send unsubscribe request first\n      await this.sendRequest({\n        event: 'unsubscribe',\n        data: {\n          subscription: subscriptionId,\n          channels,\n          requestId: unsubRequestId,\n        },\n      });\n\n      // Clean up subscription mapping\n      this.#subscriptions.delete(subscriptionId);\n    };\n\n    const subscription = {\n      subscriptionId,\n      channels: [...channels],\n      channelType,\n      unsubscribe,\n    };\n\n    // Store subscription with subscription ID as key\n    this.#subscriptions.set(subscriptionId, {\n      subscriptionId,\n      channels: [...channels], // Store copy of channels\n      channelType,\n      callback,\n      unsubscribe,\n    });\n\n    return subscription;\n  }\n\n  // =============================================================================\n  // 3. CONNECTION MANAGEMENT (PRIVATE)\n  // =============================================================================\n\n  /**\n   * Builds an authenticated WebSocket URL with bearer token as query parameter.\n   * Uses query parameter for WebSocket authentication since native WebSocket\n   * doesn't support custom headers during handshake.\n   *\n   * @param bearerToken - The bearer token to use for authentication\n   * @returns The authenticated WebSocket URL\n   */\n  #buildAuthenticatedUrl(bearerToken: string): string {\n    const baseUrl = this.#options.url;\n\n    // Add token as query parameter to the WebSocket URL\n    const url = new URL(baseUrl);\n    url.searchParams.set('token', bearerToken);\n\n    return url.toString();\n  }\n\n  /**\n   * Establishes the actual WebSocket connection\n   *\n   * @param bearerToken - The bearer token to use for authentication\n   * @returns Promise that resolves when connection is established\n   */\n  async #establishConnection(bearerToken: string): Promise<void> {\n    const wsUrl = this.#buildAuthenticatedUrl(bearerToken);\n\n    // Transition to CONNECTING state before creating WebSocket\n    this.#setState(WebSocketState.CONNECTING);\n    return this.#trace(\n      {\n        name: `${SERVICE_NAME} Connection`,\n        data: {\n          reconnectAttempt: this.#reconnectAttempts,\n        },\n        tags: {\n          service: SERVICE_NAME,\n        },\n      },\n      () => {\n        return new Promise<void>((resolve, reject) => {\n          // eslint-disable-next-line no-restricted-globals\n          const ws = new WebSocket(wsUrl);\n          this.#connectionTimeout = setTimeout(() => {\n            log('WebSocket connection timeout - forcing close', {\n              timeout: this.#options.timeout,\n            });\n            // Close the WebSocket - onclose will handle rejection and state change\n            ws.close();\n          }, this.#options.timeout);\n\n          ws.onopen = (): void => {\n            if (this.#connectionTimeout) {\n              clearTimeout(this.#connectionTimeout);\n              this.#connectionTimeout = null;\n            }\n\n            this.#ws = ws;\n            this.#setState(WebSocketState.CONNECTED);\n            this.#connectedAt = Date.now();\n\n            // Only reset after connection stays stable for a period (10 seconds)\n            // This prevents rapid reconnect loops when server accepts then immediately closes\n            this.#stableConnectionTimer = setTimeout(() => {\n              this.#stableConnectionTimer = null;\n              this.#reconnectAttempts = 0;\n              // Create new backoff sequence for fresh start on next disconnect\n              this.#newBackoff();\n              log('Connection stable - reset reconnect attempts and backoff');\n            }, 10000);\n\n            resolve();\n          };\n\n          ws.onclose = (event: CloseEvent): void => {\n            log('WebSocket onclose event triggered', {\n              code: event.code,\n              reason: event.reason || getCloseReason(event.code),\n              wasClean: event.wasClean,\n            });\n\n            // Guard against duplicate close events\n            if (this.#state === WebSocketState.DISCONNECTED) {\n              return;\n            }\n\n            // Detect if this is a manual disconnect or service cleanup based on close code\n            const isManualDisconnect =\n              event.code === MANUAL_DISCONNECT_CODE &&\n              event.reason === MANUAL_DISCONNECT_REASON;\n\n            // If connection hasn't been established yet, handle the connection promise\n            if (this.#state === WebSocketState.CONNECTING) {\n              if (isManualDisconnect) {\n                // Manual disconnect during connection - resolve to prevent reconnection\n                resolve();\n              } else {\n                // Failed connection attempt - reject to trigger reconnection\n                reject(\n                  new Error(\n                    `WebSocket connection closed during connection: ${event.code} ${event.reason}`,\n                  ),\n                );\n              }\n            }\n\n            // Calculate connection duration before we clear state (only if we were connected)\n            const connectionDurationMs =\n              this.#connectedAt > 0 ? Date.now() - this.#connectedAt : 0;\n\n            // Clear all timers\n            this.#clearTimers();\n\n            // Clear WebSocket reference to allow garbage collection\n            this.#ws = undefined;\n\n            // Clear connection tracking\n            this.#connectionPromise = null;\n            this.#connectedAt = 0;\n\n            this.#clearPendingRequests(\n              new Error(\n                `WebSocket connection closed: ${event.code} ${event.reason || getCloseReason(event.code)}`,\n              ),\n            );\n            this.#clearSubscriptions();\n\n            // Update state to disconnected\n            this.#setState(WebSocketState.DISCONNECTED);\n\n            // Check if this was a manual disconnect\n            if (isManualDisconnect) {\n              // Manual disconnect - reset attempts and don't reconnect\n              this.#reconnectAttempts = 0;\n            } else {\n              // Unexpected disconnect - schedule reconnection\n              this.#scheduleReconnect();\n            }\n\n            // eslint-disable-next-line @typescript-eslint/no-floating-promises\n            this.#trace({\n              name: `${SERVICE_NAME} Disconnection`,\n              data: {\n                code: event.code,\n                reason: event.reason || getCloseReason(event.code),\n                wasClean: event.wasClean,\n                reconnectAttempts: this.#reconnectAttempts,\n                ...(connectionDurationMs > 0 && {\n                  connectionDuration_ms: connectionDurationMs,\n                }),\n              },\n              tags: {\n                service: SERVICE_NAME,\n              },\n            });\n          };\n\n          // Set up message handler immediately - no need to wait for connection\n          ws.onmessage = (event: MessageEvent): void => {\n            try {\n              const message = this.#parseMessage(event.data);\n              this.#handleMessage(message);\n            } catch {\n              // Silently ignore invalid JSON messages\n            }\n          };\n        });\n      },\n    );\n  }\n\n  // =============================================================================\n  // 4. MESSAGE HANDLING (PRIVATE)\n  // =============================================================================\n\n  /**\n   * Handles incoming WebSocket messages\n   *\n   * @param message - The WebSocket message to handle\n   */\n  #handleMessage(message: WebSocketMessage): void {\n    // Handle server responses (correlated with requests) first\n    if (this.#isServerResponse(message)) {\n      this.#handleServerResponse(message);\n      return;\n    }\n\n    // Handle subscription notifications with valid subscriptionId\n    if (this.#isSubscriptionNotification(message)) {\n      const notificationMsg = message as ServerNotificationMessage;\n      const handled = this.#handleSubscriptionNotification(notificationMsg);\n      // If subscription notification wasn't handled (falsy subscriptionId), fall through to channel handling\n      if (handled) {\n        return;\n      }\n    }\n\n    // Trigger channel callbacks for any message with a channel property\n    if (this.#isChannelMessage(message)) {\n      const channelMsg = message;\n      this.#handleChannelMessage(channelMsg);\n    }\n  }\n\n  /**\n   * Checks if a message is a server response (correlated with client requests)\n   *\n   * @param message - The message to check\n   * @returns True if the message is a server response\n   */\n  #isServerResponse(\n    message: WebSocketMessage,\n  ): message is ServerResponseMessage {\n    return (\n      'data' in message &&\n      message.data &&\n      typeof message.data === 'object' &&\n      'requestId' in message.data\n    );\n  }\n\n  /**\n   * Checks if a message is a subscription notification (has subscriptionId)\n   *\n   * @param message - The message to check\n   * @returns True if the message is a subscription notification with subscriptionId\n   */\n  #isSubscriptionNotification(message: WebSocketMessage): boolean {\n    return 'subscriptionId' in message && !this.#isServerResponse(message);\n  }\n\n  /**\n   * Checks if a message has a channel property (system or subscription notification)\n   *\n   * @param message - The message to check\n   * @returns True if the message has a channel property\n   */\n  #isChannelMessage(\n    message: WebSocketMessage,\n  ): message is ServerNotificationMessage {\n    return 'channel' in message;\n  }\n\n  /**\n   * Handles server response messages (correlated with client requests)\n   *\n   * @param message - The server response message to handle\n   */\n  #handleServerResponse(message: ServerResponseMessage): void {\n    const { requestId } = message.data;\n\n    const request = this.#pendingRequests.get(requestId);\n    if (!request) {\n      return;\n    }\n\n    this.#pendingRequests.delete(requestId);\n    clearTimeout(request.timeout);\n\n    // Check if the response indicates failure\n    if (message.data.failed && message.data.failed.length > 0) {\n      request.reject(\n        new Error(`Request failed: ${message.data.failed.join(', ')}`),\n      );\n    } else {\n      request.resolve(message.data);\n    }\n  }\n\n  /**\n   * Handles messages with channel properties by triggering channel callbacks\n   *\n   * @param message - The message with channel property to handle\n   */\n  #handleChannelMessage(message: ServerNotificationMessage): void {\n    if (this.#channelCallbacks.size === 0) {\n      return;\n    }\n\n    this.#channelCallbacks.get(message.channel)?.callback(message);\n  }\n\n  /**\n   * Handles server notifications with subscription IDs\n   *\n   * @param message - The server notification message to handle\n   * @returns True if the message was handled, false if it should fall through to channel handling\n   */\n  #handleSubscriptionNotification(message: ServerNotificationMessage): boolean {\n    const { subscriptionId, timestamp, channel } = message;\n\n    // Only handle if subscriptionId is defined and not null (allows \"0\" as valid ID)\n    if (subscriptionId !== null && subscriptionId !== undefined) {\n      const subscription = this.#subscriptions.get(subscriptionId);\n      if (!subscription) {\n        return false;\n      }\n\n      // Calculate notification latency: time from server sent to client received\n      const receivedAt = Date.now();\n      const latency = receivedAt - timestamp;\n\n      // Trace notification processing wi th latency data\n      // Use stored channelType instead of parsing each time\n      // Promise result intentionally not awaited\n      // eslint-disable-next-line @typescript-eslint/no-floating-promises\n      this.#trace(\n        {\n          name: `${SERVICE_NAME} Notification`,\n          data: {\n            channel,\n            latency_ms: latency,\n            subscriptionId,\n          },\n          tags: {\n            service: SERVICE_NAME,\n            notification_type: subscription.channelType,\n          },\n        },\n        () => {\n          subscription.callback?.(message);\n        },\n      );\n      return true;\n    }\n\n    return false;\n  }\n\n  /**\n   * Parse WebSocket message data\n   *\n   * @param data - The raw message data to parse\n   * @returns Parsed message\n   */\n  #parseMessage(data: string): WebSocketMessage {\n    return JSON.parse(data);\n  }\n\n  // =============================================================================\n  // 5. EVENT HANDLERS (PRIVATE)\n  // =============================================================================\n\n  /**\n   * Handles WebSocket errors\n   *\n   * @param _error - Error that occurred (unused)\n   */\n  #handleError(_error: Error): void {\n    // Placeholder for future error handling logic\n  }\n\n  // =============================================================================\n  // 6. STATE MANAGEMENT (PRIVATE)\n  // =============================================================================\n\n  /**\n   * Schedules a connection attempt with exponential backoff and jitter\n   *\n   * This method is used for automatic reconnection with Cockatiel's exponential backoff:\n   * - Prevents duplicate reconnection timers (idempotent)\n   * - Applies exponential backoff with jitter based on previous failures\n   * - Jitter uses decorrelated formula to prevent thundering herd problem\n   * - Used ONLY for automatic retries, not user-initiated actions\n   *\n   * Call this from:\n   * - connect() catch block (on connection failure)\n   * - ws.onclose handler (on unexpected disconnect)\n   *\n   * For user-initiated actions (sign in, unlock), call connect() directly instead.\n   *\n   * If a reconnect is already scheduled, this is a no-op to prevent:\n   * - Orphaned timers (memory leak)\n   * - Inflated reconnect attempts counter\n   * - Prematurely long delays\n   */\n  #scheduleReconnect(): void {\n    // If a reconnect is already scheduled, don't schedule another one\n    if (this.#reconnectTimer) {\n      return;\n    }\n\n    // Increment attempts BEFORE calculating delay so backoff grows properly\n    this.#reconnectAttempts += 1;\n\n    // Use Cockatiel's exponential backoff to get delay with jitter\n    const delay = this.#backoff.duration;\n\n    // Progress to next backoff state for future reconnect attempts\n    // Pass attempt number as context (though ExponentialBackoff doesn't use it)\n    this.#backoff = this.#backoff.next({ attempt: this.#reconnectAttempts });\n\n    log('Scheduling reconnect', {\n      attempt: this.#reconnectAttempts,\n      delay_ms: delay,\n    });\n\n    this.#reconnectTimer = setTimeout(() => {\n      // Clear timer reference first\n      this.#reconnectTimer = null;\n\n      // Check if connection is still enabled before reconnecting\n      if (this.#isEnabled && !this.#isEnabled()) {\n        this.#reconnectAttempts = 0;\n        // Create new backoff sequence when disabled\n        this.#newBackoff();\n        return;\n      }\n\n      // eslint-disable-next-line @typescript-eslint/no-floating-promises\n      this.connect();\n    }, delay);\n  }\n\n  /**\n   * Creates a new exponential backoff sequence\n   */\n  #newBackoff(): void {\n    this.#backoff = new ExponentialBackoff({\n      initialDelay: this.#options.reconnectDelay,\n      maxDelay: this.#options.maxReconnectDelay,\n    }).next();\n  }\n\n  #clearTimers(): void {\n    if (this.#reconnectTimer) {\n      clearTimeout(this.#reconnectTimer);\n      this.#reconnectTimer = null;\n    }\n    if (this.#connectionTimeout) {\n      clearTimeout(this.#connectionTimeout);\n      this.#connectionTimeout = null;\n    }\n    if (this.#stableConnectionTimer) {\n      clearTimeout(this.#stableConnectionTimer);\n      this.#stableConnectionTimer = null;\n    }\n  }\n\n  /**\n   * Clears all pending requests and rejects them with the given error\n   *\n   * @param error - Error to reject with\n   */\n  #clearPendingRequests(error: Error): void {\n    for (const [, request] of this.#pendingRequests) {\n      clearTimeout(request.timeout);\n      request.reject(error);\n    }\n    this.#pendingRequests.clear();\n  }\n\n  /**\n   * Clears all active subscriptions\n   */\n  #clearSubscriptions(): void {\n    this.#subscriptions.clear();\n  }\n\n  /**\n   * Sets the connection state and emits state change events\n   *\n   * @param newState - The new WebSocket state\n   */\n  #setState(newState: WebSocketState): void {\n    const oldState = this.#state;\n    this.#state = newState;\n\n    if (oldState !== newState) {\n      // Publish connection state change event\n      // Messenger handles listener errors internally, no need for try-catch\n      this.#messenger.publish(\n        'BackendWebSocketService:connectionStateChanged',\n        this.getConnectionInfo(),\n      );\n    }\n  }\n}\n"]}