event-emission 0.2.0 → 0.3.0

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 (43) hide show
  1. package/README.md +158 -25
  2. package/dist/event-emission.d.ts +63 -14
  3. package/dist/event-emission.d.ts.map +1 -1
  4. package/dist/factory.d.ts +1 -1
  5. package/dist/factory.d.ts.map +1 -1
  6. package/dist/index.cjs +614 -291
  7. package/dist/index.cjs.map +8 -9
  8. package/dist/index.d.ts +1 -7
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +589 -284
  11. package/dist/index.js.map +8 -9
  12. package/dist/interoperability.cjs +1719 -0
  13. package/dist/interoperability.cjs.map +15 -0
  14. package/dist/{interop.d.ts → interoperability.d.ts} +2 -1
  15. package/dist/interoperability.d.ts.map +1 -0
  16. package/dist/interoperability.js +1669 -0
  17. package/dist/interoperability.js.map +15 -0
  18. package/dist/observable.cjs +286 -0
  19. package/dist/observable.cjs.map +11 -0
  20. package/dist/observable.js +253 -0
  21. package/dist/observable.js.map +11 -0
  22. package/dist/observe.cjs +344 -0
  23. package/dist/observe.cjs.map +10 -0
  24. package/dist/observe.d.ts +6 -1
  25. package/dist/observe.d.ts.map +1 -1
  26. package/dist/observe.js +313 -0
  27. package/dist/observe.js.map +10 -0
  28. package/dist/symbols.d.ts +1 -1
  29. package/dist/types.cjs +35 -0
  30. package/dist/types.cjs.map +9 -0
  31. package/dist/types.d.ts +73 -25
  32. package/dist/types.d.ts.map +1 -1
  33. package/dist/types.js +3 -0
  34. package/dist/types.js.map +9 -0
  35. package/package.json +25 -1
  36. package/src/event-emission.ts +140 -21
  37. package/src/factory.ts +686 -230
  38. package/src/index.ts +4 -33
  39. package/src/{interop.ts → interoperability.ts} +34 -6
  40. package/src/observe.ts +54 -17
  41. package/src/symbols.ts +1 -1
  42. package/src/types.ts +115 -33
  43. package/dist/interop.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -4,13 +4,7 @@ var SymbolObservable = typeof Symbol === "function" && Symbol.observable || Symb
4
4
  if (typeof Symbol === "function") {
5
5
  Symbol.observable = SymbolObservable;
6
6
  }
7
- // src/errors.ts
8
- class BufferOverflowError extends Error {
9
- constructor(eventType, bufferSize) {
10
- super(`Buffer overflow for event type "${eventType}" (max: ${bufferSize})`);
11
- this.name = "BufferOverflowError";
12
- }
13
- }
7
+
14
8
  // src/observable.ts
15
9
  function getMethod(obj, key) {
16
10
  if (obj === null || obj === undefined)
@@ -277,17 +271,13 @@ function isArrayMutator(prop) {
277
271
  return typeof prop === "string" && ARRAY_MUTATORS.has(prop);
278
272
  }
279
273
  function cloneAlongPath(obj, path) {
280
- if (obj === null || typeof obj !== "object") {
281
- return obj;
282
- }
283
- if (!path) {
284
- return Array.isArray(obj) ? [...obj] : { ...obj };
274
+ const isArray = Array.isArray(obj);
275
+ const rootClone = isArray ? [...obj] : { ...obj };
276
+ if (!path || isArray) {
277
+ return rootClone;
285
278
  }
286
279
  const parts = path.split(".");
287
- if (Array.isArray(obj)) {
288
- return [...obj];
289
- }
290
- const result = { ...obj };
280
+ const result = rootClone;
291
281
  let current = result;
292
282
  for (let i = 0;i < parts.length; i++) {
293
283
  const key = parts[i];
@@ -303,13 +293,19 @@ function cloneAlongPath(obj, path) {
303
293
  }
304
294
  return result;
305
295
  }
306
- function cloneForComparison(obj, strategy, changedPath) {
296
+ function cloneForComparison(obj, strategy, changedPath, deepClone) {
307
297
  if (obj === null || typeof obj !== "object")
308
298
  return obj;
309
299
  switch (strategy) {
310
300
  case "shallow":
311
301
  return Array.isArray(obj) ? [...obj] : { ...obj };
312
302
  case "deep":
303
+ if (deepClone) {
304
+ return deepClone(obj);
305
+ }
306
+ if (typeof structuredClone !== "function") {
307
+ throw new Error("structuredClone is not available in this runtime; provide observe.deepClone, or use cloneStrategy 'path' or 'shallow'.");
308
+ }
313
309
  return structuredClone(obj);
314
310
  case "path":
315
311
  return cloneAlongPath(obj, changedPath);
@@ -357,7 +353,7 @@ function getContextRegistry(target) {
357
353
  function createArrayMethodInterceptor(array, method, path, context) {
358
354
  const original = array[method];
359
355
  return function(...args) {
360
- const previousState = cloneForComparison(context.originalRoot, context.options.cloneStrategy, path);
356
+ const previousState = cloneForComparison(context.originalRoot, context.options.cloneStrategy, path, context.options.deepClone);
361
357
  const previousItems = [...array];
362
358
  const result = original.apply(this, args);
363
359
  const { added, removed } = computeArrayDiff(method, previousItems, array, args);
@@ -429,7 +425,7 @@ function createObservableProxyInternal(target, path, context) {
429
425
  return true;
430
426
  }
431
427
  const propPath = path ? `${path}.${prop}` : prop;
432
- const previousState = cloneForComparison(context.originalRoot, context.options.cloneStrategy, propPath);
428
+ const previousState = cloneForComparison(context.originalRoot, context.options.cloneStrategy, propPath, context.options.deepClone);
433
429
  const success = Reflect.set(obj, prop, value, receiver);
434
430
  if (success) {
435
431
  context.eventTarget.dispatchEvent({
@@ -455,7 +451,7 @@ function createObservableProxyInternal(target, path, context) {
455
451
  return Reflect.deleteProperty(obj, prop);
456
452
  }
457
453
  const propPath = path ? `${path}.${String(prop)}` : String(prop);
458
- const previousState = cloneForComparison(context.originalRoot, context.options.cloneStrategy, propPath);
454
+ const previousState = cloneForComparison(context.originalRoot, context.options.cloneStrategy, propPath, context.options.deepClone);
459
455
  const success = Reflect.deleteProperty(obj, prop);
460
456
  if (success) {
461
457
  context.eventTarget.dispatchEvent({
@@ -488,6 +484,8 @@ function isEventTarget(obj) {
488
484
  }
489
485
  function setupEventForwarding(source, target) {
490
486
  const handlers = new Map;
487
+ const sourceAddEventListener = source.addEventListener.bind(source);
488
+ const sourceRemoveEventListener = source.removeEventListener.bind(source);
491
489
  const forwardHandler = (type) => (event) => {
492
490
  const detail = event.detail ?? event;
493
491
  target.dispatchEvent({
@@ -500,7 +498,7 @@ function setupEventForwarding(source, target) {
500
498
  if (!handlers.has(type) && type !== "update" && !type.startsWith("update:")) {
501
499
  const handler = forwardHandler(type);
502
500
  handlers.set(type, handler);
503
- source.addEventListener(type, handler);
501
+ sourceAddEventListener(type, handler);
504
502
  }
505
503
  return originalAddEventListener(type, listener, options);
506
504
  };
@@ -508,7 +506,7 @@ function setupEventForwarding(source, target) {
508
506
  return () => {
509
507
  target.addEventListener = originalAddEventListener;
510
508
  for (const [type, handler] of handlers) {
511
- source.removeEventListener(type, handler);
509
+ sourceRemoveEventListener(type, handler);
512
510
  }
513
511
  handlers.clear();
514
512
  };
@@ -525,7 +523,8 @@ function getOriginal(proxy) {
525
523
  function createObservableProxy(target, eventTarget, options) {
526
524
  const resolvedOptions = {
527
525
  deep: options?.deep ?? true,
528
- cloneStrategy: options?.cloneStrategy ?? "path"
526
+ cloneStrategy: options?.cloneStrategy ?? "path",
527
+ deepClone: options?.deepClone
529
528
  };
530
529
  const context = {
531
530
  eventTarget,
@@ -534,21 +533,36 @@ function createObservableProxy(target, eventTarget, options) {
534
533
  };
535
534
  const proxy = createObservableProxyInternal(target, "", context);
536
535
  if (isEventTarget(target)) {
537
- setupEventForwarding(target, eventTarget);
536
+ const cleanupForwarding = setupEventForwarding(target, eventTarget);
537
+ const maybeComplete = eventTarget.complete;
538
+ if (typeof maybeComplete === "function") {
539
+ const originalComplete = maybeComplete.bind(eventTarget);
540
+ let cleaned = false;
541
+ eventTarget.complete = () => {
542
+ if (!cleaned) {
543
+ cleaned = true;
544
+ cleanupForwarding();
545
+ }
546
+ return originalComplete();
547
+ };
548
+ }
538
549
  }
539
550
  return proxy;
540
551
  }
541
-
552
+ // src/errors.ts
553
+ class BufferOverflowError extends Error {
554
+ constructor(eventType, bufferSize) {
555
+ super(`Buffer overflow for event type "${eventType}" (max: ${bufferSize})`);
556
+ this.name = "BufferOverflowError";
557
+ }
558
+ }
542
559
  // src/factory.ts
543
560
  function matchesWildcard(eventType, pattern) {
544
561
  if (pattern === "*")
545
562
  return true;
546
- if (pattern.endsWith(":*")) {
547
- const namespace = pattern.slice(0, -2);
548
- return eventType.startsWith(namespace + ":");
549
- }
550
- return false;
563
+ return pattern.endsWith(":*") && eventType.startsWith(pattern.slice(0, -2) + ":");
551
564
  }
565
+ var EVENT_STATE = Symbol("event-emission:event-state");
552
566
  function createEventTarget(targetOrOpts, opts) {
553
567
  if (opts?.observe === true && targetOrOpts && typeof targetOrOpts === "object") {
554
568
  const target = targetOrOpts;
@@ -557,7 +571,8 @@ function createEventTarget(targetOrOpts, opts) {
557
571
  });
558
572
  const proxy = createObservableProxy(target, eventTarget, {
559
573
  deep: opts.deep,
560
- cloneStrategy: opts.cloneStrategy
574
+ cloneStrategy: opts.cloneStrategy,
575
+ deepClone: opts.deepClone
561
576
  });
562
577
  const methodNames = [
563
578
  "addEventListener",
@@ -573,7 +588,17 @@ function createEventTarget(targetOrOpts, opts) {
573
588
  "complete",
574
589
  "subscribe",
575
590
  "toObservable",
576
- "events"
591
+ "events",
592
+ "emit",
593
+ "off",
594
+ "addListener",
595
+ "removeListener",
596
+ "prependListener",
597
+ "prependOnceListener",
598
+ "listeners",
599
+ "rawListeners",
600
+ "listenerCount",
601
+ "eventNames"
577
602
  ];
578
603
  for (const name of methodNames) {
579
604
  Object.defineProperty(proxy, name, {
@@ -597,38 +622,202 @@ function createEventTargetInternal(opts) {
597
622
  const wildcardListeners = new Set;
598
623
  let isCompleted = false;
599
624
  const completionCallbacks = new Set;
600
- const augmentEvent = (type, detail) => {
601
- const baseEvent = {
602
- bubbles: false,
603
- cancelable: false,
604
- composed: false,
605
- defaultPrevented: false,
606
- eventPhase: 2,
607
- isTrusted: false,
608
- timeStamp: Date.now(),
609
- NONE: 0,
610
- CAPTURING_PHASE: 1,
611
- AT_TARGET: 2,
612
- BUBBLING_PHASE: 3,
613
- composedPath: () => [target],
614
- stopImmediatePropagation: () => {},
615
- stopPropagation: () => {}
625
+ const now = () => typeof globalThis.performance?.now === "function" ? globalThis.performance.now() : Date.now();
626
+ const initializeEventState = (state, type, bubbles, cancelable) => {
627
+ state.initializedFlag = true;
628
+ state.stopPropagationFlag = false;
629
+ state.stopImmediatePropagationFlag = false;
630
+ state.canceledFlag = false;
631
+ state.isTrusted = false;
632
+ state.target = null;
633
+ state.currentTarget = null;
634
+ state.eventPhase = 0;
635
+ state.type = type;
636
+ state.bubbles = bubbles;
637
+ state.cancelable = cancelable;
638
+ };
639
+ const setCanceledFlag = (state) => {
640
+ if (state.cancelable && !state.inPassiveListenerFlag) {
641
+ state.canceledFlag = true;
642
+ }
643
+ };
644
+ const createEvent = (type, detail, init) => {
645
+ const state = {
646
+ dispatchFlag: false,
647
+ initializedFlag: true,
648
+ stopPropagationFlag: false,
649
+ stopImmediatePropagationFlag: false,
650
+ canceledFlag: false,
651
+ inPassiveListenerFlag: false,
652
+ composedFlag: Boolean(init?.composed),
653
+ eventPhase: init?.eventPhase ?? 0,
654
+ currentTarget: init?.currentTarget ?? init?.target ?? null,
655
+ target: init?.target ?? null,
656
+ timeStamp: init?.timeStamp ?? now(),
657
+ path: [],
658
+ type,
659
+ bubbles: Boolean(init?.bubbles),
660
+ cancelable: Boolean(init?.cancelable),
661
+ isTrusted: false
616
662
  };
617
- return Object.defineProperties({ ...baseEvent, type, detail }, {
618
- target: { value: target, enumerable: true, configurable: true },
619
- currentTarget: { value: target, enumerable: true, configurable: true },
663
+ const event = { detail };
664
+ Object.defineProperties(event, {
665
+ type: {
666
+ get: () => state.type,
667
+ enumerable: true,
668
+ configurable: true
669
+ },
670
+ bubbles: {
671
+ get: () => state.bubbles,
672
+ enumerable: true,
673
+ configurable: true
674
+ },
675
+ cancelable: {
676
+ get: () => state.cancelable,
677
+ enumerable: true,
678
+ configurable: true
679
+ },
680
+ cancelBubble: {
681
+ get: () => state.stopPropagationFlag,
682
+ set: (value) => {
683
+ if (value)
684
+ state.stopPropagationFlag = true;
685
+ },
686
+ enumerable: true,
687
+ configurable: true
688
+ },
689
+ composed: {
690
+ get: () => state.composedFlag,
691
+ enumerable: true,
692
+ configurable: true
693
+ },
694
+ currentTarget: {
695
+ get: () => state.currentTarget,
696
+ enumerable: true,
697
+ configurable: true
698
+ },
699
+ defaultPrevented: {
700
+ get: () => state.canceledFlag,
701
+ enumerable: true,
702
+ configurable: true
703
+ },
704
+ eventPhase: {
705
+ get: () => state.eventPhase,
706
+ enumerable: true,
707
+ configurable: true
708
+ },
709
+ isTrusted: {
710
+ get: () => state.isTrusted,
711
+ enumerable: true,
712
+ configurable: true
713
+ },
714
+ returnValue: {
715
+ get: () => !state.canceledFlag,
716
+ set: (value) => {
717
+ if (value === false)
718
+ setCanceledFlag(state);
719
+ },
720
+ enumerable: true,
721
+ configurable: true
722
+ },
723
+ srcElement: {
724
+ get: () => state.target,
725
+ enumerable: true,
726
+ configurable: true
727
+ },
728
+ target: {
729
+ get: () => state.target,
730
+ enumerable: true,
731
+ configurable: true
732
+ },
733
+ timeStamp: {
734
+ get: () => state.timeStamp,
735
+ enumerable: true,
736
+ configurable: true
737
+ },
738
+ composedPath: {
739
+ value: () => state.path.map((entry) => entry.invocationTarget),
740
+ enumerable: true,
741
+ configurable: true
742
+ },
743
+ initEvent: {
744
+ value: (newType, bubbles = false, cancelable = false) => {
745
+ if (state.dispatchFlag)
746
+ return;
747
+ initializeEventState(state, newType, Boolean(bubbles), Boolean(cancelable));
748
+ },
749
+ enumerable: true,
750
+ configurable: true
751
+ },
620
752
  preventDefault: {
621
- value: function() {
622
- Object.defineProperty(this, "defaultPrevented", {
623
- value: true,
624
- enumerable: true,
625
- configurable: true
626
- });
753
+ value: () => setCanceledFlag(state),
754
+ enumerable: true,
755
+ configurable: true
756
+ },
757
+ stopImmediatePropagation: {
758
+ value: () => {
759
+ state.stopPropagationFlag = true;
760
+ state.stopImmediatePropagationFlag = true;
761
+ },
762
+ enumerable: true,
763
+ configurable: true
764
+ },
765
+ stopPropagation: {
766
+ value: () => {
767
+ state.stopPropagationFlag = true;
627
768
  },
628
769
  enumerable: true,
629
770
  configurable: true
771
+ },
772
+ NONE: { value: 0, enumerable: true, configurable: true },
773
+ CAPTURING_PHASE: { value: 1, enumerable: true, configurable: true },
774
+ AT_TARGET: { value: 2, enumerable: true, configurable: true },
775
+ BUBBLING_PHASE: { value: 3, enumerable: true, configurable: true },
776
+ [EVENT_STATE]: {
777
+ value: state,
778
+ enumerable: false,
779
+ configurable: false
630
780
  }
631
781
  });
782
+ return event;
783
+ };
784
+ const getEventState = (event) => event[EVENT_STATE];
785
+ const normalizeAddListenerOptions = (options) => {
786
+ if (typeof options === "boolean") {
787
+ return {
788
+ capture: options,
789
+ passive: false,
790
+ once: false,
791
+ signal: null
792
+ };
793
+ }
794
+ return {
795
+ capture: Boolean(options?.capture),
796
+ passive: Boolean(options?.passive),
797
+ once: Boolean(options?.once),
798
+ signal: options?.signal ?? null
799
+ };
800
+ };
801
+ const normalizeCaptureOption = (options) => {
802
+ if (typeof options === "boolean")
803
+ return options;
804
+ return Boolean(options?.capture);
805
+ };
806
+ const removeListenerRecord = (type, record) => {
807
+ if (record.removed)
808
+ return;
809
+ record.removed = true;
810
+ const list = listeners.get(type);
811
+ if (list) {
812
+ const idx = list.indexOf(record);
813
+ if (idx >= 0)
814
+ list.splice(idx, 1);
815
+ if (list.length === 0)
816
+ listeners.delete(type);
817
+ }
818
+ if (record.signal && record.abortHandler) {
819
+ record.signal.removeEventListener("abort", record.abortHandler);
820
+ }
632
821
  };
633
822
  const handleListenerError = (eventType, error2) => {
634
823
  if (eventType === "error")
@@ -638,28 +827,27 @@ function createEventTargetInternal(opts) {
638
827
  return;
639
828
  }
640
829
  const errorListeners = listeners.get("error");
641
- if (errorListeners && errorListeners.size > 0) {
642
- const errorEvent = augmentEvent("error", error2);
643
- for (const rec of Array.from(errorListeners)) {
644
- try {
645
- const fn = rec.fn;
646
- fn(errorEvent);
647
- } catch {}
648
- if (rec.once)
649
- errorListeners.delete(rec);
650
- }
830
+ if (errorListeners && errorListeners.length > 0) {
831
+ dispatchEvent({ type: "error", detail: error2 });
651
832
  } else {
652
833
  throw error2;
653
834
  }
654
835
  };
655
- const notifyWildcardListeners = (eventType, detail) => {
836
+ const notifyWildcardListeners = (eventType, event) => {
656
837
  if (wildcardListeners.size === 0)
657
838
  return;
658
839
  for (const rec of Array.from(wildcardListeners)) {
659
840
  if (!matchesWildcard(eventType, rec.pattern))
660
841
  continue;
661
- const baseAugmented = augmentEvent(rec.pattern, detail);
662
- const wildcardEvent = Object.defineProperties(baseAugmented, {
842
+ const baseEvent = createEvent(rec.pattern, event.detail, {
843
+ target,
844
+ currentTarget: target,
845
+ eventPhase: 2,
846
+ bubbles: event.bubbles,
847
+ cancelable: event.cancelable,
848
+ composed: event.composed
849
+ });
850
+ const wildcardEvent = Object.defineProperties(baseEvent, {
663
851
  originalType: { value: eventType, enumerable: true, configurable: true }
664
852
  });
665
853
  try {
@@ -682,44 +870,66 @@ function createEventTargetInternal(opts) {
682
870
  if (rec.once)
683
871
  wildcardListeners.delete(rec);
684
872
  }
873
+ const state = getEventState(wildcardEvent);
874
+ if (state?.stopImmediatePropagationFlag || state?.stopPropagationFlag) {
875
+ break;
876
+ }
685
877
  }
686
878
  };
687
- const addEventListener = (type, listener, options) => {
688
- if (isCompleted) {
879
+ const addListenerInternal = (type, listener, options, position) => {
880
+ if (isCompleted || !listener) {
689
881
  return () => {};
690
882
  }
691
- const opts2 = options ?? {};
692
- const record = {
693
- fn: listener,
694
- once: opts2.once,
695
- signal: opts2.signal
696
- };
697
- let set = listeners.get(type);
698
- if (!set) {
699
- set = new Set;
700
- listeners.set(type, set);
883
+ const { capture, passive, once, signal } = normalizeAddListenerOptions(options);
884
+ let list = listeners.get(type);
885
+ if (!list) {
886
+ list = [];
887
+ listeners.set(type, list);
701
888
  }
702
- set.add(record);
703
- const unsubscribe2 = () => {
704
- const setNow = listeners.get(type);
705
- setNow?.delete(record);
706
- if (record.signal && record.abortHandler) {
707
- record.signal.removeEventListener("abort", record.abortHandler);
889
+ for (const existing of list) {
890
+ if (existing.original === listener && existing.capture === capture) {
891
+ return () => removeEventListener(type, listener, options);
708
892
  }
893
+ }
894
+ const original = listener;
895
+ const callback = typeof listener === "function" ? listener : (event) => listener.handleEvent(event);
896
+ const record = {
897
+ type,
898
+ original,
899
+ callback,
900
+ capture,
901
+ passive,
902
+ once,
903
+ signal,
904
+ removed: false
709
905
  };
710
- if (opts2.signal) {
711
- const onAbort = () => unsubscribe2();
906
+ if (position === "prepend") {
907
+ list.unshift(record);
908
+ } else {
909
+ list.push(record);
910
+ }
911
+ const unsubscribe2 = () => removeListenerRecord(type, record);
912
+ if (signal) {
913
+ const onAbort = () => removeListenerRecord(type, record);
712
914
  record.abortHandler = onAbort;
713
- opts2.signal.addEventListener("abort", onAbort, { once: true });
714
- if (opts2.signal.aborted)
915
+ signal.addEventListener("abort", onAbort, { once: true });
916
+ if (signal.aborted)
715
917
  onAbort();
716
918
  }
717
919
  return unsubscribe2;
718
920
  };
921
+ const addEventListener = (type, listener, options) => {
922
+ return addListenerInternal(type, listener, options, "append");
923
+ };
719
924
  const addWildcardListener = (pattern, listener, options) => {
720
925
  if (isCompleted)
721
926
  return () => {};
722
927
  const opts2 = options ?? {};
928
+ for (const existing of wildcardListeners) {
929
+ if (existing.pattern === pattern && existing.fn === listener) {
930
+ return () => removeWildcardListener(pattern, listener);
931
+ }
932
+ }
723
933
  const record = {
724
934
  fn: listener,
725
935
  pattern,
@@ -743,31 +953,39 @@ function createEventTargetInternal(opts) {
743
953
  return unsubscribe2;
744
954
  };
745
955
  const removeWildcardListener = (pattern, listener) => {
746
- for (const record of wildcardListeners) {
956
+ for (const record of Array.from(wildcardListeners)) {
747
957
  if (record.pattern === pattern && record.fn === listener) {
748
958
  wildcardListeners.delete(record);
749
959
  if (record.signal && record.abortHandler) {
750
960
  record.signal.removeEventListener("abort", record.abortHandler);
751
961
  }
752
- break;
753
962
  }
754
963
  }
755
964
  };
756
- const dispatchEvent = (event) => {
757
- if (isCompleted)
758
- return false;
759
- const augmentedEvent = augmentEvent(event.type, event.detail);
760
- notifyWildcardListeners(event.type, event.detail);
761
- const set = listeners.get(event.type);
762
- if (!set || set.size === 0)
763
- return true;
764
- for (const rec of Array.from(set)) {
965
+ const invokeListeners = (eventType, event, phase, listenersSnapshot) => {
966
+ const state = getEventState(event);
967
+ if (!state || state.stopPropagationFlag)
968
+ return;
969
+ state.currentTarget = target;
970
+ state.target = target;
971
+ state.eventPhase = event.AT_TARGET;
972
+ for (const rec of listenersSnapshot) {
973
+ if (rec.removed)
974
+ continue;
975
+ if (phase === "capturing" && !rec.capture)
976
+ continue;
977
+ if (phase === "bubbling" && rec.capture)
978
+ continue;
979
+ if (rec.once)
980
+ removeListenerRecord(rec.type, rec);
981
+ if (rec.passive)
982
+ state.inPassiveListenerFlag = true;
765
983
  try {
766
- const res = rec.fn(augmentedEvent);
984
+ const res = rec.callback.call(state.currentTarget, event);
767
985
  if (res && typeof res.then === "function") {
768
986
  res.catch((error2) => {
769
987
  try {
770
- handleListenerError(event.type, error2);
988
+ handleListenerError(eventType, error2);
771
989
  } catch (rethrown) {
772
990
  queueMicrotask(() => {
773
991
  throw rethrown;
@@ -776,36 +994,94 @@ function createEventTargetInternal(opts) {
776
994
  });
777
995
  }
778
996
  } catch (error2) {
779
- handleListenerError(event.type, error2);
997
+ handleListenerError(eventType, error2);
780
998
  } finally {
781
- if (rec.once)
782
- set.delete(rec);
999
+ if (rec.passive)
1000
+ state.inPassiveListenerFlag = false;
783
1001
  }
1002
+ if (state.stopImmediatePropagationFlag)
1003
+ break;
784
1004
  }
785
- return true;
786
1005
  };
787
- const removeEventListener = (type, listener) => {
788
- const set = listeners.get(type);
789
- if (!set)
790
- return;
791
- for (const record of set) {
792
- if (record.fn === listener) {
793
- set.delete(record);
794
- if (record.signal && record.abortHandler) {
795
- record.signal.removeEventListener("abort", record.abortHandler);
1006
+ const dispatchEvent = (eventInput) => {
1007
+ if (isCompleted)
1008
+ return false;
1009
+ let event;
1010
+ let state;
1011
+ if (eventInput && typeof eventInput === "object") {
1012
+ state = getEventState(eventInput);
1013
+ if (state) {
1014
+ event = eventInput;
1015
+ } else {
1016
+ const input = eventInput;
1017
+ if (typeof input.type !== "string") {
1018
+ throw new TypeError("Event type must be a string");
796
1019
  }
797
- break;
1020
+ event = createEvent(input.type, input.detail, {
1021
+ bubbles: input.bubbles,
1022
+ cancelable: input.cancelable,
1023
+ composed: input.composed,
1024
+ timeStamp: input.timeStamp
1025
+ });
1026
+ state = getEventState(event);
1027
+ }
1028
+ } else {
1029
+ throw new TypeError("dispatchEvent expects an event object");
1030
+ }
1031
+ const dispatchState = state ?? getEventState(event);
1032
+ if (dispatchState.dispatchFlag || !dispatchState.initializedFlag) {
1033
+ const message = "Failed to execute dispatchEvent: event is already being dispatched";
1034
+ if (typeof globalThis.DOMException === "function") {
1035
+ throw new globalThis.DOMException(message, "InvalidStateError");
1036
+ }
1037
+ const err = new Error(message);
1038
+ err.name = "InvalidStateError";
1039
+ throw err;
1040
+ }
1041
+ dispatchState.isTrusted = false;
1042
+ dispatchState.dispatchFlag = true;
1043
+ dispatchState.path = [
1044
+ {
1045
+ invocationTarget: target,
1046
+ invocationTargetInShadowTree: false,
1047
+ shadowAdjustedTarget: target,
1048
+ relatedTarget: null,
1049
+ touchTargets: [],
1050
+ rootOfClosedTree: false,
1051
+ slotInClosedTree: false
1052
+ }
1053
+ ];
1054
+ notifyWildcardListeners(dispatchState.type, event);
1055
+ const list = listeners.get(dispatchState.type);
1056
+ const snapshot = list ? list.slice() : [];
1057
+ invokeListeners(dispatchState.type, event, "capturing", snapshot);
1058
+ invokeListeners(dispatchState.type, event, "bubbling", snapshot);
1059
+ dispatchState.eventPhase = event.NONE;
1060
+ dispatchState.currentTarget = null;
1061
+ dispatchState.path = [];
1062
+ dispatchState.dispatchFlag = false;
1063
+ dispatchState.stopPropagationFlag = false;
1064
+ dispatchState.stopImmediatePropagationFlag = false;
1065
+ return !dispatchState.canceledFlag;
1066
+ };
1067
+ const removeEventListener = (type, listener, options) => {
1068
+ if (!listener)
1069
+ return;
1070
+ const capture = normalizeCaptureOption(options);
1071
+ const list = listeners.get(type);
1072
+ if (!list)
1073
+ return;
1074
+ for (const record of [...list]) {
1075
+ if (record.original === listener && record.capture === capture) {
1076
+ removeListenerRecord(type, record);
798
1077
  }
799
1078
  }
800
1079
  };
801
1080
  const clear = () => {
802
- for (const set of listeners.values()) {
803
- for (const record of set) {
804
- if (record.signal && record.abortHandler) {
805
- record.signal.removeEventListener("abort", record.abortHandler);
806
- }
1081
+ for (const [type, list] of Array.from(listeners.entries())) {
1082
+ for (const record of [...list]) {
1083
+ removeListenerRecord(type, record);
807
1084
  }
808
- set.clear();
809
1085
  }
810
1086
  listeners.clear();
811
1087
  for (const record of wildcardListeners) {
@@ -815,11 +1091,22 @@ function createEventTargetInternal(opts) {
815
1091
  }
816
1092
  wildcardListeners.clear();
817
1093
  };
818
- const on = (type, options) => {
1094
+ const isListenerArg = (arg) => {
1095
+ if (typeof arg === "function")
1096
+ return true;
1097
+ if (arg && typeof arg === "object" && typeof arg.handleEvent === "function")
1098
+ return true;
1099
+ return false;
1100
+ };
1101
+ const on = (type, optionsOrListener) => {
1102
+ if (isListenerArg(optionsOrListener)) {
1103
+ return addEventListener(type, optionsOrListener);
1104
+ }
1105
+ const options = optionsOrListener;
819
1106
  return new Observable((observer) => {
820
1107
  let opts2;
821
1108
  if (typeof options === "boolean") {
822
- opts2 = { signal: undefined };
1109
+ opts2 = { capture: options };
823
1110
  } else {
824
1111
  opts2 = options ?? {};
825
1112
  }
@@ -856,28 +1143,25 @@ function createEventTargetInternal(opts) {
856
1143
  });
857
1144
  };
858
1145
  const onceMethod = (type, listener, options) => {
859
- return addEventListener(type, listener, { ...options, once: true });
1146
+ if (typeof options === "boolean") {
1147
+ return addEventListener(type, listener, { capture: options, once: true });
1148
+ }
1149
+ return addEventListener(type, listener, { ...options ?? {}, once: true });
860
1150
  };
861
1151
  const removeAllListeners = (type) => {
862
1152
  if (type !== undefined) {
863
- const set = listeners.get(type);
864
- if (set) {
865
- for (const record of set) {
866
- if (record.signal && record.abortHandler) {
867
- record.signal.removeEventListener("abort", record.abortHandler);
868
- }
1153
+ const list = listeners.get(type);
1154
+ if (list) {
1155
+ for (const record of [...list]) {
1156
+ removeListenerRecord(type, record);
869
1157
  }
870
- set.clear();
871
1158
  listeners.delete(type);
872
1159
  }
873
1160
  } else {
874
- for (const set of listeners.values()) {
875
- for (const record of set) {
876
- if (record.signal && record.abortHandler) {
877
- record.signal.removeEventListener("abort", record.abortHandler);
878
- }
1161
+ for (const [eventType, list] of Array.from(listeners.entries())) {
1162
+ for (const record of [...list]) {
1163
+ removeListenerRecord(eventType, record);
879
1164
  }
880
- set.clear();
881
1165
  }
882
1166
  listeners.clear();
883
1167
  for (const record of wildcardListeners) {
@@ -892,38 +1176,33 @@ function createEventTargetInternal(opts) {
892
1176
  if (isCompleted) {
893
1177
  return () => {};
894
1178
  }
895
- const unsubscribes = [];
896
- const subscribedTypes = new Set;
897
- const subscribeToType = (type) => {
898
- if (subscribedTypes.has(type))
899
- return;
900
- subscribedTypes.add(type);
901
- const unsub = addEventListener(type, (event) => {
902
- if (mapFn) {
903
- const mapped = mapFn(event);
904
- if (mapped !== null) {
905
- target2.dispatchEvent(mapped);
906
- }
907
- } else {
908
- target2.dispatchEvent(event);
1179
+ const unsubscribe2 = addWildcardListener("*", (event) => {
1180
+ if (mapFn) {
1181
+ const mapped = mapFn(createEvent(event.originalType, event.detail, {
1182
+ target: target2,
1183
+ currentTarget: target2,
1184
+ eventPhase: 2,
1185
+ bubbles: event.bubbles,
1186
+ cancelable: event.cancelable,
1187
+ composed: event.composed
1188
+ }));
1189
+ if (mapped !== null) {
1190
+ target2.dispatchEvent(mapped);
909
1191
  }
910
- });
911
- unsubscribes.push(unsub);
912
- };
913
- for (const type of listeners.keys()) {
914
- subscribeToType(type);
915
- }
916
- const completionUnsub = () => {
917
- for (const unsub of unsubscribes) {
918
- unsub();
1192
+ } else {
1193
+ target2.dispatchEvent({
1194
+ type: event.originalType,
1195
+ detail: event.detail
1196
+ });
919
1197
  }
1198
+ });
1199
+ const completionUnsub = () => {
1200
+ unsubscribe2();
920
1201
  };
921
1202
  completionCallbacks.add(completionUnsub);
922
1203
  return () => {
923
1204
  completionCallbacks.delete(completionUnsub);
924
- for (const unsub of unsubscribes) {
925
- unsub();
926
- }
1205
+ unsubscribe2();
927
1206
  };
928
1207
  };
929
1208
  const complete2 = () => {
@@ -940,13 +1219,10 @@ function createEventTargetInternal(opts) {
940
1219
  }
941
1220
  }
942
1221
  completionCallbacks.clear();
943
- for (const set of listeners.values()) {
944
- for (const record of set) {
945
- if (record.signal && record.abortHandler) {
946
- record.signal.removeEventListener("abort", record.abortHandler);
947
- }
1222
+ for (const [eventType, list] of Array.from(listeners.entries())) {
1223
+ for (const record of [...list]) {
1224
+ removeListenerRecord(eventType, record);
948
1225
  }
949
- set.clear();
950
1226
  }
951
1227
  listeners.clear();
952
1228
  for (const record of wildcardListeners) {
@@ -1029,7 +1305,14 @@ function createEventTargetInternal(opts) {
1029
1305
  return;
1030
1306
  }
1031
1307
  const wildcardListener = (event) => {
1032
- observer.next(augmentEvent(event.originalType, event.detail));
1308
+ observer.next(createEvent(event.originalType, event.detail, {
1309
+ target,
1310
+ currentTarget: target,
1311
+ eventPhase: 2,
1312
+ bubbles: event.bubbles,
1313
+ cancelable: event.cancelable,
1314
+ composed: event.composed
1315
+ }));
1033
1316
  };
1034
1317
  const unsubscribe2 = addWildcardListener("*", wildcardListener);
1035
1318
  const onComplete = () => {
@@ -1069,19 +1352,26 @@ function createEventTargetInternal(opts) {
1069
1352
  let resolve = null;
1070
1353
  let done = false;
1071
1354
  let hasOverflow = false;
1355
+ let onAbort = null;
1356
+ const cleanupAbortListener = () => {
1357
+ if (signal && onAbort) {
1358
+ signal.removeEventListener("abort", onAbort);
1359
+ }
1360
+ };
1072
1361
  const unsub = addEventListener(type, (event) => {
1073
1362
  if (done)
1074
1363
  return;
1364
+ const typedEvent = event;
1075
1365
  if (resolve) {
1076
1366
  const r = resolve;
1077
1367
  resolve = null;
1078
- r({ value: event, done: false });
1368
+ r({ value: typedEvent, done: false });
1079
1369
  } else {
1080
1370
  if (buffer.length >= bufferSize && bufferSize !== Infinity) {
1081
1371
  switch (overflowStrategy) {
1082
1372
  case "drop-oldest":
1083
1373
  buffer.shift();
1084
- buffer.push(event);
1374
+ buffer.push(typedEvent);
1085
1375
  break;
1086
1376
  case "drop-latest":
1087
1377
  break;
@@ -1090,15 +1380,17 @@ function createEventTargetInternal(opts) {
1090
1380
  completionCallbacks.delete(onComplete);
1091
1381
  done = true;
1092
1382
  hasOverflow = true;
1383
+ cleanupAbortListener();
1093
1384
  return;
1094
1385
  }
1095
1386
  } else {
1096
- buffer.push(event);
1387
+ buffer.push(typedEvent);
1097
1388
  }
1098
1389
  }
1099
1390
  });
1100
1391
  const onComplete = () => {
1101
1392
  done = true;
1393
+ cleanupAbortListener();
1102
1394
  if (resolve) {
1103
1395
  const r = resolve;
1104
1396
  resolve = null;
@@ -1106,7 +1398,6 @@ function createEventTargetInternal(opts) {
1106
1398
  }
1107
1399
  };
1108
1400
  completionCallbacks.add(onComplete);
1109
- let onAbort = null;
1110
1401
  if (signal) {
1111
1402
  onAbort = () => {
1112
1403
  done = true;
@@ -1130,26 +1421,22 @@ function createEventTargetInternal(opts) {
1130
1421
  if (buffer.length > 0) {
1131
1422
  return { value: buffer.shift(), done: false };
1132
1423
  }
1133
- if (hasOverflow) {
1134
- hasOverflow = false;
1135
- throw new BufferOverflowError(type, bufferSize);
1136
- }
1137
- if (done) {
1138
- return { value: undefined, done: true };
1139
- }
1140
1424
  if (resolve !== null) {
1141
1425
  return Promise.reject(new Error("Concurrent calls to next() are not supported on this async iterator"));
1142
1426
  }
1143
1427
  return new Promise((_resolve, _reject) => {
1144
- if (done) {
1145
- _resolve({ value: undefined, done: true });
1146
- return;
1147
- }
1148
1428
  if (hasOverflow) {
1149
1429
  hasOverflow = false;
1150
1430
  _reject(new BufferOverflowError(type, bufferSize));
1151
1431
  return;
1152
1432
  }
1433
+ if (done) {
1434
+ _resolve({
1435
+ value: undefined,
1436
+ done: true
1437
+ });
1438
+ return;
1439
+ }
1153
1440
  resolve = _resolve;
1154
1441
  });
1155
1442
  },
@@ -1162,9 +1449,7 @@ function createEventTargetInternal(opts) {
1162
1449
  done = true;
1163
1450
  completionCallbacks.delete(onComplete);
1164
1451
  unsub();
1165
- if (signal && onAbort) {
1166
- signal.removeEventListener("abort", onAbort);
1167
- }
1452
+ cleanupAbortListener();
1168
1453
  return Promise.resolve({
1169
1454
  value: undefined,
1170
1455
  done: true
@@ -1173,6 +1458,72 @@ function createEventTargetInternal(opts) {
1173
1458
  };
1174
1459
  return iterator;
1175
1460
  }
1461
+ const emit = (type, detail) => {
1462
+ if (isCompleted)
1463
+ return false;
1464
+ const list = listeners.get(type);
1465
+ const hasListeners = list !== undefined && list.length > 0;
1466
+ let hasWildcard = false;
1467
+ if (wildcardListeners.size > 0) {
1468
+ for (const rec of wildcardListeners) {
1469
+ if (matchesWildcard(type, rec.pattern)) {
1470
+ hasWildcard = true;
1471
+ break;
1472
+ }
1473
+ }
1474
+ }
1475
+ dispatchEvent({ type, detail });
1476
+ return hasListeners || hasWildcard;
1477
+ };
1478
+ const off = (type, listener) => {
1479
+ removeEventListener(type, listener);
1480
+ };
1481
+ const addListener = (type, listener) => {
1482
+ return addEventListener(type, listener);
1483
+ };
1484
+ const removeListener = (type, listener) => {
1485
+ removeEventListener(type, listener);
1486
+ };
1487
+ const prependListener = (type, listener) => {
1488
+ return addListenerInternal(type, listener, undefined, "prepend");
1489
+ };
1490
+ const prependOnceListener = (type, listener) => {
1491
+ return addListenerInternal(type, listener, { once: true }, "prepend");
1492
+ };
1493
+ const getListeners = (type) => {
1494
+ const list = listeners.get(type);
1495
+ if (!list)
1496
+ return [];
1497
+ return list.filter((r) => !r.removed).map((r) => r.original);
1498
+ };
1499
+ const rawListenersMethod = (type) => {
1500
+ const list = listeners.get(type);
1501
+ if (!list)
1502
+ return [];
1503
+ return list.filter((r) => !r.removed).map((r) => {
1504
+ if (r.once) {
1505
+ const wrapper = (...args) => r.callback(...args);
1506
+ wrapper.listener = r.original;
1507
+ return wrapper;
1508
+ }
1509
+ return r.original;
1510
+ });
1511
+ };
1512
+ const listenerCount = (type) => {
1513
+ const list = listeners.get(type);
1514
+ if (!list)
1515
+ return 0;
1516
+ return list.filter((r) => !r.removed).length;
1517
+ };
1518
+ const eventNamesMethod = () => {
1519
+ const names = [];
1520
+ for (const [type, list] of listeners) {
1521
+ if (list.some((r) => !r.removed)) {
1522
+ names.push(type);
1523
+ }
1524
+ }
1525
+ return names;
1526
+ };
1176
1527
  const target = {
1177
1528
  addEventListener,
1178
1529
  removeEventListener,
@@ -1190,90 +1541,23 @@ function createEventTargetInternal(opts) {
1190
1541
  },
1191
1542
  subscribe,
1192
1543
  toObservable,
1193
- events
1544
+ events,
1545
+ emit,
1546
+ off,
1547
+ addListener,
1548
+ removeListener,
1549
+ prependListener,
1550
+ prependOnceListener,
1551
+ listeners: getListeners,
1552
+ rawListeners: rawListenersMethod,
1553
+ listenerCount,
1554
+ eventNames: eventNamesMethod
1194
1555
  };
1195
1556
  target[SymbolObservable] = () => {
1196
1557
  return toObservable();
1197
1558
  };
1198
1559
  return target;
1199
1560
  }
1200
- // src/interop.ts
1201
- function forwardToEventTarget(source, target, options) {
1202
- const unsubscribe2 = source.addWildcardListener("*", (event) => {
1203
- const domEvent = {
1204
- type: event.originalType,
1205
- detail: event.detail
1206
- };
1207
- target.dispatchEvent(domEvent);
1208
- }, options);
1209
- return unsubscribe2;
1210
- }
1211
- function fromEventTarget(domTarget, eventTypes, options) {
1212
- const emitter = createEventTarget({
1213
- onListenerError: options?.onListenerError
1214
- });
1215
- const handlers = new Map;
1216
- for (const type of eventTypes) {
1217
- const handler = (event) => {
1218
- emitter.dispatchEvent({
1219
- type,
1220
- detail: event.detail ?? event
1221
- });
1222
- };
1223
- handlers.set(type, handler);
1224
- domTarget.addEventListener(type, handler);
1225
- }
1226
- let onAbort = null;
1227
- if (options?.signal) {
1228
- onAbort = () => {
1229
- for (const [type, handler] of handlers) {
1230
- domTarget.removeEventListener(type, handler);
1231
- }
1232
- handlers.clear();
1233
- emitter.complete();
1234
- };
1235
- options.signal.addEventListener("abort", onAbort, { once: true });
1236
- if (options.signal.aborted)
1237
- onAbort();
1238
- }
1239
- return {
1240
- addEventListener: emitter.addEventListener,
1241
- removeEventListener: emitter.removeEventListener,
1242
- dispatchEvent: emitter.dispatchEvent,
1243
- clear: emitter.clear,
1244
- once: emitter.once,
1245
- removeAllListeners: emitter.removeAllListeners,
1246
- pipe: emitter.pipe,
1247
- addWildcardListener: emitter.addWildcardListener,
1248
- removeWildcardListener: emitter.removeWildcardListener,
1249
- on: emitter.on,
1250
- subscribe: emitter.subscribe,
1251
- toObservable: emitter.toObservable,
1252
- complete: emitter.complete,
1253
- get completed() {
1254
- return emitter.completed;
1255
- },
1256
- events: emitter.events,
1257
- destroy: () => {
1258
- if (options?.signal && onAbort) {
1259
- options.signal.removeEventListener("abort", onAbort);
1260
- }
1261
- for (const [type, handler] of handlers) {
1262
- domTarget.removeEventListener(type, handler);
1263
- }
1264
- handlers.clear();
1265
- emitter.complete();
1266
- }
1267
- };
1268
- }
1269
- function pipe(source, target, options) {
1270
- return source.addWildcardListener("*", (event) => {
1271
- target.dispatchEvent({
1272
- type: event.originalType,
1273
- detail: event.detail
1274
- });
1275
- }, options);
1276
- }
1277
1561
  // src/event-emission.ts
1278
1562
  class EventEmission {
1279
1563
  #target;
@@ -1283,14 +1567,14 @@ class EventEmission {
1283
1567
  addEventListener(type, listener, options) {
1284
1568
  return this.#target.addEventListener(type, listener, options);
1285
1569
  }
1286
- removeEventListener(type, listener) {
1287
- this.#target.removeEventListener(type, listener);
1570
+ removeEventListener(type, listener, options) {
1571
+ this.#target.removeEventListener(type, listener, options);
1288
1572
  }
1289
1573
  dispatchEvent(event) {
1290
1574
  return this.#target.dispatchEvent(event);
1291
1575
  }
1292
- on(type, options) {
1293
- return this.#target.on(type, options);
1576
+ on(type, optionsOrListener) {
1577
+ return this.#target.on(type, optionsOrListener);
1294
1578
  }
1295
1579
  once(type, listener, options) {
1296
1580
  return this.#target.once(type, listener, options);
@@ -1304,6 +1588,36 @@ class EventEmission {
1304
1588
  pipe(target, mapFn) {
1305
1589
  return this.#target.pipe(target, mapFn);
1306
1590
  }
1591
+ emit(type, detail) {
1592
+ return this.#target.emit(type, detail);
1593
+ }
1594
+ off(type, listener) {
1595
+ this.#target.off(type, listener);
1596
+ }
1597
+ addListener(type, listener) {
1598
+ return this.#target.addListener(type, listener);
1599
+ }
1600
+ removeListener(type, listener) {
1601
+ this.#target.removeListener(type, listener);
1602
+ }
1603
+ prependListener(type, listener) {
1604
+ return this.#target.prependListener(type, listener);
1605
+ }
1606
+ prependOnceListener(type, listener) {
1607
+ return this.#target.prependOnceListener(type, listener);
1608
+ }
1609
+ listeners(type) {
1610
+ return this.#target.listeners(type);
1611
+ }
1612
+ rawListeners(type) {
1613
+ return this.#target.rawListeners(type);
1614
+ }
1615
+ listenerCount(type) {
1616
+ return this.#target.listenerCount(type);
1617
+ }
1618
+ eventNames() {
1619
+ return this.#target.eventNames();
1620
+ }
1307
1621
  addWildcardListener(pattern, listener, options) {
1308
1622
  return this.#target.addWildcardListener(pattern, listener, options);
1309
1623
  }
@@ -1343,19 +1657,10 @@ class EventEmission {
1343
1657
  }
1344
1658
  }
1345
1659
  export {
1346
- setupEventForwarding,
1347
- pipe,
1348
- isObserved,
1349
- getOriginal,
1350
- fromEventTarget,
1351
- forwardToEventTarget,
1352
1660
  createEventTarget,
1353
1661
  SymbolObservable,
1354
- PROXY_MARKER,
1355
- Observable,
1356
- ORIGINAL_TARGET,
1357
1662
  EventEmission,
1358
1663
  BufferOverflowError
1359
1664
  };
1360
1665
 
1361
- //# debugId=444E2053CE7B039864756E2164756E21
1666
+ //# debugId=320F1C6E7F0CB63D64756E2164756E21