@eztra.services/engine 1.0.0-dev.20260202085509 → 1.0.0-dev.20260202093252

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ComposableController.ts","../src/EztraEngine.ts"],"sourcesContent":["import type {\n BaseController,\n StateChangeEvent,\n ControllerMessenger,\n} from '@eztra/controller';\n\n/**\n * Composable controller configuration\n */\nexport interface ComposableControllerConfig {\n /**\n * Global messenger instance\n */\n messenger: ControllerMessenger<any, any>;\n\n /**\n * Optional persistence service for all controllers\n */\n persistenceService?: any;\n\n /**\n * Feature flags\n */\n features?: {\n enablePersistence?: boolean;\n enableStateRestoration?: boolean;\n enableAutoSave?: boolean;\n };\n}\n\n/**\n * Controller map type\n */\nexport type ControllerMap = {\n [name: string]: BaseController<any, any, any>;\n};\n\n/**\n * Composed state type - merges all controller states\n */\nexport type ComposedState<Controllers extends ControllerMap> = {\n [K in keyof Controllers]: Controllers[K] extends BaseController<any, infer State, any>\n ? State\n : never;\n};\n\n/**\n * State change listener for composed state\n */\nexport type ComposedStateChangeListener = (state: any, controllerName: string) => void;\n\n/**\n * ComposableController - Orchestrates multiple controllers into a unified system\n *\n * Inspired by MetaMask's ComposableController, this provides:\n * - Unified state management across all controllers\n * - Lifecycle orchestration (initialize, start, stop, destroy)\n * - Centralized state persistence and restoration\n * - Single subscription point for all state changes\n * - Context sharing between controllers\n *\n * @example\n * ```typescript\n * const messenger = new ControllerMessenger<EztraActions, EztraEvents>();\n * const persistenceService = new StatePersistenceService(storage);\n *\n * const composable = new ComposableController({\n * messenger,\n * persistenceService,\n * features: {\n * enablePersistence: true,\n * enableStateRestoration: true,\n * },\n * });\n *\n * // Register controllers\n * composable.registerController('NetworkController', networkController);\n * composable.registerController('WalletController', walletController);\n *\n * // Initialize all controllers\n * await composable.initialize();\n *\n * // Get unified state\n * const state = composable.getState();\n * // { NetworkController: {...}, WalletController: {...} }\n *\n * // Subscribe to all state changes\n * composable.subscribe((state, controllerName) => {\n * console.log(`${controllerName} state changed:`, state);\n * });\n * ```\n */\nexport class ComposableController {\n private controllers = new Map<string, BaseController<any, any, any>>();\n private messenger: ControllerMessenger<any, any>;\n private persistenceService?: any;\n private features: Required<NonNullable<ComposableControllerConfig['features']>>;\n private listeners = new Set<ComposedStateChangeListener>();\n private initialized = false;\n\n constructor(config: ComposableControllerConfig) {\n this.messenger = config.messenger;\n this.persistenceService = config.persistenceService;\n this.features = {\n enablePersistence: config.features?.enablePersistence ?? true,\n enableStateRestoration: config.features?.enableStateRestoration ?? true,\n enableAutoSave: config.features?.enableAutoSave ?? false,\n };\n }\n\n /**\n * Register a controller\n *\n * @param name - Unique controller identifier\n * @param controller - Controller instance\n * @throws Error if controller is already registered\n */\n registerController<T extends BaseController<any, any, any>>(\n name: string,\n controller: T\n ): void {\n if (this.controllers.has(name)) {\n throw new Error(`Controller \"${name}\" is already registered`);\n }\n\n if (this.initialized) {\n throw new Error('Cannot register controllers after initialization');\n }\n\n this.controllers.set(name, controller);\n console.log(`[ComposableController] Registered controller: ${name}`);\n }\n\n /**\n * Unregister a controller\n *\n * @param name - Controller identifier\n */\n async unregisterController(name: string): Promise<void> {\n const controller = this.controllers.get(name);\n if (!controller) {\n return;\n }\n\n // Destroy controller\n await controller.destroy();\n this.controllers.delete(name);\n\n console.log(`[ComposableController] Unregistered controller: ${name}`);\n }\n\n /**\n * Get a controller by name\n *\n * @param name - Controller identifier\n * @returns Controller instance or undefined\n */\n getController<T extends BaseController<any, any, any>>(name: string): T | undefined {\n return this.controllers.get(name) as T | undefined;\n }\n\n /**\n * Get all registered controller names\n */\n getControllerNames(): string[] {\n return Array.from(this.controllers.keys());\n }\n\n /**\n * Get unified state from all controllers\n *\n * @returns Object mapping controller names to their states\n */\n getState(): Record<string, any> {\n const composedState: Record<string, any> = {};\n\n for (const [name, controller] of this.controllers) {\n composedState[name] = controller.state;\n }\n\n return composedState;\n }\n\n /**\n * Subscribe to state changes from all controllers\n *\n * @param listener - Callback for state changes\n * @returns Unsubscribe function\n */\n subscribe(listener: ComposedStateChangeListener): () => void {\n this.listeners.add(listener);\n\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Initialize all controllers\n *\n * This should be called after all controllers are registered.\n * The initialization process:\n * 1. Restore persisted state (if enabled)\n * 2. Initialize each controller in order\n * 3. Set up state change subscriptions\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n console.warn('[ComposableController] Already initialized');\n return;\n }\n\n console.log('[ComposableController] Initializing...');\n\n // Restore persisted state first\n if (this.features.enableStateRestoration && this.persistenceService) {\n await this.restoreAllStates();\n }\n\n // Initialize all controllers\n for (const [name, controller] of this.controllers) {\n try {\n console.log(`[ComposableController] Initializing ${name}...`);\n await controller.initialize();\n\n // Subscribe to controller state changes\n this.subscribeToController(name, controller);\n } catch (error) {\n console.error(`[ComposableController] Failed to initialize ${name}:`, error);\n throw error;\n }\n }\n\n this.initialized = true;\n console.log('[ComposableController] Initialization complete');\n }\n\n /**\n * Start all controllers\n *\n * This is called after initialization to begin normal operations.\n */\n async start(): Promise<void> {\n if (!this.initialized) {\n await this.initialize();\n }\n\n console.log('[ComposableController] Starting all controllers...');\n\n for (const [name, controller] of this.controllers) {\n // Check if controller has a start method\n if (typeof (controller as any).start === 'function') {\n try {\n await (controller as any).start();\n } catch (error) {\n console.error(`[ComposableController] Failed to start ${name}:`, error);\n }\n }\n }\n\n console.log('[ComposableController] All controllers started');\n }\n\n /**\n * Stop all controllers\n *\n * Persists state if auto-save is enabled.\n */\n async stop(): Promise<void> {\n console.log('[ComposableController] Stopping all controllers...');\n\n // Persist state if auto-save is enabled\n if (this.features.enableAutoSave && this.features.enablePersistence) {\n await this.persistAllStates();\n }\n\n // Stop all controllers\n for (const [name, controller] of this.controllers) {\n if (typeof (controller as any).stop === 'function') {\n try {\n await (controller as any).stop();\n } catch (error) {\n console.error(`[ComposableController] Failed to stop ${name}:`, error);\n }\n }\n }\n\n console.log('[ComposableController] All controllers stopped');\n }\n\n /**\n * Destroy all controllers and cleanup\n */\n async destroy(): Promise<void> {\n console.log('[ComposableController] Destroying...');\n\n // Persist state before destruction\n if (this.features.enablePersistence) {\n await this.persistAllStates();\n }\n\n // Destroy all controllers\n for (const [name] of this.controllers) {\n await this.unregisterController(name);\n }\n\n // Clear listeners\n this.listeners.clear();\n\n this.initialized = false;\n console.log('[ComposableController] Destroyed');\n }\n\n /**\n * Persist all controller states\n */\n async persistAllStates(): Promise<void> {\n if (!this.persistenceService) {\n return;\n }\n\n console.log('[ComposableController] Persisting all states...');\n\n for (const [name, controller] of this.controllers) {\n try {\n if (typeof (controller as any).persist === 'function') {\n await (controller as any).persist();\n }\n } catch (error) {\n console.error(`[ComposableController] Failed to persist ${name}:`, error);\n }\n }\n }\n\n /**\n * Restore all controller states from storage\n *\n * @private\n */\n private async restoreAllStates(): Promise<void> {\n console.log('[ComposableController] Restoring persisted states...');\n\n for (const [name, controller] of this.controllers) {\n try {\n if (typeof (controller as any).loadPersistedState === 'function') {\n const restored = await (controller as any).loadPersistedState();\n if (restored) {\n console.log(`[ComposableController] Restored state for ${name}`);\n }\n }\n } catch (error) {\n console.error(`[ComposableController] Failed to restore ${name}:`, error);\n }\n }\n }\n\n /**\n * Subscribe to a controller's state changes\n *\n * @private\n */\n private subscribeToController(\n name: string,\n controller: BaseController<any, any, any>\n ): void {\n // Subscribe to controller's stateChange event via messenger\n const eventName = `${name}:stateChange` as any;\n\n this.messenger.subscribe(eventName, (event: StateChangeEvent<any>) => {\n // Notify all listeners\n this.listeners.forEach((listener) => {\n try {\n listener(event.newState, name);\n } catch (error) {\n console.error(\n `[ComposableController] Error in state change listener:`,\n error\n );\n }\n });\n\n // Auto-save if enabled\n if (this.features.enableAutoSave && this.features.enablePersistence) {\n if (typeof (controller as any).persist === 'function') {\n (controller as any).persist().catch((error: Error) => {\n console.error(`[ComposableController] Auto-save failed for ${name}:`, error);\n });\n }\n }\n });\n }\n}\n","import { ControllerMessenger } from '@eztra/controller';\nimport { StatePersistenceService, type IStorage } from '@eztra/storage';\nimport {\n NetworkController,\n type NetworkControllerActions,\n type NetworkControllerEvents,\n} from '@eztra/network-controller';\nimport {\n WalletController,\n type WalletControllerActions,\n type WalletControllerEvents,\n} from '@eztra/wallet-controller';\nimport { ComposableController } from './ComposableController';\n\n/**\n * Combined actions from all controllers\n */\nexport type EztraEngineActions = NetworkControllerActions & WalletControllerActions;\n\n/**\n * Combined events from all controllers\n */\nexport type EztraEngineEvents = NetworkControllerEvents & WalletControllerEvents;\n\n/**\n * Engine configuration\n */\nexport interface EngineConfig {\n /**\n * Storage implementation\n */\n storage: IStorage;\n\n /**\n * Default chain ID\n */\n defaultChainId?: number;\n\n /**\n * Enable features\n */\n features?: {\n enablePersistence?: boolean;\n enableStateRestoration?: boolean;\n enableAutoSave?: boolean;\n };\n\n /**\n * Initial state for controllers\n */\n initialState?: {\n NetworkController?: any;\n WalletController?: any;\n };\n}\n\n/**\n * EztraEngine - Main engine class that orchestrates all controllers\n *\n * This is the primary entry point for initializing the Eztra Engine with\n * MetaMask-style controller architecture.\n *\n * Features:\n * - Automatic controller initialization\n * - Type-safe inter-controller communication\n * - Unified state management\n * - State persistence and restoration\n * - Lifecycle management\n *\n * @example\n * ```typescript\n * import { EztraEngine } from '@eztra/engine';\n * import { createWebStorage } from '@eztra/engine/storage/web';\n *\n * // Initialize engine\n * const engine = new EztraEngine({\n * storage: createWebStorage({ id: 'eztra' }),\n * defaultChainId: 1, // Ethereum\n * features: {\n * enablePersistence: true,\n * enableStateRestoration: true,\n * enableAutoSave: true,\n * },\n * });\n *\n * // Initialize all controllers\n * await engine.initialize();\n *\n * // Access controllers\n * const chainId = engine.call('NetworkController:getActiveChainId');\n * const wallet = engine.call('WalletController:getActiveWallet');\n *\n * // Subscribe to events\n * engine.subscribe('NetworkController:chainChanged', (event) => {\n * console.log('Chain changed:', event.chainId);\n * });\n *\n * // Get unified state\n * const state = engine.getState();\n * // { NetworkController: {...}, WalletController: {...} }\n * ```\n */\nexport class EztraEngine {\n private messenger: ControllerMessenger<EztraEngineActions, EztraEngineEvents>;\n private composableController: ComposableController;\n private persistenceService: StatePersistenceService;\n private initialized = false;\n\n // Public controller references\n public networkController: NetworkController;\n public walletController: WalletController;\n\n constructor(config: EngineConfig) {\n // Create global messenger\n this.messenger = new ControllerMessenger<\n EztraEngineActions,\n EztraEngineEvents\n >();\n\n // Create persistence service\n this.persistenceService = new StatePersistenceService(config.storage);\n\n // Create controllers with restricted messengers\n this.networkController = this.createNetworkController(config);\n this.walletController = this.createWalletController(config);\n\n // Create composable controller\n this.composableController = new ComposableController({\n messenger: this.messenger,\n persistenceService: this.persistenceService,\n features: config.features,\n });\n\n // Register controllers\n this.composableController.registerController(\n 'NetworkController',\n this.networkController\n );\n this.composableController.registerController(\n 'WalletController',\n this.walletController\n );\n }\n\n /**\n * Create NetworkController with restricted messenger\n *\n * @private\n */\n private createNetworkController(config: EngineConfig): NetworkController {\n return new NetworkController({\n messenger: this.messenger.getRestricted({\n name: 'NetworkController',\n allowedActions: [\n 'NetworkController:setChainId',\n 'NetworkController:getActiveChainId',\n 'NetworkController:getRpcUrl',\n 'NetworkController:refreshEndpoints',\n 'NetworkController:setWalletIndex',\n ],\n allowedEvents: [\n 'NetworkController:stateChange',\n 'NetworkController:chainChanged',\n 'NetworkController:endpointsUpdated',\n ],\n }),\n persistenceService: this.persistenceService,\n state: config.initialState?.NetworkController,\n defaultChainId: config.defaultChainId,\n });\n }\n\n /**\n * Create WalletController with restricted messenger\n *\n * @private\n */\n private createWalletController(config: EngineConfig): WalletController {\n return new WalletController({\n messenger: this.messenger.getRestricted({\n name: 'WalletController',\n allowedActions: [\n 'WalletController:addWallet',\n 'WalletController:selectWallet',\n 'WalletController:getActiveWallet',\n 'WalletController:lockWallet',\n 'WalletController:unlockWallet',\n ],\n allowedEvents: [\n 'WalletController:stateChange',\n 'WalletController:walletSelected',\n 'WalletController:walletLocked',\n 'WalletController:walletUnlocked',\n ],\n externalActions: [\n 'NetworkController:getActiveChainId',\n 'NetworkController:setWalletIndex',\n ],\n externalEvents: ['NetworkController:chainChanged'],\n }),\n persistenceService: this.persistenceService,\n state: config.initialState?.WalletController,\n });\n }\n\n /**\n * Initialize the engine and all controllers\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n console.warn('[EztraEngine] Already initialized');\n return;\n }\n\n console.log('[EztraEngine] Initializing...');\n\n // Initialize all controllers via composable controller\n await this.composableController.initialize();\n\n this.initialized = true;\n console.log('[EztraEngine] Initialization complete');\n }\n\n /**\n * Start the engine\n */\n async start(): Promise<void> {\n if (!this.initialized) {\n await this.initialize();\n }\n\n await this.composableController.start();\n }\n\n /**\n * Stop the engine\n */\n async stop(): Promise<void> {\n await this.composableController.stop();\n }\n\n /**\n * Destroy the engine and cleanup\n */\n async destroy(): Promise<void> {\n await this.composableController.destroy();\n this.initialized = false;\n }\n\n /**\n * Get unified state from all controllers\n */\n getState(): Record<string, any> {\n return this.composableController.getState();\n }\n\n /**\n * Call an action\n */\n call<Action extends keyof EztraEngineActions>(\n action: Action,\n ...params: any[]\n ): any {\n return this.messenger.call(action, ...params);\n }\n\n /**\n * Subscribe to an event\n */\n subscribe<Event extends keyof EztraEngineEvents>(\n event: Event,\n listener: any\n ): () => void {\n return this.messenger.subscribe(event, listener);\n }\n\n /**\n * Get the global messenger (for advanced usage)\n */\n getMessenger(): ControllerMessenger<EztraEngineActions, EztraEngineEvents> {\n return this.messenger;\n }\n\n /**\n * Check if engine is initialized\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n}\n\n// ==================== Singleton Pattern ====================\n\nlet engineInstance: EztraEngine | null = null;\n\n/**\n * Initialize the Eztra Engine (singleton)\n *\n * @param config - Engine configuration\n * @returns Engine instance\n * @throws Error if already initialized\n *\n * @example\n * ```typescript\n * import { initializeEngine } from '@eztra/engine';\n *\n * const engine = await initializeEngine({\n * storage: createWebStorage({ id: 'eztra' }),\n * defaultChainId: 1,\n * });\n * ```\n */\nexport async function initializeEngine(config: EngineConfig): Promise<EztraEngine> {\n if (engineInstance) {\n throw new Error('Engine already initialized. Use getEngine() to access the instance.');\n }\n\n engineInstance = new EztraEngine(config);\n await engineInstance.initialize();\n\n return engineInstance;\n}\n\n/**\n * Get the initialized engine instance\n *\n * @returns Engine instance\n * @throws Error if not initialized\n */\nexport function getEngine(): EztraEngine {\n if (!engineInstance) {\n throw new Error('Engine not initialized. Call initializeEngine() first.');\n }\n\n return engineInstance;\n}\n\n/**\n * Check if engine is initialized\n */\nexport function isEngineInitialized(): boolean {\n return engineInstance !== null && engineInstance.isInitialized();\n}\n\n/**\n * Reset engine (for testing)\n */\nexport async function resetEngine(): Promise<void> {\n if (engineInstance) {\n await engineInstance.destroy();\n engineInstance = null;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/ComposableController.ts","../../controller/src/BaseController.ts","../../controller/src/ControllerMessenger.ts","../../infrastructure/storage/src/StatePersistenceService.ts","../../networkController/src/NetworkController.ts","../../networkController/src/RpcEndpointService.ts","../../networkController/src/RpcManager.ts","../../walletController/src/WalletController.ts","../src/EztraEngine.ts"],"sourcesContent":["import type {\n BaseController,\n StateChangeEvent,\n ControllerMessenger,\n} from '@eztra/controller';\n\n/**\n * Composable controller configuration\n */\nexport interface ComposableControllerConfig {\n /**\n * Global messenger instance\n */\n messenger: ControllerMessenger<any, any>;\n\n /**\n * Optional persistence service for all controllers\n */\n persistenceService?: any;\n\n /**\n * Feature flags\n */\n features?: {\n enablePersistence?: boolean;\n enableStateRestoration?: boolean;\n enableAutoSave?: boolean;\n };\n}\n\n/**\n * Controller map type\n */\nexport type ControllerMap = {\n [name: string]: BaseController<any, any, any>;\n};\n\n/**\n * Composed state type - merges all controller states\n */\nexport type ComposedState<Controllers extends ControllerMap> = {\n [K in keyof Controllers]: Controllers[K] extends BaseController<any, infer State, any>\n ? State\n : never;\n};\n\n/**\n * State change listener for composed state\n */\nexport type ComposedStateChangeListener = (state: any, controllerName: string) => void;\n\n/**\n * ComposableController - Orchestrates multiple controllers into a unified system\n *\n * Inspired by MetaMask's ComposableController, this provides:\n * - Unified state management across all controllers\n * - Lifecycle orchestration (initialize, start, stop, destroy)\n * - Centralized state persistence and restoration\n * - Single subscription point for all state changes\n * - Context sharing between controllers\n *\n * @example\n * ```typescript\n * const messenger = new ControllerMessenger<EztraActions, EztraEvents>();\n * const persistenceService = new StatePersistenceService(storage);\n *\n * const composable = new ComposableController({\n * messenger,\n * persistenceService,\n * features: {\n * enablePersistence: true,\n * enableStateRestoration: true,\n * },\n * });\n *\n * // Register controllers\n * composable.registerController('NetworkController', networkController);\n * composable.registerController('WalletController', walletController);\n *\n * // Initialize all controllers\n * await composable.initialize();\n *\n * // Get unified state\n * const state = composable.getState();\n * // { NetworkController: {...}, WalletController: {...} }\n *\n * // Subscribe to all state changes\n * composable.subscribe((state, controllerName) => {\n * console.log(`${controllerName} state changed:`, state);\n * });\n * ```\n */\nexport class ComposableController {\n private controllers = new Map<string, BaseController<any, any, any>>();\n private messenger: ControllerMessenger<any, any>;\n private persistenceService?: any;\n private features: Required<NonNullable<ComposableControllerConfig['features']>>;\n private listeners = new Set<ComposedStateChangeListener>();\n private initialized = false;\n\n constructor(config: ComposableControllerConfig) {\n this.messenger = config.messenger;\n this.persistenceService = config.persistenceService;\n this.features = {\n enablePersistence: config.features?.enablePersistence ?? true,\n enableStateRestoration: config.features?.enableStateRestoration ?? true,\n enableAutoSave: config.features?.enableAutoSave ?? false,\n };\n }\n\n /**\n * Register a controller\n *\n * @param name - Unique controller identifier\n * @param controller - Controller instance\n * @throws Error if controller is already registered\n */\n registerController<T extends BaseController<any, any, any>>(\n name: string,\n controller: T\n ): void {\n if (this.controllers.has(name)) {\n throw new Error(`Controller \"${name}\" is already registered`);\n }\n\n if (this.initialized) {\n throw new Error('Cannot register controllers after initialization');\n }\n\n this.controllers.set(name, controller);\n console.log(`[ComposableController] Registered controller: ${name}`);\n }\n\n /**\n * Unregister a controller\n *\n * @param name - Controller identifier\n */\n async unregisterController(name: string): Promise<void> {\n const controller = this.controllers.get(name);\n if (!controller) {\n return;\n }\n\n // Destroy controller\n await controller.destroy();\n this.controllers.delete(name);\n\n console.log(`[ComposableController] Unregistered controller: ${name}`);\n }\n\n /**\n * Get a controller by name\n *\n * @param name - Controller identifier\n * @returns Controller instance or undefined\n */\n getController<T extends BaseController<any, any, any>>(name: string): T | undefined {\n return this.controllers.get(name) as T | undefined;\n }\n\n /**\n * Get all registered controller names\n */\n getControllerNames(): string[] {\n return Array.from(this.controllers.keys());\n }\n\n /**\n * Get unified state from all controllers\n *\n * @returns Object mapping controller names to their states\n */\n getState(): Record<string, any> {\n const composedState: Record<string, any> = {};\n\n for (const [name, controller] of this.controllers) {\n composedState[name] = controller.state;\n }\n\n return composedState;\n }\n\n /**\n * Subscribe to state changes from all controllers\n *\n * @param listener - Callback for state changes\n * @returns Unsubscribe function\n */\n subscribe(listener: ComposedStateChangeListener): () => void {\n this.listeners.add(listener);\n\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Initialize all controllers\n *\n * This should be called after all controllers are registered.\n * The initialization process:\n * 1. Restore persisted state (if enabled)\n * 2. Initialize each controller in order\n * 3. Set up state change subscriptions\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n console.warn('[ComposableController] Already initialized');\n return;\n }\n\n console.log('[ComposableController] Initializing...');\n\n // Restore persisted state first\n if (this.features.enableStateRestoration && this.persistenceService) {\n await this.restoreAllStates();\n }\n\n // Initialize all controllers\n for (const [name, controller] of this.controllers) {\n try {\n console.log(`[ComposableController] Initializing ${name}...`);\n await controller.initialize();\n\n // Subscribe to controller state changes\n this.subscribeToController(name, controller);\n } catch (error) {\n console.error(`[ComposableController] Failed to initialize ${name}:`, error);\n throw error;\n }\n }\n\n this.initialized = true;\n console.log('[ComposableController] Initialization complete');\n }\n\n /**\n * Start all controllers\n *\n * This is called after initialization to begin normal operations.\n */\n async start(): Promise<void> {\n if (!this.initialized) {\n await this.initialize();\n }\n\n console.log('[ComposableController] Starting all controllers...');\n\n for (const [name, controller] of this.controllers) {\n // Check if controller has a start method\n if (typeof (controller as any).start === 'function') {\n try {\n await (controller as any).start();\n } catch (error) {\n console.error(`[ComposableController] Failed to start ${name}:`, error);\n }\n }\n }\n\n console.log('[ComposableController] All controllers started');\n }\n\n /**\n * Stop all controllers\n *\n * Persists state if auto-save is enabled.\n */\n async stop(): Promise<void> {\n console.log('[ComposableController] Stopping all controllers...');\n\n // Persist state if auto-save is enabled\n if (this.features.enableAutoSave && this.features.enablePersistence) {\n await this.persistAllStates();\n }\n\n // Stop all controllers\n for (const [name, controller] of this.controllers) {\n if (typeof (controller as any).stop === 'function') {\n try {\n await (controller as any).stop();\n } catch (error) {\n console.error(`[ComposableController] Failed to stop ${name}:`, error);\n }\n }\n }\n\n console.log('[ComposableController] All controllers stopped');\n }\n\n /**\n * Destroy all controllers and cleanup\n */\n async destroy(): Promise<void> {\n console.log('[ComposableController] Destroying...');\n\n // Persist state before destruction\n if (this.features.enablePersistence) {\n await this.persistAllStates();\n }\n\n // Destroy all controllers\n for (const [name] of this.controllers) {\n await this.unregisterController(name);\n }\n\n // Clear listeners\n this.listeners.clear();\n\n this.initialized = false;\n console.log('[ComposableController] Destroyed');\n }\n\n /**\n * Persist all controller states\n */\n async persistAllStates(): Promise<void> {\n if (!this.persistenceService) {\n return;\n }\n\n console.log('[ComposableController] Persisting all states...');\n\n for (const [name, controller] of this.controllers) {\n try {\n if (typeof (controller as any).persist === 'function') {\n await (controller as any).persist();\n }\n } catch (error) {\n console.error(`[ComposableController] Failed to persist ${name}:`, error);\n }\n }\n }\n\n /**\n * Restore all controller states from storage\n *\n * @private\n */\n private async restoreAllStates(): Promise<void> {\n console.log('[ComposableController] Restoring persisted states...');\n\n for (const [name, controller] of this.controllers) {\n try {\n if (typeof (controller as any).loadPersistedState === 'function') {\n const restored = await (controller as any).loadPersistedState();\n if (restored) {\n console.log(`[ComposableController] Restored state for ${name}`);\n }\n }\n } catch (error) {\n console.error(`[ComposableController] Failed to restore ${name}:`, error);\n }\n }\n }\n\n /**\n * Subscribe to a controller's state changes\n *\n * @private\n */\n private subscribeToController(\n name: string,\n controller: BaseController<any, any, any>\n ): void {\n // Subscribe to controller's stateChange event via messenger\n const eventName = `${name}:stateChange` as any;\n\n this.messenger.subscribe(eventName, (event: StateChangeEvent<any>) => {\n // Notify all listeners\n this.listeners.forEach((listener) => {\n try {\n listener(event.newState, name);\n } catch (error) {\n console.error(\n `[ComposableController] Error in state change listener:`,\n error\n );\n }\n });\n\n // Auto-save if enabled\n if (this.features.enableAutoSave && this.features.enablePersistence) {\n if (typeof (controller as any).persist === 'function') {\n (controller as any).persist().catch((error: Error) => {\n console.error(`[ComposableController] Auto-save failed for ${name}:`, error);\n });\n }\n }\n });\n }\n}\n","import type {\n ControllerState,\n StateMetadata,\n StatePropertyMetadata,\n StateChangeEvent,\n ControllerConfig,\n RestrictedControllerMessenger,\n} from './types';\n\n/**\n * BaseController - Foundation for all Eztra Engine controllers\n *\n * Inspired by MetaMask's BaseControllerV2, this provides:\n * - State ownership and management with immutability\n * - Event-driven communication via ControllerMessenger\n * - Schema-based state persistence with validation\n * - State migration support for version upgrades\n * - Lifecycle hooks (initialize, destroy)\n * - Anonymous state support for public data\n *\n * @template Name - Controller name (e.g., 'WalletController')\n * @template State - Controller state shape\n * @template Messenger - Restricted messenger type\n *\n * @example\n * ```typescript\n * interface MyControllerState {\n * count: number;\n * secret: string;\n * }\n *\n * class MyController extends BaseController<\n * 'MyController',\n * MyControllerState,\n * MyControllerMessenger\n * > {\n * static readonly VERSION = 1;\n *\n * readonly name = 'MyController' as const;\n * readonly defaultState = { count: 0, secret: '' };\n *\n * readonly metadata: StatePropertyMetadata<MyControllerState> = {\n * count: { persist: true, anonymous: true }, // Public, persisted\n * secret: { persist: true, anonymous: false }, // Private, persisted\n * };\n *\n * async initialize() {\n * // Initialization logic\n * }\n *\n * increment() {\n * this.update(draft => {\n * draft.count += 1;\n * });\n * }\n * }\n * ```\n */\nexport abstract class BaseController<\n Name extends string,\n State extends ControllerState,\n Messenger extends RestrictedControllerMessenger<any, any, any, any, any> = RestrictedControllerMessenger<\n Name,\n any,\n any,\n any,\n any\n >\n> {\n /**\n * Controller version for state migrations\n * Increment this when making breaking changes to state structure\n */\n static readonly VERSION = 1;\n /**\n * Controller name (used for event namespacing)\n */\n public abstract readonly name: Name;\n\n /**\n * Default state for the controller\n */\n protected abstract readonly defaultState: State;\n\n /**\n * Internal state storage\n */\n private internalState: State;\n\n /**\n * Controller messenger for inter-controller communication\n */\n protected messenger: Messenger;\n\n /**\n * State metadata (persistence, access control, validation)\n * @deprecated Use StatePropertyMetadata instead\n */\n protected metadata: StateMetadata<State>;\n\n /**\n * Enhanced metadata with validators and migrators\n * Override this in subclasses to define persistence rules\n */\n protected propertyMetadata: StatePropertyMetadata<State> = {};\n\n /**\n * Optional persistence service for state save/restore\n */\n protected persistenceService?: any;\n\n /**\n * Create a new controller instance\n *\n * @param config - Controller configuration\n * @param defaultState - Default state (provided by subclass)\n */\n constructor(config: ControllerConfig<State>, defaultState: State) {\n this.messenger = config.messenger as Messenger;\n this.metadata = config.metadata || {};\n this.persistenceService = config.persistenceService;\n this.internalState = { ...defaultState, ...config.state } as State;\n }\n\n /**\n * Get current state (returns a copy to prevent direct mutation)\n */\n get state(): State {\n return { ...this.internalState };\n }\n\n /**\n * Update controller state\n * \n * @param stateUpdate - Partial state update or updater function\n */\n protected update(stateUpdate: Partial<State> | ((draft: State) => void | Partial<State>)): void {\n const prevState = this.internalState;\n\n if (typeof stateUpdate === 'function') {\n const draft = { ...this.internalState };\n const result = stateUpdate(draft);\n this.internalState = result ? { ...draft, ...result } : draft;\n } else {\n this.internalState = { ...this.internalState, ...stateUpdate };\n }\n\n // Emit state change event\n const event: StateChangeEvent<State> = {\n prevState,\n newState: this.internalState,\n };\n\n this.messenger.publish(`${this.name}:stateChange` as any, event);\n }\n\n /**\n * Initialize controller (called by engine)\n * Override this to set up subscriptions, load persisted state, etc.\n */\n abstract initialize(): Promise<void> | void;\n\n /**\n * Destroy controller (cleanup)\n * Override this to clean up subscriptions, timers, etc.\n */\n destroy(): void {\n // Default: no-op (override in subclasses)\n }\n\n /**\n * Get metadata for a state property\n */\n protected getMetadata(key: keyof State): StateMetadata<State>[string] | undefined {\n return this.metadata[key as string];\n }\n\n /**\n * Check if a state property should be persisted\n */\n protected shouldPersist(key: keyof State): boolean {\n return this.getMetadata(key)?.persist ?? false;\n }\n\n /**\n * Get persistable state (only properties with persist: true)\n */\n protected getPersistableState(): Partial<State> {\n const persistable: Partial<State> = {};\n\n for (const key in this.internalState) {\n if (this.shouldPersist(key as keyof State)) {\n persistable[key] = this.internalState[key];\n }\n }\n\n return persistable;\n }\n\n /**\n * Get anonymous state (only properties with anonymous: true)\n * Useful for public data that can be accessed without authentication\n */\n protected getAnonymousState(): Partial<State> {\n const anonymous: Partial<State> = {};\n const metadata = this.propertyMetadata || this.metadata;\n\n for (const key in this.internalState) {\n const meta = metadata[key as keyof State];\n if (meta?.anonymous === true) {\n anonymous[key as keyof State] = this.internalState[key];\n }\n }\n\n return anonymous;\n }\n\n /**\n * Get persistent state (only persisted properties)\n * Uses propertyMetadata if available, falls back to legacy metadata\n */\n protected getPersistentState(): Partial<State> {\n const persistent: Partial<State> = {};\n const metadata = this.propertyMetadata || this.metadata;\n\n for (const key in this.internalState) {\n const meta = metadata[key as keyof State];\n if (meta?.persist === true) {\n persistent[key as keyof State] = this.internalState[key];\n }\n }\n\n return persistent;\n }\n\n /**\n * Validate state using metadata validators\n * Override this method to add custom validation logic\n *\n * @param state - State to validate\n * @returns Validated state or throws error\n */\n protected async validateState(state: Partial<State>): Promise<State> {\n // Merge with current state as fallback\n const validatedState = { ...this.internalState, ...state } as State;\n const metadata = this.propertyMetadata;\n\n // Run validators\n for (const key in metadata) {\n const meta = metadata[key as keyof State];\n if (meta?.validator && key in validatedState) {\n const value = validatedState[key as keyof State];\n const isValid = meta.validator(value);\n if (!isValid) {\n throw new Error(\n `Validation failed for property \"${String(key)}\" in controller \"${this.name}\"`\n );\n }\n }\n\n // Check required properties\n if (meta?.required && !(key in validatedState)) {\n throw new Error(\n `Required property \"${String(key)}\" is missing in controller \"${this.name}\"`\n );\n }\n }\n\n return validatedState;\n }\n\n /**\n * Migrate state from an old version to the current version\n * Override this method to handle version-specific migrations\n *\n * @param oldState - State from previous version\n * @param fromVersion - Version number of old state\n * @returns Migrated state\n */\n protected async migrateState(\n oldState: any,\n fromVersion: number\n ): Promise<State> {\n let migratedState = { ...oldState };\n const metadata = this.propertyMetadata;\n\n // Run migrators for each property\n for (const key in metadata) {\n const meta = metadata[key as keyof State];\n if (meta?.migrator && key in migratedState) {\n migratedState[key] = meta.migrator(migratedState[key], fromVersion);\n }\n }\n\n // Validate migrated state\n return this.validateState(migratedState);\n }\n\n /**\n * Restore state from persisted data\n * Handles validation and migration automatically\n *\n * @param persistedState - Persisted state data\n * @param version - Version of persisted state\n * @returns Restored and validated state\n */\n protected async restoreState(\n persistedState: Partial<State>,\n version?: number\n ): Promise<State> {\n const currentVersion = (this.constructor as typeof BaseController).VERSION;\n let stateToRestore = persistedState;\n\n // Migrate if needed\n if (version !== undefined && version < currentVersion) {\n stateToRestore = await this.migrateState(persistedState, version);\n }\n\n // Validate\n const validatedState = await this.validateState(stateToRestore);\n\n // Store previous state before update\n const prevState = this.internalState;\n\n // Update internal state\n this.internalState = validatedState;\n\n // Emit state change event\n this.messenger.publish(`${this.name}:stateChange` as any, {\n prevState,\n newState: validatedState,\n });\n\n return validatedState;\n }\n\n /**\n * Check if state should be migrated\n */\n protected needsMigration(persistedVersion?: number): boolean {\n const currentVersion = (this.constructor as typeof BaseController).VERSION;\n return persistedVersion !== undefined && persistedVersion < currentVersion;\n }\n\n /**\n * Get controller version\n */\n getVersion(): number {\n return (this.constructor as typeof BaseController).VERSION;\n }\n\n /**\n * Persist current state to storage (if persistence service is available)\n *\n * @returns True if persisted successfully, false otherwise\n */\n async persist(): Promise<boolean> {\n if (!this.persistenceService) {\n return false;\n }\n\n try {\n const metadata = this.propertyMetadata || this.metadata;\n const version = this.getVersion();\n\n await this.persistenceService.persistController(\n this.name,\n this.internalState,\n metadata,\n version\n );\n\n return true;\n } catch (error) {\n console.error(`[${this.name}] Failed to persist state:`, error);\n return false;\n }\n }\n\n /**\n * Load persisted state from storage (if persistence service is available)\n *\n * @returns True if loaded successfully, false otherwise\n */\n async loadPersistedState(): Promise<boolean> {\n if (!this.persistenceService) {\n return false;\n }\n\n try {\n const metadata = this.propertyMetadata || this.metadata;\n const currentVersion = this.getVersion();\n\n const persistedState = await this.persistenceService.restoreController(\n this.name,\n metadata,\n currentVersion\n );\n\n if (persistedState) {\n // Use restoreState to validate and migrate\n const persistedVersion = this.persistenceService.getPersistedVersion?.(this.name) ?? currentVersion;\n await this.restoreState(persistedState, persistedVersion);\n return true;\n }\n\n return false;\n } catch (error) {\n console.error(`[${this.name}] Failed to load persisted state:`, error);\n return false;\n }\n }\n}\n","import type {\n ActionConstraint,\n ActionHandler,\n EventConstraint,\n EventListener,\n RestrictedControllerMessenger,\n} from './types';\n\n/**\n * ControllerMessenger - Type-safe message bus for controller communication\n *\n * Provides two mechanisms for inter-controller communication:\n * 1. Actions (RPC-style) - Synchronous or async function calls\n * 2. Events (pub/sub) - Asynchronous event notifications\n *\n * Features:\n * - Compile-time type safety for all actions and events\n * - Namespace-based action/event identification (prevents collisions)\n * - Restricted messengers limit controller access (principle of least privilege)\n * - Automatic cleanup via unsubscribe functions\n *\n * @template Actions - All available actions in the system\n * @template Events - All available events in the system\n *\n * @example\n * ```typescript\n * // Define actions and events\n * type MyActions = {\n * 'WalletController:getBalance': (address: string) => Promise<string>;\n * 'TokenController:getPrice': (symbol: string) => Promise<number>;\n * };\n *\n * type MyEvents = {\n * 'WalletController:balanceUpdated': { address: string; balance: string };\n * 'TokenController:priceUpdated': { symbol: string; price: number };\n * };\n *\n * // Create messenger\n * const messenger = new ControllerMessenger<MyActions, MyEvents>();\n *\n * // Register action handler\n * messenger.registerActionHandler(\n * 'WalletController:getBalance',\n * async (address) => {\n * return '1000000000000000000'; // 1 ETH in wei\n * }\n * );\n *\n * // Call action (type-safe)\n * const balance = await messenger.call('WalletController:getBalance', '0x123...');\n * // balance is typed as string\n *\n * // Subscribe to event\n * messenger.subscribe('WalletController:balanceUpdated', (payload) => {\n * console.log(`Balance updated: ${payload.balance}`);\n * });\n *\n * // Publish event\n * messenger.publish('WalletController:balanceUpdated', {\n * address: '0x123...',\n * balance: '2000000000000000000'\n * });\n * ```\n */\nexport class ControllerMessenger<\n Actions extends ActionConstraint,\n Events extends EventConstraint\n> {\n /**\n * Registered action handlers\n * Map: action name -> handler function\n */\n private actionHandlers = new Map<\n keyof Actions,\n ActionHandler<any[], any>\n >();\n\n /**\n * Event subscriptions\n * Map: event name -> Set of listener functions\n */\n private eventSubscriptions = new Map<\n keyof Events,\n Set<EventListener<any>>\n >();\n\n /**\n * Register an action handler\n *\n * @param action - Action name (must be unique)\n * @param handler - Handler function\n * @throws Error if action is already registered\n *\n * @example\n * ```typescript\n * messenger.registerActionHandler(\n * 'WalletController:createWallet',\n * async (mnemonic: string) => {\n * // Create wallet logic\n * return { id: '123', address: '0xabc...' };\n * }\n * );\n * ```\n */\n registerActionHandler<Action extends keyof Actions>(\n action: Action,\n handler: Actions[Action] extends ActionHandler<infer P, infer R>\n ? ActionHandler<P, R>\n : never\n ): void {\n if (this.actionHandlers.has(action)) {\n throw new Error(\n `Action handler for \"${String(action)}\" is already registered`\n );\n }\n this.actionHandlers.set(action, handler as ActionHandler<any[], any>);\n }\n\n /**\n * Unregister an action handler\n *\n * @param action - Action name to unregister\n *\n * @example\n * ```typescript\n * messenger.unregisterActionHandler('WalletController:createWallet');\n * ```\n */\n unregisterActionHandler<Action extends keyof Actions>(\n action: Action\n ): void {\n this.actionHandlers.delete(action);\n }\n\n /**\n * Call an action (RPC-style)\n *\n * @param action - Action name to call\n * @param params - Action parameters\n * @returns Action result (typed based on action definition)\n * @throws Error if action is not registered\n *\n * @example\n * ```typescript\n * // Synchronous action\n * const wallet = messenger.call('WalletController:getActiveWallet');\n *\n * // Asynchronous action\n * const balance = await messenger.call(\n * 'WalletController:getBalance',\n * '0x123...'\n * );\n * ```\n */\n call<Action extends keyof Actions>(\n action: Action,\n ...params: any[]\n ): any {\n const handler = this.actionHandlers.get(action);\n\n if (!handler) {\n throw new Error(\n `Action handler for \"${String(action)}\" is not registered`\n );\n }\n\n try {\n return handler(...params);\n } catch (error) {\n console.error(`Error executing action \"${String(action)}\":`, error);\n throw error;\n }\n }\n\n /**\n * Subscribe to an event\n *\n * @param event - Event name to subscribe to\n * @param listener - Listener function\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * const unsubscribe = messenger.subscribe(\n * 'WalletController:balanceUpdated',\n * (payload) => {\n * console.log(`New balance: ${payload.balance}`);\n * }\n * );\n *\n * // Later, unsubscribe\n * unsubscribe();\n * ```\n */\n subscribe<Event extends keyof Events>(\n event: Event,\n listener: any\n ): () => void {\n if (!this.eventSubscriptions.has(event)) {\n this.eventSubscriptions.set(event, new Set());\n }\n\n const listeners = this.eventSubscriptions.get(event)!;\n listeners.add(listener as EventListener<any>);\n\n // Return unsubscribe function\n return () => {\n this.unsubscribe(event, listener);\n };\n }\n\n /**\n * Unsubscribe from an event\n *\n * @param event - Event name\n * @param listener - Listener function to remove\n *\n * @example\n * ```typescript\n * const listener = (payload) => console.log(payload);\n * messenger.subscribe('WalletController:balanceUpdated', listener);\n *\n * // Later...\n * messenger.unsubscribe('WalletController:balanceUpdated', listener);\n * ```\n */\n unsubscribe<Event extends keyof Events>(\n event: Event,\n listener: any\n ): void {\n const listeners = this.eventSubscriptions.get(event);\n if (listeners) {\n listeners.delete(listener as EventListener<any>);\n if (listeners.size === 0) {\n this.eventSubscriptions.delete(event);\n }\n }\n }\n\n /**\n * Publish an event (pub/sub)\n *\n * All subscribed listeners are called asynchronously.\n * Errors in listeners are caught and logged to prevent one listener from affecting others.\n *\n * @param event - Event name to publish\n * @param payload - Event payload\n *\n * @example\n * ```typescript\n * messenger.publish('WalletController:balanceUpdated', {\n * address: '0x123...',\n * balance: '1000000000000000000'\n * });\n * ```\n */\n publish<Event extends keyof Events>(\n event: Event,\n payload: any\n ): void {\n const listeners = this.eventSubscriptions.get(event);\n\n if (listeners && listeners.size > 0) {\n // Call listeners in next tick to avoid blocking\n Promise.resolve().then(() => {\n listeners.forEach((listener) => {\n try {\n listener(payload);\n } catch (error) {\n console.error(\n `Error in event listener for \"${String(event)}\":`,\n error\n );\n }\n });\n });\n }\n }\n\n /**\n * Clear all subscriptions for an event\n *\n * @param event - Event name\n *\n * @example\n * ```typescript\n * messenger.clearEventSubscriptions('WalletController:balanceUpdated');\n * ```\n */\n clearEventSubscriptions<Event extends keyof Events>(event: Event): void {\n this.eventSubscriptions.delete(event);\n }\n\n /**\n * Get a restricted messenger for a controller\n *\n * Restricted messengers enforce the principle of least privilege:\n * - Controllers can only call actions they're explicitly allowed to call\n * - Controllers can only subscribe to events they're explicitly allowed to subscribe to\n * - Controllers can only publish events in their own namespace\n * - Controllers can only register actions in their own namespace\n *\n * @param options - Restriction configuration\n * @returns Restricted messenger instance\n *\n * @example\n * ```typescript\n * const walletMessenger = messenger.getRestricted({\n * name: 'WalletController',\n * allowedActions: ['WalletController:createWallet', 'WalletController:getBalance'],\n * allowedEvents: ['WalletController:balanceUpdated'],\n * externalActions: ['NetworkController:getActiveNetwork'],\n * externalEvents: ['NetworkController:networkChanged']\n * });\n *\n * // WalletController can now:\n * // - Register WalletController actions\n * // - Call WalletController and NetworkController actions\n * // - Publish WalletController events\n * // - Subscribe to WalletController and NetworkController events\n * ```\n */\n getRestricted<\n ControllerName extends string,\n AllowedActions extends Partial<Actions> = {},\n AllowedEvents extends Partial<Events> = {},\n ExternalActions extends Partial<Actions> = {},\n ExternalEvents extends Partial<Events> = {}\n >(options: {\n name: ControllerName;\n allowedActions?: (keyof AllowedActions)[];\n allowedEvents?: (keyof AllowedEvents)[];\n externalActions?: (keyof ExternalActions)[];\n externalEvents?: (keyof ExternalEvents)[];\n }): RestrictedControllerMessenger<\n ControllerName,\n Pick<Actions, Extract<keyof AllowedActions, keyof Actions>>,\n Pick<Events, Extract<keyof AllowedEvents, keyof Events>>,\n Pick<Actions, Extract<keyof ExternalActions, keyof Actions>>,\n Pick<Events, Extract<keyof ExternalEvents, keyof Events>>\n > {\n const {\n name,\n allowedActions = [],\n allowedEvents = [],\n externalActions = [],\n externalEvents = [],\n } = options;\n\n // Combine allowed and external actions/events\n const allAllowedActions = new Set([\n ...allowedActions,\n ...externalActions,\n ] as string[]);\n const allAllowedEvents = new Set([\n ...allowedEvents,\n ...externalEvents,\n ] as string[]);\n\n return {\n call: ((action: string, ...params: any[]) => {\n if (!allAllowedActions.has(action)) {\n throw new Error(\n `Controller \"${name}\" is not allowed to call action \"${action}\"`\n );\n }\n return this.call(action as keyof Actions, ...params);\n }) as any,\n\n registerActionHandler: ((action: string, handler: any) => {\n // Can only register actions in own namespace\n const actionNamespace = String(action).split(':')[0];\n if (actionNamespace !== name) {\n throw new Error(\n `Controller \"${name}\" can only register actions in its own namespace (${name}:*), attempted to register \"${action}\"`\n );\n }\n\n if (!allowedActions.includes(action as any)) {\n throw new Error(\n `Controller \"${name}\" is not allowed to register action \"${action}\"`\n );\n }\n\n return this.registerActionHandler(action as keyof Actions, handler);\n }) as any,\n\n unregisterActionHandler: ((action: string) => {\n const actionNamespace = String(action).split(':')[0];\n if (actionNamespace !== name) {\n throw new Error(\n `Controller \"${name}\" can only unregister actions in its own namespace`\n );\n }\n\n return this.unregisterActionHandler(action as keyof Actions);\n }) as any,\n\n publish: ((event: string, payload: any) => {\n // Can only publish events in own namespace\n const eventNamespace = String(event).split(':')[0];\n if (eventNamespace !== name) {\n throw new Error(\n `Controller \"${name}\" can only publish events in its own namespace (${name}:*), attempted to publish \"${event}\"`\n );\n }\n\n if (!allowedEvents.includes(event as any)) {\n throw new Error(\n `Controller \"${name}\" is not allowed to publish event \"${event}\"`\n );\n }\n\n return this.publish(event as keyof Events, payload);\n }) as any,\n\n subscribe: ((event: string, listener: any) => {\n if (!allAllowedEvents.has(event)) {\n throw new Error(\n `Controller \"${name}\" is not allowed to subscribe to event \"${event}\"`\n );\n }\n\n return this.subscribe(event as keyof Events, listener);\n }) as any,\n\n unsubscribe: ((event: string, listener: any) => {\n if (!allAllowedEvents.has(event)) {\n throw new Error(\n `Controller \"${name}\" is not allowed to unsubscribe from event \"${event}\"`\n );\n }\n\n return this.unsubscribe(event as keyof Events, listener);\n }) as any,\n\n clearEventSubscriptions: ((event: string) => {\n if (!allAllowedEvents.has(event)) {\n throw new Error(\n `Controller \"${name}\" is not allowed to clear event subscriptions for \"${event}\"`\n );\n }\n\n return this.clearEventSubscriptions(event as keyof Events);\n }) as any,\n };\n }\n\n /**\n * Get all registered action names\n * Useful for debugging and inspection\n */\n getRegisteredActions(): string[] {\n return Array.from(this.actionHandlers.keys()).map(String);\n }\n\n /**\n * Get all events that have active subscriptions\n * Useful for debugging and inspection\n */\n getActiveEvents(): string[] {\n return Array.from(this.eventSubscriptions.keys()).map(String);\n }\n\n /**\n * Get subscriber count for an event\n * Useful for debugging\n */\n getSubscriberCount<Event extends keyof Events>(event: Event): number {\n return this.eventSubscriptions.get(event)?.size ?? 0;\n }\n\n /**\n * Clear all action handlers and event subscriptions\n * Useful for cleanup and testing\n */\n clear(): void {\n this.actionHandlers.clear();\n this.eventSubscriptions.clear();\n }\n}\n","import type { StatePropertyMetadata, ControllerState } from '@eztra/controller';\n\n/**\n * IStorage interface - Platform-agnostic storage abstraction\n */\nexport interface IStorage {\n set(key: string, value: string | number | boolean): void;\n getString(key: string): string | undefined;\n getNumber(key: string): number | undefined;\n getBoolean(key: string): boolean | undefined;\n delete(key: string): void;\n contains(key: string): boolean;\n clearAll(): void;\n getAllKeys(): string[];\n}\n\n/**\n * Persisted state wrapper with version info\n */\nexport interface PersistedStateWrapper<T> {\n data: Partial<T>;\n version: number;\n timestamp: number;\n}\n\n/**\n * StatePersistenceService - Handles state serialization, deserialization, and migration\n *\n * Features:\n * - Schema-based persistence (only saves properties with persist: true)\n * - Version tracking and migration support\n * - Automatic serialization/deserialization\n * - Error recovery with fallback to default state\n *\n * @example\n * ```typescript\n * const persistenceService = new StatePersistenceService(storage);\n *\n * // Persist controller state\n * await persistenceService.persistController(\n * 'WalletController',\n * walletState,\n * walletMetadata,\n * 1 // version\n * );\n *\n * // Restore controller state\n * const restored = await persistenceService.restoreController(\n * 'WalletController',\n * walletMetadata,\n * 1 // current version\n * );\n * ```\n */\nexport class StatePersistenceService {\n constructor(private storage: IStorage) {}\n\n /**\n * Persist controller state to storage\n *\n * Only properties with `persist: true` in metadata are saved.\n *\n * @param controllerName - Unique identifier for the controller\n * @param state - Full controller state\n * @param metadata - State property metadata (defines what to persist)\n * @param version - State version number\n */\n async persistController<T extends ControllerState>(\n controllerName: string,\n state: T,\n metadata: StatePropertyMetadata<T>,\n version: number\n ): Promise<void> {\n try {\n // Extract only persistable properties\n const persistableState = this.extractPersistableState(state, metadata);\n\n // Wrap with version and timestamp\n const wrapper: PersistedStateWrapper<T> = {\n data: persistableState,\n version,\n timestamp: Date.now(),\n };\n\n // Serialize and save\n const serialized = JSON.stringify(wrapper);\n const key = this.getStorageKey(controllerName);\n this.storage.set(key, serialized);\n } catch (error) {\n console.error(\n `[StatePersistenceService] Failed to persist state for ${controllerName}:`,\n error\n );\n throw error;\n }\n }\n\n /**\n * Restore controller state from storage\n *\n * Handles version mismatches and runs migrations if needed.\n *\n * @param controllerName - Unique identifier for the controller\n * @param metadata - State property metadata (for migration)\n * @param currentVersion - Current version of the controller\n * @returns Restored state or null if not found\n */\n async restoreController<T extends ControllerState>(\n controllerName: string,\n metadata: StatePropertyMetadata<T>,\n currentVersion: number\n ): Promise<Partial<T> | null> {\n try {\n const key = this.getStorageKey(controllerName);\n const serialized = this.storage.getString(key);\n\n if (!serialized) {\n console.log(\n `[StatePersistenceService] No persisted state found for ${controllerName}`\n );\n return null;\n }\n\n // Deserialize\n const wrapper = JSON.parse(serialized) as PersistedStateWrapper<T>;\n\n // Check if migration is needed\n if (wrapper.version < currentVersion) {\n console.log(\n `[StatePersistenceService] Migrating ${controllerName} state from v${wrapper.version} to v${currentVersion}`\n );\n return this.migrateState(wrapper.data, wrapper.version, currentVersion, metadata);\n }\n\n return wrapper.data;\n } catch (error) {\n console.error(\n `[StatePersistenceService] Failed to restore state for ${controllerName}:`,\n error\n );\n return null;\n }\n }\n\n /**\n * Delete persisted state for a controller\n *\n * @param controllerName - Unique identifier for the controller\n */\n async deleteController(controllerName: string): Promise<void> {\n const key = this.getStorageKey(controllerName);\n this.storage.delete(key);\n }\n\n /**\n * Check if persisted state exists for a controller\n *\n * @param controllerName - Unique identifier for the controller\n * @returns True if state exists\n */\n hasPersistedState(controllerName: string): boolean {\n const key = this.getStorageKey(controllerName);\n return this.storage.contains(key);\n }\n\n /**\n * Get the version of persisted state\n *\n * @param controllerName - Unique identifier for the controller\n * @returns Version number or null if not found\n */\n getPersistedVersion(controllerName: string): number | null {\n try {\n const key = this.getStorageKey(controllerName);\n const serialized = this.storage.getString(key);\n\n if (!serialized) {\n return null;\n }\n\n const wrapper = JSON.parse(serialized) as PersistedStateWrapper<any>;\n return wrapper.version;\n } catch (error) {\n console.error(\n `[StatePersistenceService] Failed to get version for ${controllerName}:`,\n error\n );\n return null;\n }\n }\n\n /**\n * Clear all persisted controller states\n */\n async clearAll(): Promise<void> {\n const prefix = 'controller:';\n const allKeys = this.storage.getAllKeys();\n const controllerKeys = allKeys.filter((key) => key.startsWith(prefix));\n\n for (const key of controllerKeys) {\n this.storage.delete(key);\n }\n }\n\n /**\n * Extract persistable state based on metadata\n *\n * @private\n */\n private extractPersistableState<T extends ControllerState>(\n state: T,\n metadata: StatePropertyMetadata<T>\n ): Partial<T> {\n const persistable: Partial<T> = {};\n\n for (const key in metadata) {\n const meta = metadata[key as keyof T];\n if (meta?.persist === true && key in state) {\n persistable[key as keyof T] = state[key as keyof T];\n }\n }\n\n return persistable;\n }\n\n /**\n * Migrate state from old version to new version\n *\n * @private\n */\n private migrateState<T extends ControllerState>(\n oldState: Partial<T>,\n fromVersion: number,\n _toVersion: number,\n metadata: StatePropertyMetadata<T>\n ): Partial<T> {\n let migratedState = { ...oldState };\n\n // Run migrators for each property\n for (const key in metadata) {\n const meta = metadata[key as keyof T];\n if (meta?.migrator && key in migratedState) {\n try {\n const oldValue = migratedState[key as keyof T];\n const newValue = meta.migrator(oldValue, fromVersion);\n migratedState[key as keyof T] = newValue;\n } catch (error) {\n console.error(\n `[StatePersistenceService] Migration failed for property ${String(key)}:`,\n error\n );\n // Keep old value on migration failure\n }\n }\n }\n\n return migratedState;\n }\n\n /**\n * Get storage key for a controller\n *\n * @private\n */\n private getStorageKey(controllerName: string): string {\n return `controller:${controllerName}`;\n }\n}\n","import { BaseController } from '@eztra/controller';\nimport type {\n StatePropertyMetadata,\n RestrictedControllerMessenger,\n} from '@eztra/controller';\nimport type { RpcEndpoint } from './types';\nimport { RpcEndpointService } from './RpcEndpointService';\nimport { RpcManager } from './RpcManager';\n\n/**\n * NetworkController state\n */\nexport interface NetworkControllerState {\n /**\n * Index signature for ControllerState constraint\n */\n [key: string]: unknown;\n\n /**\n * Currently selected chain ID\n */\n selectedChainId: number;\n\n /**\n * Available RPC endpoints\n */\n rpcEndpoints: RpcEndpoint[];\n\n /**\n * Current RPC URL being used\n */\n currentRpcUrl: string | null;\n\n /**\n * Network loading state\n */\n isLoading: boolean;\n\n /**\n * Last error encountered\n */\n error: string | null;\n\n /**\n * Wallet index for RPC selection (round-robin)\n */\n walletIndex: number;\n}\n\n/**\n * NetworkController actions\n */\nexport type NetworkControllerActions = {\n 'NetworkController:setChainId': (chainId: number) => Promise<void>;\n 'NetworkController:getActiveChainId': () => number;\n 'NetworkController:getRpcUrl': (chainId: number) => string;\n 'NetworkController:refreshEndpoints': () => Promise<void>;\n 'NetworkController:setWalletIndex': (index: number) => void;\n};\n\n/**\n * NetworkController events\n */\nexport type NetworkControllerEvents = {\n 'NetworkController:stateChange': {\n prevState: NetworkControllerState;\n newState: NetworkControllerState;\n };\n 'NetworkController:chainChanged': {\n chainId: number;\n rpcUrl: string;\n };\n 'NetworkController:endpointsUpdated': {\n count: number;\n };\n};\n\n/**\n * NetworkController messenger type\n */\nexport type NetworkControllerMessenger = RestrictedControllerMessenger<\n 'NetworkController',\n NetworkControllerActions,\n NetworkControllerEvents,\n {}, // No external actions needed\n {} // No external events needed\n>;\n\n/**\n * NetworkController configuration\n */\nexport interface NetworkControllerConfig {\n messenger: NetworkControllerMessenger;\n persistenceService?: any;\n state?: Partial<NetworkControllerState>;\n defaultChainId?: number;\n}\n\n/**\n * NetworkController - Manages network selection and RPC endpoints\n *\n * Features:\n * - Chain selection (Ethereum, Solana, etc.)\n * - RPC endpoint management via RpcEndpointService\n * - Health-aware RPC selection via RpcManager\n * - Wallet-based round-robin distribution\n * - State persistence\n *\n * @example\n * ```typescript\n * const networkController = new NetworkController({\n * messenger: messenger.getRestricted({\n * name: 'NetworkController',\n * allowedActions: ['NetworkController:setChainId'],\n * allowedEvents: ['NetworkController:chainChanged'],\n * }),\n * persistenceService,\n * defaultChainId: 1, // Ethereum mainnet\n * });\n *\n * await networkController.initialize();\n *\n * // Switch chain\n * await networkController.setChainId(101); // Solana\n *\n * // Get current RPC\n * const rpcUrl = networkController.getRpcUrl(101);\n * ```\n */\nexport class NetworkController extends BaseController<\n 'NetworkController',\n NetworkControllerState,\n NetworkControllerMessenger\n> {\n static readonly VERSION = 1;\n\n readonly name = 'NetworkController' as const;\n\n readonly defaultState: NetworkControllerState = {\n selectedChainId: 1, // Ethereum mainnet default\n rpcEndpoints: [],\n currentRpcUrl: null,\n isLoading: false,\n error: null,\n walletIndex: 0,\n };\n\n protected propertyMetadata: StatePropertyMetadata<NetworkControllerState> = {\n selectedChainId: { persist: true, anonymous: false },\n rpcEndpoints: { persist: false, anonymous: true }, // Public data, fetched fresh\n currentRpcUrl: { persist: false, anonymous: true },\n isLoading: { persist: false, anonymous: true },\n error: { persist: false, anonymous: true },\n walletIndex: { persist: true, anonymous: false },\n };\n\n private rpcManager: RpcManager;\n\n constructor(config: NetworkControllerConfig) {\n super(\n {\n messenger: config.messenger,\n persistenceService: config.persistenceService,\n state: config.state,\n },\n {\n selectedChainId: config.defaultChainId ?? 1,\n rpcEndpoints: [],\n currentRpcUrl: null,\n isLoading: false,\n error: null,\n walletIndex: 0,\n }\n );\n\n this.rpcManager = new RpcManager();\n\n // Register actions\n this.registerActions();\n }\n\n /**\n * Register messenger actions\n */\n private registerActions(): void {\n this.messenger.registerActionHandler(\n 'NetworkController:setChainId',\n this.setChainId.bind(this)\n );\n\n this.messenger.registerActionHandler(\n 'NetworkController:getActiveChainId',\n this.getActiveChainId.bind(this)\n );\n\n this.messenger.registerActionHandler(\n 'NetworkController:getRpcUrl',\n this.getRpcUrl.bind(this)\n );\n\n this.messenger.registerActionHandler(\n 'NetworkController:refreshEndpoints',\n this.refreshEndpoints.bind(this)\n );\n\n this.messenger.registerActionHandler(\n 'NetworkController:setWalletIndex',\n this.setWalletIndex.bind(this)\n );\n }\n\n /**\n * Initialize controller - load RPC endpoints\n */\n async initialize(): Promise<void> {\n console.log('[NetworkController] Initializing...');\n\n // Load persisted state\n if (this.persistenceService) {\n await this.loadPersistedState();\n }\n\n // Fetch RPC endpoints from service\n await this.refreshEndpoints();\n\n console.log('[NetworkController] Initialized');\n }\n\n /**\n * Destroy controller - cleanup\n */\n override destroy(): void {\n this.messenger.unregisterActionHandler('NetworkController:setChainId');\n this.messenger.unregisterActionHandler('NetworkController:getActiveChainId');\n this.messenger.unregisterActionHandler('NetworkController:getRpcUrl');\n this.messenger.unregisterActionHandler('NetworkController:refreshEndpoints');\n this.messenger.unregisterActionHandler('NetworkController:setWalletIndex');\n\n super.destroy();\n }\n\n /**\n * Action: Set active chain ID\n */\n private async setChainId(chainId: number): Promise<void> {\n if (this.state.selectedChainId === chainId) {\n return; // No change\n }\n\n console.log(`[NetworkController] Switching to chain ${chainId}`);\n\n this.update({ isLoading: true, error: null });\n\n try {\n // Get RPC URL for new chain\n const rpcUrl = this.getRpcUrl(chainId);\n\n if (!rpcUrl) {\n throw new Error(`No RPC endpoint available for chain ${chainId}`);\n }\n\n // Update state\n this.update({\n selectedChainId: chainId,\n currentRpcUrl: rpcUrl,\n isLoading: false,\n });\n\n // Emit event\n this.messenger.publish('NetworkController:chainChanged', {\n chainId,\n rpcUrl,\n });\n\n // Persist\n if (this.persistenceService) {\n await this.persist();\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n this.update({\n isLoading: false,\n error: errorMessage,\n });\n throw error;\n }\n }\n\n /**\n * Action: Get active chain ID\n */\n private getActiveChainId(): number {\n return this.state.selectedChainId;\n }\n\n /**\n * Action: Get RPC URL for a chain\n */\n private getRpcUrl(chainId: number): string {\n const { rpcEndpoints, walletIndex } = this.state;\n\n // Use RpcManager to select healthy RPC\n const rpcUrl = this.rpcManager.getRpcForWalletIndex(\n chainId,\n rpcEndpoints,\n walletIndex\n );\n\n return rpcUrl;\n }\n\n /**\n * Action: Refresh RPC endpoints from service\n */\n private async refreshEndpoints(): Promise<void> {\n console.log('[NetworkController] Refreshing RPC endpoints...');\n\n this.update({ isLoading: true });\n\n try {\n // Fetch endpoints from RpcEndpointService\n const endpoints = await RpcEndpointService.getAll({});\n\n this.update({\n rpcEndpoints: endpoints || [],\n isLoading: false,\n error: null,\n });\n\n // Emit event\n this.messenger.publish('NetworkController:endpointsUpdated', {\n count: endpoints?.length || 0,\n });\n\n console.log(\n `[NetworkController] Loaded ${endpoints?.length || 0} RPC endpoints`\n );\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Failed to fetch endpoints';\n this.update({\n isLoading: false,\n error: errorMessage,\n });\n console.error('[NetworkController] Failed to refresh endpoints:', error);\n }\n }\n\n /**\n * Action: Set wallet index (affects RPC selection)\n */\n private setWalletIndex(index: number): void {\n if (this.state.walletIndex === index) {\n return;\n }\n\n this.update({ walletIndex: index });\n\n // Re-select RPC for current chain with new wallet index\n const rpcUrl = this.getRpcUrl(this.state.selectedChainId);\n if (rpcUrl && rpcUrl !== this.state.currentRpcUrl) {\n this.update({ currentRpcUrl: rpcUrl });\n }\n }\n}\n","/**\n * RPC Endpoint Service\n * Fetches RPC endpoints from GraphQL API\n */\n\nimport type { RpcEndpoint, RpcEndpointPageData, QueryGetListInput } from './types';\n\n// GraphQL query for fetching all RPC endpoints\nconst GET_ALL_RPC_ENDPOINTS_QUERY = `\n query GetAllRpcEndpoints($q: QueryGetListInput) {\n getAllRpcEndpoints(q: $q) {\n data {\n id\n createdAt\n updatedAt\n name\n rpcUrl\n chainId\n provider\n status\n }\n total\n pagination {\n limit\n offset\n page\n total\n }\n }\n }\n`;\n\n// GraphQL query for fetching one RPC endpoint\nconst GET_ONE_RPC_ENDPOINT_QUERY = `\n query GetOneRpcEndpoint($id: NonEmptyString!) {\n getOneRpcEndpoint(id: $id) {\n id\n createdAt\n updatedAt\n name\n rpcUrl\n chainId\n provider\n status\n }\n }\n`;\n\ninterface GraphQLResponse<T> {\n data?: T;\n errors?: Array<{ message: string }>;\n}\n\nexport class RpcEndpointService {\n private static apiUri: string = 'https://dev-api.eztra.io';\n\n /**\n * Set the API URI for GraphQL requests\n */\n static setApiUri(uri: string): void {\n RpcEndpointService.apiUri = uri;\n }\n\n /**\n * Get the current API URI\n */\n static getApiUri(): string {\n return RpcEndpointService.apiUri;\n }\n\n /**\n * Execute a GraphQL query\n */\n private static async executeQuery<T>(\n query: string,\n variables?: Record<string, unknown>\n ): Promise<T | null> {\n try {\n const response = await fetch(`${RpcEndpointService.apiUri}/graphql`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n query,\n variables,\n }),\n });\n\n if (!response.ok) {\n console.error('[RpcEndpointService] HTTP error:', response.status);\n return null;\n }\n\n const result = (await response.json()) as GraphQLResponse<T>;\n\n if (result.errors && result.errors.length > 0) {\n console.error('[RpcEndpointService] GraphQL errors:', result.errors);\n return null;\n }\n\n return result.data ?? null;\n } catch (error) {\n console.error('[RpcEndpointService] Request failed:', error);\n return null;\n }\n }\n\n /**\n * Get all RPC endpoints with optional filtering\n */\n static async getAll(\n query?: QueryGetListInput\n ): Promise<RpcEndpoint[] | null> {\n const result = await RpcEndpointService.executeQuery<{\n getAllRpcEndpoints: RpcEndpointPageData;\n }>(GET_ALL_RPC_ENDPOINTS_QUERY, { q: query });\n\n return result?.getAllRpcEndpoints?.data ?? null;\n }\n\n /**\n * Get all RPC endpoints with pagination info\n */\n static async getAllWithPagination(\n query?: QueryGetListInput\n ): Promise<RpcEndpointPageData | null> {\n const result = await RpcEndpointService.executeQuery<{\n getAllRpcEndpoints: RpcEndpointPageData;\n }>(GET_ALL_RPC_ENDPOINTS_QUERY, { q: query });\n\n return result?.getAllRpcEndpoints ?? null;\n }\n\n /**\n * Get a single RPC endpoint by ID\n */\n static async getOne(id: string): Promise<RpcEndpoint | null> {\n const result = await RpcEndpointService.executeQuery<{\n getOneRpcEndpoint: RpcEndpoint;\n }>(GET_ONE_RPC_ENDPOINT_QUERY, { id });\n\n return result?.getOneRpcEndpoint ?? null;\n }\n\n /**\n * Get RPC endpoints by chain ID\n */\n static async getByChainId(chainId: number): Promise<RpcEndpoint[] | null> {\n return RpcEndpointService.getAll({\n filter: { chainId },\n });\n }\n\n /**\n * Get active RPC endpoints\n */\n static async getActive(): Promise<RpcEndpoint[] | null> {\n return RpcEndpointService.getAll({\n filter: { status: 'ACTIVE' },\n });\n }\n\n /**\n * Get active RPC endpoints by chain ID\n */\n static async getActiveByChainId(\n chainId: number\n ): Promise<RpcEndpoint[] | null> {\n return RpcEndpointService.getAll({\n filter: { chainId, status: 'ACTIVE' },\n });\n }\n}\n","/**\n * RPC Manager\n * Manages RPC endpoint selection with health awareness and round-robin distribution\n */\n\nimport type { RpcEndpoint } from './types';\n\ninterface RpcHealth {\n url: string;\n isHealthy: boolean;\n lastChecked: number;\n responseTime: number;\n failureCount: number;\n}\n\nexport class RpcManager {\n private healthMap: Map<string, RpcHealth> = new Map();\n private healthCheckInterval: number = 30000; // 30 seconds\n private maxFailures: number = 3;\n\n /**\n * Get RPC URL for a specific wallet index (round-robin distribution)\n * @param chainId - Chain ID to get RPC for\n * @param endpoints - Available RPC endpoints\n * @param walletIndex - Wallet index for round-robin selection\n * @returns Selected RPC URL\n */\n getRpcForWalletIndex(\n chainId: number,\n endpoints: RpcEndpoint[],\n walletIndex: number\n ): string {\n // Filter endpoints by chain ID and active status\n const chainEndpoints = endpoints.filter(\n (ep) => ep.chainId === chainId && ep.status === 'ACTIVE' && ep.rpcUrl\n );\n\n if (chainEndpoints.length === 0) {\n console.warn(\n `[RpcManager] No active RPC endpoints found for chain ${chainId}`\n );\n return '';\n }\n\n // Get healthy endpoints\n const healthyEndpoints = chainEndpoints.filter((ep) =>\n this.isEndpointHealthy(ep.rpcUrl!)\n );\n\n // Use healthy endpoints if available, otherwise fall back to all endpoints\n const availableEndpoints =\n healthyEndpoints.length > 0 ? healthyEndpoints : chainEndpoints;\n\n // Round-robin selection based on wallet index\n const selectedIndex = walletIndex % availableEndpoints.length;\n const selectedEndpoint = availableEndpoints[selectedIndex];\n\n return selectedEndpoint.rpcUrl!;\n }\n\n /**\n * Get the best RPC URL for a chain (prioritizes healthy, low-latency endpoints)\n * @param chainId - Chain ID to get RPC for\n * @param endpoints - Available RPC endpoints\n * @returns Best RPC URL\n */\n getBestRpc(chainId: number, endpoints: RpcEndpoint[]): string {\n const chainEndpoints = endpoints.filter(\n (ep) => ep.chainId === chainId && ep.status === 'ACTIVE' && ep.rpcUrl\n );\n\n if (chainEndpoints.length === 0) {\n return '';\n }\n\n // Sort by health and response time\n const sorted = [...chainEndpoints].sort((a, b) => {\n const healthA = this.healthMap.get(a.rpcUrl!);\n const healthB = this.healthMap.get(b.rpcUrl!);\n\n // Prioritize healthy endpoints\n if (healthA?.isHealthy && !healthB?.isHealthy) return -1;\n if (!healthA?.isHealthy && healthB?.isHealthy) return 1;\n\n // Then by response time\n const timeA = healthA?.responseTime ?? Infinity;\n const timeB = healthB?.responseTime ?? Infinity;\n\n return timeA - timeB;\n });\n\n return sorted[0]?.rpcUrl ?? '';\n }\n\n /**\n * Check if an endpoint is healthy\n */\n private isEndpointHealthy(url: string): boolean {\n const health = this.healthMap.get(url);\n\n if (!health) {\n // No health data yet, assume healthy\n return true;\n }\n\n // Check if health data is stale\n const now = Date.now();\n if (now - health.lastChecked > this.healthCheckInterval) {\n // Stale data, assume healthy until next check\n return true;\n }\n\n return health.isHealthy;\n }\n\n /**\n * Mark an RPC endpoint as failed\n */\n markFailed(url: string): void {\n const existing = this.healthMap.get(url);\n const failureCount = (existing?.failureCount ?? 0) + 1;\n\n this.healthMap.set(url, {\n url,\n isHealthy: failureCount < this.maxFailures,\n lastChecked: Date.now(),\n responseTime: existing?.responseTime ?? Infinity,\n failureCount,\n });\n }\n\n /**\n * Mark an RPC endpoint as successful\n */\n markSuccess(url: string, responseTime: number): void {\n this.healthMap.set(url, {\n url,\n isHealthy: true,\n lastChecked: Date.now(),\n responseTime,\n failureCount: 0,\n });\n }\n\n /**\n * Reset health data for all endpoints\n */\n resetHealth(): void {\n this.healthMap.clear();\n }\n\n /**\n * Get health status for an endpoint\n */\n getHealth(url: string): RpcHealth | undefined {\n return this.healthMap.get(url);\n }\n\n /**\n * Get all health statuses\n */\n getAllHealth(): Map<string, RpcHealth> {\n return new Map(this.healthMap);\n }\n}\n","import {\n BaseController,\n type StatePropertyMetadata,\n type RestrictedControllerMessenger,\n} from '@eztra/controller';\nimport type {\n NetworkControllerActions,\n NetworkControllerEvents,\n} from '@eztra/network-controller';\n\n/**\n * Wallet account data\n */\nexport interface WalletAccount {\n index: number;\n name: string;\n addresses: {\n ethereum: string | null;\n solana: string | null;\n bitcoin: string | null;\n };\n balances: Record<string, string>; // chainId-tokenAddress -> balance\n isActive: boolean;\n}\n\n/**\n * WalletController state\n */\nexport interface WalletControllerState {\n /**\n * Index signature for ControllerState constraint\n */\n [key: string]: unknown;\n\n /**\n * All wallet accounts\n */\n wallets: WalletAccount[];\n\n /**\n * Currently selected wallet index\n */\n selectedWalletIndex: number;\n\n /**\n * Loading state\n */\n isLoading: boolean;\n\n /**\n * Last error\n */\n error: string | null;\n\n /**\n * Is wallet locked\n */\n isLocked: boolean;\n}\n\n/**\n * WalletController actions\n */\nexport type WalletControllerActions = {\n 'WalletController:addWallet': (wallet: WalletAccount) => Promise<void>;\n 'WalletController:selectWallet': (index: number) => Promise<void>;\n 'WalletController:getActiveWallet': () => WalletAccount | null;\n 'WalletController:lockWallet': () => void;\n 'WalletController:unlockWallet': (password: string) => Promise<boolean>;\n};\n\n/**\n * WalletController events\n */\nexport type WalletControllerEvents = {\n 'WalletController:stateChange': {\n prevState: WalletControllerState;\n newState: WalletControllerState;\n };\n 'WalletController:walletSelected': {\n index: number;\n wallet: WalletAccount;\n };\n 'WalletController:walletLocked': Record<string, never>;\n 'WalletController:walletUnlocked': Record<string, never>;\n};\n\n/**\n * WalletController messenger type\n *\n * Can call NetworkController actions and subscribe to its events\n */\nexport type WalletControllerMessenger = RestrictedControllerMessenger<\n 'WalletController',\n WalletControllerActions,\n WalletControllerEvents,\n NetworkControllerActions, // Can call NetworkController actions\n NetworkControllerEvents // Can subscribe to NetworkController events\n>;\n\n/**\n * WalletController configuration\n */\nexport interface WalletControllerConfig {\n messenger: WalletControllerMessenger;\n persistenceService?: any;\n state?: Partial<WalletControllerState>;\n}\n\n/**\n * WalletController - Manages wallet accounts and balances\n *\n * Features:\n * - Multi-wallet management\n * - Balance tracking per chain\n * - Inter-controller communication with NetworkController\n * - Lock/unlock functionality\n * - State persistence\n *\n * @example\n * ```typescript\n * const walletController = new WalletController({\n * messenger: messenger.getRestricted({\n * name: 'WalletController',\n * allowedActions: ['WalletController:selectWallet'],\n * allowedEvents: ['WalletController:walletSelected'],\n * externalActions: ['NetworkController:getActiveChainId'],\n * externalEvents: ['NetworkController:chainChanged'],\n * }),\n * persistenceService,\n * });\n *\n * await walletController.initialize();\n *\n * // Add wallet\n * await walletController.addWallet({\n * index: 0,\n * name: 'Main Wallet',\n * addresses: { ethereum: '0x...', solana: 'ABC...', bitcoin: null },\n * balances: {},\n * isActive: true,\n * });\n * ```\n */\nexport class WalletController extends BaseController<\n 'WalletController',\n WalletControllerState,\n WalletControllerMessenger\n> {\n static readonly VERSION = 1;\n\n readonly name = 'WalletController' as const;\n\n readonly defaultState: WalletControllerState = {\n wallets: [],\n selectedWalletIndex: 0,\n isLoading: false,\n error: null,\n isLocked: true,\n };\n\n protected propertyMetadata: StatePropertyMetadata<WalletControllerState> = {\n wallets: {\n persist: true,\n anonymous: false,\n required: false,\n },\n selectedWalletIndex: {\n persist: true,\n anonymous: false,\n },\n isLoading: {\n persist: false,\n anonymous: true,\n },\n error: {\n persist: false,\n anonymous: true,\n },\n isLocked: {\n persist: true,\n anonymous: false,\n },\n };\n\n constructor(config: WalletControllerConfig) {\n super(\n {\n messenger: config.messenger,\n persistenceService: config.persistenceService,\n state: config.state,\n },\n {\n wallets: [],\n selectedWalletIndex: 0,\n isLoading: false,\n error: null,\n isLocked: true,\n }\n );\n\n // Register actions\n this.registerActions();\n\n // Subscribe to external events\n this.subscribeToEvents();\n }\n\n /**\n * Register messenger actions\n */\n private registerActions(): void {\n this.messenger.registerActionHandler(\n 'WalletController:addWallet',\n this.addWallet.bind(this)\n );\n\n this.messenger.registerActionHandler(\n 'WalletController:selectWallet',\n this.selectWallet.bind(this)\n );\n\n this.messenger.registerActionHandler(\n 'WalletController:getActiveWallet',\n this.getActiveWallet.bind(this)\n );\n\n this.messenger.registerActionHandler(\n 'WalletController:lockWallet',\n this.lockWallet.bind(this)\n );\n\n this.messenger.registerActionHandler(\n 'WalletController:unlockWallet',\n this.unlockWallet.bind(this)\n );\n }\n\n /**\n * Subscribe to events from other controllers\n */\n private subscribeToEvents(): void {\n // Listen to network changes\n this.messenger.subscribe(\n 'NetworkController:chainChanged',\n this.onNetworkChanged.bind(this)\n );\n }\n\n /**\n * Initialize controller\n */\n async initialize(): Promise<void> {\n console.log('[WalletController] Initializing...');\n\n // Load persisted state\n if (this.persistenceService) {\n await this.loadPersistedState();\n }\n\n // Notify NetworkController about active wallet index\n const chainId = this.messenger.call('NetworkController:getActiveChainId');\n console.log(`[WalletController] Active chain: ${chainId}`);\n\n console.log('[WalletController] Initialized');\n }\n\n /**\n * Destroy controller\n */\n override destroy(): void {\n this.messenger.unregisterActionHandler('WalletController:addWallet');\n this.messenger.unregisterActionHandler('WalletController:selectWallet');\n this.messenger.unregisterActionHandler('WalletController:getActiveWallet');\n this.messenger.unregisterActionHandler('WalletController:lockWallet');\n this.messenger.unregisterActionHandler('WalletController:unlockWallet');\n\n super.destroy();\n }\n\n /**\n * Event handler: Network changed\n */\n private onNetworkChanged(event: { chainId: number; rpcUrl: string }): void {\n console.log(\n `[WalletController] Network changed to chain ${event.chainId}, may need to refresh balances`\n );\n\n // Could trigger balance refresh here\n // this.refreshBalances(event.chainId);\n }\n\n /**\n * Action: Add wallet\n */\n private async addWallet(wallet: WalletAccount): Promise<void> {\n console.log(`[WalletController] Adding wallet: ${wallet.name}`);\n\n const wallets = [...this.state.wallets, wallet];\n\n this.update({ wallets });\n\n // Persist\n if (this.persistenceService) {\n await this.persist();\n }\n }\n\n /**\n * Action: Select wallet\n */\n private async selectWallet(index: number): Promise<void> {\n if (index < 0 || index >= this.state.wallets.length) {\n throw new Error(`Invalid wallet index: ${index}`);\n }\n\n if (this.state.selectedWalletIndex === index) {\n return; // Already selected\n }\n\n const wallet = this.state.wallets[index];\n\n this.update({ selectedWalletIndex: index });\n\n // Emit event\n this.messenger.publish('WalletController:walletSelected', {\n index,\n wallet,\n });\n\n // Update NetworkController about wallet change (for RPC selection)\n this.messenger.call('NetworkController:setWalletIndex', index);\n\n // Persist\n if (this.persistenceService) {\n await this.persist();\n }\n\n console.log(`[WalletController] Selected wallet: ${wallet.name}`);\n }\n\n /**\n * Action: Get active wallet\n */\n private getActiveWallet(): WalletAccount | null {\n const { wallets, selectedWalletIndex } = this.state;\n\n if (wallets.length === 0) {\n return null;\n }\n\n return wallets[selectedWalletIndex] || null;\n }\n\n /**\n * Action: Lock wallet\n */\n private lockWallet(): void {\n this.update({ isLocked: true });\n\n this.messenger.publish('WalletController:walletLocked', {});\n\n console.log('[WalletController] Wallet locked');\n }\n\n /**\n * Action: Unlock wallet\n */\n private async unlockWallet(_password: string): Promise<boolean> {\n // TODO: Implement actual password verification\n // For now, just unlock\n this.update({ isLocked: false });\n\n this.messenger.publish('WalletController:walletUnlocked', {});\n\n console.log('[WalletController] Wallet unlocked');\n\n return true;\n }\n}\n","import { ControllerMessenger } from '@eztra/controller';\nimport { StatePersistenceService, type IStorage } from '@eztra/storage';\nimport {\n NetworkController,\n type NetworkControllerActions,\n type NetworkControllerEvents,\n} from '@eztra/network-controller';\nimport {\n WalletController,\n type WalletControllerActions,\n type WalletControllerEvents,\n} from '@eztra/wallet-controller';\nimport { ComposableController } from './ComposableController';\n\n/**\n * Combined actions from all controllers\n */\nexport type EztraEngineActions = NetworkControllerActions & WalletControllerActions;\n\n/**\n * Combined events from all controllers\n */\nexport type EztraEngineEvents = NetworkControllerEvents & WalletControllerEvents;\n\n/**\n * Engine configuration\n */\nexport interface EngineConfig {\n /**\n * Storage implementation\n */\n storage: IStorage;\n\n /**\n * Default chain ID\n */\n defaultChainId?: number;\n\n /**\n * Enable features\n */\n features?: {\n enablePersistence?: boolean;\n enableStateRestoration?: boolean;\n enableAutoSave?: boolean;\n };\n\n /**\n * Initial state for controllers\n */\n initialState?: {\n NetworkController?: any;\n WalletController?: any;\n };\n}\n\n/**\n * EztraEngine - Main engine class that orchestrates all controllers\n *\n * This is the primary entry point for initializing the Eztra Engine with\n * MetaMask-style controller architecture.\n *\n * Features:\n * - Automatic controller initialization\n * - Type-safe inter-controller communication\n * - Unified state management\n * - State persistence and restoration\n * - Lifecycle management\n *\n * @example\n * ```typescript\n * import { EztraEngine } from '@eztra/engine';\n * import { createWebStorage } from '@eztra/engine/storage/web';\n *\n * // Initialize engine\n * const engine = new EztraEngine({\n * storage: createWebStorage({ id: 'eztra' }),\n * defaultChainId: 1, // Ethereum\n * features: {\n * enablePersistence: true,\n * enableStateRestoration: true,\n * enableAutoSave: true,\n * },\n * });\n *\n * // Initialize all controllers\n * await engine.initialize();\n *\n * // Access controllers\n * const chainId = engine.call('NetworkController:getActiveChainId');\n * const wallet = engine.call('WalletController:getActiveWallet');\n *\n * // Subscribe to events\n * engine.subscribe('NetworkController:chainChanged', (event) => {\n * console.log('Chain changed:', event.chainId);\n * });\n *\n * // Get unified state\n * const state = engine.getState();\n * // { NetworkController: {...}, WalletController: {...} }\n * ```\n */\nexport class EztraEngine {\n private messenger: ControllerMessenger<EztraEngineActions, EztraEngineEvents>;\n private composableController: ComposableController;\n private persistenceService: StatePersistenceService;\n private initialized = false;\n\n // Public controller references\n public networkController: NetworkController;\n public walletController: WalletController;\n\n constructor(config: EngineConfig) {\n // Create global messenger\n this.messenger = new ControllerMessenger<\n EztraEngineActions,\n EztraEngineEvents\n >();\n\n // Create persistence service\n this.persistenceService = new StatePersistenceService(config.storage);\n\n // Create controllers with restricted messengers\n this.networkController = this.createNetworkController(config);\n this.walletController = this.createWalletController(config);\n\n // Create composable controller\n this.composableController = new ComposableController({\n messenger: this.messenger,\n persistenceService: this.persistenceService,\n features: config.features,\n });\n\n // Register controllers\n this.composableController.registerController(\n 'NetworkController',\n this.networkController\n );\n this.composableController.registerController(\n 'WalletController',\n this.walletController\n );\n }\n\n /**\n * Create NetworkController with restricted messenger\n *\n * @private\n */\n private createNetworkController(config: EngineConfig): NetworkController {\n return new NetworkController({\n messenger: this.messenger.getRestricted({\n name: 'NetworkController',\n allowedActions: [\n 'NetworkController:setChainId',\n 'NetworkController:getActiveChainId',\n 'NetworkController:getRpcUrl',\n 'NetworkController:refreshEndpoints',\n 'NetworkController:setWalletIndex',\n ],\n allowedEvents: [\n 'NetworkController:stateChange',\n 'NetworkController:chainChanged',\n 'NetworkController:endpointsUpdated',\n ],\n }),\n persistenceService: this.persistenceService,\n state: config.initialState?.NetworkController,\n defaultChainId: config.defaultChainId,\n });\n }\n\n /**\n * Create WalletController with restricted messenger\n *\n * @private\n */\n private createWalletController(config: EngineConfig): WalletController {\n return new WalletController({\n messenger: this.messenger.getRestricted({\n name: 'WalletController',\n allowedActions: [\n 'WalletController:addWallet',\n 'WalletController:selectWallet',\n 'WalletController:getActiveWallet',\n 'WalletController:lockWallet',\n 'WalletController:unlockWallet',\n ],\n allowedEvents: [\n 'WalletController:stateChange',\n 'WalletController:walletSelected',\n 'WalletController:walletLocked',\n 'WalletController:walletUnlocked',\n ],\n externalActions: [\n 'NetworkController:getActiveChainId',\n 'NetworkController:setWalletIndex',\n ],\n externalEvents: ['NetworkController:chainChanged'],\n }),\n persistenceService: this.persistenceService,\n state: config.initialState?.WalletController,\n });\n }\n\n /**\n * Initialize the engine and all controllers\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n console.warn('[EztraEngine] Already initialized');\n return;\n }\n\n console.log('[EztraEngine] Initializing...');\n\n // Initialize all controllers via composable controller\n await this.composableController.initialize();\n\n this.initialized = true;\n console.log('[EztraEngine] Initialization complete');\n }\n\n /**\n * Start the engine\n */\n async start(): Promise<void> {\n if (!this.initialized) {\n await this.initialize();\n }\n\n await this.composableController.start();\n }\n\n /**\n * Stop the engine\n */\n async stop(): Promise<void> {\n await this.composableController.stop();\n }\n\n /**\n * Destroy the engine and cleanup\n */\n async destroy(): Promise<void> {\n await this.composableController.destroy();\n this.initialized = false;\n }\n\n /**\n * Get unified state from all controllers\n */\n getState(): Record<string, any> {\n return this.composableController.getState();\n }\n\n /**\n * Call an action\n */\n call<Action extends keyof EztraEngineActions>(\n action: Action,\n ...params: any[]\n ): any {\n return this.messenger.call(action, ...params);\n }\n\n /**\n * Subscribe to an event\n */\n subscribe<Event extends keyof EztraEngineEvents>(\n event: Event,\n listener: any\n ): () => void {\n return this.messenger.subscribe(event, listener);\n }\n\n /**\n * Get the global messenger (for advanced usage)\n */\n getMessenger(): ControllerMessenger<EztraEngineActions, EztraEngineEvents> {\n return this.messenger;\n }\n\n /**\n * Check if engine is initialized\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n}\n\n// ==================== Singleton Pattern ====================\n\nlet engineInstance: EztraEngine | null = null;\n\n/**\n * Initialize the Eztra Engine (singleton)\n *\n * @param config - Engine configuration\n * @returns Engine instance\n * @throws Error if already initialized\n *\n * @example\n * ```typescript\n * import { initializeEngine } from '@eztra/engine';\n *\n * const engine = await initializeEngine({\n * storage: createWebStorage({ id: 'eztra' }),\n * defaultChainId: 1,\n * });\n * ```\n */\nexport async function initializeEngine(config: EngineConfig): Promise<EztraEngine> {\n if (engineInstance) {\n throw new Error('Engine already initialized. Use getEngine() to access the instance.');\n }\n\n engineInstance = new EztraEngine(config);\n await engineInstance.initialize();\n\n return engineInstance;\n}\n\n/**\n * Get the initialized engine instance\n *\n * @returns Engine instance\n * @throws Error if not initialized\n */\nexport function getEngine(): EztraEngine {\n if (!engineInstance) {\n throw new Error('Engine not initialized. Call initializeEngine() first.');\n }\n\n return engineInstance;\n}\n\n/**\n * Check if engine is initialized\n */\nexport function isEngineInitialized(): boolean {\n return engineInstance !== null && engineInstance.isInitialized();\n}\n\n/**\n * Reset engine (for testing)\n */\nexport async function resetEngine(): Promise<void> {\n if (engineInstance) {\n await engineInstance.destroy();\n engineInstance = null;\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eztra.services/engine",
3
- "version": "1.0.0-dev.20260202085509",
3
+ "version": "1.0.0-dev.20260202093252",
4
4
  "description": "Eztra Engine - Composable controller system",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -21,17 +21,15 @@
21
21
  ],
22
22
  "author": "Eztra Team",
23
23
  "license": "MIT",
24
- "dependencies": {
25
- "@eztra/controller": "1.0.0",
26
- "@eztra/network-controller": "1.0.0",
27
- "@eztra/wallet-controller": "1.0.0",
28
- "@eztra/storage": "1.0.0"
29
- },
30
24
  "devDependencies": {
31
25
  "@types/node": "^20.0.0",
32
26
  "tsup": "^8.0.0",
33
27
  "typescript": "^5.9.3",
34
- "vitest": "^3.2.4"
28
+ "vitest": "^3.2.4",
29
+ "@eztra/controller": "1.0.0",
30
+ "@eztra/network-controller": "1.0.0",
31
+ "@eztra/storage": "1.0.0",
32
+ "@eztra/wallet-controller": "1.0.0"
35
33
  },
36
34
  "scripts": {
37
35
  "build": "tsup",