abxbus 2.4.24 → 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 (178) 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} +49 -26
  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/middleware_otel_tracing.d.ts +2 -2
  63. package/dist/cjs/middlewares.d.ts +1 -13
  64. package/dist/cjs/middlewares.js.map +1 -1
  65. package/dist/cjs/types.d.ts +1 -1
  66. package/dist/cjs/types.js.map +1 -1
  67. package/dist/esm/{base_event.js → BaseEvent.js} +4 -4
  68. package/dist/esm/BaseEvent.js.map +7 -0
  69. package/dist/esm/EventBridge.js +275 -0
  70. package/dist/esm/EventBridge.js.map +7 -0
  71. package/dist/esm/{event_bus.js → EventBus.js} +5 -5
  72. package/dist/esm/EventBus.js.map +7 -0
  73. package/dist/esm/EventBusMiddleware.js +1 -0
  74. package/dist/esm/EventBusMiddleware.js.map +7 -0
  75. package/dist/esm/{event_handler.js → EventHandler.js} +1 -1
  76. package/dist/esm/EventHandler.js.map +7 -0
  77. package/dist/esm/{event_history.js → EventHistory.js} +1 -1
  78. package/dist/esm/EventHistory.js.map +7 -0
  79. package/dist/esm/{event_result.js → EventResult.js} +7 -5
  80. package/dist/esm/EventResult.js.map +7 -0
  81. package/dist/esm/HTTPEventBridge.js +17 -0
  82. package/dist/esm/HTTPEventBridge.js.map +7 -0
  83. package/dist/esm/{bridge_jsonl.js → JSONLEventBridge.js} +3 -3
  84. package/dist/esm/JSONLEventBridge.js.map +7 -0
  85. package/dist/esm/{lock_manager.js → LockManager.js} +1 -1
  86. package/dist/esm/LockManager.js.map +7 -0
  87. package/dist/esm/{bridge_nats.js → NATSEventBridge.js} +3 -3
  88. package/dist/esm/NATSEventBridge.js.map +7 -0
  89. package/dist/esm/{middleware_otel_tracing.js → OtelTracingMiddleware.js} +47 -24
  90. package/dist/esm/OtelTracingMiddleware.js.map +7 -0
  91. package/dist/esm/{bridge_postgres.js → PostgresEventBridge.js} +3 -3
  92. package/dist/esm/PostgresEventBridge.js.map +7 -0
  93. package/dist/esm/{bridge_redis.js → RedisEventBridge.js} +3 -3
  94. package/dist/esm/RedisEventBridge.js.map +7 -0
  95. package/dist/esm/{bridge_sqlite.js → SQLiteEventBridge.js} +3 -3
  96. package/dist/esm/SQLiteEventBridge.js.map +7 -0
  97. package/dist/esm/SocketEventBridge.js +15 -0
  98. package/dist/esm/SocketEventBridge.js.map +7 -0
  99. package/dist/esm/bridges.js +9 -296
  100. package/dist/esm/bridges.js.map +2 -2
  101. package/dist/esm/events_suck.js +2 -2
  102. package/dist/esm/events_suck.js.map +1 -1
  103. package/dist/esm/index.js +11 -19
  104. package/dist/esm/index.js.map +2 -2
  105. package/dist/esm/logging.js +2 -2
  106. package/dist/esm/logging.js.map +1 -1
  107. package/dist/esm/types.js.map +1 -1
  108. package/dist/types/BaseEvent.d.ts +211 -0
  109. package/dist/types/EventBridge.d.ts +34 -0
  110. package/dist/types/EventBus.d.ts +125 -0
  111. package/dist/types/EventBusMiddleware.d.ts +13 -0
  112. package/dist/types/EventHandler.d.ts +140 -0
  113. package/dist/types/EventHistory.d.ts +45 -0
  114. package/dist/types/EventResult.d.ts +86 -0
  115. package/dist/types/HTTPEventBridge.d.ts +10 -0
  116. package/dist/types/JSONLEventBridge.d.ts +26 -0
  117. package/dist/types/LockManager.d.ts +70 -0
  118. package/dist/types/NATSEventBridge.d.ts +20 -0
  119. package/dist/types/OtelTracingMiddleware.d.ts +49 -0
  120. package/dist/types/PostgresEventBridge.d.ts +31 -0
  121. package/dist/types/RedisEventBridge.d.ts +34 -0
  122. package/dist/types/SQLiteEventBridge.d.ts +30 -0
  123. package/dist/types/SocketEventBridge.d.ts +4 -0
  124. package/dist/types/bridge_ipc.d.ts +45 -0
  125. package/dist/types/bridges.d.ts +9 -49
  126. package/dist/types/events_suck.d.ts +2 -2
  127. package/dist/types/index.d.ts +15 -14
  128. package/dist/types/logging.d.ts +2 -2
  129. package/dist/types/middleware_otel_tracing.d.ts +2 -2
  130. package/dist/types/middlewares.d.ts +1 -13
  131. package/dist/types/types.d.ts +1 -1
  132. package/package.json +52 -10
  133. package/src/{base_event.ts → BaseEvent.ts} +5 -5
  134. package/src/EventBridge.ts +332 -0
  135. package/src/{event_bus.ts → EventBus.ts} +6 -6
  136. package/src/EventBusMiddleware.ts +16 -0
  137. package/src/{event_handler.ts → EventHandler.ts} +2 -2
  138. package/src/{event_history.ts → EventHistory.ts} +1 -1
  139. package/src/{event_result.ts → EventResult.ts} +8 -6
  140. package/src/HTTPEventBridge.ts +27 -0
  141. package/src/{bridge_jsonl.ts → JSONLEventBridge.ts} +2 -2
  142. package/src/{lock_manager.ts → LockManager.ts} +2 -2
  143. package/src/{bridge_nats.ts → NATSEventBridge.ts} +2 -2
  144. package/src/{middleware_otel_tracing.ts → OtelTracingMiddleware.ts} +55 -26
  145. package/src/{bridge_postgres.ts → PostgresEventBridge.ts} +2 -2
  146. package/src/{bridge_redis.ts → RedisEventBridge.ts} +2 -2
  147. package/src/{bridge_sqlite.ts → SQLiteEventBridge.ts} +2 -2
  148. package/src/SocketEventBridge.ts +13 -0
  149. package/src/bridges.ts +9 -376
  150. package/src/events_suck.ts +2 -2
  151. package/src/index.ts +15 -22
  152. package/src/logging.ts +3 -3
  153. package/src/middlewares.ts +1 -16
  154. package/src/types.ts +1 -1
  155. package/dist/cjs/base_event.js.map +0 -7
  156. package/dist/cjs/bridge_jsonl.js.map +0 -7
  157. package/dist/cjs/bridge_nats.js.map +0 -7
  158. package/dist/cjs/bridge_postgres.js.map +0 -7
  159. package/dist/cjs/bridge_redis.js.map +0 -7
  160. package/dist/cjs/bridge_sqlite.js.map +0 -7
  161. package/dist/cjs/event_bus.js.map +0 -7
  162. package/dist/cjs/event_handler.js.map +0 -7
  163. package/dist/cjs/event_history.js.map +0 -7
  164. package/dist/cjs/event_result.js.map +0 -7
  165. package/dist/cjs/lock_manager.js.map +0 -7
  166. package/dist/cjs/middleware_otel_tracing.js.map +0 -7
  167. package/dist/esm/base_event.js.map +0 -7
  168. package/dist/esm/bridge_jsonl.js.map +0 -7
  169. package/dist/esm/bridge_nats.js.map +0 -7
  170. package/dist/esm/bridge_postgres.js.map +0 -7
  171. package/dist/esm/bridge_redis.js.map +0 -7
  172. package/dist/esm/bridge_sqlite.js.map +0 -7
  173. package/dist/esm/event_bus.js.map +0 -7
  174. package/dist/esm/event_handler.js.map +0 -7
  175. package/dist/esm/event_history.js.map +0 -7
  176. package/dist/esm/event_result.js.map +0 -7
  177. package/dist/esm/lock_manager.js.map +0 -7
  178. package/dist/esm/middleware_otel_tracing.js.map +0 -7
@@ -16,11 +16,11 @@ var __copyProps = (to, from, except, desc) => {
16
16
  return to;
17
17
  };
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var middleware_otel_tracing_exports = {};
20
- __export(middleware_otel_tracing_exports, {
19
+ var OtelTracingMiddleware_exports = {};
20
+ __export(OtelTracingMiddleware_exports, {
21
21
  OtelTracingMiddleware: () => OtelTracingMiddleware
22
22
  });
23
- module.exports = __toCommonJS(middleware_otel_tracing_exports);
23
+ module.exports = __toCommonJS(OtelTracingMiddleware_exports);
24
24
  var import_api = require("@opentelemetry/api");
25
25
  var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
26
26
  var import_resources = require("@opentelemetry/resources");
@@ -73,7 +73,7 @@ class OtelTracingMiddleware {
73
73
  return existing;
74
74
  }
75
75
  const parent_context = this.parentContextForEvent(event) ?? import_api.ROOT_CONTEXT;
76
- const start_time = dateFromIso(event.event_started_at);
76
+ const start_time = timeInputFromIso(event.event_started_at);
77
77
  const span = this.tracer.startSpan(
78
78
  eventSpanName(eventbus, event),
79
79
  {
@@ -101,8 +101,8 @@ class OtelTracingMiddleware {
101
101
  span.setAttributes(
102
102
  event.event_parent_id ? eventSpanAttributes(eventbus, event) : topLevelEventSpanAttributes(this.root_span_attributes, eventbus, event)
103
103
  );
104
- const start_time = dateFromIso(event.event_started_at);
105
- const end_time = endTimeAfterStart(start_time, dateFromIso(event.event_completed_at));
104
+ const start_time = epochNsFromIso(event.event_started_at);
105
+ const end_time = endTimeAfterStart(start_time, epochNsFromIso(event.event_completed_at));
106
106
  span.end(end_time);
107
107
  this.event_spans.delete(event.event_id);
108
108
  this.event_contexts.delete(event.event_id);
@@ -117,7 +117,7 @@ class OtelTracingMiddleware {
117
117
  handlerSpanName(event, event_result),
118
118
  {
119
119
  attributes: handlerSpanAttributes(eventbus, event, event_result),
120
- startTime: dateFromIso(event_result.started_at)
120
+ startTime: timeInputFromIso(event_result.started_at)
121
121
  },
122
122
  parent_context
123
123
  );
@@ -139,10 +139,8 @@ class OtelTracingMiddleware {
139
139
  } else {
140
140
  span.setStatus({ code: import_api.SpanStatusCode.OK });
141
141
  }
142
- span.setAttributes(
143
- handlerSpanAttributes(eventbus, event, event_result)
144
- );
145
- span.end(endTimeAfterStart(dateFromIso(event_result.started_at), dateFromIso(event_result.completed_at)));
142
+ span.setAttributes(handlerSpanAttributes(eventbus, event, event_result));
143
+ span.end(endTimeAfterStart(epochNsFromIso(event_result.started_at), epochNsFromIso(event_result.completed_at)));
146
144
  this.handler_spans.delete(event_result.id);
147
145
  this.handler_contexts.delete(handlerSpanKey(event_result.event_id, event_result.handler_id));
148
146
  }
@@ -169,21 +167,21 @@ class OtelTracingMiddleware {
169
167
  return;
170
168
  }
171
169
  visited_event_ids.add(original_event.event_id);
172
- const start_time = dateFromIso(original_event.event_started_at);
170
+ const start_time = epochNsFromIso(original_event.event_started_at);
173
171
  const span_context = eventSpanContext(trace_id, original_event.event_id);
174
172
  const span = this.span_factory({
175
173
  name: eventSpanName(eventbus, original_event),
176
174
  span_context,
177
175
  parent_span_context,
178
176
  attributes: original_event.event_parent_id ? eventSpanAttributes(eventbus, original_event) : topLevelEventSpanAttributes(this.root_span_attributes, eventbus, original_event),
179
- start_time
177
+ start_time: timeInputFromEpochNs(start_time)
180
178
  });
181
179
  if (original_event.event_errors.length > 0) {
182
180
  recordSpanError(span, original_event.event_errors[0]);
183
181
  } else {
184
182
  span.setStatus({ code: import_api.SpanStatusCode.OK });
185
183
  }
186
- span.end(endTimeAfterStart(start_time, dateFromIso(original_event.event_completed_at)));
184
+ span.end(endTimeAfterStart(start_time, epochNsFromIso(original_event.event_completed_at)));
187
185
  for (const event_result of original_event.event_results.values()) {
188
186
  const handler_context = this.exportHandlerSpanWithFactory(eventbus, original_event, event_result, trace_id, span_context);
189
187
  for (const child of event_result.event_children) {
@@ -192,21 +190,21 @@ class OtelTracingMiddleware {
192
190
  }
193
191
  }
194
192
  exportHandlerSpanWithFactory(eventbus, event, event_result, trace_id, parent_span_context) {
195
- const start_time = dateFromIso(event_result.started_at);
193
+ const start_time = epochNsFromIso(event_result.started_at);
196
194
  const span_context = handlerSpanContext(trace_id, event_result.event_id, event_result.handler_id);
197
195
  const span = this.span_factory({
198
196
  name: handlerSpanName(event, event_result),
199
197
  span_context,
200
198
  parent_span_context,
201
199
  attributes: handlerSpanAttributes(eventbus, event, event_result),
202
- start_time
200
+ start_time: timeInputFromEpochNs(start_time)
203
201
  });
204
202
  if (event_result.error !== void 0) {
205
203
  recordSpanError(span, event_result.error);
206
204
  } else {
207
205
  span.setStatus({ code: import_api.SpanStatusCode.OK });
208
206
  }
209
- span.end(endTimeAfterStart(start_time, dateFromIso(event_result.completed_at)));
207
+ span.end(endTimeAfterStart(start_time, epochNsFromIso(event_result.completed_at)));
210
208
  return span_context;
211
209
  }
212
210
  }
@@ -225,10 +223,13 @@ function createOtlpSpanProvider(options) {
225
223
  "service.name": options.service_name ?? "abxbus"
226
224
  }),
227
225
  spanProcessors: [
228
- new import_sdk_trace_base.SimpleSpanProcessor(
226
+ new import_sdk_trace_base.BatchSpanProcessor(
229
227
  new import_exporter_trace_otlp_http.OTLPTraceExporter({
230
228
  url: normalizeOtlpTracesEndpoint(options.otlp_endpoint)
231
- })
229
+ }),
230
+ {
231
+ scheduledDelayMillis: 100
232
+ }
232
233
  )
233
234
  ]
234
235
  });
@@ -342,18 +343,40 @@ function fnv1a64Hex(input) {
342
343
  }
343
344
  return hash.toString(16).padStart(16, "0");
344
345
  }
345
- function dateFromIso(value) {
346
+ const 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})$/;
347
+ const NS_PER_SECOND = 1000000000n;
348
+ const NS_PER_MS = 1000000n;
349
+ function epochNsFromIso(value) {
346
350
  if (value == null) {
347
351
  return void 0;
348
352
  }
349
- const date = new Date(value);
350
- return Number.isNaN(date.getTime()) ? void 0 : date;
353
+ const match = ISO_EPOCH_NS_REGEX.exec(value);
354
+ if (!match) {
355
+ return void 0;
356
+ }
357
+ const [, base, fraction = "", timezone] = match;
358
+ const base_ms = Date.parse(`${base}.000${timezone}`);
359
+ if (Number.isNaN(base_ms)) {
360
+ return void 0;
361
+ }
362
+ return BigInt(base_ms) * NS_PER_MS + BigInt(fraction.padEnd(9, "0"));
363
+ }
364
+ function timeInputFromIso(value) {
365
+ return timeInputFromEpochNs(epochNsFromIso(value));
366
+ }
367
+ function timeInputFromEpochNs(epoch_ns) {
368
+ if (epoch_ns === void 0) {
369
+ return void 0;
370
+ }
371
+ const seconds = epoch_ns / NS_PER_SECOND;
372
+ const nanos = epoch_ns % NS_PER_SECOND;
373
+ return [Number(seconds), Number(nanos)];
351
374
  }
352
375
  function endTimeAfterStart(start_time, end_time) {
353
- if (!start_time || !end_time) {
354
- return end_time;
376
+ if (start_time === void 0 || end_time === void 0) {
377
+ return timeInputFromEpochNs(end_time);
355
378
  }
356
- return end_time.getTime() > start_time.getTime() ? end_time : new Date(start_time.getTime() + 1);
379
+ return timeInputFromEpochNs(end_time > start_time ? end_time : start_time + 1n);
357
380
  }
358
381
  function resolveAttributes(attributes, eventbus, event) {
359
382
  return typeof attributes === "function" ? attributes(eventbus, event) : attributes ?? {};
@@ -380,4 +403,4 @@ function recordSpanError(span, error) {
380
403
  span.recordException(message);
381
404
  span.setStatus({ code: import_api.SpanStatusCode.ERROR, message });
382
405
  }
383
- //# sourceMappingURL=middleware_otel_tracing.js.map
406
+ //# 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": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAYO;AACP,sCAAkC;AAClC,uBAAuC;AACvC,4BAAwD;AAExD,kBAAyB;AA0ClB,MAAM,sBAAoD;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc,oBAAI,IAAkB;AAAA,EACpC,iBAAiB,oBAAI,IAAqB;AAAA,EAC1C,gBAAgB,oBAAI,IAAkB;AAAA,EACtC,mBAAmB,oBAAI,IAAqB;AAAA,EAE7D,YAAY,UAAwC,CAAC,GAAG;AACtD,SAAK,YAAY,QAAQ,aAAa;AACtC,SAAK,SAAS,QAAQ,UAAU,KAAK,UAAU,UAAU,QAAQ;AACjE,SAAK,gBAAgB,QAAQ,kBAAkB,QAAQ,gBAAgB,uBAAuB,OAAO,IAAI;AACzG,SAAK,eACH,QAAQ,iBACP,KAAK,gBACF,0BAA0B,KAAK,WAAW,KAAK,eAAe,QAAQ,wBAAwB,QAAQ,IACtG;AACN,SAAK,uBAAuB,QAAQ;AAAA,EACtC;AAAA,EAEA,cAAc,UAAoB,OAAkB,QAA2B;AAC7E,QAAI,WAAW,WAAW;AACxB,UAAI,KAAK,cAAc;AACrB;AAAA,MACF;AACA,WAAK,eAAe,UAAU,KAAK;AACnC;AAAA,IACF;AAEA,QAAI,WAAW,aAAa;AAC1B,WAAK,kBAAkB,UAAU,KAAK;AAAA,IACxC;AAAA,EACF;AAAA,EAEA,oBAAoB,UAAoB,OAAkB,cAA2B,QAA2B;AAC9G,QAAI,WAAW,WAAW;AACxB,UAAI,KAAK,cAAc;AACrB;AAAA,MACF;AACA,WAAK,iBAAiB,UAAU,OAAO,YAAY;AACnD;AAAA,IACF;AAEA,QAAI,WAAW,aAAa;AAC1B,WAAK,oBAAoB,UAAU,OAAO,YAAY;AAAA,IACxD;AAAA,EACF;AAAA,EAEQ,eAAe,UAAoB,OAAwB;AACjE,UAAM,WAAW,KAAK,YAAY,IAAI,MAAM,QAAQ;AACpD,QAAI,UAAU;AACZ,aAAO;AAAA,IACT;AAEA,UAAM,iBAAiB,KAAK,sBAAsB,KAAK,KAAK;AAC5D,UAAM,aAAa,iBAAiB,MAAM,gBAAgB;AAC1D,UAAM,OAAO,KAAK,OAAO;AAAA,MACvB,cAAc,UAAU,KAAK;AAAA,MAC7B;AAAA,QACE,YAAY,MAAM,kBACd,2BAA2B,UAAU,KAAK,IAC1C,mCAAmC,KAAK,sBAAsB,UAAU,KAAK;AAAA,QACjF,WAAW;AAAA,MACb;AAAA,MACA;AAAA,IACF;AACA,UAAM,eAAe,KAAK,UAAU,QAAQ,gBAAgB,IAAI;AAChE,SAAK,YAAY,IAAI,MAAM,UAAU,IAAI;AACzC,SAAK,eAAe,IAAI,MAAM,UAAU,YAAY;AACpD,WAAO;AAAA,EACT;AAAA,EAEQ,kBAAkB,UAAoB,OAAwB;AACpE,QAAI,KAAK,cAAc;AACrB,WAAK,6BAA6B,UAAU,KAAK;AACjD;AAAA,IACF;AAEA,UAAM,OAAO,KAAK,YAAY,IAAI,MAAM,QAAQ,KAAK,KAAK,eAAe,UAAU,KAAK;AACxF,QAAI,MAAM,aAAa,SAAS,GAAG;AACjC,sBAAgB,MAAM,MAAM,aAAa,CAAC,CAAC;AAAA,IAC7C,OAAO;AACL,WAAK,UAAU,EAAE,MAAM,0BAAe,GAAG,CAAC;AAAA,IAC5C;AACA,SAAK;AAAA,MACH,MAAM,kBAAkB,oBAAoB,UAAU,KAAK,IAAI,4BAA4B,KAAK,sBAAsB,UAAU,KAAK;AAAA,IACvI;AACA,UAAM,aAAa,eAAe,MAAM,gBAAgB;AACxD,UAAM,WAAW,kBAAkB,YAAY,eAAe,MAAM,kBAAkB,CAAC;AACvF,SAAK,IAAI,QAAQ;AACjB,SAAK,YAAY,OAAO,MAAM,QAAQ;AACtC,SAAK,eAAe,OAAO,MAAM,QAAQ;AAAA,EAC3C;AAAA,EAEQ,iBAAiB,UAAoB,OAAkB,cAAiC;AAC9F,UAAM,WAAW,KAAK,cAAc,IAAI,aAAa,EAAE;AACvD,QAAI,UAAU;AACZ,aAAO;AAAA,IACT;AAEA,UAAM,iBACJ,KAAK,eAAe,IAAI,MAAM,QAAQ,KAAK,KAAK,UAAU,QAAQ,yBAAc,KAAK,eAAe,UAAU,KAAK,CAAC;AACtH,UAAM,OAAO,KAAK,OAAO;AAAA,MACvB,gBAAgB,OAAO,YAAY;AAAA,MACnC;AAAA,QACE,YAAY,sBAAsB,UAAU,OAAO,YAAY;AAAA,QAC/D,WAAW,iBAAiB,aAAa,UAAU;AAAA,MACrD;AAAA,MACA;AAAA,IACF;AACA,UAAM,eAAe,KAAK,UAAU,QAAQ,gBAAgB,IAAI;AAChE,SAAK,cAAc,IAAI,aAAa,IAAI,IAAI;AAC5C,SAAK,iBAAiB,IAAI,eAAe,aAAa,UAAU,aAAa,UAAU,GAAG,YAAY;AACtG,WAAO;AAAA,EACT;AAAA,EAEQ,oBAAoB,UAAoB,OAAkB,cAAiC;AACjG,QAAI,KAAK,cAAc;AACrB;AAAA,IACF;AAEA,UAAM,OAAO,KAAK,cAAc,IAAI,aAAa,EAAE;AACnD,QAAI,CAAC,MAAM;AACT;AAAA,IACF;AAEA,QAAI,aAAa,UAAU,QAAW;AACpC,sBAAgB,MAAM,aAAa,KAAK;AAAA,IAC1C,OAAO;AACL,WAAK,UAAU,EAAE,MAAM,0BAAe,GAAG,CAAC;AAAA,IAC5C;AACA,SAAK,cAAc,sBAAsB,UAAU,OAAO,YAAY,CAAC;AACvE,SAAK,IAAI,kBAAkB,eAAe,aAAa,UAAU,GAAG,eAAe,aAAa,YAAY,CAAC,CAAC;AAC9G,SAAK,cAAc,OAAO,aAAa,EAAE;AACzC,SAAK,iBAAiB,OAAO,eAAe,aAAa,UAAU,aAAa,UAAU,CAAC;AAAA,EAC7F;AAAA,EAEQ,sBAAsB,OAAuC;AACnE,QAAI,MAAM,mBAAmB,MAAM,6BAA6B;AAC9D,YAAM,kBAAkB,KAAK,iBAAiB,IAAI,eAAe,MAAM,iBAAiB,MAAM,2BAA2B,CAAC;AAC1H,UAAI,iBAAiB;AACnB,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO,MAAM,kBAAkB,KAAK,eAAe,IAAI,MAAM,eAAe,IAAI;AAAA,EAClF;AAAA,EAEQ,6BAA6B,UAAoB,OAAwB;AAC/E,QAAI,MAAM,iBAAiB;AACzB;AAAA,IACF;AAEA,UAAM,kBAAkB,MAAM,mBAAmB;AACjD,UAAM,WAAW,oBAAoB,gBAAgB,QAAQ;AAC7D,SAAK,2BAA2B,UAAU,iBAAiB,UAAU,QAAW,oBAAI,IAAY,CAAC;AAAA,EACnG;AAAA,EAEQ,2BACN,UACA,OACA,UACA,qBACA,mBACM;AACN,UAAM,iBAAiB,MAAM,mBAAmB;AAChD,QAAI,kBAAkB,IAAI,eAAe,QAAQ,GAAG;AAClD;AAAA,IACF;AACA,sBAAkB,IAAI,eAAe,QAAQ;AAE7C,UAAM,aAAa,eAAe,eAAe,gBAAgB;AACjE,UAAM,eAAe,iBAAiB,UAAU,eAAe,QAAQ;AACvE,UAAM,OAAO,KAAK,aAAc;AAAA,MAC9B,MAAM,cAAc,UAAU,cAAc;AAAA,MAC5C;AAAA,MACA;AAAA,MACA,YAAY,eAAe,kBACvB,oBAAoB,UAAU,cAAc,IAC5C,4BAA4B,KAAK,sBAAsB,UAAU,cAAc;AAAA,MACnF,YAAY,qBAAqB,UAAU;AAAA,IAC7C,CAAC;AACD,QAAI,eAAe,aAAa,SAAS,GAAG;AAC1C,sBAAgB,MAAM,eAAe,aAAa,CAAC,CAAC;AAAA,IACtD,OAAO;AACL,WAAK,UAAU,EAAE,MAAM,0BAAe,GAAG,CAAC;AAAA,IAC5C;AACA,SAAK,IAAI,kBAAkB,YAAY,eAAe,eAAe,kBAAkB,CAAC,CAAC;AAEzF,eAAW,gBAAgB,eAAe,cAAc,OAAO,GAAG;AAChE,YAAM,kBAAkB,KAAK,6BAA6B,UAAU,gBAAgB,cAAc,UAAU,YAAY;AACxH,iBAAW,SAAS,aAAa,gBAAgB;AAC/C,aAAK,2BAA2B,UAAU,OAAO,UAAU,iBAAiB,iBAAiB;AAAA,MAC/F;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,6BACN,UACA,OACA,cACA,UACA,qBACa;AACb,UAAM,aAAa,eAAe,aAAa,UAAU;AACzD,UAAM,eAAe,mBAAmB,UAAU,aAAa,UAAU,aAAa,UAAU;AAChG,UAAM,OAAO,KAAK,aAAc;AAAA,MAC9B,MAAM,gBAAgB,OAAO,YAAY;AAAA,MACzC;AAAA,MACA;AAAA,MACA,YAAY,sBAAsB,UAAU,OAAO,YAAY;AAAA,MAC/D,YAAY,qBAAqB,UAAU;AAAA,IAC7C,CAAC;AACD,QAAI,aAAa,UAAU,QAAW;AACpC,sBAAgB,MAAM,aAAa,KAAK;AAAA,IAC1C,OAAO;AACL,WAAK,UAAU,EAAE,MAAM,0BAAe,GAAG,CAAC;AAAA,IAC5C;AACA,SAAK,IAAI,kBAAkB,YAAY,eAAe,aAAa,YAAY,CAAC,CAAC;AACjF,WAAO;AAAA,EACT;AACF;AAEA,SAAS,eAAe,UAAkB,YAA4B;AACpE,SAAO,GAAG,QAAQ,IAAI,UAAU;AAClC;AAEA,SAAS,cAAc,UAAoB,OAA0B;AACnE,SAAO,GAAG,SAAS,IAAI,SAAS,MAAM,UAAU;AAClD;AAEA,SAAS,gBAAgB,OAAkB,cAAmC;AAC5E,SAAO,GAAG,aAAa,YAAY,IAAI,MAAM,UAAU;AACzD;AAEA,SAAS,uBAAuB,SAAgE;AAC9F,SAAO,IAAI,0CAAoB;AAAA,IAC7B,cAAU,yCAAuB;AAAA,MAC/B,gBAAgB,QAAQ,gBAAgB;AAAA,IAC1C,CAAC;AAAA,IACD,gBAAgB;AAAA,MACd,IAAI;AAAA,QACF,IAAI,kDAAkB;AAAA,UACpB,KAAK,4BAA4B,QAAQ,aAAc;AAAA,QACzD,CAAC;AAAA,QACD;AAAA,UACE,sBAAsB;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,SAAS,0BACP,WACA,UACA,sBACwB;AACxB,QAAM,qBAAqB;AAC3B,SAAO,CAAC,UAA6C;AACnD,UAAM,iBAAiB,mBAAmB;AAC1C,UAAM,cAAc,mBAAmB,SAAS;AAChD,UAAM,WAAW,mBAAmB,aAAa,mBAAmB,SAAS;AAC7E,QAAI,CAAC,kBAAkB,CAAC,eAAe,CAAC,UAAU;AAChD,YAAM,IAAI,MAAM,4GAA4G;AAAA,IAC9H;AAEA,UAAM,iBAAiB,MAAM,uBACxB,UAAU,kBAAkB,iBAAM,gBAAgB,yBAAc,MAAM,mBAAmB,IAC1F;AACJ,WAAO,IAAI,qBAAS;AAAA,MAClB;AAAA,MACA,OAAO,EAAE,MAAM,qBAAqB;AAAA,MACpC,SAAS;AAAA,MACT,aAAa,MAAM;AAAA,MACnB,mBAAmB,MAAM;AAAA,MACzB,MAAM,MAAM;AAAA,MACZ,MAAM,oBAAS;AAAA,MACf,YAAY,MAAM;AAAA,MAClB,WAAW,MAAM;AAAA,MACjB,eAAe;AAAA,MACf,YAAY;AAAA,IACd,CAA8C;AAAA,EAChD;AACF;AAEA,SAAS,4BAA4B,UAA0B;AAC7D,QAAM,UAAU,SAAS,QAAQ,QAAQ,EAAE;AAC3C,SAAO,QAAQ,SAAS,YAAY,IAAI,UAAU,GAAG,OAAO;AAC9D;AAEA,SAAS,2BAA2B,UAAoB,OAAkC;AACxF,SAAO,kBAAkB;AAAA,IACvB,uBAAuB,SAAS;AAAA,IAChC,yBAAyB,SAAS;AAAA,IAClC,mBAAmB,MAAM;AAAA,IACzB,qBAAqB,MAAM;AAAA,IAC3B,wBAAwB,MAAM;AAAA,IAC9B,qBAAqB,YAAa,MAAmC,UAAU;AAAA,IAC/E,0BAA0B,MAAM;AAAA,IAChC,sCAAsC,MAAM;AAAA,IAC5C,qBAAqB,MAAM,WAAW,KAAK,GAAG;AAAA,EAChD,CAAC;AACH;AAEA,SAAS,oBAAoB,UAAoB,OAAkC;AACjF,SAAO,kBAAkB;AAAA,IACvB,GAAG,2BAA2B,UAAU,KAAK;AAAA,IAC7C,uBAAuB,MAAM;AAAA,EAC/B,CAAC;AACH;AAEA,SAAS,sBAAsB,UAAoB,OAAkB,cAA2C;AAC9G,SAAO,kBAAkB;AAAA,IACvB,uBAAuB,SAAS;AAAA,IAChC,yBAAyB,SAAS;AAAA,IAClC,mBAAmB,MAAM;AAAA,IACzB,qBAAqB,MAAM;AAAA,IAC3B,qBAAqB,aAAa;AAAA,IAClC,uBAAuB,aAAa;AAAA,IACpC,4BAA4B,aAAa;AAAA,IACzC,gCAAgC,aAAa,QAAQ;AAAA,IACrD,0BAA0B,aAAa;AAAA,IACvC,8BAA8B,aAAa;AAAA,EAC7C,CAAC;AACH;AAEA,SAAS,mCACP,sBACA,UACA,OACgB;AAChB,SAAO,kBAAkB;AAAA,IACvB,GAAG,2BAA2B,UAAU,KAAK;AAAA,IAC7C,GAAG,kBAAkB,sBAAsB,UAAU,KAAK;AAAA,IAC1D,qBAAqB;AAAA,EACvB,CAAC;AACH;AAEA,SAAS,4BACP,sBACA,UACA,OACgB;AAChB,SAAO,kBAAkB;AAAA,IACvB,GAAG,oBAAoB,UAAU,KAAK;AAAA,IACtC,GAAG,kBAAkB,sBAAsB,UAAU,KAAK;AAAA,IAC1D,qBAAqB;AAAA,EACvB,CAAC;AACH;AAEA,SAAS,iBAAiB,UAAkB,UAA+B;AACzE,SAAO;AAAA,IACL,SAAS;AAAA,IACT,QAAQ,oBAAoB,gBAAgB,QAAQ,EAAE;AAAA,IACtD,YAAY;AAAA,EACd;AACF;AAEA,SAAS,mBAAmB,UAAkB,UAAkB,YAAiC;AAC/F,SAAO;AAAA,IACL,SAAS;AAAA,IACT,QAAQ,oBAAoB,kBAAkB,QAAQ,IAAI,UAAU,EAAE;AAAA,IACtE,YAAY;AAAA,EACd;AACF;AAEA,SAAS,oBAAoB,UAA0B;AACrD,SAAO,GAAG,WAAW,kBAAkB,QAAQ,EAAE,CAAC,GAAG,WAAW,kBAAkB,QAAQ,EAAE,CAAC;AAC/F;AAEA,SAAS,oBAAoB,OAAuB;AAClD,SAAO,WAAW,KAAK;AACzB;AAEA,SAAS,WAAW,OAAuB;AACzC,MAAI,OAAO;AACX,QAAM,QAAQ;AACd,QAAM,OAAO;AACb,WAAS,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GAAG;AACpD,YAAQ,OAAO,MAAM,WAAW,KAAK,CAAC;AACtC,WAAQ,OAAO,QAAS;AAAA,EAC1B;AACA,MAAI,SAAS,IAAI;AACf,WAAO;AAAA,EACT;AACA,SAAO,KAAK,SAAS,EAAE,EAAE,SAAS,IAAI,GAAG;AAC3C;AAEA,MAAM,qBAAqB;AAC3B,MAAM,gBAAgB;AACtB,MAAM,YAAY;AAElB,SAAS,eAAe,OAAsD;AAC5E,MAAI,SAAS,MAAM;AACjB,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,mBAAmB,KAAK,KAAK;AAC3C,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,QAAM,CAAC,EAAE,MAAM,WAAW,IAAI,QAAQ,IAAI;AAC1C,QAAM,UAAU,KAAK,MAAM,GAAG,IAAI,OAAO,QAAQ,EAAE;AACnD,MAAI,OAAO,MAAM,OAAO,GAAG;AACzB,WAAO;AAAA,EACT;AACA,SAAO,OAAO,OAAO,IAAI,YAAY,OAAO,SAAS,OAAO,GAAG,GAAG,CAAC;AACrE;AAEA,SAAS,iBAAiB,OAAyD;AACjF,SAAO,qBAAqB,eAAe,KAAK,CAAC;AACnD;AAEA,SAAS,qBAAqB,UAAqD;AACjF,MAAI,aAAa,QAAW;AAC1B,WAAO;AAAA,EACT;AACA,QAAM,UAAU,WAAW;AAC3B,QAAM,QAAQ,WAAW;AACzB,SAAO,CAAC,OAAO,OAAO,GAAG,OAAO,KAAK,CAAC;AACxC;AAEA,SAAS,kBAAkB,YAAgC,UAAqD;AAC9G,MAAI,eAAe,UAAa,aAAa,QAAW;AACtD,WAAO,qBAAqB,QAAQ;AAAA,EACtC;AAEA,SAAO,qBAAqB,WAAW,aAAa,WAAW,aAAa,EAAE;AAChF;AAEA,SAAS,kBACP,YACA,UACA,OACgB;AAChB,SAAO,OAAO,eAAe,aAAa,WAAW,UAAU,KAAK,IAAK,cAAc,CAAC;AAC1F;AAEA,SAAS,YAAY,OAAoC;AACvD,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,QAAQ;AACjE;AAEA,SAAS,kBAAkB,YAAmF;AAC5G,QAAM,YAA4B,CAAC;AACnC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,QAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,gBAAU,GAAG,IAAI;AAAA,IACnB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,MAAY,OAAsB;AACzD,MAAI,iBAAiB,OAAO;AAC1B,SAAK,gBAAgB,KAAK;AAC1B,SAAK,UAAU,EAAE,MAAM,0BAAe,OAAO,SAAS,MAAM,QAAQ,CAAC;AACrE;AAAA,EACF;AAEA,QAAM,UAAU,OAAO,UAAU,WAAW,QAAQ;AACpD,OAAK,gBAAgB,OAAO;AAC5B,OAAK,UAAU,EAAE,MAAM,0BAAe,OAAO,QAAQ,CAAC;AACxD;",
6
+ "names": []
7
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * PostgreSQL LISTEN/NOTIFY + flat-table bridge for forwarding events.
3
+ */
4
+ import { BaseEvent } from './BaseEvent.js';
5
+ import type { EventClass, EventHandlerCallable, UntypedEventHandlerFunction } from './types.js';
6
+ export declare class PostgresEventBridge {
7
+ readonly table_url: string;
8
+ readonly dsn: string;
9
+ readonly table: string;
10
+ readonly channel: string;
11
+ readonly name: string;
12
+ private readonly inbound_bus;
13
+ private running;
14
+ private client;
15
+ private table_columns;
16
+ private notification_handler;
17
+ constructor(table_url: string, channel?: string, name?: string);
18
+ on<T extends BaseEvent>(event_pattern: EventClass<T>, handler: EventHandlerCallable<T>): void;
19
+ on<T extends BaseEvent>(event_pattern: string | '*', handler: UntypedEventHandlerFunction<T>): void;
20
+ emit<T extends BaseEvent>(event: T): Promise<void>;
21
+ dispatch<T extends BaseEvent>(event: T): Promise<void>;
22
+ start(): Promise<void>;
23
+ close(): Promise<void>;
24
+ private ensureStarted;
25
+ private dispatchByEventId;
26
+ private dispatchInboundPayload;
27
+ private ensureTableExists;
28
+ private ensureBaseIndexes;
29
+ private refreshColumnCache;
30
+ private ensureColumns;
31
+ }
@@ -16,13 +16,13 @@ var __copyProps = (to, from, except, desc) => {
16
16
  return to;
17
17
  };
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var bridge_postgres_exports = {};
20
- __export(bridge_postgres_exports, {
19
+ var PostgresEventBridge_exports = {};
20
+ __export(PostgresEventBridge_exports, {
21
21
  PostgresEventBridge: () => PostgresEventBridge
22
22
  });
23
- module.exports = __toCommonJS(bridge_postgres_exports);
24
- var import_base_event = require("./base_event.js");
25
- var import_event_bus = require("./event_bus.js");
23
+ module.exports = __toCommonJS(PostgresEventBridge_exports);
24
+ var import_BaseEvent = require("./BaseEvent.js");
25
+ var import_EventBus = require("./EventBus.js");
26
26
  var import_optional_deps = require("./optional_deps.js");
27
27
  const randomSuffix = () => Math.random().toString(36).slice(2, 10);
28
28
  const IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
@@ -87,7 +87,7 @@ class PostgresEventBridge {
87
87
  const derived_channel = channel ?? DEFAULT_POSTGRES_CHANNEL;
88
88
  this.channel = validateIdentifier(derived_channel.slice(0, 63), "channel name");
89
89
  this.name = name ?? `PostgresEventBridge_${randomSuffix()}`;
90
- this.inbound_bus = new import_event_bus.EventBus(this.name, { max_history_size: 0 });
90
+ this.inbound_bus = new import_EventBus.EventBus(this.name, { max_history_size: 0 });
91
91
  this.running = false;
92
92
  this.client = null;
93
93
  this.table_columns = /* @__PURE__ */ new Set(["event_id", "event_created_at", "event_type", EVENT_PAYLOAD_COLUMN]);
@@ -209,7 +209,7 @@ class PostgresEventBridge {
209
209
  await this.dispatchInboundPayload(payload);
210
210
  }
211
211
  async dispatchInboundPayload(payload) {
212
- const event = import_base_event.BaseEvent.fromJSON(payload).eventReset();
212
+ const event = import_BaseEvent.BaseEvent.fromJSON(payload).eventReset();
213
213
  this.inbound_bus.emit(event);
214
214
  }
215
215
  async ensureTableExists() {
@@ -248,4 +248,4 @@ class PostgresEventBridge {
248
248
  }
249
249
  }
250
250
  }
251
- //# sourceMappingURL=bridge_postgres.js.map
251
+ //# 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": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Redis pub/sub bridge for forwarding events between runtimes.
3
+ *
4
+ * Usage:
5
+ * // channel from URL path
6
+ * const bridge = new RedisEventBridge('redis://user:pass@localhost:6379/1/my_channel')
7
+ *
8
+ * // explicit channel override
9
+ * const bridge2 = new RedisEventBridge('redis://user:pass@localhost:6379/1', 'my_channel')
10
+ *
11
+ * URL format:
12
+ * redis://user:pass@host:6379/<db>/<optional_channel>
13
+ */
14
+ import { BaseEvent } from './BaseEvent.js';
15
+ import type { EventClass, EventHandlerCallable, UntypedEventHandlerFunction } from './types.js';
16
+ export declare class RedisEventBridge {
17
+ readonly url: string;
18
+ readonly channel: string;
19
+ readonly name: string;
20
+ private readonly inbound_bus;
21
+ private running;
22
+ private start_promise;
23
+ private redis_pub;
24
+ private redis_sub;
25
+ constructor(redis_url: string, channel?: string, name?: string);
26
+ on<T extends BaseEvent>(event_pattern: EventClass<T>, handler: EventHandlerCallable<T>): void;
27
+ on<T extends BaseEvent>(event_pattern: string | '*', handler: UntypedEventHandlerFunction<T>): void;
28
+ emit<T extends BaseEvent>(event: T): Promise<void>;
29
+ dispatch<T extends BaseEvent>(event: T): Promise<void>;
30
+ start(): Promise<void>;
31
+ close(): Promise<void>;
32
+ private ensureStarted;
33
+ private dispatchInboundPayload;
34
+ }
@@ -16,13 +16,13 @@ var __copyProps = (to, from, except, desc) => {
16
16
  return to;
17
17
  };
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var bridge_redis_exports = {};
20
- __export(bridge_redis_exports, {
19
+ var RedisEventBridge_exports = {};
20
+ __export(RedisEventBridge_exports, {
21
21
  RedisEventBridge: () => RedisEventBridge
22
22
  });
23
- module.exports = __toCommonJS(bridge_redis_exports);
24
- var import_base_event = require("./base_event.js");
25
- var import_event_bus = require("./event_bus.js");
23
+ module.exports = __toCommonJS(RedisEventBridge_exports);
24
+ var import_BaseEvent = require("./BaseEvent.js");
25
+ var import_EventBus = require("./EventBus.js");
26
26
  var import_optional_deps = require("./optional_deps.js");
27
27
  const randomSuffix = () => Math.random().toString(36).slice(2, 10);
28
28
  const DEFAULT_REDIS_CHANNEL = "abxbus_events";
@@ -76,7 +76,7 @@ class RedisEventBridge {
76
76
  this.url = parsed.url;
77
77
  this.channel = parsed.channel;
78
78
  this.name = name ?? `RedisEventBridge_${randomSuffix()}`;
79
- this.inbound_bus = new import_event_bus.EventBus(this.name, { max_history_size: 0 });
79
+ this.inbound_bus = new import_EventBus.EventBus(this.name, { max_history_size: 0 });
80
80
  this.running = false;
81
81
  this.start_promise = null;
82
82
  this.redis_pub = null;
@@ -168,8 +168,8 @@ class RedisEventBridge {
168
168
  });
169
169
  }
170
170
  async dispatchInboundPayload(payload) {
171
- const event = import_base_event.BaseEvent.fromJSON(payload).eventReset();
171
+ const event = import_BaseEvent.BaseEvent.fromJSON(payload).eventReset();
172
172
  this.inbound_bus.emit(event);
173
173
  }
174
174
  }
175
- //# sourceMappingURL=bridge_redis.js.map
175
+ //# 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
+ }
@@ -0,0 +1,30 @@
1
+ import { BaseEvent } from './BaseEvent.js';
2
+ import type { EventClass, EventHandlerCallable, UntypedEventHandlerFunction } from './types.js';
3
+ export declare class SQLiteEventBridge {
4
+ readonly path: string;
5
+ readonly table: string;
6
+ readonly poll_interval: number;
7
+ readonly name: string;
8
+ private readonly inbound_bus;
9
+ private running;
10
+ private last_seen_event_created_at;
11
+ private last_seen_event_id;
12
+ private listener_task;
13
+ private start_task;
14
+ private db;
15
+ private table_columns;
16
+ constructor(path: string, table?: string, poll_interval?: number, name?: string);
17
+ on<T extends BaseEvent>(event_pattern: EventClass<T>, handler: EventHandlerCallable<T>): void;
18
+ on<T extends BaseEvent>(event_pattern: string | '*', handler: UntypedEventHandlerFunction<T>): void;
19
+ emit<T extends BaseEvent>(event: T): Promise<void>;
20
+ dispatch<T extends BaseEvent>(event: T): Promise<void>;
21
+ start(): Promise<void>;
22
+ close(): Promise<void>;
23
+ private ensureStarted;
24
+ private listenLoop;
25
+ private dispatchInboundPayload;
26
+ private refreshColumnCache;
27
+ private ensureColumns;
28
+ private ensureBaseIndexes;
29
+ private setCursorToLatestRow;
30
+ }
@@ -16,13 +16,13 @@ var __copyProps = (to, from, except, desc) => {
16
16
  return to;
17
17
  };
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var bridge_sqlite_exports = {};
20
- __export(bridge_sqlite_exports, {
19
+ var SQLiteEventBridge_exports = {};
20
+ __export(SQLiteEventBridge_exports, {
21
21
  SQLiteEventBridge: () => SQLiteEventBridge
22
22
  });
23
- module.exports = __toCommonJS(bridge_sqlite_exports);
24
- var import_base_event = require("./base_event.js");
25
- var import_event_bus = require("./event_bus.js");
23
+ module.exports = __toCommonJS(SQLiteEventBridge_exports);
24
+ var import_BaseEvent = require("./BaseEvent.js");
25
+ var import_EventBus = require("./EventBus.js");
26
26
  var import_optional_deps = require("./optional_deps.js");
27
27
  const randomSuffix = () => Math.random().toString(36).slice(2, 10);
28
28
  const IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
@@ -69,7 +69,7 @@ class SQLiteEventBridge {
69
69
  this.table = validateIdentifier(table, "table name");
70
70
  this.poll_interval = poll_interval;
71
71
  this.name = name ?? `SQLiteEventBridge_${randomSuffix()}`;
72
- this.inbound_bus = new import_event_bus.EventBus(this.name, { max_history_size: 0 });
72
+ this.inbound_bus = new import_EventBus.EventBus(this.name, { max_history_size: 0 });
73
73
  this.running = false;
74
74
  this.last_seen_event_created_at = "";
75
75
  this.last_seen_event_id = "";
@@ -213,7 +213,7 @@ class SQLiteEventBridge {
213
213
  }
214
214
  }
215
215
  async dispatchInboundPayload(payload) {
216
- const event = import_base_event.BaseEvent.fromJSON(payload).eventReset();
216
+ const event = import_BaseEvent.BaseEvent.fromJSON(payload).eventReset();
217
217
  this.inbound_bus.emit(event);
218
218
  }
219
219
  refreshColumnCache() {
@@ -252,4 +252,4 @@ class SQLiteEventBridge {
252
252
  this.last_seen_event_id = String(row?.event_id ?? "");
253
253
  }
254
254
  }
255
- //# sourceMappingURL=bridge_sqlite.js.map
255
+ //# 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,4 @@
1
+ import { EventBridge } from './EventBridge.js';
2
+ export declare class SocketEventBridge extends EventBridge {
3
+ constructor(path?: string | null, name?: string);
4
+ }