@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.
- package/dist/ldsEngineCreator.js +209 -136
- package/dist/types/http-utils.d.ts +20 -0
- package/dist/types/retry-interceptors/fetch-retry.d.ts +11 -0
- package/dist/types/retry-policies/fetch-throttling-retry-policy.d.ts +2 -1
- package/dist/types/retry-policies/luvio-fetch-throttling-retry-policy.d.ts +2 -1
- package/dist/types/retry-policies/unconfigured-retry-policy.d.ts +20 -0
- package/package.json +45 -45
- package/dist/types/retry-interceptors/csrf-retry.d.ts +0 -2
package/dist/ldsEngineCreator.js
CHANGED
|
@@ -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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
610
|
-
if (!isArray$
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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$
|
|
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$
|
|
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.
|
|
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(
|
|
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 ((
|
|
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
|
-
|
|
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
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
//
|
|
11502
|
-
|
|
11503
|
-
|
|
11504
|
-
|
|
11505
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
38
|
-
"@conduit-client/tools-core": "3.26.
|
|
39
|
-
"@salesforce/lds-adapters-apex": "^1.
|
|
40
|
-
"@salesforce/lds-adapters-uiapi": "^1.
|
|
41
|
-
"@salesforce/lds-ads-bridge": "^1.
|
|
42
|
-
"@salesforce/lds-aura-storage": "^1.
|
|
43
|
-
"@salesforce/lds-bindings": "^1.
|
|
44
|
-
"@salesforce/lds-instrumentation": "^1.
|
|
45
|
-
"@salesforce/lds-network-adapter": "^1.
|
|
46
|
-
"@salesforce/lds-network-aura": "^1.
|
|
47
|
-
"@salesforce/lds-network-fetch": "^1.
|
|
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.
|
|
52
|
-
"@conduit-client/command-aura-network": "3.26.
|
|
53
|
-
"@conduit-client/command-aura-normalized-cache-control": "3.26.
|
|
54
|
-
"@conduit-client/command-fetch-network": "3.26.
|
|
55
|
-
"@conduit-client/command-http-graphql-normalized-cache-control": "3.26.
|
|
56
|
-
"@conduit-client/command-http-normalized-cache-control": "3.26.
|
|
57
|
-
"@conduit-client/command-ndjson": "3.26.
|
|
58
|
-
"@conduit-client/command-network": "3.26.
|
|
59
|
-
"@conduit-client/command-sse": "3.26.
|
|
60
|
-
"@conduit-client/command-streaming": "3.26.
|
|
61
|
-
"@conduit-client/jwt-manager": "3.26.
|
|
62
|
-
"@conduit-client/service-aura-network": "3.26.
|
|
63
|
-
"@conduit-client/service-bindings-imperative": "3.26.
|
|
64
|
-
"@conduit-client/service-bindings-lwc": "3.26.
|
|
65
|
-
"@conduit-client/service-cache": "3.26.
|
|
66
|
-
"@conduit-client/service-cache-control": "3.26.
|
|
67
|
-
"@conduit-client/service-cache-inclusion-policy": "3.26.
|
|
68
|
-
"@conduit-client/service-config": "3.26.
|
|
69
|
-
"@conduit-client/service-feature-flags": "3.26.
|
|
70
|
-
"@conduit-client/service-fetch-network": "3.26.
|
|
71
|
-
"@conduit-client/service-instrument-command": "3.26.
|
|
72
|
-
"@conduit-client/service-pubsub": "3.26.
|
|
73
|
-
"@conduit-client/service-renewable-resource-manager": "3.26.
|
|
74
|
-
"@conduit-client/service-store": "3.26.
|
|
75
|
-
"@conduit-client/utils": "3.26.
|
|
76
|
-
"@luvio/network-adapter-composable": "0.161.
|
|
77
|
-
"@luvio/network-adapter-fetch": "0.161.
|
|
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.
|
|
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.
|
|
82
|
-
"@salesforce/lds-luvio-service": "^1.
|
|
83
|
-
"@salesforce/lds-luvio-uiapi-records-service": "^1.
|
|
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": "
|
|
89
|
+
"none": "421 kB",
|
|
90
90
|
"min": "190 kB",
|
|
91
|
-
"compressed": "
|
|
91
|
+
"compressed": "75 kB"
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
],
|