@salesforce/lds-runtime-aura 1.303.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.
@@ -27,14 +27,16 @@ import { serviceBroker } from 'force/luvioServiceBroker5';
27
27
  import oneStoreEnabled from '@salesforce/gate/lds.oneStoreEnabled.ltng';
28
28
  import oneStoreUiapiEnabled from '@salesforce/gate/lds.oneStoreUiapiEnabled.ltng';
29
29
  import { getDefinition, executeGlobalControllerRawResponse } from 'aura';
30
- import { buildJwtNetworkAdapter } from 'force/ldsNetworkFetchWithJwt';
31
- import auraNetworkAdapter, { dispatchAuraAction, defaultActionConfig, instrument as instrument$1, forceRecordTransactionsDisabled, ldsNetworkAdapterInstrument } from 'force/ldsNetwork';
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';
32
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';
33
33
  import { REFRESH_ADAPTER_EVENT, ADAPTER_UNFULFILLED_ERROR, instrument as instrument$2 } from 'force/ldsBindings';
34
34
  import { counter, registerCacheStats, perfStart, perfEnd, registerPeriodicLogger, interaction, timer } from 'instrumentation/service';
35
35
  import { instrument as instrument$3 } from 'force/adsBridge';
36
36
  import { withRegistration, register, setDefaultLuvio } from 'force/ldsEngine';
37
37
  import { createStorage, clearStorages } from 'force/ldsStorage';
38
+ import useHttpInsteadAuraTransport from '@salesforce/gate/lds.useHttpInsteadAuraTransport';
39
+ import { ThirdPartyTracker } from 'instrumentation:beaconLib';
38
40
  import { getObjectInfo, getObjectInfos } from 'force/ldsAdaptersUiapiLex';
39
41
 
40
42
  /**
@@ -1888,8 +1890,8 @@ const TOTAL_ADAPTER_REQUEST_SUCCESS_COUNT = {
1888
1890
  },
1889
1891
  };
1890
1892
 
1891
- const { create, keys } = Object;
1892
- const { isArray } = Array;
1893
+ const { create, keys, hasOwnProperty } = Object;
1894
+ const { isArray, from } = Array;
1893
1895
  const { stringify } = JSON;
1894
1896
 
1895
1897
  /**
@@ -2374,7 +2376,7 @@ function setAuraInstrumentationHooks() {
2374
2376
  // Our getRecord through aggregate-ui CRUD logging has moved
2375
2377
  // to lds-network-adapter. We still need to respect the
2376
2378
  // orgs environment setting
2377
- if (forceRecordTransactionsDisabled === false) {
2379
+ if (forceRecordTransactionsDisabled$1 === false) {
2378
2380
  ldsNetworkAdapterInstrument({
2379
2381
  getRecordAggregateResolve: (cb) => {
2380
2382
  const { recordId, apiName } = cb();
@@ -2516,10 +2518,11 @@ async function runRequestsWithLimit(requests, runner, concurrentRequestsLimit, p
2516
2518
  // queue for pending prediction requests
2517
2519
  const requestQueue = [...requests];
2518
2520
  // Function to process the next request in the queue
2519
- const processNextRequest = async () => {
2520
- const timeInWaterfall = Date.now() - pageStartTime - 5; /* 5ms padding */
2521
+ const processNextRequest = async (verifyPastTime = true) => {
2522
+ const timeInWaterfall = Date.now() - pageStartTime;
2521
2523
  while (requestQueue.length > 0 &&
2522
- requestQueue[0].requestMetadata.requestTime < timeInWaterfall) {
2524
+ verifyPastTime &&
2525
+ requestQueue[0].requestMetadata.requestTime <= timeInWaterfall) {
2523
2526
  requestQueue.shift();
2524
2527
  }
2525
2528
  if (requestQueue.length > 0) {
@@ -2538,7 +2541,13 @@ async function runRequestsWithLimit(requests, runner, concurrentRequestsLimit, p
2538
2541
  const initialRequests = Math.min(concurrentRequestsLimit, requestQueue.length);
2539
2542
  const promises = [];
2540
2543
  for (let i = 0; i < initialRequests; i++) {
2541
- promises.push(processNextRequest());
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));
2542
2551
  }
2543
2552
  // Wait for all initial requests to complete
2544
2553
  await Promise.all(promises);
@@ -2547,6 +2556,10 @@ async function runRequestsWithLimit(requests, runner, concurrentRequestsLimit, p
2547
2556
  function isCmpDefsRequest({ request: { adapterName } }) {
2548
2557
  return adapterName === 'getComponentsDef';
2549
2558
  }
2559
+ function predictComponentDefs(cmpDefPredictions, requestRunner) {
2560
+ const reducedPredictions = requestRunner.reduceRequests(cmpDefPredictions);
2561
+ reducedPredictions.map((request) => requestRunner.runRequest(request.request));
2562
+ }
2550
2563
  class LexPredictivePrefetcher extends ApplicationPredictivePrefetcher {
2551
2564
  constructor(context, repository, requestRunner,
2552
2565
  // These strategies need to be in sync with the "predictiveDataLoadCapable" list
@@ -2575,37 +2588,41 @@ class LexPredictivePrefetcher extends ApplicationPredictivePrefetcher {
2575
2588
  return [...exactPageRequests, ...similarPageRequests];
2576
2589
  }
2577
2590
  async predict() {
2578
- const alwaysRequests = this.page.getAlwaysRunRequests();
2579
- // IMPORTANT: The `await` has no effect on this operation because `getAllPageRequests`
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`
2580
2598
  // is sync; however if removed, it will have a negative effect when used with
2581
2599
  // Aura Network: predictions will be boxcar'd, which likely will result in a
2582
2600
  // perf regression.
2583
- const pageRequests = await this.getAllPageRequests();
2601
+ const alwaysRequests = await this.page.getAlwaysRunRequests();
2584
2602
  const alwaysRequestEntries = alwaysRequests.map((request) => {
2585
2603
  return {
2586
2604
  request,
2587
2605
  requestMetadata: { requestTime: 0 }, // ensures always requests are executed, and executed first.
2588
2606
  };
2589
2607
  });
2608
+ const nonCmpDefPredictions = pageRequests.filter((r) => !isCmpDefsRequest(r));
2590
2609
  const reducedPredictions = this.requestRunner.reduceRequests([
2591
- ...pageRequests,
2610
+ ...nonCmpDefPredictions,
2592
2611
  ...alwaysRequestEntries,
2593
2612
  ]); // In future - remove alwaysRequestEntries when on OneStore
2594
- const nonCmpDefPredictions = reducedPredictions.filter((r) => !isCmpDefsRequest(r));
2595
- const cmpDefPredictions = reducedPredictions.filter(isCmpDefsRequest);
2596
- // Non CmpDefs requests are limited by AuraActions concurent inflight limit.
2597
2613
  // Always requests must go by themself - Some of them are essential to keep the page rendering at the beginning.
2598
- const predictedRequestsWithLimit = [...alwaysRequestEntries, ...nonCmpDefPredictions].sort((a, b) => a.requestMetadata.requestTime - b.requestMetadata.requestTime); // In future - choose sort algorithm via Gate?;
2599
- const inflightPredictionRequests = runRequestsWithLimit(predictedRequestsWithLimit, this.requestRunner, this.options.inflightRequestLimit, this.repository.pageStartTime);
2600
- const inflightCmpRequests = cmpDefPredictions.map((request) => this.requestRunner.runRequest(request.request));
2601
- return Promise.all([inflightPredictionRequests, ...inflightCmpRequests]).then();
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());
2602
2622
  }
2603
2623
  }
2604
2624
 
2605
2625
  // Copy-pasted from adapter-utils. This util should be extracted from generated code and imported in prefetch repository.
2606
- const { keys: ObjectKeys$2 } = Object;
2607
- const { stringify: JSONStringify } = JSON;
2608
- const { isArray: ArrayIsArray$1 } = Array;
2609
2626
  /**
2610
2627
  * A deterministic JSON stringify implementation. Heavily adapted from https://github.com/epoberezkin/fast-json-stable-stringify.
2611
2628
  * This is needed because insertion order for JSON.stringify(object) affects output:
@@ -2629,11 +2646,11 @@ function stableJSONStringify(node) {
2629
2646
  return isFinite(node) ? '' + node : 'null';
2630
2647
  }
2631
2648
  if (typeof node !== 'object') {
2632
- return JSONStringify(node);
2649
+ return stringify(node);
2633
2650
  }
2634
2651
  let i;
2635
2652
  let out;
2636
- if (ArrayIsArray$1(node)) {
2653
+ if (isArray(node)) {
2637
2654
  out = '[';
2638
2655
  for (i = 0; i < node.length; i++) {
2639
2656
  if (i) {
@@ -2646,10 +2663,10 @@ function stableJSONStringify(node) {
2646
2663
  if (node === null) {
2647
2664
  return 'null';
2648
2665
  }
2649
- const keys = ObjectKeys$2(node).sort();
2666
+ const keys$1 = keys(node).sort();
2650
2667
  out = '';
2651
- for (i = 0; i < keys.length; i++) {
2652
- const key = keys[i];
2668
+ for (i = 0; i < keys$1.length; i++) {
2669
+ const key = keys$1[i];
2653
2670
  const value = stableJSONStringify(node[key]);
2654
2671
  if (!value) {
2655
2672
  continue;
@@ -2657,7 +2674,7 @@ function stableJSONStringify(node) {
2657
2674
  if (out) {
2658
2675
  out += ',';
2659
2676
  }
2660
- out += JSONStringify(key) + ':' + value;
2677
+ out += stringify(key) + ':' + value;
2661
2678
  }
2662
2679
  return '{' + out + '}';
2663
2680
  }
@@ -2673,8 +2690,8 @@ function deepEquals(objA, objB) {
2673
2690
  if (!isObject(objA) || !isObject(objB))
2674
2691
  return false;
2675
2692
  // Filter out keys set as undefined, we can compare undefined as equals.
2676
- const keysA = ObjectKeys$2(objA).filter((key) => objA[key] !== undefined);
2677
- const keysB = ObjectKeys$2(objB).filter((key) => objB[key] !== undefined);
2693
+ const keysA = keys(objA).filter((key) => objA[key] !== undefined);
2694
+ const keysB = keys(objB).filter((key) => objB[key] !== undefined);
2678
2695
  // If the objects do not have the same set of keys, they are not deeply equal
2679
2696
  if (keysA.length !== keysB.length)
2680
2697
  return false;
@@ -2940,9 +2957,10 @@ function requestComponents(config) {
2940
2957
  try {
2941
2958
  for (let index = 0, n = config.length; index < n; index++) {
2942
2959
  const def = config[index];
2943
- if (!(def.includes('forceGenerated') ||
2944
- def.includes('one:onePreloads') ||
2945
- onePreloads.has(def))) {
2960
+ if (def.startsWith('markup://') &&
2961
+ !(def.includes('forceGenerated') ||
2962
+ def.includes('one:onePreloads') ||
2963
+ onePreloads.has(def))) {
2946
2964
  getDefinition(def, noop);
2947
2965
  }
2948
2966
  }
@@ -2965,9 +2983,10 @@ class GetComponentsDefStrategy extends RequestStrategy {
2965
2983
  };
2966
2984
  }
2967
2985
  transformForSave(request) {
2986
+ const normalizedConfig = (request.config || []).map((def) => def.indexOf('://') === -1 ? 'markup://' + def : def);
2968
2987
  return {
2969
2988
  ...request,
2970
- config: request.config || [],
2989
+ config: normalizedConfig,
2971
2990
  };
2972
2991
  }
2973
2992
  canCombine() {
@@ -3155,7 +3174,7 @@ class GetRecordsRequestStrategy extends LuvioAdapterRequestStrategy {
3155
3174
  }
3156
3175
 
3157
3176
  function normalizeRecordIds(recordIds) {
3158
- if (!ArrayIsArray$1(recordIds)) {
3177
+ if (!isArray(recordIds)) {
3159
3178
  return [recordIds];
3160
3179
  }
3161
3180
  return recordIds;
@@ -3164,7 +3183,7 @@ function normalizeApiNames(apiNames) {
3164
3183
  if (apiNames === undefined || apiNames === null) {
3165
3184
  return [];
3166
3185
  }
3167
- return ArrayIsArray$1(apiNames) ? apiNames : [apiNames];
3186
+ return isArray(apiNames) ? apiNames : [apiNames];
3168
3187
  }
3169
3188
  class GetRecordActionsRequestStrategy extends LuvioAdapterRequestStrategy {
3170
3189
  constructor() {
@@ -3331,11 +3350,9 @@ class GetObjectInfoRequestStrategy extends LuvioAdapterRequestStrategy {
3331
3350
  }
3332
3351
  }
3333
3352
 
3334
- const { keys: ObjectKeys$1 } = Object;
3335
- const { isArray: ArrayIsArray, from: ArrayFrom } = Array;
3336
3353
  function isReduceAbleRelatedListConfig(config) {
3337
3354
  return config.relatedListsActionParameters.every((rlReq) => {
3338
- return rlReq.relatedListId !== undefined && ObjectKeys$1(rlReq).length === 1;
3355
+ return rlReq.relatedListId !== undefined && keys(rlReq).length === 1;
3339
3356
  });
3340
3357
  }
3341
3358
  class GetRelatedListsActionsRequestStrategy extends LuvioAdapterRequestStrategy {
@@ -3379,7 +3396,7 @@ class GetRelatedListsActionsRequestStrategy extends LuvioAdapterRequestStrategy
3379
3396
  */
3380
3397
  canCombine(reqA, reqB) {
3381
3398
  const [recordIdA, recordIdB] = [reqA.recordIds, reqB.recordIds].map((recordIds) => {
3382
- return ArrayIsArray(recordIds)
3399
+ return isArray(recordIds)
3383
3400
  ? recordIds.length === 1
3384
3401
  ? recordIds[0]
3385
3402
  : null
@@ -3397,7 +3414,7 @@ class GetRelatedListsActionsRequestStrategy extends LuvioAdapterRequestStrategy
3397
3414
  });
3398
3415
  return {
3399
3416
  recordIds: reqA.recordIds,
3400
- relatedListsActionParameters: ArrayFrom(relatedListsIncluded).map((relatedListId) => ({
3417
+ relatedListsActionParameters: from(relatedListsIncluded).map((relatedListId) => ({
3401
3418
  relatedListId,
3402
3419
  })),
3403
3420
  };
@@ -3717,7 +3734,6 @@ class InMemoryPrefetchStorage {
3717
3734
  }
3718
3735
  }
3719
3736
 
3720
- const { keys: ObjectKeys } = Object;
3721
3737
  const DEFAULT_STORAGE_OPTIONS = {
3722
3738
  name: 'ldsPredictiveLoading',
3723
3739
  persistent: true,
@@ -3756,7 +3772,7 @@ class AuraPrefetchStorage {
3756
3772
  * then they will (potentially incorrectly) think that we don't have any predictions.
3757
3773
  */
3758
3774
  auraStorage.getAll().then((results) => {
3759
- ObjectKeys(results).forEach((key) => this.inMemoryStorage.set(key, results[key]));
3775
+ keys(results).forEach((key) => this.inMemoryStorage.set(key, results[key]));
3760
3776
  });
3761
3777
  }
3762
3778
  set(key, value) {
@@ -3792,9 +3808,308 @@ function buildComposableNetworkAdapter(composedAdapters) {
3792
3808
  };
3793
3809
  }
3794
3810
 
3811
+ /**
3812
+ * Copyright (c) 2022, Salesforce, Inc.,
3813
+ * All rights reserved.
3814
+ * For full license text, see the LICENSE.txt file
3815
+ */
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
+ };
3833
+ /**
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.
3837
+ */
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);
3954
+ }
3955
+ });
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
+ },
4013
+ },
4014
+ };
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;
4072
+ return {
4073
+ ...resourceRequest,
4074
+ baseUri: jwtBaseUri + resourceRequest.baseUri,
4075
+ };
4076
+ };
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 = {
4094
+ shouldHandleRequest(resourceRequest) {
4095
+ return (resourceRequest.basePath.startsWith(UIAPI_FAMILY) &&
4096
+ !isPrivatePath(resourceRequest.basePath));
4097
+ },
4098
+ adapter: setupLexJwtNetworkAdapter(auraNetworkAdapter, modifyLexResourceRequest, requestTracker, requestLogger),
4099
+ };
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
+ }
3795
4110
  const composedNetworkAdapter = buildComposableNetworkAdapter([
3796
- composedNetworkAdapter$1,
3797
- // The aura network adapter must be the default.
4111
+ ...getComposedAdapters(),
4112
+ // The aura network adapter must be the default.
3798
4113
  {
3799
4114
  shouldHandleRequest() {
3800
4115
  return true;
@@ -3854,12 +4169,20 @@ function setupQueryEvaluators(luvio, store) {
3854
4169
  }
3855
4170
  let __lexPrefetcher;
3856
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
+ }
3857
4180
  function setupPredictivePrefetcher(luvio) {
3858
4181
  const storage = buildAuraPrefetchStorage();
3859
4182
  const repository = new PrefetchRepository(storage);
3860
4183
  const requestRunner = new LexRequestRunner(luvio);
3861
4184
  const inflightRequestLimit = applyPredictionRequestLimit.isOpen({ fallback: false })
3862
- ? HARDCODED_REQUEST_LIMIT
4185
+ ? getInflightRequestLimit()
3863
4186
  : 1000;
3864
4187
  const useExactMatchesPlus = useExactMatchesPlusGate.isOpen({ fallback: false });
3865
4188
  const prefetcherOptions = {
@@ -3889,30 +4212,31 @@ function setupPredictivePrefetcher(luvio) {
3889
4212
  registerPrefetcher$1(luvio, prefetcher);
3890
4213
  }
3891
4214
  __lexPrefetcher = prefetcher;
3892
- if (useCmpDefPredictions.isOpen({ fallback: false })) {
3893
- window['$A'].installOverride('ComponentDefLoader.loadingComplete', (...args) => {
3894
- /**
3895
- * To install an override (taken from the Aura.Utils.Override):
3896
- *
3897
- * The function supplied should have the following code in it:
3898
- * ------
3899
- * var config = Array.prototype.shift.apply(arguments);
3900
- * var ret = config["fn"].apply(config["scope"], arguments);
3901
- * return ret
3902
- * ------
3903
- */
3904
- const config = Array.prototype.shift.apply(args);
3905
- const ret = config['fn'].apply(config['scope'], args);
3906
- const [hasErrors, descriptors] = args;
3907
- if (!hasErrors && Array.isArray(descriptors) && descriptors.length > 0) {
3908
- __lexPrefetcher.saveRequest({
3909
- adapterName: 'getComponentsDef',
3910
- config: descriptors,
3911
- });
3912
- }
3913
- 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,
3914
4234
  });
3915
4235
  }
4236
+ catch (e) {
4237
+ // dismiss any error, the activity will log it.
4238
+ }
4239
+ return ret;
3916
4240
  }
3917
4241
  /**
3918
4242
  * @typedef {Object} RecordHomePageContext
@@ -3953,8 +4277,14 @@ function buildPredictorForContext(context) {
3953
4277
  watchPageLoadForPredictions() {
3954
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.
3955
4279
  __lexPrefetcher.startRecording();
4280
+ if (useCmpDefPredictions.isOpen({ fallback: false })) {
4281
+ window['$A'].installOverride('ComponentService.loadComponentDefsStarted', loadComponentsDefStartedOverride);
4282
+ }
3956
4283
  onIdleDetected(() => {
3957
4284
  __lexPrefetcher.stopRecording();
4285
+ if (useCmpDefPredictions.isOpen({ fallback: false })) {
4286
+ window['$A'].uninstallOverride('ComponentService.loadComponentDefsStarted', loadComponentsDefStartedOverride);
4287
+ }
3958
4288
  });
3959
4289
  },
3960
4290
  runPredictions() {
@@ -4067,4 +4397,4 @@ function ldsEngineCreator() {
4067
4397
  }
4068
4398
 
4069
4399
  export { buildPredictorForContext, ldsEngineCreator as default, initializeLDS, initializeOneStore };
4070
- // version: 1.303.0-a698c7cc67
4400
+ // version: 1.304.0-aa3e5f9550
@@ -1 +1,2 @@
1
1
  export declare function buildJwtNetworkAdapter(): void;
2
+ export declare function setupLexJwtNetworkAdapter(): void;
@@ -0,0 +1,7 @@
1
+ declare function registerHandler(_cmp: any, _name: string, _loadedCheck: () => boolean): void;
2
+ declare function markLoaded(_cmp: any): void;
3
+ export declare const ThirdPartyTracker: {
4
+ registerHandler: typeof registerHandler;
5
+ markLoaded: typeof markLoaded;
6
+ };
7
+ export {};
@@ -0,0 +1,18 @@
1
+ declare const create: {
2
+ (o: object | null): any;
3
+ (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any;
4
+ }, keys: {
5
+ (o: object): string[];
6
+ (o: {}): string[];
7
+ }, hasOwnProperty: (v: PropertyKey) => boolean;
8
+ declare const isArray: (arg: any) => arg is any[], from: {
9
+ <T>(arrayLike: ArrayLike<T>): T[];
10
+ <T_1, U>(arrayLike: ArrayLike<T_1>, mapfn: (v: T_1, k: number) => U, thisArg?: any): U[];
11
+ <T_2>(iterable: Iterable<T_2> | ArrayLike<T_2>): T_2[];
12
+ <T_3, U_1>(iterable: Iterable<T_3> | ArrayLike<T_3>, mapfn: (v: T_3, k: number) => U_1, thisArg?: any): U_1[];
13
+ };
14
+ declare const stringify: {
15
+ (value: any, replacer?: ((this: any, key: string, value: any) => any) | undefined, space?: string | number | undefined): string;
16
+ (value: any, replacer?: (string | number)[] | null | undefined, space?: string | number | undefined): string;
17
+ };
18
+ export { create as ObjectCreate, keys as ObjectKeys, hasOwnProperty as ObjectHasOwnProperty, isArray as ArrayIsArray, from as ArrayFrom, stringify as JSONStringify, };
@@ -0,0 +1,8 @@
1
+ import { type ResourceRequest } from '@luvio/engine';
2
+ import type { ModifyResourceRequestHook, RequestLogger } from '@salesforce/lds-network-fetch-with-jwt';
3
+ export declare const modifyLexResourceRequest: ModifyResourceRequestHook<unknown, any>;
4
+ export declare const requestLogger: RequestLogger;
5
+ export declare const composedFetchNetworkAdapter: {
6
+ shouldHandleRequest(resourceRequest: ResourceRequest): boolean;
7
+ adapter: import("@luvio/engine").NetworkAdapter;
8
+ };
@@ -0,0 +1,2 @@
1
+ import type { FetchResponse, ResourceRequest } from '@luvio/engine';
2
+ export declare function checkAndLogCrudInteraction(request: ResourceRequest, isResolve: boolean, error: any, response?: FetchResponse<any>): void;
@@ -1,5 +1,3 @@
1
- export declare const ObjectPrototypeHasOwnProperty: (v: PropertyKey) => boolean;
2
- export declare const ArrayIsArray: (arg: any) => arg is any[];
3
1
  /**
4
2
  * A deterministic JSON stringify implementation. Heavily adapted from https://github.com/epoberezkin/fast-json-stable-stringify.
5
3
  * This is needed because insertion order for JSON.stringify(object) affects output:
@@ -1,4 +1,5 @@
1
- import { InMemoryPrefetchStorage, type PrefetchStorage } from '.';
1
+ import { type PrefetchStorage } from '.';
2
+ import { InMemoryPrefetchStorage } from './in-memory-prefetch-storage';
2
3
  import { type AuraStorage, type AuraStorageConfig } from '@salesforce/lds-aura-storage';
3
4
  export declare const DEFAULT_STORAGE_OPTIONS: {
4
5
  name: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/lds-runtime-aura",
3
- "version": "1.303.0",
3
+ "version": "1.304.0",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "LDS engine for Aura runtime",
6
6
  "main": "dist/ldsEngineCreator.js",
@@ -35,15 +35,15 @@
35
35
  },
36
36
  "devDependencies": {
37
37
  "@luvio/service-broker": "5.3.1",
38
- "@salesforce/lds-adapters-apex": "^1.303.0",
39
- "@salesforce/lds-adapters-uiapi": "^1.303.0",
38
+ "@salesforce/lds-adapters-apex": "^1.304.0",
39
+ "@salesforce/lds-adapters-uiapi": "^1.304.0",
40
40
  "@salesforce/lds-adapters-uiapi-lex": "^1.302.0",
41
- "@salesforce/lds-ads-bridge": "^1.303.0",
42
- "@salesforce/lds-aura-storage": "^1.303.0",
43
- "@salesforce/lds-bindings": "^1.303.0",
44
- "@salesforce/lds-instrumentation": "^1.303.0",
45
- "@salesforce/lds-network-aura": "^1.303.0",
46
- "@salesforce/lds-network-fetch-with-jwt": "^1.303.0"
41
+ "@salesforce/lds-ads-bridge": "^1.304.0",
42
+ "@salesforce/lds-aura-storage": "^1.304.0",
43
+ "@salesforce/lds-bindings": "^1.304.0",
44
+ "@salesforce/lds-instrumentation": "^1.304.0",
45
+ "@salesforce/lds-network-aura": "^1.304.0",
46
+ "@salesforce/lds-network-fetch-with-jwt": "^1.304.0"
47
47
  },
48
48
  "dependencies": {
49
49
  "@luvio/command-aura-network": "5.3.1",
@@ -52,6 +52,7 @@
52
52
  "@luvio/command-sse": "5.3.1",
53
53
  "@luvio/command-streaming": "5.3.1",
54
54
  "@luvio/network-adapter-composable": "0.156.3",
55
+ "@luvio/network-adapter-fetch": "0.156.3",
55
56
  "@luvio/runtime": "5.3.1",
56
57
  "@luvio/service-aura-network": "5.3.1",
57
58
  "@luvio/service-cache-inclusion-policy": "5.3.1",
@@ -63,15 +64,15 @@
63
64
  "@luvio/service-subscription": "5.3.1",
64
65
  "@luvio/service-type-registry": "5.3.1",
65
66
  "@luvio/utils": "5.3.1",
66
- "@salesforce/lds-adapters-uiapi-lex": "^1.303.0"
67
+ "@salesforce/lds-adapters-uiapi-lex": "^1.304.0"
67
68
  },
68
69
  "luvioBundlesize": [
69
70
  {
70
71
  "path": "./dist/ldsEngineCreator.js",
71
72
  "maxSize": {
72
- "none": "151 kB",
73
- "min": "62 kB",
74
- "compressed": "28 kB"
73
+ "none": "165 kB",
74
+ "min": "68 kB",
75
+ "compressed": "30 kB"
75
76
  }
76
77
  }
77
78
  ],
@@ -1,13 +0,0 @@
1
- declare const create: {
2
- (o: object | null): any;
3
- (o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any;
4
- }, keys: {
5
- (o: object): string[];
6
- (o: {}): string[];
7
- };
8
- declare const isArray: (arg: any) => arg is any[];
9
- declare const stringify: {
10
- (value: any, replacer?: ((this: any, key: string, value: any) => any) | undefined, space?: string | number | undefined): string;
11
- (value: any, replacer?: (string | number)[] | null | undefined, space?: string | number | undefined): string;
12
- };
13
- export { create as ObjectCreate, keys as ObjectKeys, isArray as ArrayIsArray, stringify as JSONStringify, };