@salesforce/lds-runtime-aura 1.245.0 → 1.247.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.
Files changed (31) hide show
  1. package/dist/ldsEngineCreator.js +734 -7
  2. package/dist/types/aura-instrumentation/main.d.ts +2 -1
  3. package/dist/types/aura-instrumentation/utils/observability.d.ts +2 -2
  4. package/dist/types/main.d.ts +16 -0
  5. package/dist/types/predictive-loading/index.d.ts +6 -0
  6. package/dist/types/predictive-loading/pages/index.d.ts +3 -0
  7. package/dist/types/predictive-loading/pages/lex-default-page.d.ts +12 -0
  8. package/dist/types/predictive-loading/pages/predictive-prefetch-page.d.ts +11 -0
  9. package/dist/types/predictive-loading/pages/record-home-page.d.ts +46 -0
  10. package/dist/types/predictive-loading/prefetcher/index.d.ts +2 -0
  11. package/dist/types/predictive-loading/prefetcher/lex-predictive-prefetcher.d.ts +18 -0
  12. package/dist/types/predictive-loading/prefetcher/predictive-prefetcher.d.ts +20 -0
  13. package/dist/types/predictive-loading/repository/index.d.ts +2 -0
  14. package/dist/types/predictive-loading/repository/prefetch-repository.d.ts +27 -0
  15. package/dist/types/predictive-loading/repository/utils.d.ts +15 -0
  16. package/dist/types/predictive-loading/request-runner/index.d.ts +2 -0
  17. package/dist/types/predictive-loading/request-runner/lex-request-runner.d.ts +10 -0
  18. package/dist/types/predictive-loading/request-runner/request-runner.d.ts +4 -0
  19. package/dist/types/predictive-loading/request-strategy/get-record-actions-request-strategy.d.ts +22 -0
  20. package/dist/types/predictive-loading/request-strategy/get-record-avatars-request-strategy.d.ts +22 -0
  21. package/dist/types/predictive-loading/request-strategy/get-record-request-strategy.d.ts +18 -0
  22. package/dist/types/predictive-loading/request-strategy/get-records-request-strategy.d.ts +15 -0
  23. package/dist/types/predictive-loading/request-strategy/index.d.ts +7 -0
  24. package/dist/types/predictive-loading/request-strategy/luvio-adapter-request-strategy.d.ts +10 -0
  25. package/dist/types/predictive-loading/request-strategy/luvio-adapter-request.d.ts +4 -0
  26. package/dist/types/predictive-loading/request-strategy/request-strategy.d.ts +5 -0
  27. package/dist/types/predictive-loading/storage/aura-prefetch-storage.d.ts +18 -0
  28. package/dist/types/predictive-loading/storage/in-memory-prefetch-storage.d.ts +6 -0
  29. package/dist/types/predictive-loading/storage/index.d.ts +7 -0
  30. package/dist/types/predictive-loading/storage/local-prefetch-storage.d.ts +7 -0
  31. package/package.json +9 -6
@@ -14,15 +14,703 @@
14
14
  /* proxy-compat-disable */
15
15
  import { HttpStatusCode, InMemoryStore, Environment, Luvio, InMemoryStoreQueryEvaluator } from 'force/luvioEngine';
16
16
  import ldsTrackedFieldsBehaviorGate from '@salesforce/gate/lds.useNewTrackedFieldBehavior';
17
- import { instrument, configuration, InMemoryRecordRepresentationQueryEvaluator, UiApiNamespace, RecordRepresentationRepresentationType } from 'force/ldsAdaptersUiapi';
17
+ import usePredictiveLoading from '@salesforce/gate/lds.usePredictiveLoading';
18
+ import { getRecordAvatarsAdapterFactory, getRecordAdapterFactory, getRecordsAdapterFactory, getRecordActionsAdapterFactory, instrument, configuration, InMemoryRecordRepresentationQueryEvaluator, UiApiNamespace, RecordRepresentationRepresentationType, registerPrefetcher } from 'force/ldsAdaptersUiapi';
19
+ import { createStorage, clearStorages } from 'force/ldsStorage';
18
20
  import { withRegistration, register, setDefaultLuvio } from 'force/ldsEngine';
19
21
  import { REFRESH_ADAPTER_EVENT, ADAPTER_UNFULFILLED_ERROR, instrument as instrument$2 } from 'force/ldsBindings';
20
22
  import { counter, registerCacheStats, perfStart, perfEnd, registerPeriodicLogger, interaction, timer } from 'instrumentation/service';
21
- import { LRUCache, instrumentAdapter, instrumentLuvio, setupInstrumentation as setupInstrumentation$1, logObjectInfoChanged as logObjectInfoChanged$1, updatePercentileHistogramMetric, incrementCounterMetric, incrementGetRecordNotifyChangeAllowCount, incrementGetRecordNotifyChangeDropCount, incrementNotifyRecordUpdateAvailableAllowCount, incrementNotifyRecordUpdateAvailableDropCount, setLdsAdaptersUiapiInstrumentation, setLdsNetworkAdapterInstrumentation } from 'force/ldsInstrumentation';
23
+ import { LRUCache, instrumentAdapter, instrumentLuvio, setupInstrumentation as setupInstrumentation$1, logObjectInfoChanged as logObjectInfoChanged$1, updatePercentileHistogramMetric, incrementCounterMetric, incrementGetRecordNotifyChangeAllowCount, incrementGetRecordNotifyChangeDropCount, incrementNotifyRecordUpdateAvailableAllowCount, incrementNotifyRecordUpdateAvailableDropCount, setLdsAdaptersUiapiInstrumentation, setLdsNetworkAdapterInstrumentation, onIdleDetected } from 'force/ldsInstrumentation';
22
24
  import auraNetworkAdapter, { instrument as instrument$1, forceRecordTransactionsDisabled, ldsNetworkAdapterInstrument, dispatchAuraAction, defaultActionConfig } from 'force/ldsNetwork';
23
25
  import { instrument as instrument$3 } from 'force/adsBridge';
24
26
  import { buildJwtNetworkAdapter } from 'force/ldsNetworkFetchWithJwt';
25
- import { clearStorages } from 'force/ldsStorage';
27
+
28
+ class PredictivePrefetchPage {
29
+ constructor(context) {
30
+ this.context = context;
31
+ this.similarContext = undefined;
32
+ }
33
+ }
34
+
35
+ class LexDefaultPage extends PredictivePrefetchPage {
36
+ constructor(context) {
37
+ super(context);
38
+ }
39
+ buildSaveRequestData(request) {
40
+ return { context: this.context, request };
41
+ }
42
+ resolveSimilarRequest(similarRequest) {
43
+ return similarRequest;
44
+ }
45
+ getAlwaysRunRequests() {
46
+ return [];
47
+ }
48
+ }
49
+
50
+ class RecordHomePage extends PredictivePrefetchPage {
51
+ constructor(context, requestStrategies) {
52
+ super(context);
53
+ this.requestStrategies = requestStrategies;
54
+ const { recordId: _, ...rest } = this.context;
55
+ this.similarContext = {
56
+ recordId: '*',
57
+ ...rest,
58
+ };
59
+ }
60
+ buildSaveRequestData(request) {
61
+ const { adapterName } = request;
62
+ switch (adapterName) {
63
+ case 'getRecord':
64
+ return this.buildGetRecordSaveRequestData(request);
65
+ case 'getRecords':
66
+ return this.buildGetRecordsSaveRequestData(request);
67
+ case 'getRecordActions':
68
+ return this.requestStrategies.getRecordActions.buildGetRecordActionsSaveRequestData(this.similarContext, this.context, request);
69
+ case 'getRecordAvatars':
70
+ return this.requestStrategies.getRecordAvatars.buildGetRecordAvatarsSaveRequestData(this.similarContext, this.context, request);
71
+ default:
72
+ return { request, context: this.context };
73
+ }
74
+ }
75
+ buildGetRecordSaveRequestData(request) {
76
+ if (this.isGetRecordRequestContextDependent(request)) {
77
+ return {
78
+ request: this.requestStrategies.getRecord.transformForSave({
79
+ ...request,
80
+ config: {
81
+ ...request.config,
82
+ recordId: '*',
83
+ },
84
+ }),
85
+ context: this.similarContext,
86
+ };
87
+ }
88
+ return {
89
+ request: this.requestStrategies.getRecord.transformForSave(request),
90
+ context: this.context,
91
+ };
92
+ }
93
+ buildGetRecordsSaveRequestData(request) {
94
+ if (this.isGetRecordsRequestContextDependent(request)) {
95
+ return {
96
+ request: this.requestStrategies.getRecords.transformForSave({
97
+ ...request,
98
+ config: {
99
+ ...request.config,
100
+ records: [
101
+ {
102
+ ...request.config.records[0],
103
+ recordIds: ['*'],
104
+ },
105
+ ],
106
+ },
107
+ }),
108
+ context: this.context,
109
+ };
110
+ }
111
+ return {
112
+ request: this.requestStrategies.getRecords.transformForSave(request),
113
+ context: this.context,
114
+ };
115
+ }
116
+ isGetRecordRequestContextDependent(request) {
117
+ return request.config.recordId === this.context.recordId;
118
+ }
119
+ isGetRecordsRequestContextDependent(request) {
120
+ const isSingleRecordRequest = request.config.records.length === 1 && request.config.records[0].recordIds.length === 1;
121
+ return (isSingleRecordRequest &&
122
+ request.config.records[0].recordIds[0] === this.context.recordId);
123
+ }
124
+ resolveSimilarRequest(similarRequest) {
125
+ if (similarRequest.adapterName === 'getRecord') {
126
+ return this.requestStrategies.getRecord.buildConcreteRequest(similarRequest, this.context);
127
+ }
128
+ if (similarRequest.adapterName === 'getRecords') {
129
+ return this.requestStrategies.getRecords.buildConcreteRequest(similarRequest, this.context);
130
+ }
131
+ if (similarRequest.adapterName === 'getRecordActions') {
132
+ return this.requestStrategies.getRecordActions.buildConcreteRequest(similarRequest, this.context);
133
+ }
134
+ if (similarRequest.adapterName === 'getRecordAvatars') {
135
+ return this.requestStrategies.getRecordAvatars.buildConcreteRequest(similarRequest, this.context);
136
+ }
137
+ return similarRequest;
138
+ }
139
+ // Record Home performs best when we always do a minimal getRecord alongside the other requests.
140
+ getAlwaysRunRequests() {
141
+ const { recordId, objectApiName } = this.context;
142
+ return [
143
+ {
144
+ adapterName: 'getRecord',
145
+ config: {
146
+ recordId,
147
+ optionalFields: [`${objectApiName}.Id`, `${objectApiName}.RecordTypeId`],
148
+ },
149
+ },
150
+ ];
151
+ }
152
+ static handlesContext(context) {
153
+ const maybeRecordHomePageContext = context;
154
+ return (maybeRecordHomePageContext !== undefined &&
155
+ maybeRecordHomePageContext.actionName !== undefined &&
156
+ maybeRecordHomePageContext.objectApiName !== undefined &&
157
+ maybeRecordHomePageContext.recordId !== undefined &&
158
+ maybeRecordHomePageContext.type === 'recordPage');
159
+ }
160
+ }
161
+
162
+ class ApplicationPredictivePrefetcher {
163
+ constructor(context, repository, requestRunner) {
164
+ this.repository = repository;
165
+ this.requestRunner = requestRunner;
166
+ this.isRecording = false;
167
+ this.queuedPredictionRequests = [];
168
+ this._context = context;
169
+ this.page = this.getPage();
170
+ }
171
+ set context(value) {
172
+ this._context = value;
173
+ this.page = this.getPage();
174
+ }
175
+ get context() {
176
+ return this._context;
177
+ }
178
+ async stopRecording() {
179
+ this.isRecording = false;
180
+ await this.repository.flushRequestsToStorage();
181
+ }
182
+ startRecording() {
183
+ this.isRecording = true;
184
+ this.repository.clearRequestBuffer();
185
+ }
186
+ saveRequest(request) {
187
+ if (!this.isRecording) {
188
+ return Promise.resolve();
189
+ }
190
+ const { request: requestToSave, context } = this.page.buildSaveRequestData(request);
191
+ // No need to diferentiate from predictions requests because these
192
+ // are made from the adapters factory, which are not prediction aware.
193
+ return this.repository.saveRequest(context, requestToSave);
194
+ }
195
+ async predict() {
196
+ const exactPageRequests = (await this.repository.getPageRequests(this.context)) || [];
197
+ const similarPageRequests = await this.getSimilarPageRequests();
198
+ const predictedRequests = [
199
+ ...this.requestRunner.reduceRequests([...exactPageRequests, ...similarPageRequests]),
200
+ ...this.page.getAlwaysRunRequests(),
201
+ ];
202
+ this.queuedPredictionRequests.push(...predictedRequests);
203
+ return Promise.all(predictedRequests.map((request) => this.requestRunner.runRequest(request))).then();
204
+ }
205
+ async getSimilarPageRequests() {
206
+ let resolvedSimilarPageRequests = [];
207
+ if (this.page.similarContext !== undefined) {
208
+ const similarPageRequests = await this.repository.getPageRequests(this.page.similarContext);
209
+ if (similarPageRequests !== undefined) {
210
+ resolvedSimilarPageRequests = similarPageRequests.map((request) => this.page.resolveSimilarRequest(request));
211
+ }
212
+ }
213
+ return resolvedSimilarPageRequests;
214
+ }
215
+ }
216
+
217
+ class LexPredictivePrefetcher extends ApplicationPredictivePrefetcher {
218
+ constructor(context, repository, requestRunner,
219
+ // These strategies need to be in sync with the "predictiveDataLoadCapable" list
220
+ // from scripts/lds-uiapi-plugin.js
221
+ requestStrategies) {
222
+ super(context, repository, requestRunner);
223
+ this.requestStrategies = requestStrategies;
224
+ this.page = this.getPage();
225
+ }
226
+ getPage() {
227
+ if (RecordHomePage.handlesContext(this.context)) {
228
+ return new RecordHomePage(this.context, this.requestStrategies);
229
+ }
230
+ return new LexDefaultPage(this.context);
231
+ }
232
+ }
233
+
234
+ // Copy-pasted from adapter-utils. This util should be extracted from generated code and imported in prefetch repository.
235
+ const { keys: ObjectKeys } = Object;
236
+ const { stringify: JSONStringify } = JSON;
237
+ const { isArray: ArrayIsArray } = Array;
238
+ /**
239
+ * A deterministic JSON stringify implementation. Heavily adapted from https://github.com/epoberezkin/fast-json-stable-stringify.
240
+ * This is needed because insertion order for JSON.stringify(object) affects output:
241
+ * JSON.stringify({a: 1, b: 2})
242
+ * "{"a":1,"b":2}"
243
+ * JSON.stringify({b: 2, a: 1})
244
+ * "{"b":2,"a":1}"
245
+ * @param data Data to be JSON-stringified.
246
+ * @returns JSON.stringified value with consistent ordering of keys.
247
+ */
248
+ function stableJSONStringify$1(node) {
249
+ // This is for Date values.
250
+ if (node && node.toJSON && typeof node.toJSON === 'function') {
251
+ // eslint-disable-next-line no-param-reassign
252
+ node = node.toJSON();
253
+ }
254
+ if (node === undefined) {
255
+ return;
256
+ }
257
+ if (typeof node === 'number') {
258
+ return isFinite(node) ? '' + node : 'null';
259
+ }
260
+ if (typeof node !== 'object') {
261
+ return JSONStringify(node);
262
+ }
263
+ let i;
264
+ let out;
265
+ if (ArrayIsArray(node)) {
266
+ out = '[';
267
+ for (i = 0; i < node.length; i++) {
268
+ if (i) {
269
+ out += ',';
270
+ }
271
+ out += stableJSONStringify$1(node[i]) || 'null';
272
+ }
273
+ return out + ']';
274
+ }
275
+ if (node === null) {
276
+ return 'null';
277
+ }
278
+ const keys = ObjectKeys(node).sort();
279
+ out = '';
280
+ for (i = 0; i < keys.length; i++) {
281
+ const key = keys[i];
282
+ const value = stableJSONStringify$1(node[key]);
283
+ if (!value) {
284
+ continue;
285
+ }
286
+ if (out) {
287
+ out += ',';
288
+ }
289
+ out += JSONStringify(key) + ':' + value;
290
+ }
291
+ return '{' + out + '}';
292
+ }
293
+ function isObject(obj) {
294
+ return obj !== null && typeof obj === 'object';
295
+ }
296
+ function deepEquals(objA, objB) {
297
+ if (objA === objB)
298
+ return true;
299
+ if (objA instanceof Date && objB instanceof Date)
300
+ return objA.getTime() === objB.getTime();
301
+ // If one of them is not an object, they are not deeply equal
302
+ if (!isObject(objA) || !isObject(objB))
303
+ return false;
304
+ // Filter out keys set as undefined, we can compare undefined as equals.
305
+ const keysA = ObjectKeys(objA).filter((key) => objA[key] !== undefined);
306
+ const keysB = ObjectKeys(objB).filter((key) => objB[key] !== undefined);
307
+ // If the objects do not have the same set of keys, they are not deeply equal
308
+ if (keysA.length !== keysB.length)
309
+ return false;
310
+ for (const key of keysA) {
311
+ const valA = objA[key];
312
+ const valB = objB[key];
313
+ const areObjects = isObject(valA) && isObject(valB);
314
+ // If both values are objects, recursively compare them
315
+ if (areObjects && !deepEquals(valA, valB))
316
+ return false;
317
+ // If only one value is an object or if the values are not strictly equal, they are not deeply equal
318
+ if (!areObjects && valA !== valB)
319
+ return false;
320
+ }
321
+ return true;
322
+ }
323
+
324
+ class PrefetchRepository {
325
+ constructor(storage) {
326
+ this.storage = storage;
327
+ this.requestBuffer = new Map();
328
+ }
329
+ clearRequestBuffer() {
330
+ this.requestBuffer.clear();
331
+ }
332
+ async flushRequestsToStorage() {
333
+ for (const [id, batch] of this.requestBuffer) {
334
+ const rawPage = await this.storage.get(id);
335
+ const page = rawPage === undefined ? { id, requests: [] } : rawPage;
336
+ batch.forEach(({ request, requestTime }) => {
337
+ let existingRequestEntry = page.requests.find(({ request: storedRequest }) => deepEquals(storedRequest, request));
338
+ if (existingRequestEntry === undefined) {
339
+ existingRequestEntry = { request, requestMetadata: { requestTimes: [] } };
340
+ page.requests.push(existingRequestEntry);
341
+ }
342
+ existingRequestEntry.requestMetadata.requestTimes.push(requestTime);
343
+ });
344
+ await this.storage.set(id, page);
345
+ }
346
+ this.clearRequestBuffer();
347
+ }
348
+ async saveRequest(key, request) {
349
+ const identifier = stableJSONStringify$1(key);
350
+ const batchForKey = this.requestBuffer.get(identifier) || [];
351
+ batchForKey.push({
352
+ request,
353
+ requestTime: Date.now(),
354
+ });
355
+ this.requestBuffer.set(identifier, batchForKey);
356
+ }
357
+ async getPage(key) {
358
+ const identifier = stableJSONStringify$1(key);
359
+ const rawPage = await this.storage.get(identifier);
360
+ return rawPage;
361
+ }
362
+ async getPageRequests(key) {
363
+ const page = await this.getPage(key);
364
+ if (page === undefined) {
365
+ return [];
366
+ }
367
+ return page.requests.map((requestEntry) => requestEntry.request);
368
+ }
369
+ }
370
+
371
+ class RequestStrategy {
372
+ transformForSave(request) {
373
+ return request;
374
+ }
375
+ reduce(requests) {
376
+ return requests;
377
+ }
378
+ }
379
+
380
+ class LuvioAdapterRequestStrategy extends RequestStrategy {
381
+ transformForSave(request) {
382
+ return request;
383
+ }
384
+ filterRequests(unfilteredRequests) {
385
+ return unfilteredRequests.filter((request) => request.adapterName === this.adapterName);
386
+ }
387
+ reduce(unfilteredRequests) {
388
+ return this.filterRequests(unfilteredRequests);
389
+ }
390
+ }
391
+
392
+ function normalizeRecordIds$1(recordIds) {
393
+ if (!Array.isArray(recordIds)) {
394
+ return [recordIds];
395
+ }
396
+ return recordIds;
397
+ }
398
+ function canCombine$1(reqA, reqB) {
399
+ return reqA.formFactor === reqB.formFactor;
400
+ }
401
+ function combineRequests$1(reqA, reqB) {
402
+ const combined = { ...reqA };
403
+ combined.recordIds = Array.from(new Set([...normalizeRecordIds$1(reqA.recordIds), ...normalizeRecordIds$1(reqB.recordIds)]));
404
+ return combined;
405
+ }
406
+ class GetRecordAvatarsRequestStrategy extends LuvioAdapterRequestStrategy {
407
+ constructor() {
408
+ super(...arguments);
409
+ this.adapterName = 'getRecordAvatars';
410
+ this.adapterFactory = getRecordAvatarsAdapterFactory;
411
+ }
412
+ buildConcreteRequest(similarRequest, context) {
413
+ return {
414
+ ...similarRequest,
415
+ config: {
416
+ ...similarRequest.config,
417
+ recordIds: [context.recordId],
418
+ },
419
+ };
420
+ }
421
+ buildGetRecordAvatarsSaveRequestData(similarContext, context, request) {
422
+ if (this.isGetRecordAvatarsRequestContextDependent(context, request)) {
423
+ return {
424
+ request: this.transformForSave({
425
+ ...request,
426
+ config: {
427
+ ...request.config,
428
+ recordIds: ['*'],
429
+ },
430
+ }),
431
+ context: similarContext,
432
+ };
433
+ }
434
+ return {
435
+ request: this.transformForSave(request),
436
+ context,
437
+ };
438
+ }
439
+ isGetRecordAvatarsRequestContextDependent(context, request) {
440
+ return (request.config.recordIds &&
441
+ (context.recordId === request.config.recordIds || // some may set this as string instead of array
442
+ (request.config.recordIds.length === 1 &&
443
+ request.config.recordIds[0] === context.recordId)));
444
+ }
445
+ reduce(unfilteredRequests) {
446
+ const requests = this.filterRequests(unfilteredRequests);
447
+ const visitedRequests = new Set();
448
+ const reducedRequests = [];
449
+ for (let i = 0, n = requests.length; i < n; i++) {
450
+ const currentRequest = requests[i];
451
+ if (!visitedRequests.has(currentRequest)) {
452
+ const combinedRequest = { ...currentRequest };
453
+ for (let j = i + 1; j < n; j++) {
454
+ const hasNotBeenVisited = !visitedRequests.has(requests[j]);
455
+ const canCombineConfigs = canCombine$1(combinedRequest.config, requests[j].config);
456
+ if (hasNotBeenVisited && canCombineConfigs) {
457
+ combinedRequest.config = combineRequests$1(combinedRequest.config, requests[j].config);
458
+ visitedRequests.add(requests[j]);
459
+ }
460
+ }
461
+ reducedRequests.push(combinedRequest);
462
+ visitedRequests.add(currentRequest);
463
+ }
464
+ }
465
+ return reducedRequests;
466
+ }
467
+ }
468
+
469
+ class GetRecordRequestStrategy extends LuvioAdapterRequestStrategy {
470
+ constructor() {
471
+ super(...arguments);
472
+ this.adapterName = 'getRecord';
473
+ this.adapterFactory = getRecordAdapterFactory;
474
+ }
475
+ buildConcreteRequest(similarRequest, context) {
476
+ return {
477
+ ...similarRequest,
478
+ config: {
479
+ ...similarRequest.config,
480
+ recordId: context.recordId,
481
+ },
482
+ };
483
+ }
484
+ transformForSave(request) {
485
+ if (request.config.fields === undefined && request.config.optionalFields === undefined) {
486
+ return request;
487
+ }
488
+ let optionalFields = request.config.optionalFields || [];
489
+ if (!ArrayIsArray(optionalFields)) {
490
+ optionalFields = [optionalFields];
491
+ }
492
+ return {
493
+ ...request,
494
+ config: {
495
+ ...request.config,
496
+ fields: undefined,
497
+ optionalFields: [...(request.config.fields || []), ...optionalFields],
498
+ },
499
+ };
500
+ }
501
+ reduce(unfilteredRequests) {
502
+ const requests = this.filterRequests(unfilteredRequests);
503
+ const recordIdToRequestMap = {};
504
+ const resultRequests = [];
505
+ requests.forEach((request) => {
506
+ if (request.config.fields === undefined &&
507
+ request.config.optionalFields === undefined) {
508
+ resultRequests.push(request);
509
+ return;
510
+ }
511
+ if (recordIdToRequestMap[request.config.recordId] === undefined) {
512
+ recordIdToRequestMap[request.config.recordId] = [];
513
+ }
514
+ recordIdToRequestMap[request.config.recordId].push(request);
515
+ });
516
+ Object.entries(recordIdToRequestMap).forEach(([recordId, requests]) => {
517
+ const fields = new Set();
518
+ const optionalFields = new Set();
519
+ requests.forEach((request) => {
520
+ if (request.config.fields !== undefined) {
521
+ request.config.fields.forEach((field) => {
522
+ fields.add(field);
523
+ });
524
+ }
525
+ if (request.config.optionalFields !== undefined) {
526
+ request.config.optionalFields.forEach((field) => {
527
+ optionalFields.add(field);
528
+ });
529
+ }
530
+ });
531
+ resultRequests.push({
532
+ adapterName: 'getRecord',
533
+ config: {
534
+ recordId,
535
+ fields: Array.from(fields),
536
+ optionalFields: Array.from(optionalFields),
537
+ },
538
+ });
539
+ });
540
+ return resultRequests;
541
+ }
542
+ }
543
+
544
+ class GetRecordsRequestStrategy extends LuvioAdapterRequestStrategy {
545
+ constructor() {
546
+ super(...arguments);
547
+ this.adapterName = 'getRecords';
548
+ this.adapterFactory = getRecordsAdapterFactory;
549
+ }
550
+ buildConcreteRequest(similarRequest, context) {
551
+ return {
552
+ ...similarRequest,
553
+ config: {
554
+ ...similarRequest.config,
555
+ records: [{ ...similarRequest.config.records[0], recordIds: [context.recordId] }],
556
+ },
557
+ };
558
+ }
559
+ }
560
+
561
+ function normalizeRecordIds(recordIds) {
562
+ if (!Array.isArray(recordIds)) {
563
+ return [recordIds];
564
+ }
565
+ return recordIds;
566
+ }
567
+ function canCombine(reqA, reqB) {
568
+ return (reqA.retrievalMode === reqB.retrievalMode &&
569
+ reqA.formFactor === reqB.formFactor &&
570
+ (reqA.actionTypes || []).toString() === (reqB.actionTypes || []).toString() &&
571
+ (reqA.sections || []).toString() === (reqB.sections || []).toString());
572
+ }
573
+ function combineRequests(reqA, reqB) {
574
+ const combined = { ...reqA };
575
+ // let's merge the recordIds
576
+ combined.recordIds = Array.from(new Set([...normalizeRecordIds(reqA.recordIds), ...normalizeRecordIds(reqB.recordIds)]));
577
+ if (combined.retrievalMode === 'ALL') {
578
+ const combinedSet = new Set([...(combined.apiNames || []), ...(reqB.apiNames || [])]);
579
+ combined.apiNames = Array.from(combinedSet);
580
+ }
581
+ return combined;
582
+ }
583
+ class GetRecordActionsRequestStrategy extends LuvioAdapterRequestStrategy {
584
+ constructor() {
585
+ super(...arguments);
586
+ this.adapterName = 'getRecordActions';
587
+ this.adapterFactory = getRecordActionsAdapterFactory;
588
+ }
589
+ buildConcreteRequest(similarRequest, context) {
590
+ return {
591
+ ...similarRequest,
592
+ config: {
593
+ ...similarRequest.config,
594
+ recordIds: [context.recordId],
595
+ },
596
+ };
597
+ }
598
+ buildGetRecordActionsSaveRequestData(similarContext, context, request) {
599
+ if (this.isGetRecordActionsRequestContextDependent(context, request)) {
600
+ return {
601
+ request: this.transformForSave({
602
+ ...request,
603
+ config: {
604
+ ...request.config,
605
+ recordIds: ['*'],
606
+ },
607
+ }),
608
+ context: similarContext,
609
+ };
610
+ }
611
+ return {
612
+ request: this.transformForSave(request),
613
+ context,
614
+ };
615
+ }
616
+ isGetRecordActionsRequestContextDependent(context, request) {
617
+ return (request.config.recordIds &&
618
+ (context.recordId === request.config.recordIds || // some may set this as string instead of array
619
+ (request.config.recordIds.length === 1 &&
620
+ request.config.recordIds[0] === context.recordId)));
621
+ }
622
+ reduce(unfilteredRequests) {
623
+ const requests = this.filterRequests(unfilteredRequests);
624
+ const visitedRequests = new Set();
625
+ const reducedRequests = [];
626
+ for (let i = 0, n = requests.length; i < n; i++) {
627
+ const currentRequest = requests[i];
628
+ if (!visitedRequests.has(currentRequest)) {
629
+ const combinedRequest = { ...currentRequest };
630
+ for (let j = i + 1; j < n; j++) {
631
+ if (!visitedRequests.has(requests[j]) &&
632
+ canCombine(combinedRequest.config, requests[j].config)) {
633
+ combinedRequest.config = combineRequests(combinedRequest.config, requests[j].config);
634
+ visitedRequests.add(requests[j]);
635
+ }
636
+ }
637
+ reducedRequests.push(combinedRequest);
638
+ visitedRequests.add(currentRequest);
639
+ }
640
+ }
641
+ return reducedRequests;
642
+ }
643
+ }
644
+
645
+ class LexRequestRunner {
646
+ constructor(luvio) {
647
+ this.luvio = luvio;
648
+ this.requestStrategies = {
649
+ getRecord: new GetRecordRequestStrategy(),
650
+ getRecords: new GetRecordsRequestStrategy(),
651
+ getRecordActions: new GetRecordActionsRequestStrategy(),
652
+ getRecordAvatars: new GetRecordAvatarsRequestStrategy(),
653
+ };
654
+ }
655
+ reduceRequests(requests) {
656
+ return Object.values(this.requestStrategies)
657
+ .map((strategy) => strategy.reduce(requests))
658
+ .flat();
659
+ }
660
+ runRequest(request) {
661
+ if (request.adapterName in this.requestStrategies) {
662
+ const adapterFactory = this.requestStrategies[request.adapterName].adapterFactory;
663
+ return Promise.resolve(adapterFactory(this.luvio)(request.config)).then();
664
+ }
665
+ return Promise.resolve(undefined);
666
+ }
667
+ }
668
+
669
+ class InMemoryPrefetchStorage {
670
+ constructor() {
671
+ this.data = {};
672
+ }
673
+ set(key, value) {
674
+ this.data[key] = value;
675
+ return Promise.resolve();
676
+ }
677
+ get(key) {
678
+ return Promise.resolve(this.data[key]);
679
+ }
680
+ }
681
+
682
+ const DEFAULT_STORAGE_OPTIONS = {
683
+ name: 'ldsPredictiveLoading',
684
+ persistent: true,
685
+ secure: true,
686
+ maxSize: 20 * 1024 * 1024,
687
+ // @todo: there's no way of setting a "no expire" value. We should determine the best ttl for this cache.
688
+ expiration: 24 * 60 * 60,
689
+ clearOnInit: false,
690
+ debugLogging: false,
691
+ };
692
+ function buildAuraPrefetchStorage(options = {}) {
693
+ const auraStorage = createStorage({
694
+ ...DEFAULT_STORAGE_OPTIONS,
695
+ ...options,
696
+ });
697
+ if (auraStorage === null) {
698
+ return new InMemoryPrefetchStorage();
699
+ }
700
+ return new AuraPrefetchStorage(auraStorage);
701
+ }
702
+ class AuraPrefetchStorage {
703
+ constructor(auraStorage) {
704
+ this.auraStorage = auraStorage;
705
+ }
706
+ set(key, value) {
707
+ return this.auraStorage.set(key, value);
708
+ }
709
+ async get(key) {
710
+ const result = await this.auraStorage.get(key);
711
+ return result ? result : undefined;
712
+ }
713
+ }
26
714
 
27
715
  /**
28
716
  * Observability / Critical Availability Program (230+)
@@ -32,8 +720,8 @@ import { clearStorages } from 'force/ldsStorage';
32
720
  *
33
721
  * Below are the R.E.A.D.S. metrics for the Lightning Data Service, defined here[2].
34
722
  *
35
- * [1] https://salesforce.quip.com/NfW9AsbGEaTY
36
- * [2] https://salesforce.quip.com/1dFvAba1b0eq
723
+ * [1] Search "[M1] Lightning Data Service Design Spike" in Quip
724
+ * [2] Search "Lightning Data Service R.E.A.D.S. Metrics" in Quip
37
725
  */
38
726
  const OBSERVABILITY_NAMESPACE = 'LIGHTNING.lds.service';
39
727
  const ADAPTER_INVOCATION_COUNT_METRIC_NAME = 'request';
@@ -750,6 +1438,42 @@ function setupQueryEvaluators(luvio, store) {
750
1438
  luvio.registerStoreQueryEvaluator(baseQueryEvaluator);
751
1439
  luvio.registerTypeQueryEvaluator(UiApiNamespace, RecordRepresentationRepresentationType, recordRepresentationQueryEvaluator);
752
1440
  }
1441
+ let __lexPrefetcher;
1442
+ function setupPredictivePrefetcher(luvio) {
1443
+ const storage = buildAuraPrefetchStorage();
1444
+ const repository = new PrefetchRepository(storage);
1445
+ const requestRunner = new LexRequestRunner(luvio);
1446
+ const prefetcher = new LexPredictivePrefetcher({ context: 'unknown' }, repository, requestRunner, {
1447
+ getRecord: new GetRecordRequestStrategy(),
1448
+ getRecords: new GetRecordsRequestStrategy(),
1449
+ getRecordActions: new GetRecordActionsRequestStrategy(),
1450
+ getRecordAvatars: new GetRecordAvatarsRequestStrategy(),
1451
+ });
1452
+ registerPrefetcher(luvio, prefetcher);
1453
+ __lexPrefetcher = prefetcher;
1454
+ }
1455
+ // Triggers a payload.
1456
+ async function predictiveLoadPage(preloadProps) {
1457
+ // the gate is disabled and the prefetcher was not setup.
1458
+ if (__lexPrefetcher === undefined) {
1459
+ return;
1460
+ }
1461
+ // This chunk configures which page we're going to use to try and preload.
1462
+ const { objectApiName } = preloadProps.context;
1463
+ const { recordId, actionName } = preloadProps.pageReference.attributes;
1464
+ __lexPrefetcher.context = {
1465
+ objectApiName,
1466
+ recordId,
1467
+ actionName,
1468
+ type: 'recordPage',
1469
+ };
1470
+ // This chunk tells the prefetcher to receive events, send off any predictions we have from previous loads, then setup idle detection to stop predicting.
1471
+ __lexPrefetcher.startRecording();
1472
+ __lexPrefetcher.predict();
1473
+ onIdleDetected(() => {
1474
+ __lexPrefetcher.stopRecording();
1475
+ });
1476
+ }
753
1477
  // LDS initialization logic, invoked directly by Aura component tests
754
1478
  function initializeLDS() {
755
1479
  const storeOptions = {
@@ -765,6 +1489,9 @@ function initializeLDS() {
765
1489
  setupQueryEvaluators(luvio, store);
766
1490
  setDefaultLuvio({ luvio });
767
1491
  setTrackedFieldsConfig(ldsTrackedFieldsBehaviorGate.isOpen({ fallback: false }));
1492
+ if (usePredictiveLoading.isOpen({ fallback: false })) {
1493
+ setupPredictivePrefetcher(luvio);
1494
+ }
768
1495
  }
769
1496
  // service function to be invoked by Aura
770
1497
  function ldsEngineCreator() {
@@ -772,5 +1499,5 @@ function ldsEngineCreator() {
772
1499
  return { name: 'ldsEngineCreator' };
773
1500
  }
774
1501
 
775
- export { ldsEngineCreator as default, initializeLDS };
776
- // version: 1.245.0-0ea124370
1502
+ export { ldsEngineCreator as default, initializeLDS, predictiveLoadPage };
1503
+ // version: 1.247.0-4fe38c091
@@ -2,6 +2,8 @@ import type { FetchResponse, Luvio, InMemoryStore, Adapter, UnfulfilledSnapshot
2
2
  import type { AdapterMetadata } from '@salesforce/lds-bindings';
3
3
  import { ADAPTER_UNFULFILLED_ERROR } from '@salesforce/lds-bindings';
4
4
  import type { CacheStatsLogger, Timer } from 'instrumentation/service';
5
+ import { onIdleDetected } from '@salesforce/lds-instrumentation';
6
+ export { onIdleDetected };
5
7
  export interface AdapterUnfulfilledError {
6
8
  [ADAPTER_UNFULFILLED_ERROR]: boolean;
7
9
  adapterName: string;
@@ -176,4 +178,3 @@ export declare function setupInstrumentation(luvio: Luvio, store: InMemoryStore)
176
178
  */
177
179
  export declare function logCRUDLightningInteraction(eventSource: string, attributes: object): void;
178
180
  export declare const instrumentation: Instrumentation;
179
- export {};
@@ -6,8 +6,8 @@
6
6
  *
7
7
  * Below are the R.E.A.D.S. metrics for the Lightning Data Service, defined here[2].
8
8
  *
9
- * [1] https://salesforce.quip.com/NfW9AsbGEaTY
10
- * [2] https://salesforce.quip.com/1dFvAba1b0eq
9
+ * [1] Search "[M1] Lightning Data Service Design Spike" in Quip
10
+ * [2] Search "Lightning Data Service R.E.A.D.S. Metrics" in Quip
11
11
  */
12
12
  import type { MetricsKey } from 'instrumentation/service';
13
13
  export declare const OBSERVABILITY_NAMESPACE = "LIGHTNING.lds.service";
@@ -1,3 +1,19 @@
1
+ type PreloadProps = {
2
+ context: {
3
+ objectApiName: string;
4
+ };
5
+ pageReference: LexPageReference;
6
+ };
7
+ type LexPageReference = {
8
+ attributes: {
9
+ actionName: string;
10
+ objectApiName: string;
11
+ recordId: string;
12
+ };
13
+ state: any;
14
+ type: string;
15
+ };
16
+ export declare function predictiveLoadPage(preloadProps: PreloadProps): Promise<void>;
1
17
  export declare function initializeLDS(): void;
2
18
  declare function ldsEngineCreator(): {
3
19
  name: string;
@@ -0,0 +1,6 @@
1
+ export * from './pages';
2
+ export * from './prefetcher';
3
+ export * from './repository';
4
+ export * from './request-runner';
5
+ export * from './request-strategy';
6
+ export * from './storage';
@@ -0,0 +1,3 @@
1
+ export * from './predictive-prefetch-page';
2
+ export * from './lex-default-page';
3
+ export * from './record-home-page';
@@ -0,0 +1,12 @@
1
+ import type { LexRequest } from '../prefetcher';
2
+ import { PredictivePrefetchPage } from './predictive-prefetch-page';
3
+ export type DefaultPageContext = Record<string, any>;
4
+ export declare class LexDefaultPage extends PredictivePrefetchPage<LexRequest, DefaultPageContext> {
5
+ constructor(context: DefaultPageContext);
6
+ buildSaveRequestData(request: LexRequest): {
7
+ context: DefaultPageContext;
8
+ request: import("./record-home-page").RecordHomePageRequest;
9
+ };
10
+ resolveSimilarRequest(similarRequest: LexRequest): LexRequest;
11
+ getAlwaysRunRequests(): LexRequest[];
12
+ }
@@ -0,0 +1,11 @@
1
+ export declare abstract class PredictivePrefetchPage<Request, Context> {
2
+ context: Context;
3
+ similarContext: Partial<Context> | undefined;
4
+ constructor(context: Context);
5
+ abstract buildSaveRequestData(request: Request): {
6
+ context: Context;
7
+ request: Request;
8
+ };
9
+ abstract resolveSimilarRequest(similarRequest: Request): Request;
10
+ abstract getAlwaysRunRequests(): Request[];
11
+ }
@@ -0,0 +1,46 @@
1
+ import type { LexContext } from '../prefetcher';
2
+ import type { GetRecordRequest, GetRecordsRequest, GetRecordRequestStrategy, GetRecordsRequestStrategy, GetRecordActionsRequestStrategy, GetRecordActionsRequest, GetRecordAvatarsRequest, GetRecordAvatarsRequestStrategy } from '../request-strategy';
3
+ import { PredictivePrefetchPage } from './predictive-prefetch-page';
4
+ export type RecordHomePageContext = {
5
+ objectApiName: string;
6
+ recordId: string;
7
+ actionName: string;
8
+ type: 'recordPage';
9
+ };
10
+ export type RecordHomePageRequest = GetRecordRequest | GetRecordsRequest | GetRecordActionsRequest | GetRecordAvatarsRequest;
11
+ export declare class RecordHomePage extends PredictivePrefetchPage<RecordHomePageRequest, RecordHomePageContext> {
12
+ private requestStrategies;
13
+ similarContext: RecordHomePageContext;
14
+ constructor(context: RecordHomePageContext, requestStrategies: {
15
+ getRecord: GetRecordRequestStrategy;
16
+ getRecords: GetRecordsRequestStrategy;
17
+ getRecordActions: GetRecordActionsRequestStrategy;
18
+ getRecordAvatars: GetRecordAvatarsRequestStrategy;
19
+ });
20
+ buildSaveRequestData(request: RecordHomePageRequest): {
21
+ request: GetRecordRequest;
22
+ context: RecordHomePageContext;
23
+ } | {
24
+ request: GetRecordsRequest;
25
+ context: RecordHomePageContext;
26
+ } | {
27
+ request: GetRecordActionsRequest;
28
+ context: RecordHomePageContext;
29
+ } | {
30
+ request: GetRecordAvatarsRequest;
31
+ context: RecordHomePageContext;
32
+ };
33
+ buildGetRecordSaveRequestData(request: GetRecordRequest): {
34
+ request: GetRecordRequest;
35
+ context: RecordHomePageContext;
36
+ };
37
+ buildGetRecordsSaveRequestData(request: GetRecordsRequest): {
38
+ request: GetRecordsRequest;
39
+ context: RecordHomePageContext;
40
+ };
41
+ isGetRecordRequestContextDependent(request: GetRecordRequest): boolean;
42
+ isGetRecordsRequestContextDependent(request: GetRecordsRequest): boolean;
43
+ resolveSimilarRequest(similarRequest: RecordHomePageRequest): RecordHomePageRequest;
44
+ getAlwaysRunRequests(): RecordHomePageRequest[];
45
+ static handlesContext(context: LexContext): context is RecordHomePageContext;
46
+ }
@@ -0,0 +1,2 @@
1
+ export * from './predictive-prefetcher';
2
+ export * from './lex-predictive-prefetcher';
@@ -0,0 +1,18 @@
1
+ import type { DefaultPageContext, PredictivePrefetchPage } from '../pages';
2
+ import { ApplicationPredictivePrefetcher } from './predictive-prefetcher';
3
+ import type { GetRecordActionsRequestStrategy, GetRecordAvatarsRequestStrategy, GetRecordRequestStrategy, GetRecordsRequestStrategy } from '../request-strategy';
4
+ import type { RequestRunner } from '../request-runner';
5
+ import type { PrefetchRepository } from '../repository/prefetch-repository';
6
+ import type { RecordHomePageContext, RecordHomePageRequest } from '../pages/record-home-page';
7
+ export type LexRequest = RecordHomePageRequest;
8
+ export type LexContext = RecordHomePageContext | DefaultPageContext;
9
+ export declare class LexPredictivePrefetcher extends ApplicationPredictivePrefetcher<LexRequest, LexContext> {
10
+ private requestStrategies;
11
+ constructor(context: LexContext, repository: PrefetchRepository, requestRunner: RequestRunner<LexRequest>, requestStrategies: {
12
+ getRecord: GetRecordRequestStrategy;
13
+ getRecords: GetRecordsRequestStrategy;
14
+ getRecordActions: GetRecordActionsRequestStrategy;
15
+ getRecordAvatars: GetRecordAvatarsRequestStrategy;
16
+ });
17
+ getPage(): PredictivePrefetchPage<LexRequest, LexContext>;
18
+ }
@@ -0,0 +1,20 @@
1
+ import type { PrefetchRepository } from '../repository/prefetch-repository';
2
+ import type { PredictivePrefetchPage } from '../pages';
3
+ import type { RequestRunner } from '../request-runner';
4
+ export declare abstract class ApplicationPredictivePrefetcher<Request, Context extends Record<string, any>> {
5
+ private repository;
6
+ private requestRunner;
7
+ private _context;
8
+ isRecording: boolean;
9
+ page: PredictivePrefetchPage<Request, Context>;
10
+ queuedPredictionRequests: Request[];
11
+ constructor(context: Context, repository: PrefetchRepository, requestRunner: RequestRunner<Request>);
12
+ abstract getPage(): PredictivePrefetchPage<Request, Context>;
13
+ set context(value: Context);
14
+ get context(): Context;
15
+ stopRecording(): Promise<void>;
16
+ startRecording(): void;
17
+ saveRequest(request: Request): Promise<void>;
18
+ predict(): Promise<void>;
19
+ getSimilarPageRequests(): Promise<Request[]>;
20
+ }
@@ -0,0 +1,2 @@
1
+ export * from './prefetch-repository';
2
+ export * from './utils';
@@ -0,0 +1,27 @@
1
+ import type { PrefetchStorage } from '../storage';
2
+ type Key = Record<string, any>;
3
+ export type History = {
4
+ version: '1.0';
5
+ pages: Key[];
6
+ };
7
+ export type PageEntry<Request> = {
8
+ id: string;
9
+ requests: RequestEntry<Request>[];
10
+ };
11
+ export type RequestEntry<Request> = {
12
+ request: Request;
13
+ requestMetadata: {
14
+ requestTimes: number[];
15
+ };
16
+ };
17
+ export declare class PrefetchRepository {
18
+ private storage;
19
+ private requestBuffer;
20
+ constructor(storage: PrefetchStorage);
21
+ clearRequestBuffer(): void;
22
+ flushRequestsToStorage(): Promise<void>;
23
+ saveRequest<Request>(key: Key, request: Request): Promise<void>;
24
+ getPage<Request>(key: Key): Promise<PageEntry<Request> | undefined>;
25
+ getPageRequests<Request>(key: Key): Promise<Request[]>;
26
+ }
27
+ export {};
@@ -0,0 +1,15 @@
1
+ export declare const ObjectPrototypeHasOwnProperty: (v: PropertyKey) => boolean;
2
+ export declare const ArrayIsArray: (arg: any) => arg is any[];
3
+ /**
4
+ * A deterministic JSON stringify implementation. Heavily adapted from https://github.com/epoberezkin/fast-json-stable-stringify.
5
+ * This is needed because insertion order for JSON.stringify(object) affects output:
6
+ * JSON.stringify({a: 1, b: 2})
7
+ * "{"a":1,"b":2}"
8
+ * JSON.stringify({b: 2, a: 1})
9
+ * "{"b":2,"a":1}"
10
+ * @param data Data to be JSON-stringified.
11
+ * @returns JSON.stringified value with consistent ordering of keys.
12
+ */
13
+ export declare function stableJSONStringify(node: any): string | undefined;
14
+ export declare function isObject(obj: any): obj is Record<string, unknown>;
15
+ export declare function deepEquals(objA: any, objB: any): boolean;
@@ -0,0 +1,2 @@
1
+ export * from './request-runner';
2
+ export * from './lex-request-runner';
@@ -0,0 +1,10 @@
1
+ import type { Luvio } from '@luvio/engine';
2
+ import type { LexRequest } from '../prefetcher';
3
+ import type { RequestRunner } from './request-runner';
4
+ export declare class LexRequestRunner implements RequestRunner<LexRequest> {
5
+ private luvio;
6
+ private requestStrategies;
7
+ constructor(luvio: Luvio);
8
+ reduceRequests(requests: LexRequest[]): LexRequest[];
9
+ runRequest(request: LexRequest): Promise<void>;
10
+ }
@@ -0,0 +1,4 @@
1
+ export type RequestRunner<Request> = {
2
+ runRequest(request: Request): Promise<void>;
3
+ reduceRequests(requests: Request[]): Request[];
4
+ };
@@ -0,0 +1,22 @@
1
+ import type { GetRecordActionsConfig } from '@salesforce/lds-adapters-uiapi';
2
+ import { LuvioAdapterRequestStrategy } from './luvio-adapter-request-strategy';
3
+ import type { LuvioAdapterRequest } from './luvio-adapter-request';
4
+ export type GetRecordActionsRequest = {
5
+ adapterName: 'getRecordActions';
6
+ config: GetRecordActionsConfig;
7
+ };
8
+ type GetRecordActionsContext = {
9
+ recordId: string;
10
+ };
11
+ export declare class GetRecordActionsRequestStrategy extends LuvioAdapterRequestStrategy<GetRecordActionsConfig, GetRecordActionsRequest, GetRecordActionsContext> {
12
+ adapterName: string;
13
+ adapterFactory: import("@luvio/engine").AdapterFactory<GetRecordActionsConfig, import("packages/lds-adapters-uiapi/dist/es/es2018/types/src/generated/types/ActionRepresentation").ActionRepresentation>;
14
+ buildConcreteRequest(similarRequest: GetRecordActionsRequest, context: GetRecordActionsContext): GetRecordActionsRequest;
15
+ buildGetRecordActionsSaveRequestData<C extends GetRecordActionsContext>(similarContext: C, context: C, request: GetRecordActionsRequest): {
16
+ request: GetRecordActionsRequest;
17
+ context: C;
18
+ };
19
+ private isGetRecordActionsRequestContextDependent;
20
+ reduce(unfilteredRequests: LuvioAdapterRequest<unknown>[]): GetRecordActionsRequest[];
21
+ }
22
+ export {};
@@ -0,0 +1,22 @@
1
+ import type { GetRecordAvatarsConfig } from '@salesforce/lds-adapters-uiapi';
2
+ import { LuvioAdapterRequestStrategy } from './luvio-adapter-request-strategy';
3
+ import type { LuvioAdapterRequest } from './luvio-adapter-request';
4
+ export type GetRecordAvatarsRequest = {
5
+ adapterName: 'getRecordAvatars';
6
+ config: GetRecordAvatarsConfig;
7
+ };
8
+ type GetRecordAvatarsContext = {
9
+ recordId: string;
10
+ };
11
+ export declare class GetRecordAvatarsRequestStrategy extends LuvioAdapterRequestStrategy<GetRecordAvatarsConfig, GetRecordAvatarsRequest, GetRecordAvatarsContext> {
12
+ adapterName: string;
13
+ adapterFactory: import("@luvio/engine").AdapterFactory<GetRecordAvatarsConfig, import("packages/lds-adapters-uiapi/dist/es/es2018/types/src/generated/types/RecordAvatarBulkMapRepresentation").RecordAvatarBulkMapRepresentation>;
14
+ buildConcreteRequest(similarRequest: GetRecordAvatarsRequest, context: GetRecordAvatarsContext): GetRecordAvatarsRequest;
15
+ buildGetRecordAvatarsSaveRequestData<C extends GetRecordAvatarsContext>(similarContext: C, context: C, request: GetRecordAvatarsRequest): {
16
+ request: GetRecordAvatarsRequest;
17
+ context: C;
18
+ };
19
+ private isGetRecordAvatarsRequestContextDependent;
20
+ reduce(unfilteredRequests: LuvioAdapterRequest<unknown>[]): GetRecordAvatarsRequest[];
21
+ }
22
+ export {};
@@ -0,0 +1,18 @@
1
+ import type { GetRecordConfig } from '@salesforce/lds-adapters-uiapi';
2
+ import { LuvioAdapterRequestStrategy } from './luvio-adapter-request-strategy';
3
+ export type GetRecordRequest = {
4
+ adapterName: 'getRecord';
5
+ config: GetRecordConfig;
6
+ };
7
+ import type { LuvioAdapterRequest } from './luvio-adapter-request';
8
+ type GetRecordContext = {
9
+ recordId: string;
10
+ };
11
+ export declare class GetRecordRequestStrategy extends LuvioAdapterRequestStrategy<GetRecordConfig, GetRecordRequest, GetRecordContext> {
12
+ adapterName: string;
13
+ adapterFactory: import("@luvio/engine").AdapterFactory<GetRecordConfig, import("@salesforce/lds-adapters-uiapi").RecordRepresentation>;
14
+ buildConcreteRequest(similarRequest: GetRecordRequest, context: GetRecordContext): GetRecordRequest;
15
+ transformForSave(request: GetRecordRequest): GetRecordRequest;
16
+ reduce(unfilteredRequests: LuvioAdapterRequest<unknown>[]): GetRecordRequest[];
17
+ }
18
+ export {};
@@ -0,0 +1,15 @@
1
+ import type { GetRecordsConfig } from '@salesforce/lds-adapters-uiapi';
2
+ import { LuvioAdapterRequestStrategy } from './luvio-adapter-request-strategy';
3
+ export type GetRecordsRequest = {
4
+ adapterName: 'getRecords';
5
+ config: GetRecordsConfig;
6
+ };
7
+ type GetRecordsContext = {
8
+ recordId: string;
9
+ };
10
+ export declare class GetRecordsRequestStrategy extends LuvioAdapterRequestStrategy<GetRecordsConfig, GetRecordsRequest, GetRecordsContext> {
11
+ adapterName: string;
12
+ adapterFactory: import("@luvio/engine").AdapterFactory<GetRecordsConfig, import("@salesforce/lds-adapters-uiapi").BatchRepresentation>;
13
+ buildConcreteRequest(similarRequest: GetRecordsRequest, context: GetRecordsContext): GetRecordsRequest;
14
+ }
15
+ export {};
@@ -0,0 +1,7 @@
1
+ export * from './get-record-avatars-request-strategy';
2
+ export * from './get-record-request-strategy';
3
+ export * from './get-records-request-strategy';
4
+ export * from './get-record-actions-request-strategy';
5
+ export * from './luvio-adapter-request-strategy';
6
+ export * from './luvio-adapter-request';
7
+ export * from './request-strategy';
@@ -0,0 +1,10 @@
1
+ import type { AdapterFactory } from '@luvio/engine';
2
+ import { RequestStrategy } from './request-strategy';
3
+ import type { LuvioAdapterRequest } from './luvio-adapter-request';
4
+ export declare abstract class LuvioAdapterRequestStrategy<AdapterConfig, Request extends LuvioAdapterRequest<AdapterConfig>, Context> extends RequestStrategy<Request, Context> {
5
+ abstract adapterName: string;
6
+ abstract adapterFactory: AdapterFactory<AdapterConfig, any>;
7
+ transformForSave(request: Request): Request;
8
+ protected filterRequests(unfilteredRequests: LuvioAdapterRequest<unknown>[]): Request[];
9
+ reduce(unfilteredRequests: LuvioAdapterRequest<unknown>[]): Request[];
10
+ }
@@ -0,0 +1,4 @@
1
+ export type LuvioAdapterRequest<Config> = {
2
+ adapterName: string;
3
+ config: Config;
4
+ };
@@ -0,0 +1,5 @@
1
+ export declare abstract class RequestStrategy<Request, Context> {
2
+ abstract buildConcreteRequest(similarRequest: Request, context: Context): Request;
3
+ transformForSave(request: Request): Request;
4
+ reduce(requests: Request[]): Request[];
5
+ }
@@ -0,0 +1,18 @@
1
+ import { type PrefetchStorage } from '.';
2
+ import { type AuraStorage, type AuraStorageConfig } from '@salesforce/lds-aura-storage';
3
+ export declare const DEFAULT_STORAGE_OPTIONS: {
4
+ name: string;
5
+ persistent: boolean;
6
+ secure: boolean;
7
+ maxSize: number;
8
+ expiration: number;
9
+ clearOnInit: boolean;
10
+ debugLogging: boolean;
11
+ };
12
+ export declare function buildAuraPrefetchStorage(options?: Partial<AuraStorageConfig>): PrefetchStorage;
13
+ export declare class AuraPrefetchStorage implements PrefetchStorage {
14
+ private auraStorage;
15
+ constructor(auraStorage: AuraStorage);
16
+ set<T>(key: string, value: T): Promise<void>;
17
+ get<T>(key: string): Promise<T | undefined>;
18
+ }
@@ -0,0 +1,6 @@
1
+ import type { PrefetchStorage } from '.';
2
+ export declare class InMemoryPrefetchStorage implements PrefetchStorage {
3
+ data: Record<string, any>;
4
+ set<T>(key: string, value: T): Promise<void>;
5
+ get<T>(key: string): Promise<T | undefined>;
6
+ }
@@ -0,0 +1,7 @@
1
+ export type PrefetchStorage = {
2
+ get<T>(key: string): Promise<T | undefined>;
3
+ set<T>(key: string, value: T): Promise<void>;
4
+ };
5
+ export * from './in-memory-prefetch-storage';
6
+ export * from './local-prefetch-storage';
7
+ export { buildAuraPrefetchStorage } from './aura-prefetch-storage';
@@ -0,0 +1,7 @@
1
+ import type { PrefetchStorage } from '.';
2
+ export declare class LocalPrefetchStorage implements PrefetchStorage {
3
+ private localStorage;
4
+ constructor(localStorage: typeof window.localStorage);
5
+ set<T>(key: string, value: T): Promise<void>;
6
+ get<T>(key: string): Promise<T | undefined>;
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/lds-runtime-aura",
3
- "version": "1.245.0",
3
+ "version": "1.247.0",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "LDS engine for Aura runtime",
6
6
  "main": "dist/ldsEngineCreator.js",
@@ -43,16 +43,19 @@
43
43
  "@salesforce/lds-network-fetch-with-jwt": "*"
44
44
  },
45
45
  "dependencies": {
46
- "@luvio/network-adapter-composable": "0.150.5"
46
+ "@luvio/network-adapter-composable": "0.151.0"
47
47
  },
48
48
  "luvioBundlesize": [
49
49
  {
50
50
  "path": "./dist/ldsEngineCreator.js",
51
51
  "maxSize": {
52
- "none": "32 kB",
53
- "min": "13 kB",
54
- "compressed": "8 kB"
52
+ "none": "60 kB",
53
+ "min": "28 kB",
54
+ "compressed": "12 kB"
55
55
  }
56
56
  }
57
- ]
57
+ ],
58
+ "volta": {
59
+ "extends": "../../package.json"
60
+ }
58
61
  }