@salesforce/lds-network-fetch 1.435.1 → 1.437.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.
@@ -62,7 +62,9 @@ var HttpStatusCode;
62
62
  HttpStatusCode[HttpStatusCode["Unauthorized"] = 401] = "Unauthorized";
63
63
  HttpStatusCode[HttpStatusCode["Forbidden"] = 403] = "Forbidden";
64
64
  HttpStatusCode[HttpStatusCode["NotFound"] = 404] = "NotFound";
65
+ HttpStatusCode[HttpStatusCode["TooManyRequests"] = 429] = "TooManyRequests";
65
66
  HttpStatusCode[HttpStatusCode["ServerError"] = 500] = "ServerError";
67
+ HttpStatusCode[HttpStatusCode["ServiceUnavailable"] = 503] = "ServiceUnavailable";
66
68
  HttpStatusCode[HttpStatusCode["GatewayTimeout"] = 504] = "GatewayTimeout";
67
69
  })(HttpStatusCode || (HttpStatusCode = {}));
68
70
  /**
@@ -125,7 +127,7 @@ var TypeCheckShapes;
125
127
  TypeCheckShapes[TypeCheckShapes["Integer"] = 3] = "Integer";
126
128
  TypeCheckShapes[TypeCheckShapes["Unsupported"] = 4] = "Unsupported";
127
129
  })(TypeCheckShapes || (TypeCheckShapes = {}));
128
- // engine version: 0.160.4-b7e0ea82
130
+ // engine version: 0.160.5-e6ada846
129
131
 
130
132
  const { keys: keys$1 } = Object;
131
133
 
@@ -329,6 +331,9 @@ function mergeRecordFields(first, second) {
329
331
  targetFields[fieldName] = sourceFields[fieldName];
330
332
  continue;
331
333
  }
334
+ if (targetField.displayValue === null && sourceField.displayValue !== null) {
335
+ targetField.displayValue = sourceField.displayValue;
336
+ }
332
337
  mergeRecordFields(targetField.value, sourceField.value);
333
338
  continue;
334
339
  }
@@ -744,9 +749,15 @@ function getStorageAndLogger(path) {
744
749
  }
745
750
  const platformFetchAdapter = platformNetworkAdapter(fetchNetworkAdapter);
746
751
  const platformFetchAdapterWithInterceptors = async (resourceRequest, resourceRequestContext, requestInterceptors, interceptorContext) => {
747
- const pending = requestInterceptors.reduce((previousPromise, interceptor) => previousPromise.then((resourceRequest) => interceptor(resourceRequest, interceptorContext)), resolvedPromiseLike(resourceRequest));
752
+ const pending = runRequestInterceptors(resourceRequest, requestInterceptors, interceptorContext);
748
753
  return pending.then((interceptedRequest) => platformFetchAdapter(interceptedRequest, resourceRequestContext));
749
754
  };
755
+ /**
756
+ * Runs the request interceptor chain on a request and returns the intercepted
757
+ * request. Exposed so callers (e.g. the retry path) can run interceptors once
758
+ * up front and then issue the actual network call separately on each attempt.
759
+ */
760
+ const runRequestInterceptors = (resourceRequest, requestInterceptors, interceptorContext) => requestInterceptors.reduce((previousPromise, interceptor) => previousPromise.then((resourceRequest) => interceptor(resourceRequest, interceptorContext)), resolvedPromiseLike(resourceRequest));
750
761
  async function getDurableCacheDataForIncomingRequest(resourceRequest, storageAndLogger, transactionKey) {
751
762
  if (!shouldForceRefresh(resourceRequest)) {
752
763
  if (storageAndLogger?.storage) {
@@ -795,12 +806,28 @@ async function handleSendFetchRequest(resourceRequest, resourceRequestContext, i
795
806
  context.queryParams = resourceRequest.queryParams;
796
807
  context.cmp = resourceRequestContext.sourceContext?.tagName || 'none';
797
808
  }
798
- const { request: requestInterceptors = [], response: responseInterceptors = [], finally: finallyInterceptors = [], } = interceptors;
809
+ const { request: requestInterceptors = [], retry: retryInterceptor, response: responseInterceptors = [], finally: finallyInterceptors = [], } = interceptors;
799
810
  const cachedData = await getDurableCacheDataForIncomingRequest(resourceRequest, storageAndLogger, transactionKey);
800
811
  if (cachedData !== undefined) {
801
812
  return createOkResponse$1(cachedData);
802
813
  }
803
- const response = platformFetchAdapterWithInterceptors(resourceRequest, resourceRequestContext, requestInterceptors, context);
814
+ let response;
815
+ if (retryInterceptor) {
816
+ // Run the request interceptor chain ONCE up front, then hand the
817
+ // intercepted request off to the retry interceptor. The retry
818
+ // interceptor's `doFetch` goes straight to the network — request
819
+ // interceptors don't re-run on retry attempts. This mirrors the
820
+ // OneStore retry pattern (`csrf-retry.ts` calls raw `fetch(...)` on
821
+ // retry) and avoids re-executing side-effecting interceptors that
822
+ // assume one-shot invocation per logical request (tracker
823
+ // registration, perf marks, etc.).
824
+ const intercepted = await runRequestInterceptors(resourceRequest, requestInterceptors, context);
825
+ const doFetch = (req) => platformFetchAdapter(req, resourceRequestContext);
826
+ response = retryInterceptor(intercepted, doFetch, context);
827
+ }
828
+ else {
829
+ response = platformFetchAdapterWithInterceptors(resourceRequest, resourceRequestContext, requestInterceptors, context);
830
+ }
804
831
  const interceptedResponse = Promise.resolve(responseInterceptors.reduce((previousPromise, interceptor) => previousPromise.then((response) => interceptor(response, context)), resolvedPromiseLike(response)));
805
832
  // This can probably be refactored once we add an error interceptor pattern to onestore, and then
806
833
  // the intial then here can also most likely be moved to a response interceptor as well
@@ -850,4 +877,4 @@ function instrument(newInstrumentation) {
850
877
  }
851
878
 
852
879
  export { instrument, setupFetchNetworkAdapter, setupLexNetworkAdapter };
853
- // version: 1.435.1-4492aa27df
880
+ // version: 1.437.0-90398d3223
@@ -1,4 +1,4 @@
1
1
  export { setupFetchNetworkAdapter, setupLexNetworkAdapter } from './networkAdapter';
2
2
  export type { RequestLogger } from './networkAdapter';
3
- export type { RequestInterceptor, ResponseInterceptor, Interceptors } from './utils';
3
+ export type { RequestInterceptor, ResponseInterceptor, LuvioRetryInterceptor, Interceptors, } from './utils';
4
4
  export { instrument, FetchNetworkInstrumentation } from './instrumentation';
@@ -11,15 +11,40 @@ type LdsStorageConfig = {
11
11
  * @returns LdsStorageConfig if we cache that resource, otherwise null.
12
12
  */
13
13
  export declare function getStorageAndLogger(path: string): LdsStorageConfig | null;
14
+ export declare const platformFetchAdapter: import("@luvio/engine").NetworkAdapter;
14
15
  export type RequestInterceptor<Context = any> = (fetchArgs: ResourceRequest, context?: Context) => PromiseLike<ResourceRequest>;
15
16
  export type ResponseInterceptor<Context = any> = (response: FetchResponse<any>, context?: Context) => PromiseLike<FetchResponse<any>>;
16
17
  export type FinallyInterceptor<Context = any> = (context?: Context) => PromiseLike<void> | void;
18
+ /**
19
+ * Owns the fetch lifecycle for a single inbound request: it may call `doFetch`
20
+ * any number of times (e.g. to retry on 429/503 or refresh a CSRF token) and
21
+ * resolves with the final FetchResponse.
22
+ *
23
+ * `request` is the result of running the request interceptor chain ONCE, up
24
+ * front. `doFetch(req)` issues the network call directly — request
25
+ * interceptors do NOT run again on retry attempts. The interceptor is
26
+ * responsible for any per-attempt mutations (e.g. swapping a refreshed CSRF
27
+ * token onto the request before the next `doFetch`).
28
+ *
29
+ * This mirrors the OneStore retry pattern, where retry interceptors call raw
30
+ * `fetch(...)` directly on retry, and avoids re-executing side-effecting
31
+ * request interceptors (tracker registration, perf marks) that assume
32
+ * one-shot invocation per logical request.
33
+ */
34
+ export type LuvioRetryInterceptor<Context = any> = (request: ResourceRequest, doFetch: (req: ResourceRequest) => Promise<FetchResponse<any>>, context?: Context) => Promise<FetchResponse<any>>;
17
35
  export type Interceptors<Context = any> = {
18
36
  createContext?: () => Context;
19
37
  request?: RequestInterceptor<Context>[];
38
+ retry?: LuvioRetryInterceptor<Context>;
20
39
  response?: ResponseInterceptor<Context>[];
21
40
  finally?: FinallyInterceptor<Context>[];
22
41
  };
23
42
  export declare const platformFetchAdapterWithInterceptors: (resourceRequest: ResourceRequest, resourceRequestContext: ResourceRequestContext, requestInterceptors: RequestInterceptor[], interceptorContext: any) => Promise<FetchResponse<any>>;
43
+ /**
44
+ * Runs the request interceptor chain on a request and returns the intercepted
45
+ * request. Exposed so callers (e.g. the retry path) can run interceptors once
46
+ * up front and then issue the actual network call separately on each attempt.
47
+ */
48
+ export declare const runRequestInterceptors: (resourceRequest: ResourceRequest, requestInterceptors: RequestInterceptor[], interceptorContext: any) => PromiseLike<ResourceRequest>;
24
49
  export declare function getDurableCacheDataForIncomingRequest(resourceRequest: ResourceRequest, storageAndLogger: LdsStorageConfig | null, transactionKey: string): Promise<unknown>;
25
50
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/lds-network-fetch",
3
- "version": "1.435.1",
3
+ "version": "1.437.0",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "LDS Network Adapter using fetch",
6
6
  "main": "dist/ldsNetworkFetch.js",
@@ -34,11 +34,11 @@
34
34
  "release:corejar": "yarn build && ../core-build/scripts/core.js --name=lds-network-fetch"
35
35
  },
36
36
  "dependencies": {
37
- "@luvio/engine": "0.160.4",
38
- "@luvio/network-adapter-fetch": "0.160.4"
37
+ "@luvio/engine": "0.160.5",
38
+ "@luvio/network-adapter-fetch": "0.160.5"
39
39
  },
40
40
  "devDependencies": {
41
- "@salesforce/lds-network-aura": "^1.435.1"
41
+ "@salesforce/lds-network-aura": "^1.437.0"
42
42
  },
43
43
  "volta": {
44
44
  "extends": "../../package.json"