diff --git a/NEXT_STEPS.md b/NEXT_STEPS.md index 9de068c..7c2aa42 100644 --- a/NEXT_STEPS.md +++ b/NEXT_STEPS.md @@ -20,6 +20,7 @@ Estado al cierre: - `arts/sess/engine-session.ts` delega snapshot, generation, dispatch, persistencia y commits en `session-state.ts`. - `arts/sess/engine-session.ts` delega la resolucion de revoke local/global/degradado en `session-revoke.ts`. - `arts/conn/connection.ts` delega la programacion de reconnect y exhaustion en `connection-reconnect-runtime.ts`. + - `arts/timr/engine-timers.ts` delega fan-out de listeners y diagnostico de listeners en `timer-events.ts`. - Integracion total ampliada: `Auth.signOut()` valida anonimizacion, invalidacion de `Permissions` y evento `Cache.invalidate`. - Tanda focalizada verde: `npx vitest run src/arts/conn src/libs/cach src/arts/cach src/svrs/cach src/arts/auth src/svrs/auth src/libs/auth src/arts/aapp/test/ecosystem.integration.test.ts` -> 19 archivos, 82 tests. - `/test/ecosystem` revisado en navegador: carga sin errores de consola, `ar` cambia a `rtl`, Formats se actualiza por locale, Perm cambia con rol `viewer`, Cach re-scopea por locale y Conn loopback publica/recibe. diff --git a/src/arts/timr/engine-timers.ts b/src/arts/timr/engine-timers.ts index cd05f4b..700fbae 100644 --- a/src/arts/timr/engine-timers.ts +++ b/src/arts/timr/engine-timers.ts @@ -51,6 +51,7 @@ import { timerEntrySnapshot, type InternalTimerEntry } from './timer-entry.ts'; +import { createTimerEventBus } from './timer-events.ts'; import { createTimerHandle } from './timer-handle.ts'; import { assertTimerDelay, @@ -66,7 +67,6 @@ import type { TimerHandle, TimerIntervalOptions, TimerKind, - TimerListener, TimerOptions, TimerTask, TimerTaskContext @@ -75,9 +75,9 @@ import type { export function createEngineTimers(options: EngineTimersOptions = {}): EngineTimers { const clock: TimerClock = options.clock ?? createSystemTimerClock(); const diagnostics = createTimerDiagnostics(options.logger); + const events = createTimerEventBus(diagnostics); const entries = new Map(); - const listeners = new Set(); let disposed = false; let nextId = 1; @@ -89,16 +89,7 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim // ── Listener fan-out ──────────────────────────────────────────────────── function emit(event: TimerEvent): void { - for (const listener of listeners) { - try { - listener(event); - } catch (err) { - emitTimerDiagnostic(diagnostics, TIMER_DIAGNOSTIC_EVENTS.LISTENER_THREW, { - error: err, - event: event.type - }); - } - } + events.emit(event); } // ── Entry lifecycle ───────────────────────────────────────────────────── @@ -421,10 +412,7 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim onChange(listener) { if (disposed) return () => {}; - listeners.add(listener); - return () => { - listeners.delete(listener); - }; + return events.on(listener); }, dispose() { @@ -434,7 +422,7 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim const all = Array.from(entries.values()); for (const entry of all) cancelEntry(entry); emit({ type: TIMER_EVENT_DISPOSED }); - listeners.clear(); + events.clear(); } }; diff --git a/src/arts/timr/timer-events.ts b/src/arts/timr/timer-events.ts new file mode 100644 index 0000000..3214e00 --- /dev/null +++ b/src/arts/timr/timer-events.ts @@ -0,0 +1,37 @@ +import { TIMER_DIAGNOSTIC_EVENTS } from './consts.ts'; +import { emitTimerDiagnostic, type TimerDiagnostics } from './diagnostics.ts'; +import type { TimerEvent, TimerListener } from './types.ts'; + +export interface TimerEventBus { + emit(event: TimerEvent): void; + on(listener: TimerListener): () => void; + clear(): void; +} + +export function createTimerEventBus(diagnostics: TimerDiagnostics): TimerEventBus { + const listeners = new Set(); + + return { + emit(event) { + for (const listener of listeners) { + try { + listener(event); + } catch (err) { + emitTimerDiagnostic(diagnostics, TIMER_DIAGNOSTIC_EVENTS.LISTENER_THREW, { + error: err, + event: event.type + }); + } + } + }, + on(listener) { + listeners.add(listener); + return () => { + listeners.delete(listener); + }; + }, + clear() { + listeners.clear(); + } + }; +}