import type { RestrictedMessenger } from "@metamask/base-controller"; import type { AuthenticationController } from "@metamask/profile-sync-controller"; import type { BackendWebSocketServiceMethodActions } from "./BackendWebSocketService-method-action-types.mjs"; declare const SERVICE_NAME: "BackendWebSocketService"; /** * Gets human-readable close reason from RFC 6455 close code * * @param code - WebSocket close code * @returns Human-readable close reason */ export declare function getCloseReason(code: number): string; /** * WebSocket connection states */ export declare enum WebSocketState { CONNECTING = "connecting", CONNECTED = "connected", DISCONNECTING = "disconnecting", DISCONNECTED = "disconnected", ERROR = "error" } /** * WebSocket event types */ export declare enum WebSocketEventType { CONNECTED = "connected", DISCONNECTED = "disconnected", MESSAGE = "message", ERROR = "error", RECONNECTING = "reconnecting", RECONNECTED = "reconnected" } /** * Configuration options for the WebSocket service */ export type BackendWebSocketServiceOptions = { /** The WebSocket URL to connect to */ url: string; /** The messenger for inter-service communication */ messenger: BackendWebSocketServiceMessenger; /** Connection timeout in milliseconds (default: 10000) */ timeout?: number; /** Initial reconnection delay in milliseconds (default: 500) */ reconnectDelay?: number; /** Maximum reconnection delay in milliseconds (default: 5000) */ maxReconnectDelay?: number; /** Request timeout in milliseconds (default: 30000) */ requestTimeout?: number; /** Optional callback to determine if connection should be enabled (default: always enabled) */ isEnabled?: () => boolean; }; /** * Client Request message * Used when client sends a request to the server */ export type ClientRequestMessage = { event: string; data: { requestId: string; channels?: string[]; [key: string]: unknown; }; }; /** * Server Response message * Used when server responds to a client request */ export type ServerResponseMessage = { event: string; data: { requestId: string; subscriptionId?: string; succeeded?: string[]; failed?: string[]; [key: string]: unknown; }; }; /** * Server Notification message * Used when server sends unsolicited data to client * subscriptionId is optional for system-wide notifications */ export type ServerNotificationMessage = { event: string; subscriptionId?: string; channel: string; data: Record; }; /** * Union type for all WebSocket messages */ export type WebSocketMessage = ClientRequestMessage | ServerResponseMessage | ServerNotificationMessage; /** * Channel-based callback configuration */ export type ChannelCallback = { /** Channel name to match (also serves as the unique identifier) */ channelName: string; /** Callback function */ callback: (notification: ServerNotificationMessage) => void; }; /** * Unified WebSocket subscription object used for both internal storage and external API */ export type WebSocketSubscription = { /** The subscription ID from the server */ subscriptionId: string; /** Channel names for this subscription */ channels: string[]; /** Callback function for handling notifications (optional for external use) */ callback?: (notification: ServerNotificationMessage) => void; /** Function to unsubscribe and clean up */ unsubscribe: (requestId?: string) => Promise; }; /** * WebSocket connection info */ export type WebSocketConnectionInfo = { state: WebSocketState; url: string; reconnectAttempts: number; connectedAt?: number; }; export type BackendWebSocketServiceActions = BackendWebSocketServiceMethodActions; export type BackendWebSocketServiceAllowedActions = AuthenticationController.AuthenticationControllerGetBearerToken | BackendWebSocketServiceMethodActions; export type BackendWebSocketServiceAllowedEvents = AuthenticationController.AuthenticationControllerStateChangeEvent | BackendWebSocketServiceConnectionStateChangedEvent; export type BackendWebSocketServiceConnectionStateChangedEvent = { type: 'BackendWebSocketService:connectionStateChanged'; payload: [WebSocketConnectionInfo]; }; export type BackendWebSocketServiceEvents = BackendWebSocketServiceConnectionStateChangedEvent; export type BackendWebSocketServiceMessenger = RestrictedMessenger; /** * WebSocket Service with automatic reconnection, session management and direct callback routing * * Real-Time Performance Optimizations: * - Fast path message routing (zero allocations) * - Production mode removes try-catch overhead * - Optimized JSON parsing with fail-fast * - Direct callback routing bypasses event emitters * - Memory cleanup and resource management * * Mobile Integration: * Mobile apps should handle lifecycle events (background/foreground) by: * 1. Calling disconnect() when app goes to background * 2. Calling connect() when app returns to foreground * 3. Calling destroy() on app termination */ export declare class BackendWebSocketService { #private; /** * The name of the service. */ readonly name: "BackendWebSocketService"; /** * Creates a new WebSocket service instance * * @param options - Configuration options for the WebSocket service */ constructor(options: BackendWebSocketServiceOptions); /** * Establishes WebSocket connection with smart reconnection behavior * * Simplified Priority System (using AuthenticationController): * 1. App closed/backgrounded → Stop all attempts (save resources) * 2. User not signed in (wallet locked OR not authenticated) → Keep retrying * 3. User signed in (wallet unlocked + authenticated) → Connect successfully * * @returns Promise that resolves when connection is established */ connect(): Promise; /** * Closes WebSocket connection * * @returns Promise that resolves when disconnection is complete */ disconnect(): Promise; /** * Sends a message through the WebSocket (fire-and-forget, no response expected) * * This is a low-level method for sending messages without waiting for a response. * Most consumers should use `sendRequest()` instead, which handles request-response * correlation and provides proper error handling with timeouts. * * Use this method only when: * - You don't need a response from the server * - You're implementing custom message protocols * - You need fine-grained control over message timing * * @param message - The message to send * @throws Error if WebSocket is not connected or send fails * * @see sendRequest for request-response pattern with automatic correlation */ sendMessage(message: ClientRequestMessage): void; /** * Sends a request and waits for a correlated response (recommended for most use cases) * * This is the recommended high-level method for request-response communication. * It automatically handles: * - Request ID generation and correlation * - Response matching with timeout protection * - Automatic reconnection on timeout * - Proper cleanup of pending requests * * @param message - The request message (can include optional requestId for testing) * @returns Promise that resolves with the response data * @throws Error if WebSocket is not connected, request times out, or response indicates failure * * @see sendMessage for fire-and-forget messaging without response handling */ sendRequest(message: Omit & { data?: Omit & { requestId?: string; }; }): Promise; /** * Gets current connection information * * @returns Current connection status and details */ getConnectionInfo(): WebSocketConnectionInfo; /** * Gets all subscription information for a specific channel * * @param channel - The channel name to look up * @returns Array of subscription details for all subscriptions containing the channel */ getSubscriptionsByChannel(channel: string): WebSocketSubscription[]; /** * Checks if a channel has a subscription * * @param channel - The channel name to check * @returns True if the channel has a subscription, false otherwise */ channelHasSubscription(channel: string): boolean; /** * Finds all subscriptions that have channels starting with the specified prefix * * @param channelPrefix - The channel prefix to search for (e.g., "account-activity.v1") * @returns Array of subscription info for matching subscriptions */ findSubscriptionsByChannelPrefix(channelPrefix: string): WebSocketSubscription[]; /** * Register a callback for specific channels (local callback only, no server subscription) * * **Key Difference from `subscribe()`:** * - `addChannelCallback()`: Registers a local callback without creating a server-side subscription. * The callback triggers on ANY message matching the channel name, regardless of subscriptionId. * Useful for system-wide notifications or when you don't control the subscription lifecycle. * * - `subscribe()`: Creates a proper server-side subscription with a subscriptionId. * The callback only triggers for messages with the matching subscriptionId. * Includes proper lifecycle management (unsubscribe, automatic cleanup on disconnect). * * **When to use `addChannelCallback()`:** * - Listening to system-wide notifications (e.g., 'system-notifications.v1') * - Monitoring channels where subscriptions are managed elsewhere * - Debug/logging scenarios where you want to observe all channel messages * * **When to use `subscribe()` instead:** * - Creating new subscriptions that need server-side registration * - When you need proper cleanup via unsubscribe * - Most application use cases (recommended approach) * * @param options - Channel callback configuration * @param options.channelName - Channel name to match exactly * @param options.callback - Function to call when channel matches * * @example * ```typescript * // Listen to system notifications (no server subscription needed) * webSocketService.addChannelCallback({ * channelName: 'system-notifications.v1', * callback: (notification) => { * console.log('System notification:', notification.data); * } * }); * * // For account-specific subscriptions, use subscribe() instead: * // const sub = await webSocketService.subscribe({ * // channels: ['account-activity.v1.eip155:0:0x1234...'], * // callback: (notification) => { ... } * // }); * ``` * * @see subscribe for creating proper server-side subscriptions with lifecycle management */ addChannelCallback(options: { channelName: string; callback: (notification: ServerNotificationMessage) => void; }): void; /** * Remove a channel callback * * @param channelName - The channel name returned from addChannelCallback * @returns True if callback was found and removed, false otherwise */ removeChannelCallback(channelName: string): boolean; /** * Get all registered channel callbacks (for debugging) * * @returns Array of all registered channel callbacks */ getChannelCallbacks(): ChannelCallback[]; /** * Destroy the service and clean up resources * Called when service is being destroyed or app is terminating */ destroy(): void; /** * Create and manage a subscription with server-side registration (recommended for most use cases) * * This is the recommended subscription API for high-level services. It creates a proper * server-side subscription and routes notifications based on subscriptionId. * * **Key Features:** * - Creates server-side subscription with unique subscriptionId * - Callback triggered only for messages with matching subscriptionId * - Automatic lifecycle management (cleanup on disconnect) * - Includes unsubscribe method for proper cleanup * - Request-response pattern with error handling * * **When to use `subscribe()`:** * - Creating new subscriptions (account activity, price updates, etc.) * - When you need proper cleanup/unsubscribe functionality * - Most application use cases * * **When to use `addChannelCallback()` instead:** * - System-wide notifications without server-side subscription * - Observing channels managed elsewhere * - Debug/logging scenarios * * @param options - Subscription configuration * @param options.channels - Array of channel names to subscribe to * @param options.callback - Callback function for handling notifications * @param options.requestId - Optional request ID for testing (will generate UUID if not provided) * @returns Subscription object with unsubscribe method * * @example * ```typescript * // AccountActivityService usage * const subscription = await webSocketService.subscribe({ * channels: ['account-activity.v1.eip155:0:0x1234...'], * callback: (notification) => { * this.handleAccountActivity(notification.data); * } * }); * * // Later, clean up * await subscription.unsubscribe(); * ``` * * @see addChannelCallback for local callbacks without server-side subscription */ subscribe(options: { /** Channel names to subscribe to */ channels: string[]; /** Handler for incoming notifications */ callback: (notification: ServerNotificationMessage) => void; /** Optional request ID for testing (will generate UUID if not provided) */ requestId?: string; }): Promise; } export {}; //# sourceMappingURL=BackendWebSocketService.d.mts.map