@oimdb/core 3.5.0 → 3.6.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
@@ -27,6 +27,7 @@ __export(index_exports, {
27
27
  EOIMIndexEventType: () => EOIMIndexEventType,
28
28
  EOIMObjectEventType: () => EOIMObjectEventType,
29
29
  OIMCarrierKeyedEmitter: () => OIMCarrierKeyedEmitter,
30
+ OIMCarrierSingleEmitter: () => OIMCarrierSingleEmitter,
30
31
  OIMCollection: () => OIMCollection,
31
32
  OIMCollectionByPkSelector: () => OIMCollectionByPkSelector,
32
33
  OIMCollectionByPksSelector: () => OIMCollectionByPksSelector,
@@ -41,6 +42,8 @@ __export(index_exports, {
41
42
  OIMComputeRuntime: () => OIMComputeRuntime,
42
43
  OIMComputed: () => OIMComputed,
43
44
  OIMDBSettings: () => OIMDBSettings,
45
+ OIMDerivedCollectionGlobalIndexArrayBased: () => OIMDerivedCollectionGlobalIndexArrayBased,
46
+ OIMDerivedCollectionGlobalIndexSetBased: () => OIMDerivedCollectionGlobalIndexSetBased,
44
47
  OIMDerivedCollectionIndexArrayBased: () => OIMDerivedCollectionIndexArrayBased,
45
48
  OIMDerivedCollectionIndexSetBased: () => OIMDerivedCollectionIndexSetBased,
46
49
  OIMEffect: () => OIMEffect,
@@ -49,6 +52,8 @@ __export(index_exports, {
49
52
  OIMEffectDependencyKeyedCollection: () => OIMEffectDependencyKeyedCollection,
50
53
  OIMEffectDependencyKeyedIndex: () => OIMEffectDependencyKeyedIndex,
51
54
  OIMEffectDependencyKeyedObject: () => OIMEffectDependencyKeyedObject,
55
+ OIMEntitiesByGlobalIndexArrayBasedSelector: () => OIMEntitiesByGlobalIndexArrayBasedSelector,
56
+ OIMEntitiesByGlobalIndexSetBasedSelector: () => OIMEntitiesByGlobalIndexSetBasedSelector,
52
57
  OIMEntitiesByIndexKeyArrayBasedSelector: () => OIMEntitiesByIndexKeyArrayBasedSelector,
53
58
  OIMEntitiesByIndexKeySetBasedSelector: () => OIMEntitiesByIndexKeySetBasedSelector,
54
59
  OIMEntityUpdaterFactory: () => OIMEntityUpdaterFactory,
@@ -59,7 +64,13 @@ __export(index_exports, {
59
64
  OIMEventQueueSchedulerFactory: () => OIMEventQueueSchedulerFactory,
60
65
  OIMEventQueueSchedulerImmediate: () => OIMEventQueueSchedulerImmediate,
61
66
  OIMEventQueueSchedulerMicrotask: () => OIMEventQueueSchedulerMicrotask,
67
+ OIMEventQueueSchedulerSync: () => OIMEventQueueSchedulerSync,
62
68
  OIMEventQueueSchedulerTimeout: () => OIMEventQueueSchedulerTimeout,
69
+ OIMGlobalIndex: () => OIMGlobalIndex,
70
+ OIMGlobalIndexArrayBased: () => OIMGlobalIndexArrayBased,
71
+ OIMGlobalIndexManualArrayBased: () => OIMGlobalIndexManualArrayBased,
72
+ OIMGlobalIndexManualSetBased: () => OIMGlobalIndexManualSetBased,
73
+ OIMGlobalIndexSetBased: () => OIMGlobalIndexSetBased,
63
74
  OIMIndex: () => OIMIndex,
64
75
  OIMIndexArrayBased: () => OIMIndexArrayBased,
65
76
  OIMIndexComparatorFactory: () => OIMIndexComparatorFactory,
@@ -71,6 +82,7 @@ __export(index_exports, {
71
82
  OIMIndexPksByKeysArrayBasedSelector: () => OIMIndexPksByKeysArrayBasedSelector,
72
83
  OIMIndexPksByKeysSetBasedSelector: () => OIMIndexPksByKeysSetBasedSelector,
73
84
  OIMIndexSetBased: () => OIMIndexSetBased,
85
+ OIMIndexSlotMap: () => OIMIndexSlotMap,
74
86
  OIMIndexStoreArrayBased: () => OIMIndexStoreArrayBased,
75
87
  OIMIndexStoreMapDrivenArrayBased: () => OIMIndexStoreMapDrivenArrayBased,
76
88
  OIMIndexStoreMapDrivenSetBased: () => OIMIndexStoreMapDrivenSetBased,
@@ -82,12 +94,21 @@ __export(index_exports, {
82
94
  OIMObjectStoreRecordDriven: () => OIMObjectStoreRecordDriven,
83
95
  OIMObjectValueByKeySelector: () => OIMObjectValueByKeySelector,
84
96
  OIMObjectValuesByKeysSelector: () => OIMObjectValuesByKeysSelector,
97
+ OIMOrderedListCommandBuffer: () => OIMOrderedListCommandBuffer,
85
98
  OIMOrderedListCommandStream: () => OIMOrderedListCommandStream,
99
+ OIMOrderedListCommandStreamDiffDriven: () => OIMOrderedListCommandStreamDiffDriven,
86
100
  OIMOrderedListMappedCommandStream: () => OIMOrderedListMappedCommandStream,
87
101
  OIMPkSelectorFactory: () => OIMPkSelectorFactory,
88
102
  OIMReactiveCollection: () => OIMReactiveCollection,
103
+ OIMReactiveCollectionGlobalIndexManualArrayBased: () => OIMReactiveCollectionGlobalIndexManualArrayBased,
104
+ OIMReactiveCollectionGlobalIndexManualSetBased: () => OIMReactiveCollectionGlobalIndexManualSetBased,
89
105
  OIMReactiveCollectionIndexManualArrayBased: () => OIMReactiveCollectionIndexManualArrayBased,
90
106
  OIMReactiveCollectionIndexManualSetBased: () => OIMReactiveCollectionIndexManualSetBased,
107
+ OIMReactiveGlobalIndex: () => OIMReactiveGlobalIndex,
108
+ OIMReactiveGlobalIndexArrayBased: () => OIMReactiveGlobalIndexArrayBased,
109
+ OIMReactiveGlobalIndexManualArrayBased: () => OIMReactiveGlobalIndexManualArrayBased,
110
+ OIMReactiveGlobalIndexManualSetBased: () => OIMReactiveGlobalIndexManualSetBased,
111
+ OIMReactiveGlobalIndexSetBased: () => OIMReactiveGlobalIndexSetBased,
91
112
  OIMReactiveIndex: () => OIMReactiveIndex,
92
113
  OIMReactiveIndexArrayBased: () => OIMReactiveIndexArrayBased,
93
114
  OIMReactiveIndexManualArrayBased: () => OIMReactiveIndexManualArrayBased,
@@ -99,7 +120,10 @@ __export(index_exports, {
99
120
  createMergeEntityUpdater: () => createMergeEntityUpdater,
100
121
  createOIMCollectionIndexFactory: () => createOIMCollectionIndexFactory,
101
122
  createOIMCollectionKit: () => createOIMCollectionKit,
102
- createOIMOrderedListMappedCommandStream: () => createOIMOrderedListMappedCommandStream
123
+ createOIMIndexSlotMap: () => createOIMIndexSlotMap,
124
+ createOIMOrderedListCommandStreamDiffDriven: () => createOIMOrderedListCommandStreamDiffDriven,
125
+ createOIMOrderedListMappedCommandStream: () => createOIMOrderedListMappedCommandStream,
126
+ diffOrderedListByPk: () => diffOrderedListByPk
103
127
  });
104
128
  module.exports = __toCommonJS(index_exports);
105
129
 
@@ -813,6 +837,254 @@ var OIMReactiveIndexArrayBased = class extends OIMReactiveIndex {
813
837
  var OIMObjectStore = class {
814
838
  };
815
839
 
840
+ // src/abstract/OIMGlobalIndex.ts
841
+ var OIMGlobalIndex = class {
842
+ constructor(comparePks) {
843
+ this.emitter = new OIMEventEmitter();
844
+ this.comparePks = comparePks;
845
+ }
846
+ get isEmpty() {
847
+ return this.size === 0;
848
+ }
849
+ /**
850
+ * Materializes the bucket to entities, preserving positional holes: a slot
851
+ * whose entity is not present yet (or was removed) yields `undefined` at its
852
+ * position rather than being dropped — mirroring {@link OIMIndex}.
853
+ */
854
+ getEntities() {
855
+ const entities = [];
856
+ for (const slot of this.iterateSlots()) {
857
+ entities.push(slot.item);
858
+ }
859
+ return entities;
860
+ }
861
+ getMetrics() {
862
+ return { totalPks: this.size };
863
+ }
864
+ destroy() {
865
+ this.emitter.offAll();
866
+ this.clearBucket();
867
+ }
868
+ emitUpdate() {
869
+ this.emitter.emit(0 /* UPDATE */, void 0);
870
+ }
871
+ };
872
+
873
+ // src/abstract/OIMGlobalIndexSetBased.ts
874
+ var OIMGlobalIndexSetBased = class extends OIMGlobalIndex {
875
+ constructor(options = {}) {
876
+ super(options.comparePks);
877
+ this.slots = /* @__PURE__ */ new Set();
878
+ }
879
+ get size() {
880
+ return this.slots.size;
881
+ }
882
+ iterateSlots() {
883
+ return this.slots;
884
+ }
885
+ clearBucket() {
886
+ this.slots.clear();
887
+ }
888
+ getPks() {
889
+ return this.slotsToPks(this.slots);
890
+ }
891
+ getSlots() {
892
+ return this.slots;
893
+ }
894
+ slotsToPks(slots) {
895
+ const pks = /* @__PURE__ */ new Set();
896
+ for (const slot of slots) pks.add(slot.pk);
897
+ return pks;
898
+ }
899
+ setSlotsWithComparison(newSlots) {
900
+ if (this.comparePks && this.slots.size === newSlots.size) {
901
+ if (this.comparePks(
902
+ Array.from(this.slotsToPks(this.slots)),
903
+ Array.from(this.slotsToPks(newSlots))
904
+ )) {
905
+ return false;
906
+ }
907
+ }
908
+ this.slots = newSlots;
909
+ return true;
910
+ }
911
+ };
912
+
913
+ // src/abstract/OIMGlobalIndexArrayBased.ts
914
+ var OIMGlobalIndexArrayBased = class extends OIMGlobalIndex {
915
+ constructor(options = {}) {
916
+ super(options.comparePks);
917
+ this.slots = [];
918
+ }
919
+ get size() {
920
+ return this.slots.length;
921
+ }
922
+ iterateSlots() {
923
+ return this.slots;
924
+ }
925
+ clearBucket() {
926
+ this.slots = [];
927
+ }
928
+ getPks() {
929
+ return this.slotsToPks(this.slots);
930
+ }
931
+ getSlots() {
932
+ return this.slots;
933
+ }
934
+ slotsToPks(slots) {
935
+ const pks = [];
936
+ pks.length = slots.length;
937
+ for (let i = 0; i < slots.length; i++) pks[i] = slots[i].pk;
938
+ return pks;
939
+ }
940
+ setSlotsWithComparison(newSlots) {
941
+ if (this.comparePks && this.slots.length === newSlots.length) {
942
+ if (this.comparePks(
943
+ this.slotsToPks(this.slots),
944
+ this.slotsToPks(newSlots)
945
+ )) {
946
+ return false;
947
+ }
948
+ }
949
+ this.slots = newSlots;
950
+ return true;
951
+ }
952
+ };
953
+
954
+ // src/core/OIMCarrierSingleEmitter.ts
955
+ var OIMCarrierSingleEmitter = class {
956
+ constructor(queue) {
957
+ this.dirty = false;
958
+ this.isFlushEnqueued = false;
959
+ this.onFlush = () => {
960
+ this.isFlushEnqueued = false;
961
+ if (!this.dirty) return;
962
+ this.dirty = false;
963
+ this.notify();
964
+ };
965
+ this.queue = queue;
966
+ }
967
+ subscribe(handler) {
968
+ let subscribers = this.subscribers;
969
+ if (!subscribers) {
970
+ subscribers = /* @__PURE__ */ new Set();
971
+ this.subscribers = subscribers;
972
+ }
973
+ subscribers.add(handler);
974
+ return () => {
975
+ this.subscribers?.delete(handler);
976
+ };
977
+ }
978
+ markUpdated() {
979
+ this.assertNotInFlush();
980
+ if (!this.subscribers || this.subscribers.size === 0) return;
981
+ if (this.dirty) return;
982
+ this.dirty = true;
983
+ this.scheduleFlush();
984
+ }
985
+ hasSubscriptions() {
986
+ return !!this.subscribers && this.subscribers.size > 0;
987
+ }
988
+ getMetrics() {
989
+ return {
990
+ totalHandlers: this.subscribers?.size ?? 0,
991
+ queueLength: this.dirty ? 1 : 0
992
+ };
993
+ }
994
+ destroy() {
995
+ if (this.isFlushEnqueued) {
996
+ this.queue.cancel(this.onFlush);
997
+ this.isFlushEnqueued = false;
998
+ }
999
+ this.subscribers?.clear();
1000
+ this.subscribers = void 0;
1001
+ this.dirty = false;
1002
+ }
1003
+ assertNotInFlush() {
1004
+ if (this.queue.isInFlush) {
1005
+ throw new Error(
1006
+ "OIMCarrierSingleEmitter: updates during queue.flush() are not allowed. Finish all writes before calling queue.flush()."
1007
+ );
1008
+ }
1009
+ }
1010
+ scheduleFlush() {
1011
+ if (this.isFlushEnqueued) return;
1012
+ this.isFlushEnqueued = true;
1013
+ this.queue.enqueue(this.onFlush);
1014
+ }
1015
+ notify() {
1016
+ const subscribers = this.subscribers;
1017
+ if (!subscribers || subscribers.size === 0) return;
1018
+ if (subscribers.size === 1) {
1019
+ const only = subscribers.values().next().value;
1020
+ if (only) only();
1021
+ return;
1022
+ }
1023
+ const snapshot = [];
1024
+ subscribers.forEach((h) => snapshot.push(h));
1025
+ for (let i = 0; i < snapshot.length; i++) {
1026
+ const handler = snapshot[i];
1027
+ if (subscribers.has(handler)) handler();
1028
+ }
1029
+ }
1030
+ };
1031
+
1032
+ // src/abstract/OIMReactiveGlobalIndex.ts
1033
+ var OIMReactiveGlobalIndex = class {
1034
+ constructor(queue, createIndex) {
1035
+ this.updateEmitter = new OIMCarrierSingleEmitter(queue);
1036
+ this.index = createIndex(this.updateEmitter);
1037
+ }
1038
+ getEntities() {
1039
+ return this.index.getEntities();
1040
+ }
1041
+ get size() {
1042
+ return this.index.size;
1043
+ }
1044
+ get isEmpty() {
1045
+ return this.index.isEmpty;
1046
+ }
1047
+ subscribe(handler) {
1048
+ return this.updateEmitter.subscribe(handler);
1049
+ }
1050
+ hasSubscriptions() {
1051
+ return this.updateEmitter.hasSubscriptions();
1052
+ }
1053
+ getMetrics() {
1054
+ return this.index.getMetrics();
1055
+ }
1056
+ destroy() {
1057
+ this.updateEmitter.destroy();
1058
+ this.index.destroy();
1059
+ }
1060
+ };
1061
+
1062
+ // src/abstract/OIMReactiveGlobalIndexSetBased.ts
1063
+ var OIMReactiveGlobalIndexSetBased = class extends OIMReactiveGlobalIndex {
1064
+ constructor(queue, createIndex) {
1065
+ super(queue, createIndex);
1066
+ }
1067
+ getPks() {
1068
+ return this.index.getPks();
1069
+ }
1070
+ getSlots() {
1071
+ return this.index.getSlots();
1072
+ }
1073
+ };
1074
+
1075
+ // src/abstract/OIMReactiveGlobalIndexArrayBased.ts
1076
+ var OIMReactiveGlobalIndexArrayBased = class extends OIMReactiveGlobalIndex {
1077
+ constructor(queue, createIndex) {
1078
+ super(queue, createIndex);
1079
+ }
1080
+ getPks() {
1081
+ return this.index.getPks();
1082
+ }
1083
+ getSlots() {
1084
+ return this.index.getSlots();
1085
+ }
1086
+ };
1087
+
816
1088
  // src/core/OIMPkSelectorFactory.ts
817
1089
  var OIMPkSelectorFactory = class {
818
1090
  createIdSelector() {
@@ -1256,7 +1528,7 @@ var OIMReactiveCollection = class extends OIMCollection {
1256
1528
  }
1257
1529
  };
1258
1530
 
1259
- // src/modules/wrapper/index/OIMIndexManualOrderedArrayBased.ts
1531
+ // src/core/OIMIndexManualOrderedArrayBased.ts
1260
1532
  var OIMIndexManualOrderedArrayBased = class extends OIMIndexArrayBased {
1261
1533
  clear(key) {
1262
1534
  if (key === void 0) {
@@ -1372,7 +1644,7 @@ var OIMIndexManualOrderedArrayBased = class extends OIMIndexArrayBased {
1372
1644
  }
1373
1645
  };
1374
1646
 
1375
- // src/modules/wrapper/index/OIMCollectionIndexManualOrderedArrayBased.ts
1647
+ // src/core/OIMCollectionIndexManualOrderedArrayBased.ts
1376
1648
  var OIMCollectionIndexManualOrderedArrayBased = class extends OIMIndexManualOrderedArrayBased {
1377
1649
  constructor(opts) {
1378
1650
  super();
@@ -1668,35 +1940,67 @@ var OIMUpdateEventEmitter = class {
1668
1940
  }
1669
1941
  };
1670
1942
 
1671
- // src/modules/wrapper/index/OIMOrderedListCommandStream.ts
1672
- var OIMOrderedListCommandStream = class {
1673
- constructor(queue, index) {
1674
- this.isInWrite = false;
1943
+ // src/abstract/OIMOrderedListCommandBuffer.ts
1944
+ var OIMOrderedListCommandBuffer = class {
1945
+ constructor(queue) {
1675
1946
  this.commandsByKey = /* @__PURE__ */ new Map();
1676
1947
  this.onAfterFlush = () => {
1677
1948
  this.commandsByKey.clear();
1678
1949
  };
1679
- this.onIndexUpdate = (payload) => {
1680
- if (this.isInWrite) return;
1681
- if (payload.keys.length === 0) return;
1682
- for (let i = 0; i < payload.keys.length; i++) {
1683
- const key = payload.keys[i];
1684
- this.appendResetCommand(key, this.getSlotsByKey(key));
1685
- }
1686
- };
1687
1950
  this.commandsEventEmitter = new OIMUpdateEventEmitter(
1688
1951
  queue,
1689
1952
  "after_flush"
1690
1953
  );
1691
- this.index = index ?? new OIMIndexManualOrderedArrayBased();
1692
1954
  this.unsubscribeAfterFlush = queue.emitter.on(
1693
1955
  0 /* AFTER_FLUSH */,
1694
1956
  this.onAfterFlush
1695
1957
  );
1696
- this.unsubscribeFromIndexEmitter = this.index.emitter.on(
1697
- 0 /* UPDATE */,
1698
- this.onIndexUpdate
1699
- );
1958
+ }
1959
+ subscribeCommands(key, handler) {
1960
+ return this.commandsEventEmitter.subscribeOnKey(key, handler);
1961
+ }
1962
+ getBufferedCommands(key) {
1963
+ return this.commandsByKey.get(key) ?? [];
1964
+ }
1965
+ consumeCommands(key) {
1966
+ const cmds = this.commandsByKey.get(key);
1967
+ if (!cmds || cmds.length === 0) return [];
1968
+ return cmds.slice();
1969
+ }
1970
+ destroy() {
1971
+ this.commandsEventEmitter.destroy();
1972
+ this.unsubscribeAfterFlush();
1973
+ this.commandsByKey.clear();
1974
+ }
1975
+ appendCommand(key, cmd) {
1976
+ let cmds = this.commandsByKey.get(key);
1977
+ if (!cmds) {
1978
+ cmds = [];
1979
+ this.commandsByKey.set(key, cmds);
1980
+ }
1981
+ if (cmd.type === "reset") {
1982
+ cmds.length = 0;
1983
+ cmds.push(cmd);
1984
+ } else if (cmds.length > 0 && cmds[0].type === "reset") {
1985
+ cmds[0] = this.createResetCommand(this.getItemsByKey(key));
1986
+ } else {
1987
+ cmds.push(cmd);
1988
+ }
1989
+ this.commandsEventEmitter.markUpdatedKeys([key]);
1990
+ }
1991
+ appendResetCommand(key, items) {
1992
+ this.appendCommand(key, this.createResetCommand(items));
1993
+ }
1994
+ createResetCommand(items) {
1995
+ return { type: "reset", items };
1996
+ }
1997
+ };
1998
+
1999
+ // src/modules/wrapper/index/OIMOrderedListCommandStream.ts
2000
+ var OIMOrderedListCommandStream = class extends OIMOrderedListCommandBuffer {
2001
+ constructor(queue, index) {
2002
+ super(queue);
2003
+ this.index = index ?? new OIMIndexManualOrderedArrayBased();
1700
2004
  }
1701
2005
  getPksByKey(key) {
1702
2006
  return this.index.getPksByKey(key);
@@ -1706,14 +2010,10 @@ var OIMOrderedListCommandStream = class {
1706
2010
  key
1707
2011
  );
1708
2012
  }
1709
- /** {@link IOIMOrderedListCommandSource} — alias of {@link getSlotsByKey}. */
2013
+ /** {@link OIMOrderedListCommandBuffer.getItemsByKey} — the slots in order. */
1710
2014
  getItemsByKey(key) {
1711
2015
  return this.getSlotsByKey(key);
1712
2016
  }
1713
- /** {@link IOIMOrderedListCommandSource} — per-key command subscription. */
1714
- subscribeCommands(key, handler) {
1715
- return this.commandsEventEmitter.subscribeOnKey(key, handler);
1716
- }
1717
2017
  getEntitiesByKey(key) {
1718
2018
  return this.index.getEntitiesByKey(key);
1719
2019
  }
@@ -1724,57 +2024,46 @@ var OIMOrderedListCommandStream = class {
1724
2024
  return this.index.getKeys();
1725
2025
  }
1726
2026
  pushSlot(key, slot) {
1727
- this.withWrite(() => {
1728
- const index = this.index.pushSlot(key, slot);
1729
- this.appendCommand(key, { type: "insert", index, item: slot });
1730
- });
2027
+ const index = this.index.pushSlot(key, slot);
2028
+ this.appendCommand(key, { type: "insert", index, item: slot });
1731
2029
  }
1732
2030
  insertSlotAt(key, index, slot) {
1733
- this.withWrite(() => {
1734
- const safeIndex = this.index.insertSlotAt(key, index, slot);
1735
- this.appendCommand(key, {
1736
- type: "insert",
1737
- index: safeIndex,
1738
- item: slot
1739
- });
2031
+ const safeIndex = this.index.insertSlotAt(key, index, slot);
2032
+ this.appendCommand(key, {
2033
+ type: "insert",
2034
+ index: safeIndex,
2035
+ item: slot
1740
2036
  });
1741
2037
  }
1742
2038
  /** Replace the slot at `index` in place. */
1743
2039
  setSlotAt(key, index, slot) {
1744
- this.withWrite(() => {
1745
- const safeIndex = this.index.setSlotAt(key, index, slot);
1746
- if (safeIndex < 0) return;
1747
- this.appendCommand(key, {
1748
- type: "set",
1749
- index: safeIndex,
1750
- item: slot
1751
- });
2040
+ const safeIndex = this.index.setSlotAt(key, index, slot);
2041
+ if (safeIndex < 0) return;
2042
+ this.appendCommand(key, {
2043
+ type: "set",
2044
+ index: safeIndex,
2045
+ item: slot
1752
2046
  });
1753
2047
  }
1754
2048
  removeAt(key, index) {
1755
- this.withWrite(() => {
1756
- const slot = this.index.removeAt(key, index);
1757
- if (slot === void 0) return;
1758
- this.appendCommand(key, { type: "remove", index });
1759
- });
2049
+ const slot = this.index.removeAt(key, index);
2050
+ if (slot === void 0) return;
2051
+ this.appendCommand(key, { type: "remove", index });
1760
2052
  }
1761
2053
  /** Remove `count` consecutive elements from `index`; emits `remove` with `count`. */
1762
2054
  removeRange(key, index, count) {
1763
- this.withWrite(() => {
1764
- const removed = this.index.removeRange(key, index, count);
1765
- if (removed <= 0) return;
1766
- this.appendCommand(key, { type: "remove", index, count: removed });
1767
- });
2055
+ const removed = this.index.removeRange(key, index, count);
2056
+ if (removed <= 0) return;
2057
+ this.appendCommand(key, { type: "remove", index, count: removed });
1768
2058
  }
1769
2059
  move(key, fromIndex, toIndex) {
1770
- this.withWrite(() => {
1771
- const slot = this.index.move(key, fromIndex, toIndex);
1772
- if (slot === void 0) return;
1773
- this.appendCommand(key, {
1774
- type: "move",
1775
- from: fromIndex,
1776
- to: toIndex
1777
- });
2060
+ if (fromIndex === toIndex) return;
2061
+ const slot = this.index.move(key, fromIndex, toIndex);
2062
+ if (slot === void 0) return;
2063
+ this.appendCommand(key, {
2064
+ type: "move",
2065
+ from: fromIndex,
2066
+ to: toIndex
1778
2067
  });
1779
2068
  }
1780
2069
  /**
@@ -1782,74 +2071,31 @@ var OIMOrderedListCommandStream = class {
1782
2071
  * `count`. `to` is in the post-extraction coordinate space (as single `move`).
1783
2072
  */
1784
2073
  moveRange(key, from, to, count) {
1785
- this.withWrite(() => {
1786
- const moved = this.index.moveRange(key, from, to, count);
1787
- if (moved <= 0) return;
1788
- this.appendCommand(key, { type: "move", from, to, count: moved });
1789
- });
2074
+ const moved = this.index.moveRange(key, from, to, count);
2075
+ if (moved <= 0) return;
2076
+ this.appendCommand(key, { type: "move", from, to, count: moved });
1790
2077
  }
1791
2078
  setSlots(key, slots) {
1792
- this.withWrite(() => {
1793
- this.index.resetSlots(key, slots);
1794
- this.appendResetCommand(key, slots);
1795
- });
1796
- }
1797
- getBufferedCommands(key) {
1798
- return this.commandsByKey.get(key) ?? [];
1799
- }
1800
- consumeCommands(key) {
1801
- const cmds = this.commandsByKey.get(key);
1802
- if (!cmds || cmds.length === 0) return [];
1803
- return cmds.slice();
2079
+ this.index.resetSlots(key, slots);
2080
+ this.appendResetCommand(key, slots);
1804
2081
  }
1805
2082
  clear(key) {
1806
2083
  if (key === void 0) {
1807
- this.index.destroy();
1808
- this.commandsByKey.clear();
2084
+ const keys = this.getKeys().slice();
2085
+ if (keys.length === 0) return;
2086
+ this.index.clear();
2087
+ for (let i = 0; i < keys.length; i++) {
2088
+ this.appendResetCommand(keys[i], []);
2089
+ }
1809
2090
  return;
1810
2091
  }
2092
+ if (!this.index.hasKey(key)) return;
1811
2093
  this.index.clear(key);
1812
- this.commandsByKey.delete(key);
2094
+ this.appendResetCommand(key, []);
1813
2095
  }
1814
2096
  destroy() {
1815
- this.commandsEventEmitter.destroy();
1816
- this.unsubscribeAfterFlush();
1817
- this.unsubscribeFromIndexEmitter();
1818
- this.clear();
1819
- }
1820
- withWrite(fn) {
1821
- if (this.isInWrite) {
1822
- fn();
1823
- return;
1824
- }
1825
- this.isInWrite = true;
1826
- try {
1827
- fn();
1828
- } finally {
1829
- this.isInWrite = false;
1830
- }
1831
- }
1832
- appendCommand(key, cmd) {
1833
- let cmds = this.commandsByKey.get(key);
1834
- if (!cmds) {
1835
- cmds = [];
1836
- this.commandsByKey.set(key, cmds);
1837
- }
1838
- if (cmd.type === "reset") {
1839
- cmds.length = 0;
1840
- cmds.push(cmd);
1841
- } else if (cmds.length > 0 && cmds[0].type === "reset") {
1842
- cmds[0] = this.createResetCommand(this.getSlotsByKey(key));
1843
- } else {
1844
- cmds.push(cmd);
1845
- }
1846
- this.commandsEventEmitter.markUpdatedKeys([key]);
1847
- }
1848
- appendResetCommand(key, slots) {
1849
- this.appendCommand(key, this.createResetCommand(slots));
1850
- }
1851
- createResetCommand(slots) {
1852
- return { type: "reset", items: slots };
2097
+ this.index.destroy();
2098
+ super.destroy();
1853
2099
  }
1854
2100
  };
1855
2101
 
@@ -1863,42 +2109,34 @@ var OIMCollectionOrderedListCommandStream = class extends OIMOrderedListCommandS
1863
2109
  this.index = index;
1864
2110
  }
1865
2111
  push(key, pk) {
1866
- this.withWrite(() => {
1867
- const slot = this.resolvePk(pk);
1868
- const index = this.index.pushSlot(key, slot);
1869
- this.appendCommand(key, { type: "insert", index, item: slot });
1870
- });
2112
+ const slot = this.resolvePk(pk);
2113
+ const index = this.index.pushSlot(key, slot);
2114
+ this.appendCommand(key, { type: "insert", index, item: slot });
1871
2115
  }
1872
2116
  insertAt(key, index, pk) {
1873
- this.withWrite(() => {
1874
- const slot = this.resolvePk(pk);
1875
- const safeIndex = this.index.insertSlotAt(key, index, slot);
1876
- this.appendCommand(key, {
1877
- type: "insert",
1878
- index: safeIndex,
1879
- item: slot
1880
- });
2117
+ const slot = this.resolvePk(pk);
2118
+ const safeIndex = this.index.insertSlotAt(key, index, slot);
2119
+ this.appendCommand(key, {
2120
+ type: "insert",
2121
+ index: safeIndex,
2122
+ item: slot
1881
2123
  });
1882
2124
  }
1883
2125
  /** Replace the element at `index` with the slot for `pk`, in place. */
1884
2126
  setAt(key, index, pk) {
1885
- this.withWrite(() => {
1886
- const slot = this.resolvePk(pk);
1887
- const safeIndex = this.index.setSlotAt(key, index, slot);
1888
- if (safeIndex < 0) return;
1889
- this.appendCommand(key, {
1890
- type: "set",
1891
- index: safeIndex,
1892
- item: slot
1893
- });
2127
+ const slot = this.resolvePk(pk);
2128
+ const safeIndex = this.index.setSlotAt(key, index, slot);
2129
+ if (safeIndex < 0) return;
2130
+ this.appendCommand(key, {
2131
+ type: "set",
2132
+ index: safeIndex,
2133
+ item: slot
1894
2134
  });
1895
2135
  }
1896
2136
  set(key, pks) {
1897
- this.withWrite(() => {
1898
- const slots = pks.map((pk) => this.resolvePk(pk));
1899
- this.index.resetSlots(key, slots);
1900
- this.appendResetCommand(key, slots);
1901
- });
2137
+ const slots = pks.map((pk) => this.resolvePk(pk));
2138
+ this.index.resetSlots(key, slots);
2139
+ this.appendResetCommand(key, slots);
1902
2140
  }
1903
2141
  getSlotsByKey(key) {
1904
2142
  return this.index.getSlotsByKey(
@@ -1909,7 +2147,9 @@ var OIMCollectionOrderedListCommandStream = class extends OIMOrderedListCommandS
1909
2147
  return this.index.getEntitiesByKey(key);
1910
2148
  }
1911
2149
  resolvePk(pk) {
1912
- return this.index.resolvePk(pk);
2150
+ return this.index.resolvePk(
2151
+ pk
2152
+ );
1913
2153
  }
1914
2154
  };
1915
2155
 
@@ -2476,38 +2716,476 @@ var OIMDerivedCollectionIndexArrayBased = class extends OIMReactiveCollectionInd
2476
2716
  }
2477
2717
  destroy() {
2478
2718
  this.unsubscribeFromCollection();
2479
- this.keysByPk.clear();
2480
- this.orderValueByPk.clear();
2719
+ this.keysByPk.clear();
2720
+ this.orderValueByPk.clear();
2721
+ super.destroy();
2722
+ }
2723
+ sortSlots(slots) {
2724
+ if (!this.compareEntities && !this.orderBy) return slots.slice();
2725
+ return slots.slice().sort((a, b) => {
2726
+ const aItem = a.item;
2727
+ const bItem = b.item;
2728
+ if (aItem === void 0 || bItem === void 0) return 0;
2729
+ if (this.compareEntities) {
2730
+ return this.compareEntities(aItem, bItem);
2731
+ }
2732
+ const aValue = this.orderBy(aItem);
2733
+ const bValue = this.orderBy(bItem);
2734
+ if (aValue < bValue) return -1;
2735
+ if (aValue > bValue) return 1;
2736
+ return 0;
2737
+ });
2738
+ }
2739
+ normalizeKeys(keys) {
2740
+ if (keys === void 0 || keys === null) return [];
2741
+ const rawKeys = Array.isArray(keys) ? keys : [keys];
2742
+ const result = [];
2743
+ const seen = /* @__PURE__ */ new Set();
2744
+ for (const key of rawKeys) {
2745
+ if (seen.has(key)) continue;
2746
+ seen.add(key);
2747
+ result.push(key);
2748
+ }
2749
+ return result;
2750
+ }
2751
+ };
2752
+
2753
+ // src/core/OIMGlobalIndexManualArrayBased.ts
2754
+ var OIMGlobalIndexManualArrayBased = class extends OIMGlobalIndexArrayBased {
2755
+ constructor(options = {}) {
2756
+ super(options);
2757
+ }
2758
+ setSlots(slots) {
2759
+ if (this.setSlotsWithComparison(slots)) this.emitUpdate();
2760
+ }
2761
+ /**
2762
+ * Appends pre-deduplicated slots to the bucket IN PLACE and emits once.
2763
+ * O(added). Callers own dedup (used by collection-bound `addPks`).
2764
+ */
2765
+ appendSlots(slots) {
2766
+ if (slots.length === 0) return;
2767
+ for (let i = 0; i < slots.length; i++) this.slots.push(slots[i]);
2768
+ this.emitUpdate();
2769
+ }
2770
+ clear() {
2771
+ if (this.slots.length > 0) {
2772
+ this.slots = [];
2773
+ this.emitUpdate();
2774
+ }
2775
+ }
2776
+ };
2777
+
2778
+ // src/core/OIMReactiveGlobalIndexManualArrayBased.ts
2779
+ var OIMGlobalIndexManualArrayBasedReactive = class extends OIMGlobalIndexManualArrayBased {
2780
+ constructor(updateEmitter, opts) {
2781
+ super(opts);
2782
+ this.updateEmitter = updateEmitter;
2783
+ }
2784
+ emitUpdate() {
2785
+ this.updateEmitter.markUpdated();
2786
+ }
2787
+ };
2788
+ var OIMReactiveGlobalIndexManualArrayBased = class extends OIMReactiveGlobalIndexArrayBased {
2789
+ constructor(queue, opts) {
2790
+ super(
2791
+ queue,
2792
+ (updateEmitter) => new OIMGlobalIndexManualArrayBasedReactive(
2793
+ updateEmitter,
2794
+ opts?.indexOptions
2795
+ )
2796
+ );
2797
+ }
2798
+ setSlots(slots) {
2799
+ this.index.setSlots(slots);
2800
+ }
2801
+ appendSlots(slots) {
2802
+ this.index.appendSlots(slots);
2803
+ }
2804
+ clear() {
2805
+ this.index.clear();
2806
+ }
2807
+ };
2808
+
2809
+ // src/core/OIMReactiveCollectionGlobalIndexManualArrayBased.ts
2810
+ var OIMReactiveCollectionGlobalIndexManualArrayBased = class extends OIMReactiveGlobalIndexManualArrayBased {
2811
+ constructor(queue, opts) {
2812
+ const resolveSlot = opts.collection !== void 0 ? (pk) => opts.collection.getOrReserveSlotByPk(pk) : opts.resolveSlot;
2813
+ super(queue, { indexOptions: opts.indexOptions });
2814
+ // Single pk membership set for O(1) `addPks` dedup. Lazily seeded from the
2815
+ // bucket so it stays correct even after a raw `setSlots` (e.g. derived
2816
+ // rebuild), matching the keyed index's `membershipOf`.
2817
+ this.membership = /* @__PURE__ */ new Set();
2818
+ this.membershipSeeded = false;
2819
+ this.resolveSlot = resolveSlot;
2820
+ }
2821
+ setPks(pks) {
2822
+ this.membership.clear();
2823
+ for (let i = 0; i < pks.length; i++) this.membership.add(pks[i]);
2824
+ this.membershipSeeded = true;
2825
+ super.setSlots(this.resolveSlots(pks));
2826
+ }
2827
+ addPks(pks) {
2828
+ if (pks.length === 0) return;
2829
+ const membership = this.membershipOf();
2830
+ const newSlots = [];
2831
+ for (const pk of pks) {
2832
+ if (membership.has(pk)) continue;
2833
+ membership.add(pk);
2834
+ newSlots.push(this.resolveRequiredSlot(pk));
2835
+ }
2836
+ if (newSlots.length > 0) super.appendSlots(newSlots);
2837
+ }
2838
+ removePks(pks) {
2839
+ if (pks.length === 0) return;
2840
+ const membership = this.membershipOf();
2841
+ if (membership.size === 0) return;
2842
+ const pksToRemove = new Set(pks);
2843
+ const existingSlots = this.index.getSlots();
2844
+ const nextSlots = existingSlots.filter(
2845
+ (slot) => !pksToRemove.has(slot.pk)
2846
+ );
2847
+ if (nextSlots.length === existingSlots.length) return;
2848
+ for (let i = 0; i < pks.length; i++) membership.delete(pks[i]);
2849
+ if (nextSlots.length === 0) this.clear();
2850
+ else super.setSlots(nextSlots);
2851
+ }
2852
+ clear() {
2853
+ this.membership.clear();
2854
+ this.membershipSeeded = false;
2855
+ super.clear();
2856
+ }
2857
+ membershipOf() {
2858
+ if (!this.membershipSeeded) {
2859
+ this.membership.clear();
2860
+ const existing = this.index.getSlots();
2861
+ for (let i = 0; i < existing.length; i++) {
2862
+ this.membership.add(existing[i].pk);
2863
+ }
2864
+ this.membershipSeeded = true;
2865
+ }
2866
+ return this.membership;
2867
+ }
2868
+ getEntities() {
2869
+ return super.getEntities();
2870
+ }
2871
+ resolveSlots(pks) {
2872
+ const slots = [];
2873
+ slots.length = pks.length;
2874
+ for (let i = 0; i < pks.length; i++) {
2875
+ slots[i] = this.resolveRequiredSlot(pks[i]);
2876
+ }
2877
+ return slots;
2878
+ }
2879
+ resolveRequiredSlot(pk) {
2880
+ const slot = this.resolveSlot(pk);
2881
+ if (!slot) return { pk, item: void 0 };
2882
+ return slot;
2883
+ }
2884
+ };
2885
+
2886
+ // src/core/OIMGlobalIndexManualSetBased.ts
2887
+ var OIMGlobalIndexManualSetBased = class extends OIMGlobalIndexSetBased {
2888
+ constructor(options = {}) {
2889
+ super(options);
2890
+ }
2891
+ setSlots(slots) {
2892
+ if (this.setSlotsWithComparison(new Set(slots))) this.emitUpdate();
2893
+ }
2894
+ /** Adds slots IN PLACE (O(added)) and emits once if anything changed. */
2895
+ addSlots(slots) {
2896
+ if (slots.length === 0) return;
2897
+ let changed = false;
2898
+ for (let i = 0; i < slots.length; i++) {
2899
+ if (!this.slots.has(slots[i])) {
2900
+ this.slots.add(slots[i]);
2901
+ changed = true;
2902
+ }
2903
+ }
2904
+ if (changed) this.emitUpdate();
2905
+ }
2906
+ /** Removes slots IN PLACE (O(removed)) and emits once if anything changed. */
2907
+ removeSlots(slots) {
2908
+ if (slots.length === 0) return;
2909
+ let changed = false;
2910
+ for (let i = 0; i < slots.length; i++) {
2911
+ if (this.slots.delete(slots[i])) changed = true;
2912
+ }
2913
+ if (changed) this.emitUpdate();
2914
+ }
2915
+ clear() {
2916
+ if (this.slots.size > 0) {
2917
+ this.slots.clear();
2918
+ this.emitUpdate();
2919
+ }
2920
+ }
2921
+ };
2922
+
2923
+ // src/core/OIMReactiveGlobalIndexManualSetBased.ts
2924
+ var OIMGlobalIndexManualSetBasedReactive = class extends OIMGlobalIndexManualSetBased {
2925
+ constructor(updateEmitter, opts) {
2926
+ super(opts);
2927
+ this.updateEmitter = updateEmitter;
2928
+ }
2929
+ emitUpdate() {
2930
+ this.updateEmitter.markUpdated();
2931
+ }
2932
+ };
2933
+ var OIMReactiveGlobalIndexManualSetBased = class extends OIMReactiveGlobalIndexSetBased {
2934
+ constructor(queue, opts) {
2935
+ super(
2936
+ queue,
2937
+ (updateEmitter) => new OIMGlobalIndexManualSetBasedReactive(
2938
+ updateEmitter,
2939
+ opts?.indexOptions
2940
+ )
2941
+ );
2942
+ }
2943
+ setSlots(slots) {
2944
+ this.index.setSlots(slots);
2945
+ }
2946
+ addSlots(slots) {
2947
+ this.index.addSlots(slots);
2948
+ }
2949
+ removeSlots(slots) {
2950
+ this.index.removeSlots(slots);
2951
+ }
2952
+ clear() {
2953
+ this.index.clear();
2954
+ }
2955
+ };
2956
+
2957
+ // src/core/OIMReactiveCollectionGlobalIndexManualSetBased.ts
2958
+ var OIMReactiveCollectionGlobalIndexManualSetBased = class extends OIMReactiveGlobalIndexManualSetBased {
2959
+ constructor(queue, opts) {
2960
+ const resolveSlot = opts.collection !== void 0 ? (pk) => opts.collection.getOrReserveSlotByPk(pk) : opts.resolveSlot;
2961
+ super(queue, { indexOptions: opts.indexOptions });
2962
+ this.membership = /* @__PURE__ */ new Map();
2963
+ this.membershipSeeded = false;
2964
+ this.resolveSlot = resolveSlot;
2965
+ }
2966
+ setPks(pks) {
2967
+ this.membership.clear();
2968
+ const slots = [];
2969
+ for (let i = 0; i < pks.length; i++) {
2970
+ const pk = pks[i];
2971
+ const slot = this.resolveRequiredSlot(pk);
2972
+ if (!this.membership.has(pk)) this.membership.set(pk, slot);
2973
+ slots.push(slot);
2974
+ }
2975
+ this.membershipSeeded = true;
2976
+ super.setSlots(slots);
2977
+ }
2978
+ addPks(pks) {
2979
+ if (pks.length === 0) return;
2980
+ const membership = this.membershipOf();
2981
+ const newSlots = [];
2982
+ for (const pk of pks) {
2983
+ if (membership.has(pk)) continue;
2984
+ const slot = this.resolveRequiredSlot(pk);
2985
+ membership.set(pk, slot);
2986
+ newSlots.push(slot);
2987
+ }
2988
+ if (newSlots.length > 0) super.addSlots(newSlots);
2989
+ }
2990
+ removePks(pks) {
2991
+ if (pks.length === 0) return;
2992
+ const membership = this.membershipOf();
2993
+ if (membership.size === 0) return;
2994
+ const removed = [];
2995
+ for (const pk of pks) {
2996
+ const slot = membership.get(pk);
2997
+ if (slot) {
2998
+ membership.delete(pk);
2999
+ removed.push(slot);
3000
+ }
3001
+ }
3002
+ if (removed.length === 0) return;
3003
+ super.removeSlots(removed);
3004
+ }
3005
+ clear() {
3006
+ this.membership.clear();
3007
+ this.membershipSeeded = false;
3008
+ super.clear();
3009
+ }
3010
+ membershipOf() {
3011
+ if (!this.membershipSeeded) {
3012
+ this.membership.clear();
3013
+ for (const slot of this.index.getSlots()) {
3014
+ this.membership.set(slot.pk, slot);
3015
+ }
3016
+ this.membershipSeeded = true;
3017
+ }
3018
+ return this.membership;
3019
+ }
3020
+ getEntities() {
3021
+ return super.getEntities();
3022
+ }
3023
+ resolveRequiredSlot(pk) {
3024
+ const slot = this.resolveSlot(pk);
3025
+ if (!slot) return { pk, item: void 0 };
3026
+ return slot;
3027
+ }
3028
+ };
3029
+
3030
+ // src/core/OIMDerivedCollectionGlobalIndexArrayBased.ts
3031
+ var OIMDerivedCollectionGlobalIndexArrayBased = class extends OIMReactiveCollectionGlobalIndexManualArrayBased {
3032
+ constructor(queue, collection, opts) {
3033
+ super(queue, { collection, indexOptions: opts.indexOptions });
3034
+ this.presentPks = /* @__PURE__ */ new Set();
3035
+ // Last known sort value per pk (only with `orderBy`), so an update touching
3036
+ // an unrelated field can skip re-sorting when the value is unchanged.
3037
+ this.orderValueByPk = /* @__PURE__ */ new Map();
3038
+ this.onCollectionUpdate = (pks) => {
3039
+ if (pks.length === 0) {
3040
+ this.rebuildFromCollection();
3041
+ return;
3042
+ }
3043
+ const ordered = !!(this.compareEntities || this.orderBy);
3044
+ let needsSort = false;
3045
+ for (const pk of pks) {
3046
+ const prev = this.presentPks.has(pk);
3047
+ const slot = this.collection.getSlotByPk(pk);
3048
+ const entity = slot?.item;
3049
+ const next = entity !== void 0 && (!this.filter || this.filter(entity));
3050
+ let orderChanged = false;
3051
+ if (this.orderBy) {
3052
+ if (!next || entity === void 0) {
3053
+ this.orderValueByPk.delete(pk);
3054
+ } else {
3055
+ const value = this.orderBy(entity);
3056
+ orderChanged = !this.orderValueByPk.has(pk) || this.orderValueByPk.get(pk) !== value;
3057
+ this.orderValueByPk.set(pk, value);
3058
+ }
3059
+ } else if (this.compareEntities && next) {
3060
+ orderChanged = true;
3061
+ }
3062
+ if (prev && !next) {
3063
+ super.removePks([pk]);
3064
+ this.presentPks.delete(pk);
3065
+ } else if (!prev && next) {
3066
+ super.addPks([pk]);
3067
+ this.presentPks.add(pk);
3068
+ if (ordered) needsSort = true;
3069
+ } else if (prev && next && orderChanged) {
3070
+ needsSort = true;
3071
+ }
3072
+ }
3073
+ if (ordered && needsSort) {
3074
+ super.setSlots(this.sortSlots(this.index.getSlots()));
3075
+ }
3076
+ };
3077
+ this.collection = collection;
3078
+ this.compareEntities = opts.compareEntities;
3079
+ this.orderBy = opts.orderBy;
3080
+ this.filter = opts.filter;
3081
+ this.unsubscribeFromCollection = collection.emitter.on(
3082
+ 0 /* UPDATE */,
3083
+ (payload) => this.onCollectionUpdate(payload.pks)
3084
+ );
3085
+ if (opts.buildInitial !== false) {
3086
+ this.rebuildFromCollection();
3087
+ }
3088
+ }
3089
+ rebuildFromCollection() {
3090
+ this.presentPks.clear();
3091
+ this.orderValueByPk.clear();
3092
+ super.clear();
3093
+ const slots = [];
3094
+ for (const slot of this.collection.getAllSlots()) {
3095
+ if (slot.item === void 0) continue;
3096
+ if (this.filter && !this.filter(slot.item)) continue;
3097
+ this.presentPks.add(slot.pk);
3098
+ if (this.orderBy) {
3099
+ this.orderValueByPk.set(slot.pk, this.orderBy(slot.item));
3100
+ }
3101
+ slots.push(slot);
3102
+ }
3103
+ super.setSlots(this.sortSlots(slots));
3104
+ }
3105
+ clear() {
3106
+ this.presentPks.clear();
3107
+ this.orderValueByPk.clear();
3108
+ super.clear();
3109
+ }
3110
+ destroy() {
3111
+ this.unsubscribeFromCollection();
3112
+ this.presentPks.clear();
3113
+ this.orderValueByPk.clear();
3114
+ super.destroy();
3115
+ }
3116
+ sortSlots(slots) {
3117
+ if (!this.compareEntities && !this.orderBy) return slots.slice();
3118
+ return slots.slice().sort((a, b) => {
3119
+ const aItem = a.item;
3120
+ const bItem = b.item;
3121
+ if (aItem === void 0 || bItem === void 0) return 0;
3122
+ if (this.compareEntities) {
3123
+ return this.compareEntities(aItem, bItem);
3124
+ }
3125
+ const aValue = this.orderBy(aItem);
3126
+ const bValue = this.orderBy(bItem);
3127
+ if (aValue < bValue) return -1;
3128
+ if (aValue > bValue) return 1;
3129
+ return 0;
3130
+ });
3131
+ }
3132
+ };
3133
+
3134
+ // src/core/OIMDerivedCollectionGlobalIndexSetBased.ts
3135
+ var OIMDerivedCollectionGlobalIndexSetBased = class extends OIMReactiveCollectionGlobalIndexManualSetBased {
3136
+ constructor(queue, collection, opts) {
3137
+ super(queue, { collection, indexOptions: opts.indexOptions });
3138
+ this.presentPks = /* @__PURE__ */ new Set();
3139
+ this.onCollectionUpdate = (pks) => {
3140
+ if (pks.length === 0) {
3141
+ this.rebuildFromCollection();
3142
+ return;
3143
+ }
3144
+ for (const pk of pks) {
3145
+ const prev = this.presentPks.has(pk);
3146
+ const slot = this.collection.getSlotByPk(pk);
3147
+ const entity = slot?.item;
3148
+ const next = entity !== void 0 && (!this.filter || this.filter(entity));
3149
+ if (prev && !next) {
3150
+ super.removePks([pk]);
3151
+ this.presentPks.delete(pk);
3152
+ } else if (!prev && next) {
3153
+ super.addPks([pk]);
3154
+ this.presentPks.add(pk);
3155
+ }
3156
+ }
3157
+ };
3158
+ this.collection = collection;
3159
+ this.filter = opts.filter;
3160
+ this.unsubscribeFromCollection = collection.emitter.on(
3161
+ 0 /* UPDATE */,
3162
+ (payload) => this.onCollectionUpdate(payload.pks)
3163
+ );
3164
+ if (opts.buildInitial !== false) {
3165
+ this.rebuildFromCollection();
3166
+ }
3167
+ }
3168
+ rebuildFromCollection() {
3169
+ this.presentPks.clear();
3170
+ super.clear();
3171
+ const slots = /* @__PURE__ */ new Set();
3172
+ for (const slot of this.collection.getAllSlots()) {
3173
+ if (slot.item === void 0) continue;
3174
+ if (this.filter && !this.filter(slot.item)) continue;
3175
+ this.presentPks.add(slot.pk);
3176
+ slots.add(slot);
3177
+ }
3178
+ super.setSlots(slots);
3179
+ }
3180
+ clear() {
3181
+ this.presentPks.clear();
3182
+ super.clear();
3183
+ }
3184
+ destroy() {
3185
+ this.unsubscribeFromCollection();
3186
+ this.presentPks.clear();
2481
3187
  super.destroy();
2482
3188
  }
2483
- sortSlots(slots) {
2484
- if (!this.compareEntities && !this.orderBy) return slots.slice();
2485
- return slots.slice().sort((a, b) => {
2486
- const aItem = a.item;
2487
- const bItem = b.item;
2488
- if (aItem === void 0 || bItem === void 0) return 0;
2489
- if (this.compareEntities) {
2490
- return this.compareEntities(aItem, bItem);
2491
- }
2492
- const aValue = this.orderBy(aItem);
2493
- const bValue = this.orderBy(bItem);
2494
- if (aValue < bValue) return -1;
2495
- if (aValue > bValue) return 1;
2496
- return 0;
2497
- });
2498
- }
2499
- normalizeKeys(keys) {
2500
- if (keys === void 0 || keys === null) return [];
2501
- const rawKeys = Array.isArray(keys) ? keys : [keys];
2502
- const result = [];
2503
- const seen = /* @__PURE__ */ new Set();
2504
- for (const key of rawKeys) {
2505
- if (seen.has(key)) continue;
2506
- seen.add(key);
2507
- result.push(key);
2508
- }
2509
- return result;
2510
- }
2511
3189
  };
2512
3190
 
2513
3191
  // src/core/OIMCollectionIndexFactory.ts
@@ -2552,6 +3230,52 @@ var OIMCollectionIndexFactory = class {
2552
3230
  }
2553
3231
  );
2554
3232
  }
3233
+ /**
3234
+ * Keyless (whole-collection / "all") manual array-based index. No key —
3235
+ * write pks directly with `setPks`/`addPks`/`removePks`.
3236
+ */
3237
+ arrayBasedGlobalIndex(opts = {}) {
3238
+ return new OIMReactiveCollectionGlobalIndexManualArrayBased(this.queue, {
3239
+ collection: this.collection,
3240
+ indexOptions: opts.indexOptions
3241
+ });
3242
+ }
3243
+ /** Keyless (whole-collection) manual set-based index. */
3244
+ setBasedGlobalIndex(opts = {}) {
3245
+ return new OIMReactiveCollectionGlobalIndexManualSetBased(this.queue, {
3246
+ collection: this.collection,
3247
+ indexOptions: opts.indexOptions
3248
+ });
3249
+ }
3250
+ /**
3251
+ * Keyless ordered list auto-derived from the whole collection. Pass
3252
+ * `orderBy`/`compareEntities` for order, `filter` to include a subset.
3253
+ */
3254
+ derivedArrayGlobalIndex(opts = {}) {
3255
+ return new OIMDerivedCollectionGlobalIndexArrayBased(
3256
+ this.queue,
3257
+ this.collection,
3258
+ {
3259
+ buildInitial: opts.buildInitial,
3260
+ compareEntities: opts.compareEntities,
3261
+ orderBy: opts.orderBy,
3262
+ filter: opts.filter,
3263
+ indexOptions: opts.indexOptions
3264
+ }
3265
+ );
3266
+ }
3267
+ /** Keyless set auto-derived from the whole collection. */
3268
+ derivedSetGlobalIndex(opts = {}) {
3269
+ return new OIMDerivedCollectionGlobalIndexSetBased(
3270
+ this.queue,
3271
+ this.collection,
3272
+ {
3273
+ buildInitial: opts.buildInitial,
3274
+ filter: opts.filter,
3275
+ indexOptions: opts.indexOptions
3276
+ }
3277
+ );
3278
+ }
2555
3279
  orderedIndex() {
2556
3280
  return new OIMCollectionIndexManualOrderedArrayBased({
2557
3281
  collection: this.collection
@@ -3429,6 +4153,137 @@ var OIMEntitiesByIndexKeySetBasedSelector = class extends OIMSelector {
3429
4153
  }
3430
4154
  };
3431
4155
 
4156
+ // src/modules/selector/core/OIMSelectorSourceDependencyEntitiesByGlobalIndexArrayBased.ts
4157
+ var OIMSelectorSourceDependencyEntitiesByGlobalIndexArrayBased = class {
4158
+ constructor(collection, reactiveIndex) {
4159
+ this.collection = collection;
4160
+ this.reactiveIndex = reactiveIndex;
4161
+ this.currentPks = [];
4162
+ }
4163
+ subscribe(onUpdate) {
4164
+ const resubscribeCollection = () => {
4165
+ const nextPks = this.reactiveIndex.getPks();
4166
+ if (this.sameArray(this.currentPks, nextPks)) return;
4167
+ this.unsubscribeFromCollectionKeys?.();
4168
+ this.unsubscribeFromCollectionKeys = void 0;
4169
+ this.currentPks = nextPks;
4170
+ if (this.currentPks.length === 0) return;
4171
+ this.unsubscribeFromCollectionKeys = this.collection.subscribeOnKeys(this.currentPks, onUpdate);
4172
+ };
4173
+ const onIndexUpdate = () => {
4174
+ resubscribeCollection();
4175
+ onUpdate();
4176
+ };
4177
+ resubscribeCollection();
4178
+ const unsubscribeFromIndex = this.reactiveIndex.subscribe(onIndexUpdate);
4179
+ return () => {
4180
+ unsubscribeFromIndex();
4181
+ this.unsubscribeFromCollectionKeys?.();
4182
+ this.unsubscribeFromCollectionKeys = void 0;
4183
+ this.currentPks = [];
4184
+ };
4185
+ }
4186
+ sameArray(a, b) {
4187
+ if (a === b) return true;
4188
+ if (a.length !== b.length) return false;
4189
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
4190
+ return true;
4191
+ }
4192
+ };
4193
+
4194
+ // src/modules/selector/core/OIMEntitiesByGlobalIndexArrayBasedSelector.ts
4195
+ var OIMEntitiesByGlobalIndexArrayBasedSelector = class extends OIMSelector {
4196
+ constructor(runtime, collection, reactiveIndex) {
4197
+ super(runtime, [
4198
+ new OIMSelectorSourceDependencyEntitiesByGlobalIndexArrayBased(collection, reactiveIndex)
4199
+ ]);
4200
+ this.collection = collection;
4201
+ this.reactiveIndex = reactiveIndex;
4202
+ }
4203
+ getValue() {
4204
+ const pks = this.reactiveIndex.getPks();
4205
+ const entities = [];
4206
+ entities.length = pks.length;
4207
+ for (let i = 0; i < pks.length; i++) {
4208
+ entities[i] = this.collection.getOneByPk(pks[i]);
4209
+ }
4210
+ return entities;
4211
+ }
4212
+ areEqual(prev, next) {
4213
+ if (prev === next) return true;
4214
+ if (prev.length !== next.length) return false;
4215
+ for (let i = 0; i < prev.length; i++)
4216
+ if (prev[i] !== next[i]) return false;
4217
+ return true;
4218
+ }
4219
+ };
4220
+
4221
+ // src/modules/selector/core/OIMSelectorSourceDependencyEntitiesByGlobalIndexSetBased.ts
4222
+ var OIMSelectorSourceDependencyEntitiesByGlobalIndexSetBased = class {
4223
+ constructor(collection, reactiveIndex) {
4224
+ this.collection = collection;
4225
+ this.reactiveIndex = reactiveIndex;
4226
+ this.currentPks = [];
4227
+ }
4228
+ subscribe(onUpdate) {
4229
+ const resubscribeCollection = () => {
4230
+ const nextPks = Array.from(this.reactiveIndex.getPks());
4231
+ if (this.sameArray(this.currentPks, nextPks)) return;
4232
+ this.unsubscribeFromCollectionKeys?.();
4233
+ this.unsubscribeFromCollectionKeys = void 0;
4234
+ this.currentPks = nextPks;
4235
+ if (this.currentPks.length === 0) return;
4236
+ this.unsubscribeFromCollectionKeys = this.collection.subscribeOnKeys(this.currentPks, onUpdate);
4237
+ };
4238
+ const onIndexUpdate = () => {
4239
+ resubscribeCollection();
4240
+ onUpdate();
4241
+ };
4242
+ resubscribeCollection();
4243
+ const unsubscribeFromIndex = this.reactiveIndex.subscribe(onIndexUpdate);
4244
+ return () => {
4245
+ unsubscribeFromIndex();
4246
+ this.unsubscribeFromCollectionKeys?.();
4247
+ this.unsubscribeFromCollectionKeys = void 0;
4248
+ this.currentPks = [];
4249
+ };
4250
+ }
4251
+ sameArray(a, b) {
4252
+ if (a === b) return true;
4253
+ if (a.length !== b.length) return false;
4254
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
4255
+ return true;
4256
+ }
4257
+ };
4258
+
4259
+ // src/modules/selector/core/OIMEntitiesByGlobalIndexSetBasedSelector.ts
4260
+ var OIMEntitiesByGlobalIndexSetBasedSelector = class extends OIMSelector {
4261
+ constructor(runtime, collection, reactiveIndex) {
4262
+ super(runtime, [
4263
+ new OIMSelectorSourceDependencyEntitiesByGlobalIndexSetBased(collection, reactiveIndex)
4264
+ ]);
4265
+ this.collection = collection;
4266
+ this.reactiveIndex = reactiveIndex;
4267
+ }
4268
+ getValue() {
4269
+ const pks = this.reactiveIndex.getPks();
4270
+ const entities = [];
4271
+ entities.length = pks.size;
4272
+ let writeIndex = 0;
4273
+ for (const pk of pks) {
4274
+ entities[writeIndex++] = this.collection.getOneByPk(pk);
4275
+ }
4276
+ return entities;
4277
+ }
4278
+ areEqual(prev, next) {
4279
+ if (prev === next) return true;
4280
+ if (prev.length !== next.length) return false;
4281
+ for (let i = 0; i < prev.length; i++)
4282
+ if (prev[i] !== next[i]) return false;
4283
+ return true;
4284
+ }
4285
+ };
4286
+
3432
4287
  // src/dx/OIMCollectionSelectors.ts
3433
4288
  var OIMCollectionSelectors = class {
3434
4289
  constructor(queue, collection) {
@@ -3461,6 +4316,22 @@ var OIMCollectionSelectors = class {
3461
4316
  key
3462
4317
  );
3463
4318
  }
4319
+ /** Entities of a keyless (whole-collection) array-based index, ordered. */
4320
+ entitiesByArrayGlobalIndex(index) {
4321
+ return new OIMEntitiesByGlobalIndexArrayBasedSelector(
4322
+ this.runtime,
4323
+ this.collection,
4324
+ index
4325
+ );
4326
+ }
4327
+ /** Entities of a keyless (whole-collection) set-based index. */
4328
+ entitiesBySetGlobalIndex(index) {
4329
+ return new OIMEntitiesByGlobalIndexSetBasedSelector(
4330
+ this.runtime,
4331
+ this.collection,
4332
+ index
4333
+ );
4334
+ }
3464
4335
  };
3465
4336
 
3466
4337
  // src/dx/OIMCollectionKit.ts
@@ -3662,7 +4533,7 @@ var OIMCollectionChangedFields = class {
3662
4533
 
3663
4534
  // src/modules/wrapper/index/OIMOrderedListMappedCommandStream.ts
3664
4535
  var OIMOrderedListMappedCommandStream = class _OIMOrderedListMappedCommandStream {
3665
- constructor(source, opts) {
4536
+ constructor(source, create) {
3666
4537
  /** Per-key positional mirror of the mapped elements. */
3667
4538
  this.mirror = /* @__PURE__ */ new Map();
3668
4539
  /** Mapped commands produced for the current delivery, per key. */
@@ -3670,8 +4541,7 @@ var OIMOrderedListMappedCommandStream = class _OIMOrderedListMappedCommandStream
3670
4541
  this.subscribers = /* @__PURE__ */ new Map();
3671
4542
  this.sourceUnsubscribers = /* @__PURE__ */ new Map();
3672
4543
  this.source = source;
3673
- this.create = opts.create;
3674
- this.destroyItem = opts.destroy;
4544
+ this.create = create;
3675
4545
  }
3676
4546
  subscribeCommands(key, handler) {
3677
4547
  this.ensureWired(key);
@@ -3698,20 +4568,15 @@ var OIMOrderedListMappedCommandStream = class _OIMOrderedListMappedCommandStream
3698
4568
  return this.mirror.get(key) ?? [];
3699
4569
  }
3700
4570
  /** Map this source again, chaining the projection. */
3701
- map(opts) {
4571
+ map(create) {
3702
4572
  return new _OIMOrderedListMappedCommandStream(
3703
4573
  this,
3704
- opts
4574
+ create
3705
4575
  );
3706
4576
  }
3707
4577
  destroy() {
3708
4578
  this.sourceUnsubscribers.forEach((unsubscribe) => unsubscribe());
3709
4579
  this.sourceUnsubscribers.clear();
3710
- if (this.destroyItem) {
3711
- this.mirror.forEach(
3712
- (items) => items.forEach((item) => this.destroyItem(item))
3713
- );
3714
- }
3715
4580
  this.mirror.clear();
3716
4581
  this.buffer.clear();
3717
4582
  this.subscribers.clear();
@@ -3751,12 +4616,7 @@ var OIMOrderedListMappedCommandStream = class _OIMOrderedListMappedCommandStream
3751
4616
  }
3752
4617
  case "remove": {
3753
4618
  const count = cmd.count ?? 1;
3754
- const removed = mirror.splice(cmd.index, count);
3755
- if (this.destroyItem) {
3756
- for (let r = 0; r < removed.length; r++) {
3757
- this.destroyItem(removed[r]);
3758
- }
3759
- }
4619
+ mirror.splice(cmd.index, count);
3760
4620
  out.push({ type: "remove", index: cmd.index, count });
3761
4621
  break;
3762
4622
  }
@@ -3774,19 +4634,11 @@ var OIMOrderedListMappedCommandStream = class _OIMOrderedListMappedCommandStream
3774
4634
  }
3775
4635
  case "set": {
3776
4636
  const mapped = this.create(cmd.item);
3777
- const replaced = mirror.splice(cmd.index, 1, mapped);
3778
- if (this.destroyItem && replaced.length > 0) {
3779
- this.destroyItem(replaced[0]);
3780
- }
4637
+ mirror.splice(cmd.index, 1, mapped);
3781
4638
  out.push({ type: "set", index: cmd.index, item: mapped });
3782
4639
  break;
3783
4640
  }
3784
4641
  case "reset": {
3785
- if (this.destroyItem) {
3786
- for (let r = 0; r < mirror.length; r++) {
3787
- this.destroyItem(mirror[r]);
3788
- }
3789
- }
3790
4642
  const mapped = cmd.items.map((item) => this.create(item));
3791
4643
  mirror = mapped;
3792
4644
  this.mirror.set(key, mapped);
@@ -3812,8 +4664,224 @@ var OIMOrderedListMappedCommandStream = class _OIMOrderedListMappedCommandStream
3812
4664
  };
3813
4665
 
3814
4666
  // src/modules/wrapper/index/createOIMOrderedListMappedCommandStream.ts
3815
- function createOIMOrderedListMappedCommandStream(source, opts) {
3816
- return new OIMOrderedListMappedCommandStream(source, opts);
4667
+ function createOIMOrderedListMappedCommandStream(source, create) {
4668
+ return new OIMOrderedListMappedCommandStream(
4669
+ source,
4670
+ create
4671
+ );
4672
+ }
4673
+
4674
+ // src/modules/wrapper/index/OIMIndexSlotMap.ts
4675
+ var OIMIndexSlotMap = class _OIMIndexSlotMap {
4676
+ constructor(index, create) {
4677
+ this.cache = /* @__PURE__ */ new WeakMap();
4678
+ this.index = index;
4679
+ this.create = create;
4680
+ }
4681
+ /** The mapped object for a slot, created once and cached by slot identity. */
4682
+ get(slot) {
4683
+ let mapped = this.cache.get(slot);
4684
+ if (mapped === void 0 && !this.cache.has(slot)) {
4685
+ mapped = this.create(slot);
4686
+ this.cache.set(slot, mapped);
4687
+ }
4688
+ return mapped;
4689
+ }
4690
+ /**
4691
+ * Mapped objects for every slot under `key`, with stable references. For a
4692
+ * set-based index the order is unspecified (as the set is); for an
4693
+ * array-based index it follows the index order.
4694
+ */
4695
+ getByKey(key) {
4696
+ const result = [];
4697
+ for (const slot of this.index.getSlotsByKey(key)) {
4698
+ result.push(this.get(slot));
4699
+ }
4700
+ return result;
4701
+ }
4702
+ /**
4703
+ * Chain another projection. `map(f)` returns a slot map over the SAME index
4704
+ * whose objects are `f(this.get(slot))`, cached by slot identity — so both
4705
+ * levels hand back stable references and each `create` runs once per slot.
4706
+ * Mirrors the command stream's `.map()`.
4707
+ */
4708
+ map(create) {
4709
+ return new _OIMIndexSlotMap(
4710
+ this.index,
4711
+ (slot) => create(this.get(slot))
4712
+ );
4713
+ }
4714
+ /** Subscribe to a key's changes — passthrough to the index. */
4715
+ subscribeOnKey(key, handler) {
4716
+ return this.index.subscribeOnKey(key, handler);
4717
+ }
4718
+ /** Subscribe to several keys — passthrough to the index. */
4719
+ subscribeOnKeys(keys, handler) {
4720
+ return this.index.subscribeOnKeys(keys, handler);
4721
+ }
4722
+ };
4723
+
4724
+ // src/modules/wrapper/index/createOIMIndexSlotMap.ts
4725
+ function createOIMIndexSlotMap(index, create) {
4726
+ return new OIMIndexSlotMap(index, create);
4727
+ }
4728
+
4729
+ // src/modules/wrapper/index/diffOrderedListByPk.ts
4730
+ function diffOrderedListByPk(prev, next) {
4731
+ const commands = [];
4732
+ const working = prev.slice();
4733
+ const nextPks = /* @__PURE__ */ new Set();
4734
+ for (let i = 0; i < next.length; i++) nextPks.add(next[i].pk);
4735
+ for (let i = working.length - 1; i >= 0; i--) {
4736
+ if (!nextPks.has(working[i].pk)) {
4737
+ commands.push({ type: "remove", index: i });
4738
+ working.splice(i, 1);
4739
+ }
4740
+ }
4741
+ const workingPos = /* @__PURE__ */ new Map();
4742
+ for (let i = 0; i < working.length; i++) workingPos.set(working[i].pk, i);
4743
+ const commonNextJ = [];
4744
+ const seq = [];
4745
+ for (let j = 0; j < next.length; j++) {
4746
+ const p = workingPos.get(next[j].pk);
4747
+ if (p !== void 0) {
4748
+ commonNextJ.push(j);
4749
+ seq.push(p);
4750
+ }
4751
+ }
4752
+ const anchorJ = /* @__PURE__ */ new Set();
4753
+ for (const s of longestIncreasingSubsequence(seq)) {
4754
+ anchorJ.add(commonNextJ[s]);
4755
+ }
4756
+ for (let j = next.length - 1; j >= 0; j--) {
4757
+ if (anchorJ.has(j)) continue;
4758
+ const target = next[j];
4759
+ const refIdx = j + 1 < next.length ? indexByPk(working, next[j + 1].pk) : working.length;
4760
+ const p = indexByPk(working, target.pk);
4761
+ if (p === -1) {
4762
+ commands.push({ type: "insert", index: refIdx, item: target });
4763
+ working.splice(refIdx, 0, target);
4764
+ } else {
4765
+ const to = p < refIdx ? refIdx - 1 : refIdx;
4766
+ if (p !== to) {
4767
+ commands.push({ type: "move", from: p, to });
4768
+ working.splice(p, 1);
4769
+ working.splice(to, 0, target);
4770
+ }
4771
+ }
4772
+ }
4773
+ return commands;
4774
+ }
4775
+ function indexByPk(items, pk) {
4776
+ for (let i = 0; i < items.length; i++) {
4777
+ if (items[i].pk === pk) return i;
4778
+ }
4779
+ return -1;
4780
+ }
4781
+ function longestIncreasingSubsequence(seq) {
4782
+ const n = seq.length;
4783
+ if (n === 0) return [];
4784
+ const predecessor = new Array(n).fill(-1);
4785
+ const tails = [];
4786
+ for (let i = 0; i < n; i++) {
4787
+ let lo = 0;
4788
+ let hi = tails.length;
4789
+ while (lo < hi) {
4790
+ const mid = lo + hi >> 1;
4791
+ if (seq[tails[mid]] < seq[i]) lo = mid + 1;
4792
+ else hi = mid;
4793
+ }
4794
+ if (lo > 0) predecessor[i] = tails[lo - 1];
4795
+ if (lo === tails.length) tails.push(i);
4796
+ else tails[lo] = i;
4797
+ }
4798
+ const result = [];
4799
+ let k = tails[tails.length - 1];
4800
+ while (k !== -1) {
4801
+ result.push(k);
4802
+ k = predecessor[k];
4803
+ }
4804
+ result.reverse();
4805
+ return result;
4806
+ }
4807
+
4808
+ // src/modules/wrapper/index/OIMOrderedListCommandStreamDiffDriven.ts
4809
+ var OIMOrderedListCommandStreamDiffDriven = class extends OIMOrderedListCommandBuffer {
4810
+ constructor(queue, index, opts) {
4811
+ super(queue);
4812
+ this.prevByKey = /* @__PURE__ */ new Map();
4813
+ this.indexUnsubscribeByKey = /* @__PURE__ */ new Map();
4814
+ this.index = index;
4815
+ this.resetThreshold = opts?.resetThreshold ?? 0;
4816
+ }
4817
+ getItemsByKey(key) {
4818
+ this.ensureWired(key);
4819
+ return this.currentSlots(key);
4820
+ }
4821
+ subscribeCommands(key, handler) {
4822
+ this.ensureWired(key);
4823
+ return super.subscribeCommands(key, handler);
4824
+ }
4825
+ destroy() {
4826
+ this.indexUnsubscribeByKey.forEach((unsubscribe) => unsubscribe());
4827
+ this.indexUnsubscribeByKey.clear();
4828
+ this.prevByKey.clear();
4829
+ super.destroy();
4830
+ }
4831
+ currentSlots(key) {
4832
+ return this.index.getSlotsByKey(key);
4833
+ }
4834
+ /** Snapshot the current order and subscribe to the index once per key. */
4835
+ ensureWired(key) {
4836
+ if (this.indexUnsubscribeByKey.has(key)) return;
4837
+ this.prevByKey.set(key, this.currentSlots(key).slice());
4838
+ const unsubscribe = this.index.subscribeOnKey(
4839
+ key,
4840
+ () => this.onIndexChange(key)
4841
+ );
4842
+ this.indexUnsubscribeByKey.set(key, unsubscribe);
4843
+ }
4844
+ onIndexChange(key) {
4845
+ const prev = this.prevByKey.get(key) ?? [];
4846
+ const next = this.currentSlots(key);
4847
+ this.emitDiff(key, prev, next);
4848
+ this.prevByKey.set(key, next.slice());
4849
+ }
4850
+ emitDiff(key, prev, next) {
4851
+ if (sameOrderByPk(prev, next)) return;
4852
+ const commons = countCommonPks(prev, next);
4853
+ const larger = Math.max(prev.length, next.length);
4854
+ const wholeChange = prev.length === 0 || next.length === 0 || commons === 0 || this.resetThreshold > 0 && commons / larger < this.resetThreshold;
4855
+ if (wholeChange) {
4856
+ this.appendResetCommand(key, next);
4857
+ return;
4858
+ }
4859
+ const commands = diffOrderedListByPk(prev, next);
4860
+ for (let i = 0; i < commands.length; i++) {
4861
+ this.appendCommand(key, commands[i]);
4862
+ }
4863
+ }
4864
+ };
4865
+ function sameOrderByPk(a, b) {
4866
+ if (a.length !== b.length) return false;
4867
+ for (let i = 0; i < a.length; i++) {
4868
+ if (a[i].pk !== b[i].pk) return false;
4869
+ }
4870
+ return true;
4871
+ }
4872
+ function countCommonPks(prev, next) {
4873
+ const prevPks = /* @__PURE__ */ new Set();
4874
+ for (let i = 0; i < prev.length; i++) prevPks.add(prev[i].pk);
4875
+ let common = 0;
4876
+ for (let i = 0; i < next.length; i++) {
4877
+ if (prevPks.has(next[i].pk)) common++;
4878
+ }
4879
+ return common;
4880
+ }
4881
+
4882
+ // src/modules/wrapper/index/createOIMOrderedListCommandStreamDiffDriven.ts
4883
+ function createOIMOrderedListCommandStreamDiffDriven(queue, index, opts) {
4884
+ return new OIMOrderedListCommandStreamDiffDriven(queue, index, opts);
3817
4885
  }
3818
4886
 
3819
4887
  // src/core/event-queue-scheduler/OIMEventQueueSchedulerAnimationFrame.ts
@@ -3940,6 +5008,15 @@ var OIMEventQueueSchedulerImmediate = class extends OIMEventQueueScheduler {
3940
5008
  }
3941
5009
  };
3942
5010
 
5011
+ // src/core/event-queue-scheduler/OIMEventQueueSchedulerSync.ts
5012
+ var OIMEventQueueSchedulerSync = class extends OIMEventQueueScheduler {
5013
+ schedule() {
5014
+ this.flush();
5015
+ }
5016
+ cancel() {
5017
+ }
5018
+ };
5019
+
3943
5020
  // src/core/event-queue-scheduler/OIMEventQueueSchedulerFactory.ts
3944
5021
  var OIMEventQueueSchedulerFactory = class {
3945
5022
  /**
@@ -3957,6 +5034,8 @@ var OIMEventQueueSchedulerFactory = class {
3957
5034
  }
3958
5035
  case "immediate":
3959
5036
  return new OIMEventQueueSchedulerImmediate();
5037
+ case "sync":
5038
+ return new OIMEventQueueSchedulerSync();
3960
5039
  default:
3961
5040
  throw new Error(`Unknown scheduler type: ${type}`);
3962
5041
  }
@@ -3980,11 +5059,18 @@ var OIMEventQueueSchedulerFactory = class {
3980
5059
  return new OIMEventQueueSchedulerTimeout(delay);
3981
5060
  }
3982
5061
  /**
3983
- * Create an immediate scheduler (fastest execution).
5062
+ * Create an immediate scheduler (setImmediate / MessageChannel / setTimeout(0)).
3984
5063
  */
3985
5064
  static createImmediate() {
3986
5065
  return new OIMEventQueueSchedulerImmediate();
3987
5066
  }
5067
+ /**
5068
+ * Create a synchronous scheduler — flushes in the same call stack, no
5069
+ * batching. Debug/diagnostic use only (see {@link OIMEventQueueSchedulerSync}).
5070
+ */
5071
+ static createSync() {
5072
+ return new OIMEventQueueSchedulerSync();
5073
+ }
3988
5074
  };
3989
5075
 
3990
5076
  // src/constants/OIMDBSettings.ts
@@ -4393,6 +5479,7 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
4393
5479
  EOIMIndexEventType,
4394
5480
  EOIMObjectEventType,
4395
5481
  OIMCarrierKeyedEmitter,
5482
+ OIMCarrierSingleEmitter,
4396
5483
  OIMCollection,
4397
5484
  OIMCollectionByPkSelector,
4398
5485
  OIMCollectionByPksSelector,
@@ -4407,6 +5494,8 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
4407
5494
  OIMComputeRuntime,
4408
5495
  OIMComputed,
4409
5496
  OIMDBSettings,
5497
+ OIMDerivedCollectionGlobalIndexArrayBased,
5498
+ OIMDerivedCollectionGlobalIndexSetBased,
4410
5499
  OIMDerivedCollectionIndexArrayBased,
4411
5500
  OIMDerivedCollectionIndexSetBased,
4412
5501
  OIMEffect,
@@ -4415,6 +5504,8 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
4415
5504
  OIMEffectDependencyKeyedCollection,
4416
5505
  OIMEffectDependencyKeyedIndex,
4417
5506
  OIMEffectDependencyKeyedObject,
5507
+ OIMEntitiesByGlobalIndexArrayBasedSelector,
5508
+ OIMEntitiesByGlobalIndexSetBasedSelector,
4418
5509
  OIMEntitiesByIndexKeyArrayBasedSelector,
4419
5510
  OIMEntitiesByIndexKeySetBasedSelector,
4420
5511
  OIMEntityUpdaterFactory,
@@ -4425,7 +5516,13 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
4425
5516
  OIMEventQueueSchedulerFactory,
4426
5517
  OIMEventQueueSchedulerImmediate,
4427
5518
  OIMEventQueueSchedulerMicrotask,
5519
+ OIMEventQueueSchedulerSync,
4428
5520
  OIMEventQueueSchedulerTimeout,
5521
+ OIMGlobalIndex,
5522
+ OIMGlobalIndexArrayBased,
5523
+ OIMGlobalIndexManualArrayBased,
5524
+ OIMGlobalIndexManualSetBased,
5525
+ OIMGlobalIndexSetBased,
4429
5526
  OIMIndex,
4430
5527
  OIMIndexArrayBased,
4431
5528
  OIMIndexComparatorFactory,
@@ -4437,6 +5534,7 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
4437
5534
  OIMIndexPksByKeysArrayBasedSelector,
4438
5535
  OIMIndexPksByKeysSetBasedSelector,
4439
5536
  OIMIndexSetBased,
5537
+ OIMIndexSlotMap,
4440
5538
  OIMIndexStoreArrayBased,
4441
5539
  OIMIndexStoreMapDrivenArrayBased,
4442
5540
  OIMIndexStoreMapDrivenSetBased,
@@ -4448,12 +5546,21 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
4448
5546
  OIMObjectStoreRecordDriven,
4449
5547
  OIMObjectValueByKeySelector,
4450
5548
  OIMObjectValuesByKeysSelector,
5549
+ OIMOrderedListCommandBuffer,
4451
5550
  OIMOrderedListCommandStream,
5551
+ OIMOrderedListCommandStreamDiffDriven,
4452
5552
  OIMOrderedListMappedCommandStream,
4453
5553
  OIMPkSelectorFactory,
4454
5554
  OIMReactiveCollection,
5555
+ OIMReactiveCollectionGlobalIndexManualArrayBased,
5556
+ OIMReactiveCollectionGlobalIndexManualSetBased,
4455
5557
  OIMReactiveCollectionIndexManualArrayBased,
4456
5558
  OIMReactiveCollectionIndexManualSetBased,
5559
+ OIMReactiveGlobalIndex,
5560
+ OIMReactiveGlobalIndexArrayBased,
5561
+ OIMReactiveGlobalIndexManualArrayBased,
5562
+ OIMReactiveGlobalIndexManualSetBased,
5563
+ OIMReactiveGlobalIndexSetBased,
4457
5564
  OIMReactiveIndex,
4458
5565
  OIMReactiveIndexArrayBased,
4459
5566
  OIMReactiveIndexManualArrayBased,
@@ -4465,5 +5572,8 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
4465
5572
  createMergeEntityUpdater,
4466
5573
  createOIMCollectionIndexFactory,
4467
5574
  createOIMCollectionKit,
4468
- createOIMOrderedListMappedCommandStream
5575
+ createOIMIndexSlotMap,
5576
+ createOIMOrderedListCommandStreamDiffDriven,
5577
+ createOIMOrderedListMappedCommandStream,
5578
+ diffOrderedListByPk
4469
5579
  });