@salesforce/lds-runtime-aura 1.453.0 → 1.455.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.
@@ -49,7 +49,7 @@ import { createStorage, clearStorages } from 'force/ldsDurableStorage';
49
49
  import { registerSubRequestNetworkAdapter } from 'force/ldsNetwork';
50
50
 
51
51
  const { create: create$1, freeze, keys: keys$2, entries: entries$1 } = Object;
52
- const { isArray: isArray$3 } = Array;
52
+ const { isArray: isArray$4 } = Array;
53
53
  const { stringify: stringify$3, parse: parse$2 } = JSON;
54
54
  const WeakSetConstructor = WeakSet;
55
55
  const LogLevelMap = {
@@ -191,7 +191,7 @@ function stableJSONStringify$2(node) {
191
191
  }
192
192
  let i;
193
193
  let out;
194
- if (isArray$3(node)) {
194
+ if (isArray$4(node)) {
195
195
  out = "[";
196
196
  for (i = 0; i < node.length; i++) {
197
197
  if (i) {
@@ -299,7 +299,7 @@ function deepFreeze(value) {
299
299
  return;
300
300
  }
301
301
  deeplyFrozen.add(value);
302
- if (isArray$3(value)) {
302
+ if (isArray$4(value)) {
303
303
  for (let i = 0, len = value.length; i < len; i += 1) {
304
304
  deepFreeze(value[i]);
305
305
  }
@@ -526,7 +526,7 @@ function buildServiceDescriptor$p() {
526
526
  };
527
527
  }
528
528
 
529
- const { isArray: isArray$2 } = Array;
529
+ const { isArray: isArray$3 } = Array;
530
530
  let Ok$1 = class Ok {
531
531
  constructor(value) {
532
532
  this.value = value;
@@ -606,8 +606,8 @@ function deepEquals$1(x, y) {
606
606
  return y === null;
607
607
  } else if (y === null) {
608
608
  return x === null;
609
- } else if (isArray$2(x)) {
610
- if (!isArray$2(y) || x.length !== y.length) {
609
+ } else if (isArray$3(x)) {
610
+ if (!isArray$3(y) || x.length !== y.length) {
611
611
  return false;
612
612
  }
613
613
  for (let i = 0; i < x.length; ++i) {
@@ -2589,7 +2589,7 @@ function buildServiceDescriptor$d(luvio) {
2589
2589
  },
2590
2590
  };
2591
2591
  }
2592
- // version: 1.453.0-725e09cf25
2592
+ // version: 1.455.0-c53c97de2a
2593
2593
 
2594
2594
  class AuraGraphQLNormalizedCacheControlCommand extends AuraNormalizedCacheControlCommand {
2595
2595
  constructor(config, documentRootType, services) {
@@ -2928,7 +2928,7 @@ function buildServiceDescriptor$9(notifyRecordUpdateAvailable, getNormalizedLuvi
2928
2928
  },
2929
2929
  };
2930
2930
  }
2931
- // version: 1.453.0-725e09cf25
2931
+ // version: 1.455.0-c53c97de2a
2932
2932
 
2933
2933
  class RetryService {
2934
2934
  constructor(defaultRetryPolicy) {
@@ -4725,9 +4725,10 @@ var TypeCheckShapes;
4725
4725
  TypeCheckShapes[TypeCheckShapes["Integer"] = 3] = "Integer";
4726
4726
  TypeCheckShapes[TypeCheckShapes["Unsupported"] = 4] = "Unsupported";
4727
4727
  })(TypeCheckShapes || (TypeCheckShapes = {}));
4728
- // engine version: 0.161.0-fe06f180
4728
+ // engine version: 0.161.2-bd1bd38a
4729
4729
 
4730
4730
  const { keys: keys$1 } = Object;
4731
+ const { isArray: isArray$2 } = Array;
4731
4732
 
4732
4733
  // we're going to intentionally bundle this small bit of luvio engine code into
4733
4734
  // this module to keep it runtime dependency-free
@@ -4800,7 +4801,14 @@ const fetchNetworkAdapter = async (resourceRequest, _resourceRequestContext) =>
4800
4801
  function generateQueryString(params) {
4801
4802
  const searchParams = new URLSearchParams();
4802
4803
  for (const key of keys$1(params)) {
4803
- searchParams.append(key, String(params[key]));
4804
+ const value = params[key];
4805
+ // omit undefined and empty-array values entirely: String(undefined) === 'undefined'
4806
+ // and String([]) === '', both of which would otherwise serialize as a valueless
4807
+ // `key=` or literal `key=undefined` query param that servers can reject.
4808
+ if (value === undefined || (isArray$2(value) && value.length === 0)) {
4809
+ continue;
4810
+ }
4811
+ searchParams.append(key, String(value));
4804
4812
  }
4805
4813
  const queryString = searchParams.toString();
4806
4814
  if (queryString.length > 0) {
@@ -5817,7 +5825,7 @@ class PrioritizedConfigService {
5817
5825
  get: (_, property) => {
5818
5826
  const propertyPath = [...path, property];
5819
5827
  const value = this.valueFor(propertyPath);
5820
- return typeof value === "object" && value !== null && !isArray$3(value) ? this.buildReadonlyObjectProxy(propertyPath) : value;
5828
+ return typeof value === "object" && value !== null && !isArray$4(value) ? this.buildReadonlyObjectProxy(propertyPath) : value;
5821
5829
  },
5822
5830
  getOwnPropertyDescriptor: (target, property) => {
5823
5831
  const propertyPath = [...path, property];
@@ -5825,7 +5833,7 @@ class PrioritizedConfigService {
5825
5833
  return {
5826
5834
  value: (
5827
5835
  // TODO - need to wrap arrays in a Proxy as well
5828
- typeof value === "object" && value !== null && !isArray$3(value) ? this.buildReadonlyObjectProxy(propertyPath) : value
5836
+ typeof value === "object" && value !== null && !isArray$4(value) ? this.buildReadonlyObjectProxy(propertyPath) : value
5829
5837
  ),
5830
5838
  writable: false,
5831
5839
  configurable: true,
@@ -5926,7 +5934,7 @@ function getEnvironmentSetting(name) {
5926
5934
  }
5927
5935
  return undefined;
5928
5936
  }
5929
- // version: 1.453.0-e6dc0c039a
5937
+ // version: 1.455.0-96e9b41a18
5930
5938
 
5931
5939
  const auraClientService = getAuraClientService();
5932
5940
  const defaultConfig = {
@@ -6463,6 +6471,45 @@ function getCsrfTokenManager() {
6463
6471
  return cached;
6464
6472
  }
6465
6473
 
6474
+ /**
6475
+ * Extracts the HTTP method from FetchParameters, matching the Fetch API's own
6476
+ * precedence: an options.method override wins over a Request object's method
6477
+ * (e.g. `fetch(new Request(url, { method: 'GET' }), { method: 'POST' })`
6478
+ * resolves to `POST`).
6479
+ */
6480
+ function getFetchMethod([urlOrRequest, options]) {
6481
+ if (options && 'method' in options) {
6482
+ return options.method;
6483
+ }
6484
+ if (typeof urlOrRequest !== 'string' && 'method' in urlOrRequest) {
6485
+ return urlOrRequest.method;
6486
+ }
6487
+ return undefined;
6488
+ }
6489
+ /**
6490
+ * Only GET requests are safe to replay automatically on 429/503 — replaying a
6491
+ * write (POST/PUT/PATCH/DELETE) risks executing a mutation more than once.
6492
+ * Shared by both the Luvio and generic-fetch throttling retry policies so the
6493
+ * write-guard rule lives in exactly one place.
6494
+ */
6495
+ function isRetryableMethod(method) {
6496
+ return method?.toLowerCase() === 'get';
6497
+ }
6498
+ /**
6499
+ * Determines if the HTTP method requires CSRF protection.
6500
+ * Only mutating operations (POST, PUT, PATCH, DELETE) require CSRF tokens.
6501
+ */
6502
+ function isCsrfMethod(method) {
6503
+ if (!method) {
6504
+ return false;
6505
+ }
6506
+ const normalizedMethod = method.toLowerCase();
6507
+ return (normalizedMethod === 'post' ||
6508
+ normalizedMethod === 'put' ||
6509
+ normalizedMethod === 'patch' ||
6510
+ normalizedMethod === 'delete');
6511
+ }
6512
+
6466
6513
  const CSRF_TOKEN_HEADER = 'X-CSRF-Token';
6467
6514
  /**
6468
6515
  * Resolves the CSRF token manager and returns the current token. Returns
@@ -6495,23 +6542,6 @@ function areCsrfGatesEnabled() {
6495
6542
  return false;
6496
6543
  }
6497
6544
  }
6498
- /**
6499
- * Determines if the HTTP method requires CSRF protection.
6500
- * Only mutating operations (POST, PUT, PATCH, DELETE) require CSRF tokens.
6501
- *
6502
- * @param method - The HTTP method to check
6503
- * @returns true if the method requires CSRF protection
6504
- */
6505
- function isCsrfMethod(method) {
6506
- if (!method) {
6507
- return false;
6508
- }
6509
- const normalizedMethod = method.toLowerCase();
6510
- return (normalizedMethod === 'post' ||
6511
- normalizedMethod === 'put' ||
6512
- normalizedMethod === 'patch' ||
6513
- normalizedMethod === 'delete');
6514
- }
6515
6545
  /**
6516
6546
  * Builds a request interceptor that adds CSRF token headers to mutating requests.
6517
6547
  * The CSRF token is fetched once and cached for subsequent requests.
@@ -6525,17 +6555,8 @@ function buildCsrfTokenInterceptor() {
6525
6555
  if (!areCsrfGatesEnabled()) {
6526
6556
  return resolvedPromiseLike$2(fetchArgs);
6527
6557
  }
6528
- const [urlOrRequest, options] = fetchArgs;
6529
- // Determine the method from either Request object or options
6530
- let method;
6531
- if (typeof urlOrRequest !== 'string' && 'method' in urlOrRequest) {
6532
- method = urlOrRequest.method;
6533
- }
6534
- else if (options && 'method' in options) {
6535
- method = options.method;
6536
- }
6537
6558
  // Only add CSRF token for mutating operations
6538
- if (isCsrfMethod(method)) {
6559
+ if (isCsrfMethod(getFetchMethod(fetchArgs))) {
6539
6560
  const token = await getCsrfToken();
6540
6561
  if (token) {
6541
6562
  // eslint-disable-next-line no-param-reassign
@@ -6943,12 +6964,14 @@ const DEFAULT_CONFIG$2 = {
6943
6964
  jitterPercent: 0.5,
6944
6965
  };
6945
6966
  class LuvioFetchThrottlingRetryPolicy extends RetryPolicy {
6946
- constructor(config = DEFAULT_CONFIG$2) {
6967
+ constructor(config = DEFAULT_CONFIG$2, method) {
6947
6968
  super();
6948
6969
  this.config = config;
6970
+ this.method = method;
6949
6971
  }
6950
6972
  async shouldRetry(result, context) {
6951
- return ((result.status === 429 || result.status === 503) &&
6973
+ return (isRetryableMethod(this.method) &&
6974
+ (result.status === 429 || result.status === 503) &&
6952
6975
  context.attempt < this.config.maxRetries &&
6953
6976
  context.totalElapsedMs <= this.config.maxTimeToRetry);
6954
6977
  }
@@ -7011,7 +7034,7 @@ function buildLuvioFetchRetryInterceptor() {
7011
7034
  return (request, doFetch) => {
7012
7035
  const csrfPolicy = new LuvioCsrfTokenRetryPolicy();
7013
7036
  const composedPolicy = new ComposedRetryPolicy([
7014
- new LuvioFetchThrottlingRetryPolicy(),
7037
+ new LuvioFetchThrottlingRetryPolicy(undefined, request.method),
7015
7038
  csrfPolicy,
7016
7039
  ]);
7017
7040
  const retryService = new RetryService(composedPolicy);
@@ -7583,28 +7606,112 @@ async function isCsrfError(response) {
7583
7606
  }
7584
7607
  }
7585
7608
 
7586
- function buildCsrfRetryInterceptor() {
7609
+ const DEFAULT_CONFIG = {
7610
+ maxRetries: 3,
7611
+ maxTimeToRetry: 10000,
7612
+ baseDelay: 250,
7613
+ maxDelay: 5000,
7614
+ exponentialFactor: 2,
7615
+ jitterPercent: 0.5,
7616
+ };
7617
+ class FetchThrottlingRetryPolicy extends RetryPolicy {
7618
+ constructor(config = DEFAULT_CONFIG, method) {
7619
+ super();
7620
+ this.config = config;
7621
+ this.method = method;
7622
+ }
7623
+ async shouldRetry(result, context) {
7624
+ return (isRetryableMethod(this.method) &&
7625
+ (result.status === 429 || result.status === 503) &&
7626
+ context.attempt < this.config.maxRetries &&
7627
+ context.totalElapsedMs <= this.config.maxTimeToRetry);
7628
+ }
7629
+ async calculateDelay(result, context) {
7630
+ let delay;
7631
+ // If retry-after header is present and valid, use it
7632
+ const retryAfterHeader = this.parseRetryAfterHeader(result);
7633
+ if (retryAfterHeader !== undefined) {
7634
+ delay = Math.min(retryAfterHeader, this.config.maxDelay);
7635
+ }
7636
+ else {
7637
+ // Exponential backoff
7638
+ delay = Math.min(this.config.baseDelay * Math.pow(this.config.exponentialFactor, context.attempt), this.config.maxDelay);
7639
+ }
7640
+ // Add jitter to prevent thundering herd
7641
+ const jitter = delay * this.config.jitterPercent * (Math.random() - 0.5);
7642
+ return Math.max(0, delay + jitter);
7643
+ }
7644
+ parseRetryAfterHeader(result) {
7645
+ if (!result.headers) {
7646
+ return undefined;
7647
+ }
7648
+ const value = result.headers.get('Retry-After');
7649
+ if (!value) {
7650
+ return undefined;
7651
+ }
7652
+ // The Retry-After header can be either a number of seconds or an HTTP-date (IMF-fixdate)
7653
+ // Retry-After: <delay-seconds>
7654
+ // Retry-After: <http-date>
7655
+ const trimmed = value.trim();
7656
+ // Strictly treat only all-digits as seconds
7657
+ if (/^\d+$/.test(trimmed)) {
7658
+ const seconds = Number(trimmed);
7659
+ if (Number.isFinite(seconds) && seconds >= 0) {
7660
+ return seconds * 1000; // Convert to milliseconds
7661
+ }
7662
+ return undefined;
7663
+ }
7664
+ // Strict RFC 7231 IMF-fixdate format (e.g., "Sun, 06 Nov 1994 08:49:37 GMT")
7665
+ const IMF_FIXDATE = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), \d{2} (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{4} \d{2}:\d{2}:\d{2} GMT$/;
7666
+ if (!IMF_FIXDATE.test(trimmed)) {
7667
+ return undefined;
7668
+ }
7669
+ // Use Date.parse to avoid any engine-specific fallbacks
7670
+ const millis = Date.parse(trimmed);
7671
+ if (Number.isFinite(millis)) {
7672
+ return Math.max(0, millis - Date.now());
7673
+ }
7674
+ return undefined;
7675
+ }
7676
+ }
7677
+
7678
+ /**
7679
+ * A mutable holder for the current fetch args. CsrfTokenRetryPolicy's
7680
+ * prepareRetry hook updates `args` in place (e.g. to swap in a refreshed CSRF
7681
+ * token) so the retried fetch call picks up the change.
7682
+ */
7683
+ function buildCsrfPolicy(mutableRequest) {
7684
+ const csrfPolicy = new CsrfTokenRetryPolicy();
7685
+ csrfPolicy.setRequestContext(mutableRequest);
7686
+ return csrfPolicy;
7687
+ }
7688
+ /**
7689
+ * Built fresh per request so the write-guard check sees this request's own
7690
+ * HTTP method, rather than one method baked in for the life of the service.
7691
+ */
7692
+ function buildThrottlingPolicy(fetchArgs) {
7693
+ return new FetchThrottlingRetryPolicy(undefined, getFetchMethod(fetchArgs));
7694
+ }
7695
+ /**
7696
+ * Builds the retry interceptor used by the generic Conduit fetch service.
7697
+ *
7698
+ * Composes two independent per-request retry policies — throttling (429/503,
7699
+ * GET-only) and CSRF (401 token refresh) — built fresh per request rather
7700
+ * than reused off a shared defaultRetryPolicy. This keeps concurrent requests
7701
+ * from sharing mutable CSRF request-context state, and lets the throttling
7702
+ * policy see this request's own HTTP method.
7703
+ */
7704
+ function buildFetchRetryInterceptor() {
7587
7705
  return async (fetchArgs, retryService, _context) => {
7588
7706
  if (retryService) {
7589
- // Create mutable context for CSRF retry policy
7590
7707
  const mutableRequest = { args: fetchArgs };
7591
- // Pass context to CSRF policy if it's being used
7592
- const policy = retryService.defaultRetryPolicy;
7593
- // Handle both direct CSRF policy and composed policy
7594
- if (policy instanceof CsrfTokenRetryPolicy) {
7595
- policy.setRequestContext(mutableRequest);
7596
- }
7597
- else if (policy instanceof ComposedRetryPolicy) {
7598
- // Extract CSRF policy from composed policy
7599
- const csrfPolicy = policy.getPolicyByType(CsrfTokenRetryPolicy);
7600
- if (csrfPolicy) {
7601
- csrfPolicy.setRequestContext(mutableRequest);
7602
- }
7603
- }
7604
- // Retry service will call prepareRetry hook which updates mutableRequest.args
7708
+ const composedPolicy = new ComposedRetryPolicy([
7709
+ buildThrottlingPolicy(fetchArgs),
7710
+ buildCsrfPolicy(mutableRequest),
7711
+ ]);
7605
7712
  return retryService.applyRetry(async () => {
7606
7713
  return fetch(...mutableRequest.args);
7607
- });
7714
+ }, composedPolicy);
7608
7715
  }
7609
7716
  return fetch(...fetchArgs);
7610
7717
  };
@@ -7847,7 +7954,7 @@ function buildCopilotFetchServiceDescriptor(logger) {
7847
7954
  },
7848
7955
  buildJwtRequestInterceptor(logger),
7849
7956
  ],
7850
- retry: buildCsrfRetryInterceptor(),
7957
+ retry: buildFetchRetryInterceptor(),
7851
7958
  finally: [buildThirdPartyTrackerFinishInterceptor()],
7852
7959
  }),
7853
7960
  tags: { specialHacksFor: 'copilot' },
@@ -7857,7 +7964,7 @@ function buildUnauthorizedFetchServiceDescriptor() {
7857
7964
  const fetchService = buildServiceDescriptor$2({
7858
7965
  createContext: createInstrumentationIdContext(),
7859
7966
  request: [buildThirdPartyTrackerRegisterInterceptor()],
7860
- retry: buildCsrfRetryInterceptor(),
7967
+ retry: buildFetchRetryInterceptor(),
7861
7968
  finally: [buildThirdPartyTrackerFinishInterceptor()],
7862
7969
  });
7863
7970
  return {
@@ -10637,7 +10744,7 @@ function getLexRuntimeDefaultInterceptorConfig(logger) {
10637
10744
  buildEntityEncodingInterceptor(),
10638
10745
  buildFirstPartyHeaderInterceptor(),
10639
10746
  ],
10640
- retry: buildCsrfRetryInterceptor(),
10747
+ retry: buildFetchRetryInterceptor(),
10641
10748
  response: [
10642
10749
  buildLexRuntime5xxStatusResponseInterceptor(logger),
10643
10750
  buildLexRuntimeSessionExpirationResponseInterceptor(logger),
@@ -10680,73 +10787,6 @@ function buildLexRuntimeCompressedFetchServiceDescriptor(logger, retryService) {
10680
10787
  };
10681
10788
  }
10682
10789
 
10683
- const DEFAULT_CONFIG = {
10684
- maxRetries: 3,
10685
- maxTimeToRetry: 10000,
10686
- baseDelay: 250,
10687
- maxDelay: 5000,
10688
- exponentialFactor: 2,
10689
- jitterPercent: 0.5,
10690
- };
10691
- class FetchThrottlingRetryPolicy extends RetryPolicy {
10692
- constructor(config = DEFAULT_CONFIG) {
10693
- super();
10694
- this.config = config;
10695
- }
10696
- async shouldRetry(result, context) {
10697
- return ((result.status === 429 || result.status === 503) &&
10698
- context.attempt < this.config.maxRetries &&
10699
- context.totalElapsedMs <= this.config.maxTimeToRetry);
10700
- }
10701
- async calculateDelay(result, context) {
10702
- let delay;
10703
- // If retry-after header is present and valid, use it
10704
- const retryAfterHeader = this.parseRetryAfterHeader(result);
10705
- if (retryAfterHeader !== undefined) {
10706
- delay = Math.min(retryAfterHeader, this.config.maxDelay);
10707
- }
10708
- else {
10709
- // Exponential backoff
10710
- delay = Math.min(this.config.baseDelay * Math.pow(this.config.exponentialFactor, context.attempt), this.config.maxDelay);
10711
- }
10712
- // Add jitter to prevent thundering herd
10713
- const jitter = delay * this.config.jitterPercent * (Math.random() - 0.5);
10714
- return Math.max(0, delay + jitter);
10715
- }
10716
- parseRetryAfterHeader(result) {
10717
- if (!result.headers) {
10718
- return undefined;
10719
- }
10720
- const value = result.headers.get('Retry-After');
10721
- if (!value) {
10722
- return undefined;
10723
- }
10724
- // The Retry-After header can be either a number of seconds or an HTTP-date (IMF-fixdate)
10725
- // Retry-After: <delay-seconds>
10726
- // Retry-After: <http-date>
10727
- const trimmed = value.trim();
10728
- // Strictly treat only all-digits as seconds
10729
- if (/^\d+$/.test(trimmed)) {
10730
- const seconds = Number(trimmed);
10731
- if (Number.isFinite(seconds) && seconds >= 0) {
10732
- return seconds * 1000; // Convert to milliseconds
10733
- }
10734
- return undefined;
10735
- }
10736
- // Strict RFC 7231 IMF-fixdate format (e.g., "Sun, 06 Nov 1994 08:49:37 GMT")
10737
- const IMF_FIXDATE = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), \d{2} (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{4} \d{2}:\d{2}:\d{2} GMT$/;
10738
- if (!IMF_FIXDATE.test(trimmed)) {
10739
- return undefined;
10740
- }
10741
- // Use Date.parse to avoid any engine-specific fallbacks
10742
- const millis = Date.parse(trimmed);
10743
- if (Number.isFinite(millis)) {
10744
- return Math.max(0, millis - Date.now());
10745
- }
10746
- return undefined;
10747
- }
10748
- }
10749
-
10750
10790
  const CSRF_TOKEN_KEY = 'salesforce_csrf_token';
10751
10791
  const CSRF_STORAGE_NAME = 'ldsCSRFToken';
10752
10792
  const BASE_URI = '/services/data/v68.0';
@@ -10890,6 +10930,35 @@ function buildCsrfTokenManager() {
10890
10930
  });
10891
10931
  }
10892
10932
 
10933
+ /**
10934
+ * The default policy for the runtime's shared retry service.
10935
+ *
10936
+ * Every fetch-service descriptor wired with the retry service also supplies its
10937
+ * own `retry:` interceptor, which passes a per-request policy as the override to
10938
+ * `applyRetry` — so this default is never consulted on any real path. It is
10939
+ * reachable only if a descriptor is registered with the retry service but omits
10940
+ * its `retry:` interceptor; in that case service-fetch-network falls back to
10941
+ * `retryService.applyRetry(fetch)` with no override, and this policy runs.
10942
+ *
10943
+ * That is a wiring mistake, not a runtime condition. We surface it loudly in
10944
+ * development rather than silently degrading to never-retry (the behavior of a
10945
+ * plain empty policy), following the repo convention for should-never-run paths.
10946
+ */
10947
+ class UnconfiguredRetryPolicy extends RetryPolicy {
10948
+ async shouldRetry(_result, _context) {
10949
+ // istanbul ignore else: not exercised in NODE_ENV = production for test coverage
10950
+ if (process.env.NODE_ENV !== 'production') {
10951
+ throw new Error('A fetch-service descriptor was registered with the retry service but did ' +
10952
+ 'not supply a `retry:` interceptor. Retries would silently never run — ' +
10953
+ 'add a `retry:` interceptor (e.g. buildFetchRetryInterceptor()) to the descriptor.');
10954
+ }
10955
+ return false;
10956
+ }
10957
+ async calculateDelay(_result, _context) {
10958
+ return 0;
10959
+ }
10960
+ }
10961
+
10893
10962
  /* eslint-disable no-console */
10894
10963
  /**
10895
10964
  * Default storage configuration for the durable cache
@@ -11498,11 +11567,15 @@ function initializeOneStore(luvio) {
11498
11567
  reader.unMarkMissing();
11499
11568
  return linkedData.data;
11500
11569
  });
11501
- // Compose both throttling and CSRF retry policies
11502
- const throttlingPolicy = new FetchThrottlingRetryPolicy();
11503
- const csrfPolicy = new CsrfTokenRetryPolicy();
11504
- const retryPolicy = new ComposedRetryPolicy([throttlingPolicy, csrfPolicy]);
11505
- const retryServiceDescriptor = buildServiceDescriptor$8(retryPolicy);
11570
+ // The real throttling/CSRF policies are built fresh per request in
11571
+ // buildFetchRetryInterceptor (retry-interceptors/fetch-retry.ts) so each
11572
+ // request gets its own CSRF context and sees its own HTTP method. This
11573
+ // default is never consulted by any current fetch-service descriptor (they
11574
+ // all supply their own `retry` interceptor + override); UnconfiguredRetryPolicy
11575
+ // exists so that if a future descriptor is wired with this retry service but
11576
+ // forgets its `retry:` interceptor, the silent never-retry fallback surfaces
11577
+ // loudly in development instead.
11578
+ const retryServiceDescriptor = buildServiceDescriptor$8(new UnconfiguredRetryPolicy());
11506
11579
  const retryService = retryServiceDescriptor.service;
11507
11580
  const csrfTokenManagerServiceDescriptor = buildRenewableResourceManagerDescriptor(CSRF_TOKEN_MANAGER_SERVICE, buildCsrfTokenManager());
11508
11581
  const prefetchSfapJwtServiceDescriptor = {
@@ -11584,4 +11657,4 @@ function ldsEngineCreator() {
11584
11657
  }
11585
11658
 
11586
11659
  export { LexRequestStrategy, PDL_ENGINE_REGISTRATION_ID, PdlPrefetcherEventType, PdlRequestPriority, buildPredictorForContext, configService, ldsEngineCreator as default, initializeLDS, initializeOneStore, notifyUpdateAvailableFactory, registerRequestStrategy, saveRequestAsPrediction, subscribeToPrefetcherEvents, unregisterRequestStrategy, whenPredictionsReady };
11587
- // version: 1.453.0-725e09cf25
11660
+ // version: 1.455.0-c53c97de2a
@@ -0,0 +1,20 @@
1
+ import type { FetchParameters } from '@conduit-client/service-fetch-network/v1';
2
+ /**
3
+ * Extracts the HTTP method from FetchParameters, matching the Fetch API's own
4
+ * precedence: an options.method override wins over a Request object's method
5
+ * (e.g. `fetch(new Request(url, { method: 'GET' }), { method: 'POST' })`
6
+ * resolves to `POST`).
7
+ */
8
+ export declare function getFetchMethod([urlOrRequest, options]: FetchParameters): string | undefined;
9
+ /**
10
+ * Only GET requests are safe to replay automatically on 429/503 — replaying a
11
+ * write (POST/PUT/PATCH/DELETE) risks executing a mutation more than once.
12
+ * Shared by both the Luvio and generic-fetch throttling retry policies so the
13
+ * write-guard rule lives in exactly one place.
14
+ */
15
+ export declare function isRetryableMethod(method: string | undefined): boolean;
16
+ /**
17
+ * Determines if the HTTP method requires CSRF protection.
18
+ * Only mutating operations (POST, PUT, PATCH, DELETE) require CSRF tokens.
19
+ */
20
+ export declare function isCsrfMethod(method: string | undefined): boolean;
@@ -0,0 +1,11 @@
1
+ import type { RetryInterceptor } from '@conduit-client/service-fetch-network/v1';
2
+ /**
3
+ * Builds the retry interceptor used by the generic Conduit fetch service.
4
+ *
5
+ * Composes two independent per-request retry policies — throttling (429/503,
6
+ * GET-only) and CSRF (401 token refresh) — built fresh per request rather
7
+ * than reused off a shared defaultRetryPolicy. This keeps concurrent requests
8
+ * from sharing mutable CSRF request-context state, and lets the throttling
9
+ * policy see this request's own HTTP method.
10
+ */
11
+ export declare function buildFetchRetryInterceptor(): RetryInterceptor;
@@ -10,7 +10,8 @@ type FetchThrottlingRetryPolicyConfig = {
10
10
  };
11
11
  export declare class FetchThrottlingRetryPolicy extends RetryPolicy<Response> {
12
12
  private config;
13
- constructor(config?: FetchThrottlingRetryPolicyConfig);
13
+ private method?;
14
+ constructor(config?: FetchThrottlingRetryPolicyConfig, method?: string | undefined);
14
15
  shouldRetry(result: Response, context: RetryContext<Response>): Promise<boolean>;
15
16
  calculateDelay(result: Response, context: RetryContext<Response>): Promise<number>;
16
17
  parseRetryAfterHeader(result: Response): number | undefined;
@@ -10,7 +10,8 @@ type LuvioFetchThrottlingRetryPolicyConfig = {
10
10
  };
11
11
  export declare class LuvioFetchThrottlingRetryPolicy extends RetryPolicy<FetchResponse<any>> {
12
12
  private config;
13
- constructor(config?: LuvioFetchThrottlingRetryPolicyConfig);
13
+ private method?;
14
+ constructor(config?: LuvioFetchThrottlingRetryPolicyConfig, method?: string | undefined);
14
15
  shouldRetry(result: FetchResponse<any>, context: RetryContext<FetchResponse<any>>): Promise<boolean>;
15
16
  calculateDelay(result: FetchResponse<any>, context: RetryContext<FetchResponse<any>>): Promise<number>;
16
17
  parseRetryAfterHeader(result: FetchResponse<any>): number | undefined;
@@ -0,0 +1,20 @@
1
+ import type { RetryContext } from '@conduit-client/service-retry/v1';
2
+ import { RetryPolicy } from '@conduit-client/service-retry/v1';
3
+ /**
4
+ * The default policy for the runtime's shared retry service.
5
+ *
6
+ * Every fetch-service descriptor wired with the retry service also supplies its
7
+ * own `retry:` interceptor, which passes a per-request policy as the override to
8
+ * `applyRetry` — so this default is never consulted on any real path. It is
9
+ * reachable only if a descriptor is registered with the retry service but omits
10
+ * its `retry:` interceptor; in that case service-fetch-network falls back to
11
+ * `retryService.applyRetry(fetch)` with no override, and this policy runs.
12
+ *
13
+ * That is a wiring mistake, not a runtime condition. We surface it loudly in
14
+ * development rather than silently degrading to never-retry (the behavior of a
15
+ * plain empty policy), following the repo convention for should-never-run paths.
16
+ */
17
+ export declare class UnconfiguredRetryPolicy extends RetryPolicy<Response> {
18
+ shouldRetry(_result: Response, _context: RetryContext<Response>): Promise<boolean>;
19
+ calculateDelay(_result: Response, _context: RetryContext<Response>): Promise<number>;
20
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/lds-runtime-aura",
3
- "version": "1.453.0",
3
+ "version": "1.455.0",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "LDS engine for Aura runtime.",
6
6
  "main": "dist/ldsEngineCreator.js",
@@ -34,61 +34,61 @@
34
34
  "release:corejar": "yarn build && ../core-build/scripts/core.js --name=lds-runtime-aura"
35
35
  },
36
36
  "devDependencies": {
37
- "@conduit-client/service-provisioner": "3.26.1",
38
- "@conduit-client/tools-core": "3.26.1",
39
- "@salesforce/lds-adapters-apex": "^1.453.0",
40
- "@salesforce/lds-adapters-uiapi": "^1.453.0",
41
- "@salesforce/lds-ads-bridge": "^1.453.0",
42
- "@salesforce/lds-aura-storage": "^1.453.0",
43
- "@salesforce/lds-bindings": "^1.453.0",
44
- "@salesforce/lds-instrumentation": "^1.453.0",
45
- "@salesforce/lds-network-adapter": "^1.453.0",
46
- "@salesforce/lds-network-aura": "^1.453.0",
47
- "@salesforce/lds-network-fetch": "^1.453.0",
37
+ "@conduit-client/service-provisioner": "3.26.3",
38
+ "@conduit-client/tools-core": "3.26.3",
39
+ "@salesforce/lds-adapters-apex": "^1.455.0",
40
+ "@salesforce/lds-adapters-uiapi": "^1.455.0",
41
+ "@salesforce/lds-ads-bridge": "^1.455.0",
42
+ "@salesforce/lds-aura-storage": "^1.455.0",
43
+ "@salesforce/lds-bindings": "^1.455.0",
44
+ "@salesforce/lds-instrumentation": "^1.455.0",
45
+ "@salesforce/lds-network-adapter": "^1.455.0",
46
+ "@salesforce/lds-network-aura": "^1.455.0",
47
+ "@salesforce/lds-network-fetch": "^1.455.0",
48
48
  "jwt-encode": "1.0.1"
49
49
  },
50
50
  "dependencies": {
51
- "@conduit-client/command-aura-graphql-normalized-cache-control": "3.26.1",
52
- "@conduit-client/command-aura-network": "3.26.1",
53
- "@conduit-client/command-aura-normalized-cache-control": "3.26.1",
54
- "@conduit-client/command-fetch-network": "3.26.1",
55
- "@conduit-client/command-http-graphql-normalized-cache-control": "3.26.1",
56
- "@conduit-client/command-http-normalized-cache-control": "3.26.1",
57
- "@conduit-client/command-ndjson": "3.26.1",
58
- "@conduit-client/command-network": "3.26.1",
59
- "@conduit-client/command-sse": "3.26.1",
60
- "@conduit-client/command-streaming": "3.26.1",
61
- "@conduit-client/jwt-manager": "3.26.1",
62
- "@conduit-client/service-aura-network": "3.26.1",
63
- "@conduit-client/service-bindings-imperative": "3.26.1",
64
- "@conduit-client/service-bindings-lwc": "3.26.1",
65
- "@conduit-client/service-cache": "3.26.1",
66
- "@conduit-client/service-cache-control": "3.26.1",
67
- "@conduit-client/service-cache-inclusion-policy": "3.26.1",
68
- "@conduit-client/service-config": "3.26.1",
69
- "@conduit-client/service-feature-flags": "3.26.1",
70
- "@conduit-client/service-fetch-network": "3.26.1",
71
- "@conduit-client/service-instrument-command": "3.26.1",
72
- "@conduit-client/service-pubsub": "3.26.1",
73
- "@conduit-client/service-renewable-resource-manager": "3.26.1",
74
- "@conduit-client/service-store": "3.26.1",
75
- "@conduit-client/utils": "3.26.1",
76
- "@luvio/network-adapter-composable": "0.161.0",
77
- "@luvio/network-adapter-fetch": "0.161.0",
51
+ "@conduit-client/command-aura-graphql-normalized-cache-control": "3.26.3",
52
+ "@conduit-client/command-aura-network": "3.26.3",
53
+ "@conduit-client/command-aura-normalized-cache-control": "3.26.3",
54
+ "@conduit-client/command-fetch-network": "3.26.3",
55
+ "@conduit-client/command-http-graphql-normalized-cache-control": "3.26.3",
56
+ "@conduit-client/command-http-normalized-cache-control": "3.26.3",
57
+ "@conduit-client/command-ndjson": "3.26.3",
58
+ "@conduit-client/command-network": "3.26.3",
59
+ "@conduit-client/command-sse": "3.26.3",
60
+ "@conduit-client/command-streaming": "3.26.3",
61
+ "@conduit-client/jwt-manager": "3.26.3",
62
+ "@conduit-client/service-aura-network": "3.26.3",
63
+ "@conduit-client/service-bindings-imperative": "3.26.3",
64
+ "@conduit-client/service-bindings-lwc": "3.26.3",
65
+ "@conduit-client/service-cache": "3.26.3",
66
+ "@conduit-client/service-cache-control": "3.26.3",
67
+ "@conduit-client/service-cache-inclusion-policy": "3.26.3",
68
+ "@conduit-client/service-config": "3.26.3",
69
+ "@conduit-client/service-feature-flags": "3.26.3",
70
+ "@conduit-client/service-fetch-network": "3.26.3",
71
+ "@conduit-client/service-instrument-command": "3.26.3",
72
+ "@conduit-client/service-pubsub": "3.26.3",
73
+ "@conduit-client/service-renewable-resource-manager": "3.26.3",
74
+ "@conduit-client/service-store": "3.26.3",
75
+ "@conduit-client/utils": "3.26.3",
76
+ "@luvio/network-adapter-composable": "0.161.2",
77
+ "@luvio/network-adapter-fetch": "0.161.2",
78
78
  "@lwc/state": "^0.29.0",
79
- "@salesforce/lds-adapters-onestore-graphql": "^1.453.0",
79
+ "@salesforce/lds-adapters-onestore-graphql": "^1.455.0",
80
80
  "@salesforce/lds-adapters-uiapi-lex": "^1.415.0",
81
- "@salesforce/lds-durable-storage": "^1.453.0",
82
- "@salesforce/lds-luvio-service": "^1.453.0",
83
- "@salesforce/lds-luvio-uiapi-records-service": "^1.453.0"
81
+ "@salesforce/lds-durable-storage": "^1.455.0",
82
+ "@salesforce/lds-luvio-service": "^1.455.0",
83
+ "@salesforce/lds-luvio-uiapi-records-service": "^1.455.0"
84
84
  },
85
85
  "luvioBundlesize": [
86
86
  {
87
87
  "path": "./dist/ldsEngineCreator.js",
88
88
  "maxSize": {
89
- "none": "418 kB",
89
+ "none": "421 kB",
90
90
  "min": "190 kB",
91
- "compressed": "74 kB"
91
+ "compressed": "75 kB"
92
92
  }
93
93
  }
94
94
  ],
@@ -1,2 +0,0 @@
1
- import type { RetryInterceptor } from '@conduit-client/service-fetch-network/v1';
2
- export declare function buildCsrfRetryInterceptor(): RetryInterceptor;