@oimdb/core 3.10.0 → 3.11.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/README.md +18 -1
- package/dist/index.cjs +730 -451
- package/dist/index.d.cts +308 -120
- package/dist/index.d.ts +308 -120
- package/dist/index.js +724 -450
- package/llms.txt +77 -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
|
|
@@ -704,19 +728,28 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
704
728
|
// doubles as membership: a carrier is in this array iff `carrier.dirty`.
|
|
705
729
|
this.dirtyCarriers = [];
|
|
706
730
|
this.isFlushEnqueued = false;
|
|
731
|
+
// Number of live subscriptions whose single handler spans 2+ distinct
|
|
732
|
+
// carriers (a `subscribeOnKeys` over distinct keys). While this is > 0 a
|
|
733
|
+
// flush coalesces delivery so such a handler fires at most ONCE per flush,
|
|
734
|
+
// not once per changed carrier — the callback carries no key, so extra
|
|
735
|
+
// fires are pure waste. At 0 the hot single-subscriber path pays nothing:
|
|
736
|
+
// no per-flush Set, no membership checks.
|
|
737
|
+
this.multiCarrierSubscriptions = 0;
|
|
707
738
|
this.onFlush = () => {
|
|
708
739
|
this.isFlushEnqueued = false;
|
|
709
740
|
if (this.dirtyCarriers.length === 0) return;
|
|
710
741
|
const flushing = this.dirtyCarriers;
|
|
711
742
|
this.dirtyCarriers = [];
|
|
743
|
+
const delivered = this.multiCarrierSubscriptions > 0 ? this.deliveredPool ?? (this.deliveredPool = /* @__PURE__ */ new Set()) : void 0;
|
|
712
744
|
let i = 0;
|
|
713
745
|
try {
|
|
714
746
|
for (; i < flushing.length; i++) {
|
|
715
747
|
flushing[i].dirty = false;
|
|
716
|
-
this.notify(flushing[i]);
|
|
748
|
+
this.notify(flushing[i], delivered);
|
|
717
749
|
}
|
|
718
750
|
} finally {
|
|
719
751
|
for (; i < flushing.length; i++) flushing[i].dirty = false;
|
|
752
|
+
delivered?.clear();
|
|
720
753
|
}
|
|
721
754
|
};
|
|
722
755
|
this.queue = queue;
|
|
@@ -734,7 +767,13 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
734
767
|
this.addHandler(carrier, handler);
|
|
735
768
|
carriers.push(carrier);
|
|
736
769
|
}
|
|
770
|
+
const spansMultipleCarriers = carriers.length > 1;
|
|
771
|
+
if (spansMultipleCarriers) this.multiCarrierSubscriptions++;
|
|
772
|
+
let unsubscribed = false;
|
|
737
773
|
return () => {
|
|
774
|
+
if (unsubscribed) return;
|
|
775
|
+
unsubscribed = true;
|
|
776
|
+
if (spansMultipleCarriers) this.multiCarrierSubscriptions--;
|
|
738
777
|
for (let i = 0; i < carriers.length; i++) {
|
|
739
778
|
this.removeHandler(carriers[i], handler);
|
|
740
779
|
}
|
|
@@ -850,19 +889,31 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
850
889
|
this.isFlushEnqueued = true;
|
|
851
890
|
this.queue.enqueue(this.onFlush);
|
|
852
891
|
}
|
|
853
|
-
notify(carrier) {
|
|
892
|
+
notify(carrier, delivered) {
|
|
854
893
|
const subscribers = carrier.subscribers;
|
|
855
894
|
if (!subscribers || subscribers.size === 0) return;
|
|
856
895
|
if (subscribers.size === 1) {
|
|
857
896
|
const only = subscribers.values().next().value;
|
|
858
|
-
if (only)
|
|
897
|
+
if (!only) return;
|
|
898
|
+
if (delivered) {
|
|
899
|
+
const size = delivered.size;
|
|
900
|
+
delivered.add(only);
|
|
901
|
+
if (delivered.size === size) return;
|
|
902
|
+
}
|
|
903
|
+
only();
|
|
859
904
|
return;
|
|
860
905
|
}
|
|
861
906
|
const snapshot = [];
|
|
862
907
|
subscribers.forEach((h) => snapshot.push(h));
|
|
863
908
|
for (let i = 0; i < snapshot.length; i++) {
|
|
864
909
|
const handler = snapshot[i];
|
|
865
|
-
if (subscribers.has(handler))
|
|
910
|
+
if (!subscribers.has(handler)) continue;
|
|
911
|
+
if (delivered) {
|
|
912
|
+
const size = delivered.size;
|
|
913
|
+
delivered.add(handler);
|
|
914
|
+
if (delivered.size === size) continue;
|
|
915
|
+
}
|
|
916
|
+
handler();
|
|
866
917
|
}
|
|
867
918
|
}
|
|
868
919
|
};
|
|
@@ -1484,8 +1535,11 @@ var OIMCollection = class {
|
|
|
1484
1535
|
this.emitter.emit(0 /* UPDATE */, { pks });
|
|
1485
1536
|
}
|
|
1486
1537
|
clear() {
|
|
1538
|
+
const pks = this.store.getAllPks();
|
|
1487
1539
|
this.store.clear();
|
|
1488
|
-
|
|
1540
|
+
if (pks.length > 0) {
|
|
1541
|
+
this.emitter.emit(0 /* UPDATE */, { pks });
|
|
1542
|
+
}
|
|
1489
1543
|
}
|
|
1490
1544
|
countAll() {
|
|
1491
1545
|
return this.store.countAll();
|
|
@@ -1527,14 +1581,12 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1527
1581
|
// Only ever holds `slot.pk` (one canonical reference per logical key), so a
|
|
1528
1582
|
// native `Set` dedups correctly by reference even for composite pks.
|
|
1529
1583
|
this.pendingAnyUpdatePks = /* @__PURE__ */ new Set();
|
|
1530
|
-
this.isAnyUpdateClearPending = false;
|
|
1531
1584
|
this.isAnyUpdateScheduled = false;
|
|
1532
1585
|
this.runAnyUpdate = () => {
|
|
1533
1586
|
if (!this.isAnyUpdateScheduled) return;
|
|
1534
1587
|
this.isAnyUpdateScheduled = false;
|
|
1535
|
-
const pks =
|
|
1588
|
+
const pks = Array.from(this.pendingAnyUpdatePks.values());
|
|
1536
1589
|
this.pendingAnyUpdatePks.clear();
|
|
1537
|
-
this.isAnyUpdateClearPending = false;
|
|
1538
1590
|
const snapshot = Array.from(this.anyUpdateHandlers);
|
|
1539
1591
|
for (let i = 0; i < snapshot.length; i++) snapshot[i](pks);
|
|
1540
1592
|
};
|
|
@@ -1574,30 +1626,43 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1574
1626
|
this.anyUpdateHandlers.delete(handler);
|
|
1575
1627
|
};
|
|
1576
1628
|
}
|
|
1577
|
-
//
|
|
1578
|
-
//
|
|
1579
|
-
//
|
|
1580
|
-
//
|
|
1581
|
-
|
|
1629
|
+
// Two notification channels coexist on a reactive collection; they serve
|
|
1630
|
+
// different audiences and NEITHER is obsolete:
|
|
1631
|
+
// • the keyed `updateEmitter` — per-key/per-carrier pings ("did MY key
|
|
1632
|
+
// change?", payload-less `void`), for leaf subscribers like React hooks
|
|
1633
|
+
// that declare the keys they care about up front;
|
|
1634
|
+
// • this `emitter` UPDATE event — the aggregate/batch channel that carries
|
|
1635
|
+
// the full list of changed pks in one SYNCHRONOUS callback, for
|
|
1636
|
+
// consumers that do NOT know their keys ahead of time and must re-derive
|
|
1637
|
+
// over the batch: derived indexes/collections, changed-fields, persist,
|
|
1638
|
+
// snapshot-manager. `pks` always enumerates exactly what changed — even
|
|
1639
|
+
// clear() lists every removed key, so an empty array never occurs.
|
|
1640
|
+
// It is not a per-key emitter with fewer features — it is the opposite
|
|
1641
|
+
// shape (enumerated batch, not "my key"), which is why it stays.
|
|
1642
|
+
//
|
|
1643
|
+
// Emit on the batch channel only when something is actually subscribed —
|
|
1644
|
+
// otherwise every upsert/remove allocates a throwaway `{ pks }` object (and
|
|
1645
|
+
// array) that nobody reads.
|
|
1646
|
+
notifyBatch(pk) {
|
|
1582
1647
|
if (this.emitter.hasHandlers(0 /* UPDATE */)) {
|
|
1583
1648
|
this.emitter.emit(0 /* UPDATE */, { pks: [pk] });
|
|
1584
1649
|
}
|
|
1585
1650
|
}
|
|
1586
|
-
|
|
1651
|
+
notifyBatchMany(pks) {
|
|
1587
1652
|
if (this.emitter.hasHandlers(0 /* UPDATE */)) {
|
|
1588
1653
|
this.emitter.emit(0 /* UPDATE */, { pks });
|
|
1589
1654
|
}
|
|
1590
1655
|
}
|
|
1591
1656
|
upsertOneByPk(pk, entity) {
|
|
1592
1657
|
const slot = this.upsertOneWithoutNotificationsByPk(pk, entity);
|
|
1593
|
-
this.
|
|
1658
|
+
this.notifyBatch(pk);
|
|
1594
1659
|
this.updateEmitter.markUpdatedCarrier(slot);
|
|
1595
1660
|
this.trackAnyUpdatePk(pk);
|
|
1596
1661
|
return slot;
|
|
1597
1662
|
}
|
|
1598
1663
|
upsertOne(entity) {
|
|
1599
1664
|
const slot = this.upsertOneWithoutNotifications(entity);
|
|
1600
|
-
this.
|
|
1665
|
+
this.notifyBatch(slot.pk);
|
|
1601
1666
|
this.updateEmitter.markUpdatedCarrier(slot);
|
|
1602
1667
|
this.trackAnyUpdatePk(slot.pk);
|
|
1603
1668
|
return slot;
|
|
@@ -1608,7 +1673,7 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1608
1673
|
(entity) => this.upsertOneWithoutNotifications(entity)
|
|
1609
1674
|
);
|
|
1610
1675
|
const pks = slots.map((slot) => slot.pk);
|
|
1611
|
-
this.
|
|
1676
|
+
this.notifyBatchMany(pks);
|
|
1612
1677
|
for (let i = 0; i < slots.length; i++) {
|
|
1613
1678
|
this.updateEmitter.markUpdatedCarrier(slots[i]);
|
|
1614
1679
|
}
|
|
@@ -1618,7 +1683,7 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1618
1683
|
removeOne(entity) {
|
|
1619
1684
|
const pk = this.selectPk(entity);
|
|
1620
1685
|
this.store.removeOneByPk(pk);
|
|
1621
|
-
this.
|
|
1686
|
+
this.notifyBatch(pk);
|
|
1622
1687
|
this.updateEmitter.markUpdatedKey(pk);
|
|
1623
1688
|
this.trackAnyUpdatePk(pk);
|
|
1624
1689
|
}
|
|
@@ -1626,30 +1691,32 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1626
1691
|
if (entities.length === 0) return;
|
|
1627
1692
|
const pks = entities.map(this.selectPk);
|
|
1628
1693
|
this.store.removeManyByPks(pks);
|
|
1629
|
-
this.
|
|
1694
|
+
this.notifyBatchMany(pks);
|
|
1630
1695
|
this.updateEmitter.markUpdatedKeys(pks);
|
|
1631
1696
|
this.trackAnyUpdatePks(pks);
|
|
1632
1697
|
}
|
|
1633
1698
|
removeOneByPk(pk) {
|
|
1634
1699
|
this.store.removeOneByPk(pk);
|
|
1635
|
-
this.
|
|
1700
|
+
this.notifyBatch(pk);
|
|
1636
1701
|
this.updateEmitter.markUpdatedKey(pk);
|
|
1637
1702
|
this.trackAnyUpdatePk(pk);
|
|
1638
1703
|
}
|
|
1639
1704
|
removeManyByPks(pks) {
|
|
1640
1705
|
if (pks.length === 0) return;
|
|
1641
1706
|
this.store.removeManyByPks(pks);
|
|
1642
|
-
this.
|
|
1707
|
+
this.notifyBatchMany(pks);
|
|
1643
1708
|
this.updateEmitter.markUpdatedKeys(pks);
|
|
1644
1709
|
this.trackAnyUpdatePks(pks);
|
|
1645
1710
|
}
|
|
1646
1711
|
clear() {
|
|
1712
|
+
const needsPks = this.emitter.hasHandlers(0 /* UPDATE */) || this.anyUpdateHandlers.size > 0;
|
|
1713
|
+
const pks = needsPks ? this.store.getAllPks() : void 0;
|
|
1647
1714
|
this.store.clear();
|
|
1648
|
-
if (
|
|
1649
|
-
this.
|
|
1715
|
+
if (pks && pks.length > 0) {
|
|
1716
|
+
this.notifyBatchMany(pks);
|
|
1717
|
+
this.trackAnyUpdatePks(pks);
|
|
1650
1718
|
}
|
|
1651
1719
|
this.updateEmitter.markAllUpdated();
|
|
1652
|
-
this.trackAnyUpdateClear();
|
|
1653
1720
|
}
|
|
1654
1721
|
trackAnyUpdatePk(pk) {
|
|
1655
1722
|
if (this.anyUpdateHandlers.size === 0) return;
|
|
@@ -1658,14 +1725,9 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1658
1725
|
}
|
|
1659
1726
|
trackAnyUpdatePks(pks) {
|
|
1660
1727
|
if (this.anyUpdateHandlers.size === 0) return;
|
|
1661
|
-
for (let i = 0; i < pks.length; i++)
|
|
1728
|
+
for (let i = 0; i < pks.length; i++) {
|
|
1662
1729
|
this.pendingAnyUpdatePks.add(pks[i]);
|
|
1663
|
-
|
|
1664
|
-
}
|
|
1665
|
-
trackAnyUpdateClear() {
|
|
1666
|
-
if (this.anyUpdateHandlers.size === 0) return;
|
|
1667
|
-
this.isAnyUpdateClearPending = true;
|
|
1668
|
-
this.pendingAnyUpdatePks.clear();
|
|
1730
|
+
}
|
|
1669
1731
|
this.ensureAnyUpdateEnqueued();
|
|
1670
1732
|
}
|
|
1671
1733
|
ensureAnyUpdateEnqueued() {
|
|
@@ -2098,8 +2160,13 @@ var OIMUpdateEventEmitter = class {
|
|
|
2098
2160
|
var OIMOrderedListCommandBuffer = class {
|
|
2099
2161
|
constructor(queue) {
|
|
2100
2162
|
this.commandsByKey = /* @__PURE__ */ new Map();
|
|
2163
|
+
// Keys whose buffered leading `reset` is stale: an edit after the reset
|
|
2164
|
+
// should be folded into it, but we defer the (O(list-size)) rebuild to the
|
|
2165
|
+
// next read instead of redoing it on every subsequent edit in the batch.
|
|
2166
|
+
this.staleResetKeys = /* @__PURE__ */ new Set();
|
|
2101
2167
|
this.onAfterFlush = () => {
|
|
2102
2168
|
this.commandsByKey.clear();
|
|
2169
|
+
this.staleResetKeys.clear();
|
|
2103
2170
|
};
|
|
2104
2171
|
this.commandsEventEmitter = new OIMUpdateEventEmitter(
|
|
2105
2172
|
queue,
|
|
@@ -2114,9 +2181,11 @@ var OIMOrderedListCommandBuffer = class {
|
|
|
2114
2181
|
return this.commandsEventEmitter.subscribeOnKey(key, handler);
|
|
2115
2182
|
}
|
|
2116
2183
|
getBufferedCommands(key) {
|
|
2184
|
+
this.materializeStaleReset(key);
|
|
2117
2185
|
return this.commandsByKey.get(key) ?? [];
|
|
2118
2186
|
}
|
|
2119
2187
|
consumeCommands(key) {
|
|
2188
|
+
this.materializeStaleReset(key);
|
|
2120
2189
|
const cmds = this.commandsByKey.get(key);
|
|
2121
2190
|
if (!cmds || cmds.length === 0) return [];
|
|
2122
2191
|
return cmds.slice();
|
|
@@ -2125,6 +2194,20 @@ var OIMOrderedListCommandBuffer = class {
|
|
|
2125
2194
|
this.commandsEventEmitter.destroy();
|
|
2126
2195
|
this.unsubscribeAfterFlush();
|
|
2127
2196
|
this.commandsByKey.clear();
|
|
2197
|
+
this.staleResetKeys.clear();
|
|
2198
|
+
}
|
|
2199
|
+
/**
|
|
2200
|
+
* Rebuild a deferred leading `reset` from the current order, once, at read
|
|
2201
|
+
* time. All the post-reset edits that were folded in are already reflected
|
|
2202
|
+
* in the driver's backing order, so a single rebuild here is equivalent to
|
|
2203
|
+
* having recomputed the reset on each of those edits.
|
|
2204
|
+
*/
|
|
2205
|
+
materializeStaleReset(key) {
|
|
2206
|
+
if (!this.staleResetKeys.delete(key)) return;
|
|
2207
|
+
const cmds = this.commandsByKey.get(key);
|
|
2208
|
+
if (cmds && cmds.length > 0 && cmds[0].type === "reset") {
|
|
2209
|
+
cmds[0] = this.createResetCommand(this.getItemsByKey(key));
|
|
2210
|
+
}
|
|
2128
2211
|
}
|
|
2129
2212
|
appendCommand(key, cmd) {
|
|
2130
2213
|
let cmds = this.commandsByKey.get(key);
|
|
@@ -2135,8 +2218,9 @@ var OIMOrderedListCommandBuffer = class {
|
|
|
2135
2218
|
if (cmd.type === "reset") {
|
|
2136
2219
|
cmds.length = 0;
|
|
2137
2220
|
cmds.push(cmd);
|
|
2221
|
+
this.staleResetKeys.delete(key);
|
|
2138
2222
|
} else if (cmds.length > 0 && cmds[0].type === "reset") {
|
|
2139
|
-
|
|
2223
|
+
this.staleResetKeys.add(key);
|
|
2140
2224
|
} else {
|
|
2141
2225
|
cmds.push(cmd);
|
|
2142
2226
|
}
|
|
@@ -3178,10 +3262,6 @@ var OIMDerivedCollectionIndexSetBased = class extends OIMReactiveCollectionIndex
|
|
|
3178
3262
|
});
|
|
3179
3263
|
this.keysByPk = /* @__PURE__ */ new Map();
|
|
3180
3264
|
this.onCollectionUpdate = (pks) => {
|
|
3181
|
-
if (pks.length === 0) {
|
|
3182
|
-
this.rebuildFromCollection();
|
|
3183
|
-
return;
|
|
3184
|
-
}
|
|
3185
3265
|
for (const pk of pks) {
|
|
3186
3266
|
this.syncPk(pk);
|
|
3187
3267
|
}
|
|
@@ -3283,10 +3363,6 @@ var OIMDerivedCollectionIndexArrayBased = class extends OIMReactiveCollectionInd
|
|
|
3283
3363
|
// touching an unrelated field can skip re-sorting when the value is unchanged.
|
|
3284
3364
|
this.orderValueByPk = /* @__PURE__ */ new Map();
|
|
3285
3365
|
this.onCollectionUpdate = (pks) => {
|
|
3286
|
-
if (pks.length === 0) {
|
|
3287
|
-
this.rebuildFromCollection();
|
|
3288
|
-
return;
|
|
3289
|
-
}
|
|
3290
3366
|
const ordered = !!(this.compareEntities || this.orderBy);
|
|
3291
3367
|
const keysToSort = ordered ? /* @__PURE__ */ new Set() : null;
|
|
3292
3368
|
for (const pk of pks) {
|
|
@@ -3703,10 +3779,6 @@ var OIMDerivedCollectionGlobalIndexArrayBased = class extends OIMReactiveCollect
|
|
|
3703
3779
|
// an unrelated field can skip re-sorting when the value is unchanged.
|
|
3704
3780
|
this.orderValueByPk = /* @__PURE__ */ new Map();
|
|
3705
3781
|
this.onCollectionUpdate = (pks) => {
|
|
3706
|
-
if (pks.length === 0) {
|
|
3707
|
-
this.rebuildFromCollection();
|
|
3708
|
-
return;
|
|
3709
|
-
}
|
|
3710
3782
|
const ordered = !!(this.compareEntities || this.orderBy);
|
|
3711
3783
|
let needsSort = false;
|
|
3712
3784
|
for (const pk of pks) {
|
|
@@ -3804,10 +3876,6 @@ var OIMDerivedCollectionGlobalIndexSetBased = class extends OIMReactiveCollectio
|
|
|
3804
3876
|
super(queue, { collection, indexOptions: opts.indexOptions });
|
|
3805
3877
|
this.presentPks = /* @__PURE__ */ new Set();
|
|
3806
3878
|
this.onCollectionUpdate = (pks) => {
|
|
3807
|
-
if (pks.length === 0) {
|
|
3808
|
-
this.rebuildFromCollection();
|
|
3809
|
-
return;
|
|
3810
|
-
}
|
|
3811
3879
|
for (const pk of pks) {
|
|
3812
3880
|
const prev = this.presentPks.has(pk);
|
|
3813
3881
|
const slot = this.collection.getSlotByPk(pk);
|
|
@@ -3983,6 +4051,55 @@ function createOIMCollectionIndexFactory(queue, collection) {
|
|
|
3983
4051
|
return new OIMCollectionIndexFactory(queue, collection);
|
|
3984
4052
|
}
|
|
3985
4053
|
|
|
4054
|
+
// src/core/OIMDerivedCollection.ts
|
|
4055
|
+
var OIMDerivedCollection = class extends OIMReactiveCollection {
|
|
4056
|
+
constructor(queue, source, derive, opts) {
|
|
4057
|
+
super(queue, {
|
|
4058
|
+
store: opts?.store,
|
|
4059
|
+
// Each sync recomputes the WHOLE derived entity → replace, not merge.
|
|
4060
|
+
updateEntity: (draft) => draft
|
|
4061
|
+
});
|
|
4062
|
+
this.onSourceUpdate = (pks) => {
|
|
4063
|
+
for (let i = 0; i < pks.length; i++) this.syncPk(pks[i]);
|
|
4064
|
+
};
|
|
4065
|
+
this.source = source;
|
|
4066
|
+
this.derive = derive;
|
|
4067
|
+
this.compareDerived = opts?.compare ?? Object.is;
|
|
4068
|
+
this.unsubscribeFromSource = source.emitter.on(
|
|
4069
|
+
0 /* UPDATE */,
|
|
4070
|
+
(payload) => this.onSourceUpdate(payload.pks)
|
|
4071
|
+
);
|
|
4072
|
+
if (opts?.buildInitial !== false) {
|
|
4073
|
+
this.rebuildFromSource();
|
|
4074
|
+
}
|
|
4075
|
+
}
|
|
4076
|
+
rebuildFromSource() {
|
|
4077
|
+
for (const pk of this.getAllPks()) {
|
|
4078
|
+
if (this.source.getOneByPk(pk) === void 0) {
|
|
4079
|
+
this.removeOneByPk(pk);
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4082
|
+
for (const slot of this.source.getAllSlots()) {
|
|
4083
|
+
if (slot.item !== void 0) this.syncPk(slot.pk);
|
|
4084
|
+
}
|
|
4085
|
+
}
|
|
4086
|
+
destroy() {
|
|
4087
|
+
this.unsubscribeFromSource();
|
|
4088
|
+
super.destroy();
|
|
4089
|
+
}
|
|
4090
|
+
syncPk(pk) {
|
|
4091
|
+
const sourceEntity = this.source.getOneByPk(pk);
|
|
4092
|
+
if (sourceEntity === void 0) {
|
|
4093
|
+
if (this.getOneByPk(pk) !== void 0) this.removeOneByPk(pk);
|
|
4094
|
+
return;
|
|
4095
|
+
}
|
|
4096
|
+
const next = this.derive(sourceEntity, pk);
|
|
4097
|
+
const prev = this.getOneByPk(pk);
|
|
4098
|
+
if (prev !== void 0 && this.compareDerived(prev, next)) return;
|
|
4099
|
+
this.upsertOneByPk(pk, next);
|
|
4100
|
+
}
|
|
4101
|
+
};
|
|
4102
|
+
|
|
3986
4103
|
// src/core/OIMObjectStoreRecordDriven.ts
|
|
3987
4104
|
var OIMObjectStoreRecordDriven = class extends OIMObjectStore {
|
|
3988
4105
|
constructor(initial) {
|
|
@@ -4055,8 +4172,11 @@ var OIMObject = class {
|
|
|
4055
4172
|
return this.store.getAll();
|
|
4056
4173
|
}
|
|
4057
4174
|
clear() {
|
|
4175
|
+
const keys = this.store.keys();
|
|
4058
4176
|
this.store.clear();
|
|
4059
|
-
|
|
4177
|
+
if (keys.length > 0) {
|
|
4178
|
+
this.onUpdatedKeys(keys);
|
|
4179
|
+
}
|
|
4060
4180
|
}
|
|
4061
4181
|
/**
|
|
4062
4182
|
* Write fan-out hooks. Split single-key vs multi-key so a reactive subclass
|
|
@@ -4359,8 +4479,9 @@ var OIMComparatorFactory = class {
|
|
|
4359
4479
|
if (ka.length !== kb.length) return true;
|
|
4360
4480
|
for (let i = 0; i < ka.length; i++) {
|
|
4361
4481
|
const k = ka[i];
|
|
4362
|
-
if (b[k] !== a[k])
|
|
4482
|
+
if (b[k] !== a[k]) {
|
|
4363
4483
|
return true;
|
|
4484
|
+
}
|
|
4364
4485
|
}
|
|
4365
4486
|
return false;
|
|
4366
4487
|
};
|
|
@@ -4410,10 +4531,14 @@ var OIMEventQueue = class {
|
|
|
4410
4531
|
return this.isFlushing;
|
|
4411
4532
|
}
|
|
4412
4533
|
/**
|
|
4413
|
-
* Execute
|
|
4534
|
+
* Execute the tasks pending at the moment the flush starts — a single pass,
|
|
4535
|
+
* not a drain-to-empty.
|
|
4414
4536
|
*
|
|
4415
|
-
*
|
|
4416
|
-
*
|
|
4537
|
+
* The pending set is swapped out for an empty spare up front and the flush
|
|
4538
|
+
* iterates that captured set. Tasks enqueued during the flush land in the
|
|
4539
|
+
* fresh set and run on the NEXT flush, not this one. (Contrast
|
|
4540
|
+
* `OIMComputeRuntime.flush()`, which re-reads its bucket per level and so
|
|
4541
|
+
* does drain same-level tasks scheduled mid-flush.)
|
|
4417
4542
|
*/
|
|
4418
4543
|
flush() {
|
|
4419
4544
|
this.scheduler?.cancel();
|
|
@@ -4687,20 +4812,92 @@ var OIMPkCodecKeyPath = class {
|
|
|
4687
4812
|
}
|
|
4688
4813
|
};
|
|
4689
4814
|
|
|
4815
|
+
// src/modules/effect/core/OIMEffectDependencyComputed.ts
|
|
4816
|
+
var OIMEffectDependencyComputed = class {
|
|
4817
|
+
constructor(source) {
|
|
4818
|
+
this.source = source;
|
|
4819
|
+
}
|
|
4820
|
+
subscribe(onUpdate) {
|
|
4821
|
+
return this.source.emitter.on("update", onUpdate);
|
|
4822
|
+
}
|
|
4823
|
+
};
|
|
4824
|
+
|
|
4690
4825
|
// src/modules/compute/core/OIMComputeRuntime.ts
|
|
4691
4826
|
var OIMComputeRuntime = class {
|
|
4692
4827
|
constructor(queue) {
|
|
4693
4828
|
this.queue = queue;
|
|
4694
4829
|
this.isFlushScheduled = false;
|
|
4695
4830
|
this.isFlushing = false;
|
|
4831
|
+
// Active level range (min > max means nothing pending).
|
|
4696
4832
|
this.minLevel = Infinity;
|
|
4697
4833
|
this.maxLevel = -Infinity;
|
|
4698
|
-
this.dirtyByLevel =
|
|
4834
|
+
this.dirtyByLevel = [];
|
|
4699
4835
|
this.afterFlushTasks = /* @__PURE__ */ new Set();
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4836
|
+
// Topological depth per computed node — the engine is the ONLY owner of
|
|
4837
|
+
// levels; nodes never expose their own. A node's dependents look up its depth
|
|
4838
|
+
// here (by the computed reference their dependency wraps). Written once at
|
|
4839
|
+
// construction, never on the hot flush path.
|
|
4840
|
+
this.levelByComputed = /* @__PURE__ */ new WeakMap();
|
|
4841
|
+
this._isDestroyed = false;
|
|
4842
|
+
this.unsubscribeFromQueue = this.queue.emitter.on(
|
|
4843
|
+
0 /* AFTER_FLUSH */,
|
|
4844
|
+
() => {
|
|
4845
|
+
if (!this.isFlushScheduled) return;
|
|
4846
|
+
this.flush();
|
|
4847
|
+
}
|
|
4848
|
+
);
|
|
4849
|
+
}
|
|
4850
|
+
/**
|
|
4851
|
+
* Whether {@link destroy} has run. A destroyed runtime is detached from its
|
|
4852
|
+
* queue and must not be reused — `getOIMComputeRuntime` reads this to hand
|
|
4853
|
+
* out a fresh runtime instead of a dead one.
|
|
4854
|
+
*/
|
|
4855
|
+
get isDestroyed() {
|
|
4856
|
+
return this._isDestroyed;
|
|
4857
|
+
}
|
|
4858
|
+
/**
|
|
4859
|
+
* Detach from the queue and drop everything pending.
|
|
4860
|
+
*
|
|
4861
|
+
* Without this the AFTER_FLUSH subscription lives as long as the queue does,
|
|
4862
|
+
* even once every computed / effect on this runtime is gone — harmless (the
|
|
4863
|
+
* handler early-returns) but impossible to unwind. Destroying does NOT
|
|
4864
|
+
* destroy the nodes scheduled on it; destroy them first, then the runtime.
|
|
4865
|
+
* Idempotent.
|
|
4866
|
+
*/
|
|
4867
|
+
destroy() {
|
|
4868
|
+
if (this._isDestroyed) return;
|
|
4869
|
+
this._isDestroyed = true;
|
|
4870
|
+
this.unsubscribeFromQueue();
|
|
4871
|
+
for (let i = 0; i < this.dirtyByLevel.length; i++) {
|
|
4872
|
+
this.dirtyByLevel[i]?.clear();
|
|
4873
|
+
}
|
|
4874
|
+
this.afterFlushTasks.clear();
|
|
4875
|
+
this.minLevel = Infinity;
|
|
4876
|
+
this.maxLevel = -Infinity;
|
|
4877
|
+
this.isFlushScheduled = false;
|
|
4878
|
+
}
|
|
4879
|
+
/**
|
|
4880
|
+
* Topological depth for a node with these dependencies: one above the deepest
|
|
4881
|
+
* computed dependency (source-only → 0). The engine owns this — callers pass
|
|
4882
|
+
* their dependencies and get back a level, they never compute it themselves.
|
|
4883
|
+
*/
|
|
4884
|
+
computeLevel(deps) {
|
|
4885
|
+
let max = -1;
|
|
4886
|
+
for (const dep of deps) {
|
|
4887
|
+
if (dep instanceof OIMEffectDependencyComputed) {
|
|
4888
|
+
const depLevel = this.levelByComputed.get(dep.source) ?? 0;
|
|
4889
|
+
if (depLevel > max) max = depLevel;
|
|
4890
|
+
}
|
|
4891
|
+
}
|
|
4892
|
+
return max + 1;
|
|
4893
|
+
}
|
|
4894
|
+
/** Record a computed's depth so its dependents can look it up. */
|
|
4895
|
+
registerLevel(computed, level) {
|
|
4896
|
+
this.levelByComputed.set(computed, level);
|
|
4897
|
+
}
|
|
4898
|
+
/** The recorded topological depth of a computed (0 if unknown). Introspection. */
|
|
4899
|
+
getLevel(computed) {
|
|
4900
|
+
return this.levelByComputed.get(computed) ?? 0;
|
|
4704
4901
|
}
|
|
4705
4902
|
/**
|
|
4706
4903
|
* Schedule a one-shot task to run on the next `queue.flush()` (AFTER_FLUSH),
|
|
@@ -4712,10 +4909,10 @@ var OIMComputeRuntime = class {
|
|
|
4712
4909
|
if (!isActive) return;
|
|
4713
4910
|
task();
|
|
4714
4911
|
};
|
|
4715
|
-
let bucket = this.dirtyByLevel
|
|
4716
|
-
if (
|
|
4912
|
+
let bucket = this.dirtyByLevel[level];
|
|
4913
|
+
if (bucket === void 0) {
|
|
4717
4914
|
bucket = /* @__PURE__ */ new Set();
|
|
4718
|
-
this.dirtyByLevel
|
|
4915
|
+
this.dirtyByLevel[level] = bucket;
|
|
4719
4916
|
}
|
|
4720
4917
|
bucket.add(wrapped);
|
|
4721
4918
|
if (level < this.minLevel) this.minLevel = level;
|
|
@@ -4747,7 +4944,7 @@ var OIMComputeRuntime = class {
|
|
|
4747
4944
|
}
|
|
4748
4945
|
flush() {
|
|
4749
4946
|
this.isFlushScheduled = false;
|
|
4750
|
-
if (this.
|
|
4947
|
+
if (this.minLevel > this.maxLevel && this.afterFlushTasks.size === 0)
|
|
4751
4948
|
return;
|
|
4752
4949
|
this.isFlushing = true;
|
|
4753
4950
|
try {
|
|
@@ -4756,15 +4953,15 @@ var OIMComputeRuntime = class {
|
|
|
4756
4953
|
this.afterFlushTasks.clear();
|
|
4757
4954
|
for (let i = 0; i < snapshot.length; i++) snapshot[i]();
|
|
4758
4955
|
}
|
|
4759
|
-
if (this.
|
|
4956
|
+
if (this.minLevel > this.maxLevel) return;
|
|
4760
4957
|
let level = this.minLevel;
|
|
4761
4958
|
let max = this.maxLevel;
|
|
4762
4959
|
while (level <= max) {
|
|
4763
4960
|
for (; ; ) {
|
|
4764
|
-
const bucket = this.dirtyByLevel
|
|
4765
|
-
if (
|
|
4766
|
-
this.dirtyByLevel.delete(level);
|
|
4961
|
+
const bucket = this.dirtyByLevel[level];
|
|
4962
|
+
if (bucket === void 0 || bucket.size === 0) break;
|
|
4767
4963
|
const snapshot = Array.from(bucket);
|
|
4964
|
+
bucket.clear();
|
|
4768
4965
|
for (let i = 0; i < snapshot.length; i++) snapshot[i]();
|
|
4769
4966
|
}
|
|
4770
4967
|
if (this.maxLevel > max) max = this.maxLevel;
|
|
@@ -4772,24 +4969,38 @@ var OIMComputeRuntime = class {
|
|
|
4772
4969
|
}
|
|
4773
4970
|
} finally {
|
|
4774
4971
|
this.isFlushing = false;
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
this.isFlushScheduled = true;
|
|
4972
|
+
this.recomputePendingRange();
|
|
4973
|
+
}
|
|
4974
|
+
}
|
|
4975
|
+
recomputePendingRange() {
|
|
4976
|
+
let nextMin = Infinity;
|
|
4977
|
+
let nextMax = -Infinity;
|
|
4978
|
+
const buckets = this.dirtyByLevel;
|
|
4979
|
+
for (let i = 0; i < buckets.length; i++) {
|
|
4980
|
+
const bucket = buckets[i];
|
|
4981
|
+
if (bucket !== void 0 && bucket.size > 0) {
|
|
4982
|
+
if (i < nextMin) nextMin = i;
|
|
4983
|
+
if (i > nextMax) nextMax = i;
|
|
4788
4984
|
}
|
|
4789
4985
|
}
|
|
4986
|
+
this.minLevel = nextMin;
|
|
4987
|
+
this.maxLevel = nextMax;
|
|
4988
|
+
if (nextMin <= nextMax) this.isFlushScheduled = true;
|
|
4790
4989
|
}
|
|
4791
4990
|
};
|
|
4792
4991
|
|
|
4992
|
+
// src/dx/oimComputeRuntimeByQueue.ts
|
|
4993
|
+
var oimComputeRuntimeByQueue = /* @__PURE__ */ new WeakMap();
|
|
4994
|
+
|
|
4995
|
+
// src/dx/getOIMComputeRuntime.ts
|
|
4996
|
+
function getOIMComputeRuntime(queue) {
|
|
4997
|
+
const runtime = oimComputeRuntimeByQueue.get(queue);
|
|
4998
|
+
if (runtime !== void 0 && !runtime.isDestroyed) return runtime;
|
|
4999
|
+
const nextRuntime = new OIMComputeRuntime(queue);
|
|
5000
|
+
oimComputeRuntimeByQueue.set(queue, nextRuntime);
|
|
5001
|
+
return nextRuntime;
|
|
5002
|
+
}
|
|
5003
|
+
|
|
4793
5004
|
// src/modules/selector/core/OIMSelector.ts
|
|
4794
5005
|
var OIMSelector = class {
|
|
4795
5006
|
constructor(runtime, sourceDeps, computedDeps = []) {
|
|
@@ -5050,8 +5261,9 @@ var OIMEntitiesByIndexKeyArrayBasedSelector = class extends OIMSelector {
|
|
|
5050
5261
|
areEqual(prev, next) {
|
|
5051
5262
|
if (prev === next) return true;
|
|
5052
5263
|
if (prev.length !== next.length) return false;
|
|
5053
|
-
for (let i = 0; i < prev.length; i++)
|
|
5264
|
+
for (let i = 0; i < prev.length; i++) {
|
|
5054
5265
|
if (prev[i] !== next[i]) return false;
|
|
5266
|
+
}
|
|
5055
5267
|
return true;
|
|
5056
5268
|
}
|
|
5057
5269
|
};
|
|
@@ -5121,8 +5333,9 @@ var OIMEntitiesByIndexKeySetBasedSelector = class extends OIMSelector {
|
|
|
5121
5333
|
areEqual(prev, next) {
|
|
5122
5334
|
if (prev === next) return true;
|
|
5123
5335
|
if (prev.length !== next.length) return false;
|
|
5124
|
-
for (let i = 0; i < prev.length; i++)
|
|
5336
|
+
for (let i = 0; i < prev.length; i++) {
|
|
5125
5337
|
if (prev[i] !== next[i]) return false;
|
|
5338
|
+
}
|
|
5126
5339
|
return true;
|
|
5127
5340
|
}
|
|
5128
5341
|
};
|
|
@@ -5186,8 +5399,9 @@ var OIMEntitiesByGlobalIndexArrayBasedSelector = class extends OIMSelector {
|
|
|
5186
5399
|
areEqual(prev, next) {
|
|
5187
5400
|
if (prev === next) return true;
|
|
5188
5401
|
if (prev.length !== next.length) return false;
|
|
5189
|
-
for (let i = 0; i < prev.length; i++)
|
|
5402
|
+
for (let i = 0; i < prev.length; i++) {
|
|
5190
5403
|
if (prev[i] !== next[i]) return false;
|
|
5404
|
+
}
|
|
5191
5405
|
return true;
|
|
5192
5406
|
}
|
|
5193
5407
|
};
|
|
@@ -5252,8 +5466,9 @@ var OIMEntitiesByGlobalIndexSetBasedSelector = class extends OIMSelector {
|
|
|
5252
5466
|
areEqual(prev, next) {
|
|
5253
5467
|
if (prev === next) return true;
|
|
5254
5468
|
if (prev.length !== next.length) return false;
|
|
5255
|
-
for (let i = 0; i < prev.length; i++)
|
|
5469
|
+
for (let i = 0; i < prev.length; i++) {
|
|
5256
5470
|
if (prev[i] !== next[i]) return false;
|
|
5471
|
+
}
|
|
5257
5472
|
return true;
|
|
5258
5473
|
}
|
|
5259
5474
|
};
|
|
@@ -5262,7 +5477,7 @@ var OIMEntitiesByGlobalIndexSetBasedSelector = class extends OIMSelector {
|
|
|
5262
5477
|
var OIMCollectionSelectors = class {
|
|
5263
5478
|
constructor(queue, collection) {
|
|
5264
5479
|
this.collection = collection;
|
|
5265
|
-
this.runtime =
|
|
5480
|
+
this.runtime = getOIMComputeRuntime(queue);
|
|
5266
5481
|
}
|
|
5267
5482
|
byPk(pk) {
|
|
5268
5483
|
return new OIMCollectionByPkSelector(this.runtime, this.collection, pk);
|
|
@@ -5329,127 +5544,408 @@ var OIMCollectionSelectors = class {
|
|
|
5329
5544
|
}
|
|
5330
5545
|
};
|
|
5331
5546
|
|
|
5332
|
-
// src/
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
indexFactory,
|
|
5343
|
-
select,
|
|
5344
|
-
scope,
|
|
5345
|
-
destroy: () => scope.destroy()
|
|
5346
|
-
};
|
|
5347
|
-
}
|
|
5547
|
+
// src/modules/effect/core/OIMEffectDependencyKeyed.ts
|
|
5548
|
+
var OIMEffectDependencyKeyed = class {
|
|
5549
|
+
constructor(source, key) {
|
|
5550
|
+
this.source = source;
|
|
5551
|
+
this.key = key;
|
|
5552
|
+
}
|
|
5553
|
+
subscribe(onUpdate) {
|
|
5554
|
+
return this.source.subscribeOnKey(this.key, onUpdate);
|
|
5555
|
+
}
|
|
5556
|
+
};
|
|
5348
5557
|
|
|
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
|
-
}
|
|
5558
|
+
// src/modules/effect/core/OIMEffectDependencyKeyedCollection.ts
|
|
5559
|
+
var OIMEffectDependencyKeyedCollection = class {
|
|
5560
|
+
constructor(collection, pk) {
|
|
5561
|
+
this.dep = new OIMEffectDependencyKeyed(collection, pk);
|
|
5400
5562
|
}
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
this.trackPatch(pk, patch);
|
|
5404
|
-
return this.collection.upsertOneByPk(pk, patch);
|
|
5405
|
-
});
|
|
5406
|
-
this.updateEntitySnapshot(pk);
|
|
5407
|
-
return slot;
|
|
5563
|
+
get source() {
|
|
5564
|
+
return this.dep.source;
|
|
5408
5565
|
}
|
|
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;
|
|
5566
|
+
subscribe(onUpdate) {
|
|
5567
|
+
return this.dep.subscribe(onUpdate);
|
|
5417
5568
|
}
|
|
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;
|
|
5569
|
+
};
|
|
5570
|
+
|
|
5571
|
+
// src/modules/effect/core/OIMEffectDependencyKeyedIndex.ts
|
|
5572
|
+
var OIMEffectDependencyKeyedIndex = class {
|
|
5573
|
+
constructor(index, key) {
|
|
5574
|
+
this.dep = new OIMEffectDependencyKeyed(index, key);
|
|
5430
5575
|
}
|
|
5431
|
-
|
|
5432
|
-
return this.
|
|
5576
|
+
get source() {
|
|
5577
|
+
return this.dep.source;
|
|
5433
5578
|
}
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
if (!existing) return /* @__PURE__ */ new Set();
|
|
5437
|
-
return new Set(existing);
|
|
5579
|
+
subscribe(onUpdate) {
|
|
5580
|
+
return this.dep.subscribe(onUpdate);
|
|
5438
5581
|
}
|
|
5439
|
-
|
|
5440
|
-
|
|
5582
|
+
};
|
|
5583
|
+
|
|
5584
|
+
// src/modules/effect/core/OIMEffectDependencyKeyedObject.ts
|
|
5585
|
+
var OIMEffectDependencyKeyedObject = class {
|
|
5586
|
+
constructor(object, key) {
|
|
5587
|
+
this.dep = new OIMEffectDependencyKeyed(object, key);
|
|
5441
5588
|
}
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
if (!existing) return /* @__PURE__ */ new Set();
|
|
5445
|
-
return new Set(existing);
|
|
5589
|
+
get source() {
|
|
5590
|
+
return this.dep.source;
|
|
5446
5591
|
}
|
|
5447
|
-
|
|
5448
|
-
this.
|
|
5449
|
-
this.changedPksByField.clear();
|
|
5592
|
+
subscribe(onUpdate) {
|
|
5593
|
+
return this.dep.subscribe(onUpdate);
|
|
5450
5594
|
}
|
|
5451
|
-
|
|
5452
|
-
|
|
5595
|
+
};
|
|
5596
|
+
|
|
5597
|
+
// src/dx/on.ts
|
|
5598
|
+
var on = {
|
|
5599
|
+
/** Depend on one PK of a collection. */
|
|
5600
|
+
collection: (collection, pk) => new OIMEffectDependencyKeyedCollection(collection, pk),
|
|
5601
|
+
/** Depend on one key of an index. */
|
|
5602
|
+
index: (index, key) => new OIMEffectDependencyKeyedIndex(index, key),
|
|
5603
|
+
/** Depend on one key of a reactive object. */
|
|
5604
|
+
object: (object, key) => new OIMEffectDependencyKeyedObject(object, key),
|
|
5605
|
+
/** Depend on another computed. */
|
|
5606
|
+
computed: (computed) => new OIMEffectDependencyComputed(computed)
|
|
5607
|
+
};
|
|
5608
|
+
|
|
5609
|
+
// src/modules/effect/core/OIMEffect.ts
|
|
5610
|
+
var OIMEffect = class {
|
|
5611
|
+
constructor(runtime, opts, level) {
|
|
5612
|
+
this.sourceDeps = [];
|
|
5613
|
+
this.computedDeps = [];
|
|
5614
|
+
this.sourceUnsubscribers = [];
|
|
5615
|
+
this.computedUnsubscribers = [];
|
|
5616
|
+
this.isResubscribeEnqueued = false;
|
|
5617
|
+
this.isTemporarilyUnsubscribedForFlush = false;
|
|
5618
|
+
this.isScheduled = false;
|
|
5619
|
+
this.runTask = () => {
|
|
5620
|
+
this.isScheduled = false;
|
|
5621
|
+
this.dequeueScheduled = void 0;
|
|
5622
|
+
this.runOnce();
|
|
5623
|
+
};
|
|
5624
|
+
this.onSourceInvalidate = () => {
|
|
5625
|
+
this.onUpdate?.();
|
|
5626
|
+
if (!this.isTemporarilyUnsubscribedForFlush) {
|
|
5627
|
+
this.isTemporarilyUnsubscribedForFlush = true;
|
|
5628
|
+
this.unsubscribeFromSourceDeps();
|
|
5629
|
+
this.ensureResubscribeAfterFlush();
|
|
5630
|
+
}
|
|
5631
|
+
if (this.isScheduled) return;
|
|
5632
|
+
this.isScheduled = true;
|
|
5633
|
+
this.dequeueScheduled = this.runtime.schedule(this.runTask, this.level);
|
|
5634
|
+
};
|
|
5635
|
+
this.onComputedInvalidate = () => {
|
|
5636
|
+
this.onUpdate?.();
|
|
5637
|
+
if (this.isScheduled) return;
|
|
5638
|
+
this.isScheduled = true;
|
|
5639
|
+
this.dequeueScheduled = this.runtime.schedule(this.runTask, this.level);
|
|
5640
|
+
};
|
|
5641
|
+
this.onAfterFlush = () => {
|
|
5642
|
+
if (!this.isResubscribeEnqueued) return;
|
|
5643
|
+
this.isResubscribeEnqueued = false;
|
|
5644
|
+
this.dequeueResubscribe = void 0;
|
|
5645
|
+
this.isTemporarilyUnsubscribedForFlush = false;
|
|
5646
|
+
if (this.sourceUnsubscribers.length === 0) {
|
|
5647
|
+
for (const dep of this.sourceDeps) {
|
|
5648
|
+
this.sourceUnsubscribers.push(
|
|
5649
|
+
dep.subscribe(this.onSourceInvalidate)
|
|
5650
|
+
);
|
|
5651
|
+
}
|
|
5652
|
+
}
|
|
5653
|
+
};
|
|
5654
|
+
this.runtime = runtime;
|
|
5655
|
+
this.onUpdate = opts.onUpdate;
|
|
5656
|
+
this.run = opts.run;
|
|
5657
|
+
this.deps = opts.deps ?? [];
|
|
5658
|
+
for (const dep of this.deps) {
|
|
5659
|
+
if (dep instanceof OIMEffectDependencyComputed) {
|
|
5660
|
+
this.computedDeps.push(dep);
|
|
5661
|
+
} else {
|
|
5662
|
+
this.sourceDeps.push(dep);
|
|
5663
|
+
}
|
|
5664
|
+
}
|
|
5665
|
+
this.level = level ?? this.runtime.computeLevel(this.deps);
|
|
5666
|
+
this.subscribeToDeps();
|
|
5667
|
+
}
|
|
5668
|
+
destroy() {
|
|
5669
|
+
if (this.dequeueScheduled) {
|
|
5670
|
+
this.dequeueScheduled();
|
|
5671
|
+
this.dequeueScheduled = void 0;
|
|
5672
|
+
}
|
|
5673
|
+
this.unsubscribeFromAllDeps();
|
|
5674
|
+
if (this.dequeueResubscribe) {
|
|
5675
|
+
this.dequeueResubscribe();
|
|
5676
|
+
this.dequeueResubscribe = void 0;
|
|
5677
|
+
}
|
|
5678
|
+
this.isResubscribeEnqueued = false;
|
|
5679
|
+
this.isTemporarilyUnsubscribedForFlush = false;
|
|
5680
|
+
}
|
|
5681
|
+
runOnce() {
|
|
5682
|
+
this.run();
|
|
5683
|
+
}
|
|
5684
|
+
subscribeToDeps() {
|
|
5685
|
+
if (this.sourceUnsubscribers.length > 0 || this.computedUnsubscribers.length > 0)
|
|
5686
|
+
return;
|
|
5687
|
+
for (const dep of this.sourceDeps) {
|
|
5688
|
+
this.sourceUnsubscribers.push(
|
|
5689
|
+
dep.subscribe(this.onSourceInvalidate)
|
|
5690
|
+
);
|
|
5691
|
+
}
|
|
5692
|
+
for (const dep of this.computedDeps) {
|
|
5693
|
+
this.computedUnsubscribers.push(
|
|
5694
|
+
dep.subscribe(this.onComputedInvalidate)
|
|
5695
|
+
);
|
|
5696
|
+
}
|
|
5697
|
+
}
|
|
5698
|
+
unsubscribeFromSourceDeps() {
|
|
5699
|
+
if (this.sourceUnsubscribers.length === 0) return;
|
|
5700
|
+
for (const unsubscribe of this.sourceUnsubscribers) unsubscribe();
|
|
5701
|
+
this.sourceUnsubscribers = [];
|
|
5702
|
+
}
|
|
5703
|
+
unsubscribeFromAllDeps() {
|
|
5704
|
+
this.unsubscribeFromSourceDeps();
|
|
5705
|
+
if (this.computedUnsubscribers.length === 0) return;
|
|
5706
|
+
for (const unsubscribe of this.computedUnsubscribers) unsubscribe();
|
|
5707
|
+
this.computedUnsubscribers = [];
|
|
5708
|
+
}
|
|
5709
|
+
ensureResubscribeAfterFlush() {
|
|
5710
|
+
if (this.isResubscribeEnqueued) return;
|
|
5711
|
+
this.isResubscribeEnqueued = true;
|
|
5712
|
+
this.dequeueResubscribe = this.runtime.scheduleAfterFlush(
|
|
5713
|
+
this.onAfterFlush
|
|
5714
|
+
);
|
|
5715
|
+
}
|
|
5716
|
+
};
|
|
5717
|
+
|
|
5718
|
+
// src/modules/computed/enums/EOIMComputedEventType.ts
|
|
5719
|
+
var EOIMComputedEventType = /* @__PURE__ */ ((EOIMComputedEventType2) => {
|
|
5720
|
+
EOIMComputedEventType2["UPDATE"] = "update";
|
|
5721
|
+
return EOIMComputedEventType2;
|
|
5722
|
+
})(EOIMComputedEventType || {});
|
|
5723
|
+
|
|
5724
|
+
// src/modules/computed/core/OIMComputed.ts
|
|
5725
|
+
var OIMComputed = class {
|
|
5726
|
+
constructor(runtime, opts) {
|
|
5727
|
+
this.emitter = new OIMEventEmitter();
|
|
5728
|
+
this.hasValue = false;
|
|
5729
|
+
this.isDirty = true;
|
|
5730
|
+
this.runtime = runtime;
|
|
5731
|
+
this.compute = opts.compute;
|
|
5732
|
+
this.compare = opts.compare ?? Object.is;
|
|
5733
|
+
this._deps = opts.deps ?? [];
|
|
5734
|
+
this.updateEventEmitter = new OIMUpdateEventEmitter(
|
|
5735
|
+
this.runtime.queue,
|
|
5736
|
+
"immediate"
|
|
5737
|
+
);
|
|
5738
|
+
const level = this.runtime.computeLevel(this._deps);
|
|
5739
|
+
this.runtime.registerLevel(this, level);
|
|
5740
|
+
this.effect = new OIMEffect(
|
|
5741
|
+
this.runtime,
|
|
5742
|
+
{
|
|
5743
|
+
deps: this._deps,
|
|
5744
|
+
onUpdate: () => {
|
|
5745
|
+
this.isDirty = true;
|
|
5746
|
+
},
|
|
5747
|
+
run: () => {
|
|
5748
|
+
this.recomputeAndEmitIfChanged();
|
|
5749
|
+
}
|
|
5750
|
+
},
|
|
5751
|
+
level
|
|
5752
|
+
);
|
|
5753
|
+
}
|
|
5754
|
+
get needsRecompute() {
|
|
5755
|
+
return this.isDirty;
|
|
5756
|
+
}
|
|
5757
|
+
get isReady() {
|
|
5758
|
+
return this.hasValue;
|
|
5759
|
+
}
|
|
5760
|
+
get deps() {
|
|
5761
|
+
return this._deps;
|
|
5762
|
+
}
|
|
5763
|
+
get() {
|
|
5764
|
+
this.recomputeAndEmitIfChanged();
|
|
5765
|
+
return this.value;
|
|
5766
|
+
}
|
|
5767
|
+
getIfReady() {
|
|
5768
|
+
return this.hasValue ? this.value : void 0;
|
|
5769
|
+
}
|
|
5770
|
+
destroy() {
|
|
5771
|
+
this.effect.destroy();
|
|
5772
|
+
this.updateEventEmitter.destroy();
|
|
5773
|
+
this.emitter.offAll();
|
|
5774
|
+
}
|
|
5775
|
+
recomputeAndEmitIfChanged() {
|
|
5776
|
+
if (!this.isDirty) return;
|
|
5777
|
+
const prev = this.value;
|
|
5778
|
+
const hadPrev = this.hasValue;
|
|
5779
|
+
const next = this.compute();
|
|
5780
|
+
this.value = next;
|
|
5781
|
+
this.hasValue = true;
|
|
5782
|
+
this.isDirty = false;
|
|
5783
|
+
const changed = !hadPrev || !this.compare(prev, next);
|
|
5784
|
+
if (!changed) return;
|
|
5785
|
+
this.emitter.emit("update" /* UPDATE */, {
|
|
5786
|
+
keys: ["value"]
|
|
5787
|
+
});
|
|
5788
|
+
this.updateEventEmitter.markUpdatedKey("value");
|
|
5789
|
+
}
|
|
5790
|
+
};
|
|
5791
|
+
|
|
5792
|
+
// src/dx/OIMCollectionKit.ts
|
|
5793
|
+
function createOIMCollectionKit(queue, opts) {
|
|
5794
|
+
const collection = new OIMReactiveCollection(queue, opts);
|
|
5795
|
+
const indexFactory = new OIMCollectionIndexFactory(queue, collection);
|
|
5796
|
+
const select = new OIMCollectionSelectors(queue, collection);
|
|
5797
|
+
const runtime = getOIMComputeRuntime(queue);
|
|
5798
|
+
const scope = new OIMDisposeScope();
|
|
5799
|
+
scope.add(collection);
|
|
5800
|
+
return {
|
|
5801
|
+
queue,
|
|
5802
|
+
collection,
|
|
5803
|
+
indexFactory,
|
|
5804
|
+
select,
|
|
5805
|
+
on,
|
|
5806
|
+
computed: (deps, compute, options) => {
|
|
5807
|
+
const computed = new OIMComputed(runtime, {
|
|
5808
|
+
deps,
|
|
5809
|
+
compute,
|
|
5810
|
+
compare: options?.compare
|
|
5811
|
+
});
|
|
5812
|
+
scope.add(computed);
|
|
5813
|
+
return computed;
|
|
5814
|
+
},
|
|
5815
|
+
effect: (deps, run, options) => {
|
|
5816
|
+
const effect = new OIMEffect(runtime, {
|
|
5817
|
+
deps,
|
|
5818
|
+
run,
|
|
5819
|
+
onUpdate: options?.onUpdate
|
|
5820
|
+
});
|
|
5821
|
+
scope.add(effect);
|
|
5822
|
+
return effect;
|
|
5823
|
+
},
|
|
5824
|
+
scope,
|
|
5825
|
+
destroy: () => scope.destroy()
|
|
5826
|
+
};
|
|
5827
|
+
}
|
|
5828
|
+
|
|
5829
|
+
// src/dx/peekOIMComputeRuntime.ts
|
|
5830
|
+
function peekOIMComputeRuntime(queue) {
|
|
5831
|
+
const runtime = oimComputeRuntimeByQueue.get(queue);
|
|
5832
|
+
return runtime === void 0 || runtime.isDestroyed ? void 0 : runtime;
|
|
5833
|
+
}
|
|
5834
|
+
|
|
5835
|
+
// src/dx/setOIMComputeRuntime.ts
|
|
5836
|
+
function setOIMComputeRuntime(queue, runtime) {
|
|
5837
|
+
if (runtime.queue !== queue) {
|
|
5838
|
+
throw new Error(
|
|
5839
|
+
"setOIMComputeRuntime: the runtime is attached to a different queue. A runtime drains on its own queue and would never run here."
|
|
5840
|
+
);
|
|
5841
|
+
}
|
|
5842
|
+
oimComputeRuntimeByQueue.set(queue, runtime);
|
|
5843
|
+
}
|
|
5844
|
+
|
|
5845
|
+
// src/modules/wrapper/collection/OIMCollectionChangedFields.ts
|
|
5846
|
+
var OIMCollectionChangedFields = class {
|
|
5847
|
+
constructor(queue, collection, opts) {
|
|
5848
|
+
this.isInWrite = false;
|
|
5849
|
+
this.lastEntitySnapshotByPk = /* @__PURE__ */ new Map();
|
|
5850
|
+
// PKs written through this wrapper during the current flush. Their fields are
|
|
5851
|
+
// already tracked accurately via trackPatch, so the flush-time external-write
|
|
5852
|
+
// handler skips them — no redundant diff + snapshot re-clone. Cleared per flush.
|
|
5853
|
+
this.writtenThroughThisFlush = /* @__PURE__ */ new Set();
|
|
5854
|
+
this.changedFieldsByPk = /* @__PURE__ */ new Map();
|
|
5855
|
+
this.changedPksByField = /* @__PURE__ */ new Map();
|
|
5856
|
+
this.onAfterFlush = () => {
|
|
5857
|
+
this.clear();
|
|
5858
|
+
this.writtenThroughThisFlush.clear();
|
|
5859
|
+
};
|
|
5860
|
+
this.onCollectionUpdate = (payload) => {
|
|
5861
|
+
if (this.isInWrite) return;
|
|
5862
|
+
if (payload.pks.length === 0) return;
|
|
5863
|
+
for (let i = 0; i < payload.pks.length; i++) {
|
|
5864
|
+
const pk = payload.pks[i];
|
|
5865
|
+
if (this.writtenThroughThisFlush.has(pk)) continue;
|
|
5866
|
+
this.trackExternalMutationByPk(pk);
|
|
5867
|
+
}
|
|
5868
|
+
};
|
|
5869
|
+
this.collection = collection;
|
|
5870
|
+
this.detectExternalMutations = opts?.detectExternalMutations !== false;
|
|
5871
|
+
this.selectPk = opts?.selectPk ?? (() => {
|
|
5872
|
+
throw new Error(
|
|
5873
|
+
`[OIMCollectionChangedFields]: selectPk was not provided. Use upsertOneByPk(...) or pass opts.selectPk.`
|
|
5874
|
+
);
|
|
5875
|
+
});
|
|
5876
|
+
this.changedPksEventEmitter = new OIMUpdateEventEmitter(
|
|
5877
|
+
queue,
|
|
5878
|
+
"after_flush"
|
|
5879
|
+
);
|
|
5880
|
+
this.changedFieldsEventEmitter = new OIMUpdateEventEmitter(queue, "after_flush");
|
|
5881
|
+
this.unsubscribeAfterFlush = queue.emitter.on(
|
|
5882
|
+
0 /* AFTER_FLUSH */,
|
|
5883
|
+
this.onAfterFlush
|
|
5884
|
+
);
|
|
5885
|
+
if (this.detectExternalMutations) {
|
|
5886
|
+
const maybeReactive = collection;
|
|
5887
|
+
this.unsubscribeFromCollectionEmitter = maybeReactive.subscribeOnAnyUpdate ? maybeReactive.subscribeOnAnyUpdate((pks) => {
|
|
5888
|
+
this.onCollectionUpdate({
|
|
5889
|
+
pks
|
|
5890
|
+
});
|
|
5891
|
+
}) : collection.emitter.on(
|
|
5892
|
+
0 /* UPDATE */,
|
|
5893
|
+
this.onCollectionUpdate
|
|
5894
|
+
);
|
|
5895
|
+
}
|
|
5896
|
+
}
|
|
5897
|
+
upsertOneByPk(pk, patch) {
|
|
5898
|
+
const slot = this.withWrite(() => {
|
|
5899
|
+
this.trackPatch(pk, patch);
|
|
5900
|
+
return this.collection.upsertOneByPk(pk, patch);
|
|
5901
|
+
});
|
|
5902
|
+
this.updateEntitySnapshot(pk);
|
|
5903
|
+
return slot;
|
|
5904
|
+
}
|
|
5905
|
+
upsertOne(entity) {
|
|
5906
|
+
const slot = this.withWrite(() => {
|
|
5907
|
+
const pk = this.selectPk(entity);
|
|
5908
|
+
this.trackPatch(pk, entity);
|
|
5909
|
+
return this.collection.upsertOne(entity);
|
|
5910
|
+
});
|
|
5911
|
+
this.updateEntitySnapshot(slot.pk);
|
|
5912
|
+
return slot;
|
|
5913
|
+
}
|
|
5914
|
+
upsertMany(entities) {
|
|
5915
|
+
const pks = [];
|
|
5916
|
+
const slots = this.withWrite(() => {
|
|
5917
|
+
for (const entity of entities) {
|
|
5918
|
+
const pk = this.selectPk(entity);
|
|
5919
|
+
pks.push(pk);
|
|
5920
|
+
this.trackPatch(pk, entity);
|
|
5921
|
+
}
|
|
5922
|
+
return this.collection.upsertMany(entities);
|
|
5923
|
+
});
|
|
5924
|
+
for (let i = 0; i < pks.length; i++) this.updateEntitySnapshot(pks[i]);
|
|
5925
|
+
return slots;
|
|
5926
|
+
}
|
|
5927
|
+
getChangedFieldsByPk(pk) {
|
|
5928
|
+
return this.changedFieldsByPk.get(pk) ?? /* @__PURE__ */ new Set();
|
|
5929
|
+
}
|
|
5930
|
+
consumeChangedFieldsByPk(pk) {
|
|
5931
|
+
const existing = this.changedFieldsByPk.get(pk);
|
|
5932
|
+
if (!existing) return /* @__PURE__ */ new Set();
|
|
5933
|
+
return new Set(existing);
|
|
5934
|
+
}
|
|
5935
|
+
getChangedPksByField(field) {
|
|
5936
|
+
return this.changedPksByField.get(field) ?? /* @__PURE__ */ new Set();
|
|
5937
|
+
}
|
|
5938
|
+
consumeChangedPksByField(field) {
|
|
5939
|
+
const existing = this.changedPksByField.get(field);
|
|
5940
|
+
if (!existing) return /* @__PURE__ */ new Set();
|
|
5941
|
+
return new Set(existing);
|
|
5942
|
+
}
|
|
5943
|
+
clear() {
|
|
5944
|
+
this.changedFieldsByPk.clear();
|
|
5945
|
+
this.changedPksByField.clear();
|
|
5946
|
+
}
|
|
5947
|
+
destroy() {
|
|
5948
|
+
this.changedPksEventEmitter.destroy();
|
|
5453
5949
|
this.changedFieldsEventEmitter.destroy();
|
|
5454
5950
|
this.unsubscribeAfterFlush();
|
|
5455
5951
|
this.unsubscribeFromCollectionEmitter?.();
|
|
@@ -5488,8 +5984,9 @@ var OIMCollectionChangedFields = class {
|
|
|
5488
5984
|
Object.keys(nextObj).forEach((k) => keys.add(k));
|
|
5489
5985
|
const changed = [];
|
|
5490
5986
|
keys.forEach((k) => {
|
|
5491
|
-
if (prevObj[k] !== nextObj[k])
|
|
5987
|
+
if (prevObj[k] !== nextObj[k]) {
|
|
5492
5988
|
changed.push(k);
|
|
5989
|
+
}
|
|
5493
5990
|
});
|
|
5494
5991
|
return changed;
|
|
5495
5992
|
}
|
|
@@ -5655,10 +6152,15 @@ var OIMOrderedListMappedCommandStream = class _OIMOrderedListMappedCommandStream
|
|
|
5655
6152
|
try {
|
|
5656
6153
|
const subs = this.subscribers.get(key);
|
|
5657
6154
|
if (subs && subs.size > 0) {
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
6155
|
+
if (subs.size === 1) {
|
|
6156
|
+
const only = subs.values().next().value;
|
|
6157
|
+
if (only) only();
|
|
6158
|
+
} else {
|
|
6159
|
+
const snapshot = Array.from(subs);
|
|
6160
|
+
for (let s = 0; s < snapshot.length; s++) {
|
|
6161
|
+
const handler = snapshot[s];
|
|
6162
|
+
if (subs.has(handler)) handler();
|
|
6163
|
+
}
|
|
5662
6164
|
}
|
|
5663
6165
|
}
|
|
5664
6166
|
} finally {
|
|
@@ -5952,10 +6454,13 @@ var OIMEventQueueSchedulerAnimationFrame = class extends OIMEventQueueScheduler
|
|
|
5952
6454
|
this.flush();
|
|
5953
6455
|
});
|
|
5954
6456
|
} else {
|
|
5955
|
-
this.frameId =
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
6457
|
+
this.frameId = this.unref(
|
|
6458
|
+
setTimeout(() => {
|
|
6459
|
+
this.frameId = void 0;
|
|
6460
|
+
this.flush();
|
|
6461
|
+
}, 16)
|
|
6462
|
+
// ~60fps
|
|
6463
|
+
);
|
|
5959
6464
|
}
|
|
5960
6465
|
}
|
|
5961
6466
|
cancel() {
|
|
@@ -6001,10 +6506,12 @@ var OIMEventQueueSchedulerTimeout = class extends OIMEventQueueScheduler {
|
|
|
6001
6506
|
}
|
|
6002
6507
|
schedule() {
|
|
6003
6508
|
if (this.timeoutId !== void 0) return;
|
|
6004
|
-
this.timeoutId =
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6509
|
+
this.timeoutId = this.unref(
|
|
6510
|
+
setTimeout(() => {
|
|
6511
|
+
this.timeoutId = void 0;
|
|
6512
|
+
this.flush();
|
|
6513
|
+
}, this.delay)
|
|
6514
|
+
);
|
|
6008
6515
|
}
|
|
6009
6516
|
cancel() {
|
|
6010
6517
|
if (this.timeoutId === void 0) return;
|
|
@@ -6038,13 +6545,13 @@ var OIMEventQueueSchedulerImmediate = class extends OIMEventQueueScheduler {
|
|
|
6038
6545
|
this.flush();
|
|
6039
6546
|
};
|
|
6040
6547
|
if (this.useSetImmediate) {
|
|
6041
|
-
this.immediateId = setImmediate(callback);
|
|
6548
|
+
this.immediateId = this.unref(setImmediate(callback));
|
|
6042
6549
|
} else if (this.useMessageChannel && this.messageChannel) {
|
|
6043
6550
|
this.immediateId = 1;
|
|
6044
6551
|
this.pendingCallback = callback;
|
|
6045
6552
|
this.messageChannel.port1.postMessage(null);
|
|
6046
6553
|
} else {
|
|
6047
|
-
this.immediateId = setTimeout(callback, 0);
|
|
6554
|
+
this.immediateId = this.unref(setTimeout(callback, 0));
|
|
6048
6555
|
}
|
|
6049
6556
|
}
|
|
6050
6557
|
cancel() {
|
|
@@ -6137,242 +6644,6 @@ var OIMDBSettings = class {
|
|
|
6137
6644
|
OIMDBSettings.UPDATED_KEYS_INDEX_KEY = "__updatedKeys__";
|
|
6138
6645
|
OIMDBSettings.FLUSHING_KEYS_INDEX_KEY = "__flushingKeys__";
|
|
6139
6646
|
|
|
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
6647
|
// src/modules/selector/core/OIMObjectValueByKeySelector.ts
|
|
6377
6648
|
var OIMObjectValueByKeySelector = class extends OIMSelector {
|
|
6378
6649
|
constructor(runtime, obj, key) {
|
|
@@ -6450,8 +6721,9 @@ var OIMIndexPksByKeyArrayBasedSelector = class extends OIMSelector {
|
|
|
6450
6721
|
areEqual(prev, next) {
|
|
6451
6722
|
if (prev === next) return true;
|
|
6452
6723
|
if (prev.length !== next.length) return false;
|
|
6453
|
-
for (let i = 0; i < prev.length; i++)
|
|
6724
|
+
for (let i = 0; i < prev.length; i++) {
|
|
6454
6725
|
if (prev[i] !== next[i]) return false;
|
|
6726
|
+
}
|
|
6455
6727
|
return true;
|
|
6456
6728
|
}
|
|
6457
6729
|
};
|
|
@@ -6474,8 +6746,9 @@ var OIMIndexPksByKeysSetBasedSelector = class extends OIMSelector {
|
|
|
6474
6746
|
areEqual(prev, next) {
|
|
6475
6747
|
if (prev === next) return true;
|
|
6476
6748
|
if (prev.length !== next.length) return false;
|
|
6477
|
-
for (let i = 0; i < prev.length; i++)
|
|
6749
|
+
for (let i = 0; i < prev.length; i++) {
|
|
6478
6750
|
if (prev[i] !== next[i]) return false;
|
|
6751
|
+
}
|
|
6479
6752
|
return true;
|
|
6480
6753
|
}
|
|
6481
6754
|
};
|
|
@@ -6498,8 +6771,9 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
|
|
|
6498
6771
|
areEqual(prev, next) {
|
|
6499
6772
|
if (prev === next) return true;
|
|
6500
6773
|
if (prev.length !== next.length) return false;
|
|
6501
|
-
for (let i = 0; i < prev.length; i++)
|
|
6774
|
+
for (let i = 0; i < prev.length; i++) {
|
|
6502
6775
|
if (prev[i] !== next[i]) return false;
|
|
6776
|
+
}
|
|
6503
6777
|
return true;
|
|
6504
6778
|
}
|
|
6505
6779
|
};
|
|
@@ -6529,6 +6803,7 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
|
|
|
6529
6803
|
OIMComputeRuntime,
|
|
6530
6804
|
OIMComputed,
|
|
6531
6805
|
OIMDBSettings,
|
|
6806
|
+
OIMDerivedCollection,
|
|
6532
6807
|
OIMDerivedCollectionGlobalIndexArrayBased,
|
|
6533
6808
|
OIMDerivedCollectionGlobalIndexSetBased,
|
|
6534
6809
|
OIMDerivedCollectionIndexArrayBased,
|
|
@@ -6624,5 +6899,9 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
|
|
|
6624
6899
|
createOIMIndexSlotMap,
|
|
6625
6900
|
createOIMOrderedListCommandStreamDiffDriven,
|
|
6626
6901
|
createOIMOrderedListMappedCommandStream,
|
|
6627
|
-
diffOrderedListByPk
|
|
6902
|
+
diffOrderedListByPk,
|
|
6903
|
+
getOIMComputeRuntime,
|
|
6904
|
+
on,
|
|
6905
|
+
peekOIMComputeRuntime,
|
|
6906
|
+
setOIMComputeRuntime
|
|
6628
6907
|
});
|