@salesforce/lds-runtime-aura 1.459.0 → 1.461.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 +123 -2343
- package/dist/types/main.d.ts +7 -59
- package/package.json +41 -41
- package/dist/types/predictive-loading/common/index.d.ts +0 -17
- package/dist/types/predictive-loading/index.d.ts +0 -7
- package/dist/types/predictive-loading/lex/index.d.ts +0 -17
- package/dist/types/predictive-loading/lex/predictions-ready-manager.d.ts +0 -32
- package/dist/types/predictive-loading/pages/abstract-home-page.d.ts +0 -17
- package/dist/types/predictive-loading/pages/index.d.ts +0 -4
- package/dist/types/predictive-loading/pages/lex-default-page.d.ts +0 -15
- package/dist/types/predictive-loading/pages/object-home-page.d.ts +0 -23
- package/dist/types/predictive-loading/pages/predictive-prefetch-page.d.ts +0 -12
- package/dist/types/predictive-loading/pages/record-home-page.d.ts +0 -26
- package/dist/types/predictive-loading/prefetcher/events.d.ts +0 -25
- package/dist/types/predictive-loading/prefetcher/index.d.ts +0 -4
- package/dist/types/predictive-loading/prefetcher/lex-predictive-prefetcher.d.ts +0 -18
- package/dist/types/predictive-loading/prefetcher/predictive-prefetcher.d.ts +0 -38
- package/dist/types/predictive-loading/prefetcher/utils.d.ts +0 -52
- package/dist/types/predictive-loading/repository/index.d.ts +0 -2
- package/dist/types/predictive-loading/repository/prefetch-repository.d.ts +0 -31
- package/dist/types/predictive-loading/repository/utils.d.ts +0 -13
- package/dist/types/predictive-loading/request-runner/index.d.ts +0 -2
- package/dist/types/predictive-loading/request-runner/lex-request-runner.d.ts +0 -10
- package/dist/types/predictive-loading/request-runner/request-runner.d.ts +0 -5
- package/dist/types/predictive-loading/request-strategy/get-apex-request-strategy.d.ts +0 -30
- package/dist/types/predictive-loading/request-strategy/get-list-info-by-name-request-strategy.d.ts +0 -19
- package/dist/types/predictive-loading/request-strategy/get-list-infos-by-object-name-request-strategy.d.ts +0 -19
- package/dist/types/predictive-loading/request-strategy/get-list-object-info-request-strategy.d.ts +0 -18
- package/dist/types/predictive-loading/request-strategy/get-list-records-by-name-request-strategy.d.ts +0 -19
- package/dist/types/predictive-loading/request-strategy/get-object-info-request-strategy.d.ts +0 -26
- package/dist/types/predictive-loading/request-strategy/get-object-infos-request-strategy.d.ts +0 -25
- package/dist/types/predictive-loading/request-strategy/get-record-actions-request-strategy.d.ts +0 -20
- package/dist/types/predictive-loading/request-strategy/get-record-avatars-request-strategy.d.ts +0 -20
- package/dist/types/predictive-loading/request-strategy/get-record-request-strategy.d.ts +0 -26
- package/dist/types/predictive-loading/request-strategy/get-records-request-strategy.d.ts +0 -18
- package/dist/types/predictive-loading/request-strategy/get-related-list-actions-request-strategy.d.ts +0 -21
- package/dist/types/predictive-loading/request-strategy/get-related-list-info-batch-request-strategy.d.ts +0 -24
- package/dist/types/predictive-loading/request-strategy/get-related-list-info-request-strategy.d.ts +0 -50
- package/dist/types/predictive-loading/request-strategy/get-related-list-records-batch-request-strategy.d.ts +0 -32
- package/dist/types/predictive-loading/request-strategy/get-related-list-records-request-strategy.d.ts +0 -34
- package/dist/types/predictive-loading/request-strategy/get-related-lists-actions-request-strategy.d.ts +0 -28
- package/dist/types/predictive-loading/request-strategy/get-related-lists-info-strategy.d.ts +0 -30
- package/dist/types/predictive-loading/request-strategy/index.d.ts +0 -20
- package/dist/types/predictive-loading/request-strategy/lex-request-strategy.d.ts +0 -13
- package/dist/types/predictive-loading/request-strategy/luvio-adapter-request-strategy.d.ts +0 -27
- package/dist/types/predictive-loading/request-strategy/request-strategy.d.ts +0 -79
- package/dist/types/predictive-loading/request-strategy-manager/request-strategy-manager.d.ts +0 -12
- package/dist/types/predictive-loading/storage/aura-prefetch-storage.d.ts +0 -25
- package/dist/types/predictive-loading/storage/in-memory-prefetch-storage.d.ts +0 -6
- package/dist/types/predictive-loading/storage/index.d.ts +0 -8
- package/dist/types/predictive-loading/storage/local-prefetch-storage.d.ts +0 -7
package/dist/ldsEngineCreator.js
CHANGED
|
@@ -13,12 +13,8 @@
|
|
|
13
13
|
*/
|
|
14
14
|
/* proxy-compat-disable */
|
|
15
15
|
import { HttpStatusCode as HttpStatusCode$2, InMemoryStore, Environment, Luvio, InMemoryStoreQueryEvaluator } from 'force/luvioEngine';
|
|
16
|
-
import usePredictiveLoading from '@salesforce/gate/lds.usePredictiveLoading';
|
|
17
|
-
import useLocalStorage from '@salesforce/gate/lds.pdl.useLocalStorage';
|
|
18
16
|
import useOneStoreGraphql from '@salesforce/gate/lds.oneStoreGraphqlEnabled.ltng';
|
|
19
|
-
import
|
|
20
|
-
import { GetApexWireAdapterFactory, registerPrefetcher as registerPrefetcher$1 } from 'force/ldsAdaptersApex';
|
|
21
|
-
import { instrument, getRecordAvatarsAdapterFactory, getRecordAdapterFactory, coerceFieldIdArray, coerceLayoutTypeArray, coerceLayoutModeArray, getRecordsAdapterFactory, getRecordActionsAdapterFactory, getObjectInfosAdapterFactory, coerceObjectIdArray, getObjectInfoAdapterFactory, coerceObjectId, getRelatedListsActionsAdapterFactory, getRelatedListInfoBatchAdapterFactory, getRelatedListInfoAdapterFactory, getRelatedListRecordsBatchAdapterFactory, getRelatedListRecordsAdapterFactory, getListInfoByNameAdapterFactory, getListInfosByObjectNameAdapterFactory, getListRecordsByNameAdapterFactory, getListObjectInfoAdapterFactory, getRelatedListsInfoAdapterFactory, getRelatedListActionsAdapterFactory, getRecordId18Array, buildRecordRepKeyFromId, configuration, InMemoryRecordRepresentationQueryEvaluator, UiApiNamespace, RecordRepresentationRepresentationType, registerPrefetcher, RecordRepresentationVersion } from 'force/ldsAdaptersUiapi';
|
|
17
|
+
import { instrument, buildRecordRepKeyFromId, configuration, InMemoryRecordRepresentationQueryEvaluator, UiApiNamespace, RecordRepresentationRepresentationType, RecordRepresentationVersion } from 'force/ldsAdaptersUiapi';
|
|
22
18
|
import { getInstrumentation } from 'o11y/client';
|
|
23
19
|
import { findExecutableOperation, buildGraphQLInputExtension, addTypenameToDocument } from 'force/luvioGraphqlNormalization';
|
|
24
20
|
import { print, resolveAndValidateGraphQLConfig, toGraphQLErrorResponse } from 'force/luvioOnestoreGraphqlParser';
|
|
@@ -30,11 +26,10 @@ import { ThirdPartyTracker } from 'instrumentation:thirdPartyTracker';
|
|
|
30
26
|
import { markStart, markEnd, counter, registerCacheStats, perfStart, perfEnd, registerPeriodicLogger, interaction, timer, mark } from 'instrumentation/service';
|
|
31
27
|
import { instrument as instrument$2, isCsrfMethod, getFetchMethod, isRetryableMethod, isRetryableReadPost, compilePathMatchers, setupLexNetworkAdapter, UIAPI_PUBLIC_PATHS, UIAPI_PRIVATE_PATHS, isRetryableOperationType } from 'force/ldsNetworkFetch';
|
|
32
28
|
import { REFRESH_ADAPTER_EVENT, ADAPTER_UNFULFILLED_ERROR, instrument as instrument$3 } from 'force/ldsBindings';
|
|
33
|
-
import { stateManagerInstrumentation, OperationTypeValue, LRUCache, instrumentAdapter, instrumentLuvio, logMessage as logMessage$1, setupInstrumentation as setupInstrumentation$1, logObjectInfoChanged as logObjectInfoChanged$1, updatePercentileHistogramMetric, incrementCounterMetric, incrementGetRecordNotifyChangeAllowCount, incrementGetRecordNotifyChangeDropCount, incrementNotifyRecordUpdateAvailableAllowCount, incrementNotifyRecordUpdateAvailableDropCount, setLdsAdaptersUiapiInstrumentation, logError as logError$2, setLdsNetworkAdapterInstrumentation
|
|
29
|
+
import { stateManagerInstrumentation, OperationTypeValue, LRUCache, instrumentAdapter, instrumentLuvio, logMessage as logMessage$1, setupInstrumentation as setupInstrumentation$1, logObjectInfoChanged as logObjectInfoChanged$1, updatePercentileHistogramMetric, incrementCounterMetric, incrementGetRecordNotifyChangeAllowCount, incrementGetRecordNotifyChangeDropCount, incrementNotifyRecordUpdateAvailableAllowCount, incrementNotifyRecordUpdateAvailableDropCount, setLdsAdaptersUiapiInstrumentation, logError as logError$2, setLdsNetworkAdapterInstrumentation } from 'force/ldsInstrumentation';
|
|
34
30
|
import { instrument as instrument$4 } from 'force/adsBridge';
|
|
35
31
|
import { instrument as instrument$5 } from '@lwc/state';
|
|
36
32
|
import { withRegistration, register, setDefaultLuvio } from 'force/ldsEngine';
|
|
37
|
-
import applyPredictionRequestLimit from '@salesforce/gate/lds.pdl.applyRequestLimit';
|
|
38
33
|
import { pageScopedCache } from 'instrumentation/utility';
|
|
39
34
|
import lightningConnectEnabled from '@salesforce/gate/ui.services.LightningConnect.enabled';
|
|
40
35
|
import bypassAppRestrictionEnabled from '@salesforce/gate/ui.services.LightningConnect.BypassAppRestriction.enabled';
|
|
@@ -44,9 +39,8 @@ import useHttpUiapiOneRuntime from '@salesforce/gate/lds.useHttpUiapiOneRuntime'
|
|
|
44
39
|
import useHttpUiapiAuraSites from '@salesforce/gate/lds.usehttpuiapiaurasites';
|
|
45
40
|
import auraBasedRequestsEnabled from '@salesforce/gate/ui.services.auraBasedRequests.enabled';
|
|
46
41
|
import disableCreateContentDocumentAndVersionHTTPLexRuntime from '@salesforce/gate/lds.lex.http.disableCreateContentDocumentAndVersion';
|
|
47
|
-
import useHotspotLimit from '@salesforce/gate/lds.pdl.useHotspotLimit';
|
|
48
|
-
import { createStorage, clearStorages } from 'force/ldsDurableStorage';
|
|
49
42
|
import { registerSubRequestNetworkAdapter } from 'force/ldsNetwork';
|
|
43
|
+
import { clearStorages, createStorage } from 'force/ldsDurableStorage';
|
|
50
44
|
|
|
51
45
|
const { create: create$1, freeze, keys: keys$2, entries: entries$1 } = Object;
|
|
52
46
|
const { isArray: isArray$4 } = Array;
|
|
@@ -175,7 +169,7 @@ function rejectedPromiseLike$2(reason) {
|
|
|
175
169
|
function isPromiseLike$2(x) {
|
|
176
170
|
return typeof x?.then === "function";
|
|
177
171
|
}
|
|
178
|
-
function stableJSONStringify$
|
|
172
|
+
function stableJSONStringify$1(node) {
|
|
179
173
|
const withToJSON = node;
|
|
180
174
|
if (withToJSON && typeof withToJSON.toJSON === "function") {
|
|
181
175
|
node = withToJSON.toJSON();
|
|
@@ -197,7 +191,7 @@ function stableJSONStringify$2(node) {
|
|
|
197
191
|
if (i) {
|
|
198
192
|
out += ",";
|
|
199
193
|
}
|
|
200
|
-
out += stableJSONStringify$
|
|
194
|
+
out += stableJSONStringify$1(node[i]) || "null";
|
|
201
195
|
}
|
|
202
196
|
return out + "]";
|
|
203
197
|
}
|
|
@@ -209,7 +203,7 @@ function stableJSONStringify$2(node) {
|
|
|
209
203
|
out = "";
|
|
210
204
|
for (i = 0; i < objKeys.length; i++) {
|
|
211
205
|
const key = objKeys[i];
|
|
212
|
-
const value = stableJSONStringify$
|
|
206
|
+
const value = stableJSONStringify$1(record[key]);
|
|
213
207
|
if (!value) {
|
|
214
208
|
continue;
|
|
215
209
|
}
|
|
@@ -599,7 +593,7 @@ function rejectedPromiseLike$1(reason) {
|
|
|
599
593
|
function isPromiseLike$1(x) {
|
|
600
594
|
return typeof x?.then === "function";
|
|
601
595
|
}
|
|
602
|
-
function deepEquals
|
|
596
|
+
function deepEquals(x, y) {
|
|
603
597
|
if (x === void 0) {
|
|
604
598
|
return y === void 0;
|
|
605
599
|
} else if (x === null) {
|
|
@@ -611,7 +605,7 @@ function deepEquals$1(x, y) {
|
|
|
611
605
|
return false;
|
|
612
606
|
}
|
|
613
607
|
for (let i = 0; i < x.length; ++i) {
|
|
614
|
-
if (!deepEquals
|
|
608
|
+
if (!deepEquals(x[i], y[i])) {
|
|
615
609
|
return false;
|
|
616
610
|
}
|
|
617
611
|
}
|
|
@@ -627,7 +621,7 @@ function deepEquals$1(x, y) {
|
|
|
627
621
|
}
|
|
628
622
|
for (let i = 0; i < xkeys.length; ++i) {
|
|
629
623
|
const key = xkeys[i];
|
|
630
|
-
if (!deepEquals
|
|
624
|
+
if (!deepEquals(
|
|
631
625
|
x[key],
|
|
632
626
|
y[key]
|
|
633
627
|
)) {
|
|
@@ -908,7 +902,7 @@ class CacheControlCommand extends BaseCommand {
|
|
|
908
902
|
* @todo This should likely be abstract in v2. For v1, provide default comparison logic.
|
|
909
903
|
*/
|
|
910
904
|
equals(result1, result2) {
|
|
911
|
-
return deepEquals
|
|
905
|
+
return deepEquals(result1, result2);
|
|
912
906
|
}
|
|
913
907
|
/**
|
|
914
908
|
* Hook method called after a network request completes
|
|
@@ -2602,7 +2596,7 @@ function buildServiceDescriptor$d(luvio) {
|
|
|
2602
2596
|
},
|
|
2603
2597
|
};
|
|
2604
2598
|
}
|
|
2605
|
-
// version: 1.
|
|
2599
|
+
// version: 1.461.0-37b1c9d1cb
|
|
2606
2600
|
|
|
2607
2601
|
class AuraGraphQLNormalizedCacheControlCommand extends AuraNormalizedCacheControlCommand {
|
|
2608
2602
|
constructor(config, documentRootType, services) {
|
|
@@ -2941,7 +2935,7 @@ function buildServiceDescriptor$9(notifyRecordUpdateAvailable, getNormalizedLuvi
|
|
|
2941
2935
|
},
|
|
2942
2936
|
};
|
|
2943
2937
|
}
|
|
2944
|
-
// version: 1.
|
|
2938
|
+
// version: 1.461.0-37b1c9d1cb
|
|
2945
2939
|
|
|
2946
2940
|
class RetryService {
|
|
2947
2941
|
constructor(defaultRetryPolicy) {
|
|
@@ -4221,7 +4215,7 @@ function cacheKeyFor(params) {
|
|
|
4221
4215
|
if (params === void 0) {
|
|
4222
4216
|
return "jwt:";
|
|
4223
4217
|
}
|
|
4224
|
-
return `jwt:${stableJSONStringify$
|
|
4218
|
+
return `jwt:${stableJSONStringify$1(params) ?? ""}`;
|
|
4225
4219
|
}
|
|
4226
4220
|
let defaultLogger = {
|
|
4227
4221
|
trace: () => {
|
|
@@ -5250,7 +5244,7 @@ const { stringify: stringify$1 } = JSON;
|
|
|
5250
5244
|
* @param data Data to be JSON-stringified.
|
|
5251
5245
|
* @returns JSON.stringified value with consistent ordering of keys.
|
|
5252
5246
|
*/
|
|
5253
|
-
function stableJSONStringify
|
|
5247
|
+
function stableJSONStringify(node) {
|
|
5254
5248
|
// This is for Date values.
|
|
5255
5249
|
if (node && node.toJSON && typeof node.toJSON === 'function') {
|
|
5256
5250
|
// eslint-disable-next-line no-param-reassign
|
|
@@ -5276,7 +5270,7 @@ function stableJSONStringify$1(node) {
|
|
|
5276
5270
|
if (i) {
|
|
5277
5271
|
out += ',';
|
|
5278
5272
|
}
|
|
5279
|
-
out += stableJSONStringify
|
|
5273
|
+
out += stableJSONStringify(node[i]) || 'null';
|
|
5280
5274
|
}
|
|
5281
5275
|
return out + ']';
|
|
5282
5276
|
}
|
|
@@ -5287,7 +5281,7 @@ function stableJSONStringify$1(node) {
|
|
|
5287
5281
|
out = '';
|
|
5288
5282
|
for (i = 0; i < keys$1.length; i++) {
|
|
5289
5283
|
const key = keys$1[i];
|
|
5290
|
-
const value = stableJSONStringify
|
|
5284
|
+
const value = stableJSONStringify(node[key]);
|
|
5291
5285
|
if (!value) {
|
|
5292
5286
|
continue;
|
|
5293
5287
|
}
|
|
@@ -5422,7 +5416,7 @@ class Instrumentation {
|
|
|
5422
5416
|
* @param ttl TTL for the wire adapter.
|
|
5423
5417
|
*/
|
|
5424
5418
|
logAdapterCacheMissOutOfTtlDuration(name, config, ttlMissStats, currentCacheMissTimestamp, ttl) {
|
|
5425
|
-
const configKey = `${name}:${stableJSONStringify
|
|
5419
|
+
const configKey = `${name}:${stableJSONStringify(config)}`;
|
|
5426
5420
|
const existingCacheMissTimestamp = this.adapterCacheMisses.get(configKey);
|
|
5427
5421
|
this.adapterCacheMisses.set(configKey, currentCacheMissTimestamp);
|
|
5428
5422
|
if (existingCacheMissTimestamp !== undefined) {
|
|
@@ -5947,7 +5941,7 @@ function getEnvironmentSetting(name) {
|
|
|
5947
5941
|
}
|
|
5948
5942
|
return undefined;
|
|
5949
5943
|
}
|
|
5950
|
-
// version: 1.
|
|
5944
|
+
// version: 1.461.0-55ae54e753
|
|
5951
5945
|
|
|
5952
5946
|
const auraClientService = getAuraClientService();
|
|
5953
5947
|
const defaultConfig = {
|
|
@@ -5968,11 +5962,6 @@ if (auraClientService?.maxAllowedParallelXHRCounts) {
|
|
|
5968
5962
|
config.forceRecordTransactionsDisabled = getEnvironmentSetting(EnvironmentSettings.ForceRecordTransactionsDisabled);
|
|
5969
5963
|
});
|
|
5970
5964
|
}
|
|
5971
|
-
if (!applyPredictionRequestLimit.isOpen({ fallback: false })) {
|
|
5972
|
-
configService.set('lex', (config) => {
|
|
5973
|
-
config.maxAllowedParallelXHRCounts = 1000;
|
|
5974
|
-
});
|
|
5975
|
-
}
|
|
5976
5965
|
|
|
5977
5966
|
const forceRecordTransactionsDisabled = configService.config.forceRecordTransactionsDisabled;
|
|
5978
5967
|
//TODO: Some duplication here that can be most likely moved to a util class
|
|
@@ -7883,2186 +7872,116 @@ function buildGuardedLegacyJwtRequestInterceptor(logger) {
|
|
|
7883
7872
|
return (args) => hasAuthorizationHeader(args) ? resolvedPromiseLike$2(args) : legacyInterceptor(args);
|
|
7884
7873
|
}
|
|
7885
7874
|
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
class PredictivePrefetchPage {
|
|
7892
|
-
constructor(context, similarContext) {
|
|
7893
|
-
this.context = context;
|
|
7894
|
-
this.similarContext = similarContext;
|
|
7895
|
-
}
|
|
7896
|
-
getExactKey() {
|
|
7897
|
-
return { ...this.context };
|
|
7898
|
-
}
|
|
7899
|
-
getSimilarKey() {
|
|
7900
|
-
return { ...this.similarContext };
|
|
7901
|
-
}
|
|
7902
|
-
}
|
|
7903
|
-
|
|
7904
|
-
class LexDefaultPage extends PredictivePrefetchPage {
|
|
7905
|
-
constructor(context, similarContext) {
|
|
7906
|
-
super(context, similarContext);
|
|
7907
|
-
}
|
|
7908
|
-
supportsRequest(_request) {
|
|
7909
|
-
return true;
|
|
7910
|
-
}
|
|
7911
|
-
buildSaveRequestData(request) {
|
|
7912
|
-
return [{ key: this.getExactKey(), request }];
|
|
7913
|
-
}
|
|
7914
|
-
resolveSimilarRequest(similarRequest) {
|
|
7915
|
-
return similarRequest;
|
|
7916
|
-
}
|
|
7917
|
-
getAlwaysRunRequests() {
|
|
7918
|
-
return [];
|
|
7919
|
-
}
|
|
7920
|
-
shouldReduceAlwaysRequestsWithPredictions() {
|
|
7921
|
-
return true;
|
|
7922
|
-
}
|
|
7923
|
-
shouldExecuteAlwaysRequestByThemself() {
|
|
7924
|
-
return false;
|
|
7875
|
+
class NoComposedAdapterTypeError extends TypeError {
|
|
7876
|
+
constructor(message, resourceRequest) {
|
|
7877
|
+
super(message);
|
|
7878
|
+
this.resourceRequest = resourceRequest;
|
|
7925
7879
|
}
|
|
7926
7880
|
}
|
|
7927
7881
|
|
|
7928
|
-
|
|
7929
|
-
|
|
7930
|
-
(
|
|
7931
|
-
|
|
7932
|
-
|
|
7933
|
-
PdlRequestPriority[PdlRequestPriority["HIGH"] = 2] = "HIGH";
|
|
7934
|
-
})(PdlRequestPriority || (PdlRequestPriority = {}));
|
|
7935
|
-
class RequestStrategy {
|
|
7936
|
-
getRequestPriority(_request, _context) {
|
|
7937
|
-
return 1 /* RequestPriority.NORMAL */;
|
|
7938
|
-
}
|
|
7939
|
-
/**
|
|
7940
|
-
* Perform any transformations required to prepare the request for saving.
|
|
7941
|
-
*
|
|
7942
|
-
* e.g. If the request is for a record, we move all fields in the fields array
|
|
7943
|
-
* into the optionalFields array
|
|
7944
|
-
*
|
|
7945
|
-
* @param request - The request to transform
|
|
7946
|
-
* @returns
|
|
7947
|
-
*/
|
|
7948
|
-
transformForSave(request, _context) {
|
|
7949
|
-
return request;
|
|
7950
|
-
}
|
|
7951
|
-
/**
|
|
7952
|
-
* Transforms the request for saving similar requests
|
|
7953
|
-
* @param request Request to transform for saving similar requests
|
|
7954
|
-
* @returns Transformed request
|
|
7955
|
-
*/
|
|
7956
|
-
transformForSaveSimilarRequest(request, _context) {
|
|
7957
|
-
return this.transformForSave(request, _context);
|
|
7958
|
-
}
|
|
7959
|
-
/**
|
|
7960
|
-
* Filter requests to only those that are for this strategy.
|
|
7961
|
-
*
|
|
7962
|
-
* @param unfilteredRequests array of requests to filter
|
|
7963
|
-
* @returns
|
|
7964
|
-
*/
|
|
7965
|
-
filterRequests(unfilteredRequests) {
|
|
7966
|
-
return unfilteredRequests.filter((entry) => entry.request.adapterName === this.adapterName);
|
|
7967
|
-
}
|
|
7968
|
-
/**
|
|
7969
|
-
* Reduce requests by combining those based on a strategies implementations
|
|
7970
|
-
* of canCombine and combineRequests.
|
|
7971
|
-
* @param unfilteredRequests array of requests to filter
|
|
7972
|
-
* @returns
|
|
7973
|
-
*/
|
|
7974
|
-
reduce(unfilteredRequests) {
|
|
7975
|
-
const requests = this.filterRequests(unfilteredRequests);
|
|
7976
|
-
const visitedRequests = new Set();
|
|
7977
|
-
const reducedRequests = [];
|
|
7978
|
-
for (let i = 0, n = requests.length; i < n; i++) {
|
|
7979
|
-
const currentRequest = requests[i];
|
|
7980
|
-
if (!visitedRequests.has(currentRequest)) {
|
|
7981
|
-
const combinedRequest = { ...currentRequest };
|
|
7982
|
-
for (let j = i + 1; j < n; j++) {
|
|
7983
|
-
const hasNotBeenVisited = !visitedRequests.has(requests[j]);
|
|
7984
|
-
const canCombineConfigs = this.canCombine(combinedRequest.request.config, requests[j].request.config);
|
|
7985
|
-
if (hasNotBeenVisited && canCombineConfigs) {
|
|
7986
|
-
combinedRequest.request.config = this.combineRequests(combinedRequest.request.config, requests[j].request.config);
|
|
7987
|
-
if (combinedRequest.requestMetadata.requestTime >
|
|
7988
|
-
requests[j].requestMetadata.requestTime) {
|
|
7989
|
-
// This logic is debateable - Currently this always assigns the lowest requestTime to a reduced request.
|
|
7990
|
-
combinedRequest.requestMetadata.requestTime =
|
|
7991
|
-
requests[j].requestMetadata.requestTime;
|
|
7992
|
-
}
|
|
7993
|
-
visitedRequests.add(requests[j]);
|
|
7994
|
-
}
|
|
7995
|
-
}
|
|
7996
|
-
reducedRequests.push(combinedRequest);
|
|
7997
|
-
visitedRequests.add(currentRequest);
|
|
7998
|
-
}
|
|
7999
|
-
}
|
|
8000
|
-
return reducedRequests;
|
|
8001
|
-
}
|
|
8002
|
-
/**
|
|
8003
|
-
* Check if two requests can be combined.
|
|
8004
|
-
*
|
|
8005
|
-
* By default, requests are not combinable.
|
|
8006
|
-
* @param reqA config of request A
|
|
8007
|
-
* @param reqB config of request B
|
|
8008
|
-
* @returns
|
|
8009
|
-
*/
|
|
8010
|
-
canCombine(_reqA, _reqB) {
|
|
8011
|
-
return false;
|
|
8012
|
-
}
|
|
8013
|
-
/**
|
|
8014
|
-
* Takes two request configs and combines them into a single request config.
|
|
8015
|
-
*
|
|
8016
|
-
* @param reqA config of request A
|
|
8017
|
-
* @param reqB config of request B
|
|
8018
|
-
* @returns
|
|
8019
|
-
*/
|
|
8020
|
-
combineRequests(reqA, _reqB) {
|
|
8021
|
-
// By default, this should never be called since requests aren't combinable
|
|
8022
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
8023
|
-
throw new Error('Not implemented');
|
|
7882
|
+
function buildComposableNetworkAdapter(composedAdapters) {
|
|
7883
|
+
return (resourceRequest, resourceRequestContext) => {
|
|
7884
|
+
const composedAdapter = composedAdapters.find((adapter) => adapter.shouldHandleRequest(resourceRequest));
|
|
7885
|
+
if (composedAdapter === undefined) {
|
|
7886
|
+
throw new NoComposedAdapterTypeError('There are no network adapters that can process the request.', resourceRequest);
|
|
8024
7887
|
}
|
|
8025
|
-
return
|
|
8026
|
-
}
|
|
8027
|
-
/**
|
|
8028
|
-
* Checks adapter config against request context to determine if the request is context dependent.
|
|
8029
|
-
*
|
|
8030
|
-
* By default, requests are not context dependent.
|
|
8031
|
-
* @param request
|
|
8032
|
-
* @returns
|
|
8033
|
-
*/
|
|
8034
|
-
isContextDependent(_context, _request) {
|
|
8035
|
-
return false;
|
|
8036
|
-
}
|
|
7888
|
+
return composedAdapter.adapter(resourceRequest, resourceRequestContext);
|
|
7889
|
+
};
|
|
8037
7890
|
}
|
|
8038
7891
|
|
|
8039
|
-
|
|
8040
|
-
|
|
8041
|
-
|
|
8042
|
-
|
|
8043
|
-
|
|
8044
|
-
|
|
8045
|
-
|
|
8046
|
-
*/
|
|
8047
|
-
get isBoxcarable() {
|
|
8048
|
-
return true;
|
|
7892
|
+
function getComposedAdapters() {
|
|
7893
|
+
const composedAdapters = [
|
|
7894
|
+
composedNetworkAdapter$1, // SFAP adapter
|
|
7895
|
+
];
|
|
7896
|
+
// Add the UIAPI Fetch adapter if any of its API paths are enabled
|
|
7897
|
+
if (isFetchAdapterEnabled()) {
|
|
7898
|
+
composedAdapters.push(composedFetchNetworkAdapter); // UIAPI Fetch adapter
|
|
8049
7899
|
}
|
|
7900
|
+
return composedAdapters;
|
|
8050
7901
|
}
|
|
8051
|
-
|
|
8052
|
-
|
|
8053
|
-
|
|
8054
|
-
|
|
8055
|
-
|
|
8056
|
-
|
|
8057
|
-
background: false,
|
|
8058
|
-
hotspot: true,
|
|
8059
|
-
longRunning: false,
|
|
7902
|
+
const composedNetworkAdapter = buildComposableNetworkAdapter([
|
|
7903
|
+
...getComposedAdapters(),
|
|
7904
|
+
// The aura network adapter must be the default.
|
|
7905
|
+
{
|
|
7906
|
+
shouldHandleRequest() {
|
|
7907
|
+
return true;
|
|
8060
7908
|
},
|
|
7909
|
+
adapter: auraNetworkAdapter,
|
|
8061
7910
|
},
|
|
8062
|
-
|
|
8063
|
-
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
this.luvio = luvio;
|
|
8067
|
-
}
|
|
8068
|
-
execute(config, options = {}) {
|
|
8069
|
-
return this.adapterFactory(this.luvio)(config, this.createAdapterContext(options));
|
|
8070
|
-
}
|
|
8071
|
-
createAdapterContext(options) {
|
|
8072
|
-
return {
|
|
8073
|
-
...DEFAULT_RESOURCE_CONTEXT,
|
|
8074
|
-
sourceContext: {
|
|
8075
|
-
...DEFAULT_RESOURCE_CONTEXT.sourceContext,
|
|
8076
|
-
actionConfig: {
|
|
8077
|
-
...DEFAULT_RESOURCE_CONTEXT.sourceContext.actionConfig,
|
|
8078
|
-
hotspot: !options.disableHotspot,
|
|
8079
|
-
},
|
|
8080
|
-
},
|
|
8081
|
-
};
|
|
8082
|
-
}
|
|
8083
|
-
}
|
|
8084
|
-
|
|
8085
|
-
const GET_RECORD_AVATARS_ADAPTER_NAME = 'getRecordAvatars';
|
|
8086
|
-
function normalizeRecordIds$1(recordIds) {
|
|
8087
|
-
if (!Array.isArray(recordIds)) {
|
|
8088
|
-
return [recordIds];
|
|
8089
|
-
}
|
|
8090
|
-
return recordIds;
|
|
8091
|
-
}
|
|
8092
|
-
class GetRecordAvatarsRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
8093
|
-
constructor() {
|
|
8094
|
-
super(...arguments);
|
|
8095
|
-
this.adapterName = GET_RECORD_AVATARS_ADAPTER_NAME;
|
|
8096
|
-
this.adapterFactory = getRecordAvatarsAdapterFactory;
|
|
8097
|
-
}
|
|
8098
|
-
buildConcreteRequest(similarRequest, context) {
|
|
8099
|
-
return {
|
|
8100
|
-
...similarRequest,
|
|
8101
|
-
config: {
|
|
8102
|
-
...similarRequest.config,
|
|
8103
|
-
recordIds: [context.recordId],
|
|
8104
|
-
},
|
|
8105
|
-
};
|
|
8106
|
-
}
|
|
8107
|
-
transformForSaveSimilarRequest(request) {
|
|
8108
|
-
return this.transformForSave({
|
|
8109
|
-
...request,
|
|
8110
|
-
config: {
|
|
8111
|
-
...request.config,
|
|
8112
|
-
recordIds: ['*'],
|
|
8113
|
-
},
|
|
8114
|
-
});
|
|
8115
|
-
}
|
|
8116
|
-
isContextDependent(context, request) {
|
|
8117
|
-
return (request.config.recordIds &&
|
|
8118
|
-
(context.recordId === request.config.recordIds || // some may set this as string instead of array
|
|
8119
|
-
(request.config.recordIds.length === 1 &&
|
|
8120
|
-
request.config.recordIds[0] === context.recordId)));
|
|
8121
|
-
}
|
|
8122
|
-
canCombine(reqA, reqB) {
|
|
8123
|
-
return reqA.formFactor === reqB.formFactor;
|
|
8124
|
-
}
|
|
8125
|
-
combineRequests(reqA, reqB) {
|
|
8126
|
-
const combined = { ...reqA };
|
|
8127
|
-
combined.recordIds = Array.from(new Set([...normalizeRecordIds$1(reqA.recordIds), ...normalizeRecordIds$1(reqB.recordIds)]));
|
|
8128
|
-
return combined;
|
|
8129
|
-
}
|
|
8130
|
-
}
|
|
7911
|
+
]);
|
|
7912
|
+
// Route dispatcher-synthesized sub-requests (e.g. aggregate-ui) back through
|
|
7913
|
+
// the composed adapter so shouldHandleRequest and interceptors apply uniformly.
|
|
7914
|
+
registerSubRequestNetworkAdapter(composedNetworkAdapter);
|
|
8131
7915
|
|
|
8132
|
-
const
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
const normilizedLayoutTypesA = coerceLayoutTypeArray(reqA.layoutTypes) || [];
|
|
8152
|
-
const normilizedLayoutTypesB = coerceLayoutTypeArray(reqB.layoutTypes) || [];
|
|
8153
|
-
// Let's only combine when the layoutTypes are the same
|
|
8154
|
-
return (isCombinableLayoutRequest(reqA) &&
|
|
8155
|
-
isCombinableLayoutRequest(reqB) &&
|
|
8156
|
-
reqA.recordId === reqB.recordId &&
|
|
8157
|
-
normilizedLayoutTypesA.length === normilizedLayoutTypesB.length &&
|
|
8158
|
-
normilizedLayoutTypesA.every((type, index) => type === normilizedLayoutTypesB[index]));
|
|
8159
|
-
}
|
|
8160
|
-
class GetRecordRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
8161
|
-
constructor(luvio, canCombineRecordLayoutRequests = false) {
|
|
8162
|
-
super(luvio);
|
|
8163
|
-
this.canCombineRecordLayoutRequests = canCombineRecordLayoutRequests;
|
|
8164
|
-
this.adapterName = GET_RECORD_ADAPTER_NAME;
|
|
8165
|
-
this.adapterFactory = getRecordAdapterFactory;
|
|
8166
|
-
}
|
|
8167
|
-
buildConcreteRequest(similarRequest, context) {
|
|
8168
|
-
return {
|
|
8169
|
-
...similarRequest,
|
|
8170
|
-
config: {
|
|
8171
|
-
...similarRequest.config,
|
|
8172
|
-
recordId: context.recordId,
|
|
8173
|
-
},
|
|
8174
|
-
};
|
|
8175
|
-
}
|
|
8176
|
-
transformForSave(request) {
|
|
8177
|
-
if (request.config.fields === undefined && request.config.optionalFields === undefined) {
|
|
8178
|
-
return request;
|
|
8179
|
-
}
|
|
8180
|
-
let fields = coerceFieldIdArray(request.config.fields, COERCE_FIELD_ID_ARRAY_OPTIONS) || [];
|
|
8181
|
-
let optionalFields = coerceFieldIdArray(request.config.optionalFields, COERCE_FIELD_ID_ARRAY_OPTIONS) || [];
|
|
8182
|
-
return {
|
|
8183
|
-
...request,
|
|
8184
|
-
config: {
|
|
8185
|
-
...request.config,
|
|
8186
|
-
fields: undefined,
|
|
8187
|
-
optionalFields: [...fields, ...optionalFields],
|
|
8188
|
-
},
|
|
8189
|
-
};
|
|
8190
|
-
}
|
|
8191
|
-
canCombine(reqA, reqB) {
|
|
8192
|
-
// must be same record and either both are fields requests or both are combinable layout requests
|
|
8193
|
-
return (reqA.recordId === reqB.recordId &&
|
|
8194
|
-
((isFieldsRequest(reqA) && isFieldsRequest(reqB)) ||
|
|
8195
|
-
(this.canCombineRecordLayoutRequests && areCombinableLayoutRequests(reqA, reqB))));
|
|
8196
|
-
}
|
|
8197
|
-
combineRequests(reqA, reqB) {
|
|
8198
|
-
if (isFieldsRequest(reqA)) {
|
|
8199
|
-
return this.combineFieldsRequests(reqA, reqB);
|
|
8200
|
-
}
|
|
8201
|
-
else {
|
|
8202
|
-
return this.combineLayoutRequests(reqA, reqB);
|
|
8203
|
-
}
|
|
8204
|
-
}
|
|
8205
|
-
combineLayoutRequests(reqA, reqB) {
|
|
8206
|
-
const combined = {
|
|
8207
|
-
recordId: reqA.recordId,
|
|
8208
|
-
layoutTypes: coerceLayoutTypeArray(reqA.layoutTypes),
|
|
8209
|
-
};
|
|
8210
|
-
// combine Modes.
|
|
8211
|
-
// Note: the || ['View'] is important; it is to cover the case in which it needs to
|
|
8212
|
-
// combine mode: undefined (defaults to View) with mode: ['something else than View']
|
|
8213
|
-
const modeA = coerceLayoutModeArray(reqA.modes) || ['View'];
|
|
8214
|
-
const modeB = coerceLayoutModeArray(reqB.modes) || ['View'];
|
|
8215
|
-
if (reqA.modes !== undefined || reqB.modes !== undefined) {
|
|
8216
|
-
combined.modes = Array.from(new Set([...modeA, ...modeB]));
|
|
8217
|
-
}
|
|
8218
|
-
// combine Optional Fields.
|
|
8219
|
-
const optionalFieldsA = coerceFieldIdArray(reqA.optionalFields, COERCE_FIELD_ID_ARRAY_OPTIONS) || [];
|
|
8220
|
-
const optionalFieldsB = coerceFieldIdArray(reqB.optionalFields, COERCE_FIELD_ID_ARRAY_OPTIONS) || [];
|
|
8221
|
-
if (optionalFieldsA !== undefined || optionalFieldsB !== undefined) {
|
|
8222
|
-
combined.optionalFields = Array.from(new Set([...optionalFieldsA, ...optionalFieldsB]));
|
|
8223
|
-
}
|
|
8224
|
-
return combined;
|
|
8225
|
-
}
|
|
8226
|
-
combineFieldsRequests(reqA, reqB) {
|
|
8227
|
-
const fields = new Set();
|
|
8228
|
-
const optionalFields = new Set();
|
|
8229
|
-
if (reqA.fields !== undefined) {
|
|
8230
|
-
reqA.fields.forEach((field) => fields.add(field));
|
|
8231
|
-
}
|
|
8232
|
-
if (reqB.fields !== undefined) {
|
|
8233
|
-
reqB.fields.forEach((field) => fields.add(field));
|
|
8234
|
-
}
|
|
8235
|
-
if (reqA.optionalFields !== undefined) {
|
|
8236
|
-
reqA.optionalFields.forEach((field) => optionalFields.add(field));
|
|
8237
|
-
}
|
|
8238
|
-
if (reqB.optionalFields !== undefined) {
|
|
8239
|
-
reqB.optionalFields.forEach((field) => optionalFields.add(field));
|
|
7916
|
+
const OBJECT_INFO_PREFIX = 'UiApi::ObjectInfoRepresentation:';
|
|
7917
|
+
/**
|
|
7918
|
+
* Watch a Luvio instance for metadata changes.
|
|
7919
|
+
*/
|
|
7920
|
+
function setupMetadataWatcher(luvio) {
|
|
7921
|
+
// Watch for object info changes. Since we don't have enough information to understand to which
|
|
7922
|
+
// extent an object info change may impact the application the only thing we do is to clear all
|
|
7923
|
+
// the persistent storages.
|
|
7924
|
+
luvio.storeWatch(OBJECT_INFO_PREFIX, (entries) => {
|
|
7925
|
+
for (let i = 0, len = entries.length; i < len; i++) {
|
|
7926
|
+
const entry = entries[i];
|
|
7927
|
+
const isObjectInfoUpdated = entry.inserted === false;
|
|
7928
|
+
if (isObjectInfoUpdated) {
|
|
7929
|
+
logObjectInfoChanged();
|
|
7930
|
+
clearStorages().catch(() => {
|
|
7931
|
+
/* noop */
|
|
7932
|
+
});
|
|
7933
|
+
break;
|
|
7934
|
+
}
|
|
8240
7935
|
}
|
|
8241
|
-
|
|
8242
|
-
recordId: reqA.recordId,
|
|
8243
|
-
fields: Array.from(fields),
|
|
8244
|
-
optionalFields: Array.from(optionalFields),
|
|
8245
|
-
};
|
|
8246
|
-
}
|
|
8247
|
-
isContextDependent(context, request) {
|
|
8248
|
-
return request.config.recordId === context.recordId;
|
|
8249
|
-
}
|
|
8250
|
-
transformForSaveSimilarRequest(request) {
|
|
8251
|
-
return this.transformForSave({
|
|
8252
|
-
...request,
|
|
8253
|
-
config: {
|
|
8254
|
-
...request.config,
|
|
8255
|
-
recordId: '*',
|
|
8256
|
-
},
|
|
8257
|
-
});
|
|
8258
|
-
}
|
|
8259
|
-
}
|
|
8260
|
-
|
|
8261
|
-
const GET_RECORDS_ADAPTER_NAME = 'getRecords';
|
|
8262
|
-
class GetRecordsRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
8263
|
-
constructor() {
|
|
8264
|
-
super(...arguments);
|
|
8265
|
-
this.adapterName = GET_RECORDS_ADAPTER_NAME;
|
|
8266
|
-
this.adapterFactory = getRecordsAdapterFactory;
|
|
8267
|
-
}
|
|
8268
|
-
buildConcreteRequest(similarRequest, context) {
|
|
8269
|
-
return {
|
|
8270
|
-
...similarRequest,
|
|
8271
|
-
config: {
|
|
8272
|
-
...similarRequest.config,
|
|
8273
|
-
records: [{ ...similarRequest.config.records[0], recordIds: [context.recordId] }],
|
|
8274
|
-
},
|
|
8275
|
-
};
|
|
8276
|
-
}
|
|
8277
|
-
isContextDependent(context, request) {
|
|
8278
|
-
const isSingleRecordRequest = request.config.records.length === 1 && request.config.records[0].recordIds.length === 1;
|
|
8279
|
-
return isSingleRecordRequest && request.config.records[0].recordIds[0] === context.recordId;
|
|
8280
|
-
}
|
|
8281
|
-
transformForSaveSimilarRequest(request) {
|
|
8282
|
-
return this.transformForSave({
|
|
8283
|
-
...request,
|
|
8284
|
-
config: {
|
|
8285
|
-
...request.config,
|
|
8286
|
-
records: [
|
|
8287
|
-
{
|
|
8288
|
-
...request.config.records[0],
|
|
8289
|
-
recordIds: ['*'],
|
|
8290
|
-
},
|
|
8291
|
-
],
|
|
8292
|
-
},
|
|
8293
|
-
});
|
|
8294
|
-
}
|
|
7936
|
+
});
|
|
8295
7937
|
}
|
|
8296
7938
|
|
|
8297
|
-
|
|
8298
|
-
function normalizeRecordIds(recordIds) {
|
|
8299
|
-
if (!isArray(recordIds)) {
|
|
8300
|
-
return [recordIds];
|
|
8301
|
-
}
|
|
8302
|
-
return recordIds;
|
|
7939
|
+
class CacheInclusionPolicyService {
|
|
8303
7940
|
}
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
|
|
7941
|
+
class Ok {
|
|
7942
|
+
constructor(value) {
|
|
7943
|
+
this.value = value;
|
|
7944
|
+
}
|
|
7945
|
+
isOk() {
|
|
7946
|
+
return true;
|
|
7947
|
+
}
|
|
7948
|
+
isErr() {
|
|
7949
|
+
return !this.isOk();
|
|
7950
|
+
}
|
|
8309
7951
|
}
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
buildConcreteRequest(similarRequest, context) {
|
|
8317
|
-
return {
|
|
8318
|
-
...similarRequest,
|
|
8319
|
-
config: {
|
|
8320
|
-
...similarRequest.config,
|
|
8321
|
-
recordIds: [context.recordId],
|
|
8322
|
-
},
|
|
8323
|
-
};
|
|
8324
|
-
}
|
|
8325
|
-
transformForSaveSimilarRequest(request) {
|
|
8326
|
-
return this.transformForSave({
|
|
8327
|
-
...request,
|
|
8328
|
-
config: {
|
|
8329
|
-
...request.config,
|
|
8330
|
-
recordIds: ['*'],
|
|
8331
|
-
},
|
|
8332
|
-
});
|
|
8333
|
-
}
|
|
8334
|
-
canCombine(reqA, reqB) {
|
|
8335
|
-
return (reqA.retrievalMode === reqB.retrievalMode &&
|
|
8336
|
-
reqA.formFactor === reqB.formFactor &&
|
|
8337
|
-
(reqA.actionTypes || []).toString() === (reqB.actionTypes || []).toString() &&
|
|
8338
|
-
(reqA.sections || []).toString() === (reqB.sections || []).toString());
|
|
8339
|
-
}
|
|
8340
|
-
combineRequests(reqA, reqB) {
|
|
8341
|
-
const combined = { ...reqA };
|
|
8342
|
-
// let's merge the recordIds
|
|
8343
|
-
combined.recordIds = Array.from(new Set([...normalizeRecordIds(reqA.recordIds), ...normalizeRecordIds(reqB.recordIds)]));
|
|
8344
|
-
if (combined.retrievalMode === 'ALL') {
|
|
8345
|
-
const combinedSet = new Set([
|
|
8346
|
-
...normalizeApiNames(combined.apiNames),
|
|
8347
|
-
...normalizeApiNames(reqB.apiNames),
|
|
8348
|
-
]);
|
|
8349
|
-
combined.apiNames = Array.from(combinedSet);
|
|
8350
|
-
}
|
|
8351
|
-
return combined;
|
|
8352
|
-
}
|
|
8353
|
-
isContextDependent(context, request) {
|
|
8354
|
-
return (request.config.recordIds &&
|
|
8355
|
-
(context.recordId === request.config.recordIds || // some may set this as string instead of array
|
|
8356
|
-
(request.config.recordIds.length === 1 &&
|
|
8357
|
-
request.config.recordIds[0] === context.recordId)));
|
|
7952
|
+
const ok = (value) => new Ok(value);
|
|
7953
|
+
function setDifference(setA, setB) {
|
|
7954
|
+
const differenceSet = /* @__PURE__ */ new Set();
|
|
7955
|
+
for (const element of setA) {
|
|
7956
|
+
if (!setB.has(element)) {
|
|
7957
|
+
differenceSet.add(element);
|
|
8358
7958
|
}
|
|
7959
|
+
}
|
|
7960
|
+
return differenceSet;
|
|
8359
7961
|
}
|
|
8360
|
-
|
|
8361
|
-
const
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
* @param a
|
|
8365
|
-
* @param b
|
|
8366
|
-
*/
|
|
8367
|
-
function isSuperSet(a, b) {
|
|
8368
|
-
return b.every((oan) => a.has(oan));
|
|
7962
|
+
function addAllToSet(targetSet, sourceSet) {
|
|
7963
|
+
for (const element of sourceSet) {
|
|
7964
|
+
targetSet.add(element);
|
|
7965
|
+
}
|
|
8369
7966
|
}
|
|
8370
|
-
|
|
8371
|
-
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
...request.config,
|
|
8384
|
-
// (!): if we are saving this request is because the adapter already verified is valid.
|
|
8385
|
-
objectApiNames: coerceObjectIdArray(request.config.objectApiNames),
|
|
8386
|
-
},
|
|
8387
|
-
};
|
|
8388
|
-
}
|
|
8389
|
-
/**
|
|
8390
|
-
* Reduces the given GetObjectInfosRequest requests by eliminating those for which config.objectApiNames
|
|
8391
|
-
* is a subset of another GetObjectInfosRequest.
|
|
8392
|
-
*
|
|
8393
|
-
* @param unfilteredRequests - Array of unfiltered requests
|
|
8394
|
-
* @returns RequestEntry<GetObjectInfosRequest>[] - Array of reduced requests
|
|
8395
|
-
*/
|
|
8396
|
-
reduce(unfilteredRequests) {
|
|
8397
|
-
// Filter and sort requests by the length of objectApiNames in ascending order.
|
|
8398
|
-
// This ensures a superset of request (i) can only be found in a request (j) such that i < j.
|
|
8399
|
-
const objectInfosRequests = this.filterRequests(unfilteredRequests).sort((a, b) => a.request.config.objectApiNames.length - b.request.config.objectApiNames.length);
|
|
8400
|
-
// Convert request configurations to sets for easier comparison, avoiding a new set construction each iteration.
|
|
8401
|
-
const requestConfigAsSet = objectInfosRequests.map((r) => new Set(r.request.config.objectApiNames));
|
|
8402
|
-
const reducedRequests = [];
|
|
8403
|
-
// Iterate over each request to determine if it is a subset of others
|
|
8404
|
-
for (let i = 0, n = objectInfosRequests.length; i < n; i++) {
|
|
8405
|
-
const current = objectInfosRequests[i];
|
|
8406
|
-
const { request: { config: currentRequestConfig }, requestMetadata: currentRequestMetadata, } = current;
|
|
8407
|
-
let isCurrentSubsetOfOthers = false;
|
|
8408
|
-
// Check if the current request is a subset of any subsequent requests
|
|
8409
|
-
for (let j = i + 1; j < n; j++) {
|
|
8410
|
-
const possibleSuperset = objectInfosRequests[j];
|
|
8411
|
-
if (isSuperSet(requestConfigAsSet[j], currentRequestConfig.objectApiNames)) {
|
|
8412
|
-
isCurrentSubsetOfOthers = true;
|
|
8413
|
-
if (currentRequestMetadata.requestTime <
|
|
8414
|
-
possibleSuperset.requestMetadata.requestTime) {
|
|
8415
|
-
possibleSuperset.requestMetadata.requestTime =
|
|
8416
|
-
currentRequestMetadata.requestTime;
|
|
8417
|
-
}
|
|
8418
|
-
}
|
|
8419
|
-
}
|
|
8420
|
-
if (!isCurrentSubsetOfOthers) {
|
|
8421
|
-
reducedRequests.push(current);
|
|
8422
|
-
}
|
|
7967
|
+
function resolvedPromiseLike(result) {
|
|
7968
|
+
if (isPromiseLike(result)) {
|
|
7969
|
+
return result.then(
|
|
7970
|
+
(nextResult) => nextResult
|
|
7971
|
+
);
|
|
7972
|
+
}
|
|
7973
|
+
return {
|
|
7974
|
+
then: (onFulfilled, _onRejected) => {
|
|
7975
|
+
try {
|
|
7976
|
+
return resolvedPromiseLike(onFulfilled(result));
|
|
7977
|
+
} catch (e) {
|
|
7978
|
+
if (onFulfilled === void 0) {
|
|
7979
|
+
return resolvedPromiseLike(result);
|
|
8423
7980
|
}
|
|
8424
|
-
return
|
|
7981
|
+
return rejectedPromiseLike(e);
|
|
7982
|
+
}
|
|
8425
7983
|
}
|
|
8426
|
-
}
|
|
8427
|
-
|
|
8428
|
-
const GET_OBJECT_INFO_ADAPTER_NAME = 'getObjectInfo';
|
|
8429
|
-
class GetObjectInfoRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
8430
|
-
constructor() {
|
|
8431
|
-
super(...arguments);
|
|
8432
|
-
this.adapterName = GET_OBJECT_INFO_ADAPTER_NAME;
|
|
8433
|
-
this.adapterFactory = getObjectInfoAdapterFactory;
|
|
8434
|
-
}
|
|
8435
|
-
buildConcreteRequest(similarRequest, context) {
|
|
8436
|
-
return {
|
|
8437
|
-
...similarRequest,
|
|
8438
|
-
config: {
|
|
8439
|
-
...similarRequest.config,
|
|
8440
|
-
objectApiName: context.objectApiName,
|
|
8441
|
-
},
|
|
8442
|
-
};
|
|
8443
|
-
}
|
|
8444
|
-
transformForSave(request) {
|
|
8445
|
-
return {
|
|
8446
|
-
...request,
|
|
8447
|
-
config: {
|
|
8448
|
-
...request.config,
|
|
8449
|
-
// (!): if we are saving this request is because the adapter already verified is valid.
|
|
8450
|
-
objectApiName: coerceObjectId(request.config.objectApiName),
|
|
8451
|
-
},
|
|
8452
|
-
};
|
|
8453
|
-
}
|
|
8454
|
-
isContextDependent(context, request) {
|
|
8455
|
-
return (request.config.objectApiName !== undefined &&
|
|
8456
|
-
context.objectApiName === request.config.objectApiName);
|
|
8457
|
-
}
|
|
8458
|
-
/**
|
|
8459
|
-
* This method returns GetObjectInfoRequest[] that won't be part of a batch (getObjectInfos) request.
|
|
8460
|
-
*
|
|
8461
|
-
* @param unfilteredRequests all prediction requests
|
|
8462
|
-
* @returns
|
|
8463
|
-
*/
|
|
8464
|
-
reduce(unfilteredRequests) {
|
|
8465
|
-
const objectApiNamesInBatchRequest = unfilteredRequests.filter((entry) => entry.request.adapterName === GET_OBJECT_INFO_BATCH_ADAPTER_NAME).reduce((acc, { request }) => {
|
|
8466
|
-
request.config.objectApiNames.forEach((apiName) => acc.add(apiName));
|
|
8467
|
-
return acc;
|
|
8468
|
-
}, new Set());
|
|
8469
|
-
const singleRequests = this.filterRequests(unfilteredRequests);
|
|
8470
|
-
return singleRequests.filter((singleEntry) => {
|
|
8471
|
-
return !objectApiNamesInBatchRequest.has(singleEntry.request.config.objectApiName);
|
|
8472
|
-
});
|
|
8473
|
-
}
|
|
8474
|
-
}
|
|
8475
|
-
|
|
8476
|
-
const GET_RELATED_LISTS_ACTIONS_ADAPTER_NAME = 'getRelatedListsActions';
|
|
8477
|
-
function isReduceAbleRelatedListConfig(config) {
|
|
8478
|
-
return config.relatedListsActionParameters.every((rlReq) => {
|
|
8479
|
-
return rlReq.relatedListId !== undefined && keys(rlReq).length === 1;
|
|
8480
|
-
});
|
|
8481
|
-
}
|
|
8482
|
-
class GetRelatedListsActionsRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
8483
|
-
constructor() {
|
|
8484
|
-
super(...arguments);
|
|
8485
|
-
this.adapterName = GET_RELATED_LISTS_ACTIONS_ADAPTER_NAME;
|
|
8486
|
-
this.adapterFactory = getRelatedListsActionsAdapterFactory;
|
|
8487
|
-
}
|
|
8488
|
-
buildConcreteRequest(similarRequest, context) {
|
|
8489
|
-
return {
|
|
8490
|
-
...similarRequest,
|
|
8491
|
-
config: {
|
|
8492
|
-
...similarRequest.config,
|
|
8493
|
-
recordIds: [context.recordId],
|
|
8494
|
-
},
|
|
8495
|
-
};
|
|
8496
|
-
}
|
|
8497
|
-
transformForSaveSimilarRequest(request) {
|
|
8498
|
-
return this.transformForSave({
|
|
8499
|
-
...request,
|
|
8500
|
-
config: {
|
|
8501
|
-
...request.config,
|
|
8502
|
-
recordIds: ['*'],
|
|
8503
|
-
},
|
|
8504
|
-
});
|
|
8505
|
-
}
|
|
8506
|
-
isContextDependent(context, request) {
|
|
8507
|
-
const isForContext = request.config.recordIds &&
|
|
8508
|
-
(context.recordId === request.config.recordIds || // some may set this as string instead of array
|
|
8509
|
-
(request.config.recordIds.length === 1 &&
|
|
8510
|
-
request.config.recordIds[0] === context.recordId));
|
|
8511
|
-
return isForContext && isReduceAbleRelatedListConfig(request.config);
|
|
8512
|
-
}
|
|
8513
|
-
/**
|
|
8514
|
-
* Can only reduce two requests when they have the same recordId, and
|
|
8515
|
-
* the individual relatedListAction config only have relatedListId.
|
|
8516
|
-
*
|
|
8517
|
-
* @param reqA
|
|
8518
|
-
* @param reqB
|
|
8519
|
-
* @returns boolean
|
|
8520
|
-
*/
|
|
8521
|
-
canCombine(reqA, reqB) {
|
|
8522
|
-
const [recordIdA, recordIdB] = [reqA.recordIds, reqB.recordIds].map((recordIds) => {
|
|
8523
|
-
return isArray(recordIds)
|
|
8524
|
-
? recordIds.length === 1
|
|
8525
|
-
? recordIds[0]
|
|
8526
|
-
: null
|
|
8527
|
-
: recordIds;
|
|
8528
|
-
});
|
|
8529
|
-
return (recordIdA === recordIdB &&
|
|
8530
|
-
recordIdA !== null &&
|
|
8531
|
-
isReduceAbleRelatedListConfig(reqA) &&
|
|
8532
|
-
isReduceAbleRelatedListConfig(reqB));
|
|
8533
|
-
}
|
|
8534
|
-
combineRequests(reqA, reqB) {
|
|
8535
|
-
const relatedListsIncluded = new Set();
|
|
8536
|
-
[reqA, reqB].forEach(({ relatedListsActionParameters }) => {
|
|
8537
|
-
relatedListsActionParameters.forEach(({ relatedListId }) => relatedListsIncluded.add(relatedListId));
|
|
8538
|
-
});
|
|
8539
|
-
return {
|
|
8540
|
-
recordIds: reqA.recordIds,
|
|
8541
|
-
relatedListsActionParameters: from(relatedListsIncluded).map((relatedListId) => ({
|
|
8542
|
-
relatedListId,
|
|
8543
|
-
})),
|
|
8544
|
-
};
|
|
8545
|
-
}
|
|
8546
|
-
}
|
|
8547
|
-
|
|
8548
|
-
const GET_RELATED_LIST_INFO_BATCH_ADAPTER_NAME = 'getRelatedListInfoBatch';
|
|
8549
|
-
class GetRelatedListInfoBatchRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
8550
|
-
constructor() {
|
|
8551
|
-
super(...arguments);
|
|
8552
|
-
this.adapterName = GET_RELATED_LIST_INFO_BATCH_ADAPTER_NAME;
|
|
8553
|
-
this.adapterFactory = getRelatedListInfoBatchAdapterFactory;
|
|
8554
|
-
}
|
|
8555
|
-
buildConcreteRequest(similarRequest, _context) {
|
|
8556
|
-
return similarRequest;
|
|
8557
|
-
}
|
|
8558
|
-
/**
|
|
8559
|
-
* @override
|
|
8560
|
-
*/
|
|
8561
|
-
transformForSave(request) {
|
|
8562
|
-
return {
|
|
8563
|
-
...request,
|
|
8564
|
-
config: {
|
|
8565
|
-
...request.config,
|
|
8566
|
-
parentObjectApiName: coerceObjectId(request.config.parentObjectApiName),
|
|
8567
|
-
},
|
|
8568
|
-
};
|
|
8569
|
-
}
|
|
8570
|
-
isContextDependent(context, request) {
|
|
8571
|
-
// We have a higher degree of confidence of being able to use a similar request when
|
|
8572
|
-
// optional config is not set AND the object type of the page context is the same as the
|
|
8573
|
-
// object type related list is for. This approach is based heavily with early predictions
|
|
8574
|
-
// and the max of 12 aura requests in mind. Same approach is taken in the single version of
|
|
8575
|
-
// this request
|
|
8576
|
-
return (context.objectApiName === request.config.parentObjectApiName &&
|
|
8577
|
-
request.config.recordTypeId === undefined);
|
|
8578
|
-
}
|
|
8579
|
-
canCombine(reqA, reqB) {
|
|
8580
|
-
return reqA.parentObjectApiName === reqB.parentObjectApiName;
|
|
8581
|
-
}
|
|
8582
|
-
combineRequests(reqA, reqB) {
|
|
8583
|
-
const combined = { ...reqA };
|
|
8584
|
-
combined.relatedListNames = Array.from(new Set([...reqA.relatedListNames, ...reqB.relatedListNames]));
|
|
8585
|
-
return combined;
|
|
8586
|
-
}
|
|
8587
|
-
}
|
|
8588
|
-
|
|
8589
|
-
const GET_RELATED_LIST_INFO_ADAPTER_NAME = 'getRelatedListInfo';
|
|
8590
|
-
class GetRelatedListInfoRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
8591
|
-
constructor() {
|
|
8592
|
-
super(...arguments);
|
|
8593
|
-
this.adapterName = GET_RELATED_LIST_INFO_ADAPTER_NAME;
|
|
8594
|
-
this.adapterFactory = getRelatedListInfoAdapterFactory;
|
|
8595
|
-
}
|
|
8596
|
-
/**
|
|
8597
|
-
* @override
|
|
8598
|
-
*/
|
|
8599
|
-
isContextDependent(context, request) {
|
|
8600
|
-
// We have a higher degree of confidence of being able to use a similar request when
|
|
8601
|
-
// optional config is not set AND the object type of the page context is the same as the
|
|
8602
|
-
// object type related list is for. This approach is based heavily with early predictions
|
|
8603
|
-
// and the max of 12 aura requests in mind. Same approach is taken in the batch version of
|
|
8604
|
-
// this request
|
|
8605
|
-
return (context.objectApiName === request.config.parentObjectApiName &&
|
|
8606
|
-
this.isRequiredOnlyConfig(request.config));
|
|
8607
|
-
}
|
|
8608
|
-
/**
|
|
8609
|
-
* @override
|
|
8610
|
-
*/
|
|
8611
|
-
buildConcreteRequest(similarRequest, _context) {
|
|
8612
|
-
return similarRequest;
|
|
8613
|
-
}
|
|
8614
|
-
/**
|
|
8615
|
-
* @override
|
|
8616
|
-
*/
|
|
8617
|
-
transformForSave(request) {
|
|
8618
|
-
return {
|
|
8619
|
-
...request,
|
|
8620
|
-
config: {
|
|
8621
|
-
...request.config,
|
|
8622
|
-
parentObjectApiName: coerceObjectId(request.config.parentObjectApiName),
|
|
8623
|
-
},
|
|
8624
|
-
};
|
|
8625
|
-
}
|
|
8626
|
-
/**
|
|
8627
|
-
* For performance reasons (fear of over-fetching), we only want to predict single requests which either are not
|
|
8628
|
-
* part of a batch request OR specify optional parameters (thus requiring data differing from that of a batch
|
|
8629
|
-
* request).
|
|
8630
|
-
*
|
|
8631
|
-
* ADG currently handles the batching of getRelatedListInfo -> getRelatedListInfoBatch
|
|
8632
|
-
* https://gitcore.soma.salesforce.com/core-2206/core-public/blob/p4/main/core/ui-laf-components/modules/laf/batchingPortable/reducers/RelatedListInfoBatchReducer.js
|
|
8633
|
-
*
|
|
8634
|
-
* @param unfilteredRequests
|
|
8635
|
-
* @returns GetRelatedListInfoRequest[]
|
|
8636
|
-
* @override
|
|
8637
|
-
*/
|
|
8638
|
-
reduce(unfilteredRequests) {
|
|
8639
|
-
// using batch versions of request, map keys of parent record to values of related lists
|
|
8640
|
-
const batchRequests = unfilteredRequests.filter((entry) => entry.request.adapterName === GET_RELATED_LIST_INFO_BATCH_ADAPTER_NAME).reduce((result, entry) => {
|
|
8641
|
-
// pull batch request parameters that correspond to single request parameters
|
|
8642
|
-
const { parentObjectApiName, relatedListNames, recordTypeId } = entry.request.config;
|
|
8643
|
-
// key based off of parent object and its type
|
|
8644
|
-
const key = `${parentObjectApiName}_${recordTypeId}`;
|
|
8645
|
-
// make sure an entry exists for the record
|
|
8646
|
-
const relatedListIds = result.get(key) || new Set();
|
|
8647
|
-
result.set(key, relatedListIds);
|
|
8648
|
-
// add each related list to values for the record
|
|
8649
|
-
relatedListNames.forEach((list) => relatedListIds.add(list));
|
|
8650
|
-
return result;
|
|
8651
|
-
}, new Map());
|
|
8652
|
-
// return only the single requests that will NOT be covered by a batch request
|
|
8653
|
-
return this.filterRequests(unfilteredRequests).filter((entry) => {
|
|
8654
|
-
const config = entry.request.config;
|
|
8655
|
-
if (!this.isRequiredOnlyConfig(config, true)) {
|
|
8656
|
-
// requested data is customized beyond default; batch may not cover, so keep single request
|
|
8657
|
-
return true;
|
|
8658
|
-
}
|
|
8659
|
-
// key based off of parent object and its type
|
|
8660
|
-
const key = `${config.parentObjectApiName}_${config.recordTypeId}`;
|
|
8661
|
-
// keep only the lists that are not batched
|
|
8662
|
-
const batchLists = batchRequests.get(key);
|
|
8663
|
-
return !(batchLists && batchLists.has(config.relatedListId));
|
|
8664
|
-
});
|
|
8665
|
-
}
|
|
8666
|
-
/**
|
|
8667
|
-
* Return true if the request config doesn't specify values for any of the optional parameters.
|
|
8668
|
-
*
|
|
8669
|
-
* @param config
|
|
8670
|
-
* @param ignoreRecordType
|
|
8671
|
-
*/
|
|
8672
|
-
isRequiredOnlyConfig(config, ignoreRecordType = false) {
|
|
8673
|
-
return ((ignoreRecordType || config.recordTypeId === undefined) &&
|
|
8674
|
-
(config.fields || []).length === 0 &&
|
|
8675
|
-
(config.optionalFields || []).length === 0 &&
|
|
8676
|
-
config.restrictColumnsToLayout !== false // default is true
|
|
8677
|
-
);
|
|
8678
|
-
}
|
|
8679
|
-
}
|
|
8680
|
-
|
|
8681
|
-
// Copy-pasted from adapter-utils. This util should be extracted from generated code and imported in prefetch repository.
|
|
8682
|
-
/**
|
|
8683
|
-
* A deterministic JSON stringify implementation. Heavily adapted from https://github.com/epoberezkin/fast-json-stable-stringify.
|
|
8684
|
-
* This is needed because insertion order for JSON.stringify(object) affects output:
|
|
8685
|
-
* JSON.stringify({a: 1, b: 2})
|
|
8686
|
-
* "{"a":1,"b":2}"
|
|
8687
|
-
* JSON.stringify({b: 2, a: 1})
|
|
8688
|
-
* "{"b":2,"a":1}"
|
|
8689
|
-
* @param data Data to be JSON-stringified.
|
|
8690
|
-
* @returns JSON.stringified value with consistent ordering of keys.
|
|
8691
|
-
*/
|
|
8692
|
-
function stableJSONStringify(node) {
|
|
8693
|
-
// This is for Date values.
|
|
8694
|
-
if (node && node.toJSON && typeof node.toJSON === 'function') {
|
|
8695
|
-
// eslint-disable-next-line no-param-reassign
|
|
8696
|
-
node = node.toJSON();
|
|
8697
|
-
}
|
|
8698
|
-
if (node === undefined) {
|
|
8699
|
-
return;
|
|
8700
|
-
}
|
|
8701
|
-
if (typeof node === 'number') {
|
|
8702
|
-
return isFinite(node) ? '' + node : 'null';
|
|
8703
|
-
}
|
|
8704
|
-
if (typeof node !== 'object') {
|
|
8705
|
-
return stringify$1(node);
|
|
8706
|
-
}
|
|
8707
|
-
let i;
|
|
8708
|
-
let out;
|
|
8709
|
-
if (isArray(node)) {
|
|
8710
|
-
out = '[';
|
|
8711
|
-
for (i = 0; i < node.length; i++) {
|
|
8712
|
-
if (i) {
|
|
8713
|
-
out += ',';
|
|
8714
|
-
}
|
|
8715
|
-
out += stableJSONStringify(node[i]) || 'null';
|
|
8716
|
-
}
|
|
8717
|
-
return out + ']';
|
|
8718
|
-
}
|
|
8719
|
-
if (node === null) {
|
|
8720
|
-
return 'null';
|
|
8721
|
-
}
|
|
8722
|
-
const keys$1 = keys(node).sort();
|
|
8723
|
-
out = '';
|
|
8724
|
-
for (i = 0; i < keys$1.length; i++) {
|
|
8725
|
-
const key = keys$1[i];
|
|
8726
|
-
const value = stableJSONStringify(node[key]);
|
|
8727
|
-
if (!value) {
|
|
8728
|
-
continue;
|
|
8729
|
-
}
|
|
8730
|
-
if (out) {
|
|
8731
|
-
out += ',';
|
|
8732
|
-
}
|
|
8733
|
-
out += stringify$1(key) + ':' + value;
|
|
8734
|
-
}
|
|
8735
|
-
return '{' + out + '}';
|
|
8736
|
-
}
|
|
8737
|
-
function isObject(obj) {
|
|
8738
|
-
return obj !== null && typeof obj === 'object';
|
|
8739
|
-
}
|
|
8740
|
-
function deepEquals(objA, objB) {
|
|
8741
|
-
if (objA === objB)
|
|
8742
|
-
return true;
|
|
8743
|
-
if (objA instanceof Date && objB instanceof Date)
|
|
8744
|
-
return objA.getTime() === objB.getTime();
|
|
8745
|
-
// If one of them is not an object, they are not deeply equal
|
|
8746
|
-
if (!isObject(objA) || !isObject(objB))
|
|
8747
|
-
return false;
|
|
8748
|
-
// Filter out keys set as undefined, we can compare undefined as equals.
|
|
8749
|
-
const keysA = keys(objA).filter((key) => objA[key] !== undefined);
|
|
8750
|
-
const keysB = keys(objB).filter((key) => objB[key] !== undefined);
|
|
8751
|
-
// If the objects do not have the same set of keys, they are not deeply equal
|
|
8752
|
-
if (keysA.length !== keysB.length)
|
|
8753
|
-
return false;
|
|
8754
|
-
for (const key of keysA) {
|
|
8755
|
-
const valA = objA[key];
|
|
8756
|
-
const valB = objB[key];
|
|
8757
|
-
const areObjects = isObject(valA) && isObject(valB);
|
|
8758
|
-
// If both values are objects, recursively compare them
|
|
8759
|
-
if (areObjects && !deepEquals(valA, valB))
|
|
8760
|
-
return false;
|
|
8761
|
-
// If only one value is an object or if the values are not strictly equal, they are not deeply equal
|
|
8762
|
-
if (!areObjects && valA !== valB)
|
|
8763
|
-
return false;
|
|
8764
|
-
}
|
|
8765
|
-
return true;
|
|
8766
|
-
}
|
|
8767
|
-
|
|
8768
|
-
class PrefetchRepository {
|
|
8769
|
-
constructor(storage, options = {}) {
|
|
8770
|
-
this.storage = storage;
|
|
8771
|
-
this.options = options;
|
|
8772
|
-
this.requestBuffer = new Map();
|
|
8773
|
-
this.pageStartTime = Date.now();
|
|
8774
|
-
}
|
|
8775
|
-
clearRequestBuffer() {
|
|
8776
|
-
this.requestBuffer.clear();
|
|
8777
|
-
}
|
|
8778
|
-
markPageStart() {
|
|
8779
|
-
this.pageStartTime = Date.now();
|
|
8780
|
-
}
|
|
8781
|
-
async flushRequestsToStorage() {
|
|
8782
|
-
const setPromises = [];
|
|
8783
|
-
for (const [id, batch] of this.requestBuffer) {
|
|
8784
|
-
const page = { id, requests: [] };
|
|
8785
|
-
batch.forEach(({ request, requestTime }) => {
|
|
8786
|
-
const existingRequestEntry = page.requests.find(({ request: storedRequest }) => deepEquals(storedRequest, request));
|
|
8787
|
-
if (existingRequestEntry === undefined) {
|
|
8788
|
-
page.requests.push({
|
|
8789
|
-
request,
|
|
8790
|
-
requestMetadata: {
|
|
8791
|
-
requestTime,
|
|
8792
|
-
},
|
|
8793
|
-
});
|
|
8794
|
-
}
|
|
8795
|
-
else if (requestTime < existingRequestEntry.requestMetadata.requestTime) {
|
|
8796
|
-
existingRequestEntry.requestMetadata.requestTime = requestTime;
|
|
8797
|
-
}
|
|
8798
|
-
});
|
|
8799
|
-
const { modifyBeforeSaveHook, modifyPageBeforeSavingHook } = this.options;
|
|
8800
|
-
if (modifyBeforeSaveHook !== undefined) {
|
|
8801
|
-
page.requests = modifyBeforeSaveHook(page.requests);
|
|
8802
|
-
}
|
|
8803
|
-
if (modifyPageBeforeSavingHook !== undefined) {
|
|
8804
|
-
modifyPageBeforeSavingHook(page);
|
|
8805
|
-
}
|
|
8806
|
-
setPromises.push(this.storage.set(id, page));
|
|
8807
|
-
}
|
|
8808
|
-
this.clearRequestBuffer();
|
|
8809
|
-
await Promise.all(setPromises);
|
|
8810
|
-
}
|
|
8811
|
-
getKeyId(key) {
|
|
8812
|
-
return stableJSONStringify(key);
|
|
8813
|
-
}
|
|
8814
|
-
saveRequest(key, request) {
|
|
8815
|
-
const identifier = this.getKeyId(key);
|
|
8816
|
-
const batchForKey = this.requestBuffer.get(identifier) || [];
|
|
8817
|
-
batchForKey.push({
|
|
8818
|
-
request,
|
|
8819
|
-
requestTime: Date.now() - this.pageStartTime,
|
|
8820
|
-
});
|
|
8821
|
-
this.requestBuffer.set(identifier, batchForKey);
|
|
8822
|
-
}
|
|
8823
|
-
getPage(key) {
|
|
8824
|
-
const identifier = this.getKeyId(key);
|
|
8825
|
-
return this.storage.get(identifier);
|
|
8826
|
-
}
|
|
8827
|
-
getPageRequests(key) {
|
|
8828
|
-
if (!key) {
|
|
8829
|
-
return [];
|
|
8830
|
-
}
|
|
8831
|
-
const page = this.getPage(key);
|
|
8832
|
-
if (page === undefined) {
|
|
8833
|
-
return [];
|
|
8834
|
-
}
|
|
8835
|
-
return page.requests;
|
|
8836
|
-
}
|
|
8837
|
-
}
|
|
8838
|
-
|
|
8839
|
-
const GET_RELATED_LIST_RECORDS_BATCH_ADAPTER_NAME = 'getRelatedListRecordsBatch';
|
|
8840
|
-
class GetRelatedListRecordsBatchRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
8841
|
-
constructor() {
|
|
8842
|
-
super(...arguments);
|
|
8843
|
-
this.adapterName = GET_RELATED_LIST_RECORDS_BATCH_ADAPTER_NAME;
|
|
8844
|
-
this.adapterFactory = getRelatedListRecordsBatchAdapterFactory;
|
|
8845
|
-
}
|
|
8846
|
-
buildConcreteRequest(similarRequest, context) {
|
|
8847
|
-
return {
|
|
8848
|
-
...similarRequest,
|
|
8849
|
-
config: {
|
|
8850
|
-
...similarRequest.config,
|
|
8851
|
-
parentRecordId: context.recordId,
|
|
8852
|
-
},
|
|
8853
|
-
};
|
|
8854
|
-
}
|
|
8855
|
-
transformForSaveSimilarRequest(request) {
|
|
8856
|
-
return this.transformForSave({
|
|
8857
|
-
...request,
|
|
8858
|
-
config: {
|
|
8859
|
-
...request.config,
|
|
8860
|
-
parentRecordId: '*',
|
|
8861
|
-
},
|
|
8862
|
-
});
|
|
8863
|
-
}
|
|
8864
|
-
isContextDependent(context, request) {
|
|
8865
|
-
return context.recordId === request.config.parentRecordId;
|
|
8866
|
-
}
|
|
8867
|
-
/**
|
|
8868
|
-
* Can combine two seperate batch requests if the parentRecordId is the same.
|
|
8869
|
-
* @param reqA The first GetRelatedListRecordsBatchConfig.
|
|
8870
|
-
* @param reqB The first GetRelatedListRecordsBatchConfig.
|
|
8871
|
-
* @returns true if the requests can be combined, otherwise false.
|
|
8872
|
-
*/
|
|
8873
|
-
canCombine(reqA, reqB) {
|
|
8874
|
-
return reqA.parentRecordId === reqB.parentRecordId;
|
|
8875
|
-
}
|
|
8876
|
-
/**
|
|
8877
|
-
* Merge the relatedListParameters together between two combinable batch requests.
|
|
8878
|
-
* @param reqA The first GetRelatedListRecordsBatchConfig.
|
|
8879
|
-
* @param reqB The first GetRelatedListRecordsBatchConfig.
|
|
8880
|
-
* @returns The combined request.
|
|
8881
|
-
*/
|
|
8882
|
-
combineRequests(reqA, reqB) {
|
|
8883
|
-
const relatedListParametersMap = new Set(reqA.relatedListParameters.map((relatedListParameter) => {
|
|
8884
|
-
return stableJSONStringify(relatedListParameter);
|
|
8885
|
-
}));
|
|
8886
|
-
const reqBRelatedListParametersToAdd = reqB.relatedListParameters.filter((relatedListParameter) => {
|
|
8887
|
-
return !relatedListParametersMap.has(stableJSONStringify(relatedListParameter));
|
|
8888
|
-
});
|
|
8889
|
-
reqA.relatedListParameters = reqA.relatedListParameters.concat(reqBRelatedListParametersToAdd);
|
|
8890
|
-
return reqA;
|
|
8891
|
-
}
|
|
8892
|
-
}
|
|
8893
|
-
|
|
8894
|
-
const GET_RELATED_LIST_RECORDS_ADAPTER_NAME = 'getRelatedListRecords';
|
|
8895
|
-
class GetRelatedListRecordsRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
8896
|
-
constructor() {
|
|
8897
|
-
super(...arguments);
|
|
8898
|
-
this.adapterName = GET_RELATED_LIST_RECORDS_ADAPTER_NAME;
|
|
8899
|
-
this.adapterFactory = getRelatedListRecordsAdapterFactory;
|
|
8900
|
-
}
|
|
8901
|
-
buildConcreteRequest(similarRequest, context) {
|
|
8902
|
-
return {
|
|
8903
|
-
...similarRequest,
|
|
8904
|
-
config: {
|
|
8905
|
-
...similarRequest.config,
|
|
8906
|
-
parentRecordId: context.recordId,
|
|
8907
|
-
},
|
|
8908
|
-
};
|
|
8909
|
-
}
|
|
8910
|
-
/**
|
|
8911
|
-
*
|
|
8912
|
-
* This method returns GetRelatedListRecordsRequest[] that won't be part of a batch request.
|
|
8913
|
-
*
|
|
8914
|
-
* ADG currently handles the batching of GetRelatedListRecords -> GetRelatedListRecordsBatch
|
|
8915
|
-
* https://gitcore.soma.salesforce.com/core-2206/core-public/blob/p4/main/core/ui-laf-components/modules/laf/batchingPortable/reducers/RelatedListRecordsBatchReducer.js
|
|
8916
|
-
*
|
|
8917
|
-
* For performance reasons (fear to overfetch), we only check that the Single relatedListId is not present in any of the Batch requests,
|
|
8918
|
-
* but we don't check for any other parameters.
|
|
8919
|
-
*
|
|
8920
|
-
* @param unfilteredRequests All of the request available for predictions.
|
|
8921
|
-
* @returns GetRelatedListRecordsRequest[] That should be a prediction.
|
|
8922
|
-
*/
|
|
8923
|
-
reduce(unfilteredRequests) {
|
|
8924
|
-
// Batch requests by [parentRecordId]->[RelatedListIds]
|
|
8925
|
-
const batchRequests = unfilteredRequests.filter((entry) => entry.request.adapterName === GET_RELATED_LIST_RECORDS_BATCH_ADAPTER_NAME).reduce((acc, entry) => {
|
|
8926
|
-
// required properties, enforced by adapter typecheck
|
|
8927
|
-
const { parentRecordId, relatedListParameters } = entry.request.config;
|
|
8928
|
-
const existingRlSet = acc.get(parentRecordId) || new Set();
|
|
8929
|
-
// relatedListId enforced by adapter typecheck
|
|
8930
|
-
relatedListParameters.forEach((rlParam) => existingRlSet.add(rlParam.relatedListId));
|
|
8931
|
-
acc.set(parentRecordId, existingRlSet);
|
|
8932
|
-
return acc;
|
|
8933
|
-
}, new Map());
|
|
8934
|
-
const singleRequests = unfilteredRequests.filter((entry) => entry.request.adapterName === this.adapterName);
|
|
8935
|
-
return singleRequests.filter((entry) => {
|
|
8936
|
-
// required props enforced by adapter typecheck
|
|
8937
|
-
const { parentRecordId, relatedListId } = entry.request.config;
|
|
8938
|
-
const batchForParentRecordId = batchRequests.get(parentRecordId);
|
|
8939
|
-
return !(batchForParentRecordId && batchForParentRecordId.has(relatedListId));
|
|
8940
|
-
});
|
|
8941
|
-
}
|
|
8942
|
-
transformForSaveSimilarRequest(request) {
|
|
8943
|
-
return this.transformForSave({
|
|
8944
|
-
...request,
|
|
8945
|
-
config: {
|
|
8946
|
-
...request.config,
|
|
8947
|
-
parentRecordId: '*',
|
|
8948
|
-
},
|
|
8949
|
-
});
|
|
8950
|
-
}
|
|
8951
|
-
isContextDependent(context, request) {
|
|
8952
|
-
return context.recordId === request.config.parentRecordId;
|
|
8953
|
-
}
|
|
8954
|
-
}
|
|
8955
|
-
|
|
8956
|
-
const APEX_RESOURCE_CONTEXT = {
|
|
8957
|
-
...DEFAULT_RESOURCE_CONTEXT,
|
|
8958
|
-
sourceContext: {
|
|
8959
|
-
...DEFAULT_RESOURCE_CONTEXT.sourceContext,
|
|
8960
|
-
// We don't want to override anything for Apex, it is not part
|
|
8961
|
-
// of UiApi, and it can cause undesired behavior.
|
|
8962
|
-
actionConfig: undefined,
|
|
8963
|
-
},
|
|
8964
|
-
};
|
|
8965
|
-
function getApexPdlFactory(luvio) {
|
|
8966
|
-
return ({ invokerParams, config }, requestContext) => {
|
|
8967
|
-
return GetApexWireAdapterFactory(luvio, invokerParams)(config, requestContext);
|
|
8968
|
-
};
|
|
8969
|
-
}
|
|
8970
|
-
const GET_APEX_ADAPTER_NAME = 'getApex';
|
|
8971
|
-
class GetApexRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
8972
|
-
constructor() {
|
|
8973
|
-
super(...arguments);
|
|
8974
|
-
this.adapterName = GET_APEX_ADAPTER_NAME;
|
|
8975
|
-
this.adapterFactory = getApexPdlFactory;
|
|
8976
|
-
}
|
|
8977
|
-
buildConcreteRequest(similarRequest) {
|
|
8978
|
-
return similarRequest;
|
|
8979
|
-
}
|
|
8980
|
-
createAdapterContext(_options) {
|
|
8981
|
-
return APEX_RESOURCE_CONTEXT;
|
|
8982
|
-
}
|
|
8983
|
-
getRequestPriority(_request, _context) {
|
|
8984
|
-
return 0 /* RequestPriority.LOW */;
|
|
8985
|
-
}
|
|
8986
|
-
}
|
|
8987
|
-
|
|
8988
|
-
const GET_LIST_INFO_BY_NAME_ADAPTER_NAME = 'getListInfoByName';
|
|
8989
|
-
class GetListInfoByNameRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
8990
|
-
constructor() {
|
|
8991
|
-
super(...arguments);
|
|
8992
|
-
this.adapterName = GET_LIST_INFO_BY_NAME_ADAPTER_NAME;
|
|
8993
|
-
this.adapterFactory = getListInfoByNameAdapterFactory;
|
|
8994
|
-
}
|
|
8995
|
-
buildConcreteRequest(similarRequest) {
|
|
8996
|
-
return similarRequest;
|
|
8997
|
-
}
|
|
8998
|
-
transformForSave(request) {
|
|
8999
|
-
return {
|
|
9000
|
-
...request,
|
|
9001
|
-
config: {
|
|
9002
|
-
...request.config,
|
|
9003
|
-
// (!): if we are saving this request is because the adapter already verified is valid.
|
|
9004
|
-
objectApiName: coerceObjectId(request.config.objectApiName),
|
|
9005
|
-
},
|
|
9006
|
-
};
|
|
9007
|
-
}
|
|
9008
|
-
canCombine(reqA, reqB) {
|
|
9009
|
-
return (reqA.objectApiName === reqB.objectApiName &&
|
|
9010
|
-
reqA.listViewApiName === reqB.listViewApiName);
|
|
9011
|
-
}
|
|
9012
|
-
combineRequests(reqA, _reqB) {
|
|
9013
|
-
return reqA;
|
|
9014
|
-
}
|
|
9015
|
-
}
|
|
9016
|
-
|
|
9017
|
-
const GET_LIST_INFOS_BY_OBJECT_NAME_ADAPTER_NAME = 'getListInfosByObjectName';
|
|
9018
|
-
class GetListInfosByObjectNameRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
9019
|
-
constructor() {
|
|
9020
|
-
super(...arguments);
|
|
9021
|
-
this.adapterName = GET_LIST_INFOS_BY_OBJECT_NAME_ADAPTER_NAME;
|
|
9022
|
-
this.adapterFactory = getListInfosByObjectNameAdapterFactory;
|
|
9023
|
-
}
|
|
9024
|
-
buildConcreteRequest(similarRequest) {
|
|
9025
|
-
return similarRequest;
|
|
9026
|
-
}
|
|
9027
|
-
transformForSave(request) {
|
|
9028
|
-
return {
|
|
9029
|
-
...request,
|
|
9030
|
-
config: {
|
|
9031
|
-
...request.config,
|
|
9032
|
-
// (!): if we are saving this request is because the adapter already verified is valid.
|
|
9033
|
-
objectApiName: coerceObjectId(request.config.objectApiName),
|
|
9034
|
-
},
|
|
9035
|
-
};
|
|
9036
|
-
}
|
|
9037
|
-
canCombine(reqA, reqB) {
|
|
9038
|
-
return (reqA.objectApiName === reqB.objectApiName &&
|
|
9039
|
-
reqA.q === reqB.q &&
|
|
9040
|
-
reqA.recentListsOnly === reqB.recentListsOnly &&
|
|
9041
|
-
reqA.pageSize === reqB.pageSize);
|
|
9042
|
-
}
|
|
9043
|
-
combineRequests(reqA, _reqB) {
|
|
9044
|
-
return reqA;
|
|
9045
|
-
}
|
|
9046
|
-
}
|
|
9047
|
-
|
|
9048
|
-
const GET_LIST_RECORDS_BY_NAME_ADAPTER_NAME = 'getListRecordsByName';
|
|
9049
|
-
function arrEq(array1, array2) {
|
|
9050
|
-
if (array1.length !== array2.length) {
|
|
9051
|
-
return false;
|
|
9052
|
-
}
|
|
9053
|
-
const sortedArray1 = [...array1].sort();
|
|
9054
|
-
const sortedArray2 = [...array2].sort();
|
|
9055
|
-
return sortedArray1.every((value, index) => value === sortedArray2[index]);
|
|
9056
|
-
}
|
|
9057
|
-
class GetListRecordsByNameRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
9058
|
-
constructor() {
|
|
9059
|
-
super(...arguments);
|
|
9060
|
-
this.adapterName = GET_LIST_RECORDS_BY_NAME_ADAPTER_NAME;
|
|
9061
|
-
this.adapterFactory = getListRecordsByNameAdapterFactory;
|
|
9062
|
-
}
|
|
9063
|
-
buildConcreteRequest(similarRequest) {
|
|
9064
|
-
return similarRequest;
|
|
9065
|
-
}
|
|
9066
|
-
transformForSave(request) {
|
|
9067
|
-
// No longer combining fields and optionalFields due to issue W-17353101
|
|
9068
|
-
return request;
|
|
9069
|
-
}
|
|
9070
|
-
canCombine(reqA, reqB) {
|
|
9071
|
-
return (reqA.objectApiName === reqB.objectApiName &&
|
|
9072
|
-
reqA.listViewApiName === reqB.listViewApiName &&
|
|
9073
|
-
reqA.pageSize === reqB.pageSize &&
|
|
9074
|
-
reqA.searchTerm === reqB.searchTerm &&
|
|
9075
|
-
reqA.sortBy === reqB.sortBy &&
|
|
9076
|
-
reqA.where === reqB.where &&
|
|
9077
|
-
arrEq(reqA.fields || [], reqB.fields || []) &&
|
|
9078
|
-
arrEq(reqB.optionalFields || [], reqB.optionalFields || []));
|
|
9079
|
-
}
|
|
9080
|
-
combineRequests(reqA, _reqB) {
|
|
9081
|
-
return reqA;
|
|
9082
|
-
}
|
|
9083
|
-
}
|
|
9084
|
-
|
|
9085
|
-
const GET_LIST_OBJECT_INFO_ADAPTER_NAME = 'getListObjectInfo';
|
|
9086
|
-
class GetListObjectInfoRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
9087
|
-
constructor() {
|
|
9088
|
-
super(...arguments);
|
|
9089
|
-
this.adapterName = GET_LIST_OBJECT_INFO_ADAPTER_NAME;
|
|
9090
|
-
this.adapterFactory = getListObjectInfoAdapterFactory;
|
|
9091
|
-
}
|
|
9092
|
-
buildConcreteRequest(similarRequest) {
|
|
9093
|
-
return similarRequest;
|
|
9094
|
-
}
|
|
9095
|
-
transformForSave(request) {
|
|
9096
|
-
return {
|
|
9097
|
-
...request,
|
|
9098
|
-
config: {
|
|
9099
|
-
...request.config,
|
|
9100
|
-
// (!): if we are saving this request is because the adapter already verified is valid.
|
|
9101
|
-
objectApiName: coerceObjectId(request.config.objectApiName),
|
|
9102
|
-
},
|
|
9103
|
-
};
|
|
9104
|
-
}
|
|
9105
|
-
canCombine(reqA, reqB) {
|
|
9106
|
-
return reqA.objectApiName === reqB.objectApiName;
|
|
9107
|
-
}
|
|
9108
|
-
combineRequests(reqA, _reqB) {
|
|
9109
|
-
return reqA;
|
|
9110
|
-
}
|
|
9111
|
-
}
|
|
9112
|
-
|
|
9113
|
-
const GET_RELATED_LISTS_INFO_ADAPTER_NAME = 'getRelatedListsInfo';
|
|
9114
|
-
class GetRelatedListsInfoRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
9115
|
-
constructor() {
|
|
9116
|
-
super(...arguments);
|
|
9117
|
-
this.adapterName = GET_RELATED_LISTS_INFO_ADAPTER_NAME;
|
|
9118
|
-
this.adapterFactory = getRelatedListsInfoAdapterFactory;
|
|
9119
|
-
}
|
|
9120
|
-
/**
|
|
9121
|
-
* @override
|
|
9122
|
-
*/
|
|
9123
|
-
isContextDependent(context, request) {
|
|
9124
|
-
return (context.objectApiName === coerceObjectId(request.config.parentObjectApiName) &&
|
|
9125
|
-
context.recordTypeId === request.config.recordTypeId);
|
|
9126
|
-
}
|
|
9127
|
-
/**
|
|
9128
|
-
* @override
|
|
9129
|
-
*/
|
|
9130
|
-
buildConcreteRequest(similarRequest, _context) {
|
|
9131
|
-
return similarRequest;
|
|
9132
|
-
}
|
|
9133
|
-
/**
|
|
9134
|
-
* @override
|
|
9135
|
-
*/
|
|
9136
|
-
transformForSave(request) {
|
|
9137
|
-
return {
|
|
9138
|
-
...request,
|
|
9139
|
-
config: {
|
|
9140
|
-
...request.config,
|
|
9141
|
-
parentObjectApiName: coerceObjectId(request.config.parentObjectApiName),
|
|
9142
|
-
},
|
|
9143
|
-
};
|
|
9144
|
-
}
|
|
9145
|
-
canCombine(reqA, reqB) {
|
|
9146
|
-
// only combine if both requests are equal.
|
|
9147
|
-
return (reqA.parentObjectApiName === reqB.parentObjectApiName &&
|
|
9148
|
-
reqA.recordTypeId === reqB.recordTypeId);
|
|
9149
|
-
}
|
|
9150
|
-
combineRequests(reqA, _reqB) {
|
|
9151
|
-
return reqA;
|
|
9152
|
-
}
|
|
9153
|
-
}
|
|
9154
|
-
|
|
9155
|
-
const GET_RELATED_LIST_ACTIONS_ADAPTER_NAME = 'getRelatedListActions';
|
|
9156
|
-
/**
|
|
9157
|
-
* Returns true if the config is only the required configuration.
|
|
9158
|
-
*
|
|
9159
|
-
* @param config - The related list actions config
|
|
9160
|
-
* @returns boolean - true if the config is only the required configuration
|
|
9161
|
-
*/
|
|
9162
|
-
function isRequiredOnlyConfig(config) {
|
|
9163
|
-
return (config.apiNames === undefined &&
|
|
9164
|
-
config.actionTypes === undefined &&
|
|
9165
|
-
config.formFactor === undefined &&
|
|
9166
|
-
config.retrievalMode === undefined &&
|
|
9167
|
-
config.sections === undefined);
|
|
9168
|
-
}
|
|
9169
|
-
class GetRelatedListActionsRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
9170
|
-
constructor() {
|
|
9171
|
-
super(...arguments);
|
|
9172
|
-
this.adapterName = GET_RELATED_LIST_ACTIONS_ADAPTER_NAME;
|
|
9173
|
-
this.adapterFactory = getRelatedListActionsAdapterFactory;
|
|
9174
|
-
}
|
|
9175
|
-
buildConcreteRequest(similarRequest, context) {
|
|
9176
|
-
return {
|
|
9177
|
-
...similarRequest,
|
|
9178
|
-
config: {
|
|
9179
|
-
...similarRequest.config,
|
|
9180
|
-
recordIds: [context.recordId],
|
|
9181
|
-
},
|
|
9182
|
-
};
|
|
9183
|
-
}
|
|
9184
|
-
transformForSave(request) {
|
|
9185
|
-
// we only need to coerce the required configuration because only those fields are
|
|
9186
|
-
// manipulated by the strategy.
|
|
9187
|
-
return {
|
|
9188
|
-
...request,
|
|
9189
|
-
config: {
|
|
9190
|
-
...request.config,
|
|
9191
|
-
// (!): if is recorded in PDL, it was already validated by the adapter.
|
|
9192
|
-
recordIds: getRecordId18Array(request.config.recordIds) || [],
|
|
9193
|
-
},
|
|
9194
|
-
};
|
|
9195
|
-
}
|
|
9196
|
-
transformForSaveSimilarRequest(request) {
|
|
9197
|
-
return {
|
|
9198
|
-
...request,
|
|
9199
|
-
config: {
|
|
9200
|
-
...request.config,
|
|
9201
|
-
recordIds: ['*'],
|
|
9202
|
-
},
|
|
9203
|
-
};
|
|
9204
|
-
}
|
|
9205
|
-
isContextDependent(context, { config }) {
|
|
9206
|
-
// Note: despite recordIds being an array, it is common to send just one recordId as a string.
|
|
9207
|
-
// Also, recordIds is a required param, and the factory would have failed if recordIds is missing,
|
|
9208
|
-
// normalizing to an empty array to avoid an error from PDL if that logic fails.
|
|
9209
|
-
const requestRecordsIds = getRecordId18Array(config.recordIds) || [];
|
|
9210
|
-
const configHasOnlyOneRecord = requestRecordsIds.length === 1;
|
|
9211
|
-
return (configHasOnlyOneRecord &&
|
|
9212
|
-
requestRecordsIds[0] === context.recordId &&
|
|
9213
|
-
isRequiredOnlyConfig(config));
|
|
9214
|
-
}
|
|
9215
|
-
canCombine(reqA, reqB) {
|
|
9216
|
-
// At the moment, these are not combinable by this strategy, except when they are the same request
|
|
9217
|
-
return (isRequiredOnlyConfig(reqA) &&
|
|
9218
|
-
isRequiredOnlyConfig(reqB) &&
|
|
9219
|
-
reqA.recordIds.length === 1 &&
|
|
9220
|
-
reqB.recordIds.length === 1 &&
|
|
9221
|
-
reqA.recordIds[0] === reqB.recordIds[0] &&
|
|
9222
|
-
reqA.relatedListId === reqB.relatedListId);
|
|
9223
|
-
}
|
|
9224
|
-
combineRequests(reqA, _reqB) {
|
|
9225
|
-
// both request are the same, return only one of them.
|
|
9226
|
-
return reqA;
|
|
9227
|
-
}
|
|
9228
|
-
}
|
|
9229
|
-
|
|
9230
|
-
/**
|
|
9231
|
-
* Base implementation of a home page
|
|
9232
|
-
*/
|
|
9233
|
-
class AbstractHomePage extends LexDefaultPage {
|
|
9234
|
-
constructor(context, similarContext, requestStrategyManager, supportedAdapters) {
|
|
9235
|
-
super(context, similarContext);
|
|
9236
|
-
this.requestStrategyManager = requestStrategyManager;
|
|
9237
|
-
this.supportedAdapters = supportedAdapters;
|
|
9238
|
-
}
|
|
9239
|
-
supportsRequest(request) {
|
|
9240
|
-
return this.supportedAdapters.has(request.adapterName);
|
|
9241
|
-
}
|
|
9242
|
-
buildSaveRequestData(request) {
|
|
9243
|
-
const requestBuckets = [];
|
|
9244
|
-
const { adapterName } = request;
|
|
9245
|
-
const matchingRequestStrategy = this.requestStrategyManager.get(adapterName);
|
|
9246
|
-
if (matchingRequestStrategy === undefined) {
|
|
9247
|
-
return [];
|
|
9248
|
-
}
|
|
9249
|
-
if (matchingRequestStrategy.isContextDependent(this.context, request)) {
|
|
9250
|
-
requestBuckets.push({
|
|
9251
|
-
key: this.getSimilarKey(),
|
|
9252
|
-
request: matchingRequestStrategy.transformForSaveSimilarRequest(request, this.context),
|
|
9253
|
-
});
|
|
9254
|
-
}
|
|
9255
|
-
else {
|
|
9256
|
-
requestBuckets.push({
|
|
9257
|
-
key: this.getExactKey(),
|
|
9258
|
-
request: matchingRequestStrategy.transformForSave(request, this.context),
|
|
9259
|
-
});
|
|
9260
|
-
}
|
|
9261
|
-
return requestBuckets;
|
|
9262
|
-
}
|
|
9263
|
-
}
|
|
9264
|
-
|
|
9265
|
-
const RECORD_HOME_SUPPORTED_ADAPTERS = new Set([
|
|
9266
|
-
GET_APEX_ADAPTER_NAME,
|
|
9267
|
-
GET_OBJECT_INFO_ADAPTER_NAME,
|
|
9268
|
-
GET_OBJECT_INFO_BATCH_ADAPTER_NAME,
|
|
9269
|
-
GET_RECORD_ACTIONS_ADAPTER_NAME,
|
|
9270
|
-
GET_RECORD_AVATARS_ADAPTER_NAME,
|
|
9271
|
-
GET_RECORD_ADAPTER_NAME,
|
|
9272
|
-
GET_RECORDS_ADAPTER_NAME,
|
|
9273
|
-
GET_RELATED_LIST_INFO_BATCH_ADAPTER_NAME,
|
|
9274
|
-
GET_RELATED_LIST_INFO_ADAPTER_NAME,
|
|
9275
|
-
GET_RELATED_LIST_RECORDS_BATCH_ADAPTER_NAME,
|
|
9276
|
-
GET_RELATED_LIST_RECORDS_ADAPTER_NAME,
|
|
9277
|
-
GET_RELATED_LISTS_ACTIONS_ADAPTER_NAME,
|
|
9278
|
-
GET_RELATED_LISTS_INFO_ADAPTER_NAME,
|
|
9279
|
-
GET_RELATED_LIST_ACTIONS_ADAPTER_NAME,
|
|
9280
|
-
'templateApi',
|
|
9281
|
-
'Aura.getComponentsDef', // external - Predictive Loading for CMP Definitions
|
|
9282
|
-
]);
|
|
9283
|
-
class RecordHomePage extends AbstractHomePage {
|
|
9284
|
-
constructor(context, requestStrategyManager) {
|
|
9285
|
-
super(context, {
|
|
9286
|
-
...context,
|
|
9287
|
-
recordId: '*',
|
|
9288
|
-
}, requestStrategyManager, RECORD_HOME_SUPPORTED_ADAPTERS);
|
|
9289
|
-
}
|
|
9290
|
-
getExactKey() {
|
|
9291
|
-
return RecordHomePage.contextToExactKey(this.context);
|
|
9292
|
-
}
|
|
9293
|
-
resolveSimilarRequest(similarRequest) {
|
|
9294
|
-
const { adapterName } = similarRequest;
|
|
9295
|
-
const matchingRequestStrategy = this.requestStrategyManager.get(adapterName);
|
|
9296
|
-
if (matchingRequestStrategy === undefined) {
|
|
9297
|
-
return similarRequest;
|
|
9298
|
-
}
|
|
9299
|
-
return matchingRequestStrategy.buildConcreteRequest(similarRequest, this.context);
|
|
9300
|
-
}
|
|
9301
|
-
// Record Home performs best when we always do a minimal getRecord alongside the other requests.
|
|
9302
|
-
// The reason is that the Highlights and Detail panel will always request the recordTypeId first.
|
|
9303
|
-
// https://sourcegraph.soma.salesforce.com/perforce.soma.salesforce.com/app/main/core/-/blob/ui-laf-components/modules/laf/templateApi/getRecordLayoutTemplate.js?L24
|
|
9304
|
-
getAlwaysRunRequests() {
|
|
9305
|
-
const { recordId, objectApiName } = this.context;
|
|
9306
|
-
return [
|
|
9307
|
-
{
|
|
9308
|
-
adapterName: 'getRecord',
|
|
9309
|
-
config: {
|
|
9310
|
-
recordId,
|
|
9311
|
-
optionalFields: [`${objectApiName}.Id`, `${objectApiName}.RecordTypeId`],
|
|
9312
|
-
},
|
|
9313
|
-
},
|
|
9314
|
-
];
|
|
9315
|
-
}
|
|
9316
|
-
/**
|
|
9317
|
-
* In RH, we should execute the getRecord(id, type) by itself as we want the result asap, so
|
|
9318
|
-
* it does not stop rendering.
|
|
9319
|
-
* @returns true
|
|
9320
|
-
*/
|
|
9321
|
-
shouldExecuteAlwaysRequestByThemself() {
|
|
9322
|
-
return true;
|
|
9323
|
-
}
|
|
9324
|
-
static handlesContext(context) {
|
|
9325
|
-
return (context !== undefined &&
|
|
9326
|
-
context.actionName !== undefined &&
|
|
9327
|
-
context.objectApiName !== undefined &&
|
|
9328
|
-
context.recordId !== undefined &&
|
|
9329
|
-
context.type === 'recordPage');
|
|
9330
|
-
}
|
|
9331
|
-
static contextToExactKey(context) {
|
|
9332
|
-
const { recordTypeId: _, ...key } = context;
|
|
9333
|
-
return key;
|
|
9334
|
-
}
|
|
9335
|
-
}
|
|
9336
|
-
|
|
9337
|
-
const OBJECT_HOME_SUPPORTED_ADAPTERS = new Set([
|
|
9338
|
-
GET_LIST_INFO_BY_NAME_ADAPTER_NAME,
|
|
9339
|
-
GET_LIST_OBJECT_INFO_ADAPTER_NAME,
|
|
9340
|
-
GET_LIST_RECORDS_BY_NAME_ADAPTER_NAME,
|
|
9341
|
-
GET_LIST_INFOS_BY_OBJECT_NAME_ADAPTER_NAME,
|
|
9342
|
-
GET_OBJECT_INFO_BATCH_ADAPTER_NAME,
|
|
9343
|
-
]);
|
|
9344
|
-
class ObjectHomePage extends AbstractHomePage {
|
|
9345
|
-
constructor(context, requestStrategyManager) {
|
|
9346
|
-
super(context, context, requestStrategyManager, OBJECT_HOME_SUPPORTED_ADAPTERS);
|
|
9347
|
-
}
|
|
9348
|
-
// these are requests that run always regardless of any other request existing
|
|
9349
|
-
getAlwaysRunRequests() {
|
|
9350
|
-
const { listViewApiName, objectApiName } = this.context;
|
|
9351
|
-
return [
|
|
9352
|
-
{
|
|
9353
|
-
adapterName: 'getListInfoByName',
|
|
9354
|
-
config: {
|
|
9355
|
-
objectApiName: objectApiName,
|
|
9356
|
-
listViewApiName: listViewApiName,
|
|
9357
|
-
},
|
|
9358
|
-
},
|
|
9359
|
-
{
|
|
9360
|
-
adapterName: 'getListInfosByObjectName',
|
|
9361
|
-
config: {
|
|
9362
|
-
objectApiName: objectApiName,
|
|
9363
|
-
pageSize: 100,
|
|
9364
|
-
q: '',
|
|
9365
|
-
},
|
|
9366
|
-
},
|
|
9367
|
-
{
|
|
9368
|
-
adapterName: 'getListInfosByObjectName',
|
|
9369
|
-
config: {
|
|
9370
|
-
objectApiName: objectApiName,
|
|
9371
|
-
pageSize: 10,
|
|
9372
|
-
recentListsOnly: true,
|
|
9373
|
-
},
|
|
9374
|
-
},
|
|
9375
|
-
{
|
|
9376
|
-
adapterName: 'getListObjectInfo',
|
|
9377
|
-
config: {
|
|
9378
|
-
objectApiName: objectApiName,
|
|
9379
|
-
},
|
|
9380
|
-
},
|
|
9381
|
-
];
|
|
9382
|
-
}
|
|
9383
|
-
/**
|
|
9384
|
-
* In OH, the always requests are reduced with predictions, and because they
|
|
9385
|
-
* can't be merged with other predictions, they will always run by themself.
|
|
9386
|
-
* This value must be `false`, otherwise we may see repeated requests.
|
|
9387
|
-
*
|
|
9388
|
-
* @returns false
|
|
9389
|
-
*/
|
|
9390
|
-
shouldExecuteAlwaysRequestByThemself() {
|
|
9391
|
-
return false;
|
|
9392
|
-
}
|
|
9393
|
-
// Identifies a valid ObjectHomeContext
|
|
9394
|
-
static handlesContext(context) {
|
|
9395
|
-
return (context !== undefined &&
|
|
9396
|
-
context.listViewApiName !== undefined &&
|
|
9397
|
-
context.objectApiName !== undefined &&
|
|
9398
|
-
context.type === 'objectHomePage');
|
|
9399
|
-
}
|
|
9400
|
-
}
|
|
9401
|
-
|
|
9402
|
-
var PdlPrefetcherEventType;
|
|
9403
|
-
(function (PdlPrefetcherEventType) {
|
|
9404
|
-
PdlPrefetcherEventType["STARTED_RECORDING"] = "started-recording";
|
|
9405
|
-
PdlPrefetcherEventType["STOPPED_RECORDING"] = "stopped-recording";
|
|
9406
|
-
})(PdlPrefetcherEventType || (PdlPrefetcherEventType = {}));
|
|
9407
|
-
class PrefetcherEventEmitter {
|
|
9408
|
-
constructor() {
|
|
9409
|
-
this.listeners = new Map();
|
|
9410
|
-
}
|
|
9411
|
-
subscribeTo(type, listener) {
|
|
9412
|
-
const typeListeners = this.listeners.get(type) ?? [];
|
|
9413
|
-
typeListeners.push(listener);
|
|
9414
|
-
this.listeners.set(type, typeListeners);
|
|
9415
|
-
return () => {
|
|
9416
|
-
const currentListeners = this.listeners.get(type) ?? [];
|
|
9417
|
-
this.listeners.set(type, currentListeners.filter((l) => l !== listener));
|
|
9418
|
-
};
|
|
9419
|
-
}
|
|
9420
|
-
emit(event) {
|
|
9421
|
-
const typeListeners = this.listeners.get(event.type) ?? [];
|
|
9422
|
-
typeListeners.forEach((listener) => {
|
|
9423
|
-
try {
|
|
9424
|
-
listener(event);
|
|
9425
|
-
}
|
|
9426
|
-
catch (error) {
|
|
9427
|
-
// swallow errors in production.
|
|
9428
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
9429
|
-
throw error;
|
|
9430
|
-
}
|
|
9431
|
-
}
|
|
9432
|
-
});
|
|
9433
|
-
}
|
|
9434
|
-
}
|
|
9435
|
-
|
|
9436
|
-
class ApplicationPredictivePrefetcher {
|
|
9437
|
-
constructor(context, repository, requestRunner, eventEmitter) {
|
|
9438
|
-
this.repository = repository;
|
|
9439
|
-
this.requestRunner = requestRunner;
|
|
9440
|
-
this.eventEmitter = eventEmitter;
|
|
9441
|
-
this.isRecording = false;
|
|
9442
|
-
this.totalRequestCount = 0;
|
|
9443
|
-
this.queuedPredictionRequests = [];
|
|
9444
|
-
this._context = context;
|
|
9445
|
-
this.page = this.getPage();
|
|
9446
|
-
}
|
|
9447
|
-
set context(value) {
|
|
9448
|
-
this._context = value;
|
|
9449
|
-
this.page = this.getPage();
|
|
9450
|
-
}
|
|
9451
|
-
get context() {
|
|
9452
|
-
return this._context;
|
|
9453
|
-
}
|
|
9454
|
-
subscribeToEvent(type, callback) {
|
|
9455
|
-
return this.eventEmitter.subscribeTo(type, callback);
|
|
9456
|
-
}
|
|
9457
|
-
async stopRecording() {
|
|
9458
|
-
this.isRecording = false;
|
|
9459
|
-
this.totalRequestCount = 0;
|
|
9460
|
-
await this.repository.flushRequestsToStorage();
|
|
9461
|
-
this.eventEmitter.emit({
|
|
9462
|
-
type: PdlPrefetcherEventType.STOPPED_RECORDING,
|
|
9463
|
-
page: this.page,
|
|
9464
|
-
});
|
|
9465
|
-
}
|
|
9466
|
-
startRecording() {
|
|
9467
|
-
this.isRecording = true;
|
|
9468
|
-
this.repository.markPageStart();
|
|
9469
|
-
this.repository.clearRequestBuffer();
|
|
9470
|
-
this.eventEmitter.emit({
|
|
9471
|
-
type: PdlPrefetcherEventType.STARTED_RECORDING,
|
|
9472
|
-
page: this.page,
|
|
9473
|
-
});
|
|
9474
|
-
}
|
|
9475
|
-
saveRequest(request) {
|
|
9476
|
-
if (!this.isRecording) {
|
|
9477
|
-
return;
|
|
9478
|
-
}
|
|
9479
|
-
executeAsyncActivity(METRIC_KEYS.PREDICTIVE_DATA_LOADING_SAVE_REQUEST, (_act) => {
|
|
9480
|
-
if (this.page.supportsRequest(request)) {
|
|
9481
|
-
const saveBuckets = this.page.buildSaveRequestData(request);
|
|
9482
|
-
saveBuckets.forEach((saveBucket) => {
|
|
9483
|
-
const { request: requestToSave, key } = saveBucket;
|
|
9484
|
-
// No need to differentiate from predictions requests because these
|
|
9485
|
-
// are made from the adapters factory, which are not prediction aware.
|
|
9486
|
-
this.repository.saveRequest(key, requestToSave);
|
|
9487
|
-
});
|
|
9488
|
-
}
|
|
9489
|
-
return Promise.resolve().then();
|
|
9490
|
-
}, PDL_EXECUTE_ASYNC_OPTIONS);
|
|
9491
|
-
}
|
|
9492
|
-
async predict() {
|
|
9493
|
-
const alwaysRequests = this.page.getAlwaysRunRequests();
|
|
9494
|
-
const similarPageRequests = this.getSimilarPageRequests();
|
|
9495
|
-
const exactPageRequests = this.getExactPageRequests();
|
|
9496
|
-
// Always requests can't be reduced in - Some of them are essential to keep the page rendering at the beginning.
|
|
9497
|
-
const reducedRequests = this.requestRunner
|
|
9498
|
-
.reduceRequests([...exactPageRequests, ...similarPageRequests])
|
|
9499
|
-
.map((entry) => entry.request);
|
|
9500
|
-
const predictedRequests = [...alwaysRequests, ...reducedRequests];
|
|
9501
|
-
this.queuedPredictionRequests.push(...predictedRequests);
|
|
9502
|
-
this.totalRequestCount = predictedRequests.length;
|
|
9503
|
-
return Promise.all(predictedRequests.map((request) => this.requestRunner.runRequest(request))).then();
|
|
9504
|
-
}
|
|
9505
|
-
getPredictionSummary() {
|
|
9506
|
-
return {
|
|
9507
|
-
exact: this.getExactPageRequests().length,
|
|
9508
|
-
similar: this.getSimilarPageRequests().length,
|
|
9509
|
-
totalRequestCount: this.totalRequestCount,
|
|
9510
|
-
};
|
|
9511
|
-
}
|
|
9512
|
-
hasPredictions() {
|
|
9513
|
-
const summary = this.getPredictionSummary();
|
|
9514
|
-
return summary.exact > 0 || summary.similar > 0;
|
|
9515
|
-
}
|
|
9516
|
-
getSimilarPageRequests() {
|
|
9517
|
-
return this.repository.getPageRequests(this.page.getSimilarKey()).map((entry) => {
|
|
9518
|
-
return {
|
|
9519
|
-
...entry,
|
|
9520
|
-
request: this.page.resolveSimilarRequest(entry.request),
|
|
9521
|
-
};
|
|
9522
|
-
});
|
|
9523
|
-
}
|
|
9524
|
-
getExactPageRequests() {
|
|
9525
|
-
return this.repository.getPageRequests(this.page.getExactKey()) || [];
|
|
9526
|
-
}
|
|
9527
|
-
}
|
|
9528
|
-
|
|
9529
|
-
/**
|
|
9530
|
-
* Runs a list of requests with a specified concurrency limit.
|
|
9531
|
-
*
|
|
9532
|
-
* @template Request - The type of the requests being processed.
|
|
9533
|
-
* @param {RequestEntry<Request>[]} requests - An array of request entries to be processed in the array order.
|
|
9534
|
-
* @param {RequestRunner<Request>} runner - The runner instance responsible for executing the requests.
|
|
9535
|
-
* @param {number} concurrentRequestsLimit - The maximum number of concurrent requests allowed.
|
|
9536
|
-
* @param {number} pageStartTime - The start time of the page load, used to calculate the time elapsed since the page starts loading.
|
|
9537
|
-
* @returns {Promise<void>} A promise that resolves when all requests have been processed.
|
|
9538
|
-
*
|
|
9539
|
-
* This function manages a queue of pending requests and processes them with a concurrency limit.
|
|
9540
|
-
* Requests are only processed if their `requestTime` is less than the time elapsed since `pageStartTime`.
|
|
9541
|
-
*/
|
|
9542
|
-
async function runRequestsWithLimit(requests, runner, concurrentRequestsLimit, pageStartTime) {
|
|
9543
|
-
// queue for pending prediction requests
|
|
9544
|
-
const requestQueue = [...requests];
|
|
9545
|
-
// Function to process the next request in the queue
|
|
9546
|
-
const processNextRequest = async (verifyPastTime = true) => {
|
|
9547
|
-
const timeInWaterfall = Date.now() - pageStartTime;
|
|
9548
|
-
while (requestQueue.length > 0 &&
|
|
9549
|
-
verifyPastTime &&
|
|
9550
|
-
requestQueue[0].requestMetadata.requestTime <= timeInWaterfall) {
|
|
9551
|
-
requestQueue.shift();
|
|
9552
|
-
}
|
|
9553
|
-
if (requestQueue.length > 0) {
|
|
9554
|
-
// (!) requestQueue will always have at least one element ensured by the above check.
|
|
9555
|
-
const nextRequest = requestQueue.shift();
|
|
9556
|
-
try {
|
|
9557
|
-
// Run the request and wait for it to complete
|
|
9558
|
-
await runner.runRequest(nextRequest.request);
|
|
9559
|
-
}
|
|
9560
|
-
finally {
|
|
9561
|
-
await processNextRequest();
|
|
9562
|
-
}
|
|
9563
|
-
}
|
|
9564
|
-
};
|
|
9565
|
-
// Start processing requests up to concurrentRequestsLimit
|
|
9566
|
-
const initialRequests = Math.min(concurrentRequestsLimit, requestQueue.length);
|
|
9567
|
-
const promises = [];
|
|
9568
|
-
for (let i = 0; i < initialRequests; i++) {
|
|
9569
|
-
// Initial requests should always execute, without verifying if they are past due.
|
|
9570
|
-
// Reasoning:
|
|
9571
|
-
// It may be that one of the alwaysRequest (with 0 as start time) that is reduced
|
|
9572
|
-
// with the regular requests to make these to have 0 as the initial time in the waterfall.
|
|
9573
|
-
// Because predictions are behind an await (see W-16139321), it could be that when this code is evaluated
|
|
9574
|
-
// is already past time for the request.
|
|
9575
|
-
promises.push(processNextRequest(false));
|
|
9576
|
-
}
|
|
9577
|
-
// Wait for all initial requests to complete
|
|
9578
|
-
await Promise.all(promises);
|
|
9579
|
-
}
|
|
9580
|
-
/**
|
|
9581
|
-
* Runs entire list of LEX requests, applying hotspot up to the specified limit and disabling for all remaining
|
|
9582
|
-
*
|
|
9583
|
-
* @param {RequestEntry<LexRequest>[]} requests - An array of request entries to be processed in the array order.
|
|
9584
|
-
* @param {RequestRunner<LexRequest, LexRequestOptions>} runner - The runner instance responsible for executing the requests.
|
|
9585
|
-
* @param {number} hotspotLimit - The number of hotspot requests allowed.
|
|
9586
|
-
* @returns {Promise<void>} A promise that resolves when all requests have been processed.
|
|
9587
|
-
*
|
|
9588
|
-
* This function processes a queue of pending requests, enabling hotspot for the first N requests,
|
|
9589
|
-
* as specified by the hotspotLimit argument. The remaining requests have hotspot disabled.
|
|
9590
|
-
*/
|
|
9591
|
-
async function runRequestsWithHotspotLimit(requests, runner, hotspotLimit) {
|
|
9592
|
-
const promises = requests.map((request, index) => {
|
|
9593
|
-
// determine if hotspot needs to be disabled or not
|
|
9594
|
-
const disableHotspot = index >= hotspotLimit;
|
|
9595
|
-
// run request with hotspot setting
|
|
9596
|
-
return runner.runRequest(request.request, { disableHotspot });
|
|
9597
|
-
});
|
|
9598
|
-
// promise for all requests
|
|
9599
|
-
await Promise.all(promises);
|
|
9600
|
-
}
|
|
9601
|
-
/**
|
|
9602
|
-
* Compares two request entries based on their priority and, if the priorities are the same, their request times.
|
|
9603
|
-
* This function is typically used for sorting requests where priority takes precedence, and timing is used
|
|
9604
|
-
* as a secondary criterion. The function assumes that any necessary filtering of requests has already been done.
|
|
9605
|
-
*
|
|
9606
|
-
* @template Context - Extends `DefaultPageContext`, provides additional context for the request priority determination.
|
|
9607
|
-
*
|
|
9608
|
-
* @param {RequestEntry<LexRequest>} requestA - The first request entry containing the request and its metadata.
|
|
9609
|
-
* @param {RequestEntry<LexRequest>} requestB - The second request entry containing the request and its metadata.
|
|
9610
|
-
* @param {RequestStrategyManager} requestStrategyManager - Manager that provides access to request strategies based on adapter names.
|
|
9611
|
-
* @param {Context} context - The context in which the requests are being compared, used to determine request priority.
|
|
9612
|
-
*
|
|
9613
|
-
* @returns {number} A negative number if the first request should come before the second, a positive number if the
|
|
9614
|
-
* second should come before the first, or zero if they are considered equal for sorting purposes.
|
|
9615
|
-
* This is determined first by the priority (higher priority comes first) and then by the request
|
|
9616
|
-
* time (earlier request comes first) if priorities are the same. The priorities are fetched from
|
|
9617
|
-
* the `requestStrategyManager` for each request's `adapterName`. If a strategy is not found,
|
|
9618
|
-
* the priority defaults to `RequestPriority.LOW`.
|
|
9619
|
-
*/
|
|
9620
|
-
function compareByPriorityThenTime({ request: requestA, requestMetadata: requestMetadataA }, { request: requestB, requestMetadata: requestMetadataB }, requestStrategyManager, context) {
|
|
9621
|
-
const aPriority = requestStrategyManager.get(requestA.adapterName)?.getRequestPriority(requestA, context) ||
|
|
9622
|
-
0 /* RequestPriority.LOW */;
|
|
9623
|
-
const bPriority = requestStrategyManager.get(requestB.adapterName)?.getRequestPriority(requestB, context) ||
|
|
9624
|
-
0 /* RequestPriority.LOW */;
|
|
9625
|
-
if (aPriority === bPriority) {
|
|
9626
|
-
// when both requests have the same priority, use the request time in waterfall.
|
|
9627
|
-
return requestMetadataA.requestTime - requestMetadataB.requestTime;
|
|
9628
|
-
}
|
|
9629
|
-
else {
|
|
9630
|
-
// sort by priority, descending
|
|
9631
|
-
return bPriority - aPriority;
|
|
9632
|
-
}
|
|
9633
|
-
}
|
|
9634
|
-
/**
|
|
9635
|
-
* Returns the value of the gate that controls whether to use the hotspot limit. Value is cached after the initial call
|
|
9636
|
-
*
|
|
9637
|
-
* @returns {boolean} true if the gate is open, false otherwise.
|
|
9638
|
-
*/
|
|
9639
|
-
let useHotspotLimitOpen;
|
|
9640
|
-
function isUseHotspotLimitOpen() {
|
|
9641
|
-
useHotspotLimitOpen = useHotspotLimitOpen ?? useHotspotLimit.isOpen({ fallback: false });
|
|
9642
|
-
return useHotspotLimitOpen;
|
|
9643
|
-
}
|
|
9644
|
-
|
|
9645
|
-
function isBoxcarableRequest({ request: { adapterName } }, requestStrategyManager) {
|
|
9646
|
-
const strategy = requestStrategyManager.get(adapterName);
|
|
9647
|
-
return strategy === undefined || strategy.isBoxcarable;
|
|
9648
|
-
}
|
|
9649
|
-
function predictNonBoxcarableRequest(nonBoxcaredPredictions, requestRunner) {
|
|
9650
|
-
const reducedPredictions = requestRunner.reduceRequests(nonBoxcaredPredictions);
|
|
9651
|
-
reducedPredictions.map((request) => requestRunner.runRequest(request.request));
|
|
9652
|
-
}
|
|
9653
|
-
const DEFAULT_RECORD_TYPE_ID = '012000000000000AAA';
|
|
9654
|
-
const AURA_BOXCAR_THREADS_THRESHOLD = 3;
|
|
9655
|
-
class LexPredictivePrefetcher extends ApplicationPredictivePrefetcher {
|
|
9656
|
-
constructor(context, repository, requestRunner, eventEmitter,
|
|
9657
|
-
// These strategies need to be in sync with the "predictiveDataLoadCapable" list
|
|
9658
|
-
// from scripts/lds-uiapi-plugin.js
|
|
9659
|
-
requestStrategyManager, options) {
|
|
9660
|
-
super(context, repository, requestRunner, eventEmitter);
|
|
9661
|
-
this.options = options;
|
|
9662
|
-
this.requestStrategyManager = requestStrategyManager;
|
|
9663
|
-
this.page = this.getPage();
|
|
9664
|
-
}
|
|
9665
|
-
getPage() {
|
|
9666
|
-
if (RecordHomePage.handlesContext(this.context)) {
|
|
9667
|
-
/*
|
|
9668
|
-
* `recordTypeId` is required in order to create similar request keys. However, the means by which it is
|
|
9669
|
-
* obtained varies based on when in the app lifecycle predictions are requested.
|
|
9670
|
-
*/
|
|
9671
|
-
// check context for record type
|
|
9672
|
-
if (!this.context.recordTypeId) {
|
|
9673
|
-
// don't have it (i.e., early predictions), so need try to obtain via exact matches
|
|
9674
|
-
const exact = this.repository.getPage(RecordHomePage.contextToExactKey(this.context));
|
|
9675
|
-
// use found recordTypeId, otherwise fallback to default
|
|
9676
|
-
this.context.recordTypeId = (exact && exact.recordTypeId) || DEFAULT_RECORD_TYPE_ID;
|
|
9677
|
-
}
|
|
9678
|
-
return new RecordHomePage(this.context, this.requestStrategyManager);
|
|
9679
|
-
}
|
|
9680
|
-
else if (ObjectHomePage.handlesContext(this.context)) {
|
|
9681
|
-
return new ObjectHomePage(this.context, this.requestStrategyManager);
|
|
9682
|
-
}
|
|
9683
|
-
return new LexDefaultPage(this.context);
|
|
9684
|
-
}
|
|
9685
|
-
getAllPageRequests() {
|
|
9686
|
-
const exactPageRequests = this.getExactPageRequests();
|
|
9687
|
-
const similarPageRequests = this.getSimilarPageRequests();
|
|
9688
|
-
return [...exactPageRequests, ...similarPageRequests];
|
|
9689
|
-
}
|
|
9690
|
-
getPredictedRequestsOrderedByPriority() {
|
|
9691
|
-
// perf: caching access, to avoid this.prop in loops.
|
|
9692
|
-
const { requestStrategyManager, context } = this;
|
|
9693
|
-
const alwaysRequests = this.page.getAlwaysRunRequests();
|
|
9694
|
-
const pageRequests = this.getAllPageRequests();
|
|
9695
|
-
// IMPORTANT: Because there's no way to differentiate a cmpDef prediction from the page
|
|
9696
|
-
// requesting the cmpDef, we need to predict cmpDefs before we start watching
|
|
9697
|
-
// for predictions in the page. Having this code after an
|
|
9698
|
-
// await will make the predictions to be saved as predictions too.
|
|
9699
|
-
predictNonBoxcarableRequest(pageRequests.filter((r) => !isBoxcarableRequest(r, requestStrategyManager)), this.requestRunner);
|
|
9700
|
-
const alwaysRequestEntries = alwaysRequests.map((request) => {
|
|
9701
|
-
return {
|
|
9702
|
-
request,
|
|
9703
|
-
requestMetadata: { requestTime: 0 }, // ensures always requests are executed, and executed first.
|
|
9704
|
-
};
|
|
9705
|
-
});
|
|
9706
|
-
const boxcarablePredictions = pageRequests.filter((r) => isBoxcarableRequest(r, requestStrategyManager));
|
|
9707
|
-
const reducedPredictions = this.page.shouldReduceAlwaysRequestsWithPredictions()
|
|
9708
|
-
? this.requestRunner.reduceRequests([...boxcarablePredictions, ...alwaysRequestEntries])
|
|
9709
|
-
: this.requestRunner.reduceRequests(boxcarablePredictions);
|
|
9710
|
-
// Sorting in order requested
|
|
9711
|
-
reducedPredictions.sort((a, b) => compareByPriorityThenTime(a, b, requestStrategyManager, context));
|
|
9712
|
-
// When available, alwaysRequestEntries are prioritized.
|
|
9713
|
-
return this.page.shouldExecuteAlwaysRequestByThemself()
|
|
9714
|
-
? [...alwaysRequestEntries, ...reducedPredictions]
|
|
9715
|
-
: reducedPredictions;
|
|
9716
|
-
}
|
|
9717
|
-
async predict() {
|
|
9718
|
-
const requests = this.getPredictedRequestsOrderedByPriority();
|
|
9719
|
-
this.totalRequestCount = requests.length;
|
|
9720
|
-
if (isUseHotspotLimitOpen()) {
|
|
9721
|
-
await runRequestsWithHotspotLimit(requests, this.requestRunner, Math.floor(this.options.inflightRequestLimit / 2));
|
|
9722
|
-
}
|
|
9723
|
-
else {
|
|
9724
|
-
await runRequestsWithLimit(requests, this.requestRunner,
|
|
9725
|
-
// don't get available thread count below threshold else Aura will boxcar
|
|
9726
|
-
this.options.inflightRequestLimit - AURA_BOXCAR_THREADS_THRESHOLD,
|
|
9727
|
-
// `this.repository.pageStartTime` would be the correct here,
|
|
9728
|
-
// but when doing predict+watch, it could be (set in watch)
|
|
9729
|
-
// repository.startTime is not set yet, Date.now() is a better alternative,
|
|
9730
|
-
// that is correct, and works on both cases.
|
|
9731
|
-
Date.now());
|
|
9732
|
-
}
|
|
9733
|
-
}
|
|
9734
|
-
}
|
|
9735
|
-
|
|
9736
|
-
class LexRequestRunner {
|
|
9737
|
-
constructor(requestStrategyManager) {
|
|
9738
|
-
this.requestStrategyManager = requestStrategyManager;
|
|
9739
|
-
this.requestStrategyManager = requestStrategyManager;
|
|
9740
|
-
}
|
|
9741
|
-
reduceRequests(requests) {
|
|
9742
|
-
return this.requestStrategyManager
|
|
9743
|
-
.getAll()
|
|
9744
|
-
.map((strategy) => strategy.reduce(requests))
|
|
9745
|
-
.flat();
|
|
9746
|
-
}
|
|
9747
|
-
runRequest(request, options = {}) {
|
|
9748
|
-
const strategy = this.requestStrategyManager.get(request.adapterName);
|
|
9749
|
-
if (strategy) {
|
|
9750
|
-
return Promise.resolve(strategy.execute(request.config, options)).then();
|
|
9751
|
-
}
|
|
9752
|
-
return Promise.resolve(undefined);
|
|
9753
|
-
}
|
|
9754
|
-
}
|
|
9755
|
-
|
|
9756
|
-
class InMemoryPrefetchStorage {
|
|
9757
|
-
constructor() {
|
|
9758
|
-
this.data = {};
|
|
9759
|
-
}
|
|
9760
|
-
set(key, value) {
|
|
9761
|
-
this.data[key] = value;
|
|
9762
|
-
return Promise.resolve();
|
|
9763
|
-
}
|
|
9764
|
-
get(key) {
|
|
9765
|
-
return this.data[key];
|
|
9766
|
-
}
|
|
9767
|
-
}
|
|
9768
|
-
|
|
9769
|
-
const DEFAULT_STORAGE_OPTIONS = {
|
|
9770
|
-
name: 'ldsPredictiveLoading',
|
|
9771
|
-
persistent: true,
|
|
9772
|
-
secure: true,
|
|
9773
|
-
maxSize: 7 * 1024 * 1024,
|
|
9774
|
-
expiration: 5 * 24 * 60 * 60,
|
|
9775
|
-
clearOnInit: false,
|
|
9776
|
-
debugLogging: false,
|
|
9777
|
-
version: 3,
|
|
9778
|
-
};
|
|
9779
|
-
function buildAuraPrefetchStorage(options = {}) {
|
|
9780
|
-
const { onPredictionsReadyCallback, ...storageOptions } = options;
|
|
9781
|
-
const auraStorage = createStorage({
|
|
9782
|
-
...DEFAULT_STORAGE_OPTIONS,
|
|
9783
|
-
...storageOptions,
|
|
9784
|
-
});
|
|
9785
|
-
const inMemoryStorage = new InMemoryPrefetchStorage();
|
|
9786
|
-
if (auraStorage === null) {
|
|
9787
|
-
return inMemoryStorage;
|
|
9788
|
-
}
|
|
9789
|
-
return new AuraPrefetchStorage(auraStorage, inMemoryStorage, onPredictionsReadyCallback);
|
|
9790
|
-
}
|
|
9791
|
-
function buildAuraLocalStoragePrefetchStorage(options = {}) {
|
|
9792
|
-
const { onPredictionsReadyCallback, ...storageOptions } = options;
|
|
9793
|
-
const auraStorage = createStorage({
|
|
9794
|
-
...DEFAULT_STORAGE_OPTIONS,
|
|
9795
|
-
...storageOptions,
|
|
9796
|
-
secure: false,
|
|
9797
|
-
adapterType: 'localstorage',
|
|
9798
|
-
name: 'pdl',
|
|
9799
|
-
maxSize: 4096000, // 4MB
|
|
9800
|
-
});
|
|
9801
|
-
if (auraStorage === null) {
|
|
9802
|
-
return buildAuraPrefetchStorage(options);
|
|
9803
|
-
}
|
|
9804
|
-
const inMemoryStorage = new InMemoryPrefetchStorage();
|
|
9805
|
-
return new AuraPrefetchStorage(auraStorage, inMemoryStorage, onPredictionsReadyCallback);
|
|
9806
|
-
}
|
|
9807
|
-
class AuraPrefetchStorage {
|
|
9808
|
-
constructor(auraStorage, inMemoryStorage, onPredictionsReadyCallback = () => { }) {
|
|
9809
|
-
this.auraStorage = auraStorage;
|
|
9810
|
-
this.inMemoryStorage = inMemoryStorage;
|
|
9811
|
-
/**
|
|
9812
|
-
* Because of aura is an event loop hog and we therefore need to minimize asynchronicity in LEX,
|
|
9813
|
-
* we need need to preload predictions and treat read operations sync. Not making it sync, will cause
|
|
9814
|
-
* some request to be sent the network when they could be dedupe against those from the predictions.
|
|
9815
|
-
*
|
|
9816
|
-
* Drawbacks of this approach:
|
|
9817
|
-
* 1. Loading all of aura storage into memory and then updating it based on changes to that in memory
|
|
9818
|
-
* representation means that updates to predictions in aura storage across different tabs will result
|
|
9819
|
-
* in overwrites, not graceful merges of predictions.
|
|
9820
|
-
* 2. If whoever is consuming this tries to get and run predictions before this is done loading,
|
|
9821
|
-
* then they will (potentially incorrectly) think that we don't have any predictions.
|
|
9822
|
-
*/
|
|
9823
|
-
auraStorage.getAll().then((results) => {
|
|
9824
|
-
keys(results).forEach((key) => this.inMemoryStorage.set(key, results[key]));
|
|
9825
|
-
onPredictionsReadyCallback();
|
|
9826
|
-
});
|
|
9827
|
-
}
|
|
9828
|
-
set(key, value) {
|
|
9829
|
-
const inMemoryResult = this.inMemoryStorage.set(key, value);
|
|
9830
|
-
this.auraStorage.set(key, value).catch((error) => {
|
|
9831
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
9832
|
-
// eslint-disable-next-line no-console
|
|
9833
|
-
console.error('Error save LDS prediction: ', error);
|
|
9834
|
-
}
|
|
9835
|
-
});
|
|
9836
|
-
return inMemoryResult;
|
|
9837
|
-
}
|
|
9838
|
-
get(key) {
|
|
9839
|
-
// we never read from the AuraStorage, except in construction.
|
|
9840
|
-
return this.inMemoryStorage.get(key);
|
|
9841
|
-
}
|
|
9842
|
-
}
|
|
9843
|
-
|
|
9844
|
-
function isLocalStorageAvailable() {
|
|
9845
|
-
try {
|
|
9846
|
-
const testKey = 'test';
|
|
9847
|
-
window.localStorage.setItem(testKey, '1');
|
|
9848
|
-
window.localStorage.removeItem(testKey);
|
|
9849
|
-
return true;
|
|
9850
|
-
}
|
|
9851
|
-
catch (e) {
|
|
9852
|
-
return false;
|
|
9853
|
-
}
|
|
9854
|
-
}
|
|
9855
|
-
function buildPrefetchStorage(useLocalStorage, options) {
|
|
9856
|
-
if (useLocalStorage && isLocalStorageAvailable()) {
|
|
9857
|
-
return buildAuraLocalStoragePrefetchStorage(options);
|
|
9858
|
-
}
|
|
9859
|
-
else {
|
|
9860
|
-
return buildAuraPrefetchStorage(options);
|
|
9861
|
-
}
|
|
9862
|
-
}
|
|
9863
|
-
|
|
9864
|
-
class NoComposedAdapterTypeError extends TypeError {
|
|
9865
|
-
constructor(message, resourceRequest) {
|
|
9866
|
-
super(message);
|
|
9867
|
-
this.resourceRequest = resourceRequest;
|
|
9868
|
-
}
|
|
9869
|
-
}
|
|
9870
|
-
|
|
9871
|
-
function buildComposableNetworkAdapter(composedAdapters) {
|
|
9872
|
-
return (resourceRequest, resourceRequestContext) => {
|
|
9873
|
-
const composedAdapter = composedAdapters.find((adapter) => adapter.shouldHandleRequest(resourceRequest));
|
|
9874
|
-
if (composedAdapter === undefined) {
|
|
9875
|
-
throw new NoComposedAdapterTypeError('There are no network adapters that can process the request.', resourceRequest);
|
|
9876
|
-
}
|
|
9877
|
-
return composedAdapter.adapter(resourceRequest, resourceRequestContext);
|
|
9878
|
-
};
|
|
9879
|
-
}
|
|
9880
|
-
|
|
9881
|
-
function getComposedAdapters() {
|
|
9882
|
-
const composedAdapters = [
|
|
9883
|
-
composedNetworkAdapter$1, // SFAP adapter
|
|
9884
|
-
];
|
|
9885
|
-
// Add the UIAPI Fetch adapter if any of its API paths are enabled
|
|
9886
|
-
if (isFetchAdapterEnabled()) {
|
|
9887
|
-
composedAdapters.push(composedFetchNetworkAdapter); // UIAPI Fetch adapter
|
|
9888
|
-
}
|
|
9889
|
-
return composedAdapters;
|
|
9890
|
-
}
|
|
9891
|
-
const composedNetworkAdapter = buildComposableNetworkAdapter([
|
|
9892
|
-
...getComposedAdapters(),
|
|
9893
|
-
// The aura network adapter must be the default.
|
|
9894
|
-
{
|
|
9895
|
-
shouldHandleRequest() {
|
|
9896
|
-
return true;
|
|
9897
|
-
},
|
|
9898
|
-
adapter: auraNetworkAdapter,
|
|
9899
|
-
},
|
|
9900
|
-
]);
|
|
9901
|
-
// Route dispatcher-synthesized sub-requests (e.g. aggregate-ui) back through
|
|
9902
|
-
// the composed adapter so shouldHandleRequest and interceptors apply uniformly.
|
|
9903
|
-
registerSubRequestNetworkAdapter(composedNetworkAdapter);
|
|
9904
|
-
|
|
9905
|
-
const OBJECT_INFO_PREFIX = 'UiApi::ObjectInfoRepresentation:';
|
|
9906
|
-
/**
|
|
9907
|
-
* Watch a Luvio instance for metadata changes.
|
|
9908
|
-
*/
|
|
9909
|
-
function setupMetadataWatcher(luvio) {
|
|
9910
|
-
// Watch for object info changes. Since we don't have enough information to understand to which
|
|
9911
|
-
// extent an object info change may impact the application the only thing we do is to clear all
|
|
9912
|
-
// the persistent storages.
|
|
9913
|
-
luvio.storeWatch(OBJECT_INFO_PREFIX, (entries) => {
|
|
9914
|
-
for (let i = 0, len = entries.length; i < len; i++) {
|
|
9915
|
-
const entry = entries[i];
|
|
9916
|
-
const isObjectInfoUpdated = entry.inserted === false;
|
|
9917
|
-
if (isObjectInfoUpdated) {
|
|
9918
|
-
logObjectInfoChanged();
|
|
9919
|
-
clearStorages().catch(() => {
|
|
9920
|
-
/* noop */
|
|
9921
|
-
});
|
|
9922
|
-
break;
|
|
9923
|
-
}
|
|
9924
|
-
}
|
|
9925
|
-
});
|
|
9926
|
-
}
|
|
9927
|
-
|
|
9928
|
-
class RequestStrategyManager {
|
|
9929
|
-
constructor(requestStrategies = []) {
|
|
9930
|
-
this.requestStrategies = [];
|
|
9931
|
-
this.requestStrategiesByAdapterName = new Map();
|
|
9932
|
-
this.register(requestStrategies);
|
|
9933
|
-
}
|
|
9934
|
-
setRequestStrategy(requestStrategy) {
|
|
9935
|
-
const adapterName = requestStrategy.adapterName;
|
|
9936
|
-
if (!this.requestStrategiesByAdapterName.has(adapterName)) {
|
|
9937
|
-
this.requestStrategiesByAdapterName.set(adapterName, requestStrategy);
|
|
9938
|
-
this.requestStrategies.push(requestStrategy);
|
|
9939
|
-
return true;
|
|
9940
|
-
}
|
|
9941
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
9942
|
-
throw new Error(`Registered an already existing request strategy: ${adapterName}`);
|
|
9943
|
-
}
|
|
9944
|
-
return false;
|
|
9945
|
-
}
|
|
9946
|
-
deleteRequestStrategy(requestStrategy) {
|
|
9947
|
-
const adapterName = requestStrategy.adapterName;
|
|
9948
|
-
if (this.requestStrategiesByAdapterName.has(adapterName)) {
|
|
9949
|
-
this.requestStrategiesByAdapterName.delete(adapterName);
|
|
9950
|
-
const indexToRemove = this.requestStrategies.findIndex((strategy) => strategy === requestStrategy);
|
|
9951
|
-
this.requestStrategies.splice(indexToRemove, 1);
|
|
9952
|
-
return true;
|
|
9953
|
-
}
|
|
9954
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
9955
|
-
throw new Error(`Could not find existing request strategy to unregister: ${adapterName}`);
|
|
9956
|
-
}
|
|
9957
|
-
return false;
|
|
9958
|
-
}
|
|
9959
|
-
register(requestStrategies) {
|
|
9960
|
-
return requestStrategies.map((requestStrategy) => this.setRequestStrategy(requestStrategy));
|
|
9961
|
-
}
|
|
9962
|
-
unregister(requestStrategies) {
|
|
9963
|
-
return requestStrategies.map((requestStrategy) => this.deleteRequestStrategy(requestStrategy));
|
|
9964
|
-
}
|
|
9965
|
-
get(adapterName) {
|
|
9966
|
-
return this.requestStrategiesByAdapterName.get(adapterName);
|
|
9967
|
-
}
|
|
9968
|
-
getAll() {
|
|
9969
|
-
return this.requestStrategies;
|
|
9970
|
-
}
|
|
9971
|
-
}
|
|
9972
|
-
|
|
9973
|
-
/**
|
|
9974
|
-
* Manages the state of predictions and notifies registered callbacks when predictions are ready.
|
|
9975
|
-
*/
|
|
9976
|
-
class PredictionsReadyManager {
|
|
9977
|
-
constructor() {
|
|
9978
|
-
/**
|
|
9979
|
-
* Array of callbacks to be executed when predictions are ready.
|
|
9980
|
-
* @private
|
|
9981
|
-
*/
|
|
9982
|
-
this.predictionsReadyCallbacks = [];
|
|
9983
|
-
/**
|
|
9984
|
-
* Indicates whether the predictions are ready.
|
|
9985
|
-
* @private
|
|
9986
|
-
*/
|
|
9987
|
-
this.predictionsReady = false;
|
|
9988
|
-
}
|
|
9989
|
-
/**
|
|
9990
|
-
* Registers a callback to be called when predictions are ready.
|
|
9991
|
-
* If predictions are already ready, the callback is invoked immediately.
|
|
9992
|
-
*
|
|
9993
|
-
* @param {() => void} callback - The callback function to be executed when predictions are ready.
|
|
9994
|
-
*/
|
|
9995
|
-
whenPredictionsReady(callback) {
|
|
9996
|
-
if (this.predictionsReady) {
|
|
9997
|
-
callback();
|
|
9998
|
-
}
|
|
9999
|
-
else {
|
|
10000
|
-
this.predictionsReadyCallbacks.push(callback);
|
|
10001
|
-
}
|
|
10002
|
-
}
|
|
10003
|
-
/**
|
|
10004
|
-
* Notifies that predictions are ready by invoking all registered callbacks.
|
|
10005
|
-
*/
|
|
10006
|
-
notifyPredictionsReady() {
|
|
10007
|
-
this.predictionsReady = true;
|
|
10008
|
-
this.predictionsReadyCallbacks.forEach((cb) => cb());
|
|
10009
|
-
}
|
|
10010
|
-
/**
|
|
10011
|
-
* Retrieves the list of callbacks registered to be executed when predictions are ready.
|
|
10012
|
-
*
|
|
10013
|
-
* @returns {Array<() => void>} Array of callback functions.
|
|
10014
|
-
*/
|
|
10015
|
-
getCallbacks() {
|
|
10016
|
-
return this.predictionsReadyCallbacks;
|
|
10017
|
-
}
|
|
10018
|
-
}
|
|
10019
|
-
|
|
10020
|
-
class CacheInclusionPolicyService {
|
|
10021
|
-
}
|
|
10022
|
-
class Ok {
|
|
10023
|
-
constructor(value) {
|
|
10024
|
-
this.value = value;
|
|
10025
|
-
}
|
|
10026
|
-
isOk() {
|
|
10027
|
-
return true;
|
|
10028
|
-
}
|
|
10029
|
-
isErr() {
|
|
10030
|
-
return !this.isOk();
|
|
10031
|
-
}
|
|
10032
|
-
}
|
|
10033
|
-
const ok = (value) => new Ok(value);
|
|
10034
|
-
function setDifference(setA, setB) {
|
|
10035
|
-
const differenceSet = /* @__PURE__ */ new Set();
|
|
10036
|
-
for (const element of setA) {
|
|
10037
|
-
if (!setB.has(element)) {
|
|
10038
|
-
differenceSet.add(element);
|
|
10039
|
-
}
|
|
10040
|
-
}
|
|
10041
|
-
return differenceSet;
|
|
10042
|
-
}
|
|
10043
|
-
function addAllToSet(targetSet, sourceSet) {
|
|
10044
|
-
for (const element of sourceSet) {
|
|
10045
|
-
targetSet.add(element);
|
|
10046
|
-
}
|
|
10047
|
-
}
|
|
10048
|
-
function resolvedPromiseLike(result) {
|
|
10049
|
-
if (isPromiseLike(result)) {
|
|
10050
|
-
return result.then(
|
|
10051
|
-
(nextResult) => nextResult
|
|
10052
|
-
);
|
|
10053
|
-
}
|
|
10054
|
-
return {
|
|
10055
|
-
then: (onFulfilled, _onRejected) => {
|
|
10056
|
-
try {
|
|
10057
|
-
return resolvedPromiseLike(onFulfilled(result));
|
|
10058
|
-
} catch (e) {
|
|
10059
|
-
if (onFulfilled === void 0) {
|
|
10060
|
-
return resolvedPromiseLike(result);
|
|
10061
|
-
}
|
|
10062
|
-
return rejectedPromiseLike(e);
|
|
10063
|
-
}
|
|
10064
|
-
}
|
|
10065
|
-
};
|
|
7984
|
+
};
|
|
10066
7985
|
}
|
|
10067
7986
|
function rejectedPromiseLike(reason) {
|
|
10068
7987
|
if (isPromiseLike(reason)) {
|
|
@@ -11120,9 +9039,12 @@ register({
|
|
|
11120
9039
|
// Publish buildPredictorForContext on the force/ldsEngine registration bus so that
|
|
11121
9040
|
// shared laf loaders can obtain it without a dynamic import of the aura ldsEngineCreator module,
|
|
11122
9041
|
// which would evaluate this whole bootstrap a second time. See ADR
|
|
11123
|
-
// 2026-07-10-pdl-service-provisioner-decoupling.
|
|
11124
|
-
//
|
|
11125
|
-
//
|
|
9042
|
+
// 2026-07-10-pdl-service-provisioner-decoupling. Predictive data loading (PDL) has been
|
|
9043
|
+
// removed from this default engine creator (LEX now boots the One Runtime / one.app engine
|
|
9044
|
+
// creators, which carry their own PDL), so buildPredictorForContext is a permanent no-op
|
|
9045
|
+
// that returns undefined. The registration is retained so those shared cross-runtime laf
|
|
9046
|
+
// loaders still resolve a defined function off the bus and take their existing
|
|
9047
|
+
// "no predictor" path.
|
|
11126
9048
|
register({
|
|
11127
9049
|
id: PDL_ENGINE_REGISTRATION_ID,
|
|
11128
9050
|
buildPredictorForContext,
|
|
@@ -11143,91 +9065,6 @@ function setupQueryEvaluators(luvio, store) {
|
|
|
11143
9065
|
luvio.registerStoreQueryEvaluator(baseQueryEvaluator);
|
|
11144
9066
|
luvio.registerTypeQueryEvaluator(UiApiNamespace, RecordRepresentationRepresentationType, recordRepresentationQueryEvaluator);
|
|
11145
9067
|
}
|
|
11146
|
-
let __lexPrefetcher;
|
|
11147
|
-
const requestStrategyManager = new RequestStrategyManager();
|
|
11148
|
-
/**
|
|
11149
|
-
* Registers a request strategy to be utilized by PDL.
|
|
11150
|
-
* @param requestStrategy - {@link LexRequestStrategy} The request strategy/strategies to register.
|
|
11151
|
-
* @returns boolean | boolean[] - true/false depending on registration success.
|
|
11152
|
-
*/
|
|
11153
|
-
function registerRequestStrategy(...requestStrategy) {
|
|
11154
|
-
const result = requestStrategyManager.register(requestStrategy);
|
|
11155
|
-
return result.length === 1 ? result[0] : result;
|
|
11156
|
-
}
|
|
11157
|
-
/**
|
|
11158
|
-
* Unregisters a request strategy to be utilized by PDL.
|
|
11159
|
-
* @param requestStrategy - {@link LexRequestStrategy} The request strategy to unregister.
|
|
11160
|
-
* @returns boolean | boolean[] - true/false depending on unregistration success.
|
|
11161
|
-
*/
|
|
11162
|
-
function unregisterRequestStrategy(...requestStrategy) {
|
|
11163
|
-
const result = requestStrategyManager.unregister(requestStrategy);
|
|
11164
|
-
return result.length === 1 ? result[0] : result;
|
|
11165
|
-
}
|
|
11166
|
-
const predictionsReadyManager = new PredictionsReadyManager();
|
|
11167
|
-
function whenPredictionsReady(callback) {
|
|
11168
|
-
predictionsReadyManager.whenPredictionsReady(callback);
|
|
11169
|
-
}
|
|
11170
|
-
function setupPredictivePrefetcher(luvio) {
|
|
11171
|
-
const allStrategies = [
|
|
11172
|
-
new GetRecordRequestStrategy(luvio, canCombineRecordLayoutRequests.isOpen({ fallback: false })),
|
|
11173
|
-
new GetRecordsRequestStrategy(luvio),
|
|
11174
|
-
new GetRecordActionsRequestStrategy(luvio),
|
|
11175
|
-
new GetRecordAvatarsRequestStrategy(luvio),
|
|
11176
|
-
new GetObjectInfoRequestStrategy(luvio),
|
|
11177
|
-
new GetObjectInfosRequestStrategy(luvio),
|
|
11178
|
-
new GetRelatedListsActionsRequestStrategy(luvio),
|
|
11179
|
-
new GetRelatedListRecordsRequestStrategy(luvio),
|
|
11180
|
-
new GetRelatedListRecordsBatchRequestStrategy(luvio),
|
|
11181
|
-
new GetRelatedListInfoRequestStrategy(luvio),
|
|
11182
|
-
new GetRelatedListInfoBatchRequestStrategy(luvio),
|
|
11183
|
-
new GetListInfoByNameRequestStrategy(luvio),
|
|
11184
|
-
new GetListRecordsByNameRequestStrategy(luvio),
|
|
11185
|
-
new GetApexRequestStrategy(luvio),
|
|
11186
|
-
new GetListInfosByObjectNameRequestStrategy(luvio),
|
|
11187
|
-
new GetListObjectInfoRequestStrategy(luvio),
|
|
11188
|
-
new GetRelatedListsInfoRequestStrategy(luvio),
|
|
11189
|
-
new GetRelatedListActionsRequestStrategy(luvio),
|
|
11190
|
-
];
|
|
11191
|
-
requestStrategyManager.register(allStrategies);
|
|
11192
|
-
const storage = buildPrefetchStorage(useLocalStorage.isOpen({ fallback: false }), {
|
|
11193
|
-
onPredictionsReadyCallback: () => predictionsReadyManager.notifyPredictionsReady(),
|
|
11194
|
-
});
|
|
11195
|
-
const requestRunner = new LexRequestRunner(requestStrategyManager);
|
|
11196
|
-
const repository = new PrefetchRepository(storage, {
|
|
11197
|
-
modifyBeforeSaveHook: (requests) => requestRunner.reduceRequests(requests),
|
|
11198
|
-
modifyPageBeforeSavingHook: (page) => {
|
|
11199
|
-
if (RecordHomePage.handlesContext(__lexPrefetcher.context)) {
|
|
11200
|
-
page.recordTypeId = __lexPrefetcher.context.recordTypeId;
|
|
11201
|
-
}
|
|
11202
|
-
},
|
|
11203
|
-
});
|
|
11204
|
-
const inflightRequestLimit = configService.config.maxAllowedParallelXHRCounts;
|
|
11205
|
-
const prefetcherOptions = {
|
|
11206
|
-
inflightRequestLimit,
|
|
11207
|
-
};
|
|
11208
|
-
const eventEmitter = new PrefetcherEventEmitter();
|
|
11209
|
-
const prefetcher = new LexPredictivePrefetcher({ context: 'unknown' }, repository, requestRunner, eventEmitter, requestStrategyManager, prefetcherOptions);
|
|
11210
|
-
registerPrefetcher(luvio, prefetcher);
|
|
11211
|
-
registerPrefetcher$1(luvio, prefetcher);
|
|
11212
|
-
__lexPrefetcher = prefetcher;
|
|
11213
|
-
}
|
|
11214
|
-
function saveRequestAsPrediction(request) {
|
|
11215
|
-
if (__lexPrefetcher !== undefined) {
|
|
11216
|
-
__lexPrefetcher.saveRequest(request);
|
|
11217
|
-
}
|
|
11218
|
-
}
|
|
11219
|
-
/**
|
|
11220
|
-
* Subscribes to a specific prefetcher event type.
|
|
11221
|
-
* @param type - The type of event to subscribe to.
|
|
11222
|
-
* @param callback - The callback to invoke when the specified event occurs.
|
|
11223
|
-
* @returns A function to unsubscribe from the prefetcher events.
|
|
11224
|
-
*/
|
|
11225
|
-
function subscribeToPrefetcherEvents(type, callback) {
|
|
11226
|
-
if (__lexPrefetcher !== undefined) {
|
|
11227
|
-
return __lexPrefetcher.subscribeToEvent(type, callback);
|
|
11228
|
-
}
|
|
11229
|
-
return () => { };
|
|
11230
|
-
}
|
|
11231
9068
|
// This is copied from lds-adapters-uiapi because the exports are totally messed up
|
|
11232
9069
|
const notifyUpdateAvailableFactory = (luvio) => {
|
|
11233
9070
|
return function notifyRecordUpdateAvailable(configs) {
|
|
@@ -11244,70 +9081,16 @@ const notifyUpdateAvailableFactory = (luvio) => {
|
|
|
11244
9081
|
};
|
|
11245
9082
|
};
|
|
11246
9083
|
/**
|
|
11247
|
-
*
|
|
11248
|
-
* @property {string} objectApiName - The API name of the object.
|
|
11249
|
-
* @property {string} recordId - The unique identifier for the record.
|
|
11250
|
-
* @property {string} actionName - The name of the action being performed.
|
|
11251
|
-
* @property {'recordPage'} type - The type of the context, specifically for a record page.
|
|
11252
|
-
*/
|
|
11253
|
-
/**
|
|
11254
|
-
* Builds a predictor for a given record home page context. This predictor is responsible for
|
|
11255
|
-
* preloading data based on predictions for the current context and create new predictions based
|
|
11256
|
-
* on page requests of this context.
|
|
9084
|
+
* Builds a predictor for a given page context.
|
|
11257
9085
|
*
|
|
11258
|
-
*
|
|
11259
|
-
*
|
|
11260
|
-
*
|
|
11261
|
-
*
|
|
11262
|
-
*
|
|
11263
|
-
* getPredictionSummary: () => Map<String,Number>
|
|
11264
|
-
* }} An object containing methods to handle predictions:
|
|
11265
|
-
* - hasPredictions: Checks if there are any predictions available.
|
|
11266
|
-
* - watchPageLoadForPredictions: Starts recording the page request for prediction purposes.
|
|
11267
|
-
* - runPredictions: Executes the predictions based on the recorded data and returns a promise
|
|
11268
|
-
* of when those predictions are completed.
|
|
11269
|
-
* - getPredictionSummary: Returns the count of exact and similar prediction requests
|
|
9086
|
+
* Predictive data loading (PDL) has been removed from the default LDS engine creator, so this
|
|
9087
|
+
* is a permanent no-op that returns undefined ("no predictor"). It is retained only to satisfy
|
|
9088
|
+
* the `@salesforce/lds-pdl-engine` bus registration above; shared cross-runtime laf loaders read
|
|
9089
|
+
* it off the bus and already handle an undefined result by skipping predictions. LEX predictive
|
|
9090
|
+
* loading now lives in the One Runtime / one.app engine creators.
|
|
11270
9091
|
*/
|
|
11271
|
-
function buildPredictorForContext(
|
|
11272
|
-
|
|
11273
|
-
if (__lexPrefetcher === undefined) {
|
|
11274
|
-
return;
|
|
11275
|
-
}
|
|
11276
|
-
const currentContext = __lexPrefetcher.context;
|
|
11277
|
-
let isSameContext = false;
|
|
11278
|
-
if (RecordHomePage.handlesContext(currentContext) && RecordHomePage.handlesContext(context)) {
|
|
11279
|
-
isSameContext =
|
|
11280
|
-
currentContext.actionName === context.actionName &&
|
|
11281
|
-
currentContext.objectApiName === context.objectApiName &&
|
|
11282
|
-
currentContext.recordId === context.recordId;
|
|
11283
|
-
}
|
|
11284
|
-
else if (ObjectHomePage.handlesContext(currentContext) &&
|
|
11285
|
-
ObjectHomePage.handlesContext(context)) {
|
|
11286
|
-
isSameContext =
|
|
11287
|
-
currentContext.objectApiName === context.objectApiName &&
|
|
11288
|
-
currentContext.listViewApiName === context.listViewApiName;
|
|
11289
|
-
}
|
|
11290
|
-
// // This chunk configures which page we're going to use to try and preload.
|
|
11291
|
-
__lexPrefetcher.context = context;
|
|
11292
|
-
return {
|
|
11293
|
-
hasPredictions() {
|
|
11294
|
-
return __lexPrefetcher.hasPredictions();
|
|
11295
|
-
},
|
|
11296
|
-
watchPageLoadForPredictions() {
|
|
11297
|
-
// This chunk tells the prefetcher to receive events, send off any predictions we have from previous loads, then setup idle detection to stop predicting.
|
|
11298
|
-
__lexPrefetcher.startRecording();
|
|
11299
|
-
onIdleDetected(() => __lexPrefetcher.stopRecording());
|
|
11300
|
-
},
|
|
11301
|
-
runPredictions() {
|
|
11302
|
-
if (isSameContext) {
|
|
11303
|
-
return Promise.resolve();
|
|
11304
|
-
}
|
|
11305
|
-
return executeAsyncActivity(METRIC_KEYS.PREDICTIVE_DATA_LOADING_PREDICT, (_act) => __lexPrefetcher.predict(), PDL_EXECUTE_ASYNC_OPTIONS);
|
|
11306
|
-
},
|
|
11307
|
-
getPredictionSummary() {
|
|
11308
|
-
return __lexPrefetcher.getPredictionSummary();
|
|
11309
|
-
},
|
|
11310
|
-
};
|
|
9092
|
+
function buildPredictorForContext(_context) {
|
|
9093
|
+
return undefined;
|
|
11311
9094
|
}
|
|
11312
9095
|
function initializeLDS() {
|
|
11313
9096
|
const storeOptions = {
|
|
@@ -11323,9 +9106,6 @@ function initializeLDS() {
|
|
|
11323
9106
|
setupQueryEvaluators(luvio, store);
|
|
11324
9107
|
setDefaultLuvio({ luvio });
|
|
11325
9108
|
setTrackedFieldsConfig();
|
|
11326
|
-
if (usePredictiveLoading.isOpen({ fallback: false })) {
|
|
11327
|
-
setupPredictivePrefetcher(luvio);
|
|
11328
|
-
}
|
|
11329
9109
|
return luvio; // Return the luvio instance so that we can inject it for OneStore
|
|
11330
9110
|
}
|
|
11331
9111
|
// W-23092947: fetch request tags allowed to stay on HTTP on Aura sites (external hosts).
|
|
@@ -11456,5 +9236,5 @@ function ldsEngineCreator() {
|
|
|
11456
9236
|
return { name: 'ldsEngineCreator' };
|
|
11457
9237
|
}
|
|
11458
9238
|
|
|
11459
|
-
export {
|
|
11460
|
-
// version: 1.
|
|
9239
|
+
export { PDL_ENGINE_REGISTRATION_ID, buildPredictorForContext, configService, ldsEngineCreator as default, initializeLDS, initializeOneStore, notifyUpdateAvailableFactory };
|
|
9240
|
+
// version: 1.461.0-37b1c9d1cb
|