@salesforce/lds-network-fetch 1.461.0 → 1.463.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/ldsNetworkFetch.js
CHANGED
|
@@ -909,13 +909,11 @@ function instrument(newInstrumentation) {
|
|
|
909
909
|
}
|
|
910
910
|
|
|
911
911
|
/**
|
|
912
|
-
* Canonical registry of
|
|
913
|
-
* read/write nature —
|
|
914
|
-
*
|
|
915
|
-
*
|
|
916
|
-
*
|
|
917
|
-
* from `network-fetch.ts`. Templates use `{segment}` placeholders (see
|
|
918
|
-
* `compilePathMatchers`); callers normalize trailing slashes.
|
|
912
|
+
* Canonical registry of UIAPI url paths LDS sends over HTTP, and their
|
|
913
|
+
* read/write nature — shared by every runtime's transport allowlist and
|
|
914
|
+
* read-POST retry classifier. A leaf module (no local imports), since
|
|
915
|
+
* `network-fetch.ts` imports the retry interceptor, which must import paths
|
|
916
|
+
* from here rather than back from `network-fetch.ts`.
|
|
919
917
|
*/
|
|
920
918
|
/**
|
|
921
919
|
* Public UIAPI paths verified for HTTP transport: no `UiTier` Connect
|
|
@@ -933,10 +931,13 @@ const UIAPI_PUBLIC_PATH_ENTRIES = [
|
|
|
933
931
|
// getPicklistValuesByRecordType — IPicklistValuesByRecordTypeResource
|
|
934
932
|
{ path: '/ui-api/object-info/{objectApiName}/picklist-values/{recordTypeId}' },
|
|
935
933
|
// ----- Records -----
|
|
936
|
-
// createRecord (POST) — IRecordDataCollectionResource
|
|
937
|
-
|
|
938
|
-
//
|
|
939
|
-
{ path: '/ui-api/records
|
|
934
|
+
// createRecord (POST) — IRecordDataCollectionResource.
|
|
935
|
+
// Onboarded to the server Idempotency-Key feature: the interceptor mints a
|
|
936
|
+
// key for the POST so a throttled create can replay safely (dedupe by key).
|
|
937
|
+
{ path: '/ui-api/records', idempotentWrite: true },
|
|
938
|
+
// getRecord / updateRecord (PATCH) / deleteRecord (DELETE) — IRecordDataResource.
|
|
939
|
+
// Onboarded to the server Idempotency-Key feature (PATCH/DELETE writes).
|
|
940
|
+
{ path: '/ui-api/records/{recordId}', idempotentWrite: true },
|
|
940
941
|
// getRecords (batch GET) — IBatchRecordDataResource
|
|
941
942
|
{ path: '/ui-api/records/batch/{recordIds}' },
|
|
942
943
|
// executeBatchRecordOperations (POST, no recordIds segment) — IBatchRecordResource
|
|
@@ -1127,6 +1128,34 @@ function isRetryableReadPost(basePath) {
|
|
|
1127
1128
|
}
|
|
1128
1129
|
return RETRYABLE_READ_POST_MATCHERS.some((matcher) => matcher.test(path));
|
|
1129
1130
|
}
|
|
1131
|
+
// The idempotent-write subset, precompiled once at module load from the same
|
|
1132
|
+
// entries so a flagged path is always also a registered transport path.
|
|
1133
|
+
const IDEMPOTENT_WRITE_MATCHERS = compilePathMatchers([...UIAPI_PUBLIC_PATH_ENTRIES, ...UIAPI_PRIVATE_PATH_ENTRIES]
|
|
1134
|
+
.filter((entry) => entry.idempotentWrite)
|
|
1135
|
+
.map((entry) => entry.path));
|
|
1136
|
+
// Non-flagged templates that structurally collide with a flagged one (e.g.
|
|
1137
|
+
// `/ui-api/records/batch` vs `/ui-api/records/{recordId}`) — a match here means
|
|
1138
|
+
// the concrete path is the sibling, not an idempotent write. Derived from the
|
|
1139
|
+
// registry so a new sibling can't silently inherit minting.
|
|
1140
|
+
const IDEMPOTENT_WRITE_EXCLUSION_MATCHERS = compilePathMatchers([...UIAPI_PUBLIC_PATH_ENTRIES, ...UIAPI_PRIVATE_PATH_ENTRIES]
|
|
1141
|
+
.filter((entry) => !entry.idempotentWrite)
|
|
1142
|
+
.map((entry) => entry.path));
|
|
1143
|
+
/**
|
|
1144
|
+
* True when the request path is onboarded to the Idempotency-Key feature.
|
|
1145
|
+
* Gates minting only; must match a flagged template and not a more-specific
|
|
1146
|
+
* non-flagged sibling (see IDEMPOTENT_WRITE_EXCLUSION_MATCHERS).
|
|
1147
|
+
*/
|
|
1148
|
+
function isIdempotentWrite(basePath) {
|
|
1149
|
+
if (!basePath) {
|
|
1150
|
+
return false;
|
|
1151
|
+
}
|
|
1152
|
+
let path = basePath.trim();
|
|
1153
|
+
if (path.endsWith('/')) {
|
|
1154
|
+
path = path.substring(0, path.length - 1);
|
|
1155
|
+
}
|
|
1156
|
+
return (IDEMPOTENT_WRITE_MATCHERS.some((matcher) => matcher.test(path)) &&
|
|
1157
|
+
!IDEMPOTENT_WRITE_EXCLUSION_MATCHERS.some((matcher) => matcher.test(path)));
|
|
1158
|
+
}
|
|
1130
1159
|
|
|
1131
1160
|
/**
|
|
1132
1161
|
* Extracts the HTTP method from FetchParameters, matching the Fetch API's own
|
|
@@ -1165,10 +1194,11 @@ function isRetryableOperationType(operationType) {
|
|
|
1165
1194
|
return operationType === 'query';
|
|
1166
1195
|
}
|
|
1167
1196
|
/**
|
|
1168
|
-
*
|
|
1169
|
-
*
|
|
1197
|
+
* True for a mutating HTTP method (POST/PUT/PATCH/DELETE) — gates both CSRF
|
|
1198
|
+
* token attachment and Idempotency-Key minting, since both apply to the same
|
|
1199
|
+
* set of methods.
|
|
1170
1200
|
*/
|
|
1171
|
-
function
|
|
1201
|
+
function isMutatingMethod(method) {
|
|
1172
1202
|
if (!method) {
|
|
1173
1203
|
return false;
|
|
1174
1204
|
}
|
|
@@ -1178,6 +1208,48 @@ function isCsrfMethod(method) {
|
|
|
1178
1208
|
normalizedMethod === 'patch' ||
|
|
1179
1209
|
normalizedMethod === 'delete');
|
|
1180
1210
|
}
|
|
1211
|
+
const HTTP_HEADER_RETRY_AFTER = 'retry-after';
|
|
1212
|
+
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$/;
|
|
1213
|
+
/**
|
|
1214
|
+
* Parses a `Retry-After` header (case-insensitive lookup) into milliseconds.
|
|
1215
|
+
* Accepts fractional delay-seconds — the idempotency handler and the mobile
|
|
1216
|
+
* reference parser both emit them — or an IMF-fixdate. `Number.isFinite`
|
|
1217
|
+
* rejects `Infinity`/`-Infinity`, which otherwise round-trip cleanly through
|
|
1218
|
+
* `parseFloat` and would produce a non-finite delay.
|
|
1219
|
+
*/
|
|
1220
|
+
function parseRetryAfterMs(headers) {
|
|
1221
|
+
if (!headers) {
|
|
1222
|
+
return undefined;
|
|
1223
|
+
}
|
|
1224
|
+
let value;
|
|
1225
|
+
for (const key in headers) {
|
|
1226
|
+
if (key.toLowerCase() === HTTP_HEADER_RETRY_AFTER) {
|
|
1227
|
+
value = headers[key];
|
|
1228
|
+
break;
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
if (!value) {
|
|
1232
|
+
return undefined;
|
|
1233
|
+
}
|
|
1234
|
+
const trimmed = value.trim();
|
|
1235
|
+
const seconds = parseFloat(trimmed);
|
|
1236
|
+
if (Number.isFinite(seconds) && String(seconds) === trimmed) {
|
|
1237
|
+
return seconds >= 0 ? Math.round(seconds * 1000) : undefined;
|
|
1238
|
+
}
|
|
1239
|
+
if (!IMF_FIXDATE.test(trimmed)) {
|
|
1240
|
+
return undefined;
|
|
1241
|
+
}
|
|
1242
|
+
const millis = Date.parse(trimmed);
|
|
1243
|
+
return Number.isFinite(millis) ? Math.max(0, millis - Date.now()) : undefined;
|
|
1244
|
+
}
|
|
1245
|
+
/**
|
|
1246
|
+
* Reads the `errorCode` off a UiApiError body. UIAPI returns either a single
|
|
1247
|
+
* `{ errorCode, message }` object or a `[{ errorCode }]` array; handle both.
|
|
1248
|
+
*/
|
|
1249
|
+
function readUiApiErrorCode(response) {
|
|
1250
|
+
const body = response.body;
|
|
1251
|
+
return Array.isArray(body) ? body[0]?.errorCode : body?.errorCode;
|
|
1252
|
+
}
|
|
1181
1253
|
|
|
1182
|
-
export { UIAPI_PRIVATE_PATHS, UIAPI_PUBLIC_PATHS, compilePathMatchers, getFetchMethod, instrument,
|
|
1183
|
-
// version: 1.
|
|
1254
|
+
export { UIAPI_PRIVATE_PATHS, UIAPI_PUBLIC_PATHS, compilePathMatchers, getFetchMethod, instrument, isIdempotentWrite, isMutatingMethod, isRetryableMethod, isRetryableOperationType, isRetryableReadPost, parseRetryAfterMs, readUiApiErrorCode, setupFetchNetworkAdapter, setupLexNetworkAdapter };
|
|
1255
|
+
// version: 1.463.0-ea9ecd17fc
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FetchParameters } from '@conduit-client/service-fetch-network/v1';
|
|
2
|
+
import type { FetchResponse } from '@luvio/engine';
|
|
2
3
|
/**
|
|
3
4
|
* Extracts the HTTP method from FetchParameters, matching the Fetch API's own
|
|
4
5
|
* precedence: an options.method override wins over a Request object's method
|
|
@@ -24,7 +25,21 @@ export declare function isRetryableMethod(method: string | undefined): boolean;
|
|
|
24
25
|
*/
|
|
25
26
|
export declare function isRetryableOperationType(operationType: string | undefined): boolean;
|
|
26
27
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
28
|
+
* True for a mutating HTTP method (POST/PUT/PATCH/DELETE) — gates both CSRF
|
|
29
|
+
* token attachment and Idempotency-Key minting, since both apply to the same
|
|
30
|
+
* set of methods.
|
|
29
31
|
*/
|
|
30
|
-
export declare function
|
|
32
|
+
export declare function isMutatingMethod(method: string | undefined): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Parses a `Retry-After` header (case-insensitive lookup) into milliseconds.
|
|
35
|
+
* Accepts fractional delay-seconds — the idempotency handler and the mobile
|
|
36
|
+
* reference parser both emit them — or an IMF-fixdate. `Number.isFinite`
|
|
37
|
+
* rejects `Infinity`/`-Infinity`, which otherwise round-trip cleanly through
|
|
38
|
+
* `parseFloat` and would produce a non-finite delay.
|
|
39
|
+
*/
|
|
40
|
+
export declare function parseRetryAfterMs(headers: Record<string, string> | undefined): number | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Reads the `errorCode` off a UiApiError body. UIAPI returns either a single
|
|
43
|
+
* `{ errorCode, message }` object or a `[{ errorCode }]` array; handle both.
|
|
44
|
+
*/
|
|
45
|
+
export declare function readUiApiErrorCode(response: FetchResponse<any>): string | undefined;
|
package/dist/types/main.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ export { setupFetchNetworkAdapter, setupLexNetworkAdapter } from './networkAdapt
|
|
|
2
2
|
export type { RequestLogger } from './networkAdapter';
|
|
3
3
|
export type { RequestInterceptor, ResponseInterceptor, LuvioRetryInterceptor, Interceptors, } from './utils';
|
|
4
4
|
export { instrument, FetchNetworkInstrumentation } from './instrumentation';
|
|
5
|
-
export { UIAPI_PUBLIC_PATHS, UIAPI_PRIVATE_PATHS, compilePathMatchers, isRetryableReadPost, } from './uiapi-http-paths';
|
|
6
|
-
export { getFetchMethod, isRetryableMethod, isRetryableOperationType,
|
|
5
|
+
export { UIAPI_PUBLIC_PATHS, UIAPI_PRIVATE_PATHS, compilePathMatchers, isRetryableReadPost, isIdempotentWrite, } from './uiapi-http-paths';
|
|
6
|
+
export { getFetchMethod, isRetryableMethod, isRetryableOperationType, isMutatingMethod, parseRetryAfterMs, readUiApiErrorCode, } from './http-utils';
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Canonical registry of
|
|
3
|
-
* read/write nature —
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* from `network-fetch.ts`. Templates use `{segment}` placeholders (see
|
|
8
|
-
* `compilePathMatchers`); callers normalize trailing slashes.
|
|
2
|
+
* Canonical registry of UIAPI url paths LDS sends over HTTP, and their
|
|
3
|
+
* read/write nature — shared by every runtime's transport allowlist and
|
|
4
|
+
* read-POST retry classifier. A leaf module (no local imports), since
|
|
5
|
+
* `network-fetch.ts` imports the retry interceptor, which must import paths
|
|
6
|
+
* from here rather than back from `network-fetch.ts`.
|
|
9
7
|
*/
|
|
10
8
|
/** Public transport paths, derived from the canonical registry above. */
|
|
11
9
|
export declare const UIAPI_PUBLIC_PATHS: string[];
|
|
@@ -23,3 +21,9 @@ export declare function compilePathMatchers(paths: string[]): RegExp[];
|
|
|
23
21
|
* the same way the transport allowlist does before matching.
|
|
24
22
|
*/
|
|
25
23
|
export declare function isRetryableReadPost(basePath: string | undefined): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* True when the request path is onboarded to the Idempotency-Key feature.
|
|
26
|
+
* Gates minting only; must match a flagged template and not a more-specific
|
|
27
|
+
* non-flagged sibling (see IDEMPOTENT_WRITE_EXCLUSION_MATCHERS).
|
|
28
|
+
*/
|
|
29
|
+
export declare function isIdempotentWrite(basePath: string | undefined): boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/lds-network-fetch",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.463.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
5
5
|
"description": "LDS Network Adapter using fetch",
|
|
6
6
|
"main": "dist/ldsNetworkFetch.js",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
"release:corejar": "yarn build && ../core-build/scripts/core.js --name=lds-network-fetch"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@conduit-client/service-fetch-network": "3.
|
|
37
|
+
"@conduit-client/service-fetch-network": "3.30.0",
|
|
38
38
|
"@luvio/engine": "0.161.2",
|
|
39
39
|
"@luvio/network-adapter-fetch": "0.161.2"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@salesforce/lds-network-aura": "^1.
|
|
42
|
+
"@salesforce/lds-network-aura": "^1.463.0"
|
|
43
43
|
},
|
|
44
44
|
"volta": {
|
|
45
45
|
"extends": "../../package.json"
|