@salesforce/lds-runtime-aura 1.404.0-dev1 → 1.404.0-dev2

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.
@@ -2666,7 +2666,7 @@ function buildServiceDescriptor$d(luvio) {
2666
2666
  },
2667
2667
  };
2668
2668
  }
2669
- // version: 1.404.0-dev1-9582436c8f
2669
+ // version: 1.404.0-dev2-c0a696aed4
2670
2670
 
2671
2671
  /*!
2672
2672
  * Copyright (c) 2022, Salesforce, Inc.,
@@ -3004,7 +3004,7 @@ function buildServiceDescriptor$9(notifyRecordUpdateAvailable, getNormalizedLuvi
3004
3004
  },
3005
3005
  };
3006
3006
  }
3007
- // version: 1.404.0-dev1-9582436c8f
3007
+ // version: 1.404.0-dev2-c0a696aed4
3008
3008
 
3009
3009
  /*!
3010
3010
  * Copyright (c) 2022, Salesforce, Inc.,
@@ -4707,7 +4707,7 @@ function getEnvironmentSetting(name) {
4707
4707
  }
4708
4708
  return undefined;
4709
4709
  }
4710
- // version: 1.404.0-dev1-9582436c8f
4710
+ // version: 1.404.0-dev2-c0a696aed4
4711
4711
 
4712
4712
  /**
4713
4713
  * Observability / Critical Availability Program (230+)
@@ -5715,6 +5715,202 @@ function buildLexRuntimeLuvio5xxStatusResponseInterceptor() {
5715
5715
  };
5716
5716
  }
5717
5717
 
5718
+ const CSRF_TOKEN_KEY = 'salesforce_csrf_token';
5719
+ const CSRF_STORAGE_NAME = 'ldsCSRFToken';
5720
+ const BASE_URI = '/services/data/v66.0';
5721
+ const UI_API_BASE_URI = `${BASE_URI}/ui-api`;
5722
+ const CSRF_TOKEN_ENDPOINT = `${UI_API_BASE_URI}/session/csrf`;
5723
+ const CSRF_STORAGE_CONFIG = {
5724
+ name: CSRF_STORAGE_NAME,
5725
+ persistent: true,
5726
+ secure: true,
5727
+ maxSize: 1024,
5728
+ expiration: 24 * 60 * 60,
5729
+ clearOnInit: false,
5730
+ debugLogging: false,
5731
+ };
5732
+ /**
5733
+ * Manages CSRF token fetching and caching for secure requests.
5734
+ * Implements a singleton pattern to ensure consistent token management across the application.
5735
+ */
5736
+ class CsrfTokenManager {
5737
+ constructor() {
5738
+ this.tokenPromise = null;
5739
+ // Initialize AuraStorage
5740
+ this.storage = createStorage(CSRF_STORAGE_CONFIG);
5741
+ }
5742
+ static getInstance() {
5743
+ if (!CsrfTokenManager.instance) {
5744
+ CsrfTokenManager.instance = new CsrfTokenManager();
5745
+ }
5746
+ return CsrfTokenManager.instance;
5747
+ }
5748
+ /**
5749
+ * Obtain a CSRF token, either from AuraStorage or by fetching a fresh one.
5750
+ *
5751
+ * @private
5752
+ */
5753
+ async loadOrFetchToken() {
5754
+ // First try to get token from AuraStorage
5755
+ if (this.storage) {
5756
+ try {
5757
+ const cachedToken = await this.storage.get(CSRF_TOKEN_KEY);
5758
+ if (typeof cachedToken === 'string' && cachedToken) {
5759
+ return cachedToken;
5760
+ }
5761
+ }
5762
+ catch {
5763
+ // If storage read fails, continue to fetch
5764
+ }
5765
+ }
5766
+ // No cached token, fetch from server
5767
+ return this.fetchFreshToken();
5768
+ }
5769
+ /**
5770
+ * Call API endpoint to acquire a CSRF token and cache it.
5771
+ *
5772
+ * @private
5773
+ */
5774
+ async fetchFreshToken() {
5775
+ try {
5776
+ const response = await fetch(CSRF_TOKEN_ENDPOINT, {
5777
+ method: 'GET',
5778
+ credentials: 'same-origin',
5779
+ });
5780
+ if (!response.ok) {
5781
+ return undefined;
5782
+ }
5783
+ const data = await response.json();
5784
+ const token = data.csrfToken;
5785
+ if (token && this.storage) {
5786
+ // Cache the token in AuraStorage
5787
+ try {
5788
+ await this.storage.set(CSRF_TOKEN_KEY, token);
5789
+ }
5790
+ catch {
5791
+ // Non-fatal: token is still available even if caching fails
5792
+ }
5793
+ }
5794
+ return token;
5795
+ }
5796
+ catch {
5797
+ return undefined;
5798
+ }
5799
+ }
5800
+ /**
5801
+ * Returns the current token value as a Promise.
5802
+ * Lazy-loads the token on first call (from cache or by fetching).
5803
+ */
5804
+ async getToken() {
5805
+ // Lazy initialization: only fetch token when actually needed
5806
+ if (!this.tokenPromise) {
5807
+ this.tokenPromise = this.loadOrFetchToken();
5808
+ }
5809
+ return this.tokenPromise;
5810
+ }
5811
+ /**
5812
+ * Obtains and returns a new token value as a promise.
5813
+ * This will clear the cached token and fetch a fresh one.
5814
+ */
5815
+ async refreshToken() {
5816
+ // Clear cached token
5817
+ if (this.storage) {
5818
+ try {
5819
+ await this.storage.remove(CSRF_TOKEN_KEY);
5820
+ }
5821
+ catch {
5822
+ // Non-fatal: continue with refresh even if clear fails
5823
+ }
5824
+ }
5825
+ // Fetch (and cache) fresh token
5826
+ this.tokenPromise = this.fetchFreshToken();
5827
+ return this.tokenPromise;
5828
+ }
5829
+ /**
5830
+ * Reset the singleton instance (useful for testing).
5831
+ * @internal
5832
+ */
5833
+ static resetInstance() {
5834
+ CsrfTokenManager.instance = null;
5835
+ }
5836
+ }
5837
+ CsrfTokenManager.instance = null;
5838
+
5839
+ const CSRF_TOKEN_HEADER = 'X-CSRF-Token';
5840
+ /**
5841
+ * Determines if the HTTP method requires CSRF protection.
5842
+ * Only mutating operations (POST, PUT, PATCH, DELETE) require CSRF tokens.
5843
+ *
5844
+ * @param method - The HTTP method to check
5845
+ * @returns true if the method requires CSRF protection
5846
+ */
5847
+ function isCsrfMethod(method) {
5848
+ if (!method) {
5849
+ return false;
5850
+ }
5851
+ const normalizedMethod = method.toLowerCase();
5852
+ return (normalizedMethod === 'post' ||
5853
+ normalizedMethod === 'put' ||
5854
+ normalizedMethod === 'patch' ||
5855
+ normalizedMethod === 'delete');
5856
+ }
5857
+ /**
5858
+ * Builds a request interceptor that adds CSRF token headers to mutating requests.
5859
+ * The CSRF token is fetched once and cached for subsequent requests.
5860
+ * Only POST, PUT, PATCH, and DELETE requests will have the CSRF token added.
5861
+ *
5862
+ * @returns A RequestInterceptor function for FetchParameters
5863
+ */
5864
+ function buildCsrfTokenInterceptor() {
5865
+ const csrfTokenManager = CsrfTokenManager.getInstance();
5866
+ return async (fetchArgs) => {
5867
+ const [urlOrRequest, options] = fetchArgs;
5868
+ // Determine the method from either Request object or options
5869
+ let method;
5870
+ if (typeof urlOrRequest !== 'string' && 'method' in urlOrRequest) {
5871
+ method = urlOrRequest.method;
5872
+ }
5873
+ else if (options && 'method' in options) {
5874
+ method = options.method;
5875
+ }
5876
+ // Only add CSRF token for mutating operations
5877
+ if (isCsrfMethod(method)) {
5878
+ const token = await csrfTokenManager.getToken();
5879
+ if (token) {
5880
+ fetchArgs = setHeader(CSRF_TOKEN_HEADER, token, fetchArgs);
5881
+ }
5882
+ }
5883
+ return resolvedPromiseLike$2(fetchArgs);
5884
+ };
5885
+ }
5886
+ /**
5887
+ * Builds a Luvio request interceptor that adds CSRF token headers to mutating requests.
5888
+ * The CSRF token is fetched once and cached for subsequent requests.
5889
+ * Only POST, PUT, PATCH, and DELETE requests will have the CSRF token added.
5890
+ *
5891
+ * @returns A request interceptor function for Luvio ResourceRequest objects
5892
+ */
5893
+ function buildLuvioCsrfTokenInterceptor() {
5894
+ const csrfTokenManager = CsrfTokenManager.getInstance();
5895
+ return async (resourceRequest) => {
5896
+ // Ensure headers object exists
5897
+ if (!resourceRequest.headers) {
5898
+ resourceRequest.headers = {};
5899
+ }
5900
+ // Only add CSRF token for mutating operations
5901
+ if (isCsrfMethod(resourceRequest.method)) {
5902
+ // Don't overwrite existing CSRF token header if it already exists
5903
+ if (!resourceRequest.headers[CSRF_TOKEN_HEADER]) {
5904
+ const token = await csrfTokenManager.getToken();
5905
+ if (token) {
5906
+ resourceRequest.headers[CSRF_TOKEN_HEADER] = token;
5907
+ }
5908
+ }
5909
+ }
5910
+ return resolvedPromiseLike$2(resourceRequest);
5911
+ };
5912
+ }
5913
+
5718
5914
  const API_PATHS = [
5719
5915
  // getLookupActions
5720
5916
  // '/ui-api/actions/lookup/{objectApiNames}',
@@ -5776,7 +5972,7 @@ const composedFetchNetworkAdapter = {
5776
5972
  return API_PATH_MATCHERS.some((matcher) => matcher.test(path));
5777
5973
  },
5778
5974
  adapter: setupLexNetworkAdapter(requestTracker, requestLogger, {
5779
- request: [buildLuvioPageScopedCacheRequestInterceptor()],
5975
+ request: [buildLuvioPageScopedCacheRequestInterceptor(), buildLuvioCsrfTokenInterceptor()],
5780
5976
  response: [
5781
5977
  buildLexRuntimeLuvio5xxStatusResponseInterceptor(),
5782
5978
  buildLexRuntimeLuvioAuthExpirationRedirectResponseInterceptor(),
@@ -5855,120 +6051,6 @@ function buildTransportMarksReceiveInterceptor() {
5855
6051
  };
5856
6052
  }
5857
6053
 
5858
- const CSRF_TOKEN_KEY = 'salesforce_csrf_token';
5859
- const CSRF_STORAGE_NAME = 'ldsCSRFToken';
5860
- const CSRF_STORAGE_CONFIG = {
5861
- name: CSRF_STORAGE_NAME,
5862
- persistent: true,
5863
- secure: true,
5864
- maxSize: 1024,
5865
- expiration: 24 * 60 * 60,
5866
- clearOnInit: false,
5867
- debugLogging: false,
5868
- };
5869
- /**
5870
- * Manages CSRF token fetching and caching for secure requests.
5871
- * Implements a singleton pattern to ensure consistent token management across the application.
5872
- */
5873
- class CsrfTokenManager {
5874
- constructor() {
5875
- // Initialize AuraStorage
5876
- this.storage = createStorage(CSRF_STORAGE_CONFIG);
5877
- // Try to load token from AuraStorage on initialization
5878
- this.tokenPromise = this.loadOrFetchToken();
5879
- }
5880
- static getInstance() {
5881
- if (!CsrfTokenManager.instance) {
5882
- CsrfTokenManager.instance = new CsrfTokenManager();
5883
- }
5884
- return CsrfTokenManager.instance;
5885
- }
5886
- /**
5887
- * Obtain a CSRF token, either from AuraStorage or by fetching a fresh one.
5888
- *
5889
- * @private
5890
- */
5891
- async loadOrFetchToken() {
5892
- // First try to get token from AuraStorage
5893
- if (this.storage) {
5894
- try {
5895
- const cachedToken = await this.storage.get(CSRF_TOKEN_KEY);
5896
- if (typeof cachedToken === 'string' && cachedToken) {
5897
- return cachedToken;
5898
- }
5899
- }
5900
- catch {
5901
- // If storage read fails, continue to fetch
5902
- }
5903
- }
5904
- // No cached token, fetch from server
5905
- return this.fetchFreshToken();
5906
- }
5907
- /**
5908
- * Call API endpoint to acquire a CSRF token and cache it.
5909
- *
5910
- * @private
5911
- */
5912
- async fetchFreshToken() {
5913
- try {
5914
- const response = await fetch('/session/csrf', {
5915
- method: 'GET',
5916
- credentials: 'same-origin',
5917
- });
5918
- if (!response.ok) {
5919
- return undefined;
5920
- }
5921
- const data = await response.json();
5922
- const token = data.csrfToken;
5923
- if (token && this.storage) {
5924
- // Cache the token in AuraStorage
5925
- try {
5926
- await this.storage.set(CSRF_TOKEN_KEY, token);
5927
- }
5928
- catch {
5929
- // Non-fatal: token is still available even if caching fails
5930
- }
5931
- }
5932
- return token;
5933
- }
5934
- catch {
5935
- return undefined;
5936
- }
5937
- }
5938
- /**
5939
- * Returns the current token value as a Promise.
5940
- */
5941
- async getToken() {
5942
- return this.tokenPromise;
5943
- }
5944
- /**
5945
- * Obtains and returns a new token value as a promise.
5946
- * This will clear the cached token and fetch a fresh one.
5947
- */
5948
- async refreshToken() {
5949
- // Clear cached token
5950
- if (this.storage) {
5951
- try {
5952
- await this.storage.remove(CSRF_TOKEN_KEY);
5953
- }
5954
- catch {
5955
- // Non-fatal: continue with refresh even if clear fails
5956
- }
5957
- }
5958
- // Fetch (and cache) fresh token
5959
- this.tokenPromise = this.fetchFreshToken();
5960
- return this.tokenPromise;
5961
- }
5962
- /**
5963
- * Reset the singleton instance (useful for testing).
5964
- * @internal
5965
- */
5966
- static resetInstance() {
5967
- CsrfTokenManager.instance = null;
5968
- }
5969
- }
5970
- CsrfTokenManager.instance = null;
5971
-
5972
6054
  const DEFAULT_CONFIG$1 = {
5973
6055
  maxRetries: 1, // Only retry once after token refresh
5974
6056
  };
@@ -6077,6 +6159,7 @@ function buildLexRuntimeDefaultFetchServiceDescriptor(logger, retryService) {
6077
6159
  buildThirdPartyTrackerRegisterInterceptor(),
6078
6160
  buildPageScopedCacheRequestInterceptor(),
6079
6161
  buildTransportMarksSendInterceptor(),
6162
+ buildCsrfTokenInterceptor(),
6080
6163
  ],
6081
6164
  response: [
6082
6165
  buildLexRuntime5xxStatusResponseInterceptor(logger),
@@ -6098,6 +6181,7 @@ function buildLexRuntimeAllow5xxFetchServiceDescriptor(logger, retryService) {
6098
6181
  buildThirdPartyTrackerRegisterInterceptor(),
6099
6182
  buildPageScopedCacheRequestInterceptor(),
6100
6183
  buildTransportMarksSendInterceptor(),
6184
+ buildCsrfTokenInterceptor(),
6101
6185
  ],
6102
6186
  response: [buildLexRuntimeAuthExpirationRedirectResponseInterceptor(logger)],
6103
6187
  finally: [
@@ -9704,4 +9788,4 @@ function ldsEngineCreator() {
9704
9788
  }
9705
9789
 
9706
9790
  export { LexRequestStrategy, PdlRequestPriority, buildPredictorForContext, ldsEngineCreator as default, initializeLDS, initializeOneStore, notifyUpdateAvailableFactory, registerRequestStrategy, saveRequestAsPrediction, unregisterRequestStrategy, whenPredictionsReady };
9707
- // version: 1.404.0-dev1-48073cfce6
9791
+ // version: 1.404.0-dev2-3aea909b9d
@@ -22,6 +22,7 @@ declare class CsrfTokenManager {
22
22
  private fetchFreshToken;
23
23
  /**
24
24
  * Returns the current token value as a Promise.
25
+ * Lazy-loads the token on first call (from cache or by fetching).
25
26
  */
26
27
  getToken(): Promise<string | undefined>;
27
28
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/lds-runtime-aura",
3
- "version": "1.404.0-dev1",
3
+ "version": "1.404.0-dev2",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "LDS engine for Aura runtime",
6
6
  "main": "dist/ldsEngineCreator.js",
@@ -36,14 +36,14 @@
36
36
  "devDependencies": {
37
37
  "@conduit-client/service-provisioner": "3.2.0",
38
38
  "@conduit-client/tools-core": "3.2.0",
39
- "@salesforce/lds-adapters-apex": "^1.404.0-dev1",
40
- "@salesforce/lds-adapters-uiapi": "^1.404.0-dev1",
41
- "@salesforce/lds-ads-bridge": "^1.404.0-dev1",
42
- "@salesforce/lds-aura-storage": "^1.404.0-dev1",
43
- "@salesforce/lds-bindings": "^1.404.0-dev1",
44
- "@salesforce/lds-instrumentation": "^1.404.0-dev1",
45
- "@salesforce/lds-network-aura": "^1.404.0-dev1",
46
- "@salesforce/lds-network-fetch": "^1.404.0-dev1",
39
+ "@salesforce/lds-adapters-apex": "^1.404.0-dev2",
40
+ "@salesforce/lds-adapters-uiapi": "^1.404.0-dev2",
41
+ "@salesforce/lds-ads-bridge": "^1.404.0-dev2",
42
+ "@salesforce/lds-aura-storage": "^1.404.0-dev2",
43
+ "@salesforce/lds-bindings": "^1.404.0-dev2",
44
+ "@salesforce/lds-instrumentation": "^1.404.0-dev2",
45
+ "@salesforce/lds-network-aura": "^1.404.0-dev2",
46
+ "@salesforce/lds-network-fetch": "^1.404.0-dev2",
47
47
  "jwt-encode": "1.0.1"
48
48
  },
49
49
  "dependencies": {
@@ -71,10 +71,10 @@
71
71
  "@luvio/network-adapter-composable": "0.158.7",
72
72
  "@luvio/network-adapter-fetch": "0.158.7",
73
73
  "@lwc/state": "^0.23.0",
74
- "@salesforce/lds-adapters-onestore-graphql": "^1.404.0-dev1",
75
- "@salesforce/lds-adapters-uiapi-lex": "^1.404.0-dev1",
76
- "@salesforce/lds-luvio-service": "^1.404.0-dev1",
77
- "@salesforce/lds-luvio-uiapi-records-service": "^1.404.0-dev1"
74
+ "@salesforce/lds-adapters-onestore-graphql": "^1.404.0-dev2",
75
+ "@salesforce/lds-adapters-uiapi-lex": "^1.404.0-dev2",
76
+ "@salesforce/lds-luvio-service": "^1.404.0-dev2",
77
+ "@salesforce/lds-luvio-uiapi-records-service": "^1.404.0-dev2"
78
78
  },
79
79
  "luvioBundlesize": [
80
80
  {