@memberjunction/react-runtime 5.25.0 → 5.27.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.
@@ -19975,6 +19975,20 @@ var BaseInfo = /*#__PURE__*/function () {
19975
19975
  this.copyInitData(initData);
19976
19976
  }
19977
19977
  }
19978
+ /**
19979
+ * Default JSON serialization for BaseInfo subclasses.
19980
+ *
19981
+ * Emits all non-underscored direct field declarations. For `_`-prefixed private backing fields
19982
+ * (the MJ pattern for collection storage — e.g. `_Fields`, `_RelatedEntities`, `_OrganicKeys`),
19983
+ * emits the value of the corresponding same-named public getter instead. Purely computed getters
19984
+ * without a backing field (display-name formatters, derived flags) are intentionally skipped —
19985
+ * they can throw when source fields are null and don't belong on the wire anyway.
19986
+ *
19987
+ * Nested BaseInfo instances and arrays of them unwrap automatically via JSON.stringify's
19988
+ * native toJSON() protocol.
19989
+ *
19990
+ * Subclasses may override to emit a filtered subset or custom shape (see EntityFieldValueInfo).
19991
+ */
19978
19992
  return _createClass(BaseInfo, [{
19979
19993
  key: "copyInitData",
19980
19994
  value:
@@ -20003,6 +20017,32 @@ var BaseInfo = /*#__PURE__*/function () {
20003
20017
  }
20004
20018
  }
20005
20019
  }
20020
+ }, {
20021
+ key: "toJSON",
20022
+ value: function toJSON() {
20023
+ var result = {};
20024
+ var self = this;
20025
+ for (var _i = 0, _Object$keys = Object.keys(this); _i < _Object$keys.length; _i++) {
20026
+ var key = _Object$keys[_i];
20027
+ if (!key.startsWith('_')) {
20028
+ result[key] = self[key];
20029
+ continue;
20030
+ }
20031
+ // Private backing field — expose via its public getter if one exists with the same name minus the underscore
20032
+ var publicKey = key.slice(1);
20033
+ if (!publicKey) continue;
20034
+ var proto = Object.getPrototypeOf(this);
20035
+ while (proto && proto !== Object.prototype) {
20036
+ var desc = Object.getOwnPropertyDescriptor(proto, publicKey);
20037
+ if (desc && typeof desc.get === 'function') {
20038
+ result[publicKey] = self[publicKey];
20039
+ break;
20040
+ }
20041
+ proto = Object.getPrototypeOf(proto);
20042
+ }
20043
+ }
20044
+ return result;
20045
+ }
20006
20046
  }]);
20007
20047
  }();
20008
20048
  ;// ../../MJCore/dist/generic/platformVariants.js
@@ -22629,7 +22669,7 @@ var EntityOrganicKeyInfo = /*#__PURE__*/function (_BaseInfo3) {
22629
22669
  if (initData) {
22630
22670
  _this3.copyInitData(initData);
22631
22671
  _this3._RelatedEntities = [];
22632
- var re = initData.EntityOrganicKeyRelatedEntities || initData._RelatedEntities;
22672
+ var re = initData.EntityOrganicKeyRelatedEntities || initData._RelatedEntities || initData.RelatedEntities;
22633
22673
  if (re && Array.isArray(re)) {
22634
22674
  // sort by sequence
22635
22675
  var sorted = entityInfo_toConsumableArray(re);
@@ -22883,8 +22923,20 @@ var EntityFieldValueInfo = /*#__PURE__*/function (_BaseInfo6) {
22883
22923
  _this6.copyInitData(initData);
22884
22924
  return _this6;
22885
22925
  }
22926
+ /**
22927
+ * Returns a plain object suitable for JSON serialization.
22928
+ * Called automatically by JSON.stringify().
22929
+ */
22886
22930
  entityInfo_inherits(EntityFieldValueInfo, _BaseInfo6);
22887
- return entityInfo_createClass(EntityFieldValueInfo);
22931
+ return entityInfo_createClass(EntityFieldValueInfo, [{
22932
+ key: "toJSON",
22933
+ value: function toJSON() {
22934
+ return {
22935
+ Value: this.Value,
22936
+ Code: this.Code
22937
+ };
22938
+ }
22939
+ }]);
22888
22940
  }(BaseInfo);
22889
22941
  var GeneratedFormSectionType = {
22890
22942
  Top: 'Top',
@@ -23693,6 +23745,14 @@ var EntityInfo = /*#__PURE__*/function (_BaseInfo0) {
23693
23745
  * since those inserts bypass BaseEntity and never trigger cache invalidation.
23694
23746
  */
23695
23747
  _this0.TrustServerCacheCompletely = true;
23748
+ /**
23749
+ * Controls whether this entity participates in server-side and client-side
23750
+ * caching at all. When false (default for non-__mj entities), the entire
23751
+ * cache code path is short-circuited: no PreRunView cache check, no
23752
+ * auto-cache storage, no HandleBaseEntityEvent fingerprint scan, no
23753
+ * client-side IndexedDB cache. Zero overhead on hot save/query paths.
23754
+ */
23755
+ _this0.AllowCaching = false;
23696
23756
  /**
23697
23757
  * Whether this entity is available through the GraphQL API
23698
23758
  */
@@ -23937,9 +23997,9 @@ var EntityInfo = /*#__PURE__*/function (_BaseInfo0) {
23937
23997
  if (initData) {
23938
23998
  _this0.copyInitData(initData);
23939
23999
  // do some special handling to create class instances instead of just data objects
23940
- // copy the Entity Fields
24000
+ // copy the Entity Fields (accept EntityFields, _Fields, or Fields as input names)
23941
24001
  _this0._Fields = [];
23942
- var ef = initData.EntityFields || initData._Fields;
24002
+ var ef = initData.EntityFields || initData._Fields || initData.Fields;
23943
24003
  if (ef) {
23944
24004
  for (var j = 0; j < ef.length; j++) {
23945
24005
  _this0._Fields.push(new EntityFieldInfo(ef[j]));
@@ -23963,9 +24023,9 @@ var EntityInfo = /*#__PURE__*/function (_BaseInfo0) {
23963
24023
  }
23964
24024
  // auto-populate FieldCategories from the FieldCategoryInfo setting
23965
24025
  _this0._FieldCategories = _this0.parseFieldCategoriesFromSettings();
23966
- // copy the Related Entities
24026
+ // copy the Related Entities (accept EntityRelationships, _RelatedEntities, or RelatedEntities as input names)
23967
24027
  _this0._RelatedEntities = [];
23968
- var er = initData.EntityRelationships || initData._RelatedEntities;
24028
+ var er = initData.EntityRelationships || initData._RelatedEntities || initData.RelatedEntities;
23969
24029
  if (er) {
23970
24030
  // check to see if ANY of the records in the er array have a non-null or non-zero sequence value. The reason is
23971
24031
  // if we have any sequence values populated we want to sort by that sequence, and we want to consider null to be a high number
@@ -24001,7 +24061,7 @@ var EntityInfo = /*#__PURE__*/function (_BaseInfo0) {
24001
24061
  }
24002
24062
  // copy the Organic Keys (sorted by sequence inside EntityOrganicKeyInfo constructor)
24003
24063
  _this0._OrganicKeys = [];
24004
- var ok = initData.EntityOrganicKeys || initData._OrganicKeys;
24064
+ var ok = initData.EntityOrganicKeys || initData._OrganicKeys || initData.OrganicKeys;
24005
24065
  if (ok && Array.isArray(ok)) {
24006
24066
  var _iterator3 = entityInfo_createForOfIteratorHelper(ok),
24007
24067
  _step3;
@@ -32301,10 +32361,13 @@ var DEFAULT_CONFIG = {
32301
32361
  enabled: true,
32302
32362
  maxSizeBytes: 150 * 1024 * 1024,
32303
32363
  // 150MB
32304
- maxEntries: 5000,
32305
- defaultTTLMs: 5 * 60 * 1000,
32364
+ defaultTTLMs: 0,
32365
+ // No TTL event-based invalidation is the primary mechanism
32366
+ evictionPolicy: 'lru',
32367
+ maxPercentOfCachePerEntity: 50,
32368
+ evictionSweepIntervalMs: 300000,
32306
32369
  // 5 minutes
32307
- evictionPolicy: 'lru'
32370
+ verboseLogging: false
32308
32371
  };
32309
32372
  // ============================================================================
32310
32373
  // STORAGE CATEGORIES
@@ -32390,6 +32453,10 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
32390
32453
  */
32391
32454
  _this._changeCallbacks = new Map();
32392
32455
  _this._persistTimeout = null;
32456
+ /**
32457
+ * Handle for the periodic eviction sweep timer.
32458
+ */
32459
+ _this._sweepTimer = null;
32393
32460
  return _this;
32394
32461
  }
32395
32462
  // ========================================================================
@@ -32441,6 +32508,8 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
32441
32508
  return this.loadRegistry();
32442
32509
  case 1:
32443
32510
  this._initialized = true;
32511
+ // Start periodic eviction sweep for TTL-expired entries
32512
+ this.startEvictionSweep();
32444
32513
  // Subscribe to BaseEntity events for universal cache invalidation.
32445
32514
  // When any entity is saved/deleted, update all cached RunView results for that entity.
32446
32515
  this.subscribeToBaseEntityEvents();
@@ -32479,6 +32548,18 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
32479
32548
  value: function UpdateConfig(config) {
32480
32549
  this._config = localCacheManager_objectSpread(localCacheManager_objectSpread({}, this._config), config);
32481
32550
  }
32551
+ /**
32552
+ * Checks whether caching is enabled for a given entity. Returns the entity's
32553
+ * AllowCaching metadata flag. This is the single source of truth for cache
32554
+ * eligibility — schema-level opt-in is applied at CodeGen time via the
32555
+ * `newEntityDefaults.AllowCachingBySchema` config, which flips this flag when
32556
+ * the entity is first inserted into the metadata.
32557
+ */
32558
+ }, {
32559
+ key: "IsCachingEnabledForEntity",
32560
+ value: function IsCachingEnabledForEntity(entityInfo) {
32561
+ return entityInfo.AllowCaching === true;
32562
+ }
32482
32563
  /**
32483
32564
  * Replaces the storage provider after initialization. This is needed when
32484
32565
  * the initial provider (e.g., in-memory) needs to be swapped for a
@@ -32694,72 +32775,78 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
32694
32775
  }
32695
32776
  return _context3.a(2);
32696
32777
  case 1:
32697
- entityName = baseEntity.EntityInfo.Name;
32698
- fingerprints = this._entityFingerprintIndex.get(entityName);
32699
- if (!(!fingerprints || fingerprints.size === 0)) {
32778
+ entityName = baseEntity.EntityInfo.Name; // Short-circuit: if caching is disabled for this entity, skip the fingerprint scan
32779
+ if (this.IsCachingEnabledForEntity(baseEntity.EntityInfo)) {
32700
32780
  _context3.n = 2;
32701
32781
  break;
32702
32782
  }
32703
32783
  return _context3.a(2);
32704
32784
  case 2:
32705
- primaryKeys = baseEntity.EntityInfo.PrimaryKeys;
32706
- if (!(!primaryKeys || primaryKeys.length === 0)) {
32785
+ fingerprints = this._entityFingerprintIndex.get(entityName);
32786
+ if (!(!fingerprints || fingerprints.size === 0)) {
32707
32787
  _context3.n = 3;
32708
32788
  break;
32709
32789
  }
32710
32790
  return _context3.a(2);
32711
32791
  case 3:
32792
+ primaryKeys = baseEntity.EntityInfo.PrimaryKeys;
32793
+ if (!(!primaryKeys || primaryKeys.length === 0)) {
32794
+ _context3.n = 4;
32795
+ break;
32796
+ }
32797
+ return _context3.a(2);
32798
+ case 4:
32712
32799
  // Build a CompositeKey from the entity's primary key fields
32713
32800
  key = new CompositeKey();
32714
32801
  key.LoadFromEntityInfoAndRecord(baseEntity.EntityInfo, baseEntity.GetAll());
32715
32802
  if (!(key.KeyValuePairs.length === 0 || key.KeyValuePairs.some(function (kv) {
32716
32803
  return kv.Value == null;
32717
32804
  }))) {
32718
- _context3.n = 4;
32805
+ _context3.n = 5;
32719
32806
  break;
32720
32807
  }
32721
32808
  return _context3.a(2);
32722
- case 4:
32809
+ case 5:
32723
32810
  LogStatusVerbose("LocalCacheManager: BaseEntity ".concat(entityEvent.type, " event for \"").concat(entityName, "\" PK=").concat(key.ToConcatenatedString(), ", updating ").concat(fingerprints.size, " cached fingerprint(s)"));
32724
32811
  fingerprintSnapshot = localCacheManager_toConsumableArray(fingerprints);
32725
32812
  nowISO = new Date().toISOString();
32726
32813
  _iterator2 = localCacheManager_createForOfIteratorHelper(fingerprintSnapshot);
32727
- _context3.p = 5;
32814
+ _context3.p = 6;
32728
32815
  _iterator2.s();
32729
- case 6:
32816
+ case 7:
32730
32817
  if ((_step2 = _iterator2.n()).done) {
32731
- _context3.n = 11;
32818
+ _context3.n = 12;
32732
32819
  break;
32733
32820
  }
32734
32821
  fingerprint = _step2.value;
32735
- _context3.p = 7;
32736
- _context3.n = 8;
32822
+ _context3.p = 8;
32823
+ _context3.n = 9;
32737
32824
  return this.processEntityEventForFingerprint(entityEvent.type, fingerprint, baseEntity, key, nowISO);
32738
- case 8:
32739
- _context3.n = 10;
32740
- break;
32741
32825
  case 9:
32742
- _context3.p = 9;
32826
+ _context3.n = 11;
32827
+ break;
32828
+ case 10:
32829
+ _context3.p = 10;
32743
32830
  _t3 = _context3.v;
32744
32831
  LogError("HandleBaseEntityEvent: failed to update fingerprint \"".concat(fingerprint, "\": ").concat(_t3.message));
32745
- case 10:
32746
- _context3.n = 6;
32747
- break;
32748
32832
  case 11:
32749
- _context3.n = 13;
32833
+ _context3.n = 7;
32750
32834
  break;
32751
32835
  case 12:
32752
- _context3.p = 12;
32753
- _t4 = _context3.v;
32754
- _iterator2.e(_t4);
32836
+ _context3.n = 14;
32837
+ break;
32755
32838
  case 13:
32756
32839
  _context3.p = 13;
32757
- _iterator2.f();
32758
- return _context3.f(13);
32840
+ _t4 = _context3.v;
32841
+ _iterator2.e(_t4);
32759
32842
  case 14:
32843
+ _context3.p = 14;
32844
+ _iterator2.f();
32845
+ return _context3.f(14);
32846
+ case 15:
32760
32847
  return _context3.a(2);
32761
32848
  }
32762
- }, _callee3, this, [[7, 9], [5, 12, 13, 14]]);
32849
+ }, _callee3, this, [[8, 10], [6, 13, 14, 15]]);
32763
32850
  }));
32764
32851
  function HandleBaseEntityEvent(_x4) {
32765
32852
  return _HandleBaseEntityEvent.apply(this, arguments);
@@ -32777,7 +32864,7 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
32777
32864
  key: "HandleRemoteInvalidateEvent",
32778
32865
  value: (function () {
32779
32866
  var _HandleRemoteInvalidateEvent = localCacheManager_asyncToGenerator(/*#__PURE__*/localCacheManager_regenerator().m(function _callee4(entityEvent) {
32780
- var payload, entityName, fingerprints, action, md, entityInfo, _i, _arr, fp, primaryKeys, _i2, _arr2, _fp, nowISO, fingerprintSnapshot, key, _iterator3, _step3, _fp2, _iterator4, _step4, fingerprint, recordData, _key, _iterator5, _step5, _fingerprint, _iterator6, _step6, _fp3, _iterator7, _step7, _fp4, _t5, _t6, _t7, _t8, _t9, _t0, _t1, _t10;
32867
+ var payload, entityName, md, entityInfo, fingerprints, action, _i, _arr, fp, primaryKeys, _i2, _arr2, _fp, nowISO, fingerprintSnapshot, key, _iterator3, _step3, _fp2, _iterator4, _step4, fingerprint, recordData, _key, _iterator5, _step5, _fingerprint, _iterator6, _step6, _fp3, _iterator7, _step7, _fp4, _t5, _t6, _t7, _t8, _t9, _t0, _t1, _t10;
32781
32868
  return localCacheManager_regenerator().w(function (_context4) {
32782
32869
  while (1) switch (_context4.p = _context4.n) {
32783
32870
  case 0:
@@ -32789,141 +32876,148 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
32789
32876
  }
32790
32877
  return _context4.a(2);
32791
32878
  case 1:
32792
- fingerprints = this._entityFingerprintIndex.get(entityName);
32793
- if (!(!fingerprints || fingerprints.size === 0)) {
32879
+ // Short-circuit: if caching is disabled for this entity, skip processing
32880
+ md = new Metadata();
32881
+ entityInfo = md.EntityByName(entityName);
32882
+ if (!(entityInfo && !this.IsCachingEnabledForEntity(entityInfo))) {
32794
32883
  _context4.n = 2;
32795
32884
  break;
32796
32885
  }
32797
32886
  return _context4.a(2);
32798
32887
  case 2:
32799
- action = payload === null || payload === void 0 ? void 0 : payload.action; // Look up entity metadata for PK field names
32800
- md = new Metadata();
32801
- entityInfo = md.EntityByName(entityName);
32888
+ fingerprints = this._entityFingerprintIndex.get(entityName);
32889
+ if (!(!fingerprints || fingerprints.size === 0)) {
32890
+ _context4.n = 3;
32891
+ break;
32892
+ }
32893
+ return _context4.a(2);
32894
+ case 3:
32895
+ action = payload === null || payload === void 0 ? void 0 : payload.action; // entityInfo was looked up above for the AllowCaching check
32802
32896
  if (entityInfo) {
32803
- _context4.n = 6;
32897
+ _context4.n = 7;
32804
32898
  break;
32805
32899
  }
32806
32900
  LogStatusVerbose("LocalCacheManager: remote-invalidate \u2014 entity \"".concat(entityName, "\" not found in metadata, invalidating caches"));
32807
32901
  _i = 0, _arr = localCacheManager_toConsumableArray(fingerprints);
32808
- case 3:
32902
+ case 4:
32809
32903
  if (!(_i < _arr.length)) {
32810
- _context4.n = 5;
32904
+ _context4.n = 6;
32811
32905
  break;
32812
32906
  }
32813
32907
  fp = _arr[_i];
32814
- _context4.n = 4;
32908
+ _context4.n = 5;
32815
32909
  return this.InvalidateRunViewResult(fp);
32816
- case 4:
32910
+ case 5:
32817
32911
  _i++;
32818
- _context4.n = 3;
32912
+ _context4.n = 4;
32819
32913
  break;
32820
- case 5:
32821
- return _context4.a(2);
32822
32914
  case 6:
32915
+ return _context4.a(2);
32916
+ case 7:
32823
32917
  primaryKeys = entityInfo.PrimaryKeys;
32824
32918
  if (!(!primaryKeys || primaryKeys.length === 0)) {
32825
- _context4.n = 10;
32919
+ _context4.n = 11;
32826
32920
  break;
32827
32921
  }
32828
32922
  LogStatusVerbose("LocalCacheManager: remote-invalidate \u2014 no PKs for \"".concat(entityName, "\", invalidating ").concat(fingerprints.size, " cached fingerprint(s)"));
32829
32923
  _i2 = 0, _arr2 = localCacheManager_toConsumableArray(fingerprints);
32830
- case 7:
32924
+ case 8:
32831
32925
  if (!(_i2 < _arr2.length)) {
32832
- _context4.n = 9;
32926
+ _context4.n = 10;
32833
32927
  break;
32834
32928
  }
32835
32929
  _fp = _arr2[_i2];
32836
- _context4.n = 8;
32930
+ _context4.n = 9;
32837
32931
  return this.InvalidateRunViewResult(_fp);
32838
- case 8:
32932
+ case 9:
32839
32933
  _i2++;
32840
- _context4.n = 7;
32934
+ _context4.n = 8;
32841
32935
  break;
32842
- case 9:
32843
- return _context4.a(2);
32844
32936
  case 10:
32937
+ return _context4.a(2);
32938
+ case 11:
32845
32939
  nowISO = new Date().toISOString();
32846
32940
  fingerprintSnapshot = localCacheManager_toConsumableArray(fingerprints); // Handle delete: remove the record from all cached results
32847
32941
  if (!(action === 'delete')) {
32848
- _context4.n = 29;
32942
+ _context4.n = 30;
32849
32943
  break;
32850
32944
  }
32851
32945
  key = this.parseCompositeKeyFromJSON(payload === null || payload === void 0 ? void 0 : payload.primaryKeyValues);
32852
32946
  if (key) {
32853
- _context4.n = 18;
32947
+ _context4.n = 19;
32854
32948
  break;
32855
32949
  }
32856
32950
  LogStatusVerbose("LocalCacheManager: remote-invalidate (delete) \u2014 no PK values for \"".concat(entityName, "\", invalidating caches"));
32857
32951
  _iterator3 = localCacheManager_createForOfIteratorHelper(fingerprintSnapshot);
32858
- _context4.p = 11;
32952
+ _context4.p = 12;
32859
32953
  _iterator3.s();
32860
- case 12:
32954
+ case 13:
32861
32955
  if ((_step3 = _iterator3.n()).done) {
32862
- _context4.n = 14;
32956
+ _context4.n = 15;
32863
32957
  break;
32864
32958
  }
32865
32959
  _fp2 = _step3.value;
32866
- _context4.n = 13;
32960
+ _context4.n = 14;
32867
32961
  return this.InvalidateRunViewResult(_fp2);
32868
- case 13:
32869
- _context4.n = 12;
32870
- break;
32871
32962
  case 14:
32872
- _context4.n = 16;
32963
+ _context4.n = 13;
32873
32964
  break;
32874
32965
  case 15:
32875
- _context4.p = 15;
32876
- _t5 = _context4.v;
32877
- _iterator3.e(_t5);
32966
+ _context4.n = 17;
32967
+ break;
32878
32968
  case 16:
32879
32969
  _context4.p = 16;
32880
- _iterator3.f();
32881
- return _context4.f(16);
32970
+ _t5 = _context4.v;
32971
+ _iterator3.e(_t5);
32882
32972
  case 17:
32883
- return _context4.a(2);
32973
+ _context4.p = 17;
32974
+ _iterator3.f();
32975
+ return _context4.f(17);
32884
32976
  case 18:
32977
+ return _context4.a(2);
32978
+ case 19:
32885
32979
  LogStatusVerbose("LocalCacheManager: remote-invalidate (delete) for \"".concat(entityName, "\" PK=").concat(key.ToConcatenatedString(), ", removing from ").concat(fingerprints.size, " cached fingerprint(s)"));
32886
32980
  _iterator4 = localCacheManager_createForOfIteratorHelper(fingerprintSnapshot);
32887
- _context4.p = 19;
32981
+ _context4.p = 20;
32888
32982
  _iterator4.s();
32889
- case 20:
32983
+ case 21:
32890
32984
  if ((_step4 = _iterator4.n()).done) {
32891
- _context4.n = 25;
32985
+ _context4.n = 26;
32892
32986
  break;
32893
32987
  }
32894
32988
  fingerprint = _step4.value;
32895
- _context4.p = 21;
32896
- _context4.n = 22;
32989
+ _context4.p = 22;
32990
+ _context4.n = 23;
32897
32991
  return this.RemoveSingleEntity(fingerprint, key, nowISO);
32898
- case 22:
32899
- _context4.n = 24;
32900
- break;
32901
32992
  case 23:
32902
- _context4.p = 23;
32993
+ _context4.n = 25;
32994
+ break;
32995
+ case 24:
32996
+ _context4.p = 24;
32903
32997
  _t6 = _context4.v;
32904
32998
  LogError("HandleRemoteInvalidateEvent: failed to remove from \"".concat(fingerprint, "\": ").concat(_t6.message));
32905
- case 24:
32906
- _context4.n = 20;
32907
- break;
32908
32999
  case 25:
32909
- _context4.n = 27;
33000
+ _context4.n = 21;
32910
33001
  break;
32911
33002
  case 26:
32912
- _context4.p = 26;
32913
- _t7 = _context4.v;
32914
- _iterator4.e(_t7);
33003
+ _context4.n = 28;
33004
+ break;
32915
33005
  case 27:
32916
33006
  _context4.p = 27;
32917
- _iterator4.f();
32918
- return _context4.f(27);
33007
+ _t7 = _context4.v;
33008
+ _iterator4.e(_t7);
32919
33009
  case 28:
32920
- return _context4.a(2);
33010
+ _context4.p = 28;
33011
+ _iterator4.f();
33012
+ return _context4.f(28);
32921
33013
  case 29:
33014
+ return _context4.a(2);
33015
+ case 30:
32922
33016
  if (!(action === 'save' && payload !== null && payload !== void 0 && payload.recordData)) {
32923
- _context4.n = 52;
33017
+ _context4.n = 53;
32924
33018
  break;
32925
33019
  }
32926
- _context4.p = 30;
33020
+ _context4.p = 31;
32927
33021
  recordData = JSON.parse(payload.recordData); // Build CompositeKey from record data using entity PK fields
32928
33022
  _key = this.buildCompositeKeyFromRow(recordData, primaryKeys.map(function (pk) {
32929
33023
  return pk.Name;
@@ -32931,121 +33025,121 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
32931
33025
  if (!_key.KeyValuePairs.some(function (kv) {
32932
33026
  return kv.Value == null;
32933
33027
  })) {
32934
- _context4.n = 31;
33028
+ _context4.n = 32;
32935
33029
  break;
32936
33030
  }
32937
33031
  return _context4.a(2);
32938
- case 31:
33032
+ case 32:
32939
33033
  LogStatusVerbose("LocalCacheManager: remote-invalidate (save) for \"".concat(entityName, "\" PK=").concat(_key.ToConcatenatedString(), ", updating ").concat(fingerprints.size, " cached fingerprint(s)"));
32940
33034
  _iterator5 = localCacheManager_createForOfIteratorHelper(fingerprintSnapshot);
32941
- _context4.p = 32;
33035
+ _context4.p = 33;
32942
33036
  _iterator5.s();
32943
- case 33:
33037
+ case 34:
32944
33038
  if ((_step5 = _iterator5.n()).done) {
32945
- _context4.n = 40;
33039
+ _context4.n = 41;
32946
33040
  break;
32947
33041
  }
32948
33042
  _fingerprint = _step5.value;
32949
- _context4.p = 34;
33043
+ _context4.p = 35;
32950
33044
  if (this.isFilteredFingerprint(_fingerprint)) {
32951
- _context4.n = 36;
33045
+ _context4.n = 37;
32952
33046
  break;
32953
33047
  }
32954
- _context4.n = 35;
33048
+ _context4.n = 36;
32955
33049
  return this.UpsertSingleEntity(_fingerprint, recordData, _key, nowISO);
32956
- case 35:
32957
- _context4.n = 37;
32958
- break;
32959
33050
  case 36:
32960
- _context4.n = 37;
32961
- return this.InvalidateRunViewResult(_fingerprint);
32962
- case 37:
32963
- _context4.n = 39;
33051
+ _context4.n = 38;
32964
33052
  break;
33053
+ case 37:
33054
+ _context4.n = 38;
33055
+ return this.InvalidateRunViewResult(_fingerprint);
32965
33056
  case 38:
32966
- _context4.p = 38;
33057
+ _context4.n = 40;
33058
+ break;
33059
+ case 39:
33060
+ _context4.p = 39;
32967
33061
  _t8 = _context4.v;
32968
33062
  LogError("HandleRemoteInvalidateEvent: failed to update \"".concat(_fingerprint, "\": ").concat(_t8.message));
32969
- case 39:
32970
- _context4.n = 33;
32971
- break;
32972
33063
  case 40:
32973
- _context4.n = 42;
33064
+ _context4.n = 34;
32974
33065
  break;
32975
33066
  case 41:
32976
- _context4.p = 41;
32977
- _t9 = _context4.v;
32978
- _iterator5.e(_t9);
33067
+ _context4.n = 43;
33068
+ break;
32979
33069
  case 42:
32980
33070
  _context4.p = 42;
32981
- _iterator5.f();
32982
- return _context4.f(42);
33071
+ _t9 = _context4.v;
33072
+ _iterator5.e(_t9);
32983
33073
  case 43:
32984
- _context4.n = 51;
32985
- break;
33074
+ _context4.p = 43;
33075
+ _iterator5.f();
33076
+ return _context4.f(43);
32986
33077
  case 44:
32987
- _context4.p = 44;
33078
+ _context4.n = 52;
33079
+ break;
33080
+ case 45:
33081
+ _context4.p = 45;
32988
33082
  _t0 = _context4.v;
32989
33083
  LogError("HandleRemoteInvalidateEvent: failed to parse recordData for \"".concat(entityName, "\": ").concat(_t0.message));
32990
33084
  _iterator6 = localCacheManager_createForOfIteratorHelper(fingerprintSnapshot);
32991
- _context4.p = 45;
33085
+ _context4.p = 46;
32992
33086
  _iterator6.s();
32993
- case 46:
33087
+ case 47:
32994
33088
  if ((_step6 = _iterator6.n()).done) {
32995
- _context4.n = 48;
33089
+ _context4.n = 49;
32996
33090
  break;
32997
33091
  }
32998
33092
  _fp3 = _step6.value;
32999
- _context4.n = 47;
33093
+ _context4.n = 48;
33000
33094
  return this.InvalidateRunViewResult(_fp3);
33001
- case 47:
33002
- _context4.n = 46;
33003
- break;
33004
33095
  case 48:
33005
- _context4.n = 50;
33096
+ _context4.n = 47;
33006
33097
  break;
33007
33098
  case 49:
33008
- _context4.p = 49;
33009
- _t1 = _context4.v;
33010
- _iterator6.e(_t1);
33099
+ _context4.n = 51;
33100
+ break;
33011
33101
  case 50:
33012
33102
  _context4.p = 50;
33013
- _iterator6.f();
33014
- return _context4.f(50);
33103
+ _t1 = _context4.v;
33104
+ _iterator6.e(_t1);
33015
33105
  case 51:
33016
- return _context4.a(2);
33106
+ _context4.p = 51;
33107
+ _iterator6.f();
33108
+ return _context4.f(51);
33017
33109
  case 52:
33110
+ return _context4.a(2);
33111
+ case 53:
33018
33112
  // Fallback: no record data or unrecognized action — invalidate
33019
33113
  LogStatusVerbose("LocalCacheManager: remote-invalidate (".concat(action || 'unknown', ") for \"").concat(entityName, "\", invalidating ").concat(fingerprints.size, " cached fingerprint(s)"));
33020
33114
  _iterator7 = localCacheManager_createForOfIteratorHelper(fingerprintSnapshot);
33021
- _context4.p = 53;
33115
+ _context4.p = 54;
33022
33116
  _iterator7.s();
33023
- case 54:
33117
+ case 55:
33024
33118
  if ((_step7 = _iterator7.n()).done) {
33025
- _context4.n = 56;
33119
+ _context4.n = 57;
33026
33120
  break;
33027
33121
  }
33028
33122
  _fp4 = _step7.value;
33029
- _context4.n = 55;
33123
+ _context4.n = 56;
33030
33124
  return this.InvalidateRunViewResult(_fp4);
33031
- case 55:
33032
- _context4.n = 54;
33033
- break;
33034
33125
  case 56:
33035
- _context4.n = 58;
33126
+ _context4.n = 55;
33036
33127
  break;
33037
33128
  case 57:
33038
- _context4.p = 57;
33039
- _t10 = _context4.v;
33040
- _iterator7.e(_t10);
33129
+ _context4.n = 59;
33130
+ break;
33041
33131
  case 58:
33042
33132
  _context4.p = 58;
33043
- _iterator7.f();
33044
- return _context4.f(58);
33133
+ _t10 = _context4.v;
33134
+ _iterator7.e(_t10);
33045
33135
  case 59:
33136
+ _context4.p = 59;
33137
+ _iterator7.f();
33138
+ return _context4.f(59);
33139
+ case 60:
33046
33140
  return _context4.a(2);
33047
33141
  }
33048
- }, _callee4, this, [[53, 57, 58, 59], [45, 49, 50, 51], [34, 38], [32, 41, 42, 43], [30, 44], [21, 23], [19, 26, 27, 28], [11, 15, 16, 17]]);
33142
+ }, _callee4, this, [[54, 58, 59, 60], [46, 50, 51, 52], [35, 39], [33, 42, 43, 44], [31, 45], [22, 24], [20, 27, 28, 29], [12, 16, 17, 18]]);
33049
33143
  }));
33050
33144
  function HandleRemoteInvalidateEvent(_x5) {
33051
33145
  return _HandleRemoteInvalidateEvent.apply(this, arguments);
@@ -33624,7 +33718,7 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
33624
33718
  key: "SetRunViewResult",
33625
33719
  value: (function () {
33626
33720
  var _SetRunViewResult = localCacheManager_asyncToGenerator(/*#__PURE__*/localCacheManager_regenerator().m(function _callee1(fingerprint, params, results, maxUpdatedAt, aggregateResults, totalRowCount) {
33627
- var data, value, sizeBytes, _params$Aggregates$le, _params$Aggregates, _t16;
33721
+ var data, value, sizeBytes, entityName, _params$Aggregates$le, _params$Aggregates, _t16;
33628
33722
  return localCacheManager_regenerator().w(function (_context1) {
33629
33723
  while (1) switch (_context1.p = _context1.n) {
33630
33724
  case 0:
@@ -33646,14 +33740,18 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
33646
33740
  data.totalRowCount = totalRowCount;
33647
33741
  }
33648
33742
  value = JSON.stringify(data);
33649
- sizeBytes = this.estimateSize(value); // Check if we need to evict entries
33743
+ sizeBytes = this.estimateSize(value); // Per-entity memory limit: evict oldest entries for this entity if over budget
33744
+ entityName = params.EntityName || 'Unknown';
33650
33745
  _context1.n = 2;
33651
- return this.evictIfNeeded(sizeBytes);
33746
+ return this.enforcePerEntityMemoryLimit(entityName, sizeBytes);
33652
33747
  case 2:
33653
- _context1.p = 2;
33654
33748
  _context1.n = 3;
33655
- return this._storageProvider.SetItem(fingerprint, value, CacheCategory.RunViewCache);
33749
+ return this.evictIfNeeded(sizeBytes);
33656
33750
  case 3:
33751
+ _context1.p = 3;
33752
+ _context1.n = 4;
33753
+ return this._storageProvider.SetItem(fingerprint, value, CacheCategory.RunViewCache);
33754
+ case 4:
33657
33755
  this.registerEntry({
33658
33756
  key: fingerprint,
33659
33757
  type: 'runview',
@@ -33677,16 +33775,16 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
33677
33775
  // Maintain entity→fingerprint reverse index for universal cache invalidation
33678
33776
  this.addToEntityIndex(fingerprint);
33679
33777
  LogStatusVerbose("LocalCacheManager.SetRunViewResult: Cached ".concat(results.length, " rows for \"").concat(fingerprint.substring(0, 60), "\" (").concat(sizeBytes, " bytes)"));
33680
- _context1.n = 5;
33778
+ _context1.n = 6;
33681
33779
  break;
33682
- case 4:
33683
- _context1.p = 4;
33780
+ case 5:
33781
+ _context1.p = 5;
33684
33782
  _t16 = _context1.v;
33685
33783
  LogError("LocalCacheManager.SetRunViewResult failed: ".concat(_t16));
33686
- case 5:
33784
+ case 6:
33687
33785
  return _context1.a(2);
33688
33786
  }
33689
- }, _callee1, this, [[2, 4]]);
33787
+ }, _callee1, this, [[3, 5]]);
33690
33788
  }));
33691
33789
  function SetRunViewResult(_x25, _x26, _x27, _x28, _x29, _x30) {
33692
33790
  return _SetRunViewResult.apply(this, arguments);
@@ -35027,7 +35125,7 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
35027
35125
  key: "evictIfNeeded",
35028
35126
  value: (function () {
35029
35127
  var _evictIfNeeded = localCacheManager_asyncToGenerator(/*#__PURE__*/localCacheManager_regenerator().m(function _callee29(neededBytes) {
35030
- var stats, wouldExceedSize, wouldExceedCount, targetFreeBytes, targetFreeCount;
35128
+ var stats, wouldExceedSize, targetFreeBytes;
35031
35129
  return localCacheManager_regenerator().w(function (_context29) {
35032
35130
  while (1) switch (_context29.n) {
35033
35131
  case 0:
@@ -35039,18 +35137,17 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
35039
35137
  case 1:
35040
35138
  stats = this.GetStats();
35041
35139
  wouldExceedSize = stats.totalSizeBytes + neededBytes > this._config.maxSizeBytes;
35042
- wouldExceedCount = stats.totalEntries >= this._config.maxEntries;
35043
- if (!(!wouldExceedSize && !wouldExceedCount)) {
35140
+ if (wouldExceedSize) {
35044
35141
  _context29.n = 2;
35045
35142
  break;
35046
35143
  }
35047
35144
  return _context29.a(2);
35048
35145
  case 2:
35049
- // Calculate how much to free
35050
- targetFreeBytes = Math.max(neededBytes, this._config.maxSizeBytes * 0.1); // At least 10% of max
35051
- targetFreeCount = Math.max(1, Math.floor(this._config.maxEntries * 0.1)); // At least 10% of max
35146
+ // Calculate how much to free — at least the incoming entry's size, but
35147
+ // free 10% of total budget to avoid thrashing on every store.
35148
+ targetFreeBytes = Math.max(neededBytes, this._config.maxSizeBytes * 0.1);
35052
35149
  _context29.n = 3;
35053
- return this.evict(targetFreeBytes, targetFreeCount);
35150
+ return this.evict(targetFreeBytes);
35054
35151
  case 3:
35055
35152
  return _context29.a(2);
35056
35153
  }
@@ -35068,8 +35165,8 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
35068
35165
  }, {
35069
35166
  key: "evict",
35070
35167
  value: (function () {
35071
- var _evict = localCacheManager_asyncToGenerator(/*#__PURE__*/localCacheManager_regenerator().m(function _callee30(targetBytes, targetCount) {
35072
- var entries, freedBytes, freedCount, toDelete, _iterator20, _step20, _entry, _i5, _toDelete, key, entry, category, _t33, _t34, _t35;
35168
+ var _evict = localCacheManager_asyncToGenerator(/*#__PURE__*/localCacheManager_regenerator().m(function _callee30(targetBytes) {
35169
+ var entries, freedBytes, toDelete, _iterator20, _step20, _entry, _i5, _toDelete, key, entry, category, _t33, _t34, _t35;
35073
35170
  return localCacheManager_regenerator().w(function (_context30) {
35074
35171
  while (1) switch (_context30.p = _context30.n) {
35075
35172
  case 0:
@@ -35100,7 +35197,6 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
35100
35197
  return _context30.a(3, 5);
35101
35198
  case 5:
35102
35199
  freedBytes = 0;
35103
- freedCount = 0;
35104
35200
  toDelete = [];
35105
35201
  _iterator20 = localCacheManager_createForOfIteratorHelper(entries);
35106
35202
  _context30.p = 6;
@@ -35111,7 +35207,7 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
35111
35207
  break;
35112
35208
  }
35113
35209
  _entry = _step20.value;
35114
- if (!(freedBytes >= targetBytes && freedCount >= targetCount)) {
35210
+ if (!(freedBytes >= targetBytes)) {
35115
35211
  _context30.n = 8;
35116
35212
  break;
35117
35213
  }
@@ -35119,7 +35215,6 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
35119
35215
  case 8:
35120
35216
  toDelete.push(_entry.key);
35121
35217
  freedBytes += _entry.sizeBytes;
35122
- freedCount++;
35123
35218
  case 9:
35124
35219
  _context30.n = 7;
35125
35220
  break;
@@ -35185,10 +35280,282 @@ var LocalCacheManager = /*#__PURE__*/function (_BaseSingleton) {
35185
35280
  }
35186
35281
  }, _callee30, this, [[15, 18], [6, 11, 12, 13]]);
35187
35282
  }));
35188
- function evict(_x67, _x68) {
35283
+ function evict(_x67) {
35189
35284
  return _evict.apply(this, arguments);
35190
35285
  }
35191
35286
  return evict;
35287
+ }()
35288
+ /**
35289
+ * Returns the memory limit in bytes for a given entity based on
35290
+ * maxPercentOfCachePerEntity. Returns 0 if no limit applies.
35291
+ */
35292
+ )
35293
+ }, {
35294
+ key: "getEntityMemoryLimitBytes",
35295
+ value: function getEntityMemoryLimitBytes() {
35296
+ var pct = this._config.maxPercentOfCachePerEntity;
35297
+ if (pct <= 0) return 0;
35298
+ return Math.floor(this._config.maxSizeBytes * pct / 100);
35299
+ }
35300
+ /**
35301
+ * Enforces per-entity memory limits. When an entity's total cached bytes
35302
+ * (including the incoming entry) would exceed its limit, evicts the
35303
+ * least-recently-accessed entries for that entity until under the limit.
35304
+ * @param incomingSizeBytes - estimated size of the entry about to be stored
35305
+ */
35306
+ }, {
35307
+ key: "enforcePerEntityMemoryLimit",
35308
+ value: (function () {
35309
+ var _enforcePerEntityMemoryLimit = localCacheManager_asyncToGenerator(/*#__PURE__*/localCacheManager_regenerator().m(function _callee31(entityName, incomingSizeBytes) {
35310
+ var _this7 = this;
35311
+ var limitBytes, fingerprints, entries, totalBytes, bytesToFree, _iterator21, _step21, entry, category, _t36, _t37;
35312
+ return localCacheManager_regenerator().w(function (_context31) {
35313
+ while (1) switch (_context31.p = _context31.n) {
35314
+ case 0:
35315
+ limitBytes = this.getEntityMemoryLimitBytes();
35316
+ if (!(limitBytes <= 0 || !this._storageProvider)) {
35317
+ _context31.n = 1;
35318
+ break;
35319
+ }
35320
+ return _context31.a(2);
35321
+ case 1:
35322
+ fingerprints = this._entityFingerprintIndex.get(entityName);
35323
+ if (!(!fingerprints || fingerprints.size === 0)) {
35324
+ _context31.n = 2;
35325
+ break;
35326
+ }
35327
+ return _context31.a(2);
35328
+ case 2:
35329
+ // Sum up total bytes for this entity, including the incoming entry
35330
+ entries = localCacheManager_toConsumableArray(fingerprints).map(function (fp) {
35331
+ return _this7._registry.get(fp);
35332
+ }).filter(function (e) {
35333
+ return !!e;
35334
+ });
35335
+ totalBytes = entries.reduce(function (sum, e) {
35336
+ return sum + e.sizeBytes;
35337
+ }, 0) + incomingSizeBytes;
35338
+ if (!(totalBytes <= limitBytes)) {
35339
+ _context31.n = 3;
35340
+ break;
35341
+ }
35342
+ return _context31.a(2);
35343
+ case 3:
35344
+ // Sort by lastAccessedAt ascending (LRU first)
35345
+ entries.sort(function (a, b) {
35346
+ return a.lastAccessedAt - b.lastAccessedAt;
35347
+ });
35348
+ bytesToFree = totalBytes - limitBytes;
35349
+ if (this._config.verboseLogging) {
35350
+ LogStatusEx({
35351
+ message: " \uD83D\uDDD1\uFE0F [Cache PER-ENTITY EVICT] Entity \"".concat(entityName, "\" using ").concat((totalBytes / 1024 / 1024).toFixed(1), "MB (limit: ").concat((limitBytes / 1024 / 1024).toFixed(1), "MB), evicting LRU entries"),
35352
+ verboseOnly: true
35353
+ });
35354
+ }
35355
+ _iterator21 = localCacheManager_createForOfIteratorHelper(entries);
35356
+ _context31.p = 4;
35357
+ _iterator21.s();
35358
+ case 5:
35359
+ if ((_step21 = _iterator21.n()).done) {
35360
+ _context31.n = 10;
35361
+ break;
35362
+ }
35363
+ entry = _step21.value;
35364
+ if (!(bytesToFree <= 0)) {
35365
+ _context31.n = 6;
35366
+ break;
35367
+ }
35368
+ return _context31.a(3, 10);
35369
+ case 6:
35370
+ _context31.p = 6;
35371
+ category = this.getCategoryForType(entry.type);
35372
+ _context31.n = 7;
35373
+ return this._storageProvider.Remove(entry.key, category);
35374
+ case 7:
35375
+ this.removeFromEntityIndex(entry.key);
35376
+ bytesToFree -= entry.sizeBytes;
35377
+ this._registry.delete(entry.key);
35378
+ _context31.n = 9;
35379
+ break;
35380
+ case 8:
35381
+ _context31.p = 8;
35382
+ _t36 = _context31.v;
35383
+ case 9:
35384
+ _context31.n = 5;
35385
+ break;
35386
+ case 10:
35387
+ _context31.n = 12;
35388
+ break;
35389
+ case 11:
35390
+ _context31.p = 11;
35391
+ _t37 = _context31.v;
35392
+ _iterator21.e(_t37);
35393
+ case 12:
35394
+ _context31.p = 12;
35395
+ _iterator21.f();
35396
+ return _context31.f(12);
35397
+ case 13:
35398
+ this.debouncedPersistRegistry();
35399
+ case 14:
35400
+ return _context31.a(2);
35401
+ }
35402
+ }, _callee31, this, [[6, 8], [4, 11, 12, 13]]);
35403
+ }));
35404
+ function enforcePerEntityMemoryLimit(_x68, _x69) {
35405
+ return _enforcePerEntityMemoryLimit.apply(this, arguments);
35406
+ }
35407
+ return enforcePerEntityMemoryLimit;
35408
+ }()
35409
+ /**
35410
+ * Starts the periodic eviction sweep timer. Called during initialization.
35411
+ * The sweep catches entries that should have been evicted (TTL expired)
35412
+ * but weren't because no new stores triggered eviction.
35413
+ */
35414
+ )
35415
+ }, {
35416
+ key: "startEvictionSweep",
35417
+ value: function startEvictionSweep() {
35418
+ var _this8 = this;
35419
+ this.stopEvictionSweep(); // Clear any existing timer
35420
+ var intervalMs = this._config.evictionSweepIntervalMs;
35421
+ if (intervalMs <= 0) return; // Disabled
35422
+ this._sweepTimer = setInterval(function () {
35423
+ _this8.runEvictionSweep().catch(function (err) {
35424
+ LogError("LocalCacheManager: eviction sweep failed: ".concat(err.message));
35425
+ });
35426
+ }, intervalMs);
35427
+ // Don't prevent Node.js process from exiting
35428
+ if (localCacheManager_typeof(this._sweepTimer) === 'object' && 'unref' in this._sweepTimer) {
35429
+ this._sweepTimer.unref();
35430
+ }
35431
+ }
35432
+ /**
35433
+ * Stops the periodic eviction sweep timer.
35434
+ */
35435
+ }, {
35436
+ key: "stopEvictionSweep",
35437
+ value: function stopEvictionSweep() {
35438
+ if (this._sweepTimer) {
35439
+ clearInterval(this._sweepTimer);
35440
+ this._sweepTimer = null;
35441
+ }
35442
+ }
35443
+ /**
35444
+ * Runs a single eviction sweep: evicts entries that have exceeded their TTL
35445
+ * or entries for entities that are over their per-entity cap.
35446
+ */
35447
+ }, {
35448
+ key: "runEvictionSweep",
35449
+ value: (function () {
35450
+ var _runEvictionSweep = localCacheManager_asyncToGenerator(/*#__PURE__*/localCacheManager_regenerator().m(function _callee32() {
35451
+ var now, ttlMs, toDelete, _iterator22, _step22, _step22$value, _key4, _entry2, _iterator23, _step23, key, entry, category, _t38, _t39, _t40;
35452
+ return localCacheManager_regenerator().w(function (_context32) {
35453
+ while (1) switch (_context32.p = _context32.n) {
35454
+ case 0:
35455
+ if (!(!this._storageProvider || !this._config.enabled)) {
35456
+ _context32.n = 1;
35457
+ break;
35458
+ }
35459
+ return _context32.a(2);
35460
+ case 1:
35461
+ now = Date.now();
35462
+ ttlMs = this._config.defaultTTLMs;
35463
+ toDelete = [];
35464
+ _iterator22 = localCacheManager_createForOfIteratorHelper(this._registry);
35465
+ _context32.p = 2;
35466
+ _iterator22.s();
35467
+ case 3:
35468
+ if ((_step22 = _iterator22.n()).done) {
35469
+ _context32.n = 6;
35470
+ break;
35471
+ }
35472
+ _step22$value = localCacheManager_slicedToArray(_step22.value, 2), _key4 = _step22$value[0], _entry2 = _step22$value[1];
35473
+ if (!(ttlMs > 0 && _entry2.cachedAt + ttlMs < now)) {
35474
+ _context32.n = 4;
35475
+ break;
35476
+ }
35477
+ toDelete.push(_key4);
35478
+ return _context32.a(3, 5);
35479
+ case 4:
35480
+ // expiresAt check (if set individually)
35481
+ if (_entry2.expiresAt && _entry2.expiresAt < now) {
35482
+ toDelete.push(_key4);
35483
+ }
35484
+ case 5:
35485
+ _context32.n = 3;
35486
+ break;
35487
+ case 6:
35488
+ _context32.n = 8;
35489
+ break;
35490
+ case 7:
35491
+ _context32.p = 7;
35492
+ _t38 = _context32.v;
35493
+ _iterator22.e(_t38);
35494
+ case 8:
35495
+ _context32.p = 8;
35496
+ _iterator22.f();
35497
+ return _context32.f(8);
35498
+ case 9:
35499
+ if (!(toDelete.length > 0)) {
35500
+ _context32.n = 20;
35501
+ break;
35502
+ }
35503
+ if (this._config.verboseLogging) {
35504
+ LogStatusEx({
35505
+ message: " \uD83D\uDDD1\uFE0F [Cache SWEEP] Evicting ".concat(toDelete.length, " TTL-expired entries"),
35506
+ verboseOnly: true
35507
+ });
35508
+ }
35509
+ _iterator23 = localCacheManager_createForOfIteratorHelper(toDelete);
35510
+ _context32.p = 10;
35511
+ _iterator23.s();
35512
+ case 11:
35513
+ if ((_step23 = _iterator23.n()).done) {
35514
+ _context32.n = 16;
35515
+ break;
35516
+ }
35517
+ key = _step23.value;
35518
+ _context32.p = 12;
35519
+ entry = this._registry.get(key);
35520
+ category = this.getCategoryForType(entry === null || entry === void 0 ? void 0 : entry.type);
35521
+ _context32.n = 13;
35522
+ return this._storageProvider.Remove(key, category);
35523
+ case 13:
35524
+ if (entry !== null && entry !== void 0 && entry.fingerprint) {
35525
+ this.removeFromEntityIndex(entry.fingerprint);
35526
+ }
35527
+ this._registry.delete(key);
35528
+ _context32.n = 15;
35529
+ break;
35530
+ case 14:
35531
+ _context32.p = 14;
35532
+ _t39 = _context32.v;
35533
+ case 15:
35534
+ _context32.n = 11;
35535
+ break;
35536
+ case 16:
35537
+ _context32.n = 18;
35538
+ break;
35539
+ case 17:
35540
+ _context32.p = 17;
35541
+ _t40 = _context32.v;
35542
+ _iterator23.e(_t40);
35543
+ case 18:
35544
+ _context32.p = 18;
35545
+ _iterator23.f();
35546
+ return _context32.f(18);
35547
+ case 19:
35548
+ _context32.n = 20;
35549
+ return this.persistRegistry();
35550
+ case 20:
35551
+ return _context32.a(2);
35552
+ }
35553
+ }, _callee32, this, [[12, 14], [10, 17, 18, 19], [2, 7, 8, 9]]);
35554
+ }));
35555
+ function runEvictionSweep() {
35556
+ return _runEvictionSweep.apply(this, arguments);
35557
+ }
35558
+ return runEvictionSweep;
35192
35559
  }())
35193
35560
  }], [{
35194
35561
  key: "Instance",
@@ -39408,6 +39775,9 @@ var ProviderBase = /*#__PURE__*/function () {
39408
39775
  if (!params.EntityName) return true; // View-based queries without entity name — allow caching
39409
39776
  var entity = this.EntityByName(params.EntityName);
39410
39777
  if (!entity) return true; // Entity not found — allow caching (will fail later anyway)
39778
+ // If caching is disabled for this entity (neither the per-entity flag nor the
39779
+ // schema-level config enables it), skip all cache operations.
39780
+ if (!LocalCacheManager.Instance.IsCachingEnabledForEntity(entity)) return false;
39411
39781
  // Always exempt Record Changes — rows are created via spCreateRecordChange_Internal
39412
39782
  // inside save SQL batches, never through BaseEntity.Save(), so the cache is never
39413
39783
  // invalidated by entity events. Even if TrustServerCacheCompletely is accidentally
@@ -54123,7 +54493,7 @@ function _regenerator(){/*! regenerator-runtime -- Copyright (c) 2014-present, F
54123
54493
  * zod schema definition for the entity MJ: Encryption Keys
54124
54494
  */var MJEncryptionKeySchema=z.object({ID:z.string().describe("\n * * Field Name: ID\n * * Display Name: ID\n * * SQL Data Type: uniqueidentifier\n * * Default Value: newsequentialid()\n * * Description: Unique identifier for the encryption key configuration."),Name:z.string().describe("\n * * Field Name: Name\n * * Display Name: Name\n * * SQL Data Type: nvarchar(100)\n * * Description: Unique name for this key (e.g., PII Master Key, API Secrets Key)."),Description:z.string().nullable().describe("\n * * Field Name: Description\n * * Display Name: Description\n * * SQL Data Type: nvarchar(MAX)\n * * Description: Description of this key purpose and scope."),EncryptionKeySourceID:z.string().describe("\n * * Field Name: EncryptionKeySourceID\n * * Display Name: Encryption Key Source ID\n * * SQL Data Type: uniqueidentifier\n * * Related Entity/Foreign Key: MJ: Encryption Key Sources (vwEncryptionKeySources.ID)\n * * Description: References the key source that provides the key material."),EncryptionAlgorithmID:z.string().describe("\n * * Field Name: EncryptionAlgorithmID\n * * Display Name: Encryption Algorithm ID\n * * SQL Data Type: uniqueidentifier\n * * Related Entity/Foreign Key: MJ: Encryption Algorithms (vwEncryptionAlgorithms.ID)\n * * Description: References the algorithm to use for encryption/decryption."),KeyLookupValue:z.string().describe("\n * * Field Name: KeyLookupValue\n * * Display Name: Key Lookup Value\n * * SQL Data Type: nvarchar(500)\n * * Description: Source-specific lookup value (e.g., environment variable name, vault path)."),KeyVersion:z.string().describe("\n * * Field Name: KeyVersion\n * * Display Name: Key Version\n * * SQL Data Type: nvarchar(20)\n * * Default Value: 1\n * * Description: Version string for key rotation tracking. Incremented during rotation."),Marker:z.string().describe("\n * * Field Name: Marker\n * * Display Name: Marker\n * * SQL Data Type: nvarchar(20)\n * * Default Value: $ENC$\n * * Description: Prefix marker for encrypted values (default: $ENC$)."),IsActive:z.boolean().describe("\n * * Field Name: IsActive\n * * Display Name: Is Active\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: Whether this key can be used for new encryption operations."),Status:z.union([z.literal('Active'),z.literal('Expired'),z.literal('Inactive'),z.literal('Rotating')]).describe("\n * * Field Name: Status\n * * Display Name: Status\n * * SQL Data Type: nvarchar(20)\n * * Default Value: Active\n * * Value List Type: List\n * * Possible Values \n * * Active\n * * Expired\n * * Inactive\n * * Rotating\n * * Description: Current status: Active, Inactive, Rotating, or Expired."),ActivatedAt:z.date().nullable().describe("\n * * Field Name: ActivatedAt\n * * Display Name: Activated At\n * * SQL Data Type: datetimeoffset\n * * Description: When the current key version was activated."),ExpiresAt:z.date().nullable().describe("\n * * Field Name: ExpiresAt\n * * Display Name: Expires At\n * * SQL Data Type: datetimeoffset\n * * Description: Optional expiration date. Keys past this date cannot be used for new encryption."),__mj_CreatedAt:z.date().describe("\n * * Field Name: __mj_CreatedAt\n * * Display Name: Created At\n * * SQL Data Type: datetimeoffset\n * * Default Value: getutcdate()"),__mj_UpdatedAt:z.date().describe("\n * * Field Name: __mj_UpdatedAt\n * * Display Name: Updated At\n * * SQL Data Type: datetimeoffset\n * * Default Value: getutcdate()"),EncryptionKeySource:z.string().describe("\n * * Field Name: EncryptionKeySource\n * * Display Name: Encryption Key Source\n * * SQL Data Type: nvarchar(100)"),EncryptionAlgorithm:z.string().describe("\n * * Field Name: EncryptionAlgorithm\n * * Display Name: Encryption Algorithm\n * * SQL Data Type: nvarchar(50)")});/**
54125
54495
  * zod schema definition for the entity MJ: Entities
54126
- */var MJEntitySchema=z.object({ID:z.string().describe("\n * * Field Name: ID\n * * Display Name: ID\n * * SQL Data Type: uniqueidentifier\n * * Default Value: newsequentialid()"),ParentID:z.string().nullable().describe("\n * * Field Name: ParentID\n * * Display Name: Parent\n * * SQL Data Type: uniqueidentifier\n * * Related Entity/Foreign Key: MJ: Entities (vwEntities.ID)"),Name:z.string().describe("\n * * Field Name: Name\n * * Display Name: Name\n * * SQL Data Type: nvarchar(255)\n * * Description: The canonical, unique name for this entity. For entities in schemas with an EntityNamePrefix configured (e.g., \"MJ: \" for the core schema), the Name includes the prefix: \"MJ: AI Models\", \"MJ: Users\", etc. This is the value used in GetEntityObject(), RunView({ EntityName }), and @RegisterClass decorators. The DisplayName column provides the shorter, UI-friendly alternative without the prefix."),NameSuffix:z.string().nullable().describe("\n * * Field Name: NameSuffix\n * * Display Name: Name Suffix\n * * SQL Data Type: nvarchar(255)\n * * Description: Optional suffix appended to entity names for display purposes."),Description:z.string().nullable().describe("\n * * Field Name: Description\n * * Display Name: Description\n * * SQL Data Type: nvarchar(MAX)"),AutoUpdateDescription:z.boolean().describe("\n * * Field Name: AutoUpdateDescription\n * * Display Name: Auto Update Description\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When set to 1 (default), whenever a description is modified in the underlying view (first choice) or table (second choice), the Description column in the entity definition will be automatically updated. If you never set metadata in the database directly, you can leave this alone. However, if you have metadata set in the database level for description, and you want to provide a DIFFERENT description in this entity definition, turn this bit off and then set the Description field and future CodeGen runs will NOT override the Description field here."),BaseTable:z.string().describe("\n * * Field Name: BaseTable\n * * Display Name: Base Table\n * * SQL Data Type: nvarchar(255)\n * * Description: The underlying database table name for this entity."),BaseView:z.string().describe("\n * * Field Name: BaseView\n * * Display Name: Base View\n * * SQL Data Type: nvarchar(255)\n * * Description: The \"wrapper\" database view used for querying this entity with joins and computed fields."),BaseViewGenerated:z.boolean().describe("\n * * Field Name: BaseViewGenerated\n * * Display Name: Base View Generated\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When set to 0, CodeGen no longer generates a base view for the entity."),SchemaName:z.string().describe("\n * * Field Name: SchemaName\n * * Display Name: Schema Name\n * * SQL Data Type: nvarchar(255)\n * * Default Value: dbo\n * * Description: Database schema containing this entity's table and view."),VirtualEntity:z.boolean().describe("\n * * Field Name: VirtualEntity\n * * Display Name: Virtual Entity\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: Indicates if this is a virtual entity without a physical database table."),TrackRecordChanges:z.boolean().describe("\n * * Field Name: TrackRecordChanges\n * * Display Name: Track Record Changes\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When set to 1, changes made via the MemberJunction architecture will result in tracking records being created in the RecordChange table. In addition, when turned on CodeGen will ensure that your table has two fields: __mj_CreatedAt and __mj_UpdatedAt which are special fields used in conjunction with the RecordChange table to track changes to rows in your entity."),AuditRecordAccess:z.boolean().describe("\n * * Field Name: AuditRecordAccess\n * * Display Name: Audit Record Access\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When set to 1, accessing a record by an end-user will result in an Audit Log record being created"),AuditViewRuns:z.boolean().describe("\n * * Field Name: AuditViewRuns\n * * Display Name: Audit View Runs\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When set to 1, users running a view against this entity will result in an Audit Log record being created."),IncludeInAPI:z.boolean().describe("\n * * Field Name: IncludeInAPI\n * * Display Name: Include In API\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: If set to 0, the entity will not be available at all in the GraphQL API or the object model."),AllowAllRowsAPI:z.boolean().describe("\n * * Field Name: AllowAllRowsAPI\n * * Display Name: Allow All Rows API\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: If set to 1, a GraphQL query will be enabled that allows access to all rows in the entity."),AllowUpdateAPI:z.boolean().describe("\n * * Field Name: AllowUpdateAPI\n * * Display Name: Allow Update API\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: Global flag controlling if updates are allowed for any user, or not. If set to 1, a GraqhQL mutation and stored procedure are created. Permissions are still required to perform the action but if this flag is set to 0, no user will be able to perform the action."),AllowCreateAPI:z.boolean().describe("\n * * Field Name: AllowCreateAPI\n * * Display Name: Allow Create API\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: Global flag controlling if creates are allowed for any user, or not. If set to 1, a GraqhQL mutation and stored procedure are created. Permissions are still required to perform the action but if this flag is set to 0, no user will be able to perform the action."),AllowDeleteAPI:z.boolean().describe("\n * * Field Name: AllowDeleteAPI\n * * Display Name: Allow Delete API\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: Global flag controlling if deletes are allowed for any user, or not. If set to 1, a GraqhQL mutation and stored procedure are created. Permissions are still required to perform the action but if this flag is set to 0, no user will be able to perform the action."),CustomResolverAPI:z.boolean().describe("\n * * Field Name: CustomResolverAPI\n * * Display Name: Custom Resolver API\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: Set to 1 if a custom resolver has been created for the entity."),AllowUserSearchAPI:z.boolean().describe("\n * * Field Name: AllowUserSearchAPI\n * * Display Name: Allow User Search\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: Enabling this bit will result in search being possible at the API and UI layers"),FullTextSearchEnabled:z.boolean().describe("\n * * Field Name: FullTextSearchEnabled\n * * Display Name: Full-Text Search Enabled\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: Whether full-text search indexing is enabled for this entity."),FullTextCatalog:z.string().nullable().describe("\n * * Field Name: FullTextCatalog\n * * Display Name: Full-Text Catalog\n * * SQL Data Type: nvarchar(255)\n * * Description: Name of the SQL Server full-text catalog if search is enabled."),FullTextCatalogGenerated:z.boolean().describe("\n * * Field Name: FullTextCatalogGenerated\n * * Display Name: Full-Text Catalog Generated\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: Indicates if the full-text catalog was auto-generated by CodeGen."),FullTextIndex:z.string().nullable().describe("\n * * Field Name: FullTextIndex\n * * Display Name: Full-Text Index\n * * SQL Data Type: nvarchar(255)\n * * Description: Name of the full-text index on this entity's table."),FullTextIndexGenerated:z.boolean().describe("\n * * Field Name: FullTextIndexGenerated\n * * Display Name: Full-Text Index Generated\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: Indicates if the full-text index was auto-generated by CodeGen."),FullTextSearchFunction:z.string().nullable().describe("\n * * Field Name: FullTextSearchFunction\n * * Display Name: Search Function\n * * SQL Data Type: nvarchar(255)\n * * Description: Name of the function used for full-text searching this entity."),FullTextSearchFunctionGenerated:z.boolean().describe("\n * * Field Name: FullTextSearchFunctionGenerated\n * * Display Name: Search Function Generated\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: Indicates if the search function was auto-generated by CodeGen."),UserViewMaxRows:z.number().nullable().describe("\n * * Field Name: UserViewMaxRows\n * * Display Name: User View Max Rows\n * * SQL Data Type: int\n * * Default Value: 1000\n * * Description: Maximum number of rows to return in user-created views for this entity."),spCreate:z.string().nullable().describe("\n * * Field Name: spCreate\n * * Display Name: Create Procedure\n * * SQL Data Type: nvarchar(255)\n * * Description: Name of the stored procedure for creating records in this entity."),spUpdate:z.string().nullable().describe("\n * * Field Name: spUpdate\n * * Display Name: Update Procedure\n * * SQL Data Type: nvarchar(255)\n * * Description: Name of the stored procedure for updating records in this entity."),spDelete:z.string().nullable().describe("\n * * Field Name: spDelete\n * * Display Name: Delete Procedure\n * * SQL Data Type: nvarchar(255)\n * * Description: Name of the stored procedure for deleting records in this entity."),spCreateGenerated:z.boolean().describe("\n * * Field Name: spCreateGenerated\n * * Display Name: Create SP Generated\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: Indicates if the create procedure was auto-generated by CodeGen."),spUpdateGenerated:z.boolean().describe("\n * * Field Name: spUpdateGenerated\n * * Display Name: Update SP Generated\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: Indicates if the update procedure was auto-generated by CodeGen."),spDeleteGenerated:z.boolean().describe("\n * * Field Name: spDeleteGenerated\n * * Display Name: Delete SP Generated\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: Indicates if the delete procedure was auto-generated by CodeGen."),CascadeDeletes:z.boolean().describe("\n * * Field Name: CascadeDeletes\n * * Display Name: Cascade Deletes\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: When set to 1, the deleted spDelete will pre-process deletion to related entities that have 1:M cardinality with this entity. This does not have effect if spDeleteGenerated = 0"),DeleteType:z.union([z.literal('Hard'),z.literal('Soft')]).describe("\n * * Field Name: DeleteType\n * * Display Name: Delete Type\n * * SQL Data Type: nvarchar(10)\n * * Default Value: Hard\n * * Value List Type: List\n * * Possible Values \n * * Hard\n * * Soft\n * * Description: Hard deletes physically remove rows from the underlying BaseTable. Soft deletes do not remove rows but instead mark the row as deleted by using the special field __mj_DeletedAt which will automatically be added to the entity's basetable by the CodeGen tool."),AllowRecordMerge:z.boolean().describe("\n * * Field Name: AllowRecordMerge\n * * Display Name: Allow Record Merge\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: This field must be turned on in order to enable merging of records for the entity. For AllowRecordMerge to be turned on, AllowDeleteAPI must be set to 1, and DeleteType must be set to Soft"),spMatch:z.string().nullable().describe("\n * * Field Name: spMatch\n * * Display Name: Match Procedure\n * * SQL Data Type: nvarchar(255)\n * * Description: When specified, this stored procedure is used to find matching records in this particular entity. The convention is to pass in the primary key(s) columns for the given entity to the procedure and the return will be zero to many rows where there is a column for each primary key field(s) and a ProbabilityScore (numeric(1,12)) column that has a 0 to 1 value of the probability of a match."),RelationshipDefaultDisplayType:z.union([z.literal('Dropdown'),z.literal('Search')]).describe("\n * * Field Name: RelationshipDefaultDisplayType\n * * Display Name: Default Relationship Display Type\n * * SQL Data Type: nvarchar(20)\n * * Default Value: Search\n * * Value List Type: List\n * * Possible Values \n * * Dropdown\n * * Search\n * * Description: When another entity links to this entity with a foreign key, this is the default component type that will be used in the UI. CodeGen will populate the RelatedEntityDisplayType column in the Entity Fields entity with whatever is provided here whenever a new foreign key is detected by CodeGen. The selection can be overridden on a per-foreign-key basis in each row of the Entity Fields entity."),UserFormGenerated:z.boolean().describe("\n * * Field Name: UserFormGenerated\n * * Display Name: User Form Generated\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: Indicates if the default user form was auto-generated for this entity."),EntityObjectSubclassName:z.string().nullable().describe("\n * * Field Name: EntityObjectSubclassName\n * * Display Name: Subclass Name\n * * SQL Data Type: nvarchar(255)\n * * Description: TypeScript class name for the entity subclass in the codebase."),EntityObjectSubclassImport:z.string().nullable().describe("\n * * Field Name: EntityObjectSubclassImport\n * * Display Name: Subclass Import Path\n * * SQL Data Type: nvarchar(255)\n * * Description: Import path for the entity subclass in the TypeScript codebase."),PreferredCommunicationField:z.string().nullable().describe("\n * * Field Name: PreferredCommunicationField\n * * Display Name: Preferred Communication Field\n * * SQL Data Type: nvarchar(255)\n * * Description: Used to specify a field within the entity that in turn contains the field name that will be used for record-level communication preferences. For example in a hypothetical entity called Contacts, say there is a field called PreferredComm and that field had possible values of Email1, SMS, and Phone, and those value in turn corresponded to field names in the entity. Each record in the Contacts entity could have a specific preference for which field would be used for communication. The MJ Communication Framework will use this information when available, as a priority ahead of the data in the Entity Communication Fields entity which is entity-level and not record-level."),Icon:z.string().nullable().describe("\n * * Field Name: Icon\n * * Display Name: Icon\n * * SQL Data Type: nvarchar(500)\n * * Description: Optional, specify an icon (CSS Class) for each entity for display in the UI"),__mj_CreatedAt:z.date().describe("\n * * Field Name: __mj_CreatedAt\n * * Display Name: Created At\n * * SQL Data Type: datetimeoffset\n * * Default Value: getutcdate()"),__mj_UpdatedAt:z.date().describe("\n * * Field Name: __mj_UpdatedAt\n * * Display Name: Updated At\n * * SQL Data Type: datetimeoffset\n * * Default Value: getutcdate()"),ScopeDefault:z.string().nullable().describe("\n * * Field Name: ScopeDefault\n * * Display Name: Default Scope\n * * SQL Data Type: nvarchar(100)\n * * Description: Optional, comma-delimited string indicating the default scope for entity visibility. Options include Users, Admins, AI, and All. Defaults to All when NULL. This is used for simple defaults for filtering entity visibility, not security enforcement."),RowsToPackWithSchema:z.union([z.literal('All'),z.literal('None'),z.literal('Sample')]).describe("\n * * Field Name: RowsToPackWithSchema\n * * Display Name: Rows To Pack\n * * SQL Data Type: nvarchar(20)\n * * Default Value: None\n * * Value List Type: List\n * * Possible Values \n * * All\n * * None\n * * Sample\n * * Description: Determines how entity rows should be packaged for external use. Options include None, Sample, and All. Defaults to None."),RowsToPackSampleMethod:z.union([z.literal('bottom n'),z.literal('random'),z.literal('top n')]).describe("\n * * Field Name: RowsToPackSampleMethod\n * * Display Name: Packing Sample Method\n * * SQL Data Type: nvarchar(20)\n * * Default Value: random\n * * Value List Type: List\n * * Possible Values \n * * bottom n\n * * random\n * * top n\n * * Description: Defines the sampling method for row packing when RowsToPackWithSchema is set to Sample. Options include random, top n, and bottom n. Defaults to random."),RowsToPackSampleCount:z.number().describe("\n * * Field Name: RowsToPackSampleCount\n * * Display Name: Packing Sample Count\n * * SQL Data Type: int\n * * Default Value: 0\n * * Description: The number of rows to pack when RowsToPackWithSchema is set to Sample, based on the designated sampling method. Defaults to 0."),RowsToPackSampleOrder:z.string().nullable().describe("\n * * Field Name: RowsToPackSampleOrder\n * * Display Name: Packing Sample Order\n * * SQL Data Type: nvarchar(MAX)\n * * Description: An optional ORDER BY clause for row packing when RowsToPackWithSchema is set to Sample. Allows custom ordering for selected entity data when using top n and bottom n."),AutoRowCountFrequency:z.number().nullable().describe("\n * * Field Name: AutoRowCountFrequency\n * * Display Name: Refresh Frequency (Hours)\n * * SQL Data Type: int\n * * Description: Frequency in hours for automatically performing row counts on this entity. If NULL, automatic row counting is disabled. If greater than 0, schedules recurring SELECT COUNT(*) queries at the specified interval."),RowCount:z.number().nullable().describe("\n * * Field Name: RowCount\n * * Display Name: Row Count\n * * SQL Data Type: bigint\n * * Description: Cached row count for this entity, populated by automatic row count processes when AutoRowCountFrequency is configured."),RowCountRunAt:z.date().nullable().describe("\n * * Field Name: RowCountRunAt\n * * Display Name: Last Counted At\n * * SQL Data Type: datetimeoffset\n * * Description: Timestamp indicating when the last automatic row count was performed for this entity."),Status:z.union([z.literal('Active'),z.literal('Deprecated'),z.literal('Disabled')]).describe("\n * * Field Name: Status\n * * Display Name: Status\n * * SQL Data Type: nvarchar(25)\n * * Default Value: Active\n * * Value List Type: List\n * * Possible Values \n * * Active\n * * Deprecated\n * * Disabled\n * * Description: Status of the entity. Active: fully functional; Deprecated: functional but generates console warnings when used; Disabled: not available for use even though metadata and physical table remain."),DisplayName:z.string().nullable().describe("\n * * Field Name: DisplayName\n * * Display Name: Display Name\n * * SQL Data Type: nvarchar(255)\n * * Description: User-friendly display name shown in the Explorer UI and other interfaces. When set, this is used instead of the entity Name for display purposes. Typically contains the entity name without the schema prefix \u2014 e.g., \"AI Models\" when Name is \"MJ: AI Models\". If NULL, the UI falls back to using the full Name."),AllowMultipleSubtypes:z.boolean().describe("\n * * Field Name: AllowMultipleSubtypes\n * * Display Name: Allow Multiple Subtypes\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: When false (default), child types are disjoint - a record can only be one child type at a time. When true, a record can simultaneously exist as multiple child types (e.g., a Person can be both a Member and a Volunteer)."),AutoUpdateFullTextSearch:z.boolean().describe("\n * * Field Name: AutoUpdateFullTextSearch\n * * Display Name: Auto Update Search Settings\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When true, CodeGen LLM can auto-configure full-text search settings (FullTextSearchEnabled, catalog, index, function) during code generation runs."),AutoUpdateAllowUserSearchAPI:z.boolean().describe("\n * * Field Name: AutoUpdateAllowUserSearchAPI\n * * Display Name: Auto Update Search API\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When true, CodeGen LLM can auto-set AllowUserSearchAPI during code generation runs."),TrustServerCacheCompletely:z.boolean().describe("\n * * Field Name: TrustServerCacheCompletely\n * * Display Name: Trust Server Cache\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When true (default), the server-side RunView cache will store and return cached results for this entity, trusting that all mutations flow through BaseEntity.Save() which fires cache invalidation events. Set to false for entities whose rows are created as side-effects of other operations via raw SQL (e.g., Record Changes created by spCreateRecordChange_Internal), since those inserts bypass BaseEntity and never trigger cache invalidation."),SupportsGeoCoding:z.boolean().describe("\n * * Field Name: SupportsGeoCoding\n * * Display Name: Supports Geo-Coding\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: When true, CodeGen generates geo-aware subclass code, adds __mj_Latitude/__mj_Longitude virtual fields to the base view, and the UI shows a map view toggle. Auto-set by CodeGen when LLM detects geo-capable fields (address, lat/lng, etc.)."),AutoUpdateSupportsGeoCoding:z.boolean().describe("\n * * Field Name: AutoUpdateSupportsGeoCoding\n * * Display Name: Auto Update Geo-Coding\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When true (default), CodeGen can automatically set SupportsGeoCoding based on LLM analysis of entity fields. Set to 0 to lock the value and prevent CodeGen from changing it."),CodeName:z.string().nullable().describe("\n * * Field Name: CodeName\n * * Display Name: Code Name\n * * SQL Data Type: nvarchar(MAX)\n * * Description: Schema-based programmatic code name derived from the entity Name. Uses GetClassNameSchemaPrefix(SchemaName) as the prefix, then strips EntityNamePrefix from the Name and removes spaces. For \"__mj\" schema with entity \"MJ: AI Models\", this produces \"MJAIModels\". For entities in other schemas, the sanitized schema name is prepended. Used in GraphQL type generation and internal code references."),ClassName:z.string().nullable().describe("\n * * Field Name: ClassName\n * * Display Name: Class Name\n * * SQL Data Type: nvarchar(MAX)\n * * Description: Schema-based programmatic class name used for TypeScript entity classes, Zod schemas, and Angular form components. Computed as GetProgrammaticName(GetClassNameSchemaPrefix(SchemaName) + BaseTable + NameSuffix). The prefix is derived from SchemaName (guaranteed unique by SQL Server), not from EntityNamePrefix. For the core __mj schema, the prefix is \"MJ\"; for all other schemas it is the alphanumeric-sanitized schema name. This prevents cross-schema collisions and aligns with GraphQL type naming in getGraphQLTypeNameBase()."),BaseTableCodeName:z.string().nullable().describe("\n * * Field Name: BaseTableCodeName\n * * Display Name: Base Table Code Name\n * * SQL Data Type: nvarchar(MAX)"),ParentEntity:z.string().nullable().describe("\n * * Field Name: ParentEntity\n * * Display Name: Parent Entity\n * * SQL Data Type: nvarchar(255)"),ParentBaseTable:z.string().nullable().describe("\n * * Field Name: ParentBaseTable\n * * Display Name: Parent Base Table\n * * SQL Data Type: nvarchar(255)"),ParentBaseView:z.string().nullable().describe("\n * * Field Name: ParentBaseView\n * * Display Name: Parent Base View\n * * SQL Data Type: nvarchar(255)")});/**
54496
+ */var MJEntitySchema=z.object({ID:z.string().describe("\n * * Field Name: ID\n * * Display Name: ID\n * * SQL Data Type: uniqueidentifier\n * * Default Value: newsequentialid()"),ParentID:z.string().nullable().describe("\n * * Field Name: ParentID\n * * Display Name: Parent\n * * SQL Data Type: uniqueidentifier\n * * Related Entity/Foreign Key: MJ: Entities (vwEntities.ID)"),Name:z.string().describe("\n * * Field Name: Name\n * * Display Name: Name\n * * SQL Data Type: nvarchar(255)\n * * Description: The canonical, unique name for this entity. For entities in schemas with an EntityNamePrefix configured (e.g., \"MJ: \" for the core schema), the Name includes the prefix: \"MJ: AI Models\", \"MJ: Users\", etc. This is the value used in GetEntityObject(), RunView({ EntityName }), and @RegisterClass decorators. The DisplayName column provides the shorter, UI-friendly alternative without the prefix."),NameSuffix:z.string().nullable().describe("\n * * Field Name: NameSuffix\n * * Display Name: Name Suffix\n * * SQL Data Type: nvarchar(255)\n * * Description: Optional suffix appended to entity names for display purposes."),Description:z.string().nullable().describe("\n * * Field Name: Description\n * * Display Name: Description\n * * SQL Data Type: nvarchar(MAX)"),AutoUpdateDescription:z.boolean().describe("\n * * Field Name: AutoUpdateDescription\n * * Display Name: Auto Update Description\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When set to 1 (default), whenever a description is modified in the underlying view (first choice) or table (second choice), the Description column in the entity definition will be automatically updated. If you never set metadata in the database directly, you can leave this alone. However, if you have metadata set in the database level for description, and you want to provide a DIFFERENT description in this entity definition, turn this bit off and then set the Description field and future CodeGen runs will NOT override the Description field here."),BaseTable:z.string().describe("\n * * Field Name: BaseTable\n * * Display Name: Base Table\n * * SQL Data Type: nvarchar(255)\n * * Description: The underlying database table name for this entity."),BaseView:z.string().describe("\n * * Field Name: BaseView\n * * Display Name: Base View\n * * SQL Data Type: nvarchar(255)\n * * Description: The \"wrapper\" database view used for querying this entity with joins and computed fields."),BaseViewGenerated:z.boolean().describe("\n * * Field Name: BaseViewGenerated\n * * Display Name: Base View Generated\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When set to 0, CodeGen no longer generates a base view for the entity."),SchemaName:z.string().describe("\n * * Field Name: SchemaName\n * * Display Name: Schema Name\n * * SQL Data Type: nvarchar(255)\n * * Default Value: dbo\n * * Description: Database schema containing this entity's table and view."),VirtualEntity:z.boolean().describe("\n * * Field Name: VirtualEntity\n * * Display Name: Virtual Entity\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: Indicates if this is a virtual entity without a physical database table."),TrackRecordChanges:z.boolean().describe("\n * * Field Name: TrackRecordChanges\n * * Display Name: Track Record Changes\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When set to 1, changes made via the MemberJunction architecture will result in tracking records being created in the RecordChange table. In addition, when turned on CodeGen will ensure that your table has two fields: __mj_CreatedAt and __mj_UpdatedAt which are special fields used in conjunction with the RecordChange table to track changes to rows in your entity."),AuditRecordAccess:z.boolean().describe("\n * * Field Name: AuditRecordAccess\n * * Display Name: Audit Record Access\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When set to 1, accessing a record by an end-user will result in an Audit Log record being created"),AuditViewRuns:z.boolean().describe("\n * * Field Name: AuditViewRuns\n * * Display Name: Audit View Runs\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When set to 1, users running a view against this entity will result in an Audit Log record being created."),IncludeInAPI:z.boolean().describe("\n * * Field Name: IncludeInAPI\n * * Display Name: Include In API\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: If set to 0, the entity will not be available at all in the GraphQL API or the object model."),AllowAllRowsAPI:z.boolean().describe("\n * * Field Name: AllowAllRowsAPI\n * * Display Name: Allow All Rows API\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: If set to 1, a GraphQL query will be enabled that allows access to all rows in the entity."),AllowUpdateAPI:z.boolean().describe("\n * * Field Name: AllowUpdateAPI\n * * Display Name: Allow Update API\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: Global flag controlling if updates are allowed for any user, or not. If set to 1, a GraqhQL mutation and stored procedure are created. Permissions are still required to perform the action but if this flag is set to 0, no user will be able to perform the action."),AllowCreateAPI:z.boolean().describe("\n * * Field Name: AllowCreateAPI\n * * Display Name: Allow Create API\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: Global flag controlling if creates are allowed for any user, or not. If set to 1, a GraqhQL mutation and stored procedure are created. Permissions are still required to perform the action but if this flag is set to 0, no user will be able to perform the action."),AllowDeleteAPI:z.boolean().describe("\n * * Field Name: AllowDeleteAPI\n * * Display Name: Allow Delete API\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: Global flag controlling if deletes are allowed for any user, or not. If set to 1, a GraqhQL mutation and stored procedure are created. Permissions are still required to perform the action but if this flag is set to 0, no user will be able to perform the action."),CustomResolverAPI:z.boolean().describe("\n * * Field Name: CustomResolverAPI\n * * Display Name: Custom Resolver API\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: Set to 1 if a custom resolver has been created for the entity."),AllowUserSearchAPI:z.boolean().describe("\n * * Field Name: AllowUserSearchAPI\n * * Display Name: Allow User Search\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: Enabling this bit will result in search being possible at the API and UI layers"),FullTextSearchEnabled:z.boolean().describe("\n * * Field Name: FullTextSearchEnabled\n * * Display Name: Full-Text Search Enabled\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: Whether full-text search indexing is enabled for this entity."),FullTextCatalog:z.string().nullable().describe("\n * * Field Name: FullTextCatalog\n * * Display Name: Full-Text Catalog\n * * SQL Data Type: nvarchar(255)\n * * Description: Name of the SQL Server full-text catalog if search is enabled."),FullTextCatalogGenerated:z.boolean().describe("\n * * Field Name: FullTextCatalogGenerated\n * * Display Name: Full-Text Catalog Generated\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: Indicates if the full-text catalog was auto-generated by CodeGen."),FullTextIndex:z.string().nullable().describe("\n * * Field Name: FullTextIndex\n * * Display Name: Full-Text Index\n * * SQL Data Type: nvarchar(255)\n * * Description: Name of the full-text index on this entity's table."),FullTextIndexGenerated:z.boolean().describe("\n * * Field Name: FullTextIndexGenerated\n * * Display Name: Full-Text Index Generated\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: Indicates if the full-text index was auto-generated by CodeGen."),FullTextSearchFunction:z.string().nullable().describe("\n * * Field Name: FullTextSearchFunction\n * * Display Name: Search Function\n * * SQL Data Type: nvarchar(255)\n * * Description: Name of the function used for full-text searching this entity."),FullTextSearchFunctionGenerated:z.boolean().describe("\n * * Field Name: FullTextSearchFunctionGenerated\n * * Display Name: Search Function Generated\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: Indicates if the search function was auto-generated by CodeGen."),UserViewMaxRows:z.number().nullable().describe("\n * * Field Name: UserViewMaxRows\n * * Display Name: User View Max Rows\n * * SQL Data Type: int\n * * Default Value: 1000\n * * Description: Maximum number of rows to return in user-created views for this entity."),spCreate:z.string().nullable().describe("\n * * Field Name: spCreate\n * * Display Name: Create Procedure\n * * SQL Data Type: nvarchar(255)\n * * Description: Name of the stored procedure for creating records in this entity."),spUpdate:z.string().nullable().describe("\n * * Field Name: spUpdate\n * * Display Name: Update Procedure\n * * SQL Data Type: nvarchar(255)\n * * Description: Name of the stored procedure for updating records in this entity."),spDelete:z.string().nullable().describe("\n * * Field Name: spDelete\n * * Display Name: Delete Procedure\n * * SQL Data Type: nvarchar(255)\n * * Description: Name of the stored procedure for deleting records in this entity."),spCreateGenerated:z.boolean().describe("\n * * Field Name: spCreateGenerated\n * * Display Name: Create SP Generated\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: Indicates if the create procedure was auto-generated by CodeGen."),spUpdateGenerated:z.boolean().describe("\n * * Field Name: spUpdateGenerated\n * * Display Name: Update SP Generated\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: Indicates if the update procedure was auto-generated by CodeGen."),spDeleteGenerated:z.boolean().describe("\n * * Field Name: spDeleteGenerated\n * * Display Name: Delete SP Generated\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: Indicates if the delete procedure was auto-generated by CodeGen."),CascadeDeletes:z.boolean().describe("\n * * Field Name: CascadeDeletes\n * * Display Name: Cascade Deletes\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: When set to 1, the deleted spDelete will pre-process deletion to related entities that have 1:M cardinality with this entity. This does not have effect if spDeleteGenerated = 0"),DeleteType:z.union([z.literal('Hard'),z.literal('Soft')]).describe("\n * * Field Name: DeleteType\n * * Display Name: Delete Type\n * * SQL Data Type: nvarchar(10)\n * * Default Value: Hard\n * * Value List Type: List\n * * Possible Values \n * * Hard\n * * Soft\n * * Description: Hard deletes physically remove rows from the underlying BaseTable. Soft deletes do not remove rows but instead mark the row as deleted by using the special field __mj_DeletedAt which will automatically be added to the entity's basetable by the CodeGen tool."),AllowRecordMerge:z.boolean().describe("\n * * Field Name: AllowRecordMerge\n * * Display Name: Allow Record Merge\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: This field must be turned on in order to enable merging of records for the entity. For AllowRecordMerge to be turned on, AllowDeleteAPI must be set to 1, and DeleteType must be set to Soft"),spMatch:z.string().nullable().describe("\n * * Field Name: spMatch\n * * Display Name: Match Procedure\n * * SQL Data Type: nvarchar(255)\n * * Description: When specified, this stored procedure is used to find matching records in this particular entity. The convention is to pass in the primary key(s) columns for the given entity to the procedure and the return will be zero to many rows where there is a column for each primary key field(s) and a ProbabilityScore (numeric(1,12)) column that has a 0 to 1 value of the probability of a match."),RelationshipDefaultDisplayType:z.union([z.literal('Dropdown'),z.literal('Search')]).describe("\n * * Field Name: RelationshipDefaultDisplayType\n * * Display Name: Default Relationship Display Type\n * * SQL Data Type: nvarchar(20)\n * * Default Value: Search\n * * Value List Type: List\n * * Possible Values \n * * Dropdown\n * * Search\n * * Description: When another entity links to this entity with a foreign key, this is the default component type that will be used in the UI. CodeGen will populate the RelatedEntityDisplayType column in the Entity Fields entity with whatever is provided here whenever a new foreign key is detected by CodeGen. The selection can be overridden on a per-foreign-key basis in each row of the Entity Fields entity."),UserFormGenerated:z.boolean().describe("\n * * Field Name: UserFormGenerated\n * * Display Name: User Form Generated\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: Indicates if the default user form was auto-generated for this entity."),EntityObjectSubclassName:z.string().nullable().describe("\n * * Field Name: EntityObjectSubclassName\n * * Display Name: Subclass Name\n * * SQL Data Type: nvarchar(255)\n * * Description: TypeScript class name for the entity subclass in the codebase."),EntityObjectSubclassImport:z.string().nullable().describe("\n * * Field Name: EntityObjectSubclassImport\n * * Display Name: Subclass Import Path\n * * SQL Data Type: nvarchar(255)\n * * Description: Import path for the entity subclass in the TypeScript codebase."),PreferredCommunicationField:z.string().nullable().describe("\n * * Field Name: PreferredCommunicationField\n * * Display Name: Preferred Communication Field\n * * SQL Data Type: nvarchar(255)\n * * Description: Used to specify a field within the entity that in turn contains the field name that will be used for record-level communication preferences. For example in a hypothetical entity called Contacts, say there is a field called PreferredComm and that field had possible values of Email1, SMS, and Phone, and those value in turn corresponded to field names in the entity. Each record in the Contacts entity could have a specific preference for which field would be used for communication. The MJ Communication Framework will use this information when available, as a priority ahead of the data in the Entity Communication Fields entity which is entity-level and not record-level."),Icon:z.string().nullable().describe("\n * * Field Name: Icon\n * * Display Name: Icon\n * * SQL Data Type: nvarchar(500)\n * * Description: Optional, specify an icon (CSS Class) for each entity for display in the UI"),__mj_CreatedAt:z.date().describe("\n * * Field Name: __mj_CreatedAt\n * * Display Name: Created At\n * * SQL Data Type: datetimeoffset\n * * Default Value: getutcdate()"),__mj_UpdatedAt:z.date().describe("\n * * Field Name: __mj_UpdatedAt\n * * Display Name: Updated At\n * * SQL Data Type: datetimeoffset\n * * Default Value: getutcdate()"),ScopeDefault:z.string().nullable().describe("\n * * Field Name: ScopeDefault\n * * Display Name: Default Scope\n * * SQL Data Type: nvarchar(100)\n * * Description: Optional, comma-delimited string indicating the default scope for entity visibility. Options include Users, Admins, AI, and All. Defaults to All when NULL. This is used for simple defaults for filtering entity visibility, not security enforcement."),RowsToPackWithSchema:z.union([z.literal('All'),z.literal('None'),z.literal('Sample')]).describe("\n * * Field Name: RowsToPackWithSchema\n * * Display Name: Rows To Pack\n * * SQL Data Type: nvarchar(20)\n * * Default Value: None\n * * Value List Type: List\n * * Possible Values \n * * All\n * * None\n * * Sample\n * * Description: Determines how entity rows should be packaged for external use. Options include None, Sample, and All. Defaults to None."),RowsToPackSampleMethod:z.union([z.literal('bottom n'),z.literal('random'),z.literal('top n')]).describe("\n * * Field Name: RowsToPackSampleMethod\n * * Display Name: Packing Sample Method\n * * SQL Data Type: nvarchar(20)\n * * Default Value: random\n * * Value List Type: List\n * * Possible Values \n * * bottom n\n * * random\n * * top n\n * * Description: Defines the sampling method for row packing when RowsToPackWithSchema is set to Sample. Options include random, top n, and bottom n. Defaults to random."),RowsToPackSampleCount:z.number().describe("\n * * Field Name: RowsToPackSampleCount\n * * Display Name: Packing Sample Count\n * * SQL Data Type: int\n * * Default Value: 0\n * * Description: The number of rows to pack when RowsToPackWithSchema is set to Sample, based on the designated sampling method. Defaults to 0."),RowsToPackSampleOrder:z.string().nullable().describe("\n * * Field Name: RowsToPackSampleOrder\n * * Display Name: Packing Sample Order\n * * SQL Data Type: nvarchar(MAX)\n * * Description: An optional ORDER BY clause for row packing when RowsToPackWithSchema is set to Sample. Allows custom ordering for selected entity data when using top n and bottom n."),AutoRowCountFrequency:z.number().nullable().describe("\n * * Field Name: AutoRowCountFrequency\n * * Display Name: Refresh Frequency (Hours)\n * * SQL Data Type: int\n * * Description: Frequency in hours for automatically performing row counts on this entity. If NULL, automatic row counting is disabled. If greater than 0, schedules recurring SELECT COUNT(*) queries at the specified interval."),RowCount:z.number().nullable().describe("\n * * Field Name: RowCount\n * * Display Name: Row Count\n * * SQL Data Type: bigint\n * * Description: Cached row count for this entity, populated by automatic row count processes when AutoRowCountFrequency is configured."),RowCountRunAt:z.date().nullable().describe("\n * * Field Name: RowCountRunAt\n * * Display Name: Last Counted At\n * * SQL Data Type: datetimeoffset\n * * Description: Timestamp indicating when the last automatic row count was performed for this entity."),Status:z.union([z.literal('Active'),z.literal('Deprecated'),z.literal('Disabled')]).describe("\n * * Field Name: Status\n * * Display Name: Status\n * * SQL Data Type: nvarchar(25)\n * * Default Value: Active\n * * Value List Type: List\n * * Possible Values \n * * Active\n * * Deprecated\n * * Disabled\n * * Description: Status of the entity. Active: fully functional; Deprecated: functional but generates console warnings when used; Disabled: not available for use even though metadata and physical table remain."),DisplayName:z.string().nullable().describe("\n * * Field Name: DisplayName\n * * Display Name: Display Name\n * * SQL Data Type: nvarchar(255)\n * * Description: User-friendly display name shown in the Explorer UI and other interfaces. When set, this is used instead of the entity Name for display purposes. Typically contains the entity name without the schema prefix \u2014 e.g., \"AI Models\" when Name is \"MJ: AI Models\". If NULL, the UI falls back to using the full Name."),AllowMultipleSubtypes:z.boolean().describe("\n * * Field Name: AllowMultipleSubtypes\n * * Display Name: Allow Multiple Subtypes\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: When false (default), child types are disjoint - a record can only be one child type at a time. When true, a record can simultaneously exist as multiple child types (e.g., a Person can be both a Member and a Volunteer)."),AutoUpdateFullTextSearch:z.boolean().describe("\n * * Field Name: AutoUpdateFullTextSearch\n * * Display Name: Auto Update Search Settings\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When true, CodeGen LLM can auto-configure full-text search settings (FullTextSearchEnabled, catalog, index, function) during code generation runs."),AutoUpdateAllowUserSearchAPI:z.boolean().describe("\n * * Field Name: AutoUpdateAllowUserSearchAPI\n * * Display Name: Auto Update Search API\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When true, CodeGen LLM can auto-set AllowUserSearchAPI during code generation runs."),TrustServerCacheCompletely:z.boolean().describe("\n * * Field Name: TrustServerCacheCompletely\n * * Display Name: Trust Server Cache\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When true (default), the server-side RunView cache will store and return cached results for this entity, trusting that all mutations flow through BaseEntity.Save() which fires cache invalidation events. Set to false for entities whose rows are created as side-effects of other operations via raw SQL (e.g., Record Changes created by spCreateRecordChange_Internal), since those inserts bypass BaseEntity and never trigger cache invalidation."),SupportsGeoCoding:z.boolean().describe("\n * * Field Name: SupportsGeoCoding\n * * Display Name: Supports Geo-Coding\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: When true, CodeGen generates geo-aware subclass code, adds __mj_Latitude/__mj_Longitude virtual fields to the base view, and the UI shows a map view toggle. Auto-set by CodeGen when LLM detects geo-capable fields (address, lat/lng, etc.)."),AutoUpdateSupportsGeoCoding:z.boolean().describe("\n * * Field Name: AutoUpdateSupportsGeoCoding\n * * Display Name: Auto Update Geo-Coding\n * * SQL Data Type: bit\n * * Default Value: 1\n * * Description: When true (default), CodeGen can automatically set SupportsGeoCoding based on LLM analysis of entity fields. Set to 0 to lock the value and prevent CodeGen from changing it."),AllowCaching:z.boolean().describe("\n * * Field Name: AllowCaching\n * * Display Name: Allow Caching\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: Controls whether this entity participates in server-side and client-side caching. When false, all cache operations (PreRunView checks, auto-cache storage, BaseEntity event fingerprint scans, client-side IndexedDB cache) are skipped entirely. This column is the single source of truth at runtime; schema-level defaults are applied at CodeGen time via newEntityDefaults.AllowCachingBySchema."),DetectExternalChanges:z.boolean().describe("\n * * Field Name: DetectExternalChanges\n * * Display Name: Detect External Changes\n * * SQL Data Type: bit\n * * Default Value: 0\n * * Description: When set to 1 AND TrackRecordChanges is also 1, the external change detection system will scan this entity for changes made outside the MJ framework (direct SQL, third-party tools, etc.) and replay them through Save() to create proper RecordChange audit entries. Default is 0 (opt-out) because most entities, especially __mj schema metadata tables, are managed by migrations/CodeGen and should not be scanned."),CodeName:z.string().nullable().describe("\n * * Field Name: CodeName\n * * Display Name: Code Name\n * * SQL Data Type: nvarchar(MAX)\n * * Description: Schema-based programmatic code name derived from the entity Name. Uses GetClassNameSchemaPrefix(SchemaName) as the prefix, then strips EntityNamePrefix from the Name and removes spaces. For \"__mj\" schema with entity \"MJ: AI Models\", this produces \"MJAIModels\". For entities in other schemas, the sanitized schema name is prepended. Used in GraphQL type generation and internal code references."),ClassName:z.string().nullable().describe("\n * * Field Name: ClassName\n * * Display Name: Class Name\n * * SQL Data Type: nvarchar(MAX)\n * * Description: Schema-based programmatic class name used for TypeScript entity classes, Zod schemas, and Angular form components. Computed as GetProgrammaticName(GetClassNameSchemaPrefix(SchemaName) + BaseTable + NameSuffix). The prefix is derived from SchemaName (guaranteed unique by SQL Server), not from EntityNamePrefix. For the core __mj schema, the prefix is \"MJ\"; for all other schemas it is the alphanumeric-sanitized schema name. This prevents cross-schema collisions and aligns with GraphQL type naming in getGraphQLTypeNameBase()."),BaseTableCodeName:z.string().nullable().describe("\n * * Field Name: BaseTableCodeName\n * * Display Name: Base Table Code Name\n * * SQL Data Type: nvarchar(MAX)"),ParentEntity:z.string().nullable().describe("\n * * Field Name: ParentEntity\n * * Display Name: Parent Entity\n * * SQL Data Type: nvarchar(255)"),ParentBaseTable:z.string().nullable().describe("\n * * Field Name: ParentBaseTable\n * * Display Name: Parent Base Table\n * * SQL Data Type: nvarchar(255)"),ParentBaseView:z.string().nullable().describe("\n * * Field Name: ParentBaseView\n * * Display Name: Parent Base View\n * * SQL Data Type: nvarchar(255)")});/**
54127
54497
  * zod schema definition for the entity MJ: Entity Action Filters
54128
54498
  */var MJEntityActionFilterSchema=z.object({ID:z.string().describe("\n * * Field Name: ID\n * * Display Name: ID\n * * SQL Data Type: uniqueidentifier\n * * Default Value: newsequentialid()"),EntityActionID:z.string().describe("\n * * Field Name: EntityActionID\n * * Display Name: Entity Action\n * * SQL Data Type: uniqueidentifier\n * * Related Entity/Foreign Key: MJ: Entity Actions (vwEntityActions.ID)"),ActionFilterID:z.string().describe("\n * * Field Name: ActionFilterID\n * * Display Name: Action Filter\n * * SQL Data Type: uniqueidentifier\n * * Related Entity/Foreign Key: MJ: Action Filters (vwActionFilters.ID)"),Sequence:z.number().describe("\n * * Field Name: Sequence\n * * Display Name: Sequence\n * * SQL Data Type: int\n * * Description: Order of filter execution."),Status:z.union([z.literal('Active'),z.literal('Disabled'),z.literal('Pending')]).describe("\n * * Field Name: Status\n * * Display Name: Status\n * * SQL Data Type: nvarchar(20)\n * * Default Value: Pending\n * * Value List Type: List\n * * Possible Values \n * * Active\n * * Disabled\n * * Pending\n * * Description: Status of the entity action filter (Pending, Active, Disabled)."),__mj_CreatedAt:z.date().describe("\n * * Field Name: __mj_CreatedAt\n * * Display Name: Created At\n * * SQL Data Type: datetimeoffset\n * * Default Value: getutcdate()"),__mj_UpdatedAt:z.date().describe("\n * * Field Name: __mj_UpdatedAt\n * * Display Name: Updated At\n * * SQL Data Type: datetimeoffset\n * * Default Value: getutcdate()"),EntityAction:z.string().describe("\n * * Field Name: EntityAction\n * * Display Name: Entity Action Name\n * * SQL Data Type: nvarchar(425)"),ActionFilter:z.string().describe("\n * * Field Name: ActionFilter\n * * Display Name: Action Filter Name\n * * SQL Data Type: nvarchar(MAX)")});/**
54129
54499
  * zod schema definition for the entity MJ: Entity Action Invocation Types
@@ -70530,6 +70900,18 @@ provider=dist/* Metadata */.OS.Provider;_context136.p=1;_context136.n=2;return p
70530
70900
  * * Default Value: 1
70531
70901
  * * Description: When true (default), CodeGen can automatically set SupportsGeoCoding based on LLM analysis of entity fields. Set to 0 to lock the value and prevent CodeGen from changing it.
70532
70902
  */},{key:"AutoUpdateSupportsGeoCoding",get:function get(){return this.Get('AutoUpdateSupportsGeoCoding');},set:function set(value){this.Set('AutoUpdateSupportsGeoCoding',value);}/**
70903
+ * * Field Name: AllowCaching
70904
+ * * Display Name: Allow Caching
70905
+ * * SQL Data Type: bit
70906
+ * * Default Value: 0
70907
+ * * Description: Controls whether this entity participates in server-side and client-side caching. When false, all cache operations (PreRunView checks, auto-cache storage, BaseEntity event fingerprint scans, client-side IndexedDB cache) are skipped entirely. This column is the single source of truth at runtime; schema-level defaults are applied at CodeGen time via newEntityDefaults.AllowCachingBySchema.
70908
+ */},{key:"AllowCaching",get:function get(){return this.Get('AllowCaching');},set:function set(value){this.Set('AllowCaching',value);}/**
70909
+ * * Field Name: DetectExternalChanges
70910
+ * * Display Name: Detect External Changes
70911
+ * * SQL Data Type: bit
70912
+ * * Default Value: 0
70913
+ * * Description: When set to 1 AND TrackRecordChanges is also 1, the external change detection system will scan this entity for changes made outside the MJ framework (direct SQL, third-party tools, etc.) and replay them through Save() to create proper RecordChange audit entries. Default is 0 (opt-out) because most entities, especially __mj schema metadata tables, are managed by migrations/CodeGen and should not be scanned.
70914
+ */},{key:"DetectExternalChanges",get:function get(){return this.Get('DetectExternalChanges');},set:function set(value){this.Set('DetectExternalChanges',value);}/**
70533
70915
  * * Field Name: CodeName
70534
70916
  * * Display Name: Code Name
70535
70917
  * * SQL Data Type: nvarchar(MAX)
@@ -93677,12 +94059,19 @@ function util_GetGlobalObjectStore() {
93677
94059
  }
93678
94060
  /**
93679
94061
  * This utility function will copy all scalar and array properties from an object to a new object and return the new object.
93680
- * This function will NOT copy functions or non-plain objects (unless resolveCircularReferences is true).
94062
+ * This function will NOT copy non-plain object instances (unless they implement `toJSON()` or `resolveCircularReferences` is true).
94063
+ *
94064
+ * The function respects the standard JavaScript `toJSON()` protocol: if a value exposes a `toJSON()` method
94065
+ * (as `Date`, `BaseInfo` subclasses, and user-defined classes can), the method is invoked and its return value
94066
+ * is processed in place of the original. This mirrors how `JSON.stringify()` handles serialization.
94067
+ *
94068
+ * Arrays are recursively processed — each item is copied/toJSON'd individually — so nested objects with
94069
+ * `toJSON()` are unwrapped to their serializable form.
93681
94070
  *
93682
94071
  * @param input - The object to copy
93683
94072
  * @param resolveCircularReferences - If true, handles circular references and complex objects for safe JSON serialization.
93684
94073
  * When enabled, circular references are replaced with '[Circular Reference]',
93685
- * complex objects (Sockets, Streams, etc.) are replaced with their type names,
94074
+ * complex objects without `toJSON()` are replaced with their type names,
93686
94075
  * Error objects are specially handled to extract name/message/stack,
93687
94076
  * and Dates are converted to ISO strings. Default: false
93688
94077
  * @param maxDepth - Maximum recursion depth when resolveCircularReferences is true (default: 10)
@@ -93723,11 +94112,8 @@ function CopyScalarsAndArrays(input) {
93723
94112
  return _copy(item, depth + 1);
93724
94113
  });
93725
94114
  }
93726
- // Handle Date objects
93727
- if (_.isDate(value)) {
93728
- return value.toISOString();
93729
- }
93730
94115
  // Handle Error objects specially to get their properties
94116
+ // (checked before toJSON so we always get name/message/stack, even if Error subclasses define toJSON)
93731
94117
  if (value instanceof Error) {
93732
94118
  return _objectSpread({
93733
94119
  name: value.name,
@@ -93735,6 +94121,10 @@ function CopyScalarsAndArrays(input) {
93735
94121
  stack: value.stack
93736
94122
  }, _copy(_.omit(value, ['name', 'message', 'stack']), depth + 1));
93737
94123
  }
94124
+ // Respect the toJSON() protocol (covers Date, BaseInfo subclasses, and any class that implements it)
94125
+ if (typeof value.toJSON === 'function') {
94126
+ return _copy(value.toJSON(), depth + 1);
94127
+ }
93738
94128
  // Handle plain objects (POJOs)
93739
94129
  if (_.isPlainObject(value)) {
93740
94130
  var result = {};
@@ -93745,7 +94135,7 @@ function CopyScalarsAndArrays(input) {
93745
94135
  }
93746
94136
  return result;
93747
94137
  }
93748
- // For complex objects (Socket, Stream, Buffer, etc.), just use the type name
94138
+ // For complex objects without toJSON (Socket, Stream, Buffer, etc.), just use the type name
93749
94139
  var typeName = ((_value$constructor = value.constructor) === null || _value$constructor === void 0 ? void 0 : _value$constructor.name) || 'Object';
93750
94140
  if (typeName !== 'Object') {
93751
94141
  return "[".concat(typeName, "]");
@@ -93754,21 +94144,41 @@ function CopyScalarsAndArrays(input) {
93754
94144
  };
93755
94145
  return _copy(input, 0);
93756
94146
  } else {
93757
- // Original implementation for backward compatibility
94147
+ // Simple mode: preserves existing behavior (primitives/functions pass through, class instances
94148
+ // without toJSON get their keys dropped) while honoring the toJSON() protocol and recursing
94149
+ // into array items so nested objects with toJSON are unwrapped.
93758
94150
  var result = {};
93759
94151
  Object.keys(input).forEach(function (key) {
93760
94152
  var value = input[key];
93761
- // Check for null or scalar types directly
94153
+ // Primitives, null, functions pass through
93762
94154
  if (value === null || util_typeof(value) !== 'object') {
93763
94155
  result[key] = value;
93764
- } else if (Array.isArray(value)) {
93765
- // Handle arrays by creating a new array with the same elements
93766
- result[key] = _toConsumableArray(value);
93767
- } else if (util_typeof(value) === 'object' && value.constructor === Object) {
93768
- // Recursively copy plain objects
94156
+ return;
94157
+ }
94158
+ // toJSON protocol — use the method's output
94159
+ var valueToJSON = value.toJSON;
94160
+ if (typeof valueToJSON === 'function') {
94161
+ result[key] = valueToJSON.call(value);
94162
+ return;
94163
+ }
94164
+ // Arrays — process each item; items with toJSON are unwrapped, class instances without it are replaced with null to preserve array length
94165
+ if (Array.isArray(value)) {
94166
+ result[key] = value.map(function (item) {
94167
+ if (item === null || util_typeof(item) !== 'object') return item;
94168
+ var itemToJSON = item.toJSON;
94169
+ if (typeof itemToJSON === 'function') return itemToJSON.call(item);
94170
+ if (item.constructor === Object) return CopyScalarsAndArrays(item);
94171
+ // Non-plain, non-toJSON class instances inside an array — can't drop without changing
94172
+ // array length, so fall back to null (sanitized placeholder)
94173
+ return null;
94174
+ });
94175
+ return;
94176
+ }
94177
+ // Plain objects — recurse (key omitted for class instances without toJSON)
94178
+ if (value.constructor === Object) {
93769
94179
  result[key] = CopyScalarsAndArrays(value);
93770
94180
  }
93771
- // Functions and non-plain objects are intentionally ignored
94181
+ // else: non-plain class instance without toJSON → key is dropped entirely (matches legacy)
93772
94182
  });
93773
94183
  return result;
93774
94184
  }