@katn30/trakr 3.0.0 → 4.1.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 +128 -4
- package/dist/dev/index.cjs +600 -63
- package/dist/dev/index.cjs.map +1 -1
- package/dist/dev/index.d.cts +71 -10
- package/dist/dev/index.d.ts +71 -10
- package/dist/dev/index.js +595 -62
- package/dist/dev/index.js.map +1 -1
- package/dist/prod/index.cjs +600 -63
- package/dist/prod/index.cjs.map +1 -1
- package/dist/prod/index.js +595 -62
- package/dist/prod/index.js.map +1 -1
- package/package.json +1 -1
package/dist/prod/index.cjs
CHANGED
|
@@ -24,6 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
EventTracked: () => EventTracked,
|
|
25
25
|
EventTrackedCollection: () => EventTrackedCollection,
|
|
26
26
|
EventTracker: () => EventTracker,
|
|
27
|
+
Id: () => Id,
|
|
27
28
|
State: () => State,
|
|
28
29
|
Tracked: () => Tracked,
|
|
29
30
|
TrackedCollection: () => TrackedCollection,
|
|
@@ -31,7 +32,10 @@ __export(index_exports, {
|
|
|
31
32
|
TrackedObject: () => TrackedObject,
|
|
32
33
|
Tracker: () => Tracker,
|
|
33
34
|
TrackerSession: () => TrackerSession,
|
|
34
|
-
TypedEvent: () => TypedEvent
|
|
35
|
+
TypedEvent: () => TypedEvent,
|
|
36
|
+
getIdentity: () => getIdentity,
|
|
37
|
+
getIdentityObject: () => getIdentityObject,
|
|
38
|
+
getIdentityProperties: () => getIdentityProperties
|
|
35
39
|
});
|
|
36
40
|
module.exports = __toCommonJS(index_exports);
|
|
37
41
|
|
|
@@ -294,17 +298,73 @@ var OperationProperties = class {
|
|
|
294
298
|
|
|
295
299
|
// src/ExternallyAssigned.ts
|
|
296
300
|
var AUTO_ID = /* @__PURE__ */ Symbol("autoId");
|
|
301
|
+
var ID_PROPS = /* @__PURE__ */ Symbol("idProps");
|
|
297
302
|
function AutoId(_target, context) {
|
|
298
303
|
context.addInitializer(function() {
|
|
299
|
-
Object.
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
304
|
+
const proto = Object.getPrototypeOf(this);
|
|
305
|
+
if (!Object.prototype.hasOwnProperty.call(proto, AUTO_ID)) {
|
|
306
|
+
Object.defineProperty(proto, AUTO_ID, {
|
|
307
|
+
value: String(context.name),
|
|
308
|
+
configurable: true
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
addIdentityProp(proto, String(context.name));
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
function Id(_target, context) {
|
|
315
|
+
context.addInitializer(function() {
|
|
316
|
+
const proto = Object.getPrototypeOf(this);
|
|
317
|
+
addIdentityProp(proto, String(context.name));
|
|
303
318
|
});
|
|
304
319
|
}
|
|
320
|
+
function addIdentityProp(proto, propertyName) {
|
|
321
|
+
if (!Object.prototype.hasOwnProperty.call(proto, ID_PROPS)) {
|
|
322
|
+
Object.defineProperty(proto, ID_PROPS, {
|
|
323
|
+
value: [],
|
|
324
|
+
configurable: true,
|
|
325
|
+
writable: true
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
const list = proto[ID_PROPS];
|
|
329
|
+
if (!list.includes(propertyName)) list.push(propertyName);
|
|
330
|
+
}
|
|
305
331
|
function getAutoIdProperty(proto) {
|
|
306
332
|
return AUTO_ID in proto ? proto[AUTO_ID] : void 0;
|
|
307
333
|
}
|
|
334
|
+
function getIdentityProperties(proto) {
|
|
335
|
+
const chain = [];
|
|
336
|
+
let current = proto;
|
|
337
|
+
while (current) {
|
|
338
|
+
chain.push(current);
|
|
339
|
+
current = Object.getPrototypeOf(current);
|
|
340
|
+
}
|
|
341
|
+
const merged = [];
|
|
342
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
343
|
+
const proto2 = chain[i];
|
|
344
|
+
if (!Object.prototype.hasOwnProperty.call(proto2, ID_PROPS)) continue;
|
|
345
|
+
const list = proto2[ID_PROPS];
|
|
346
|
+
for (const name of list) {
|
|
347
|
+
if (!merged.includes(name)) merged.push(name);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return merged;
|
|
351
|
+
}
|
|
352
|
+
function getIdentity(obj) {
|
|
353
|
+
const props = getIdentityProperties(Object.getPrototypeOf(obj));
|
|
354
|
+
if (props.length === 0) return void 0;
|
|
355
|
+
if (props.length === 1) {
|
|
356
|
+
return obj[props[0]];
|
|
357
|
+
}
|
|
358
|
+
const result = {};
|
|
359
|
+
for (const p of props) result[p] = obj[p];
|
|
360
|
+
return result;
|
|
361
|
+
}
|
|
362
|
+
function getIdentityObject(obj) {
|
|
363
|
+
const props = getIdentityProperties(Object.getPrototypeOf(obj));
|
|
364
|
+
const result = {};
|
|
365
|
+
for (const p of props) result[p] = obj[p];
|
|
366
|
+
return result;
|
|
367
|
+
}
|
|
308
368
|
|
|
309
369
|
// src/TrackedObjectStateMachine.ts
|
|
310
370
|
function applyStateTransition(obj, event, direction, context) {
|
|
@@ -778,6 +838,9 @@ var Tracker = class {
|
|
|
778
838
|
this._commitStateOperation = lastOp;
|
|
779
839
|
this.reset();
|
|
780
840
|
}
|
|
841
|
+
getByTrackingId(trackingId) {
|
|
842
|
+
return this.trackedObjects.find((o) => o.trackingId === trackingId);
|
|
843
|
+
}
|
|
781
844
|
/** @internal */
|
|
782
845
|
_isInUndoStack(op) {
|
|
783
846
|
return this._undoOperations.includes(op);
|
|
@@ -1369,15 +1432,18 @@ var TrackedCollectionChanged = class {
|
|
|
1369
1432
|
// src/EventRegistry.ts
|
|
1370
1433
|
var EVENT_METADATA = /* @__PURE__ */ Symbol("eventMetadata");
|
|
1371
1434
|
var instanceState = /* @__PURE__ */ new WeakMap();
|
|
1435
|
+
var instanceHistory = /* @__PURE__ */ new WeakMap();
|
|
1436
|
+
var instanceHistoryTimes = /* @__PURE__ */ new WeakMap();
|
|
1372
1437
|
var subscribedInstances = /* @__PURE__ */ new WeakSet();
|
|
1373
1438
|
var itemOriginCollection = /* @__PURE__ */ new WeakMap();
|
|
1439
|
+
var DEFAULT_GROUP = "";
|
|
1374
1440
|
function hasOwnEventMetadata(proto) {
|
|
1375
1441
|
return Object.prototype.hasOwnProperty.call(proto, EVENT_METADATA);
|
|
1376
1442
|
}
|
|
1377
1443
|
function ownEventMetadata(proto) {
|
|
1378
1444
|
return hasOwnEventMetadata(proto) ? proto[EVENT_METADATA] : void 0;
|
|
1379
1445
|
}
|
|
1380
|
-
function registerEventProperty(proto, property,
|
|
1446
|
+
function registerEventProperty(proto, property, options) {
|
|
1381
1447
|
if (!hasOwnEventMetadata(proto)) {
|
|
1382
1448
|
Object.defineProperty(proto, EVENT_METADATA, {
|
|
1383
1449
|
value: /* @__PURE__ */ new Map(),
|
|
@@ -1386,7 +1452,7 @@ function registerEventProperty(proto, property, eventType) {
|
|
|
1386
1452
|
}
|
|
1387
1453
|
const map = proto[EVENT_METADATA];
|
|
1388
1454
|
if (!map.has(property)) {
|
|
1389
|
-
map.set(property,
|
|
1455
|
+
map.set(property, options);
|
|
1390
1456
|
}
|
|
1391
1457
|
}
|
|
1392
1458
|
function getEventMetadata(proto) {
|
|
@@ -1400,31 +1466,97 @@ function getEventMetadata(proto) {
|
|
|
1400
1466
|
for (let i = chain.length - 1; i >= 0; i--) {
|
|
1401
1467
|
const own = ownEventMetadata(chain[i]);
|
|
1402
1468
|
if (!own) continue;
|
|
1403
|
-
own.forEach((
|
|
1404
|
-
if (!merged.has(property)) merged.set(property,
|
|
1469
|
+
own.forEach((options, property) => {
|
|
1470
|
+
if (!merged.has(property)) merged.set(property, options);
|
|
1405
1471
|
});
|
|
1406
1472
|
}
|
|
1407
1473
|
return merged;
|
|
1408
1474
|
}
|
|
1475
|
+
var contextStacks = /* @__PURE__ */ new WeakMap();
|
|
1476
|
+
function pushContext(tracker, ctx) {
|
|
1477
|
+
let stack = contextStacks.get(tracker);
|
|
1478
|
+
if (!stack) {
|
|
1479
|
+
stack = [];
|
|
1480
|
+
contextStacks.set(tracker, stack);
|
|
1481
|
+
}
|
|
1482
|
+
stack.push(ctx);
|
|
1483
|
+
}
|
|
1484
|
+
function popContext(tracker) {
|
|
1485
|
+
const stack = contextStacks.get(tracker);
|
|
1486
|
+
if (stack && stack.length > 0) stack.pop();
|
|
1487
|
+
}
|
|
1488
|
+
function peekContext(tracker) {
|
|
1489
|
+
const stack = contextStacks.get(tracker);
|
|
1490
|
+
return stack && stack.length > 0 ? stack[stack.length - 1] : void 0;
|
|
1491
|
+
}
|
|
1409
1492
|
function ensureEventStateSubscription(target) {
|
|
1410
1493
|
if (subscribedInstances.has(target)) return;
|
|
1411
1494
|
subscribedInstances.add(target);
|
|
1412
1495
|
target.changed.subscribe((evt) => {
|
|
1413
1496
|
const meta = getEventMetadata(Object.getPrototypeOf(target));
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1497
|
+
const propMeta = meta.get(evt.property);
|
|
1498
|
+
if (!propMeta) return;
|
|
1499
|
+
if (propMeta.history) {
|
|
1500
|
+
appendHistoryEntry(
|
|
1501
|
+
target,
|
|
1502
|
+
evt.property,
|
|
1503
|
+
evt.newValue,
|
|
1504
|
+
evt.oldValue,
|
|
1505
|
+
propMeta.history,
|
|
1506
|
+
propMeta.coalesceWithin
|
|
1507
|
+
);
|
|
1420
1508
|
} else {
|
|
1421
|
-
|
|
1422
|
-
}
|
|
1423
|
-
if (entry.currentValue === entry.originalValue) {
|
|
1424
|
-
state.delete(evt.property);
|
|
1509
|
+
updateFinalValue(target, evt.property, evt.newValue, evt.oldValue);
|
|
1425
1510
|
}
|
|
1426
1511
|
});
|
|
1427
1512
|
}
|
|
1513
|
+
function updateFinalValue(target, property, newValue, oldValue) {
|
|
1514
|
+
const state = getOrCreateEventState(target);
|
|
1515
|
+
let entry = state.get(property);
|
|
1516
|
+
if (!entry) {
|
|
1517
|
+
entry = { originalValue: oldValue, currentValue: newValue };
|
|
1518
|
+
state.set(property, entry);
|
|
1519
|
+
} else {
|
|
1520
|
+
entry.currentValue = newValue;
|
|
1521
|
+
}
|
|
1522
|
+
if (entry.currentValue === entry.originalValue) {
|
|
1523
|
+
state.delete(property);
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
function appendHistoryEntry(target, property, newValue, oldValue, historyConfig, coalesceWithin) {
|
|
1527
|
+
const chains = getOrCreateHistoryState(target);
|
|
1528
|
+
let chain = chains.get(property);
|
|
1529
|
+
if (!chain) {
|
|
1530
|
+
chain = [];
|
|
1531
|
+
chains.set(property, chain);
|
|
1532
|
+
}
|
|
1533
|
+
const times = getOrCreateHistoryTimes(target);
|
|
1534
|
+
const now = Date.now();
|
|
1535
|
+
const lastTime = times.get(property);
|
|
1536
|
+
const shouldReplace = coalesceWithin !== void 0 && lastTime !== void 0 && now - lastTime < coalesceWithin && chain.length > 0;
|
|
1537
|
+
let entry;
|
|
1538
|
+
if (typeof historyConfig === "object" && historyConfig.entryFactory) {
|
|
1539
|
+
const ctx = peekContext(target.tracker);
|
|
1540
|
+
const change = { time: /* @__PURE__ */ new Date() };
|
|
1541
|
+
entry = historyConfig.entryFactory(target, newValue, oldValue, change, ctx);
|
|
1542
|
+
} else {
|
|
1543
|
+
entry = { property, value: newValue };
|
|
1544
|
+
}
|
|
1545
|
+
if (shouldReplace) {
|
|
1546
|
+
chain[chain.length - 1] = entry;
|
|
1547
|
+
} else {
|
|
1548
|
+
chain.push(entry);
|
|
1549
|
+
}
|
|
1550
|
+
times.set(property, now);
|
|
1551
|
+
}
|
|
1552
|
+
function getOrCreateHistoryTimes(target) {
|
|
1553
|
+
let times = instanceHistoryTimes.get(target);
|
|
1554
|
+
if (!times) {
|
|
1555
|
+
times = /* @__PURE__ */ new Map();
|
|
1556
|
+
instanceHistoryTimes.set(target, times);
|
|
1557
|
+
}
|
|
1558
|
+
return times;
|
|
1559
|
+
}
|
|
1428
1560
|
function getOrCreateEventState(target) {
|
|
1429
1561
|
let state = instanceState.get(target);
|
|
1430
1562
|
if (!state) {
|
|
@@ -1433,11 +1565,24 @@ function getOrCreateEventState(target) {
|
|
|
1433
1565
|
}
|
|
1434
1566
|
return state;
|
|
1435
1567
|
}
|
|
1568
|
+
function getOrCreateHistoryState(target) {
|
|
1569
|
+
let state = instanceHistory.get(target);
|
|
1570
|
+
if (!state) {
|
|
1571
|
+
state = /* @__PURE__ */ new Map();
|
|
1572
|
+
instanceHistory.set(target, state);
|
|
1573
|
+
}
|
|
1574
|
+
return state;
|
|
1575
|
+
}
|
|
1436
1576
|
function getEventState(target) {
|
|
1437
1577
|
return instanceState.get(target) ?? /* @__PURE__ */ new Map();
|
|
1438
1578
|
}
|
|
1579
|
+
function getHistoryState(target) {
|
|
1580
|
+
return instanceHistory.get(target) ?? /* @__PURE__ */ new Map();
|
|
1581
|
+
}
|
|
1439
1582
|
function clearEventState(target) {
|
|
1440
1583
|
instanceState.delete(target);
|
|
1584
|
+
instanceHistory.delete(target);
|
|
1585
|
+
instanceHistoryTimes.delete(target);
|
|
1441
1586
|
}
|
|
1442
1587
|
function recordItemOrigin(item, collection) {
|
|
1443
1588
|
itemOriginCollection.set(item, collection);
|
|
@@ -1446,42 +1591,312 @@ function getItemOrigin(item) {
|
|
|
1446
1591
|
return itemOriginCollection.get(item);
|
|
1447
1592
|
}
|
|
1448
1593
|
|
|
1594
|
+
// src/EventTrackedCollection.ts
|
|
1595
|
+
var EventTrackedCollection = class extends TrackedCollection {
|
|
1596
|
+
constructor(tracker, items, validator, options) {
|
|
1597
|
+
super(tracker, items, validator);
|
|
1598
|
+
this._historyOps = [];
|
|
1599
|
+
this._baselineItems = /* @__PURE__ */ new Set();
|
|
1600
|
+
this._eventOptions = options;
|
|
1601
|
+
for (const item of this.collection) {
|
|
1602
|
+
this._baselineItems.add(item);
|
|
1603
|
+
if (item instanceof TrackedObject) {
|
|
1604
|
+
recordItemOrigin(item, this);
|
|
1605
|
+
this._validateItemHasIdentity(item);
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
this.changed.subscribe((evt) => {
|
|
1609
|
+
for (const item of evt.added) {
|
|
1610
|
+
if (item instanceof TrackedObject) {
|
|
1611
|
+
recordItemOrigin(item, this);
|
|
1612
|
+
this._validateItemHasIdentity(item);
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
if (this._isAggregateMode() && !this.tracker._isReplaying) {
|
|
1616
|
+
for (const item of evt.added) {
|
|
1617
|
+
if (item instanceof TrackedObject) {
|
|
1618
|
+
this._recordAddOp(item);
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
for (const item of evt.removed) {
|
|
1622
|
+
if (item instanceof TrackedObject) {
|
|
1623
|
+
this._recordRemoveOp(item);
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
});
|
|
1628
|
+
if (this._isHistoryMode()) {
|
|
1629
|
+
this._attachItemChangeWatchers();
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
/** @internal */
|
|
1633
|
+
get _lifecycleOptions() {
|
|
1634
|
+
if (!this._eventOptions) return void 0;
|
|
1635
|
+
if (this._isAggregateMode()) return void 0;
|
|
1636
|
+
return {
|
|
1637
|
+
itemAdded: this._eventOptions.itemAdded,
|
|
1638
|
+
itemRemoved: this._eventOptions.itemRemoved
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
/** @internal */
|
|
1642
|
+
get _aggregateOptions() {
|
|
1643
|
+
return this._isAggregateMode() ? this._eventOptions : void 0;
|
|
1644
|
+
}
|
|
1645
|
+
/** @internal */
|
|
1646
|
+
get _historyOpsList() {
|
|
1647
|
+
return this._historyOps;
|
|
1648
|
+
}
|
|
1649
|
+
/** @internal */
|
|
1650
|
+
_clearHistoryOps() {
|
|
1651
|
+
this._historyOps.length = 0;
|
|
1652
|
+
this._baselineItems.clear();
|
|
1653
|
+
for (const item of this.collection) this._baselineItems.add(item);
|
|
1654
|
+
}
|
|
1655
|
+
/** @internal */
|
|
1656
|
+
_isInBaseline(item) {
|
|
1657
|
+
return this._baselineItems.has(item);
|
|
1658
|
+
}
|
|
1659
|
+
/** @internal */
|
|
1660
|
+
_baselineListSnapshot() {
|
|
1661
|
+
return [...this._baselineItems];
|
|
1662
|
+
}
|
|
1663
|
+
/** @internal */
|
|
1664
|
+
_rebaseline() {
|
|
1665
|
+
this._baselineItems.clear();
|
|
1666
|
+
for (const item of this.collection) this._baselineItems.add(item);
|
|
1667
|
+
}
|
|
1668
|
+
_isAggregateMode() {
|
|
1669
|
+
if (!this._eventOptions) return false;
|
|
1670
|
+
return this._eventOptions.eventType !== void 0 || this._eventOptions.history !== void 0;
|
|
1671
|
+
}
|
|
1672
|
+
_isHistoryMode() {
|
|
1673
|
+
return !!this._eventOptions?.history;
|
|
1674
|
+
}
|
|
1675
|
+
_validateItemHasIdentity(item) {
|
|
1676
|
+
const props = getIdentityProperties(Object.getPrototypeOf(item));
|
|
1677
|
+
if (props.length === 0) {
|
|
1678
|
+
throw new Error(
|
|
1679
|
+
`EventTrackedCollection item type ${item.constructor.name} must declare at least one @Id or @AutoId property when used with eventType or history mode`
|
|
1680
|
+
);
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
_attachItemChangeWatchers() {
|
|
1684
|
+
const watchItem = (item) => {
|
|
1685
|
+
item.changed.subscribe((_evt) => {
|
|
1686
|
+
if (this.tracker._isReplaying) return;
|
|
1687
|
+
if (!this.collection.includes(item)) return;
|
|
1688
|
+
this._recordChangeOp(item);
|
|
1689
|
+
});
|
|
1690
|
+
};
|
|
1691
|
+
for (const item of this.collection) {
|
|
1692
|
+
if (item instanceof TrackedObject) watchItem(item);
|
|
1693
|
+
}
|
|
1694
|
+
this.changed.subscribe((evt) => {
|
|
1695
|
+
for (const item of evt.added) {
|
|
1696
|
+
if (item instanceof TrackedObject) watchItem(item);
|
|
1697
|
+
}
|
|
1698
|
+
});
|
|
1699
|
+
}
|
|
1700
|
+
_recordAddOp(item) {
|
|
1701
|
+
const opts = this._eventOptions;
|
|
1702
|
+
if (typeof opts?.history === "object" && opts.history.entryFactory) {
|
|
1703
|
+
const ctx = peekContext(this.tracker);
|
|
1704
|
+
const change = { time: /* @__PURE__ */ new Date() };
|
|
1705
|
+
this._historyOps.push({
|
|
1706
|
+
op: "add",
|
|
1707
|
+
raw: opts.history.entryFactory(item, change, ctx)
|
|
1708
|
+
});
|
|
1709
|
+
} else if (opts?.history === true) {
|
|
1710
|
+
this._historyOps.push({ op: "add", item, snapshot: snapshotItemAtRecordTime(item) });
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
_recordRemoveOp(item) {
|
|
1714
|
+
const opts = this._eventOptions;
|
|
1715
|
+
const identity = getIdentity(item);
|
|
1716
|
+
if (typeof opts?.history === "object" && opts.history.entryFactory) {
|
|
1717
|
+
const ctx = peekContext(this.tracker);
|
|
1718
|
+
const change = { time: /* @__PURE__ */ new Date() };
|
|
1719
|
+
this._historyOps.push({
|
|
1720
|
+
op: "remove",
|
|
1721
|
+
raw: opts.history.entryFactory(item, change, ctx)
|
|
1722
|
+
});
|
|
1723
|
+
} else if (opts?.history === true) {
|
|
1724
|
+
this._historyOps.push({ op: "remove", identity });
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
_recordChangeOpDiff(item) {
|
|
1728
|
+
const proto = Object.getPrototypeOf(item);
|
|
1729
|
+
const idProps = getIdentityProperties(proto);
|
|
1730
|
+
const meta = getEventMetadata(proto);
|
|
1731
|
+
const rec = item;
|
|
1732
|
+
const diff = {};
|
|
1733
|
+
for (const [propName] of meta) {
|
|
1734
|
+
if (idProps.includes(propName)) continue;
|
|
1735
|
+
const v = rec[propName];
|
|
1736
|
+
diff[propName] = v === void 0 ? null : v;
|
|
1737
|
+
}
|
|
1738
|
+
return diff;
|
|
1739
|
+
}
|
|
1740
|
+
_recordChangeOp(item) {
|
|
1741
|
+
const opts = this._eventOptions;
|
|
1742
|
+
if (typeof opts?.history === "object" && opts.history.entryFactory) {
|
|
1743
|
+
const ctx = peekContext(this.tracker);
|
|
1744
|
+
const change = { time: /* @__PURE__ */ new Date() };
|
|
1745
|
+
this._historyOps.push({
|
|
1746
|
+
op: "change",
|
|
1747
|
+
raw: opts.history.entryFactory(item, change, ctx)
|
|
1748
|
+
});
|
|
1749
|
+
} else if (opts?.history === true) {
|
|
1750
|
+
const identity = getIdentity(item);
|
|
1751
|
+
const diff = this._recordChangeOpDiff(item);
|
|
1752
|
+
this._historyOps.push({ op: "change", identity, item, diff });
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
};
|
|
1756
|
+
function snapshotItemAtRecordTime(item) {
|
|
1757
|
+
const proto = Object.getPrototypeOf(item);
|
|
1758
|
+
const meta = getEventMetadata(proto);
|
|
1759
|
+
const idProps = getIdentityProperties(proto);
|
|
1760
|
+
const autoIdProp = getAutoIdProperty(proto);
|
|
1761
|
+
const rec = item;
|
|
1762
|
+
const snap = {};
|
|
1763
|
+
for (const idProp of idProps) {
|
|
1764
|
+
if (idProp === autoIdProp) snap[idProp] = null;
|
|
1765
|
+
else snap[idProp] = rec[idProp];
|
|
1766
|
+
}
|
|
1767
|
+
for (const [propName] of meta) {
|
|
1768
|
+
if (idProps.includes(propName)) continue;
|
|
1769
|
+
const v = rec[propName];
|
|
1770
|
+
snap[propName] = v === void 0 ? null : v;
|
|
1771
|
+
}
|
|
1772
|
+
return snap;
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1449
1775
|
// src/EventTracker.ts
|
|
1450
1776
|
var EventTracker = class extends Tracker {
|
|
1777
|
+
withContext(ctx, action) {
|
|
1778
|
+
pushContext(this, ctx);
|
|
1779
|
+
try {
|
|
1780
|
+
return action();
|
|
1781
|
+
} finally {
|
|
1782
|
+
popContext(this);
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1451
1785
|
onCommit(keys) {
|
|
1452
1786
|
super.onCommit(keys);
|
|
1453
1787
|
for (const obj of this.trackedObjects) {
|
|
1454
1788
|
clearEventState(obj);
|
|
1455
1789
|
}
|
|
1790
|
+
for (const col of this.trackedCollections) {
|
|
1791
|
+
if (col instanceof EventTrackedCollection) {
|
|
1792
|
+
col._clearHistoryOps();
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1456
1795
|
}
|
|
1457
1796
|
generateEvents() {
|
|
1458
1797
|
const events = [];
|
|
1459
1798
|
for (const obj of this.trackedObjects) {
|
|
1460
|
-
const meta = getEventMetadata(Object.getPrototypeOf(obj));
|
|
1461
1799
|
const origin = getItemOrigin(obj);
|
|
1462
|
-
|
|
1800
|
+
if (!origin) continue;
|
|
1801
|
+
const legacy = origin._lifecycleOptions;
|
|
1802
|
+
if (!legacy) continue;
|
|
1803
|
+
const meta = getEventMetadata(Object.getPrototypeOf(obj));
|
|
1463
1804
|
switch (obj.state) {
|
|
1464
1805
|
case "Insert" /* Insert */:
|
|
1465
|
-
if (
|
|
1466
|
-
events.push(buildItemAddedEvent(obj, meta,
|
|
1806
|
+
if (legacy.itemAdded) {
|
|
1807
|
+
events.push(buildItemAddedEvent(obj, meta, legacy.itemAdded));
|
|
1467
1808
|
}
|
|
1468
1809
|
break;
|
|
1469
1810
|
case "Deleted" /* Deleted */:
|
|
1470
|
-
if (
|
|
1471
|
-
events.push(buildItemRemovedEvent(obj,
|
|
1811
|
+
if (legacy.itemRemoved) {
|
|
1812
|
+
events.push(buildItemRemovedEvent(obj, legacy.itemRemoved));
|
|
1472
1813
|
}
|
|
1473
1814
|
break;
|
|
1474
1815
|
case "Changed" /* Changed */:
|
|
1475
1816
|
pushFieldClusterEvents(obj, meta, events);
|
|
1476
1817
|
break;
|
|
1477
|
-
case "Unchanged" /* Unchanged */:
|
|
1478
|
-
default:
|
|
1479
|
-
break;
|
|
1480
1818
|
}
|
|
1481
1819
|
}
|
|
1820
|
+
const ownedCollections = /* @__PURE__ */ new Map();
|
|
1821
|
+
for (const col of this.trackedCollections) {
|
|
1822
|
+
if (!(col instanceof EventTrackedCollection)) continue;
|
|
1823
|
+
const agg = col._aggregateOptions;
|
|
1824
|
+
if (!agg?.owner) continue;
|
|
1825
|
+
const owner = agg.owner.object;
|
|
1826
|
+
let list = ownedCollections.get(owner);
|
|
1827
|
+
if (!list) {
|
|
1828
|
+
list = [];
|
|
1829
|
+
ownedCollections.set(owner, list);
|
|
1830
|
+
}
|
|
1831
|
+
list.push(col);
|
|
1832
|
+
}
|
|
1833
|
+
for (const obj of this.trackedObjects) {
|
|
1834
|
+
const origin = getItemOrigin(obj);
|
|
1835
|
+
if (origin) continue;
|
|
1836
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1837
|
+
const meta = getEventMetadata(Object.getPrototypeOf(obj));
|
|
1838
|
+
const stateMap = getEventState(obj);
|
|
1839
|
+
const historyMap = getHistoryState(obj);
|
|
1840
|
+
for (const [propName, propMeta] of meta) {
|
|
1841
|
+
const group = propMeta.eventType ?? DEFAULT_GROUP;
|
|
1842
|
+
if (propMeta.history) {
|
|
1843
|
+
const chain = historyMap.get(propName);
|
|
1844
|
+
if (chain && chain.length > 0) {
|
|
1845
|
+
addToGroup(groups, group, propName, [...chain]);
|
|
1846
|
+
}
|
|
1847
|
+
} else {
|
|
1848
|
+
const entry = stateMap.get(propName);
|
|
1849
|
+
if (entry) {
|
|
1850
|
+
addToGroup(groups, group, propName, normalizeValue(entry.currentValue));
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
const owned = ownedCollections.get(obj) ?? [];
|
|
1855
|
+
for (const col of owned) {
|
|
1856
|
+
const slot = computeCollectionSlot(col, this);
|
|
1857
|
+
if (slot === void 0) continue;
|
|
1858
|
+
const agg = col._aggregateOptions;
|
|
1859
|
+
const group = agg.eventType ?? DEFAULT_GROUP;
|
|
1860
|
+
const propertyName = agg.owner.property;
|
|
1861
|
+
addToGroup(groups, group, propertyName, slot);
|
|
1862
|
+
}
|
|
1863
|
+
if (groups.size === 0) continue;
|
|
1864
|
+
const identity = getIdentity(obj);
|
|
1865
|
+
for (const [group, payload] of groups) {
|
|
1866
|
+
const event = {
|
|
1867
|
+
eventType: group,
|
|
1868
|
+
payload,
|
|
1869
|
+
trackingId: obj.trackingId
|
|
1870
|
+
};
|
|
1871
|
+
if (identity !== void 0) {
|
|
1872
|
+
event.targetId = identity;
|
|
1873
|
+
}
|
|
1874
|
+
events.push(event);
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
for (const col of this.trackedCollections) {
|
|
1878
|
+
if (!(col instanceof EventTrackedCollection)) continue;
|
|
1879
|
+
const agg = col._aggregateOptions;
|
|
1880
|
+
if (!agg || agg.owner) continue;
|
|
1881
|
+
const slot = computeCollectionSlot(col, this);
|
|
1882
|
+
if (slot === void 0) continue;
|
|
1883
|
+
const eventType = agg.eventType ?? DEFAULT_GROUP;
|
|
1884
|
+
events.push({
|
|
1885
|
+
eventType,
|
|
1886
|
+
payload: slot
|
|
1887
|
+
});
|
|
1888
|
+
}
|
|
1482
1889
|
return events;
|
|
1483
1890
|
}
|
|
1484
1891
|
};
|
|
1892
|
+
function addToGroup(groups, group, key, value) {
|
|
1893
|
+
let payload = groups.get(group);
|
|
1894
|
+
if (!payload) {
|
|
1895
|
+
payload = {};
|
|
1896
|
+
groups.set(group, payload);
|
|
1897
|
+
}
|
|
1898
|
+
payload[key] = value;
|
|
1899
|
+
}
|
|
1485
1900
|
function buildItemAddedEvent(obj, meta, eventType) {
|
|
1486
1901
|
const payload = {};
|
|
1487
1902
|
for (const [propertyName] of meta) {
|
|
@@ -1510,12 +1925,13 @@ function pushFieldClusterEvents(obj, meta, events) {
|
|
|
1510
1925
|
const state = getEventState(obj);
|
|
1511
1926
|
if (state.size === 0) return;
|
|
1512
1927
|
const grouped = /* @__PURE__ */ new Map();
|
|
1513
|
-
for (const [propertyName,
|
|
1928
|
+
for (const [propertyName, propMeta] of meta) {
|
|
1514
1929
|
if (!state.has(propertyName)) continue;
|
|
1515
|
-
|
|
1930
|
+
if (!propMeta.eventType) continue;
|
|
1931
|
+
let bucket = grouped.get(propMeta.eventType);
|
|
1516
1932
|
if (!bucket) {
|
|
1517
1933
|
bucket = [];
|
|
1518
|
-
grouped.set(eventType, bucket);
|
|
1934
|
+
grouped.set(propMeta.eventType, bucket);
|
|
1519
1935
|
}
|
|
1520
1936
|
bucket.push(propertyName);
|
|
1521
1937
|
}
|
|
@@ -1537,58 +1953,176 @@ function pushFieldClusterEvents(obj, meta, events) {
|
|
|
1537
1953
|
events.push(event);
|
|
1538
1954
|
}
|
|
1539
1955
|
}
|
|
1956
|
+
function computeCollectionSlot(col, tracker) {
|
|
1957
|
+
const agg = col._aggregateOptions;
|
|
1958
|
+
const isHistory = agg.history !== void 0 && agg.history !== false;
|
|
1959
|
+
if (isHistory) return computeHistoryOps(col, agg);
|
|
1960
|
+
return computeBucketedSlot(col, tracker);
|
|
1961
|
+
}
|
|
1962
|
+
function computeHistoryOps(col, agg) {
|
|
1963
|
+
const opsList = col._historyOpsList;
|
|
1964
|
+
const hasFactory = typeof agg.history === "object" && agg.history.entryFactory;
|
|
1965
|
+
const ops = [];
|
|
1966
|
+
for (const op of opsList) {
|
|
1967
|
+
if (hasFactory) {
|
|
1968
|
+
ops.push(op.raw);
|
|
1969
|
+
continue;
|
|
1970
|
+
}
|
|
1971
|
+
if (op.op === "add") {
|
|
1972
|
+
ops.push({ op: "add", item: op.snapshot ?? (op.item ? snapshotItemForAdded(op.item) : {}) });
|
|
1973
|
+
} else if (op.op === "remove") {
|
|
1974
|
+
const idObj = op.identity && typeof op.identity === "object" ? op.identity : identityToSingleKeyObject(op.identity, col);
|
|
1975
|
+
ops.push({ op: "remove", ...idObj });
|
|
1976
|
+
} else if (op.op === "change" && op.item) {
|
|
1977
|
+
const idObj = getIdentityObject(op.item);
|
|
1978
|
+
const diff = op.diff ?? computeItemDiff(op.item);
|
|
1979
|
+
ops.push({ op: "change", ...idObj, ...diff });
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
if (ops.length === 0) return void 0;
|
|
1983
|
+
return { ops };
|
|
1984
|
+
}
|
|
1985
|
+
function identityToSingleKeyObject(identity, col) {
|
|
1986
|
+
const baseline = col._baselineListSnapshot();
|
|
1987
|
+
const sample = baseline.find((i) => i instanceof TrackedObject);
|
|
1988
|
+
const currentSample = col.collection.find(
|
|
1989
|
+
(i) => i instanceof TrackedObject
|
|
1990
|
+
);
|
|
1991
|
+
const proto = sample ? Object.getPrototypeOf(sample) : currentSample ? Object.getPrototypeOf(currentSample) : void 0;
|
|
1992
|
+
if (!proto) return {};
|
|
1993
|
+
const props = getIdentityProperties(proto);
|
|
1994
|
+
if (props.length === 1) return { [props[0]]: identity };
|
|
1995
|
+
return identity && typeof identity === "object" ? identity : {};
|
|
1996
|
+
}
|
|
1997
|
+
function computeBucketedSlot(col, tracker) {
|
|
1998
|
+
const added = [];
|
|
1999
|
+
const changed = [];
|
|
2000
|
+
const removed = [];
|
|
2001
|
+
const isPrimitive = !hasTrackedObjectItems(col);
|
|
2002
|
+
for (const item of col.collection) {
|
|
2003
|
+
if (item instanceof TrackedObject) {
|
|
2004
|
+
if (item.state === "Insert" /* Insert */) {
|
|
2005
|
+
added.push(snapshotItemForAdded(item));
|
|
2006
|
+
} else if (item.state === "Changed" /* Changed */) {
|
|
2007
|
+
const entry = buildChangedEntry(item);
|
|
2008
|
+
if (entry) changed.push(entry);
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
if (isPrimitive) {
|
|
2013
|
+
for (const item of col.collection) {
|
|
2014
|
+
if (!col._isInBaseline(item)) added.push(item);
|
|
2015
|
+
}
|
|
2016
|
+
for (const baselineItem of col._baselineListSnapshot()) {
|
|
2017
|
+
if (!col.collection.includes(baselineItem)) removed.push(baselineItem);
|
|
2018
|
+
}
|
|
2019
|
+
} else {
|
|
2020
|
+
for (const obj of tracker.trackedObjects) {
|
|
2021
|
+
if (obj.state !== "Deleted" /* Deleted */) continue;
|
|
2022
|
+
if (getItemOrigin(obj) !== col) continue;
|
|
2023
|
+
const identity = getIdentity(obj);
|
|
2024
|
+
removed.push(identity);
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
if (added.length === 0 && changed.length === 0 && removed.length === 0) {
|
|
2028
|
+
return void 0;
|
|
2029
|
+
}
|
|
2030
|
+
const slot = { added, removed };
|
|
2031
|
+
if (!isPrimitive) slot.changed = changed;
|
|
2032
|
+
return slot;
|
|
2033
|
+
}
|
|
2034
|
+
function hasTrackedObjectItems(col) {
|
|
2035
|
+
for (const item of col.collection) {
|
|
2036
|
+
if (item instanceof TrackedObject) return true;
|
|
2037
|
+
}
|
|
2038
|
+
for (const item of col._baselineListSnapshot()) {
|
|
2039
|
+
if (item instanceof TrackedObject) return true;
|
|
2040
|
+
}
|
|
2041
|
+
return false;
|
|
2042
|
+
}
|
|
2043
|
+
function snapshotItemForAdded(item) {
|
|
2044
|
+
const proto = Object.getPrototypeOf(item);
|
|
2045
|
+
const meta = getEventMetadata(proto);
|
|
2046
|
+
const idProps = getIdentityProperties(proto);
|
|
2047
|
+
const autoIdProp = getAutoIdProperty(proto);
|
|
2048
|
+
const snapshot = {};
|
|
2049
|
+
const rec = item;
|
|
2050
|
+
for (const idProp of idProps) {
|
|
2051
|
+
if (idProp === autoIdProp) {
|
|
2052
|
+
snapshot[idProp] = null;
|
|
2053
|
+
} else {
|
|
2054
|
+
snapshot[idProp] = rec[idProp];
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
for (const [propName] of meta) {
|
|
2058
|
+
if (idProps.includes(propName)) continue;
|
|
2059
|
+
snapshot[propName] = normalizeValue(rec[propName]);
|
|
2060
|
+
}
|
|
2061
|
+
return snapshot;
|
|
2062
|
+
}
|
|
2063
|
+
function buildChangedEntry(item) {
|
|
2064
|
+
const state = getEventState(item);
|
|
2065
|
+
const history = getHistoryState(item);
|
|
2066
|
+
if (state.size === 0 && history.size === 0) return void 0;
|
|
2067
|
+
const proto = Object.getPrototypeOf(item);
|
|
2068
|
+
const idProps = getIdentityProperties(proto);
|
|
2069
|
+
const rec = item;
|
|
2070
|
+
const entry = {};
|
|
2071
|
+
for (const idProp of idProps) {
|
|
2072
|
+
entry[idProp] = rec[idProp];
|
|
2073
|
+
}
|
|
2074
|
+
for (const [propName, e] of state) {
|
|
2075
|
+
if (idProps.includes(propName)) continue;
|
|
2076
|
+
entry[propName] = normalizeValue(e.currentValue);
|
|
2077
|
+
}
|
|
2078
|
+
for (const [propName, chain] of history) {
|
|
2079
|
+
if (idProps.includes(propName)) continue;
|
|
2080
|
+
entry[propName] = [...chain];
|
|
2081
|
+
}
|
|
2082
|
+
return entry;
|
|
2083
|
+
}
|
|
2084
|
+
function computeItemDiff(item) {
|
|
2085
|
+
const state = getEventState(item);
|
|
2086
|
+
const proto = Object.getPrototypeOf(item);
|
|
2087
|
+
const idProps = getIdentityProperties(proto);
|
|
2088
|
+
const diff = {};
|
|
2089
|
+
for (const [propName, e] of state) {
|
|
2090
|
+
if (idProps.includes(propName)) continue;
|
|
2091
|
+
diff[propName] = normalizeValue(e.currentValue);
|
|
2092
|
+
}
|
|
2093
|
+
return diff;
|
|
2094
|
+
}
|
|
1540
2095
|
function normalizeValue(value) {
|
|
1541
2096
|
return value === void 0 ? null : value;
|
|
1542
2097
|
}
|
|
1543
2098
|
|
|
1544
2099
|
// src/EventTracked.ts
|
|
1545
|
-
function EventTracked(
|
|
1546
|
-
const trackedDecorator = Tracked(validator, onChange,
|
|
2100
|
+
function EventTracked(validator, onChange, options) {
|
|
2101
|
+
const trackedDecorator = Tracked(validator, onChange, {
|
|
2102
|
+
coalesceWithin: options?.coalesceWithin
|
|
2103
|
+
});
|
|
1547
2104
|
function decorator(target, context) {
|
|
1548
2105
|
const result = trackedDecorator(target, context);
|
|
1549
2106
|
const propertyName = String(context.name);
|
|
1550
2107
|
context.addInitializer(function() {
|
|
1551
|
-
registerEventProperty(
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
);
|
|
2108
|
+
registerEventProperty(Object.getPrototypeOf(this), propertyName, {
|
|
2109
|
+
eventType: options?.eventType,
|
|
2110
|
+
history: options?.history,
|
|
2111
|
+
coalesceWithin: options?.coalesceWithin
|
|
2112
|
+
});
|
|
1556
2113
|
ensureEventStateSubscription(this);
|
|
1557
2114
|
});
|
|
1558
2115
|
return result;
|
|
1559
2116
|
}
|
|
1560
2117
|
return decorator;
|
|
1561
2118
|
}
|
|
1562
|
-
|
|
1563
|
-
// src/EventTrackedCollection.ts
|
|
1564
|
-
var EventTrackedCollection = class extends TrackedCollection {
|
|
1565
|
-
constructor(tracker, items, validator, eventOptions) {
|
|
1566
|
-
super(tracker, items, validator);
|
|
1567
|
-
this._eventOptions = eventOptions;
|
|
1568
|
-
for (const item of this.collection) {
|
|
1569
|
-
if (item instanceof TrackedObject) {
|
|
1570
|
-
recordItemOrigin(item, this);
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1573
|
-
this.changed.subscribe((evt) => {
|
|
1574
|
-
for (const item of evt.added) {
|
|
1575
|
-
if (item instanceof TrackedObject) {
|
|
1576
|
-
recordItemOrigin(item, this);
|
|
1577
|
-
}
|
|
1578
|
-
}
|
|
1579
|
-
});
|
|
1580
|
-
}
|
|
1581
|
-
/** @internal */
|
|
1582
|
-
get _lifecycleOptions() {
|
|
1583
|
-
return this._eventOptions;
|
|
1584
|
-
}
|
|
1585
|
-
};
|
|
1586
2119
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1587
2120
|
0 && (module.exports = {
|
|
1588
2121
|
AutoId,
|
|
1589
2122
|
EventTracked,
|
|
1590
2123
|
EventTrackedCollection,
|
|
1591
2124
|
EventTracker,
|
|
2125
|
+
Id,
|
|
1592
2126
|
State,
|
|
1593
2127
|
Tracked,
|
|
1594
2128
|
TrackedCollection,
|
|
@@ -1596,6 +2130,9 @@ var EventTrackedCollection = class extends TrackedCollection {
|
|
|
1596
2130
|
TrackedObject,
|
|
1597
2131
|
Tracker,
|
|
1598
2132
|
TrackerSession,
|
|
1599
|
-
TypedEvent
|
|
2133
|
+
TypedEvent,
|
|
2134
|
+
getIdentity,
|
|
2135
|
+
getIdentityObject,
|
|
2136
|
+
getIdentityProperties
|
|
1600
2137
|
});
|
|
1601
2138
|
//# sourceMappingURL=index.cjs.map
|