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