@salesforce/lds-runtime-aura 1.441.0 → 1.443.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 +360 -159
- package/dist/types/aura-utils.d.ts +21 -0
- package/dist/types/fetch-service-descriptors/jwt-authorized-fetch-service.d.ts +0 -4
- package/dist/types/request-interceptors/csrf-manager.d.ts +6 -43
- package/dist/types/request-interceptors/csrf-service.d.ts +19 -0
- package/dist/types/request-interceptors/first-party-header.d.ts +17 -0
- package/dist/types/response-interceptors/error-body-normalization.d.ts +20 -0
- package/dist/types/retry-policies/csrf-token-retry-policy.d.ts +0 -1
- package/dist/types/retry-policies/luvio-csrf-token-retry-policy.d.ts +0 -1
- package/package.json +43 -42
package/dist/ldsEngineCreator.js
CHANGED
|
@@ -22,7 +22,7 @@ import { instrument, getRecordAvatarsAdapterFactory, getRecordAdapterFactory, co
|
|
|
22
22
|
import { getInstrumentation } from 'o11y/client';
|
|
23
23
|
import { findExecutableOperation, buildGraphQLInputExtension, addTypenameToDocument } from 'force/luvioGraphqlNormalization';
|
|
24
24
|
import { print, resolveAndValidateGraphQLConfig, toGraphQLErrorResponse } from 'force/luvioOnestoreGraphqlParser';
|
|
25
|
-
import { setServices } from 'force/luvioServiceProvisioner1';
|
|
25
|
+
import getServices, { setServices } from 'force/luvioServiceProvisioner1';
|
|
26
26
|
import { assertIsValid, JsonSchemaViolationError, MissingRequiredPropertyError } from 'force/luvioJsonschemaValidate5';
|
|
27
27
|
import { dispatchGlobalEvent, executeGlobalControllerRawResponse } from 'aura';
|
|
28
28
|
import auraNetworkAdapter, { dispatchAuraAction, defaultActionConfig, instrument as instrument$1, forceRecordTransactionsDisabled as forceRecordTransactionsDisabled$1, ldsNetworkAdapterInstrument, CrudEventState, CrudEventType, UIAPI_RECORDS_PATH, UIAPI_RELATED_LIST_RECORDS_BATCH_PATH, UIAPI_RELATED_LIST_RECORDS_PATH } from 'force/ldsNetwork';
|
|
@@ -36,7 +36,6 @@ import { instrument as instrument$5 } from '@lwc/state';
|
|
|
36
36
|
import { withRegistration, register, setDefaultLuvio } from 'force/ldsEngine';
|
|
37
37
|
import applyPredictionRequestLimit from '@salesforce/gate/lds.pdl.applyRequestLimit';
|
|
38
38
|
import { pageScopedCache } from 'instrumentation/utility';
|
|
39
|
-
import { createStorage, clearStorages } from 'force/ldsDurableStorage';
|
|
40
39
|
import lightningConnectEnabled from '@salesforce/gate/ui.services.LightningConnect.enabled';
|
|
41
40
|
import bypassAppRestrictionEnabled from '@salesforce/gate/ui.services.LightningConnect.BypassAppRestriction.enabled';
|
|
42
41
|
import csrfValidationEnabled from '@salesforce/gate/ui.services.LightningConnect.CsrfValidation.enabled';
|
|
@@ -47,6 +46,7 @@ import useHttpUiapiOneRuntimePublic from '@salesforce/gate/lds.useHttpUiapiOneRu
|
|
|
47
46
|
import useHttpUiapiOneRuntimePrivate from '@salesforce/gate/lds.useHttpUiapiOneRuntimePrivate';
|
|
48
47
|
import disableCreateContentDocumentAndVersionHTTPLexRuntime from '@salesforce/gate/lds.lex.http.disableCreateContentDocumentAndVersion';
|
|
49
48
|
import useHotspotLimit from '@salesforce/gate/lds.pdl.useHotspotLimit';
|
|
49
|
+
import { createStorage, clearStorages } from 'force/ldsDurableStorage';
|
|
50
50
|
import { registerSubRequestNetworkAdapter } from 'force/ldsNetwork';
|
|
51
51
|
|
|
52
52
|
const { create: create$1, freeze, keys: keys$2, entries: entries$1 } = Object;
|
|
@@ -2644,7 +2644,7 @@ function buildServiceDescriptor$d(luvio) {
|
|
|
2644
2644
|
},
|
|
2645
2645
|
};
|
|
2646
2646
|
}
|
|
2647
|
-
// version: 1.
|
|
2647
|
+
// version: 1.443.0-be70f6bb6e
|
|
2648
2648
|
|
|
2649
2649
|
class AuraGraphQLNormalizedCacheControlCommand extends AuraNormalizedCacheControlCommand {
|
|
2650
2650
|
constructor(config, documentRootType, services) {
|
|
@@ -2982,7 +2982,7 @@ function buildServiceDescriptor$9(notifyRecordUpdateAvailable, getNormalizedLuvi
|
|
|
2982
2982
|
},
|
|
2983
2983
|
};
|
|
2984
2984
|
}
|
|
2985
|
-
// version: 1.
|
|
2985
|
+
// version: 1.443.0-be70f6bb6e
|
|
2986
2986
|
|
|
2987
2987
|
class RetryService {
|
|
2988
2988
|
constructor(defaultRetryPolicy) {
|
|
@@ -3134,6 +3134,50 @@ function buildServiceDescriptor$8(defaultRetryPolicy) {
|
|
|
3134
3134
|
};
|
|
3135
3135
|
}
|
|
3136
3136
|
|
|
3137
|
+
class BasicRenewableResourceManager {
|
|
3138
|
+
constructor(config) {
|
|
3139
|
+
this.config = config;
|
|
3140
|
+
}
|
|
3141
|
+
get() {
|
|
3142
|
+
return this.config.storage.get().then((cached) => cached !== void 0 ? cached : this.fetchAndStore());
|
|
3143
|
+
}
|
|
3144
|
+
refresh(staleValue) {
|
|
3145
|
+
if (staleValue === void 0) {
|
|
3146
|
+
return this.fetchAndStore();
|
|
3147
|
+
}
|
|
3148
|
+
return this.config.storage.get().then(
|
|
3149
|
+
(current) => current !== void 0 && current !== staleValue ? current : this.fetchAndStore()
|
|
3150
|
+
);
|
|
3151
|
+
}
|
|
3152
|
+
clear() {
|
|
3153
|
+
return this.config.storage.clear();
|
|
3154
|
+
}
|
|
3155
|
+
/**
|
|
3156
|
+
* Single in-flight fetch shared by all concurrent `get`/`refresh` callers.
|
|
3157
|
+
* Overwrites storage on a successful fetch of a defined value only; a
|
|
3158
|
+
* rejected fetch or a resolved-`undefined` leaves the cached value intact.
|
|
3159
|
+
*/
|
|
3160
|
+
fetchAndStore() {
|
|
3161
|
+
if (this.inFlightFetch) return this.inFlightFetch;
|
|
3162
|
+
const pending = this.config.fetch().then(
|
|
3163
|
+
(fetched) => fetched === void 0 ? fetched : this.config.storage.set(fetched).then(() => fetched)
|
|
3164
|
+
);
|
|
3165
|
+
this.inFlightFetch = pending;
|
|
3166
|
+
const releaseSlot = () => {
|
|
3167
|
+
if (this.inFlightFetch === pending) this.inFlightFetch = void 0;
|
|
3168
|
+
};
|
|
3169
|
+
pending.then(releaseSlot, releaseSlot);
|
|
3170
|
+
return pending;
|
|
3171
|
+
}
|
|
3172
|
+
}
|
|
3173
|
+
function buildRenewableResourceManagerDescriptor(type, service) {
|
|
3174
|
+
return {
|
|
3175
|
+
version: "1.0",
|
|
3176
|
+
service,
|
|
3177
|
+
type
|
|
3178
|
+
};
|
|
3179
|
+
}
|
|
3180
|
+
|
|
3137
3181
|
function isUserVisibleError(error) {
|
|
3138
3182
|
return error instanceof Error && "type" in error && error.type === "user-visible";
|
|
3139
3183
|
}
|
|
@@ -3990,13 +4034,13 @@ function buildLWCGraphQLWireBindingsServiceDescriptor() {
|
|
|
3990
4034
|
};
|
|
3991
4035
|
}
|
|
3992
4036
|
|
|
3993
|
-
function e
|
|
4037
|
+
function e(e2) {
|
|
3994
4038
|
this.message = e2;
|
|
3995
4039
|
}
|
|
3996
|
-
e
|
|
4040
|
+
e.prototype = new Error(), e.prototype.name = "InvalidCharacterError";
|
|
3997
4041
|
var r = "undefined" != typeof window && window.atob && window.atob.bind(window) || function(r2) {
|
|
3998
4042
|
var t2 = String(r2).replace(/=+$/, "");
|
|
3999
|
-
if (t2.length % 4 == 1) throw new e
|
|
4043
|
+
if (t2.length % 4 == 1) throw new e("'atob' failed: The string to be decoded is not correctly encoded.");
|
|
4000
4044
|
for (var n2, o2, a = 0, i = 0, c = ""; o2 = t2.charAt(i++); ~o2 && (n2 = a % 4 ? 64 * n2 + o2 : o2, a++ % 4) ? c += String.fromCharCode(255 & n2 >> (-2 * a & 6)) : 0) o2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(o2);
|
|
4001
4045
|
return c;
|
|
4002
4046
|
};
|
|
@@ -4025,19 +4069,19 @@ function t(e2) {
|
|
|
4025
4069
|
return r(t2);
|
|
4026
4070
|
}
|
|
4027
4071
|
}
|
|
4028
|
-
function n
|
|
4072
|
+
function n(e2) {
|
|
4029
4073
|
this.message = e2;
|
|
4030
4074
|
}
|
|
4031
4075
|
function o(e2, r2) {
|
|
4032
|
-
if ("string" != typeof e2) throw new n
|
|
4076
|
+
if ("string" != typeof e2) throw new n("Invalid token specified");
|
|
4033
4077
|
var o2 = true === (r2 = r2 || {}).header ? 0 : 1;
|
|
4034
4078
|
try {
|
|
4035
4079
|
return JSON.parse(t(e2.split(".")[o2]));
|
|
4036
4080
|
} catch (e3) {
|
|
4037
|
-
throw new n
|
|
4081
|
+
throw new n("Invalid token specified: " + e3.message);
|
|
4038
4082
|
}
|
|
4039
4083
|
}
|
|
4040
|
-
n
|
|
4084
|
+
n.prototype = new Error(), n.prototype.name = "InvalidTokenError";
|
|
4041
4085
|
class JwtToken {
|
|
4042
4086
|
/**
|
|
4043
4087
|
* Create a new JwtToken.
|
|
@@ -4864,8 +4908,6 @@ function generateRequestId$1() {
|
|
|
4864
4908
|
}
|
|
4865
4909
|
}
|
|
4866
4910
|
|
|
4867
|
-
function e(e){this.message=e;}e.prototype=new Error,e.prototype.name="InvalidCharacterError";"undefined"!=typeof window&&window.atob&&window.atob.bind(window)||function(r){var t=String(r).replace(/=+$/,"");if(t.length%4==1)throw new e("'atob' failed: The string to be decoded is not correctly encoded.");for(var n,o,a=0,i=0,c="";o=t.charAt(i++);~o&&(n=a%4?64*n+o:o,a++%4)?c+=String.fromCharCode(255&n>>(-2*a&6)):0)o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(o);return c};function n(e){this.message=e;}n.prototype=new Error,n.prototype.name="InvalidTokenError";
|
|
4868
|
-
|
|
4869
4911
|
/**
|
|
4870
4912
|
* Observability / Critical Availability Program (230+)
|
|
4871
4913
|
*
|
|
@@ -5675,9 +5717,28 @@ function getEnvironmentSetting(name) {
|
|
|
5675
5717
|
}
|
|
5676
5718
|
return undefined;
|
|
5677
5719
|
}
|
|
5678
|
-
// version: 1.
|
|
5720
|
+
// version: 1.443.0-3de9a44799
|
|
5721
|
+
|
|
5722
|
+
/**
|
|
5723
|
+
* Helpers for reaching the Aura framework from the LDS Aura runtime.
|
|
5724
|
+
*
|
|
5725
|
+
* `window.$A` is only present when the runtime is hosted inside LEX; in tests
|
|
5726
|
+
* and non-Aura runtimes it is absent. Centralizing the guarded access keeps the
|
|
5727
|
+
* `$A` lookup in one place instead of duplicating the `environmentHasAura`
|
|
5728
|
+
* check across modules.
|
|
5729
|
+
*/
|
|
5730
|
+
/**
|
|
5731
|
+
* Returns `$A.clientService` when running inside an Aura environment, or
|
|
5732
|
+
* `undefined` otherwise. Defensive: never throws.
|
|
5733
|
+
*/
|
|
5734
|
+
function getAuraClientService() {
|
|
5735
|
+
if (typeof window === 'undefined' || typeof window.$A === 'undefined') {
|
|
5736
|
+
return undefined;
|
|
5737
|
+
}
|
|
5738
|
+
return window.$A.clientService;
|
|
5739
|
+
}
|
|
5679
5740
|
|
|
5680
|
-
const
|
|
5741
|
+
const auraClientService = getAuraClientService();
|
|
5681
5742
|
const defaultConfig = {
|
|
5682
5743
|
maxAllowedParallelXHRCounts: 9,
|
|
5683
5744
|
forceRecordTransactionsDisabled: false,
|
|
@@ -5688,10 +5749,11 @@ const configServiceDescriptor = buildServiceDescriptor$1({
|
|
|
5688
5749
|
default: defaultConfig,
|
|
5689
5750
|
});
|
|
5690
5751
|
const configService = configServiceDescriptor.service;
|
|
5691
|
-
if (
|
|
5752
|
+
if (auraClientService?.maxAllowedParallelXHRCounts) {
|
|
5692
5753
|
configService.set('lex', (config) => {
|
|
5693
5754
|
config.maxAllowedParallelXHRCounts =
|
|
5694
|
-
|
|
5755
|
+
auraClientService.maxAllowedParallelXHRCounts?.() ??
|
|
5756
|
+
defaultConfig.maxAllowedParallelXHRCounts;
|
|
5695
5757
|
config.forceRecordTransactionsDisabled = getEnvironmentSetting(EnvironmentSettings.ForceRecordTransactionsDisabled);
|
|
5696
5758
|
});
|
|
5697
5759
|
}
|
|
@@ -6121,146 +6183,91 @@ function buildLexRuntimeLuvio5xxStatusResponseInterceptor() {
|
|
|
6121
6183
|
};
|
|
6122
6184
|
}
|
|
6123
6185
|
|
|
6124
|
-
const CSRF_TOKEN_KEY = 'salesforce_csrf_token';
|
|
6125
|
-
const CSRF_STORAGE_NAME = 'ldsCSRFToken';
|
|
6126
|
-
const BASE_URI = '/services/data/v68.0';
|
|
6127
|
-
const UI_API_BASE_URI = `${BASE_URI}/ui-api`;
|
|
6128
|
-
const CSRF_TOKEN_ENDPOINT = `${UI_API_BASE_URI}/session/csrf`;
|
|
6129
|
-
const CSRF_STORAGE_CONFIG = {
|
|
6130
|
-
name: CSRF_STORAGE_NAME,
|
|
6131
|
-
persistent: true,
|
|
6132
|
-
secure: true,
|
|
6133
|
-
maxSize: 1024,
|
|
6134
|
-
expiration: 24 * 60 * 60,
|
|
6135
|
-
clearOnInit: false,
|
|
6136
|
-
debugLogging: false,
|
|
6137
|
-
};
|
|
6138
6186
|
/**
|
|
6139
|
-
*
|
|
6140
|
-
*
|
|
6187
|
+
* Normalizes Connect REST error envelopes into the Aura Shape A
|
|
6188
|
+
* (ConnectInJava) shape, so consumers can read `response.body.errorCode`
|
|
6189
|
+
* regardless of transport.
|
|
6190
|
+
*
|
|
6191
|
+
* - HTTP error envelope (this path): `[{ errorCode, message }, ...]`
|
|
6192
|
+
* - Aura Shape A: `{ errorCode, message, statusCode, ... }`
|
|
6193
|
+
*
|
|
6194
|
+
* The full array is preserved at `body.enhancedErrorInfo.allErrors` since
|
|
6195
|
+
* Connect can return multiple errors per response.
|
|
6196
|
+
*
|
|
6197
|
+
* Aura Shape B (`{ error: "..." }`) is an Aura-only fallback that never
|
|
6198
|
+
* appears on the HTTP path, so no normalization is needed for it here.
|
|
6199
|
+
*
|
|
6200
|
+
* Ordering: must run AFTER any other interceptor that inspects the raw
|
|
6201
|
+
* error body shape (e.g. the 5xx interceptor's ErrorId extraction reads
|
|
6202
|
+
* `body[0].message` from the array form).
|
|
6141
6203
|
*/
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
return CsrfTokenManager.instance;
|
|
6154
|
-
}
|
|
6155
|
-
/**
|
|
6156
|
-
* Obtain a CSRF token, either from AuraStorage or by fetching a fresh one.
|
|
6157
|
-
*
|
|
6158
|
-
* @private
|
|
6159
|
-
*/
|
|
6160
|
-
async loadOrFetchToken() {
|
|
6161
|
-
// First try to get token from AuraStorage
|
|
6162
|
-
if (this.storage) {
|
|
6163
|
-
try {
|
|
6164
|
-
const cachedToken = await this.storage.get(CSRF_TOKEN_KEY);
|
|
6165
|
-
if (typeof cachedToken === 'string' && cachedToken) {
|
|
6166
|
-
return cachedToken;
|
|
6167
|
-
}
|
|
6168
|
-
}
|
|
6169
|
-
catch {
|
|
6170
|
-
// If storage read fails, continue to fetch
|
|
6171
|
-
}
|
|
6172
|
-
}
|
|
6173
|
-
// No cached token, fetch from server
|
|
6174
|
-
return this.fetchFreshToken();
|
|
6175
|
-
}
|
|
6176
|
-
/**
|
|
6177
|
-
* Call API endpoint to acquire a CSRF token and cache it.
|
|
6178
|
-
*
|
|
6179
|
-
* @private
|
|
6180
|
-
*/
|
|
6181
|
-
async fetchFreshToken() {
|
|
6182
|
-
try {
|
|
6183
|
-
const response = await fetch(CSRF_TOKEN_ENDPOINT, {
|
|
6184
|
-
method: 'GET',
|
|
6185
|
-
credentials: 'same-origin',
|
|
6186
|
-
});
|
|
6187
|
-
if (!response.ok) {
|
|
6188
|
-
return undefined;
|
|
6189
|
-
}
|
|
6190
|
-
const data = await response.json();
|
|
6191
|
-
const token = data.csrfToken;
|
|
6192
|
-
if (token && this.storage) {
|
|
6193
|
-
// Cache the token in AuraStorage
|
|
6194
|
-
try {
|
|
6195
|
-
await this.storage.set(CSRF_TOKEN_KEY, token);
|
|
6196
|
-
}
|
|
6197
|
-
catch {
|
|
6198
|
-
// Non-fatal: token is still available even if caching fails
|
|
6199
|
-
}
|
|
6200
|
-
}
|
|
6201
|
-
return token;
|
|
6202
|
-
}
|
|
6203
|
-
catch {
|
|
6204
|
-
return undefined;
|
|
6205
|
-
}
|
|
6206
|
-
}
|
|
6207
|
-
/**
|
|
6208
|
-
* Returns the current token value as a Promise.
|
|
6209
|
-
* Lazy-loads the token on first call (from cache or by fetching).
|
|
6210
|
-
*/
|
|
6211
|
-
async getToken() {
|
|
6212
|
-
// Lazy initialization: only fetch token when actually needed
|
|
6213
|
-
if (!this.tokenPromise) {
|
|
6214
|
-
this.tokenPromise = this.loadOrFetchToken();
|
|
6215
|
-
}
|
|
6216
|
-
return this.tokenPromise;
|
|
6217
|
-
}
|
|
6218
|
-
/**
|
|
6219
|
-
* Obtains and returns a new token value as a promise.
|
|
6220
|
-
* This will clear the cached token and fetch a fresh one.
|
|
6221
|
-
*
|
|
6222
|
-
* Concurrent calls coalesce onto a single in-flight refresh — important when
|
|
6223
|
-
* multiple requests fail with INVALID_ACCESS_TOKEN simultaneously and each
|
|
6224
|
-
* retry policy independently calls refreshToken(). Without this, every caller
|
|
6225
|
-
* triggers its own /session/csrf round-trip.
|
|
6226
|
-
*/
|
|
6227
|
-
refreshToken() {
|
|
6228
|
-
if (this.refreshInFlight) {
|
|
6229
|
-
return this.refreshInFlight;
|
|
6204
|
+
function buildLuvioErrorBodyNormalizationInterceptor() {
|
|
6205
|
+
return async (response) => {
|
|
6206
|
+
if (!response.ok && Array.isArray(response.body)) {
|
|
6207
|
+
const allErrors = response.body;
|
|
6208
|
+
response.body = {
|
|
6209
|
+
...allErrors[0],
|
|
6210
|
+
statusCode: response.status,
|
|
6211
|
+
enhancedErrorInfo: {
|
|
6212
|
+
allErrors,
|
|
6213
|
+
},
|
|
6214
|
+
};
|
|
6230
6215
|
}
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6216
|
+
return response;
|
|
6217
|
+
};
|
|
6218
|
+
}
|
|
6219
|
+
|
|
6220
|
+
/**
|
|
6221
|
+
* Service name the CSRF token manager is registered under by
|
|
6222
|
+
* `initializeOneStore` (see `buildRenewableResourceManagerDescriptor`).
|
|
6223
|
+
*/
|
|
6224
|
+
const CSRF_TOKEN_MANAGER_SERVICE = 'csrfTokenManager';
|
|
6225
|
+
const CSRF_TOKEN_MANAGER_REQUEST = {
|
|
6226
|
+
[CSRF_TOKEN_MANAGER_SERVICE]: {
|
|
6227
|
+
type: CSRF_TOKEN_MANAGER_SERVICE,
|
|
6228
|
+
version: '1.0',
|
|
6229
|
+
},
|
|
6230
|
+
};
|
|
6231
|
+
let cached;
|
|
6232
|
+
/**
|
|
6233
|
+
* Resolves the CSRF token manager from the service provisioner.
|
|
6234
|
+
*
|
|
6235
|
+
* The manager is registered during `initializeOneStore`, which runs before any
|
|
6236
|
+
* request flows; the interceptors and retry policies that call this resolve
|
|
6237
|
+
* lazily (per request / per retry), so the service is always available by then.
|
|
6238
|
+
*
|
|
6239
|
+
* The resolved promise is memoized so resolution happens once rather than per
|
|
6240
|
+
* request. A rejection is NOT memoized — `getServices` rejects when the service
|
|
6241
|
+
* is unavailable, and caching that would permanently wedge CSRF handling — so a
|
|
6242
|
+
* later call retries the resolution.
|
|
6243
|
+
*/
|
|
6244
|
+
function getCsrfTokenManager() {
|
|
6245
|
+
if (!cached) {
|
|
6246
|
+
cached = Promise.resolve(getServices(CSRF_TOKEN_MANAGER_REQUEST))
|
|
6247
|
+
.then((services) => services[CSRF_TOKEN_MANAGER_SERVICE])
|
|
6248
|
+
.catch((error) => {
|
|
6249
|
+
cached = undefined;
|
|
6250
|
+
throw error;
|
|
6250
6251
|
});
|
|
6251
|
-
return refresh;
|
|
6252
|
-
}
|
|
6253
|
-
/**
|
|
6254
|
-
* Reset the singleton instance (useful for testing).
|
|
6255
|
-
* @internal
|
|
6256
|
-
*/
|
|
6257
|
-
static resetInstance() {
|
|
6258
|
-
CsrfTokenManager.instance = null;
|
|
6259
6252
|
}
|
|
6253
|
+
return cached;
|
|
6260
6254
|
}
|
|
6261
|
-
CsrfTokenManager.instance = null;
|
|
6262
6255
|
|
|
6263
6256
|
const CSRF_TOKEN_HEADER = 'X-CSRF-Token';
|
|
6257
|
+
/**
|
|
6258
|
+
* Resolves the CSRF token manager and returns the current token. Returns
|
|
6259
|
+
* `undefined` if the manager cannot be resolved (service not yet provisioned)
|
|
6260
|
+
* or has no token, so a request is never blocked by token resolution.
|
|
6261
|
+
*/
|
|
6262
|
+
async function getCsrfToken() {
|
|
6263
|
+
try {
|
|
6264
|
+
const manager = await getCsrfTokenManager();
|
|
6265
|
+
return await manager.get();
|
|
6266
|
+
}
|
|
6267
|
+
catch {
|
|
6268
|
+
return undefined;
|
|
6269
|
+
}
|
|
6270
|
+
}
|
|
6264
6271
|
/**
|
|
6265
6272
|
* Checks if all required gates are enabled for CSRF token interceptor.
|
|
6266
6273
|
*
|
|
@@ -6303,7 +6310,6 @@ function isCsrfMethod(method) {
|
|
|
6303
6310
|
* @returns A RequestInterceptor function for FetchParameters
|
|
6304
6311
|
*/
|
|
6305
6312
|
function buildCsrfTokenInterceptor() {
|
|
6306
|
-
const csrfTokenManager = CsrfTokenManager.getInstance();
|
|
6307
6313
|
return async (fetchArgs) => {
|
|
6308
6314
|
// Check if all required gates are enabled before running
|
|
6309
6315
|
if (!areCsrfGatesEnabled()) {
|
|
@@ -6320,7 +6326,7 @@ function buildCsrfTokenInterceptor() {
|
|
|
6320
6326
|
}
|
|
6321
6327
|
// Only add CSRF token for mutating operations
|
|
6322
6328
|
if (isCsrfMethod(method)) {
|
|
6323
|
-
const token = await
|
|
6329
|
+
const token = await getCsrfToken();
|
|
6324
6330
|
if (token) {
|
|
6325
6331
|
// eslint-disable-next-line no-param-reassign
|
|
6326
6332
|
fetchArgs = setHeader(CSRF_TOKEN_HEADER, token, fetchArgs);
|
|
@@ -6337,7 +6343,6 @@ function buildCsrfTokenInterceptor() {
|
|
|
6337
6343
|
* @returns A request interceptor function for Luvio ResourceRequest objects
|
|
6338
6344
|
*/
|
|
6339
6345
|
function buildLuvioCsrfTokenInterceptor() {
|
|
6340
|
-
const csrfTokenManager = CsrfTokenManager.getInstance();
|
|
6341
6346
|
return async (resourceRequest) => {
|
|
6342
6347
|
// Check if all required gates are enabled before running
|
|
6343
6348
|
if (!areCsrfGatesEnabled()) {
|
|
@@ -6351,7 +6356,7 @@ function buildLuvioCsrfTokenInterceptor() {
|
|
|
6351
6356
|
if (isCsrfMethod(resourceRequest.method)) {
|
|
6352
6357
|
// Don't overwrite existing CSRF token header if it already exists
|
|
6353
6358
|
if (!resourceRequest.headers[CSRF_TOKEN_HEADER]) {
|
|
6354
|
-
const token = await
|
|
6359
|
+
const token = await getCsrfToken();
|
|
6355
6360
|
if (token) {
|
|
6356
6361
|
resourceRequest.headers[CSRF_TOKEN_HEADER] = token;
|
|
6357
6362
|
}
|
|
@@ -6391,6 +6396,39 @@ function buildLuvioEntityEncodingInterceptor() {
|
|
|
6391
6396
|
};
|
|
6392
6397
|
}
|
|
6393
6398
|
|
|
6399
|
+
const FIRST_PARTY_HEADER = 'X-Salesforce-First-Party';
|
|
6400
|
+
const FIRST_PARTY_VALUE = 'platform-ui';
|
|
6401
|
+
/**
|
|
6402
|
+
* Builds a request interceptor that adds the LDS first party header to every
|
|
6403
|
+
* outbound request.
|
|
6404
|
+
*
|
|
6405
|
+
* @returns A RequestInterceptor function for FetchParameters
|
|
6406
|
+
*/
|
|
6407
|
+
function buildFirstPartyHeaderInterceptor() {
|
|
6408
|
+
return async (fetchArgs) => {
|
|
6409
|
+
const returnedFetchArgs = setHeader(FIRST_PARTY_HEADER, FIRST_PARTY_VALUE, fetchArgs);
|
|
6410
|
+
return resolvedPromiseLike$2(returnedFetchArgs);
|
|
6411
|
+
};
|
|
6412
|
+
}
|
|
6413
|
+
/**
|
|
6414
|
+
* Builds a Luvio request interceptor that adds the LDS first party header to
|
|
6415
|
+
* every outbound `ResourceRequest`. See {@link buildFirstPartyHeaderInterceptor} for
|
|
6416
|
+
* the header semantics.
|
|
6417
|
+
*
|
|
6418
|
+
* @returns A request interceptor for Luvio ResourceRequest objects
|
|
6419
|
+
*/
|
|
6420
|
+
function buildLuvioFirstPartyHeaderInterceptor() {
|
|
6421
|
+
return async (resourceRequest) => {
|
|
6422
|
+
if (!resourceRequest.headers) {
|
|
6423
|
+
resourceRequest.headers = {};
|
|
6424
|
+
}
|
|
6425
|
+
if (!resourceRequest.headers[FIRST_PARTY_HEADER]) {
|
|
6426
|
+
resourceRequest.headers[FIRST_PARTY_HEADER] = FIRST_PARTY_VALUE;
|
|
6427
|
+
}
|
|
6428
|
+
return resolvedPromiseLike$2(resourceRequest);
|
|
6429
|
+
};
|
|
6430
|
+
}
|
|
6431
|
+
|
|
6394
6432
|
function createInstrumentationIdContext() {
|
|
6395
6433
|
return () => ({
|
|
6396
6434
|
instrumentationId: generateRequestId(),
|
|
@@ -6620,7 +6658,6 @@ class LuvioCsrfTokenRetryPolicy extends RetryPolicy {
|
|
|
6620
6658
|
constructor(config = DEFAULT_CONFIG$3) {
|
|
6621
6659
|
super();
|
|
6622
6660
|
this.config = config;
|
|
6623
|
-
this.csrfTokenManager = CsrfTokenManager.getInstance();
|
|
6624
6661
|
}
|
|
6625
6662
|
setRequestContext(context) {
|
|
6626
6663
|
this.requestContext = context;
|
|
@@ -6642,11 +6679,20 @@ class LuvioCsrfTokenRetryPolicy extends RetryPolicy {
|
|
|
6642
6679
|
if (!this.requestContext) {
|
|
6643
6680
|
return;
|
|
6644
6681
|
}
|
|
6645
|
-
|
|
6682
|
+
let newToken;
|
|
6683
|
+
try {
|
|
6684
|
+
const manager = await getCsrfTokenManager();
|
|
6685
|
+
newToken = await manager.refresh();
|
|
6686
|
+
}
|
|
6687
|
+
catch {
|
|
6688
|
+
// Manager unavailable — drop the stale token below so the request
|
|
6689
|
+
// interceptor refetches on the retry.
|
|
6690
|
+
newToken = undefined;
|
|
6691
|
+
}
|
|
6646
6692
|
const req = this.requestContext.request;
|
|
6647
6693
|
const { [CSRF_TOKEN_HEADER]: _stale, ...remainingHeaders } = req.headers ?? {};
|
|
6648
6694
|
// If refresh failed, drop the stale token entirely so the request interceptor
|
|
6649
|
-
// will fetch a fresh one via
|
|
6695
|
+
// will fetch a fresh one via get() on the retry.
|
|
6650
6696
|
const headers = newToken
|
|
6651
6697
|
? { ...remainingHeaders, [CSRF_TOKEN_HEADER]: newToken }
|
|
6652
6698
|
: remainingHeaders;
|
|
@@ -7151,12 +7197,14 @@ const composedFetchNetworkAdapter = {
|
|
|
7151
7197
|
buildLuvioTransportMarksSendInterceptor(),
|
|
7152
7198
|
buildLuvioPageScopedCacheRequestInterceptor(),
|
|
7153
7199
|
buildLuvioCsrfTokenInterceptor(),
|
|
7200
|
+
buildLuvioFirstPartyHeaderInterceptor(),
|
|
7154
7201
|
buildLuvioEntityEncodingInterceptor(),
|
|
7155
7202
|
],
|
|
7156
7203
|
retry: buildLuvioFetchRetryInterceptor(),
|
|
7157
7204
|
response: [
|
|
7158
7205
|
buildLexRuntimeLuvio5xxStatusResponseInterceptor(),
|
|
7159
7206
|
buildLexRuntimeLuvioAuthExpirationRedirectResponseInterceptor(),
|
|
7207
|
+
buildLuvioErrorBodyNormalizationInterceptor(),
|
|
7160
7208
|
buildLuvioTransportMarksReceiveInterceptor(),
|
|
7161
7209
|
buildLuvioActionMarksReceiveInterceptor(),
|
|
7162
7210
|
],
|
|
@@ -7201,7 +7249,6 @@ class CsrfTokenRetryPolicy extends RetryPolicy {
|
|
|
7201
7249
|
constructor(config = DEFAULT_CONFIG$1) {
|
|
7202
7250
|
super();
|
|
7203
7251
|
this.config = config;
|
|
7204
|
-
this.csrfTokenManager = CsrfTokenManager.getInstance();
|
|
7205
7252
|
}
|
|
7206
7253
|
/**
|
|
7207
7254
|
* Allows the fetch service to pass mutable request context.
|
|
@@ -7253,7 +7300,15 @@ class CsrfTokenRetryPolicy extends RetryPolicy {
|
|
|
7253
7300
|
*/
|
|
7254
7301
|
async prepareRetry(_result, _context) {
|
|
7255
7302
|
// Refresh the CSRF token (we already know this is a CSRF error from shouldRetry)
|
|
7256
|
-
|
|
7303
|
+
let newToken;
|
|
7304
|
+
try {
|
|
7305
|
+
const manager = await getCsrfTokenManager();
|
|
7306
|
+
newToken = await manager.refresh();
|
|
7307
|
+
}
|
|
7308
|
+
catch {
|
|
7309
|
+
// Manager unavailable — the retry will fail again, which is expected.
|
|
7310
|
+
newToken = undefined;
|
|
7311
|
+
}
|
|
7257
7312
|
if (!newToken || !this.requestContext) {
|
|
7258
7313
|
// If we can't get a new token or don't have request context,
|
|
7259
7314
|
// the retry will fail again but that's expected
|
|
@@ -10086,6 +10141,7 @@ function getLexRuntimeDefaultInterceptorConfig(logger) {
|
|
|
10086
10141
|
buildTransportMarksSendInterceptor(),
|
|
10087
10142
|
buildCsrfTokenInterceptor(),
|
|
10088
10143
|
buildEntityEncodingInterceptor(),
|
|
10144
|
+
buildFirstPartyHeaderInterceptor(),
|
|
10089
10145
|
],
|
|
10090
10146
|
retry: buildCsrfRetryInterceptor(),
|
|
10091
10147
|
response: [
|
|
@@ -10197,6 +10253,149 @@ class FetchThrottlingRetryPolicy extends RetryPolicy {
|
|
|
10197
10253
|
}
|
|
10198
10254
|
}
|
|
10199
10255
|
|
|
10256
|
+
const CSRF_TOKEN_KEY = 'salesforce_csrf_token';
|
|
10257
|
+
const CSRF_STORAGE_NAME = 'ldsCSRFToken';
|
|
10258
|
+
const BASE_URI = '/services/data/v68.0';
|
|
10259
|
+
const UI_API_BASE_URI = `${BASE_URI}/ui-api`;
|
|
10260
|
+
const CSRF_TOKEN_ENDPOINT = `${UI_API_BASE_URI}/session/csrf`;
|
|
10261
|
+
const CSRF_STORAGE_CONFIG = {
|
|
10262
|
+
name: CSRF_STORAGE_NAME,
|
|
10263
|
+
persistent: true,
|
|
10264
|
+
secure: true,
|
|
10265
|
+
maxSize: 1024,
|
|
10266
|
+
expiration: 24 * 60 * 60,
|
|
10267
|
+
clearOnInit: false,
|
|
10268
|
+
debugLogging: false,
|
|
10269
|
+
};
|
|
10270
|
+
/**
|
|
10271
|
+
* Reads the CSRF token Aura preloads onto the bootstrap payload. When the
|
|
10272
|
+
* Connect Framework CSRF token is minted at template-render time it is exposed
|
|
10273
|
+
* via `$A.clientService.getConnectCsrfToken()`. Reading it here lets the first
|
|
10274
|
+
* state-changing request skip the cold `/ui-api/session/csrf` round trip.
|
|
10275
|
+
*
|
|
10276
|
+
* Defensive against a missing getter or server killswitch: returns `undefined`,
|
|
10277
|
+
* never throws.
|
|
10278
|
+
*/
|
|
10279
|
+
function readPreloadedToken() {
|
|
10280
|
+
const clientService = getAuraClientService();
|
|
10281
|
+
if (typeof clientService?.getConnectCsrfToken !== 'function') {
|
|
10282
|
+
return undefined;
|
|
10283
|
+
}
|
|
10284
|
+
try {
|
|
10285
|
+
const token = clientService.getConnectCsrfToken();
|
|
10286
|
+
return typeof token === 'string' && token ? token : undefined;
|
|
10287
|
+
}
|
|
10288
|
+
catch {
|
|
10289
|
+
return undefined;
|
|
10290
|
+
}
|
|
10291
|
+
}
|
|
10292
|
+
/**
|
|
10293
|
+
* Fetches a fresh CSRF token from the server. Resolves `undefined` (not a
|
|
10294
|
+
* rejection) on any non-ok response, missing token, or network/parse error so
|
|
10295
|
+
* the manager treats it as "no value" and leaves any cached token intact. The
|
|
10296
|
+
* CSRF retry policy — not this fetch — owns retry semantics.
|
|
10297
|
+
*/
|
|
10298
|
+
async function fetchFreshToken() {
|
|
10299
|
+
try {
|
|
10300
|
+
const response = await fetch(CSRF_TOKEN_ENDPOINT, {
|
|
10301
|
+
method: 'GET',
|
|
10302
|
+
credentials: 'same-origin',
|
|
10303
|
+
});
|
|
10304
|
+
if (!response.ok) {
|
|
10305
|
+
return undefined;
|
|
10306
|
+
}
|
|
10307
|
+
const data = await response.json();
|
|
10308
|
+
const token = data.csrfToken;
|
|
10309
|
+
return typeof token === 'string' && token ? token : undefined;
|
|
10310
|
+
}
|
|
10311
|
+
catch {
|
|
10312
|
+
return undefined;
|
|
10313
|
+
}
|
|
10314
|
+
}
|
|
10315
|
+
/**
|
|
10316
|
+
* Adapts the durable AuraStorage backing store to the {@link ResourceStorage}
|
|
10317
|
+
* contract the renewable-resource manager expects.
|
|
10318
|
+
*
|
|
10319
|
+
* The Aura-preloaded token is written into the store **once at creation** (only
|
|
10320
|
+
* when the store is otherwise empty), so the first `get()` finds it and the
|
|
10321
|
+
* first mutation skips the network. Seeding the store — rather than having
|
|
10322
|
+
* `get()` fall back to the preload on every empty read — means a later
|
|
10323
|
+
* `clear()` (logout / org switch) is not silently resurrected by the preload.
|
|
10324
|
+
*
|
|
10325
|
+
* Every operation awaits the one-time seed so reads and writes observe a
|
|
10326
|
+
* consistent store. Storage read/write failures are non-fatal.
|
|
10327
|
+
*/
|
|
10328
|
+
function buildCsrfResourceStorage() {
|
|
10329
|
+
const storage = createStorage(CSRF_STORAGE_CONFIG);
|
|
10330
|
+
// Pre-seed the preloaded token into the store, once, if the store is empty.
|
|
10331
|
+
const seeded = (async () => {
|
|
10332
|
+
const preloadedToken = readPreloadedToken();
|
|
10333
|
+
if (!storage || !preloadedToken) {
|
|
10334
|
+
return;
|
|
10335
|
+
}
|
|
10336
|
+
try {
|
|
10337
|
+
const existing = await storage.get(CSRF_TOKEN_KEY);
|
|
10338
|
+
if (typeof existing !== 'string' || !existing) {
|
|
10339
|
+
await storage.set(CSRF_TOKEN_KEY, preloadedToken);
|
|
10340
|
+
}
|
|
10341
|
+
}
|
|
10342
|
+
catch {
|
|
10343
|
+
// Non-fatal: fall back to fetching a fresh token on first use.
|
|
10344
|
+
}
|
|
10345
|
+
})();
|
|
10346
|
+
return {
|
|
10347
|
+
get: async () => {
|
|
10348
|
+
await seeded;
|
|
10349
|
+
if (storage) {
|
|
10350
|
+
try {
|
|
10351
|
+
const cached = await storage.get(CSRF_TOKEN_KEY);
|
|
10352
|
+
if (typeof cached === 'string' && cached) {
|
|
10353
|
+
return cached;
|
|
10354
|
+
}
|
|
10355
|
+
}
|
|
10356
|
+
catch {
|
|
10357
|
+
// Non-fatal: treat as a cache miss so the manager fetches.
|
|
10358
|
+
}
|
|
10359
|
+
}
|
|
10360
|
+
return undefined;
|
|
10361
|
+
},
|
|
10362
|
+
set: async (value) => {
|
|
10363
|
+
await seeded;
|
|
10364
|
+
if (storage) {
|
|
10365
|
+
try {
|
|
10366
|
+
await storage.set(CSRF_TOKEN_KEY, value);
|
|
10367
|
+
}
|
|
10368
|
+
catch {
|
|
10369
|
+
// Non-fatal: token is still usable even if caching fails.
|
|
10370
|
+
}
|
|
10371
|
+
}
|
|
10372
|
+
},
|
|
10373
|
+
clear: async () => {
|
|
10374
|
+
await seeded;
|
|
10375
|
+
if (storage) {
|
|
10376
|
+
try {
|
|
10377
|
+
await storage.remove(CSRF_TOKEN_KEY);
|
|
10378
|
+
}
|
|
10379
|
+
catch {
|
|
10380
|
+
// Non-fatal: continue even if the clear fails.
|
|
10381
|
+
}
|
|
10382
|
+
}
|
|
10383
|
+
},
|
|
10384
|
+
};
|
|
10385
|
+
}
|
|
10386
|
+
/**
|
|
10387
|
+
* Builds the CSRF token manager: a {@link BasicRenewableResourceManager} that
|
|
10388
|
+
* lazily caches the token in durable storage, coalesces concurrent fetches onto
|
|
10389
|
+
* a single in-flight request, and dedups refresh storms. Registered as a
|
|
10390
|
+
* provisioner service (`csrfTokenManager`) by `initializeOneStore`.
|
|
10391
|
+
*/
|
|
10392
|
+
function buildCsrfTokenManager() {
|
|
10393
|
+
return new BasicRenewableResourceManager({
|
|
10394
|
+
fetch: fetchFreshToken,
|
|
10395
|
+
storage: buildCsrfResourceStorage(),
|
|
10396
|
+
});
|
|
10397
|
+
}
|
|
10398
|
+
|
|
10200
10399
|
/* eslint-disable no-console */
|
|
10201
10400
|
/**
|
|
10202
10401
|
* Default storage configuration for the durable cache
|
|
@@ -10791,6 +10990,7 @@ function initializeOneStore(luvio) {
|
|
|
10791
10990
|
const retryPolicy = new ComposedRetryPolicy([throttlingPolicy, csrfPolicy]);
|
|
10792
10991
|
const retryServiceDescriptor = buildServiceDescriptor$8(retryPolicy);
|
|
10793
10992
|
const retryService = retryServiceDescriptor.service;
|
|
10993
|
+
const csrfTokenManagerServiceDescriptor = buildRenewableResourceManagerDescriptor(CSRF_TOKEN_MANAGER_SERVICE, buildCsrfTokenManager());
|
|
10794
10994
|
const prefetchSfapJwtServiceDescriptor = {
|
|
10795
10995
|
type: 'prefetchSfapJwt',
|
|
10796
10996
|
version: '1.0',
|
|
@@ -10838,6 +11038,7 @@ function initializeOneStore(luvio) {
|
|
|
10838
11038
|
buildLWCGraphQLWireBindingsServiceDescriptor(),
|
|
10839
11039
|
configServiceDescriptor,
|
|
10840
11040
|
prefetchSfapJwtServiceDescriptor,
|
|
11041
|
+
csrfTokenManagerServiceDescriptor,
|
|
10841
11042
|
];
|
|
10842
11043
|
setServices(services);
|
|
10843
11044
|
}
|
|
@@ -10857,4 +11058,4 @@ function ldsEngineCreator() {
|
|
|
10857
11058
|
}
|
|
10858
11059
|
|
|
10859
11060
|
export { LexRequestStrategy, PdlPrefetcherEventType, PdlRequestPriority, buildPredictorForContext, configService, ldsEngineCreator as default, initializeLDS, initializeOneStore, notifyUpdateAvailableFactory, registerRequestStrategy, saveRequestAsPrediction, subscribeToPrefetcherEvents, unregisterRequestStrategy, whenPredictionsReady };
|
|
10860
|
-
// version: 1.
|
|
11061
|
+
// version: 1.443.0-be70f6bb6e
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for reaching the Aura framework from the LDS Aura runtime.
|
|
3
|
+
*
|
|
4
|
+
* `window.$A` is only present when the runtime is hosted inside LEX; in tests
|
|
5
|
+
* and non-Aura runtimes it is absent. Centralizing the guarded access keeps the
|
|
6
|
+
* `$A` lookup in one place instead of duplicating the `environmentHasAura`
|
|
7
|
+
* check across modules.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* The subset of the Aura client service LDS reaches for. Methods are optional
|
|
11
|
+
* because availability depends on the host's Aura version and server gates.
|
|
12
|
+
*/
|
|
13
|
+
export interface AuraClientService {
|
|
14
|
+
maxAllowedParallelXHRCounts?: () => number;
|
|
15
|
+
getConnectCsrfToken?: () => unknown;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Returns `$A.clientService` when running inside an Aura environment, or
|
|
19
|
+
* `undefined` otherwise. Defensive: never throws.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getAuraClientService(): AuraClientService | undefined;
|
|
@@ -8,8 +8,4 @@ export declare function buildJwtAuthorizedSfapFetchServiceDescriptor(logger: Log
|
|
|
8
8
|
* copilot commands.
|
|
9
9
|
*/
|
|
10
10
|
export declare function buildCopilotFetchServiceDescriptor(logger: LoggerService): FetchServiceDescriptor;
|
|
11
|
-
export declare const lightningJwtResolver: {
|
|
12
|
-
getJwt(): Promise<any>;
|
|
13
|
-
};
|
|
14
|
-
export declare function buildJwtAuthorizedLightningFetchServiceDescriptor(): FetchServiceDescriptor;
|
|
15
11
|
export declare function buildUnauthorizedFetchServiceDescriptor(): FetchServiceDescriptor;
|
|
@@ -1,45 +1,8 @@
|
|
|
1
|
+
import { type RenewableResourceManager } from '@conduit-client/service-renewable-resource-manager/v1';
|
|
1
2
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
3
|
+
* Builds the CSRF token manager: a {@link BasicRenewableResourceManager} that
|
|
4
|
+
* lazily caches the token in durable storage, coalesces concurrent fetches onto
|
|
5
|
+
* a single in-flight request, and dedups refresh storms. Registered as a
|
|
6
|
+
* provisioner service (`csrfTokenManager`) by `initializeOneStore`.
|
|
4
7
|
*/
|
|
5
|
-
declare
|
|
6
|
-
private static instance;
|
|
7
|
-
private tokenPromise;
|
|
8
|
-
private refreshInFlight;
|
|
9
|
-
private storage;
|
|
10
|
-
private constructor();
|
|
11
|
-
static getInstance(): CsrfTokenManager;
|
|
12
|
-
/**
|
|
13
|
-
* Obtain a CSRF token, either from AuraStorage or by fetching a fresh one.
|
|
14
|
-
*
|
|
15
|
-
* @private
|
|
16
|
-
*/
|
|
17
|
-
private loadOrFetchToken;
|
|
18
|
-
/**
|
|
19
|
-
* Call API endpoint to acquire a CSRF token and cache it.
|
|
20
|
-
*
|
|
21
|
-
* @private
|
|
22
|
-
*/
|
|
23
|
-
private fetchFreshToken;
|
|
24
|
-
/**
|
|
25
|
-
* Returns the current token value as a Promise.
|
|
26
|
-
* Lazy-loads the token on first call (from cache or by fetching).
|
|
27
|
-
*/
|
|
28
|
-
getToken(): Promise<string | undefined>;
|
|
29
|
-
/**
|
|
30
|
-
* Obtains and returns a new token value as a promise.
|
|
31
|
-
* This will clear the cached token and fetch a fresh one.
|
|
32
|
-
*
|
|
33
|
-
* Concurrent calls coalesce onto a single in-flight refresh — important when
|
|
34
|
-
* multiple requests fail with INVALID_ACCESS_TOKEN simultaneously and each
|
|
35
|
-
* retry policy independently calls refreshToken(). Without this, every caller
|
|
36
|
-
* triggers its own /session/csrf round-trip.
|
|
37
|
-
*/
|
|
38
|
-
refreshToken(): Promise<string | undefined>;
|
|
39
|
-
/**
|
|
40
|
-
* Reset the singleton instance (useful for testing).
|
|
41
|
-
* @internal
|
|
42
|
-
*/
|
|
43
|
-
static resetInstance(): void;
|
|
44
|
-
}
|
|
45
|
-
export { CsrfTokenManager };
|
|
8
|
+
export declare function buildCsrfTokenManager(): RenewableResourceManager<string>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { RenewableResourceManager } from '@conduit-client/service-renewable-resource-manager/v1';
|
|
2
|
+
/**
|
|
3
|
+
* Service name the CSRF token manager is registered under by
|
|
4
|
+
* `initializeOneStore` (see `buildRenewableResourceManagerDescriptor`).
|
|
5
|
+
*/
|
|
6
|
+
export declare const CSRF_TOKEN_MANAGER_SERVICE = "csrfTokenManager";
|
|
7
|
+
/**
|
|
8
|
+
* Resolves the CSRF token manager from the service provisioner.
|
|
9
|
+
*
|
|
10
|
+
* The manager is registered during `initializeOneStore`, which runs before any
|
|
11
|
+
* request flows; the interceptors and retry policies that call this resolve
|
|
12
|
+
* lazily (per request / per retry), so the service is always available by then.
|
|
13
|
+
*
|
|
14
|
+
* The resolved promise is memoized so resolution happens once rather than per
|
|
15
|
+
* request. A rejection is NOT memoized — `getServices` rejects when the service
|
|
16
|
+
* is unavailable, and caching that would permanently wedge CSRF handling — so a
|
|
17
|
+
* later call retries the resolution.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getCsrfTokenManager(): Promise<RenewableResourceManager<string>>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type RequestInterceptor } from '@conduit-client/service-fetch-network/v1';
|
|
2
|
+
import type { ResourceRequest } from '@luvio/engine';
|
|
3
|
+
/**
|
|
4
|
+
* Builds a request interceptor that adds the LDS first party header to every
|
|
5
|
+
* outbound request.
|
|
6
|
+
*
|
|
7
|
+
* @returns A RequestInterceptor function for FetchParameters
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildFirstPartyHeaderInterceptor(): RequestInterceptor;
|
|
10
|
+
/**
|
|
11
|
+
* Builds a Luvio request interceptor that adds the LDS first party header to
|
|
12
|
+
* every outbound `ResourceRequest`. See {@link buildFirstPartyHeaderInterceptor} for
|
|
13
|
+
* the header semantics.
|
|
14
|
+
*
|
|
15
|
+
* @returns A request interceptor for Luvio ResourceRequest objects
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildLuvioFirstPartyHeaderInterceptor(): (resourceRequest: ResourceRequest) => Promise<ResourceRequest>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ResponseInterceptor as LuvioResponseInterceptor } from '@salesforce/lds-network-fetch';
|
|
2
|
+
/**
|
|
3
|
+
* Normalizes Connect REST error envelopes into the Aura Shape A
|
|
4
|
+
* (ConnectInJava) shape, so consumers can read `response.body.errorCode`
|
|
5
|
+
* regardless of transport.
|
|
6
|
+
*
|
|
7
|
+
* - HTTP error envelope (this path): `[{ errorCode, message }, ...]`
|
|
8
|
+
* - Aura Shape A: `{ errorCode, message, statusCode, ... }`
|
|
9
|
+
*
|
|
10
|
+
* The full array is preserved at `body.enhancedErrorInfo.allErrors` since
|
|
11
|
+
* Connect can return multiple errors per response.
|
|
12
|
+
*
|
|
13
|
+
* Aura Shape B (`{ error: "..." }`) is an Aura-only fallback that never
|
|
14
|
+
* appears on the HTTP path, so no normalization is needed for it here.
|
|
15
|
+
*
|
|
16
|
+
* Ordering: must run AFTER any other interceptor that inspects the raw
|
|
17
|
+
* error body shape (e.g. the 5xx interceptor's ErrorId extraction reads
|
|
18
|
+
* `body[0].message` from the array form).
|
|
19
|
+
*/
|
|
20
|
+
export declare function buildLuvioErrorBodyNormalizationInterceptor(): LuvioResponseInterceptor;
|
|
@@ -12,7 +12,6 @@ export interface MutableLuvioRequest {
|
|
|
12
12
|
}
|
|
13
13
|
export declare class LuvioCsrfTokenRetryPolicy extends RetryPolicy<FetchResponse<any>> {
|
|
14
14
|
private config;
|
|
15
|
-
private csrfTokenManager;
|
|
16
15
|
private requestContext?;
|
|
17
16
|
constructor(config?: LuvioCsrfTokenRetryPolicyConfig);
|
|
18
17
|
setRequestContext(context: MutableLuvioRequest): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/lds-runtime-aura",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.443.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
5
5
|
"description": "LDS engine for Aura runtime.",
|
|
6
6
|
"main": "dist/ldsEngineCreator.js",
|
|
@@ -34,60 +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.
|
|
38
|
-
"@conduit-client/tools-core": "3.
|
|
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.22.0",
|
|
38
|
+
"@conduit-client/tools-core": "3.22.0",
|
|
39
|
+
"@salesforce/lds-adapters-apex": "^1.443.0",
|
|
40
|
+
"@salesforce/lds-adapters-uiapi": "^1.443.0",
|
|
41
|
+
"@salesforce/lds-ads-bridge": "^1.443.0",
|
|
42
|
+
"@salesforce/lds-aura-storage": "^1.443.0",
|
|
43
|
+
"@salesforce/lds-bindings": "^1.443.0",
|
|
44
|
+
"@salesforce/lds-instrumentation": "^1.443.0",
|
|
45
|
+
"@salesforce/lds-network-adapter": "^1.443.0",
|
|
46
|
+
"@salesforce/lds-network-aura": "^1.443.0",
|
|
47
|
+
"@salesforce/lds-network-fetch": "^1.443.0",
|
|
48
48
|
"jwt-encode": "1.0.1"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@conduit-client/command-aura-graphql-normalized-cache-control": "3.
|
|
52
|
-
"@conduit-client/command-aura-network": "3.
|
|
53
|
-
"@conduit-client/command-aura-normalized-cache-control": "3.
|
|
54
|
-
"@conduit-client/command-aura-resource-cache-control": "3.
|
|
55
|
-
"@conduit-client/command-fetch-network": "3.
|
|
56
|
-
"@conduit-client/command-http-graphql-normalized-cache-control": "3.
|
|
57
|
-
"@conduit-client/command-http-normalized-cache-control": "3.
|
|
58
|
-
"@conduit-client/command-ndjson": "3.
|
|
59
|
-
"@conduit-client/command-network": "3.
|
|
60
|
-
"@conduit-client/command-sse": "3.
|
|
61
|
-
"@conduit-client/command-streaming": "3.
|
|
62
|
-
"@conduit-client/service-aura-network": "3.
|
|
63
|
-
"@conduit-client/service-bindings-imperative": "3.
|
|
64
|
-
"@conduit-client/service-bindings-lwc": "3.
|
|
65
|
-
"@conduit-client/service-cache": "3.
|
|
66
|
-
"@conduit-client/service-cache-control": "3.
|
|
67
|
-
"@conduit-client/service-cache-inclusion-policy": "3.
|
|
68
|
-
"@conduit-client/service-config": "3.
|
|
69
|
-
"@conduit-client/service-feature-flags": "3.
|
|
70
|
-
"@conduit-client/service-fetch-network": "3.
|
|
71
|
-
"@conduit-client/service-instrument-command": "3.
|
|
72
|
-
"@conduit-client/service-pubsub": "3.
|
|
73
|
-
"@conduit-client/service-
|
|
74
|
-
"@conduit-client/
|
|
51
|
+
"@conduit-client/command-aura-graphql-normalized-cache-control": "3.22.0",
|
|
52
|
+
"@conduit-client/command-aura-network": "3.22.0",
|
|
53
|
+
"@conduit-client/command-aura-normalized-cache-control": "3.22.0",
|
|
54
|
+
"@conduit-client/command-aura-resource-cache-control": "3.22.0",
|
|
55
|
+
"@conduit-client/command-fetch-network": "3.22.0",
|
|
56
|
+
"@conduit-client/command-http-graphql-normalized-cache-control": "3.22.0",
|
|
57
|
+
"@conduit-client/command-http-normalized-cache-control": "3.22.0",
|
|
58
|
+
"@conduit-client/command-ndjson": "3.22.0",
|
|
59
|
+
"@conduit-client/command-network": "3.22.0",
|
|
60
|
+
"@conduit-client/command-sse": "3.22.0",
|
|
61
|
+
"@conduit-client/command-streaming": "3.22.0",
|
|
62
|
+
"@conduit-client/service-aura-network": "3.22.0",
|
|
63
|
+
"@conduit-client/service-bindings-imperative": "3.22.0",
|
|
64
|
+
"@conduit-client/service-bindings-lwc": "3.22.0",
|
|
65
|
+
"@conduit-client/service-cache": "3.22.0",
|
|
66
|
+
"@conduit-client/service-cache-control": "3.22.0",
|
|
67
|
+
"@conduit-client/service-cache-inclusion-policy": "3.22.0",
|
|
68
|
+
"@conduit-client/service-config": "3.22.0",
|
|
69
|
+
"@conduit-client/service-feature-flags": "3.22.0",
|
|
70
|
+
"@conduit-client/service-fetch-network": "3.22.0",
|
|
71
|
+
"@conduit-client/service-instrument-command": "3.22.0",
|
|
72
|
+
"@conduit-client/service-pubsub": "3.22.0",
|
|
73
|
+
"@conduit-client/service-renewable-resource-manager": "3.22.0",
|
|
74
|
+
"@conduit-client/service-store": "3.22.0",
|
|
75
|
+
"@conduit-client/utils": "3.22.0",
|
|
75
76
|
"@luvio/network-adapter-composable": "0.160.5",
|
|
76
77
|
"@luvio/network-adapter-fetch": "0.160.5",
|
|
77
78
|
"@lwc/state": "^0.29.0",
|
|
78
|
-
"@salesforce/lds-adapters-onestore-graphql": "^1.
|
|
79
|
+
"@salesforce/lds-adapters-onestore-graphql": "^1.443.0",
|
|
79
80
|
"@salesforce/lds-adapters-uiapi-lex": "^1.415.0",
|
|
80
|
-
"@salesforce/lds-durable-storage": "^1.
|
|
81
|
-
"@salesforce/lds-luvio-service": "^1.
|
|
82
|
-
"@salesforce/lds-luvio-uiapi-records-service": "^1.
|
|
81
|
+
"@salesforce/lds-durable-storage": "^1.443.0",
|
|
82
|
+
"@salesforce/lds-luvio-service": "^1.443.0",
|
|
83
|
+
"@salesforce/lds-luvio-uiapi-records-service": "^1.443.0"
|
|
83
84
|
},
|
|
84
85
|
"luvioBundlesize": [
|
|
85
86
|
{
|
|
86
87
|
"path": "./dist/ldsEngineCreator.js",
|
|
87
88
|
"maxSize": {
|
|
88
|
-
"none": "
|
|
89
|
+
"none": "390 kB",
|
|
89
90
|
"min": "190 kB",
|
|
90
|
-
"compressed": "
|
|
91
|
+
"compressed": "65.5 kB"
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
],
|