@katn30/trakr 2.2.1 → 3.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.
@@ -21,6 +21,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  AutoId: () => AutoId,
24
+ EventTracked: () => EventTracked,
25
+ EventTrackedCollection: () => EventTrackedCollection,
26
+ EventTracker: () => EventTracker,
24
27
  State: () => State,
25
28
  Tracked: () => Tracked,
26
29
  TrackedCollection: () => TrackedCollection,
@@ -1362,9 +1365,230 @@ var TrackedCollectionChanged = class {
1362
1365
  this.newCollection = newCollection;
1363
1366
  }
1364
1367
  };
1368
+
1369
+ // src/EventRegistry.ts
1370
+ var EVENT_METADATA = /* @__PURE__ */ Symbol("eventMetadata");
1371
+ var instanceState = /* @__PURE__ */ new WeakMap();
1372
+ var subscribedInstances = /* @__PURE__ */ new WeakSet();
1373
+ var itemOriginCollection = /* @__PURE__ */ new WeakMap();
1374
+ function hasOwnEventMetadata(proto) {
1375
+ return Object.prototype.hasOwnProperty.call(proto, EVENT_METADATA);
1376
+ }
1377
+ function ownEventMetadata(proto) {
1378
+ return hasOwnEventMetadata(proto) ? proto[EVENT_METADATA] : void 0;
1379
+ }
1380
+ function registerEventProperty(proto, property, eventType) {
1381
+ if (!hasOwnEventMetadata(proto)) {
1382
+ Object.defineProperty(proto, EVENT_METADATA, {
1383
+ value: /* @__PURE__ */ new Map(),
1384
+ configurable: true
1385
+ });
1386
+ }
1387
+ const map = proto[EVENT_METADATA];
1388
+ if (!map.has(property)) {
1389
+ map.set(property, eventType);
1390
+ }
1391
+ }
1392
+ function getEventMetadata(proto) {
1393
+ const chain = [];
1394
+ let current = proto;
1395
+ while (current) {
1396
+ chain.push(current);
1397
+ current = Object.getPrototypeOf(current);
1398
+ }
1399
+ const merged = /* @__PURE__ */ new Map();
1400
+ for (let i = chain.length - 1; i >= 0; i--) {
1401
+ const own = ownEventMetadata(chain[i]);
1402
+ if (!own) continue;
1403
+ own.forEach((eventType, property) => {
1404
+ if (!merged.has(property)) merged.set(property, eventType);
1405
+ });
1406
+ }
1407
+ return merged;
1408
+ }
1409
+ function ensureEventStateSubscription(target) {
1410
+ if (subscribedInstances.has(target)) return;
1411
+ subscribedInstances.add(target);
1412
+ target.changed.subscribe((evt) => {
1413
+ const meta = getEventMetadata(Object.getPrototypeOf(target));
1414
+ if (!meta.has(evt.property)) return;
1415
+ const state = getOrCreateEventState(target);
1416
+ let entry = state.get(evt.property);
1417
+ if (!entry) {
1418
+ entry = { originalValue: evt.oldValue, currentValue: evt.newValue };
1419
+ state.set(evt.property, entry);
1420
+ } else {
1421
+ entry.currentValue = evt.newValue;
1422
+ }
1423
+ if (entry.currentValue === entry.originalValue) {
1424
+ state.delete(evt.property);
1425
+ }
1426
+ });
1427
+ }
1428
+ function getOrCreateEventState(target) {
1429
+ let state = instanceState.get(target);
1430
+ if (!state) {
1431
+ state = /* @__PURE__ */ new Map();
1432
+ instanceState.set(target, state);
1433
+ }
1434
+ return state;
1435
+ }
1436
+ function getEventState(target) {
1437
+ return instanceState.get(target) ?? /* @__PURE__ */ new Map();
1438
+ }
1439
+ function clearEventState(target) {
1440
+ instanceState.delete(target);
1441
+ }
1442
+ function recordItemOrigin(item, collection) {
1443
+ itemOriginCollection.set(item, collection);
1444
+ }
1445
+ function getItemOrigin(item) {
1446
+ return itemOriginCollection.get(item);
1447
+ }
1448
+
1449
+ // src/EventTracker.ts
1450
+ var EventTracker = class extends Tracker {
1451
+ onCommit(keys) {
1452
+ super.onCommit(keys);
1453
+ for (const obj of this.trackedObjects) {
1454
+ clearEventState(obj);
1455
+ }
1456
+ }
1457
+ generateEvents() {
1458
+ const events = [];
1459
+ for (const obj of this.trackedObjects) {
1460
+ const meta = getEventMetadata(Object.getPrototypeOf(obj));
1461
+ const origin = getItemOrigin(obj);
1462
+ const lifecycle = origin?._lifecycleOptions;
1463
+ switch (obj.state) {
1464
+ case "Insert" /* Insert */:
1465
+ if (lifecycle?.itemAdded) {
1466
+ events.push(buildItemAddedEvent(obj, meta, lifecycle.itemAdded));
1467
+ }
1468
+ break;
1469
+ case "Deleted" /* Deleted */:
1470
+ if (lifecycle?.itemRemoved) {
1471
+ events.push(buildItemRemovedEvent(obj, lifecycle.itemRemoved));
1472
+ }
1473
+ break;
1474
+ case "Changed" /* Changed */:
1475
+ pushFieldClusterEvents(obj, meta, events);
1476
+ break;
1477
+ case "Unchanged" /* Unchanged */:
1478
+ default:
1479
+ break;
1480
+ }
1481
+ }
1482
+ return events;
1483
+ }
1484
+ };
1485
+ function buildItemAddedEvent(obj, meta, eventType) {
1486
+ const payload = {};
1487
+ for (const [propertyName] of meta) {
1488
+ const value = obj[propertyName];
1489
+ payload[propertyName] = normalizeValue(value);
1490
+ }
1491
+ return {
1492
+ eventType,
1493
+ payload,
1494
+ trackingId: obj.trackingId
1495
+ };
1496
+ }
1497
+ function buildItemRemovedEvent(obj, eventType) {
1498
+ const autoIdProp = getAutoIdProperty(Object.getPrototypeOf(obj));
1499
+ const targetId = autoIdProp ? obj[autoIdProp] : void 0;
1500
+ const event = {
1501
+ eventType,
1502
+ payload: {}
1503
+ };
1504
+ if (typeof targetId === "number") {
1505
+ event.targetId = targetId;
1506
+ }
1507
+ return event;
1508
+ }
1509
+ function pushFieldClusterEvents(obj, meta, events) {
1510
+ const state = getEventState(obj);
1511
+ if (state.size === 0) return;
1512
+ const grouped = /* @__PURE__ */ new Map();
1513
+ for (const [propertyName, eventType] of meta) {
1514
+ if (!state.has(propertyName)) continue;
1515
+ let bucket = grouped.get(eventType);
1516
+ if (!bucket) {
1517
+ bucket = [];
1518
+ grouped.set(eventType, bucket);
1519
+ }
1520
+ bucket.push(propertyName);
1521
+ }
1522
+ const autoIdProp = getAutoIdProperty(Object.getPrototypeOf(obj));
1523
+ const targetIdRaw = autoIdProp ? obj[autoIdProp] : void 0;
1524
+ for (const [eventType, propertyNames] of grouped) {
1525
+ const payload = {};
1526
+ for (const propertyName of propertyNames) {
1527
+ payload[propertyName] = normalizeValue(state.get(propertyName).currentValue);
1528
+ }
1529
+ const event = {
1530
+ eventType,
1531
+ payload,
1532
+ trackingId: obj.trackingId
1533
+ };
1534
+ if (typeof targetIdRaw === "number") {
1535
+ event.targetId = targetIdRaw;
1536
+ }
1537
+ events.push(event);
1538
+ }
1539
+ }
1540
+ function normalizeValue(value) {
1541
+ return value === void 0 ? null : value;
1542
+ }
1543
+
1544
+ // src/EventTracked.ts
1545
+ function EventTracked(eventType, validator, onChange, options) {
1546
+ const trackedDecorator = Tracked(validator, onChange, options);
1547
+ function decorator(target, context) {
1548
+ const result = trackedDecorator(target, context);
1549
+ const propertyName = String(context.name);
1550
+ context.addInitializer(function() {
1551
+ registerEventProperty(
1552
+ Object.getPrototypeOf(this),
1553
+ propertyName,
1554
+ eventType
1555
+ );
1556
+ ensureEventStateSubscription(this);
1557
+ });
1558
+ return result;
1559
+ }
1560
+ return decorator;
1561
+ }
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
+ };
1365
1586
  // Annotate the CommonJS export names for ESM import in node:
1366
1587
  0 && (module.exports = {
1367
1588
  AutoId,
1589
+ EventTracked,
1590
+ EventTrackedCollection,
1591
+ EventTracker,
1368
1592
  State,
1369
1593
  Tracked,
1370
1594
  TrackedCollection,