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