/** * Sharable Pending Operations Library * * A generic library for managing pending operations with timeout, cleanup, * and lifecycle management. Can be used on both client and server sides * for WebSocket communication or any async operation tracking. */ import { JSONRPCResponse, JSONRPCId, type JSONRPCRequest } from "./schemas/jsonrpc"; /** * Configuration options for PendingOperations * * @interface PendingOperationsConfig * @description Configures timeout behavior, cleanup intervals, and ID generation for pending operations */ export interface PendingOperationsConfig { /** * Default timeout in milliseconds for operations (default: 30000) * @default 30000 * @description Sets the default timeout for operations that don't specify their own timeout */ defaultTimeout?: number; /** * Cleanup interval in milliseconds for expired operations (default: 10000) * @default 10000 * @description How often the system checks for and cleans up expired operations */ cleanupInterval?: number; /** * Enable automatic cleanup of expired operations (default: true) * @default true * @description Whether to automatically clean up expired operations in the background */ enableAutoCleanup?: boolean; /** * Custom ID generator function (default: randomUUIDv7) * @default generateId * @description Function to generate unique IDs for operations. Must return unique strings. */ generateId?: () => string; } /** * Base interface for all pending operation data * * @interface PendingOperationBase * @description Common properties shared by all pending operation types */ export interface PendingOperationBase { /** * Unique identifier for the operation * @description Generated automatically by the ID generator function */ id: JSONRPCId; /** * Timestamp when the operation was created * @description Used for age calculations and timeout management */ timestamp: number; /** * Timeout in milliseconds for this specific operation * @description Overrides the default timeout if specified */ timeout?: number; /** * Optional data for the operation * @description Arbitrary data for application-specific use */ data?: any; } /** * Promise-based pending operation (used for server-to-client calls) * * @interface PromisePendingOperation * @extends PendingOperationBase * @description Represents an operation that provides a Promise interface for async resolution * @example * ```typescript * const { id, promise } = pendingOps.addPromiseOperation(); * promise.then(result => console.log('Success:', result)); * // Later: pendingOps.resolve(id, { data: 'result' }); * ``` */ export interface PromisePendingOperation extends PendingOperationBase { /** Operation type identifier */ type: "promise"; /** * Promise resolve function * @description Called when the operation completes successfully */ resolve: (value: any) => void; /** * Promise reject function * @description Called when the operation fails or times out */ reject: (reason?: any) => void; /** * Optional timeout handle for cleanup * @description Internal timeout handle for automatic cleanup */ timeoutHandle?: NodeJS.Timeout; } /** * Data-based pending operation (used for request tracking and context storage) * Replaces both RequestPendingOperation and ContextPendingOperation * * @interface DataPendingOperation * @extends PendingOperationBase * @description Flexible operation type that can store any data payload. Use for client-server requests, context tracking, or any data-centric operations. * @example * ```typescript * // Request-style usage * const id = pendingOps.addDataOperation( * { requestType: 'getUserProfile', payload: { userId: 123 } }, * { connectionId: 'client-001', timeout: 30000 } * ); * * // Context-style usage * const id2 = pendingOps.addDataOperation( * { functionName: 'processCommand', context: { command: 'export' } }, * { timeout: 60000 } * ); * ``` */ export interface DataPendingOperation extends PendingOperationBase { /** Operation type identifier */ type: "data"; /** * Arbitrary data payload for the operation * @description Can contain requestType/payload, functionName/context, connectionId, connection, or any other data structure */ data: any; /** * Optional timeout handle for cleanup * @description Internal timeout handle for automatic cleanup */ timeoutHandle?: NodeJS.Timeout; } /** * Union type for all pending operation types */ export type PendingOperation = PromisePendingOperation | DataPendingOperation; /** * Event handlers for pending operations */ export interface PendingOperationEventHandlers { /** Called when an operation times out */ onTimeout?: (operation: PendingOperation) => void; /** Called when an operation is resolved */ onResolve?: (operation: PendingOperation, result?: any) => void; /** Called when an operation is rejected */ onReject?: (operation: PendingOperation, reason?: any) => void; /** Called when an operation is removed/cleaned up */ onCleanup?: (operation: PendingOperation) => void; } /** * Statistics about pending operations */ export interface PendingOperationStats { /** Total number of pending operations */ total: number; /** Number of operations by type */ byType: Record; /** Number of operations that will expire soon (within next minute) */ expiringSoon: number; /** Oldest operation timestamp */ oldestTimestamp?: number; /** Average age of operations in milliseconds */ averageAge: number; } /** * Abstract base class for pending operations management * Contains all common functionality while allowing specialized subclasses */ export declare abstract class PendingOperationsBase { protected operations: Map; protected config: Required; protected cleanupIntervalHandle?: NodeJS.Timeout; protected eventHandlers: PendingOperationEventHandlers; constructor(config?: PendingOperationsConfig, eventHandlers?: PendingOperationEventHandlers); /** * Resolve a pending operation with a result */ resolve(id: JSONRPCId, result?: any): boolean; /** * Reject a pending operation with a reason */ reject(id: JSONRPCId, reason?: any): boolean; /** * Get a pending operation by ID */ get(id: JSONRPCId): PendingOperation | undefined; /** * Check if an operation exists */ has(id: JSONRPCId): boolean; /** * Remove an operation without resolving or rejecting */ remove(id: JSONRPCId): boolean; /** * Get all pending operations */ getAll(): Map; /** * Get pending operations by type */ getByType(type: PendingOperation["type"]): PendingOperation[]; /** * Clear all pending operations */ clear(reason?: any): number; /** * Clean up expired operations */ cleanupExpired(): number; /** * Get statistics about pending operations */ getStats(): PendingOperationStats; /** * Start automatic cleanup of expired operations */ private startAutoCleanup; /** * Stop automatic cleanup */ stopAutoCleanup(): void; /** * Handle operation timeout */ protected handleTimeout({ id }: { id: JSONRPCId; }): void; /** * Destroy the pending operations manager */ destroy(reason?: any): void; /** * Get the current configuration */ getConfig(): Required; /** * Update event handlers */ setEventHandlers(handlers: PendingOperationEventHandlers): void; /** * Abstract method that subclasses must implement for their specific operation type */ abstract add(...args: any[]): any; handleAdd(options?: { timeout?: number; customId?: JSONRPCId; }): { id: string | number; timeout: number; timeoutHandle: NodeJS.Timeout | undefined; }; } /** * Specialized class for promise-based operations only * Enforces type safety by only exposing promise-related methods */ export declare class PromisePendingOperations extends PendingOperationsBase { /** * Add a promise-based pending operation */ add(data: any, options?: { timeout?: number; customId?: JSONRPCId; }): { id: JSONRPCId; promise: Promise; }; } /** * Specialized class for data-based operations only * Enforces type safety by only exposing data-related methods */ export declare class DataPendingOperations extends PendingOperationsBase { /** * Add a data-based pending operation */ add(data: any, options?: { timeout?: number; customId?: JSONRPCId; }): { id: JSONRPCId; }; } /** * Create a PendingOperations instance with Promise-based operations * Optimized for server-to-client function calls * * @param config Optional configuration for the pending operations * @param eventHandlers Optional event handlers for operation lifecycle * @returns PromisePendingOperations instance that only allows promise operations */ export declare function createPromisePendingOperations(config?: PendingOperationsConfig, eventHandlers?: PendingOperationEventHandlers): PromisePendingOperations; /** * Create a PendingOperations instance with Data-based operations * Optimized for both request processing and context handling * * @param config Optional configuration for the pending operations * @param eventHandlers Optional event handlers for operation lifecycle * @returns DataPendingOperations instance that only allows data operations */ export declare function createDataPendingOperations(config?: PendingOperationsConfig, eventHandlers?: PendingOperationEventHandlers): DataPendingOperations; export declare class JSONRPCCall { private pendingRequests; private isDestroyed; constructor(config?: PendingOperationsConfig); /** * Process a JSON-RPC response */ handleResponse(response: JSONRPCResponse): void; /** * Send a JSON-RPC request and return a promise for the response */ handleRequest(method: string, params?: any, options?: { timeout?: number; customId?: JSONRPCId; }): { promise: Promise; request: JSONRPCRequest; }; /** * Get manager statistics */ getStats(): { pendingRequests: PendingOperationStats; }; /** * Clean up resources */ destroy(): void; }