import type { TraceCallback } from "@metamask/controller-utils"; import type { KeyringControllerLockEvent, KeyringControllerUnlockEvent } from "@metamask/keyring-controller"; import type { Messenger } from "@metamask/messenger"; import type { AuthenticationController } from "@metamask/profile-sync-controller"; import type { BackendWebSocketServiceMethodActions } from "./BackendWebSocketService-method-action-types.cjs"; 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", /** @deprecated This value is no longer used internally and will be removed in a future major release */ DISCONNECTING = "disconnecting", DISCONNECTED = "disconnected", /** @deprecated TThis value is no longer used internally and will be removed in a future major release */ 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: 10000) */ reconnectDelay?: number; /** Maximum reconnection delay in milliseconds (default: 60000) */ maxReconnectDelay?: number; /** Request timeout in milliseconds (default: 30000) */ requestTimeout?: number; /** Optional callback to determine if connection should be enabled (default: always enabled) */ isEnabled?: () => boolean; /** Optional callback to trace performance of WebSocket operations (default: no-op) */ traceFn?: TraceCallback; }; /** * 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; timestamp: number; }; /** * 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[]; /** Channel type with version (e.g., 'account-activity.v1') extracted from first channel */ channelType: 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; timeout: number; reconnectDelay: number; maxReconnectDelay: number; requestTimeout: number; connectedAt?: number; }; export type BackendWebSocketServiceActions = BackendWebSocketServiceMethodActions; type AllowedActions = AuthenticationController.AuthenticationControllerGetBearerTokenAction; export type BackendWebSocketServiceConnectionStateChangedEvent = { type: 'BackendWebSocketService:connectionStateChanged'; payload: [WebSocketConnectionInfo]; }; type AllowedEvents = AuthenticationController.AuthenticationControllerStateChangeEvent | KeyringControllerLockEvent | KeyringControllerUnlockEvent; export type BackendWebSocketServiceEvents = BackendWebSocketServiceConnectionStateChangedEvent; export type BackendWebSocketServiceMessenger = Messenger; /** * WebSocket Service with automatic reconnection, session management and direct callback routing * * Connection Management: * - Automatically subscribes to AuthenticationController:stateChange (sign in/out) * - Automatically subscribes to KeyringController:lock/unlock events * - Idempotent connect() function safe for multiple rapid calls * - Auto-reconnects on unexpected disconnects (manualDisconnect = false) * * Platform Responsibilities: * - Call connect() when app opens/foregrounds * - Call disconnect() when app closes/backgrounds * - Provide isEnabled() callback (feature flag) * - Call destroy() on app termination * * 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 */ 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 * * Connection Requirements (all must be true): * 1. Feature enabled (isEnabled() = true) * 2. Wallet unlocked (checked by getBearerToken) * 3. User signed in (checked by getBearerToken) * * Platform code should call this when app opens/foregrounds. * Automatically called on KeyringController:unlock event. * * @returns Promise that resolves when connection is established */ connect(): Promise; /** * Closes WebSocket connection */ disconnect(): void; /** * Forces a WebSocket reconnection to clean up subscription state * * This method is useful when subscription state may be out of sync and needs to be reset. * It performs a controlled disconnect-then-reconnect sequence: * - Disconnects cleanly to trigger subscription cleanup * - Schedules reconnection with exponential backoff to prevent rapid loops * - All subscriptions will be cleaned up automatically on disconnect * * Use cases: * - Recovering from subscription/unsubscription issues * - Cleaning up orphaned subscriptions * - Forcing a fresh subscription state * * @returns Promise that resolves when disconnection is complete (reconnection is scheduled) */ forceReconnection(): 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) * @param options.channelType - Channel type identifier * @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[]; /** Channel type with version (e.g., 'account-activity.v1') for tracing and monitoring */ channelType: 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.cts.map