abxbus 2.4.26 → 2.4.27

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.
Files changed (176) hide show
  1. package/dist/cjs/BaseEvent.d.ts +211 -0
  2. package/dist/cjs/{base_event.js → BaseEvent.js} +23 -23
  3. package/dist/cjs/BaseEvent.js.map +7 -0
  4. package/dist/cjs/EventBridge.d.ts +34 -0
  5. package/dist/cjs/EventBridge.js +295 -0
  6. package/dist/cjs/EventBridge.js.map +7 -0
  7. package/dist/cjs/EventBus.d.ts +125 -0
  8. package/dist/cjs/{event_bus.js → EventBus.js} +21 -21
  9. package/dist/cjs/EventBus.js.map +7 -0
  10. package/dist/cjs/EventBusMiddleware.d.ts +13 -0
  11. package/dist/cjs/EventBusMiddleware.js +17 -0
  12. package/dist/cjs/EventBusMiddleware.js.map +7 -0
  13. package/dist/cjs/EventHandler.d.ts +140 -0
  14. package/dist/cjs/{event_handler.js → EventHandler.js} +4 -4
  15. package/dist/cjs/EventHandler.js.map +7 -0
  16. package/dist/cjs/EventHistory.d.ts +45 -0
  17. package/dist/cjs/{event_history.js → EventHistory.js} +4 -4
  18. package/dist/cjs/EventHistory.js.map +7 -0
  19. package/dist/cjs/EventResult.d.ts +86 -0
  20. package/dist/cjs/{event_result.js → EventResult.js} +18 -16
  21. package/dist/cjs/EventResult.js.map +7 -0
  22. package/dist/cjs/HTTPEventBridge.d.ts +10 -0
  23. package/dist/cjs/HTTPEventBridge.js +37 -0
  24. package/dist/cjs/HTTPEventBridge.js.map +7 -0
  25. package/dist/cjs/JSONLEventBridge.d.ts +26 -0
  26. package/dist/cjs/{bridge_jsonl.js → JSONLEventBridge.js} +8 -8
  27. package/dist/cjs/JSONLEventBridge.js.map +7 -0
  28. package/dist/cjs/LockManager.d.ts +70 -0
  29. package/dist/cjs/{lock_manager.js → LockManager.js} +4 -4
  30. package/dist/cjs/LockManager.js.map +7 -0
  31. package/dist/cjs/NATSEventBridge.d.ts +20 -0
  32. package/dist/cjs/{bridge_nats.js → NATSEventBridge.js} +8 -8
  33. package/dist/cjs/NATSEventBridge.js.map +7 -0
  34. package/dist/cjs/OtelTracingMiddleware.d.ts +49 -0
  35. package/dist/cjs/{middleware_otel_tracing.js → OtelTracingMiddleware.js} +4 -4
  36. package/dist/cjs/OtelTracingMiddleware.js.map +7 -0
  37. package/dist/cjs/PostgresEventBridge.d.ts +31 -0
  38. package/dist/cjs/{bridge_postgres.js → PostgresEventBridge.js} +8 -8
  39. package/dist/cjs/PostgresEventBridge.js.map +7 -0
  40. package/dist/cjs/RedisEventBridge.d.ts +34 -0
  41. package/dist/cjs/{bridge_redis.js → RedisEventBridge.js} +8 -8
  42. package/dist/cjs/RedisEventBridge.js.map +7 -0
  43. package/dist/cjs/SQLiteEventBridge.d.ts +30 -0
  44. package/dist/cjs/{bridge_sqlite.js → SQLiteEventBridge.js} +8 -8
  45. package/dist/cjs/SQLiteEventBridge.js.map +7 -0
  46. package/dist/cjs/SocketEventBridge.d.ts +4 -0
  47. package/dist/cjs/SocketEventBridge.js +35 -0
  48. package/dist/cjs/SocketEventBridge.js.map +7 -0
  49. package/dist/cjs/bridge_ipc.d.ts +45 -0
  50. package/dist/cjs/bridges.d.ts +9 -49
  51. package/dist/cjs/bridges.js +16 -303
  52. package/dist/cjs/bridges.js.map +2 -2
  53. package/dist/cjs/events_suck.d.ts +2 -2
  54. package/dist/cjs/events_suck.js +4 -4
  55. package/dist/cjs/events_suck.js.map +2 -2
  56. package/dist/cjs/index.d.ts +15 -14
  57. package/dist/cjs/index.js +24 -24
  58. package/dist/cjs/index.js.map +2 -2
  59. package/dist/cjs/logging.d.ts +2 -2
  60. package/dist/cjs/logging.js +7 -7
  61. package/dist/cjs/logging.js.map +2 -2
  62. package/dist/cjs/middlewares.d.ts +1 -13
  63. package/dist/cjs/middlewares.js.map +1 -1
  64. package/dist/cjs/types.d.ts +1 -1
  65. package/dist/cjs/types.js.map +1 -1
  66. package/dist/esm/{base_event.js → BaseEvent.js} +4 -4
  67. package/dist/esm/BaseEvent.js.map +7 -0
  68. package/dist/esm/EventBridge.js +275 -0
  69. package/dist/esm/EventBridge.js.map +7 -0
  70. package/dist/esm/{event_bus.js → EventBus.js} +5 -5
  71. package/dist/esm/EventBus.js.map +7 -0
  72. package/dist/esm/EventBusMiddleware.js +1 -0
  73. package/dist/esm/EventBusMiddleware.js.map +7 -0
  74. package/dist/esm/{event_handler.js → EventHandler.js} +1 -1
  75. package/dist/esm/EventHandler.js.map +7 -0
  76. package/dist/esm/{event_history.js → EventHistory.js} +1 -1
  77. package/dist/esm/EventHistory.js.map +7 -0
  78. package/dist/esm/{event_result.js → EventResult.js} +7 -5
  79. package/dist/esm/EventResult.js.map +7 -0
  80. package/dist/esm/HTTPEventBridge.js +17 -0
  81. package/dist/esm/HTTPEventBridge.js.map +7 -0
  82. package/dist/esm/{bridge_jsonl.js → JSONLEventBridge.js} +3 -3
  83. package/dist/esm/JSONLEventBridge.js.map +7 -0
  84. package/dist/esm/{lock_manager.js → LockManager.js} +1 -1
  85. package/dist/esm/LockManager.js.map +7 -0
  86. package/dist/esm/{bridge_nats.js → NATSEventBridge.js} +3 -3
  87. package/dist/esm/NATSEventBridge.js.map +7 -0
  88. package/dist/esm/{middleware_otel_tracing.js → OtelTracingMiddleware.js} +1 -1
  89. package/dist/esm/OtelTracingMiddleware.js.map +7 -0
  90. package/dist/esm/{bridge_postgres.js → PostgresEventBridge.js} +3 -3
  91. package/dist/esm/PostgresEventBridge.js.map +7 -0
  92. package/dist/esm/{bridge_redis.js → RedisEventBridge.js} +3 -3
  93. package/dist/esm/RedisEventBridge.js.map +7 -0
  94. package/dist/esm/{bridge_sqlite.js → SQLiteEventBridge.js} +3 -3
  95. package/dist/esm/SQLiteEventBridge.js.map +7 -0
  96. package/dist/esm/SocketEventBridge.js +15 -0
  97. package/dist/esm/SocketEventBridge.js.map +7 -0
  98. package/dist/esm/bridges.js +9 -296
  99. package/dist/esm/bridges.js.map +2 -2
  100. package/dist/esm/events_suck.js +2 -2
  101. package/dist/esm/events_suck.js.map +1 -1
  102. package/dist/esm/index.js +11 -19
  103. package/dist/esm/index.js.map +2 -2
  104. package/dist/esm/logging.js +2 -2
  105. package/dist/esm/logging.js.map +1 -1
  106. package/dist/esm/types.js.map +1 -1
  107. package/dist/types/BaseEvent.d.ts +211 -0
  108. package/dist/types/EventBridge.d.ts +34 -0
  109. package/dist/types/EventBus.d.ts +125 -0
  110. package/dist/types/EventBusMiddleware.d.ts +13 -0
  111. package/dist/types/EventHandler.d.ts +140 -0
  112. package/dist/types/EventHistory.d.ts +45 -0
  113. package/dist/types/EventResult.d.ts +86 -0
  114. package/dist/types/HTTPEventBridge.d.ts +10 -0
  115. package/dist/types/JSONLEventBridge.d.ts +26 -0
  116. package/dist/types/LockManager.d.ts +70 -0
  117. package/dist/types/NATSEventBridge.d.ts +20 -0
  118. package/dist/types/OtelTracingMiddleware.d.ts +49 -0
  119. package/dist/types/PostgresEventBridge.d.ts +31 -0
  120. package/dist/types/RedisEventBridge.d.ts +34 -0
  121. package/dist/types/SQLiteEventBridge.d.ts +30 -0
  122. package/dist/types/SocketEventBridge.d.ts +4 -0
  123. package/dist/types/bridge_ipc.d.ts +45 -0
  124. package/dist/types/bridges.d.ts +9 -49
  125. package/dist/types/events_suck.d.ts +2 -2
  126. package/dist/types/index.d.ts +15 -14
  127. package/dist/types/logging.d.ts +2 -2
  128. package/dist/types/middlewares.d.ts +1 -13
  129. package/dist/types/types.d.ts +1 -1
  130. package/package.json +52 -10
  131. package/src/{base_event.ts → BaseEvent.ts} +5 -5
  132. package/src/EventBridge.ts +332 -0
  133. package/src/{event_bus.ts → EventBus.ts} +6 -6
  134. package/src/EventBusMiddleware.ts +16 -0
  135. package/src/{event_handler.ts → EventHandler.ts} +2 -2
  136. package/src/{event_history.ts → EventHistory.ts} +1 -1
  137. package/src/{event_result.ts → EventResult.ts} +8 -6
  138. package/src/HTTPEventBridge.ts +27 -0
  139. package/src/{bridge_jsonl.ts → JSONLEventBridge.ts} +2 -2
  140. package/src/{lock_manager.ts → LockManager.ts} +2 -2
  141. package/src/{bridge_nats.ts → NATSEventBridge.ts} +2 -2
  142. package/src/{middleware_otel_tracing.ts → OtelTracingMiddleware.ts} +4 -4
  143. package/src/{bridge_postgres.ts → PostgresEventBridge.ts} +2 -2
  144. package/src/{bridge_redis.ts → RedisEventBridge.ts} +2 -2
  145. package/src/{bridge_sqlite.ts → SQLiteEventBridge.ts} +2 -2
  146. package/src/SocketEventBridge.ts +13 -0
  147. package/src/bridges.ts +9 -376
  148. package/src/events_suck.ts +2 -2
  149. package/src/index.ts +15 -22
  150. package/src/logging.ts +3 -3
  151. package/src/middlewares.ts +1 -16
  152. package/src/types.ts +1 -1
  153. package/dist/cjs/base_event.js.map +0 -7
  154. package/dist/cjs/bridge_jsonl.js.map +0 -7
  155. package/dist/cjs/bridge_nats.js.map +0 -7
  156. package/dist/cjs/bridge_postgres.js.map +0 -7
  157. package/dist/cjs/bridge_redis.js.map +0 -7
  158. package/dist/cjs/bridge_sqlite.js.map +0 -7
  159. package/dist/cjs/event_bus.js.map +0 -7
  160. package/dist/cjs/event_handler.js.map +0 -7
  161. package/dist/cjs/event_history.js.map +0 -7
  162. package/dist/cjs/event_result.js.map +0 -7
  163. package/dist/cjs/lock_manager.js.map +0 -7
  164. package/dist/cjs/middleware_otel_tracing.js.map +0 -7
  165. package/dist/esm/base_event.js.map +0 -7
  166. package/dist/esm/bridge_jsonl.js.map +0 -7
  167. package/dist/esm/bridge_nats.js.map +0 -7
  168. package/dist/esm/bridge_postgres.js.map +0 -7
  169. package/dist/esm/bridge_redis.js.map +0 -7
  170. package/dist/esm/bridge_sqlite.js.map +0 -7
  171. package/dist/esm/event_bus.js.map +0 -7
  172. package/dist/esm/event_handler.js.map +0 -7
  173. package/dist/esm/event_history.js.map +0 -7
  174. package/dist/esm/event_result.js.map +0 -7
  175. package/dist/esm/lock_manager.js.map +0 -7
  176. package/dist/esm/middleware_otel_tracing.js.map +0 -7
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/LockManager.ts"],
4
+ "sourcesContent": ["import type { BaseEvent } from './BaseEvent.js'\nimport type { EventResult } from './EventResult.js'\nimport { createAsyncLocalStorage, type AsyncLocalStorageLike } from './async_context.js'\n\n// \u2500\u2500\u2500 Deferred / withResolvers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type Deferred<T> = {\n promise: Promise<T>\n resolve: (value: T | PromiseLike<T>) => void\n reject: (reason?: unknown) => void\n}\n\nexport const withResolvers = <T>(): Deferred<T> => {\n if (typeof Promise.withResolvers === 'function') {\n return Promise.withResolvers<T>()\n }\n let resolve!: (value: T | PromiseLike<T>) => void\n let reject!: (reason?: unknown) => void\n const promise = new Promise<T>((resolve_fn, reject_fn) => {\n resolve = resolve_fn\n reject = reject_fn\n })\n return { promise, resolve, reject }\n}\n\n// \u2500\u2500\u2500 Concurrency modes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const EVENT_CONCURRENCY_MODES = ['global-serial', 'bus-serial', 'parallel'] as const\nexport type EventConcurrencyMode = (typeof EVENT_CONCURRENCY_MODES)[number]\n\nexport const EVENT_HANDLER_CONCURRENCY_MODES = ['serial', 'parallel'] as const\nexport type EventHandlerConcurrencyMode = (typeof EVENT_HANDLER_CONCURRENCY_MODES)[number]\n\nexport const EVENT_HANDLER_COMPLETION_MODES = ['all', 'first'] as const\nexport type EventHandlerCompletionMode = (typeof EVENT_HANDLER_COMPLETION_MODES)[number]\n\n// \u2500\u2500\u2500 AsyncLock \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class AsyncLock {\n size: number\n in_use: number\n waiters: Array<() => void>\n\n constructor(size: number) {\n this.size = size\n this.in_use = 0\n this.waiters = []\n }\n\n async acquire(): Promise<void> {\n if (this.size === Infinity) {\n return\n }\n if (this.in_use < this.size) {\n this.in_use += 1\n return\n }\n await new Promise<void>((resolve) => {\n this.waiters.push(resolve)\n })\n }\n\n release(): void {\n if (this.size === Infinity) {\n return\n }\n const next = this.waiters.shift()\n if (next) {\n // Handoff: keep permit accounted for and transfer directly to next waiter.\n next()\n return\n }\n this.in_use = Math.max(0, this.in_use - 1)\n }\n}\n\nexport const runWithLock = async <T>(lock: AsyncLock | null, fn: () => Promise<T>): Promise<T> => {\n if (!lock) {\n return await fn()\n }\n await lock.acquire()\n try {\n return await fn()\n } finally {\n lock.release()\n }\n}\n\nconst handler_context_storage: AsyncLocalStorageLike | null = createAsyncLocalStorage()\n\n// \u2500\u2500\u2500 HandlerLock \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type HandlerExecutionState = 'held' | 'yielded' | 'closed'\n\n// Tracks a single handler execution's ownership of a handler lock.\n// Reacquire is race-safe: if the handler exits while waiting to reclaim,\n// the reclaimed lock is immediately released to avoid leaks.\nexport class HandlerLock {\n private lock: AsyncLock | null\n private state: HandlerExecutionState\n\n constructor(lock: AsyncLock | null) {\n this.lock = lock\n this.state = 'held'\n }\n\n // used by EventBus._processEventImmediately to yield the parent handler's lock to the child event so it can be processed immediately\n yieldHandlerLockForChildRun(): boolean {\n if (!this.lock || this.state !== 'held') {\n return false\n }\n this.state = 'yielded'\n this.lock.release()\n return true\n }\n\n // used by EventBus._processEventImmediately to reacquire the handler lock after the child event has been processed\n async reclaimHandlerLockIfRunning(): Promise<boolean> {\n if (!this.lock || this.state !== 'yielded') {\n return false\n }\n await this.lock.acquire()\n if (this.state !== 'yielded') {\n // Handler exited while this reacquire was pending.\n this.lock.release()\n return false\n }\n this.state = 'held'\n return true\n }\n\n // used by EventResult.runHandler to exit the handler lock after the handler has finished executing\n exitHandlerRun(): void {\n if (this.state === 'closed') {\n return\n }\n const should_release = !!this.lock && this.state === 'held'\n this.state = 'closed'\n if (should_release) {\n this.lock!.release()\n }\n }\n\n // used by EventBus._processEventImmediately to yield the handler lock and reacquire it after the child event has been processed\n async runQueueJump<T>(fn: () => Promise<T>): Promise<T> {\n const yielded = this.yieldHandlerLockForChildRun()\n try {\n return await fn()\n } finally {\n if (yielded) {\n await this.reclaimHandlerLockIfRunning()\n }\n }\n }\n}\n\n// \u2500\u2500\u2500 LockManager \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n// Interface that must be implemented by the EventBus class to be used by the LockManager\nexport type EventBusInterfaceForLockManager = {\n isIdleAndQueueEmpty: () => boolean\n event_concurrency: EventConcurrencyMode\n _lock_for_event_global_serial: AsyncLock\n}\n\nexport type LockManagerOptions = {\n auto_schedule_idle_checks?: boolean\n}\n\n// The LockManager is responsible for managing the concurrency of events and handlers\nexport class LockManager {\n private bus: EventBusInterfaceForLockManager // Live bus reference; used to read defaults and idle state.\n private auto_schedule_idle_checks: boolean\n\n readonly bus_event_lock: AsyncLock // Per-bus event lock; created with LockManager and never swapped.\n private pause_depth: number // Re-entrant pause counter; increments on _requestRunloopPause, decrements on release.\n private pause_waiters: Array<() => void> // Resolvers for _waitUntilRunloopResumed; drained when pause_depth hits 0.\n private active_handler_results: EventResult[] // Stack of active handler results for \"inside handler\" detection.\n\n private idle_waiters: Array<(became_idle: boolean) => void> // Resolvers waiting for stable idle; cleared when idle confirmed.\n private idle_check_pending: boolean // Debounce flag to avoid scheduling redundant idle checks.\n private idle_check_streak: number // Counts consecutive idle checks; used to require two ticks of idle.\n\n constructor(bus: EventBusInterfaceForLockManager, options: LockManagerOptions = {}) {\n this.bus = bus\n this.auto_schedule_idle_checks = options.auto_schedule_idle_checks ?? true\n this.bus_event_lock = new AsyncLock(1) // used for the bus-serial concurrency mode\n\n this.pause_depth = 0\n this.pause_waiters = []\n this.active_handler_results = []\n\n this.idle_waiters = []\n this.idle_check_pending = false\n this.idle_check_streak = 0\n }\n\n // Low-level runloop pause: increments a re-entrant counter and returns a release\n // function. Used for broad, bus-scoped pauses during queue-jump across buses.\n _requestRunloopPause(): () => void {\n this.pause_depth += 1\n let released = false\n return () => {\n if (released) {\n return\n }\n released = true\n this.pause_depth = Math.max(0, this.pause_depth - 1)\n if (this.pause_depth !== 0) {\n return\n }\n const waiters = this.pause_waiters\n this.pause_waiters = []\n for (const resolve of waiters) {\n resolve()\n }\n }\n }\n\n _waitUntilRunloopResumed(): Promise<void> {\n if (this.pause_depth === 0) {\n return Promise.resolve()\n }\n return new Promise((resolve) => {\n this.pause_waiters.push(resolve)\n })\n }\n\n _isPaused(): boolean {\n return this.pause_depth > 0\n }\n\n async _runWithHandlerDispatchContext<T>(result: EventResult, fn: () => Promise<T>): Promise<T> {\n this.active_handler_results.push(result)\n try {\n if (!handler_context_storage) {\n return await fn()\n }\n return await handler_context_storage.run(result, fn)\n } finally {\n const idx = this.active_handler_results.indexOf(result)\n if (idx >= 0) {\n this.active_handler_results.splice(idx, 1)\n }\n }\n }\n\n _getActiveHandlerResultForCurrentAsyncContext(): EventResult | undefined {\n const result = handler_context_storage?.getStore() as EventResult | undefined\n return result?.status === 'started' ? result : undefined\n }\n\n _getActiveHandlerResults(): EventResult[] {\n return [...this.active_handler_results]\n }\n\n // Per-bus check: true only if this specific bus has a handler on its stack.\n _isAnyHandlerActive(): boolean {\n return this.active_handler_results.length > 0\n }\n\n waitForIdle(timeout_seconds: number | null = null): Promise<boolean> {\n return new Promise((resolve) => {\n let done = false\n let timeout_id: ReturnType<typeof setTimeout> | null = null\n\n const finish = (became_idle: boolean): void => {\n if (done) {\n return\n }\n done = true\n if (timeout_id !== null) {\n clearTimeout(timeout_id)\n timeout_id = null\n }\n resolve(became_idle)\n }\n\n this.idle_waiters.push(finish)\n this.scheduleIdleCheck()\n\n if (timeout_seconds === null || timeout_seconds === undefined) {\n return\n }\n\n const timeout_ms = Math.max(0, Number(timeout_seconds)) * 1000\n if (!Number.isFinite(timeout_ms)) {\n return\n }\n\n timeout_id = setTimeout(() => {\n const index = this.idle_waiters.indexOf(finish)\n if (index >= 0) {\n this.idle_waiters.splice(index, 1)\n }\n finish(false)\n }, timeout_ms)\n })\n }\n\n // Called by EventBus.markEventCompleted and EventBus.markHandlerCompleted to notify\n // waitUntilIdle() callers that the bus may now be idle.\n _notifyIdleListeners(): void {\n // Fast-path: most completions have no waitUntilIdle() callers waiting,\n // so skip expensive idle snapshot scans in that common case.\n if (this.idle_waiters.length === 0) {\n this.idle_check_streak = 0\n return\n }\n\n if (!this.bus.isIdleAndQueueEmpty()) {\n this.idle_check_streak = 0\n if (this.idle_waiters.length > 0) {\n this.scheduleIdleCheck()\n }\n return\n }\n\n this.idle_check_streak += 1\n if (this.idle_check_streak < 2) {\n if (this.idle_waiters.length > 0) {\n this.scheduleIdleCheck()\n }\n return\n }\n\n this.idle_check_streak = 0\n const waiters = this.idle_waiters\n this.idle_waiters = []\n for (const resolve of waiters) {\n resolve(true)\n }\n }\n\n // get the bus-level lock that prevents/allows multiple events to be processed concurrently on the same bus\n getLockForEvent(event: BaseEvent): AsyncLock | null {\n const resolved = event.event_concurrency ?? this.bus.event_concurrency\n if (resolved === 'parallel') {\n return null\n }\n if (resolved === 'global-serial') {\n return this.bus._lock_for_event_global_serial\n }\n return this.bus_event_lock\n }\n\n async _runWithEventLock<T>(\n event: BaseEvent,\n fn: () => Promise<T>,\n options: { bypass_event_locks?: boolean; pre_acquired_lock?: AsyncLock | null } = {}\n ): Promise<T> {\n const pre_acquired = options.pre_acquired_lock ?? null\n if (options.bypass_event_locks || pre_acquired) {\n return await fn()\n }\n return await runWithLock(this.getLockForEvent(event), fn)\n }\n\n async _runWithHandlerLock<T>(\n event: BaseEvent,\n default_handler_concurrency: EventHandlerConcurrencyMode | undefined,\n fn: (lock: HandlerLock | null) => Promise<T>\n ): Promise<T> {\n const lock = event._getHandlerLock(default_handler_concurrency)\n if (lock) {\n await lock.acquire()\n }\n const handler_lock = lock ? new HandlerLock(lock) : null\n try {\n return await fn(handler_lock)\n } finally {\n handler_lock?.exitHandlerRun()\n }\n }\n\n // Schedules a debounced idle check to run after a short delay. Used to gate\n // waitUntilIdle() calls during handler execution and after event completion.\n private scheduleIdleCheck(): void {\n if (!this.auto_schedule_idle_checks) {\n return\n }\n if (this.idle_check_pending) {\n return\n }\n this.idle_check_pending = true\n setTimeout(() => {\n this.idle_check_pending = false\n this._notifyIdleListeners()\n }, 0)\n }\n\n // Reset all state to initial values\n clear(): void {\n this.pause_depth = 0\n this.pause_waiters = []\n this.active_handler_results = []\n this.idle_waiters = []\n this.idle_check_pending = false\n this.idle_check_streak = 0\n }\n}\n"],
5
+ "mappings": "AAEA,SAAS,+BAA2D;AAU7D,MAAM,gBAAgB,MAAsB;AACjD,MAAI,OAAO,QAAQ,kBAAkB,YAAY;AAC/C,WAAO,QAAQ,cAAiB;AAAA,EAClC;AACA,MAAI;AACJ,MAAI;AACJ,QAAM,UAAU,IAAI,QAAW,CAAC,YAAY,cAAc;AACxD,cAAU;AACV,aAAS;AAAA,EACX,CAAC;AACD,SAAO,EAAE,SAAS,SAAS,OAAO;AACpC;AAIO,MAAM,0BAA0B,CAAC,iBAAiB,cAAc,UAAU;AAG1E,MAAM,kCAAkC,CAAC,UAAU,UAAU;AAG7D,MAAM,iCAAiC,CAAC,OAAO,OAAO;AAKtD,MAAM,UAAU;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,MAAc;AACxB,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,UAAU,CAAC;AAAA,EAClB;AAAA,EAEA,MAAM,UAAyB;AAC7B,QAAI,KAAK,SAAS,UAAU;AAC1B;AAAA,IACF;AACA,QAAI,KAAK,SAAS,KAAK,MAAM;AAC3B,WAAK,UAAU;AACf;AAAA,IACF;AACA,UAAM,IAAI,QAAc,CAAC,YAAY;AACnC,WAAK,QAAQ,KAAK,OAAO;AAAA,IAC3B,CAAC;AAAA,EACH;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,SAAS,UAAU;AAC1B;AAAA,IACF;AACA,UAAM,OAAO,KAAK,QAAQ,MAAM;AAChC,QAAI,MAAM;AAER,WAAK;AACL;AAAA,IACF;AACA,SAAK,SAAS,KAAK,IAAI,GAAG,KAAK,SAAS,CAAC;AAAA,EAC3C;AACF;AAEO,MAAM,cAAc,OAAU,MAAwB,OAAqC;AAChG,MAAI,CAAC,MAAM;AACT,WAAO,MAAM,GAAG;AAAA,EAClB;AACA,QAAM,KAAK,QAAQ;AACnB,MAAI;AACF,WAAO,MAAM,GAAG;AAAA,EAClB,UAAE;AACA,SAAK,QAAQ;AAAA,EACf;AACF;AAEA,MAAM,0BAAwD,wBAAwB;AAS/E,MAAM,YAAY;AAAA,EACf;AAAA,EACA;AAAA,EAER,YAAY,MAAwB;AAClC,SAAK,OAAO;AACZ,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA,EAGA,8BAAuC;AACrC,QAAI,CAAC,KAAK,QAAQ,KAAK,UAAU,QAAQ;AACvC,aAAO;AAAA,IACT;AACA,SAAK,QAAQ;AACb,SAAK,KAAK,QAAQ;AAClB,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,8BAAgD;AACpD,QAAI,CAAC,KAAK,QAAQ,KAAK,UAAU,WAAW;AAC1C,aAAO;AAAA,IACT;AACA,UAAM,KAAK,KAAK,QAAQ;AACxB,QAAI,KAAK,UAAU,WAAW;AAE5B,WAAK,KAAK,QAAQ;AAClB,aAAO;AAAA,IACT;AACA,SAAK,QAAQ;AACb,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,iBAAuB;AACrB,QAAI,KAAK,UAAU,UAAU;AAC3B;AAAA,IACF;AACA,UAAM,iBAAiB,CAAC,CAAC,KAAK,QAAQ,KAAK,UAAU;AACrD,SAAK,QAAQ;AACb,QAAI,gBAAgB;AAClB,WAAK,KAAM,QAAQ;AAAA,IACrB;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,aAAgB,IAAkC;AACtD,UAAM,UAAU,KAAK,4BAA4B;AACjD,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,UAAE;AACA,UAAI,SAAS;AACX,cAAM,KAAK,4BAA4B;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AACF;AAgBO,MAAM,YAAY;AAAA,EACf;AAAA;AAAA,EACA;AAAA,EAEC;AAAA;AAAA,EACD;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EAER,YAAY,KAAsC,UAA8B,CAAC,GAAG;AAClF,SAAK,MAAM;AACX,SAAK,4BAA4B,QAAQ,6BAA6B;AACtE,SAAK,iBAAiB,IAAI,UAAU,CAAC;AAErC,SAAK,cAAc;AACnB,SAAK,gBAAgB,CAAC;AACtB,SAAK,yBAAyB,CAAC;AAE/B,SAAK,eAAe,CAAC;AACrB,SAAK,qBAAqB;AAC1B,SAAK,oBAAoB;AAAA,EAC3B;AAAA;AAAA;AAAA,EAIA,uBAAmC;AACjC,SAAK,eAAe;AACpB,QAAI,WAAW;AACf,WAAO,MAAM;AACX,UAAI,UAAU;AACZ;AAAA,MACF;AACA,iBAAW;AACX,WAAK,cAAc,KAAK,IAAI,GAAG,KAAK,cAAc,CAAC;AACnD,UAAI,KAAK,gBAAgB,GAAG;AAC1B;AAAA,MACF;AACA,YAAM,UAAU,KAAK;AACrB,WAAK,gBAAgB,CAAC;AACtB,iBAAW,WAAW,SAAS;AAC7B,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEA,2BAA0C;AACxC,QAAI,KAAK,gBAAgB,GAAG;AAC1B,aAAO,QAAQ,QAAQ;AAAA,IACzB;AACA,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,WAAK,cAAc,KAAK,OAAO;AAAA,IACjC,CAAC;AAAA,EACH;AAAA,EAEA,YAAqB;AACnB,WAAO,KAAK,cAAc;AAAA,EAC5B;AAAA,EAEA,MAAM,+BAAkC,QAAqB,IAAkC;AAC7F,SAAK,uBAAuB,KAAK,MAAM;AACvC,QAAI;AACF,UAAI,CAAC,yBAAyB;AAC5B,eAAO,MAAM,GAAG;AAAA,MAClB;AACA,aAAO,MAAM,wBAAwB,IAAI,QAAQ,EAAE;AAAA,IACrD,UAAE;AACA,YAAM,MAAM,KAAK,uBAAuB,QAAQ,MAAM;AACtD,UAAI,OAAO,GAAG;AACZ,aAAK,uBAAuB,OAAO,KAAK,CAAC;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAAA,EAEA,gDAAyE;AACvE,UAAM,SAAS,yBAAyB,SAAS;AACjD,WAAO,QAAQ,WAAW,YAAY,SAAS;AAAA,EACjD;AAAA,EAEA,2BAA0C;AACxC,WAAO,CAAC,GAAG,KAAK,sBAAsB;AAAA,EACxC;AAAA;AAAA,EAGA,sBAA+B;AAC7B,WAAO,KAAK,uBAAuB,SAAS;AAAA,EAC9C;AAAA,EAEA,YAAY,kBAAiC,MAAwB;AACnE,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAI,OAAO;AACX,UAAI,aAAmD;AAEvD,YAAM,SAAS,CAAC,gBAA+B;AAC7C,YAAI,MAAM;AACR;AAAA,QACF;AACA,eAAO;AACP,YAAI,eAAe,MAAM;AACvB,uBAAa,UAAU;AACvB,uBAAa;AAAA,QACf;AACA,gBAAQ,WAAW;AAAA,MACrB;AAEA,WAAK,aAAa,KAAK,MAAM;AAC7B,WAAK,kBAAkB;AAEvB,UAAI,oBAAoB,QAAQ,oBAAoB,QAAW;AAC7D;AAAA,MACF;AAEA,YAAM,aAAa,KAAK,IAAI,GAAG,OAAO,eAAe,CAAC,IAAI;AAC1D,UAAI,CAAC,OAAO,SAAS,UAAU,GAAG;AAChC;AAAA,MACF;AAEA,mBAAa,WAAW,MAAM;AAC5B,cAAM,QAAQ,KAAK,aAAa,QAAQ,MAAM;AAC9C,YAAI,SAAS,GAAG;AACd,eAAK,aAAa,OAAO,OAAO,CAAC;AAAA,QACnC;AACA,eAAO,KAAK;AAAA,MACd,GAAG,UAAU;AAAA,IACf,CAAC;AAAA,EACH;AAAA;AAAA;AAAA,EAIA,uBAA6B;AAG3B,QAAI,KAAK,aAAa,WAAW,GAAG;AAClC,WAAK,oBAAoB;AACzB;AAAA,IACF;AAEA,QAAI,CAAC,KAAK,IAAI,oBAAoB,GAAG;AACnC,WAAK,oBAAoB;AACzB,UAAI,KAAK,aAAa,SAAS,GAAG;AAChC,aAAK,kBAAkB;AAAA,MACzB;AACA;AAAA,IACF;AAEA,SAAK,qBAAqB;AAC1B,QAAI,KAAK,oBAAoB,GAAG;AAC9B,UAAI,KAAK,aAAa,SAAS,GAAG;AAChC,aAAK,kBAAkB;AAAA,MACzB;AACA;AAAA,IACF;AAEA,SAAK,oBAAoB;AACzB,UAAM,UAAU,KAAK;AACrB,SAAK,eAAe,CAAC;AACrB,eAAW,WAAW,SAAS;AAC7B,cAAQ,IAAI;AAAA,IACd;AAAA,EACF;AAAA;AAAA,EAGA,gBAAgB,OAAoC;AAClD,UAAM,WAAW,MAAM,qBAAqB,KAAK,IAAI;AACrD,QAAI,aAAa,YAAY;AAC3B,aAAO;AAAA,IACT;AACA,QAAI,aAAa,iBAAiB;AAChC,aAAO,KAAK,IAAI;AAAA,IAClB;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,kBACJ,OACA,IACA,UAAkF,CAAC,GACvE;AACZ,UAAM,eAAe,QAAQ,qBAAqB;AAClD,QAAI,QAAQ,sBAAsB,cAAc;AAC9C,aAAO,MAAM,GAAG;AAAA,IAClB;AACA,WAAO,MAAM,YAAY,KAAK,gBAAgB,KAAK,GAAG,EAAE;AAAA,EAC1D;AAAA,EAEA,MAAM,oBACJ,OACA,6BACA,IACY;AACZ,UAAM,OAAO,MAAM,gBAAgB,2BAA2B;AAC9D,QAAI,MAAM;AACR,YAAM,KAAK,QAAQ;AAAA,IACrB;AACA,UAAM,eAAe,OAAO,IAAI,YAAY,IAAI,IAAI;AACpD,QAAI;AACF,aAAO,MAAM,GAAG,YAAY;AAAA,IAC9B,UAAE;AACA,oBAAc,eAAe;AAAA,IAC/B;AAAA,EACF;AAAA;AAAA;AAAA,EAIQ,oBAA0B;AAChC,QAAI,CAAC,KAAK,2BAA2B;AACnC;AAAA,IACF;AACA,QAAI,KAAK,oBAAoB;AAC3B;AAAA,IACF;AACA,SAAK,qBAAqB;AAC1B,eAAW,MAAM;AACf,WAAK,qBAAqB;AAC1B,WAAK,qBAAqB;AAAA,IAC5B,GAAG,CAAC;AAAA,EACN;AAAA;AAAA,EAGA,QAAc;AACZ,SAAK,cAAc;AACnB,SAAK,gBAAgB,CAAC;AACtB,SAAK,yBAAyB,CAAC;AAC/B,SAAK,eAAe,CAAC;AACrB,SAAK,qBAAqB;AAC1B,SAAK,oBAAoB;AAAA,EAC3B;AACF;",
6
+ "names": []
7
+ }
@@ -1,5 +1,5 @@
1
- import { BaseEvent } from "./base_event.js";
2
- import { EventBus } from "./event_bus.js";
1
+ import { BaseEvent } from "./BaseEvent.js";
2
+ import { EventBus } from "./EventBus.js";
3
3
  import { assertOptionalDependencyAvailable, importOptionalDependency, isNodeRuntime } from "./optional_deps.js";
4
4
  const randomSuffix = () => Math.random().toString(36).slice(2, 10);
5
5
  class NATSEventBridge {
@@ -85,4 +85,4 @@ class NATSEventBridge {
85
85
  export {
86
86
  NATSEventBridge
87
87
  };
88
- //# sourceMappingURL=bridge_nats.js.map
88
+ //# sourceMappingURL=NATSEventBridge.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/NATSEventBridge.ts"],
4
+ "sourcesContent": ["import { BaseEvent } from './BaseEvent.js'\nimport { EventBus } from './EventBus.js'\nimport { assertOptionalDependencyAvailable, importOptionalDependency, isNodeRuntime } from './optional_deps.js'\nimport type { EventClass, EventHandlerCallable, EventPattern, UntypedEventHandlerFunction } from './types.js'\n\nconst randomSuffix = (): string => Math.random().toString(36).slice(2, 10)\n\nexport class NATSEventBridge {\n readonly server: string\n readonly subject: string\n readonly name: string\n\n private readonly inbound_bus: EventBus\n private running: boolean\n private nc: any | null\n private sub_task: Promise<void> | null\n\n constructor(server: string, subject: string, name?: string) {\n assertOptionalDependencyAvailable('NATSEventBridge', 'nats')\n\n this.server = server\n this.subject = subject\n this.name = name ?? `NATSEventBridge_${randomSuffix()}`\n this.inbound_bus = new EventBus(this.name, { max_history_size: 0 })\n this.running = false\n this.nc = null\n this.sub_task = null\n\n this.dispatch = this.dispatch.bind(this)\n this.emit = this.emit.bind(this)\n this.on = this.on.bind(this)\n }\n\n on<T extends BaseEvent>(event_pattern: EventClass<T>, handler: EventHandlerCallable<T>): void\n on<T extends BaseEvent>(event_pattern: string | '*', handler: UntypedEventHandlerFunction<T>): void\n on(event_pattern: EventPattern | '*', handler: EventHandlerCallable | UntypedEventHandlerFunction): void {\n this.ensureStarted()\n if (typeof event_pattern === 'string') {\n this.inbound_bus.on(event_pattern, handler as UntypedEventHandlerFunction<BaseEvent>)\n return\n }\n this.inbound_bus.on(event_pattern as EventClass<BaseEvent>, handler as EventHandlerCallable<BaseEvent>)\n }\n\n async emit<T extends BaseEvent>(event: T): Promise<void> {\n this.ensureStarted()\n if (!this.nc) await this.start()\n\n const payload = JSON.stringify(event.toJSON())\n this.nc.publish(this.subject, new TextEncoder().encode(payload))\n }\n\n async dispatch<T extends BaseEvent>(event: T): Promise<void> {\n return this.emit(event)\n }\n\n async start(): Promise<void> {\n if (this.running) return\n if (!isNodeRuntime()) {\n throw new Error('NATSEventBridge is only supported in Node.js runtimes')\n }\n\n const mod = await importOptionalDependency('NATSEventBridge', 'nats')\n const connect = mod.connect\n this.nc = await connect({ servers: this.server })\n const sub = this.nc.subscribe(this.subject)\n\n this.running = true\n this.sub_task = (async () => {\n for await (const msg of sub) {\n try {\n const payload = JSON.parse(new TextDecoder().decode(msg.data))\n await this.dispatchInboundPayload(payload)\n } catch {\n // Ignore malformed payloads.\n }\n }\n })()\n }\n\n async close(): Promise<void> {\n this.running = false\n if (this.nc) {\n await this.nc.drain()\n await this.nc.close()\n this.nc = null\n }\n await Promise.allSettled(this.sub_task ? [this.sub_task] : [])\n this.sub_task = null\n this.inbound_bus.destroy()\n }\n\n private ensureStarted(): void {\n if (this.running) return\n void this.start().catch((error: unknown) => {\n console.error('[abxbus] NATSEventBridge failed to start', error)\n })\n }\n\n private async dispatchInboundPayload(payload: unknown): Promise<void> {\n const event = BaseEvent.fromJSON(payload).eventReset()\n this.inbound_bus.emit(event)\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAC1B,SAAS,gBAAgB;AACzB,SAAS,mCAAmC,0BAA0B,qBAAqB;AAG3F,MAAM,eAAe,MAAc,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE;AAElE,MAAM,gBAAgB;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EAEQ;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,QAAgB,SAAiB,MAAe;AAC1D,sCAAkC,mBAAmB,MAAM;AAE3D,SAAK,SAAS;AACd,SAAK,UAAU;AACf,SAAK,OAAO,QAAQ,mBAAmB,aAAa,CAAC;AACrD,SAAK,cAAc,IAAI,SAAS,KAAK,MAAM,EAAE,kBAAkB,EAAE,CAAC;AAClE,SAAK,UAAU;AACf,SAAK,KAAK;AACV,SAAK,WAAW;AAEhB,SAAK,WAAW,KAAK,SAAS,KAAK,IAAI;AACvC,SAAK,OAAO,KAAK,KAAK,KAAK,IAAI;AAC/B,SAAK,KAAK,KAAK,GAAG,KAAK,IAAI;AAAA,EAC7B;AAAA,EAIA,GAAG,eAAmC,SAAmE;AACvG,SAAK,cAAc;AACnB,QAAI,OAAO,kBAAkB,UAAU;AACrC,WAAK,YAAY,GAAG,eAAe,OAAiD;AACpF;AAAA,IACF;AACA,SAAK,YAAY,GAAG,eAAwC,OAA0C;AAAA,EACxG;AAAA,EAEA,MAAM,KAA0B,OAAyB;AACvD,SAAK,cAAc;AACnB,QAAI,CAAC,KAAK,GAAI,OAAM,KAAK,MAAM;AAE/B,UAAM,UAAU,KAAK,UAAU,MAAM,OAAO,CAAC;AAC7C,SAAK,GAAG,QAAQ,KAAK,SAAS,IAAI,YAAY,EAAE,OAAO,OAAO,CAAC;AAAA,EACjE;AAAA,EAEA,MAAM,SAA8B,OAAyB;AAC3D,WAAO,KAAK,KAAK,KAAK;AAAA,EACxB;AAAA,EAEA,MAAM,QAAuB;AAC3B,QAAI,KAAK,QAAS;AAClB,QAAI,CAAC,cAAc,GAAG;AACpB,YAAM,IAAI,MAAM,uDAAuD;AAAA,IACzE;AAEA,UAAM,MAAM,MAAM,yBAAyB,mBAAmB,MAAM;AACpE,UAAM,UAAU,IAAI;AACpB,SAAK,KAAK,MAAM,QAAQ,EAAE,SAAS,KAAK,OAAO,CAAC;AAChD,UAAM,MAAM,KAAK,GAAG,UAAU,KAAK,OAAO;AAE1C,SAAK,UAAU;AACf,SAAK,YAAY,YAAY;AAC3B,uBAAiB,OAAO,KAAK;AAC3B,YAAI;AACF,gBAAM,UAAU,KAAK,MAAM,IAAI,YAAY,EAAE,OAAO,IAAI,IAAI,CAAC;AAC7D,gBAAM,KAAK,uBAAuB,OAAO;AAAA,QAC3C,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,GAAG;AAAA,EACL;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,UAAU;AACf,QAAI,KAAK,IAAI;AACX,YAAM,KAAK,GAAG,MAAM;AACpB,YAAM,KAAK,GAAG,MAAM;AACpB,WAAK,KAAK;AAAA,IACZ;AACA,UAAM,QAAQ,WAAW,KAAK,WAAW,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC;AAC7D,SAAK,WAAW;AAChB,SAAK,YAAY,QAAQ;AAAA,EAC3B;AAAA,EAEQ,gBAAsB;AAC5B,QAAI,KAAK,QAAS;AAClB,SAAK,KAAK,MAAM,EAAE,MAAM,CAAC,UAAmB;AAC1C,cAAQ,MAAM,4CAA4C,KAAK;AAAA,IACjE,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,uBAAuB,SAAiC;AACpE,UAAM,QAAQ,UAAU,SAAS,OAAO,EAAE,WAAW;AACrD,SAAK,YAAY,KAAK,KAAK;AAAA,EAC7B;AACF;",
6
+ "names": []
7
+ }
@@ -388,4 +388,4 @@ function recordSpanError(span, error) {
388
388
  export {
389
389
  OtelTracingMiddleware
390
390
  };
391
- //# sourceMappingURL=middleware_otel_tracing.js.map
391
+ //# sourceMappingURL=OtelTracingMiddleware.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/OtelTracingMiddleware.ts"],
4
+ "sourcesContent": ["import {\n ROOT_CONTEXT,\n SpanKind,\n SpanStatusCode,\n trace,\n type Context,\n type Span,\n type SpanAttributeValue,\n type SpanAttributes,\n type SpanContext,\n type TimeInput,\n type Tracer,\n} from '@opentelemetry/api'\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'\nimport { resourceFromAttributes } from '@opentelemetry/resources'\nimport { BasicTracerProvider, BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'\nimport type { SpanLimits, SpanProcessor } from '@opentelemetry/sdk-trace-base'\nimport { SpanImpl } from '@opentelemetry/sdk-trace-base/build/src/Span.js'\n\nimport type { BaseEvent } from './BaseEvent.js'\nimport type { EventBus } from './EventBus.js'\nimport type { EventResult } from './EventResult.js'\nimport type { EventBusMiddleware } from './EventBusMiddleware.js'\nimport type { EventStatus } from './types.js'\n\ntype OpenTelemetryTraceApi = Pick<typeof trace, 'getTracer' | 'setSpan'> & Partial<Pick<typeof trace, 'setSpanContext'>>\n\nexport type OtelTracingSpanFactoryInput = {\n name: string\n span_context: SpanContext\n parent_span_context?: SpanContext\n attributes: SpanAttributes\n start_time?: TimeInput\n}\n\nexport type OtelTracingSpanFactory = (input: OtelTracingSpanFactoryInput) => Span\n\ntype OtelTracingSpanProviderInternals = {\n _activeSpanProcessor?: SpanProcessor\n _config?: {\n resource?: unknown\n spanLimits?: SpanLimits\n }\n _resource?: unknown\n}\n\nexport type OtelTracingSpanProvider = object\n\nexport type OtelTracingMiddlewareOptions = {\n tracer?: Tracer\n trace_api?: OpenTelemetryTraceApi\n span_provider?: OtelTracingSpanProvider\n span_factory?: OtelTracingSpanFactory\n otlp_endpoint?: string\n service_name?: string\n instrumentation_name?: string\n root_span_attributes?: SpanAttributes | ((eventbus: EventBus, event: BaseEvent) => SpanAttributes)\n}\n\nexport class OtelTracingMiddleware implements EventBusMiddleware {\n private readonly tracer: Tracer\n private readonly trace_api: OpenTelemetryTraceApi\n private readonly span_factory?: OtelTracingSpanFactory\n private readonly span_provider?: OtelTracingSpanProvider\n private readonly root_span_attributes: OtelTracingMiddlewareOptions['root_span_attributes']\n private readonly event_spans = new Map<string, Span>()\n private readonly event_contexts = new Map<string, Context>()\n private readonly handler_spans = new Map<string, Span>()\n private readonly handler_contexts = new Map<string, Context>()\n\n constructor(options: OtelTracingMiddlewareOptions = {}) {\n this.trace_api = options.trace_api ?? trace\n this.tracer = options.tracer ?? this.trace_api.getTracer('abxbus')\n this.span_provider = options.span_provider ?? (options.otlp_endpoint ? createOtlpSpanProvider(options) : undefined)\n this.span_factory =\n options.span_factory ??\n (this.span_provider\n ? createProviderSpanFactory(this.trace_api, this.span_provider, options.instrumentation_name ?? 'abxbus')\n : undefined)\n this.root_span_attributes = options.root_span_attributes\n }\n\n onEventChange(eventbus: EventBus, event: BaseEvent, status: EventStatus): void {\n if (status === 'started') {\n if (this.span_factory) {\n return\n }\n this.startEventSpan(eventbus, event)\n return\n }\n\n if (status === 'completed') {\n this.completeEventSpan(eventbus, event)\n }\n }\n\n onEventResultChange(eventbus: EventBus, event: BaseEvent, event_result: EventResult, status: EventStatus): void {\n if (status === 'started') {\n if (this.span_factory) {\n return\n }\n this.startHandlerSpan(eventbus, event, event_result)\n return\n }\n\n if (status === 'completed') {\n this.completeHandlerSpan(eventbus, event, event_result)\n }\n }\n\n private startEventSpan(eventbus: EventBus, event: BaseEvent): Span {\n const existing = this.event_spans.get(event.event_id)\n if (existing) {\n return existing\n }\n\n const parent_context = this.parentContextForEvent(event) ?? ROOT_CONTEXT\n const start_time = timeInputFromIso(event.event_started_at)\n const span = this.tracer.startSpan(\n eventSpanName(eventbus, event),\n {\n attributes: event.event_parent_id\n ? eventStartedSpanAttributes(eventbus, event)\n : topLevelEventStartedSpanAttributes(this.root_span_attributes, eventbus, event),\n startTime: start_time,\n },\n parent_context\n )\n const span_context = this.trace_api.setSpan(parent_context, span)\n this.event_spans.set(event.event_id, span)\n this.event_contexts.set(event.event_id, span_context)\n return span\n }\n\n private completeEventSpan(eventbus: EventBus, event: BaseEvent): void {\n if (this.span_factory) {\n this.completeEventSpanWithFactory(eventbus, event)\n return\n }\n\n const span = this.event_spans.get(event.event_id) ?? this.startEventSpan(eventbus, event)\n if (event.event_errors.length > 0) {\n recordSpanError(span, event.event_errors[0])\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n span.setAttributes(\n event.event_parent_id ? eventSpanAttributes(eventbus, event) : topLevelEventSpanAttributes(this.root_span_attributes, eventbus, event)\n )\n const start_time = epochNsFromIso(event.event_started_at)\n const end_time = endTimeAfterStart(start_time, epochNsFromIso(event.event_completed_at))\n span.end(end_time)\n this.event_spans.delete(event.event_id)\n this.event_contexts.delete(event.event_id)\n }\n\n private startHandlerSpan(eventbus: EventBus, event: BaseEvent, event_result: EventResult): Span {\n const existing = this.handler_spans.get(event_result.id)\n if (existing) {\n return existing\n }\n\n const parent_context =\n this.event_contexts.get(event.event_id) ?? this.trace_api.setSpan(ROOT_CONTEXT, this.startEventSpan(eventbus, event))\n const span = this.tracer.startSpan(\n handlerSpanName(event, event_result),\n {\n attributes: handlerSpanAttributes(eventbus, event, event_result),\n startTime: timeInputFromIso(event_result.started_at),\n },\n parent_context\n )\n const span_context = this.trace_api.setSpan(parent_context, span)\n this.handler_spans.set(event_result.id, span)\n this.handler_contexts.set(handlerSpanKey(event_result.event_id, event_result.handler_id), span_context)\n return span\n }\n\n private completeHandlerSpan(eventbus: EventBus, event: BaseEvent, event_result: EventResult): void {\n if (this.span_factory) {\n return\n }\n\n const span = this.handler_spans.get(event_result.id)\n if (!span) {\n return\n }\n\n if (event_result.error !== undefined) {\n recordSpanError(span, event_result.error)\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n span.setAttributes(handlerSpanAttributes(eventbus, event, event_result))\n span.end(endTimeAfterStart(epochNsFromIso(event_result.started_at), epochNsFromIso(event_result.completed_at)))\n this.handler_spans.delete(event_result.id)\n this.handler_contexts.delete(handlerSpanKey(event_result.event_id, event_result.handler_id))\n }\n\n private parentContextForEvent(event: BaseEvent): Context | undefined {\n if (event.event_parent_id && event.event_emitted_by_handler_id) {\n const handler_context = this.handler_contexts.get(handlerSpanKey(event.event_parent_id, event.event_emitted_by_handler_id))\n if (handler_context) {\n return handler_context\n }\n }\n\n return event.event_parent_id ? this.event_contexts.get(event.event_parent_id) : undefined\n }\n\n private completeEventSpanWithFactory(eventbus: EventBus, event: BaseEvent): void {\n if (event.event_parent_id) {\n return\n }\n\n const top_level_event = event._event_original ?? event\n const trace_id = traceIdForRootEvent(top_level_event.event_id)\n this.exportEventTreeWithFactory(eventbus, top_level_event, trace_id, undefined, new Set<string>())\n }\n\n private exportEventTreeWithFactory(\n eventbus: EventBus,\n event: BaseEvent,\n trace_id: string,\n parent_span_context: SpanContext | undefined,\n visited_event_ids: Set<string>\n ): void {\n const original_event = event._event_original ?? event\n if (visited_event_ids.has(original_event.event_id)) {\n return\n }\n visited_event_ids.add(original_event.event_id)\n\n const start_time = epochNsFromIso(original_event.event_started_at)\n const span_context = eventSpanContext(trace_id, original_event.event_id)\n const span = this.span_factory!({\n name: eventSpanName(eventbus, original_event),\n span_context,\n parent_span_context,\n attributes: original_event.event_parent_id\n ? eventSpanAttributes(eventbus, original_event)\n : topLevelEventSpanAttributes(this.root_span_attributes, eventbus, original_event),\n start_time: timeInputFromEpochNs(start_time),\n })\n if (original_event.event_errors.length > 0) {\n recordSpanError(span, original_event.event_errors[0])\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n span.end(endTimeAfterStart(start_time, epochNsFromIso(original_event.event_completed_at)))\n\n for (const event_result of original_event.event_results.values()) {\n const handler_context = this.exportHandlerSpanWithFactory(eventbus, original_event, event_result, trace_id, span_context)\n for (const child of event_result.event_children) {\n this.exportEventTreeWithFactory(eventbus, child, trace_id, handler_context, visited_event_ids)\n }\n }\n }\n\n private exportHandlerSpanWithFactory(\n eventbus: EventBus,\n event: BaseEvent,\n event_result: EventResult,\n trace_id: string,\n parent_span_context: SpanContext\n ): SpanContext {\n const start_time = epochNsFromIso(event_result.started_at)\n const span_context = handlerSpanContext(trace_id, event_result.event_id, event_result.handler_id)\n const span = this.span_factory!({\n name: handlerSpanName(event, event_result),\n span_context,\n parent_span_context,\n attributes: handlerSpanAttributes(eventbus, event, event_result),\n start_time: timeInputFromEpochNs(start_time),\n })\n if (event_result.error !== undefined) {\n recordSpanError(span, event_result.error)\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n span.end(endTimeAfterStart(start_time, epochNsFromIso(event_result.completed_at)))\n return span_context\n }\n}\n\nfunction handlerSpanKey(event_id: string, handler_id: string): string {\n return `${event_id}:${handler_id}`\n}\n\nfunction eventSpanName(eventbus: EventBus, event: BaseEvent): string {\n return `${eventbus.name}.emit(${event.event_type})`\n}\n\nfunction handlerSpanName(event: BaseEvent, event_result: EventResult): string {\n return `${event_result.handler_name}(${event.event_type})`\n}\n\nfunction createOtlpSpanProvider(options: OtelTracingMiddlewareOptions): OtelTracingSpanProvider {\n return new BasicTracerProvider({\n resource: resourceFromAttributes({\n 'service.name': options.service_name ?? 'abxbus',\n }),\n spanProcessors: [\n new BatchSpanProcessor(\n new OTLPTraceExporter({\n url: normalizeOtlpTracesEndpoint(options.otlp_endpoint!),\n }),\n {\n scheduledDelayMillis: 100,\n }\n ),\n ],\n })\n}\n\nfunction createProviderSpanFactory(\n trace_api: OpenTelemetryTraceApi,\n provider: OtelTracingSpanProvider,\n instrumentation_name: string\n): OtelTracingSpanFactory {\n const provider_internals = provider as OtelTracingSpanProviderInternals\n return (input: OtelTracingSpanFactoryInput): Span => {\n const span_processor = provider_internals._activeSpanProcessor\n const span_limits = provider_internals._config?.spanLimits\n const resource = provider_internals._resource ?? provider_internals._config?.resource\n if (!span_processor || !span_limits || !resource) {\n throw new Error('OtelTracingMiddleware span_provider must be an OpenTelemetry SDK trace provider with active span internals')\n }\n\n const parent_context = input.parent_span_context\n ? (trace_api.setSpanContext ?? trace.setSpanContext)(ROOT_CONTEXT, input.parent_span_context)\n : ROOT_CONTEXT\n return new SpanImpl({\n resource,\n scope: { name: instrumentation_name },\n context: parent_context,\n spanContext: input.span_context,\n parentSpanContext: input.parent_span_context,\n name: input.name,\n kind: SpanKind.INTERNAL,\n attributes: input.attributes,\n startTime: input.start_time,\n spanProcessor: span_processor,\n spanLimits: span_limits,\n } as ConstructorParameters<typeof SpanImpl>[0])\n }\n}\n\nfunction normalizeOtlpTracesEndpoint(endpoint: string): string {\n const trimmed = endpoint.replace(/\\/+$/, '')\n return trimmed.endsWith('/v1/traces') ? trimmed : `${trimmed}/v1/traces`\n}\n\nfunction eventStartedSpanAttributes(eventbus: EventBus, event: BaseEvent): SpanAttributes {\n return compactAttributes({\n 'abxbus.event_bus.id': eventbus.id,\n 'abxbus.event_bus.name': eventbus.name,\n 'abxbus.event_id': event.event_id,\n 'abxbus.event_type': event.event_type,\n 'abxbus.event_version': event.event_version,\n 'abxbus.session_id': stringValue((event as { session_id?: unknown }).session_id),\n 'abxbus.event_parent_id': event.event_parent_id,\n 'abxbus.event_emitted_by_handler_id': event.event_emitted_by_handler_id,\n 'abxbus.event_path': event.event_path.join(' '),\n })\n}\n\nfunction eventSpanAttributes(eventbus: EventBus, event: BaseEvent): SpanAttributes {\n return compactAttributes({\n ...eventStartedSpanAttributes(eventbus, event),\n 'abxbus.event_status': event.event_status,\n })\n}\n\nfunction handlerSpanAttributes(eventbus: EventBus, event: BaseEvent, event_result: EventResult): SpanAttributes {\n return compactAttributes({\n 'abxbus.event_bus.id': eventbus.id,\n 'abxbus.event_bus.name': eventbus.name,\n 'abxbus.event_id': event.event_id,\n 'abxbus.event_type': event.event_type,\n 'abxbus.handler_id': event_result.handler_id,\n 'abxbus.handler_name': event_result.handler_name,\n 'abxbus.handler_file_path': event_result.handler_file_path,\n 'abxbus.handler_event_pattern': event_result.handler.event_pattern,\n 'abxbus.event_result_id': event_result.id,\n 'abxbus.event_result_status': event_result.status,\n })\n}\n\nfunction topLevelEventStartedSpanAttributes(\n root_span_attributes: OtelTracingMiddlewareOptions['root_span_attributes'],\n eventbus: EventBus,\n event: BaseEvent\n): SpanAttributes {\n return compactAttributes({\n ...eventStartedSpanAttributes(eventbus, event),\n ...resolveAttributes(root_span_attributes, eventbus, event),\n 'abxbus.trace.root': true,\n })\n}\n\nfunction topLevelEventSpanAttributes(\n root_span_attributes: OtelTracingMiddlewareOptions['root_span_attributes'],\n eventbus: EventBus,\n event: BaseEvent\n): SpanAttributes {\n return compactAttributes({\n ...eventSpanAttributes(eventbus, event),\n ...resolveAttributes(root_span_attributes, eventbus, event),\n 'abxbus.trace.root': true,\n })\n}\n\nfunction eventSpanContext(trace_id: string, event_id: string): SpanContext {\n return {\n traceId: trace_id,\n spanId: deterministicSpanId(`abxbus.event:${event_id}`),\n traceFlags: 1,\n }\n}\n\nfunction handlerSpanContext(trace_id: string, event_id: string, handler_id: string): SpanContext {\n return {\n traceId: trace_id,\n spanId: deterministicSpanId(`abxbus.handler:${event_id}:${handler_id}`),\n traceFlags: 1,\n }\n}\n\nfunction traceIdForRootEvent(event_id: string): string {\n return `${fnv1a64Hex(`abxbus.trace.a:${event_id}`)}${fnv1a64Hex(`abxbus.trace.b:${event_id}`)}`\n}\n\nfunction deterministicSpanId(input: string): string {\n return fnv1a64Hex(input)\n}\n\nfunction fnv1a64Hex(input: string): string {\n let hash = 0xcbf29ce484222325n\n const prime = 0x100000001b3n\n const mask = 0xffffffffffffffffn\n for (let index = 0; index < input.length; index += 1) {\n hash ^= BigInt(input.charCodeAt(index))\n hash = (hash * prime) & mask\n }\n if (hash === 0n) {\n hash = 1n\n }\n return hash.toString(16).padStart(16, '0')\n}\n\nconst ISO_EPOCH_NS_REGEX = /^(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2})(?:\\.(\\d{1,9}))?(Z|[+-]\\d{2}:\\d{2})$/\nconst NS_PER_SECOND = 1_000_000_000n\nconst NS_PER_MS = 1_000_000n\n\nfunction epochNsFromIso(value: string | null | undefined): bigint | undefined {\n if (value == null) {\n return undefined\n }\n const match = ISO_EPOCH_NS_REGEX.exec(value)\n if (!match) {\n return undefined\n }\n const [, base, fraction = '', timezone] = match\n const base_ms = Date.parse(`${base}.000${timezone}`)\n if (Number.isNaN(base_ms)) {\n return undefined\n }\n return BigInt(base_ms) * NS_PER_MS + BigInt(fraction.padEnd(9, '0'))\n}\n\nfunction timeInputFromIso(value: string | null | undefined): TimeInput | undefined {\n return timeInputFromEpochNs(epochNsFromIso(value))\n}\n\nfunction timeInputFromEpochNs(epoch_ns: bigint | undefined): TimeInput | undefined {\n if (epoch_ns === undefined) {\n return undefined\n }\n const seconds = epoch_ns / NS_PER_SECOND\n const nanos = epoch_ns % NS_PER_SECOND\n return [Number(seconds), Number(nanos)]\n}\n\nfunction endTimeAfterStart(start_time: bigint | undefined, end_time: bigint | undefined): TimeInput | undefined {\n if (start_time === undefined || end_time === undefined) {\n return timeInputFromEpochNs(end_time)\n }\n\n return timeInputFromEpochNs(end_time > start_time ? end_time : start_time + 1n)\n}\n\nfunction resolveAttributes(\n attributes: OtelTracingMiddlewareOptions['root_span_attributes'],\n eventbus: EventBus,\n event: BaseEvent\n): SpanAttributes {\n return typeof attributes === 'function' ? attributes(eventbus, event) : (attributes ?? {})\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined\n}\n\nfunction compactAttributes(attributes: Record<string, SpanAttributeValue | null | undefined>): SpanAttributes {\n const compacted: SpanAttributes = {}\n for (const [key, value] of Object.entries(attributes)) {\n if (value !== null && value !== undefined) {\n compacted[key] = value\n }\n }\n return compacted\n}\n\nfunction recordSpanError(span: Span, error: unknown): void {\n if (error instanceof Error) {\n span.recordException(error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })\n return\n }\n\n const message = typeof error === 'string' ? error : 'Unknown abxbus handler error'\n span.recordException(message)\n span.setStatus({ code: SpanStatusCode.ERROR, message })\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,5 +1,5 @@
1
- import { BaseEvent } from "./base_event.js";
2
- import { EventBus } from "./event_bus.js";
1
+ import { BaseEvent } from "./BaseEvent.js";
2
+ import { EventBus } from "./EventBus.js";
3
3
  import { assertOptionalDependencyAvailable, importOptionalDependency, isNodeRuntime } from "./optional_deps.js";
4
4
  const randomSuffix = () => Math.random().toString(36).slice(2, 10);
5
5
  const IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
@@ -228,4 +228,4 @@ class PostgresEventBridge {
228
228
  export {
229
229
  PostgresEventBridge
230
230
  };
231
- //# sourceMappingURL=bridge_postgres.js.map
231
+ //# sourceMappingURL=PostgresEventBridge.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/PostgresEventBridge.ts"],
4
+ "sourcesContent": ["/**\n * PostgreSQL LISTEN/NOTIFY + flat-table bridge for forwarding events.\n */\nimport { BaseEvent } from './BaseEvent.js'\nimport { EventBus } from './EventBus.js'\nimport { assertOptionalDependencyAvailable, importOptionalDependency, isNodeRuntime } from './optional_deps.js'\nimport type { EventClass, EventHandlerCallable, EventPattern, UntypedEventHandlerFunction } from './types.js'\n\nconst randomSuffix = (): string => Math.random().toString(36).slice(2, 10)\nconst IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/\nconst DEFAULT_POSTGRES_TABLE = 'abxbus_events'\nconst DEFAULT_POSTGRES_CHANNEL = 'abxbus_events'\nconst EVENT_PAYLOAD_COLUMN = 'event_payload'\n\nconst validateIdentifier = (value: string, label: string): string => {\n if (!IDENTIFIER_RE.test(value)) {\n throw new Error(`Invalid ${label}: ${JSON.stringify(value)}. Use only [A-Za-z0-9_] and start with a letter/_`)\n }\n return value\n}\n\nconst indexName = (table: string, suffix: string): string => validateIdentifier(`${table}_${suffix}`.slice(0, 63), 'index name')\n\nconst parseTableUrl = (table_url: string): { dsn: string; table: string } => {\n let parsed: URL\n try {\n parsed = new URL(table_url)\n } catch {\n throw new Error(\n 'PostgresEventBridge URL must include at least database in path, e.g. postgresql://user:pass@host:5432/dbname[/tablename]'\n )\n }\n\n const segments = parsed.pathname.split('/').filter(Boolean)\n if (segments.length < 1) {\n throw new Error(\n 'PostgresEventBridge URL must include at least database in path, e.g. postgresql://user:pass@host:5432/dbname[/tablename]'\n )\n }\n\n const db_name = segments[0]\n const table = segments.length >= 2 ? validateIdentifier(segments[1], 'table name') : DEFAULT_POSTGRES_TABLE\n const dsn_url = new URL(parsed.toString())\n dsn_url.pathname = `/${db_name}`\n return { dsn: dsn_url.toString(), table }\n}\n\nconst splitBridgePayload = (\n payload: Record<string, unknown>\n): { event_fields: Record<string, unknown>; event_payload: Record<string, unknown> } => {\n const event_fields: Record<string, unknown> = {}\n const event_payload: Record<string, unknown> = { ...payload }\n for (const [key, value] of Object.entries(payload)) {\n if (key.startsWith('event_')) {\n event_fields[key] = value\n }\n }\n return { event_fields, event_payload }\n}\n\nexport class PostgresEventBridge {\n readonly table_url: string\n readonly dsn: string\n readonly table: string\n readonly channel: string\n readonly name: string\n\n private readonly inbound_bus: EventBus\n private running: boolean\n private client: any | null\n private table_columns: Set<string>\n private notification_handler: ((msg: { channel: string; payload?: string }) => void) | null\n\n constructor(table_url: string, channel?: string, name?: string) {\n assertOptionalDependencyAvailable('PostgresEventBridge', 'pg')\n\n const parsed = parseTableUrl(table_url)\n this.table_url = table_url\n this.dsn = parsed.dsn\n this.table = parsed.table\n\n const derived_channel = channel ?? DEFAULT_POSTGRES_CHANNEL\n this.channel = validateIdentifier(derived_channel.slice(0, 63), 'channel name')\n this.name = name ?? `PostgresEventBridge_${randomSuffix()}`\n\n this.inbound_bus = new EventBus(this.name, { max_history_size: 0 })\n this.running = false\n this.client = null\n this.table_columns = new Set(['event_id', 'event_created_at', 'event_type', EVENT_PAYLOAD_COLUMN])\n this.notification_handler = null\n\n this.dispatch = this.dispatch.bind(this)\n this.emit = this.emit.bind(this)\n this.on = this.on.bind(this)\n }\n\n on<T extends BaseEvent>(event_pattern: EventClass<T>, handler: EventHandlerCallable<T>): void\n on<T extends BaseEvent>(event_pattern: string | '*', handler: UntypedEventHandlerFunction<T>): void\n on(event_pattern: EventPattern | '*', handler: EventHandlerCallable | UntypedEventHandlerFunction): void {\n this.ensureStarted()\n if (typeof event_pattern === 'string') {\n this.inbound_bus.on(event_pattern, handler as UntypedEventHandlerFunction<BaseEvent>)\n return\n }\n this.inbound_bus.on(event_pattern as EventClass<BaseEvent>, handler as EventHandlerCallable<BaseEvent>)\n }\n\n async emit<T extends BaseEvent>(event: T): Promise<void> {\n this.ensureStarted()\n if (!this.client) await this.start()\n\n const payload = event.toJSON() as Record<string, unknown>\n const { event_fields, event_payload } = splitBridgePayload(payload)\n const write_payload: Record<string, unknown> = { ...event_fields, [EVENT_PAYLOAD_COLUMN]: event_payload }\n const keys = Object.keys(write_payload).sort()\n await this.ensureColumns(keys)\n\n const columns_sql = keys.map((key) => `\"${key}\"`).join(', ')\n const placeholders_sql = keys.map((_, index) => `$${index + 1}`).join(', ')\n const values = keys.map((key) =>\n write_payload[key] === null || write_payload[key] === undefined ? null : JSON.stringify(write_payload[key])\n )\n\n const update_fields = keys.filter((key) => key !== 'event_id')\n let upsert_sql = `INSERT INTO \"${this.table}\" (${columns_sql}) VALUES (${placeholders_sql})`\n if (update_fields.length > 0) {\n const updates_sql = update_fields.map((key) => `\"${key}\" = EXCLUDED.\"${key}\"`).join(', ')\n upsert_sql += ` ON CONFLICT (\"event_id\") DO UPDATE SET ${updates_sql}`\n } else {\n upsert_sql += ' ON CONFLICT (\"event_id\") DO NOTHING'\n }\n\n await this.client.query(upsert_sql, values)\n await this.client.query('SELECT pg_notify($1, $2)', [this.channel, JSON.stringify(String(event.event_id))])\n }\n\n async dispatch<T extends BaseEvent>(event: T): Promise<void> {\n return this.emit(event)\n }\n\n async start(): Promise<void> {\n if (this.running) return\n if (!isNodeRuntime()) {\n throw new Error('PostgresEventBridge is only supported in Node.js runtimes')\n }\n\n const mod = await importOptionalDependency('PostgresEventBridge', 'pg')\n const Client = mod.Client ?? mod.default?.Client\n this.client = new Client({ connectionString: this.dsn })\n this.client.on('error', () => {})\n await this.client.connect()\n\n await this.ensureTableExists()\n await this.refreshColumnCache()\n await this.ensureColumns(['event_id', 'event_created_at', 'event_type', EVENT_PAYLOAD_COLUMN])\n await this.ensureBaseIndexes()\n\n this.notification_handler = (msg: { channel: string; payload?: string }) => {\n if (msg.channel !== this.channel || !msg.payload) return\n void this.dispatchByEventId(msg.payload).catch(() => {\n // Ignore transient shutdown races while closing connections.\n })\n }\n\n this.client.on('notification', this.notification_handler)\n await this.client.query(`LISTEN ${this.channel}`)\n this.running = true\n }\n\n async close(): Promise<void> {\n this.running = false\n if (this.client) {\n try {\n await this.client.query(`UNLISTEN ${this.channel}`)\n } catch {\n // ignore\n }\n if (this.notification_handler) {\n this.client.off('notification', this.notification_handler)\n this.notification_handler = null\n }\n await this.client.end()\n this.client = null\n }\n this.inbound_bus.destroy()\n }\n\n private ensureStarted(): void {\n if (this.running) return\n void this.start().catch((error: unknown) => {\n console.error('[abxbus] PostgresEventBridge failed to start', error)\n })\n }\n\n private async dispatchByEventId(event_id: string): Promise<void> {\n if (!this.running || !this.client) return\n const result = await this.client.query(`SELECT * FROM \"${this.table}\" WHERE \"event_id\" = $1`, [event_id])\n const row = result.rows?.[0] as Record<string, unknown> | undefined\n if (!row) return\n\n const payload: Record<string, unknown> = {}\n const raw_event_payload = row[EVENT_PAYLOAD_COLUMN]\n if (typeof raw_event_payload === 'string') {\n try {\n const decoded_event_payload = JSON.parse(raw_event_payload)\n if (decoded_event_payload && typeof decoded_event_payload === 'object' && !Array.isArray(decoded_event_payload)) {\n Object.assign(payload, decoded_event_payload as Record<string, unknown>)\n }\n } catch {\n // ignore malformed payload column\n }\n }\n\n for (const [key, raw_value] of Object.entries(row)) {\n if (key === EVENT_PAYLOAD_COLUMN || !key.startsWith('event_')) continue\n if (raw_value === null || raw_value === undefined) continue\n if (typeof raw_value !== 'string') {\n payload[key] = raw_value\n continue\n }\n try {\n payload[key] = JSON.parse(raw_value)\n } catch {\n payload[key] = raw_value\n }\n }\n\n await this.dispatchInboundPayload(payload)\n }\n\n private async dispatchInboundPayload(payload: unknown): Promise<void> {\n const event = BaseEvent.fromJSON(payload).eventReset()\n this.inbound_bus.emit(event)\n }\n\n private async ensureTableExists(): Promise<void> {\n if (!this.client) return\n await this.client.query(\n `CREATE TABLE IF NOT EXISTS \"${this.table}\" (\"event_id\" TEXT PRIMARY KEY, \"event_created_at\" TEXT, \"event_type\" TEXT, \"event_payload\" TEXT)`\n )\n }\n\n private async ensureBaseIndexes(): Promise<void> {\n if (!this.client) return\n\n const event_created_at_idx = indexName(this.table, 'event_created_at_idx')\n const event_type_idx = indexName(this.table, 'event_type_idx')\n\n await this.client.query(`CREATE INDEX IF NOT EXISTS \"${event_created_at_idx}\" ON \"${this.table}\" (\"event_created_at\")`)\n await this.client.query(`CREATE INDEX IF NOT EXISTS \"${event_type_idx}\" ON \"${this.table}\" (\"event_type\")`)\n }\n\n private async refreshColumnCache(): Promise<void> {\n if (!this.client) return\n const result = await this.client.query(\n `SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = $1`,\n [this.table]\n )\n this.table_columns = new Set((result.rows as Array<{ column_name: string }>).map((row) => row.column_name))\n }\n\n private async ensureColumns(keys: string[]): Promise<void> {\n if (!this.client) return\n for (const key of keys) {\n validateIdentifier(key, 'event field name')\n if (key !== EVENT_PAYLOAD_COLUMN && !key.startsWith('event_')) {\n throw new Error(`Invalid event field name for bridge column: ${JSON.stringify(key)}. Only event_* fields become columns`)\n }\n }\n\n const missing = keys.filter((key) => !this.table_columns.has(key))\n for (const key of missing) {\n await this.client.query(`ALTER TABLE \"${this.table}\" ADD COLUMN IF NOT EXISTS \"${key}\" TEXT`)\n this.table_columns.add(key)\n }\n }\n}\n"],
5
+ "mappings": "AAGA,SAAS,iBAAiB;AAC1B,SAAS,gBAAgB;AACzB,SAAS,mCAAmC,0BAA0B,qBAAqB;AAG3F,MAAM,eAAe,MAAc,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE;AACzE,MAAM,gBAAgB;AACtB,MAAM,yBAAyB;AAC/B,MAAM,2BAA2B;AACjC,MAAM,uBAAuB;AAE7B,MAAM,qBAAqB,CAAC,OAAe,UAA0B;AACnE,MAAI,CAAC,cAAc,KAAK,KAAK,GAAG;AAC9B,UAAM,IAAI,MAAM,WAAW,KAAK,KAAK,KAAK,UAAU,KAAK,CAAC,mDAAmD;AAAA,EAC/G;AACA,SAAO;AACT;AAEA,MAAM,YAAY,CAAC,OAAe,WAA2B,mBAAmB,GAAG,KAAK,IAAI,MAAM,GAAG,MAAM,GAAG,EAAE,GAAG,YAAY;AAE/H,MAAM,gBAAgB,CAAC,cAAsD;AAC3E,MAAI;AACJ,MAAI;AACF,aAAS,IAAI,IAAI,SAAS;AAAA,EAC5B,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW,OAAO,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AAC1D,MAAI,SAAS,SAAS,GAAG;AACvB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,SAAS,CAAC;AAC1B,QAAM,QAAQ,SAAS,UAAU,IAAI,mBAAmB,SAAS,CAAC,GAAG,YAAY,IAAI;AACrF,QAAM,UAAU,IAAI,IAAI,OAAO,SAAS,CAAC;AACzC,UAAQ,WAAW,IAAI,OAAO;AAC9B,SAAO,EAAE,KAAK,QAAQ,SAAS,GAAG,MAAM;AAC1C;AAEA,MAAM,qBAAqB,CACzB,YACsF;AACtF,QAAM,eAAwC,CAAC;AAC/C,QAAM,gBAAyC,EAAE,GAAG,QAAQ;AAC5D,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,QAAI,IAAI,WAAW,QAAQ,GAAG;AAC5B,mBAAa,GAAG,IAAI;AAAA,IACtB;AAAA,EACF;AACA,SAAO,EAAE,cAAc,cAAc;AACvC;AAEO,MAAM,oBAAoB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEQ;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,WAAmB,SAAkB,MAAe;AAC9D,sCAAkC,uBAAuB,IAAI;AAE7D,UAAM,SAAS,cAAc,SAAS;AACtC,SAAK,YAAY;AACjB,SAAK,MAAM,OAAO;AAClB,SAAK,QAAQ,OAAO;AAEpB,UAAM,kBAAkB,WAAW;AACnC,SAAK,UAAU,mBAAmB,gBAAgB,MAAM,GAAG,EAAE,GAAG,cAAc;AAC9E,SAAK,OAAO,QAAQ,uBAAuB,aAAa,CAAC;AAEzD,SAAK,cAAc,IAAI,SAAS,KAAK,MAAM,EAAE,kBAAkB,EAAE,CAAC;AAClE,SAAK,UAAU;AACf,SAAK,SAAS;AACd,SAAK,gBAAgB,oBAAI,IAAI,CAAC,YAAY,oBAAoB,cAAc,oBAAoB,CAAC;AACjG,SAAK,uBAAuB;AAE5B,SAAK,WAAW,KAAK,SAAS,KAAK,IAAI;AACvC,SAAK,OAAO,KAAK,KAAK,KAAK,IAAI;AAC/B,SAAK,KAAK,KAAK,GAAG,KAAK,IAAI;AAAA,EAC7B;AAAA,EAIA,GAAG,eAAmC,SAAmE;AACvG,SAAK,cAAc;AACnB,QAAI,OAAO,kBAAkB,UAAU;AACrC,WAAK,YAAY,GAAG,eAAe,OAAiD;AACpF;AAAA,IACF;AACA,SAAK,YAAY,GAAG,eAAwC,OAA0C;AAAA,EACxG;AAAA,EAEA,MAAM,KAA0B,OAAyB;AACvD,SAAK,cAAc;AACnB,QAAI,CAAC,KAAK,OAAQ,OAAM,KAAK,MAAM;AAEnC,UAAM,UAAU,MAAM,OAAO;AAC7B,UAAM,EAAE,cAAc,cAAc,IAAI,mBAAmB,OAAO;AAClE,UAAM,gBAAyC,EAAE,GAAG,cAAc,CAAC,oBAAoB,GAAG,cAAc;AACxG,UAAM,OAAO,OAAO,KAAK,aAAa,EAAE,KAAK;AAC7C,UAAM,KAAK,cAAc,IAAI;AAE7B,UAAM,cAAc,KAAK,IAAI,CAAC,QAAQ,IAAI,GAAG,GAAG,EAAE,KAAK,IAAI;AAC3D,UAAM,mBAAmB,KAAK,IAAI,CAAC,GAAG,UAAU,IAAI,QAAQ,CAAC,EAAE,EAAE,KAAK,IAAI;AAC1E,UAAM,SAAS,KAAK;AAAA,MAAI,CAAC,QACvB,cAAc,GAAG,MAAM,QAAQ,cAAc,GAAG,MAAM,SAAY,OAAO,KAAK,UAAU,cAAc,GAAG,CAAC;AAAA,IAC5G;AAEA,UAAM,gBAAgB,KAAK,OAAO,CAAC,QAAQ,QAAQ,UAAU;AAC7D,QAAI,aAAa,gBAAgB,KAAK,KAAK,MAAM,WAAW,aAAa,gBAAgB;AACzF,QAAI,cAAc,SAAS,GAAG;AAC5B,YAAM,cAAc,cAAc,IAAI,CAAC,QAAQ,IAAI,GAAG,iBAAiB,GAAG,GAAG,EAAE,KAAK,IAAI;AACxF,oBAAc,2CAA2C,WAAW;AAAA,IACtE,OAAO;AACL,oBAAc;AAAA,IAChB;AAEA,UAAM,KAAK,OAAO,MAAM,YAAY,MAAM;AAC1C,UAAM,KAAK,OAAO,MAAM,4BAA4B,CAAC,KAAK,SAAS,KAAK,UAAU,OAAO,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,EAC5G;AAAA,EAEA,MAAM,SAA8B,OAAyB;AAC3D,WAAO,KAAK,KAAK,KAAK;AAAA,EACxB;AAAA,EAEA,MAAM,QAAuB;AAC3B,QAAI,KAAK,QAAS;AAClB,QAAI,CAAC,cAAc,GAAG;AACpB,YAAM,IAAI,MAAM,2DAA2D;AAAA,IAC7E;AAEA,UAAM,MAAM,MAAM,yBAAyB,uBAAuB,IAAI;AACtE,UAAM,SAAS,IAAI,UAAU,IAAI,SAAS;AAC1C,SAAK,SAAS,IAAI,OAAO,EAAE,kBAAkB,KAAK,IAAI,CAAC;AACvD,SAAK,OAAO,GAAG,SAAS,MAAM;AAAA,IAAC,CAAC;AAChC,UAAM,KAAK,OAAO,QAAQ;AAE1B,UAAM,KAAK,kBAAkB;AAC7B,UAAM,KAAK,mBAAmB;AAC9B,UAAM,KAAK,cAAc,CAAC,YAAY,oBAAoB,cAAc,oBAAoB,CAAC;AAC7F,UAAM,KAAK,kBAAkB;AAE7B,SAAK,uBAAuB,CAAC,QAA+C;AAC1E,UAAI,IAAI,YAAY,KAAK,WAAW,CAAC,IAAI,QAAS;AAClD,WAAK,KAAK,kBAAkB,IAAI,OAAO,EAAE,MAAM,MAAM;AAAA,MAErD,CAAC;AAAA,IACH;AAEA,SAAK,OAAO,GAAG,gBAAgB,KAAK,oBAAoB;AACxD,UAAM,KAAK,OAAO,MAAM,UAAU,KAAK,OAAO,EAAE;AAChD,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,UAAU;AACf,QAAI,KAAK,QAAQ;AACf,UAAI;AACF,cAAM,KAAK,OAAO,MAAM,YAAY,KAAK,OAAO,EAAE;AAAA,MACpD,QAAQ;AAAA,MAER;AACA,UAAI,KAAK,sBAAsB;AAC7B,aAAK,OAAO,IAAI,gBAAgB,KAAK,oBAAoB;AACzD,aAAK,uBAAuB;AAAA,MAC9B;AACA,YAAM,KAAK,OAAO,IAAI;AACtB,WAAK,SAAS;AAAA,IAChB;AACA,SAAK,YAAY,QAAQ;AAAA,EAC3B;AAAA,EAEQ,gBAAsB;AAC5B,QAAI,KAAK,QAAS;AAClB,SAAK,KAAK,MAAM,EAAE,MAAM,CAAC,UAAmB;AAC1C,cAAQ,MAAM,gDAAgD,KAAK;AAAA,IACrE,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,kBAAkB,UAAiC;AAC/D,QAAI,CAAC,KAAK,WAAW,CAAC,KAAK,OAAQ;AACnC,UAAM,SAAS,MAAM,KAAK,OAAO,MAAM,kBAAkB,KAAK,KAAK,2BAA2B,CAAC,QAAQ,CAAC;AACxG,UAAM,MAAM,OAAO,OAAO,CAAC;AAC3B,QAAI,CAAC,IAAK;AAEV,UAAM,UAAmC,CAAC;AAC1C,UAAM,oBAAoB,IAAI,oBAAoB;AAClD,QAAI,OAAO,sBAAsB,UAAU;AACzC,UAAI;AACF,cAAM,wBAAwB,KAAK,MAAM,iBAAiB;AAC1D,YAAI,yBAAyB,OAAO,0BAA0B,YAAY,CAAC,MAAM,QAAQ,qBAAqB,GAAG;AAC/G,iBAAO,OAAO,SAAS,qBAAgD;AAAA,QACzE;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,eAAW,CAAC,KAAK,SAAS,KAAK,OAAO,QAAQ,GAAG,GAAG;AAClD,UAAI,QAAQ,wBAAwB,CAAC,IAAI,WAAW,QAAQ,EAAG;AAC/D,UAAI,cAAc,QAAQ,cAAc,OAAW;AACnD,UAAI,OAAO,cAAc,UAAU;AACjC,gBAAQ,GAAG,IAAI;AACf;AAAA,MACF;AACA,UAAI;AACF,gBAAQ,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,MACrC,QAAQ;AACN,gBAAQ,GAAG,IAAI;AAAA,MACjB;AAAA,IACF;AAEA,UAAM,KAAK,uBAAuB,OAAO;AAAA,EAC3C;AAAA,EAEA,MAAc,uBAAuB,SAAiC;AACpE,UAAM,QAAQ,UAAU,SAAS,OAAO,EAAE,WAAW;AACrD,SAAK,YAAY,KAAK,KAAK;AAAA,EAC7B;AAAA,EAEA,MAAc,oBAAmC;AAC/C,QAAI,CAAC,KAAK,OAAQ;AAClB,UAAM,KAAK,OAAO;AAAA,MAChB,+BAA+B,KAAK,KAAK;AAAA,IAC3C;AAAA,EACF;AAAA,EAEA,MAAc,oBAAmC;AAC/C,QAAI,CAAC,KAAK,OAAQ;AAElB,UAAM,uBAAuB,UAAU,KAAK,OAAO,sBAAsB;AACzE,UAAM,iBAAiB,UAAU,KAAK,OAAO,gBAAgB;AAE7D,UAAM,KAAK,OAAO,MAAM,+BAA+B,oBAAoB,SAAS,KAAK,KAAK,wBAAwB;AACtH,UAAM,KAAK,OAAO,MAAM,+BAA+B,cAAc,SAAS,KAAK,KAAK,kBAAkB;AAAA,EAC5G;AAAA,EAEA,MAAc,qBAAoC;AAChD,QAAI,CAAC,KAAK,OAAQ;AAClB,UAAM,SAAS,MAAM,KAAK,OAAO;AAAA,MAC/B;AAAA,MACA,CAAC,KAAK,KAAK;AAAA,IACb;AACA,SAAK,gBAAgB,IAAI,IAAK,OAAO,KAAwC,IAAI,CAAC,QAAQ,IAAI,WAAW,CAAC;AAAA,EAC5G;AAAA,EAEA,MAAc,cAAc,MAA+B;AACzD,QAAI,CAAC,KAAK,OAAQ;AAClB,eAAW,OAAO,MAAM;AACtB,yBAAmB,KAAK,kBAAkB;AAC1C,UAAI,QAAQ,wBAAwB,CAAC,IAAI,WAAW,QAAQ,GAAG;AAC7D,cAAM,IAAI,MAAM,+CAA+C,KAAK,UAAU,GAAG,CAAC,sCAAsC;AAAA,MAC1H;AAAA,IACF;AAEA,UAAM,UAAU,KAAK,OAAO,CAAC,QAAQ,CAAC,KAAK,cAAc,IAAI,GAAG,CAAC;AACjE,eAAW,OAAO,SAAS;AACzB,YAAM,KAAK,OAAO,MAAM,gBAAgB,KAAK,KAAK,+BAA+B,GAAG,QAAQ;AAC5F,WAAK,cAAc,IAAI,GAAG;AAAA,IAC5B;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -1,5 +1,5 @@
1
- import { BaseEvent } from "./base_event.js";
2
- import { EventBus } from "./event_bus.js";
1
+ import { BaseEvent } from "./BaseEvent.js";
2
+ import { EventBus } from "./EventBus.js";
3
3
  import { assertOptionalDependencyAvailable, importOptionalDependency, isNodeRuntime } from "./optional_deps.js";
4
4
  const randomSuffix = () => Math.random().toString(36).slice(2, 10);
5
5
  const DEFAULT_REDIS_CHANNEL = "abxbus_events";
@@ -152,4 +152,4 @@ class RedisEventBridge {
152
152
  export {
153
153
  RedisEventBridge
154
154
  };
155
- //# sourceMappingURL=bridge_redis.js.map
155
+ //# sourceMappingURL=RedisEventBridge.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/RedisEventBridge.ts"],
4
+ "sourcesContent": ["/**\n * Redis pub/sub bridge for forwarding events between runtimes.\n *\n * Usage:\n * // channel from URL path\n * const bridge = new RedisEventBridge('redis://user:pass@localhost:6379/1/my_channel')\n *\n * // explicit channel override\n * const bridge2 = new RedisEventBridge('redis://user:pass@localhost:6379/1', 'my_channel')\n *\n * URL format:\n * redis://user:pass@host:6379/<db>/<optional_channel>\n */\nimport { BaseEvent } from './BaseEvent.js'\nimport { EventBus } from './EventBus.js'\nimport { assertOptionalDependencyAvailable, importOptionalDependency, isNodeRuntime } from './optional_deps.js'\nimport type { EventClass, EventHandlerCallable, EventPattern, UntypedEventHandlerFunction } from './types.js'\n\nconst randomSuffix = (): string => Math.random().toString(36).slice(2, 10)\nconst DEFAULT_REDIS_CHANNEL = 'abxbus_events'\nconst DB_INIT_KEY = '__abxbus:bridge_init__'\n\nconst parseRedisUrl = (redis_url: string, channel?: string): { url: string; channel: string } => {\n let parsed: URL\n try {\n parsed = new URL(redis_url)\n } catch {\n throw new Error(`RedisEventBridge URL must be a valid redis:// or rediss:// URL, got: ${redis_url}`)\n }\n\n const protocol = parsed.protocol.replace(/:$/, '').toLowerCase()\n if (protocol !== 'redis' && protocol !== 'rediss') {\n throw new Error(`RedisEventBridge URL must use redis:// or rediss://, got: ${redis_url}`)\n }\n\n const segments = parsed.pathname.split('/').filter(Boolean)\n if (segments.length > 2) {\n throw new Error(`RedisEventBridge URL path must be /<db> or /<db>/<channel>, got: ${parsed.pathname || '/'}`)\n }\n\n let db_index = '0'\n let channel_from_url: string | undefined\n\n if (segments.length > 0) {\n db_index = segments[0]\n if (!/^\\d+$/.test(db_index)) {\n throw new Error(`RedisEventBridge URL db path segment must be numeric, got: ${JSON.stringify(db_index)} in ${redis_url}`)\n }\n if (segments.length === 2) {\n channel_from_url = segments[1]\n }\n }\n\n const resolved_channel = channel ?? channel_from_url ?? DEFAULT_REDIS_CHANNEL\n if (!resolved_channel) {\n throw new Error('RedisEventBridge channel must not be empty')\n }\n\n const normalized = new URL(parsed.toString())\n normalized.pathname = `/${db_index}`\n return { url: normalized.toString(), channel: resolved_channel }\n}\n\nexport class RedisEventBridge {\n readonly url: string\n readonly channel: string\n readonly name: string\n\n private readonly inbound_bus: EventBus\n private running: boolean\n private start_promise: Promise<void> | null\n private redis_pub: any | null\n private redis_sub: any | null\n\n constructor(redis_url: string, channel?: string, name?: string) {\n assertOptionalDependencyAvailable('RedisEventBridge', 'ioredis')\n\n const parsed = parseRedisUrl(redis_url, channel)\n this.url = parsed.url\n this.channel = parsed.channel\n this.name = name ?? `RedisEventBridge_${randomSuffix()}`\n this.inbound_bus = new EventBus(this.name, { max_history_size: 0 })\n this.running = false\n this.start_promise = null\n this.redis_pub = null\n this.redis_sub = null\n\n this.dispatch = this.dispatch.bind(this)\n this.emit = this.emit.bind(this)\n this.on = this.on.bind(this)\n }\n\n on<T extends BaseEvent>(event_pattern: EventClass<T>, handler: EventHandlerCallable<T>): void\n on<T extends BaseEvent>(event_pattern: string | '*', handler: UntypedEventHandlerFunction<T>): void\n on(event_pattern: EventPattern | '*', handler: EventHandlerCallable | UntypedEventHandlerFunction): void {\n this.ensureStarted()\n if (typeof event_pattern === 'string') {\n this.inbound_bus.on(event_pattern, handler as UntypedEventHandlerFunction<BaseEvent>)\n return\n }\n this.inbound_bus.on(event_pattern as EventClass<BaseEvent>, handler as EventHandlerCallable<BaseEvent>)\n }\n\n async emit<T extends BaseEvent>(event: T): Promise<void> {\n this.ensureStarted()\n if (!this.redis_pub) await this.start()\n const payload = JSON.stringify(event.toJSON())\n await this.redis_pub.publish(this.channel, payload)\n }\n\n async dispatch<T extends BaseEvent>(event: T): Promise<void> {\n return this.emit(event)\n }\n\n async start(): Promise<void> {\n if (this.running) return\n if (this.start_promise) {\n await this.start_promise\n return\n }\n\n // `on(...)` auto-start and explicit `await start()` can happen back-to-back; use one in-flight\n // startup promise so we do not leak extra Redis clients.\n this.start_promise = (async () => {\n if (!isNodeRuntime()) {\n throw new Error('RedisEventBridge is only supported in Node.js runtimes')\n }\n\n const mod = await importOptionalDependency('RedisEventBridge', 'ioredis')\n const Redis = mod.default ?? mod.Redis ?? mod\n const redis_pub = new Redis(this.url)\n const redis_sub = new Redis(this.url)\n\n redis_pub.on('error', () => {})\n redis_sub.on('error', () => {})\n\n // Redis logical DBs are created lazily; writing a short-lived key initializes/validates the selected DB.\n await redis_pub.set(DB_INIT_KEY, '1', 'EX', 60, 'NX')\n redis_sub.on('message', (channel_name: string, message: string) => {\n if (channel_name !== this.channel) return\n try {\n const payload = JSON.parse(message)\n void this.dispatchInboundPayload(payload)\n } catch {\n // Ignore malformed payloads.\n }\n })\n await redis_sub.subscribe(this.channel)\n this.redis_pub = redis_pub\n this.redis_sub = redis_sub\n this.running = true\n })()\n\n try {\n await this.start_promise\n } finally {\n this.start_promise = null\n }\n }\n\n async close(): Promise<void> {\n if (this.start_promise) {\n await this.start_promise.catch(() => {})\n }\n this.running = false\n if (this.redis_sub) {\n try {\n await this.redis_sub.unsubscribe(this.channel)\n } catch {\n // ignore\n }\n await this.redis_sub.quit()\n this.redis_sub = null\n }\n if (this.redis_pub) {\n await this.redis_pub.quit()\n this.redis_pub = null\n }\n this.inbound_bus.destroy()\n }\n\n private ensureStarted(): void {\n if (this.running) return\n if (this.start_promise) return\n void this.start().catch((error: unknown) => {\n console.error('[abxbus] RedisEventBridge failed to start', error)\n })\n }\n\n private async dispatchInboundPayload(payload: unknown): Promise<void> {\n const event = BaseEvent.fromJSON(payload).eventReset()\n this.inbound_bus.emit(event)\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,5 +1,5 @@
1
- import { BaseEvent } from "./base_event.js";
2
- import { EventBus } from "./event_bus.js";
1
+ import { BaseEvent } from "./BaseEvent.js";
2
+ import { EventBus } from "./EventBus.js";
3
3
  import { isNodeRuntime } from "./optional_deps.js";
4
4
  const randomSuffix = () => Math.random().toString(36).slice(2, 10);
5
5
  const IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
@@ -232,4 +232,4 @@ class SQLiteEventBridge {
232
232
  export {
233
233
  SQLiteEventBridge
234
234
  };
235
- //# sourceMappingURL=bridge_sqlite.js.map
235
+ //# sourceMappingURL=SQLiteEventBridge.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/SQLiteEventBridge.ts"],
4
+ "sourcesContent": ["import { BaseEvent } from './BaseEvent.js'\nimport { EventBus } from './EventBus.js'\nimport { isNodeRuntime } from './optional_deps.js'\nimport type { EventClass, EventHandlerCallable, EventPattern, UntypedEventHandlerFunction } from './types.js'\n\nconst randomSuffix = (): string => Math.random().toString(36).slice(2, 10)\nconst IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/\nconst EVENT_PAYLOAD_COLUMN = 'event_payload'\n\nconst validateIdentifier = (value: string, label: string): string => {\n if (!IDENTIFIER_RE.test(value)) {\n throw new Error(`Invalid ${label}: ${JSON.stringify(value)}. Use only [A-Za-z0-9_] and start with a letter/_`)\n }\n return value\n}\n\nconst loadNodeSqlite = async (): Promise<any> => {\n const dynamic_import = Function('module_name', 'return import(module_name)') as (module_name: string) => Promise<unknown>\n try {\n return (await dynamic_import('node:sqlite')) as any\n } catch {\n throw new Error('SQLiteEventBridge requires Node.js with built-in \"node:sqlite\" support (Node 22+).')\n }\n}\n\nconst splitBridgePayload = (\n payload: Record<string, unknown>\n): { event_fields: Record<string, unknown>; event_payload: Record<string, unknown> } => {\n const event_fields: Record<string, unknown> = {}\n const event_payload: Record<string, unknown> = { ...payload }\n for (const [key, value] of Object.entries(payload)) {\n if (key.startsWith('event_')) {\n event_fields[key] = value\n }\n }\n return { event_fields, event_payload }\n}\n\nexport class SQLiteEventBridge {\n readonly path: string\n readonly table: string\n readonly poll_interval: number\n readonly name: string\n\n private readonly inbound_bus: EventBus\n private running: boolean\n private last_seen_event_created_at: string\n private last_seen_event_id: string\n private listener_task: Promise<void> | null\n private start_task: Promise<void> | null\n private db: any | null\n private table_columns: Set<string>\n\n constructor(path: string, table: string = 'abxbus_events', poll_interval: number = 0.25, name?: string) {\n this.path = path\n this.table = validateIdentifier(table, 'table name')\n this.poll_interval = poll_interval\n this.name = name ?? `SQLiteEventBridge_${randomSuffix()}`\n this.inbound_bus = new EventBus(this.name, { max_history_size: 0 })\n this.running = false\n this.last_seen_event_created_at = ''\n this.last_seen_event_id = ''\n this.listener_task = null\n this.start_task = null\n this.db = null\n this.table_columns = new Set(['event_id', 'event_created_at', 'event_type', EVENT_PAYLOAD_COLUMN])\n\n this.dispatch = this.dispatch.bind(this)\n this.emit = this.emit.bind(this)\n this.on = this.on.bind(this)\n }\n\n on<T extends BaseEvent>(event_pattern: EventClass<T>, handler: EventHandlerCallable<T>): void\n on<T extends BaseEvent>(event_pattern: string | '*', handler: UntypedEventHandlerFunction<T>): void\n on(event_pattern: EventPattern | '*', handler: EventHandlerCallable | UntypedEventHandlerFunction): void {\n this.ensureStarted()\n if (typeof event_pattern === 'string') {\n this.inbound_bus.on(event_pattern, handler as UntypedEventHandlerFunction<BaseEvent>)\n return\n }\n this.inbound_bus.on(event_pattern as EventClass<BaseEvent>, handler as EventHandlerCallable<BaseEvent>)\n }\n\n async emit<T extends BaseEvent>(event: T): Promise<void> {\n this.ensureStarted()\n if (!this.running) {\n await this.start()\n }\n if (!this.db) {\n throw new Error('SQLiteEventBridge database not initialized')\n }\n\n const payload = event.toJSON() as Record<string, unknown>\n const { event_fields, event_payload } = splitBridgePayload(payload)\n const write_payload: Record<string, unknown> = { ...event_fields, [EVENT_PAYLOAD_COLUMN]: event_payload }\n const payload_keys = Object.keys(write_payload).sort()\n this.ensureColumns(payload_keys)\n\n const columns_sql = payload_keys.map((key) => `\"${key}\"`).join(', ')\n const placeholders_sql = payload_keys.map((key) => (key === EVENT_PAYLOAD_COLUMN ? 'json(?)' : '?')).join(', ')\n const values = payload_keys.map((key) =>\n write_payload[key] === null || write_payload[key] === undefined ? null : JSON.stringify(write_payload[key])\n )\n\n const update_fields = payload_keys.filter((key) => key !== 'event_id')\n let upsert_sql = `INSERT INTO \"${this.table}\" (${columns_sql}) VALUES (${placeholders_sql})`\n if (update_fields.length > 0) {\n const updates_sql = update_fields.map((key) => `\"${key}\" = excluded.\"${key}\"`).join(', ')\n upsert_sql += ` ON CONFLICT(\"event_id\") DO UPDATE SET ${updates_sql}`\n } else {\n upsert_sql += ' ON CONFLICT(\"event_id\") DO NOTHING'\n }\n\n this.db.prepare(upsert_sql).run(...values)\n }\n\n async dispatch<T extends BaseEvent>(event: T): Promise<void> {\n return this.emit(event)\n }\n\n async start(): Promise<void> {\n if (this.running) return\n if (this.start_task) {\n await this.start_task\n return\n }\n\n this.start_task = (async (): Promise<void> => {\n if (!isNodeRuntime()) {\n throw new Error('SQLiteEventBridge is only supported in Node.js runtimes')\n }\n\n const mod = await loadNodeSqlite()\n const Database = mod.DatabaseSync ?? mod.default?.DatabaseSync\n if (typeof Database !== 'function') {\n throw new Error('SQLiteEventBridge could not load DatabaseSync from node:sqlite. Please use Node.js 22+.')\n }\n this.db = new Database(this.path)\n this.db.exec('PRAGMA journal_mode = WAL')\n this.db\n .prepare(\n `CREATE TABLE IF NOT EXISTS \"${this.table}\" (\"event_id\" TEXT PRIMARY KEY, \"event_created_at\" TEXT, \"event_type\" TEXT, \"event_payload\" JSON)`\n )\n .run()\n\n this.refreshColumnCache()\n this.ensureColumns(['event_id', 'event_created_at', 'event_type', EVENT_PAYLOAD_COLUMN])\n this.ensureBaseIndexes()\n this.setCursorToLatestRow()\n\n this.running = true\n this.listener_task = this.listenLoop()\n })()\n\n try {\n await this.start_task\n } finally {\n this.start_task = null\n }\n }\n\n async close(): Promise<void> {\n await Promise.allSettled(this.start_task ? [this.start_task] : [])\n this.running = false\n await Promise.allSettled(this.listener_task ? [this.listener_task] : [])\n this.listener_task = null\n\n if (this.db) {\n this.db.close()\n this.db = null\n }\n\n this.inbound_bus.destroy()\n }\n\n private ensureStarted(): void {\n if (this.running || this.listener_task || this.start_task) return\n void this.start().catch((error: unknown) => {\n console.error('[abxbus] SQLiteEventBridge failed to start', error)\n })\n }\n\n private async listenLoop(): Promise<void> {\n while (this.running) {\n try {\n if (this.db) {\n const rows = this.db\n .prepare(\n `SELECT * FROM \"${this.table}\" WHERE COALESCE(\"event_created_at\", '') > ? OR (COALESCE(\"event_created_at\", '') = ? AND COALESCE(\"event_id\", '') > ?) ORDER BY COALESCE(\"event_created_at\", '') ASC, COALESCE(\"event_id\", '') ASC`\n )\n .all(this.last_seen_event_created_at, this.last_seen_event_created_at, this.last_seen_event_id) as Array<\n Record<string, unknown>\n >\n\n for (const row of rows) {\n this.last_seen_event_created_at = String(row.event_created_at ?? '')\n this.last_seen_event_id = String(row.event_id ?? '')\n\n const raw_payload_blob = row[EVENT_PAYLOAD_COLUMN]\n const payload: Record<string, unknown> = {}\n if (typeof raw_payload_blob === 'string') {\n try {\n const decoded_event_payload = JSON.parse(raw_payload_blob)\n if (decoded_event_payload && typeof decoded_event_payload === 'object' && !Array.isArray(decoded_event_payload)) {\n Object.assign(payload, decoded_event_payload as Record<string, unknown>)\n }\n } catch {\n // ignore malformed payload column\n }\n }\n\n for (const [key, raw_value] of Object.entries(row)) {\n if (key === EVENT_PAYLOAD_COLUMN || !key.startsWith('event_')) continue\n if (raw_value === null || raw_value === undefined) continue\n\n if (typeof raw_value !== 'string') {\n payload[key] = raw_value\n continue\n }\n\n try {\n payload[key] = JSON.parse(raw_value)\n } catch {\n payload[key] = raw_value\n }\n }\n\n await this.dispatchInboundPayload(payload)\n }\n }\n } catch {\n // Keep polling on transient errors.\n }\n await new Promise((resolve) => setTimeout(resolve, Math.max(1, this.poll_interval * 1000)))\n }\n }\n\n private async dispatchInboundPayload(payload: unknown): Promise<void> {\n const event = BaseEvent.fromJSON(payload).eventReset()\n this.inbound_bus.emit(event)\n }\n\n private refreshColumnCache(): void {\n if (!this.db) return\n const rows = this.db.prepare(`PRAGMA table_info(\"${this.table}\")`).all() as Array<{ name: string }>\n this.table_columns = new Set(rows.map((row) => String(row.name)))\n }\n\n private ensureColumns(keys: string[]): void {\n if (!this.db) return\n\n for (const key of keys) {\n validateIdentifier(key, 'event field name')\n if (key !== EVENT_PAYLOAD_COLUMN && !key.startsWith('event_')) {\n throw new Error(`Invalid event field name for bridge column: ${JSON.stringify(key)}. Only event_* fields become columns`)\n }\n }\n\n const missing_columns = keys.filter((key) => !this.table_columns.has(key))\n for (const key of missing_columns) {\n const column_type = key === EVENT_PAYLOAD_COLUMN ? 'JSON' : 'TEXT'\n this.db.prepare(`ALTER TABLE \"${this.table}\" ADD COLUMN \"${key}\" ${column_type}`).run()\n this.table_columns.add(key)\n }\n }\n\n private ensureBaseIndexes(): void {\n if (!this.db) return\n\n const event_created_at_index = `${this.table}_event_created_at_idx`\n const event_type_index = `${this.table}_event_type_idx`\n\n this.db.prepare(`CREATE INDEX IF NOT EXISTS \"${event_created_at_index}\" ON \"${this.table}\" (\"event_created_at\")`).run()\n this.db.prepare(`CREATE INDEX IF NOT EXISTS \"${event_type_index}\" ON \"${this.table}\" (\"event_type\")`).run()\n }\n\n private setCursorToLatestRow(): void {\n if (!this.db) return\n\n const row = this.db\n .prepare(\n `SELECT COALESCE(\"event_created_at\", '') AS event_created_at, COALESCE(\"event_id\", '') AS event_id FROM \"${this.table}\" ORDER BY COALESCE(\"event_created_at\", '') DESC, COALESCE(\"event_id\", '') DESC LIMIT 1`\n )\n .get() as { event_created_at?: string; event_id?: string } | undefined\n\n this.last_seen_event_created_at = String(row?.event_created_at ?? '')\n this.last_seen_event_id = String(row?.event_id ?? '')\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,15 @@
1
+ import { EventBridge, randomSuffix } from "./EventBridge.js";
2
+ class SocketEventBridge extends EventBridge {
3
+ constructor(path, name) {
4
+ const normalized = path ? path.startsWith("unix://") ? path.slice(7) : path : null;
5
+ if (normalized === "") {
6
+ throw new Error("SocketEventBridge path must not be empty");
7
+ }
8
+ const endpoint = normalized ? `unix://${normalized}` : null;
9
+ super(endpoint, endpoint, name ?? `SocketEventBridge_${randomSuffix()}`);
10
+ }
11
+ }
12
+ export {
13
+ SocketEventBridge
14
+ };
15
+ //# sourceMappingURL=SocketEventBridge.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/SocketEventBridge.ts"],
4
+ "sourcesContent": ["import { EventBridge, randomSuffix } from './EventBridge.js'\n\nexport class SocketEventBridge extends EventBridge {\n constructor(path?: string | null, name?: string) {\n const normalized = path ? (path.startsWith('unix://') ? path.slice(7) : path) : null\n if (normalized === '') {\n throw new Error('SocketEventBridge path must not be empty')\n }\n\n const endpoint = normalized ? `unix://${normalized}` : null\n super(endpoint, endpoint, name ?? `SocketEventBridge_${randomSuffix()}`)\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,aAAa,oBAAoB;AAEnC,MAAM,0BAA0B,YAAY;AAAA,EACjD,YAAY,MAAsB,MAAe;AAC/C,UAAM,aAAa,OAAQ,KAAK,WAAW,SAAS,IAAI,KAAK,MAAM,CAAC,IAAI,OAAQ;AAChF,QAAI,eAAe,IAAI;AACrB,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AAEA,UAAM,WAAW,aAAa,UAAU,UAAU,KAAK;AACvD,UAAM,UAAU,UAAU,QAAQ,qBAAqB,aAAa,CAAC,EAAE;AAAA,EACzE;AACF;",
6
+ "names": []
7
+ }