@oimdb/core 1.3.1 → 1.4.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.
package/dist/index.cjs CHANGED
@@ -21,15 +21,26 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  EOIMCollectionEventType: () => EOIMCollectionEventType,
24
+ EOIMComputedEventType: () => EOIMComputedEventType,
25
+ EOIMEffectPhase: () => EOIMEffectPhase,
24
26
  EOIMEventQueueEventType: () => EOIMEventQueueEventType,
25
27
  EOIMEventQueueSchedulerEventType: () => EOIMEventQueueSchedulerEventType,
26
28
  EOIMIndexEventType: () => EOIMIndexEventType,
29
+ EOIMObjectEventType: () => EOIMObjectEventType,
27
30
  EOIMUpdateEventCoalescerEventType: () => EOIMUpdateEventCoalescerEventType,
28
31
  OIMCollection: () => OIMCollection,
32
+ OIMCollectionChangedFieldsWrapper: () => OIMCollectionChangedFieldsWrapper,
29
33
  OIMCollectionStore: () => OIMCollectionStore,
30
34
  OIMCollectionStoreMapDriven: () => OIMCollectionStoreMapDriven,
31
35
  OIMComparatorFactory: () => OIMComparatorFactory,
36
+ OIMComputed: () => OIMComputed,
32
37
  OIMDBSettings: () => OIMDBSettings,
38
+ OIMEffect: () => OIMEffect,
39
+ OIMEffectDependencyComputed: () => OIMEffectDependencyComputed,
40
+ OIMEffectDependencyKeyed: () => OIMEffectDependencyKeyed,
41
+ OIMEffectDependencyKeyedCollection: () => OIMEffectDependencyKeyedCollection,
42
+ OIMEffectDependencyKeyedIndex: () => OIMEffectDependencyKeyedIndex,
43
+ OIMEffectDependencyKeyedObject: () => OIMEffectDependencyKeyedObject,
33
44
  OIMEntityUpdaterFactory: () => OIMEntityUpdaterFactory,
34
45
  OIMEventEmitter: () => OIMEventEmitter,
35
46
  OIMEventQueue: () => OIMEventQueue,
@@ -42,6 +53,7 @@ __export(index_exports, {
42
53
  OIMIndexArrayBased: () => OIMIndexArrayBased,
43
54
  OIMIndexComparatorFactory: () => OIMIndexComparatorFactory,
44
55
  OIMIndexManualArrayBased: () => OIMIndexManualArrayBased,
56
+ OIMIndexManualOrderedArrayBased: () => OIMIndexManualOrderedArrayBased,
45
57
  OIMIndexManualSetBased: () => OIMIndexManualSetBased,
46
58
  OIMIndexSetBased: () => OIMIndexSetBased,
47
59
  OIMIndexStoreArrayBased: () => OIMIndexStoreArrayBased,
@@ -49,6 +61,11 @@ __export(index_exports, {
49
61
  OIMIndexStoreMapDrivenSetBased: () => OIMIndexStoreMapDrivenSetBased,
50
62
  OIMIndexStoreSetBased: () => OIMIndexStoreSetBased,
51
63
  OIMMap2Keys: () => OIMMap2Keys,
64
+ OIMObject: () => OIMObject,
65
+ OIMObjectStore: () => OIMObjectStore,
66
+ OIMObjectStoreMapDriven: () => OIMObjectStoreMapDriven,
67
+ OIMObjectStoreRecordDriven: () => OIMObjectStoreRecordDriven,
68
+ OIMOrderedListIndexCommandStreamWrapper: () => OIMOrderedListIndexCommandStreamWrapper,
52
69
  OIMPkSelectorFactory: () => OIMPkSelectorFactory,
53
70
  OIMRICollection: () => OIMRICollection,
54
71
  OIMReactiveCollection: () => OIMReactiveCollection,
@@ -56,9 +73,13 @@ __export(index_exports, {
56
73
  OIMReactiveIndexManualArrayBased: () => OIMReactiveIndexManualArrayBased,
57
74
  OIMReactiveIndexManualSetBased: () => OIMReactiveIndexManualSetBased,
58
75
  OIMReactiveIndexSetBased: () => OIMReactiveIndexSetBased,
76
+ OIMReactiveObject: () => OIMReactiveObject,
59
77
  OIMUpdateEventCoalescer: () => OIMUpdateEventCoalescer,
60
78
  OIMUpdateEventCoalescerCollection: () => OIMUpdateEventCoalescerCollection,
79
+ OIMUpdateEventCoalescerComputed: () => OIMUpdateEventCoalescerComputed,
61
80
  OIMUpdateEventCoalescerIndex: () => OIMUpdateEventCoalescerIndex,
81
+ OIMUpdateEventCoalescerManual: () => OIMUpdateEventCoalescerManual,
82
+ OIMUpdateEventCoalescerObject: () => OIMUpdateEventCoalescerObject,
62
83
  OIMUpdateEventEmitter: () => OIMUpdateEventEmitter
63
84
  });
64
85
  module.exports = __toCommonJS(index_exports);
@@ -93,39 +114,40 @@ var OIMEventEmitter = class {
93
114
  }
94
115
  return bucket;
95
116
  }
117
+ /**
118
+ * Compacts the handlers array by removing null entries (tombstones) left by handler removal.
119
+ * Rebuilds the indexByHandler map with updated indices and resets the tombstone count.
120
+ * This reduces array fragmentation and improves iteration performance.
121
+ */
96
122
  compactBucket(bucket) {
97
123
  const handlers = bucket.handlers;
98
124
  const length = handlers.length;
99
125
  const newHandlers = [];
100
126
  bucket.indexByHandler.clear();
101
- if (bucket.tombstoneCount < length >> 2) {
102
- newHandlers.length = length - bucket.tombstoneCount;
103
- }
104
- let writeIndex = 0;
105
127
  for (let i = 0; i < length; i++) {
106
128
  const handler = handlers[i];
107
129
  if (handler) {
108
- newHandlers[writeIndex] = handler;
130
+ const writeIndex = newHandlers.length;
131
+ newHandlers.push(handler);
109
132
  bucket.indexByHandler.set(handler, writeIndex);
110
- writeIndex++;
111
133
  }
112
134
  }
113
- if (newHandlers.length !== writeIndex) {
114
- newHandlers.length = writeIndex;
115
- }
116
135
  bucket.handlers = newHandlers;
117
136
  bucket.tombstoneCount = 0;
118
137
  }
119
138
  on(event, handler) {
120
139
  const bucket = this.getOrCreateBucket(event);
121
- if (bucket.indexByHandler.has(handler))
122
- return;
140
+ if (bucket.indexByHandler.has(handler)) {
141
+ return () => {
142
+ this.off(event, handler);
143
+ };
144
+ }
123
145
  const index = bucket.handlers.length;
124
146
  bucket.handlers.push(handler);
125
- bucket.indexByHandler.set(
126
- handler,
127
- index
128
- );
147
+ bucket.indexByHandler.set(handler, index);
148
+ return () => {
149
+ this.off(event, handler);
150
+ };
129
151
  }
130
152
  emit(event, payload) {
131
153
  const bucket = this.buckets[event];
@@ -140,10 +162,11 @@ var OIMEventEmitter = class {
140
162
  }
141
163
  bucket.isEmitting--;
142
164
  if (bucket.isEmitting === 0 && bucket.tombstoneCount > 0) {
143
- if (bucket.tombstoneCount >= length >> 1) {
144
- this.compactBucket(bucket);
145
- } else if (length === bucket.tombstoneCount) {
165
+ const currentLength = bucket.handlers.length;
166
+ if (bucket.tombstoneCount === currentLength) {
146
167
  delete this.buckets[event];
168
+ } else if (bucket.tombstoneCount >= currentLength >> 1) {
169
+ this.compactBucket(bucket);
147
170
  }
148
171
  }
149
172
  }
@@ -157,10 +180,10 @@ var OIMEventEmitter = class {
157
180
  bucket.indexByHandler.delete(handler);
158
181
  if (bucket.isEmitting === 0) {
159
182
  const length = bucket.handlers.length;
160
- if (bucket.tombstoneCount >= length >> 1) {
161
- this.compactBucket(bucket);
162
- } else if (length === bucket.tombstoneCount) {
183
+ if (bucket.tombstoneCount === length) {
163
184
  delete this.buckets[event];
185
+ } else if (bucket.tombstoneCount >= length >> 1) {
186
+ this.compactBucket(bucket);
164
187
  }
165
188
  }
166
189
  }
@@ -522,34 +545,50 @@ var EOIMUpdateEventCoalescerEventType = /* @__PURE__ */ ((EOIMUpdateEventCoalesc
522
545
  // src/core/OIMUpdateEventEmitter.ts
523
546
  var OIMUpdateEventEmitter = class {
524
547
  constructor(opts) {
548
+ this.keyHandlersBeforeFlush = /* @__PURE__ */ new Map();
525
549
  this.keyHandlers = /* @__PURE__ */ new Map();
550
+ this.isDestroyed = false;
551
+ this.isDispatching = false;
552
+ this.isInPrePhase = false;
553
+ this.hasPendingDuringPrePhase = false;
554
+ this.isFlushEnqueued = false;
526
555
  this.handleHasChanges = () => {
527
- this.queue.enqueue(() => {
528
- const updatedKeys = this.coalescer.getUpdatedKeys();
529
- if (this.keyHandlers.size === 0) {
530
- this.coalescer.clearUpdatedKeys();
531
- return;
532
- }
533
- if (updatedKeys.size * 2 < this.keyHandlers.size) {
534
- for (const key of updatedKeys.values()) {
535
- const handlers = this.keyHandlers.get(key);
536
- if (handlers) {
537
- for (const handler of handlers) {
538
- handler();
539
- }
540
- }
541
- }
542
- } else {
543
- for (const [key, handlers] of this.keyHandlers) {
544
- if (updatedKeys.has(key)) {
545
- for (const handler of handlers) {
546
- handler();
547
- }
548
- }
549
- }
550
- }
556
+ if (this.isDispatching && this.isInPrePhase) {
557
+ this.hasPendingDuringPrePhase = true;
558
+ return;
559
+ }
560
+ if (this.isFlushEnqueued) return;
561
+ this.isFlushEnqueued = true;
562
+ this.queue.enqueue(this.onFlush);
563
+ };
564
+ // Stable handler reference to avoid allocating a new closure on every HAS_CHANGES.
565
+ this.onFlush = () => {
566
+ this.isFlushEnqueued = false;
567
+ if (this.isDestroyed) {
551
568
  this.coalescer.clearUpdatedKeys();
552
- });
569
+ this.coalescer.clearFlushingUpdatedKeys();
570
+ return;
571
+ }
572
+ if (this.keyHandlers.size === 0 && this.keyHandlersBeforeFlush.size === 0) {
573
+ this.coalescer.clearUpdatedKeys();
574
+ return;
575
+ }
576
+ const makeHandlerSnapshot = (handlers) => {
577
+ const snapshot = [];
578
+ handlers.forEach((h) => snapshot.push(h));
579
+ return snapshot;
580
+ };
581
+ try {
582
+ this.isDispatching = true;
583
+ this.isInPrePhase = true;
584
+ this.hasPendingDuringPrePhase = false;
585
+ const allKeysForNormalPhase = this.runPrePhaseDrain(makeHandlerSnapshot);
586
+ this.isInPrePhase = false;
587
+ this.runHandlersPhase(allKeysForNormalPhase, makeHandlerSnapshot);
588
+ } finally {
589
+ this.isInPrePhase = false;
590
+ this.isDispatching = false;
591
+ }
553
592
  };
554
593
  this.coalescer = opts.coalescer;
555
594
  this.coalescer.emitter.on(
@@ -558,11 +597,90 @@ var OIMUpdateEventEmitter = class {
558
597
  );
559
598
  this.queue = opts.queue;
560
599
  }
600
+ /**
601
+ * Helps to run computed values etc.
602
+ */
603
+ runPrePhaseDrain(makeHandlerSnapshot) {
604
+ const allKeysForNormalPhase = /* @__PURE__ */ new Set();
605
+ let hasMorePreWork = true;
606
+ while (hasMorePreWork) {
607
+ this.coalescer.markUpdatedKeysAsFlushing();
608
+ const flushingKeys = this.coalescer.getFlushingUpdatedKeys();
609
+ flushingKeys.forEach((key) => allKeysForNormalPhase.add(key));
610
+ try {
611
+ if (this.keyHandlersBeforeFlush.size > 0) {
612
+ if (flushingKeys.size * 2 < this.keyHandlersBeforeFlush.size) {
613
+ flushingKeys.forEach((key) => {
614
+ if (this.isDestroyed) return;
615
+ const handlers = this.keyHandlersBeforeFlush.get(key);
616
+ if (!handlers || handlers.size === 0) return;
617
+ const handlerSnapshot = makeHandlerSnapshot(handlers);
618
+ for (let i = 0; i < handlerSnapshot.length; i++) {
619
+ if (this.isDestroyed) return;
620
+ const handler = handlerSnapshot[i];
621
+ if (handlers.has(handler)) handler();
622
+ }
623
+ });
624
+ } else {
625
+ this.keyHandlersBeforeFlush.forEach((handlers, key) => {
626
+ if (this.isDestroyed) return;
627
+ if (!flushingKeys.has(key)) return;
628
+ if (!handlers || handlers.size === 0) return;
629
+ const handlerSnapshot = makeHandlerSnapshot(handlers);
630
+ for (let i = 0; i < handlerSnapshot.length; i++) {
631
+ if (this.isDestroyed) return;
632
+ const handler = handlerSnapshot[i];
633
+ if (handlers.has(handler)) handler();
634
+ }
635
+ });
636
+ }
637
+ }
638
+ } finally {
639
+ this.coalescer.clearFlushingUpdatedKeys();
640
+ }
641
+ const nextHasMorePreWork = this.hasPendingDuringPrePhase || this.coalescer.getUpdatedKeys().size > 0;
642
+ this.hasPendingDuringPrePhase = false;
643
+ hasMorePreWork = nextHasMorePreWork;
644
+ }
645
+ return allKeysForNormalPhase;
646
+ }
647
+ runHandlersPhase(allKeysForNormalPhase, makeHandlerSnapshot) {
648
+ if (this.keyHandlers.size === 0 || allKeysForNormalPhase.size === 0)
649
+ return;
650
+ if (allKeysForNormalPhase.size * 2 < this.keyHandlers.size) {
651
+ allKeysForNormalPhase.forEach((key) => {
652
+ if (this.isDestroyed) return;
653
+ const handlers = this.keyHandlers.get(key);
654
+ if (!handlers || handlers.size === 0) return;
655
+ const handlerSnapshot = makeHandlerSnapshot(handlers);
656
+ for (let i = 0; i < handlerSnapshot.length; i++) {
657
+ if (this.isDestroyed) return;
658
+ const handler = handlerSnapshot[i];
659
+ if (handlers.has(handler)) handler();
660
+ }
661
+ });
662
+ } else {
663
+ this.keyHandlers.forEach((handlers, key) => {
664
+ if (this.isDestroyed) return;
665
+ if (!allKeysForNormalPhase.has(key)) return;
666
+ if (!handlers || handlers.size === 0) return;
667
+ const handlerSnapshot = makeHandlerSnapshot(handlers);
668
+ for (let i = 0; i < handlerSnapshot.length; i++) {
669
+ if (this.isDestroyed) return;
670
+ const handler = handlerSnapshot[i];
671
+ if (handlers.has(handler)) handler();
672
+ }
673
+ });
674
+ }
675
+ }
561
676
  destroy() {
677
+ if (this.isDestroyed) return;
678
+ this.isDestroyed = true;
562
679
  this.coalescer.emitter.off(
563
680
  0 /* HAS_CHANGES */,
564
681
  this.handleHasChanges
565
682
  );
683
+ this.keyHandlersBeforeFlush.clear();
566
684
  this.keyHandlers.clear();
567
685
  }
568
686
  /**
@@ -570,9 +688,9 @@ var OIMUpdateEventEmitter = class {
570
688
  */
571
689
  getMetrics() {
572
690
  let totalHandlers = 0;
573
- for (const handlers of this.keyHandlers.values()) {
691
+ this.keyHandlers.forEach((handlers) => {
574
692
  totalHandlers += handlers.size;
575
- }
693
+ });
576
694
  return {
577
695
  totalKeys: this.keyHandlers.size,
578
696
  totalHandlers,
@@ -584,13 +702,32 @@ var OIMUpdateEventEmitter = class {
584
702
  * Check if there are any active subscriptions
585
703
  */
586
704
  hasSubscriptions() {
587
- return this.keyHandlers.size > 0;
705
+ return this.keyHandlers.size > 0 || this.keyHandlersBeforeFlush.size > 0;
588
706
  }
589
707
  /**
590
708
  * Get the number of handlers for a specific key
591
709
  */
592
710
  getHandlerCount(key) {
593
- return this.keyHandlers.get(key)?.size ?? 0;
711
+ return (this.keyHandlers.get(key)?.size ?? 0) + (this.keyHandlersBeforeFlush.get(key)?.size ?? 0);
712
+ }
713
+ subscribeOnKeyBeforeFlush(key, handler) {
714
+ let handlers = this.keyHandlersBeforeFlush.get(key);
715
+ if (!handlers) {
716
+ handlers = /* @__PURE__ */ new Set();
717
+ this.keyHandlersBeforeFlush.set(key, handlers);
718
+ }
719
+ handlers.add(handler);
720
+ return () => {
721
+ this.unsubscribeFromKeyBeforeFlush(key, handler);
722
+ };
723
+ }
724
+ unsubscribeFromKeyBeforeFlush(key, handler) {
725
+ const handlers = this.keyHandlersBeforeFlush.get(key);
726
+ if (!handlers) return;
727
+ handlers.delete(handler);
728
+ if (handlers.size === 0) {
729
+ this.keyHandlersBeforeFlush.delete(key);
730
+ }
594
731
  }
595
732
  subscribeOnKey(key, handler) {
596
733
  let handlers = this.keyHandlers.get(key);
@@ -630,6 +767,30 @@ var OIMUpdateEventEmitter = class {
630
767
  }
631
768
  };
632
769
  }
770
+ subscribeOnKeysBeforeFlush(keys, handler) {
771
+ const subscribedKeys = [];
772
+ for (const key of keys) {
773
+ let handlers = this.keyHandlersBeforeFlush.get(key);
774
+ if (!handlers) {
775
+ handlers = /* @__PURE__ */ new Set();
776
+ this.keyHandlersBeforeFlush.set(key, handlers);
777
+ }
778
+ if (!handlers.has(handler)) {
779
+ handlers.add(handler);
780
+ subscribedKeys.push(key);
781
+ }
782
+ }
783
+ return () => {
784
+ for (const key of subscribedKeys) {
785
+ this.unsubscribeFromKeyBeforeFlush(key, handler);
786
+ }
787
+ };
788
+ }
789
+ unsubscribeFromKeysBeforeFlush(keys, handler) {
790
+ for (const key of keys) {
791
+ this.unsubscribeFromKeyBeforeFlush(key, handler);
792
+ }
793
+ }
633
794
  unsubscribeFromKeys(keys, handler) {
634
795
  for (const key of keys) {
635
796
  this.unsubscribeFromKey(key, handler);
@@ -724,15 +885,19 @@ var OIMDBSettings = class {
724
885
  * This constant is exported so users can create their own indexes and pass them to coalescers.
725
886
  */
726
887
  OIMDBSettings.UPDATED_KEYS_INDEX_KEY = "__updatedKeys__";
888
+ OIMDBSettings.FLUSHING_KEYS_INDEX_KEY = "__flushingKeys__";
727
889
 
728
890
  // src/core/OIMUpdateEventCoalescer.ts
729
891
  var OIMUpdateEventCoalescer = class {
730
- constructor(index) {
892
+ constructor(index, flushingIndex) {
731
893
  this.emitter = new OIMEventEmitter();
732
894
  this.hasEmittedChanges = false;
733
895
  this.updatedKeysIndex = index ?? new OIMIndexManualSetBased({
734
896
  store: new OIMIndexStoreMapDrivenSetBased()
735
897
  });
898
+ this.flushingUpdatedKeysIndex = flushingIndex ?? new OIMIndexManualSetBased({
899
+ store: new OIMIndexStoreMapDrivenSetBased()
900
+ });
736
901
  if (!this.updatedKeysIndex.hasKey(OIMDBSettings.UPDATED_KEYS_INDEX_KEY)) {
737
902
  this.updatedKeysIndex.setPks(
738
903
  OIMDBSettings.UPDATED_KEYS_INDEX_KEY,
@@ -748,6 +913,18 @@ var OIMUpdateEventCoalescer = class {
748
913
  OIMDBSettings.UPDATED_KEYS_INDEX_KEY
749
914
  );
750
915
  }
916
+ getFlushingUpdatedKeys() {
917
+ return this.flushingUpdatedKeysIndex.getPksByKey(
918
+ OIMDBSettings.FLUSHING_KEYS_INDEX_KEY
919
+ );
920
+ }
921
+ markUpdatedKeysAsFlushing() {
922
+ this.flushingUpdatedKeysIndex.setPks(
923
+ OIMDBSettings.FLUSHING_KEYS_INDEX_KEY,
924
+ Array.from(this.getUpdatedKeys())
925
+ );
926
+ this.clearUpdatedKeys();
927
+ }
751
928
  /**
752
929
  * Clear all updated keys and reset the changed state
753
930
  */
@@ -763,6 +940,12 @@ var OIMUpdateEventCoalescer = class {
763
940
  void 0
764
941
  );
765
942
  }
943
+ clearFlushingUpdatedKeys() {
944
+ this.flushingUpdatedKeysIndex.setPks(
945
+ OIMDBSettings.FLUSHING_KEYS_INDEX_KEY,
946
+ []
947
+ );
948
+ }
766
949
  /**
767
950
  * Add keys to the updated set and emit HAS_CHANGES event if needed
768
951
  */
@@ -838,6 +1021,8 @@ var OIMReactiveIndexSetBased = class {
838
1021
  return this.index.getMetrics();
839
1022
  }
840
1023
  destroy() {
1024
+ this.updateEventEmitter.destroy();
1025
+ this.coalescer.destroy();
841
1026
  this.index.destroy();
842
1027
  }
843
1028
  };
@@ -879,10 +1064,16 @@ var OIMReactiveIndexArrayBased = class {
879
1064
  return this.index.getMetrics();
880
1065
  }
881
1066
  destroy() {
1067
+ this.updateEventEmitter.destroy();
1068
+ this.coalescer.destroy();
882
1069
  this.index.destroy();
883
1070
  }
884
1071
  };
885
1072
 
1073
+ // src/abstract/OIMObjectStore.ts
1074
+ var OIMObjectStore = class {
1075
+ };
1076
+
886
1077
  // src/core/OIMPkSelectorFactory.ts
887
1078
  var OIMPkSelectorFactory = class {
888
1079
  createIdSelector() {
@@ -940,6 +1131,9 @@ var OIMCollectionStoreMapDriven = class extends OIMCollectionStore {
940
1131
  getAllPks() {
941
1132
  return Array.from(this.entities.keys());
942
1133
  }
1134
+ destroy() {
1135
+ this.clear();
1136
+ }
943
1137
  };
944
1138
 
945
1139
  // src/core/OIMEntityUpdaterFactory.ts
@@ -1037,6 +1231,10 @@ var OIMCollection = class {
1037
1231
  this.store.setOneByPk(pk, entity);
1038
1232
  }
1039
1233
  }
1234
+ destroy() {
1235
+ this.store.destroy();
1236
+ this.emitter.offAll();
1237
+ }
1040
1238
  };
1041
1239
 
1042
1240
  // src/core/OIMUpdateEventCoalescerCollection.ts
@@ -1077,6 +1275,143 @@ var OIMReactiveCollection = class extends OIMCollection {
1077
1275
  queue
1078
1276
  });
1079
1277
  }
1278
+ destroy() {
1279
+ this.updateEventEmitter.destroy();
1280
+ this.coalescer.destroy();
1281
+ super.destroy();
1282
+ }
1283
+ };
1284
+
1285
+ // src/core/OIMObjectStoreRecordDriven.ts
1286
+ var OIMObjectStoreRecordDriven = class extends OIMObjectStore {
1287
+ constructor(initial) {
1288
+ super();
1289
+ this.properties = Object.assign(/* @__PURE__ */ Object.create(null), initial ?? {});
1290
+ }
1291
+ setProperty(key, value) {
1292
+ this.properties[key] = value;
1293
+ }
1294
+ merge(draft) {
1295
+ Object.assign(this.properties, draft);
1296
+ }
1297
+ delete(key) {
1298
+ delete this.properties[key];
1299
+ }
1300
+ get(key) {
1301
+ return this.properties[key];
1302
+ }
1303
+ getAll() {
1304
+ return { ...this.properties };
1305
+ }
1306
+ clear() {
1307
+ this.properties = /* @__PURE__ */ Object.create(null);
1308
+ }
1309
+ count() {
1310
+ return Object.keys(this.properties).length;
1311
+ }
1312
+ keys() {
1313
+ return Object.keys(this.properties);
1314
+ }
1315
+ values() {
1316
+ return Object.values(this.properties);
1317
+ }
1318
+ entries() {
1319
+ return Object.entries(this.properties);
1320
+ }
1321
+ destroy() {
1322
+ this.clear();
1323
+ }
1324
+ };
1325
+
1326
+ // src/enum/EOIMObjectEventType.ts
1327
+ var EOIMObjectEventType = /* @__PURE__ */ ((EOIMObjectEventType2) => {
1328
+ EOIMObjectEventType2[EOIMObjectEventType2["UPDATE"] = 0] = "UPDATE";
1329
+ return EOIMObjectEventType2;
1330
+ })(EOIMObjectEventType || {});
1331
+
1332
+ // src/core/OIMObject.ts
1333
+ var OIMObject = class {
1334
+ constructor(opts) {
1335
+ this.emitter = new OIMEventEmitter();
1336
+ this.store = opts?.store ?? new OIMObjectStoreRecordDriven();
1337
+ }
1338
+ setProperty(key, value) {
1339
+ this.store.setProperty(key, value);
1340
+ this.emitter.emit(0 /* UPDATE */, { keys: [key] });
1341
+ }
1342
+ merge(draft) {
1343
+ this.store.merge(draft);
1344
+ this.emitter.emit(0 /* UPDATE */, {
1345
+ keys: Object.keys(draft)
1346
+ });
1347
+ }
1348
+ delete(key) {
1349
+ this.store.delete(key);
1350
+ this.emitter.emit(0 /* UPDATE */, { keys: [key] });
1351
+ }
1352
+ get(key) {
1353
+ return this.store.get(key);
1354
+ }
1355
+ getAll() {
1356
+ return this.store.getAll();
1357
+ }
1358
+ clear() {
1359
+ this.store.clear();
1360
+ this.emitter.emit(0 /* UPDATE */, { keys: [] });
1361
+ }
1362
+ count() {
1363
+ return this.store.count();
1364
+ }
1365
+ keys() {
1366
+ return this.store.keys();
1367
+ }
1368
+ values() {
1369
+ return this.store.values();
1370
+ }
1371
+ entries() {
1372
+ return this.store.entries();
1373
+ }
1374
+ destroy() {
1375
+ this.store.destroy();
1376
+ this.emitter.offAll();
1377
+ }
1378
+ };
1379
+
1380
+ // src/core/OIMUpdateEventCoalescerObject.ts
1381
+ var OIMUpdateEventCoalescerObject = class extends OIMUpdateEventCoalescer {
1382
+ constructor(objectEmitter) {
1383
+ super();
1384
+ this.objectEmitter = objectEmitter;
1385
+ /**
1386
+ * When the object is updated, we keep track of the updated keys.
1387
+ */
1388
+ this.handleUpdate = (payload) => {
1389
+ this.addUpdatedKeys(payload.keys);
1390
+ };
1391
+ this.objectEmitter.on(0 /* UPDATE */, this.handleUpdate);
1392
+ }
1393
+ destroy() {
1394
+ this.objectEmitter.off(0 /* UPDATE */, this.handleUpdate);
1395
+ this.emitter.offAll();
1396
+ this.clearUpdatedKeys();
1397
+ }
1398
+ };
1399
+
1400
+ // src/core/OIMReactiveObject.ts
1401
+ var OIMReactiveObject = class extends OIMObject {
1402
+ constructor(queue, opts) {
1403
+ super(opts);
1404
+ this.coalescer = new OIMUpdateEventCoalescerObject(this.emitter);
1405
+ this.updateEventEmitter = new OIMUpdateEventEmitter({
1406
+ coalescer: this.coalescer,
1407
+ queue
1408
+ });
1409
+ }
1410
+ destroy() {
1411
+ this.updateEventEmitter.destroy();
1412
+ this.coalescer.destroy();
1413
+ super.destroy();
1414
+ }
1080
1415
  };
1081
1416
 
1082
1417
  // src/core/OIMReactiveIndexManualSetBased.ts
@@ -1207,6 +1542,53 @@ var OIMRICollection = class extends OIMReactiveCollection {
1207
1542
  }
1208
1543
  };
1209
1544
 
1545
+ // src/core/OIMObjectStoreMapDriven.ts
1546
+ var OIMObjectStoreMapDriven = class extends OIMObjectStore {
1547
+ constructor() {
1548
+ super(...arguments);
1549
+ this.properties = /* @__PURE__ */ new Map();
1550
+ }
1551
+ setProperty(key, value) {
1552
+ this.properties.set(key, value);
1553
+ }
1554
+ merge(draft) {
1555
+ for (const key in draft) {
1556
+ if (!Object.prototype.hasOwnProperty.call(draft, key)) continue;
1557
+ this.properties.set(
1558
+ key,
1559
+ draft[key]
1560
+ );
1561
+ }
1562
+ }
1563
+ delete(key) {
1564
+ this.properties.delete(key);
1565
+ }
1566
+ get(key) {
1567
+ return this.properties.get(key);
1568
+ }
1569
+ getAll() {
1570
+ return Object.fromEntries(this.properties.entries());
1571
+ }
1572
+ clear() {
1573
+ this.properties.clear();
1574
+ }
1575
+ count() {
1576
+ return this.properties.size;
1577
+ }
1578
+ keys() {
1579
+ return Array.from(this.properties.keys());
1580
+ }
1581
+ values() {
1582
+ return Array.from(this.properties.values());
1583
+ }
1584
+ entries() {
1585
+ return Array.from(this.properties.entries());
1586
+ }
1587
+ destroy() {
1588
+ this.properties.clear();
1589
+ }
1590
+ };
1591
+
1210
1592
  // src/core/OIMComparatorFactory.ts
1211
1593
  var OIMComparatorFactory = class {
1212
1594
  createShallowComparator() {
@@ -1237,6 +1619,8 @@ var OIMEventQueue = class {
1237
1619
  constructor(options = {}) {
1238
1620
  this.emitter = new OIMEventEmitter();
1239
1621
  this.queue = [];
1622
+ this.isFlushing = false;
1623
+ this.pendingSchedule = false;
1240
1624
  this.scheduler = options.scheduler;
1241
1625
  if (this.scheduler) {
1242
1626
  this.flushBound = () => this.flush();
@@ -1252,7 +1636,12 @@ var OIMEventQueue = class {
1252
1636
  */
1253
1637
  enqueue(fn) {
1254
1638
  this.queue.push(fn);
1255
- if (this.scheduler && this.queue.length === 1) {
1639
+ if (!this.scheduler) return;
1640
+ if (this.isFlushing) {
1641
+ this.pendingSchedule = true;
1642
+ return;
1643
+ }
1644
+ if (this.queue.length === 1) {
1256
1645
  this.scheduler.schedule();
1257
1646
  }
1258
1647
  }
@@ -1262,6 +1651,8 @@ var OIMEventQueue = class {
1262
1651
  */
1263
1652
  flush() {
1264
1653
  if (this.queue.length === 0) return;
1654
+ this.scheduler?.cancel();
1655
+ this.isFlushing = true;
1265
1656
  this.emitter.emit(1 /* BEFORE_FLUSH */, void 0);
1266
1657
  const currentQueue = this.queue.slice();
1267
1658
  this.queue.length = 0;
@@ -1269,6 +1660,13 @@ var OIMEventQueue = class {
1269
1660
  currentQueue[i]();
1270
1661
  }
1271
1662
  this.emitter.emit(0 /* AFTER_FLUSH */, void 0);
1663
+ this.isFlushing = false;
1664
+ if (this.scheduler && this.pendingSchedule && this.queue.length > 0) {
1665
+ this.pendingSchedule = false;
1666
+ this.scheduler.schedule();
1667
+ } else {
1668
+ this.pendingSchedule = false;
1669
+ }
1272
1670
  }
1273
1671
  /**
1274
1672
  * Get the current number of queued functions.
@@ -1336,7 +1734,7 @@ var OIMIndexComparatorFactory = class {
1336
1734
  if (existingSet.size !== newSet.size || existingSet.size !== existingPks.length) {
1337
1735
  return false;
1338
1736
  }
1339
- for (const pk of existingSet) {
1737
+ for (const pk of Array.from(existingSet)) {
1340
1738
  if (!newSet.has(pk)) {
1341
1739
  return false;
1342
1740
  }
@@ -1402,6 +1800,270 @@ var OIMMap2Keys = class {
1402
1800
  }
1403
1801
  };
1404
1802
 
1803
+ // src/modules/wrapper/OIMUpdateEventCoalescerManual.ts
1804
+ var OIMUpdateEventCoalescerManual = class extends OIMUpdateEventCoalescer {
1805
+ markUpdatedKeys(keys) {
1806
+ if (keys.length === 0) return;
1807
+ this.addUpdatedKeys(keys);
1808
+ }
1809
+ destroy() {
1810
+ this.emitter.offAll();
1811
+ this.updatedKeysIndex.destroy();
1812
+ this.flushingUpdatedKeysIndex.destroy();
1813
+ }
1814
+ };
1815
+
1816
+ // src/modules/wrapper/collection/OIMCollectionChangedFieldsWrapper.ts
1817
+ var OIMCollectionChangedFieldsWrapper = class {
1818
+ constructor(queue, collection, opts) {
1819
+ this.changedFieldsByPk = /* @__PURE__ */ new Map();
1820
+ this.changedPksByField = /* @__PURE__ */ new Map();
1821
+ this.collection = collection;
1822
+ this.selectPk = opts?.selectPk ?? (() => {
1823
+ throw new Error(
1824
+ `[OIMCollectionChangedFieldsWrapper]: selectPk was not provided. Use upsertOneByPk(...) or pass opts.selectPk.`
1825
+ );
1826
+ });
1827
+ this.changedPksCoalescer = new OIMUpdateEventCoalescerManual();
1828
+ this.changedPksEventEmitter = new OIMUpdateEventEmitter({
1829
+ coalescer: this.changedPksCoalescer,
1830
+ queue
1831
+ });
1832
+ this.changedFieldsCoalescer = new OIMUpdateEventCoalescerManual();
1833
+ this.changedFieldsEventEmitter = new OIMUpdateEventEmitter({
1834
+ coalescer: this.changedFieldsCoalescer,
1835
+ queue
1836
+ });
1837
+ }
1838
+ upsertOneByPk(pk, patch) {
1839
+ this.trackPatch(pk, patch);
1840
+ this.collection.upsertOneByPk(pk, patch);
1841
+ }
1842
+ upsertOne(entity) {
1843
+ const pk = this.selectPk(entity);
1844
+ this.trackPatch(pk, entity);
1845
+ this.collection.upsertOne(entity);
1846
+ }
1847
+ upsertMany(entities) {
1848
+ for (const entity of entities) {
1849
+ const pk = this.selectPk(entity);
1850
+ this.trackPatch(pk, entity);
1851
+ }
1852
+ this.collection.upsertMany(entities);
1853
+ }
1854
+ getChangedFieldsByPk(pk) {
1855
+ return this.changedFieldsByPk.get(pk) ?? /* @__PURE__ */ new Set();
1856
+ }
1857
+ consumeChangedFieldsByPk(pk) {
1858
+ const existing = this.changedFieldsByPk.get(pk);
1859
+ if (!existing) return /* @__PURE__ */ new Set();
1860
+ this.changedFieldsByPk.delete(pk);
1861
+ return existing;
1862
+ }
1863
+ getChangedPksByField(field) {
1864
+ return this.changedPksByField.get(field) ?? /* @__PURE__ */ new Set();
1865
+ }
1866
+ consumeChangedPksByField(field) {
1867
+ const existing = this.changedPksByField.get(field);
1868
+ if (!existing) return /* @__PURE__ */ new Set();
1869
+ this.changedPksByField.delete(field);
1870
+ return existing;
1871
+ }
1872
+ clear() {
1873
+ this.changedFieldsByPk.clear();
1874
+ this.changedPksByField.clear();
1875
+ }
1876
+ destroy() {
1877
+ this.changedPksEventEmitter.destroy();
1878
+ this.changedFieldsEventEmitter.destroy();
1879
+ this.changedPksCoalescer.destroy();
1880
+ this.changedFieldsCoalescer.destroy();
1881
+ this.clear();
1882
+ }
1883
+ trackPatch(pk, patch) {
1884
+ if (pk === void 0 || pk === null || pk === "") {
1885
+ throw new Error(
1886
+ `[OIMCollectionChangedFieldsWrapper]: PK is required to track changes.`
1887
+ );
1888
+ }
1889
+ const keys = Object.keys(patch);
1890
+ if (keys.length === 0) return;
1891
+ let pkFields = this.changedFieldsByPk.get(pk);
1892
+ if (!pkFields) {
1893
+ pkFields = /* @__PURE__ */ new Set();
1894
+ this.changedFieldsByPk.set(pk, pkFields);
1895
+ }
1896
+ for (const key of keys) {
1897
+ pkFields.add(key);
1898
+ let fieldPks = this.changedPksByField.get(key);
1899
+ if (!fieldPks) {
1900
+ fieldPks = /* @__PURE__ */ new Set();
1901
+ this.changedPksByField.set(key, fieldPks);
1902
+ }
1903
+ fieldPks.add(pk);
1904
+ }
1905
+ this.changedPksCoalescer.markUpdatedKeys([pk]);
1906
+ this.changedFieldsCoalescer.markUpdatedKeys(keys);
1907
+ }
1908
+ };
1909
+
1910
+ // src/modules/wrapper/index/OIMIndexManualOrderedArrayBased.ts
1911
+ var OIMIndexManualOrderedArrayBased = class extends OIMIndexArrayBased {
1912
+ clear(key) {
1913
+ if (key === void 0) {
1914
+ const keys = this.getKeys();
1915
+ if (keys.length > 0) {
1916
+ this.store.clear();
1917
+ this.emitUpdate(Array.from(keys));
1918
+ }
1919
+ return;
1920
+ }
1921
+ if (this.store.getOneByKey(key) !== void 0) {
1922
+ this.store.removeOneByKey(key);
1923
+ this.emitUpdate([key]);
1924
+ }
1925
+ }
1926
+ push(key, itemKey) {
1927
+ const list = this.getOrCreateList(key);
1928
+ const index = list.length;
1929
+ list.push(itemKey);
1930
+ this.emitUpdate([key]);
1931
+ return index;
1932
+ }
1933
+ insertAt(key, index, itemKey) {
1934
+ const list = this.getOrCreateList(key);
1935
+ const safeIndex = Math.max(0, Math.min(index, list.length));
1936
+ list.splice(safeIndex, 0, itemKey);
1937
+ this.emitUpdate([key]);
1938
+ }
1939
+ removeAt(key, index) {
1940
+ const list = this.store.getOneByKey(key);
1941
+ if (!list) return void 0;
1942
+ if (index < 0 || index >= list.length) return void 0;
1943
+ const [removed] = list.splice(index, 1);
1944
+ if (list.length === 0) {
1945
+ this.store.removeOneByKey(key);
1946
+ }
1947
+ this.emitUpdate([key]);
1948
+ return removed;
1949
+ }
1950
+ move(key, fromIndex, toIndex) {
1951
+ const list = this.store.getOneByKey(key);
1952
+ if (!list) return void 0;
1953
+ if (fromIndex < 0 || fromIndex >= list.length) return void 0;
1954
+ if (toIndex < 0 || toIndex >= list.length) return void 0;
1955
+ if (fromIndex === toIndex) return list[fromIndex];
1956
+ const [itemKey] = list.splice(fromIndex, 1);
1957
+ if (itemKey === void 0) return void 0;
1958
+ list.splice(toIndex, 0, itemKey);
1959
+ this.emitUpdate([key]);
1960
+ return itemKey;
1961
+ }
1962
+ reset(key, itemKeys) {
1963
+ if (itemKeys.length === 0) {
1964
+ if (this.store.getOneByKey(key) !== void 0) {
1965
+ this.store.removeOneByKey(key);
1966
+ this.emitUpdate([key]);
1967
+ }
1968
+ return;
1969
+ }
1970
+ this.store.setOneByKey(key, Array.from(itemKeys));
1971
+ this.emitUpdate([key]);
1972
+ }
1973
+ getOrCreateList(key) {
1974
+ let list = this.store.getOneByKey(key);
1975
+ if (!list) {
1976
+ list = [];
1977
+ this.store.setOneByKey(key, list);
1978
+ }
1979
+ return list;
1980
+ }
1981
+ };
1982
+
1983
+ // src/modules/wrapper/index/OIMOrderedListIndexCommandStreamWrapper.ts
1984
+ var OIMOrderedListIndexCommandStreamWrapper = class {
1985
+ constructor(queue, index) {
1986
+ this.commandsByKey = /* @__PURE__ */ new Map();
1987
+ this.coalescer = new OIMUpdateEventCoalescerManual();
1988
+ this.commandsEventEmitter = new OIMUpdateEventEmitter({
1989
+ coalescer: this.coalescer,
1990
+ queue
1991
+ });
1992
+ this.index = index ?? new OIMIndexManualOrderedArrayBased();
1993
+ }
1994
+ getPksByKey(key) {
1995
+ return this.index.getPksByKey(key);
1996
+ }
1997
+ hasKey(key) {
1998
+ return this.index.hasKey(key);
1999
+ }
2000
+ getKeys() {
2001
+ return this.index.getKeys();
2002
+ }
2003
+ push(key, itemKey) {
2004
+ const index = this.index.push(key, itemKey);
2005
+ this.appendCommand(key, { type: "add", key: itemKey, index });
2006
+ }
2007
+ removeAt(key, index) {
2008
+ const itemKey = this.index.removeAt(key, index);
2009
+ if (itemKey === void 0) return;
2010
+ this.appendCommand(key, { type: "remove", key: itemKey, index });
2011
+ }
2012
+ move(key, fromIndex, toIndex) {
2013
+ const itemKey = this.index.move(key, fromIndex, toIndex);
2014
+ if (itemKey === void 0) return;
2015
+ this.appendCommand(key, {
2016
+ type: "move",
2017
+ key: itemKey,
2018
+ fromIndex,
2019
+ toIndex
2020
+ });
2021
+ }
2022
+ reset(key, keys) {
2023
+ this.index.reset(key, keys);
2024
+ this.appendCommand(key, { type: "reset", keys });
2025
+ }
2026
+ /**
2027
+ * Read-only peek at buffered commands without clearing them.
2028
+ */
2029
+ getBufferedCommands(key) {
2030
+ return this.commandsByKey.get(key) ?? [];
2031
+ }
2032
+ /**
2033
+ * Drain buffered commands for a key, preserving order.
2034
+ * Intended usage: call inside a `commandsEventEmitter.subscribeOnKey(key, ...)` handler.
2035
+ */
2036
+ consumeCommands(key) {
2037
+ const cmds = this.commandsByKey.get(key);
2038
+ if (!cmds || cmds.length === 0) return [];
2039
+ this.commandsByKey.delete(key);
2040
+ return cmds;
2041
+ }
2042
+ clear(key) {
2043
+ if (key === void 0) {
2044
+ this.index.destroy();
2045
+ this.commandsByKey.clear();
2046
+ return;
2047
+ }
2048
+ this.index.clear(key);
2049
+ this.commandsByKey.delete(key);
2050
+ }
2051
+ destroy() {
2052
+ this.commandsEventEmitter.destroy();
2053
+ this.coalescer.destroy();
2054
+ this.clear();
2055
+ }
2056
+ appendCommand(key, cmd) {
2057
+ let cmds = this.commandsByKey.get(key);
2058
+ if (!cmds) {
2059
+ cmds = [];
2060
+ this.commandsByKey.set(key, cmds);
2061
+ }
2062
+ cmds.push(cmd);
2063
+ this.coalescer.markUpdatedKeys([key]);
2064
+ }
2065
+ };
2066
+
1405
2067
  // src/core/event-queue-scheduler/OIMEventQueueSchedulerAnimationFrame.ts
1406
2068
  var OIMEventQueueSchedulerAnimationFrame = class extends OIMEventQueueScheduler {
1407
2069
  constructor() {
@@ -1570,18 +2232,311 @@ var OIMEventQueueSchedulerFactory = class {
1570
2232
  return new OIMEventQueueSchedulerImmediate();
1571
2233
  }
1572
2234
  };
2235
+
2236
+ // src/modules/effect/core/OIMEffect.ts
2237
+ var OIMEffect = class {
2238
+ constructor(queue, opts) {
2239
+ this.unsubscribers = [];
2240
+ this.isDestroyed = false;
2241
+ this.isInFlush = false;
2242
+ this.hasRunInThisFlush = false;
2243
+ this.isScheduled = false;
2244
+ this.handleQueueBeforeFlush = () => {
2245
+ this.isInFlush = true;
2246
+ this.hasRunInThisFlush = false;
2247
+ };
2248
+ this.handleQueueAfterFlush = () => {
2249
+ this.isInFlush = false;
2250
+ this.hasRunInThisFlush = false;
2251
+ };
2252
+ this.runTask = () => {
2253
+ this.isScheduled = false;
2254
+ if (this.isDestroyed) return;
2255
+ this.runOnce();
2256
+ };
2257
+ this.invalidate = () => {
2258
+ if (this.isDestroyed) return;
2259
+ this.onInvalidate?.();
2260
+ if (this.isInFlush) {
2261
+ if (this.hasRunInThisFlush) return;
2262
+ this.hasRunInThisFlush = true;
2263
+ this.runOnce();
2264
+ return;
2265
+ }
2266
+ if (this.isScheduled) return;
2267
+ this.isScheduled = true;
2268
+ this.queue.enqueue(this.runTask);
2269
+ };
2270
+ this.queue = queue;
2271
+ this.phase = opts.phase;
2272
+ this.onInvalidate = opts.onInvalidate;
2273
+ this.run = opts.run;
2274
+ this.deps = opts.deps ?? [];
2275
+ this.queue.emitter.on(
2276
+ 1 /* BEFORE_FLUSH */,
2277
+ this.handleQueueBeforeFlush
2278
+ );
2279
+ this.queue.emitter.on(
2280
+ 0 /* AFTER_FLUSH */,
2281
+ this.handleQueueAfterFlush
2282
+ );
2283
+ for (const dep of this.deps) {
2284
+ this.unsubscribers.push(dep.subscribe(this.phase, this.invalidate));
2285
+ }
2286
+ }
2287
+ destroy() {
2288
+ if (this.isDestroyed) return;
2289
+ this.isDestroyed = true;
2290
+ for (const unsubscribe of this.unsubscribers) unsubscribe();
2291
+ this.unsubscribers = [];
2292
+ this.queue.emitter.off(
2293
+ 1 /* BEFORE_FLUSH */,
2294
+ this.handleQueueBeforeFlush
2295
+ );
2296
+ this.queue.emitter.off(
2297
+ 0 /* AFTER_FLUSH */,
2298
+ this.handleQueueAfterFlush
2299
+ );
2300
+ }
2301
+ runOnce() {
2302
+ if (this.isDestroyed) return;
2303
+ this.run();
2304
+ }
2305
+ };
2306
+
2307
+ // src/modules/effect/enum/EOIMEffectPhase.ts
2308
+ var EOIMEffectPhase = /* @__PURE__ */ ((EOIMEffectPhase2) => {
2309
+ EOIMEffectPhase2["PRE"] = "pre";
2310
+ EOIMEffectPhase2["HANDLERS"] = "handlers";
2311
+ return EOIMEffectPhase2;
2312
+ })(EOIMEffectPhase || {});
2313
+
2314
+ // src/modules/computed/enum/EOIMComputedEventType.ts
2315
+ var EOIMComputedEventType = /* @__PURE__ */ ((EOIMComputedEventType2) => {
2316
+ EOIMComputedEventType2["UPDATE"] = "update";
2317
+ return EOIMComputedEventType2;
2318
+ })(EOIMComputedEventType || {});
2319
+
2320
+ // src/modules/computed/core/OIMUpdateEventCoalescerComputed.ts
2321
+ var OIMUpdateEventCoalescerComputed = class extends OIMUpdateEventCoalescer {
2322
+ constructor(computedEmitter) {
2323
+ super();
2324
+ this.computedEmitter = computedEmitter;
2325
+ this.handleUpdate = (payload) => {
2326
+ this.addUpdatedKeys(payload.keys);
2327
+ };
2328
+ this.computedEmitter.on(
2329
+ "update" /* UPDATE */,
2330
+ this.handleUpdate
2331
+ );
2332
+ }
2333
+ destroy() {
2334
+ this.computedEmitter.off(
2335
+ "update" /* UPDATE */,
2336
+ this.handleUpdate
2337
+ );
2338
+ this.emitter.offAll();
2339
+ this.clearUpdatedKeys();
2340
+ }
2341
+ };
2342
+
2343
+ // src/modules/computed/core/OIMComputed.ts
2344
+ var OIMComputed = class {
2345
+ constructor(queue, opts) {
2346
+ this.emitter = new OIMEventEmitter();
2347
+ this.hasValue = false;
2348
+ this.isDirty = true;
2349
+ this.isInFlush = false;
2350
+ this.hasRecomputedInThisFlush = false;
2351
+ this.handleQueueBeforeFlush = () => {
2352
+ this.isInFlush = true;
2353
+ this.hasRecomputedInThisFlush = false;
2354
+ };
2355
+ this.handleQueueAfterFlush = () => {
2356
+ this.isInFlush = false;
2357
+ this.hasRecomputedInThisFlush = false;
2358
+ };
2359
+ this.queue = queue;
2360
+ this.compute = opts.compute;
2361
+ this.compare = opts.compare ?? Object.is;
2362
+ this.deps = opts.deps ?? [];
2363
+ this.coalescer = new OIMUpdateEventCoalescerComputed(
2364
+ this.emitter
2365
+ );
2366
+ this.updateEventEmitter = new OIMUpdateEventEmitter({
2367
+ coalescer: this.coalescer,
2368
+ queue: this.queue
2369
+ });
2370
+ this.queue.emitter.on(
2371
+ 1 /* BEFORE_FLUSH */,
2372
+ this.handleQueueBeforeFlush
2373
+ );
2374
+ this.queue.emitter.on(
2375
+ 0 /* AFTER_FLUSH */,
2376
+ this.handleQueueAfterFlush
2377
+ );
2378
+ this.effect = new OIMEffect(this.queue, {
2379
+ deps: this.deps,
2380
+ phase: "pre" /* PRE */,
2381
+ onInvalidate: () => {
2382
+ this.isDirty = true;
2383
+ },
2384
+ run: () => {
2385
+ if (this.isInFlush) {
2386
+ if (this.hasRecomputedInThisFlush) return;
2387
+ this.hasRecomputedInThisFlush = true;
2388
+ }
2389
+ this.recomputeAndEmitIfChanged();
2390
+ }
2391
+ });
2392
+ }
2393
+ get() {
2394
+ this.recomputeAndEmitIfChanged();
2395
+ return this.value;
2396
+ }
2397
+ getIfReady() {
2398
+ return this.hasValue ? this.value : void 0;
2399
+ }
2400
+ destroy() {
2401
+ this.effect.destroy();
2402
+ this.queue.emitter.off(
2403
+ 1 /* BEFORE_FLUSH */,
2404
+ this.handleQueueBeforeFlush
2405
+ );
2406
+ this.queue.emitter.off(
2407
+ 0 /* AFTER_FLUSH */,
2408
+ this.handleQueueAfterFlush
2409
+ );
2410
+ this.updateEventEmitter.destroy();
2411
+ this.coalescer.destroy();
2412
+ this.emitter.offAll();
2413
+ }
2414
+ recomputeAndEmitIfChanged() {
2415
+ if (!this.isDirty) return;
2416
+ const prev = this.value;
2417
+ const hadPrev = this.hasValue;
2418
+ const next = this.compute();
2419
+ this.value = next;
2420
+ this.hasValue = true;
2421
+ this.isDirty = false;
2422
+ const changed = !hadPrev || !this.compare(prev, next);
2423
+ if (!changed) return;
2424
+ this.emitter.emit("update" /* UPDATE */, {
2425
+ keys: ["value"]
2426
+ });
2427
+ }
2428
+ };
2429
+
2430
+ // src/modules/effect/core/OIMEffectDependencyKeyed.ts
2431
+ function isReadonlyArray(value) {
2432
+ return Array.isArray(value);
2433
+ }
2434
+ var OIMEffectDependencyKeyed = class {
2435
+ constructor(updateEventEmitter, keyOrKeys) {
2436
+ this.updateEventEmitter = updateEventEmitter;
2437
+ if (isReadonlyArray(keyOrKeys)) {
2438
+ this.keys = keyOrKeys;
2439
+ } else {
2440
+ this.key = keyOrKeys;
2441
+ }
2442
+ }
2443
+ subscribe(phase, onInvalidate) {
2444
+ const isPre = phase === "pre" /* PRE */;
2445
+ if (this.keys !== void 0) {
2446
+ return isPre ? this.updateEventEmitter.subscribeOnKeysBeforeFlush(
2447
+ this.keys,
2448
+ onInvalidate
2449
+ ) : this.updateEventEmitter.subscribeOnKeys(
2450
+ this.keys,
2451
+ onInvalidate
2452
+ );
2453
+ }
2454
+ if (this.key === void 0) return () => {
2455
+ };
2456
+ return isPre ? this.updateEventEmitter.subscribeOnKeyBeforeFlush(
2457
+ this.key,
2458
+ onInvalidate
2459
+ ) : this.updateEventEmitter.subscribeOnKey(this.key, onInvalidate);
2460
+ }
2461
+ };
2462
+
2463
+ // src/modules/effect/core/OIMEffectDependencyKeyedObject.ts
2464
+ var OIMEffectDependencyKeyedObject = class {
2465
+ constructor(object, keyOrKeys) {
2466
+ this.dep = new OIMEffectDependencyKeyed(
2467
+ object.updateEventEmitter,
2468
+ keyOrKeys
2469
+ );
2470
+ }
2471
+ subscribe(phase, onInvalidate) {
2472
+ return this.dep.subscribe(phase, onInvalidate);
2473
+ }
2474
+ };
2475
+
2476
+ // src/modules/effect/core/OIMEffectDependencyKeyedCollection.ts
2477
+ var OIMEffectDependencyKeyedCollection = class {
2478
+ constructor(collection, pkOrPks) {
2479
+ this.dep = new OIMEffectDependencyKeyed(
2480
+ collection.updateEventEmitter,
2481
+ pkOrPks
2482
+ );
2483
+ }
2484
+ subscribe(phase, onInvalidate) {
2485
+ return this.dep.subscribe(phase, onInvalidate);
2486
+ }
2487
+ };
2488
+
2489
+ // src/modules/effect/core/OIMEffectDependencyKeyedIndex.ts
2490
+ var OIMEffectDependencyKeyedIndex = class {
2491
+ constructor(index, keyOrKeys) {
2492
+ this.dep = new OIMEffectDependencyKeyed(
2493
+ index.updateEventEmitter,
2494
+ keyOrKeys
2495
+ );
2496
+ }
2497
+ subscribe(phase, onInvalidate) {
2498
+ return this.dep.subscribe(phase, onInvalidate);
2499
+ }
2500
+ };
2501
+
2502
+ // src/modules/effect/core/OIMEffectDependencyComputed.ts
2503
+ var OIMEffectDependencyComputed = class {
2504
+ constructor(computed) {
2505
+ this.computed = computed;
2506
+ }
2507
+ subscribe(phase, onInvalidate) {
2508
+ if (phase === "pre" /* PRE */) {
2509
+ return this.computed.emitter.on("update", onInvalidate);
2510
+ }
2511
+ return this.computed.updateEventEmitter.subscribeOnKey(
2512
+ "value",
2513
+ onInvalidate
2514
+ );
2515
+ }
2516
+ };
1573
2517
  // Annotate the CommonJS export names for ESM import in node:
1574
2518
  0 && (module.exports = {
1575
2519
  EOIMCollectionEventType,
2520
+ EOIMComputedEventType,
2521
+ EOIMEffectPhase,
1576
2522
  EOIMEventQueueEventType,
1577
2523
  EOIMEventQueueSchedulerEventType,
1578
2524
  EOIMIndexEventType,
2525
+ EOIMObjectEventType,
1579
2526
  EOIMUpdateEventCoalescerEventType,
1580
2527
  OIMCollection,
2528
+ OIMCollectionChangedFieldsWrapper,
1581
2529
  OIMCollectionStore,
1582
2530
  OIMCollectionStoreMapDriven,
1583
2531
  OIMComparatorFactory,
2532
+ OIMComputed,
1584
2533
  OIMDBSettings,
2534
+ OIMEffect,
2535
+ OIMEffectDependencyComputed,
2536
+ OIMEffectDependencyKeyed,
2537
+ OIMEffectDependencyKeyedCollection,
2538
+ OIMEffectDependencyKeyedIndex,
2539
+ OIMEffectDependencyKeyedObject,
1585
2540
  OIMEntityUpdaterFactory,
1586
2541
  OIMEventEmitter,
1587
2542
  OIMEventQueue,
@@ -1594,6 +2549,7 @@ var OIMEventQueueSchedulerFactory = class {
1594
2549
  OIMIndexArrayBased,
1595
2550
  OIMIndexComparatorFactory,
1596
2551
  OIMIndexManualArrayBased,
2552
+ OIMIndexManualOrderedArrayBased,
1597
2553
  OIMIndexManualSetBased,
1598
2554
  OIMIndexSetBased,
1599
2555
  OIMIndexStoreArrayBased,
@@ -1601,6 +2557,11 @@ var OIMEventQueueSchedulerFactory = class {
1601
2557
  OIMIndexStoreMapDrivenSetBased,
1602
2558
  OIMIndexStoreSetBased,
1603
2559
  OIMMap2Keys,
2560
+ OIMObject,
2561
+ OIMObjectStore,
2562
+ OIMObjectStoreMapDriven,
2563
+ OIMObjectStoreRecordDriven,
2564
+ OIMOrderedListIndexCommandStreamWrapper,
1604
2565
  OIMPkSelectorFactory,
1605
2566
  OIMRICollection,
1606
2567
  OIMReactiveCollection,
@@ -1608,8 +2569,12 @@ var OIMEventQueueSchedulerFactory = class {
1608
2569
  OIMReactiveIndexManualArrayBased,
1609
2570
  OIMReactiveIndexManualSetBased,
1610
2571
  OIMReactiveIndexSetBased,
2572
+ OIMReactiveObject,
1611
2573
  OIMUpdateEventCoalescer,
1612
2574
  OIMUpdateEventCoalescerCollection,
2575
+ OIMUpdateEventCoalescerComputed,
1613
2576
  OIMUpdateEventCoalescerIndex,
2577
+ OIMUpdateEventCoalescerManual,
2578
+ OIMUpdateEventCoalescerObject,
1614
2579
  OIMUpdateEventEmitter
1615
2580
  });