@kosdev-code/kos-ui-sdk 3.0.21 → 3.0.23

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.
Files changed (54) hide show
  1. package/core/core/kosCore.d.ts +1 -0
  2. package/core/core/kosCore.d.ts.map +1 -1
  3. package/core/core/kosModel.d.ts +11 -0
  4. package/core/core/kosModel.d.ts.map +1 -1
  5. package/core/core/kosModelManager.d.ts +8 -0
  6. package/core/core/kosModelManager.d.ts.map +1 -1
  7. package/core/core/lifecycle/constants.d.ts +1 -1
  8. package/core/core/lifecycle/constants.d.ts.map +1 -1
  9. package/core/core/model/kos-subscription-manager.d.ts +1 -0
  10. package/core/core/model/kos-subscription-manager.d.ts.map +1 -1
  11. package/core/core/registration/index.d.ts +1 -1
  12. package/core/core/registration/index.d.ts.map +1 -1
  13. package/core/core/registration/model-registration.d.ts +11 -0
  14. package/core/core/registration/model-registration.d.ts.map +1 -1
  15. package/core/index.d.ts +1 -1
  16. package/core/index.d.ts.map +1 -1
  17. package/core/util/kos-model-utils.d.ts +13 -0
  18. package/core/util/kos-model-utils.d.ts.map +1 -1
  19. package/{index-DUoSahlA.cjs → index-CRb8ucfF.cjs} +115 -48
  20. package/index-CRb8ucfF.cjs.map +1 -0
  21. package/{index-BUwbSjst.js → index-YzHb2lnB.js} +116 -49
  22. package/index-YzHb2lnB.js.map +1 -0
  23. package/index.cjs +113 -26
  24. package/index.cjs.map +1 -1
  25. package/index.js +114 -27
  26. package/index.js.map +1 -1
  27. package/models/decorators/kos-config-bean-prop.d.ts +5 -0
  28. package/models/decorators/kos-config-bean-prop.d.ts.map +1 -1
  29. package/models/decorators/kos-config-bean.d.ts +7 -1
  30. package/models/decorators/kos-config-bean.d.ts.map +1 -1
  31. package/models/models/config-bean/config-bean-model.d.ts +9 -0
  32. package/models/models/config-bean/config-bean-model.d.ts.map +1 -1
  33. package/models/models/config-bean/config-bean-types.d.ts +2 -0
  34. package/models/models/config-bean/config-bean-types.d.ts.map +1 -1
  35. package/models/models/config-bean-prop/config-bean-prop-model.d.ts +3 -0
  36. package/models/models/config-bean-prop/config-bean-prop-model.d.ts.map +1 -1
  37. package/models/models/config-bean-prop/types/index.d.ts +10 -0
  38. package/models/models/region-info/region-info-model.d.ts +12 -1
  39. package/models/models/region-info/region-info-model.d.ts.map +1 -1
  40. package/models/models/region-info/services/region-info-services.d.ts +2 -2
  41. package/models/models/region-info/services/region-info-services.d.ts.map +1 -1
  42. package/models/models/region-info/types/index.d.ts +7 -0
  43. package/models/models/region-info/types/index.d.ts.map +1 -1
  44. package/models/services/config-bean/index.d.ts +2 -2
  45. package/models/services/config-bean/index.d.ts.map +1 -1
  46. package/package.json +2 -2
  47. package/testing/index.d.ts +51 -9
  48. package/testing/index.d.ts.map +1 -1
  49. package/testing.cjs +57 -3
  50. package/testing.cjs.map +1 -1
  51. package/testing.js +57 -3
  52. package/testing.js.map +1 -1
  53. package/index-BUwbSjst.js.map +0 -1
  54. package/index-DUoSahlA.cjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { makeAutoObservable, observable, makeObservable, action, createAtom, autorun, runInAction, observe, isComputedProp, reaction, when, ObservableMap, computed, isObservable } from "mobx";
1
+ import { makeAutoObservable, observable, makeObservable, action, createAtom, autorun, runInAction, observe, isComputedProp, reaction, ObservableMap, when, computed, isObservable } from "mobx";
2
2
  import log$q from "loglevel";
3
3
  import { createMachine, invoke, transition, action as action$1, state, interpret, immediate } from "robot3";
4
4
  const HEADER_METHOD = `method`;
@@ -2491,7 +2491,7 @@ var KosModelEvents = /* @__PURE__ */ ((KosModelEvents2) => {
2491
2491
  KosModelEvents2["READY"] = `ready`;
2492
2492
  KosModelEvents2["GO_ONLINE"] = `go_online`;
2493
2493
  KosModelEvents2["GO_OFFLINE"] = `go_offline`;
2494
- KosModelEvents2["RESET"] = `go_offline`;
2494
+ KosModelEvents2["RESET"] = `reset`;
2495
2495
  KosModelEvents2["UNLOAD"] = `unload`;
2496
2496
  KosModelEvents2["FAILED"] = "failed";
2497
2497
  KosModelEvents2["GO_ACTIVE"] = "go_active";
@@ -2516,6 +2516,9 @@ const destroyKosModel = async (model) => {
2516
2516
  await KosCore.getInstance().modelManager.initiateDestroyModel(model);
2517
2517
  };
2518
2518
  const unloadKosModel = async (dataModel) => {
2519
+ KosLog.warn(
2520
+ `unloadKosModel(${dataModel?.id}) is deprecated and never resolves. Use destroyKosModel() to release a model, or reload() to refresh it.`
2521
+ );
2519
2522
  await KosCore.getInstance().whenReady();
2520
2523
  if (!dataModel.id) {
2521
2524
  throw new Error("Model ID is required");
@@ -2526,6 +2529,9 @@ const unloadKosModel = async (dataModel) => {
2526
2529
  }
2527
2530
  };
2528
2531
  const resetKosModel = async (model) => {
2532
+ KosLog.warn(
2533
+ `resetKosModel(${model?.id}) is deprecated: the reset route drops every topic handler registered at INIT or with no lifecycle. Implement reload() on the model and refetch and reconcile in place.`
2534
+ );
2529
2535
  await KosCore.getInstance().whenReady();
2530
2536
  await KosCore.getInstance().modelManager.reloadModel(model);
2531
2537
  KosLog.debug(
@@ -3692,6 +3698,21 @@ function setupReplayHandler(topic, bufferSize) {
3692
3698
  replay(t, bufferSize);
3693
3699
  });
3694
3700
  }
3701
+ const isPrintable = (model) => typeof model.toJSON === "function";
3702
+ const isKosDataModel = (model) => model[DependencyModels] !== void 0;
3703
+ const isKosModelContainer = (model) => model.revision !== void 0 && model.index !== void 0;
3704
+ const resolveChild = (attribute) => {
3705
+ if (!attribute) return void 0;
3706
+ if (isKosDataModel(attribute)) return attribute;
3707
+ if (isKosModelContainer(attribute)) return attribute.data;
3708
+ if (attribute instanceof Map || attribute instanceof ObservableMap || attribute instanceof Set) {
3709
+ return Array.from(attribute.values()).filter(isKosDataModel);
3710
+ }
3711
+ if (Array.isArray(attribute)) {
3712
+ return attribute.filter(isKosDataModel);
3713
+ }
3714
+ return void 0;
3715
+ };
3695
3716
  const deletionMap = /* @__PURE__ */ new Map();
3696
3717
  const KosDeletionManager = {
3697
3718
  addToDeletionQueue: (modelId, timeout) => {
@@ -4182,21 +4203,6 @@ const rejectAfterDelay$1 = (ms, model, status) => {
4182
4203
  };
4183
4204
  return { promise, cancel };
4184
4205
  };
4185
- const isPrintable = (model) => typeof model.toJSON === "function";
4186
- const isKosDataModel = (model) => model[DependencyModels] !== void 0;
4187
- const isKosModelContainer = (model) => model.revision !== void 0 && model.index !== void 0;
4188
- const resolveChild = (attribute) => {
4189
- if (!attribute) return void 0;
4190
- if (isKosDataModel(attribute)) return attribute;
4191
- if (isKosModelContainer(attribute)) return attribute.data;
4192
- if (attribute instanceof Map || attribute instanceof ObservableMap || attribute instanceof Set) {
4193
- return Array.from(attribute.values()).filter(isKosDataModel);
4194
- }
4195
- if (Array.isArray(attribute)) {
4196
- return attribute.filter(isKosDataModel);
4197
- }
4198
- return void 0;
4199
- };
4200
4206
  const createModelDependency = (model, dependency) => {
4201
4207
  const _dataModelId = dependency.id || dependency.modelType;
4202
4208
  const dataModelId = resolveParameters({
@@ -9803,6 +9809,8 @@ class KosSubscriptionManager {
9803
9809
  const config2 = subscriptions2[topic];
9804
9810
  const topicLifecycle = config2.lifecycle;
9805
9811
  if (lifecycle && lifecycle !== topicLifecycle) return;
9812
+ if (!lifecycle && topicLifecycle === DependencyLifecycle.ACTIVATE && this.model.activeStatus !== KosModelState.ACTIVE)
9813
+ return;
9806
9814
  const resolvedTopic = this.resolvePropKey(topic);
9807
9815
  if (this.onceTopics.has(resolvedTopic)) {
9808
9816
  this.log.debug(`Skipping once topic (already fired): ${resolvedTopic}`);
@@ -9875,7 +9883,7 @@ class KosSubscriptionManager {
9875
9883
  this.registeredTopics.clear();
9876
9884
  }
9877
9885
  subscribe(subscription, topic, handler, activatable) {
9878
- const destinationAddress = subscription.destinationAddress ? this.resolvePropKey(subscription.destinationAddress) : null;
9886
+ const { destinationAddress, explicitDestination } = this.resolveDestination(subscription);
9879
9887
  if (subscription.websocket) {
9880
9888
  this.log.debug(`Subscribing to WebSocket topic: ${topic}`);
9881
9889
  const socketSub = WebSocketTransport.getInstance().subscribeTopic({
@@ -9884,7 +9892,7 @@ class KosSubscriptionManager {
9884
9892
  fos: subscription.fos,
9885
9893
  bridge: subscription.bridge,
9886
9894
  destinationAddress,
9887
- explicitDestination: subscription.explicitDestination
9895
+ explicitDestination
9888
9896
  });
9889
9897
  if (activatable) {
9890
9898
  this.activatableDisposers.push(socketSub);
@@ -9984,6 +9992,27 @@ class KosSubscriptionManager {
9984
9992
  );
9985
9993
  }
9986
9994
  }
9995
+ // A destination template whose model property is unset names no destination:
9996
+ // it resolves to null and is not treated as explicit, so the transport keeps
9997
+ // its connId fallback for that model.
9998
+ resolveDestination(subscription) {
9999
+ const template = subscription.destinationAddress;
10000
+ const explicitDestination = subscription.explicitDestination ?? false;
10001
+ if (!template) {
10002
+ return { destinationAddress: null, explicitDestination };
10003
+ }
10004
+ const match = template.match(/{PROP_(.+?)}/);
10005
+ if (match) {
10006
+ const value = this.modelData?.[match[1]];
10007
+ if (value === null || value === void 0) {
10008
+ return { destinationAddress: null, explicitDestination: false };
10009
+ }
10010
+ }
10011
+ return {
10012
+ destinationAddress: this.resolvePropKey(template),
10013
+ explicitDestination
10014
+ };
10015
+ }
9987
10016
  resolvePropKey(template) {
9988
10017
  const propRegex = /.*({PROP_(.+)})/;
9989
10018
  let topic = template.includes("{MODEL_ID}") ? template.replace("{MODEL_ID}", this.modelId) : template;
@@ -10023,7 +10052,7 @@ class KosSubscriptionManager {
10023
10052
  try {
10024
10053
  let eventSource;
10025
10054
  if (config2.websocket) {
10026
- const destinationAddress = config2.destinationAddress ? this.resolvePropKey(config2.destinationAddress) : null;
10055
+ const { destinationAddress, explicitDestination } = this.resolveDestination(config2);
10027
10056
  WebSocketTransport.getInstance().subscribeTopic({
10028
10057
  topic: resolvedTopic,
10029
10058
  callback: () => {
@@ -10032,7 +10061,7 @@ class KosSubscriptionManager {
10032
10061
  fos: config2.fos,
10033
10062
  bridge: config2.bridge,
10034
10063
  destinationAddress,
10035
- explicitDestination: config2.explicitDestination
10064
+ explicitDestination
10036
10065
  });
10037
10066
  eventSource = iterate(resolvedTopic);
10038
10067
  } else {
@@ -10905,6 +10934,20 @@ class KosModel {
10905
10934
  );
10906
10935
  this.subscriptionManager?.registerAll(lifecycle);
10907
10936
  }
10937
+ /**
10938
+ * The counterpart of `unload()` for a reload that keeps the instance: every
10939
+ * manager `unload()` disposed comes back, not only the subscriptions.
10940
+ * @internal
10941
+ */
10942
+ restoreAfterReload() {
10943
+ this.onlineLifecycleManager?.register();
10944
+ this.subscriptionManager?.registerAll();
10945
+ this.httpRouteManager?.registerAll();
10946
+ this.effectManager?.setup();
10947
+ kosAction(() => {
10948
+ this.loaded = true;
10949
+ });
10950
+ }
10908
10951
  /**
10909
10952
  * Initialize the state machine for a specific lifecycle phase.
10910
10953
  * Called from lifecycle hooks (init, load, ready, activate).
@@ -11305,6 +11348,10 @@ class KosModelManager {
11305
11348
  * by its ID, it transitions the model to the RESETTING state using the
11306
11349
  * RESET event.
11307
11350
  *
11351
+ * @deprecated The reset route re-runs load() and ready() only and loses the
11352
+ * handlers registered at INIT or with no lifecycle. Models refresh through
11353
+ * `reload()`, driven by KOS Core.
11354
+ *
11308
11355
  * @param model - The data model to be reloaded. Must implement the `IKosDataModel` interface.
11309
11356
  * The `id` property of the model is used to locate the corresponding model.
11310
11357
  *
@@ -11355,17 +11402,51 @@ class KosModelManager {
11355
11402
  * the following actions:
11356
11403
  * 1. Calls the `unload` method on the model, if it exists.
11357
11404
  * 2. Removes the model from the manager using the `removeModel` method.
11405
+ * 3. Releases the model's children (decorated children, container members,
11406
+ * companions) from the manager the same way, recursively.
11358
11407
  *
11359
11408
  * @throws This method does not explicitly throw errors, but any errors occurring
11360
11409
  * during the `unload` or `removeModel` operations will propagate to the caller.
11361
11410
  */
11362
11411
  async destroyModel(model) {
11363
11412
  if (model?.modelId && this.dependencies.canDestroy(model.modelId)) {
11413
+ const children = model.getChildren();
11364
11414
  await model.unload?.();
11365
11415
  this.removeModel(model);
11366
11416
  this.dependencies.removeAll(model.modelId);
11367
11417
  clearModelHookCacheEntry(model.modelId);
11368
- }
11418
+ this.emptyContainersOf(model);
11419
+ children.forEach((child) => this.releaseUnloadedChild(child));
11420
+ }
11421
+ }
11422
+ // Each container held as a child is emptied with one bulk removal, so its
11423
+ // indexes are recalculated once and its per-member observers are released.
11424
+ emptyContainersOf(model) {
11425
+ const data = model.modelData;
11426
+ const childKeys = Object.keys(data?.[ChildModels] || {});
11427
+ for (const key of childKeys) {
11428
+ const container = data[key];
11429
+ if (!isKosModelContainer(container)) continue;
11430
+ const ids = container.data.map((member) => member.id);
11431
+ if (ids.length) container.removeAll(ids);
11432
+ }
11433
+ }
11434
+ // A destroyed model's unload() has already unloaded its children; only the
11435
+ // registry half of destruction is left for them. Never walks dependencies:
11436
+ // a child something else depends on stays registered, and a child already
11437
+ // removed or queued for deletion is left to that path.
11438
+ releaseUnloadedChild(child) {
11439
+ const { modelId } = child;
11440
+ if (!this.getModelById(modelId)) return;
11441
+ if (!this.dependencies.canDestroy(modelId)) return;
11442
+ const grandchildren = child.getChildren();
11443
+ this.removeModel(child);
11444
+ this.dependencies.removeAll(modelId);
11445
+ clearModelHookCacheEntry(modelId);
11446
+ this.emptyContainersOf(child);
11447
+ grandchildren.forEach(
11448
+ (grandchild) => this.releaseUnloadedChild(grandchild)
11449
+ );
11369
11450
  }
11370
11451
  /**
11371
11452
  * Creates an instance of a model based on the specified type ID and optional model ID.
@@ -11752,30 +11833,13 @@ class KosCore {
11752
11833
  this.transport.token = data.body;
11753
11834
  }
11754
11835
  });
11755
- subscribe(WebSocketEvents.DISCONNECTED, async () => {
11756
- await Promise.allSettled(
11757
- this.modelManager.models.map(async (model) => {
11758
- try {
11759
- await model.offline?.();
11760
- } catch (e) {
11761
- log$5.error(`model ${model.modelId} offline() threw:`, e);
11762
- }
11763
- model.onlineLifecycleManager?.dispose();
11764
- })
11765
- );
11836
+ subscribe(WebSocketEvents.DISCONNECTED, () => {
11766
11837
  this.fsmService.service.send(KosCoreEvents.GO_OFFLINE);
11767
11838
  });
11768
11839
  subscribe(WebSocketEvents.CONNECTED, async () => {
11769
11840
  await this.whenReady();
11770
- await Promise.allSettled(
11771
- this.modelManager.models.map(async (model) => {
11772
- model.onlineLifecycleManager?.register();
11773
- try {
11774
- await model.online?.();
11775
- } catch (e) {
11776
- log$5.error(`model ${model.modelId} online() threw:`, e);
11777
- }
11778
- })
11841
+ this.modelManager.models.forEach(
11842
+ (model) => model.onlineLifecycleManager?.register()
11779
11843
  );
11780
11844
  this.fsmService.service.send(KosCoreEvents.GO_ONLINE);
11781
11845
  });
@@ -11846,9 +11910,7 @@ class KosCore {
11846
11910
  continue;
11847
11911
  }
11848
11912
  log$5.info(`reloading model ${model.modelId}`);
11849
- model.unload?.();
11850
- await model.modelData.reload();
11851
- model.registerSubscribers?.();
11913
+ await this.reloadModel(model, model.modelData);
11852
11914
  log$5.info(`reloading model ${model.modelId} complete`);
11853
11915
  }
11854
11916
  }
@@ -11859,9 +11921,7 @@ class KosCore {
11859
11921
  continue;
11860
11922
  }
11861
11923
  log$5.warn(`reloading model ${model.modelId}`);
11862
- model.unload?.();
11863
- await model.modelData.reload();
11864
- model.registerSubscribers?.();
11924
+ await this.reloadModel(model, model.modelData);
11865
11925
  }
11866
11926
  }
11867
11927
  const elapsed = Date.now() - currentTime;
@@ -11872,6 +11932,13 @@ class KosCore {
11872
11932
  });
11873
11933
  }, 1e3 - elapsed);
11874
11934
  }
11935
+ // unload() must finish before reload() starts, and whatever it disposed must
11936
+ // come back afterwards; the data model's reload() only refreshes data.
11937
+ async reloadModel(model, data) {
11938
+ await model.unload?.();
11939
+ await data.reload();
11940
+ model.restoreAfterReload?.();
11941
+ }
11875
11942
  async online() {
11876
11943
  log$5.debug("KOS Core going online");
11877
11944
  await this._transport.whenReady();
@@ -13537,4 +13604,4 @@ export {
13537
13604
  ObservableData as y,
13538
13605
  kosAction as z
13539
13606
  };
13540
- //# sourceMappingURL=index-BUwbSjst.js.map
13607
+ //# sourceMappingURL=index-YzHb2lnB.js.map