@salesforce/lds-network-fetch 1.457.0 → 1.458.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.
@@ -908,5 +908,276 @@ function instrument(newInstrumentation) {
908
908
  Object.assign(instrumentation, newInstrumentation);
909
909
  }
910
910
 
911
- export { instrument, setupFetchNetworkAdapter, setupLexNetworkAdapter };
912
- // version: 1.457.0-b38a7243f7
911
+ /**
912
+ * Canonical registry of the UIAPI url paths LDS sends over HTTP and their
913
+ * read/write nature — the single source of truth for every runtime's transport
914
+ * allowlist and read-POST retry classifier. A leaf module (no local imports) so
915
+ * both can consume it without an import cycle: `network-fetch.ts` imports the
916
+ * retry interceptor, so the retry layer must import paths from here, not back
917
+ * from `network-fetch.ts`. Templates use `{segment}` placeholders (see
918
+ * `compilePathMatchers`); callers normalize trailing slashes.
919
+ */
920
+ /**
921
+ * Public UIAPI paths verified for HTTP transport: no `UiTier` Connect
922
+ * clientFilter, and actually invoked by a Luvio adapter wired into
923
+ * `ldsEngineCreator.js`. All URL shapes an LDS adapter can hit are registered.
924
+ */
925
+ const UIAPI_PUBLIC_PATH_ENTRIES = [
926
+ // ----- Object Info -----
927
+ // getObjectInfo — IObjectInfoResource
928
+ { path: '/ui-api/object-info/{objectApiName}' },
929
+ // getObjectInfos (batch) — IObjectInfoBatchResource
930
+ { path: '/ui-api/object-info/batch/{objectApiNames}' },
931
+ // getPicklistValues — IPicklistValuesResource
932
+ { path: '/ui-api/object-info/{objectApiName}/picklist-values/{recordTypeId}/{fieldApiName}' },
933
+ // getPicklistValuesByRecordType — IPicklistValuesByRecordTypeResource
934
+ { path: '/ui-api/object-info/{objectApiName}/picklist-values/{recordTypeId}' },
935
+ // ----- Records -----
936
+ // createRecord (POST) — IRecordDataCollectionResource
937
+ { path: '/ui-api/records' },
938
+ // getRecord / updateRecord (PATCH) / deleteRecord (DELETE) — IRecordDataResource
939
+ { path: '/ui-api/records/{recordId}' },
940
+ // getRecords (batch GET) — IBatchRecordDataResource
941
+ { path: '/ui-api/records/batch/{recordIds}' },
942
+ // executeBatchRecordOperations (POST, no recordIds segment) — IBatchRecordResource
943
+ { path: '/ui-api/records/batch' },
944
+ // getRecordUi — IRecordUiResource
945
+ { path: '/ui-api/record-ui/{recordIds}' },
946
+ // ----- Layout -----
947
+ // getLayout — ILayoutResource
948
+ { path: '/ui-api/layout/{objectApiName}' },
949
+ // getPathLayout — IPathLayoutResource
950
+ { path: '/ui-api/path/layout/{objectApiName}' },
951
+ // ----- Record Defaults -----
952
+ // getRecordCreateDefaults — IRecordCreateDefaultsResource
953
+ { path: '/ui-api/record-defaults/create/{objectApiName}' },
954
+ // getRecordDefaultsTemplateForCreate — IRecordDefaultsTemplateCreateResource
955
+ { path: '/ui-api/record-defaults/template/create/{objectApiName}' },
956
+ // getRecordDefaultsTemplateClone — IRecordDefaultsTemplateCloneResource
957
+ { path: '/ui-api/record-defaults/template/clone/{recordId}' },
958
+ // ----- Duplicates -----
959
+ // getDuplicateConfig — IDuplicateConfigResource
960
+ { path: '/ui-api/duplicates/{objectApiName}' },
961
+ // findDuplicates (POST) — IPredupeResource
962
+ { path: '/ui-api/predupe', retryableReadPost: true },
963
+ // ----- GraphQL -----
964
+ // executeGraphQL (POST) — IGraphQLResource (no /ui-api prefix).
965
+ // Query-only on the Luvio path: the GraphQL parser rejects non-`query`
966
+ // operations before they reach the network (see lds-graphql-parser gql.ts),
967
+ // so a mutation can never traverse this path.
968
+ { path: '/graphql', retryableReadPost: true },
969
+ // ----- List UI -----
970
+ // getListUiByName (2-segment form) — IListUiResource212
971
+ { path: '/ui-api/list-ui/{objectApiName}/{listViewApiName}' },
972
+ // 1-segment form covers both:
973
+ // /ui-api/list-ui/{listViewId} — IListUiResource
974
+ // /ui-api/list-ui/{objectApiName} — IListCollectionResource
975
+ { path: '/ui-api/list-ui/{objectApiNameOrListViewId}' },
976
+ // getListInfoByName (GET) / updateListInfoByApiName (PATCH) / deleteListInfo (DELETE) — IListInfoResource
977
+ // (Also covers /ui-api/list-info/{listViewId} via shape collision.)
978
+ { path: '/ui-api/list-info/{objectApiName}/{listViewApiName}' },
979
+ // getListInfosByObjectName (GET) / createListInfo (POST) — IListInfoCreationAndCollectionResource
980
+ // (Also covers /ui-api/list-info/batch — IListInfoBatchResource — via shape collision.)
981
+ { path: '/ui-api/list-info/{objectApiName}' },
982
+ // getListObjectInfo — IListObjectInfoResource
983
+ { path: '/ui-api/list-object-info/{objectApiName}' },
984
+ // postListRecordsByName (POST) — IListRecordsResource
985
+ { path: '/ui-api/list-records/{objectApiName}/{listViewApiName}', retryableReadPost: true },
986
+ // getListPreferences (GET) / updateListPreferences (PATCH) — IListPreferencesResource
987
+ { path: '/ui-api/list-preferences/{objectApiName}/{listViewApiName}' },
988
+ // ----- Related List UI -----
989
+ // getRelatedListInfo (GET) / updateRelatedListInfo (PATCH) — IRelatedListInfoResource
990
+ // (Also covers /ui-api/related-list-info/{parentRecordId}/{relatedListId} via shape collision.)
991
+ { path: '/ui-api/related-list-info/{parentObjectApiName}/{relatedListId}' },
992
+ // getRelatedListInfoBatch — IRelatedListInfoBatchResource
993
+ { path: '/ui-api/related-list-info/batch/{parentObjectApiName}/{relatedListNames}' },
994
+ // getRelatedListsInfo (collection) — IRelatedListInfoCollectionResource
995
+ { path: '/ui-api/related-list-info/{parentObjectApiName}' },
996
+ // postRelatedListRecords (POST) — IRelatedListRecordsResource
997
+ {
998
+ path: '/ui-api/related-list-records/{parentRecordId}/{relatedListId}',
999
+ retryableReadPost: true,
1000
+ },
1001
+ // postRelatedListRecordsBatch (POST, 3-segment form) — IRelatedListRecordsBatchResource
1002
+ { path: '/ui-api/related-list-records/batch/{parentRecordId}', retryableReadPost: true },
1003
+ // getRelatedListRecordsBatch (GET, 4-segment form) — IRelatedListRecordsBatchResource [newly added]
1004
+ { path: '/ui-api/related-list-records/batch/{parentRecordId}/{relatedListIds}' },
1005
+ // getRelatedListCount — IRelatedListRecordCountResource
1006
+ { path: '/ui-api/related-list-count/{parentRecordId}/{relatedListId}' },
1007
+ // getRelatedListsCount (batch) — IRelatedListRecordCountBatchResource
1008
+ { path: '/ui-api/related-list-count/batch/{parentRecordId}/{relatedListNames}' },
1009
+ // getRelatedListPreferences (GET) / updateRelatedListPreferences (PATCH) — IRelatedListPreferencesResource
1010
+ { path: '/ui-api/related-list-preferences/{preferencesId}' },
1011
+ // getRelatedListPreferencesBatch — IRelatedListPreferencesBatchResource
1012
+ { path: '/ui-api/related-list-preferences/batch/{preferencesIds}' },
1013
+ // ----- Actions -----
1014
+ // getGlobalActions — IActionGlobalResource
1015
+ { path: '/ui-api/actions/global' },
1016
+ // getActionLayout — IActionLayoutResource
1017
+ { path: '/ui-api/actions/layout/{actionApiName}' },
1018
+ // getLookupActions — IActionLookupResource
1019
+ { path: '/ui-api/actions/lookup/{objectApiNames}' },
1020
+ // getObjectCreateActions — IActionObjectResource
1021
+ { path: '/ui-api/actions/object/{objectApiName}/record-create' },
1022
+ // getActionOverrides — IActionOverrideResource
1023
+ { path: '/ui-api/actions/overrides/{objectApiName}' },
1024
+ // performQuickAction (POST) / performUpdateRecordQuickAction (PATCH) — IActionPerformQuickActionResource
1025
+ { path: '/ui-api/actions/perform-quick-action/{actionApiName}' },
1026
+ // getQuickActionInfo — IActionQuickActionInfoResource
1027
+ { path: '/ui-api/actions/quick-action-info/{actionApiName}' },
1028
+ // getRecordActions — IActionRecordResource
1029
+ { path: '/ui-api/actions/record/{recordIds}' },
1030
+ // getRecordEditActions — IActionRecordEditResource
1031
+ { path: '/ui-api/actions/record/{recordIds}/record-edit' },
1032
+ // getAllRelatedListActionsForRecord (4-segment form) — IActionRelatedListResource [newly added]
1033
+ { path: '/ui-api/actions/record/{recordIds}/related-list' },
1034
+ // postRelatedListActions (POST) — IActionRelatedListResource
1035
+ { path: '/ui-api/actions/record/{recordIds}/related-list/{relatedListId}' },
1036
+ // postRelatedListsActions (POST) / getRelatedListsActions (GET, 5-segment form) — IActionRelatedListBatchResource
1037
+ { path: '/ui-api/actions/record/{recordIds}/related-list/batch' },
1038
+ // getRelatedListsActions (GET, 6-segment form) — IActionRelatedListBatchResource [newly added]
1039
+ { path: '/ui-api/actions/record/{recordIds}/related-list/batch/{relatedListIds}' },
1040
+ // getRelatedListRecordActions — IActionRelatedListRecordResource
1041
+ { path: '/ui-api/actions/record/{recordIds}/related-list-record/{relatedListRecordIds}' },
1042
+ // getQuickActionDefaults — IActionQuickActionDefaultsResource
1043
+ { path: '/ui-api/actions/record-defaults/{actionApiName}' },
1044
+ // getFlexipageFormulaOverrides — IActionFlexipageFormulaActivationResource
1045
+ { path: '/ui-api/actions/formula-activation/{actionFeature}' },
1046
+ // ----- Lookup / Search -----
1047
+ // getLookupRecords issues lookup as a POST — ILookupEntityResource.
1048
+ // The POST form is 2-segment: /ui-api/lookups/{objectApiName}/{fieldApiName}
1049
+ // (targetApiName is a query param, not a path segment). The 3-segment GET
1050
+ // form exists on the same resource but no wired LDS adapter emits it, so
1051
+ // only the POST shape is registered.
1052
+ { path: '/ui-api/lookups/{objectApiName}/{fieldApiName}', retryableReadPost: true },
1053
+ // searchResults (POST) — ISearchResultsResource
1054
+ { path: '/ui-api/search/results', retryableReadPost: true },
1055
+ // searchKeywordResults (POST) — IKeywordSearchResultsResource
1056
+ { path: '/ui-api/search/results/keyword', retryableReadPost: true },
1057
+ // getSearchFilterMetadata — ISearchInfoFilterMetadataCollectionResource
1058
+ { path: '/ui-api/search-info/{objectApiName}/filters' },
1059
+ // getSearchFilterOptions — ISearchInfoFilterOptionsResource
1060
+ { path: '/ui-api/search-info/{objectApiName}/filters/{filterApiName}/options' },
1061
+ // getLookupMetadata — ILookupMetadataResource
1062
+ { path: '/ui-api/search-info/{objectApiName}/lookup/{fieldApiName}' },
1063
+ // ----- MRU Lists -----
1064
+ // getMruListUi — IMruListUiResource
1065
+ { path: '/ui-api/mru-list-ui/{objectApiName}' },
1066
+ // getMruListRecords — IMruListRecordsResource
1067
+ { path: '/ui-api/mru-list-records/{objectApiName}' },
1068
+ // ----- Apps / Nav -----
1069
+ // getNavItems — INavItemsResource
1070
+ { path: '/ui-api/nav-items' },
1071
+ // getAllApps — IAppsResource
1072
+ { path: '/ui-api/apps' },
1073
+ // getAppDetails — IAppResource
1074
+ { path: '/ui-api/apps/{appId}' },
1075
+ ];
1076
+ /**
1077
+ * Private UIAPI paths gated by the per-runtime private-endpoint gates: the
1078
+ * Connect resource carries a `UiTier` clientFilter (UI-tier callers only, not
1079
+ * the public REST API) and LDS invokes it via a Luvio adapter.
1080
+ */
1081
+ const UIAPI_PRIVATE_PATH_ENTRIES = [
1082
+ // ----- Record Avatars -----
1083
+ // getRecordAvatars (batch) — IRecordAvatarsBatchResource
1084
+ { path: '/ui-api/record-avatars/batch/{recordIds}' },
1085
+ // updateRecordAvatar (POST) — IRecordAvatarsAssociationResource
1086
+ { path: '/ui-api/record-avatars/{recordId}/association' },
1087
+ // ----- Layout -----
1088
+ // getLayoutUserState (GET) / updateLayoutUserState (PATCH) — ILayoutUserStateResource
1089
+ { path: '/ui-api/layout/{objectApiName}/user-state' },
1090
+ // ----- GraphQL -----
1091
+ // executeGraphQLBatch (POST) — IGraphQLBatchResource (no /ui-api prefix).
1092
+ // Query-only for the same reason as /graphql (parser rejects non-queries).
1093
+ { path: '/graphql/batch', retryableReadPost: true },
1094
+ // ----- Aggregate UI -----
1095
+ // executeAggregateUi (POST) — IAggregateUiResource
1096
+ { path: '/ui-api/aggregate-ui', retryableReadPost: true },
1097
+ ];
1098
+ /** Public transport paths, derived from the canonical registry above. */
1099
+ const UIAPI_PUBLIC_PATHS = UIAPI_PUBLIC_PATH_ENTRIES.map((entry) => entry.path);
1100
+ /** Private (gated) transport paths, derived from the canonical registry above. */
1101
+ const UIAPI_PRIVATE_PATHS = UIAPI_PRIVATE_PATH_ENTRIES.map((entry) => entry.path);
1102
+ /**
1103
+ * Compiles path templates into anchored matchers: each `{...}` placeholder
1104
+ * becomes `[^/]+` (one segment), anchored with `^`/`$`.
1105
+ */
1106
+ function compilePathMatchers(paths) {
1107
+ return paths.map((path) => new RegExp(`^${path.replace(/\{.+?\}/g, '[^/]+')}$`));
1108
+ }
1109
+ // The read-POST subset, precompiled once at module load from the same entries
1110
+ // so a retryable path is always also a registered transport path.
1111
+ const RETRYABLE_READ_POST_MATCHERS = compilePathMatchers([...UIAPI_PUBLIC_PATH_ENTRIES, ...UIAPI_PRIVATE_PATH_ENTRIES]
1112
+ .filter((entry) => entry.retryableReadPost)
1113
+ .map((entry) => entry.path));
1114
+ /**
1115
+ * True when the request path is a known read issued over POST (GraphQL,
1116
+ * aggregate-ui, search, …), so the Luvio throttling policy can replay it on
1117
+ * 429/503. Complements `isRetryableMethod` (GET). Normalizes the trailing slash
1118
+ * the same way the transport allowlist does before matching.
1119
+ */
1120
+ function isRetryableReadPost(basePath) {
1121
+ if (!basePath) {
1122
+ return false;
1123
+ }
1124
+ let path = basePath.trim();
1125
+ if (path.endsWith('/')) {
1126
+ path = path.substring(0, path.length - 1);
1127
+ }
1128
+ return RETRYABLE_READ_POST_MATCHERS.some((matcher) => matcher.test(path));
1129
+ }
1130
+
1131
+ /**
1132
+ * Extracts the HTTP method from FetchParameters, matching the Fetch API's own
1133
+ * precedence: an options.method override wins over a Request object's method
1134
+ * (e.g. `fetch(new Request(url, { method: 'GET' }), { method: 'POST' })`
1135
+ * resolves to `POST`).
1136
+ */
1137
+ function getFetchMethod([urlOrRequest, options]) {
1138
+ if (options && 'method' in options) {
1139
+ return options.method;
1140
+ }
1141
+ if (typeof urlOrRequest !== 'string' && 'method' in urlOrRequest) {
1142
+ return urlOrRequest.method;
1143
+ }
1144
+ return undefined;
1145
+ }
1146
+ /**
1147
+ * Only GET requests are safe to replay automatically on 429/503 — replaying a
1148
+ * write (POST/PUT/PATCH/DELETE) risks executing a mutation more than once.
1149
+ * Shared by both the Luvio and generic-fetch throttling retry policies so the
1150
+ * write-guard rule lives in exactly one place.
1151
+ */
1152
+ function isRetryableMethod(method) {
1153
+ return method?.toLowerCase() === 'get';
1154
+ }
1155
+ /**
1156
+ * A request whose operationType is `query` is a read, so it is safe to replay
1157
+ * automatically on 429/503 even when the transport uses a non-GET method (e.g.
1158
+ * a GraphQL/aggregate-ui read issued as a POST). This complements
1159
+ * `isRetryableMethod`: OneStore seeds the command's operationType into the
1160
+ * per-request context, and the throttling policy retries when either the method
1161
+ * is GET or the operationType is `query`. Only `query` is retryable — `mutation`
1162
+ * and an absent/`graphql` operationType are never replayed.
1163
+ */
1164
+ function isRetryableOperationType(operationType) {
1165
+ return operationType === 'query';
1166
+ }
1167
+ /**
1168
+ * Determines if the HTTP method requires CSRF protection.
1169
+ * Only mutating operations (POST, PUT, PATCH, DELETE) require CSRF tokens.
1170
+ */
1171
+ function isCsrfMethod(method) {
1172
+ if (!method) {
1173
+ return false;
1174
+ }
1175
+ const normalizedMethod = method.toLowerCase();
1176
+ return (normalizedMethod === 'post' ||
1177
+ normalizedMethod === 'put' ||
1178
+ normalizedMethod === 'patch' ||
1179
+ normalizedMethod === 'delete');
1180
+ }
1181
+
1182
+ export { UIAPI_PRIVATE_PATHS, UIAPI_PUBLIC_PATHS, compilePathMatchers, getFetchMethod, instrument, isCsrfMethod, isRetryableMethod, isRetryableOperationType, isRetryableReadPost, setupFetchNetworkAdapter, setupLexNetworkAdapter };
1183
+ // version: 1.458.0-5aef0572f2
@@ -0,0 +1,30 @@
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
+ * A request whose operationType is `query` is a read, so it is safe to replay
18
+ * automatically on 429/503 even when the transport uses a non-GET method (e.g.
19
+ * a GraphQL/aggregate-ui read issued as a POST). This complements
20
+ * `isRetryableMethod`: OneStore seeds the command's operationType into the
21
+ * per-request context, and the throttling policy retries when either the method
22
+ * is GET or the operationType is `query`. Only `query` is retryable — `mutation`
23
+ * and an absent/`graphql` operationType are never replayed.
24
+ */
25
+ export declare function isRetryableOperationType(operationType: string | undefined): boolean;
26
+ /**
27
+ * Determines if the HTTP method requires CSRF protection.
28
+ * Only mutating operations (POST, PUT, PATCH, DELETE) require CSRF tokens.
29
+ */
30
+ export declare function isCsrfMethod(method: string | undefined): boolean;
@@ -2,3 +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, isCsrfMethod, } from './http-utils';
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Canonical registry of the UIAPI url paths LDS sends over HTTP and their
3
+ * read/write nature — the single source of truth for every runtime's transport
4
+ * allowlist and read-POST retry classifier. A leaf module (no local imports) so
5
+ * both can consume it without an import cycle: `network-fetch.ts` imports the
6
+ * retry interceptor, so the retry layer must import paths from here, not back
7
+ * from `network-fetch.ts`. Templates use `{segment}` placeholders (see
8
+ * `compilePathMatchers`); callers normalize trailing slashes.
9
+ */
10
+ /** Public transport paths, derived from the canonical registry above. */
11
+ export declare const UIAPI_PUBLIC_PATHS: string[];
12
+ /** Private (gated) transport paths, derived from the canonical registry above. */
13
+ export declare const UIAPI_PRIVATE_PATHS: string[];
14
+ /**
15
+ * Compiles path templates into anchored matchers: each `{...}` placeholder
16
+ * becomes `[^/]+` (one segment), anchored with `^`/`$`.
17
+ */
18
+ export declare function compilePathMatchers(paths: string[]): RegExp[];
19
+ /**
20
+ * True when the request path is a known read issued over POST (GraphQL,
21
+ * aggregate-ui, search, …), so the Luvio throttling policy can replay it on
22
+ * 429/503. Complements `isRetryableMethod` (GET). Normalizes the trailing slash
23
+ * the same way the transport allowlist does before matching.
24
+ */
25
+ export declare function isRetryableReadPost(basePath: string | undefined): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/lds-network-fetch",
3
- "version": "1.457.0",
3
+ "version": "1.458.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,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.27.1",
37
38
  "@luvio/engine": "0.161.2",
38
39
  "@luvio/network-adapter-fetch": "0.161.2"
39
40
  },
40
41
  "devDependencies": {
41
- "@salesforce/lds-network-aura": "^1.457.0"
42
+ "@salesforce/lds-network-aura": "^1.458.0"
42
43
  },
43
44
  "volta": {
44
45
  "extends": "../../package.json"