@oimdb/core 1.3.0 → 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,35 +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)) return;
140
+ if (bucket.indexByHandler.has(handler)) {
141
+ return () => {
142
+ this.off(event, handler);
143
+ };
144
+ }
122
145
  const index = bucket.handlers.length;
123
146
  bucket.handlers.push(handler);
124
147
  bucket.indexByHandler.set(handler, index);
148
+ return () => {
149
+ this.off(event, handler);
150
+ };
125
151
  }
126
152
  emit(event, payload) {
127
153
  const bucket = this.buckets[event];
@@ -136,10 +162,11 @@ var OIMEventEmitter = class {
136
162
  }
137
163
  bucket.isEmitting--;
138
164
  if (bucket.isEmitting === 0 && bucket.tombstoneCount > 0) {
139
- if (bucket.tombstoneCount >= length >> 1) {
140
- this.compactBucket(bucket);
141
- } else if (length === bucket.tombstoneCount) {
165
+ const currentLength = bucket.handlers.length;
166
+ if (bucket.tombstoneCount === currentLength) {
142
167
  delete this.buckets[event];
168
+ } else if (bucket.tombstoneCount >= currentLength >> 1) {
169
+ this.compactBucket(bucket);
143
170
  }
144
171
  }
145
172
  }
@@ -153,10 +180,10 @@ var OIMEventEmitter = class {
153
180
  bucket.indexByHandler.delete(handler);
154
181
  if (bucket.isEmitting === 0) {
155
182
  const length = bucket.handlers.length;
156
- if (bucket.tombstoneCount >= length >> 1) {
157
- this.compactBucket(bucket);
158
- } else if (length === bucket.tombstoneCount) {
183
+ if (bucket.tombstoneCount === length) {
159
184
  delete this.buckets[event];
185
+ } else if (bucket.tombstoneCount >= length >> 1) {
186
+ this.compactBucket(bucket);
160
187
  }
161
188
  }
162
189
  }
@@ -518,34 +545,50 @@ var EOIMUpdateEventCoalescerEventType = /* @__PURE__ */ ((EOIMUpdateEventCoalesc
518
545
  // src/core/OIMUpdateEventEmitter.ts
519
546
  var OIMUpdateEventEmitter = class {
520
547
  constructor(opts) {
548
+ this.keyHandlersBeforeFlush = /* @__PURE__ */ new Map();
521
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;
522
555
  this.handleHasChanges = () => {
523
- this.queue.enqueue(() => {
524
- const updatedKeys = this.coalescer.getUpdatedKeys();
525
- if (this.keyHandlers.size === 0) {
526
- this.coalescer.clearUpdatedKeys();
527
- return;
528
- }
529
- if (updatedKeys.size * 2 < this.keyHandlers.size) {
530
- for (const key of updatedKeys.values()) {
531
- const handlers = this.keyHandlers.get(key);
532
- if (handlers) {
533
- for (const handler of handlers) {
534
- handler();
535
- }
536
- }
537
- }
538
- } else {
539
- for (const [key, handlers] of this.keyHandlers) {
540
- if (updatedKeys.has(key)) {
541
- for (const handler of handlers) {
542
- handler();
543
- }
544
- }
545
- }
546
- }
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) {
547
568
  this.coalescer.clearUpdatedKeys();
548
- });
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
+ }
549
592
  };
550
593
  this.coalescer = opts.coalescer;
551
594
  this.coalescer.emitter.on(
@@ -554,11 +597,90 @@ var OIMUpdateEventEmitter = class {
554
597
  );
555
598
  this.queue = opts.queue;
556
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
+ }
557
676
  destroy() {
677
+ if (this.isDestroyed) return;
678
+ this.isDestroyed = true;
558
679
  this.coalescer.emitter.off(
559
680
  0 /* HAS_CHANGES */,
560
681
  this.handleHasChanges
561
682
  );
683
+ this.keyHandlersBeforeFlush.clear();
562
684
  this.keyHandlers.clear();
563
685
  }
564
686
  /**
@@ -566,9 +688,9 @@ var OIMUpdateEventEmitter = class {
566
688
  */
567
689
  getMetrics() {
568
690
  let totalHandlers = 0;
569
- for (const handlers of this.keyHandlers.values()) {
691
+ this.keyHandlers.forEach((handlers) => {
570
692
  totalHandlers += handlers.size;
571
- }
693
+ });
572
694
  return {
573
695
  totalKeys: this.keyHandlers.size,
574
696
  totalHandlers,
@@ -580,13 +702,32 @@ var OIMUpdateEventEmitter = class {
580
702
  * Check if there are any active subscriptions
581
703
  */
582
704
  hasSubscriptions() {
583
- return this.keyHandlers.size > 0;
705
+ return this.keyHandlers.size > 0 || this.keyHandlersBeforeFlush.size > 0;
584
706
  }
585
707
  /**
586
708
  * Get the number of handlers for a specific key
587
709
  */
588
710
  getHandlerCount(key) {
589
- 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
+ }
590
731
  }
591
732
  subscribeOnKey(key, handler) {
592
733
  let handlers = this.keyHandlers.get(key);
@@ -626,6 +767,30 @@ var OIMUpdateEventEmitter = class {
626
767
  }
627
768
  };
628
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
+ }
629
794
  unsubscribeFromKeys(keys, handler) {
630
795
  for (const key of keys) {
631
796
  this.unsubscribeFromKey(key, handler);
@@ -720,15 +885,19 @@ var OIMDBSettings = class {
720
885
  * This constant is exported so users can create their own indexes and pass them to coalescers.
721
886
  */
722
887
  OIMDBSettings.UPDATED_KEYS_INDEX_KEY = "__updatedKeys__";
888
+ OIMDBSettings.FLUSHING_KEYS_INDEX_KEY = "__flushingKeys__";
723
889
 
724
890
  // src/core/OIMUpdateEventCoalescer.ts
725
891
  var OIMUpdateEventCoalescer = class {
726
- constructor(index) {
892
+ constructor(index, flushingIndex) {
727
893
  this.emitter = new OIMEventEmitter();
728
894
  this.hasEmittedChanges = false;
729
895
  this.updatedKeysIndex = index ?? new OIMIndexManualSetBased({
730
896
  store: new OIMIndexStoreMapDrivenSetBased()
731
897
  });
898
+ this.flushingUpdatedKeysIndex = flushingIndex ?? new OIMIndexManualSetBased({
899
+ store: new OIMIndexStoreMapDrivenSetBased()
900
+ });
732
901
  if (!this.updatedKeysIndex.hasKey(OIMDBSettings.UPDATED_KEYS_INDEX_KEY)) {
733
902
  this.updatedKeysIndex.setPks(
734
903
  OIMDBSettings.UPDATED_KEYS_INDEX_KEY,
@@ -744,6 +913,18 @@ var OIMUpdateEventCoalescer = class {
744
913
  OIMDBSettings.UPDATED_KEYS_INDEX_KEY
745
914
  );
746
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
+ }
747
928
  /**
748
929
  * Clear all updated keys and reset the changed state
749
930
  */
@@ -759,6 +940,12 @@ var OIMUpdateEventCoalescer = class {
759
940
  void 0
760
941
  );
761
942
  }
943
+ clearFlushingUpdatedKeys() {
944
+ this.flushingUpdatedKeysIndex.setPks(
945
+ OIMDBSettings.FLUSHING_KEYS_INDEX_KEY,
946
+ []
947
+ );
948
+ }
762
949
  /**
763
950
  * Add keys to the updated set and emit HAS_CHANGES event if needed
764
951
  */
@@ -834,6 +1021,8 @@ var OIMReactiveIndexSetBased = class {
834
1021
  return this.index.getMetrics();
835
1022
  }
836
1023
  destroy() {
1024
+ this.updateEventEmitter.destroy();
1025
+ this.coalescer.destroy();
837
1026
  this.index.destroy();
838
1027
  }
839
1028
  };
@@ -875,10 +1064,16 @@ var OIMReactiveIndexArrayBased = class {
875
1064
  return this.index.getMetrics();
876
1065
  }
877
1066
  destroy() {
1067
+ this.updateEventEmitter.destroy();
1068
+ this.coalescer.destroy();
878
1069
  this.index.destroy();
879
1070
  }
880
1071
  };
881
1072
 
1073
+ // src/abstract/OIMObjectStore.ts
1074
+ var OIMObjectStore = class {
1075
+ };
1076
+
882
1077
  // src/core/OIMPkSelectorFactory.ts
883
1078
  var OIMPkSelectorFactory = class {
884
1079
  createIdSelector() {
@@ -936,6 +1131,9 @@ var OIMCollectionStoreMapDriven = class extends OIMCollectionStore {
936
1131
  getAllPks() {
937
1132
  return Array.from(this.entities.keys());
938
1133
  }
1134
+ destroy() {
1135
+ this.clear();
1136
+ }
939
1137
  };
940
1138
 
941
1139
  // src/core/OIMEntityUpdaterFactory.ts
@@ -1033,6 +1231,10 @@ var OIMCollection = class {
1033
1231
  this.store.setOneByPk(pk, entity);
1034
1232
  }
1035
1233
  }
1234
+ destroy() {
1235
+ this.store.destroy();
1236
+ this.emitter.offAll();
1237
+ }
1036
1238
  };
1037
1239
 
1038
1240
  // src/core/OIMUpdateEventCoalescerCollection.ts
@@ -1073,6 +1275,143 @@ var OIMReactiveCollection = class extends OIMCollection {
1073
1275
  queue
1074
1276
  });
1075
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
+ }
1076
1415
  };
1077
1416
 
1078
1417
  // src/core/OIMReactiveIndexManualSetBased.ts
@@ -1199,7 +1538,54 @@ var OIMReactiveIndexManualArrayBased = class extends OIMReactiveIndexArrayBased
1199
1538
  var OIMRICollection = class extends OIMReactiveCollection {
1200
1539
  constructor(queue, opts) {
1201
1540
  super(queue, opts.collectionOpts);
1202
- this.indexes = opts.indexes;
1541
+ this.indexes = opts.indexes || {};
1542
+ }
1543
+ };
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();
1203
1589
  }
1204
1590
  };
1205
1591
 
@@ -1233,6 +1619,8 @@ var OIMEventQueue = class {
1233
1619
  constructor(options = {}) {
1234
1620
  this.emitter = new OIMEventEmitter();
1235
1621
  this.queue = [];
1622
+ this.isFlushing = false;
1623
+ this.pendingSchedule = false;
1236
1624
  this.scheduler = options.scheduler;
1237
1625
  if (this.scheduler) {
1238
1626
  this.flushBound = () => this.flush();
@@ -1248,7 +1636,12 @@ var OIMEventQueue = class {
1248
1636
  */
1249
1637
  enqueue(fn) {
1250
1638
  this.queue.push(fn);
1251
- 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) {
1252
1645
  this.scheduler.schedule();
1253
1646
  }
1254
1647
  }
@@ -1258,6 +1651,8 @@ var OIMEventQueue = class {
1258
1651
  */
1259
1652
  flush() {
1260
1653
  if (this.queue.length === 0) return;
1654
+ this.scheduler?.cancel();
1655
+ this.isFlushing = true;
1261
1656
  this.emitter.emit(1 /* BEFORE_FLUSH */, void 0);
1262
1657
  const currentQueue = this.queue.slice();
1263
1658
  this.queue.length = 0;
@@ -1265,6 +1660,13 @@ var OIMEventQueue = class {
1265
1660
  currentQueue[i]();
1266
1661
  }
1267
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
+ }
1268
1670
  }
1269
1671
  /**
1270
1672
  * Get the current number of queued functions.
@@ -1332,7 +1734,7 @@ var OIMIndexComparatorFactory = class {
1332
1734
  if (existingSet.size !== newSet.size || existingSet.size !== existingPks.length) {
1333
1735
  return false;
1334
1736
  }
1335
- for (const pk of existingSet) {
1737
+ for (const pk of Array.from(existingSet)) {
1336
1738
  if (!newSet.has(pk)) {
1337
1739
  return false;
1338
1740
  }
@@ -1398,6 +1800,270 @@ var OIMMap2Keys = class {
1398
1800
  }
1399
1801
  };
1400
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
+
1401
2067
  // src/core/event-queue-scheduler/OIMEventQueueSchedulerAnimationFrame.ts
1402
2068
  var OIMEventQueueSchedulerAnimationFrame = class extends OIMEventQueueScheduler {
1403
2069
  constructor() {
@@ -1566,18 +2232,311 @@ var OIMEventQueueSchedulerFactory = class {
1566
2232
  return new OIMEventQueueSchedulerImmediate();
1567
2233
  }
1568
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
+ };
1569
2517
  // Annotate the CommonJS export names for ESM import in node:
1570
2518
  0 && (module.exports = {
1571
2519
  EOIMCollectionEventType,
2520
+ EOIMComputedEventType,
2521
+ EOIMEffectPhase,
1572
2522
  EOIMEventQueueEventType,
1573
2523
  EOIMEventQueueSchedulerEventType,
1574
2524
  EOIMIndexEventType,
2525
+ EOIMObjectEventType,
1575
2526
  EOIMUpdateEventCoalescerEventType,
1576
2527
  OIMCollection,
2528
+ OIMCollectionChangedFieldsWrapper,
1577
2529
  OIMCollectionStore,
1578
2530
  OIMCollectionStoreMapDriven,
1579
2531
  OIMComparatorFactory,
2532
+ OIMComputed,
1580
2533
  OIMDBSettings,
2534
+ OIMEffect,
2535
+ OIMEffectDependencyComputed,
2536
+ OIMEffectDependencyKeyed,
2537
+ OIMEffectDependencyKeyedCollection,
2538
+ OIMEffectDependencyKeyedIndex,
2539
+ OIMEffectDependencyKeyedObject,
1581
2540
  OIMEntityUpdaterFactory,
1582
2541
  OIMEventEmitter,
1583
2542
  OIMEventQueue,
@@ -1590,6 +2549,7 @@ var OIMEventQueueSchedulerFactory = class {
1590
2549
  OIMIndexArrayBased,
1591
2550
  OIMIndexComparatorFactory,
1592
2551
  OIMIndexManualArrayBased,
2552
+ OIMIndexManualOrderedArrayBased,
1593
2553
  OIMIndexManualSetBased,
1594
2554
  OIMIndexSetBased,
1595
2555
  OIMIndexStoreArrayBased,
@@ -1597,6 +2557,11 @@ var OIMEventQueueSchedulerFactory = class {
1597
2557
  OIMIndexStoreMapDrivenSetBased,
1598
2558
  OIMIndexStoreSetBased,
1599
2559
  OIMMap2Keys,
2560
+ OIMObject,
2561
+ OIMObjectStore,
2562
+ OIMObjectStoreMapDriven,
2563
+ OIMObjectStoreRecordDriven,
2564
+ OIMOrderedListIndexCommandStreamWrapper,
1600
2565
  OIMPkSelectorFactory,
1601
2566
  OIMRICollection,
1602
2567
  OIMReactiveCollection,
@@ -1604,8 +2569,12 @@ var OIMEventQueueSchedulerFactory = class {
1604
2569
  OIMReactiveIndexManualArrayBased,
1605
2570
  OIMReactiveIndexManualSetBased,
1606
2571
  OIMReactiveIndexSetBased,
2572
+ OIMReactiveObject,
1607
2573
  OIMUpdateEventCoalescer,
1608
2574
  OIMUpdateEventCoalescerCollection,
2575
+ OIMUpdateEventCoalescerComputed,
1609
2576
  OIMUpdateEventCoalescerIndex,
2577
+ OIMUpdateEventCoalescerManual,
2578
+ OIMUpdateEventCoalescerObject,
1610
2579
  OIMUpdateEventEmitter
1611
2580
  });