@salesforce/lds-runtime-one-app 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/oneAppLdsEngineCreator.js +215 -136
- package/dist/types/http-utils.d.ts +20 -0
- package/dist/types/retry-interceptors/fetch-retry.d.ts +17 -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
|
@@ -48,7 +48,7 @@ import { createStorage, clearStorages } from 'force/ldsDurableStorage';
|
|
|
48
48
|
import { registerSubRequestNetworkAdapter } from 'force/ldsNetwork';
|
|
49
49
|
|
|
50
50
|
const { create: create$1, freeze, keys: keys$2, entries: entries$1 } = Object;
|
|
51
|
-
const { isArray: isArray$
|
|
51
|
+
const { isArray: isArray$4 } = Array;
|
|
52
52
|
const { stringify: stringify$3, parse: parse$2 } = JSON;
|
|
53
53
|
const WeakSetConstructor = WeakSet;
|
|
54
54
|
const LogLevelMap = {
|
|
@@ -190,7 +190,7 @@ function stableJSONStringify$2(node) {
|
|
|
190
190
|
}
|
|
191
191
|
let i;
|
|
192
192
|
let out;
|
|
193
|
-
if (isArray$
|
|
193
|
+
if (isArray$4(node)) {
|
|
194
194
|
out = "[";
|
|
195
195
|
for (i = 0; i < node.length; i++) {
|
|
196
196
|
if (i) {
|
|
@@ -298,7 +298,7 @@ function deepFreeze(value) {
|
|
|
298
298
|
return;
|
|
299
299
|
}
|
|
300
300
|
deeplyFrozen.add(value);
|
|
301
|
-
if (isArray$
|
|
301
|
+
if (isArray$4(value)) {
|
|
302
302
|
for (let i = 0, len = value.length; i < len; i += 1) {
|
|
303
303
|
deepFreeze(value[i]);
|
|
304
304
|
}
|
|
@@ -525,7 +525,7 @@ function buildServiceDescriptor$p() {
|
|
|
525
525
|
};
|
|
526
526
|
}
|
|
527
527
|
|
|
528
|
-
const { isArray: isArray$
|
|
528
|
+
const { isArray: isArray$3 } = Array;
|
|
529
529
|
let Ok$1 = class Ok {
|
|
530
530
|
constructor(value) {
|
|
531
531
|
this.value = value;
|
|
@@ -605,8 +605,8 @@ function deepEquals$1(x, y) {
|
|
|
605
605
|
return y === null;
|
|
606
606
|
} else if (y === null) {
|
|
607
607
|
return x === null;
|
|
608
|
-
} else if (isArray$
|
|
609
|
-
if (!isArray$
|
|
608
|
+
} else if (isArray$3(x)) {
|
|
609
|
+
if (!isArray$3(y) || x.length !== y.length) {
|
|
610
610
|
return false;
|
|
611
611
|
}
|
|
612
612
|
for (let i = 0; i < x.length; ++i) {
|
|
@@ -2588,7 +2588,7 @@ function buildServiceDescriptor$d(luvio) {
|
|
|
2588
2588
|
},
|
|
2589
2589
|
};
|
|
2590
2590
|
}
|
|
2591
|
-
// version: 1.
|
|
2591
|
+
// version: 1.455.0-c53c97de2a
|
|
2592
2592
|
|
|
2593
2593
|
class AuraGraphQLNormalizedCacheControlCommand extends AuraNormalizedCacheControlCommand {
|
|
2594
2594
|
constructor(config, documentRootType, services) {
|
|
@@ -2927,7 +2927,7 @@ function buildServiceDescriptor$9(notifyRecordUpdateAvailable, getNormalizedLuvi
|
|
|
2927
2927
|
},
|
|
2928
2928
|
};
|
|
2929
2929
|
}
|
|
2930
|
-
// version: 1.
|
|
2930
|
+
// version: 1.455.0-c53c97de2a
|
|
2931
2931
|
|
|
2932
2932
|
class RetryService {
|
|
2933
2933
|
constructor(defaultRetryPolicy) {
|
|
@@ -4640,9 +4640,10 @@ var TypeCheckShapes;
|
|
|
4640
4640
|
TypeCheckShapes[TypeCheckShapes["Integer"] = 3] = "Integer";
|
|
4641
4641
|
TypeCheckShapes[TypeCheckShapes["Unsupported"] = 4] = "Unsupported";
|
|
4642
4642
|
})(TypeCheckShapes || (TypeCheckShapes = {}));
|
|
4643
|
-
// engine version: 0.161.
|
|
4643
|
+
// engine version: 0.161.2-bd1bd38a
|
|
4644
4644
|
|
|
4645
4645
|
const { keys: keys$1 } = Object;
|
|
4646
|
+
const { isArray: isArray$2 } = Array;
|
|
4646
4647
|
|
|
4647
4648
|
// we're going to intentionally bundle this small bit of luvio engine code into
|
|
4648
4649
|
// this module to keep it runtime dependency-free
|
|
@@ -4715,7 +4716,14 @@ const fetchNetworkAdapter = async (resourceRequest, _resourceRequestContext) =>
|
|
|
4715
4716
|
function generateQueryString(params) {
|
|
4716
4717
|
const searchParams = new URLSearchParams();
|
|
4717
4718
|
for (const key of keys$1(params)) {
|
|
4718
|
-
|
|
4719
|
+
const value = params[key];
|
|
4720
|
+
// omit undefined and empty-array values entirely: String(undefined) === 'undefined'
|
|
4721
|
+
// and String([]) === '', both of which would otherwise serialize as a valueless
|
|
4722
|
+
// `key=` or literal `key=undefined` query param that servers can reject.
|
|
4723
|
+
if (value === undefined || (isArray$2(value) && value.length === 0)) {
|
|
4724
|
+
continue;
|
|
4725
|
+
}
|
|
4726
|
+
searchParams.append(key, String(value));
|
|
4719
4727
|
}
|
|
4720
4728
|
const queryString = searchParams.toString();
|
|
4721
4729
|
if (queryString.length > 0) {
|
|
@@ -5732,7 +5740,7 @@ class PrioritizedConfigService {
|
|
|
5732
5740
|
get: (_, property) => {
|
|
5733
5741
|
const propertyPath = [...path, property];
|
|
5734
5742
|
const value = this.valueFor(propertyPath);
|
|
5735
|
-
return typeof value === "object" && value !== null && !isArray$
|
|
5743
|
+
return typeof value === "object" && value !== null && !isArray$4(value) ? this.buildReadonlyObjectProxy(propertyPath) : value;
|
|
5736
5744
|
},
|
|
5737
5745
|
getOwnPropertyDescriptor: (target, property) => {
|
|
5738
5746
|
const propertyPath = [...path, property];
|
|
@@ -5740,7 +5748,7 @@ class PrioritizedConfigService {
|
|
|
5740
5748
|
return {
|
|
5741
5749
|
value: (
|
|
5742
5750
|
// TODO - need to wrap arrays in a Proxy as well
|
|
5743
|
-
typeof value === "object" && value !== null && !isArray$
|
|
5751
|
+
typeof value === "object" && value !== null && !isArray$4(value) ? this.buildReadonlyObjectProxy(propertyPath) : value
|
|
5744
5752
|
),
|
|
5745
5753
|
writable: false,
|
|
5746
5754
|
configurable: true,
|
|
@@ -5841,7 +5849,7 @@ function getEnvironmentSetting(name) {
|
|
|
5841
5849
|
}
|
|
5842
5850
|
return undefined;
|
|
5843
5851
|
}
|
|
5844
|
-
// version: 1.
|
|
5852
|
+
// version: 1.455.0-96e9b41a18
|
|
5845
5853
|
|
|
5846
5854
|
/**
|
|
5847
5855
|
* Helpers for reaching the Aura framework from the LDS Aura runtime.
|
|
@@ -6414,6 +6422,45 @@ function getCsrfTokenManager() {
|
|
|
6414
6422
|
return cached;
|
|
6415
6423
|
}
|
|
6416
6424
|
|
|
6425
|
+
/**
|
|
6426
|
+
* Extracts the HTTP method from FetchParameters, matching the Fetch API's own
|
|
6427
|
+
* precedence: an options.method override wins over a Request object's method
|
|
6428
|
+
* (e.g. `fetch(new Request(url, { method: 'GET' }), { method: 'POST' })`
|
|
6429
|
+
* resolves to `POST`).
|
|
6430
|
+
*/
|
|
6431
|
+
function getFetchMethod([urlOrRequest, options]) {
|
|
6432
|
+
if (options && 'method' in options) {
|
|
6433
|
+
return options.method;
|
|
6434
|
+
}
|
|
6435
|
+
if (typeof urlOrRequest !== 'string' && 'method' in urlOrRequest) {
|
|
6436
|
+
return urlOrRequest.method;
|
|
6437
|
+
}
|
|
6438
|
+
return undefined;
|
|
6439
|
+
}
|
|
6440
|
+
/**
|
|
6441
|
+
* Only GET requests are safe to replay automatically on 429/503 — replaying a
|
|
6442
|
+
* write (POST/PUT/PATCH/DELETE) risks executing a mutation more than once.
|
|
6443
|
+
* Shared by both the Luvio and generic-fetch throttling retry policies so the
|
|
6444
|
+
* write-guard rule lives in exactly one place.
|
|
6445
|
+
*/
|
|
6446
|
+
function isRetryableMethod(method) {
|
|
6447
|
+
return method?.toLowerCase() === 'get';
|
|
6448
|
+
}
|
|
6449
|
+
/**
|
|
6450
|
+
* Determines if the HTTP method requires CSRF protection.
|
|
6451
|
+
* Only mutating operations (POST, PUT, PATCH, DELETE) require CSRF tokens.
|
|
6452
|
+
*/
|
|
6453
|
+
function isCsrfMethod(method) {
|
|
6454
|
+
if (!method) {
|
|
6455
|
+
return false;
|
|
6456
|
+
}
|
|
6457
|
+
const normalizedMethod = method.toLowerCase();
|
|
6458
|
+
return (normalizedMethod === 'post' ||
|
|
6459
|
+
normalizedMethod === 'put' ||
|
|
6460
|
+
normalizedMethod === 'patch' ||
|
|
6461
|
+
normalizedMethod === 'delete');
|
|
6462
|
+
}
|
|
6463
|
+
|
|
6417
6464
|
const CSRF_TOKEN_HEADER = 'X-CSRF-Token';
|
|
6418
6465
|
/**
|
|
6419
6466
|
* Resolves the CSRF token manager and returns the current token. Returns
|
|
@@ -6446,23 +6493,6 @@ function areCsrfGatesEnabled() {
|
|
|
6446
6493
|
return false;
|
|
6447
6494
|
}
|
|
6448
6495
|
}
|
|
6449
|
-
/**
|
|
6450
|
-
* Determines if the HTTP method requires CSRF protection.
|
|
6451
|
-
* Only mutating operations (POST, PUT, PATCH, DELETE) require CSRF tokens.
|
|
6452
|
-
*
|
|
6453
|
-
* @param method - The HTTP method to check
|
|
6454
|
-
* @returns true if the method requires CSRF protection
|
|
6455
|
-
*/
|
|
6456
|
-
function isCsrfMethod(method) {
|
|
6457
|
-
if (!method) {
|
|
6458
|
-
return false;
|
|
6459
|
-
}
|
|
6460
|
-
const normalizedMethod = method.toLowerCase();
|
|
6461
|
-
return (normalizedMethod === 'post' ||
|
|
6462
|
-
normalizedMethod === 'put' ||
|
|
6463
|
-
normalizedMethod === 'patch' ||
|
|
6464
|
-
normalizedMethod === 'delete');
|
|
6465
|
-
}
|
|
6466
6496
|
/**
|
|
6467
6497
|
* Builds a request interceptor that adds CSRF token headers to mutating requests.
|
|
6468
6498
|
* The CSRF token is fetched once and cached for subsequent requests.
|
|
@@ -6476,17 +6506,8 @@ function buildCsrfTokenInterceptor() {
|
|
|
6476
6506
|
if (!areCsrfGatesEnabled()) {
|
|
6477
6507
|
return resolvedPromiseLike$2(fetchArgs);
|
|
6478
6508
|
}
|
|
6479
|
-
const [urlOrRequest, options] = fetchArgs;
|
|
6480
|
-
// Determine the method from either Request object or options
|
|
6481
|
-
let method;
|
|
6482
|
-
if (typeof urlOrRequest !== 'string' && 'method' in urlOrRequest) {
|
|
6483
|
-
method = urlOrRequest.method;
|
|
6484
|
-
}
|
|
6485
|
-
else if (options && 'method' in options) {
|
|
6486
|
-
method = options.method;
|
|
6487
|
-
}
|
|
6488
6509
|
// Only add CSRF token for mutating operations
|
|
6489
|
-
if (isCsrfMethod(
|
|
6510
|
+
if (isCsrfMethod(getFetchMethod(fetchArgs))) {
|
|
6490
6511
|
const token = await getCsrfToken();
|
|
6491
6512
|
if (token) {
|
|
6492
6513
|
// eslint-disable-next-line no-param-reassign
|
|
@@ -6894,12 +6915,14 @@ const DEFAULT_CONFIG$2 = {
|
|
|
6894
6915
|
jitterPercent: 0.5,
|
|
6895
6916
|
};
|
|
6896
6917
|
class LuvioFetchThrottlingRetryPolicy extends RetryPolicy {
|
|
6897
|
-
constructor(config = DEFAULT_CONFIG$2) {
|
|
6918
|
+
constructor(config = DEFAULT_CONFIG$2, method) {
|
|
6898
6919
|
super();
|
|
6899
6920
|
this.config = config;
|
|
6921
|
+
this.method = method;
|
|
6900
6922
|
}
|
|
6901
6923
|
async shouldRetry(result, context) {
|
|
6902
|
-
return ((
|
|
6924
|
+
return (isRetryableMethod(this.method) &&
|
|
6925
|
+
(result.status === 429 || result.status === 503) &&
|
|
6903
6926
|
context.attempt < this.config.maxRetries &&
|
|
6904
6927
|
context.totalElapsedMs <= this.config.maxTimeToRetry);
|
|
6905
6928
|
}
|
|
@@ -6962,7 +6985,7 @@ function buildLuvioFetchRetryInterceptor() {
|
|
|
6962
6985
|
return (request, doFetch) => {
|
|
6963
6986
|
const csrfPolicy = new LuvioCsrfTokenRetryPolicy();
|
|
6964
6987
|
const composedPolicy = new ComposedRetryPolicy([
|
|
6965
|
-
new LuvioFetchThrottlingRetryPolicy(),
|
|
6988
|
+
new LuvioFetchThrottlingRetryPolicy(undefined, request.method),
|
|
6966
6989
|
csrfPolicy,
|
|
6967
6990
|
]);
|
|
6968
6991
|
const retryService = new RetryService(composedPolicy);
|
|
@@ -7512,28 +7535,118 @@ async function isCsrfError(response) {
|
|
|
7512
7535
|
}
|
|
7513
7536
|
}
|
|
7514
7537
|
|
|
7515
|
-
|
|
7538
|
+
const DEFAULT_CONFIG = {
|
|
7539
|
+
maxRetries: 3,
|
|
7540
|
+
maxTimeToRetry: 10000,
|
|
7541
|
+
baseDelay: 250,
|
|
7542
|
+
maxDelay: 5000,
|
|
7543
|
+
exponentialFactor: 2,
|
|
7544
|
+
jitterPercent: 0.5,
|
|
7545
|
+
};
|
|
7546
|
+
class FetchThrottlingRetryPolicy extends RetryPolicy {
|
|
7547
|
+
constructor(config = DEFAULT_CONFIG, method) {
|
|
7548
|
+
super();
|
|
7549
|
+
this.config = config;
|
|
7550
|
+
this.method = method;
|
|
7551
|
+
}
|
|
7552
|
+
async shouldRetry(result, context) {
|
|
7553
|
+
return (isRetryableMethod(this.method) &&
|
|
7554
|
+
(result.status === 429 || result.status === 503) &&
|
|
7555
|
+
context.attempt < this.config.maxRetries &&
|
|
7556
|
+
context.totalElapsedMs <= this.config.maxTimeToRetry);
|
|
7557
|
+
}
|
|
7558
|
+
async calculateDelay(result, context) {
|
|
7559
|
+
let delay;
|
|
7560
|
+
// If retry-after header is present and valid, use it
|
|
7561
|
+
const retryAfterHeader = this.parseRetryAfterHeader(result);
|
|
7562
|
+
if (retryAfterHeader !== undefined) {
|
|
7563
|
+
delay = Math.min(retryAfterHeader, this.config.maxDelay);
|
|
7564
|
+
}
|
|
7565
|
+
else {
|
|
7566
|
+
// Exponential backoff
|
|
7567
|
+
delay = Math.min(this.config.baseDelay * Math.pow(this.config.exponentialFactor, context.attempt), this.config.maxDelay);
|
|
7568
|
+
}
|
|
7569
|
+
// Add jitter to prevent thundering herd
|
|
7570
|
+
const jitter = delay * this.config.jitterPercent * (Math.random() - 0.5);
|
|
7571
|
+
return Math.max(0, delay + jitter);
|
|
7572
|
+
}
|
|
7573
|
+
parseRetryAfterHeader(result) {
|
|
7574
|
+
if (!result.headers) {
|
|
7575
|
+
return undefined;
|
|
7576
|
+
}
|
|
7577
|
+
const value = result.headers.get('Retry-After');
|
|
7578
|
+
if (!value) {
|
|
7579
|
+
return undefined;
|
|
7580
|
+
}
|
|
7581
|
+
// The Retry-After header can be either a number of seconds or an HTTP-date (IMF-fixdate)
|
|
7582
|
+
// Retry-After: <delay-seconds>
|
|
7583
|
+
// Retry-After: <http-date>
|
|
7584
|
+
const trimmed = value.trim();
|
|
7585
|
+
// Strictly treat only all-digits as seconds
|
|
7586
|
+
if (/^\d+$/.test(trimmed)) {
|
|
7587
|
+
const seconds = Number(trimmed);
|
|
7588
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
7589
|
+
return seconds * 1000; // Convert to milliseconds
|
|
7590
|
+
}
|
|
7591
|
+
return undefined;
|
|
7592
|
+
}
|
|
7593
|
+
// Strict RFC 7231 IMF-fixdate format (e.g., "Sun, 06 Nov 1994 08:49:37 GMT")
|
|
7594
|
+
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$/;
|
|
7595
|
+
if (!IMF_FIXDATE.test(trimmed)) {
|
|
7596
|
+
return undefined;
|
|
7597
|
+
}
|
|
7598
|
+
// Use Date.parse to avoid any engine-specific fallbacks
|
|
7599
|
+
const millis = Date.parse(trimmed);
|
|
7600
|
+
if (Number.isFinite(millis)) {
|
|
7601
|
+
return Math.max(0, millis - Date.now());
|
|
7602
|
+
}
|
|
7603
|
+
return undefined;
|
|
7604
|
+
}
|
|
7605
|
+
}
|
|
7606
|
+
|
|
7607
|
+
/**
|
|
7608
|
+
* A mutable holder for the current fetch args. CsrfTokenRetryPolicy's
|
|
7609
|
+
* prepareRetry hook updates `args` in place (e.g. to swap in a refreshed CSRF
|
|
7610
|
+
* token) so the retried fetch call picks up the change.
|
|
7611
|
+
*/
|
|
7612
|
+
function buildCsrfPolicy(mutableRequest) {
|
|
7613
|
+
const csrfPolicy = new CsrfTokenRetryPolicy();
|
|
7614
|
+
csrfPolicy.setRequestContext(mutableRequest);
|
|
7615
|
+
return csrfPolicy;
|
|
7616
|
+
}
|
|
7617
|
+
/**
|
|
7618
|
+
* Built fresh per request so the write-guard check sees this request's own
|
|
7619
|
+
* HTTP method, rather than one method baked in for the life of the service.
|
|
7620
|
+
*/
|
|
7621
|
+
function buildThrottlingPolicy(fetchArgs) {
|
|
7622
|
+
return new FetchThrottlingRetryPolicy(undefined, getFetchMethod(fetchArgs));
|
|
7623
|
+
}
|
|
7624
|
+
/**
|
|
7625
|
+
* Builds the retry interceptor used by the generic Conduit fetch service.
|
|
7626
|
+
*
|
|
7627
|
+
* Composes two independent per-request retry policies — throttling (429/503,
|
|
7628
|
+
* GET-only) and CSRF (401 token refresh) — built fresh per request rather
|
|
7629
|
+
* than reused off a shared defaultRetryPolicy. This keeps concurrent requests
|
|
7630
|
+
* from sharing mutable CSRF request-context state, and lets the throttling
|
|
7631
|
+
* policy see this request's own HTTP method.
|
|
7632
|
+
*
|
|
7633
|
+
* The `retryService` handed in by the framework is used only as the runner for
|
|
7634
|
+
* `applyRetry` — the real policy is always the per-request `composedPolicy`
|
|
7635
|
+
* passed as the override, never the service's own `defaultRetryPolicy`. When no
|
|
7636
|
+
* `retryService` is injected (e.g. the copilot/unauthorized descriptors, which
|
|
7637
|
+
* intentionally opt out of retries), we fall through to a plain fetch.
|
|
7638
|
+
*/
|
|
7639
|
+
function buildFetchRetryInterceptor() {
|
|
7516
7640
|
return async (fetchArgs, retryService, _context) => {
|
|
7517
7641
|
if (retryService) {
|
|
7518
|
-
// Create mutable context for CSRF retry policy
|
|
7519
7642
|
const mutableRequest = { args: fetchArgs };
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
policy.setRequestContext(mutableRequest);
|
|
7525
|
-
}
|
|
7526
|
-
else if (policy instanceof ComposedRetryPolicy) {
|
|
7527
|
-
// Extract CSRF policy from composed policy
|
|
7528
|
-
const csrfPolicy = policy.getPolicyByType(CsrfTokenRetryPolicy);
|
|
7529
|
-
if (csrfPolicy) {
|
|
7530
|
-
csrfPolicy.setRequestContext(mutableRequest);
|
|
7531
|
-
}
|
|
7532
|
-
}
|
|
7533
|
-
// Retry service will call prepareRetry hook which updates mutableRequest.args
|
|
7643
|
+
const composedPolicy = new ComposedRetryPolicy([
|
|
7644
|
+
buildThrottlingPolicy(fetchArgs),
|
|
7645
|
+
buildCsrfPolicy(mutableRequest),
|
|
7646
|
+
]);
|
|
7534
7647
|
return retryService.applyRetry(async () => {
|
|
7535
7648
|
return fetch(...mutableRequest.args);
|
|
7536
|
-
});
|
|
7649
|
+
}, composedPolicy);
|
|
7537
7650
|
}
|
|
7538
7651
|
return fetch(...fetchArgs);
|
|
7539
7652
|
};
|
|
@@ -7776,7 +7889,7 @@ function buildCopilotFetchServiceDescriptor(logger) {
|
|
|
7776
7889
|
},
|
|
7777
7890
|
buildJwtRequestInterceptor(logger),
|
|
7778
7891
|
],
|
|
7779
|
-
retry:
|
|
7892
|
+
retry: buildFetchRetryInterceptor(),
|
|
7780
7893
|
finally: [buildThirdPartyTrackerFinishInterceptor()],
|
|
7781
7894
|
}),
|
|
7782
7895
|
tags: { specialHacksFor: 'copilot' },
|
|
@@ -7786,7 +7899,7 @@ function buildUnauthorizedFetchServiceDescriptor() {
|
|
|
7786
7899
|
const fetchService = buildServiceDescriptor$2({
|
|
7787
7900
|
createContext: createInstrumentationIdContext(),
|
|
7788
7901
|
request: [buildThirdPartyTrackerRegisterInterceptor()],
|
|
7789
|
-
retry:
|
|
7902
|
+
retry: buildFetchRetryInterceptor(),
|
|
7790
7903
|
finally: [buildThirdPartyTrackerFinishInterceptor()],
|
|
7791
7904
|
});
|
|
7792
7905
|
return {
|
|
@@ -10566,7 +10679,7 @@ function getLexRuntimeDefaultInterceptorConfig(logger) {
|
|
|
10566
10679
|
buildEntityEncodingInterceptor(),
|
|
10567
10680
|
buildFirstPartyHeaderInterceptor(),
|
|
10568
10681
|
],
|
|
10569
|
-
retry:
|
|
10682
|
+
retry: buildFetchRetryInterceptor(),
|
|
10570
10683
|
response: [
|
|
10571
10684
|
buildLexRuntime5xxStatusResponseInterceptor(logger),
|
|
10572
10685
|
buildLexRuntimeSessionExpirationResponseInterceptor(logger),
|
|
@@ -10609,73 +10722,6 @@ function buildLexRuntimeCompressedFetchServiceDescriptor(logger, retryService) {
|
|
|
10609
10722
|
};
|
|
10610
10723
|
}
|
|
10611
10724
|
|
|
10612
|
-
const DEFAULT_CONFIG = {
|
|
10613
|
-
maxRetries: 3,
|
|
10614
|
-
maxTimeToRetry: 10000,
|
|
10615
|
-
baseDelay: 250,
|
|
10616
|
-
maxDelay: 5000,
|
|
10617
|
-
exponentialFactor: 2,
|
|
10618
|
-
jitterPercent: 0.5,
|
|
10619
|
-
};
|
|
10620
|
-
class FetchThrottlingRetryPolicy extends RetryPolicy {
|
|
10621
|
-
constructor(config = DEFAULT_CONFIG) {
|
|
10622
|
-
super();
|
|
10623
|
-
this.config = config;
|
|
10624
|
-
}
|
|
10625
|
-
async shouldRetry(result, context) {
|
|
10626
|
-
return ((result.status === 429 || result.status === 503) &&
|
|
10627
|
-
context.attempt < this.config.maxRetries &&
|
|
10628
|
-
context.totalElapsedMs <= this.config.maxTimeToRetry);
|
|
10629
|
-
}
|
|
10630
|
-
async calculateDelay(result, context) {
|
|
10631
|
-
let delay;
|
|
10632
|
-
// If retry-after header is present and valid, use it
|
|
10633
|
-
const retryAfterHeader = this.parseRetryAfterHeader(result);
|
|
10634
|
-
if (retryAfterHeader !== undefined) {
|
|
10635
|
-
delay = Math.min(retryAfterHeader, this.config.maxDelay);
|
|
10636
|
-
}
|
|
10637
|
-
else {
|
|
10638
|
-
// Exponential backoff
|
|
10639
|
-
delay = Math.min(this.config.baseDelay * Math.pow(this.config.exponentialFactor, context.attempt), this.config.maxDelay);
|
|
10640
|
-
}
|
|
10641
|
-
// Add jitter to prevent thundering herd
|
|
10642
|
-
const jitter = delay * this.config.jitterPercent * (Math.random() - 0.5);
|
|
10643
|
-
return Math.max(0, delay + jitter);
|
|
10644
|
-
}
|
|
10645
|
-
parseRetryAfterHeader(result) {
|
|
10646
|
-
if (!result.headers) {
|
|
10647
|
-
return undefined;
|
|
10648
|
-
}
|
|
10649
|
-
const value = result.headers.get('Retry-After');
|
|
10650
|
-
if (!value) {
|
|
10651
|
-
return undefined;
|
|
10652
|
-
}
|
|
10653
|
-
// The Retry-After header can be either a number of seconds or an HTTP-date (IMF-fixdate)
|
|
10654
|
-
// Retry-After: <delay-seconds>
|
|
10655
|
-
// Retry-After: <http-date>
|
|
10656
|
-
const trimmed = value.trim();
|
|
10657
|
-
// Strictly treat only all-digits as seconds
|
|
10658
|
-
if (/^\d+$/.test(trimmed)) {
|
|
10659
|
-
const seconds = Number(trimmed);
|
|
10660
|
-
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
10661
|
-
return seconds * 1000; // Convert to milliseconds
|
|
10662
|
-
}
|
|
10663
|
-
return undefined;
|
|
10664
|
-
}
|
|
10665
|
-
// Strict RFC 7231 IMF-fixdate format (e.g., "Sun, 06 Nov 1994 08:49:37 GMT")
|
|
10666
|
-
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$/;
|
|
10667
|
-
if (!IMF_FIXDATE.test(trimmed)) {
|
|
10668
|
-
return undefined;
|
|
10669
|
-
}
|
|
10670
|
-
// Use Date.parse to avoid any engine-specific fallbacks
|
|
10671
|
-
const millis = Date.parse(trimmed);
|
|
10672
|
-
if (Number.isFinite(millis)) {
|
|
10673
|
-
return Math.max(0, millis - Date.now());
|
|
10674
|
-
}
|
|
10675
|
-
return undefined;
|
|
10676
|
-
}
|
|
10677
|
-
}
|
|
10678
|
-
|
|
10679
10725
|
const CSRF_TOKEN_KEY = 'salesforce_csrf_token';
|
|
10680
10726
|
const CSRF_STORAGE_NAME = 'ldsCSRFToken';
|
|
10681
10727
|
const BASE_URI = '/services/data/v68.0';
|
|
@@ -10819,6 +10865,35 @@ function buildCsrfTokenManager() {
|
|
|
10819
10865
|
});
|
|
10820
10866
|
}
|
|
10821
10867
|
|
|
10868
|
+
/**
|
|
10869
|
+
* The default policy for the runtime's shared retry service.
|
|
10870
|
+
*
|
|
10871
|
+
* Every fetch-service descriptor wired with the retry service also supplies its
|
|
10872
|
+
* own `retry:` interceptor, which passes a per-request policy as the override to
|
|
10873
|
+
* `applyRetry` — so this default is never consulted on any real path. It is
|
|
10874
|
+
* reachable only if a descriptor is registered with the retry service but omits
|
|
10875
|
+
* its `retry:` interceptor; in that case service-fetch-network falls back to
|
|
10876
|
+
* `retryService.applyRetry(fetch)` with no override, and this policy runs.
|
|
10877
|
+
*
|
|
10878
|
+
* That is a wiring mistake, not a runtime condition. We surface it loudly in
|
|
10879
|
+
* development rather than silently degrading to never-retry (the behavior of a
|
|
10880
|
+
* plain empty policy), following the repo convention for should-never-run paths.
|
|
10881
|
+
*/
|
|
10882
|
+
class UnconfiguredRetryPolicy extends RetryPolicy {
|
|
10883
|
+
async shouldRetry(_result, _context) {
|
|
10884
|
+
// istanbul ignore else: not exercised in NODE_ENV = production for test coverage
|
|
10885
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
10886
|
+
throw new Error('A fetch-service descriptor was registered with the retry service but did ' +
|
|
10887
|
+
'not supply a `retry:` interceptor. Retries would silently never run — ' +
|
|
10888
|
+
'add a `retry:` interceptor (e.g. buildFetchRetryInterceptor()) to the descriptor.');
|
|
10889
|
+
}
|
|
10890
|
+
return false;
|
|
10891
|
+
}
|
|
10892
|
+
async calculateDelay(_result, _context) {
|
|
10893
|
+
return 0;
|
|
10894
|
+
}
|
|
10895
|
+
}
|
|
10896
|
+
|
|
10822
10897
|
/* eslint-disable no-console */
|
|
10823
10898
|
/**
|
|
10824
10899
|
* Default storage configuration for the durable cache
|
|
@@ -11420,11 +11495,15 @@ function initializeOneStore(luvio) {
|
|
|
11420
11495
|
reader.unMarkMissing();
|
|
11421
11496
|
return linkedData.data;
|
|
11422
11497
|
});
|
|
11423
|
-
//
|
|
11424
|
-
|
|
11425
|
-
|
|
11426
|
-
|
|
11427
|
-
|
|
11498
|
+
// The real throttling/CSRF policies are built fresh per request in
|
|
11499
|
+
// buildFetchRetryInterceptor (retry-interceptors/fetch-retry.ts) so each
|
|
11500
|
+
// request gets its own CSRF context and sees its own HTTP method. This
|
|
11501
|
+
// default is never consulted by any current fetch-service descriptor (they
|
|
11502
|
+
// all supply their own `retry` interceptor + override); UnconfiguredRetryPolicy
|
|
11503
|
+
// exists so that if a future descriptor is wired with this retry service but
|
|
11504
|
+
// forgets its `retry:` interceptor, the silent never-retry fallback surfaces
|
|
11505
|
+
// loudly in development instead.
|
|
11506
|
+
const retryServiceDescriptor = buildServiceDescriptor$8(new UnconfiguredRetryPolicy());
|
|
11428
11507
|
const retryService = retryServiceDescriptor.service;
|
|
11429
11508
|
const csrfTokenManagerServiceDescriptor = buildRenewableResourceManagerDescriptor(CSRF_TOKEN_MANAGER_SERVICE, buildCsrfTokenManager());
|
|
11430
11509
|
const prefetchSfapJwtServiceDescriptor = {
|
|
@@ -11500,4 +11579,4 @@ function ldsEngineCreator() {
|
|
|
11500
11579
|
}
|
|
11501
11580
|
|
|
11502
11581
|
export { LexRequestStrategy, PDL_ENGINE_REGISTRATION_ID, PdlPrefetcherEventType, PdlRequestPriority, buildPredictorForContext, configService, ldsEngineCreator as default, initializeLDS, initializeOneStore, notifyUpdateAvailableFactory, registerRequestStrategy, saveRequestAsPrediction, subscribeToPrefetcherEvents, unregisterRequestStrategy, whenPredictionsReady };
|
|
11503
|
-
// version: 1.
|
|
11582
|
+
// 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,17 @@
|
|
|
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
|
+
* The `retryService` handed in by the framework is used only as the runner for
|
|
12
|
+
* `applyRetry` — the real policy is always the per-request `composedPolicy`
|
|
13
|
+
* passed as the override, never the service's own `defaultRetryPolicy`. When no
|
|
14
|
+
* `retryService` is injected (e.g. the copilot/unauthorized descriptors, which
|
|
15
|
+
* intentionally opt out of retries), we fall through to a plain fetch.
|
|
16
|
+
*/
|
|
17
|
+
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-one-app",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.455.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
5
5
|
"description": "LDS engine for the one.app (LEX) runtime.",
|
|
6
6
|
"main": "dist/oneAppLdsEngineCreator.js",
|
|
@@ -34,61 +34,61 @@
|
|
|
34
34
|
"release:corejar": "yarn build && ../core-build/scripts/core.js --name=lds-runtime-one-app"
|
|
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/oneAppLdsEngineCreator.js",
|
|
88
88
|
"maxSize": {
|
|
89
|
-
"none": "
|
|
89
|
+
"none": "418 kB",
|
|
90
90
|
"min": "190 kB",
|
|
91
|
-
"compressed": "
|
|
91
|
+
"compressed": "74 kB"
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
],
|