diff --git a/src/services/moduleService.ts b/src/services/moduleService.ts index 1d4d6e0..f237d8d 100644 --- a/src/services/moduleService.ts +++ b/src/services/moduleService.ts @@ -42,11 +42,12 @@ function listenerKey (moduleName: string, event: string): string { return `${moduleName}::${event}` } -function ensureEventDispatcher (rpc: ModuleRpc): void { - if (wiredInstances.has(rpc as object)) { +export function attachModuleEventDispatcher (rpcInstance: object): void { + if (wiredInstances.has(rpcInstance)) { return } - wiredInstances.add(rpc as object) + wiredInstances.add(rpcInstance) + const rpc = rpcInstance as ModuleRpc rpc.onModuleEvent(({ module, event, payload }) => { const set = listeners.get(listenerKey(module, event)) if (set === undefined || set.size === 0) { @@ -105,7 +106,7 @@ export class ModuleService { set.add(listener) void requireInitialized() - .then((rpc) => { ensureEventDispatcher(rpc as unknown as ModuleRpc) }) + .then((rpc) => { attachModuleEventDispatcher(rpc as unknown as object) }) .catch(() => { /* worklet not ready yet; init will attach the dispatcher */ }) return () => { diff --git a/src/services/workletLifecycleService.ts b/src/services/workletLifecycleService.ts index 5459fe8..920cabc 100644 --- a/src/services/workletLifecycleService.ts +++ b/src/services/workletLifecycleService.ts @@ -32,6 +32,7 @@ import type { WorkletState } from '../store/workletStore' import HRPC from '@tetherto/pear-wrk-wdk/hrpc' import { createResolvablePromise } from '../utils/promise' import { bumpEpoch } from '../utils/workletEpoch' +import { attachModuleEventDispatcher } from './moduleService' /** * Worklet Lifecycle Service @@ -120,6 +121,7 @@ export class WorkletLifecycleService { } const hrpcInstance = new HRPC(IPC) + attachModuleEventDispatcher(hrpcInstance) const result = await hrpcInstance.workletStart({ config: JSON.stringify(wdkConfigs), diff --git a/tests/services/moduleService.test.ts b/tests/services/moduleService.test.ts index f1ce7b9..b6d8b45 100644 --- a/tests/services/moduleService.test.ts +++ b/tests/services/moduleService.test.ts @@ -17,7 +17,7 @@ * Module-agnostic: it only forwards callModule/lifecycle/events by name. */ -import { ModuleService } from '../../src/services/moduleService' +import { attachModuleEventDispatcher, ModuleService } from '../../src/services/moduleService' import { requireInitialized } from '../../src/utils/storeHelpers' jest.mock('../../src/utils/storeHelpers', () => ({ @@ -72,6 +72,13 @@ describe('ModuleService', () => { }) describe('onModuleEvent', () => { + it('attaches eagerly without requiring an application listener', () => { + attachModuleEventDispatcher(mockHRPC) + attachModuleEventDispatcher(mockHRPC) + + expect(mockHRPC.onModuleEvent).toHaveBeenCalledTimes(1) + }) + it('fans out worklet events to subscribers and stops after unsubscribe', async () => { let dispatch: ((evt: { module: string, event: string, payload?: string | null }) => void) | undefined mockHRPC.onModuleEvent.mockImplementation((cb: typeof dispatch) => { dispatch = cb }) diff --git a/tests/services/workletLifecycleService.test.ts b/tests/services/workletLifecycleService.test.ts index 59ca570..6cb537b 100644 --- a/tests/services/workletLifecycleService.test.ts +++ b/tests/services/workletLifecycleService.test.ts @@ -37,6 +37,7 @@ const mockWorkletStart = jest.fn(() => Promise.resolve({ status: 'success' })) const mockInitializeWDK = jest.fn(() => Promise.resolve({ status: 'success' })) const mockHRPCInstance = { workletStart: mockWorkletStart, + onModuleEvent: jest.fn(), ipc: mockWorkletInstance.IPC, initializeWDK: mockInitializeWDK, } @@ -210,9 +211,12 @@ describe('WorkletLifecycleService', () => { expect(HRPC).toHaveBeenCalledWith(mockWorkletInstance.IPC) + expect(mockHRPCInstance.onModuleEvent).toHaveBeenCalledTimes(1) expect(mockHRPCInstance.workletStart).toHaveBeenCalledWith({ config: JSON.stringify(defaultNetworkConfigs), }) + expect(mockHRPCInstance.onModuleEvent.mock.invocationCallOrder[0]) + .toBeLessThan(mockHRPCInstance.workletStart.mock.invocationCallOrder[0]) expect(mockStore.setState).toHaveBeenCalled()