abxbus 2.4.32 → 2.5.1

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 (70) hide show
  1. package/README.md +74 -51
  2. package/dist/cjs/BaseEvent.d.ts +46 -55
  3. package/dist/cjs/BaseEvent.js +350 -169
  4. package/dist/cjs/BaseEvent.js.map +3 -3
  5. package/dist/cjs/EventBus.d.ts +8 -1
  6. package/dist/cjs/EventBus.js +153 -85
  7. package/dist/cjs/EventBus.js.map +2 -2
  8. package/dist/cjs/EventHandler.d.ts +3 -3
  9. package/dist/cjs/EventHandler.js.map +1 -1
  10. package/dist/cjs/EventResult.js +16 -22
  11. package/dist/cjs/EventResult.js.map +2 -2
  12. package/dist/cjs/LockManager.d.ts +1 -0
  13. package/dist/cjs/LockManager.js +4 -1
  14. package/dist/cjs/LockManager.js.map +2 -2
  15. package/dist/cjs/events_suck.js +1 -1
  16. package/dist/cjs/events_suck.js.map +2 -2
  17. package/dist/cjs/index.d.ts +1 -0
  18. package/dist/cjs/index.js.map +2 -2
  19. package/dist/cjs/timing.js +1 -1
  20. package/dist/cjs/timing.js.map +2 -2
  21. package/dist/esm/BaseEvent.js +351 -170
  22. package/dist/esm/BaseEvent.js.map +3 -3
  23. package/dist/esm/EventBus.js +153 -85
  24. package/dist/esm/EventBus.js.map +2 -2
  25. package/dist/esm/EventHandler.js.map +1 -1
  26. package/dist/esm/EventResult.js +16 -22
  27. package/dist/esm/EventResult.js.map +2 -2
  28. package/dist/esm/LockManager.js +4 -1
  29. package/dist/esm/LockManager.js.map +2 -2
  30. package/dist/esm/events_suck.js +1 -1
  31. package/dist/esm/events_suck.js.map +2 -2
  32. package/dist/esm/index.js.map +2 -2
  33. package/dist/esm/timing.js +1 -1
  34. package/dist/esm/timing.js.map +2 -2
  35. package/dist/types/BaseEvent.d.ts +46 -55
  36. package/dist/types/EventBus.d.ts +8 -1
  37. package/dist/types/EventHandler.d.ts +3 -3
  38. package/dist/types/LockManager.d.ts +1 -0
  39. package/dist/types/index.d.ts +1 -0
  40. package/package.json +4 -3
  41. package/src/BaseEvent.ts +456 -219
  42. package/src/EventBus.ts +186 -99
  43. package/src/EventHandler.ts +3 -3
  44. package/src/EventResult.ts +18 -22
  45. package/src/LockManager.ts +5 -1
  46. package/src/events_suck.ts +1 -1
  47. package/src/index.ts +1 -0
  48. package/src/timing.ts +1 -1
  49. package/dist/cjs/base_event.d.ts +0 -211
  50. package/dist/cjs/bridge_jsonl.d.ts +0 -26
  51. package/dist/cjs/bridge_nats.d.ts +0 -20
  52. package/dist/cjs/bridge_postgres.d.ts +0 -31
  53. package/dist/cjs/bridge_redis.d.ts +0 -34
  54. package/dist/cjs/bridge_sqlite.d.ts +0 -30
  55. package/dist/cjs/event_bus.d.ts +0 -125
  56. package/dist/cjs/event_handler.d.ts +0 -139
  57. package/dist/cjs/event_history.d.ts +0 -45
  58. package/dist/cjs/event_result.d.ts +0 -86
  59. package/dist/cjs/lock_manager.d.ts +0 -70
  60. package/dist/types/base_event.d.ts +0 -211
  61. package/dist/types/bridge_jsonl.d.ts +0 -26
  62. package/dist/types/bridge_nats.d.ts +0 -20
  63. package/dist/types/bridge_postgres.d.ts +0 -31
  64. package/dist/types/bridge_redis.d.ts +0 -34
  65. package/dist/types/bridge_sqlite.d.ts +0 -30
  66. package/dist/types/event_bus.d.ts +0 -125
  67. package/dist/types/event_handler.d.ts +0 -139
  68. package/dist/types/event_history.d.ts +0 -45
  69. package/dist/types/event_result.d.ts +0 -86
  70. package/dist/types/lock_manager.d.ts +0 -70
@@ -157,6 +157,7 @@ class EventBus {
157
157
  find_waiters;
158
158
  // set of EphemeralFindEventHandler objects that are waiting for a matching future event
159
159
  middlewares;
160
+ destroyed;
160
161
  static normalizeMiddlewares(middlewares) {
161
162
  const normalized = [];
162
163
  for (const middleware of middlewares ?? []) {
@@ -178,9 +179,9 @@ class EventBus {
178
179
  this.event_handler_concurrency = options.event_handler_concurrency ?? "serial";
179
180
  this.event_handler_completion = options.event_handler_completion ?? "all";
180
181
  this.event_handler_detect_file_paths = options.event_handler_detect_file_paths ?? true;
181
- this.event_timeout = options.event_timeout === void 0 ? 60 : options.event_timeout;
182
- this.event_handler_slow_timeout = options.event_handler_slow_timeout === void 0 ? 30 : options.event_handler_slow_timeout;
183
- this.event_slow_timeout = options.event_slow_timeout === void 0 ? 300 : options.event_slow_timeout;
182
+ this.event_timeout = options.event_timeout ?? 60;
183
+ this.event_handler_slow_timeout = options.event_handler_slow_timeout ?? 30;
184
+ this.event_slow_timeout = options.event_slow_timeout ?? 300;
184
185
  this.runloop_running = false;
185
186
  this.handlers = /* @__PURE__ */ new Map();
186
187
  this.handlers_by_key = /* @__PURE__ */ new Map();
@@ -193,6 +194,7 @@ class EventBus {
193
194
  this.in_flight_event_ids = /* @__PURE__ */ new Set();
194
195
  this.locks = new import_LockManager.LockManager(this);
195
196
  this.middlewares = EventBus.normalizeMiddlewares(options.middlewares);
197
+ this.destroyed = false;
196
198
  this.all_instances.add(this);
197
199
  this.dispatch = this.dispatch.bind(this);
198
200
  this.emit = this.emit.bind(this);
@@ -279,7 +281,7 @@ class EventBus {
279
281
  }
280
282
  async _runHandlersWithTimeout(event, pending_entries, event_timeout, fn) {
281
283
  try {
282
- if (event_timeout === null || pending_entries.length === 0) {
284
+ if (event_timeout === null || event_timeout <= 0 || pending_entries.length === 0) {
283
285
  await fn();
284
286
  } else {
285
287
  await (0, import_timing._runWithTimeout)(event_timeout, () => this._createEventTimeoutError(event, pending_entries, event_timeout), fn);
@@ -416,10 +418,11 @@ class EventBus {
416
418
  options.event_handler_detect_file_paths = record.event_handler_detect_file_paths;
417
419
  }
418
420
  const bus = new EventBus(name, options);
419
- if (!record.handlers || typeof record.handlers !== "object" || Array.isArray(record.handlers)) {
421
+ const raw_handlers = record.handlers ?? {};
422
+ if (!raw_handlers || typeof raw_handlers !== "object" || Array.isArray(raw_handlers)) {
420
423
  throw new Error("EventBus.fromJSON(data) requires handlers as an id-keyed object");
421
424
  }
422
- for (const [handler_id, payload] of Object.entries(record.handlers)) {
425
+ for (const [handler_id, payload] of Object.entries(raw_handlers)) {
423
426
  if (!payload || typeof payload !== "object") {
424
427
  continue;
425
428
  }
@@ -432,11 +435,12 @@ class EventBus {
432
435
  );
433
436
  bus.handlers.set(parsed.id, parsed);
434
437
  }
435
- if (!record.handlers_by_key || typeof record.handlers_by_key !== "object" || Array.isArray(record.handlers_by_key)) {
438
+ const raw_handlers_by_key = record.handlers_by_key ?? {};
439
+ if (!raw_handlers_by_key || typeof raw_handlers_by_key !== "object" || Array.isArray(raw_handlers_by_key)) {
436
440
  throw new Error("EventBus.fromJSON(data) requires handlers_by_key as an object");
437
441
  }
438
442
  bus.handlers_by_key.clear();
439
- for (const [raw_key, raw_ids] of Object.entries(record.handlers_by_key)) {
443
+ for (const [raw_key, raw_ids] of Object.entries(raw_handlers_by_key)) {
440
444
  if (!Array.isArray(raw_ids)) {
441
445
  continue;
442
446
  }
@@ -509,21 +513,49 @@ class EventBus {
509
513
  removeEventFromHistory(event_id) {
510
514
  return this.event_history.delete(event_id);
511
515
  }
512
- // destroy the event bus and all its state to allow for garbage collection
513
- destroy() {
514
- this.all_instances.discard(this);
515
- this.handlers.clear();
516
- this.handlers_by_key.clear();
517
- for (const event of this.event_history.values()) {
518
- event._gc();
516
+ _raiseIfDestroyed() {
517
+ if (this.destroyed) {
518
+ throw new Error(`${this.toString()} has been destroyed and cannot be used again`);
519
519
  }
520
- this.event_history.clear();
521
- this.pending_event_queue.length = 0;
522
- this.in_flight_event_ids.clear();
523
- this.find_waiters.clear();
524
- this.locks.clear();
520
+ }
521
+ destroy(clear_or_options = true) {
522
+ const clear = typeof clear_or_options === "object" && clear_or_options !== null ? clear_or_options.clear ?? true : clear_or_options;
523
+ if (this.destroyed) {
524
+ if (clear) {
525
+ this.handlers.clear();
526
+ this.handlers_by_key.clear();
527
+ this.event_history.clear();
528
+ this.middlewares.length = 0;
529
+ }
530
+ return Promise.resolve();
531
+ }
532
+ const finish = () => {
533
+ this.destroyed = true;
534
+ this.all_instances.discard(this);
535
+ this.runloop_running = false;
536
+ for (const waiter of Array.from(this.find_waiters)) {
537
+ if (waiter.timeout_id) {
538
+ clearTimeout(waiter.timeout_id);
539
+ }
540
+ this.find_waiters.delete(waiter);
541
+ waiter.resolve(null);
542
+ }
543
+ this.pending_event_queue.length = 0;
544
+ this.in_flight_event_ids.clear();
545
+ this.locks.clear();
546
+ if (!clear) {
547
+ return;
548
+ }
549
+ this.handlers.clear();
550
+ this.handlers_by_key.clear();
551
+ this.event_history.clear();
552
+ this.middlewares.length = 0;
553
+ };
554
+ finish();
555
+ return Promise.resolve();
525
556
  }
526
557
  on(event_pattern, handler, options = {}) {
558
+ this._raiseIfDestroyed();
527
559
  const normalized_key = (0, import_types.normalizeEventPattern)(event_pattern);
528
560
  const handler_name = import_EventHandler.EventHandler.handlerNameFromCallable(handler);
529
561
  const handler_entry = new import_EventHandler.EventHandler({
@@ -548,6 +580,7 @@ class EventBus {
548
580
  return handler_entry;
549
581
  }
550
582
  off(event_pattern, handler) {
583
+ this._raiseIfDestroyed();
551
584
  const normalized_key = (0, import_types.normalizeEventPattern)(event_pattern);
552
585
  if (typeof handler === "object" && handler instanceof import_EventHandler.EventHandler && handler.id !== void 0) {
553
586
  handler = handler.id;
@@ -568,7 +601,12 @@ class EventBus {
568
601
  }
569
602
  }
570
603
  emit(event) {
604
+ this._raiseIfDestroyed();
571
605
  const original_event = event._event_original ?? event;
606
+ const current_result = this.locks._getRawActiveHandlerResultForCurrentAsyncContext();
607
+ if (current_result && current_result.status !== "pending" && current_result.status !== "started" && (current_result.error instanceof import_EventHandler.EventHandlerTimeoutError || current_result.error instanceof import_EventHandler.EventHandlerCancelledError || current_result.error instanceof import_EventHandler.EventHandlerAbortedError)) {
608
+ return original_event;
609
+ }
572
610
  if (!original_event.event_bus) {
573
611
  original_event.event_bus = this;
574
612
  }
@@ -606,7 +644,11 @@ class EventBus {
606
644
  this._resolveFindWaiters(original_event);
607
645
  original_event.event_pending_bus_count += 1;
608
646
  this.pending_event_queue.push(original_event);
609
- this._startRunloop();
647
+ if (this.locks.getLockForEvent(original_event) === null) {
648
+ this._startParallelEventTaskFromQueue(original_event);
649
+ } else {
650
+ this._startRunloop();
651
+ }
610
652
  return this._getEventProxyScopedToThisBus(original_event);
611
653
  }
612
654
  // alias for emit
@@ -628,6 +670,7 @@ class EventBus {
628
670
  return results.length > 0 ? results[0] : null;
629
671
  }
630
672
  async filter(event_pattern, where_or_options = {}, maybe_options = {}) {
673
+ this._raiseIfDestroyed();
631
674
  const where = typeof where_or_options === "function" ? where_or_options : () => true;
632
675
  const options = typeof where_or_options === "function" ? maybe_options : where_or_options;
633
676
  const matches = await this.event_history.filter(event_pattern, where, {
@@ -658,6 +701,7 @@ class EventBus {
658
701
  });
659
702
  }
660
703
  async waitUntilIdle(timeout = null) {
704
+ this._raiseIfDestroyed();
661
705
  return await this.locks.waitForIdle(timeout);
662
706
  }
663
707
  // Weak idle check: only checks if handlers are idle, doesnt check that the queue is empty
@@ -708,6 +752,7 @@ class EventBus {
708
752
  return this.event_history.get(event_id) ?? this.all_instances.findEventById(event_id);
709
753
  }
710
754
  _startRunloop() {
755
+ this._raiseIfDestroyed();
711
756
  if (this.runloop_running) {
712
757
  return;
713
758
  }
@@ -716,6 +761,21 @@ class EventBus {
716
761
  void this._runloop();
717
762
  });
718
763
  }
764
+ _startParallelEventTaskFromQueue(event) {
765
+ if (this.in_flight_event_ids.has(event.event_id)) {
766
+ return;
767
+ }
768
+ const queue_index = this.pending_event_queue.indexOf(event);
769
+ if (queue_index >= 0) {
770
+ this.pending_event_queue.splice(queue_index, 1);
771
+ } else if (event.event_status === "completed") {
772
+ return;
773
+ }
774
+ this.in_flight_event_ids.add(event.event_id);
775
+ this.scheduleMicrotask(() => {
776
+ void this._processEvent(event);
777
+ });
778
+ }
719
779
  // schedule the processing of an event on the event bus by its normal _runloop
720
780
  // optionally using a pre-acquired lock if we're inside handling of a parent event
721
781
  async _processEvent(event, options = {}) {
@@ -729,6 +789,7 @@ class EventBus {
729
789
  event._markStarted();
730
790
  pending_entries = event._createPendingHandlerResults(this);
731
791
  const resolved_event_timeout = event.event_timeout ?? this.event_timeout;
792
+ const resolved_event_slow_timeout = event.event_slow_timeout ?? this.event_slow_timeout;
732
793
  if (this.middlewares.length > 0) {
733
794
  for (const entry of pending_entries) {
734
795
  await this._onEventResultChange(scoped_event, entry.result, "pending");
@@ -740,7 +801,10 @@ class EventBus {
740
801
  event,
741
802
  pending_entries,
742
803
  resolved_event_timeout,
743
- () => (0, import_timing._runWithSlowMonitor)(event._createSlowEventWarningTimer(), () => scoped_event._runHandlers(pending_entries))
804
+ () => (0, import_timing._runWithSlowMonitor)(
805
+ event._createSlowEventWarningTimer(resolved_event_slow_timeout, this.name),
806
+ () => scoped_event._runHandlers(pending_entries)
807
+ )
744
808
  ),
745
809
  options
746
810
  );
@@ -753,7 +817,7 @@ class EventBus {
753
817
  this.locks._notifyIdleListeners();
754
818
  }
755
819
  }
756
- // Called when a handler does `await child.done()` — processes the child event
820
+ // Called when a handler does `await child.now()` — processes the child event
757
821
  // immediately ("queue-jump") instead of waiting for the _runloop to pick it up.
758
822
  //
759
823
  // Yield-and-reacquire: if the calling handler holds a handler concurrency lock,
@@ -766,9 +830,9 @@ class EventBus {
766
830
  const currently_active_event_result = proxy_result ?? this.locks._getActiveHandlerResultForCurrentAsyncContext();
767
831
  if (!currently_active_event_result) {
768
832
  const queue_index = this.pending_event_queue.indexOf(original_event);
769
- const can_process_now = queue_index === 0 && !this.locks._isPaused() && !this.in_flight_event_ids.has(original_event.event_id) && !this._hasProcessedEvent(original_event);
770
- if (can_process_now) {
771
- const event_lock = this.locks.getLockForEvent(original_event);
833
+ const event_lock = this.locks.getLockForEvent(original_event);
834
+ const can_process_queue_head_normally = queue_index === 0 && !this.locks._isPaused() && !this.in_flight_event_ids.has(original_event.event_id) && !this._hasProcessedEvent(original_event) && (event_lock === null || event_lock.in_use === 0);
835
+ if (can_process_queue_head_normally) {
772
836
  let pre_acquired_lock = null;
773
837
  if (event_lock) {
774
838
  await event_lock.acquire();
@@ -776,8 +840,7 @@ class EventBus {
776
840
  }
777
841
  const queue_head = this.pending_event_queue[0];
778
842
  const queue_head_original = queue_head?._event_original ?? queue_head;
779
- const still_can_process_now = queue_head_original === original_event && !this.locks._isPaused() && !this.in_flight_event_ids.has(original_event.event_id) && !this._hasProcessedEvent(original_event);
780
- if (still_can_process_now) {
843
+ if (queue_head_original === original_event && !this.locks._isPaused() && !this.in_flight_event_ids.has(original_event.event_id) && !this._hasProcessedEvent(original_event)) {
781
844
  this.pending_event_queue.shift();
782
845
  this.in_flight_event_ids.add(original_event.event_id);
783
846
  await this._processEvent(original_event, {
@@ -785,15 +848,13 @@ class EventBus {
785
848
  pre_acquired_lock
786
849
  });
787
850
  if (original_event.event_status !== "completed") {
788
- await original_event.eventCompleted();
851
+ await this._processEventImmediatelyAcrossBuses(original_event);
789
852
  }
790
853
  return event;
791
854
  }
792
- if (pre_acquired_lock) {
793
- pre_acquired_lock.release();
794
- }
855
+ pre_acquired_lock?.release();
795
856
  }
796
- await original_event.eventCompleted();
857
+ await this._processEventImmediatelyAcrossBuses(original_event);
797
858
  return event;
798
859
  }
799
860
  const active_parent = currently_active_event_result.event._event_original ?? currently_active_event_result.event;
@@ -817,65 +878,68 @@ class EventBus {
817
878
  // Processes a queue-jumped event across all buses that have it emitted.
818
879
  // Called from _processEventImmediately after the parent handler's lock has been yielded.
819
880
  async _processEventImmediatelyAcrossBuses(event) {
820
- const ordered = [];
821
- const seen = /* @__PURE__ */ new Set();
822
- const event_path = Array.isArray(event.event_path) ? event.event_path : [];
823
- for (const label of event_path) {
824
- for (const bus of this.all_instances) {
825
- if (bus.label !== label) {
826
- continue;
827
- }
828
- if (!bus.event_history.has(event.event_id)) {
829
- continue;
830
- }
831
- if (bus._hasProcessedEvent(event)) {
832
- continue;
833
- }
834
- if (!seen.has(bus)) {
835
- ordered.push(bus);
836
- seen.add(bus);
837
- }
838
- }
839
- }
840
- if (!seen.has(this) && this.event_history.has(event.event_id)) {
841
- ordered.push(this);
842
- }
843
- if (ordered.length === 0) {
844
- await event.eventCompleted();
845
- return;
846
- }
847
881
  const initiating_event_lock = this.locks.getLockForEvent(event);
848
- const pause_releases = [];
849
- try {
850
- for (const bus of ordered) {
851
- if (bus !== this) {
852
- pause_releases.push(bus.locks._requestRunloopPause());
882
+ for (; ; ) {
883
+ const ordered = [];
884
+ const seen = /* @__PURE__ */ new Set();
885
+ const event_path = Array.isArray(event.event_path) ? event.event_path : [];
886
+ for (const label of event_path) {
887
+ for (const bus of this.all_instances) {
888
+ if (bus.label !== label) {
889
+ continue;
890
+ }
891
+ if (!bus.event_history.has(event.event_id)) {
892
+ continue;
893
+ }
894
+ if (bus._hasProcessedEvent(event)) {
895
+ continue;
896
+ }
897
+ if (!seen.has(bus)) {
898
+ ordered.push(bus);
899
+ seen.add(bus);
900
+ }
853
901
  }
854
902
  }
855
- for (const bus of ordered) {
856
- const index = bus.pending_event_queue.indexOf(event);
857
- if (index >= 0) {
858
- bus.pending_event_queue.splice(index, 1);
903
+ if (!seen.has(this) && this.event_history.has(event.event_id) && !this._hasProcessedEvent(event)) {
904
+ ordered.push(this);
905
+ }
906
+ const pause_releases = [];
907
+ let processed_bus = false;
908
+ try {
909
+ for (const bus of ordered) {
910
+ if (bus !== this) {
911
+ pause_releases.push(bus.locks._requestRunloopPause());
912
+ }
859
913
  }
860
- if (bus._hasProcessedEvent(event)) {
861
- continue;
914
+ for (const bus of ordered) {
915
+ const index = bus.pending_event_queue.indexOf(event);
916
+ if (index >= 0) {
917
+ bus.pending_event_queue.splice(index, 1);
918
+ }
919
+ if (bus._hasProcessedEvent(event)) {
920
+ continue;
921
+ }
922
+ if (bus.in_flight_event_ids.has(event.event_id)) {
923
+ continue;
924
+ }
925
+ bus.in_flight_event_ids.add(event.event_id);
926
+ processed_bus = true;
927
+ const bus_event_lock = bus.locks.getLockForEvent(event);
928
+ const should_bypass_event_lock = bus === this || initiating_event_lock !== null && bus_event_lock === initiating_event_lock;
929
+ await bus._processEvent(event, {
930
+ bypass_event_locks: should_bypass_event_lock
931
+ });
862
932
  }
863
- if (bus.in_flight_event_ids.has(event.event_id)) {
864
- continue;
933
+ } finally {
934
+ for (const release of pause_releases) {
935
+ release();
865
936
  }
866
- bus.in_flight_event_ids.add(event.event_id);
867
- const bus_event_lock = bus.locks.getLockForEvent(event);
868
- const should_bypass_event_lock = bus === this || initiating_event_lock !== null && bus_event_lock === initiating_event_lock;
869
- await bus._processEvent(event, {
870
- bypass_event_locks: should_bypass_event_lock
871
- });
872
937
  }
873
- if (event.event_status !== "completed") {
874
- await event.eventCompleted();
938
+ if (event.event_status === "completed") {
939
+ return;
875
940
  }
876
- } finally {
877
- for (const release of pause_releases) {
878
- release();
941
+ if (!processed_bus) {
942
+ await new Promise((resolve) => setTimeout(resolve, 1));
879
943
  }
880
944
  }
881
945
  }
@@ -960,7 +1024,11 @@ class EventBus {
960
1024
  if (prop === "dispatch" || prop === "emit") {
961
1025
  const emit_child_event = (child_event) => {
962
1026
  const original_child = child_event._event_original ?? child_event;
963
- if (handler_result) {
1027
+ const handler_result_is_terminal = handler_result && handler_result.status !== "pending" && handler_result.status !== "started";
1028
+ if (handler_result_is_terminal && (handler_result.error instanceof import_EventHandler.EventHandlerTimeoutError || handler_result.error instanceof import_EventHandler.EventHandlerCancelledError || handler_result.error instanceof import_EventHandler.EventHandlerAbortedError)) {
1029
+ return original_child;
1030
+ }
1031
+ if (handler_result && !handler_result_is_terminal) {
964
1032
  handler_result._linkEmittedChildEvent(original_child);
965
1033
  } else if (!original_child.event_parent_id && original_child.event_id !== parent_event_id) {
966
1034
  original_child.event_parent_id = parent_event_id;