@oimdb/core 3.10.0 → 3.11.1
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/README.md +18 -1
- package/dist/index.cjs +748 -446
- package/dist/index.d.cts +319 -120
- package/dist/index.d.ts +319 -120
- package/dist/index.js +742 -445
- package/llms.txt +79 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -44,6 +44,7 @@ __export(index_exports, {
|
|
|
44
44
|
OIMComputeRuntime: () => OIMComputeRuntime,
|
|
45
45
|
OIMComputed: () => OIMComputed,
|
|
46
46
|
OIMDBSettings: () => OIMDBSettings,
|
|
47
|
+
OIMDerivedCollection: () => OIMDerivedCollection,
|
|
47
48
|
OIMDerivedCollectionGlobalIndexArrayBased: () => OIMDerivedCollectionGlobalIndexArrayBased,
|
|
48
49
|
OIMDerivedCollectionGlobalIndexSetBased: () => OIMDerivedCollectionGlobalIndexSetBased,
|
|
49
50
|
OIMDerivedCollectionIndexArrayBased: () => OIMDerivedCollectionIndexArrayBased,
|
|
@@ -139,7 +140,11 @@ __export(index_exports, {
|
|
|
139
140
|
createOIMIndexSlotMap: () => createOIMIndexSlotMap,
|
|
140
141
|
createOIMOrderedListCommandStreamDiffDriven: () => createOIMOrderedListCommandStreamDiffDriven,
|
|
141
142
|
createOIMOrderedListMappedCommandStream: () => createOIMOrderedListMappedCommandStream,
|
|
142
|
-
diffOrderedListByPk: () => diffOrderedListByPk
|
|
143
|
+
diffOrderedListByPk: () => diffOrderedListByPk,
|
|
144
|
+
getOIMComputeRuntime: () => getOIMComputeRuntime,
|
|
145
|
+
on: () => on,
|
|
146
|
+
peekOIMComputeRuntime: () => peekOIMComputeRuntime,
|
|
147
|
+
setOIMComputeRuntime: () => setOIMComputeRuntime
|
|
143
148
|
});
|
|
144
149
|
module.exports = __toCommonJS(index_exports);
|
|
145
150
|
|
|
@@ -370,6 +375,25 @@ var OIMEventQueueScheduler = class {
|
|
|
370
375
|
flush() {
|
|
371
376
|
this.emitter.emit(0 /* FLUSH */, void 0);
|
|
372
377
|
}
|
|
378
|
+
/**
|
|
379
|
+
* Detach a Node timer handle from the event loop, returning it unchanged.
|
|
380
|
+
*
|
|
381
|
+
* A pending flush must never be a reason for a process to stay alive: if
|
|
382
|
+
* nothing else is running there is no UI left to update, and the flush is
|
|
383
|
+
* moot. Without this a scheduled-but-not-yet-run flush keeps Node awake —
|
|
384
|
+
* which is why a test suite that leaves a queue scheduled reports
|
|
385
|
+
* "a worker process has failed to exit gracefully".
|
|
386
|
+
*
|
|
387
|
+
* In the browser `setTimeout` returns a number, which has no `unref`, so the
|
|
388
|
+
* call is guarded and the handle passes straight through.
|
|
389
|
+
*/
|
|
390
|
+
unref(handle) {
|
|
391
|
+
const maybeUnrefable = handle;
|
|
392
|
+
if (typeof maybeUnrefable?.unref === "function") {
|
|
393
|
+
maybeUnrefable.unref();
|
|
394
|
+
}
|
|
395
|
+
return handle;
|
|
396
|
+
}
|
|
373
397
|
};
|
|
374
398
|
|
|
375
399
|
// src/core/OIMKeyedBucketSetBased.ts
|
|
@@ -709,14 +733,17 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
709
733
|
if (this.dirtyCarriers.length === 0) return;
|
|
710
734
|
const flushing = this.dirtyCarriers;
|
|
711
735
|
this.dirtyCarriers = [];
|
|
736
|
+
const multiCarrierHandlers = this.multiCarrierHandlers;
|
|
737
|
+
const delivered = multiCarrierHandlers !== void 0 && multiCarrierHandlers.size > 0 ? this.deliveredPool ?? (this.deliveredPool = /* @__PURE__ */ new Set()) : void 0;
|
|
712
738
|
let i = 0;
|
|
713
739
|
try {
|
|
714
740
|
for (; i < flushing.length; i++) {
|
|
715
741
|
flushing[i].dirty = false;
|
|
716
|
-
this.notify(flushing[i]);
|
|
742
|
+
this.notify(flushing[i], delivered);
|
|
717
743
|
}
|
|
718
744
|
} finally {
|
|
719
745
|
for (; i < flushing.length; i++) flushing[i].dirty = false;
|
|
746
|
+
delivered?.clear();
|
|
720
747
|
}
|
|
721
748
|
};
|
|
722
749
|
this.queue = queue;
|
|
@@ -734,7 +761,15 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
734
761
|
this.addHandler(carrier, handler);
|
|
735
762
|
carriers.push(carrier);
|
|
736
763
|
}
|
|
764
|
+
const spansMultipleCarriers = carriers.length > 1;
|
|
765
|
+
if (spansMultipleCarriers) this.retainMultiCarrierHandler(handler);
|
|
766
|
+
let unsubscribed = false;
|
|
737
767
|
return () => {
|
|
768
|
+
if (unsubscribed) return;
|
|
769
|
+
unsubscribed = true;
|
|
770
|
+
if (spansMultipleCarriers) {
|
|
771
|
+
this.releaseMultiCarrierHandler(handler);
|
|
772
|
+
}
|
|
738
773
|
for (let i = 0; i < carriers.length; i++) {
|
|
739
774
|
this.removeHandler(carriers[i], handler);
|
|
740
775
|
}
|
|
@@ -745,10 +780,25 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
745
780
|
if (carrier) this.removeHandler(carrier, handler);
|
|
746
781
|
}
|
|
747
782
|
unsubscribeFromKeys(keys, handler) {
|
|
783
|
+
if (keys.length > 1) this.releaseMultiCarrierHandler(handler);
|
|
748
784
|
for (let i = 0; i < keys.length; i++) {
|
|
749
785
|
this.unsubscribeFromKey(keys[i], handler);
|
|
750
786
|
}
|
|
751
787
|
}
|
|
788
|
+
/** Take a reference for a handler whose subscription spans several carriers. */
|
|
789
|
+
retainMultiCarrierHandler(handler) {
|
|
790
|
+
const handlers = this.multiCarrierHandlers ?? (this.multiCarrierHandlers = /* @__PURE__ */ new Map());
|
|
791
|
+
handlers.set(handler, (handlers.get(handler) ?? 0) + 1);
|
|
792
|
+
}
|
|
793
|
+
/** Drop one reference; the handler leaves the set when none are left. */
|
|
794
|
+
releaseMultiCarrierHandler(handler) {
|
|
795
|
+
const handlers = this.multiCarrierHandlers;
|
|
796
|
+
if (handlers === void 0) return;
|
|
797
|
+
const count = handlers.get(handler);
|
|
798
|
+
if (count === void 0) return;
|
|
799
|
+
if (count > 1) handlers.set(handler, count - 1);
|
|
800
|
+
else handlers.delete(handler);
|
|
801
|
+
}
|
|
752
802
|
addHandler(carrier, handler) {
|
|
753
803
|
let subscribers = carrier.subscribers;
|
|
754
804
|
if (!subscribers) {
|
|
@@ -837,6 +887,8 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
837
887
|
}
|
|
838
888
|
this.dirtyCarriers = [];
|
|
839
889
|
this.isFlushEnqueued = false;
|
|
890
|
+
this.multiCarrierHandlers?.clear();
|
|
891
|
+
this.deliveredPool?.clear();
|
|
840
892
|
}
|
|
841
893
|
assertNotInFlush() {
|
|
842
894
|
if (this.queue.isInFlush) {
|
|
@@ -850,21 +902,43 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
850
902
|
this.isFlushEnqueued = true;
|
|
851
903
|
this.queue.enqueue(this.onFlush);
|
|
852
904
|
}
|
|
853
|
-
notify(carrier) {
|
|
905
|
+
notify(carrier, delivered) {
|
|
854
906
|
const subscribers = carrier.subscribers;
|
|
855
907
|
if (!subscribers || subscribers.size === 0) return;
|
|
908
|
+
const multiCarrierHandlers = delivered ? this.multiCarrierHandlers : void 0;
|
|
856
909
|
if (subscribers.size === 1) {
|
|
857
910
|
const only = subscribers.values().next().value;
|
|
858
|
-
if (only)
|
|
911
|
+
if (!only) return;
|
|
912
|
+
if (this.isAlreadyDelivered(only, delivered, multiCarrierHandlers)) {
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
only();
|
|
859
916
|
return;
|
|
860
917
|
}
|
|
861
918
|
const snapshot = [];
|
|
862
919
|
subscribers.forEach((h) => snapshot.push(h));
|
|
863
920
|
for (let i = 0; i < snapshot.length; i++) {
|
|
864
921
|
const handler = snapshot[i];
|
|
865
|
-
if (subscribers.has(handler))
|
|
922
|
+
if (!subscribers.has(handler)) continue;
|
|
923
|
+
if (this.isAlreadyDelivered(handler, delivered, multiCarrierHandlers)) {
|
|
924
|
+
continue;
|
|
925
|
+
}
|
|
926
|
+
handler();
|
|
866
927
|
}
|
|
867
928
|
}
|
|
929
|
+
/**
|
|
930
|
+
* Whether this handler already fired in the current flush and must be
|
|
931
|
+
* skipped. Only multi-carrier handlers are tracked; everything else always
|
|
932
|
+
* delivers. Membership is recorded via the size delta of a single `add` —
|
|
933
|
+
* one hash probe instead of `has` + `add`.
|
|
934
|
+
*/
|
|
935
|
+
isAlreadyDelivered(handler, delivered, multiCarrierHandlers) {
|
|
936
|
+
if (delivered === void 0) return false;
|
|
937
|
+
if (multiCarrierHandlers?.has(handler) !== true) return false;
|
|
938
|
+
const size = delivered.size;
|
|
939
|
+
delivered.add(handler);
|
|
940
|
+
return delivered.size === size;
|
|
941
|
+
}
|
|
868
942
|
};
|
|
869
943
|
|
|
870
944
|
// src/core/OIMKeyedCarrierProvider.ts
|
|
@@ -1484,8 +1558,11 @@ var OIMCollection = class {
|
|
|
1484
1558
|
this.emitter.emit(0 /* UPDATE */, { pks });
|
|
1485
1559
|
}
|
|
1486
1560
|
clear() {
|
|
1561
|
+
const pks = this.store.getAllPks();
|
|
1487
1562
|
this.store.clear();
|
|
1488
|
-
|
|
1563
|
+
if (pks.length > 0) {
|
|
1564
|
+
this.emitter.emit(0 /* UPDATE */, { pks });
|
|
1565
|
+
}
|
|
1489
1566
|
}
|
|
1490
1567
|
countAll() {
|
|
1491
1568
|
return this.store.countAll();
|
|
@@ -1527,14 +1604,12 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1527
1604
|
// Only ever holds `slot.pk` (one canonical reference per logical key), so a
|
|
1528
1605
|
// native `Set` dedups correctly by reference even for composite pks.
|
|
1529
1606
|
this.pendingAnyUpdatePks = /* @__PURE__ */ new Set();
|
|
1530
|
-
this.isAnyUpdateClearPending = false;
|
|
1531
1607
|
this.isAnyUpdateScheduled = false;
|
|
1532
1608
|
this.runAnyUpdate = () => {
|
|
1533
1609
|
if (!this.isAnyUpdateScheduled) return;
|
|
1534
1610
|
this.isAnyUpdateScheduled = false;
|
|
1535
|
-
const pks =
|
|
1611
|
+
const pks = Array.from(this.pendingAnyUpdatePks.values());
|
|
1536
1612
|
this.pendingAnyUpdatePks.clear();
|
|
1537
|
-
this.isAnyUpdateClearPending = false;
|
|
1538
1613
|
const snapshot = Array.from(this.anyUpdateHandlers);
|
|
1539
1614
|
for (let i = 0; i < snapshot.length; i++) snapshot[i](pks);
|
|
1540
1615
|
};
|
|
@@ -1574,30 +1649,43 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1574
1649
|
this.anyUpdateHandlers.delete(handler);
|
|
1575
1650
|
};
|
|
1576
1651
|
}
|
|
1577
|
-
//
|
|
1578
|
-
//
|
|
1579
|
-
//
|
|
1580
|
-
//
|
|
1581
|
-
|
|
1652
|
+
// Two notification channels coexist on a reactive collection; they serve
|
|
1653
|
+
// different audiences and NEITHER is obsolete:
|
|
1654
|
+
// • the keyed `updateEmitter` — per-key/per-carrier pings ("did MY key
|
|
1655
|
+
// change?", payload-less `void`), for leaf subscribers like React hooks
|
|
1656
|
+
// that declare the keys they care about up front;
|
|
1657
|
+
// • this `emitter` UPDATE event — the aggregate/batch channel that carries
|
|
1658
|
+
// the full list of changed pks in one SYNCHRONOUS callback, for
|
|
1659
|
+
// consumers that do NOT know their keys ahead of time and must re-derive
|
|
1660
|
+
// over the batch: derived indexes/collections, changed-fields, persist,
|
|
1661
|
+
// snapshot-manager. `pks` always enumerates exactly what changed — even
|
|
1662
|
+
// clear() lists every removed key, so an empty array never occurs.
|
|
1663
|
+
// It is not a per-key emitter with fewer features — it is the opposite
|
|
1664
|
+
// shape (enumerated batch, not "my key"), which is why it stays.
|
|
1665
|
+
//
|
|
1666
|
+
// Emit on the batch channel only when something is actually subscribed —
|
|
1667
|
+
// otherwise every upsert/remove allocates a throwaway `{ pks }` object (and
|
|
1668
|
+
// array) that nobody reads.
|
|
1669
|
+
notifyBatch(pk) {
|
|
1582
1670
|
if (this.emitter.hasHandlers(0 /* UPDATE */)) {
|
|
1583
1671
|
this.emitter.emit(0 /* UPDATE */, { pks: [pk] });
|
|
1584
1672
|
}
|
|
1585
1673
|
}
|
|
1586
|
-
|
|
1674
|
+
notifyBatchMany(pks) {
|
|
1587
1675
|
if (this.emitter.hasHandlers(0 /* UPDATE */)) {
|
|
1588
1676
|
this.emitter.emit(0 /* UPDATE */, { pks });
|
|
1589
1677
|
}
|
|
1590
1678
|
}
|
|
1591
1679
|
upsertOneByPk(pk, entity) {
|
|
1592
1680
|
const slot = this.upsertOneWithoutNotificationsByPk(pk, entity);
|
|
1593
|
-
this.
|
|
1681
|
+
this.notifyBatch(pk);
|
|
1594
1682
|
this.updateEmitter.markUpdatedCarrier(slot);
|
|
1595
1683
|
this.trackAnyUpdatePk(pk);
|
|
1596
1684
|
return slot;
|
|
1597
1685
|
}
|
|
1598
1686
|
upsertOne(entity) {
|
|
1599
1687
|
const slot = this.upsertOneWithoutNotifications(entity);
|
|
1600
|
-
this.
|
|
1688
|
+
this.notifyBatch(slot.pk);
|
|
1601
1689
|
this.updateEmitter.markUpdatedCarrier(slot);
|
|
1602
1690
|
this.trackAnyUpdatePk(slot.pk);
|
|
1603
1691
|
return slot;
|
|
@@ -1608,7 +1696,7 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1608
1696
|
(entity) => this.upsertOneWithoutNotifications(entity)
|
|
1609
1697
|
);
|
|
1610
1698
|
const pks = slots.map((slot) => slot.pk);
|
|
1611
|
-
this.
|
|
1699
|
+
this.notifyBatchMany(pks);
|
|
1612
1700
|
for (let i = 0; i < slots.length; i++) {
|
|
1613
1701
|
this.updateEmitter.markUpdatedCarrier(slots[i]);
|
|
1614
1702
|
}
|
|
@@ -1618,7 +1706,7 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1618
1706
|
removeOne(entity) {
|
|
1619
1707
|
const pk = this.selectPk(entity);
|
|
1620
1708
|
this.store.removeOneByPk(pk);
|
|
1621
|
-
this.
|
|
1709
|
+
this.notifyBatch(pk);
|
|
1622
1710
|
this.updateEmitter.markUpdatedKey(pk);
|
|
1623
1711
|
this.trackAnyUpdatePk(pk);
|
|
1624
1712
|
}
|
|
@@ -1626,30 +1714,32 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1626
1714
|
if (entities.length === 0) return;
|
|
1627
1715
|
const pks = entities.map(this.selectPk);
|
|
1628
1716
|
this.store.removeManyByPks(pks);
|
|
1629
|
-
this.
|
|
1717
|
+
this.notifyBatchMany(pks);
|
|
1630
1718
|
this.updateEmitter.markUpdatedKeys(pks);
|
|
1631
1719
|
this.trackAnyUpdatePks(pks);
|
|
1632
1720
|
}
|
|
1633
1721
|
removeOneByPk(pk) {
|
|
1634
1722
|
this.store.removeOneByPk(pk);
|
|
1635
|
-
this.
|
|
1723
|
+
this.notifyBatch(pk);
|
|
1636
1724
|
this.updateEmitter.markUpdatedKey(pk);
|
|
1637
1725
|
this.trackAnyUpdatePk(pk);
|
|
1638
1726
|
}
|
|
1639
1727
|
removeManyByPks(pks) {
|
|
1640
1728
|
if (pks.length === 0) return;
|
|
1641
1729
|
this.store.removeManyByPks(pks);
|
|
1642
|
-
this.
|
|
1730
|
+
this.notifyBatchMany(pks);
|
|
1643
1731
|
this.updateEmitter.markUpdatedKeys(pks);
|
|
1644
1732
|
this.trackAnyUpdatePks(pks);
|
|
1645
1733
|
}
|
|
1646
1734
|
clear() {
|
|
1735
|
+
const needsPks = this.emitter.hasHandlers(0 /* UPDATE */) || this.anyUpdateHandlers.size > 0;
|
|
1736
|
+
const pks = needsPks ? this.store.getAllPks() : void 0;
|
|
1647
1737
|
this.store.clear();
|
|
1648
|
-
if (
|
|
1649
|
-
this.
|
|
1738
|
+
if (pks && pks.length > 0) {
|
|
1739
|
+
this.notifyBatchMany(pks);
|
|
1740
|
+
this.trackAnyUpdatePks(pks);
|
|
1650
1741
|
}
|
|
1651
1742
|
this.updateEmitter.markAllUpdated();
|
|
1652
|
-
this.trackAnyUpdateClear();
|
|
1653
1743
|
}
|
|
1654
1744
|
trackAnyUpdatePk(pk) {
|
|
1655
1745
|
if (this.anyUpdateHandlers.size === 0) return;
|
|
@@ -1658,14 +1748,9 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1658
1748
|
}
|
|
1659
1749
|
trackAnyUpdatePks(pks) {
|
|
1660
1750
|
if (this.anyUpdateHandlers.size === 0) return;
|
|
1661
|
-
for (let i = 0; i < pks.length; i++)
|
|
1751
|
+
for (let i = 0; i < pks.length; i++) {
|
|
1662
1752
|
this.pendingAnyUpdatePks.add(pks[i]);
|
|
1663
|
-
|
|
1664
|
-
}
|
|
1665
|
-
trackAnyUpdateClear() {
|
|
1666
|
-
if (this.anyUpdateHandlers.size === 0) return;
|
|
1667
|
-
this.isAnyUpdateClearPending = true;
|
|
1668
|
-
this.pendingAnyUpdatePks.clear();
|
|
1753
|
+
}
|
|
1669
1754
|
this.ensureAnyUpdateEnqueued();
|
|
1670
1755
|
}
|
|
1671
1756
|
ensureAnyUpdateEnqueued() {
|
|
@@ -2098,8 +2183,13 @@ var OIMUpdateEventEmitter = class {
|
|
|
2098
2183
|
var OIMOrderedListCommandBuffer = class {
|
|
2099
2184
|
constructor(queue) {
|
|
2100
2185
|
this.commandsByKey = /* @__PURE__ */ new Map();
|
|
2186
|
+
// Keys whose buffered leading `reset` is stale: an edit after the reset
|
|
2187
|
+
// should be folded into it, but we defer the (O(list-size)) rebuild to the
|
|
2188
|
+
// next read instead of redoing it on every subsequent edit in the batch.
|
|
2189
|
+
this.staleResetKeys = /* @__PURE__ */ new Set();
|
|
2101
2190
|
this.onAfterFlush = () => {
|
|
2102
2191
|
this.commandsByKey.clear();
|
|
2192
|
+
this.staleResetKeys.clear();
|
|
2103
2193
|
};
|
|
2104
2194
|
this.commandsEventEmitter = new OIMUpdateEventEmitter(
|
|
2105
2195
|
queue,
|
|
@@ -2114,9 +2204,11 @@ var OIMOrderedListCommandBuffer = class {
|
|
|
2114
2204
|
return this.commandsEventEmitter.subscribeOnKey(key, handler);
|
|
2115
2205
|
}
|
|
2116
2206
|
getBufferedCommands(key) {
|
|
2207
|
+
this.materializeStaleReset(key);
|
|
2117
2208
|
return this.commandsByKey.get(key) ?? [];
|
|
2118
2209
|
}
|
|
2119
2210
|
consumeCommands(key) {
|
|
2211
|
+
this.materializeStaleReset(key);
|
|
2120
2212
|
const cmds = this.commandsByKey.get(key);
|
|
2121
2213
|
if (!cmds || cmds.length === 0) return [];
|
|
2122
2214
|
return cmds.slice();
|
|
@@ -2125,6 +2217,20 @@ var OIMOrderedListCommandBuffer = class {
|
|
|
2125
2217
|
this.commandsEventEmitter.destroy();
|
|
2126
2218
|
this.unsubscribeAfterFlush();
|
|
2127
2219
|
this.commandsByKey.clear();
|
|
2220
|
+
this.staleResetKeys.clear();
|
|
2221
|
+
}
|
|
2222
|
+
/**
|
|
2223
|
+
* Rebuild a deferred leading `reset` from the current order, once, at read
|
|
2224
|
+
* time. All the post-reset edits that were folded in are already reflected
|
|
2225
|
+
* in the driver's backing order, so a single rebuild here is equivalent to
|
|
2226
|
+
* having recomputed the reset on each of those edits.
|
|
2227
|
+
*/
|
|
2228
|
+
materializeStaleReset(key) {
|
|
2229
|
+
if (!this.staleResetKeys.delete(key)) return;
|
|
2230
|
+
const cmds = this.commandsByKey.get(key);
|
|
2231
|
+
if (cmds && cmds.length > 0 && cmds[0].type === "reset") {
|
|
2232
|
+
cmds[0] = this.createResetCommand(this.getItemsByKey(key));
|
|
2233
|
+
}
|
|
2128
2234
|
}
|
|
2129
2235
|
appendCommand(key, cmd) {
|
|
2130
2236
|
let cmds = this.commandsByKey.get(key);
|
|
@@ -2135,8 +2241,9 @@ var OIMOrderedListCommandBuffer = class {
|
|
|
2135
2241
|
if (cmd.type === "reset") {
|
|
2136
2242
|
cmds.length = 0;
|
|
2137
2243
|
cmds.push(cmd);
|
|
2244
|
+
this.staleResetKeys.delete(key);
|
|
2138
2245
|
} else if (cmds.length > 0 && cmds[0].type === "reset") {
|
|
2139
|
-
|
|
2246
|
+
this.staleResetKeys.add(key);
|
|
2140
2247
|
} else {
|
|
2141
2248
|
cmds.push(cmd);
|
|
2142
2249
|
}
|
|
@@ -3178,10 +3285,6 @@ var OIMDerivedCollectionIndexSetBased = class extends OIMReactiveCollectionIndex
|
|
|
3178
3285
|
});
|
|
3179
3286
|
this.keysByPk = /* @__PURE__ */ new Map();
|
|
3180
3287
|
this.onCollectionUpdate = (pks) => {
|
|
3181
|
-
if (pks.length === 0) {
|
|
3182
|
-
this.rebuildFromCollection();
|
|
3183
|
-
return;
|
|
3184
|
-
}
|
|
3185
3288
|
for (const pk of pks) {
|
|
3186
3289
|
this.syncPk(pk);
|
|
3187
3290
|
}
|
|
@@ -3283,10 +3386,6 @@ var OIMDerivedCollectionIndexArrayBased = class extends OIMReactiveCollectionInd
|
|
|
3283
3386
|
// touching an unrelated field can skip re-sorting when the value is unchanged.
|
|
3284
3387
|
this.orderValueByPk = /* @__PURE__ */ new Map();
|
|
3285
3388
|
this.onCollectionUpdate = (pks) => {
|
|
3286
|
-
if (pks.length === 0) {
|
|
3287
|
-
this.rebuildFromCollection();
|
|
3288
|
-
return;
|
|
3289
|
-
}
|
|
3290
3389
|
const ordered = !!(this.compareEntities || this.orderBy);
|
|
3291
3390
|
const keysToSort = ordered ? /* @__PURE__ */ new Set() : null;
|
|
3292
3391
|
for (const pk of pks) {
|
|
@@ -3703,10 +3802,6 @@ var OIMDerivedCollectionGlobalIndexArrayBased = class extends OIMReactiveCollect
|
|
|
3703
3802
|
// an unrelated field can skip re-sorting when the value is unchanged.
|
|
3704
3803
|
this.orderValueByPk = /* @__PURE__ */ new Map();
|
|
3705
3804
|
this.onCollectionUpdate = (pks) => {
|
|
3706
|
-
if (pks.length === 0) {
|
|
3707
|
-
this.rebuildFromCollection();
|
|
3708
|
-
return;
|
|
3709
|
-
}
|
|
3710
3805
|
const ordered = !!(this.compareEntities || this.orderBy);
|
|
3711
3806
|
let needsSort = false;
|
|
3712
3807
|
for (const pk of pks) {
|
|
@@ -3804,10 +3899,6 @@ var OIMDerivedCollectionGlobalIndexSetBased = class extends OIMReactiveCollectio
|
|
|
3804
3899
|
super(queue, { collection, indexOptions: opts.indexOptions });
|
|
3805
3900
|
this.presentPks = /* @__PURE__ */ new Set();
|
|
3806
3901
|
this.onCollectionUpdate = (pks) => {
|
|
3807
|
-
if (pks.length === 0) {
|
|
3808
|
-
this.rebuildFromCollection();
|
|
3809
|
-
return;
|
|
3810
|
-
}
|
|
3811
3902
|
for (const pk of pks) {
|
|
3812
3903
|
const prev = this.presentPks.has(pk);
|
|
3813
3904
|
const slot = this.collection.getSlotByPk(pk);
|
|
@@ -3983,6 +4074,55 @@ function createOIMCollectionIndexFactory(queue, collection) {
|
|
|
3983
4074
|
return new OIMCollectionIndexFactory(queue, collection);
|
|
3984
4075
|
}
|
|
3985
4076
|
|
|
4077
|
+
// src/core/OIMDerivedCollection.ts
|
|
4078
|
+
var OIMDerivedCollection = class extends OIMReactiveCollection {
|
|
4079
|
+
constructor(queue, source, derive, opts) {
|
|
4080
|
+
super(queue, {
|
|
4081
|
+
store: opts?.store,
|
|
4082
|
+
// Each sync recomputes the WHOLE derived entity → replace, not merge.
|
|
4083
|
+
updateEntity: (draft) => draft
|
|
4084
|
+
});
|
|
4085
|
+
this.onSourceUpdate = (pks) => {
|
|
4086
|
+
for (let i = 0; i < pks.length; i++) this.syncPk(pks[i]);
|
|
4087
|
+
};
|
|
4088
|
+
this.source = source;
|
|
4089
|
+
this.derive = derive;
|
|
4090
|
+
this.compareDerived = opts?.compare ?? Object.is;
|
|
4091
|
+
this.unsubscribeFromSource = source.emitter.on(
|
|
4092
|
+
0 /* UPDATE */,
|
|
4093
|
+
(payload) => this.onSourceUpdate(payload.pks)
|
|
4094
|
+
);
|
|
4095
|
+
if (opts?.buildInitial !== false) {
|
|
4096
|
+
this.rebuildFromSource();
|
|
4097
|
+
}
|
|
4098
|
+
}
|
|
4099
|
+
rebuildFromSource() {
|
|
4100
|
+
for (const pk of this.getAllPks()) {
|
|
4101
|
+
if (this.source.getOneByPk(pk) === void 0) {
|
|
4102
|
+
this.removeOneByPk(pk);
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
for (const slot of this.source.getAllSlots()) {
|
|
4106
|
+
if (slot.item !== void 0) this.syncPk(slot.pk);
|
|
4107
|
+
}
|
|
4108
|
+
}
|
|
4109
|
+
destroy() {
|
|
4110
|
+
this.unsubscribeFromSource();
|
|
4111
|
+
super.destroy();
|
|
4112
|
+
}
|
|
4113
|
+
syncPk(pk) {
|
|
4114
|
+
const sourceEntity = this.source.getOneByPk(pk);
|
|
4115
|
+
if (sourceEntity === void 0) {
|
|
4116
|
+
if (this.getOneByPk(pk) !== void 0) this.removeOneByPk(pk);
|
|
4117
|
+
return;
|
|
4118
|
+
}
|
|
4119
|
+
const next = this.derive(sourceEntity, pk);
|
|
4120
|
+
const prev = this.getOneByPk(pk);
|
|
4121
|
+
if (prev !== void 0 && this.compareDerived(prev, next)) return;
|
|
4122
|
+
this.upsertOneByPk(pk, next);
|
|
4123
|
+
}
|
|
4124
|
+
};
|
|
4125
|
+
|
|
3986
4126
|
// src/core/OIMObjectStoreRecordDriven.ts
|
|
3987
4127
|
var OIMObjectStoreRecordDriven = class extends OIMObjectStore {
|
|
3988
4128
|
constructor(initial) {
|
|
@@ -4055,8 +4195,11 @@ var OIMObject = class {
|
|
|
4055
4195
|
return this.store.getAll();
|
|
4056
4196
|
}
|
|
4057
4197
|
clear() {
|
|
4198
|
+
const keys = this.store.keys();
|
|
4058
4199
|
this.store.clear();
|
|
4059
|
-
|
|
4200
|
+
if (keys.length > 0) {
|
|
4201
|
+
this.onUpdatedKeys(keys);
|
|
4202
|
+
}
|
|
4060
4203
|
}
|
|
4061
4204
|
/**
|
|
4062
4205
|
* Write fan-out hooks. Split single-key vs multi-key so a reactive subclass
|
|
@@ -4359,8 +4502,9 @@ var OIMComparatorFactory = class {
|
|
|
4359
4502
|
if (ka.length !== kb.length) return true;
|
|
4360
4503
|
for (let i = 0; i < ka.length; i++) {
|
|
4361
4504
|
const k = ka[i];
|
|
4362
|
-
if (b[k] !== a[k])
|
|
4505
|
+
if (b[k] !== a[k]) {
|
|
4363
4506
|
return true;
|
|
4507
|
+
}
|
|
4364
4508
|
}
|
|
4365
4509
|
return false;
|
|
4366
4510
|
};
|
|
@@ -4410,10 +4554,14 @@ var OIMEventQueue = class {
|
|
|
4410
4554
|
return this.isFlushing;
|
|
4411
4555
|
}
|
|
4412
4556
|
/**
|
|
4413
|
-
* Execute
|
|
4557
|
+
* Execute the tasks pending at the moment the flush starts — a single pass,
|
|
4558
|
+
* not a drain-to-empty.
|
|
4414
4559
|
*
|
|
4415
|
-
*
|
|
4416
|
-
*
|
|
4560
|
+
* The pending set is swapped out for an empty spare up front and the flush
|
|
4561
|
+
* iterates that captured set. Tasks enqueued during the flush land in the
|
|
4562
|
+
* fresh set and run on the NEXT flush, not this one. (Contrast
|
|
4563
|
+
* `OIMComputeRuntime.flush()`, which re-reads its bucket per level and so
|
|
4564
|
+
* does drain same-level tasks scheduled mid-flush.)
|
|
4417
4565
|
*/
|
|
4418
4566
|
flush() {
|
|
4419
4567
|
this.scheduler?.cancel();
|
|
@@ -4687,20 +4835,92 @@ var OIMPkCodecKeyPath = class {
|
|
|
4687
4835
|
}
|
|
4688
4836
|
};
|
|
4689
4837
|
|
|
4838
|
+
// src/modules/effect/core/OIMEffectDependencyComputed.ts
|
|
4839
|
+
var OIMEffectDependencyComputed = class {
|
|
4840
|
+
constructor(source) {
|
|
4841
|
+
this.source = source;
|
|
4842
|
+
}
|
|
4843
|
+
subscribe(onUpdate) {
|
|
4844
|
+
return this.source.emitter.on("update", onUpdate);
|
|
4845
|
+
}
|
|
4846
|
+
};
|
|
4847
|
+
|
|
4690
4848
|
// src/modules/compute/core/OIMComputeRuntime.ts
|
|
4691
4849
|
var OIMComputeRuntime = class {
|
|
4692
4850
|
constructor(queue) {
|
|
4693
4851
|
this.queue = queue;
|
|
4694
4852
|
this.isFlushScheduled = false;
|
|
4695
4853
|
this.isFlushing = false;
|
|
4854
|
+
// Active level range (min > max means nothing pending).
|
|
4696
4855
|
this.minLevel = Infinity;
|
|
4697
4856
|
this.maxLevel = -Infinity;
|
|
4698
|
-
this.dirtyByLevel =
|
|
4857
|
+
this.dirtyByLevel = [];
|
|
4699
4858
|
this.afterFlushTasks = /* @__PURE__ */ new Set();
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4859
|
+
// Topological depth per computed node — the engine is the ONLY owner of
|
|
4860
|
+
// levels; nodes never expose their own. A node's dependents look up its depth
|
|
4861
|
+
// here (by the computed reference their dependency wraps). Written once at
|
|
4862
|
+
// construction, never on the hot flush path.
|
|
4863
|
+
this.levelByComputed = /* @__PURE__ */ new WeakMap();
|
|
4864
|
+
this._isDestroyed = false;
|
|
4865
|
+
this.unsubscribeFromQueue = this.queue.emitter.on(
|
|
4866
|
+
0 /* AFTER_FLUSH */,
|
|
4867
|
+
() => {
|
|
4868
|
+
if (!this.isFlushScheduled) return;
|
|
4869
|
+
this.flush();
|
|
4870
|
+
}
|
|
4871
|
+
);
|
|
4872
|
+
}
|
|
4873
|
+
/**
|
|
4874
|
+
* Whether {@link destroy} has run. A destroyed runtime is detached from its
|
|
4875
|
+
* queue and must not be reused — `getOIMComputeRuntime` reads this to hand
|
|
4876
|
+
* out a fresh runtime instead of a dead one.
|
|
4877
|
+
*/
|
|
4878
|
+
get isDestroyed() {
|
|
4879
|
+
return this._isDestroyed;
|
|
4880
|
+
}
|
|
4881
|
+
/**
|
|
4882
|
+
* Detach from the queue and drop everything pending.
|
|
4883
|
+
*
|
|
4884
|
+
* Without this the AFTER_FLUSH subscription lives as long as the queue does,
|
|
4885
|
+
* even once every computed / effect on this runtime is gone — harmless (the
|
|
4886
|
+
* handler early-returns) but impossible to unwind. Destroying does NOT
|
|
4887
|
+
* destroy the nodes scheduled on it; destroy them first, then the runtime.
|
|
4888
|
+
* Idempotent.
|
|
4889
|
+
*/
|
|
4890
|
+
destroy() {
|
|
4891
|
+
if (this._isDestroyed) return;
|
|
4892
|
+
this._isDestroyed = true;
|
|
4893
|
+
this.unsubscribeFromQueue();
|
|
4894
|
+
for (let i = 0; i < this.dirtyByLevel.length; i++) {
|
|
4895
|
+
this.dirtyByLevel[i]?.clear();
|
|
4896
|
+
}
|
|
4897
|
+
this.afterFlushTasks.clear();
|
|
4898
|
+
this.minLevel = Infinity;
|
|
4899
|
+
this.maxLevel = -Infinity;
|
|
4900
|
+
this.isFlushScheduled = false;
|
|
4901
|
+
}
|
|
4902
|
+
/**
|
|
4903
|
+
* Topological depth for a node with these dependencies: one above the deepest
|
|
4904
|
+
* computed dependency (source-only → 0). The engine owns this — callers pass
|
|
4905
|
+
* their dependencies and get back a level, they never compute it themselves.
|
|
4906
|
+
*/
|
|
4907
|
+
computeLevel(deps) {
|
|
4908
|
+
let max = -1;
|
|
4909
|
+
for (const dep of deps) {
|
|
4910
|
+
if (dep instanceof OIMEffectDependencyComputed) {
|
|
4911
|
+
const depLevel = this.levelByComputed.get(dep.source) ?? 0;
|
|
4912
|
+
if (depLevel > max) max = depLevel;
|
|
4913
|
+
}
|
|
4914
|
+
}
|
|
4915
|
+
return max + 1;
|
|
4916
|
+
}
|
|
4917
|
+
/** Record a computed's depth so its dependents can look it up. */
|
|
4918
|
+
registerLevel(computed, level) {
|
|
4919
|
+
this.levelByComputed.set(computed, level);
|
|
4920
|
+
}
|
|
4921
|
+
/** The recorded topological depth of a computed (0 if unknown). Introspection. */
|
|
4922
|
+
getLevel(computed) {
|
|
4923
|
+
return this.levelByComputed.get(computed) ?? 0;
|
|
4704
4924
|
}
|
|
4705
4925
|
/**
|
|
4706
4926
|
* Schedule a one-shot task to run on the next `queue.flush()` (AFTER_FLUSH),
|
|
@@ -4712,10 +4932,10 @@ var OIMComputeRuntime = class {
|
|
|
4712
4932
|
if (!isActive) return;
|
|
4713
4933
|
task();
|
|
4714
4934
|
};
|
|
4715
|
-
let bucket = this.dirtyByLevel
|
|
4716
|
-
if (
|
|
4935
|
+
let bucket = this.dirtyByLevel[level];
|
|
4936
|
+
if (bucket === void 0) {
|
|
4717
4937
|
bucket = /* @__PURE__ */ new Set();
|
|
4718
|
-
this.dirtyByLevel
|
|
4938
|
+
this.dirtyByLevel[level] = bucket;
|
|
4719
4939
|
}
|
|
4720
4940
|
bucket.add(wrapped);
|
|
4721
4941
|
if (level < this.minLevel) this.minLevel = level;
|
|
@@ -4747,7 +4967,7 @@ var OIMComputeRuntime = class {
|
|
|
4747
4967
|
}
|
|
4748
4968
|
flush() {
|
|
4749
4969
|
this.isFlushScheduled = false;
|
|
4750
|
-
if (this.
|
|
4970
|
+
if (this.minLevel > this.maxLevel && this.afterFlushTasks.size === 0)
|
|
4751
4971
|
return;
|
|
4752
4972
|
this.isFlushing = true;
|
|
4753
4973
|
try {
|
|
@@ -4756,15 +4976,15 @@ var OIMComputeRuntime = class {
|
|
|
4756
4976
|
this.afterFlushTasks.clear();
|
|
4757
4977
|
for (let i = 0; i < snapshot.length; i++) snapshot[i]();
|
|
4758
4978
|
}
|
|
4759
|
-
if (this.
|
|
4979
|
+
if (this.minLevel > this.maxLevel) return;
|
|
4760
4980
|
let level = this.minLevel;
|
|
4761
4981
|
let max = this.maxLevel;
|
|
4762
4982
|
while (level <= max) {
|
|
4763
4983
|
for (; ; ) {
|
|
4764
|
-
const bucket = this.dirtyByLevel
|
|
4765
|
-
if (
|
|
4766
|
-
this.dirtyByLevel.delete(level);
|
|
4984
|
+
const bucket = this.dirtyByLevel[level];
|
|
4985
|
+
if (bucket === void 0 || bucket.size === 0) break;
|
|
4767
4986
|
const snapshot = Array.from(bucket);
|
|
4987
|
+
bucket.clear();
|
|
4768
4988
|
for (let i = 0; i < snapshot.length; i++) snapshot[i]();
|
|
4769
4989
|
}
|
|
4770
4990
|
if (this.maxLevel > max) max = this.maxLevel;
|
|
@@ -4772,24 +4992,38 @@ var OIMComputeRuntime = class {
|
|
|
4772
4992
|
}
|
|
4773
4993
|
} finally {
|
|
4774
4994
|
this.isFlushing = false;
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
this.isFlushScheduled = true;
|
|
4995
|
+
this.recomputePendingRange();
|
|
4996
|
+
}
|
|
4997
|
+
}
|
|
4998
|
+
recomputePendingRange() {
|
|
4999
|
+
let nextMin = Infinity;
|
|
5000
|
+
let nextMax = -Infinity;
|
|
5001
|
+
const buckets = this.dirtyByLevel;
|
|
5002
|
+
for (let i = 0; i < buckets.length; i++) {
|
|
5003
|
+
const bucket = buckets[i];
|
|
5004
|
+
if (bucket !== void 0 && bucket.size > 0) {
|
|
5005
|
+
if (i < nextMin) nextMin = i;
|
|
5006
|
+
if (i > nextMax) nextMax = i;
|
|
4788
5007
|
}
|
|
4789
5008
|
}
|
|
5009
|
+
this.minLevel = nextMin;
|
|
5010
|
+
this.maxLevel = nextMax;
|
|
5011
|
+
if (nextMin <= nextMax) this.isFlushScheduled = true;
|
|
4790
5012
|
}
|
|
4791
5013
|
};
|
|
4792
5014
|
|
|
5015
|
+
// src/dx/oimComputeRuntimeByQueue.ts
|
|
5016
|
+
var oimComputeRuntimeByQueue = /* @__PURE__ */ new WeakMap();
|
|
5017
|
+
|
|
5018
|
+
// src/dx/getOIMComputeRuntime.ts
|
|
5019
|
+
function getOIMComputeRuntime(queue) {
|
|
5020
|
+
const runtime = oimComputeRuntimeByQueue.get(queue);
|
|
5021
|
+
if (runtime !== void 0 && !runtime.isDestroyed) return runtime;
|
|
5022
|
+
const nextRuntime = new OIMComputeRuntime(queue);
|
|
5023
|
+
oimComputeRuntimeByQueue.set(queue, nextRuntime);
|
|
5024
|
+
return nextRuntime;
|
|
5025
|
+
}
|
|
5026
|
+
|
|
4793
5027
|
// src/modules/selector/core/OIMSelector.ts
|
|
4794
5028
|
var OIMSelector = class {
|
|
4795
5029
|
constructor(runtime, sourceDeps, computedDeps = []) {
|
|
@@ -5050,8 +5284,9 @@ var OIMEntitiesByIndexKeyArrayBasedSelector = class extends OIMSelector {
|
|
|
5050
5284
|
areEqual(prev, next) {
|
|
5051
5285
|
if (prev === next) return true;
|
|
5052
5286
|
if (prev.length !== next.length) return false;
|
|
5053
|
-
for (let i = 0; i < prev.length; i++)
|
|
5287
|
+
for (let i = 0; i < prev.length; i++) {
|
|
5054
5288
|
if (prev[i] !== next[i]) return false;
|
|
5289
|
+
}
|
|
5055
5290
|
return true;
|
|
5056
5291
|
}
|
|
5057
5292
|
};
|
|
@@ -5121,8 +5356,9 @@ var OIMEntitiesByIndexKeySetBasedSelector = class extends OIMSelector {
|
|
|
5121
5356
|
areEqual(prev, next) {
|
|
5122
5357
|
if (prev === next) return true;
|
|
5123
5358
|
if (prev.length !== next.length) return false;
|
|
5124
|
-
for (let i = 0; i < prev.length; i++)
|
|
5359
|
+
for (let i = 0; i < prev.length; i++) {
|
|
5125
5360
|
if (prev[i] !== next[i]) return false;
|
|
5361
|
+
}
|
|
5126
5362
|
return true;
|
|
5127
5363
|
}
|
|
5128
5364
|
};
|
|
@@ -5186,8 +5422,9 @@ var OIMEntitiesByGlobalIndexArrayBasedSelector = class extends OIMSelector {
|
|
|
5186
5422
|
areEqual(prev, next) {
|
|
5187
5423
|
if (prev === next) return true;
|
|
5188
5424
|
if (prev.length !== next.length) return false;
|
|
5189
|
-
for (let i = 0; i < prev.length; i++)
|
|
5425
|
+
for (let i = 0; i < prev.length; i++) {
|
|
5190
5426
|
if (prev[i] !== next[i]) return false;
|
|
5427
|
+
}
|
|
5191
5428
|
return true;
|
|
5192
5429
|
}
|
|
5193
5430
|
};
|
|
@@ -5252,8 +5489,9 @@ var OIMEntitiesByGlobalIndexSetBasedSelector = class extends OIMSelector {
|
|
|
5252
5489
|
areEqual(prev, next) {
|
|
5253
5490
|
if (prev === next) return true;
|
|
5254
5491
|
if (prev.length !== next.length) return false;
|
|
5255
|
-
for (let i = 0; i < prev.length; i++)
|
|
5492
|
+
for (let i = 0; i < prev.length; i++) {
|
|
5256
5493
|
if (prev[i] !== next[i]) return false;
|
|
5494
|
+
}
|
|
5257
5495
|
return true;
|
|
5258
5496
|
}
|
|
5259
5497
|
};
|
|
@@ -5262,7 +5500,7 @@ var OIMEntitiesByGlobalIndexSetBasedSelector = class extends OIMSelector {
|
|
|
5262
5500
|
var OIMCollectionSelectors = class {
|
|
5263
5501
|
constructor(queue, collection) {
|
|
5264
5502
|
this.collection = collection;
|
|
5265
|
-
this.runtime =
|
|
5503
|
+
this.runtime = getOIMComputeRuntime(queue);
|
|
5266
5504
|
}
|
|
5267
5505
|
byPk(pk) {
|
|
5268
5506
|
return new OIMCollectionByPkSelector(this.runtime, this.collection, pk);
|
|
@@ -5329,120 +5567,401 @@ var OIMCollectionSelectors = class {
|
|
|
5329
5567
|
}
|
|
5330
5568
|
};
|
|
5331
5569
|
|
|
5332
|
-
// src/
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
indexFactory,
|
|
5343
|
-
select,
|
|
5344
|
-
scope,
|
|
5345
|
-
destroy: () => scope.destroy()
|
|
5346
|
-
};
|
|
5347
|
-
}
|
|
5570
|
+
// src/modules/effect/core/OIMEffectDependencyKeyed.ts
|
|
5571
|
+
var OIMEffectDependencyKeyed = class {
|
|
5572
|
+
constructor(source, key) {
|
|
5573
|
+
this.source = source;
|
|
5574
|
+
this.key = key;
|
|
5575
|
+
}
|
|
5576
|
+
subscribe(onUpdate) {
|
|
5577
|
+
return this.source.subscribeOnKey(this.key, onUpdate);
|
|
5578
|
+
}
|
|
5579
|
+
};
|
|
5348
5580
|
|
|
5349
|
-
// src/modules/
|
|
5350
|
-
var
|
|
5351
|
-
constructor(
|
|
5352
|
-
this.
|
|
5353
|
-
this.lastEntitySnapshotByPk = /* @__PURE__ */ new Map();
|
|
5354
|
-
// PKs written through this wrapper during the current flush. Their fields are
|
|
5355
|
-
// already tracked accurately via trackPatch, so the flush-time external-write
|
|
5356
|
-
// handler skips them — no redundant diff + snapshot re-clone. Cleared per flush.
|
|
5357
|
-
this.writtenThroughThisFlush = /* @__PURE__ */ new Set();
|
|
5358
|
-
this.changedFieldsByPk = /* @__PURE__ */ new Map();
|
|
5359
|
-
this.changedPksByField = /* @__PURE__ */ new Map();
|
|
5360
|
-
this.onAfterFlush = () => {
|
|
5361
|
-
this.clear();
|
|
5362
|
-
this.writtenThroughThisFlush.clear();
|
|
5363
|
-
};
|
|
5364
|
-
this.onCollectionUpdate = (payload) => {
|
|
5365
|
-
if (this.isInWrite) return;
|
|
5366
|
-
if (payload.pks.length === 0) return;
|
|
5367
|
-
for (let i = 0; i < payload.pks.length; i++) {
|
|
5368
|
-
const pk = payload.pks[i];
|
|
5369
|
-
if (this.writtenThroughThisFlush.has(pk)) continue;
|
|
5370
|
-
this.trackExternalMutationByPk(pk);
|
|
5371
|
-
}
|
|
5372
|
-
};
|
|
5373
|
-
this.collection = collection;
|
|
5374
|
-
this.detectExternalMutations = opts?.detectExternalMutations !== false;
|
|
5375
|
-
this.selectPk = opts?.selectPk ?? (() => {
|
|
5376
|
-
throw new Error(
|
|
5377
|
-
`[OIMCollectionChangedFields]: selectPk was not provided. Use upsertOneByPk(...) or pass opts.selectPk.`
|
|
5378
|
-
);
|
|
5379
|
-
});
|
|
5380
|
-
this.changedPksEventEmitter = new OIMUpdateEventEmitter(
|
|
5381
|
-
queue,
|
|
5382
|
-
"after_flush"
|
|
5383
|
-
);
|
|
5384
|
-
this.changedFieldsEventEmitter = new OIMUpdateEventEmitter(queue, "after_flush");
|
|
5385
|
-
this.unsubscribeAfterFlush = queue.emitter.on(
|
|
5386
|
-
0 /* AFTER_FLUSH */,
|
|
5387
|
-
this.onAfterFlush
|
|
5388
|
-
);
|
|
5389
|
-
if (this.detectExternalMutations) {
|
|
5390
|
-
const maybeReactive = collection;
|
|
5391
|
-
this.unsubscribeFromCollectionEmitter = maybeReactive.subscribeOnAnyUpdate ? maybeReactive.subscribeOnAnyUpdate((pks) => {
|
|
5392
|
-
this.onCollectionUpdate({
|
|
5393
|
-
pks
|
|
5394
|
-
});
|
|
5395
|
-
}) : collection.emitter.on(
|
|
5396
|
-
0 /* UPDATE */,
|
|
5397
|
-
this.onCollectionUpdate
|
|
5398
|
-
);
|
|
5399
|
-
}
|
|
5581
|
+
// src/modules/effect/core/OIMEffectDependencyKeyedCollection.ts
|
|
5582
|
+
var OIMEffectDependencyKeyedCollection = class {
|
|
5583
|
+
constructor(collection, pk) {
|
|
5584
|
+
this.dep = new OIMEffectDependencyKeyed(collection, pk);
|
|
5400
5585
|
}
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
this.trackPatch(pk, patch);
|
|
5404
|
-
return this.collection.upsertOneByPk(pk, patch);
|
|
5405
|
-
});
|
|
5406
|
-
this.updateEntitySnapshot(pk);
|
|
5407
|
-
return slot;
|
|
5586
|
+
get source() {
|
|
5587
|
+
return this.dep.source;
|
|
5408
5588
|
}
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
const pk = this.selectPk(entity);
|
|
5412
|
-
this.trackPatch(pk, entity);
|
|
5413
|
-
return this.collection.upsertOne(entity);
|
|
5414
|
-
});
|
|
5415
|
-
this.updateEntitySnapshot(slot.pk);
|
|
5416
|
-
return slot;
|
|
5589
|
+
subscribe(onUpdate) {
|
|
5590
|
+
return this.dep.subscribe(onUpdate);
|
|
5417
5591
|
}
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
this.trackPatch(pk, entity);
|
|
5425
|
-
}
|
|
5426
|
-
return this.collection.upsertMany(entities);
|
|
5427
|
-
});
|
|
5428
|
-
for (let i = 0; i < pks.length; i++) this.updateEntitySnapshot(pks[i]);
|
|
5429
|
-
return slots;
|
|
5592
|
+
};
|
|
5593
|
+
|
|
5594
|
+
// src/modules/effect/core/OIMEffectDependencyKeyedIndex.ts
|
|
5595
|
+
var OIMEffectDependencyKeyedIndex = class {
|
|
5596
|
+
constructor(index, key) {
|
|
5597
|
+
this.dep = new OIMEffectDependencyKeyed(index, key);
|
|
5430
5598
|
}
|
|
5431
|
-
|
|
5432
|
-
return this.
|
|
5599
|
+
get source() {
|
|
5600
|
+
return this.dep.source;
|
|
5433
5601
|
}
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
if (!existing) return /* @__PURE__ */ new Set();
|
|
5437
|
-
return new Set(existing);
|
|
5602
|
+
subscribe(onUpdate) {
|
|
5603
|
+
return this.dep.subscribe(onUpdate);
|
|
5438
5604
|
}
|
|
5439
|
-
|
|
5440
|
-
|
|
5605
|
+
};
|
|
5606
|
+
|
|
5607
|
+
// src/modules/effect/core/OIMEffectDependencyKeyedObject.ts
|
|
5608
|
+
var OIMEffectDependencyKeyedObject = class {
|
|
5609
|
+
constructor(object, key) {
|
|
5610
|
+
this.dep = new OIMEffectDependencyKeyed(object, key);
|
|
5441
5611
|
}
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5612
|
+
get source() {
|
|
5613
|
+
return this.dep.source;
|
|
5614
|
+
}
|
|
5615
|
+
subscribe(onUpdate) {
|
|
5616
|
+
return this.dep.subscribe(onUpdate);
|
|
5617
|
+
}
|
|
5618
|
+
};
|
|
5619
|
+
|
|
5620
|
+
// src/dx/on.ts
|
|
5621
|
+
var on = {
|
|
5622
|
+
/** Depend on one PK of a collection. */
|
|
5623
|
+
collection: (collection, pk) => new OIMEffectDependencyKeyedCollection(collection, pk),
|
|
5624
|
+
/** Depend on one key of an index. */
|
|
5625
|
+
index: (index, key) => new OIMEffectDependencyKeyedIndex(index, key),
|
|
5626
|
+
/** Depend on one key of a reactive object. */
|
|
5627
|
+
object: (object, key) => new OIMEffectDependencyKeyedObject(object, key),
|
|
5628
|
+
/** Depend on another computed. */
|
|
5629
|
+
computed: (computed) => new OIMEffectDependencyComputed(computed)
|
|
5630
|
+
};
|
|
5631
|
+
|
|
5632
|
+
// src/modules/effect/core/OIMEffect.ts
|
|
5633
|
+
var OIMEffect = class {
|
|
5634
|
+
constructor(runtime, opts, level) {
|
|
5635
|
+
this.sourceDeps = [];
|
|
5636
|
+
this.computedDeps = [];
|
|
5637
|
+
this.sourceUnsubscribers = [];
|
|
5638
|
+
this.computedUnsubscribers = [];
|
|
5639
|
+
this.isResubscribeEnqueued = false;
|
|
5640
|
+
this.isTemporarilyUnsubscribedForFlush = false;
|
|
5641
|
+
this.isScheduled = false;
|
|
5642
|
+
this.runTask = () => {
|
|
5643
|
+
this.isScheduled = false;
|
|
5644
|
+
this.dequeueScheduled = void 0;
|
|
5645
|
+
this.runOnce();
|
|
5646
|
+
};
|
|
5647
|
+
this.onSourceInvalidate = () => {
|
|
5648
|
+
this.onUpdate?.();
|
|
5649
|
+
if (!this.isTemporarilyUnsubscribedForFlush) {
|
|
5650
|
+
this.isTemporarilyUnsubscribedForFlush = true;
|
|
5651
|
+
this.unsubscribeFromSourceDeps();
|
|
5652
|
+
this.ensureResubscribeAfterFlush();
|
|
5653
|
+
}
|
|
5654
|
+
if (this.isScheduled) return;
|
|
5655
|
+
this.isScheduled = true;
|
|
5656
|
+
this.dequeueScheduled = this.runtime.schedule(this.runTask, this.level);
|
|
5657
|
+
};
|
|
5658
|
+
this.onComputedInvalidate = () => {
|
|
5659
|
+
this.onUpdate?.();
|
|
5660
|
+
if (this.isScheduled) return;
|
|
5661
|
+
this.isScheduled = true;
|
|
5662
|
+
this.dequeueScheduled = this.runtime.schedule(this.runTask, this.level);
|
|
5663
|
+
};
|
|
5664
|
+
this.onAfterFlush = () => {
|
|
5665
|
+
if (!this.isResubscribeEnqueued) return;
|
|
5666
|
+
this.isResubscribeEnqueued = false;
|
|
5667
|
+
this.dequeueResubscribe = void 0;
|
|
5668
|
+
this.isTemporarilyUnsubscribedForFlush = false;
|
|
5669
|
+
if (this.sourceUnsubscribers.length === 0) {
|
|
5670
|
+
for (const dep of this.sourceDeps) {
|
|
5671
|
+
this.sourceUnsubscribers.push(
|
|
5672
|
+
dep.subscribe(this.onSourceInvalidate)
|
|
5673
|
+
);
|
|
5674
|
+
}
|
|
5675
|
+
}
|
|
5676
|
+
};
|
|
5677
|
+
this.runtime = runtime;
|
|
5678
|
+
this.onUpdate = opts.onUpdate;
|
|
5679
|
+
this.run = opts.run;
|
|
5680
|
+
this.deps = opts.deps ?? [];
|
|
5681
|
+
for (const dep of this.deps) {
|
|
5682
|
+
if (dep instanceof OIMEffectDependencyComputed) {
|
|
5683
|
+
this.computedDeps.push(dep);
|
|
5684
|
+
} else {
|
|
5685
|
+
this.sourceDeps.push(dep);
|
|
5686
|
+
}
|
|
5687
|
+
}
|
|
5688
|
+
this.level = level ?? this.runtime.computeLevel(this.deps);
|
|
5689
|
+
this.subscribeToDeps();
|
|
5690
|
+
}
|
|
5691
|
+
destroy() {
|
|
5692
|
+
if (this.dequeueScheduled) {
|
|
5693
|
+
this.dequeueScheduled();
|
|
5694
|
+
this.dequeueScheduled = void 0;
|
|
5695
|
+
}
|
|
5696
|
+
this.unsubscribeFromAllDeps();
|
|
5697
|
+
if (this.dequeueResubscribe) {
|
|
5698
|
+
this.dequeueResubscribe();
|
|
5699
|
+
this.dequeueResubscribe = void 0;
|
|
5700
|
+
}
|
|
5701
|
+
this.isResubscribeEnqueued = false;
|
|
5702
|
+
this.isTemporarilyUnsubscribedForFlush = false;
|
|
5703
|
+
}
|
|
5704
|
+
runOnce() {
|
|
5705
|
+
this.run();
|
|
5706
|
+
}
|
|
5707
|
+
subscribeToDeps() {
|
|
5708
|
+
if (this.sourceUnsubscribers.length > 0 || this.computedUnsubscribers.length > 0)
|
|
5709
|
+
return;
|
|
5710
|
+
for (const dep of this.sourceDeps) {
|
|
5711
|
+
this.sourceUnsubscribers.push(
|
|
5712
|
+
dep.subscribe(this.onSourceInvalidate)
|
|
5713
|
+
);
|
|
5714
|
+
}
|
|
5715
|
+
for (const dep of this.computedDeps) {
|
|
5716
|
+
this.computedUnsubscribers.push(
|
|
5717
|
+
dep.subscribe(this.onComputedInvalidate)
|
|
5718
|
+
);
|
|
5719
|
+
}
|
|
5720
|
+
}
|
|
5721
|
+
unsubscribeFromSourceDeps() {
|
|
5722
|
+
if (this.sourceUnsubscribers.length === 0) return;
|
|
5723
|
+
for (const unsubscribe of this.sourceUnsubscribers) unsubscribe();
|
|
5724
|
+
this.sourceUnsubscribers = [];
|
|
5725
|
+
}
|
|
5726
|
+
unsubscribeFromAllDeps() {
|
|
5727
|
+
this.unsubscribeFromSourceDeps();
|
|
5728
|
+
if (this.computedUnsubscribers.length === 0) return;
|
|
5729
|
+
for (const unsubscribe of this.computedUnsubscribers) unsubscribe();
|
|
5730
|
+
this.computedUnsubscribers = [];
|
|
5731
|
+
}
|
|
5732
|
+
ensureResubscribeAfterFlush() {
|
|
5733
|
+
if (this.isResubscribeEnqueued) return;
|
|
5734
|
+
this.isResubscribeEnqueued = true;
|
|
5735
|
+
this.dequeueResubscribe = this.runtime.scheduleAfterFlush(
|
|
5736
|
+
this.onAfterFlush
|
|
5737
|
+
);
|
|
5738
|
+
}
|
|
5739
|
+
};
|
|
5740
|
+
|
|
5741
|
+
// src/modules/computed/enums/EOIMComputedEventType.ts
|
|
5742
|
+
var EOIMComputedEventType = /* @__PURE__ */ ((EOIMComputedEventType2) => {
|
|
5743
|
+
EOIMComputedEventType2["UPDATE"] = "update";
|
|
5744
|
+
return EOIMComputedEventType2;
|
|
5745
|
+
})(EOIMComputedEventType || {});
|
|
5746
|
+
|
|
5747
|
+
// src/modules/computed/core/OIMComputed.ts
|
|
5748
|
+
var OIMComputed = class {
|
|
5749
|
+
constructor(runtime, opts) {
|
|
5750
|
+
this.emitter = new OIMEventEmitter();
|
|
5751
|
+
this.hasValue = false;
|
|
5752
|
+
this.isDirty = true;
|
|
5753
|
+
this.runtime = runtime;
|
|
5754
|
+
this.compute = opts.compute;
|
|
5755
|
+
this.compare = opts.compare ?? Object.is;
|
|
5756
|
+
this._deps = opts.deps ?? [];
|
|
5757
|
+
this.updateEventEmitter = new OIMUpdateEventEmitter(
|
|
5758
|
+
this.runtime.queue,
|
|
5759
|
+
"immediate"
|
|
5760
|
+
);
|
|
5761
|
+
const level = this.runtime.computeLevel(this._deps);
|
|
5762
|
+
this.runtime.registerLevel(this, level);
|
|
5763
|
+
this.effect = new OIMEffect(
|
|
5764
|
+
this.runtime,
|
|
5765
|
+
{
|
|
5766
|
+
deps: this._deps,
|
|
5767
|
+
onUpdate: () => {
|
|
5768
|
+
this.isDirty = true;
|
|
5769
|
+
},
|
|
5770
|
+
run: () => {
|
|
5771
|
+
this.recomputeAndEmitIfChanged();
|
|
5772
|
+
}
|
|
5773
|
+
},
|
|
5774
|
+
level
|
|
5775
|
+
);
|
|
5776
|
+
}
|
|
5777
|
+
get needsRecompute() {
|
|
5778
|
+
return this.isDirty;
|
|
5779
|
+
}
|
|
5780
|
+
get isReady() {
|
|
5781
|
+
return this.hasValue;
|
|
5782
|
+
}
|
|
5783
|
+
get deps() {
|
|
5784
|
+
return this._deps;
|
|
5785
|
+
}
|
|
5786
|
+
get() {
|
|
5787
|
+
this.recomputeAndEmitIfChanged();
|
|
5788
|
+
return this.value;
|
|
5789
|
+
}
|
|
5790
|
+
getIfReady() {
|
|
5791
|
+
return this.hasValue ? this.value : void 0;
|
|
5792
|
+
}
|
|
5793
|
+
destroy() {
|
|
5794
|
+
this.effect.destroy();
|
|
5795
|
+
this.updateEventEmitter.destroy();
|
|
5796
|
+
this.emitter.offAll();
|
|
5797
|
+
}
|
|
5798
|
+
recomputeAndEmitIfChanged() {
|
|
5799
|
+
if (!this.isDirty) return;
|
|
5800
|
+
const prev = this.value;
|
|
5801
|
+
const hadPrev = this.hasValue;
|
|
5802
|
+
const next = this.compute();
|
|
5803
|
+
this.value = next;
|
|
5804
|
+
this.hasValue = true;
|
|
5805
|
+
this.isDirty = false;
|
|
5806
|
+
const changed = !hadPrev || !this.compare(prev, next);
|
|
5807
|
+
if (!changed) return;
|
|
5808
|
+
this.emitter.emit("update" /* UPDATE */, {
|
|
5809
|
+
keys: ["value"]
|
|
5810
|
+
});
|
|
5811
|
+
this.updateEventEmitter.markUpdatedKey("value");
|
|
5812
|
+
}
|
|
5813
|
+
};
|
|
5814
|
+
|
|
5815
|
+
// src/dx/OIMCollectionKit.ts
|
|
5816
|
+
function createOIMCollectionKit(queue, opts) {
|
|
5817
|
+
const collection = new OIMReactiveCollection(queue, opts);
|
|
5818
|
+
const indexFactory = new OIMCollectionIndexFactory(queue, collection);
|
|
5819
|
+
const select = new OIMCollectionSelectors(queue, collection);
|
|
5820
|
+
const runtime = getOIMComputeRuntime(queue);
|
|
5821
|
+
const scope = new OIMDisposeScope();
|
|
5822
|
+
scope.add(collection);
|
|
5823
|
+
return {
|
|
5824
|
+
queue,
|
|
5825
|
+
collection,
|
|
5826
|
+
indexFactory,
|
|
5827
|
+
select,
|
|
5828
|
+
on,
|
|
5829
|
+
computed: (deps, compute, options) => {
|
|
5830
|
+
const computed = new OIMComputed(runtime, {
|
|
5831
|
+
deps,
|
|
5832
|
+
compute,
|
|
5833
|
+
compare: options?.compare
|
|
5834
|
+
});
|
|
5835
|
+
scope.add(computed);
|
|
5836
|
+
return computed;
|
|
5837
|
+
},
|
|
5838
|
+
effect: (deps, run, options) => {
|
|
5839
|
+
const effect = new OIMEffect(runtime, {
|
|
5840
|
+
deps,
|
|
5841
|
+
run,
|
|
5842
|
+
onUpdate: options?.onUpdate
|
|
5843
|
+
});
|
|
5844
|
+
scope.add(effect);
|
|
5845
|
+
return effect;
|
|
5846
|
+
},
|
|
5847
|
+
scope,
|
|
5848
|
+
destroy: () => scope.destroy()
|
|
5849
|
+
};
|
|
5850
|
+
}
|
|
5851
|
+
|
|
5852
|
+
// src/dx/peekOIMComputeRuntime.ts
|
|
5853
|
+
function peekOIMComputeRuntime(queue) {
|
|
5854
|
+
const runtime = oimComputeRuntimeByQueue.get(queue);
|
|
5855
|
+
return runtime === void 0 || runtime.isDestroyed ? void 0 : runtime;
|
|
5856
|
+
}
|
|
5857
|
+
|
|
5858
|
+
// src/dx/setOIMComputeRuntime.ts
|
|
5859
|
+
function setOIMComputeRuntime(queue, runtime) {
|
|
5860
|
+
if (runtime.queue !== queue) {
|
|
5861
|
+
throw new Error(
|
|
5862
|
+
"setOIMComputeRuntime: the runtime is attached to a different queue. A runtime drains on its own queue and would never run here."
|
|
5863
|
+
);
|
|
5864
|
+
}
|
|
5865
|
+
oimComputeRuntimeByQueue.set(queue, runtime);
|
|
5866
|
+
}
|
|
5867
|
+
|
|
5868
|
+
// src/modules/wrapper/collection/OIMCollectionChangedFields.ts
|
|
5869
|
+
var OIMCollectionChangedFields = class {
|
|
5870
|
+
constructor(queue, collection, opts) {
|
|
5871
|
+
this.isInWrite = false;
|
|
5872
|
+
this.lastEntitySnapshotByPk = /* @__PURE__ */ new Map();
|
|
5873
|
+
// PKs written through this wrapper during the current flush. Their fields are
|
|
5874
|
+
// already tracked accurately via trackPatch, so the flush-time external-write
|
|
5875
|
+
// handler skips them — no redundant diff + snapshot re-clone. Cleared per flush.
|
|
5876
|
+
this.writtenThroughThisFlush = /* @__PURE__ */ new Set();
|
|
5877
|
+
this.changedFieldsByPk = /* @__PURE__ */ new Map();
|
|
5878
|
+
this.changedPksByField = /* @__PURE__ */ new Map();
|
|
5879
|
+
this.onAfterFlush = () => {
|
|
5880
|
+
this.clear();
|
|
5881
|
+
this.writtenThroughThisFlush.clear();
|
|
5882
|
+
};
|
|
5883
|
+
this.onCollectionUpdate = (payload) => {
|
|
5884
|
+
if (this.isInWrite) return;
|
|
5885
|
+
if (payload.pks.length === 0) return;
|
|
5886
|
+
for (let i = 0; i < payload.pks.length; i++) {
|
|
5887
|
+
const pk = payload.pks[i];
|
|
5888
|
+
if (this.writtenThroughThisFlush.has(pk)) continue;
|
|
5889
|
+
this.trackExternalMutationByPk(pk);
|
|
5890
|
+
}
|
|
5891
|
+
};
|
|
5892
|
+
this.collection = collection;
|
|
5893
|
+
this.detectExternalMutations = opts?.detectExternalMutations !== false;
|
|
5894
|
+
this.selectPk = opts?.selectPk ?? (() => {
|
|
5895
|
+
throw new Error(
|
|
5896
|
+
`[OIMCollectionChangedFields]: selectPk was not provided. Use upsertOneByPk(...) or pass opts.selectPk.`
|
|
5897
|
+
);
|
|
5898
|
+
});
|
|
5899
|
+
this.changedPksEventEmitter = new OIMUpdateEventEmitter(
|
|
5900
|
+
queue,
|
|
5901
|
+
"after_flush"
|
|
5902
|
+
);
|
|
5903
|
+
this.changedFieldsEventEmitter = new OIMUpdateEventEmitter(queue, "after_flush");
|
|
5904
|
+
this.unsubscribeAfterFlush = queue.emitter.on(
|
|
5905
|
+
0 /* AFTER_FLUSH */,
|
|
5906
|
+
this.onAfterFlush
|
|
5907
|
+
);
|
|
5908
|
+
if (this.detectExternalMutations) {
|
|
5909
|
+
const maybeReactive = collection;
|
|
5910
|
+
this.unsubscribeFromCollectionEmitter = maybeReactive.subscribeOnAnyUpdate ? maybeReactive.subscribeOnAnyUpdate((pks) => {
|
|
5911
|
+
this.onCollectionUpdate({
|
|
5912
|
+
pks
|
|
5913
|
+
});
|
|
5914
|
+
}) : collection.emitter.on(
|
|
5915
|
+
0 /* UPDATE */,
|
|
5916
|
+
this.onCollectionUpdate
|
|
5917
|
+
);
|
|
5918
|
+
}
|
|
5919
|
+
}
|
|
5920
|
+
upsertOneByPk(pk, patch) {
|
|
5921
|
+
const slot = this.withWrite(() => {
|
|
5922
|
+
this.trackPatch(pk, patch);
|
|
5923
|
+
return this.collection.upsertOneByPk(pk, patch);
|
|
5924
|
+
});
|
|
5925
|
+
this.updateEntitySnapshot(pk);
|
|
5926
|
+
return slot;
|
|
5927
|
+
}
|
|
5928
|
+
upsertOne(entity) {
|
|
5929
|
+
const slot = this.withWrite(() => {
|
|
5930
|
+
const pk = this.selectPk(entity);
|
|
5931
|
+
this.trackPatch(pk, entity);
|
|
5932
|
+
return this.collection.upsertOne(entity);
|
|
5933
|
+
});
|
|
5934
|
+
this.updateEntitySnapshot(slot.pk);
|
|
5935
|
+
return slot;
|
|
5936
|
+
}
|
|
5937
|
+
upsertMany(entities) {
|
|
5938
|
+
const pks = [];
|
|
5939
|
+
const slots = this.withWrite(() => {
|
|
5940
|
+
for (const entity of entities) {
|
|
5941
|
+
const pk = this.selectPk(entity);
|
|
5942
|
+
pks.push(pk);
|
|
5943
|
+
this.trackPatch(pk, entity);
|
|
5944
|
+
}
|
|
5945
|
+
return this.collection.upsertMany(entities);
|
|
5946
|
+
});
|
|
5947
|
+
for (let i = 0; i < pks.length; i++) this.updateEntitySnapshot(pks[i]);
|
|
5948
|
+
return slots;
|
|
5949
|
+
}
|
|
5950
|
+
getChangedFieldsByPk(pk) {
|
|
5951
|
+
return this.changedFieldsByPk.get(pk) ?? /* @__PURE__ */ new Set();
|
|
5952
|
+
}
|
|
5953
|
+
consumeChangedFieldsByPk(pk) {
|
|
5954
|
+
const existing = this.changedFieldsByPk.get(pk);
|
|
5955
|
+
if (!existing) return /* @__PURE__ */ new Set();
|
|
5956
|
+
return new Set(existing);
|
|
5957
|
+
}
|
|
5958
|
+
getChangedPksByField(field) {
|
|
5959
|
+
return this.changedPksByField.get(field) ?? /* @__PURE__ */ new Set();
|
|
5960
|
+
}
|
|
5961
|
+
consumeChangedPksByField(field) {
|
|
5962
|
+
const existing = this.changedPksByField.get(field);
|
|
5963
|
+
if (!existing) return /* @__PURE__ */ new Set();
|
|
5964
|
+
return new Set(existing);
|
|
5446
5965
|
}
|
|
5447
5966
|
clear() {
|
|
5448
5967
|
this.changedFieldsByPk.clear();
|
|
@@ -5488,8 +6007,9 @@ var OIMCollectionChangedFields = class {
|
|
|
5488
6007
|
Object.keys(nextObj).forEach((k) => keys.add(k));
|
|
5489
6008
|
const changed = [];
|
|
5490
6009
|
keys.forEach((k) => {
|
|
5491
|
-
if (prevObj[k] !== nextObj[k])
|
|
6010
|
+
if (prevObj[k] !== nextObj[k]) {
|
|
5492
6011
|
changed.push(k);
|
|
6012
|
+
}
|
|
5493
6013
|
});
|
|
5494
6014
|
return changed;
|
|
5495
6015
|
}
|
|
@@ -5655,10 +6175,15 @@ var OIMOrderedListMappedCommandStream = class _OIMOrderedListMappedCommandStream
|
|
|
5655
6175
|
try {
|
|
5656
6176
|
const subs = this.subscribers.get(key);
|
|
5657
6177
|
if (subs && subs.size > 0) {
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
6178
|
+
if (subs.size === 1) {
|
|
6179
|
+
const only = subs.values().next().value;
|
|
6180
|
+
if (only) only();
|
|
6181
|
+
} else {
|
|
6182
|
+
const snapshot = Array.from(subs);
|
|
6183
|
+
for (let s = 0; s < snapshot.length; s++) {
|
|
6184
|
+
const handler = snapshot[s];
|
|
6185
|
+
if (subs.has(handler)) handler();
|
|
6186
|
+
}
|
|
5662
6187
|
}
|
|
5663
6188
|
}
|
|
5664
6189
|
} finally {
|
|
@@ -5952,10 +6477,13 @@ var OIMEventQueueSchedulerAnimationFrame = class extends OIMEventQueueScheduler
|
|
|
5952
6477
|
this.flush();
|
|
5953
6478
|
});
|
|
5954
6479
|
} else {
|
|
5955
|
-
this.frameId =
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
6480
|
+
this.frameId = this.unref(
|
|
6481
|
+
setTimeout(() => {
|
|
6482
|
+
this.frameId = void 0;
|
|
6483
|
+
this.flush();
|
|
6484
|
+
}, 16)
|
|
6485
|
+
// ~60fps
|
|
6486
|
+
);
|
|
5959
6487
|
}
|
|
5960
6488
|
}
|
|
5961
6489
|
cancel() {
|
|
@@ -6001,10 +6529,12 @@ var OIMEventQueueSchedulerTimeout = class extends OIMEventQueueScheduler {
|
|
|
6001
6529
|
}
|
|
6002
6530
|
schedule() {
|
|
6003
6531
|
if (this.timeoutId !== void 0) return;
|
|
6004
|
-
this.timeoutId =
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6532
|
+
this.timeoutId = this.unref(
|
|
6533
|
+
setTimeout(() => {
|
|
6534
|
+
this.timeoutId = void 0;
|
|
6535
|
+
this.flush();
|
|
6536
|
+
}, this.delay)
|
|
6537
|
+
);
|
|
6008
6538
|
}
|
|
6009
6539
|
cancel() {
|
|
6010
6540
|
if (this.timeoutId === void 0) return;
|
|
@@ -6038,13 +6568,13 @@ var OIMEventQueueSchedulerImmediate = class extends OIMEventQueueScheduler {
|
|
|
6038
6568
|
this.flush();
|
|
6039
6569
|
};
|
|
6040
6570
|
if (this.useSetImmediate) {
|
|
6041
|
-
this.immediateId = setImmediate(callback);
|
|
6571
|
+
this.immediateId = this.unref(setImmediate(callback));
|
|
6042
6572
|
} else if (this.useMessageChannel && this.messageChannel) {
|
|
6043
6573
|
this.immediateId = 1;
|
|
6044
6574
|
this.pendingCallback = callback;
|
|
6045
6575
|
this.messageChannel.port1.postMessage(null);
|
|
6046
6576
|
} else {
|
|
6047
|
-
this.immediateId = setTimeout(callback, 0);
|
|
6577
|
+
this.immediateId = this.unref(setTimeout(callback, 0));
|
|
6048
6578
|
}
|
|
6049
6579
|
}
|
|
6050
6580
|
cancel() {
|
|
@@ -6137,242 +6667,6 @@ var OIMDBSettings = class {
|
|
|
6137
6667
|
OIMDBSettings.UPDATED_KEYS_INDEX_KEY = "__updatedKeys__";
|
|
6138
6668
|
OIMDBSettings.FLUSHING_KEYS_INDEX_KEY = "__flushingKeys__";
|
|
6139
6669
|
|
|
6140
|
-
// src/modules/effect/core/OIMEffectDependencyComputed.ts
|
|
6141
|
-
var OIMEffectDependencyComputed = class {
|
|
6142
|
-
constructor(source) {
|
|
6143
|
-
this.source = source;
|
|
6144
|
-
}
|
|
6145
|
-
subscribe(onUpdate) {
|
|
6146
|
-
return this.source.emitter.on("update", onUpdate);
|
|
6147
|
-
}
|
|
6148
|
-
};
|
|
6149
|
-
|
|
6150
|
-
// src/modules/effect/core/OIMEffect.ts
|
|
6151
|
-
var OIMEffect = class {
|
|
6152
|
-
constructor(runtime, opts) {
|
|
6153
|
-
this.sourceDeps = [];
|
|
6154
|
-
this.computedDeps = [];
|
|
6155
|
-
this.sourceUnsubscribers = [];
|
|
6156
|
-
this.computedUnsubscribers = [];
|
|
6157
|
-
this.isResubscribeEnqueued = false;
|
|
6158
|
-
this.isTemporarilyUnsubscribedForFlush = false;
|
|
6159
|
-
this.isScheduled = false;
|
|
6160
|
-
this.runTask = () => {
|
|
6161
|
-
this.isScheduled = false;
|
|
6162
|
-
this.dequeueScheduled = void 0;
|
|
6163
|
-
this.runOnce();
|
|
6164
|
-
};
|
|
6165
|
-
this.onSourceInvalidate = () => {
|
|
6166
|
-
this.onUpdate?.();
|
|
6167
|
-
if (!this.isTemporarilyUnsubscribedForFlush) {
|
|
6168
|
-
this.isTemporarilyUnsubscribedForFlush = true;
|
|
6169
|
-
this.unsubscribeFromSourceDeps();
|
|
6170
|
-
this.ensureResubscribeAfterFlush();
|
|
6171
|
-
}
|
|
6172
|
-
if (this.isScheduled) return;
|
|
6173
|
-
this.isScheduled = true;
|
|
6174
|
-
this.dequeueScheduled = this.runtime.schedule(this.runTask);
|
|
6175
|
-
};
|
|
6176
|
-
this.onComputedInvalidate = () => {
|
|
6177
|
-
this.onUpdate?.();
|
|
6178
|
-
if (this.isScheduled) return;
|
|
6179
|
-
this.isScheduled = true;
|
|
6180
|
-
this.dequeueScheduled = this.runtime.schedule(this.runTask);
|
|
6181
|
-
};
|
|
6182
|
-
this.onAfterFlush = () => {
|
|
6183
|
-
if (!this.isResubscribeEnqueued) return;
|
|
6184
|
-
this.isResubscribeEnqueued = false;
|
|
6185
|
-
this.dequeueResubscribe = void 0;
|
|
6186
|
-
this.isTemporarilyUnsubscribedForFlush = false;
|
|
6187
|
-
if (this.sourceUnsubscribers.length === 0) {
|
|
6188
|
-
for (const dep of this.sourceDeps) {
|
|
6189
|
-
this.sourceUnsubscribers.push(
|
|
6190
|
-
dep.subscribe(this.onSourceInvalidate)
|
|
6191
|
-
);
|
|
6192
|
-
}
|
|
6193
|
-
}
|
|
6194
|
-
};
|
|
6195
|
-
this.runtime = runtime;
|
|
6196
|
-
this.onUpdate = opts.onUpdate;
|
|
6197
|
-
this.run = opts.run;
|
|
6198
|
-
this.deps = opts.deps ?? [];
|
|
6199
|
-
for (const dep of this.deps) {
|
|
6200
|
-
if (dep instanceof OIMEffectDependencyComputed) {
|
|
6201
|
-
this.computedDeps.push(dep);
|
|
6202
|
-
} else {
|
|
6203
|
-
this.sourceDeps.push(dep);
|
|
6204
|
-
}
|
|
6205
|
-
}
|
|
6206
|
-
this.subscribeToDeps();
|
|
6207
|
-
}
|
|
6208
|
-
destroy() {
|
|
6209
|
-
if (this.dequeueScheduled) {
|
|
6210
|
-
this.dequeueScheduled();
|
|
6211
|
-
this.dequeueScheduled = void 0;
|
|
6212
|
-
}
|
|
6213
|
-
this.unsubscribeFromAllDeps();
|
|
6214
|
-
if (this.dequeueResubscribe) {
|
|
6215
|
-
this.dequeueResubscribe();
|
|
6216
|
-
this.dequeueResubscribe = void 0;
|
|
6217
|
-
}
|
|
6218
|
-
this.isResubscribeEnqueued = false;
|
|
6219
|
-
this.isTemporarilyUnsubscribedForFlush = false;
|
|
6220
|
-
}
|
|
6221
|
-
runOnce() {
|
|
6222
|
-
this.run();
|
|
6223
|
-
}
|
|
6224
|
-
subscribeToDeps() {
|
|
6225
|
-
if (this.sourceUnsubscribers.length > 0 || this.computedUnsubscribers.length > 0)
|
|
6226
|
-
return;
|
|
6227
|
-
for (const dep of this.sourceDeps) {
|
|
6228
|
-
this.sourceUnsubscribers.push(
|
|
6229
|
-
dep.subscribe(this.onSourceInvalidate)
|
|
6230
|
-
);
|
|
6231
|
-
}
|
|
6232
|
-
for (const dep of this.computedDeps) {
|
|
6233
|
-
this.computedUnsubscribers.push(
|
|
6234
|
-
dep.subscribe(this.onComputedInvalidate)
|
|
6235
|
-
);
|
|
6236
|
-
}
|
|
6237
|
-
}
|
|
6238
|
-
unsubscribeFromSourceDeps() {
|
|
6239
|
-
if (this.sourceUnsubscribers.length === 0) return;
|
|
6240
|
-
for (const unsubscribe of this.sourceUnsubscribers) unsubscribe();
|
|
6241
|
-
this.sourceUnsubscribers = [];
|
|
6242
|
-
}
|
|
6243
|
-
unsubscribeFromAllDeps() {
|
|
6244
|
-
this.unsubscribeFromSourceDeps();
|
|
6245
|
-
if (this.computedUnsubscribers.length === 0) return;
|
|
6246
|
-
for (const unsubscribe of this.computedUnsubscribers) unsubscribe();
|
|
6247
|
-
this.computedUnsubscribers = [];
|
|
6248
|
-
}
|
|
6249
|
-
ensureResubscribeAfterFlush() {
|
|
6250
|
-
if (this.isResubscribeEnqueued) return;
|
|
6251
|
-
this.isResubscribeEnqueued = true;
|
|
6252
|
-
this.dequeueResubscribe = this.runtime.scheduleAfterFlush(
|
|
6253
|
-
this.onAfterFlush
|
|
6254
|
-
);
|
|
6255
|
-
}
|
|
6256
|
-
};
|
|
6257
|
-
|
|
6258
|
-
// src/modules/computed/enums/EOIMComputedEventType.ts
|
|
6259
|
-
var EOIMComputedEventType = /* @__PURE__ */ ((EOIMComputedEventType2) => {
|
|
6260
|
-
EOIMComputedEventType2["UPDATE"] = "update";
|
|
6261
|
-
return EOIMComputedEventType2;
|
|
6262
|
-
})(EOIMComputedEventType || {});
|
|
6263
|
-
|
|
6264
|
-
// src/modules/computed/core/OIMComputed.ts
|
|
6265
|
-
var OIMComputed = class {
|
|
6266
|
-
constructor(runtime, opts) {
|
|
6267
|
-
this.emitter = new OIMEventEmitter();
|
|
6268
|
-
this.hasValue = false;
|
|
6269
|
-
this.isDirty = true;
|
|
6270
|
-
this.runtime = runtime;
|
|
6271
|
-
this.compute = opts.compute;
|
|
6272
|
-
this.compare = opts.compare ?? Object.is;
|
|
6273
|
-
this._deps = opts.deps ?? [];
|
|
6274
|
-
this.updateEventEmitter = new OIMUpdateEventEmitter(
|
|
6275
|
-
this.runtime.queue,
|
|
6276
|
-
"immediate"
|
|
6277
|
-
);
|
|
6278
|
-
this.effect = new OIMEffect(this.runtime, {
|
|
6279
|
-
deps: this._deps,
|
|
6280
|
-
onUpdate: () => {
|
|
6281
|
-
this.isDirty = true;
|
|
6282
|
-
},
|
|
6283
|
-
run: () => {
|
|
6284
|
-
this.recomputeAndEmitIfChanged();
|
|
6285
|
-
}
|
|
6286
|
-
});
|
|
6287
|
-
}
|
|
6288
|
-
get needsRecompute() {
|
|
6289
|
-
return this.isDirty;
|
|
6290
|
-
}
|
|
6291
|
-
get isReady() {
|
|
6292
|
-
return this.hasValue;
|
|
6293
|
-
}
|
|
6294
|
-
get deps() {
|
|
6295
|
-
return this._deps;
|
|
6296
|
-
}
|
|
6297
|
-
get() {
|
|
6298
|
-
this.recomputeAndEmitIfChanged();
|
|
6299
|
-
return this.value;
|
|
6300
|
-
}
|
|
6301
|
-
getIfReady() {
|
|
6302
|
-
return this.hasValue ? this.value : void 0;
|
|
6303
|
-
}
|
|
6304
|
-
destroy() {
|
|
6305
|
-
this.effect.destroy();
|
|
6306
|
-
this.updateEventEmitter.destroy();
|
|
6307
|
-
this.emitter.offAll();
|
|
6308
|
-
}
|
|
6309
|
-
recomputeAndEmitIfChanged() {
|
|
6310
|
-
if (!this.isDirty) return;
|
|
6311
|
-
const prev = this.value;
|
|
6312
|
-
const hadPrev = this.hasValue;
|
|
6313
|
-
const next = this.compute();
|
|
6314
|
-
this.value = next;
|
|
6315
|
-
this.hasValue = true;
|
|
6316
|
-
this.isDirty = false;
|
|
6317
|
-
const changed = !hadPrev || !this.compare(prev, next);
|
|
6318
|
-
if (!changed) return;
|
|
6319
|
-
this.emitter.emit("update" /* UPDATE */, {
|
|
6320
|
-
keys: ["value"]
|
|
6321
|
-
});
|
|
6322
|
-
this.updateEventEmitter.markUpdatedKey("value");
|
|
6323
|
-
}
|
|
6324
|
-
};
|
|
6325
|
-
|
|
6326
|
-
// src/modules/effect/core/OIMEffectDependencyKeyed.ts
|
|
6327
|
-
var OIMEffectDependencyKeyed = class {
|
|
6328
|
-
constructor(source, key) {
|
|
6329
|
-
this.source = source;
|
|
6330
|
-
this.key = key;
|
|
6331
|
-
}
|
|
6332
|
-
subscribe(onUpdate) {
|
|
6333
|
-
return this.source.subscribeOnKey(this.key, onUpdate);
|
|
6334
|
-
}
|
|
6335
|
-
};
|
|
6336
|
-
|
|
6337
|
-
// src/modules/effect/core/OIMEffectDependencyKeyedObject.ts
|
|
6338
|
-
var OIMEffectDependencyKeyedObject = class {
|
|
6339
|
-
constructor(object, key) {
|
|
6340
|
-
this.dep = new OIMEffectDependencyKeyed(object, key);
|
|
6341
|
-
}
|
|
6342
|
-
get source() {
|
|
6343
|
-
return this.dep.source;
|
|
6344
|
-
}
|
|
6345
|
-
subscribe(onUpdate) {
|
|
6346
|
-
return this.dep.subscribe(onUpdate);
|
|
6347
|
-
}
|
|
6348
|
-
};
|
|
6349
|
-
|
|
6350
|
-
// src/modules/effect/core/OIMEffectDependencyKeyedCollection.ts
|
|
6351
|
-
var OIMEffectDependencyKeyedCollection = class {
|
|
6352
|
-
constructor(collection, pk) {
|
|
6353
|
-
this.dep = new OIMEffectDependencyKeyed(collection, pk);
|
|
6354
|
-
}
|
|
6355
|
-
get source() {
|
|
6356
|
-
return this.dep.source;
|
|
6357
|
-
}
|
|
6358
|
-
subscribe(onUpdate) {
|
|
6359
|
-
return this.dep.subscribe(onUpdate);
|
|
6360
|
-
}
|
|
6361
|
-
};
|
|
6362
|
-
|
|
6363
|
-
// src/modules/effect/core/OIMEffectDependencyKeyedIndex.ts
|
|
6364
|
-
var OIMEffectDependencyKeyedIndex = class {
|
|
6365
|
-
constructor(index, key) {
|
|
6366
|
-
this.dep = new OIMEffectDependencyKeyed(index, key);
|
|
6367
|
-
}
|
|
6368
|
-
get source() {
|
|
6369
|
-
return this.dep.source;
|
|
6370
|
-
}
|
|
6371
|
-
subscribe(onUpdate) {
|
|
6372
|
-
return this.dep.subscribe(onUpdate);
|
|
6373
|
-
}
|
|
6374
|
-
};
|
|
6375
|
-
|
|
6376
6670
|
// src/modules/selector/core/OIMObjectValueByKeySelector.ts
|
|
6377
6671
|
var OIMObjectValueByKeySelector = class extends OIMSelector {
|
|
6378
6672
|
constructor(runtime, obj, key) {
|
|
@@ -6450,8 +6744,9 @@ var OIMIndexPksByKeyArrayBasedSelector = class extends OIMSelector {
|
|
|
6450
6744
|
areEqual(prev, next) {
|
|
6451
6745
|
if (prev === next) return true;
|
|
6452
6746
|
if (prev.length !== next.length) return false;
|
|
6453
|
-
for (let i = 0; i < prev.length; i++)
|
|
6747
|
+
for (let i = 0; i < prev.length; i++) {
|
|
6454
6748
|
if (prev[i] !== next[i]) return false;
|
|
6749
|
+
}
|
|
6455
6750
|
return true;
|
|
6456
6751
|
}
|
|
6457
6752
|
};
|
|
@@ -6474,8 +6769,9 @@ var OIMIndexPksByKeysSetBasedSelector = class extends OIMSelector {
|
|
|
6474
6769
|
areEqual(prev, next) {
|
|
6475
6770
|
if (prev === next) return true;
|
|
6476
6771
|
if (prev.length !== next.length) return false;
|
|
6477
|
-
for (let i = 0; i < prev.length; i++)
|
|
6772
|
+
for (let i = 0; i < prev.length; i++) {
|
|
6478
6773
|
if (prev[i] !== next[i]) return false;
|
|
6774
|
+
}
|
|
6479
6775
|
return true;
|
|
6480
6776
|
}
|
|
6481
6777
|
};
|
|
@@ -6498,8 +6794,9 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
|
|
|
6498
6794
|
areEqual(prev, next) {
|
|
6499
6795
|
if (prev === next) return true;
|
|
6500
6796
|
if (prev.length !== next.length) return false;
|
|
6501
|
-
for (let i = 0; i < prev.length; i++)
|
|
6797
|
+
for (let i = 0; i < prev.length; i++) {
|
|
6502
6798
|
if (prev[i] !== next[i]) return false;
|
|
6799
|
+
}
|
|
6503
6800
|
return true;
|
|
6504
6801
|
}
|
|
6505
6802
|
};
|
|
@@ -6529,6 +6826,7 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
|
|
|
6529
6826
|
OIMComputeRuntime,
|
|
6530
6827
|
OIMComputed,
|
|
6531
6828
|
OIMDBSettings,
|
|
6829
|
+
OIMDerivedCollection,
|
|
6532
6830
|
OIMDerivedCollectionGlobalIndexArrayBased,
|
|
6533
6831
|
OIMDerivedCollectionGlobalIndexSetBased,
|
|
6534
6832
|
OIMDerivedCollectionIndexArrayBased,
|
|
@@ -6624,5 +6922,9 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
|
|
|
6624
6922
|
createOIMIndexSlotMap,
|
|
6625
6923
|
createOIMOrderedListCommandStreamDiffDriven,
|
|
6626
6924
|
createOIMOrderedListMappedCommandStream,
|
|
6627
|
-
diffOrderedListByPk
|
|
6925
|
+
diffOrderedListByPk,
|
|
6926
|
+
getOIMComputeRuntime,
|
|
6927
|
+
on,
|
|
6928
|
+
peekOIMComputeRuntime,
|
|
6929
|
+
setOIMComputeRuntime
|
|
6628
6930
|
});
|