@memberjunction/react-runtime 5.51.0 → 5.51.2

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.
@@ -1,25 +1,25 @@
1
1
 
2
- > @memberjunction/react-runtime@5.51.0 build
2
+ > @memberjunction/react-runtime@5.51.2 build
3
3
  > npm run build:node && npm run build:umd
4
4
 
5
5
 
6
- > @memberjunction/react-runtime@5.51.0 build:node
6
+ > @memberjunction/react-runtime@5.51.2 build:node
7
7
  > tsc && tsc-alias -f
8
8
 
9
9
 
10
- > @memberjunction/react-runtime@5.51.0 build:umd
10
+ > @memberjunction/react-runtime@5.51.2 build:umd
11
11
  > webpack --config webpack.umd.config.cjs
12
12
 
13
- Browserslist: browsers data (caniuse-lite) is 6 months old. Please run:
13
+ Browserslist: browsers data (caniuse-lite) is 8 months old. Please run:
14
14
  npx update-browserslist-db@latest
15
15
  Why you should do it regularly: https://github.com/browserslist/update-db#readme
16
16
  [BABEL] Note: The code generator has deoptimised the styling of /home/runner/work/MJ/MJ/packages/MJCoreEntities/dist/generated/entity_subclasses.js as it exceeds the max of 500KB.
17
- asset runtime.umd.js 8.78 MiB [compared for emit] [big] (name: main)
17
+ asset runtime.umd.js 8.79 MiB [compared for emit] [big] (name: main)
18
18
  asset 324.runtime.umd.js 218 KiB [compared for emit]
19
19
  asset 490.runtime.umd.js 182 KiB [compared for emit] (id hint: vendors)
20
- orphan modules 8.77 MiB [orphan] 571 modules
20
+ orphan modules 8.78 MiB [orphan] 571 modules
21
21
  runtime modules 6.94 KiB 10 modules
22
- cacheable modules 8.91 MiB
22
+ cacheable modules 8.92 MiB
23
23
  modules by path ../../../node_modules/ 781 KiB
24
24
  modules by path ../../../node_modules/rxjs/dist/esm5/internal/ 30.4 KiB 16 modules
25
25
  modules by path ../../../node_modules/debug/src/*.js 12.7 KiB 2 modules
@@ -28,7 +28,7 @@ cacheable modules 8.91 MiB
28
28
  ../../MJCoreEntities/dist/index.js + 66 modules 5.41 MiB [built] [code generated]
29
29
  ../../MJCoreEntities/dist/engines/UserViewEngine.js 19.6 KiB [built] [code generated]
30
30
  ./dist/index.js + 29 modules 440 KiB [built] [code generated]
31
- ../../MJCore/dist/index.js + 88 modules 1.8 MiB [built] [code generated]
32
- ../../MJGlobal/dist/index.js + 24 modules 312 KiB [built] [code generated]
31
+ ../../MJCore/dist/index.js + 88 modules 1.81 MiB [built] [code generated]
32
+ ../../MJGlobal/dist/index.js + 24 modules 317 KiB [built] [code generated]
33
33
  ../../GraphQLDataProvider/dist/index.mjs 194 KiB [built] [code generated]
34
- webpack 5.105.0 compiled successfully in 70217 ms
34
+ webpack 5.105.0 compiled successfully in 58157 ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # @memberjunction/react-runtime
2
2
 
3
+ ## 5.51.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [f560edc]
8
+ - Updated dependencies [0130b53]
9
+ - @memberjunction/global@5.51.2
10
+ - @memberjunction/core@5.51.2
11
+ - @memberjunction/core-entities@5.51.2
12
+ - @memberjunction/graphql-dataprovider@5.51.2
13
+ - @memberjunction/interactive-component-types@5.51.2
14
+
15
+ ## 5.51.1
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies [cc6f321]
20
+ - Updated dependencies [e10a71f]
21
+ - @memberjunction/global@5.51.1
22
+ - @memberjunction/core@5.51.1
23
+ - @memberjunction/graphql-dataprovider@5.51.1
24
+ - @memberjunction/core-entities@5.51.1
25
+ - @memberjunction/interactive-component-types@5.51.1
26
+
3
27
  ## 5.51.0
4
28
 
5
29
  ### Patch Changes
@@ -361,7 +361,7 @@ var se=Object.defineProperty;var d=(g,e)=>se(g,"name",{value:e,configurable:!0})
361
361
  }
362
362
  }
363
363
  }
364
- `,r={entityDocumentID:e.entityDocumentID};e.maxRecords!==void 0&&(r.maxRecords=e.maxRecords),e.filter!==void 0&&(r.filter=e.filter);const s=await this._dataProvider.ExecuteGQL(t,r);if(!s?.FetchEntityVectors)throw new Error("Invalid response from server");return s.FetchEntityVectors}catch(t){const r=t;return (0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogError */ .ZI8)("GraphQLAIClient.FetchEntityVectors failed",void 0,r),{Success:!1,Results:[],TotalCount:0,ElapsedMs:0,ErrorMessage:r.message||"Unknown error"}}}}const F="5.51.0",$="default";class X{static{d(this,"BrowserStorageProviderBase")}constructor(){this._storage=new Map}getCategoryMap(e){const t=e||$;let r=this._storage.get(t);return r||(r=new Map,this._storage.set(t,r)),r}async GetItem(e,t){const s=this.getCategoryMap(t||$).get(e);return s===void 0?null:s}async GetItems(e,t){const r=new Map;if(e.length===0)return r;const s=this.getCategoryMap(t||$);for(const n of new Set(e)){const a=s.get(n);r.set(n,a===void 0?null:a)}return r}async SetItem(e,t,r){this.getCategoryMap(r||$).set(e,t)}async Remove(e,t){this.getCategoryMap(t||$).delete(e)}async ClearCategory(e){const t=e||$;this._storage.delete(t)}async GetCategoryKeys(e){const t=this._storage.get(e||$);return t?Array.from(t.keys()):[]}}const $e="MJ_Metadata",Pe=0;function Me(){try{const g=F.split("."),e=parseInt(g[0],10),t=parseInt(g[1],10);if(!Number.isFinite(e)||!Number.isFinite(t))throw new Error(`Could not parse major.minor from version "${F}"`);return e*1e3+t+Pe}catch(g){return (0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:g,message:"Failed to derive IDB version from PACKAGE_VERSION; using fallback 99999"}),99999}}d(Me,"computeIdbVersion");const Ae=Me(),Y=["mj:default","mj:Metadata","mj:RunViewCache","mj:RunQueryCache","mj:DatasetCache"];class Z extends X{static{d(this,"BrowserIndexedDBStorageProvider")}constructor(){super(),this._dbReady=!1,this.dbPromise=(0,_tempfix_idb__WEBPACK_IMPORTED_MODULE_10__/* .openDB */ .P2)($e,Ae,{upgrade:d((e,t,r)=>{try{(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogStatus */ .b09)(`[IDBCache] Upgrading IndexedDB schema v${t} \u2192 v${r} (package ${F}). Dropping all stores; caches will repopulate on first use.`);for(const s of Array.from(e.objectStoreNames))e.deleteObjectStore(s);for(const s of Y)e.objectStoreNames.contains(s)||e.createObjectStore(s)}catch(s){(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:s,message:s?.message})}},"upgrade"),blocked:d((e,t)=>{(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogStatus */ .b09)(`[IDBCache] Upgrade from v${e} to v${t} blocked by another tab. Close other tabs to allow the upgrade to proceed.`)},"blocked")}),this.dbPromise.then(e=>{this._dbReady=!0,e.onversionchange=()=>{(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogStatus */ .b09)("[IDBCache] DB schema upgraded in another tab \u2014 closing local connection."),e.close(),this._dbReady=!1}}).catch(e=>{(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:e,message:"IndexedDB initialization failed: "+e?.message})})}get IsReady(){return this._dbReady}isKnownCategory(e){const t=`mj:${e}`;return Y.includes(t)}getStoreName(e){const t=e||$;return this.isKnownCategory(t)?`mj:${t}`:"mj:default"}getStoreKey(e,t){const r=t||$;return this.isKnownCategory(r)?e:`[${r}]:${e}`}async SetItem(e,t,r){try{const s=await this.dbPromise,n=this.getStoreName(r),a=this.getStoreKey(e,r),i=s.transaction(n,"readwrite");await i.objectStore(n).put(t,a),await i.done}catch(s){(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:s,message:s?.message})}}async GetItem(e,t){try{const r=await this.dbPromise,s=this.getStoreName(t),n=this.getStoreKey(e,t),a=await r.transaction(s).objectStore(s).get(n);return a===void 0?null:a}catch(r){return (0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:r,message:r?.message}),null}}async GetItems(e,t){const r=new Map;if(e.length===0)return r;try{const s=await this.dbPromise,n=this.getStoreName(t),a=Array.from(new Set(e)),i=a.map(f=>this.getStoreKey(f,t)),o=s.transaction(n,"readonly"),m=o.objectStore(n),u=i.map(f=>m.get(f)),h=await Promise.all(u);await o.done;for(let f=0;f<a.length;f++){const y=h[f];r.set(a[f],y===void 0?null:y)}return r}catch(s){(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:s,message:s?.message});for(const n of new Set(e))r.set(n,null);return r}}async Remove(e,t){try{const r=await this.dbPromise,s=this.getStoreName(t),n=this.getStoreKey(e,t),a=r.transaction(s,"readwrite");await a.objectStore(s).delete(n),await a.done}catch(r){(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:r,message:r?.message})}}async ClearCategory(e){try{const t=await this.dbPromise,r=e||$,s=this.getStoreName(e);if(this.isKnownCategory(r)){const n=t.transaction(s,"readwrite");await n.objectStore(s).clear(),await n.done}else{const n=`[${r}]:`,a=t.transaction("mj:default","readwrite"),i=a.objectStore("mj:default"),o=await i.getAllKeys();for(const m of o)typeof m=="string"&&m.startsWith(n)&&await i.delete(m);await a.done}}catch(t){(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:t,message:t?.message})}}async GetCategoryKeys(e){try{const t=await this.dbPromise,r=e||$,s=this.getStoreName(e),i=await t.transaction(s,"readonly").objectStore(s).getAllKeys();if(this.isKnownCategory(r))return i.map(m=>String(m));const o=`[${r}]:`;return i.map(m=>String(m)).filter(m=>m.startsWith(o)).map(m=>m.slice(o.length))}catch(t){return (0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:t,message:t?.message}),[]}}}const b=new A,Ne=(0,graphql_request__WEBPACK_IMPORTED_MODULE_0__/* .gql */ .J1)`subscription RemoteOperationProgress($channelId: ID!) {
364
+ `,r={entityDocumentID:e.entityDocumentID};e.maxRecords!==void 0&&(r.maxRecords=e.maxRecords),e.filter!==void 0&&(r.filter=e.filter);const s=await this._dataProvider.ExecuteGQL(t,r);if(!s?.FetchEntityVectors)throw new Error("Invalid response from server");return s.FetchEntityVectors}catch(t){const r=t;return (0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogError */ .ZI8)("GraphQLAIClient.FetchEntityVectors failed",void 0,r),{Success:!1,Results:[],TotalCount:0,ElapsedMs:0,ErrorMessage:r.message||"Unknown error"}}}}const F="5.51.2",$="default";class X{static{d(this,"BrowserStorageProviderBase")}constructor(){this._storage=new Map}getCategoryMap(e){const t=e||$;let r=this._storage.get(t);return r||(r=new Map,this._storage.set(t,r)),r}async GetItem(e,t){const s=this.getCategoryMap(t||$).get(e);return s===void 0?null:s}async GetItems(e,t){const r=new Map;if(e.length===0)return r;const s=this.getCategoryMap(t||$);for(const n of new Set(e)){const a=s.get(n);r.set(n,a===void 0?null:a)}return r}async SetItem(e,t,r){this.getCategoryMap(r||$).set(e,t)}async Remove(e,t){this.getCategoryMap(t||$).delete(e)}async ClearCategory(e){const t=e||$;this._storage.delete(t)}async GetCategoryKeys(e){const t=this._storage.get(e||$);return t?Array.from(t.keys()):[]}}const $e="MJ_Metadata",Pe=0;function Me(){try{const g=F.split("."),e=parseInt(g[0],10),t=parseInt(g[1],10);if(!Number.isFinite(e)||!Number.isFinite(t))throw new Error(`Could not parse major.minor from version "${F}"`);return e*1e3+t+Pe}catch(g){return (0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:g,message:"Failed to derive IDB version from PACKAGE_VERSION; using fallback 99999"}),99999}}d(Me,"computeIdbVersion");const Ae=Me(),Y=["mj:default","mj:Metadata","mj:RunViewCache","mj:RunQueryCache","mj:DatasetCache"];class Z extends X{static{d(this,"BrowserIndexedDBStorageProvider")}constructor(){super(),this._dbReady=!1,this.dbPromise=(0,_tempfix_idb__WEBPACK_IMPORTED_MODULE_10__/* .openDB */ .P2)($e,Ae,{upgrade:d((e,t,r)=>{try{(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogStatus */ .b09)(`[IDBCache] Upgrading IndexedDB schema v${t} \u2192 v${r} (package ${F}). Dropping all stores; caches will repopulate on first use.`);for(const s of Array.from(e.objectStoreNames))e.deleteObjectStore(s);for(const s of Y)e.objectStoreNames.contains(s)||e.createObjectStore(s)}catch(s){(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:s,message:s?.message})}},"upgrade"),blocked:d((e,t)=>{(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogStatus */ .b09)(`[IDBCache] Upgrade from v${e} to v${t} blocked by another tab. Close other tabs to allow the upgrade to proceed.`)},"blocked")}),this.dbPromise.then(e=>{this._dbReady=!0,e.onversionchange=()=>{(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogStatus */ .b09)("[IDBCache] DB schema upgraded in another tab \u2014 closing local connection."),e.close(),this._dbReady=!1}}).catch(e=>{(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:e,message:"IndexedDB initialization failed: "+e?.message})})}get IsReady(){return this._dbReady}isKnownCategory(e){const t=`mj:${e}`;return Y.includes(t)}getStoreName(e){const t=e||$;return this.isKnownCategory(t)?`mj:${t}`:"mj:default"}getStoreKey(e,t){const r=t||$;return this.isKnownCategory(r)?e:`[${r}]:${e}`}async SetItem(e,t,r){try{const s=await this.dbPromise,n=this.getStoreName(r),a=this.getStoreKey(e,r),i=s.transaction(n,"readwrite");await i.objectStore(n).put(t,a),await i.done}catch(s){(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:s,message:s?.message})}}async GetItem(e,t){try{const r=await this.dbPromise,s=this.getStoreName(t),n=this.getStoreKey(e,t),a=await r.transaction(s).objectStore(s).get(n);return a===void 0?null:a}catch(r){return (0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:r,message:r?.message}),null}}async GetItems(e,t){const r=new Map;if(e.length===0)return r;try{const s=await this.dbPromise,n=this.getStoreName(t),a=Array.from(new Set(e)),i=a.map(f=>this.getStoreKey(f,t)),o=s.transaction(n,"readonly"),m=o.objectStore(n),u=i.map(f=>m.get(f)),h=await Promise.all(u);await o.done;for(let f=0;f<a.length;f++){const y=h[f];r.set(a[f],y===void 0?null:y)}return r}catch(s){(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:s,message:s?.message});for(const n of new Set(e))r.set(n,null);return r}}async Remove(e,t){try{const r=await this.dbPromise,s=this.getStoreName(t),n=this.getStoreKey(e,t),a=r.transaction(s,"readwrite");await a.objectStore(s).delete(n),await a.done}catch(r){(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:r,message:r?.message})}}async ClearCategory(e){try{const t=await this.dbPromise,r=e||$,s=this.getStoreName(e);if(this.isKnownCategory(r)){const n=t.transaction(s,"readwrite");await n.objectStore(s).clear(),await n.done}else{const n=`[${r}]:`,a=t.transaction("mj:default","readwrite"),i=a.objectStore("mj:default"),o=await i.getAllKeys();for(const m of o)typeof m=="string"&&m.startsWith(n)&&await i.delete(m);await a.done}}catch(t){(0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:t,message:t?.message})}}async GetCategoryKeys(e){try{const t=await this.dbPromise,r=e||$,s=this.getStoreName(e),i=await t.transaction(s,"readonly").objectStore(s).getAllKeys();if(this.isKnownCategory(r))return i.map(m=>String(m));const o=`[${r}]:`;return i.map(m=>String(m)).filter(m=>m.startsWith(o)).map(m=>m.slice(o.length))}catch(t){return (0,_memberjunction_core__WEBPACK_IMPORTED_MODULE_1__/* .LogErrorEx */ .Q1A)({error:t,message:t?.message}),[]}}}const b=new A,Ne=(0,graphql_request__WEBPACK_IMPORTED_MODULE_0__/* .gql */ .J1)`subscription RemoteOperationProgress($channelId: ID!) {
365
365
  RemoteOperationProgress(channelId: $channelId) {
366
366
  ChannelId
367
367
  ProgressJSON
@@ -23018,8 +23018,9 @@ var RowLevelSecurityFilterInfo = /*#__PURE__*/function (_BaseInfo4) {
23018
23018
  for (var i = 0; i < keys.length; i++) {
23019
23019
  var key = keys[i];
23020
23020
  var val = user[key];
23021
- if (val !== null && securityInfo_typeof(val) !== 'object') {
23022
- ret = ret.replace(new RegExp("{{User".concat(key, "}}"), 'g'), String(val));
23021
+ if (val !== null && val !== undefined && securityInfo_typeof(val) !== 'object') {
23022
+ var safeVal = String(val).replace(/'/g, "''");
23023
+ ret = ret.replace(new RegExp("{{User".concat(key, "}}"), 'g'), safeVal);
23023
23024
  }
23024
23025
  }
23025
23026
  // Per-session magic-link resource scope. Fail-closed: an absent scope resolves
@@ -49097,6 +49098,7 @@ function baseEngine_setPrototypeOf(t, e) { return baseEngine_setPrototypeOf = Ob
49097
49098
 
49098
49099
 
49099
49100
 
49101
+
49100
49102
  /**
49101
49103
  * Property configuration for the BaseEngine class to automatically load/set properties on the class.
49102
49104
  */
@@ -50992,7 +50994,18 @@ var BaseEngine = /*#__PURE__*/function (_BaseSingleton) {
50992
50994
  // Compare all primary key values
50993
50995
  return primaryKeys.every(function (pk, idx) {
50994
50996
  var entityValue = e[pk.Name];
50995
- return entityValue === targetKeyValues[idx];
50997
+ var targetValue = targetKeyValues[idx];
50998
+ // UUID columns must compare case-insensitively: the SAME id can arrive with
50999
+ // different casing depending on its source (a client-minted lowercase UUID from
51000
+ // BaseEntity.NewRecord vs. an uppercase value loaded from SQL Server). A raw `===`
51001
+ // then misses the match, and the caller's "not found → add it" branch appends a
51002
+ // DUPLICATE copy of the row into the engine cache. Drive this off metadata
51003
+ // (EntityFieldInfo.IsUniqueIdentifier, which is PG-aware) — never a string-shape
51004
+ // heuristic. See guides/UUID_COMPARISON_GUIDE.md.
51005
+ if (pk.IsUniqueIdentifier) {
51006
+ return (0,dist/* UUIDsEqual */.jd)(entityValue, targetValue);
51007
+ }
51008
+ return entityValue === targetValue;
50996
51009
  });
50997
51010
  });
50998
51011
  }
@@ -51696,49 +51709,117 @@ var BaseEngine = /*#__PURE__*/function (_BaseSingleton) {
51696
51709
  key: "OnExternalCacheChange",
51697
51710
  value: (function () {
51698
51711
  var _OnExternalCacheChange = baseEngine_asyncToGenerator(/*#__PURE__*/baseEngine_regenerator().m(function _callee22(config, event) {
51699
- var parsed, _parsed$totalRowCount, _t15;
51712
+ var parsed, generation, rows, _parsed$totalRowCount, _t15;
51700
51713
  return baseEngine_regenerator().w(function (_context23) {
51701
51714
  while (1) switch (_context23.p = _context23.n) {
51702
51715
  case 0:
51703
51716
  if (!(event.Data && event.Action === 'set')) {
51704
- _context23.n = 4;
51717
+ _context23.n = 6;
51705
51718
  break;
51706
51719
  }
51707
51720
  _context23.p = 1;
51708
51721
  parsed = JSON.parse(event.Data);
51709
51722
  if (!(parsed !== null && parsed !== void 0 && parsed.results && Array.isArray(parsed.results))) {
51710
- _context23.n = 2;
51723
+ _context23.n = 4;
51724
+ break;
51725
+ }
51726
+ // Claim a refresh generation BEFORE the awaited materialization — the same
51727
+ // protocol LoadSingleConfig uses around its awaited RunView. Without it, two
51728
+ // overlapping cache events (or an event racing a full reload) can resolve out
51729
+ // of order and the stale result would be the one that assigns last.
51730
+ generation = this.beginConfigRefresh(config.PropertyName);
51731
+ _context23.n = 2;
51732
+ return this.materializeCacheEventRows(config, parsed.results);
51733
+ case 2:
51734
+ rows = _context23.v;
51735
+ if (this.isLatestConfigRefresh(config.PropertyName, generation)) {
51736
+ _context23.n = 3;
51737
+ break;
51738
+ }
51739
+ return _context23.a(2);
51740
+ case 3:
51741
+ if (!rows) {
51742
+ _context23.n = 4;
51711
51743
  break;
51712
51744
  }
51713
51745
  this.HandleSingleViewResult(config, {
51714
51746
  Success: true,
51715
- Results: parsed.results,
51716
- RowCount: parsed.results.length,
51717
- TotalRowCount: (_parsed$totalRowCount = parsed.totalRowCount) !== null && _parsed$totalRowCount !== void 0 ? _parsed$totalRowCount : parsed.results.length,
51747
+ Results: rows,
51748
+ RowCount: rows.length,
51749
+ TotalRowCount: (_parsed$totalRowCount = parsed.totalRowCount) !== null && _parsed$totalRowCount !== void 0 ? _parsed$totalRowCount : rows.length,
51718
51750
  ExecutionTime: 0,
51719
51751
  ErrorMessage: '',
51720
51752
  UserViewRunID: ''
51721
51753
  });
51722
51754
  return _context23.a(2);
51723
- case 2:
51724
- _context23.n = 4;
51755
+ case 4:
51756
+ _context23.n = 6;
51725
51757
  break;
51726
- case 3:
51727
- _context23.p = 3;
51758
+ case 5:
51759
+ _context23.p = 5;
51728
51760
  _t15 = _context23.v;
51729
- case 4:
51730
- _context23.n = 5;
51761
+ // Designed degradation, but not a silent one: this catch also masks
51762
+ // materialization failures (e.g. an entity class that cannot construct in
51763
+ // this process), and without a trace the only symptom is every cache event
51764
+ // turning into a database reload.
51765
+ LogStatus("BaseEngine.OnExternalCacheChange: payload for '".concat(config.PropertyName, "' could not be applied (").concat(_t15 instanceof Error ? _t15.message : String(_t15), ") \u2014 falling back to full reload"));
51766
+ case 6:
51767
+ _context23.n = 7;
51731
51768
  return this.LoadSingleConfig(config, this._contextUser);
51732
- case 5:
51769
+ case 7:
51733
51770
  return _context23.a(2);
51734
51771
  }
51735
- }, _callee22, this, [[1, 3]]);
51772
+ }, _callee22, this, [[1, 5]]);
51736
51773
  }));
51737
51774
  function OnExternalCacheChange(_x32, _x33) {
51738
51775
  return _OnExternalCacheChange.apply(this, arguments);
51739
51776
  }
51740
51777
  return OnExternalCacheChange;
51741
51778
  }()
51779
+ /**
51780
+ * Converts rows from a cache-change payload into the shape this config's property expects.
51781
+ *
51782
+ * Cache payloads are JSON, so their rows are plain objects with string dates. A config loaded
51783
+ * as `entity_object` must not receive them directly — the property's declared element type
51784
+ * would be violated and BaseEntity's coercing accessors bypassed, which is what turns a typed
51785
+ * `__mj_CreatedAt` into a raw string at runtime. Mirrors the conversion the RunView cache-hit
51786
+ * path performs, and enforces in this direction the same type-homogeneity invariant
51787
+ * {@link canUseImmediateMutation} enforces for the sibling mutation path.
51788
+ *
51789
+ * @returns the rows to assign, or null when they cannot be safely materialized (caller should
51790
+ * fall back to a full reload).
51791
+ */
51792
+ )
51793
+ }, {
51794
+ key: "materializeCacheEventRows",
51795
+ value: (function () {
51796
+ var _materializeCacheEventRows = baseEngine_asyncToGenerator(/*#__PURE__*/baseEngine_regenerator().m(function _callee23(config, rows) {
51797
+ var effectiveResultType;
51798
+ return baseEngine_regenerator().w(function (_context24) {
51799
+ while (1) switch (_context24.n) {
51800
+ case 0:
51801
+ effectiveResultType = config.ResultType || this.EngineDefaultResultType;
51802
+ if (!(effectiveResultType === 'simple')) {
51803
+ _context24.n = 1;
51804
+ break;
51805
+ }
51806
+ return _context24.a(2, rows);
51807
+ case 1:
51808
+ if (config.EntityName) {
51809
+ _context24.n = 2;
51810
+ break;
51811
+ }
51812
+ return _context24.a(2, null);
51813
+ case 2:
51814
+ return _context24.a(2, util_TransformSimpleObjectToEntityObject(this.ProviderToUse, config.EntityName, rows, this._contextUser));
51815
+ }
51816
+ }, _callee23, this);
51817
+ }));
51818
+ function materializeCacheEventRows(_x34, _x35) {
51819
+ return _materializeCacheEventRows.apply(this, arguments);
51820
+ }
51821
+ return materializeCacheEventRows;
51822
+ }()
51742
51823
  /**
51743
51824
  * Sets an expiration timer for a metadata property.
51744
51825
  * @param propertyName - The name of the property
@@ -51765,21 +51846,21 @@ var BaseEngine = /*#__PURE__*/function (_BaseSingleton) {
51765
51846
  }, {
51766
51847
  key: "AddDynamicConfig",
51767
51848
  value: (function () {
51768
- var _AddDynamicConfig = baseEngine_asyncToGenerator(/*#__PURE__*/baseEngine_regenerator().m(function _callee23(config, contextUser) {
51849
+ var _AddDynamicConfig = baseEngine_asyncToGenerator(/*#__PURE__*/baseEngine_regenerator().m(function _callee24(config, contextUser) {
51769
51850
  var c;
51770
- return baseEngine_regenerator().w(function (_context24) {
51771
- while (1) switch (_context24.n) {
51851
+ return baseEngine_regenerator().w(function (_context25) {
51852
+ while (1) switch (_context25.n) {
51772
51853
  case 0:
51773
51854
  c = this.UpgradeObjectToConfig(config);
51774
51855
  this._dynamicConfigs.set(c.PropertyName, c);
51775
- _context24.n = 1;
51856
+ _context25.n = 1;
51776
51857
  return this.LoadSingleConfig(c, contextUser || this._contextUser);
51777
51858
  case 1:
51778
- return _context24.a(2);
51859
+ return _context25.a(2);
51779
51860
  }
51780
- }, _callee23, this);
51861
+ }, _callee24, this);
51781
51862
  }));
51782
- function AddDynamicConfig(_x34, _x35) {
51863
+ function AddDynamicConfig(_x36, _x37) {
51783
51864
  return _AddDynamicConfig.apply(this, arguments);
51784
51865
  }
51785
51866
  return AddDynamicConfig;
@@ -51806,26 +51887,26 @@ var BaseEngine = /*#__PURE__*/function (_BaseSingleton) {
51806
51887
  }, {
51807
51888
  key: "RefreshItem",
51808
51889
  value: (function () {
51809
- var _RefreshItem = baseEngine_asyncToGenerator(/*#__PURE__*/baseEngine_regenerator().m(function _callee24(propertyName) {
51890
+ var _RefreshItem = baseEngine_asyncToGenerator(/*#__PURE__*/baseEngine_regenerator().m(function _callee25(propertyName) {
51810
51891
  var config;
51811
- return baseEngine_regenerator().w(function (_context25) {
51812
- while (1) switch (_context25.n) {
51892
+ return baseEngine_regenerator().w(function (_context26) {
51893
+ while (1) switch (_context26.n) {
51813
51894
  case 0:
51814
51895
  config = this._metadataConfigs.find(function (c) {
51815
51896
  return c.PropertyName === propertyName;
51816
51897
  }) || this._dynamicConfigs.get(propertyName);
51817
51898
  if (!config) {
51818
- _context25.n = 1;
51899
+ _context26.n = 1;
51819
51900
  break;
51820
51901
  }
51821
- _context25.n = 1;
51902
+ _context26.n = 1;
51822
51903
  return this.LoadSingleConfig(config, this._contextUser);
51823
51904
  case 1:
51824
- return _context25.a(2);
51905
+ return _context26.a(2);
51825
51906
  }
51826
- }, _callee24, this);
51907
+ }, _callee25, this);
51827
51908
  }));
51828
- function RefreshItem(_x36) {
51909
+ function RefreshItem(_x38) {
51829
51910
  return _RefreshItem.apply(this, arguments);
51830
51911
  }
51831
51912
  return RefreshItem;
@@ -51837,16 +51918,16 @@ var BaseEngine = /*#__PURE__*/function (_BaseSingleton) {
51837
51918
  }, {
51838
51919
  key: "RefreshAllItems",
51839
51920
  value: (function () {
51840
- var _RefreshAllItems = baseEngine_asyncToGenerator(/*#__PURE__*/baseEngine_regenerator().m(function _callee25() {
51841
- return baseEngine_regenerator().w(function (_context26) {
51842
- while (1) switch (_context26.n) {
51921
+ var _RefreshAllItems = baseEngine_asyncToGenerator(/*#__PURE__*/baseEngine_regenerator().m(function _callee26() {
51922
+ return baseEngine_regenerator().w(function (_context27) {
51923
+ while (1) switch (_context27.n) {
51843
51924
  case 0:
51844
- _context26.n = 1;
51925
+ _context27.n = 1;
51845
51926
  return this.LoadConfigs([].concat(baseEngine_toConsumableArray(this._metadataConfigs), baseEngine_toConsumableArray(Array.from(this._dynamicConfigs.values()))), this._contextUser);
51846
51927
  case 1:
51847
- return _context26.a(2);
51928
+ return _context27.a(2);
51848
51929
  }
51849
- }, _callee25, this);
51930
+ }, _callee26, this);
51850
51931
  }));
51851
51932
  function RefreshAllItems() {
51852
51933
  return _RefreshAllItems.apply(this, arguments);
@@ -51861,15 +51942,15 @@ var BaseEngine = /*#__PURE__*/function (_BaseSingleton) {
51861
51942
  }, {
51862
51943
  key: "AdditionalLoading",
51863
51944
  value: (function () {
51864
- var _AdditionalLoading = baseEngine_asyncToGenerator(/*#__PURE__*/baseEngine_regenerator().m(function _callee26(contextUser) {
51865
- return baseEngine_regenerator().w(function (_context27) {
51866
- while (1) switch (_context27.n) {
51945
+ var _AdditionalLoading = baseEngine_asyncToGenerator(/*#__PURE__*/baseEngine_regenerator().m(function _callee27(contextUser) {
51946
+ return baseEngine_regenerator().w(function (_context28) {
51947
+ while (1) switch (_context28.n) {
51867
51948
  case 0:
51868
- return _context27.a(2);
51949
+ return _context28.a(2);
51869
51950
  }
51870
- }, _callee26);
51951
+ }, _callee27);
51871
51952
  }));
51872
- function AdditionalLoading(_x37) {
51953
+ function AdditionalLoading(_x39) {
51873
51954
  return _AdditionalLoading.apply(this, arguments);
51874
51955
  }
51875
51956
  return AdditionalLoading;
@@ -55796,11 +55877,17 @@ var DatabaseProviderBase = /*#__PURE__*/function (_ProviderBase) {
55796
55877
  }, {
55797
55878
  key: "ValidateUserProvidedSQLClause",
55798
55879
  value: function ValidateUserProvidedSQLClause(clause) {
55799
- // Remove string literals to avoid false positives
55800
- var stringLiteralPattern = /(['"])(?:(?=(\\?))\2[\s\S])*?\1/g;
55801
- var clauseWithoutStrings = clause.replace(stringLiteralPattern, '');
55880
+ // Remove string literals to avoid false positives.
55881
+ //
55882
+ // 🚨 SECURITY: this uses the SHARED stripper in @memberjunction/global. It must match how
55883
+ // SQL Server / PostgreSQL actually parse literals — see StripSQLStringLiterals for the full
55884
+ // rationale and the backslash-escape bypass it exists to prevent. Do NOT inline a regex here;
55885
+ // an inline copy is exactly how this screen and SQLExpressionValidator drifted apart before.
55886
+ var clauseWithoutStrings = (0,dist/* StripSQLStringLiterals */.SN)(clause);
55802
55887
  var lowerClause = clauseWithoutStrings.toLowerCase();
55803
- var forbiddenPatterns = [/\binsert\b/, /\bupdate\b/, /\bdelete\b/, /\bexec\b/, /\bexecute\b/, /\bdrop\b/, /--/, /\/\*/, /\*\//, /\bunion\b/, /\bxp_/, /;/];
55888
+ var forbiddenPatterns = [/\binsert\b/, /\bupdate\b/, /\bdelete\b/, /\bexec\b/, /\bexecute\b/, /\bdrop\b/, /--/, /\/\*/, /\*\//, /\bunion\b/, /\bxp_/, /;/,
55889
+ // Time-based blind injection vector — no legitimate filter/order-by clause uses WAITFOR.
55890
+ /\bwaitfor\b/];
55804
55891
  for (var _i = 0, _forbiddenPatterns = forbiddenPatterns; _i < _forbiddenPatterns.length; _i++) {
55805
55892
  var pattern = _forbiddenPatterns[_i];
55806
55893
  if (pattern.test(lowerClause)) return false;
@@ -110680,13 +110767,12 @@ var ConversationEngine = /*#__PURE__*/function (_BaseEngine) {
110680
110767
  key: "sortConversations",
110681
110768
  value: function sortConversations(conversations) {
110682
110769
  return conversations_toConsumableArray(conversations).sort(function (a, b) {
110683
- var _a$__mj_UpdatedAt$get, _a$__mj_UpdatedAt, _b$__mj_UpdatedAt$get, _b$__mj_UpdatedAt;
110684
110770
  // Pinned conversations first
110685
110771
  if (a.IsPinned && !b.IsPinned) return -1;
110686
110772
  if (!a.IsPinned && b.IsPinned) return 1;
110687
110773
  // Then by updated date descending
110688
- var aTime = (_a$__mj_UpdatedAt$get = (_a$__mj_UpdatedAt = a.__mj_UpdatedAt) === null || _a$__mj_UpdatedAt === void 0 ? void 0 : _a$__mj_UpdatedAt.getTime()) !== null && _a$__mj_UpdatedAt$get !== void 0 ? _a$__mj_UpdatedAt$get : 0;
110689
- var bTime = (_b$__mj_UpdatedAt$get = (_b$__mj_UpdatedAt = b.__mj_UpdatedAt) === null || _b$__mj_UpdatedAt === void 0 ? void 0 : _b$__mj_UpdatedAt.getTime()) !== null && _b$__mj_UpdatedAt$get !== void 0 ? _b$__mj_UpdatedAt$get : 0;
110774
+ var aTime = (0,MJGlobal_dist/* ToEpochMs */.ZI)(a.__mj_UpdatedAt);
110775
+ var bTime = (0,MJGlobal_dist/* ToEpochMs */.ZI)(b.__mj_UpdatedAt);
110690
110776
  return bTime - aTime;
110691
110777
  });
110692
110778
  }
@@ -124267,6 +124353,8 @@ __webpack_require__.d(__webpack_exports__, {
124267
124353
  fK: () => (/* reexport */ RequiresSubclass),
124268
124354
  rH: () => (/* reexport */ SQLExpressionValidator),
124269
124355
  NG: () => (/* reexport */ SafeJSONParse),
124356
+ SN: () => (/* reexport */ StripSQLStringLiterals),
124357
+ ZI: () => (/* reexport */ ToEpochMs),
124270
124358
  jd: () => (/* reexport */ UUIDsEqual),
124271
124359
  Om: () => (/* reexport */ ValidationErrorInfo),
124272
124360
  wX: () => (/* reexport */ ValidationErrorType),
@@ -124275,7 +124363,7 @@ __webpack_require__.d(__webpack_exports__, {
124275
124363
  gZ: () => (/* reexport */ uuidv4)
124276
124364
  });
124277
124365
 
124278
- // UNUSED EXPORTS: ALLOWED_SQL_FUNCTIONS, BuildCronExpression, CRON_DAY_NAMES, ClassFactory, ClassIsOptionalKeyedSpecialization, ClassRegistration, ClassRequiresSubclass, CleanJSON, CleanJavaScript, ConvertMarkdownStringToHtmlList, CopyScalarsAndArrays, DANGEROUS_SQL_KEYWORDS, DEFAULT_RICH_TEXT_SCAN_LENGTH, DeepDiffer, DefaultCronSchedule, DeprecationWarningManager, DescribeCronExpression, DiffChangeType, ENCRYPTED_SENTINEL, EscapeHTML, FULL_QUERY_ALLOWED_KEYWORDS, FieldRulesEvaluator, FieldTransformEngine, FormatTimeOfDay, GetClassInheritance, GetClassName, GetFieldTransform, GetFullClassHierarchy, GetRootClass, GetSuperclass, HighlightSearchMatches, InvokeManualResize, IsClassConstructor, IsDescendantClassOf, IsEncryptedSentinel, IsOnlyTimezoneShift, IsPlausibleCronExpression, IsRootClass, IsSubclassOf, IsValidUUID, IsValueEncrypted, JSONValidator, KeyedSerialTaskQueue, MJEvent, MJGlobalProperty, OPTIONAL_KEYED_SPECIALIZATION_KEY, ObjectCache, ObjectCacheEntry, Ordinal, ParseCronExpression, ParseJSONRecursive, REQUIRES_SUBCLASS_KEY, RegisterClassEx, RegisterFieldTransform, SafeExpressionEvaluator, ShutdownRegistry, ToJSONSafe, adjustCasing, compareStringsByLine, convertCamelCaseToHaveSpaces, createDisplayName, defaultExpressionEvaluator, detectRichTextFormat, ensureRegExp, ensureRegExps, generatePluralName, getIrregularPlural, getValueAtPath, matchesAllPatterns, matchesAnyPattern, parsePattern, parsePatterns, replaceAllSpaces, resolveMappingRef, resolveValueMapping, stripTrailingChars, stripWhitespace
124366
+ // UNUSED EXPORTS: ALLOWED_SQL_FUNCTIONS, BLOCKED_SYSTEM_OBJECT_PATTERNS, BuildCronExpression, CRON_DAY_NAMES, ClassFactory, ClassIsOptionalKeyedSpecialization, ClassRegistration, ClassRequiresSubclass, CleanJSON, CleanJavaScript, ConvertMarkdownStringToHtmlList, CopyScalarsAndArrays, DANGEROUS_SQL_KEYWORDS, DEFAULT_RICH_TEXT_SCAN_LENGTH, DeepDiffer, DefaultCronSchedule, DeprecationWarningManager, DescribeCronExpression, DiffChangeType, ENCRYPTED_SENTINEL, EscapeHTML, FULL_QUERY_ALLOWED_KEYWORDS, FieldRulesEvaluator, FieldTransformEngine, FormatTimeOfDay, GetClassInheritance, GetClassName, GetFieldTransform, GetFullClassHierarchy, GetRootClass, GetSuperclass, HighlightSearchMatches, InvokeManualResize, IsClassConstructor, IsDescendantClassOf, IsEncryptedSentinel, IsOnlyTimezoneShift, IsPlausibleCronExpression, IsRootClass, IsSubclassOf, IsValidUUID, IsValueEncrypted, JSONValidator, KeyedSerialTaskQueue, MJEvent, MJGlobalProperty, OPTIONAL_KEYED_SPECIALIZATION_KEY, ObjectCache, ObjectCacheEntry, Ordinal, ParseCronExpression, ParseJSONRecursive, REQUIRES_SUBCLASS_KEY, RegisterClassEx, RegisterFieldTransform, SafeExpressionEvaluator, ShutdownRegistry, ToJSONSafe, adjustCasing, compareStringsByLine, convertCamelCaseToHaveSpaces, createDisplayName, defaultExpressionEvaluator, detectRichTextFormat, ensureRegExp, ensureRegExps, generatePluralName, getIrregularPlural, getValueAtPath, matchesAllPatterns, matchesAnyPattern, parsePattern, parsePatterns, replaceAllSpaces, resolveMappingRef, resolveValueMapping, stripTrailingChars, stripWhitespace
124279
124367
 
124280
124368
  ;// ../../MJGlobal/dist/ClassUtils.js
124281
124369
  /**
@@ -126656,6 +126744,21 @@ function recursiveReplaceString(str, options, depth, path) {
126656
126744
  // If we get here, return the original string
126657
126745
  return str;
126658
126746
  }
126747
+ /**
126748
+ * Epoch milliseconds for a value that may be a Date, an ISO/parseable string, a numeric
126749
+ * timestamp, or absent. Returns 0 for null/undefined/unparseable input so it is safe to use
126750
+ * directly in a sort comparator.
126751
+ *
126752
+ * Framework date fields such as `__mj_CreatedAt` are typed as `Date` but can hold a raw string
126753
+ * at runtime when rows arrive from a serialized source (cache payloads, wire JSON) rather than
126754
+ * through BaseEntity's coercing accessors. Optional chaining does not protect a `.getTime()`
126755
+ * call in that case — `"…"?.getTime` is `undefined`, and calling it throws.
126756
+ */
126757
+ function ToEpochMs(value) {
126758
+ if (value == null) return 0;
126759
+ var ms = value instanceof Date ? value.getTime() : new Date(value).getTime();
126760
+ return Number.isNaN(ms) ? 0 : ms;
126761
+ }
126659
126762
  ;// ../../MJGlobal/dist/MJLruCache.js
126660
126763
  function MJLruCache_typeof(o) { "@babel/helpers - typeof"; return MJLruCache_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, MJLruCache_typeof(o); }
126661
126764
  function MJLruCache_slicedToArray(r, e) { return MJLruCache_arrayWithHoles(r) || MJLruCache_iterableToArrayLimit(r, e) || MJLruCache_unsupportedIterableToArray(r, e) || MJLruCache_nonIterableRest(); }
@@ -129136,6 +129239,63 @@ var FULL_QUERY_ALLOWED_KEYWORDS = [
129136
129239
  // standalone SELECT statement, so allowing FOR in full-query context is safe.
129137
129240
  // (FOR UPDATE remains blocked via the independent UPDATE keyword.)
129138
129241
  'FOR'];
129242
+ /**
129243
+ * System catalog / metadata objects that must never be referenced from a user-supplied
129244
+ * expression or ad-hoc query, in ANY context (including `full_query`). These sit outside
129245
+ * MemberJunction's entity-permission model, so allowing them turns a validated SELECT into
129246
+ * a schema-enumeration and credential-exfiltration primitive
129247
+ * (e.g. `SELECT name, password_hash FROM sys.sql_logins`,
129248
+ * `SELECT * FROM INFORMATION_SCHEMA.COLUMNS`, `SELECT * FROM pg_catalog.pg_authid`).
129249
+ * String literals are stripped before this check runs, so a literal value like `'sys.x'` is safe.
129250
+ */
129251
+ var BLOCKED_SYSTEM_OBJECT_PATTERNS = [/\bSYS\s*\.\s*\w/i,
129252
+ // SQL Server system catalog schema: sys.sql_logins, sys.objects, sys.fn_*, ...
129253
+ /\bINFORMATION_SCHEMA\b/i,
129254
+ // ANSI catalog views — schema/table/column enumeration
129255
+ /\bSYSLOGINS\b/i,
129256
+ // legacy SQL Server logins view
129257
+ /\bPG_CATALOG\s*\./i,
129258
+ // PostgreSQL system catalog schema
129259
+ /\bPG_(AUTHID|SHADOW|USER|ROLES)\b/i // PostgreSQL credential / role catalogs
129260
+ ];
129261
+ /**
129262
+ * Matches SQL string literals the way SQL Server and PostgreSQL (with the default
129263
+ * `standard_conforming_strings=on`) actually parse them: a literal is closed by the next
129264
+ * single quote, `''` is an embedded quote, and a backslash is an ORDINARY character that
129265
+ * does NOT escape the closing quote. Double-quoted runs are matched with the same doubling
129266
+ * rule so a delimited identifier can't hide a payload either.
129267
+ *
129268
+ * @see StripSQLStringLiterals — use that, not this constant, so every caller gets the
129269
+ * documented semantics and the two validators in MJ can never drift apart again.
129270
+ */
129271
+ var SQL_STRING_LITERAL_PATTERN = /'(?:[^']|'')*'|"(?:[^"]|"")*"/g;
129272
+ /**
129273
+ * Removes SQL string literals from a clause or expression so that a keyword denylist can be
129274
+ * applied to the *code* portion without tripping over keywords that appear inside quoted data
129275
+ * (e.g. `Comments LIKE '%--%'`).
129276
+ *
129277
+ * 🚨 SECURITY — this is the single implementation of literal-stripping for MJ's SQL screens, and
129278
+ * it MUST stay byte-for-byte consistent with how the database parses literals. If the stripper
129279
+ * removes a span the database does NOT treat as a literal, everything hidden inside that span
129280
+ * bypasses the denylist while the database still executes it.
129281
+ *
129282
+ * An earlier version of this logic (duplicated in two places, which is how it survived) honored
129283
+ * **backslash escaping** — `/(['"])(?:(?=(\\?))\2[\s\S])*?\1/g`. SQL Server and PostgreSQL do not
129284
+ * treat `\` as an escape character, so `x = 'a\') ; DROP TABLE Users; --'` was swallowed whole as
129285
+ * one "literal" and stripped to `x = `, which passed every denylist — while the database closed
129286
+ * the literal at the real quote and executed the stacked statement.
129287
+ *
129288
+ * **Do NOT reintroduce backslash-escape handling here, and do NOT inline a second copy of this
129289
+ * regex anywhere else — call this function.**
129290
+ *
129291
+ * @param sql The clause, expression, or query to strip literals from
129292
+ * @returns The input with every complete string literal removed. An UNTERMINATED literal is left
129293
+ * in place on purpose: the stray quote and everything after it stay visible to the
129294
+ * denylist rather than being silently swallowed.
129295
+ */
129296
+ function StripSQLStringLiterals(sql) {
129297
+ return sql.replace(SQL_STRING_LITERAL_PATTERN, '');
129298
+ }
129139
129299
  /**
129140
129300
  * Safe SQL functions allowed in expressions, organized by category
129141
129301
  */
@@ -129241,14 +129401,14 @@ var SQLExpressionValidator = /*#__PURE__*/function (_BaseSingleton) {
129241
129401
  }
129242
129402
  /**
129243
129403
  * Remove string literals to avoid false positives in keyword detection.
129244
- * Handles both single and double quoted strings with escaped quotes.
129404
+ *
129405
+ * 🚨 SECURITY: delegates to {@link StripSQLStringLiterals} — read the warning there before
129406
+ * changing anything about how literals are matched. This must never grow its own regex again.
129245
129407
  */
129246
129408
  }, {
129247
129409
  key: "removeStringLiterals",
129248
129410
  value: function removeStringLiterals(expression) {
129249
- // Match both single and double quoted strings, handling escaped quotes
129250
- var stringPattern = /(['"])(?:(?=(\\?))\2[\s\S])*?\1/g;
129251
- return expression.replace(stringPattern, '');
129411
+ return StripSQLStringLiterals(expression);
129252
129412
  }
129253
129413
  /**
129254
129414
  * Check for dangerous SQL patterns that indicate injection attempts
@@ -129308,15 +129468,29 @@ var SQLExpressionValidator = /*#__PURE__*/function (_BaseSingleton) {
129308
129468
  };
129309
129469
  }
129310
129470
  }
129311
- // Check statement terminator (prevents multi-statement injection).
129312
- // For full_query context, strip comments first (a trailing semicolon may be followed by
129313
- // an inline comment like `ORDER BY x DESC; -- highest first`), then strip the trailing
129314
- // semicolon. Only reject if semicolons remain mid-statement, indicating injection.
129471
+ // Block references to database system catalogs / metadata objects in ALL contexts
129472
+ // (including full_query). These live outside MemberJunction's entity-permission model, so
129473
+ // permitting them turns a validated SELECT into a schema-enumeration / credential-exfiltration
129474
+ // primitive. String literals were already stripped upstream, so legitimate literal values are safe.
129315
129475
  } catch (err) {
129316
129476
  _iterator.e(err);
129317
129477
  } finally {
129318
129478
  _iterator.f();
129319
129479
  }
129480
+ for (var _i = 0, _BLOCKED_SYSTEM_OBJEC = BLOCKED_SYSTEM_OBJECT_PATTERNS; _i < _BLOCKED_SYSTEM_OBJEC.length; _i++) {
129481
+ var sysPattern = _BLOCKED_SYSTEM_OBJEC[_i];
129482
+ if (sysPattern.test(textToCheck)) {
129483
+ return {
129484
+ valid: false,
129485
+ error: 'Access to database system catalogs / metadata objects is not allowed',
129486
+ trigger: 'system-object'
129487
+ };
129488
+ }
129489
+ }
129490
+ // Check statement terminator (prevents multi-statement injection).
129491
+ // For full_query context, strip comments first (a trailing semicolon may be followed by
129492
+ // an inline comment like `ORDER BY x DESC; -- highest first`), then strip the trailing
129493
+ // semicolon. Only reject if semicolons remain mid-statement, indicating injection.
129320
129494
  var textForSemicolonCheck = isFullQuery ? this.stripSQLComments(expression).replace(/;\s*$/, '') // strip comments then trailing semicolon
129321
129495
  : expression;
129322
129496
  if (textForSemicolonCheck.includes(';')) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/react-runtime",
3
- "version": "5.51.0",
3
+ "version": "5.51.2",
4
4
  "description": "Platform-agnostic React component runtime for MemberJunction. Provides core compilation, registry, and execution capabilities for React components in any JavaScript environment.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -29,11 +29,11 @@
29
29
  },
30
30
  "homepage": "https://github.com/MemberJunction/MJ#readme",
31
31
  "dependencies": {
32
- "@memberjunction/core": "5.51.0",
33
- "@memberjunction/global": "5.51.0",
34
- "@memberjunction/interactive-component-types": "5.51.0",
35
- "@memberjunction/core-entities": "5.51.0",
36
- "@memberjunction/graphql-dataprovider": "5.51.0",
32
+ "@memberjunction/core": "5.51.2",
33
+ "@memberjunction/global": "5.51.2",
34
+ "@memberjunction/interactive-component-types": "5.51.2",
35
+ "@memberjunction/core-entities": "5.51.2",
36
+ "@memberjunction/graphql-dataprovider": "5.51.2",
37
37
  "@babel/standalone": "^7.29.1",
38
38
  "rxjs": "^7.8.2"
39
39
  },