@kosdev-code/kos-ui-sdk 3.0.2 → 3.0.3

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/index.cjs CHANGED
@@ -2127,6 +2127,22 @@ class PluginExtensionManager {
2127
2127
  return this.extensions;
2128
2128
  }
2129
2129
  }
2130
+ var KosContainerIndexEvents = /* @__PURE__ */ ((KosContainerIndexEvents2) => {
2131
+ KosContainerIndexEvents2["ADDED"] = "kos/model/container/index/added";
2132
+ KosContainerIndexEvents2["REMOVED"] = "kos/model/container/index/removed";
2133
+ KosContainerIndexEvents2["CHANGED"] = "kos/model/container/index/changed";
2134
+ KosContainerIndexEvents2["SEED"] = "kos/model/container/index/seed";
2135
+ KosContainerIndexEvents2["PURGE"] = "kos/model/container/index/purge";
2136
+ KosContainerIndexEvents2["REQUEST_SEED"] = "kos/model/container/index/request-seed";
2137
+ return KosContainerIndexEvents2;
2138
+ })(KosContainerIndexEvents || {});
2139
+ const INDEX_RECORD_SYMBOL = /* @__PURE__ */ Symbol.for(
2140
+ "@kosdev-code/kos-ui-sdk.indexRecord"
2141
+ );
2142
+ const INDEX_COLLECTION_KEY = "@kosdev-code/kos-ui-sdk.collection";
2143
+ function isIndexableItem(value) {
2144
+ return typeof value === "object" && value !== null && INDEX_RECORD_SYMBOL in value;
2145
+ }
2130
2146
  function arraysAreEqual(arr1, arr2) {
2131
2147
  if (arr1.length !== arr2.length) return false;
2132
2148
  return arr1.every((item1) => arr2.includes(item1));
@@ -2407,6 +2423,7 @@ class KosModelContainer {
2407
2423
  this._establishModelRelationships(model);
2408
2424
  this._enforceCapacityLimits();
2409
2425
  this._configureModelMonitoring(model);
2426
+ this._publishIndexAdded(model);
2410
2427
  if (!defer) {
2411
2428
  this.increment();
2412
2429
  }
@@ -2483,7 +2500,44 @@ class KosModelContainer {
2483
2500
  () => [disposer, ...computedDisposers].forEach((d) => d())
2484
2501
  );
2485
2502
  }
2503
+ /**
2504
+ * Publish KosContainerIndexEvents.ADDED for an indexable item.
2505
+ * No-op when the model carries no INDEX_RECORD_SYMBOL (not opted
2506
+ * into indexing) or when the record has no resolvable collection
2507
+ * (item has no own tag and no inheritable container context).
2508
+ *
2509
+ * @private
2510
+ */
2511
+ _publishIndexAdded(model) {
2512
+ if (!isIndexableItem(model)) return;
2513
+ const contribution = model[INDEX_RECORD_SYMBOL];
2514
+ if (!contribution.collection) return;
2515
+ const payload = {
2516
+ record: contribution
2517
+ };
2518
+ publish(KosContainerIndexEvents.ADDED, payload);
2519
+ }
2520
+ /**
2521
+ * Publish KosContainerIndexEvents.REMOVED for an indexable item.
2522
+ * Called with the model BEFORE it's deleted from the container so
2523
+ * the payload can carry modelType + collection.
2524
+ *
2525
+ * @private
2526
+ */
2527
+ _publishIndexRemoved(model) {
2528
+ if (!model || !isIndexableItem(model)) return;
2529
+ const contribution = model[INDEX_RECORD_SYMBOL];
2530
+ if (!contribution.collection) return;
2531
+ const payload = {
2532
+ id: contribution.id,
2533
+ modelType: contribution.modelType,
2534
+ collection: contribution.collection
2535
+ };
2536
+ publish(KosContainerIndexEvents.REMOVED, payload);
2537
+ }
2486
2538
  removeModel(id, defer) {
2539
+ const removedModel = this._data.get(id);
2540
+ this._publishIndexRemoved(removedModel);
2487
2541
  this._data.delete(id);
2488
2542
  const orderIndex = this._insertionOrder.indexOf(id);
2489
2543
  if (orderIndex !== -1) {
@@ -11543,6 +11597,135 @@ const KosContextManager = {
11543
11597
  };
11544
11598
  KosContextManager.createContext("root");
11545
11599
  const resolveKosContext = (model) => KosContextManager.getContext(model.id);
11600
+ function kosIndexAware(options) {
11601
+ return (target) => {
11602
+ const collection = options?.collection;
11603
+ const fields = options?.fields ?? [];
11604
+ installRecordAccessor(target, collection, fields);
11605
+ if (fields.length > 0) {
11606
+ installChangeEffect(target, fields);
11607
+ }
11608
+ return target;
11609
+ };
11610
+ }
11611
+ function installRecordAccessor(target, collection, fields) {
11612
+ Object.defineProperty(target.prototype, INDEX_RECORD_SYMBOL, {
11613
+ get() {
11614
+ const record = {
11615
+ id: this.id,
11616
+ modelType: this.modelTypeId
11617
+ };
11618
+ const resolved = typeof collection === "function" ? collection(this) : collection;
11619
+ const inherited = resolved === void 0 ? KosContextManager.getContext(this.id)?.get(
11620
+ INDEX_COLLECTION_KEY
11621
+ ) : void 0;
11622
+ const finalCollection = resolved ?? inherited;
11623
+ if (finalCollection !== void 0) {
11624
+ record.collection = finalCollection;
11625
+ }
11626
+ for (const field of fields) {
11627
+ record[field] = this[field];
11628
+ }
11629
+ return record;
11630
+ },
11631
+ enumerable: false,
11632
+ configurable: true
11633
+ });
11634
+ }
11635
+ function installChangeEffect(target, fields) {
11636
+ target.prototype[ModelEffects] = target.prototype[ModelEffects] || {};
11637
+ target.prototype[ModelEffects].handleIndexFieldChange = {
11638
+ dependencies: (model) => fields.map((field) => model[field]),
11639
+ value: function() {
11640
+ const record = this[INDEX_RECORD_SYMBOL];
11641
+ if (!record.collection) {
11642
+ return;
11643
+ }
11644
+ const payload = {
11645
+ record
11646
+ };
11647
+ publish(KosContainerIndexEvents.CHANGED, payload);
11648
+ }
11649
+ };
11650
+ }
11651
+ function kosContainerIndexAware(options) {
11652
+ return (target) => {
11653
+ const itemsProperty = options.itemsProperty;
11654
+ const declaredCollection = options.collection;
11655
+ installContextWriter(target, declaredCollection);
11656
+ installRequestSeedHandler(target, itemsProperty);
11657
+ installPurgeOnUnload(target, itemsProperty);
11658
+ return target;
11659
+ };
11660
+ }
11661
+ function installContextWriter(target, declaredCollection) {
11662
+ if (declaredCollection === void 0) return;
11663
+ const originalInit = target.prototype.init;
11664
+ target.prototype.init = async function(context) {
11665
+ context?.set(INDEX_COLLECTION_KEY, declaredCollection);
11666
+ if (originalInit) {
11667
+ await originalInit.call(this, context);
11668
+ }
11669
+ };
11670
+ }
11671
+ function installRequestSeedHandler(target, itemsProperty) {
11672
+ target.prototype[SubscriptionHandlers] = target.prototype[SubscriptionHandlers] || {};
11673
+ target.prototype[SubscriptionHandlers][KosContainerIndexEvents.REQUEST_SEED] = {
11674
+ websocket: false,
11675
+ skipParse: true,
11676
+ // The subscription manager calls transform(body) before
11677
+ // condition/handler. For an internal EventBus event with a
11678
+ // plain object payload we just want to pass it through
11679
+ // untouched.
11680
+ transform: (payload) => payload,
11681
+ condition: () => true,
11682
+ handler: function() {
11683
+ const items = this[itemsProperty] ?? [];
11684
+ const records = collectRecords(items);
11685
+ if (records.size === 0) return;
11686
+ const payload = {
11687
+ modelType: this.modelTypeId,
11688
+ items: Array.from(records.values())
11689
+ };
11690
+ publish(KosContainerIndexEvents.SEED, payload);
11691
+ }
11692
+ };
11693
+ }
11694
+ function installPurgeOnUnload(target, itemsProperty) {
11695
+ const originalUnload = target.prototype.unload;
11696
+ target.prototype.unload = function(context) {
11697
+ const items = this[itemsProperty] ?? [];
11698
+ const collections = /* @__PURE__ */ new Set();
11699
+ for (const item of items) {
11700
+ if (!isIndexableItem(item)) continue;
11701
+ const contribution = item[INDEX_RECORD_SYMBOL];
11702
+ if (contribution.collection) {
11703
+ collections.add(contribution.collection);
11704
+ }
11705
+ }
11706
+ for (const collection of collections) {
11707
+ const payload = {
11708
+ modelType: this.modelTypeId,
11709
+ collection
11710
+ };
11711
+ publish(KosContainerIndexEvents.PURGE, payload);
11712
+ }
11713
+ if (originalUnload) {
11714
+ return originalUnload.call(this, context);
11715
+ }
11716
+ return void 0;
11717
+ };
11718
+ }
11719
+ function collectRecords(items) {
11720
+ const result = /* @__PURE__ */ new Map();
11721
+ for (const item of items) {
11722
+ if (!isIndexableItem(item)) continue;
11723
+ const contribution = item[INDEX_RECORD_SYMBOL];
11724
+ if (!contribution.collection) continue;
11725
+ result.set(contribution.id, contribution);
11726
+ }
11727
+ return result;
11728
+ }
11546
11729
  const log$s = KosLog.createLogger({ name: "kos-data-container" });
11547
11730
  class KosDataContainer {
11548
11731
  _data;
@@ -26481,6 +26664,8 @@ exports.HEADER_TOPIC = HEADER_TOPIC;
26481
26664
  exports.HEADER_URL = HEADER_URL;
26482
26665
  exports.HEADER_WORK_TRACKER = HEADER_WORK_TRACKER;
26483
26666
  exports.HttpRouteHandlers = HttpRouteHandlers;
26667
+ exports.INDEX_COLLECTION_KEY = INDEX_COLLECTION_KEY;
26668
+ exports.INDEX_RECORD_SYMBOL = INDEX_RECORD_SYMBOL;
26484
26669
  exports.KOS_EXECUTION_CONTEXT = KOS_EXECUTION_CONTEXT;
26485
26670
  exports.KOS_MODEL_ID = KOS_MODEL_ID;
26486
26671
  exports.KOS_RECOVERING_SESSION_KEY = KOS_RECOVERING_SESSION_KEY;
@@ -26493,6 +26678,7 @@ exports.KeyValueServices = index$c;
26493
26678
  exports.Kos = Kos;
26494
26679
  exports.KosConfigPropertySpec = Registration;
26495
26680
  exports.KosContainerIndex = KosContainerIndex;
26681
+ exports.KosContainerIndexEvents = KosContainerIndexEvents;
26496
26682
  exports.KosContextBean = KosContextBean;
26497
26683
  exports.KosContextManager = KosContextManager;
26498
26684
  exports.KosCore = KosCore;
@@ -26746,6 +26932,7 @@ exports.initializeStateMachine = initializeStateMachine;
26746
26932
  exports.injectStateMachineSupport = injectStateMachineSupport;
26747
26933
  exports.isBoolean = isBoolean;
26748
26934
  exports.isDisposable = isDisposable;
26935
+ exports.isIndexableItem = isIndexableItem;
26749
26936
  exports.isKosCompanionTypeFactory = isKosCompanionTypeFactory;
26750
26937
  exports.isKosDataModel = isKosDataModel;
26751
26938
  exports.isKosExecutionContext = isKosExecutionContext;
@@ -26767,11 +26954,13 @@ exports.kosComputed = kosComputed;
26767
26954
  exports.kosConfigBean = kosConfigBean;
26768
26955
  exports.kosConfigProperty = kosConfigProperty;
26769
26956
  exports.kosContainerAware = kosContainerAware;
26957
+ exports.kosContainerIndexAware = kosContainerIndexAware;
26770
26958
  exports.kosContext = kosContext;
26771
26959
  exports.kosDependency = kosDependency;
26772
26960
  exports.kosEffect = kosEffect;
26773
26961
  exports.kosFuture = kosFuture;
26774
26962
  exports.kosFutureAware = kosFutureAware;
26963
+ exports.kosIndexAware = kosIndexAware;
26775
26964
  exports.kosLogger = kosLogger;
26776
26965
  exports.kosLoggerAware = kosLoggerAware;
26777
26966
  exports.kosModel = kosModel;