@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.js
CHANGED
|
@@ -225,6 +225,25 @@ var OIMEventQueueScheduler = class {
|
|
|
225
225
|
flush() {
|
|
226
226
|
this.emitter.emit(0 /* FLUSH */, void 0);
|
|
227
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Detach a Node timer handle from the event loop, returning it unchanged.
|
|
230
|
+
*
|
|
231
|
+
* A pending flush must never be a reason for a process to stay alive: if
|
|
232
|
+
* nothing else is running there is no UI left to update, and the flush is
|
|
233
|
+
* moot. Without this a scheduled-but-not-yet-run flush keeps Node awake —
|
|
234
|
+
* which is why a test suite that leaves a queue scheduled reports
|
|
235
|
+
* "a worker process has failed to exit gracefully".
|
|
236
|
+
*
|
|
237
|
+
* In the browser `setTimeout` returns a number, which has no `unref`, so the
|
|
238
|
+
* call is guarded and the handle passes straight through.
|
|
239
|
+
*/
|
|
240
|
+
unref(handle) {
|
|
241
|
+
const maybeUnrefable = handle;
|
|
242
|
+
if (typeof maybeUnrefable?.unref === "function") {
|
|
243
|
+
maybeUnrefable.unref();
|
|
244
|
+
}
|
|
245
|
+
return handle;
|
|
246
|
+
}
|
|
228
247
|
};
|
|
229
248
|
|
|
230
249
|
// src/core/OIMKeyedBucketSetBased.ts
|
|
@@ -564,14 +583,17 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
564
583
|
if (this.dirtyCarriers.length === 0) return;
|
|
565
584
|
const flushing = this.dirtyCarriers;
|
|
566
585
|
this.dirtyCarriers = [];
|
|
586
|
+
const multiCarrierHandlers = this.multiCarrierHandlers;
|
|
587
|
+
const delivered = multiCarrierHandlers !== void 0 && multiCarrierHandlers.size > 0 ? this.deliveredPool ?? (this.deliveredPool = /* @__PURE__ */ new Set()) : void 0;
|
|
567
588
|
let i = 0;
|
|
568
589
|
try {
|
|
569
590
|
for (; i < flushing.length; i++) {
|
|
570
591
|
flushing[i].dirty = false;
|
|
571
|
-
this.notify(flushing[i]);
|
|
592
|
+
this.notify(flushing[i], delivered);
|
|
572
593
|
}
|
|
573
594
|
} finally {
|
|
574
595
|
for (; i < flushing.length; i++) flushing[i].dirty = false;
|
|
596
|
+
delivered?.clear();
|
|
575
597
|
}
|
|
576
598
|
};
|
|
577
599
|
this.queue = queue;
|
|
@@ -589,7 +611,15 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
589
611
|
this.addHandler(carrier, handler);
|
|
590
612
|
carriers.push(carrier);
|
|
591
613
|
}
|
|
614
|
+
const spansMultipleCarriers = carriers.length > 1;
|
|
615
|
+
if (spansMultipleCarriers) this.retainMultiCarrierHandler(handler);
|
|
616
|
+
let unsubscribed = false;
|
|
592
617
|
return () => {
|
|
618
|
+
if (unsubscribed) return;
|
|
619
|
+
unsubscribed = true;
|
|
620
|
+
if (spansMultipleCarriers) {
|
|
621
|
+
this.releaseMultiCarrierHandler(handler);
|
|
622
|
+
}
|
|
593
623
|
for (let i = 0; i < carriers.length; i++) {
|
|
594
624
|
this.removeHandler(carriers[i], handler);
|
|
595
625
|
}
|
|
@@ -600,10 +630,25 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
600
630
|
if (carrier) this.removeHandler(carrier, handler);
|
|
601
631
|
}
|
|
602
632
|
unsubscribeFromKeys(keys, handler) {
|
|
633
|
+
if (keys.length > 1) this.releaseMultiCarrierHandler(handler);
|
|
603
634
|
for (let i = 0; i < keys.length; i++) {
|
|
604
635
|
this.unsubscribeFromKey(keys[i], handler);
|
|
605
636
|
}
|
|
606
637
|
}
|
|
638
|
+
/** Take a reference for a handler whose subscription spans several carriers. */
|
|
639
|
+
retainMultiCarrierHandler(handler) {
|
|
640
|
+
const handlers = this.multiCarrierHandlers ?? (this.multiCarrierHandlers = /* @__PURE__ */ new Map());
|
|
641
|
+
handlers.set(handler, (handlers.get(handler) ?? 0) + 1);
|
|
642
|
+
}
|
|
643
|
+
/** Drop one reference; the handler leaves the set when none are left. */
|
|
644
|
+
releaseMultiCarrierHandler(handler) {
|
|
645
|
+
const handlers = this.multiCarrierHandlers;
|
|
646
|
+
if (handlers === void 0) return;
|
|
647
|
+
const count = handlers.get(handler);
|
|
648
|
+
if (count === void 0) return;
|
|
649
|
+
if (count > 1) handlers.set(handler, count - 1);
|
|
650
|
+
else handlers.delete(handler);
|
|
651
|
+
}
|
|
607
652
|
addHandler(carrier, handler) {
|
|
608
653
|
let subscribers = carrier.subscribers;
|
|
609
654
|
if (!subscribers) {
|
|
@@ -692,6 +737,8 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
692
737
|
}
|
|
693
738
|
this.dirtyCarriers = [];
|
|
694
739
|
this.isFlushEnqueued = false;
|
|
740
|
+
this.multiCarrierHandlers?.clear();
|
|
741
|
+
this.deliveredPool?.clear();
|
|
695
742
|
}
|
|
696
743
|
assertNotInFlush() {
|
|
697
744
|
if (this.queue.isInFlush) {
|
|
@@ -705,21 +752,43 @@ var OIMCarrierKeyedEmitter = class {
|
|
|
705
752
|
this.isFlushEnqueued = true;
|
|
706
753
|
this.queue.enqueue(this.onFlush);
|
|
707
754
|
}
|
|
708
|
-
notify(carrier) {
|
|
755
|
+
notify(carrier, delivered) {
|
|
709
756
|
const subscribers = carrier.subscribers;
|
|
710
757
|
if (!subscribers || subscribers.size === 0) return;
|
|
758
|
+
const multiCarrierHandlers = delivered ? this.multiCarrierHandlers : void 0;
|
|
711
759
|
if (subscribers.size === 1) {
|
|
712
760
|
const only = subscribers.values().next().value;
|
|
713
|
-
if (only)
|
|
761
|
+
if (!only) return;
|
|
762
|
+
if (this.isAlreadyDelivered(only, delivered, multiCarrierHandlers)) {
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
only();
|
|
714
766
|
return;
|
|
715
767
|
}
|
|
716
768
|
const snapshot = [];
|
|
717
769
|
subscribers.forEach((h) => snapshot.push(h));
|
|
718
770
|
for (let i = 0; i < snapshot.length; i++) {
|
|
719
771
|
const handler = snapshot[i];
|
|
720
|
-
if (subscribers.has(handler))
|
|
772
|
+
if (!subscribers.has(handler)) continue;
|
|
773
|
+
if (this.isAlreadyDelivered(handler, delivered, multiCarrierHandlers)) {
|
|
774
|
+
continue;
|
|
775
|
+
}
|
|
776
|
+
handler();
|
|
721
777
|
}
|
|
722
778
|
}
|
|
779
|
+
/**
|
|
780
|
+
* Whether this handler already fired in the current flush and must be
|
|
781
|
+
* skipped. Only multi-carrier handlers are tracked; everything else always
|
|
782
|
+
* delivers. Membership is recorded via the size delta of a single `add` —
|
|
783
|
+
* one hash probe instead of `has` + `add`.
|
|
784
|
+
*/
|
|
785
|
+
isAlreadyDelivered(handler, delivered, multiCarrierHandlers) {
|
|
786
|
+
if (delivered === void 0) return false;
|
|
787
|
+
if (multiCarrierHandlers?.has(handler) !== true) return false;
|
|
788
|
+
const size = delivered.size;
|
|
789
|
+
delivered.add(handler);
|
|
790
|
+
return delivered.size === size;
|
|
791
|
+
}
|
|
723
792
|
};
|
|
724
793
|
|
|
725
794
|
// src/core/OIMKeyedCarrierProvider.ts
|
|
@@ -1339,8 +1408,11 @@ var OIMCollection = class {
|
|
|
1339
1408
|
this.emitter.emit(0 /* UPDATE */, { pks });
|
|
1340
1409
|
}
|
|
1341
1410
|
clear() {
|
|
1411
|
+
const pks = this.store.getAllPks();
|
|
1342
1412
|
this.store.clear();
|
|
1343
|
-
|
|
1413
|
+
if (pks.length > 0) {
|
|
1414
|
+
this.emitter.emit(0 /* UPDATE */, { pks });
|
|
1415
|
+
}
|
|
1344
1416
|
}
|
|
1345
1417
|
countAll() {
|
|
1346
1418
|
return this.store.countAll();
|
|
@@ -1382,14 +1454,12 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1382
1454
|
// Only ever holds `slot.pk` (one canonical reference per logical key), so a
|
|
1383
1455
|
// native `Set` dedups correctly by reference even for composite pks.
|
|
1384
1456
|
this.pendingAnyUpdatePks = /* @__PURE__ */ new Set();
|
|
1385
|
-
this.isAnyUpdateClearPending = false;
|
|
1386
1457
|
this.isAnyUpdateScheduled = false;
|
|
1387
1458
|
this.runAnyUpdate = () => {
|
|
1388
1459
|
if (!this.isAnyUpdateScheduled) return;
|
|
1389
1460
|
this.isAnyUpdateScheduled = false;
|
|
1390
|
-
const pks =
|
|
1461
|
+
const pks = Array.from(this.pendingAnyUpdatePks.values());
|
|
1391
1462
|
this.pendingAnyUpdatePks.clear();
|
|
1392
|
-
this.isAnyUpdateClearPending = false;
|
|
1393
1463
|
const snapshot = Array.from(this.anyUpdateHandlers);
|
|
1394
1464
|
for (let i = 0; i < snapshot.length; i++) snapshot[i](pks);
|
|
1395
1465
|
};
|
|
@@ -1429,30 +1499,43 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1429
1499
|
this.anyUpdateHandlers.delete(handler);
|
|
1430
1500
|
};
|
|
1431
1501
|
}
|
|
1432
|
-
//
|
|
1433
|
-
//
|
|
1434
|
-
//
|
|
1435
|
-
//
|
|
1436
|
-
|
|
1502
|
+
// Two notification channels coexist on a reactive collection; they serve
|
|
1503
|
+
// different audiences and NEITHER is obsolete:
|
|
1504
|
+
// • the keyed `updateEmitter` — per-key/per-carrier pings ("did MY key
|
|
1505
|
+
// change?", payload-less `void`), for leaf subscribers like React hooks
|
|
1506
|
+
// that declare the keys they care about up front;
|
|
1507
|
+
// • this `emitter` UPDATE event — the aggregate/batch channel that carries
|
|
1508
|
+
// the full list of changed pks in one SYNCHRONOUS callback, for
|
|
1509
|
+
// consumers that do NOT know their keys ahead of time and must re-derive
|
|
1510
|
+
// over the batch: derived indexes/collections, changed-fields, persist,
|
|
1511
|
+
// snapshot-manager. `pks` always enumerates exactly what changed — even
|
|
1512
|
+
// clear() lists every removed key, so an empty array never occurs.
|
|
1513
|
+
// It is not a per-key emitter with fewer features — it is the opposite
|
|
1514
|
+
// shape (enumerated batch, not "my key"), which is why it stays.
|
|
1515
|
+
//
|
|
1516
|
+
// Emit on the batch channel only when something is actually subscribed —
|
|
1517
|
+
// otherwise every upsert/remove allocates a throwaway `{ pks }` object (and
|
|
1518
|
+
// array) that nobody reads.
|
|
1519
|
+
notifyBatch(pk) {
|
|
1437
1520
|
if (this.emitter.hasHandlers(0 /* UPDATE */)) {
|
|
1438
1521
|
this.emitter.emit(0 /* UPDATE */, { pks: [pk] });
|
|
1439
1522
|
}
|
|
1440
1523
|
}
|
|
1441
|
-
|
|
1524
|
+
notifyBatchMany(pks) {
|
|
1442
1525
|
if (this.emitter.hasHandlers(0 /* UPDATE */)) {
|
|
1443
1526
|
this.emitter.emit(0 /* UPDATE */, { pks });
|
|
1444
1527
|
}
|
|
1445
1528
|
}
|
|
1446
1529
|
upsertOneByPk(pk, entity) {
|
|
1447
1530
|
const slot = this.upsertOneWithoutNotificationsByPk(pk, entity);
|
|
1448
|
-
this.
|
|
1531
|
+
this.notifyBatch(pk);
|
|
1449
1532
|
this.updateEmitter.markUpdatedCarrier(slot);
|
|
1450
1533
|
this.trackAnyUpdatePk(pk);
|
|
1451
1534
|
return slot;
|
|
1452
1535
|
}
|
|
1453
1536
|
upsertOne(entity) {
|
|
1454
1537
|
const slot = this.upsertOneWithoutNotifications(entity);
|
|
1455
|
-
this.
|
|
1538
|
+
this.notifyBatch(slot.pk);
|
|
1456
1539
|
this.updateEmitter.markUpdatedCarrier(slot);
|
|
1457
1540
|
this.trackAnyUpdatePk(slot.pk);
|
|
1458
1541
|
return slot;
|
|
@@ -1463,7 +1546,7 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1463
1546
|
(entity) => this.upsertOneWithoutNotifications(entity)
|
|
1464
1547
|
);
|
|
1465
1548
|
const pks = slots.map((slot) => slot.pk);
|
|
1466
|
-
this.
|
|
1549
|
+
this.notifyBatchMany(pks);
|
|
1467
1550
|
for (let i = 0; i < slots.length; i++) {
|
|
1468
1551
|
this.updateEmitter.markUpdatedCarrier(slots[i]);
|
|
1469
1552
|
}
|
|
@@ -1473,7 +1556,7 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1473
1556
|
removeOne(entity) {
|
|
1474
1557
|
const pk = this.selectPk(entity);
|
|
1475
1558
|
this.store.removeOneByPk(pk);
|
|
1476
|
-
this.
|
|
1559
|
+
this.notifyBatch(pk);
|
|
1477
1560
|
this.updateEmitter.markUpdatedKey(pk);
|
|
1478
1561
|
this.trackAnyUpdatePk(pk);
|
|
1479
1562
|
}
|
|
@@ -1481,30 +1564,32 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1481
1564
|
if (entities.length === 0) return;
|
|
1482
1565
|
const pks = entities.map(this.selectPk);
|
|
1483
1566
|
this.store.removeManyByPks(pks);
|
|
1484
|
-
this.
|
|
1567
|
+
this.notifyBatchMany(pks);
|
|
1485
1568
|
this.updateEmitter.markUpdatedKeys(pks);
|
|
1486
1569
|
this.trackAnyUpdatePks(pks);
|
|
1487
1570
|
}
|
|
1488
1571
|
removeOneByPk(pk) {
|
|
1489
1572
|
this.store.removeOneByPk(pk);
|
|
1490
|
-
this.
|
|
1573
|
+
this.notifyBatch(pk);
|
|
1491
1574
|
this.updateEmitter.markUpdatedKey(pk);
|
|
1492
1575
|
this.trackAnyUpdatePk(pk);
|
|
1493
1576
|
}
|
|
1494
1577
|
removeManyByPks(pks) {
|
|
1495
1578
|
if (pks.length === 0) return;
|
|
1496
1579
|
this.store.removeManyByPks(pks);
|
|
1497
|
-
this.
|
|
1580
|
+
this.notifyBatchMany(pks);
|
|
1498
1581
|
this.updateEmitter.markUpdatedKeys(pks);
|
|
1499
1582
|
this.trackAnyUpdatePks(pks);
|
|
1500
1583
|
}
|
|
1501
1584
|
clear() {
|
|
1585
|
+
const needsPks = this.emitter.hasHandlers(0 /* UPDATE */) || this.anyUpdateHandlers.size > 0;
|
|
1586
|
+
const pks = needsPks ? this.store.getAllPks() : void 0;
|
|
1502
1587
|
this.store.clear();
|
|
1503
|
-
if (
|
|
1504
|
-
this.
|
|
1588
|
+
if (pks && pks.length > 0) {
|
|
1589
|
+
this.notifyBatchMany(pks);
|
|
1590
|
+
this.trackAnyUpdatePks(pks);
|
|
1505
1591
|
}
|
|
1506
1592
|
this.updateEmitter.markAllUpdated();
|
|
1507
|
-
this.trackAnyUpdateClear();
|
|
1508
1593
|
}
|
|
1509
1594
|
trackAnyUpdatePk(pk) {
|
|
1510
1595
|
if (this.anyUpdateHandlers.size === 0) return;
|
|
@@ -1513,14 +1598,9 @@ var OIMReactiveCollection = class extends OIMCollection {
|
|
|
1513
1598
|
}
|
|
1514
1599
|
trackAnyUpdatePks(pks) {
|
|
1515
1600
|
if (this.anyUpdateHandlers.size === 0) return;
|
|
1516
|
-
for (let i = 0; i < pks.length; i++)
|
|
1601
|
+
for (let i = 0; i < pks.length; i++) {
|
|
1517
1602
|
this.pendingAnyUpdatePks.add(pks[i]);
|
|
1518
|
-
|
|
1519
|
-
}
|
|
1520
|
-
trackAnyUpdateClear() {
|
|
1521
|
-
if (this.anyUpdateHandlers.size === 0) return;
|
|
1522
|
-
this.isAnyUpdateClearPending = true;
|
|
1523
|
-
this.pendingAnyUpdatePks.clear();
|
|
1603
|
+
}
|
|
1524
1604
|
this.ensureAnyUpdateEnqueued();
|
|
1525
1605
|
}
|
|
1526
1606
|
ensureAnyUpdateEnqueued() {
|
|
@@ -1953,8 +2033,13 @@ var OIMUpdateEventEmitter = class {
|
|
|
1953
2033
|
var OIMOrderedListCommandBuffer = class {
|
|
1954
2034
|
constructor(queue) {
|
|
1955
2035
|
this.commandsByKey = /* @__PURE__ */ new Map();
|
|
2036
|
+
// Keys whose buffered leading `reset` is stale: an edit after the reset
|
|
2037
|
+
// should be folded into it, but we defer the (O(list-size)) rebuild to the
|
|
2038
|
+
// next read instead of redoing it on every subsequent edit in the batch.
|
|
2039
|
+
this.staleResetKeys = /* @__PURE__ */ new Set();
|
|
1956
2040
|
this.onAfterFlush = () => {
|
|
1957
2041
|
this.commandsByKey.clear();
|
|
2042
|
+
this.staleResetKeys.clear();
|
|
1958
2043
|
};
|
|
1959
2044
|
this.commandsEventEmitter = new OIMUpdateEventEmitter(
|
|
1960
2045
|
queue,
|
|
@@ -1969,9 +2054,11 @@ var OIMOrderedListCommandBuffer = class {
|
|
|
1969
2054
|
return this.commandsEventEmitter.subscribeOnKey(key, handler);
|
|
1970
2055
|
}
|
|
1971
2056
|
getBufferedCommands(key) {
|
|
2057
|
+
this.materializeStaleReset(key);
|
|
1972
2058
|
return this.commandsByKey.get(key) ?? [];
|
|
1973
2059
|
}
|
|
1974
2060
|
consumeCommands(key) {
|
|
2061
|
+
this.materializeStaleReset(key);
|
|
1975
2062
|
const cmds = this.commandsByKey.get(key);
|
|
1976
2063
|
if (!cmds || cmds.length === 0) return [];
|
|
1977
2064
|
return cmds.slice();
|
|
@@ -1980,6 +2067,20 @@ var OIMOrderedListCommandBuffer = class {
|
|
|
1980
2067
|
this.commandsEventEmitter.destroy();
|
|
1981
2068
|
this.unsubscribeAfterFlush();
|
|
1982
2069
|
this.commandsByKey.clear();
|
|
2070
|
+
this.staleResetKeys.clear();
|
|
2071
|
+
}
|
|
2072
|
+
/**
|
|
2073
|
+
* Rebuild a deferred leading `reset` from the current order, once, at read
|
|
2074
|
+
* time. All the post-reset edits that were folded in are already reflected
|
|
2075
|
+
* in the driver's backing order, so a single rebuild here is equivalent to
|
|
2076
|
+
* having recomputed the reset on each of those edits.
|
|
2077
|
+
*/
|
|
2078
|
+
materializeStaleReset(key) {
|
|
2079
|
+
if (!this.staleResetKeys.delete(key)) return;
|
|
2080
|
+
const cmds = this.commandsByKey.get(key);
|
|
2081
|
+
if (cmds && cmds.length > 0 && cmds[0].type === "reset") {
|
|
2082
|
+
cmds[0] = this.createResetCommand(this.getItemsByKey(key));
|
|
2083
|
+
}
|
|
1983
2084
|
}
|
|
1984
2085
|
appendCommand(key, cmd) {
|
|
1985
2086
|
let cmds = this.commandsByKey.get(key);
|
|
@@ -1990,8 +2091,9 @@ var OIMOrderedListCommandBuffer = class {
|
|
|
1990
2091
|
if (cmd.type === "reset") {
|
|
1991
2092
|
cmds.length = 0;
|
|
1992
2093
|
cmds.push(cmd);
|
|
2094
|
+
this.staleResetKeys.delete(key);
|
|
1993
2095
|
} else if (cmds.length > 0 && cmds[0].type === "reset") {
|
|
1994
|
-
|
|
2096
|
+
this.staleResetKeys.add(key);
|
|
1995
2097
|
} else {
|
|
1996
2098
|
cmds.push(cmd);
|
|
1997
2099
|
}
|
|
@@ -3033,10 +3135,6 @@ var OIMDerivedCollectionIndexSetBased = class extends OIMReactiveCollectionIndex
|
|
|
3033
3135
|
});
|
|
3034
3136
|
this.keysByPk = /* @__PURE__ */ new Map();
|
|
3035
3137
|
this.onCollectionUpdate = (pks) => {
|
|
3036
|
-
if (pks.length === 0) {
|
|
3037
|
-
this.rebuildFromCollection();
|
|
3038
|
-
return;
|
|
3039
|
-
}
|
|
3040
3138
|
for (const pk of pks) {
|
|
3041
3139
|
this.syncPk(pk);
|
|
3042
3140
|
}
|
|
@@ -3138,10 +3236,6 @@ var OIMDerivedCollectionIndexArrayBased = class extends OIMReactiveCollectionInd
|
|
|
3138
3236
|
// touching an unrelated field can skip re-sorting when the value is unchanged.
|
|
3139
3237
|
this.orderValueByPk = /* @__PURE__ */ new Map();
|
|
3140
3238
|
this.onCollectionUpdate = (pks) => {
|
|
3141
|
-
if (pks.length === 0) {
|
|
3142
|
-
this.rebuildFromCollection();
|
|
3143
|
-
return;
|
|
3144
|
-
}
|
|
3145
3239
|
const ordered = !!(this.compareEntities || this.orderBy);
|
|
3146
3240
|
const keysToSort = ordered ? /* @__PURE__ */ new Set() : null;
|
|
3147
3241
|
for (const pk of pks) {
|
|
@@ -3558,10 +3652,6 @@ var OIMDerivedCollectionGlobalIndexArrayBased = class extends OIMReactiveCollect
|
|
|
3558
3652
|
// an unrelated field can skip re-sorting when the value is unchanged.
|
|
3559
3653
|
this.orderValueByPk = /* @__PURE__ */ new Map();
|
|
3560
3654
|
this.onCollectionUpdate = (pks) => {
|
|
3561
|
-
if (pks.length === 0) {
|
|
3562
|
-
this.rebuildFromCollection();
|
|
3563
|
-
return;
|
|
3564
|
-
}
|
|
3565
3655
|
const ordered = !!(this.compareEntities || this.orderBy);
|
|
3566
3656
|
let needsSort = false;
|
|
3567
3657
|
for (const pk of pks) {
|
|
@@ -3659,10 +3749,6 @@ var OIMDerivedCollectionGlobalIndexSetBased = class extends OIMReactiveCollectio
|
|
|
3659
3749
|
super(queue, { collection, indexOptions: opts.indexOptions });
|
|
3660
3750
|
this.presentPks = /* @__PURE__ */ new Set();
|
|
3661
3751
|
this.onCollectionUpdate = (pks) => {
|
|
3662
|
-
if (pks.length === 0) {
|
|
3663
|
-
this.rebuildFromCollection();
|
|
3664
|
-
return;
|
|
3665
|
-
}
|
|
3666
3752
|
for (const pk of pks) {
|
|
3667
3753
|
const prev = this.presentPks.has(pk);
|
|
3668
3754
|
const slot = this.collection.getSlotByPk(pk);
|
|
@@ -3838,6 +3924,55 @@ function createOIMCollectionIndexFactory(queue, collection) {
|
|
|
3838
3924
|
return new OIMCollectionIndexFactory(queue, collection);
|
|
3839
3925
|
}
|
|
3840
3926
|
|
|
3927
|
+
// src/core/OIMDerivedCollection.ts
|
|
3928
|
+
var OIMDerivedCollection = class extends OIMReactiveCollection {
|
|
3929
|
+
constructor(queue, source, derive, opts) {
|
|
3930
|
+
super(queue, {
|
|
3931
|
+
store: opts?.store,
|
|
3932
|
+
// Each sync recomputes the WHOLE derived entity → replace, not merge.
|
|
3933
|
+
updateEntity: (draft) => draft
|
|
3934
|
+
});
|
|
3935
|
+
this.onSourceUpdate = (pks) => {
|
|
3936
|
+
for (let i = 0; i < pks.length; i++) this.syncPk(pks[i]);
|
|
3937
|
+
};
|
|
3938
|
+
this.source = source;
|
|
3939
|
+
this.derive = derive;
|
|
3940
|
+
this.compareDerived = opts?.compare ?? Object.is;
|
|
3941
|
+
this.unsubscribeFromSource = source.emitter.on(
|
|
3942
|
+
0 /* UPDATE */,
|
|
3943
|
+
(payload) => this.onSourceUpdate(payload.pks)
|
|
3944
|
+
);
|
|
3945
|
+
if (opts?.buildInitial !== false) {
|
|
3946
|
+
this.rebuildFromSource();
|
|
3947
|
+
}
|
|
3948
|
+
}
|
|
3949
|
+
rebuildFromSource() {
|
|
3950
|
+
for (const pk of this.getAllPks()) {
|
|
3951
|
+
if (this.source.getOneByPk(pk) === void 0) {
|
|
3952
|
+
this.removeOneByPk(pk);
|
|
3953
|
+
}
|
|
3954
|
+
}
|
|
3955
|
+
for (const slot of this.source.getAllSlots()) {
|
|
3956
|
+
if (slot.item !== void 0) this.syncPk(slot.pk);
|
|
3957
|
+
}
|
|
3958
|
+
}
|
|
3959
|
+
destroy() {
|
|
3960
|
+
this.unsubscribeFromSource();
|
|
3961
|
+
super.destroy();
|
|
3962
|
+
}
|
|
3963
|
+
syncPk(pk) {
|
|
3964
|
+
const sourceEntity = this.source.getOneByPk(pk);
|
|
3965
|
+
if (sourceEntity === void 0) {
|
|
3966
|
+
if (this.getOneByPk(pk) !== void 0) this.removeOneByPk(pk);
|
|
3967
|
+
return;
|
|
3968
|
+
}
|
|
3969
|
+
const next = this.derive(sourceEntity, pk);
|
|
3970
|
+
const prev = this.getOneByPk(pk);
|
|
3971
|
+
if (prev !== void 0 && this.compareDerived(prev, next)) return;
|
|
3972
|
+
this.upsertOneByPk(pk, next);
|
|
3973
|
+
}
|
|
3974
|
+
};
|
|
3975
|
+
|
|
3841
3976
|
// src/core/OIMObjectStoreRecordDriven.ts
|
|
3842
3977
|
var OIMObjectStoreRecordDriven = class extends OIMObjectStore {
|
|
3843
3978
|
constructor(initial) {
|
|
@@ -3910,8 +4045,11 @@ var OIMObject = class {
|
|
|
3910
4045
|
return this.store.getAll();
|
|
3911
4046
|
}
|
|
3912
4047
|
clear() {
|
|
4048
|
+
const keys = this.store.keys();
|
|
3913
4049
|
this.store.clear();
|
|
3914
|
-
|
|
4050
|
+
if (keys.length > 0) {
|
|
4051
|
+
this.onUpdatedKeys(keys);
|
|
4052
|
+
}
|
|
3915
4053
|
}
|
|
3916
4054
|
/**
|
|
3917
4055
|
* Write fan-out hooks. Split single-key vs multi-key so a reactive subclass
|
|
@@ -4214,8 +4352,9 @@ var OIMComparatorFactory = class {
|
|
|
4214
4352
|
if (ka.length !== kb.length) return true;
|
|
4215
4353
|
for (let i = 0; i < ka.length; i++) {
|
|
4216
4354
|
const k = ka[i];
|
|
4217
|
-
if (b[k] !== a[k])
|
|
4355
|
+
if (b[k] !== a[k]) {
|
|
4218
4356
|
return true;
|
|
4357
|
+
}
|
|
4219
4358
|
}
|
|
4220
4359
|
return false;
|
|
4221
4360
|
};
|
|
@@ -4265,10 +4404,14 @@ var OIMEventQueue = class {
|
|
|
4265
4404
|
return this.isFlushing;
|
|
4266
4405
|
}
|
|
4267
4406
|
/**
|
|
4268
|
-
* Execute
|
|
4407
|
+
* Execute the tasks pending at the moment the flush starts — a single pass,
|
|
4408
|
+
* not a drain-to-empty.
|
|
4269
4409
|
*
|
|
4270
|
-
*
|
|
4271
|
-
*
|
|
4410
|
+
* The pending set is swapped out for an empty spare up front and the flush
|
|
4411
|
+
* iterates that captured set. Tasks enqueued during the flush land in the
|
|
4412
|
+
* fresh set and run on the NEXT flush, not this one. (Contrast
|
|
4413
|
+
* `OIMComputeRuntime.flush()`, which re-reads its bucket per level and so
|
|
4414
|
+
* does drain same-level tasks scheduled mid-flush.)
|
|
4272
4415
|
*/
|
|
4273
4416
|
flush() {
|
|
4274
4417
|
this.scheduler?.cancel();
|
|
@@ -4542,20 +4685,92 @@ var OIMPkCodecKeyPath = class {
|
|
|
4542
4685
|
}
|
|
4543
4686
|
};
|
|
4544
4687
|
|
|
4688
|
+
// src/modules/effect/core/OIMEffectDependencyComputed.ts
|
|
4689
|
+
var OIMEffectDependencyComputed = class {
|
|
4690
|
+
constructor(source) {
|
|
4691
|
+
this.source = source;
|
|
4692
|
+
}
|
|
4693
|
+
subscribe(onUpdate) {
|
|
4694
|
+
return this.source.emitter.on("update", onUpdate);
|
|
4695
|
+
}
|
|
4696
|
+
};
|
|
4697
|
+
|
|
4545
4698
|
// src/modules/compute/core/OIMComputeRuntime.ts
|
|
4546
4699
|
var OIMComputeRuntime = class {
|
|
4547
4700
|
constructor(queue) {
|
|
4548
4701
|
this.queue = queue;
|
|
4549
4702
|
this.isFlushScheduled = false;
|
|
4550
4703
|
this.isFlushing = false;
|
|
4704
|
+
// Active level range (min > max means nothing pending).
|
|
4551
4705
|
this.minLevel = Infinity;
|
|
4552
4706
|
this.maxLevel = -Infinity;
|
|
4553
|
-
this.dirtyByLevel =
|
|
4707
|
+
this.dirtyByLevel = [];
|
|
4554
4708
|
this.afterFlushTasks = /* @__PURE__ */ new Set();
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4709
|
+
// Topological depth per computed node — the engine is the ONLY owner of
|
|
4710
|
+
// levels; nodes never expose their own. A node's dependents look up its depth
|
|
4711
|
+
// here (by the computed reference their dependency wraps). Written once at
|
|
4712
|
+
// construction, never on the hot flush path.
|
|
4713
|
+
this.levelByComputed = /* @__PURE__ */ new WeakMap();
|
|
4714
|
+
this._isDestroyed = false;
|
|
4715
|
+
this.unsubscribeFromQueue = this.queue.emitter.on(
|
|
4716
|
+
0 /* AFTER_FLUSH */,
|
|
4717
|
+
() => {
|
|
4718
|
+
if (!this.isFlushScheduled) return;
|
|
4719
|
+
this.flush();
|
|
4720
|
+
}
|
|
4721
|
+
);
|
|
4722
|
+
}
|
|
4723
|
+
/**
|
|
4724
|
+
* Whether {@link destroy} has run. A destroyed runtime is detached from its
|
|
4725
|
+
* queue and must not be reused — `getOIMComputeRuntime` reads this to hand
|
|
4726
|
+
* out a fresh runtime instead of a dead one.
|
|
4727
|
+
*/
|
|
4728
|
+
get isDestroyed() {
|
|
4729
|
+
return this._isDestroyed;
|
|
4730
|
+
}
|
|
4731
|
+
/**
|
|
4732
|
+
* Detach from the queue and drop everything pending.
|
|
4733
|
+
*
|
|
4734
|
+
* Without this the AFTER_FLUSH subscription lives as long as the queue does,
|
|
4735
|
+
* even once every computed / effect on this runtime is gone — harmless (the
|
|
4736
|
+
* handler early-returns) but impossible to unwind. Destroying does NOT
|
|
4737
|
+
* destroy the nodes scheduled on it; destroy them first, then the runtime.
|
|
4738
|
+
* Idempotent.
|
|
4739
|
+
*/
|
|
4740
|
+
destroy() {
|
|
4741
|
+
if (this._isDestroyed) return;
|
|
4742
|
+
this._isDestroyed = true;
|
|
4743
|
+
this.unsubscribeFromQueue();
|
|
4744
|
+
for (let i = 0; i < this.dirtyByLevel.length; i++) {
|
|
4745
|
+
this.dirtyByLevel[i]?.clear();
|
|
4746
|
+
}
|
|
4747
|
+
this.afterFlushTasks.clear();
|
|
4748
|
+
this.minLevel = Infinity;
|
|
4749
|
+
this.maxLevel = -Infinity;
|
|
4750
|
+
this.isFlushScheduled = false;
|
|
4751
|
+
}
|
|
4752
|
+
/**
|
|
4753
|
+
* Topological depth for a node with these dependencies: one above the deepest
|
|
4754
|
+
* computed dependency (source-only → 0). The engine owns this — callers pass
|
|
4755
|
+
* their dependencies and get back a level, they never compute it themselves.
|
|
4756
|
+
*/
|
|
4757
|
+
computeLevel(deps) {
|
|
4758
|
+
let max = -1;
|
|
4759
|
+
for (const dep of deps) {
|
|
4760
|
+
if (dep instanceof OIMEffectDependencyComputed) {
|
|
4761
|
+
const depLevel = this.levelByComputed.get(dep.source) ?? 0;
|
|
4762
|
+
if (depLevel > max) max = depLevel;
|
|
4763
|
+
}
|
|
4764
|
+
}
|
|
4765
|
+
return max + 1;
|
|
4766
|
+
}
|
|
4767
|
+
/** Record a computed's depth so its dependents can look it up. */
|
|
4768
|
+
registerLevel(computed, level) {
|
|
4769
|
+
this.levelByComputed.set(computed, level);
|
|
4770
|
+
}
|
|
4771
|
+
/** The recorded topological depth of a computed (0 if unknown). Introspection. */
|
|
4772
|
+
getLevel(computed) {
|
|
4773
|
+
return this.levelByComputed.get(computed) ?? 0;
|
|
4559
4774
|
}
|
|
4560
4775
|
/**
|
|
4561
4776
|
* Schedule a one-shot task to run on the next `queue.flush()` (AFTER_FLUSH),
|
|
@@ -4567,10 +4782,10 @@ var OIMComputeRuntime = class {
|
|
|
4567
4782
|
if (!isActive) return;
|
|
4568
4783
|
task();
|
|
4569
4784
|
};
|
|
4570
|
-
let bucket = this.dirtyByLevel
|
|
4571
|
-
if (
|
|
4785
|
+
let bucket = this.dirtyByLevel[level];
|
|
4786
|
+
if (bucket === void 0) {
|
|
4572
4787
|
bucket = /* @__PURE__ */ new Set();
|
|
4573
|
-
this.dirtyByLevel
|
|
4788
|
+
this.dirtyByLevel[level] = bucket;
|
|
4574
4789
|
}
|
|
4575
4790
|
bucket.add(wrapped);
|
|
4576
4791
|
if (level < this.minLevel) this.minLevel = level;
|
|
@@ -4602,7 +4817,7 @@ var OIMComputeRuntime = class {
|
|
|
4602
4817
|
}
|
|
4603
4818
|
flush() {
|
|
4604
4819
|
this.isFlushScheduled = false;
|
|
4605
|
-
if (this.
|
|
4820
|
+
if (this.minLevel > this.maxLevel && this.afterFlushTasks.size === 0)
|
|
4606
4821
|
return;
|
|
4607
4822
|
this.isFlushing = true;
|
|
4608
4823
|
try {
|
|
@@ -4611,15 +4826,15 @@ var OIMComputeRuntime = class {
|
|
|
4611
4826
|
this.afterFlushTasks.clear();
|
|
4612
4827
|
for (let i = 0; i < snapshot.length; i++) snapshot[i]();
|
|
4613
4828
|
}
|
|
4614
|
-
if (this.
|
|
4829
|
+
if (this.minLevel > this.maxLevel) return;
|
|
4615
4830
|
let level = this.minLevel;
|
|
4616
4831
|
let max = this.maxLevel;
|
|
4617
4832
|
while (level <= max) {
|
|
4618
4833
|
for (; ; ) {
|
|
4619
|
-
const bucket = this.dirtyByLevel
|
|
4620
|
-
if (
|
|
4621
|
-
this.dirtyByLevel.delete(level);
|
|
4834
|
+
const bucket = this.dirtyByLevel[level];
|
|
4835
|
+
if (bucket === void 0 || bucket.size === 0) break;
|
|
4622
4836
|
const snapshot = Array.from(bucket);
|
|
4837
|
+
bucket.clear();
|
|
4623
4838
|
for (let i = 0; i < snapshot.length; i++) snapshot[i]();
|
|
4624
4839
|
}
|
|
4625
4840
|
if (this.maxLevel > max) max = this.maxLevel;
|
|
@@ -4627,24 +4842,38 @@ var OIMComputeRuntime = class {
|
|
|
4627
4842
|
}
|
|
4628
4843
|
} finally {
|
|
4629
4844
|
this.isFlushing = false;
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
this.isFlushScheduled = true;
|
|
4845
|
+
this.recomputePendingRange();
|
|
4846
|
+
}
|
|
4847
|
+
}
|
|
4848
|
+
recomputePendingRange() {
|
|
4849
|
+
let nextMin = Infinity;
|
|
4850
|
+
let nextMax = -Infinity;
|
|
4851
|
+
const buckets = this.dirtyByLevel;
|
|
4852
|
+
for (let i = 0; i < buckets.length; i++) {
|
|
4853
|
+
const bucket = buckets[i];
|
|
4854
|
+
if (bucket !== void 0 && bucket.size > 0) {
|
|
4855
|
+
if (i < nextMin) nextMin = i;
|
|
4856
|
+
if (i > nextMax) nextMax = i;
|
|
4643
4857
|
}
|
|
4644
4858
|
}
|
|
4859
|
+
this.minLevel = nextMin;
|
|
4860
|
+
this.maxLevel = nextMax;
|
|
4861
|
+
if (nextMin <= nextMax) this.isFlushScheduled = true;
|
|
4645
4862
|
}
|
|
4646
4863
|
};
|
|
4647
4864
|
|
|
4865
|
+
// src/dx/oimComputeRuntimeByQueue.ts
|
|
4866
|
+
var oimComputeRuntimeByQueue = /* @__PURE__ */ new WeakMap();
|
|
4867
|
+
|
|
4868
|
+
// src/dx/getOIMComputeRuntime.ts
|
|
4869
|
+
function getOIMComputeRuntime(queue) {
|
|
4870
|
+
const runtime = oimComputeRuntimeByQueue.get(queue);
|
|
4871
|
+
if (runtime !== void 0 && !runtime.isDestroyed) return runtime;
|
|
4872
|
+
const nextRuntime = new OIMComputeRuntime(queue);
|
|
4873
|
+
oimComputeRuntimeByQueue.set(queue, nextRuntime);
|
|
4874
|
+
return nextRuntime;
|
|
4875
|
+
}
|
|
4876
|
+
|
|
4648
4877
|
// src/modules/selector/core/OIMSelector.ts
|
|
4649
4878
|
var OIMSelector = class {
|
|
4650
4879
|
constructor(runtime, sourceDeps, computedDeps = []) {
|
|
@@ -4905,8 +5134,9 @@ var OIMEntitiesByIndexKeyArrayBasedSelector = class extends OIMSelector {
|
|
|
4905
5134
|
areEqual(prev, next) {
|
|
4906
5135
|
if (prev === next) return true;
|
|
4907
5136
|
if (prev.length !== next.length) return false;
|
|
4908
|
-
for (let i = 0; i < prev.length; i++)
|
|
5137
|
+
for (let i = 0; i < prev.length; i++) {
|
|
4909
5138
|
if (prev[i] !== next[i]) return false;
|
|
5139
|
+
}
|
|
4910
5140
|
return true;
|
|
4911
5141
|
}
|
|
4912
5142
|
};
|
|
@@ -4976,8 +5206,9 @@ var OIMEntitiesByIndexKeySetBasedSelector = class extends OIMSelector {
|
|
|
4976
5206
|
areEqual(prev, next) {
|
|
4977
5207
|
if (prev === next) return true;
|
|
4978
5208
|
if (prev.length !== next.length) return false;
|
|
4979
|
-
for (let i = 0; i < prev.length; i++)
|
|
5209
|
+
for (let i = 0; i < prev.length; i++) {
|
|
4980
5210
|
if (prev[i] !== next[i]) return false;
|
|
5211
|
+
}
|
|
4981
5212
|
return true;
|
|
4982
5213
|
}
|
|
4983
5214
|
};
|
|
@@ -5041,8 +5272,9 @@ var OIMEntitiesByGlobalIndexArrayBasedSelector = class extends OIMSelector {
|
|
|
5041
5272
|
areEqual(prev, next) {
|
|
5042
5273
|
if (prev === next) return true;
|
|
5043
5274
|
if (prev.length !== next.length) return false;
|
|
5044
|
-
for (let i = 0; i < prev.length; i++)
|
|
5275
|
+
for (let i = 0; i < prev.length; i++) {
|
|
5045
5276
|
if (prev[i] !== next[i]) return false;
|
|
5277
|
+
}
|
|
5046
5278
|
return true;
|
|
5047
5279
|
}
|
|
5048
5280
|
};
|
|
@@ -5107,8 +5339,9 @@ var OIMEntitiesByGlobalIndexSetBasedSelector = class extends OIMSelector {
|
|
|
5107
5339
|
areEqual(prev, next) {
|
|
5108
5340
|
if (prev === next) return true;
|
|
5109
5341
|
if (prev.length !== next.length) return false;
|
|
5110
|
-
for (let i = 0; i < prev.length; i++)
|
|
5342
|
+
for (let i = 0; i < prev.length; i++) {
|
|
5111
5343
|
if (prev[i] !== next[i]) return false;
|
|
5344
|
+
}
|
|
5112
5345
|
return true;
|
|
5113
5346
|
}
|
|
5114
5347
|
};
|
|
@@ -5117,7 +5350,7 @@ var OIMEntitiesByGlobalIndexSetBasedSelector = class extends OIMSelector {
|
|
|
5117
5350
|
var OIMCollectionSelectors = class {
|
|
5118
5351
|
constructor(queue, collection) {
|
|
5119
5352
|
this.collection = collection;
|
|
5120
|
-
this.runtime =
|
|
5353
|
+
this.runtime = getOIMComputeRuntime(queue);
|
|
5121
5354
|
}
|
|
5122
5355
|
byPk(pk) {
|
|
5123
5356
|
return new OIMCollectionByPkSelector(this.runtime, this.collection, pk);
|
|
@@ -5184,120 +5417,401 @@ var OIMCollectionSelectors = class {
|
|
|
5184
5417
|
}
|
|
5185
5418
|
};
|
|
5186
5419
|
|
|
5187
|
-
// src/
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
indexFactory,
|
|
5198
|
-
select,
|
|
5199
|
-
scope,
|
|
5200
|
-
destroy: () => scope.destroy()
|
|
5201
|
-
};
|
|
5202
|
-
}
|
|
5420
|
+
// src/modules/effect/core/OIMEffectDependencyKeyed.ts
|
|
5421
|
+
var OIMEffectDependencyKeyed = class {
|
|
5422
|
+
constructor(source, key) {
|
|
5423
|
+
this.source = source;
|
|
5424
|
+
this.key = key;
|
|
5425
|
+
}
|
|
5426
|
+
subscribe(onUpdate) {
|
|
5427
|
+
return this.source.subscribeOnKey(this.key, onUpdate);
|
|
5428
|
+
}
|
|
5429
|
+
};
|
|
5203
5430
|
|
|
5204
|
-
// src/modules/
|
|
5205
|
-
var
|
|
5206
|
-
constructor(
|
|
5207
|
-
this.
|
|
5208
|
-
this.lastEntitySnapshotByPk = /* @__PURE__ */ new Map();
|
|
5209
|
-
// PKs written through this wrapper during the current flush. Their fields are
|
|
5210
|
-
// already tracked accurately via trackPatch, so the flush-time external-write
|
|
5211
|
-
// handler skips them — no redundant diff + snapshot re-clone. Cleared per flush.
|
|
5212
|
-
this.writtenThroughThisFlush = /* @__PURE__ */ new Set();
|
|
5213
|
-
this.changedFieldsByPk = /* @__PURE__ */ new Map();
|
|
5214
|
-
this.changedPksByField = /* @__PURE__ */ new Map();
|
|
5215
|
-
this.onAfterFlush = () => {
|
|
5216
|
-
this.clear();
|
|
5217
|
-
this.writtenThroughThisFlush.clear();
|
|
5218
|
-
};
|
|
5219
|
-
this.onCollectionUpdate = (payload) => {
|
|
5220
|
-
if (this.isInWrite) return;
|
|
5221
|
-
if (payload.pks.length === 0) return;
|
|
5222
|
-
for (let i = 0; i < payload.pks.length; i++) {
|
|
5223
|
-
const pk = payload.pks[i];
|
|
5224
|
-
if (this.writtenThroughThisFlush.has(pk)) continue;
|
|
5225
|
-
this.trackExternalMutationByPk(pk);
|
|
5226
|
-
}
|
|
5227
|
-
};
|
|
5228
|
-
this.collection = collection;
|
|
5229
|
-
this.detectExternalMutations = opts?.detectExternalMutations !== false;
|
|
5230
|
-
this.selectPk = opts?.selectPk ?? (() => {
|
|
5231
|
-
throw new Error(
|
|
5232
|
-
`[OIMCollectionChangedFields]: selectPk was not provided. Use upsertOneByPk(...) or pass opts.selectPk.`
|
|
5233
|
-
);
|
|
5234
|
-
});
|
|
5235
|
-
this.changedPksEventEmitter = new OIMUpdateEventEmitter(
|
|
5236
|
-
queue,
|
|
5237
|
-
"after_flush"
|
|
5238
|
-
);
|
|
5239
|
-
this.changedFieldsEventEmitter = new OIMUpdateEventEmitter(queue, "after_flush");
|
|
5240
|
-
this.unsubscribeAfterFlush = queue.emitter.on(
|
|
5241
|
-
0 /* AFTER_FLUSH */,
|
|
5242
|
-
this.onAfterFlush
|
|
5243
|
-
);
|
|
5244
|
-
if (this.detectExternalMutations) {
|
|
5245
|
-
const maybeReactive = collection;
|
|
5246
|
-
this.unsubscribeFromCollectionEmitter = maybeReactive.subscribeOnAnyUpdate ? maybeReactive.subscribeOnAnyUpdate((pks) => {
|
|
5247
|
-
this.onCollectionUpdate({
|
|
5248
|
-
pks
|
|
5249
|
-
});
|
|
5250
|
-
}) : collection.emitter.on(
|
|
5251
|
-
0 /* UPDATE */,
|
|
5252
|
-
this.onCollectionUpdate
|
|
5253
|
-
);
|
|
5254
|
-
}
|
|
5431
|
+
// src/modules/effect/core/OIMEffectDependencyKeyedCollection.ts
|
|
5432
|
+
var OIMEffectDependencyKeyedCollection = class {
|
|
5433
|
+
constructor(collection, pk) {
|
|
5434
|
+
this.dep = new OIMEffectDependencyKeyed(collection, pk);
|
|
5255
5435
|
}
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
this.trackPatch(pk, patch);
|
|
5259
|
-
return this.collection.upsertOneByPk(pk, patch);
|
|
5260
|
-
});
|
|
5261
|
-
this.updateEntitySnapshot(pk);
|
|
5262
|
-
return slot;
|
|
5436
|
+
get source() {
|
|
5437
|
+
return this.dep.source;
|
|
5263
5438
|
}
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
const pk = this.selectPk(entity);
|
|
5267
|
-
this.trackPatch(pk, entity);
|
|
5268
|
-
return this.collection.upsertOne(entity);
|
|
5269
|
-
});
|
|
5270
|
-
this.updateEntitySnapshot(slot.pk);
|
|
5271
|
-
return slot;
|
|
5439
|
+
subscribe(onUpdate) {
|
|
5440
|
+
return this.dep.subscribe(onUpdate);
|
|
5272
5441
|
}
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
this.trackPatch(pk, entity);
|
|
5280
|
-
}
|
|
5281
|
-
return this.collection.upsertMany(entities);
|
|
5282
|
-
});
|
|
5283
|
-
for (let i = 0; i < pks.length; i++) this.updateEntitySnapshot(pks[i]);
|
|
5284
|
-
return slots;
|
|
5442
|
+
};
|
|
5443
|
+
|
|
5444
|
+
// src/modules/effect/core/OIMEffectDependencyKeyedIndex.ts
|
|
5445
|
+
var OIMEffectDependencyKeyedIndex = class {
|
|
5446
|
+
constructor(index, key) {
|
|
5447
|
+
this.dep = new OIMEffectDependencyKeyed(index, key);
|
|
5285
5448
|
}
|
|
5286
|
-
|
|
5287
|
-
return this.
|
|
5449
|
+
get source() {
|
|
5450
|
+
return this.dep.source;
|
|
5288
5451
|
}
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
if (!existing) return /* @__PURE__ */ new Set();
|
|
5292
|
-
return new Set(existing);
|
|
5452
|
+
subscribe(onUpdate) {
|
|
5453
|
+
return this.dep.subscribe(onUpdate);
|
|
5293
5454
|
}
|
|
5294
|
-
|
|
5295
|
-
|
|
5455
|
+
};
|
|
5456
|
+
|
|
5457
|
+
// src/modules/effect/core/OIMEffectDependencyKeyedObject.ts
|
|
5458
|
+
var OIMEffectDependencyKeyedObject = class {
|
|
5459
|
+
constructor(object, key) {
|
|
5460
|
+
this.dep = new OIMEffectDependencyKeyed(object, key);
|
|
5296
5461
|
}
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5462
|
+
get source() {
|
|
5463
|
+
return this.dep.source;
|
|
5464
|
+
}
|
|
5465
|
+
subscribe(onUpdate) {
|
|
5466
|
+
return this.dep.subscribe(onUpdate);
|
|
5467
|
+
}
|
|
5468
|
+
};
|
|
5469
|
+
|
|
5470
|
+
// src/dx/on.ts
|
|
5471
|
+
var on = {
|
|
5472
|
+
/** Depend on one PK of a collection. */
|
|
5473
|
+
collection: (collection, pk) => new OIMEffectDependencyKeyedCollection(collection, pk),
|
|
5474
|
+
/** Depend on one key of an index. */
|
|
5475
|
+
index: (index, key) => new OIMEffectDependencyKeyedIndex(index, key),
|
|
5476
|
+
/** Depend on one key of a reactive object. */
|
|
5477
|
+
object: (object, key) => new OIMEffectDependencyKeyedObject(object, key),
|
|
5478
|
+
/** Depend on another computed. */
|
|
5479
|
+
computed: (computed) => new OIMEffectDependencyComputed(computed)
|
|
5480
|
+
};
|
|
5481
|
+
|
|
5482
|
+
// src/modules/effect/core/OIMEffect.ts
|
|
5483
|
+
var OIMEffect = class {
|
|
5484
|
+
constructor(runtime, opts, level) {
|
|
5485
|
+
this.sourceDeps = [];
|
|
5486
|
+
this.computedDeps = [];
|
|
5487
|
+
this.sourceUnsubscribers = [];
|
|
5488
|
+
this.computedUnsubscribers = [];
|
|
5489
|
+
this.isResubscribeEnqueued = false;
|
|
5490
|
+
this.isTemporarilyUnsubscribedForFlush = false;
|
|
5491
|
+
this.isScheduled = false;
|
|
5492
|
+
this.runTask = () => {
|
|
5493
|
+
this.isScheduled = false;
|
|
5494
|
+
this.dequeueScheduled = void 0;
|
|
5495
|
+
this.runOnce();
|
|
5496
|
+
};
|
|
5497
|
+
this.onSourceInvalidate = () => {
|
|
5498
|
+
this.onUpdate?.();
|
|
5499
|
+
if (!this.isTemporarilyUnsubscribedForFlush) {
|
|
5500
|
+
this.isTemporarilyUnsubscribedForFlush = true;
|
|
5501
|
+
this.unsubscribeFromSourceDeps();
|
|
5502
|
+
this.ensureResubscribeAfterFlush();
|
|
5503
|
+
}
|
|
5504
|
+
if (this.isScheduled) return;
|
|
5505
|
+
this.isScheduled = true;
|
|
5506
|
+
this.dequeueScheduled = this.runtime.schedule(this.runTask, this.level);
|
|
5507
|
+
};
|
|
5508
|
+
this.onComputedInvalidate = () => {
|
|
5509
|
+
this.onUpdate?.();
|
|
5510
|
+
if (this.isScheduled) return;
|
|
5511
|
+
this.isScheduled = true;
|
|
5512
|
+
this.dequeueScheduled = this.runtime.schedule(this.runTask, this.level);
|
|
5513
|
+
};
|
|
5514
|
+
this.onAfterFlush = () => {
|
|
5515
|
+
if (!this.isResubscribeEnqueued) return;
|
|
5516
|
+
this.isResubscribeEnqueued = false;
|
|
5517
|
+
this.dequeueResubscribe = void 0;
|
|
5518
|
+
this.isTemporarilyUnsubscribedForFlush = false;
|
|
5519
|
+
if (this.sourceUnsubscribers.length === 0) {
|
|
5520
|
+
for (const dep of this.sourceDeps) {
|
|
5521
|
+
this.sourceUnsubscribers.push(
|
|
5522
|
+
dep.subscribe(this.onSourceInvalidate)
|
|
5523
|
+
);
|
|
5524
|
+
}
|
|
5525
|
+
}
|
|
5526
|
+
};
|
|
5527
|
+
this.runtime = runtime;
|
|
5528
|
+
this.onUpdate = opts.onUpdate;
|
|
5529
|
+
this.run = opts.run;
|
|
5530
|
+
this.deps = opts.deps ?? [];
|
|
5531
|
+
for (const dep of this.deps) {
|
|
5532
|
+
if (dep instanceof OIMEffectDependencyComputed) {
|
|
5533
|
+
this.computedDeps.push(dep);
|
|
5534
|
+
} else {
|
|
5535
|
+
this.sourceDeps.push(dep);
|
|
5536
|
+
}
|
|
5537
|
+
}
|
|
5538
|
+
this.level = level ?? this.runtime.computeLevel(this.deps);
|
|
5539
|
+
this.subscribeToDeps();
|
|
5540
|
+
}
|
|
5541
|
+
destroy() {
|
|
5542
|
+
if (this.dequeueScheduled) {
|
|
5543
|
+
this.dequeueScheduled();
|
|
5544
|
+
this.dequeueScheduled = void 0;
|
|
5545
|
+
}
|
|
5546
|
+
this.unsubscribeFromAllDeps();
|
|
5547
|
+
if (this.dequeueResubscribe) {
|
|
5548
|
+
this.dequeueResubscribe();
|
|
5549
|
+
this.dequeueResubscribe = void 0;
|
|
5550
|
+
}
|
|
5551
|
+
this.isResubscribeEnqueued = false;
|
|
5552
|
+
this.isTemporarilyUnsubscribedForFlush = false;
|
|
5553
|
+
}
|
|
5554
|
+
runOnce() {
|
|
5555
|
+
this.run();
|
|
5556
|
+
}
|
|
5557
|
+
subscribeToDeps() {
|
|
5558
|
+
if (this.sourceUnsubscribers.length > 0 || this.computedUnsubscribers.length > 0)
|
|
5559
|
+
return;
|
|
5560
|
+
for (const dep of this.sourceDeps) {
|
|
5561
|
+
this.sourceUnsubscribers.push(
|
|
5562
|
+
dep.subscribe(this.onSourceInvalidate)
|
|
5563
|
+
);
|
|
5564
|
+
}
|
|
5565
|
+
for (const dep of this.computedDeps) {
|
|
5566
|
+
this.computedUnsubscribers.push(
|
|
5567
|
+
dep.subscribe(this.onComputedInvalidate)
|
|
5568
|
+
);
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5571
|
+
unsubscribeFromSourceDeps() {
|
|
5572
|
+
if (this.sourceUnsubscribers.length === 0) return;
|
|
5573
|
+
for (const unsubscribe of this.sourceUnsubscribers) unsubscribe();
|
|
5574
|
+
this.sourceUnsubscribers = [];
|
|
5575
|
+
}
|
|
5576
|
+
unsubscribeFromAllDeps() {
|
|
5577
|
+
this.unsubscribeFromSourceDeps();
|
|
5578
|
+
if (this.computedUnsubscribers.length === 0) return;
|
|
5579
|
+
for (const unsubscribe of this.computedUnsubscribers) unsubscribe();
|
|
5580
|
+
this.computedUnsubscribers = [];
|
|
5581
|
+
}
|
|
5582
|
+
ensureResubscribeAfterFlush() {
|
|
5583
|
+
if (this.isResubscribeEnqueued) return;
|
|
5584
|
+
this.isResubscribeEnqueued = true;
|
|
5585
|
+
this.dequeueResubscribe = this.runtime.scheduleAfterFlush(
|
|
5586
|
+
this.onAfterFlush
|
|
5587
|
+
);
|
|
5588
|
+
}
|
|
5589
|
+
};
|
|
5590
|
+
|
|
5591
|
+
// src/modules/computed/enums/EOIMComputedEventType.ts
|
|
5592
|
+
var EOIMComputedEventType = /* @__PURE__ */ ((EOIMComputedEventType2) => {
|
|
5593
|
+
EOIMComputedEventType2["UPDATE"] = "update";
|
|
5594
|
+
return EOIMComputedEventType2;
|
|
5595
|
+
})(EOIMComputedEventType || {});
|
|
5596
|
+
|
|
5597
|
+
// src/modules/computed/core/OIMComputed.ts
|
|
5598
|
+
var OIMComputed = class {
|
|
5599
|
+
constructor(runtime, opts) {
|
|
5600
|
+
this.emitter = new OIMEventEmitter();
|
|
5601
|
+
this.hasValue = false;
|
|
5602
|
+
this.isDirty = true;
|
|
5603
|
+
this.runtime = runtime;
|
|
5604
|
+
this.compute = opts.compute;
|
|
5605
|
+
this.compare = opts.compare ?? Object.is;
|
|
5606
|
+
this._deps = opts.deps ?? [];
|
|
5607
|
+
this.updateEventEmitter = new OIMUpdateEventEmitter(
|
|
5608
|
+
this.runtime.queue,
|
|
5609
|
+
"immediate"
|
|
5610
|
+
);
|
|
5611
|
+
const level = this.runtime.computeLevel(this._deps);
|
|
5612
|
+
this.runtime.registerLevel(this, level);
|
|
5613
|
+
this.effect = new OIMEffect(
|
|
5614
|
+
this.runtime,
|
|
5615
|
+
{
|
|
5616
|
+
deps: this._deps,
|
|
5617
|
+
onUpdate: () => {
|
|
5618
|
+
this.isDirty = true;
|
|
5619
|
+
},
|
|
5620
|
+
run: () => {
|
|
5621
|
+
this.recomputeAndEmitIfChanged();
|
|
5622
|
+
}
|
|
5623
|
+
},
|
|
5624
|
+
level
|
|
5625
|
+
);
|
|
5626
|
+
}
|
|
5627
|
+
get needsRecompute() {
|
|
5628
|
+
return this.isDirty;
|
|
5629
|
+
}
|
|
5630
|
+
get isReady() {
|
|
5631
|
+
return this.hasValue;
|
|
5632
|
+
}
|
|
5633
|
+
get deps() {
|
|
5634
|
+
return this._deps;
|
|
5635
|
+
}
|
|
5636
|
+
get() {
|
|
5637
|
+
this.recomputeAndEmitIfChanged();
|
|
5638
|
+
return this.value;
|
|
5639
|
+
}
|
|
5640
|
+
getIfReady() {
|
|
5641
|
+
return this.hasValue ? this.value : void 0;
|
|
5642
|
+
}
|
|
5643
|
+
destroy() {
|
|
5644
|
+
this.effect.destroy();
|
|
5645
|
+
this.updateEventEmitter.destroy();
|
|
5646
|
+
this.emitter.offAll();
|
|
5647
|
+
}
|
|
5648
|
+
recomputeAndEmitIfChanged() {
|
|
5649
|
+
if (!this.isDirty) return;
|
|
5650
|
+
const prev = this.value;
|
|
5651
|
+
const hadPrev = this.hasValue;
|
|
5652
|
+
const next = this.compute();
|
|
5653
|
+
this.value = next;
|
|
5654
|
+
this.hasValue = true;
|
|
5655
|
+
this.isDirty = false;
|
|
5656
|
+
const changed = !hadPrev || !this.compare(prev, next);
|
|
5657
|
+
if (!changed) return;
|
|
5658
|
+
this.emitter.emit("update" /* UPDATE */, {
|
|
5659
|
+
keys: ["value"]
|
|
5660
|
+
});
|
|
5661
|
+
this.updateEventEmitter.markUpdatedKey("value");
|
|
5662
|
+
}
|
|
5663
|
+
};
|
|
5664
|
+
|
|
5665
|
+
// src/dx/OIMCollectionKit.ts
|
|
5666
|
+
function createOIMCollectionKit(queue, opts) {
|
|
5667
|
+
const collection = new OIMReactiveCollection(queue, opts);
|
|
5668
|
+
const indexFactory = new OIMCollectionIndexFactory(queue, collection);
|
|
5669
|
+
const select = new OIMCollectionSelectors(queue, collection);
|
|
5670
|
+
const runtime = getOIMComputeRuntime(queue);
|
|
5671
|
+
const scope = new OIMDisposeScope();
|
|
5672
|
+
scope.add(collection);
|
|
5673
|
+
return {
|
|
5674
|
+
queue,
|
|
5675
|
+
collection,
|
|
5676
|
+
indexFactory,
|
|
5677
|
+
select,
|
|
5678
|
+
on,
|
|
5679
|
+
computed: (deps, compute, options) => {
|
|
5680
|
+
const computed = new OIMComputed(runtime, {
|
|
5681
|
+
deps,
|
|
5682
|
+
compute,
|
|
5683
|
+
compare: options?.compare
|
|
5684
|
+
});
|
|
5685
|
+
scope.add(computed);
|
|
5686
|
+
return computed;
|
|
5687
|
+
},
|
|
5688
|
+
effect: (deps, run, options) => {
|
|
5689
|
+
const effect = new OIMEffect(runtime, {
|
|
5690
|
+
deps,
|
|
5691
|
+
run,
|
|
5692
|
+
onUpdate: options?.onUpdate
|
|
5693
|
+
});
|
|
5694
|
+
scope.add(effect);
|
|
5695
|
+
return effect;
|
|
5696
|
+
},
|
|
5697
|
+
scope,
|
|
5698
|
+
destroy: () => scope.destroy()
|
|
5699
|
+
};
|
|
5700
|
+
}
|
|
5701
|
+
|
|
5702
|
+
// src/dx/peekOIMComputeRuntime.ts
|
|
5703
|
+
function peekOIMComputeRuntime(queue) {
|
|
5704
|
+
const runtime = oimComputeRuntimeByQueue.get(queue);
|
|
5705
|
+
return runtime === void 0 || runtime.isDestroyed ? void 0 : runtime;
|
|
5706
|
+
}
|
|
5707
|
+
|
|
5708
|
+
// src/dx/setOIMComputeRuntime.ts
|
|
5709
|
+
function setOIMComputeRuntime(queue, runtime) {
|
|
5710
|
+
if (runtime.queue !== queue) {
|
|
5711
|
+
throw new Error(
|
|
5712
|
+
"setOIMComputeRuntime: the runtime is attached to a different queue. A runtime drains on its own queue and would never run here."
|
|
5713
|
+
);
|
|
5714
|
+
}
|
|
5715
|
+
oimComputeRuntimeByQueue.set(queue, runtime);
|
|
5716
|
+
}
|
|
5717
|
+
|
|
5718
|
+
// src/modules/wrapper/collection/OIMCollectionChangedFields.ts
|
|
5719
|
+
var OIMCollectionChangedFields = class {
|
|
5720
|
+
constructor(queue, collection, opts) {
|
|
5721
|
+
this.isInWrite = false;
|
|
5722
|
+
this.lastEntitySnapshotByPk = /* @__PURE__ */ new Map();
|
|
5723
|
+
// PKs written through this wrapper during the current flush. Their fields are
|
|
5724
|
+
// already tracked accurately via trackPatch, so the flush-time external-write
|
|
5725
|
+
// handler skips them — no redundant diff + snapshot re-clone. Cleared per flush.
|
|
5726
|
+
this.writtenThroughThisFlush = /* @__PURE__ */ new Set();
|
|
5727
|
+
this.changedFieldsByPk = /* @__PURE__ */ new Map();
|
|
5728
|
+
this.changedPksByField = /* @__PURE__ */ new Map();
|
|
5729
|
+
this.onAfterFlush = () => {
|
|
5730
|
+
this.clear();
|
|
5731
|
+
this.writtenThroughThisFlush.clear();
|
|
5732
|
+
};
|
|
5733
|
+
this.onCollectionUpdate = (payload) => {
|
|
5734
|
+
if (this.isInWrite) return;
|
|
5735
|
+
if (payload.pks.length === 0) return;
|
|
5736
|
+
for (let i = 0; i < payload.pks.length; i++) {
|
|
5737
|
+
const pk = payload.pks[i];
|
|
5738
|
+
if (this.writtenThroughThisFlush.has(pk)) continue;
|
|
5739
|
+
this.trackExternalMutationByPk(pk);
|
|
5740
|
+
}
|
|
5741
|
+
};
|
|
5742
|
+
this.collection = collection;
|
|
5743
|
+
this.detectExternalMutations = opts?.detectExternalMutations !== false;
|
|
5744
|
+
this.selectPk = opts?.selectPk ?? (() => {
|
|
5745
|
+
throw new Error(
|
|
5746
|
+
`[OIMCollectionChangedFields]: selectPk was not provided. Use upsertOneByPk(...) or pass opts.selectPk.`
|
|
5747
|
+
);
|
|
5748
|
+
});
|
|
5749
|
+
this.changedPksEventEmitter = new OIMUpdateEventEmitter(
|
|
5750
|
+
queue,
|
|
5751
|
+
"after_flush"
|
|
5752
|
+
);
|
|
5753
|
+
this.changedFieldsEventEmitter = new OIMUpdateEventEmitter(queue, "after_flush");
|
|
5754
|
+
this.unsubscribeAfterFlush = queue.emitter.on(
|
|
5755
|
+
0 /* AFTER_FLUSH */,
|
|
5756
|
+
this.onAfterFlush
|
|
5757
|
+
);
|
|
5758
|
+
if (this.detectExternalMutations) {
|
|
5759
|
+
const maybeReactive = collection;
|
|
5760
|
+
this.unsubscribeFromCollectionEmitter = maybeReactive.subscribeOnAnyUpdate ? maybeReactive.subscribeOnAnyUpdate((pks) => {
|
|
5761
|
+
this.onCollectionUpdate({
|
|
5762
|
+
pks
|
|
5763
|
+
});
|
|
5764
|
+
}) : collection.emitter.on(
|
|
5765
|
+
0 /* UPDATE */,
|
|
5766
|
+
this.onCollectionUpdate
|
|
5767
|
+
);
|
|
5768
|
+
}
|
|
5769
|
+
}
|
|
5770
|
+
upsertOneByPk(pk, patch) {
|
|
5771
|
+
const slot = this.withWrite(() => {
|
|
5772
|
+
this.trackPatch(pk, patch);
|
|
5773
|
+
return this.collection.upsertOneByPk(pk, patch);
|
|
5774
|
+
});
|
|
5775
|
+
this.updateEntitySnapshot(pk);
|
|
5776
|
+
return slot;
|
|
5777
|
+
}
|
|
5778
|
+
upsertOne(entity) {
|
|
5779
|
+
const slot = this.withWrite(() => {
|
|
5780
|
+
const pk = this.selectPk(entity);
|
|
5781
|
+
this.trackPatch(pk, entity);
|
|
5782
|
+
return this.collection.upsertOne(entity);
|
|
5783
|
+
});
|
|
5784
|
+
this.updateEntitySnapshot(slot.pk);
|
|
5785
|
+
return slot;
|
|
5786
|
+
}
|
|
5787
|
+
upsertMany(entities) {
|
|
5788
|
+
const pks = [];
|
|
5789
|
+
const slots = this.withWrite(() => {
|
|
5790
|
+
for (const entity of entities) {
|
|
5791
|
+
const pk = this.selectPk(entity);
|
|
5792
|
+
pks.push(pk);
|
|
5793
|
+
this.trackPatch(pk, entity);
|
|
5794
|
+
}
|
|
5795
|
+
return this.collection.upsertMany(entities);
|
|
5796
|
+
});
|
|
5797
|
+
for (let i = 0; i < pks.length; i++) this.updateEntitySnapshot(pks[i]);
|
|
5798
|
+
return slots;
|
|
5799
|
+
}
|
|
5800
|
+
getChangedFieldsByPk(pk) {
|
|
5801
|
+
return this.changedFieldsByPk.get(pk) ?? /* @__PURE__ */ new Set();
|
|
5802
|
+
}
|
|
5803
|
+
consumeChangedFieldsByPk(pk) {
|
|
5804
|
+
const existing = this.changedFieldsByPk.get(pk);
|
|
5805
|
+
if (!existing) return /* @__PURE__ */ new Set();
|
|
5806
|
+
return new Set(existing);
|
|
5807
|
+
}
|
|
5808
|
+
getChangedPksByField(field) {
|
|
5809
|
+
return this.changedPksByField.get(field) ?? /* @__PURE__ */ new Set();
|
|
5810
|
+
}
|
|
5811
|
+
consumeChangedPksByField(field) {
|
|
5812
|
+
const existing = this.changedPksByField.get(field);
|
|
5813
|
+
if (!existing) return /* @__PURE__ */ new Set();
|
|
5814
|
+
return new Set(existing);
|
|
5301
5815
|
}
|
|
5302
5816
|
clear() {
|
|
5303
5817
|
this.changedFieldsByPk.clear();
|
|
@@ -5343,8 +5857,9 @@ var OIMCollectionChangedFields = class {
|
|
|
5343
5857
|
Object.keys(nextObj).forEach((k) => keys.add(k));
|
|
5344
5858
|
const changed = [];
|
|
5345
5859
|
keys.forEach((k) => {
|
|
5346
|
-
if (prevObj[k] !== nextObj[k])
|
|
5860
|
+
if (prevObj[k] !== nextObj[k]) {
|
|
5347
5861
|
changed.push(k);
|
|
5862
|
+
}
|
|
5348
5863
|
});
|
|
5349
5864
|
return changed;
|
|
5350
5865
|
}
|
|
@@ -5510,10 +6025,15 @@ var OIMOrderedListMappedCommandStream = class _OIMOrderedListMappedCommandStream
|
|
|
5510
6025
|
try {
|
|
5511
6026
|
const subs = this.subscribers.get(key);
|
|
5512
6027
|
if (subs && subs.size > 0) {
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
6028
|
+
if (subs.size === 1) {
|
|
6029
|
+
const only = subs.values().next().value;
|
|
6030
|
+
if (only) only();
|
|
6031
|
+
} else {
|
|
6032
|
+
const snapshot = Array.from(subs);
|
|
6033
|
+
for (let s = 0; s < snapshot.length; s++) {
|
|
6034
|
+
const handler = snapshot[s];
|
|
6035
|
+
if (subs.has(handler)) handler();
|
|
6036
|
+
}
|
|
5517
6037
|
}
|
|
5518
6038
|
}
|
|
5519
6039
|
} finally {
|
|
@@ -5807,10 +6327,13 @@ var OIMEventQueueSchedulerAnimationFrame = class extends OIMEventQueueScheduler
|
|
|
5807
6327
|
this.flush();
|
|
5808
6328
|
});
|
|
5809
6329
|
} else {
|
|
5810
|
-
this.frameId =
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
6330
|
+
this.frameId = this.unref(
|
|
6331
|
+
setTimeout(() => {
|
|
6332
|
+
this.frameId = void 0;
|
|
6333
|
+
this.flush();
|
|
6334
|
+
}, 16)
|
|
6335
|
+
// ~60fps
|
|
6336
|
+
);
|
|
5814
6337
|
}
|
|
5815
6338
|
}
|
|
5816
6339
|
cancel() {
|
|
@@ -5856,10 +6379,12 @@ var OIMEventQueueSchedulerTimeout = class extends OIMEventQueueScheduler {
|
|
|
5856
6379
|
}
|
|
5857
6380
|
schedule() {
|
|
5858
6381
|
if (this.timeoutId !== void 0) return;
|
|
5859
|
-
this.timeoutId =
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
6382
|
+
this.timeoutId = this.unref(
|
|
6383
|
+
setTimeout(() => {
|
|
6384
|
+
this.timeoutId = void 0;
|
|
6385
|
+
this.flush();
|
|
6386
|
+
}, this.delay)
|
|
6387
|
+
);
|
|
5863
6388
|
}
|
|
5864
6389
|
cancel() {
|
|
5865
6390
|
if (this.timeoutId === void 0) return;
|
|
@@ -5893,13 +6418,13 @@ var OIMEventQueueSchedulerImmediate = class extends OIMEventQueueScheduler {
|
|
|
5893
6418
|
this.flush();
|
|
5894
6419
|
};
|
|
5895
6420
|
if (this.useSetImmediate) {
|
|
5896
|
-
this.immediateId = setImmediate(callback);
|
|
6421
|
+
this.immediateId = this.unref(setImmediate(callback));
|
|
5897
6422
|
} else if (this.useMessageChannel && this.messageChannel) {
|
|
5898
6423
|
this.immediateId = 1;
|
|
5899
6424
|
this.pendingCallback = callback;
|
|
5900
6425
|
this.messageChannel.port1.postMessage(null);
|
|
5901
6426
|
} else {
|
|
5902
|
-
this.immediateId = setTimeout(callback, 0);
|
|
6427
|
+
this.immediateId = this.unref(setTimeout(callback, 0));
|
|
5903
6428
|
}
|
|
5904
6429
|
}
|
|
5905
6430
|
cancel() {
|
|
@@ -5992,242 +6517,6 @@ var OIMDBSettings = class {
|
|
|
5992
6517
|
OIMDBSettings.UPDATED_KEYS_INDEX_KEY = "__updatedKeys__";
|
|
5993
6518
|
OIMDBSettings.FLUSHING_KEYS_INDEX_KEY = "__flushingKeys__";
|
|
5994
6519
|
|
|
5995
|
-
// src/modules/effect/core/OIMEffectDependencyComputed.ts
|
|
5996
|
-
var OIMEffectDependencyComputed = class {
|
|
5997
|
-
constructor(source) {
|
|
5998
|
-
this.source = source;
|
|
5999
|
-
}
|
|
6000
|
-
subscribe(onUpdate) {
|
|
6001
|
-
return this.source.emitter.on("update", onUpdate);
|
|
6002
|
-
}
|
|
6003
|
-
};
|
|
6004
|
-
|
|
6005
|
-
// src/modules/effect/core/OIMEffect.ts
|
|
6006
|
-
var OIMEffect = class {
|
|
6007
|
-
constructor(runtime, opts) {
|
|
6008
|
-
this.sourceDeps = [];
|
|
6009
|
-
this.computedDeps = [];
|
|
6010
|
-
this.sourceUnsubscribers = [];
|
|
6011
|
-
this.computedUnsubscribers = [];
|
|
6012
|
-
this.isResubscribeEnqueued = false;
|
|
6013
|
-
this.isTemporarilyUnsubscribedForFlush = false;
|
|
6014
|
-
this.isScheduled = false;
|
|
6015
|
-
this.runTask = () => {
|
|
6016
|
-
this.isScheduled = false;
|
|
6017
|
-
this.dequeueScheduled = void 0;
|
|
6018
|
-
this.runOnce();
|
|
6019
|
-
};
|
|
6020
|
-
this.onSourceInvalidate = () => {
|
|
6021
|
-
this.onUpdate?.();
|
|
6022
|
-
if (!this.isTemporarilyUnsubscribedForFlush) {
|
|
6023
|
-
this.isTemporarilyUnsubscribedForFlush = true;
|
|
6024
|
-
this.unsubscribeFromSourceDeps();
|
|
6025
|
-
this.ensureResubscribeAfterFlush();
|
|
6026
|
-
}
|
|
6027
|
-
if (this.isScheduled) return;
|
|
6028
|
-
this.isScheduled = true;
|
|
6029
|
-
this.dequeueScheduled = this.runtime.schedule(this.runTask);
|
|
6030
|
-
};
|
|
6031
|
-
this.onComputedInvalidate = () => {
|
|
6032
|
-
this.onUpdate?.();
|
|
6033
|
-
if (this.isScheduled) return;
|
|
6034
|
-
this.isScheduled = true;
|
|
6035
|
-
this.dequeueScheduled = this.runtime.schedule(this.runTask);
|
|
6036
|
-
};
|
|
6037
|
-
this.onAfterFlush = () => {
|
|
6038
|
-
if (!this.isResubscribeEnqueued) return;
|
|
6039
|
-
this.isResubscribeEnqueued = false;
|
|
6040
|
-
this.dequeueResubscribe = void 0;
|
|
6041
|
-
this.isTemporarilyUnsubscribedForFlush = false;
|
|
6042
|
-
if (this.sourceUnsubscribers.length === 0) {
|
|
6043
|
-
for (const dep of this.sourceDeps) {
|
|
6044
|
-
this.sourceUnsubscribers.push(
|
|
6045
|
-
dep.subscribe(this.onSourceInvalidate)
|
|
6046
|
-
);
|
|
6047
|
-
}
|
|
6048
|
-
}
|
|
6049
|
-
};
|
|
6050
|
-
this.runtime = runtime;
|
|
6051
|
-
this.onUpdate = opts.onUpdate;
|
|
6052
|
-
this.run = opts.run;
|
|
6053
|
-
this.deps = opts.deps ?? [];
|
|
6054
|
-
for (const dep of this.deps) {
|
|
6055
|
-
if (dep instanceof OIMEffectDependencyComputed) {
|
|
6056
|
-
this.computedDeps.push(dep);
|
|
6057
|
-
} else {
|
|
6058
|
-
this.sourceDeps.push(dep);
|
|
6059
|
-
}
|
|
6060
|
-
}
|
|
6061
|
-
this.subscribeToDeps();
|
|
6062
|
-
}
|
|
6063
|
-
destroy() {
|
|
6064
|
-
if (this.dequeueScheduled) {
|
|
6065
|
-
this.dequeueScheduled();
|
|
6066
|
-
this.dequeueScheduled = void 0;
|
|
6067
|
-
}
|
|
6068
|
-
this.unsubscribeFromAllDeps();
|
|
6069
|
-
if (this.dequeueResubscribe) {
|
|
6070
|
-
this.dequeueResubscribe();
|
|
6071
|
-
this.dequeueResubscribe = void 0;
|
|
6072
|
-
}
|
|
6073
|
-
this.isResubscribeEnqueued = false;
|
|
6074
|
-
this.isTemporarilyUnsubscribedForFlush = false;
|
|
6075
|
-
}
|
|
6076
|
-
runOnce() {
|
|
6077
|
-
this.run();
|
|
6078
|
-
}
|
|
6079
|
-
subscribeToDeps() {
|
|
6080
|
-
if (this.sourceUnsubscribers.length > 0 || this.computedUnsubscribers.length > 0)
|
|
6081
|
-
return;
|
|
6082
|
-
for (const dep of this.sourceDeps) {
|
|
6083
|
-
this.sourceUnsubscribers.push(
|
|
6084
|
-
dep.subscribe(this.onSourceInvalidate)
|
|
6085
|
-
);
|
|
6086
|
-
}
|
|
6087
|
-
for (const dep of this.computedDeps) {
|
|
6088
|
-
this.computedUnsubscribers.push(
|
|
6089
|
-
dep.subscribe(this.onComputedInvalidate)
|
|
6090
|
-
);
|
|
6091
|
-
}
|
|
6092
|
-
}
|
|
6093
|
-
unsubscribeFromSourceDeps() {
|
|
6094
|
-
if (this.sourceUnsubscribers.length === 0) return;
|
|
6095
|
-
for (const unsubscribe of this.sourceUnsubscribers) unsubscribe();
|
|
6096
|
-
this.sourceUnsubscribers = [];
|
|
6097
|
-
}
|
|
6098
|
-
unsubscribeFromAllDeps() {
|
|
6099
|
-
this.unsubscribeFromSourceDeps();
|
|
6100
|
-
if (this.computedUnsubscribers.length === 0) return;
|
|
6101
|
-
for (const unsubscribe of this.computedUnsubscribers) unsubscribe();
|
|
6102
|
-
this.computedUnsubscribers = [];
|
|
6103
|
-
}
|
|
6104
|
-
ensureResubscribeAfterFlush() {
|
|
6105
|
-
if (this.isResubscribeEnqueued) return;
|
|
6106
|
-
this.isResubscribeEnqueued = true;
|
|
6107
|
-
this.dequeueResubscribe = this.runtime.scheduleAfterFlush(
|
|
6108
|
-
this.onAfterFlush
|
|
6109
|
-
);
|
|
6110
|
-
}
|
|
6111
|
-
};
|
|
6112
|
-
|
|
6113
|
-
// src/modules/computed/enums/EOIMComputedEventType.ts
|
|
6114
|
-
var EOIMComputedEventType = /* @__PURE__ */ ((EOIMComputedEventType2) => {
|
|
6115
|
-
EOIMComputedEventType2["UPDATE"] = "update";
|
|
6116
|
-
return EOIMComputedEventType2;
|
|
6117
|
-
})(EOIMComputedEventType || {});
|
|
6118
|
-
|
|
6119
|
-
// src/modules/computed/core/OIMComputed.ts
|
|
6120
|
-
var OIMComputed = class {
|
|
6121
|
-
constructor(runtime, opts) {
|
|
6122
|
-
this.emitter = new OIMEventEmitter();
|
|
6123
|
-
this.hasValue = false;
|
|
6124
|
-
this.isDirty = true;
|
|
6125
|
-
this.runtime = runtime;
|
|
6126
|
-
this.compute = opts.compute;
|
|
6127
|
-
this.compare = opts.compare ?? Object.is;
|
|
6128
|
-
this._deps = opts.deps ?? [];
|
|
6129
|
-
this.updateEventEmitter = new OIMUpdateEventEmitter(
|
|
6130
|
-
this.runtime.queue,
|
|
6131
|
-
"immediate"
|
|
6132
|
-
);
|
|
6133
|
-
this.effect = new OIMEffect(this.runtime, {
|
|
6134
|
-
deps: this._deps,
|
|
6135
|
-
onUpdate: () => {
|
|
6136
|
-
this.isDirty = true;
|
|
6137
|
-
},
|
|
6138
|
-
run: () => {
|
|
6139
|
-
this.recomputeAndEmitIfChanged();
|
|
6140
|
-
}
|
|
6141
|
-
});
|
|
6142
|
-
}
|
|
6143
|
-
get needsRecompute() {
|
|
6144
|
-
return this.isDirty;
|
|
6145
|
-
}
|
|
6146
|
-
get isReady() {
|
|
6147
|
-
return this.hasValue;
|
|
6148
|
-
}
|
|
6149
|
-
get deps() {
|
|
6150
|
-
return this._deps;
|
|
6151
|
-
}
|
|
6152
|
-
get() {
|
|
6153
|
-
this.recomputeAndEmitIfChanged();
|
|
6154
|
-
return this.value;
|
|
6155
|
-
}
|
|
6156
|
-
getIfReady() {
|
|
6157
|
-
return this.hasValue ? this.value : void 0;
|
|
6158
|
-
}
|
|
6159
|
-
destroy() {
|
|
6160
|
-
this.effect.destroy();
|
|
6161
|
-
this.updateEventEmitter.destroy();
|
|
6162
|
-
this.emitter.offAll();
|
|
6163
|
-
}
|
|
6164
|
-
recomputeAndEmitIfChanged() {
|
|
6165
|
-
if (!this.isDirty) return;
|
|
6166
|
-
const prev = this.value;
|
|
6167
|
-
const hadPrev = this.hasValue;
|
|
6168
|
-
const next = this.compute();
|
|
6169
|
-
this.value = next;
|
|
6170
|
-
this.hasValue = true;
|
|
6171
|
-
this.isDirty = false;
|
|
6172
|
-
const changed = !hadPrev || !this.compare(prev, next);
|
|
6173
|
-
if (!changed) return;
|
|
6174
|
-
this.emitter.emit("update" /* UPDATE */, {
|
|
6175
|
-
keys: ["value"]
|
|
6176
|
-
});
|
|
6177
|
-
this.updateEventEmitter.markUpdatedKey("value");
|
|
6178
|
-
}
|
|
6179
|
-
};
|
|
6180
|
-
|
|
6181
|
-
// src/modules/effect/core/OIMEffectDependencyKeyed.ts
|
|
6182
|
-
var OIMEffectDependencyKeyed = class {
|
|
6183
|
-
constructor(source, key) {
|
|
6184
|
-
this.source = source;
|
|
6185
|
-
this.key = key;
|
|
6186
|
-
}
|
|
6187
|
-
subscribe(onUpdate) {
|
|
6188
|
-
return this.source.subscribeOnKey(this.key, onUpdate);
|
|
6189
|
-
}
|
|
6190
|
-
};
|
|
6191
|
-
|
|
6192
|
-
// src/modules/effect/core/OIMEffectDependencyKeyedObject.ts
|
|
6193
|
-
var OIMEffectDependencyKeyedObject = class {
|
|
6194
|
-
constructor(object, key) {
|
|
6195
|
-
this.dep = new OIMEffectDependencyKeyed(object, key);
|
|
6196
|
-
}
|
|
6197
|
-
get source() {
|
|
6198
|
-
return this.dep.source;
|
|
6199
|
-
}
|
|
6200
|
-
subscribe(onUpdate) {
|
|
6201
|
-
return this.dep.subscribe(onUpdate);
|
|
6202
|
-
}
|
|
6203
|
-
};
|
|
6204
|
-
|
|
6205
|
-
// src/modules/effect/core/OIMEffectDependencyKeyedCollection.ts
|
|
6206
|
-
var OIMEffectDependencyKeyedCollection = class {
|
|
6207
|
-
constructor(collection, pk) {
|
|
6208
|
-
this.dep = new OIMEffectDependencyKeyed(collection, pk);
|
|
6209
|
-
}
|
|
6210
|
-
get source() {
|
|
6211
|
-
return this.dep.source;
|
|
6212
|
-
}
|
|
6213
|
-
subscribe(onUpdate) {
|
|
6214
|
-
return this.dep.subscribe(onUpdate);
|
|
6215
|
-
}
|
|
6216
|
-
};
|
|
6217
|
-
|
|
6218
|
-
// src/modules/effect/core/OIMEffectDependencyKeyedIndex.ts
|
|
6219
|
-
var OIMEffectDependencyKeyedIndex = class {
|
|
6220
|
-
constructor(index, key) {
|
|
6221
|
-
this.dep = new OIMEffectDependencyKeyed(index, key);
|
|
6222
|
-
}
|
|
6223
|
-
get source() {
|
|
6224
|
-
return this.dep.source;
|
|
6225
|
-
}
|
|
6226
|
-
subscribe(onUpdate) {
|
|
6227
|
-
return this.dep.subscribe(onUpdate);
|
|
6228
|
-
}
|
|
6229
|
-
};
|
|
6230
|
-
|
|
6231
6520
|
// src/modules/selector/core/OIMObjectValueByKeySelector.ts
|
|
6232
6521
|
var OIMObjectValueByKeySelector = class extends OIMSelector {
|
|
6233
6522
|
constructor(runtime, obj, key) {
|
|
@@ -6305,8 +6594,9 @@ var OIMIndexPksByKeyArrayBasedSelector = class extends OIMSelector {
|
|
|
6305
6594
|
areEqual(prev, next) {
|
|
6306
6595
|
if (prev === next) return true;
|
|
6307
6596
|
if (prev.length !== next.length) return false;
|
|
6308
|
-
for (let i = 0; i < prev.length; i++)
|
|
6597
|
+
for (let i = 0; i < prev.length; i++) {
|
|
6309
6598
|
if (prev[i] !== next[i]) return false;
|
|
6599
|
+
}
|
|
6310
6600
|
return true;
|
|
6311
6601
|
}
|
|
6312
6602
|
};
|
|
@@ -6329,8 +6619,9 @@ var OIMIndexPksByKeysSetBasedSelector = class extends OIMSelector {
|
|
|
6329
6619
|
areEqual(prev, next) {
|
|
6330
6620
|
if (prev === next) return true;
|
|
6331
6621
|
if (prev.length !== next.length) return false;
|
|
6332
|
-
for (let i = 0; i < prev.length; i++)
|
|
6622
|
+
for (let i = 0; i < prev.length; i++) {
|
|
6333
6623
|
if (prev[i] !== next[i]) return false;
|
|
6624
|
+
}
|
|
6334
6625
|
return true;
|
|
6335
6626
|
}
|
|
6336
6627
|
};
|
|
@@ -6353,8 +6644,9 @@ var OIMIndexPksByKeysArrayBasedSelector = class extends OIMSelector {
|
|
|
6353
6644
|
areEqual(prev, next) {
|
|
6354
6645
|
if (prev === next) return true;
|
|
6355
6646
|
if (prev.length !== next.length) return false;
|
|
6356
|
-
for (let i = 0; i < prev.length; i++)
|
|
6647
|
+
for (let i = 0; i < prev.length; i++) {
|
|
6357
6648
|
if (prev[i] !== next[i]) return false;
|
|
6649
|
+
}
|
|
6358
6650
|
return true;
|
|
6359
6651
|
}
|
|
6360
6652
|
};
|
|
@@ -6383,6 +6675,7 @@ export {
|
|
|
6383
6675
|
OIMComputeRuntime,
|
|
6384
6676
|
OIMComputed,
|
|
6385
6677
|
OIMDBSettings,
|
|
6678
|
+
OIMDerivedCollection,
|
|
6386
6679
|
OIMDerivedCollectionGlobalIndexArrayBased,
|
|
6387
6680
|
OIMDerivedCollectionGlobalIndexSetBased,
|
|
6388
6681
|
OIMDerivedCollectionIndexArrayBased,
|
|
@@ -6478,5 +6771,9 @@ export {
|
|
|
6478
6771
|
createOIMIndexSlotMap,
|
|
6479
6772
|
createOIMOrderedListCommandStreamDiffDriven,
|
|
6480
6773
|
createOIMOrderedListMappedCommandStream,
|
|
6481
|
-
diffOrderedListByPk
|
|
6774
|
+
diffOrderedListByPk,
|
|
6775
|
+
getOIMComputeRuntime,
|
|
6776
|
+
on,
|
|
6777
|
+
peekOIMComputeRuntime,
|
|
6778
|
+
setOIMComputeRuntime
|
|
6482
6779
|
};
|