@salesforce/lds-runtime-aura 1.302.0 → 1.304.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 +1676 -500
- package/dist/types/__mocks__/@salesforce/lds-network-fetch-with-jwt.d.ts +1 -0
- package/dist/types/__mocks__/instrumentation:beaconLib.d.ts +7 -0
- package/dist/types/jwt-authorized-fetch-service.d.ts +2 -0
- package/dist/types/language.d.ts +18 -0
- package/dist/types/network-fetch.d.ts +8 -0
- package/dist/types/network-instrumentation.d.ts +2 -0
- package/dist/types/network-sfap.d.ts +1 -1
- package/dist/types/predictive-loading/pages/object-home-page.d.ts +10 -5
- package/dist/types/predictive-loading/pages/record-home-page.d.ts +10 -4
- package/dist/types/predictive-loading/prefetcher/lex-predictive-prefetcher.d.ts +21 -4
- package/dist/types/predictive-loading/prefetcher/predictive-prefetcher.d.ts +1 -15
- package/dist/types/predictive-loading/repository/utils.d.ts +0 -2
- package/dist/types/predictive-loading/request-strategy/get-apex-request-strategy.d.ts +0 -4
- package/dist/types/predictive-loading/request-strategy/get-components-request-strategy.d.ts +4 -7
- package/dist/types/predictive-loading/request-strategy/get-list-info-by-name-request-strategy.d.ts +0 -4
- package/dist/types/predictive-loading/request-strategy/get-list-infos-by-object-name-request-strategy.d.ts +0 -4
- package/dist/types/predictive-loading/request-strategy/get-list-object-info-request-strategy.d.ts +16 -0
- package/dist/types/predictive-loading/request-strategy/get-list-records-by-name-request-strategy.d.ts +0 -4
- package/dist/types/predictive-loading/request-strategy/get-object-info-request-strategy.d.ts +2 -2
- package/dist/types/predictive-loading/request-strategy/get-object-infos-request-strategy.d.ts +2 -4
- package/dist/types/predictive-loading/request-strategy/get-related-list-records-request-strategy.d.ts +2 -2
- package/dist/types/predictive-loading/request-strategy/get-related-lists-actions-request-strategy.d.ts +1 -1
- package/dist/types/predictive-loading/request-strategy/index.d.ts +1 -1
- package/dist/types/predictive-loading/request-strategy/luvio-adapter-request-strategy.d.ts +6 -77
- package/dist/types/predictive-loading/request-strategy/request-strategy.d.ts +65 -4
- package/dist/types/predictive-loading/storage/aura-prefetch-storage.d.ts +2 -1
- package/package.json +33 -24
- package/dist/types/aura-instrumentation/utils/language.d.ts +0 -13
- package/dist/types/predictive-loading/request-strategy/config-based-request-strategy.d.ts +0 -15
- package/dist/types/predictive-loading/request-strategy/luvio-adapter-request.d.ts +0 -8
package/dist/ldsEngineCreator.js
CHANGED
|
@@ -19,23 +19,439 @@ import useApexPredictions from '@salesforce/gate/lds.pdl.useApexPredictions';
|
|
|
19
19
|
import useRelatedListsPredictions from '@salesforce/gate/lds.pdl.useRelatedListsPredictions';
|
|
20
20
|
import useCmpDefPredictions from '@salesforce/gate/lds.pdl.useCmpDefPredictions';
|
|
21
21
|
import applyPredictionRequestLimit from '@salesforce/gate/lds.pdl.applyRequestLimit';
|
|
22
|
-
import
|
|
22
|
+
import useExactMatchesPlusGate from '@salesforce/gate/lds.pdl.useExactMatchesPlus';
|
|
23
23
|
import { GetApexWireAdapterFactory, registerPrefetcher as registerPrefetcher$1 } from 'force/ldsAdaptersApex';
|
|
24
|
-
import { instrument, getRecordAvatarsAdapterFactory, getRecordAdapterFactory, coerceFieldIdArray, getRecordsAdapterFactory, getRecordActionsAdapterFactory, getObjectInfosAdapterFactory, coerceObjectIdArray, getObjectInfoAdapterFactory, coerceObjectId, getRelatedListsActionsAdapterFactory, getRelatedListInfoBatchAdapterFactory, getRelatedListRecordsBatchAdapterFactory, getRelatedListRecordsAdapterFactory, getListInfoByNameAdapterFactory, getListInfosByObjectNameAdapterFactory, getListRecordsByNameAdapterFactory, configuration, InMemoryRecordRepresentationQueryEvaluator, UiApiNamespace, RecordRepresentationRepresentationType, registerPrefetcher } from 'force/ldsAdaptersUiapi';
|
|
25
|
-
import {
|
|
24
|
+
import { instrument, getRecordAvatarsAdapterFactory, getRecordAdapterFactory, coerceFieldIdArray, getRecordsAdapterFactory, getRecordActionsAdapterFactory, getObjectInfosAdapterFactory, coerceObjectIdArray, getObjectInfoAdapterFactory, coerceObjectId, getRelatedListsActionsAdapterFactory, getRelatedListInfoBatchAdapterFactory, getRelatedListRecordsBatchAdapterFactory, getRelatedListRecordsAdapterFactory, getListInfoByNameAdapterFactory, getListInfosByObjectNameAdapterFactory, getListRecordsByNameAdapterFactory, getListObjectInfoAdapterFactory, configuration, InMemoryRecordRepresentationQueryEvaluator, UiApiNamespace, RecordRepresentationRepresentationType, registerPrefetcher } from 'force/ldsAdaptersUiapi';
|
|
25
|
+
import { BaseCommand, convertAuraResponseToData, convertFetchResponseToData } from 'force/luvioRuntime5';
|
|
26
|
+
import { serviceBroker } from 'force/luvioServiceBroker5';
|
|
26
27
|
import oneStoreEnabled from '@salesforce/gate/lds.oneStoreEnabled.ltng';
|
|
27
28
|
import oneStoreUiapiEnabled from '@salesforce/gate/lds.oneStoreUiapiEnabled.ltng';
|
|
28
29
|
import { getDefinition, executeGlobalControllerRawResponse } from 'aura';
|
|
30
|
+
import { buildJwtNetworkAdapter, setupLexJwtNetworkAdapter } from 'force/ldsNetworkFetchWithJwt';
|
|
31
|
+
import auraNetworkAdapter, { dispatchAuraAction, defaultActionConfig, instrument as instrument$1, forceRecordTransactionsDisabled as forceRecordTransactionsDisabled$1, ldsNetworkAdapterInstrument, CrudEventState, CrudEventType, UIAPI_RECORDS_PATH, UIAPI_RELATED_LIST_RECORDS_BATCH_PATH, UIAPI_RELATED_LIST_RECORDS_PATH } from 'force/ldsNetwork';
|
|
29
32
|
import { LRUCache, instrumentAdapter, instrumentLuvio, setupInstrumentation as setupInstrumentation$1, logObjectInfoChanged as logObjectInfoChanged$1, updatePercentileHistogramMetric, incrementCounterMetric, incrementGetRecordNotifyChangeAllowCount, incrementGetRecordNotifyChangeDropCount, incrementNotifyRecordUpdateAvailableAllowCount, incrementNotifyRecordUpdateAvailableDropCount, setLdsAdaptersUiapiInstrumentation, setLdsNetworkAdapterInstrumentation, executeAsyncActivity, METRIC_KEYS, onIdleDetected } from 'force/ldsInstrumentation';
|
|
30
33
|
import { REFRESH_ADAPTER_EVENT, ADAPTER_UNFULFILLED_ERROR, instrument as instrument$2 } from 'force/ldsBindings';
|
|
31
34
|
import { counter, registerCacheStats, perfStart, perfEnd, registerPeriodicLogger, interaction, timer } from 'instrumentation/service';
|
|
32
|
-
import auraNetworkAdapter, { instrument as instrument$1, forceRecordTransactionsDisabled, ldsNetworkAdapterInstrument, dispatchAuraAction, defaultActionConfig } from 'force/ldsNetwork';
|
|
33
35
|
import { instrument as instrument$3 } from 'force/adsBridge';
|
|
34
36
|
import { withRegistration, register, setDefaultLuvio } from 'force/ldsEngine';
|
|
35
37
|
import { createStorage, clearStorages } from 'force/ldsStorage';
|
|
36
|
-
import
|
|
38
|
+
import useHttpInsteadAuraTransport from '@salesforce/gate/lds.useHttpInsteadAuraTransport';
|
|
39
|
+
import { ThirdPartyTracker } from 'instrumentation:beaconLib';
|
|
37
40
|
import { getObjectInfo, getObjectInfos } from 'force/ldsAdaptersUiapiLex';
|
|
38
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Copyright (c) 2022, Salesforce, Inc.,
|
|
44
|
+
* All rights reserved.
|
|
45
|
+
* For full license text, see the LICENSE.txt file
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* An implementation of BaseCommand that makes network requests but does not try to
|
|
51
|
+
* use the store.
|
|
52
|
+
*/
|
|
53
|
+
class NetworkCommand extends BaseCommand {
|
|
54
|
+
constructor(services) {
|
|
55
|
+
super();
|
|
56
|
+
this.services = services;
|
|
57
|
+
}
|
|
58
|
+
execute() {
|
|
59
|
+
return this.fetch();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function buildNetworkCommandBaseClassService() {
|
|
63
|
+
return {
|
|
64
|
+
type: 'networkCommandBaseClass',
|
|
65
|
+
version: '1.0',
|
|
66
|
+
service: NetworkCommand,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Copyright (c) 2022, Salesforce, Inc.,
|
|
72
|
+
* All rights reserved.
|
|
73
|
+
* For full license text, see the LICENSE.txt file
|
|
74
|
+
*/
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* An implementation of BaseCommand that makes network requests but does not try to
|
|
79
|
+
* use the store.
|
|
80
|
+
*/
|
|
81
|
+
class AuraNetworkCommand extends NetworkCommand {
|
|
82
|
+
constructor(services) {
|
|
83
|
+
super(services);
|
|
84
|
+
this.services = services;
|
|
85
|
+
this.actionConfig = {
|
|
86
|
+
background: false,
|
|
87
|
+
hotspot: true,
|
|
88
|
+
longRunning: false,
|
|
89
|
+
storable: false,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
fetch() {
|
|
93
|
+
return convertAuraResponseToData(this.services.auraNetwork(this.endpoint, this.auraParams, this.actionConfig));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function buildAuraNetworkCommandBaseClassService() {
|
|
97
|
+
return {
|
|
98
|
+
type: 'auraNetworkCommandBaseClass',
|
|
99
|
+
version: '1.0',
|
|
100
|
+
service: AuraNetworkCommand,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Copyright (c) 2022, Salesforce, Inc.,
|
|
106
|
+
* All rights reserved.
|
|
107
|
+
* For full license text, see the LICENSE.txt file
|
|
108
|
+
*/
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* An implementation of BaseCommand that makes network requests but does not try to
|
|
113
|
+
* use the store.
|
|
114
|
+
*/
|
|
115
|
+
class FetchNetworkCommand extends NetworkCommand {
|
|
116
|
+
constructor(services) {
|
|
117
|
+
super(services);
|
|
118
|
+
this.services = services;
|
|
119
|
+
}
|
|
120
|
+
fetch() {
|
|
121
|
+
return convertFetchResponseToData(this.services.fetch(...this.fetchParams));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function buildFetchNetworkCommandBaseClassService() {
|
|
125
|
+
return {
|
|
126
|
+
type: 'fetchNetworkCommandBaseClass',
|
|
127
|
+
version: '1.0',
|
|
128
|
+
service: FetchNetworkCommand,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Copyright (c) 2022, Salesforce, Inc.,
|
|
134
|
+
* All rights reserved.
|
|
135
|
+
* For full license text, see the LICENSE.txt file
|
|
136
|
+
*/
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
function resolvedPromiseLike(result) {
|
|
140
|
+
// Don't nest anything promise like
|
|
141
|
+
if (isPromiseOrPromiseLike(result)) {
|
|
142
|
+
return result.then((nextResult) => nextResult);
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
then: (onFulfilled, _onRejected) => {
|
|
146
|
+
if (onFulfilled) {
|
|
147
|
+
try {
|
|
148
|
+
return resolvedPromiseLike(onFulfilled(result));
|
|
149
|
+
}
|
|
150
|
+
catch (e) {
|
|
151
|
+
return rejectedPromiseLike(e);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// assume TResult1 == Result and just pass result down the chain
|
|
155
|
+
return resolvedPromiseLike(result);
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Returns a PromiseLike object that rejects with the specified reason.
|
|
161
|
+
*
|
|
162
|
+
* @param reason rejection value
|
|
163
|
+
* @returns PromiseLike that rejects with reason
|
|
164
|
+
*/
|
|
165
|
+
function rejectedPromiseLike(reason) {
|
|
166
|
+
if (isPromiseOrPromiseLike(reason)) {
|
|
167
|
+
return reason.then((nextResult) => nextResult);
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
then: (_onFulfilled, onRejected) => {
|
|
171
|
+
if (onRejected) {
|
|
172
|
+
try {
|
|
173
|
+
return resolvedPromiseLike(onRejected(reason));
|
|
174
|
+
}
|
|
175
|
+
catch (e) {
|
|
176
|
+
return rejectedPromiseLike(e);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// assume TResult2 == Result and just pass rejection down the chain
|
|
180
|
+
return rejectedPromiseLike(reason);
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function isPromiseOrPromiseLike(value) {
|
|
185
|
+
return (value instanceof Promise ||
|
|
186
|
+
(typeof value === 'object' && value !== null && typeof value.then === 'function'));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Converts an arbitrary value to an Error.
|
|
191
|
+
*
|
|
192
|
+
* @param x anything
|
|
193
|
+
* @returns Error corresponding to x
|
|
194
|
+
*/
|
|
195
|
+
function toError(x) {
|
|
196
|
+
if (x instanceof Error) {
|
|
197
|
+
return x;
|
|
198
|
+
}
|
|
199
|
+
return new Error(`${x}`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
class Ok {
|
|
203
|
+
constructor(value) {
|
|
204
|
+
this.value = value;
|
|
205
|
+
}
|
|
206
|
+
isOk() {
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
isErr() {
|
|
210
|
+
return !this.isOk();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
class Err {
|
|
214
|
+
constructor(error) {
|
|
215
|
+
this.error = error;
|
|
216
|
+
}
|
|
217
|
+
isOk() {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
isErr() {
|
|
221
|
+
return !this.isOk();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const ok = (value) => new Ok(value);
|
|
225
|
+
const err = (err) => new Err(err);
|
|
226
|
+
// an error to indicate that the data inside a Result construct
|
|
227
|
+
// is missing or incomplete
|
|
228
|
+
class DataNotFoundError extends Error {
|
|
229
|
+
constructor(message) {
|
|
230
|
+
super(message);
|
|
231
|
+
this.name = 'DataNotFoundError';
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
class DataIncompleteError extends Error {
|
|
235
|
+
constructor(message, partialData) {
|
|
236
|
+
super(message);
|
|
237
|
+
this.partialData = partialData;
|
|
238
|
+
this.name = 'DataIncompleteError';
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function isDataNotFoundError(error) {
|
|
242
|
+
return error instanceof DataNotFoundError || error.name === 'DataNotFoundError';
|
|
243
|
+
}
|
|
244
|
+
function isDataIncompleteError(error) {
|
|
245
|
+
return error instanceof DataIncompleteError || error.name === 'DataIncompleteError';
|
|
246
|
+
}
|
|
247
|
+
function isCacheHitOrError(value) {
|
|
248
|
+
if (value.isErr() && (isDataIncompleteError(value.error) || isDataNotFoundError(value.error))) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Copyright (c) 2022, Salesforce, Inc.,
|
|
256
|
+
* All rights reserved.
|
|
257
|
+
* For full license text, see the LICENSE.txt file
|
|
258
|
+
*/
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* An implementation of BaseCommand that supports streaming responses and does not use the store.
|
|
263
|
+
*/
|
|
264
|
+
class StreamingCommand extends BaseCommand {
|
|
265
|
+
constructor(services) {
|
|
266
|
+
super();
|
|
267
|
+
this.services = services;
|
|
268
|
+
}
|
|
269
|
+
execute() {
|
|
270
|
+
return this.convertFetchStreamResponseToData(this.services.fetch(...this.fetchParams));
|
|
271
|
+
}
|
|
272
|
+
convertFetchStreamResponseToData(response) {
|
|
273
|
+
return response.then((response) => {
|
|
274
|
+
if (response.ok && response.body) {
|
|
275
|
+
return ok(this.decodeByteStream(response.body));
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
return err(toError(response.ok ? 'Response body not present' : response.statusText));
|
|
279
|
+
}
|
|
280
|
+
}, (reason) => err(toError(reason)));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
function buildStreamingCommandBaseClassService() {
|
|
284
|
+
return {
|
|
285
|
+
type: 'streamingCommandBaseClass',
|
|
286
|
+
version: '1.0',
|
|
287
|
+
service: StreamingCommand,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Copyright (c) 2022, Salesforce, Inc.,
|
|
293
|
+
* All rights reserved.
|
|
294
|
+
* For full license text, see the LICENSE.txt file
|
|
295
|
+
*/
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* An implementation of StreamingCommand that handles SSE (Server-Sent Event) streams.
|
|
300
|
+
*/
|
|
301
|
+
class SSECommand extends StreamingCommand {
|
|
302
|
+
constructor(services) {
|
|
303
|
+
super(services);
|
|
304
|
+
this.services = services;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Decodes the bytes returned by fetch into the correct shape.
|
|
308
|
+
*
|
|
309
|
+
* @param byteStream ReadableStream<Uint8Array> returned by fetch
|
|
310
|
+
* @returns ReadableStream<StreamedData> that will be the result of the Command
|
|
311
|
+
*/
|
|
312
|
+
decodeByteStream(byteStream) {
|
|
313
|
+
return this.decodeSSEStream(byteStream
|
|
314
|
+
// eslint-disable-next-line no-undef
|
|
315
|
+
.pipeThrough(new TextDecoderStream())
|
|
316
|
+
.pipeThrough(new SSEParsingStream()));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
function buildSSECommandBaseClassService() {
|
|
320
|
+
return {
|
|
321
|
+
type: 'SSECommandBaseClass',
|
|
322
|
+
version: '1.0',
|
|
323
|
+
service: SSECommand,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
const sseRegex = /^(?<field>[^:]*?)(: ?(?<value>.*?))?(?:\r\n?|\n)/;
|
|
327
|
+
// +-------v------++--------v--------++-----v----+
|
|
328
|
+
// | | |
|
|
329
|
+
// | | CRLF | CR | LF
|
|
330
|
+
// | |
|
|
331
|
+
// | ": value", or ": comment" if no field name (optional)
|
|
332
|
+
// |
|
|
333
|
+
// field name (optional); can be entire line if no ":"
|
|
334
|
+
class SSEParsingStream extends TransformStream {
|
|
335
|
+
constructor() {
|
|
336
|
+
let ignoreLeadingLF = false, partialLine = '', data = '', event = '', id = '', retry;
|
|
337
|
+
super({
|
|
338
|
+
transform(chunk, controller) {
|
|
339
|
+
// account for case where chunk boundary splits \r\n
|
|
340
|
+
if (ignoreLeadingLF && chunk.startsWith('\n')) {
|
|
341
|
+
// eslint-disable-next-line no-param-reassign
|
|
342
|
+
chunk = chunk.slice(1);
|
|
343
|
+
}
|
|
344
|
+
ignoreLeadingLF = chunk.endsWith('\r');
|
|
345
|
+
// prepend partial last line from previous chunk
|
|
346
|
+
let text = partialLine + chunk;
|
|
347
|
+
let match;
|
|
348
|
+
while ((match = text.match(sseRegex))) {
|
|
349
|
+
text = text.slice(match[0].length);
|
|
350
|
+
// blank linke, end of text/event-stream message
|
|
351
|
+
if (match.groups.field === '' && match.groups.value === undefined) {
|
|
352
|
+
// drop messages with no data
|
|
353
|
+
if (data === '') {
|
|
354
|
+
event = '';
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
// strip trailing \n from data
|
|
358
|
+
if (data.endsWith('\n')) {
|
|
359
|
+
data = data.slice(0, -1);
|
|
360
|
+
}
|
|
361
|
+
const sseMessage = {
|
|
362
|
+
data,
|
|
363
|
+
id,
|
|
364
|
+
// default event value is "message"
|
|
365
|
+
event: event || 'message',
|
|
366
|
+
};
|
|
367
|
+
if (retry !== undefined) {
|
|
368
|
+
sseMessage.retry = retry;
|
|
369
|
+
}
|
|
370
|
+
controller.enqueue(sseMessage);
|
|
371
|
+
// clear data & event for next message; id and retry persist until changed
|
|
372
|
+
data = event = '';
|
|
373
|
+
}
|
|
374
|
+
// data: line
|
|
375
|
+
else if (match.groups.field === 'data') {
|
|
376
|
+
data += (match.groups.value || '') + '\n';
|
|
377
|
+
}
|
|
378
|
+
// event: line
|
|
379
|
+
else if (match.groups.field === 'event') {
|
|
380
|
+
event = match.groups.value || '';
|
|
381
|
+
}
|
|
382
|
+
// id: line
|
|
383
|
+
else if (match.groups.field === 'id') {
|
|
384
|
+
const idValue = match.groups.value || '';
|
|
385
|
+
if (!idValue.includes('\u0000')) {
|
|
386
|
+
id = idValue;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
// retry: line
|
|
390
|
+
else if (match.groups.field === 'retry') {
|
|
391
|
+
// ignore bogus values
|
|
392
|
+
if (/^\d+$/.exec(match.groups.value)) {
|
|
393
|
+
retry = parseInt(match.groups.value);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
// comment or unrecognized field, ignore
|
|
397
|
+
else ;
|
|
398
|
+
}
|
|
399
|
+
// save partial line for next chunk
|
|
400
|
+
partialLine = text;
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Copyright (c) 2022, Salesforce, Inc.,
|
|
408
|
+
* All rights reserved.
|
|
409
|
+
* For full license text, see the LICENSE.txt file
|
|
410
|
+
*/
|
|
411
|
+
|
|
412
|
+
function buildInstrumentCommand(services) {
|
|
413
|
+
const meter = services.instrumentation.metrics.getMeter('onestore');
|
|
414
|
+
return function instrumentCommand(commandClass, commandName) {
|
|
415
|
+
const invocationCounter = meter.createCounter(`${commandName}.command.invocation.count`);
|
|
416
|
+
const errorCounter = meter.createCounter(`${commandName}.command.error.count`);
|
|
417
|
+
const durationHistogram = meter.createHistogram(`${commandName}.command.duration`);
|
|
418
|
+
return class extends commandClass {
|
|
419
|
+
execute(...args) {
|
|
420
|
+
invocationCounter.add(1);
|
|
421
|
+
let result;
|
|
422
|
+
const start = performance.now();
|
|
423
|
+
function recordDuration() {
|
|
424
|
+
const end = performance.now();
|
|
425
|
+
durationHistogram.record(end - start);
|
|
426
|
+
}
|
|
427
|
+
try {
|
|
428
|
+
result = super.execute(...args);
|
|
429
|
+
}
|
|
430
|
+
catch (e) {
|
|
431
|
+
errorCounter.add(1);
|
|
432
|
+
throw e;
|
|
433
|
+
}
|
|
434
|
+
if (typeof result === 'object' && result !== null && 'then' in result) {
|
|
435
|
+
result.then(recordDuration, () => {
|
|
436
|
+
errorCounter.add(1);
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
recordDuration();
|
|
441
|
+
}
|
|
442
|
+
return result;
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
function buildInstrumentCommandServiceDescriptor(services) {
|
|
448
|
+
return {
|
|
449
|
+
type: 'instrumentCommand',
|
|
450
|
+
version: '1.0',
|
|
451
|
+
service: buildInstrumentCommand(services),
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
|
|
39
455
|
/**
|
|
40
456
|
* Copyright (c) 2022, Salesforce, Inc.,
|
|
41
457
|
* All rights reserved.
|
|
@@ -261,67 +677,10 @@ class TTLFilteredStore {
|
|
|
261
677
|
.keys()
|
|
262
678
|
.elements()
|
|
263
679
|
.filter((key) => this.get(key) !== undefined));
|
|
264
|
-
}
|
|
265
|
-
toKeySet(keys) {
|
|
266
|
-
return this.baseStore.toKeySet(keys);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Copyright (c) 2022, Salesforce, Inc.,
|
|
272
|
-
* All rights reserved.
|
|
273
|
-
* For full license text, see the LICENSE.txt file
|
|
274
|
-
*/
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
function resolvedPromiseLike$1(result) {
|
|
278
|
-
// Don't nest anything promise like
|
|
279
|
-
if (isPromiseOrPromiseLike$1(result)) {
|
|
280
|
-
return result.then((nextResult) => nextResult);
|
|
281
|
-
}
|
|
282
|
-
return {
|
|
283
|
-
then: (onFulfilled, _onRejected) => {
|
|
284
|
-
if (onFulfilled) {
|
|
285
|
-
try {
|
|
286
|
-
return resolvedPromiseLike$1(onFulfilled(result));
|
|
287
|
-
}
|
|
288
|
-
catch (e) {
|
|
289
|
-
return rejectedPromiseLike$1(e);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
// assume TResult1 == Result and just pass result down the chain
|
|
293
|
-
return resolvedPromiseLike$1(result);
|
|
294
|
-
},
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Returns a PromiseLike object that rejects with the specified reason.
|
|
299
|
-
*
|
|
300
|
-
* @param reason rejection value
|
|
301
|
-
* @returns PromiseLike that rejects with reason
|
|
302
|
-
*/
|
|
303
|
-
function rejectedPromiseLike$1(reason) {
|
|
304
|
-
if (isPromiseOrPromiseLike$1(reason)) {
|
|
305
|
-
return reason.then((nextResult) => nextResult);
|
|
306
|
-
}
|
|
307
|
-
return {
|
|
308
|
-
then: (_onFulfilled, onRejected) => {
|
|
309
|
-
if (onRejected) {
|
|
310
|
-
try {
|
|
311
|
-
return resolvedPromiseLike$1(onRejected(reason));
|
|
312
|
-
}
|
|
313
|
-
catch (e) {
|
|
314
|
-
return rejectedPromiseLike$1(e);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
// assume TResult2 == Result and just pass rejection down the chain
|
|
318
|
-
return rejectedPromiseLike$1(reason);
|
|
319
|
-
},
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
function isPromiseOrPromiseLike$1(value) {
|
|
323
|
-
return (value instanceof Promise ||
|
|
324
|
-
(typeof value === 'object' && value !== null && typeof value.then === 'function'));
|
|
680
|
+
}
|
|
681
|
+
toKeySet(keys) {
|
|
682
|
+
return this.baseStore.toKeySet(keys);
|
|
683
|
+
}
|
|
325
684
|
}
|
|
326
685
|
|
|
327
686
|
/**
|
|
@@ -343,7 +702,7 @@ class InMemoryCacheInclusionPolicy {
|
|
|
343
702
|
const { l1, readFromL1 } = options;
|
|
344
703
|
// l1 is all we've got
|
|
345
704
|
const readResult = readFromL1(l1);
|
|
346
|
-
return resolvedPromiseLike
|
|
705
|
+
return resolvedPromiseLike(readResult);
|
|
347
706
|
}
|
|
348
707
|
/**
|
|
349
708
|
* Writes data to a single level in memory store.
|
|
@@ -351,7 +710,7 @@ class InMemoryCacheInclusionPolicy {
|
|
|
351
710
|
write(options) {
|
|
352
711
|
const { l1, writeToL1 } = options;
|
|
353
712
|
writeToL1(l1);
|
|
354
|
-
return resolvedPromiseLike
|
|
713
|
+
return resolvedPromiseLike(undefined);
|
|
355
714
|
}
|
|
356
715
|
}
|
|
357
716
|
/**
|
|
@@ -374,32 +733,6 @@ function buildInMemoryCacheInclusionPolicyService() {
|
|
|
374
733
|
*/
|
|
375
734
|
|
|
376
735
|
|
|
377
|
-
// an error to indicate that the data inside a WithErrors construct
|
|
378
|
-
// is missing or incomplete
|
|
379
|
-
let DataNotFoundError$1 = class DataNotFoundError extends Error {
|
|
380
|
-
constructor(message) {
|
|
381
|
-
super(message);
|
|
382
|
-
this.name = 'DataNotFoundError';
|
|
383
|
-
}
|
|
384
|
-
};
|
|
385
|
-
function isDataNotFoundError$1(error) {
|
|
386
|
-
return error instanceof DataNotFoundError$1 || error.name === 'DataNotFoundError';
|
|
387
|
-
}
|
|
388
|
-
function isCacheHitOrError$1(value) {
|
|
389
|
-
// return cache result if data was found or error was encountered
|
|
390
|
-
const { data, errors } = value;
|
|
391
|
-
const cacheHit = data !== undefined && errors.length === 0;
|
|
392
|
-
const errorEncountered = errors.length > 0 && !isDataNotFoundError$1(errors[0]);
|
|
393
|
-
return cacheHit || errorEncountered;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* Copyright (c) 2022, Salesforce, Inc.,
|
|
398
|
-
* All rights reserved.
|
|
399
|
-
* For full license text, see the LICENSE.txt file
|
|
400
|
-
*/
|
|
401
|
-
|
|
402
|
-
|
|
403
736
|
class CacheThenNetworkPolicy {
|
|
404
737
|
constructor(services, validator) {
|
|
405
738
|
this.services = services;
|
|
@@ -417,7 +750,7 @@ class CacheThenNetworkPolicy {
|
|
|
417
750
|
writeToCache: (services, networkResult) => this.writeWithValidation(() => writeToCacheOriginal(networkResult, services)),
|
|
418
751
|
});
|
|
419
752
|
return readFromCacheDedupe({ ...this.services, store: ttlStore }).then((value) => {
|
|
420
|
-
if (isCacheHitOrError
|
|
753
|
+
if (isCacheHitOrError(value)) {
|
|
421
754
|
return value;
|
|
422
755
|
}
|
|
423
756
|
// result not found in cache, try network
|
|
@@ -453,24 +786,154 @@ function buildCacheThenNetworkPolicy(services, validator) {
|
|
|
453
786
|
* For full license text, see the LICENSE.txt file
|
|
454
787
|
*/
|
|
455
788
|
|
|
789
|
+
class NoopOTelTraceAPI {
|
|
790
|
+
getTracer(_name, _version, _options) {
|
|
791
|
+
return new NoopTracer();
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
class NoopTracer {
|
|
795
|
+
startSpan(_name, _options, _context) {
|
|
796
|
+
return new NoopSpan();
|
|
797
|
+
}
|
|
798
|
+
startActiveSpan(name, options, context, fn) {
|
|
799
|
+
let opts;
|
|
800
|
+
let ctx;
|
|
801
|
+
let fun;
|
|
802
|
+
if (typeof options === 'function') {
|
|
803
|
+
fun = options;
|
|
804
|
+
}
|
|
805
|
+
else {
|
|
806
|
+
opts = options;
|
|
807
|
+
if (typeof context === 'function') {
|
|
808
|
+
fun = context;
|
|
809
|
+
}
|
|
810
|
+
else {
|
|
811
|
+
ctx = context;
|
|
812
|
+
fun = fn;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
const span = this.startSpan(name, opts, ctx);
|
|
816
|
+
try {
|
|
817
|
+
return fun(span);
|
|
818
|
+
}
|
|
819
|
+
finally {
|
|
820
|
+
span.end();
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
class NoopSpan {
|
|
825
|
+
spanContext() {
|
|
826
|
+
// TODO: I'll need to double check, but I think even if we provide a
|
|
827
|
+
// noop implementation, there is still a requirement to pass along context
|
|
828
|
+
return {
|
|
829
|
+
spanId: 'noopSpanId',
|
|
830
|
+
traceId: 'noopTraceId',
|
|
831
|
+
traceFlags: 0,
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
setAttribute(_key, _value) {
|
|
835
|
+
return this;
|
|
836
|
+
}
|
|
837
|
+
setAttributes(_attributes) {
|
|
838
|
+
return this;
|
|
839
|
+
}
|
|
840
|
+
addEvent(_name, _attributesOrStartTime, _startTime) {
|
|
841
|
+
return this;
|
|
842
|
+
}
|
|
843
|
+
setStatus(_status) {
|
|
844
|
+
return this;
|
|
845
|
+
}
|
|
846
|
+
updateName(_name) {
|
|
847
|
+
return this;
|
|
848
|
+
}
|
|
849
|
+
end(_endTime) {
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
isRecording() {
|
|
853
|
+
return false;
|
|
854
|
+
}
|
|
855
|
+
recordException(_exception, _time) {
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
456
859
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
constructor(message) {
|
|
461
|
-
super(message);
|
|
462
|
-
this.name = 'DataNotFoundError';
|
|
860
|
+
class NoopOTelMetricsAPI {
|
|
861
|
+
getMeter(__name, _version, __options) {
|
|
862
|
+
return new NoopMeter();
|
|
463
863
|
}
|
|
464
864
|
}
|
|
465
|
-
|
|
466
|
-
|
|
865
|
+
class NoopMeter {
|
|
866
|
+
createHistogram(_name, _options) {
|
|
867
|
+
return new NoopHistogram();
|
|
868
|
+
}
|
|
869
|
+
createCounter(_name, _options) {
|
|
870
|
+
return new NoopCounter();
|
|
871
|
+
}
|
|
872
|
+
createUpDownCounter(_name, _options) {
|
|
873
|
+
return new NoopUpDownCounter();
|
|
874
|
+
}
|
|
875
|
+
createObservableGauge(_name, _options) {
|
|
876
|
+
return new NoopObservableGuage();
|
|
877
|
+
}
|
|
878
|
+
createObservableCounter(_name, _options) {
|
|
879
|
+
return new NoopObservableCounter();
|
|
880
|
+
}
|
|
881
|
+
createObservableUpDownCounter(_name, _options) {
|
|
882
|
+
return new NoopObservableUpDownCounter();
|
|
883
|
+
}
|
|
884
|
+
addBatchObservableCallback(_callback, _observables) {
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
removeBatchObservableCallback(_callback, _observables) {
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
467
890
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
891
|
+
class NoopCounter {
|
|
892
|
+
add(_value, _attributes, _context) {
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
class NoopHistogram {
|
|
897
|
+
record(_value, _attributes, _context) {
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
class NoopUpDownCounter {
|
|
902
|
+
add(_value, _attributes, _context) {
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
class NoopObservableCounter {
|
|
907
|
+
addCallback(_callback) {
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
removeCallback(_callback) {
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
class NoopObservableGuage {
|
|
915
|
+
addCallback(_callback) {
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
removeCallback(_callback) {
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
class NoopObservableUpDownCounter {
|
|
923
|
+
addCallback(_callback) {
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
removeCallback(_callback) {
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
/* eslint-disable no-dupe-class-members */
|
|
932
|
+
function buildNoopInstrumentationService() {
|
|
933
|
+
return {
|
|
934
|
+
trace: new NoopOTelTraceAPI(),
|
|
935
|
+
metrics: new NoopOTelMetricsAPI(),
|
|
936
|
+
};
|
|
474
937
|
}
|
|
475
938
|
|
|
476
939
|
/**
|
|
@@ -604,101 +1067,412 @@ function buildKeyBasedRequestDedupeService() {
|
|
|
604
1067
|
*/
|
|
605
1068
|
|
|
606
1069
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
1070
|
+
/**
|
|
1071
|
+
* A simple implementation of KeyKeySubscriptionService.
|
|
1072
|
+
*/
|
|
1073
|
+
class DefaultKeySubscriptionService {
|
|
1074
|
+
constructor() {
|
|
1075
|
+
this.nextId = 1;
|
|
1076
|
+
this.subscriptions = [];
|
|
611
1077
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
1078
|
+
subscribe(options) {
|
|
1079
|
+
const subscriptionId = this.nextId++;
|
|
1080
|
+
const { subscription, callback } = options;
|
|
1081
|
+
this.subscriptions.push({ subscriptionId, keys: subscription, callback });
|
|
1082
|
+
return () => {
|
|
1083
|
+
this.subscriptions = this.subscriptions.filter((subscription) => subscription.subscriptionId !== subscriptionId);
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
publish(keys, _options) {
|
|
1087
|
+
const subscriptions = this.subscriptions.slice();
|
|
1088
|
+
for (let i = 0; i < subscriptions.length; ++i) {
|
|
1089
|
+
const { keys: subscriptionKeys, callback } = subscriptions[i];
|
|
1090
|
+
if (keys.overlaps(subscriptionKeys)) {
|
|
1091
|
+
callback();
|
|
621
1092
|
}
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
};
|
|
1093
|
+
}
|
|
1094
|
+
return resolvedPromiseLike(undefined);
|
|
1095
|
+
}
|
|
626
1096
|
}
|
|
627
1097
|
/**
|
|
628
|
-
*
|
|
1098
|
+
* Constructs a default KeySubscriptionService
|
|
629
1099
|
*
|
|
630
|
-
* @
|
|
631
|
-
* @returns PromiseLike that rejects with reason
|
|
1100
|
+
* @returns default KeySubscriptionService
|
|
632
1101
|
*/
|
|
633
|
-
function
|
|
634
|
-
|
|
635
|
-
|
|
1102
|
+
function buildDefaultKeySubscriptionService() {
|
|
1103
|
+
return {
|
|
1104
|
+
type: 'keySubscription',
|
|
1105
|
+
version: '1.0',
|
|
1106
|
+
service: new DefaultKeySubscriptionService(),
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
/**
|
|
1111
|
+
* Copyright (c) 2022, Salesforce, Inc.,
|
|
1112
|
+
* All rights reserved.
|
|
1113
|
+
* For full license text, see the LICENSE.txt file
|
|
1114
|
+
*/
|
|
1115
|
+
|
|
1116
|
+
|
|
1117
|
+
class DefaultTypeNotFoundError extends Error {
|
|
1118
|
+
}
|
|
1119
|
+
class DefaultTypeRegistry {
|
|
1120
|
+
constructor() {
|
|
1121
|
+
this.registry = {};
|
|
1122
|
+
this.TypeNotFoundError = DefaultTypeNotFoundError;
|
|
1123
|
+
}
|
|
1124
|
+
register(type, _options) {
|
|
1125
|
+
if (!this.registry[type.namespace]) {
|
|
1126
|
+
this.registry[type.namespace] = {};
|
|
1127
|
+
}
|
|
1128
|
+
this.registry[type.namespace][type.typeName] = type;
|
|
1129
|
+
}
|
|
1130
|
+
get(namespace, typeName, _options) {
|
|
1131
|
+
const registryNamespace = this.registry[namespace];
|
|
1132
|
+
if (!registryNamespace) {
|
|
1133
|
+
throw new DefaultTypeNotFoundError(`namespace ${namespace} not found`);
|
|
1134
|
+
}
|
|
1135
|
+
const type = registryNamespace[typeName];
|
|
1136
|
+
if (!type) {
|
|
1137
|
+
throw new DefaultTypeNotFoundError(`type ${typeName} not found in namespace ${namespace}`);
|
|
1138
|
+
}
|
|
1139
|
+
return type;
|
|
636
1140
|
}
|
|
1141
|
+
}
|
|
1142
|
+
/**
|
|
1143
|
+
* Constructs an in-memory implementation of StoreService.
|
|
1144
|
+
*
|
|
1145
|
+
* @returns in-memory implementation of StoreService
|
|
1146
|
+
*/
|
|
1147
|
+
function buildDefaultTypeRegistryService() {
|
|
637
1148
|
return {
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
return resolvedPromiseLike(onRejected(reason));
|
|
642
|
-
}
|
|
643
|
-
catch (e) {
|
|
644
|
-
return rejectedPromiseLike(e);
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
// assume TResult2 == Result and just pass rejection down the chain
|
|
648
|
-
return rejectedPromiseLike(reason);
|
|
649
|
-
},
|
|
1149
|
+
type: 'typeRegistry',
|
|
1150
|
+
version: '1.0',
|
|
1151
|
+
service: new DefaultTypeRegistry(),
|
|
650
1152
|
};
|
|
651
1153
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
1154
|
+
|
|
1155
|
+
/**
|
|
1156
|
+
* Copyright (c) 2022, Salesforce, Inc.,
|
|
1157
|
+
* All rights reserved.
|
|
1158
|
+
* For full license text, see the LICENSE.txt file
|
|
1159
|
+
*/
|
|
1160
|
+
|
|
1161
|
+
function e(e){this.message=e;}e.prototype=new Error,e.prototype.name="InvalidCharacterError";var r="undefined"!=typeof window&&window.atob&&window.atob.bind(window)||function(r){var t=String(r).replace(/=+$/,"");if(t.length%4==1)throw new e("'atob' failed: The string to be decoded is not correctly encoded.");for(var n,o,a=0,i=0,c="";o=t.charAt(i++);~o&&(n=a%4?64*n+o:o,a++%4)?c+=String.fromCharCode(255&n>>(-2*a&6)):0)o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(o);return c};function t(e){var t=e.replace(/-/g,"+").replace(/_/g,"/");switch(t.length%4){case 0:break;case 2:t+="==";break;case 3:t+="=";break;default:throw "Illegal base64url string!"}try{return function(e){return decodeURIComponent(r(e).replace(/(.)/g,(function(e,r){var t=r.charCodeAt(0).toString(16).toUpperCase();return t.length<2&&(t="0"+t),"%"+t})))}(t)}catch(e){return r(t)}}function n(e){this.message=e;}function o(e,r){if("string"!=typeof e)throw new n("Invalid token specified");var o=!0===(r=r||{}).header?0:1;try{return JSON.parse(t(e.split(".")[o]))}catch(e){throw new n("Invalid token specified: "+e.message)}}n.prototype=new Error,n.prototype.name="InvalidTokenError";
|
|
1162
|
+
|
|
1163
|
+
/**
|
|
1164
|
+
* Copyright (c) 2022, Salesforce, Inc.,
|
|
1165
|
+
* All rights reserved.
|
|
1166
|
+
* For full license text, see the LICENSE.txt file
|
|
1167
|
+
*/
|
|
1168
|
+
|
|
1169
|
+
const LogLevelMap = {
|
|
1170
|
+
TRACE: 4,
|
|
1171
|
+
DEBUG: 3,
|
|
1172
|
+
INFO: 2,
|
|
1173
|
+
WARN: 1,
|
|
1174
|
+
ERROR: 0,
|
|
1175
|
+
};
|
|
1176
|
+
/**
|
|
1177
|
+
* A simple Logger implementation.
|
|
1178
|
+
*/
|
|
1179
|
+
class ConsoleLogger {
|
|
1180
|
+
constructor(level = 'WARN',
|
|
1181
|
+
// eslint-disable-next-line no-console
|
|
1182
|
+
printer = console.log, formatter = (level, message) => `${level}: ${message}`) {
|
|
1183
|
+
this.level = level;
|
|
1184
|
+
this.printer = printer;
|
|
1185
|
+
this.formatter = formatter;
|
|
1186
|
+
this.messages = [];
|
|
1187
|
+
}
|
|
1188
|
+
trace(message) {
|
|
1189
|
+
this.log('TRACE', message);
|
|
1190
|
+
}
|
|
1191
|
+
debug(message) {
|
|
1192
|
+
this.log('DEBUG', message);
|
|
1193
|
+
}
|
|
1194
|
+
info(message) {
|
|
1195
|
+
this.log('INFO', message);
|
|
1196
|
+
}
|
|
1197
|
+
warn(message) {
|
|
1198
|
+
this.log('WARN', message);
|
|
1199
|
+
}
|
|
1200
|
+
error(message) {
|
|
1201
|
+
this.log('ERROR', message);
|
|
1202
|
+
}
|
|
1203
|
+
log(level, message) {
|
|
1204
|
+
if (LogLevelMap[level] > LogLevelMap[this.level]) {
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
this.printer(this.formatter(level, message));
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
/**
|
|
1211
|
+
* Constructs a new LoggerService.
|
|
1212
|
+
*/
|
|
1213
|
+
function loggerService(level, printer, formatter) {
|
|
1214
|
+
return new ConsoleLogger(level, printer, formatter);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
/**
|
|
1218
|
+
* Represents a JWT token with its decoded info and optional extra info.
|
|
1219
|
+
*
|
|
1220
|
+
* @typeparam T - Type of the additional payload in the JWT.
|
|
1221
|
+
* @typeparam ExtraInfo - Type of the additional information.
|
|
1222
|
+
*/
|
|
1223
|
+
class JwtToken {
|
|
1224
|
+
/**
|
|
1225
|
+
* Create a new JwtToken.
|
|
1226
|
+
*
|
|
1227
|
+
* @param _token - The JWT string.
|
|
1228
|
+
* @param _decodedInfo - The decoded information from the JWT.
|
|
1229
|
+
* @param _extraInfo - Any additional information associated with the JWT.
|
|
1230
|
+
*/
|
|
1231
|
+
constructor(_token, _decodedInfo, _extraInfo) {
|
|
1232
|
+
this._token = _token;
|
|
1233
|
+
this._decodedInfo = _decodedInfo;
|
|
1234
|
+
this._extraInfo = _extraInfo;
|
|
1235
|
+
}
|
|
1236
|
+
/**
|
|
1237
|
+
* Get the JWT string.
|
|
1238
|
+
*
|
|
1239
|
+
* @returns The JWT string.
|
|
1240
|
+
*/
|
|
1241
|
+
get token() {
|
|
1242
|
+
return this._token;
|
|
1243
|
+
}
|
|
1244
|
+
/**
|
|
1245
|
+
* Get the additional information associated with the JWT.
|
|
1246
|
+
*
|
|
1247
|
+
* @returns The additional information.
|
|
1248
|
+
*/
|
|
1249
|
+
get extraInfo() {
|
|
1250
|
+
return this._extraInfo;
|
|
1251
|
+
}
|
|
1252
|
+
/**
|
|
1253
|
+
* Get the decoded information from the JWT.
|
|
1254
|
+
*
|
|
1255
|
+
* @returns The decoded information.
|
|
1256
|
+
*/
|
|
1257
|
+
get decodedInfo() {
|
|
1258
|
+
return this._decodedInfo;
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Get the remaining time in seconds until the JWT expires.
|
|
1262
|
+
*
|
|
1263
|
+
* @returns The remaining time in seconds.
|
|
1264
|
+
*/
|
|
1265
|
+
get tokenRemainingSeconds() {
|
|
1266
|
+
return this.decodedInfo.exp - Date.now() / 1000;
|
|
1267
|
+
}
|
|
1268
|
+
/**
|
|
1269
|
+
* Check if the JWT is expired.
|
|
1270
|
+
*
|
|
1271
|
+
* @returns True if the JWT is expired, false otherwise.
|
|
1272
|
+
*/
|
|
1273
|
+
get isExpired() {
|
|
1274
|
+
return this.tokenRemainingSeconds <= 0;
|
|
1275
|
+
}
|
|
655
1276
|
}
|
|
656
1277
|
|
|
657
1278
|
/**
|
|
658
|
-
*
|
|
659
|
-
* All rights reserved.
|
|
660
|
-
* For full license text, see the LICENSE.txt file
|
|
1279
|
+
* Default logger if none is provided. Is overwritten in non-production environments.
|
|
661
1280
|
*/
|
|
662
|
-
|
|
663
|
-
|
|
1281
|
+
let defaultLogger = {
|
|
1282
|
+
trace: () => { },
|
|
1283
|
+
debug: () => { },
|
|
1284
|
+
info: () => { },
|
|
1285
|
+
warn: () => { },
|
|
1286
|
+
error: () => { },
|
|
1287
|
+
};
|
|
1288
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1289
|
+
defaultLogger = loggerService();
|
|
1290
|
+
}
|
|
664
1291
|
/**
|
|
665
|
-
*
|
|
1292
|
+
* Decodes JWT token information and provides a default expiry if none is present.
|
|
1293
|
+
*
|
|
1294
|
+
* @param token - JWT token as a string.
|
|
1295
|
+
* @param defaultTokenTTLInSeconds - Default expiry time in seconds if "exp" claim is not present in token.
|
|
1296
|
+
* @param logger - Logger for logging warnings and errors.
|
|
1297
|
+
*
|
|
1298
|
+
* @returns An object of decoded JWT token information.
|
|
666
1299
|
*/
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
1300
|
+
function computeDecodedInfo(token, defaultTokenTTLInSeconds, logger) {
|
|
1301
|
+
const decodedInfo = o(token);
|
|
1302
|
+
if (decodedInfo.exp === undefined) {
|
|
1303
|
+
logger.warn(`"exp" claim is not present in the provided token.`);
|
|
1304
|
+
decodedInfo.exp = Date.now() / 1000 + defaultTokenTTLInSeconds;
|
|
671
1305
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
1306
|
+
return decodedInfo;
|
|
1307
|
+
}
|
|
1308
|
+
/**
|
|
1309
|
+
* A repository for JWT tokens.
|
|
1310
|
+
*/
|
|
1311
|
+
class JwtRepository {
|
|
1312
|
+
/**
|
|
1313
|
+
* @param limitInSeconds - Time in seconds before the token's expiry to notify observers.
|
|
1314
|
+
* @param defaultTokenTTLInSeconds - Default token expiry time in seconds if "exp" claim is not present in token.
|
|
1315
|
+
* @param logger - Logger for logging warnings and errors.
|
|
1316
|
+
*/
|
|
1317
|
+
constructor(limitInSeconds = 5, defaultTokenTTLInSeconds = 120, logger = defaultLogger) {
|
|
1318
|
+
this.limitInSeconds = limitInSeconds;
|
|
1319
|
+
this.defaultTokenTTLInSeconds = defaultTokenTTLInSeconds;
|
|
1320
|
+
this.logger = logger;
|
|
1321
|
+
this.observers = [];
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Get the current token.
|
|
1325
|
+
*/
|
|
1326
|
+
get token() {
|
|
1327
|
+
return this._token;
|
|
1328
|
+
}
|
|
1329
|
+
/**
|
|
1330
|
+
* Set the current token.
|
|
1331
|
+
*
|
|
1332
|
+
* @param token - JWT token as a string.
|
|
1333
|
+
* @param extraInfo - Optional extra information.
|
|
1334
|
+
*/
|
|
1335
|
+
setToken(token, extraInfo) {
|
|
1336
|
+
const decodedInfo = computeDecodedInfo(token, this.defaultTokenTTLInSeconds, this.logger);
|
|
1337
|
+
this._token = new JwtToken(token, decodedInfo, extraInfo);
|
|
1338
|
+
this.observeTokenExpiration();
|
|
1339
|
+
return this._token;
|
|
1340
|
+
}
|
|
1341
|
+
/**
|
|
1342
|
+
* Remove the current token.
|
|
1343
|
+
*/
|
|
1344
|
+
removeToken() {
|
|
1345
|
+
this._token = undefined;
|
|
1346
|
+
this.clearTimeoutHandler();
|
|
1347
|
+
}
|
|
1348
|
+
/**
|
|
1349
|
+
* Subscribe to the token nearing its expiration.
|
|
1350
|
+
*
|
|
1351
|
+
* @param cb - Callback function to execute when token is nearing expiration.
|
|
1352
|
+
*/
|
|
1353
|
+
subscribeToTokenNearExpiration(cb) {
|
|
1354
|
+
this.observers.push(cb);
|
|
1355
|
+
this.observeTokenExpiration();
|
|
676
1356
|
return () => {
|
|
677
|
-
this.
|
|
1357
|
+
this.observers = this.observers.filter((observer) => observer !== cb);
|
|
678
1358
|
};
|
|
679
1359
|
}
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
}
|
|
1360
|
+
/**
|
|
1361
|
+
* Clear the timeout handler.
|
|
1362
|
+
*/
|
|
1363
|
+
clearTimeoutHandler() {
|
|
1364
|
+
if (this.timeoutHandler !== undefined) {
|
|
1365
|
+
clearTimeout(this.timeoutHandler);
|
|
687
1366
|
}
|
|
688
|
-
|
|
1367
|
+
}
|
|
1368
|
+
/**
|
|
1369
|
+
* Observe and handle token expiration.
|
|
1370
|
+
*/
|
|
1371
|
+
observeTokenExpiration() {
|
|
1372
|
+
this.clearTimeoutHandler();
|
|
1373
|
+
if (this.observers.length === 0 || this.token === undefined) {
|
|
1374
|
+
return;
|
|
1375
|
+
}
|
|
1376
|
+
this.timeoutHandler = setTimeout(() => this.notifyTokenIsExpiring(), this.computeTimeoutTimeInMs());
|
|
1377
|
+
}
|
|
1378
|
+
/**
|
|
1379
|
+
* Compute the timeout time in milliseconds.
|
|
1380
|
+
*/
|
|
1381
|
+
computeTimeoutTimeInMs() {
|
|
1382
|
+
const remainingSeconds = this.token.tokenRemainingSeconds;
|
|
1383
|
+
let timeoutTimeInSeconds = remainingSeconds - this.limitInSeconds;
|
|
1384
|
+
return timeoutTimeInSeconds < 0 ? 0 : timeoutTimeInSeconds * 1000;
|
|
1385
|
+
}
|
|
1386
|
+
/**
|
|
1387
|
+
* Notify all observers that the token is expiring.
|
|
1388
|
+
*/
|
|
1389
|
+
notifyTokenIsExpiring() {
|
|
1390
|
+
this.observers.forEach((cb) => {
|
|
1391
|
+
try {
|
|
1392
|
+
cb.call(undefined, this.token);
|
|
1393
|
+
}
|
|
1394
|
+
catch (e) {
|
|
1395
|
+
this.logger.error(e.message);
|
|
1396
|
+
}
|
|
1397
|
+
});
|
|
689
1398
|
}
|
|
690
1399
|
}
|
|
1400
|
+
|
|
691
1401
|
/**
|
|
692
|
-
*
|
|
1402
|
+
* JwtManager class.
|
|
1403
|
+
* It provides methods for managing JWT (Json Web Token), such as retrieving and refreshing.
|
|
693
1404
|
*
|
|
694
|
-
* @
|
|
1405
|
+
* @template T The data type the JwtToken carries. Default to unknown.
|
|
1406
|
+
* @template ExtraInfo The type of the optional extra information returned by the getJwt method. Defaults to undefined.
|
|
1407
|
+
* @property {JwtRepository<T, ExtraInfo>} jwtRepository JwtRepository instance used for token management.
|
|
1408
|
+
* @property {JwtResolver<ExtraInfo>} resolver JwtResolver instance used for token retrieval.
|
|
695
1409
|
*/
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
1410
|
+
class JwtManager {
|
|
1411
|
+
/**
|
|
1412
|
+
* Constructor for JwtManager class.
|
|
1413
|
+
*
|
|
1414
|
+
* @param {JwtRepository<T, ExtraInfo>} jwtRepository JwtRepository instance used for token management.
|
|
1415
|
+
* @param {JwtResolver<ExtraInfo>} resolver JwtResolver instance used for token retrieval.
|
|
1416
|
+
* @param {JwtManagerOptions} options JwtManagerOptions bag to customize behavior.
|
|
1417
|
+
*/
|
|
1418
|
+
constructor(jwtRepository, resolver, options) {
|
|
1419
|
+
this.jwtRepository = jwtRepository;
|
|
1420
|
+
this.resolver = resolver;
|
|
1421
|
+
if (options === null || options === void 0 ? void 0 : options.keepTokenUpdated) {
|
|
1422
|
+
jwtRepository.subscribeToTokenNearExpiration(() => this.refreshToken());
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
/**
|
|
1426
|
+
* Method to get a JWT token.
|
|
1427
|
+
* If there's a token request in progress, it will return the Promise of this request.
|
|
1428
|
+
* If the current token is undefined or expired, it will initiate a token refresh.
|
|
1429
|
+
* Otherwise, it will return the current token.
|
|
1430
|
+
*
|
|
1431
|
+
* @returns {JwtToken<T, ExtraInfo> | Promise<JwtToken<T, ExtraInfo>>} The current token or the Promise of a token request.
|
|
1432
|
+
*/
|
|
1433
|
+
getJwt() {
|
|
1434
|
+
if (this.inflightPromise) {
|
|
1435
|
+
return this.inflightPromise;
|
|
1436
|
+
}
|
|
1437
|
+
const token = this.jwtRepository.token;
|
|
1438
|
+
if (token === undefined || token.isExpired) {
|
|
1439
|
+
return this.refreshToken();
|
|
1440
|
+
}
|
|
1441
|
+
return token;
|
|
1442
|
+
}
|
|
1443
|
+
/**
|
|
1444
|
+
* Method to refresh a JWT token.
|
|
1445
|
+
* If a refresh request is already in progress, it will return the Promise of this request.
|
|
1446
|
+
* Otherwise, it will start a new refresh request and return its Promise.
|
|
1447
|
+
*
|
|
1448
|
+
* @returns {Promise<JwtToken<T, ExtraInfo>>} Promise of the refreshed token.
|
|
1449
|
+
*/
|
|
1450
|
+
refreshToken() {
|
|
1451
|
+
if (this.inflightPromise === undefined) {
|
|
1452
|
+
this.inflightPromise = new Promise((resolve, reject) => {
|
|
1453
|
+
this.resolver
|
|
1454
|
+
.getJwt()
|
|
1455
|
+
.then(({ jwt, extraInfo }) => {
|
|
1456
|
+
this.inflightPromise = undefined;
|
|
1457
|
+
const token = this.jwtRepository.setToken(jwt, extraInfo);
|
|
1458
|
+
resolve(token);
|
|
1459
|
+
})
|
|
1460
|
+
.catch((reason) => {
|
|
1461
|
+
this.inflightPromise = undefined;
|
|
1462
|
+
reject(reason);
|
|
1463
|
+
});
|
|
1464
|
+
});
|
|
1465
|
+
}
|
|
1466
|
+
return this.inflightPromise;
|
|
1467
|
+
}
|
|
1468
|
+
/**
|
|
1469
|
+
* Method to check if a token refresh is in progress.
|
|
1470
|
+
*
|
|
1471
|
+
* @returns {boolean} true if a token refresh is in progress, false otherwise.
|
|
1472
|
+
*/
|
|
1473
|
+
get isRefreshingToken() {
|
|
1474
|
+
return this.inflightPromise !== undefined;
|
|
1475
|
+
}
|
|
702
1476
|
}
|
|
703
1477
|
|
|
704
1478
|
/**
|
|
@@ -708,41 +1482,194 @@ function buildDefaultKeySubscriptionService() {
|
|
|
708
1482
|
*/
|
|
709
1483
|
|
|
710
1484
|
|
|
711
|
-
|
|
1485
|
+
function buildFetchService(interceptors = { request: [] }) {
|
|
1486
|
+
return {
|
|
1487
|
+
type: 'fetch',
|
|
1488
|
+
version: '1.0',
|
|
1489
|
+
service: function (...args) {
|
|
1490
|
+
const { request: requestInterceptors = [] } = interceptors;
|
|
1491
|
+
const pending = requestInterceptors.reduce((previousPromise, interceptor) => previousPromise.then(interceptor), resolvedPromiseLike(args));
|
|
1492
|
+
return pending.then((args) => fetch(...args));
|
|
1493
|
+
},
|
|
1494
|
+
};
|
|
712
1495
|
}
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
1496
|
+
|
|
1497
|
+
const UNEXPECTED_AUTHORIZATION_HEADER_MESSAGE = 'Unexpected Authorization header encountered. To specify a custom Authorization header, use a Fetch service that is not configured with JwtRequestHeaderInterceptor';
|
|
1498
|
+
function setHeaderAuthorization({ token }, [resource, options = {}]) {
|
|
1499
|
+
let hasAuthorizationHeaderBeenSet = false;
|
|
1500
|
+
const Authorization = `Bearer ${token}`;
|
|
1501
|
+
// The following is necessary because fetch(RequestInfo, options|RequestInit)
|
|
1502
|
+
// does not merge properties from options|RequestInit.headers into RequestInfo.headers,
|
|
1503
|
+
// instead it will pave over RequestInfo.headers if options|RequestInit.headers
|
|
1504
|
+
// is defined. Therefore, this function must preserve any pre-existing headers
|
|
1505
|
+
// properties across two different arguments that themselves may be four
|
|
1506
|
+
// different data types.
|
|
1507
|
+
//
|
|
1508
|
+
// - a string
|
|
1509
|
+
// - an instance of URL
|
|
1510
|
+
// - an instance of Request
|
|
1511
|
+
//
|
|
1512
|
+
// And for this argument we only need to guard against overwriting an
|
|
1513
|
+
// existing `headers` property whose value is an instance of Headers.
|
|
1514
|
+
// This will only be valid when the resource argument is an instance of
|
|
1515
|
+
// Request, which implicitly holds a property called `headers` whose
|
|
1516
|
+
// value is an instance of Headers AND options has not been explicitly
|
|
1517
|
+
// provided, or has but does not have a headers property. The existance
|
|
1518
|
+
// of an explicit headers property would likely be intentional, so
|
|
1519
|
+
// we defer to the calling code.
|
|
1520
|
+
if (resource instanceof Request && !(options === null || options === void 0 ? void 0 : options.headers)) {
|
|
1521
|
+
// If the resource object's headers instance already contains an
|
|
1522
|
+
// "Authorization" header, then we have to assume this is a mistake
|
|
1523
|
+
// so throw an exception that will result in the fetch call returning
|
|
1524
|
+
// a rejected promise.
|
|
1525
|
+
if (resource.headers.has('Authorization')) {
|
|
1526
|
+
throw new Error(UNEXPECTED_AUTHORIZATION_HEADER_MESSAGE);
|
|
721
1527
|
}
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
1528
|
+
// Otherwise, set the "Authorization" header with the provided
|
|
1529
|
+
// JWT value (because options?.headers also doesn't exist)
|
|
1530
|
+
resource.headers.set('Authorization', Authorization);
|
|
1531
|
+
hasAuthorizationHeaderBeenSet = true;
|
|
1532
|
+
}
|
|
1533
|
+
// When the options object is provided, it may already have a
|
|
1534
|
+
// `headers` property whose value is an instance of Headers, or
|
|
1535
|
+
// a `headers` property that is a plain object comprised of key=>value
|
|
1536
|
+
// pairs that will be converted into a Headers object by fetch().
|
|
1537
|
+
//
|
|
1538
|
+
// If the options object contains a property called `headers` whose value
|
|
1539
|
+
// is an instance of Headers...
|
|
1540
|
+
if ((options === null || options === void 0 ? void 0 : options.headers) instanceof Headers) {
|
|
1541
|
+
// ...Check to see if that object contains an "Authorization" header.
|
|
1542
|
+
// If it does, then we have to assume this is a mistake so throw an
|
|
1543
|
+
// exception.
|
|
1544
|
+
if (options === null || options === void 0 ? void 0 : options.headers.has('Authorization')) {
|
|
1545
|
+
throw new Error(UNEXPECTED_AUTHORIZATION_HEADER_MESSAGE);
|
|
728
1546
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
1547
|
+
// Otherwise, set the "Authorization" header with the provided
|
|
1548
|
+
// JWT token value:
|
|
1549
|
+
options === null || options === void 0 ? void 0 : options.headers.set('Authorization', Authorization);
|
|
1550
|
+
}
|
|
1551
|
+
else {
|
|
1552
|
+
// Else, check if options contains a `headers` property whose value
|
|
1553
|
+
// is a plain object comprised of key=>value pairs. If this
|
|
1554
|
+
// object contains a property called "Authorization", then we have
|
|
1555
|
+
// to assume this is a mistake so throw an exception.
|
|
1556
|
+
if ((options === null || options === void 0 ? void 0 : options.headers) && Reflect.has(options === null || options === void 0 ? void 0 : options.headers, 'Authorization')) {
|
|
1557
|
+
throw new Error(UNEXPECTED_AUTHORIZATION_HEADER_MESSAGE);
|
|
1558
|
+
}
|
|
1559
|
+
// Otherwise, add a property called "Authorization", whose value is
|
|
1560
|
+
// the provided JWT value, as long as it has not been set on Request
|
|
1561
|
+
if (!hasAuthorizationHeaderBeenSet) {
|
|
1562
|
+
options.headers = {
|
|
1563
|
+
...options === null || options === void 0 ? void 0 : options.headers,
|
|
1564
|
+
Authorization,
|
|
1565
|
+
};
|
|
732
1566
|
}
|
|
733
|
-
return type;
|
|
734
1567
|
}
|
|
1568
|
+
return [resource, options];
|
|
1569
|
+
}
|
|
1570
|
+
function buildJwtRequestHeaderInterceptor(jwtManager, jwtRequestModifier = (_e, fetchArgs) => fetchArgs) {
|
|
1571
|
+
return (args) => {
|
|
1572
|
+
return resolvedPromiseLike(jwtManager.getJwt()).then((token) => {
|
|
1573
|
+
const fetchArgsWithRequestHeaderAuthorization = setHeaderAuthorization(token, args);
|
|
1574
|
+
return token.extraInfo
|
|
1575
|
+
? jwtRequestModifier(token.extraInfo, fetchArgsWithRequestHeaderAuthorization)
|
|
1576
|
+
: fetchArgsWithRequestHeaderAuthorization;
|
|
1577
|
+
});
|
|
1578
|
+
};
|
|
735
1579
|
}
|
|
1580
|
+
|
|
1581
|
+
const SALESFORCE_API_BASE_URI_FLAG = 'api.salesforce.com';
|
|
1582
|
+
const SFAPController = 'SalesforceApiPlatformController';
|
|
1583
|
+
const SFAPJwtMethod = 'getSFAPLightningJwtService';
|
|
736
1584
|
/**
|
|
737
|
-
*
|
|
1585
|
+
* We expect jwt info and baseUri to be present in the response.
|
|
738
1586
|
*
|
|
739
|
-
* @
|
|
1587
|
+
* @param body
|
|
740
1588
|
*/
|
|
741
|
-
function
|
|
1589
|
+
function validateResponse(body) {
|
|
1590
|
+
if (!body || !body.jwt || !body.baseUri) {
|
|
1591
|
+
// wrapped the invocation in env conditional
|
|
1592
|
+
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
1593
|
+
throw new Error(`Expected jwt info and baseUri to be present but instead got: ${JSON.stringify(body)}`);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
/**
|
|
1597
|
+
* Resolves Jwt token for SFAP by calling Aura action
|
|
1598
|
+
* {@link JwtResolver} for platform SFAP
|
|
1599
|
+
*/
|
|
1600
|
+
const platformSfapJwtResolver = {
|
|
1601
|
+
getJwt() {
|
|
1602
|
+
return new Promise((resolve, reject) => {
|
|
1603
|
+
dispatchAuraAction(`${SFAPController}.${SFAPJwtMethod}`, {}, defaultActionConfig)
|
|
1604
|
+
.then((response) => {
|
|
1605
|
+
const body = response.body;
|
|
1606
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1607
|
+
validateResponse(body);
|
|
1608
|
+
}
|
|
1609
|
+
resolve({
|
|
1610
|
+
jwt: body.jwt,
|
|
1611
|
+
extraInfo: {
|
|
1612
|
+
baseUri: body.baseUri,
|
|
1613
|
+
},
|
|
1614
|
+
});
|
|
1615
|
+
})
|
|
1616
|
+
.catch((error) => {
|
|
1617
|
+
if (error instanceof Error) {
|
|
1618
|
+
reject(error.message);
|
|
1619
|
+
return;
|
|
1620
|
+
}
|
|
1621
|
+
// AuraFetchResponse errors
|
|
1622
|
+
const { status } = error;
|
|
1623
|
+
if (status !== HttpStatusCode.ServerError) {
|
|
1624
|
+
// ConnectInJavaError
|
|
1625
|
+
reject(error.body.message);
|
|
1626
|
+
return;
|
|
1627
|
+
}
|
|
1628
|
+
reject(error.body.error);
|
|
1629
|
+
});
|
|
1630
|
+
});
|
|
1631
|
+
},
|
|
1632
|
+
};
|
|
1633
|
+
/**
|
|
1634
|
+
* This hook is used to modify the resource request before it is sent to the server.
|
|
1635
|
+
* SFAP uses extraInfo assocaiated JwtToken to update the baseUri for the resource request.
|
|
1636
|
+
*
|
|
1637
|
+
* @param resourceRequest
|
|
1638
|
+
* @param jwtToken
|
|
1639
|
+
* @returns resourceRequest with updated baseUri
|
|
1640
|
+
*/
|
|
1641
|
+
const modifySfapResourceRequest = function (resourceRequest, jwtToken) {
|
|
1642
|
+
const { baseUri } = jwtToken.extraInfo;
|
|
742
1643
|
return {
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
1644
|
+
...resourceRequest,
|
|
1645
|
+
baseUri,
|
|
1646
|
+
};
|
|
1647
|
+
};
|
|
1648
|
+
const sfapNetworkAdapter = buildJwtNetworkAdapter(platformSfapJwtResolver, modifySfapResourceRequest);
|
|
1649
|
+
const composedNetworkAdapter$1 = {
|
|
1650
|
+
shouldHandleRequest(resourceRequest) {
|
|
1651
|
+
return resourceRequest.baseUri === SALESFORCE_API_BASE_URI_FLAG;
|
|
1652
|
+
},
|
|
1653
|
+
adapter: sfapNetworkAdapter,
|
|
1654
|
+
};
|
|
1655
|
+
|
|
1656
|
+
function buildJwtAuthorizedSfapFetchService() {
|
|
1657
|
+
const jwtRepository = new JwtRepository();
|
|
1658
|
+
const jwtManager = new JwtManager(jwtRepository, platformSfapJwtResolver);
|
|
1659
|
+
const jwtRequestModifier = ({ baseUri }, [resource, request]) => {
|
|
1660
|
+
if (typeof resource !== 'string') {
|
|
1661
|
+
// istanbul ignore else: this will not be tested in NODE_ENV = production for test coverage
|
|
1662
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1663
|
+
throw new Error('JwtAuthorizedSfapFetchService expects a string path');
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
return [`${baseUri}${resource}`, request];
|
|
1667
|
+
};
|
|
1668
|
+
const jwtRequestHeaderInterceptor = buildJwtRequestHeaderInterceptor(jwtManager, jwtRequestModifier);
|
|
1669
|
+
const jwtAuthorizedFetchService = buildFetchService({ request: [jwtRequestHeaderInterceptor] });
|
|
1670
|
+
return {
|
|
1671
|
+
...jwtAuthorizedFetchService,
|
|
1672
|
+
tags: { authenticationScopes: 'sfap_api' },
|
|
746
1673
|
};
|
|
747
1674
|
}
|
|
748
1675
|
|
|
@@ -774,9 +1701,10 @@ class LexDefaultPage extends PredictivePrefetchPage {
|
|
|
774
1701
|
}
|
|
775
1702
|
|
|
776
1703
|
class RecordHomePage extends PredictivePrefetchPage {
|
|
777
|
-
constructor(context, requestStrategies) {
|
|
1704
|
+
constructor(context, requestStrategies, options) {
|
|
778
1705
|
super(context);
|
|
779
1706
|
this.requestStrategies = requestStrategies;
|
|
1707
|
+
this.options = options;
|
|
780
1708
|
const { recordId: _, ...rest } = this.context;
|
|
781
1709
|
this.similarContext = {
|
|
782
1710
|
recordId: '*',
|
|
@@ -784,12 +1712,27 @@ class RecordHomePage extends PredictivePrefetchPage {
|
|
|
784
1712
|
};
|
|
785
1713
|
}
|
|
786
1714
|
buildSaveRequestData(request) {
|
|
1715
|
+
const requestBuckets = [];
|
|
787
1716
|
const { adapterName } = request;
|
|
788
1717
|
const matchingRequestStrategy = this.requestStrategies[adapterName];
|
|
789
1718
|
if (matchingRequestStrategy === undefined) {
|
|
790
1719
|
return [];
|
|
791
1720
|
}
|
|
792
|
-
|
|
1721
|
+
if (matchingRequestStrategy.isContextDependent(this.context, request)) {
|
|
1722
|
+
requestBuckets.push({
|
|
1723
|
+
context: this.similarContext,
|
|
1724
|
+
request: matchingRequestStrategy.transformForSaveSimilarRequest(request),
|
|
1725
|
+
});
|
|
1726
|
+
// When `options.useExactMatchesPlus` is not enabled, we can save this request on the similar bucket only
|
|
1727
|
+
if (!this.options.useExactMatchesPlus) {
|
|
1728
|
+
return requestBuckets;
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
requestBuckets.push({
|
|
1732
|
+
context: this.context,
|
|
1733
|
+
request: matchingRequestStrategy.transformForSave(request),
|
|
1734
|
+
});
|
|
1735
|
+
return requestBuckets;
|
|
793
1736
|
}
|
|
794
1737
|
resolveSimilarRequest(similarRequest) {
|
|
795
1738
|
const { adapterName } = similarRequest;
|
|
@@ -823,18 +1766,34 @@ class RecordHomePage extends PredictivePrefetchPage {
|
|
|
823
1766
|
}
|
|
824
1767
|
|
|
825
1768
|
class ObjectHomePage extends PredictivePrefetchPage {
|
|
826
|
-
constructor(context, requestStrategies) {
|
|
1769
|
+
constructor(context, requestStrategies, options) {
|
|
827
1770
|
super(context);
|
|
828
1771
|
this.requestStrategies = requestStrategies;
|
|
1772
|
+
this.options = options;
|
|
829
1773
|
this.similarContext = context;
|
|
830
1774
|
}
|
|
831
1775
|
buildSaveRequestData(request) {
|
|
1776
|
+
const requestBuckets = [];
|
|
832
1777
|
const { adapterName } = request;
|
|
833
1778
|
const matchingRequestStrategy = this.requestStrategies[adapterName];
|
|
834
|
-
if (matchingRequestStrategy) {
|
|
835
|
-
return
|
|
1779
|
+
if (matchingRequestStrategy === undefined) {
|
|
1780
|
+
return [];
|
|
836
1781
|
}
|
|
837
|
-
|
|
1782
|
+
if (matchingRequestStrategy.isContextDependent(this.context, request)) {
|
|
1783
|
+
requestBuckets.push({
|
|
1784
|
+
context: this.similarContext,
|
|
1785
|
+
request: matchingRequestStrategy.transformForSaveSimilarRequest(request),
|
|
1786
|
+
});
|
|
1787
|
+
// When `options.useExactMatchesPlus` is not enabled, we can save this request on the similar bucket only
|
|
1788
|
+
if (!this.options.useExactMatchesPlus) {
|
|
1789
|
+
return requestBuckets;
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
requestBuckets.push({
|
|
1793
|
+
context: this.context,
|
|
1794
|
+
request: matchingRequestStrategy.transformForSave(request),
|
|
1795
|
+
});
|
|
1796
|
+
return requestBuckets;
|
|
838
1797
|
}
|
|
839
1798
|
// no similar requests between LVs
|
|
840
1799
|
resolveSimilarRequest(similarRequest) {
|
|
@@ -867,6 +1826,12 @@ class ObjectHomePage extends PredictivePrefetchPage {
|
|
|
867
1826
|
recentListsOnly: true,
|
|
868
1827
|
},
|
|
869
1828
|
},
|
|
1829
|
+
{
|
|
1830
|
+
adapterName: 'getListObjectInfo',
|
|
1831
|
+
config: {
|
|
1832
|
+
objectApiName: objectApiName,
|
|
1833
|
+
},
|
|
1834
|
+
},
|
|
870
1835
|
];
|
|
871
1836
|
}
|
|
872
1837
|
// Identifies a valid ObjectHomeContext
|
|
@@ -925,8 +1890,8 @@ const TOTAL_ADAPTER_REQUEST_SUCCESS_COUNT = {
|
|
|
925
1890
|
},
|
|
926
1891
|
};
|
|
927
1892
|
|
|
928
|
-
const { create, keys } = Object;
|
|
929
|
-
const { isArray } = Array;
|
|
1893
|
+
const { create, keys, hasOwnProperty } = Object;
|
|
1894
|
+
const { isArray, from } = Array;
|
|
930
1895
|
const { stringify } = JSON;
|
|
931
1896
|
|
|
932
1897
|
/**
|
|
@@ -1411,7 +2376,7 @@ function setAuraInstrumentationHooks() {
|
|
|
1411
2376
|
// Our getRecord through aggregate-ui CRUD logging has moved
|
|
1412
2377
|
// to lds-network-adapter. We still need to respect the
|
|
1413
2378
|
// orgs environment setting
|
|
1414
|
-
if (forceRecordTransactionsDisabled === false) {
|
|
2379
|
+
if (forceRecordTransactionsDisabled$1 === false) {
|
|
1415
2380
|
ldsNetworkAdapterInstrument({
|
|
1416
2381
|
getRecordAggregateResolve: (cb) => {
|
|
1417
2382
|
const { recordId, apiName } = cb();
|
|
@@ -1454,10 +2419,9 @@ function logCRUDLightningInteraction(eventSource, attributes) {
|
|
|
1454
2419
|
const instrumentation = new Instrumentation();
|
|
1455
2420
|
|
|
1456
2421
|
class ApplicationPredictivePrefetcher {
|
|
1457
|
-
constructor(context, repository, requestRunner
|
|
2422
|
+
constructor(context, repository, requestRunner) {
|
|
1458
2423
|
this.repository = repository;
|
|
1459
2424
|
this.requestRunner = requestRunner;
|
|
1460
|
-
this.options = options;
|
|
1461
2425
|
this.isRecording = false;
|
|
1462
2426
|
this.queuedPredictionRequests = [];
|
|
1463
2427
|
this._context = context;
|
|
@@ -1554,10 +2518,11 @@ async function runRequestsWithLimit(requests, runner, concurrentRequestsLimit, p
|
|
|
1554
2518
|
// queue for pending prediction requests
|
|
1555
2519
|
const requestQueue = [...requests];
|
|
1556
2520
|
// Function to process the next request in the queue
|
|
1557
|
-
const processNextRequest = async () => {
|
|
1558
|
-
const timeInWaterfall = Date.now() - pageStartTime
|
|
2521
|
+
const processNextRequest = async (verifyPastTime = true) => {
|
|
2522
|
+
const timeInWaterfall = Date.now() - pageStartTime;
|
|
1559
2523
|
while (requestQueue.length > 0 &&
|
|
1560
|
-
|
|
2524
|
+
verifyPastTime &&
|
|
2525
|
+
requestQueue[0].requestMetadata.requestTime <= timeInWaterfall) {
|
|
1561
2526
|
requestQueue.shift();
|
|
1562
2527
|
}
|
|
1563
2528
|
if (requestQueue.length > 0) {
|
|
@@ -1576,7 +2541,13 @@ async function runRequestsWithLimit(requests, runner, concurrentRequestsLimit, p
|
|
|
1576
2541
|
const initialRequests = Math.min(concurrentRequestsLimit, requestQueue.length);
|
|
1577
2542
|
const promises = [];
|
|
1578
2543
|
for (let i = 0; i < initialRequests; i++) {
|
|
1579
|
-
|
|
2544
|
+
// Initial requests should always execute, without verifying if they are past due.
|
|
2545
|
+
// Reasoning:
|
|
2546
|
+
// It may be that one of the alwaysRequest (with 0 as start time) that is reduced
|
|
2547
|
+
// with the regular requests to make these to have 0 as the initial time in the waterfall.
|
|
2548
|
+
// Because predictions are behind an await (see W-16139321), it could be that when this code is evaluated
|
|
2549
|
+
// is already past time for the request.
|
|
2550
|
+
promises.push(processNextRequest(false));
|
|
1580
2551
|
}
|
|
1581
2552
|
// Wait for all initial requests to complete
|
|
1582
2553
|
await Promise.all(promises);
|
|
@@ -1585,58 +2556,73 @@ async function runRequestsWithLimit(requests, runner, concurrentRequestsLimit, p
|
|
|
1585
2556
|
function isCmpDefsRequest({ request: { adapterName } }) {
|
|
1586
2557
|
return adapterName === 'getComponentsDef';
|
|
1587
2558
|
}
|
|
2559
|
+
function predictComponentDefs(cmpDefPredictions, requestRunner) {
|
|
2560
|
+
const reducedPredictions = requestRunner.reduceRequests(cmpDefPredictions);
|
|
2561
|
+
reducedPredictions.map((request) => requestRunner.runRequest(request.request));
|
|
2562
|
+
}
|
|
1588
2563
|
class LexPredictivePrefetcher extends ApplicationPredictivePrefetcher {
|
|
1589
2564
|
constructor(context, repository, requestRunner,
|
|
1590
2565
|
// These strategies need to be in sync with the "predictiveDataLoadCapable" list
|
|
1591
2566
|
// from scripts/lds-uiapi-plugin.js
|
|
1592
2567
|
requestStrategies, options) {
|
|
1593
|
-
super(context, repository, requestRunner
|
|
2568
|
+
super(context, repository, requestRunner);
|
|
1594
2569
|
this.requestStrategies = requestStrategies;
|
|
2570
|
+
this.options = options;
|
|
1595
2571
|
this.page = this.getPage();
|
|
1596
2572
|
}
|
|
1597
2573
|
getPage() {
|
|
1598
2574
|
if (RecordHomePage.handlesContext(this.context)) {
|
|
1599
|
-
return new RecordHomePage(this.context, this.requestStrategies);
|
|
2575
|
+
return new RecordHomePage(this.context, this.requestStrategies, this.options);
|
|
1600
2576
|
}
|
|
1601
2577
|
else if (ObjectHomePage.handlesContext(this.context)) {
|
|
1602
|
-
return new ObjectHomePage(this.context, this.requestStrategies);
|
|
2578
|
+
return new ObjectHomePage(this.context, this.requestStrategies, this.options);
|
|
1603
2579
|
}
|
|
1604
2580
|
return new LexDefaultPage(this.context);
|
|
1605
2581
|
}
|
|
2582
|
+
getAllPageRequests() {
|
|
2583
|
+
const exactPageRequests = this.getExactPageRequest();
|
|
2584
|
+
if (exactPageRequests.length > 0 && this.options.useExactMatchesPlus === true) {
|
|
2585
|
+
return exactPageRequests;
|
|
2586
|
+
}
|
|
2587
|
+
const similarPageRequests = this.getSimilarPageRequests();
|
|
2588
|
+
return [...exactPageRequests, ...similarPageRequests];
|
|
2589
|
+
}
|
|
1606
2590
|
async predict() {
|
|
1607
|
-
const
|
|
1608
|
-
// IMPORTANT:
|
|
1609
|
-
//
|
|
1610
|
-
//
|
|
1611
|
-
//
|
|
1612
|
-
|
|
1613
|
-
|
|
2591
|
+
const pageRequests = this.getAllPageRequests();
|
|
2592
|
+
// IMPORTANT: Because there's no way to diferentiate a cmpDef prediction from the page
|
|
2593
|
+
// requesting the cmpDef, we need to predict cmpDefs before we start watching
|
|
2594
|
+
// for predictions in the page. Having this code after an
|
|
2595
|
+
// await will make the predictions to be saved as predictions too.
|
|
2596
|
+
predictComponentDefs(pageRequests.filter(isCmpDefsRequest), this.requestRunner);
|
|
2597
|
+
// IMPORTANT: The `await` has no effect on this operation because `getAlwaysRunRequests`
|
|
2598
|
+
// is sync; however if removed, it will have a negative effect when used with
|
|
2599
|
+
// Aura Network: predictions will be boxcar'd, which likely will result in a
|
|
2600
|
+
// perf regression.
|
|
2601
|
+
const alwaysRequests = await this.page.getAlwaysRunRequests();
|
|
1614
2602
|
const alwaysRequestEntries = alwaysRequests.map((request) => {
|
|
1615
2603
|
return {
|
|
1616
2604
|
request,
|
|
1617
2605
|
requestMetadata: { requestTime: 0 }, // ensures always requests are executed, and executed first.
|
|
1618
2606
|
};
|
|
1619
2607
|
});
|
|
2608
|
+
const nonCmpDefPredictions = pageRequests.filter((r) => !isCmpDefsRequest(r));
|
|
1620
2609
|
const reducedPredictions = this.requestRunner.reduceRequests([
|
|
1621
|
-
...
|
|
1622
|
-
...similarPageRequests,
|
|
2610
|
+
...nonCmpDefPredictions,
|
|
1623
2611
|
...alwaysRequestEntries,
|
|
1624
2612
|
]); // In future - remove alwaysRequestEntries when on OneStore
|
|
1625
|
-
const nonCmpDefPredictions = reducedPredictions.filter((r) => !isCmpDefsRequest(r));
|
|
1626
|
-
const cmpDefPredictions = reducedPredictions.filter(isCmpDefsRequest);
|
|
1627
|
-
// Non CmpDefs requests are limited by AuraActions concurent inflight limit.
|
|
1628
2613
|
// Always requests must go by themself - Some of them are essential to keep the page rendering at the beginning.
|
|
1629
|
-
const predictedRequestsWithLimit = [...alwaysRequestEntries, ...
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
2614
|
+
const predictedRequestsWithLimit = [...alwaysRequestEntries, ...reducedPredictions].sort((a, b) => a.requestMetadata.requestTime - b.requestMetadata.requestTime); // In future - choose sort algorithm via Gate?;
|
|
2615
|
+
await runRequestsWithLimit(predictedRequestsWithLimit, this.requestRunner, this.options.inflightRequestLimit,
|
|
2616
|
+
// `this.repository.pageStartTime` would be the correct here, but because
|
|
2617
|
+
// the await hack (see W-16139321), there's some delta by the time this executed,
|
|
2618
|
+
// on the other hand, when W-16139321 is fixed,
|
|
2619
|
+
// when doing predict+watch, it could be (set in watch) repository.startTime is not set yet,
|
|
2620
|
+
// Date.now() is a better alternative, that is correct, and works on both cases.
|
|
2621
|
+
Date.now());
|
|
1633
2622
|
}
|
|
1634
2623
|
}
|
|
1635
2624
|
|
|
1636
2625
|
// Copy-pasted from adapter-utils. This util should be extracted from generated code and imported in prefetch repository.
|
|
1637
|
-
const { keys: ObjectKeys$2 } = Object;
|
|
1638
|
-
const { stringify: JSONStringify } = JSON;
|
|
1639
|
-
const { isArray: ArrayIsArray$1 } = Array;
|
|
1640
2626
|
/**
|
|
1641
2627
|
* A deterministic JSON stringify implementation. Heavily adapted from https://github.com/epoberezkin/fast-json-stable-stringify.
|
|
1642
2628
|
* This is needed because insertion order for JSON.stringify(object) affects output:
|
|
@@ -1660,11 +2646,11 @@ function stableJSONStringify(node) {
|
|
|
1660
2646
|
return isFinite(node) ? '' + node : 'null';
|
|
1661
2647
|
}
|
|
1662
2648
|
if (typeof node !== 'object') {
|
|
1663
|
-
return
|
|
2649
|
+
return stringify(node);
|
|
1664
2650
|
}
|
|
1665
2651
|
let i;
|
|
1666
2652
|
let out;
|
|
1667
|
-
if (
|
|
2653
|
+
if (isArray(node)) {
|
|
1668
2654
|
out = '[';
|
|
1669
2655
|
for (i = 0; i < node.length; i++) {
|
|
1670
2656
|
if (i) {
|
|
@@ -1677,10 +2663,10 @@ function stableJSONStringify(node) {
|
|
|
1677
2663
|
if (node === null) {
|
|
1678
2664
|
return 'null';
|
|
1679
2665
|
}
|
|
1680
|
-
const keys =
|
|
2666
|
+
const keys$1 = keys(node).sort();
|
|
1681
2667
|
out = '';
|
|
1682
|
-
for (i = 0; i < keys.length; i++) {
|
|
1683
|
-
const key = keys[i];
|
|
2668
|
+
for (i = 0; i < keys$1.length; i++) {
|
|
2669
|
+
const key = keys$1[i];
|
|
1684
2670
|
const value = stableJSONStringify(node[key]);
|
|
1685
2671
|
if (!value) {
|
|
1686
2672
|
continue;
|
|
@@ -1688,7 +2674,7 @@ function stableJSONStringify(node) {
|
|
|
1688
2674
|
if (out) {
|
|
1689
2675
|
out += ',';
|
|
1690
2676
|
}
|
|
1691
|
-
out +=
|
|
2677
|
+
out += stringify(key) + ':' + value;
|
|
1692
2678
|
}
|
|
1693
2679
|
return '{' + out + '}';
|
|
1694
2680
|
}
|
|
@@ -1704,8 +2690,8 @@ function deepEquals(objA, objB) {
|
|
|
1704
2690
|
if (!isObject(objA) || !isObject(objB))
|
|
1705
2691
|
return false;
|
|
1706
2692
|
// Filter out keys set as undefined, we can compare undefined as equals.
|
|
1707
|
-
const keysA =
|
|
1708
|
-
const keysB =
|
|
2693
|
+
const keysA = keys(objA).filter((key) => objA[key] !== undefined);
|
|
2694
|
+
const keysB = keys(objB).filter((key) => objB[key] !== undefined);
|
|
1709
2695
|
// If the objects do not have the same set of keys, they are not deeply equal
|
|
1710
2696
|
if (keysA.length !== keysB.length)
|
|
1711
2697
|
return false;
|
|
@@ -1778,25 +2764,12 @@ class PrefetchRepository {
|
|
|
1778
2764
|
const page = this.getPage(key);
|
|
1779
2765
|
if (page === undefined) {
|
|
1780
2766
|
return [];
|
|
1781
|
-
}
|
|
1782
|
-
return page.requests;
|
|
1783
|
-
}
|
|
1784
|
-
}
|
|
1785
|
-
|
|
1786
|
-
class RequestStrategy {
|
|
1787
|
-
transformForSave(request) {
|
|
1788
|
-
return request;
|
|
1789
|
-
}
|
|
1790
|
-
reduce(requests) {
|
|
1791
|
-
return requests;
|
|
2767
|
+
}
|
|
2768
|
+
return page.requests;
|
|
1792
2769
|
}
|
|
1793
2770
|
}
|
|
1794
2771
|
|
|
1795
|
-
class
|
|
1796
|
-
constructor(options = {}) {
|
|
1797
|
-
super();
|
|
1798
|
-
this.prefetcherOptions = options;
|
|
1799
|
-
}
|
|
2772
|
+
class RequestStrategy {
|
|
1800
2773
|
/**
|
|
1801
2774
|
* Perform any transformations required to prepare the request for saving.
|
|
1802
2775
|
*
|
|
@@ -1809,6 +2782,14 @@ class LuvioAdapterRequestStrategy extends RequestStrategy {
|
|
|
1809
2782
|
transformForSave(request) {
|
|
1810
2783
|
return request;
|
|
1811
2784
|
}
|
|
2785
|
+
/**
|
|
2786
|
+
* Transforms the request for saving similar requests
|
|
2787
|
+
* @param request Request to transform for saving similar requests
|
|
2788
|
+
* @returns Transformed request
|
|
2789
|
+
*/
|
|
2790
|
+
transformForSaveSimilarRequest(request) {
|
|
2791
|
+
return this.transformForSave(request);
|
|
2792
|
+
}
|
|
1812
2793
|
/**
|
|
1813
2794
|
* Filter requests to only those that are for this strategy.
|
|
1814
2795
|
*
|
|
@@ -1887,58 +2868,6 @@ class LuvioAdapterRequestStrategy extends RequestStrategy {
|
|
|
1887
2868
|
isContextDependent(_context, _request) {
|
|
1888
2869
|
return false;
|
|
1889
2870
|
}
|
|
1890
|
-
/**
|
|
1891
|
-
* Builds request for saving,
|
|
1892
|
-
* - transforming the request
|
|
1893
|
-
* - handling the cases where the request is context dependent (this is homework for the subclass)
|
|
1894
|
-
* @param _similarContext Context with at least one parameter as a wildcard '*'
|
|
1895
|
-
* @param context Exact context for a given page
|
|
1896
|
-
* @param request Request to build save request data for
|
|
1897
|
-
* @returns Save request data
|
|
1898
|
-
*/
|
|
1899
|
-
buildSaveRequestData(similarContext, context, request) {
|
|
1900
|
-
const saveRequestDataBuckets = [];
|
|
1901
|
-
if (this.isContextDependent(context, request)) {
|
|
1902
|
-
saveRequestDataBuckets.push({
|
|
1903
|
-
request: this.transformForSaveSimilarRequest(request),
|
|
1904
|
-
context: similarContext,
|
|
1905
|
-
});
|
|
1906
|
-
const useSaveBuckets = this.prefetcherOptions && this.prefetcherOptions.useSaveBuckets;
|
|
1907
|
-
if (!useSaveBuckets) {
|
|
1908
|
-
return saveRequestDataBuckets;
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
saveRequestDataBuckets.push({
|
|
1912
|
-
request: this.transformForSave(request),
|
|
1913
|
-
context,
|
|
1914
|
-
});
|
|
1915
|
-
return saveRequestDataBuckets;
|
|
1916
|
-
}
|
|
1917
|
-
/**
|
|
1918
|
-
* Transforms the request for saving similar requests
|
|
1919
|
-
* @param request Request to transform for saving similar requests
|
|
1920
|
-
* @returns Transformed request
|
|
1921
|
-
*/
|
|
1922
|
-
transformForSaveSimilarRequest(request) {
|
|
1923
|
-
return this.transformForSave(request);
|
|
1924
|
-
}
|
|
1925
|
-
}
|
|
1926
|
-
|
|
1927
|
-
/**
|
|
1928
|
-
* This is a base class for non-luvio request strategies, which needs to be treated as
|
|
1929
|
-
* LuvioAdapterRequestStrategy.
|
|
1930
|
-
*/
|
|
1931
|
-
class ConfigBasedRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
1932
|
-
constructor() {
|
|
1933
|
-
super(...arguments);
|
|
1934
|
-
/**
|
|
1935
|
-
* Config based request strategies are not based on Luvio factory, however
|
|
1936
|
-
* the lex-predictive*, they all expect a LuvioAdapterRequestStrategy.
|
|
1937
|
-
*/
|
|
1938
|
-
this.adapterFactory = (_luvio) => {
|
|
1939
|
-
return (config) => this.executeWithConfig(config);
|
|
1940
|
-
};
|
|
1941
|
-
}
|
|
1942
2871
|
}
|
|
1943
2872
|
|
|
1944
2873
|
const noop = () => { };
|
|
@@ -2028,9 +2957,10 @@ function requestComponents(config) {
|
|
|
2028
2957
|
try {
|
|
2029
2958
|
for (let index = 0, n = config.length; index < n; index++) {
|
|
2030
2959
|
const def = config[index];
|
|
2031
|
-
if (
|
|
2032
|
-
def.includes('
|
|
2033
|
-
|
|
2960
|
+
if (def.startsWith('markup://') &&
|
|
2961
|
+
!(def.includes('forceGenerated') ||
|
|
2962
|
+
def.includes('one:onePreloads') ||
|
|
2963
|
+
onePreloads.has(def))) {
|
|
2034
2964
|
getDefinition(def, noop);
|
|
2035
2965
|
}
|
|
2036
2966
|
}
|
|
@@ -2039,12 +2969,12 @@ function requestComponents(config) {
|
|
|
2039
2969
|
// dismiss the error.
|
|
2040
2970
|
}
|
|
2041
2971
|
}
|
|
2042
|
-
class GetComponentsDefStrategy extends
|
|
2972
|
+
class GetComponentsDefStrategy extends RequestStrategy {
|
|
2043
2973
|
constructor() {
|
|
2044
2974
|
super(...arguments);
|
|
2045
2975
|
this.adapterName = 'getComponentsDef';
|
|
2046
2976
|
}
|
|
2047
|
-
|
|
2977
|
+
execute(config) {
|
|
2048
2978
|
return requestComponents(config);
|
|
2049
2979
|
}
|
|
2050
2980
|
buildConcreteRequest(similarRequest, _context) {
|
|
@@ -2052,18 +2982,11 @@ class GetComponentsDefStrategy extends ConfigBasedRequestStrategy {
|
|
|
2052
2982
|
...similarRequest,
|
|
2053
2983
|
};
|
|
2054
2984
|
}
|
|
2055
|
-
buildSaveRequestData(similarContext, _context, request) {
|
|
2056
|
-
return [
|
|
2057
|
-
{
|
|
2058
|
-
request: this.transformForSave(request),
|
|
2059
|
-
context: similarContext,
|
|
2060
|
-
},
|
|
2061
|
-
];
|
|
2062
|
-
}
|
|
2063
2985
|
transformForSave(request) {
|
|
2986
|
+
const normalizedConfig = (request.config || []).map((def) => def.indexOf('://') === -1 ? 'markup://' + def : def);
|
|
2064
2987
|
return {
|
|
2065
2988
|
...request,
|
|
2066
|
-
config:
|
|
2989
|
+
config: normalizedConfig,
|
|
2067
2990
|
};
|
|
2068
2991
|
}
|
|
2069
2992
|
canCombine() {
|
|
@@ -2074,6 +2997,26 @@ class GetComponentsDefStrategy extends ConfigBasedRequestStrategy {
|
|
|
2074
2997
|
reqB.forEach((c) => result.add(c));
|
|
2075
2998
|
return [...result];
|
|
2076
2999
|
}
|
|
3000
|
+
isContextDependent(_context, _request) {
|
|
3001
|
+
return true;
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3004
|
+
|
|
3005
|
+
const LDS_PDL_CMP_IDENTIFIER = 'lds:pdl';
|
|
3006
|
+
const DEFAULT_RESOURCE_CONTEXT = {
|
|
3007
|
+
sourceContext: { tagName: LDS_PDL_CMP_IDENTIFIER },
|
|
3008
|
+
};
|
|
3009
|
+
class LuvioAdapterRequestStrategy extends RequestStrategy {
|
|
3010
|
+
constructor(luvio) {
|
|
3011
|
+
super();
|
|
3012
|
+
this.luvio = luvio;
|
|
3013
|
+
}
|
|
3014
|
+
execute(config, requestContext) {
|
|
3015
|
+
return this.adapterFactory(this.luvio)(config, {
|
|
3016
|
+
...DEFAULT_RESOURCE_CONTEXT,
|
|
3017
|
+
...requestContext,
|
|
3018
|
+
});
|
|
3019
|
+
}
|
|
2077
3020
|
}
|
|
2078
3021
|
|
|
2079
3022
|
function normalizeRecordIds$1(recordIds) {
|
|
@@ -2231,7 +3174,7 @@ class GetRecordsRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
|
2231
3174
|
}
|
|
2232
3175
|
|
|
2233
3176
|
function normalizeRecordIds(recordIds) {
|
|
2234
|
-
if (!
|
|
3177
|
+
if (!isArray(recordIds)) {
|
|
2235
3178
|
return [recordIds];
|
|
2236
3179
|
}
|
|
2237
3180
|
return recordIds;
|
|
@@ -2240,7 +3183,7 @@ function normalizeApiNames(apiNames) {
|
|
|
2240
3183
|
if (apiNames === undefined || apiNames === null) {
|
|
2241
3184
|
return [];
|
|
2242
3185
|
}
|
|
2243
|
-
return
|
|
3186
|
+
return isArray(apiNames) ? apiNames : [apiNames];
|
|
2244
3187
|
}
|
|
2245
3188
|
class GetRecordActionsRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
2246
3189
|
constructor() {
|
|
@@ -2358,14 +3301,6 @@ class GetObjectInfosRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
|
2358
3301
|
}
|
|
2359
3302
|
return reducedRequests;
|
|
2360
3303
|
}
|
|
2361
|
-
buildSaveRequestData(similarContext, context, request) {
|
|
2362
|
-
return [
|
|
2363
|
-
{
|
|
2364
|
-
request: this.transformForSave(request),
|
|
2365
|
-
context,
|
|
2366
|
-
},
|
|
2367
|
-
];
|
|
2368
|
-
}
|
|
2369
3304
|
}
|
|
2370
3305
|
|
|
2371
3306
|
class GetObjectInfoRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
@@ -2415,11 +3350,9 @@ class GetObjectInfoRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
|
2415
3350
|
}
|
|
2416
3351
|
}
|
|
2417
3352
|
|
|
2418
|
-
const { keys: ObjectKeys$1 } = Object;
|
|
2419
|
-
const { isArray: ArrayIsArray, from: ArrayFrom } = Array;
|
|
2420
3353
|
function isReduceAbleRelatedListConfig(config) {
|
|
2421
3354
|
return config.relatedListsActionParameters.every((rlReq) => {
|
|
2422
|
-
return rlReq.relatedListId !== undefined &&
|
|
3355
|
+
return rlReq.relatedListId !== undefined && keys(rlReq).length === 1;
|
|
2423
3356
|
});
|
|
2424
3357
|
}
|
|
2425
3358
|
class GetRelatedListsActionsRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
@@ -2463,7 +3396,7 @@ class GetRelatedListsActionsRequestStrategy extends LuvioAdapterRequestStrategy
|
|
|
2463
3396
|
*/
|
|
2464
3397
|
canCombine(reqA, reqB) {
|
|
2465
3398
|
const [recordIdA, recordIdB] = [reqA.recordIds, reqB.recordIds].map((recordIds) => {
|
|
2466
|
-
return
|
|
3399
|
+
return isArray(recordIds)
|
|
2467
3400
|
? recordIds.length === 1
|
|
2468
3401
|
? recordIds[0]
|
|
2469
3402
|
: null
|
|
@@ -2481,7 +3414,7 @@ class GetRelatedListsActionsRequestStrategy extends LuvioAdapterRequestStrategy
|
|
|
2481
3414
|
});
|
|
2482
3415
|
return {
|
|
2483
3416
|
recordIds: reqA.recordIds,
|
|
2484
|
-
relatedListsActionParameters:
|
|
3417
|
+
relatedListsActionParameters: from(relatedListsIncluded).map((relatedListId) => ({
|
|
2485
3418
|
relatedListId,
|
|
2486
3419
|
})),
|
|
2487
3420
|
};
|
|
@@ -2637,14 +3570,6 @@ class GetApexRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
|
2637
3570
|
buildConcreteRequest(similarRequest) {
|
|
2638
3571
|
return similarRequest;
|
|
2639
3572
|
}
|
|
2640
|
-
buildSaveRequestData(_similarContext, context, request) {
|
|
2641
|
-
return [
|
|
2642
|
-
{
|
|
2643
|
-
request: this.transformForSave(request),
|
|
2644
|
-
context,
|
|
2645
|
-
},
|
|
2646
|
-
];
|
|
2647
|
-
}
|
|
2648
3573
|
}
|
|
2649
3574
|
|
|
2650
3575
|
const GET_LIST_INFO_BY_NAME_ADAPTER_NAME = 'getListInfoByName';
|
|
@@ -2667,14 +3592,6 @@ class GetListInfoByNameRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
|
2667
3592
|
},
|
|
2668
3593
|
};
|
|
2669
3594
|
}
|
|
2670
|
-
buildSaveRequestData(_similarContext, context, request) {
|
|
2671
|
-
return [
|
|
2672
|
-
{
|
|
2673
|
-
request: this.transformForSave(request),
|
|
2674
|
-
context,
|
|
2675
|
-
},
|
|
2676
|
-
];
|
|
2677
|
-
}
|
|
2678
3595
|
canCombine(reqA, reqB) {
|
|
2679
3596
|
return (reqA.objectApiName === reqB.objectApiName &&
|
|
2680
3597
|
reqA.listViewApiName === reqB.listViewApiName);
|
|
@@ -2704,14 +3621,6 @@ class GetListInfosByObjectNameRequestStrategy extends LuvioAdapterRequestStrateg
|
|
|
2704
3621
|
},
|
|
2705
3622
|
};
|
|
2706
3623
|
}
|
|
2707
|
-
buildSaveRequestData(_similarContext, context, request) {
|
|
2708
|
-
return [
|
|
2709
|
-
{
|
|
2710
|
-
request: this.transformForSave(request),
|
|
2711
|
-
context,
|
|
2712
|
-
},
|
|
2713
|
-
];
|
|
2714
|
-
}
|
|
2715
3624
|
canCombine(reqA, reqB) {
|
|
2716
3625
|
return (reqA.objectApiName === reqB.objectApiName &&
|
|
2717
3626
|
reqA.q === reqB.q &&
|
|
@@ -2753,36 +3662,50 @@ class GetListRecordsByNameRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
|
2753
3662
|
// to build the key should solve this issue till then we can't move fields into optional fields
|
|
2754
3663
|
return request;
|
|
2755
3664
|
}
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
3665
|
+
}
|
|
3666
|
+
|
|
3667
|
+
const GET_LIST_OBJECT_INFO_ADAPTER_NAME = 'getListObjectInfo';
|
|
3668
|
+
class GetListObjectInfoRequestStrategy extends LuvioAdapterRequestStrategy {
|
|
3669
|
+
constructor() {
|
|
3670
|
+
super(...arguments);
|
|
3671
|
+
this.adapterName = GET_LIST_OBJECT_INFO_ADAPTER_NAME;
|
|
3672
|
+
this.adapterFactory = getListObjectInfoAdapterFactory;
|
|
3673
|
+
}
|
|
3674
|
+
buildConcreteRequest(similarRequest) {
|
|
3675
|
+
return similarRequest;
|
|
3676
|
+
}
|
|
3677
|
+
transformForSave(request) {
|
|
3678
|
+
return {
|
|
3679
|
+
...request,
|
|
3680
|
+
config: {
|
|
3681
|
+
...request.config,
|
|
3682
|
+
// (!): if we are saving this request is because the adapter already verified is valid.
|
|
3683
|
+
objectApiName: coerceObjectId(request.config.objectApiName),
|
|
2761
3684
|
},
|
|
2762
|
-
|
|
3685
|
+
};
|
|
2763
3686
|
}
|
|
2764
3687
|
}
|
|
2765
3688
|
|
|
2766
|
-
const LDS_PDL_CMP_IDENTIFIER = 'lds:pdl';
|
|
2767
3689
|
class LexRequestRunner {
|
|
2768
3690
|
constructor(luvio) {
|
|
2769
3691
|
this.luvio = luvio;
|
|
2770
3692
|
this.requestStrategies = {
|
|
2771
|
-
getRecord: new GetRecordRequestStrategy(
|
|
2772
|
-
getRecords: new GetRecordsRequestStrategy(
|
|
2773
|
-
getRecordActions: new GetRecordActionsRequestStrategy(
|
|
2774
|
-
getRecordAvatars: new GetRecordAvatarsRequestStrategy(
|
|
2775
|
-
getObjectInfo: new GetObjectInfoRequestStrategy(
|
|
2776
|
-
getObjectInfos: new GetObjectInfosRequestStrategy(
|
|
2777
|
-
getRelatedListsActions: new GetRelatedListsActionsRequestStrategy(
|
|
2778
|
-
getRelatedListInfoBatch: new GetRelatedListInfoBatchRequestStrategy(
|
|
2779
|
-
getRelatedListRecords: new GetRelatedListRecordsRequestStrategy(
|
|
2780
|
-
getRelatedListRecordsBatch: new GetRelatedListRecordsBatchRequestStrategy(
|
|
2781
|
-
getListInfoByName: new GetListInfoByNameRequestStrategy(
|
|
2782
|
-
getListRecordsByName: new GetListRecordsByNameRequestStrategy(
|
|
2783
|
-
getApex: new GetApexRequestStrategy(
|
|
2784
|
-
getComponentsDef: new GetComponentsDefStrategy(
|
|
2785
|
-
getListInfosByObjectName: new GetListInfosByObjectNameRequestStrategy(
|
|
3693
|
+
getRecord: new GetRecordRequestStrategy(luvio),
|
|
3694
|
+
getRecords: new GetRecordsRequestStrategy(luvio),
|
|
3695
|
+
getRecordActions: new GetRecordActionsRequestStrategy(luvio),
|
|
3696
|
+
getRecordAvatars: new GetRecordAvatarsRequestStrategy(luvio),
|
|
3697
|
+
getObjectInfo: new GetObjectInfoRequestStrategy(luvio),
|
|
3698
|
+
getObjectInfos: new GetObjectInfosRequestStrategy(luvio),
|
|
3699
|
+
getRelatedListsActions: new GetRelatedListsActionsRequestStrategy(luvio),
|
|
3700
|
+
getRelatedListInfoBatch: new GetRelatedListInfoBatchRequestStrategy(luvio),
|
|
3701
|
+
getRelatedListRecords: new GetRelatedListRecordsRequestStrategy(luvio),
|
|
3702
|
+
getRelatedListRecordsBatch: new GetRelatedListRecordsBatchRequestStrategy(luvio),
|
|
3703
|
+
getListInfoByName: new GetListInfoByNameRequestStrategy(luvio),
|
|
3704
|
+
getListRecordsByName: new GetListRecordsByNameRequestStrategy(luvio),
|
|
3705
|
+
getApex: new GetApexRequestStrategy(luvio),
|
|
3706
|
+
getComponentsDef: new GetComponentsDefStrategy(),
|
|
3707
|
+
getListInfosByObjectName: new GetListInfosByObjectNameRequestStrategy(luvio),
|
|
3708
|
+
getListObjectInfo: new GetListObjectInfoRequestStrategy(luvio),
|
|
2786
3709
|
};
|
|
2787
3710
|
}
|
|
2788
3711
|
reduceRequests(requests) {
|
|
@@ -2792,10 +3715,7 @@ class LexRequestRunner {
|
|
|
2792
3715
|
}
|
|
2793
3716
|
runRequest(request) {
|
|
2794
3717
|
if (request.adapterName in this.requestStrategies) {
|
|
2795
|
-
|
|
2796
|
-
return Promise.resolve(adapterFactory(this.luvio)(request.config, {
|
|
2797
|
-
sourceContext: { tagName: LDS_PDL_CMP_IDENTIFIER },
|
|
2798
|
-
})).then();
|
|
3718
|
+
return Promise.resolve(this.requestStrategies[request.adapterName].execute(request.config)).then();
|
|
2799
3719
|
}
|
|
2800
3720
|
return Promise.resolve(undefined);
|
|
2801
3721
|
}
|
|
@@ -2814,13 +3734,12 @@ class InMemoryPrefetchStorage {
|
|
|
2814
3734
|
}
|
|
2815
3735
|
}
|
|
2816
3736
|
|
|
2817
|
-
const { keys: ObjectKeys } = Object;
|
|
2818
3737
|
const DEFAULT_STORAGE_OPTIONS = {
|
|
2819
3738
|
name: 'ldsPredictiveLoading',
|
|
2820
3739
|
persistent: true,
|
|
2821
3740
|
secure: true,
|
|
2822
3741
|
maxSize: 7 * 1024 * 1024,
|
|
2823
|
-
expiration:
|
|
3742
|
+
expiration: 5 * 24 * 60 * 60,
|
|
2824
3743
|
clearOnInit: false,
|
|
2825
3744
|
debugLogging: false,
|
|
2826
3745
|
version: 3,
|
|
@@ -2853,7 +3772,7 @@ class AuraPrefetchStorage {
|
|
|
2853
3772
|
* then they will (potentially incorrectly) think that we don't have any predictions.
|
|
2854
3773
|
*/
|
|
2855
3774
|
auraStorage.getAll().then((results) => {
|
|
2856
|
-
|
|
3775
|
+
keys(results).forEach((key) => this.inMemoryStorage.set(key, results[key]));
|
|
2857
3776
|
});
|
|
2858
3777
|
}
|
|
2859
3778
|
set(key, value) {
|
|
@@ -2889,84 +3808,308 @@ function buildComposableNetworkAdapter(composedAdapters) {
|
|
|
2889
3808
|
};
|
|
2890
3809
|
}
|
|
2891
3810
|
|
|
2892
|
-
const SALESFORCE_API_BASE_URI_FLAG = 'api.salesforce.com';
|
|
2893
|
-
const SFAPController = 'SalesforceApiPlatformController';
|
|
2894
|
-
const SFAPJwtMethod = 'getSFAPLightningJwtService';
|
|
2895
3811
|
/**
|
|
2896
|
-
*
|
|
2897
|
-
*
|
|
2898
|
-
*
|
|
3812
|
+
* Copyright (c) 2022, Salesforce, Inc.,
|
|
3813
|
+
* All rights reserved.
|
|
3814
|
+
* For full license text, see the LICENSE.txt file
|
|
2899
3815
|
*/
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
3816
|
+
|
|
3817
|
+
/*
|
|
3818
|
+
* ATTENTION!
|
|
3819
|
+
* THIS IS A GENERATED FILE FROM https://github.com/salesforce-experience-platform-emu/lds-lightning-platform
|
|
3820
|
+
* If you would like to contribute to LDS, please follow the steps outlined in the git repo.
|
|
3821
|
+
* Any changes made to this file in p4 will be automatically overwritten.
|
|
3822
|
+
* *******************************************************************************************
|
|
3823
|
+
*/
|
|
3824
|
+
/* proxy-compat-disable */
|
|
3825
|
+
var EnvironmentSettings;
|
|
3826
|
+
(function (EnvironmentSettings) {
|
|
3827
|
+
EnvironmentSettings["ForceRecordTransactionsDisabled"] = "forceRecordTransactionsDisabled";
|
|
3828
|
+
})(EnvironmentSettings || (EnvironmentSettings = {}));
|
|
3829
|
+
const GATE_FORCE_RECORD_TRANSACTIONS_DISABLED = '$Browser.S1Features.forceRecordTransactionsDisabled';
|
|
3830
|
+
const supportedEnvironmentSettings = {
|
|
3831
|
+
[EnvironmentSettings.ForceRecordTransactionsDisabled]: GATE_FORCE_RECORD_TRANSACTIONS_DISABLED,
|
|
3832
|
+
};
|
|
2907
3833
|
/**
|
|
2908
|
-
*
|
|
2909
|
-
*
|
|
3834
|
+
* Returns aura configuration settings. Used to check gate/perm statuses.
|
|
3835
|
+
* @param name Name of the setting to check.
|
|
3836
|
+
* @returns Value of the setting, or undefined if $A is not available.
|
|
2910
3837
|
*/
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
3838
|
+
function getEnvironmentSetting(name) {
|
|
3839
|
+
if (typeof window === 'undefined') {
|
|
3840
|
+
// server environment i.e. SSR in LWR
|
|
3841
|
+
return undefined;
|
|
3842
|
+
}
|
|
3843
|
+
const environmentSetting = supportedEnvironmentSettings[name];
|
|
3844
|
+
if (typeof window.$A !== 'undefined' && environmentSetting !== undefined) {
|
|
3845
|
+
return window.$A.get(environmentSetting);
|
|
3846
|
+
}
|
|
3847
|
+
return undefined;
|
|
3848
|
+
}
|
|
3849
|
+
// version: 1.304.0-d87b57badb
|
|
3850
|
+
|
|
3851
|
+
const forceRecordTransactionsDisabled = getEnvironmentSetting(EnvironmentSettings.ForceRecordTransactionsDisabled);
|
|
3852
|
+
//TODO: Some duplication here that can be most likely moved to a util class
|
|
3853
|
+
const NO_RECORD_ID_204 = '204_NO_RECORD_ID';
|
|
3854
|
+
const NO_RECORD_TYPE_204 = '204_NO_RECORD_TYPE';
|
|
3855
|
+
let crudInstrumentationCallbacks = {};
|
|
3856
|
+
let crudRLInstrumentationCallbacks = {};
|
|
3857
|
+
if (forceRecordTransactionsDisabled === false) {
|
|
3858
|
+
// Record callbacks
|
|
3859
|
+
crudInstrumentationCallbacks = {
|
|
3860
|
+
createRecordRejectFunction: (config) => {
|
|
3861
|
+
logCRUDLightningInteraction(CrudEventType.CREATE, {
|
|
3862
|
+
// recordId: config.params.recordInput.apiName, // seems wrong?
|
|
3863
|
+
recordId: config.params.recordId || NO_RECORD_ID_204,
|
|
3864
|
+
state: CrudEventState.ERROR,
|
|
3865
|
+
});
|
|
3866
|
+
},
|
|
3867
|
+
createRecordResolveFunction: (config) => {
|
|
3868
|
+
const recordId = config.body ? config.body.id : NO_RECORD_ID_204;
|
|
3869
|
+
const recordType = config.body ? config.body.apiName : NO_RECORD_TYPE_204;
|
|
3870
|
+
logCRUDLightningInteraction(CrudEventType.CREATE, {
|
|
3871
|
+
recordId,
|
|
3872
|
+
recordType,
|
|
3873
|
+
state: CrudEventState.SUCCESS,
|
|
3874
|
+
});
|
|
3875
|
+
},
|
|
3876
|
+
deleteRecordRejectFunction: (config) => {
|
|
3877
|
+
logCRUDLightningInteraction(CrudEventType.DELETE, {
|
|
3878
|
+
recordId: config.params.recordId,
|
|
3879
|
+
state: CrudEventState.ERROR,
|
|
3880
|
+
});
|
|
3881
|
+
},
|
|
3882
|
+
deleteRecordResolveFunction: (config) => {
|
|
3883
|
+
logCRUDLightningInteraction(CrudEventType.DELETE, {
|
|
3884
|
+
recordId: config.params.recordId,
|
|
3885
|
+
state: CrudEventState.SUCCESS,
|
|
3886
|
+
});
|
|
3887
|
+
},
|
|
3888
|
+
// These should be handled by the network adapater?
|
|
3889
|
+
// getRecordAggregateRejectFunction: (config: InstrumentationRejectConfig) => {
|
|
3890
|
+
// logCRUDLightningInteraction(CrudEventType.READ, {
|
|
3891
|
+
// recordId: config.params.recordId,
|
|
3892
|
+
// state: CrudEventState.ERROR,
|
|
3893
|
+
// });
|
|
3894
|
+
// },
|
|
3895
|
+
// getRecordAggregateResolveFunction: (config: InstrumentationResolveConfig) => {
|
|
3896
|
+
// logCRUDLightningInteraction(CrudEventType.READ, {
|
|
3897
|
+
// recordId: config.params.recordId,
|
|
3898
|
+
// recordType: config.body.apiName,
|
|
3899
|
+
// state: CrudEventState.SUCCESS,
|
|
3900
|
+
// });
|
|
3901
|
+
// },
|
|
3902
|
+
getRecordRejectFunction: (config) => {
|
|
3903
|
+
logCRUDLightningInteraction(CrudEventType.READ, {
|
|
3904
|
+
recordId: config.params.recordId,
|
|
3905
|
+
state: CrudEventState.ERROR,
|
|
3906
|
+
});
|
|
3907
|
+
},
|
|
3908
|
+
getRecordResolveFunction: (config) => {
|
|
3909
|
+
logCRUDLightningInteraction(CrudEventType.READ, {
|
|
3910
|
+
recordId: config.params.recordId,
|
|
3911
|
+
recordType: config.body.apiName,
|
|
3912
|
+
state: CrudEventState.SUCCESS,
|
|
3913
|
+
});
|
|
3914
|
+
},
|
|
3915
|
+
updateRecordRejectFunction: (config) => {
|
|
3916
|
+
logCRUDLightningInteraction(CrudEventType.UPDATE, {
|
|
3917
|
+
recordId: config.params.recordId,
|
|
3918
|
+
state: CrudEventState.ERROR,
|
|
3919
|
+
});
|
|
3920
|
+
},
|
|
3921
|
+
updateRecordResolveFunction: (config) => {
|
|
3922
|
+
const recordType = config.body ? config.body.apiName : NO_RECORD_TYPE_204;
|
|
3923
|
+
logCRUDLightningInteraction(CrudEventType.UPDATE, {
|
|
3924
|
+
recordId: config.params.recordId,
|
|
3925
|
+
recordType,
|
|
3926
|
+
state: CrudEventState.SUCCESS,
|
|
3927
|
+
});
|
|
3928
|
+
},
|
|
3929
|
+
};
|
|
3930
|
+
// Related list callbacks
|
|
3931
|
+
crudRLInstrumentationCallbacks = {
|
|
3932
|
+
getRelatedListRecordsRejectFunction: (config) => {
|
|
3933
|
+
logCRUDLightningInteraction(CrudEventType.READS, {
|
|
3934
|
+
parentRecordId: config.params.parentRecordId,
|
|
3935
|
+
relatedListId: config.params.relatedListId,
|
|
3936
|
+
state: CrudEventState.ERROR,
|
|
3937
|
+
});
|
|
3938
|
+
},
|
|
3939
|
+
getRelatedListRecordsResolveFunction: (config) => {
|
|
3940
|
+
logGetRelatedListRecordsInteraction(config.body);
|
|
3941
|
+
},
|
|
3942
|
+
getRelatedListRecordsBatchRejectFunction: (config) => {
|
|
3943
|
+
logCRUDLightningInteraction(CrudEventType.READS, {
|
|
3944
|
+
parentRecordId: config.params.parentRecordId,
|
|
3945
|
+
relatedListIds: config.params.relatedListParameters.map((entry) => entry.relatedListId),
|
|
3946
|
+
state: CrudEventState.ERROR,
|
|
3947
|
+
});
|
|
3948
|
+
},
|
|
3949
|
+
getRelatedListRecordsBatchResolveFunction: (config) => {
|
|
3950
|
+
config.body.results.forEach((res) => {
|
|
3951
|
+
// Log for each RL that was returned from batch endpoint
|
|
3952
|
+
if (res.statusCode === 200) {
|
|
3953
|
+
logGetRelatedListRecordsInteraction(res.result);
|
|
2938
3954
|
}
|
|
2939
|
-
reject(error.body.error);
|
|
2940
3955
|
});
|
|
2941
|
-
}
|
|
3956
|
+
},
|
|
3957
|
+
};
|
|
3958
|
+
}
|
|
3959
|
+
// Helper function copied from ui-api
|
|
3960
|
+
function logGetRelatedListRecordsInteraction(body) {
|
|
3961
|
+
const records = body.records;
|
|
3962
|
+
// Don't log anything if the related list has no records.
|
|
3963
|
+
if (records.length === 0) {
|
|
3964
|
+
return;
|
|
3965
|
+
}
|
|
3966
|
+
const recordIds = records.map((record) => {
|
|
3967
|
+
return record.id;
|
|
3968
|
+
});
|
|
3969
|
+
/**
|
|
3970
|
+
* In almost every case - the relatedList records will all be of the same apiName, but there is an edge case for
|
|
3971
|
+
Activities entity that could return Events & Tasks- so handle that case by returning a joined string.
|
|
3972
|
+
ADS Implementation only looks at the first record returned to determine the apiName.
|
|
3973
|
+
See force/recordLibrary/recordMetricsPlugin.js _getRecordType method.
|
|
3974
|
+
*/
|
|
3975
|
+
logCRUDLightningInteraction(CrudEventType.READS, {
|
|
3976
|
+
parentRecordId: body.listReference.inContextOfRecordId,
|
|
3977
|
+
relatedListId: body.listReference.relatedListId,
|
|
3978
|
+
recordIds,
|
|
3979
|
+
recordType: body.records[0].apiName,
|
|
3980
|
+
state: CrudEventState.SUCCESS,
|
|
3981
|
+
});
|
|
3982
|
+
}
|
|
3983
|
+
const crudInstrumentationConfig = {
|
|
3984
|
+
records: {
|
|
3985
|
+
post: {
|
|
3986
|
+
rejectFn: crudInstrumentationCallbacks.createRecordRejectFunction,
|
|
3987
|
+
resolveFn: crudInstrumentationCallbacks.createRecordResolveFunction,
|
|
3988
|
+
},
|
|
3989
|
+
get: {
|
|
3990
|
+
rejectFn: crudInstrumentationCallbacks.getRecordRejectFunction,
|
|
3991
|
+
resolveFn: crudInstrumentationCallbacks.getRecordResolveFunction,
|
|
3992
|
+
},
|
|
3993
|
+
patch: {
|
|
3994
|
+
rejectFn: crudInstrumentationCallbacks.updateRecordRejectFunction,
|
|
3995
|
+
resolveFn: crudInstrumentationCallbacks.updateRecordResolveFunction,
|
|
3996
|
+
},
|
|
3997
|
+
delete: {
|
|
3998
|
+
rejectFn: crudInstrumentationCallbacks.deleteRecordRejectFunction,
|
|
3999
|
+
resolveFn: crudInstrumentationCallbacks.deleteRecordResolveFunction,
|
|
4000
|
+
},
|
|
4001
|
+
},
|
|
4002
|
+
relatedListRecords: {
|
|
4003
|
+
post: {
|
|
4004
|
+
rejectFn: crudRLInstrumentationCallbacks.getRelatedListRecordsRejectFunction,
|
|
4005
|
+
resolveFn: crudRLInstrumentationCallbacks.getRelatedListRecordsResolveFunction,
|
|
4006
|
+
},
|
|
4007
|
+
},
|
|
4008
|
+
relatedListRecordsBatch: {
|
|
4009
|
+
post: {
|
|
4010
|
+
rejectFn: crudRLInstrumentationCallbacks.getRelatedListRecordsBatchRejectFunction,
|
|
4011
|
+
resolveFn: crudRLInstrumentationCallbacks.getRelatedListRecordsBatchResolveFunction,
|
|
4012
|
+
},
|
|
2942
4013
|
},
|
|
2943
4014
|
};
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
4015
|
+
function checkAndLogCrudInteraction(request, isResolve, error, response) {
|
|
4016
|
+
let configPath;
|
|
4017
|
+
const baseUrl = `${request.baseUri}${request.basePath}`;
|
|
4018
|
+
if (baseUrl.startsWith(UIAPI_RECORDS_PATH)) {
|
|
4019
|
+
configPath = crudInstrumentationConfig['records']; // maybe use a constant for this
|
|
4020
|
+
}
|
|
4021
|
+
else if (baseUrl.startsWith(UIAPI_RELATED_LIST_RECORDS_BATCH_PATH)) {
|
|
4022
|
+
configPath = crudInstrumentationConfig['relatedListRecordsBatch'];
|
|
4023
|
+
}
|
|
4024
|
+
else if (baseUrl.startsWith(UIAPI_RELATED_LIST_RECORDS_PATH)) {
|
|
4025
|
+
configPath = crudInstrumentationConfig['relatedListRecords'];
|
|
4026
|
+
}
|
|
4027
|
+
if (configPath) {
|
|
4028
|
+
const crudCallbacks = configPath[request.method];
|
|
4029
|
+
if (crudCallbacks) {
|
|
4030
|
+
if (isResolve && crudCallbacks.resolveFn) {
|
|
4031
|
+
crudCallbacks.resolveFn(setResolveConfig(request, response));
|
|
4032
|
+
}
|
|
4033
|
+
else if (crudCallbacks.rejectFn) {
|
|
4034
|
+
crudCallbacks.rejectFn(setRejectConfig(request, error));
|
|
4035
|
+
}
|
|
4036
|
+
}
|
|
4037
|
+
}
|
|
4038
|
+
}
|
|
4039
|
+
function setResolveConfig(request, response) {
|
|
4040
|
+
const responseBody = response ? response.body : {};
|
|
4041
|
+
const urlParams = request.urlParams || {};
|
|
4042
|
+
return {
|
|
4043
|
+
body: responseBody,
|
|
4044
|
+
params: {
|
|
4045
|
+
recordId: urlParams.recordId,
|
|
4046
|
+
},
|
|
4047
|
+
};
|
|
4048
|
+
}
|
|
4049
|
+
function setRejectConfig(request, error) {
|
|
4050
|
+
const requestBody = request.body || {};
|
|
4051
|
+
const urlParams = request.urlParams || {};
|
|
4052
|
+
return {
|
|
4053
|
+
err: error,
|
|
4054
|
+
params: {
|
|
4055
|
+
recordId: urlParams.recordId,
|
|
4056
|
+
// pass these in even if they're undefined
|
|
4057
|
+
parentRecordId: urlParams.parentRecordId,
|
|
4058
|
+
relatedListId: urlParams.relatedListId,
|
|
4059
|
+
relatedListParameters: requestBody.relatedListParameters,
|
|
4060
|
+
},
|
|
4061
|
+
};
|
|
4062
|
+
}
|
|
4063
|
+
|
|
4064
|
+
const UIAPI_FAMILY = '/ui-api/'; // swap this to an allowlist per family (or build it off package.jsons?)
|
|
4065
|
+
// Denylist
|
|
4066
|
+
const PRIVATE_RESOURCES = ['record-avatars', 'user-state']; // These resources have Connect client filters, must be requested through UiTier :eyeroll:
|
|
4067
|
+
function isPrivatePath(basePath) {
|
|
4068
|
+
return PRIVATE_RESOURCES.some((privateResource) => basePath.includes(privateResource));
|
|
4069
|
+
}
|
|
4070
|
+
const modifyLexResourceRequest = function (resourceRequest, jwtToken) {
|
|
4071
|
+
const jwtBaseUri = jwtToken.decodedInfo.iss;
|
|
2954
4072
|
return {
|
|
2955
4073
|
...resourceRequest,
|
|
2956
|
-
baseUri,
|
|
4074
|
+
baseUri: jwtBaseUri + resourceRequest.baseUri,
|
|
2957
4075
|
};
|
|
2958
4076
|
};
|
|
2959
|
-
const
|
|
2960
|
-
|
|
4077
|
+
const requestTracker = {
|
|
4078
|
+
registerHandler: (request, name, loadedCheck) => {
|
|
4079
|
+
ThirdPartyTracker.registerHandler(request, name, loadedCheck);
|
|
4080
|
+
},
|
|
4081
|
+
markFinished: (request) => {
|
|
4082
|
+
ThirdPartyTracker.markLoaded(request);
|
|
4083
|
+
},
|
|
4084
|
+
};
|
|
4085
|
+
const requestLogger = {
|
|
4086
|
+
resolve: (request, response = {}) => {
|
|
4087
|
+
checkAndLogCrudInteraction(request, true, null, response);
|
|
4088
|
+
},
|
|
4089
|
+
reject: (request, error) => {
|
|
4090
|
+
checkAndLogCrudInteraction(request, false, error);
|
|
4091
|
+
},
|
|
4092
|
+
};
|
|
4093
|
+
const composedFetchNetworkAdapter = {
|
|
2961
4094
|
shouldHandleRequest(resourceRequest) {
|
|
2962
|
-
return resourceRequest.
|
|
4095
|
+
return (resourceRequest.basePath.startsWith(UIAPI_FAMILY) &&
|
|
4096
|
+
!isPrivatePath(resourceRequest.basePath));
|
|
2963
4097
|
},
|
|
2964
|
-
adapter:
|
|
4098
|
+
adapter: setupLexJwtNetworkAdapter(auraNetworkAdapter, modifyLexResourceRequest, requestTracker, requestLogger),
|
|
2965
4099
|
};
|
|
2966
4100
|
|
|
4101
|
+
function getComposedAdapters() {
|
|
4102
|
+
const composedAdapters = [
|
|
4103
|
+
composedNetworkAdapter$1, // SFAP adapter
|
|
4104
|
+
];
|
|
4105
|
+
if (useHttpInsteadAuraTransport.isOpen({ fallback: false })) {
|
|
4106
|
+
composedAdapters.push(composedFetchNetworkAdapter); // UIAPI Fetch adapter?
|
|
4107
|
+
}
|
|
4108
|
+
return composedAdapters;
|
|
4109
|
+
}
|
|
2967
4110
|
const composedNetworkAdapter = buildComposableNetworkAdapter([
|
|
2968
|
-
|
|
2969
|
-
// The
|
|
4111
|
+
...getComposedAdapters(),
|
|
4112
|
+
// The aura network adapter must be the default.
|
|
2970
4113
|
{
|
|
2971
4114
|
shouldHandleRequest() {
|
|
2972
4115
|
return true;
|
|
@@ -3026,64 +4169,74 @@ function setupQueryEvaluators(luvio, store) {
|
|
|
3026
4169
|
}
|
|
3027
4170
|
let __lexPrefetcher;
|
|
3028
4171
|
const HARDCODED_REQUEST_LIMIT = 9;
|
|
4172
|
+
function getInflightRequestLimit() {
|
|
4173
|
+
try {
|
|
4174
|
+
return window['$A'].clientService.maxAllowedParallelXHRCounts() - 3;
|
|
4175
|
+
}
|
|
4176
|
+
catch (e) {
|
|
4177
|
+
return HARDCODED_REQUEST_LIMIT;
|
|
4178
|
+
}
|
|
4179
|
+
}
|
|
3029
4180
|
function setupPredictivePrefetcher(luvio) {
|
|
3030
4181
|
const storage = buildAuraPrefetchStorage();
|
|
3031
4182
|
const repository = new PrefetchRepository(storage);
|
|
3032
4183
|
const requestRunner = new LexRequestRunner(luvio);
|
|
3033
4184
|
const inflightRequestLimit = applyPredictionRequestLimit.isOpen({ fallback: false })
|
|
3034
|
-
?
|
|
4185
|
+
? getInflightRequestLimit()
|
|
3035
4186
|
: 1000;
|
|
3036
|
-
const
|
|
4187
|
+
const useExactMatchesPlus = useExactMatchesPlusGate.isOpen({ fallback: false });
|
|
3037
4188
|
const prefetcherOptions = {
|
|
3038
4189
|
inflightRequestLimit,
|
|
3039
|
-
|
|
4190
|
+
useExactMatchesPlus,
|
|
3040
4191
|
};
|
|
3041
4192
|
const prefetcher = new LexPredictivePrefetcher({ context: 'unknown' }, repository, requestRunner, {
|
|
3042
|
-
getRecord: new GetRecordRequestStrategy(
|
|
3043
|
-
getRecords: new GetRecordsRequestStrategy(
|
|
3044
|
-
getRecordActions: new GetRecordActionsRequestStrategy(
|
|
3045
|
-
getRecordAvatars: new GetRecordAvatarsRequestStrategy(
|
|
3046
|
-
getObjectInfo: new GetObjectInfoRequestStrategy(
|
|
3047
|
-
getObjectInfos: new GetObjectInfosRequestStrategy(
|
|
3048
|
-
getRelatedListsActions: new GetRelatedListsActionsRequestStrategy(
|
|
3049
|
-
getRelatedListRecords: new GetRelatedListRecordsRequestStrategy(
|
|
3050
|
-
getRelatedListRecordsBatch: new GetRelatedListRecordsBatchRequestStrategy(
|
|
3051
|
-
getRelatedListInfoBatch: new GetRelatedListInfoBatchRequestStrategy(
|
|
3052
|
-
getListInfoByName: new GetListInfoByNameRequestStrategy(
|
|
3053
|
-
getListRecordsByName: new GetListRecordsByNameRequestStrategy(
|
|
3054
|
-
|
|
3055
|
-
getComponentsDef: new GetComponentsDefStrategy(
|
|
3056
|
-
getListInfosByObjectName: new GetListInfosByObjectNameRequestStrategy(
|
|
4193
|
+
getRecord: new GetRecordRequestStrategy(luvio),
|
|
4194
|
+
getRecords: new GetRecordsRequestStrategy(luvio),
|
|
4195
|
+
getRecordActions: new GetRecordActionsRequestStrategy(luvio),
|
|
4196
|
+
getRecordAvatars: new GetRecordAvatarsRequestStrategy(luvio),
|
|
4197
|
+
getObjectInfo: new GetObjectInfoRequestStrategy(luvio),
|
|
4198
|
+
getObjectInfos: new GetObjectInfosRequestStrategy(luvio),
|
|
4199
|
+
getRelatedListsActions: new GetRelatedListsActionsRequestStrategy(luvio),
|
|
4200
|
+
getRelatedListRecords: new GetRelatedListRecordsRequestStrategy(luvio),
|
|
4201
|
+
getRelatedListRecordsBatch: new GetRelatedListRecordsBatchRequestStrategy(luvio),
|
|
4202
|
+
getRelatedListInfoBatch: new GetRelatedListInfoBatchRequestStrategy(luvio),
|
|
4203
|
+
getListInfoByName: new GetListInfoByNameRequestStrategy(luvio),
|
|
4204
|
+
getListRecordsByName: new GetListRecordsByNameRequestStrategy(luvio),
|
|
4205
|
+
getApex: new GetApexRequestStrategy(luvio),
|
|
4206
|
+
getComponentsDef: new GetComponentsDefStrategy(),
|
|
4207
|
+
getListInfosByObjectName: new GetListInfosByObjectNameRequestStrategy(luvio),
|
|
4208
|
+
getListObjectInfo: new GetListObjectInfoRequestStrategy(luvio),
|
|
3057
4209
|
}, prefetcherOptions);
|
|
3058
4210
|
registerPrefetcher(luvio, prefetcher);
|
|
3059
4211
|
if (useApexPredictions.isOpen({ fallback: false })) {
|
|
3060
4212
|
registerPrefetcher$1(luvio, prefetcher);
|
|
3061
4213
|
}
|
|
3062
4214
|
__lexPrefetcher = prefetcher;
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
});
|
|
3083
|
-
}
|
|
3084
|
-
return ret;
|
|
4215
|
+
}
|
|
4216
|
+
function loadComponentsDefStartedOverride(...args) {
|
|
4217
|
+
/**
|
|
4218
|
+
* To install an override (taken from the Aura.Utils.Override):
|
|
4219
|
+
*
|
|
4220
|
+
* The function supplied should have the following code in it:
|
|
4221
|
+
* ------
|
|
4222
|
+
* var config = Array.prototype.shift.apply(arguments);
|
|
4223
|
+
* var ret = config["fn"].apply(config["scope"], arguments);
|
|
4224
|
+
* return ret
|
|
4225
|
+
* ------
|
|
4226
|
+
*/
|
|
4227
|
+
const config = Array.prototype.shift.apply(args);
|
|
4228
|
+
const ret = config['fn'].apply(config['scope'], args);
|
|
4229
|
+
try {
|
|
4230
|
+
const defs = keys(args[0] || {});
|
|
4231
|
+
__lexPrefetcher.saveRequest({
|
|
4232
|
+
adapterName: 'getComponentsDef',
|
|
4233
|
+
config: defs,
|
|
3085
4234
|
});
|
|
3086
4235
|
}
|
|
4236
|
+
catch (e) {
|
|
4237
|
+
// dismiss any error, the activity will log it.
|
|
4238
|
+
}
|
|
4239
|
+
return ret;
|
|
3087
4240
|
}
|
|
3088
4241
|
/**
|
|
3089
4242
|
* @typedef {Object} RecordHomePageContext
|
|
@@ -3124,8 +4277,14 @@ function buildPredictorForContext(context) {
|
|
|
3124
4277
|
watchPageLoadForPredictions() {
|
|
3125
4278
|
// This chunk tells the prefetcher to receive events, send off any predictions we have from previous loads, then setup idle detection to stop predicting.
|
|
3126
4279
|
__lexPrefetcher.startRecording();
|
|
4280
|
+
if (useCmpDefPredictions.isOpen({ fallback: false })) {
|
|
4281
|
+
window['$A'].installOverride('ComponentService.loadComponentDefsStarted', loadComponentsDefStartedOverride);
|
|
4282
|
+
}
|
|
3127
4283
|
onIdleDetected(() => {
|
|
3128
4284
|
__lexPrefetcher.stopRecording();
|
|
4285
|
+
if (useCmpDefPredictions.isOpen({ fallback: false })) {
|
|
4286
|
+
window['$A'].uninstallOverride('ComponentService.loadComponentDefsStarted', loadComponentsDefStartedOverride);
|
|
4287
|
+
}
|
|
3129
4288
|
});
|
|
3130
4289
|
},
|
|
3131
4290
|
runPredictions() {
|
|
@@ -3184,7 +4343,15 @@ function initializeOneStore() {
|
|
|
3184
4343
|
defaultCachePolicyName: 'cache-then-network',
|
|
3185
4344
|
},
|
|
3186
4345
|
};
|
|
4346
|
+
const jwtAuthorizedSfapFetchService = buildJwtAuthorizedSfapFetchService();
|
|
4347
|
+
// TODO [W-1234567]: Export descriptor builder for o11y and noop instrumentaiton
|
|
4348
|
+
const instrumentationServiceDescriptor = {
|
|
4349
|
+
type: 'instrumentation',
|
|
4350
|
+
version: '1.0',
|
|
4351
|
+
service: buildNoopInstrumentationService(),
|
|
4352
|
+
};
|
|
3187
4353
|
const services = [
|
|
4354
|
+
jwtAuthorizedSfapFetchService,
|
|
3188
4355
|
keySubscriptionServiceDescriptor,
|
|
3189
4356
|
metadataRepositoryServiceDescriptor,
|
|
3190
4357
|
storeServiceDescriptor,
|
|
@@ -3193,6 +4360,15 @@ function initializeOneStore() {
|
|
|
3193
4360
|
buildDefaultTypeRegistryService(),
|
|
3194
4361
|
buildAuraNetworkService(),
|
|
3195
4362
|
buildInMemoryCacheInclusionPolicyService(),
|
|
4363
|
+
buildAuraNetworkCommandBaseClassService(),
|
|
4364
|
+
buildFetchNetworkCommandBaseClassService(),
|
|
4365
|
+
buildNetworkCommandBaseClassService(),
|
|
4366
|
+
buildStreamingCommandBaseClassService(),
|
|
4367
|
+
buildSSECommandBaseClassService(),
|
|
4368
|
+
instrumentationServiceDescriptor,
|
|
4369
|
+
buildInstrumentCommandServiceDescriptor({
|
|
4370
|
+
instrumentation: instrumentationServiceDescriptor.service,
|
|
4371
|
+
}),
|
|
3196
4372
|
];
|
|
3197
4373
|
serviceBroker.publish(services);
|
|
3198
4374
|
}
|
|
@@ -3221,4 +4397,4 @@ function ldsEngineCreator() {
|
|
|
3221
4397
|
}
|
|
3222
4398
|
|
|
3223
4399
|
export { buildPredictorForContext, ldsEngineCreator as default, initializeLDS, initializeOneStore };
|
|
3224
|
-
// version: 1.
|
|
4400
|
+
// version: 1.304.0-aa3e5f9550
|