{"version":3,"file":"BackendWebSocketService.cjs","sourceRoot":"","sources":["../src/BackendWebSocketService.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RestrictedMessenger } from '@metamask/base-controller';\nimport type { AuthenticationController } from '@metamask/profile-sync-controller';\nimport { getErrorMessage } from '@metamask/utils';\nimport { v4 as uuidV4 } from 'uuid';\n\nimport type { BackendWebSocketServiceMethodActions } from './BackendWebSocketService-method-action-types';\nimport { projectLogger, createModuleLogger } from './logger';\n\nconst SERVICE_NAME = 'BackendWebSocketService' as const;\n\nconst log = createModuleLogger(projectLogger, SERVICE_NAME);\n\nconst MESSENGER_EXPOSED_METHODS = [\n  'connect',\n  'disconnect',\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  DISCONNECTING = 'disconnecting',\n  DISCONNECTED = 'disconnected',\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: 500) */\n  reconnectDelay?: number;\n\n  /** Maximum reconnection delay in milliseconds (default: 5000) */\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\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};\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  /** 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  connectedAt?: number;\n};\n\n// Action types for the messaging system - using generated method actions\nexport type BackendWebSocketServiceActions =\n  BackendWebSocketServiceMethodActions;\n\nexport type BackendWebSocketServiceAllowedActions =\n  | AuthenticationController.AuthenticationControllerGetBearerToken\n  | BackendWebSocketServiceMethodActions;\n\nexport type BackendWebSocketServiceAllowedEvents =\n  | AuthenticationController.AuthenticationControllerStateChangeEvent\n  | BackendWebSocketServiceConnectionStateChangedEvent;\n\n// Event types for WebSocket connection state changes\nexport type BackendWebSocketServiceConnectionStateChangedEvent = {\n  type: 'BackendWebSocketService:connectionStateChanged';\n  payload: [WebSocketConnectionInfo];\n};\n\nexport type BackendWebSocketServiceEvents =\n  BackendWebSocketServiceConnectionStateChangedEvent;\n\nexport type BackendWebSocketServiceMessenger = RestrictedMessenger<\n  typeof SERVICE_NAME,\n  BackendWebSocketServiceActions | BackendWebSocketServiceAllowedActions,\n  BackendWebSocketServiceEvents | BackendWebSocketServiceAllowedEvents,\n  BackendWebSocketServiceAllowedActions['type'],\n  BackendWebSocketServiceAllowedEvents['type']\n>;\n\n/**\n * WebSocket Service with automatic reconnection, session management and direct callback routing\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 *\n * Mobile Integration:\n * Mobile apps should handle lifecycle events (background/foreground) by:\n * 1. Calling disconnect() when app goes to background\n * 2. Calling connect() when app returns to foreground\n * 3. Calling destroy() on app termination\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'>\n  >;\n\n  readonly #isEnabled: (() => boolean) | undefined;\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  // 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 | null = null;\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  // =============================================================================\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\n    this.#options = {\n      url: options.url,\n      timeout: options.timeout ?? 10000,\n      reconnectDelay: options.reconnectDelay ?? 500,\n      maxReconnectDelay: options.maxReconnectDelay ?? 5000,\n      requestTimeout: options.requestTimeout ?? 30000,\n    };\n\n    // Setup authentication (always enabled)\n    this.#setupAuthentication();\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 authentication event handling - simplified approach using AuthenticationController\n   * AuthenticationController.isSignedIn includes both wallet unlock AND identity provider auth.\n   * App lifecycle (AppStateWebSocketManager) handles WHEN to connect/disconnect for resources.\n   *\n   */\n  #setupAuthentication(): void {\n    try {\n      // Subscribe to authentication state changes - this includes wallet unlock state\n      // AuthenticationController can only be signed in if wallet is unlocked\n      // Using selector to only listen for isSignedIn property changes for better performance\n      this.#messenger.subscribe(\n        'AuthenticationController:stateChange',\n        (isSignedIn: boolean) => {\n          if (isSignedIn) {\n            // User signed in (wallet unlocked + authenticated) - try to connect\n            // Clear any pending reconnection timer since we're attempting connection\n            this.#clearTimers();\n            this.connect().catch((error) => {\n              log('Failed to connect after sign-in', { error });\n            });\n          } else {\n            // User signed out (wallet locked OR signed out) - disconnect and stop reconnection attempts\n            this.#clearTimers();\n            this.#reconnectAttempts = 0;\n            this.disconnect().catch((error) => {\n              log('Failed to disconnect after sign-out', { error });\n            });\n          }\n        },\n        (state: AuthenticationController.AuthenticationControllerState) =>\n          state.isSignedIn,\n      );\n    } catch (error) {\n      throw new Error(`Authentication setup failed: ${getErrorMessage(error)}`);\n    }\n  }\n\n  // =============================================================================\n  // 2. PUBLIC API METHODS\n  // =============================================================================\n\n  /**\n   * Establishes WebSocket connection with smart reconnection behavior\n   *\n   * Simplified Priority System (using AuthenticationController):\n   * 1. App closed/backgrounded → Stop all attempts (save resources)\n   * 2. User not signed in (wallet locked OR not authenticated) → Keep retrying\n   * 3. User signed in (wallet unlocked + authenticated) → Connect successfully\n   *\n   * @returns Promise that resolves when connection is established\n   */\n  async connect(): Promise<void> {\n    // Priority 1: Check if connection is enabled via callback (app lifecycle check)\n    // If app is closed/backgrounded, stop all connection attempts to save resources\n    if (this.#isEnabled && !this.#isEnabled()) {\n      // Clear any pending reconnection attempts since app 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.#state === WebSocketState.CONNECTING && this.#connectionPromise) {\n      await this.#connectionPromise;\n      return;\n    }\n\n    // Priority 2: Check authentication requirements (simplified - just check if signed in)\n    let bearerToken: string;\n    try {\n      // AuthenticationController.getBearerToken() handles wallet unlock checks internally\n      const token = await this.#messenger.call(\n        'AuthenticationController:getBearerToken',\n      );\n      if (!token) {\n        this.#scheduleReconnect();\n        return;\n      }\n      bearerToken = token;\n    } catch (error) {\n      log('Failed to check authentication requirements', { error });\n\n      // If we can't connect for ANY reason, schedule a retry\n      this.#scheduleReconnect();\n      return;\n    }\n\n    this.#setState(WebSocketState.CONNECTING);\n\n    // Create and store the connection promise\n    this.#connectionPromise = this.#establishConnection(bearerToken);\n\n    try {\n      await this.#connectionPromise;\n    } catch (error) {\n      const errorMessage = getErrorMessage(error);\n      log('Connection attempt failed', { errorMessage, error });\n      this.#setState(WebSocketState.ERROR);\n\n      throw new Error(`Failed to connect to WebSocket: ${errorMessage}`);\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   * @returns Promise that resolves when disconnection is complete\n   */\n  async disconnect(): Promise<void> {\n    if (\n      this.#state === WebSocketState.DISCONNECTED ||\n      this.#state === WebSocketState.DISCONNECTING\n    ) {\n      return;\n    }\n\n    this.#setState(WebSocketState.DISCONNECTING);\n    this.#clearTimers();\n    this.#clearPendingRequests(new Error('WebSocket disconnected'));\n\n    // Clear any pending connection promise\n    this.#connectionPromise = null;\n\n    if (this.#ws) {\n      this.#ws.close(1000, 'Normal closure');\n    }\n\n    this.#setState(WebSocketState.DISCONNECTED);\n    log('WebSocket manually disconnected');\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<T = ServerResponseMessage['data']>(\n    message: Omit<ClientRequestMessage, 'data'> & {\n      data?: Omit<ClientRequestMessage['data'], 'requestId'> & {\n        requestId?: string;\n      };\n    },\n  ): Promise<T> {\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      reconnectAttempts: this.#reconnectAttempts,\n      connectedAt: this.#connectedAt ?? undefined,\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          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          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    this.#clearTimers();\n    this.#clearSubscriptions();\n\n    // Clear any pending connection promise\n    this.#connectionPromise = null;\n\n    // Clear all pending requests\n    this.#clearPendingRequests(new Error('Service cleanup'));\n\n    if (this.#ws && this.#ws.readyState === WebSocket.OPEN) {\n      this.#ws.close(1000, 'Service cleanup');\n    }\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   * @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    /** 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, 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    // Check for failures\n    if (subscriptionResponse.failed && subscriptionResponse.failed.length > 0) {\n      throw new Error(\n        `Subscription failed for channels: ${subscriptionResponse.failed.join(', ')}`,\n      );\n    }\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      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      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    return new Promise((resolve, reject) => {\n      const ws = new WebSocket(wsUrl);\n      this.#connectionTimeout = setTimeout(() => {\n        log('WebSocket connection timeout - forcing close', {\n          timeout: this.#options.timeout,\n        });\n        ws.close();\n        reject(\n          new Error(`Connection timeout after ${this.#options.timeout}ms`),\n        );\n      }, this.#options.timeout);\n\n      ws.onopen = () => {\n        if (this.#connectionTimeout) {\n          clearTimeout(this.#connectionTimeout);\n          this.#connectionTimeout = null;\n        }\n        this.#ws = ws;\n        this.#setState(WebSocketState.CONNECTED);\n        this.#connectedAt = Date.now();\n\n        // Reset reconnect attempts on successful connection\n        this.#reconnectAttempts = 0;\n\n        resolve();\n      };\n\n      ws.onerror = (event: Event) => {\n        log('WebSocket onerror event triggered', { event });\n        if (this.#state === WebSocketState.CONNECTING) {\n          // Handle connection-phase errors\n          if (this.#connectionTimeout) {\n            clearTimeout(this.#connectionTimeout);\n            this.#connectionTimeout = null;\n          }\n          const error = new Error(`WebSocket connection error to ${wsUrl}`);\n          reject(error);\n        } else {\n          // Handle runtime errors\n          this.#handleError(new Error(`WebSocket error: ${event.type}`));\n        }\n      };\n\n      ws.onclose = (event: CloseEvent) => {\n        log('WebSocket onclose event triggered', {\n          code: event.code,\n          reason: event.reason || 'none',\n          wasClean: event.wasClean,\n        });\n        if (this.#state === WebSocketState.CONNECTING) {\n          // Handle connection-phase close events\n          if (this.#connectionTimeout) {\n            clearTimeout(this.#connectionTimeout);\n            this.#connectionTimeout = null;\n          }\n          reject(\n            new Error(\n              `WebSocket connection closed during connection: ${event.code} ${event.reason}`,\n            ),\n          );\n        } else {\n          this.#handleClose(event);\n        }\n      };\n\n      // Set up message handler immediately - no need to wait for connection\n      ws.onmessage = (event: MessageEvent) => {\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  // 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 handled = this.#handleSubscriptionNotification(\n        message as ServerNotificationMessage,\n      );\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      this.#handleChannelMessage(message);\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    // Direct lookup for exact channel match\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 } = message;\n\n    // Only handle if subscriptionId is defined and not null (allows \"0\" as valid ID)\n    if (subscriptionId !== null && subscriptionId !== undefined) {\n      this.#subscriptions.get(subscriptionId)?.callback?.(message);\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 close events (mobile optimized)\n   *\n   * @param event - The WebSocket close event\n   */\n  #handleClose(event: CloseEvent): void {\n    this.#clearTimers();\n    this.#connectedAt = null;\n\n    // Clear any pending connection promise\n    this.#connectionPromise = null;\n\n    // Clear subscriptions and pending requests on any disconnect\n    // This ensures clean state for reconnection\n    this.#clearPendingRequests(new Error('WebSocket connection closed'));\n    this.#clearSubscriptions();\n\n    if (this.#state === WebSocketState.DISCONNECTING) {\n      // Manual disconnect\n      this.#setState(WebSocketState.DISCONNECTED);\n      return;\n    }\n\n    // For unexpected disconnects, update the state to reflect that we're disconnected\n    this.#setState(WebSocketState.DISCONNECTED);\n\n    // Check if we should attempt reconnection based on close code\n    const shouldReconnect = this.#shouldReconnectOnClose(event.code);\n\n    if (shouldReconnect) {\n      log('Connection lost unexpectedly, will attempt reconnection', {\n        code: event.code,\n      });\n      this.#scheduleReconnect();\n    }\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 reconnection attempt with exponential backoff\n   */\n  #scheduleReconnect(): void {\n    this.#reconnectAttempts += 1;\n\n    const rawDelay =\n      this.#options.reconnectDelay * Math.pow(1.5, this.#reconnectAttempts - 1);\n    const delay = Math.min(rawDelay, this.#options.maxReconnectDelay);\n\n    log('Scheduling reconnection attempt', {\n      attempt: this.#reconnectAttempts,\n      delayMs: 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        log('Reconnection disabled by isEnabled - stopping all attempts');\n        this.#reconnectAttempts = 0;\n        return;\n      }\n\n      // Attempt to reconnect - if it fails, schedule another attempt\n      this.connect().catch(() => {\n        this.#scheduleReconnect();\n      });\n    }, delay);\n  }\n\n  /**\n   * Clears all active timers\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  }\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      log('WebSocket state changed', { oldState, newState });\n\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  // =============================================================================\n  // 7. UTILITY METHODS (PRIVATE)\n  // =============================================================================\n\n  /**\n   * Determines if reconnection should be attempted based on close code\n   *\n   * @param code - WebSocket close code\n   * @returns True if reconnection should be attempted\n   */\n  #shouldReconnectOnClose(code: number): boolean {\n    // Don't reconnect only on normal closure (manual disconnect)\n    return code !== 1000;\n  }\n}\n"]}