{
  "version": 3,
  "sources": ["../../src/lib/2.app/flows/registry/setup-registry.ts"],
  "sourcesContent": ["import type {\n  NFEventConsumer,\n  NFEventData,\n  NFEventProvider,\n  NFEventUnsubscribe,\n} from '../../../1.domain/registry/event.contract';\nimport type { ForManagingEvents } from 'lib/2.app/driver-ports/registry/for-managing-events.port';\nimport type { NFEventRegistryConfig } from 'lib/2.app/config/registry.contract';\n\nexport function createRegistry(opts: NFEventRegistryConfig): ForManagingEvents {\n  // resources\n  const resources = new Map<string, unknown>();\n  const pending = new Map<string, Set<NFEventConsumer<any>>>();\n\n  // events\n  const events = new Map<string, NFEventData[]>();\n  const listeners = new Map<string, Set<NFEventConsumer<NFEventData<any>>>>();\n  const recentlyUsedEvents = new Set<string>();\n\n  const REMOVE_EVENTS = Math.ceil(opts.maxEvents * opts.removePercentage);\n\n  /**\n   * RESOURCE: Register a resource by name. If the resource is a provider function, it is\n   * invoked to obtain the actual resource. All callbacks waiting for this\n   * resource via `onReady` are invoked once the resource is registered.\n   */\n  const register = async <T>(type: string, resource: T | NFEventProvider<T>): Promise<void> => {\n    const value =\n      typeof resource === 'function' ? await (resource as NFEventProvider<T>)() : resource;\n\n    resources.set(type, value);\n\n    const callbacks = pending.get(type);\n    if (callbacks) {\n      pending.delete(type);\n      callbacks.forEach(cb => cb(value));\n    }\n  };\n\n  /**\n   * RESOURCE: Subscribe to the readiness of a resource. If the resource is already\n   * registered, the callback is invoked immediately. Otherwise, the callback\n   * is invoked once the resource is registered.\n   */\n  const onReady = <T>(type: string, callback: NFEventConsumer<T>): NFEventUnsubscribe => {\n    const existing = resources.get(type);\n    if (existing !== undefined) {\n      callback(existing as T);\n      return () => {};\n    }\n\n    let callbacks = pending.get(type);\n    if (!callbacks) {\n      callbacks = new Set();\n      pending.set(type, callbacks);\n    }\n    callbacks.add(callback);\n\n    return () => {\n      callbacks!.delete(callback);\n      if (callbacks!.size === 0) {\n        pending.delete(type);\n      }\n    };\n  };\n\n  /**\n   * EVENT: Subscribe to events of a specific type. The callback is invoked for all\n   * past events of that type, and for all future events.\n   */\n  const on = <T>(type: string, callback: NFEventConsumer<NFEventData<T>>): NFEventUnsubscribe => {\n    const history = events.get(type);\n    const historyCopy = history ? [...history] : null;\n\n    let typeListeners = listeners.get(type);\n    if (!typeListeners) {\n      typeListeners = new Set();\n      listeners.set(type, typeListeners);\n    }\n    typeListeners.add(callback);\n\n    if (historyCopy && historyCopy.length > 0) {\n      queueMicrotask(() => {\n        historyCopy.forEach(event => callback(event));\n      });\n    }\n\n    return () => {\n      typeListeners!.delete(callback);\n      if (typeListeners!.size === 0) {\n        listeners.delete(type);\n      }\n    };\n  };\n\n  /**\n   * Emit an event of a specific type with associated data. The event is stored\n   * in the history for that type, and all listeners subscribed to that type are\n   * invoked with the new event. If the number of stored events exceeds\n   * the maximum, the oldest events are removed based on the configured\n   * removal percentage. If the number of event types exceeds the maximum,\n   * the oldest event type and its history are removed.\n   */\n  const emit = <T>(type: string, data: T): void => {\n    const event: NFEventData<T> = {\n      data,\n      timestamp: Date.now(),\n    };\n\n    recentlyUsedEvents.delete(type);\n    recentlyUsedEvents.add(type);\n\n    if (recentlyUsedEvents.size > opts.maxStreams) {\n      const oldest = recentlyUsedEvents.values().next().value;\n      if (oldest) {\n        recentlyUsedEvents.delete(oldest);\n        events.delete(oldest);\n      }\n    }\n\n    let history = events.get(type) || [];\n    history.push(event);\n\n    if (history.length > opts.maxEvents) {\n      history = history.slice(-(opts.maxEvents - REMOVE_EVENTS));\n    }\n\n    events.set(type, history);\n\n    const typeListeners = listeners.get(type);\n    if (typeListeners && typeListeners.size > 0) {\n      typeListeners.forEach(listener => listener(event));\n    }\n  };\n\n  const clear = (type?: string): void => {\n    if (type) {\n      // Clear event-related data\n      events.delete(type);\n      listeners.delete(type);\n\n      // Clear resource-related data\n      resources.delete(type);\n      pending.delete(type);\n\n      recentlyUsedEvents.delete(type);\n    } else {\n      // Clear all data\n      events.clear();\n      listeners.clear();\n      pending.clear();\n      resources.clear();\n      recentlyUsedEvents.clear();\n    }\n  };\n\n  return () => ({\n    register,\n    onReady,\n    emit,\n    on,\n    clear,\n  });\n}\n"],
  "mappings": "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",
  "names": []
}
