@salesforce/lds-runtime-aura 1.358.0 → 1.360.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.
Files changed (2) hide show
  1. package/dist/ldsEngineCreator.js +411 -258
  2. package/package.json +35 -34
@@ -518,65 +518,130 @@ class CacheControlCommand extends BaseCommand {
518
518
  constructor(services) {
519
519
  super();
520
520
  this.services = services;
521
+ this.keysUsed = new Set();
522
+ this.keysUpdated = undefined;
521
523
  this.operationType = 'query';
522
- this.rebuildUnsubscribe = () => { };
523
- this.refreshUnsubscribe = () => { };
524
524
  this.lastEmittedData = undefined;
525
- this.subscribeToKeys = () => undefined;
526
- this.unsubscribeFromKeys = () => undefined;
525
+ this.unsubscribeFromKeysImpl = () => undefined;
527
526
  this.subscriptions = [];
528
527
  this.instantiationTime = Date.now() / 1000; // in seconds
529
528
  }
530
529
  execute(overrides) {
530
+ this.keysUpdated = undefined;
531
531
  this.unsubscribeFromKeys();
532
- this.subscribeToKeys = () => undefined;
533
532
  const mergedCacheControlConfig = mergeCacheControlConfigs(this.cacheControlStrategyConfig, overrides);
534
- const resultPromise = this.services.cacheController.execute(mergedCacheControlConfig, (cache) => this.buildRequestRunner(cache), {
533
+ let returnData;
534
+ let returnError;
535
+ const requestRunner = {
536
+ readFromCache: (cache) => {
537
+ const resultPromise = this.buildResultWithSubscribe(cache);
538
+ return resultPromise.then((result) => {
539
+ if (result.isErr()) {
540
+ return err(result.error);
541
+ }
542
+ returnData = result;
543
+ return ok(undefined);
544
+ });
545
+ },
546
+ requestFromNetwork: () => {
547
+ const that = this;
548
+ return (async function* () {
549
+ const result = await that.requestFromNetwork();
550
+ if (result.isErr()) {
551
+ returnError = result;
552
+ }
553
+ yield result;
554
+ })();
555
+ },
556
+ writeToCache: (cache, networkResult) => {
557
+ return this.writeToCacheAndRecordKeys(cache, networkResult);
558
+ },
559
+ };
560
+ const resultPromise = this.services.cacheController.execute(mergedCacheControlConfig, requestRunner, {
535
561
  instrumentationAttributes: this.instrumentationAttributes,
536
562
  });
537
563
  return resultPromise.then((result) => {
538
- if (this.subscriptions.length > 0) {
539
- this.subscribeToKeys();
540
- }
541
- if (result.isOk() && this.lastEmittedData === undefined) {
542
- this.lastEmittedData = result.value.data;
564
+ return this.publishUpdatedKeys().then(() => {
565
+ // First check if there was an error from the network
566
+ if (returnError) {
567
+ return returnError;
568
+ }
569
+ // Then return other errors from read/write
570
+ if (result.isErr()) {
571
+ return err(result.error);
572
+ }
573
+ if (this.subscriptions.length > 0) {
574
+ this.subscribeToKeysUsed();
575
+ }
576
+ if (returnData === undefined) {
577
+ return err(new Error('Cache miss after fetching from network'));
578
+ }
579
+ if (returnData.isOk() && this.lastEmittedData === undefined) {
580
+ this.lastEmittedData = returnData.value.data;
581
+ }
582
+ return returnData;
583
+ });
584
+ });
585
+ }
586
+ publishUpdatedKeys() {
587
+ if (this.services.pubSub) {
588
+ if (this.keysUpdated !== undefined && this.keysUpdated.size > 0) {
589
+ return this.services.pubSub.publish({
590
+ type: 'cacheUpdate',
591
+ data: this.keysUpdated,
592
+ });
543
593
  }
544
- return result;
594
+ }
595
+ return resolvedPromiseLike(undefined);
596
+ }
597
+ subscribeToKeysUsed() {
598
+ this.unsubscribeFromKeys();
599
+ const { pubSub } = this.services;
600
+ if (!pubSub) {
601
+ this.unsubscribeFromKeysImpl = () => undefined;
602
+ return;
603
+ }
604
+ const rebuildUnsubscribe = pubSub.subscribe({
605
+ type: 'cacheUpdate',
606
+ predicate: (event) => setOverlaps(event.data, this.keysUsed),
607
+ callback: () => this.rerun({ now: this.instantiationTime }).then(() => undefined),
608
+ keys: this.keysUsed,
609
+ });
610
+ const refreshUnsubscribe = pubSub.subscribe({
611
+ type: 'cacheInvalidation',
612
+ predicate: (event) => setOverlaps(event.data, this.keysUsed),
613
+ callback: () => this.rerun().then(() => undefined),
614
+ keys: this.keysUsed,
545
615
  });
616
+ this.unsubscribeFromKeysImpl = () => {
617
+ rebuildUnsubscribe();
618
+ refreshUnsubscribe();
619
+ };
620
+ return;
621
+ }
622
+ unsubscribeFromKeys() {
623
+ this.unsubscribeFromKeysImpl();
546
624
  }
547
625
  // TODO: This should likely be abstract in v2. For v1, provide default comparison logic.
548
626
  equals(result1, result2) {
549
627
  return deepEquals$1(result1, result2);
550
628
  }
551
- buildRequestRunner(cache) {
552
- return {
553
- readFromCache: () => this.buildResultWithSubscribe(cache),
554
- requestFromNetwork: () => this.requestFromNetwork(),
555
- writeToCache: (networkResult) => this.writeToCacheAndPublish(cache, networkResult),
556
- };
557
- }
558
629
  async afterRequestHooks(_options) { }
559
630
  refresh() {
560
631
  return this.rerun({ cacheControlConfig: { type: 'no-cache' } }).then((result) => {
561
632
  if (result.isErr()) {
562
- return result;
633
+ return err(result.error);
563
634
  }
564
635
  return ok(undefined);
565
636
  });
566
637
  }
567
- // TODO: This is added as a temporary measure for ensuring that cache write events are
568
- // published to pubSub. A follow-up will be required to find the right home for this logic.
569
- writeToCacheAndPublish(cache, networkResult) {
638
+ writeToCacheAndRecordKeys(cache, networkResult) {
570
639
  const recordableCache = cache.record();
571
- const writeResult = this.writeToCache(recordableCache, networkResult);
572
- this.instantiationTime = Date.now() / 1000;
573
- if (this.services.pubSub) {
574
- this.services.pubSub.publish({
575
- type: 'cacheUpdate',
576
- data: recordableCache.keysUpdated,
577
- });
578
- }
579
- return writeResult;
640
+ return this.writeToCache(recordableCache, networkResult).then((result) => {
641
+ this.instantiationTime = Date.now() / 1000;
642
+ this.keysUpdated = recordableCache.keysUpdated;
643
+ return ok(result);
644
+ });
580
645
  }
581
646
  buildResultWithSubscribe(cache) {
582
647
  const recordableCache = cache.record();
@@ -587,15 +652,12 @@ class CacheControlCommand extends BaseCommand {
587
652
  }
588
653
  else {
589
654
  const data = readResult.value;
590
- if (data !== undefined) {
591
- this.subscribeToKeys = () => this.subscribeToKeySet(recordableCache.keysRead);
592
- return ok({
593
- data,
594
- subscribe: this.buildSubscribe(),
595
- refresh: () => this.refresh(),
596
- });
597
- }
598
- return ok(undefined);
655
+ this.keysUsed = recordableCache.keysRead;
656
+ return ok({
657
+ data,
658
+ subscribe: this.buildSubscribe(),
659
+ refresh: () => this.refresh(),
660
+ });
599
661
  }
600
662
  });
601
663
  }
@@ -611,7 +673,7 @@ class CacheControlCommand extends BaseCommand {
611
673
  buildSubscribe() {
612
674
  return (consumerCallback) => {
613
675
  if (this.subscriptions.length === 0 && this.operationType === 'query') {
614
- this.subscribeToKeys();
676
+ this.subscribeToKeysUsed();
615
677
  }
616
678
  this.subscriptions.push(consumerCallback);
617
679
  return () => {
@@ -635,27 +697,6 @@ class CacheControlCommand extends BaseCommand {
635
697
  return result;
636
698
  });
637
699
  }
638
- subscribeToKeySet(keysRead) {
639
- const { pubSub } = this.services;
640
- if (!pubSub) {
641
- return;
642
- }
643
- const createKeySubscriber = (type, callback) => pubSub.subscribe({
644
- type,
645
- predicate: (event) => setOverlaps(event.data, keysRead),
646
- callback,
647
- });
648
- // Unsubscribe to be sure that this command didn't re-execute and re-subscribe in between the start of command execution and now
649
- // it shouldn't be possible for this command to resubscribe between the beginning of execution and now
650
- // ...but lets be defensive.
651
- this.unsubscribeFromKeys();
652
- const rebuildUnsubscribe = createKeySubscriber('cacheUpdate', () => this.rerun({ now: this.instantiationTime }).then(() => undefined));
653
- const refreshUnsubscribe = createKeySubscriber('cacheInvalidation', () => this.rerun().then(() => undefined));
654
- this.unsubscribeFromKeys = () => {
655
- rebuildUnsubscribe();
656
- refreshUnsubscribe();
657
- };
658
- }
659
700
  invokeConsumerCallbacks(data) {
660
701
  this.subscriptions.forEach((cb) => {
661
702
  try {
@@ -771,13 +812,19 @@ class AuraResourceCacheControlCommand extends AuraCacheControlCommand {
771
812
  }
772
813
  readFromCache(cache) {
773
814
  var _a;
774
- return resolvedPromiseLike(ok((_a = cache.get(this.buildKey())) === null || _a === void 0 ? void 0 : _a.value));
815
+ const data = (_a = cache.get(this.buildKey())) === null || _a === void 0 ? void 0 : _a.value;
816
+ if (data === undefined) {
817
+ return resolvedPromiseLike(err(new Error('Failed to find data in cache')));
818
+ }
819
+ return resolvedPromiseLike(ok(data));
775
820
  }
776
821
  writeToCache(cache, networkResult) {
777
822
  if (networkResult.isOk()) {
778
823
  cache.set(this.buildKey(), {
779
824
  value: networkResult.value,
780
- metadata: { cacheControl: this.buildCacheControlMetadata(networkResult.value) },
825
+ metadata: {
826
+ cacheControl: this.buildCacheControlMetadata(networkResult.value),
827
+ },
781
828
  });
782
829
  }
783
830
  return resolvedPromiseLike(undefined);
@@ -1735,18 +1782,14 @@ function buildServiceDescriptor$4() {
1735
1782
 
1736
1783
 
1737
1784
  class CacheControlStrategy {
1738
- constructor(services, config, buildRequestRunner) {
1785
+ constructor(services, config, requestRunner) {
1739
1786
  this.services = services;
1740
1787
  this.config = config;
1741
- const requestRunnerCache = this.services.cache.filter((_, entry) => {
1788
+ this.requestRunner = requestRunner;
1789
+ this.filteredCache = this.services.cache.filter((_, entry) => {
1742
1790
  const { cacheControl } = entry.metadata;
1743
1791
  return !this.expiredChecks.some((check) => check(cacheControl));
1744
1792
  });
1745
- this.requestRunner = buildRequestRunner(requestRunnerCache);
1746
- }
1747
- isCacheHit(cacheReadValue) {
1748
- const isCacheMiss = cacheReadValue.isErr() || cacheReadValue.value === undefined;
1749
- return !isCacheMiss;
1750
1793
  }
1751
1794
  get expiredChecks() {
1752
1795
  return [
@@ -1760,45 +1803,90 @@ class CacheControlStrategy {
1760
1803
  }
1761
1804
  }
1762
1805
 
1806
+ class NoCacheCacheControlStrategy extends CacheControlStrategy {
1807
+ execute() {
1808
+ // TODO - should be using wrapper here that suppresses no-store writes
1809
+ const tempCache = this.filteredCache;
1810
+ return new Promise(async (resolve, reject) => {
1811
+ try {
1812
+ let readResult = ok(undefined);
1813
+ for await (const rfnResult of this.requestRunner.requestFromNetwork()) {
1814
+ if (rfnResult) {
1815
+ const result = await this.services.cacheInclusionPolicy.write({
1816
+ l1: tempCache,
1817
+ writeToL1: (l1) => this.requestRunner.writeToCache(l1, rfnResult),
1818
+ });
1819
+ if (result.isErr()) {
1820
+ return resolve(result);
1821
+ }
1822
+ }
1823
+ // give readFromCache another shot at the cache
1824
+ readResult = await this.services.cacheInclusionPolicy.read({
1825
+ l1: tempCache,
1826
+ readFromL1: (l1) => this.requestRunner.readFromCache(l1),
1827
+ });
1828
+ if (readResult.isOk()) {
1829
+ resolve(readResult);
1830
+ }
1831
+ }
1832
+ return resolve(readResult);
1833
+ }
1834
+ catch (error) {
1835
+ return reject(error);
1836
+ }
1837
+ });
1838
+ }
1839
+ }
1840
+
1763
1841
  class MaxAgeCacheControlStrategy extends CacheControlStrategy {
1764
1842
  execute(options) {
1765
1843
  const startTime = this.services.instrumentation
1766
1844
  ? this.services.instrumentation.currentTimeMs()
1767
1845
  : 0;
1768
- return this.requestRunner.readFromCache().then((value) => {
1769
- if (this.isCacheHit(value)) {
1770
- this.collectCacheHitInstrumentation(startTime, options === null || options === void 0 ? void 0 : options.instrumentationAttributes);
1771
- return value;
1772
- }
1773
- return this.handleCacheMiss(startTime, options === null || options === void 0 ? void 0 : options.instrumentationAttributes);
1774
- });
1775
- }
1776
- handleCacheMiss(startTime, instrumentationAttributes) {
1777
- let error;
1778
- return this.requestRunner
1779
- .requestFromNetwork()
1780
- .then((value) => {
1781
- if (value.isErr()) {
1782
- error = value;
1783
- return resolvedPromiseLike(null);
1784
- }
1785
- return this.requestRunner.writeToCache(value);
1786
- })
1787
- .then(() => {
1788
- if (error) {
1789
- return resolvedPromiseLike(null);
1790
- }
1791
- return this.requestRunner.readFromCache();
1846
+ return this.services.cacheInclusionPolicy
1847
+ .read({
1848
+ l1: this.filteredCache,
1849
+ readFromL1: (l1) => this.requestRunner.readFromCache(l1),
1792
1850
  })
1793
1851
  .then((value) => {
1794
- if (value === null) {
1795
- return error;
1796
- }
1797
- if (!this.isCacheHit(value)) {
1798
- return err(new Error('Cache miss after fetching from network'));
1852
+ // ignore error from initial cache read
1853
+ if (value.isOk()) {
1854
+ this.collectCacheHitInstrumentation(startTime, options === null || options === void 0 ? void 0 : options.instrumentationAttributes);
1855
+ return ok(undefined);
1799
1856
  }
1800
- this.collectCacheMissInstrumentation(startTime, instrumentationAttributes);
1801
- return value;
1857
+ this.collectCacheMissInstrumentation(startTime, options === null || options === void 0 ? void 0 : options.instrumentationAttributes);
1858
+ // initial cache read failed, awaits are ok beyond this point since the data
1859
+ // must come from network requests
1860
+ const tempCache = this.filteredCache;
1861
+ return new Promise(async (resolve, reject) => {
1862
+ try {
1863
+ let readResult = ok(undefined);
1864
+ for await (const rfnResult of this.requestRunner.requestFromNetwork()) {
1865
+ // async generator has a value to ingest
1866
+ if (rfnResult) {
1867
+ const result = await this.services.cacheInclusionPolicy.write({
1868
+ l1: tempCache,
1869
+ writeToL1: (l1) => this.requestRunner.writeToCache(l1, rfnResult),
1870
+ });
1871
+ if (result.isErr()) {
1872
+ return resolve(err(result.error));
1873
+ }
1874
+ }
1875
+ // give readFromCache another shot at the cache
1876
+ readResult = await this.services.cacheInclusionPolicy.read({
1877
+ l1: tempCache,
1878
+ readFromL1: (l1) => this.requestRunner.readFromCache(l1),
1879
+ });
1880
+ if (readResult.isOk()) {
1881
+ resolve(ok(undefined));
1882
+ }
1883
+ }
1884
+ return resolve(readResult);
1885
+ }
1886
+ catch (e) {
1887
+ return reject(e);
1888
+ }
1889
+ });
1802
1890
  });
1803
1891
  }
1804
1892
  collectCacheHitInstrumentation(startTime, instrumentationAttributes) {
@@ -1834,118 +1922,6 @@ class MaxAgeCacheControlStrategy extends CacheControlStrategy {
1834
1922
  }
1835
1923
  }
1836
1924
 
1837
- class NoCacheCacheControlStrategy extends CacheControlStrategy {
1838
- execute() {
1839
- return this.requestRunner.requestFromNetwork().then((networkResult) => {
1840
- if (networkResult.isErr()) {
1841
- return networkResult;
1842
- }
1843
- // Attempt to write to the cache
1844
- return this.requestRunner
1845
- .writeToCache(networkResult)
1846
- .then(() => this.requestRunner.readFromCache())
1847
- .then((cachedResult) => {
1848
- if (!this.isCacheHit(cachedResult)) {
1849
- return err(new Error('Cache miss after saving network result'));
1850
- }
1851
- return cachedResult;
1852
- });
1853
- });
1854
- }
1855
- }
1856
-
1857
- const isAndQuery = (query) => '$and' in query;
1858
- const isOrQuery = (query) => '$or' in query;
1859
- const isNotQuery = (query) => '$not' in query;
1860
- const matchesMetadata = (metadataQuery, cacheControl) => {
1861
- var _a;
1862
- if ('cacheControlType' in metadataQuery &&
1863
- cacheControl.type !== metadataQuery.cacheControlType.$eq) {
1864
- return false;
1865
- }
1866
- if ('maxAge' in metadataQuery && cacheControl.type === 'max-age') {
1867
- const maxAge = (_a = cacheControl.maxAge) !== null && _a !== void 0 ? _a : 0;
1868
- if ((metadataQuery.maxAge.$gte !== undefined && maxAge < metadataQuery.maxAge.$gte) ||
1869
- (metadataQuery.maxAge.$lte !== undefined && maxAge > metadataQuery.maxAge.$lte)) {
1870
- return false;
1871
- }
1872
- }
1873
- return true;
1874
- };
1875
- function queryToPredicate(query) {
1876
- return (key, entry) => {
1877
- if (!query)
1878
- return false;
1879
- if (isAndQuery(query))
1880
- return query.$and.every((subQuery) => queryToPredicate(subQuery)(key, entry));
1881
- if (isOrQuery(query))
1882
- return query.$or.some((subQuery) => queryToPredicate(subQuery)(key, entry));
1883
- if (isNotQuery(query))
1884
- return !queryToPredicate(query.$not)(key, entry);
1885
- if ('key' in query)
1886
- return matchesKey(query.key, key);
1887
- if ('metadata' in query)
1888
- return matchesMetadata(query.metadata, entry.metadata.cacheControl);
1889
- if ('value' in query)
1890
- return false; // TODO: Not implemented
1891
- throw new Error('Unknown Query Operation');
1892
- };
1893
- }
1894
- function matchesKey(keyQuery, key) {
1895
- if ('$regex' in keyQuery) {
1896
- return keyQuery.$regex.test(key);
1897
- }
1898
- return false;
1899
- }
1900
-
1901
- /**
1902
- * Processes a cache update operation and determines the appropriate modification.
1903
- *
1904
- * This function analyzes the provided `update` and the `existing` cache entry
1905
- * to determine the necessary update type. It returns one of three possible outcomes:
1906
- *
1907
- * - `{ type: 'entry', entry }`: A full cache entry update, including both value and metadata.
1908
- * - `{ type: 'metadata', metadata }`: A metadata-only update, leaving the value unchanged.
1909
- * - `{ type: 'no-op' }`: No changes are needed, and the cache should remain as is.
1910
- *
1911
- * @param update - The cache update operation to apply.
1912
- * @param existing - The existing cache entry being modified.
1913
- * @returns An object indicating the type of update:
1914
- * - A full cache entry update (`type: 'entry'`)
1915
- * - A metadata-only update (`type: 'metadata'`)
1916
- * - A no-op (`type: 'no-op'`) if no changes are required.
1917
- */
1918
- function buildUpdate(update, existing) {
1919
- switch (update.type) {
1920
- case 'invalidate':
1921
- const updatedCacheControl = buildInvalidatedCacheControl(existing.metadata.cacheControl);
1922
- return updatedCacheControl !== undefined
1923
- ? { type: 'metadata', metadata: updatedCacheControl }
1924
- : { type: 'no-op' };
1925
- default:
1926
- throw new Error(`Invalid update operation: ${update.type}`);
1927
- }
1928
- }
1929
- /**
1930
- * Builds an updated CacheControlMetadata object that invalidates the cache entry.
1931
- *
1932
- * @param existingCacheControl - The current CacheControlMetadata.
1933
- * @returns A new CacheControlMetadata object with `maxAge` set to `0`, or undefined if no changes are needed.
1934
- */
1935
- function buildInvalidatedCacheControl(existingCacheControl) {
1936
- switch (existingCacheControl.type) {
1937
- case 'max-age':
1938
- case 'stale-while-revalidate':
1939
- if (existingCacheControl.maxAge !== 0) {
1940
- return {
1941
- ...existingCacheControl,
1942
- maxAge: 0,
1943
- };
1944
- }
1945
- }
1946
- return undefined; // No-op: no changes
1947
- }
1948
-
1949
1925
  /**
1950
1926
  * A class that allows the execution of requested cache control strategies,
1951
1927
  * while also enforcing the canonical cache control metadata.
@@ -1954,16 +1930,16 @@ class CacheController {
1954
1930
  constructor(services) {
1955
1931
  this.services = services;
1956
1932
  }
1957
- execute(config, buildRequestRunner, options) {
1958
- const strategy = this.getCacheControlStrategy(config, buildRequestRunner);
1933
+ execute(config, requestRunner, options) {
1934
+ const strategy = this.getCacheControlStrategy(config, requestRunner);
1959
1935
  return strategy.execute(options);
1960
1936
  }
1961
- getCacheControlStrategy(config, buildRequestRunner) {
1937
+ getCacheControlStrategy(config, requestRunner) {
1962
1938
  if (config.type === 'max-age') {
1963
- return new MaxAgeCacheControlStrategy(this.services, config, buildRequestRunner);
1939
+ return new MaxAgeCacheControlStrategy(this.services, config, requestRunner);
1964
1940
  }
1965
1941
  else if (config.type === 'no-cache') {
1966
- return new NoCacheCacheControlStrategy(this.services, config, buildRequestRunner);
1942
+ return new NoCacheCacheControlStrategy(this.services, config, requestRunner);
1967
1943
  }
1968
1944
  throw new Error(`Unknown cache control strategy ${config.type}`);
1969
1945
  }
@@ -1972,39 +1948,22 @@ class CacheController {
1972
1948
  * Returns an async generator that yields `[key, entry]`.
1973
1949
  */
1974
1950
  async *find(query) {
1975
- const cache = this.services.cache;
1976
- const predicate = queryToPredicate(query);
1977
- const filteredEntries = cache.filter(predicate).entries();
1978
- for (const entry of filteredEntries) {
1979
- yield entry;
1980
- }
1951
+ yield* this.services.cacheInclusionPolicy.find(query);
1981
1952
  }
1982
1953
  /**
1983
1954
  * Finds and modifies cache entries that match the given query.
1984
1955
  * Extends `find(query)` and returns an async generator of modified keys.
1985
1956
  */
1986
1957
  async *findAndModify(query, cacheUpdate) {
1987
- for await (const [key, value] of this.find(query)) {
1988
- const update = buildUpdate(cacheUpdate, value);
1989
- switch (update.type) {
1990
- case 'entry':
1991
- this.services.cache.set(key, update.entry);
1992
- yield key;
1993
- break;
1994
- case 'metadata':
1995
- this.services.cache.setMetadata(key, update.metadata);
1996
- yield key;
1997
- break;
1998
- }
1999
- }
1958
+ yield* this.services.cacheInclusionPolicy.findAndModify(query, cacheUpdate);
2000
1959
  }
2001
1960
  }
2002
1961
 
2003
- function buildServiceDescriptor$3(cache) {
1962
+ function buildServiceDescriptor$3(cache, cacheInclusionPolicy) {
2004
1963
  return {
2005
1964
  type: 'cacheController',
2006
1965
  version: '1.0',
2007
- service: new CacheController({ cache }),
1966
+ service: new CacheController({ cache, cacheInclusionPolicy }),
2008
1967
  };
2009
1968
  }
2010
1969
 
@@ -2032,14 +1991,33 @@ class DefaultPubSubService {
2032
1991
  }
2033
1992
  eventTypeSubscriptions.push(subscription);
2034
1993
  return () => {
2035
- this.subscriptions.set(subscription.type, eventTypeSubscriptions.filter((value) => value !== subscription));
1994
+ this.subscriptions.set(subscription.type, this.subscriptions.get(subscription.type).filter((value) => value !== subscription));
2036
1995
  };
2037
1996
  }
2038
1997
  publish(event) {
1998
+ const promises = [];
1999
+ const subscriptions = this.getSubscriptions(event);
2000
+ subscriptions.forEach((subscription) => {
2001
+ // need to check that the subscription hasn't been unsubscribed during one of the callbacks
2002
+ if (!this.getSubscriptions(event).includes(subscription)) {
2003
+ return;
2004
+ }
2005
+ // Ensure callback maintains its context
2006
+ const returnVal = subscription.callback.call(subscription, event);
2007
+ if (isPromiseLike(returnVal)) {
2008
+ promises.push(returnVal);
2009
+ }
2010
+ });
2011
+ if (promises.length > 0) {
2012
+ return Promise.all(promises).then(() => undefined);
2013
+ }
2014
+ return resolvedPromiseLike(undefined);
2015
+ }
2016
+ getSubscriptions(event) {
2039
2017
  const eventTypeSubscriptions = this.subscriptions.get(event.type);
2040
2018
  const wildcardSubscriptions = this.subscriptions.get(EventTypeWildcard);
2041
2019
  if (eventTypeSubscriptions === undefined && wildcardSubscriptions === undefined) {
2042
- return resolvedPromiseLike(undefined);
2020
+ return [];
2043
2021
  }
2044
2022
  let matchingSubscriptions = [];
2045
2023
  if (eventTypeSubscriptions !== undefined) {
@@ -2051,17 +2029,7 @@ class DefaultPubSubService {
2051
2029
  });
2052
2030
  }
2053
2031
  matchingSubscriptions = [...matchingSubscriptions, ...(wildcardSubscriptions || [])];
2054
- const promises = [];
2055
- matchingSubscriptions.forEach((subscription) => {
2056
- const returnVal = subscription.callback(event);
2057
- if (isPromiseLike(returnVal)) {
2058
- promises.push(returnVal);
2059
- }
2060
- });
2061
- if (promises.length > 0) {
2062
- return Promise.all(promises).then(() => undefined);
2063
- }
2064
- return resolvedPromiseLike(undefined);
2032
+ return matchingSubscriptions;
2065
2033
  }
2066
2034
  }
2067
2035
  /**
@@ -2704,7 +2672,7 @@ var TypeCheckShapes;
2704
2672
  TypeCheckShapes[TypeCheckShapes["Integer"] = 3] = "Integer";
2705
2673
  TypeCheckShapes[TypeCheckShapes["Unsupported"] = 4] = "Unsupported";
2706
2674
  })(TypeCheckShapes || (TypeCheckShapes = {}));
2707
- // engine version: 0.156.7-d2b9c7ef
2675
+ // engine version: 0.157.4-1c316582
2708
2676
 
2709
2677
  const { keys: keys$1 } = Object;
2710
2678
 
@@ -5689,7 +5657,7 @@ function getEnvironmentSetting(name) {
5689
5657
  }
5690
5658
  return undefined;
5691
5659
  }
5692
- // version: 1.358.0-abc73971a1
5660
+ // version: 1.360.0-3cf173d4f8
5693
5661
 
5694
5662
  const forceRecordTransactionsDisabled = getEnvironmentSetting(EnvironmentSettings.ForceRecordTransactionsDisabled);
5695
5663
  //TODO: Some duplication here that can be most likely moved to a util class
@@ -6100,6 +6068,190 @@ class PredictionsReadyManager {
6100
6068
  }
6101
6069
  }
6102
6070
 
6071
+ /**
6072
+ * Copyright (c) 2022, Salesforce, Inc.,
6073
+ * All rights reserved.
6074
+ * For full license text, see the LICENSE.txt file
6075
+ */
6076
+
6077
+
6078
+ /**
6079
+ * CacheInclusionPolicy is an interface for accessing the cache
6080
+ * and synchronizing the cache data with another external cache.
6081
+ *
6082
+ * https://en.wikipedia.org/wiki/Cache_inclusion_policy
6083
+ */
6084
+ class CacheInclusionPolicyService {
6085
+ }
6086
+
6087
+ const isAndQuery = (query) => '$and' in query;
6088
+ const isOrQuery = (query) => '$or' in query;
6089
+ const isNotQuery = (query) => '$not' in query;
6090
+ const matchesMetadata = (metadataQuery, cacheControl) => {
6091
+ var _a;
6092
+ if ('cacheControlType' in metadataQuery &&
6093
+ cacheControl.type !== metadataQuery.cacheControlType.$eq) {
6094
+ return false;
6095
+ }
6096
+ if ('maxAge' in metadataQuery && cacheControl.type === 'max-age') {
6097
+ const maxAge = (_a = cacheControl.maxAge) !== null && _a !== void 0 ? _a : 0;
6098
+ if ((metadataQuery.maxAge.$gte !== undefined && maxAge < metadataQuery.maxAge.$gte) ||
6099
+ (metadataQuery.maxAge.$lte !== undefined && maxAge > metadataQuery.maxAge.$lte)) {
6100
+ return false;
6101
+ }
6102
+ }
6103
+ return true;
6104
+ };
6105
+ function queryToPredicate(query) {
6106
+ return (key, entry) => {
6107
+ if (!query)
6108
+ return false;
6109
+ if (isAndQuery(query))
6110
+ return query.$and.every((subQuery) => queryToPredicate(subQuery)(key, entry));
6111
+ if (isOrQuery(query))
6112
+ return query.$or.some((subQuery) => queryToPredicate(subQuery)(key, entry));
6113
+ if (isNotQuery(query))
6114
+ return !queryToPredicate(query.$not)(key, entry);
6115
+ if ('key' in query)
6116
+ return matchesKey(query.key, key);
6117
+ if ('metadata' in query)
6118
+ return matchesMetadata(query.metadata, entry.metadata.cacheControl);
6119
+ if ('value' in query)
6120
+ return false; // TODO: Not implemented
6121
+ throw new Error('Unknown Query Operation');
6122
+ };
6123
+ }
6124
+ function matchesKey(keyQuery, key) {
6125
+ if ('$regex' in keyQuery) {
6126
+ return keyQuery.$regex.test(key);
6127
+ }
6128
+ return false;
6129
+ }
6130
+
6131
+ /**
6132
+ * Processes a cache update operation and determines the appropriate modification.
6133
+ *
6134
+ * This function analyzes the provided `update` and the `existing` cache entry
6135
+ * to determine the necessary update type. It returns one of three possible outcomes:
6136
+ *
6137
+ * - `{ type: 'entry', entry }`: A full cache entry update, including both value and metadata.
6138
+ * - `{ type: 'metadata', metadata }`: A metadata-only update, leaving the value unchanged.
6139
+ * - `{ type: 'no-op' }`: No changes are needed, and the cache should remain as is.
6140
+ *
6141
+ * @param update - The cache update operation to apply.
6142
+ * @param existing - The existing cache entry being modified.
6143
+ * @returns An object indicating the type of update:
6144
+ * - A full cache entry update (`type: 'entry'`)
6145
+ * - A metadata-only update (`type: 'metadata'`)
6146
+ * - A no-op (`type: 'no-op'`) if no changes are required.
6147
+ */
6148
+ function buildUpdate(update, existing) {
6149
+ switch (update.type) {
6150
+ case 'invalidate':
6151
+ const updatedCacheControl = buildInvalidatedCacheControl(existing.metadata.cacheControl);
6152
+ return updatedCacheControl !== undefined
6153
+ ? { type: 'metadata', metadata: updatedCacheControl }
6154
+ : { type: 'no-op' };
6155
+ default:
6156
+ throw new Error(`Invalid update operation: ${update.type}`);
6157
+ }
6158
+ }
6159
+ /**
6160
+ * Builds an updated CacheControlMetadata object that invalidates the cache entry.
6161
+ *
6162
+ * @param existingCacheControl - The current CacheControlMetadata.
6163
+ * @returns A new CacheControlMetadata object with `maxAge` set to `0`, or undefined if no changes are needed.
6164
+ */
6165
+ function buildInvalidatedCacheControl(existingCacheControl) {
6166
+ switch (existingCacheControl.type) {
6167
+ case 'max-age':
6168
+ case 'stale-while-revalidate':
6169
+ if (existingCacheControl.maxAge !== 0) {
6170
+ return {
6171
+ ...existingCacheControl,
6172
+ maxAge: 0,
6173
+ };
6174
+ }
6175
+ }
6176
+ return undefined; // No-op: no changes
6177
+ }
6178
+
6179
+ /**
6180
+ * Implementation of CacheInclusionPolicy that uses a single level, in memory,
6181
+ * synchronous L1 cache.
6182
+ */
6183
+ class InMemoryCacheInclusionPolicy extends CacheInclusionPolicyService {
6184
+ constructor(services) {
6185
+ super();
6186
+ this.services = services;
6187
+ }
6188
+ /**
6189
+ * Reads data out of a single level in memory store.
6190
+ */
6191
+ read(options) {
6192
+ const { l1, readFromL1 } = options;
6193
+ // l1 is all we've got
6194
+ return readFromL1(l1);
6195
+ }
6196
+ /**
6197
+ * Writes data to a single level in memory store.
6198
+ */
6199
+ write(options) {
6200
+ const { l1, writeToL1 } = options;
6201
+ return writeToL1(l1);
6202
+ }
6203
+ /**
6204
+ * Finds cache entries that match the given query.
6205
+ * Returns an async generator that yields `[key, entry]`.
6206
+ */
6207
+ async *find(query) {
6208
+ const cache = this.services.cache;
6209
+ const predicate = queryToPredicate(query);
6210
+ const filteredEntries = cache.filter(predicate).entries();
6211
+ for (const entry of filteredEntries) {
6212
+ yield entry;
6213
+ }
6214
+ }
6215
+ /**
6216
+ * Finds and modifies cache entries that match the given query.
6217
+ * Extends `find(query)` and returns an async generator of modified keys.
6218
+ */
6219
+ async *findAndModify(query, cacheUpdate) {
6220
+ const cache = this.services.cache;
6221
+ for await (const [key, value] of this.find(query)) {
6222
+ const update = buildUpdate(cacheUpdate, value);
6223
+ switch (update.type) {
6224
+ case 'entry':
6225
+ this.write({
6226
+ l1: cache,
6227
+ writeToL1: (l1) => resolvedPromiseLike(ok(l1.set(key, update.entry))),
6228
+ });
6229
+ yield key;
6230
+ break;
6231
+ case 'metadata':
6232
+ this.write({
6233
+ l1: cache,
6234
+ writeToL1: (l1) => resolvedPromiseLike(ok(l1.setMetadata(key, update.metadata))),
6235
+ });
6236
+ yield key;
6237
+ break;
6238
+ }
6239
+ }
6240
+ }
6241
+ }
6242
+ /**
6243
+ * Constructs an in-memory-only CacheInclusionPolicy.
6244
+ *
6245
+ * @returns in-memory-only CacheInclusionPolicy
6246
+ */
6247
+ function buildInMemoryCacheInclusionPolicyService(cache) {
6248
+ return {
6249
+ service: new InMemoryCacheInclusionPolicy({ cache }),
6250
+ type: 'cacheInclusionPolicy',
6251
+ version: '1.0',
6252
+ };
6253
+ }
6254
+
6103
6255
  // This code *should* be in lds-network-adapter, but when combined with the Aura
6104
6256
  // component test workaround in lds-default-luvio it creates a circular dependecy
6105
6257
  // between lds-default-luvio and lds-network-adapter. We do the register on behalf
@@ -6342,6 +6494,7 @@ function initializeOneStore() {
6342
6494
  const loggerService = new ConsoleLogger$1('ERROR');
6343
6495
  const cacheServiceDescriptor = buildServiceDescriptor$4();
6344
6496
  const instrumentationServiceDescriptor = buildServiceDescriptor$5(loggerService);
6497
+ const inMemoryCacheInclusionPolicyServiceDescriptor = buildInMemoryCacheInclusionPolicyService(cacheServiceDescriptor.service);
6345
6498
  const services = [
6346
6499
  instrumentationServiceDescriptor,
6347
6500
  buildUnauthorizedFetchServiceDescriptor(),
@@ -6349,7 +6502,7 @@ function initializeOneStore() {
6349
6502
  buildCopilotFetchServiceDescriptor(loggerService),
6350
6503
  buildAuraNetworkService(),
6351
6504
  buildServiceDescriptor$6(instrumentationServiceDescriptor.service),
6352
- buildServiceDescriptor$3(cacheServiceDescriptor.service),
6505
+ buildServiceDescriptor$3(cacheServiceDescriptor.service, inMemoryCacheInclusionPolicyServiceDescriptor.service),
6353
6506
  buildServiceDescriptor$d(),
6354
6507
  buildServiceDescriptor$1(),
6355
6508
  buildServiceDescriptor$9(),
@@ -6382,4 +6535,4 @@ function ldsEngineCreator() {
6382
6535
  }
6383
6536
 
6384
6537
  export { LexRequestStrategy, PdlRequestPriority, buildPredictorForContext, ldsEngineCreator as default, initializeLDS, initializeOneStore, registerRequestStrategy, saveRequestAsPrediction, unregisterRequestStrategy, whenPredictionsReady };
6385
- // version: 1.358.0-d83368bac0
6538
+ // version: 1.360.0-580249acee
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/lds-runtime-aura",
3
- "version": "1.358.0",
3
+ "version": "1.360.0",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "LDS engine for Aura runtime",
6
6
  "main": "dist/ldsEngineCreator.js",
@@ -34,48 +34,49 @@
34
34
  "release:corejar": "yarn build && ../core-build/scripts/core.js --name=lds-runtime-aura"
35
35
  },
36
36
  "devDependencies": {
37
- "@luvio/service-provisioner": " 5.39.0",
38
- "@luvio/tools-core": " 5.39.0",
39
- "@salesforce/lds-adapters-apex": "^1.358.0",
40
- "@salesforce/lds-adapters-uiapi": "^1.358.0",
37
+ "@luvio/service-provisioner": "5.40.3",
38
+ "@luvio/tools-core": "5.40.3",
39
+ "@salesforce/lds-adapters-apex": "^1.360.0",
40
+ "@salesforce/lds-adapters-uiapi": "^1.360.0",
41
41
  "@salesforce/lds-adapters-uiapi-lex": "^1.302.0",
42
- "@salesforce/lds-ads-bridge": "^1.358.0",
43
- "@salesforce/lds-aura-storage": "^1.358.0",
44
- "@salesforce/lds-bindings": "^1.358.0",
45
- "@salesforce/lds-instrumentation": "^1.358.0",
46
- "@salesforce/lds-network-aura": "^1.358.0",
47
- "@salesforce/lds-network-fetch": "^1.358.0",
42
+ "@salesforce/lds-ads-bridge": "^1.360.0",
43
+ "@salesforce/lds-aura-storage": "^1.360.0",
44
+ "@salesforce/lds-bindings": "^1.360.0",
45
+ "@salesforce/lds-instrumentation": "^1.360.0",
46
+ "@salesforce/lds-network-aura": "^1.360.0",
47
+ "@salesforce/lds-network-fetch": "^1.360.0",
48
48
  "jwt-encode": "1.0.1"
49
49
  },
50
50
  "dependencies": {
51
- "@luvio/command-aura-network": " 5.39.0",
52
- "@luvio/command-aura-normalized-cache-control": " 5.39.0",
53
- "@luvio/command-aura-resource-cache-control": " 5.39.0",
54
- "@luvio/command-fetch-network": " 5.39.0",
55
- "@luvio/command-http-normalized-cache-control": " 5.39.0",
56
- "@luvio/command-ndjson": " 5.39.0",
57
- "@luvio/command-network": " 5.39.0",
58
- "@luvio/command-sse": " 5.39.0",
59
- "@luvio/command-streaming": " 5.39.0",
60
- "@luvio/network-adapter-composable": "0.156.7",
61
- "@luvio/network-adapter-fetch": "0.156.7",
62
- "@luvio/service-aura-network": " 5.39.0",
63
- "@luvio/service-cache": " 5.39.0",
64
- "@luvio/service-cache-control": " 5.39.0",
65
- "@luvio/service-fetch-network": " 5.39.0",
66
- "@luvio/service-instrument-command": " 5.39.0",
67
- "@luvio/service-pubsub": " 5.39.0",
68
- "@luvio/service-store": " 5.39.0",
69
- "@luvio/utils": " 5.39.0",
70
- "@salesforce/lds-adapters-uiapi-lex": "^1.358.0"
51
+ "@luvio/command-aura-network": "5.40.3",
52
+ "@luvio/command-aura-normalized-cache-control": "5.40.3",
53
+ "@luvio/command-aura-resource-cache-control": "5.40.3",
54
+ "@luvio/command-fetch-network": "5.40.3",
55
+ "@luvio/command-http-normalized-cache-control": "5.40.3",
56
+ "@luvio/command-ndjson": "5.40.3",
57
+ "@luvio/command-network": "5.40.3",
58
+ "@luvio/command-sse": "5.40.3",
59
+ "@luvio/command-streaming": "5.40.3",
60
+ "@luvio/network-adapter-composable": "0.157.4",
61
+ "@luvio/network-adapter-fetch": "0.157.4",
62
+ "@luvio/service-aura-network": "5.40.3",
63
+ "@luvio/service-cache": "5.40.3",
64
+ "@luvio/service-cache-control": "5.40.3",
65
+ "@luvio/service-cache-inclusion-policy": "5.40.3",
66
+ "@luvio/service-fetch-network": "5.40.3",
67
+ "@luvio/service-instrument-command": "5.40.3",
68
+ "@luvio/service-pubsub": "5.40.3",
69
+ "@luvio/service-store": "5.40.3",
70
+ "@luvio/utils": "5.40.3",
71
+ "@salesforce/lds-adapters-uiapi-lex": "^1.360.0"
71
72
  },
72
73
  "luvioBundlesize": [
73
74
  {
74
75
  "path": "./dist/ldsEngineCreator.js",
75
76
  "maxSize": {
76
- "none": "238 kB",
77
- "min": "98 kB",
78
- "compressed": "41 kB"
77
+ "none": "245 kB",
78
+ "min": "100 kB",
79
+ "compressed": "45 kB"
79
80
  }
80
81
  }
81
82
  ],