@salesforce/lds-runtime-mobile 1.163.0 → 1.163.2

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 (3) hide show
  1. package/dist/main.js +137 -103
  2. package/package.json +1 -1
  3. package/sfdc/main.js +137 -103
package/dist/main.js CHANGED
@@ -19,6 +19,7 @@ import { parseAndVisit, Kind, visit, execute, buildSchema, isObjectType, default
19
19
  import { getRecordId18, keyBuilderQuickActionExecutionRepresentation, ingestQuickActionExecutionRepresentation, keyBuilderContentDocumentCompositeRepresentation, getResponseCacheKeysContentDocumentCompositeRepresentation, keyBuilderFromTypeContentDocumentCompositeRepresentation, ingestContentDocumentCompositeRepresentation, keyBuilderRecord, getTypeCacheKeysRecord, keyBuilderFromTypeRecordRepresentation, ingestRecord, RecordRepresentationRepresentationType, ObjectInfoRepresentationType, getRecordAdapterFactory, getObjectInfoAdapterFactory, getObjectInfosAdapterFactory, UiApiNamespace, RecordRepresentationType, RecordRepresentationTTL, RecordRepresentationVersion } from '@salesforce/lds-adapters-uiapi';
20
20
  import caseSensitiveUserId from '@salesforce/user/Id';
21
21
  import { idleDetector, getInstrumentation } from 'o11y/client';
22
+ import ldsUseShortUrlGate from '@salesforce/gate/lds.useShortUrl';
22
23
  import { instrument as instrument$1 } from '@salesforce/lds-bindings';
23
24
  import LOCALE from '@salesforce/i18n/locale';
24
25
  import CURRENCY from '@salesforce/i18n/currency';
@@ -10795,6 +10796,14 @@ function getRecordKeyFromRecordRequest(luvio, resourceRequest) {
10795
10796
  function getRecordKeyForId(luvio, recordId) {
10796
10797
  return keyBuilderRecord(luvio, { recordId });
10797
10798
  }
10799
+ /**
10800
+ * Drafts are stored with denormalized fields and normalized field links. This method
10801
+ * filters out the field links and returns a flattened record representation.
10802
+ *
10803
+ * Note that reference field links get re-applied during draft record ingestion
10804
+ * @param record draft record representation
10805
+ * @returns flattened record representation
10806
+ */
10798
10807
  function filterOutReferenceFieldsAndLinks(record) {
10799
10808
  const filteredFields = {};
10800
10809
  const fieldNames = keys$2(record.fields);
@@ -10813,32 +10822,6 @@ function filterOutReferenceFieldsAndLinks(record) {
10813
10822
  delete filteredRecords.links;
10814
10823
  return filteredRecords;
10815
10824
  }
10816
- async function resolveReferencesOneLevelDeep(record, getRecordFromKey) {
10817
- const fieldNames = keys$2(record.fields);
10818
- const resolvedFields = {};
10819
- for (const fieldName of fieldNames) {
10820
- const field = record.fields[fieldName];
10821
- if (isFieldLink(field)) {
10822
- const denormalizedRecord = await getRecordFromKey(field.value.__ref);
10823
- if (denormalizedRecord !== undefined) {
10824
- resolvedFields[fieldName] = {
10825
- value: filterOutReferenceFieldsAndLinks(denormalizedRecord),
10826
- displayValue: null,
10827
- };
10828
- }
10829
- else {
10830
- resolvedFields[fieldName] = {
10831
- value: null,
10832
- displayValue: null,
10833
- };
10834
- }
10835
- }
10836
- else {
10837
- resolvedFields[fieldName] = field;
10838
- }
10839
- }
10840
- return { ...record, fields: resolvedFields };
10841
- }
10842
10825
 
10843
10826
  /**
10844
10827
  * Checks if a resource request is a GET method on the record endpoint
@@ -11135,11 +11118,15 @@ const DEFAULT_FIELD_RECORD_TYPE_ID = 'RecordTypeId';
11135
11118
  */
11136
11119
  function replayDraftsOnRecord(record, draftMetadata) {
11137
11120
  let objectInfo;
11121
+ let luvio;
11138
11122
  if (record && draftMetadata) {
11139
11123
  objectInfo = draftMetadata.objectInfos.get(record.apiName);
11140
11124
  }
11125
+ if (draftMetadata) {
11126
+ luvio = draftMetadata.luvio;
11127
+ }
11141
11128
  // remove drafts before reapply
11142
- const baseRecord = record === undefined ? undefined : removeDrafts(record, objectInfo);
11129
+ const baseRecord = record === undefined ? undefined : removeDrafts(record, luvio, objectInfo);
11143
11130
  // record is a draft create
11144
11131
  if (baseRecord === undefined) {
11145
11132
  if (draftMetadata === undefined) {
@@ -11262,7 +11249,7 @@ function recursivelyApplyDraftsToRecord(record, draftMetadata, recordOperations)
11262
11249
  * @param record record with drafts applied
11263
11250
  * @returns
11264
11251
  */
11265
- function removeDrafts(record, objectInfo) {
11252
+ function removeDrafts(record, luvio, objectInfo) {
11266
11253
  const { drafts, fields } = record;
11267
11254
  if (drafts === undefined) {
11268
11255
  return record;
@@ -11278,6 +11265,12 @@ function removeDrafts(record, objectInfo) {
11278
11265
  const originalField = drafts.serverValues[fieldName];
11279
11266
  if (originalField !== undefined) {
11280
11267
  updatedFields[fieldName] = originalField;
11268
+ if (objectInfo && luvio) {
11269
+ const reference = getReferenceInfoForKey(fieldName, originalField, luvio, objectInfo);
11270
+ if (reference) {
11271
+ updatedFields[reference.referenceFieldName] = reference.field;
11272
+ }
11273
+ }
11281
11274
  // restore the record type id on the root of the record
11282
11275
  if (fieldName === DEFAULT_FIELD_RECORD_TYPE_ID) {
11283
11276
  const originalRecordTypeId = originalField.value;
@@ -11315,7 +11308,6 @@ function removeDrafts(record, objectInfo) {
11315
11308
  * @param fields List of draft record fields
11316
11309
  */
11317
11310
  function buildRecordFieldValueRepresentationsFromDraftFields(luvio, apiName, fields, objectInfos, referencedRecords, formatDisplayValue) {
11318
- var _a;
11319
11311
  const fieldNames = keys$2(fields);
11320
11312
  const recordFields = {};
11321
11313
  const objectInfo = objectInfos.get(apiName);
@@ -11329,7 +11321,7 @@ function buildRecordFieldValueRepresentationsFromDraftFields(luvio, apiName, fie
11329
11321
  if (objectInfo !== undefined) {
11330
11322
  const fieldInfo = objectInfo.fields[fieldName];
11331
11323
  if (fieldInfo !== undefined) {
11332
- const { dataType, relationshipName, referenceToInfos } = fieldInfo;
11324
+ const { dataType } = fieldInfo;
11333
11325
  recordFields[fieldName].displayValue = formatDisplayValue(draftField, dataType);
11334
11326
  if (dataType === 'DateTime' &&
11335
11327
  draftField !== null &&
@@ -11341,46 +11333,6 @@ function buildRecordFieldValueRepresentationsFromDraftFields(luvio, apiName, fie
11341
11333
  throw Error('date field value not valid');
11342
11334
  }
11343
11335
  }
11344
- if (dataType === 'Reference' && relationshipName !== null && draftField !== null) {
11345
- if (typeof draftField !== 'string') {
11346
- throw Error('reference field value is not a string');
11347
- }
11348
- const key = getRecordKeyForId(luvio, draftField);
11349
- const referencedRecord = referencedRecords.get(key);
11350
- if (referencedRecord) {
11351
- recordFields[relationshipName] = {
11352
- displayValue: null,
11353
- value: createLink(key),
11354
- };
11355
- }
11356
- else {
11357
- recordFields[relationshipName] = {
11358
- displayValue: null,
11359
- value: null,
11360
- };
11361
- }
11362
- // for custom objects, we select the 'Name' field
11363
- // otherwise we check the object info for name fields.
11364
- //if there are multiple we select 'Name' if it exists, otherwise the first one
11365
- if (referencedRecord !== undefined && referenceToInfos.length > 0) {
11366
- let nameField;
11367
- const referenceToInfo = referenceToInfos[0];
11368
- const nameFields = referenceToInfo.nameFields;
11369
- if (nameFields.length !== 0) {
11370
- nameField = nameFields.find((x) => x === 'Name');
11371
- if (nameField === undefined) {
11372
- nameField = nameFields[0];
11373
- }
11374
- }
11375
- if (nameField !== undefined) {
11376
- const nameFieldRef = referencedRecord.fields[nameField];
11377
- if (nameFieldRef) {
11378
- recordFields[relationshipName].displayValue =
11379
- (_a = nameFieldRef.displayValue) !== null && _a !== void 0 ? _a : nameFieldRef.value;
11380
- }
11381
- }
11382
- }
11383
- }
11384
11336
  }
11385
11337
  }
11386
11338
  }
@@ -11454,9 +11406,78 @@ function buildSyntheticRecordRepresentation(luvio, createOperation, userId, obje
11454
11406
  },
11455
11407
  };
11456
11408
  }
11409
+ function applyReferenceLinksToDraft(record, draftMetadata) {
11410
+ var _a;
11411
+ const { objectInfos, referencedRecords, luvio } = draftMetadata;
11412
+ const objectInfo = objectInfos.get(record.apiName);
11413
+ if (objectInfo === undefined) {
11414
+ return record;
11415
+ }
11416
+ let fieldNames = Object.keys(record.fields);
11417
+ const recordFields = { ...record.fields };
11418
+ for (const draftField of fieldNames) {
11419
+ const fieldInfo = objectInfo.fields[draftField];
11420
+ if (fieldInfo === undefined) {
11421
+ continue;
11422
+ }
11423
+ const { dataType, relationshipName, referenceToInfos } = fieldInfo;
11424
+ const draftFieldValue = record.fields[draftField].value;
11425
+ if (dataType === 'Reference' && relationshipName !== null && draftFieldValue !== null) {
11426
+ if (typeof draftFieldValue !== 'string') {
11427
+ throw Error('reference field value is not a string');
11428
+ }
11429
+ const key = getRecordKeyForId(luvio, draftFieldValue);
11430
+ const referencedRecord = referencedRecords.get(key);
11431
+ recordFields[relationshipName] = {
11432
+ displayValue: null,
11433
+ value: createLink(key),
11434
+ };
11435
+ // for custom objects, we select the 'Name' field
11436
+ // otherwise we check the object info for name fields.
11437
+ //if there are multiple we select 'Name' if it exists, otherwise the first one
11438
+ if (referencedRecord !== undefined && referenceToInfos.length > 0) {
11439
+ let nameField;
11440
+ const referenceToInfo = referenceToInfos[0];
11441
+ const nameFields = referenceToInfo.nameFields;
11442
+ if (nameFields.length !== 0) {
11443
+ nameField = nameFields.find((x) => x === 'Name');
11444
+ if (nameField === undefined) {
11445
+ nameField = nameFields[0];
11446
+ }
11447
+ }
11448
+ if (nameField !== undefined) {
11449
+ const nameFieldRef = referencedRecord.fields[nameField];
11450
+ if (nameFieldRef) {
11451
+ recordFields[relationshipName].displayValue =
11452
+ (_a = nameFieldRef.displayValue) !== null && _a !== void 0 ? _a : nameFieldRef.value;
11453
+ }
11454
+ }
11455
+ }
11456
+ }
11457
+ }
11458
+ return { ...record, fields: recordFields };
11459
+ }
11457
11460
  function createLink(key) {
11458
11461
  return { __ref: key };
11459
11462
  }
11463
+ function getReferenceInfoForKey(fieldName, field, luvio, objectInfo) {
11464
+ const { dataType, relationshipName } = objectInfo.fields[fieldName];
11465
+ const draftFieldValue = field.value;
11466
+ if (dataType === 'Reference' && relationshipName !== null && draftFieldValue !== null) {
11467
+ if (typeof draftFieldValue !== 'string') {
11468
+ throw Error('reference field value is not a string');
11469
+ }
11470
+ const key = getRecordKeyForId(luvio, draftFieldValue);
11471
+ return {
11472
+ referenceFieldName: relationshipName,
11473
+ field: {
11474
+ displayValue: null,
11475
+ value: createLink(key),
11476
+ },
11477
+ };
11478
+ }
11479
+ return undefined;
11480
+ }
11460
11481
 
11461
11482
  async function getAdapterData(adapter, config) {
11462
11483
  const snapshot = await adapter(config);
@@ -11648,8 +11669,7 @@ class UiApiActionHandler extends AbstractResourceRequestActionHandler {
11648
11669
  *
11649
11670
  * @param action The draft action related to this record
11650
11671
  * @param _queue The draft queue
11651
- * @returns The record with the updated draft queue applied. This record is resolved with references one-level
11652
- * deep to ensure that reference links are properly established during ingestion to it
11672
+ * @returns The record with the updated draft queue applied. References are not included and must be applied at ingest.
11653
11673
  *
11654
11674
  * or
11655
11675
  *
@@ -11673,7 +11693,7 @@ class UiApiActionHandler extends AbstractResourceRequestActionHandler {
11673
11693
  if (recordWithDrafts === undefined) {
11674
11694
  return undefined;
11675
11695
  }
11676
- return resolveReferencesOneLevelDeep(recordWithDrafts, this.durableStore.getDenormalizedRecord.bind(this.durableStore));
11696
+ return filterOutReferenceFieldsAndLinks(recordWithDrafts);
11677
11697
  }
11678
11698
  const record = await this.durableStore.getDenormalizedRecord(key);
11679
11699
  if (record === undefined) {
@@ -11684,7 +11704,7 @@ class UiApiActionHandler extends AbstractResourceRequestActionHandler {
11684
11704
  if (recordWithDrafts === undefined) {
11685
11705
  return recordWithDrafts;
11686
11706
  }
11687
- return resolveReferencesOneLevelDeep(recordWithDrafts, this.durableStore.getDenormalizedRecord.bind(this.durableStore));
11707
+ return filterOutReferenceFieldsAndLinks(recordWithDrafts);
11688
11708
  }
11689
11709
  applyDraftsToIncomingData(key, data, draftMetadata, publishData) {
11690
11710
  if (isField(key)) {
@@ -11711,19 +11731,26 @@ class UiApiActionHandler extends AbstractResourceRequestActionHandler {
11711
11731
  }
11712
11732
  }
11713
11733
  const recordWithDrafts = replayDraftsOnRecord(partialRecord, draftMetadata);
11734
+ const recordWithSpanningRefLinks = applyReferenceLinksToDraft(recordWithDrafts, draftMetadata);
11714
11735
  // publish the normalized fields
11715
11736
  const normalizedRecord = {
11716
- ...recordWithDrafts,
11737
+ ...recordWithSpanningRefLinks,
11717
11738
  ...data,
11718
11739
  fields: { ...data.fields },
11719
11740
  };
11720
- for (const fieldName of recordFieldNames) {
11741
+ for (const fieldName of keys$2(recordWithSpanningRefLinks.fields)) {
11721
11742
  const fieldKey = buildRecordFieldStoreKey(key, fieldName);
11722
11743
  if (this.collectedFields[fieldKey] !== undefined) {
11723
- const fieldData = recordWithDrafts.fields[fieldName];
11744
+ const fieldData = recordWithSpanningRefLinks.fields[fieldName];
11724
11745
  normalizedRecord.fields[fieldName] = { __ref: fieldKey };
11725
11746
  publishData(fieldKey, fieldData);
11726
11747
  }
11748
+ else if (recordWithSpanningRefLinks.fields[fieldName] &&
11749
+ recordWithSpanningRefLinks.fields[fieldName].value &&
11750
+ recordWithSpanningRefLinks.fields[fieldName].value.__ref !== undefined) {
11751
+ normalizedRecord.fields[fieldName] = { __ref: fieldKey };
11752
+ publishData(fieldKey, recordWithSpanningRefLinks.fields[fieldName]);
11753
+ }
11727
11754
  }
11728
11755
  // publish the normalized record
11729
11756
  publishData(key, normalizedRecord);
@@ -12901,27 +12928,10 @@ class ContentDocumentCompositeRepresentationActionHandler extends AbstractResour
12901
12928
  if (contentVersion === undefined) {
12902
12929
  return undefined;
12903
12930
  }
12904
- // this lambda can be shared across the calls to resolveReferencesOneLevelDeep
12905
- const luvio = this.getLuvio();
12906
- const contentDocumentKey = getRecordKeyForId(luvio, contentDocumentId);
12907
- const contentDocumentLinkKey = getRecordKeyForId(luvio, contentDocumentLinkId);
12908
- const contentVersionKey = getRecordKeyForId(luvio, contentVersionId);
12909
- const getRecordFromKey = async (key) => {
12910
- if (key === contentDocumentKey) {
12911
- return contentDocRecord;
12912
- }
12913
- if (key === contentDocumentLinkKey) {
12914
- return contentDocLink;
12915
- }
12916
- if (key === contentVersionKey) {
12917
- return contentVersion;
12918
- }
12919
- return this.durableStore.getDenormalizedRecord(key);
12920
- };
12921
12931
  // finally we resolve all references for each record
12922
- const contentDocResolved = await resolveReferencesOneLevelDeep(contentDocRecord, getRecordFromKey);
12923
- const contentDocLinkResolved = await resolveReferencesOneLevelDeep(contentDocLink, getRecordFromKey);
12924
- const contentVersionResolved = await resolveReferencesOneLevelDeep(contentVersion, getRecordFromKey);
12932
+ const contentDocResolved = await filterOutReferenceFieldsAndLinks(contentDocRecord);
12933
+ const contentDocLinkResolved = await filterOutReferenceFieldsAndLinks(contentDocLink);
12934
+ const contentVersionResolved = await filterOutReferenceFieldsAndLinks(contentVersion);
12925
12935
  return {
12926
12936
  contentDocument: contentDocResolved,
12927
12937
  contentDocumentLinks: [contentDocLinkResolved],
@@ -13701,6 +13711,10 @@ class ScopedFieldsCollection {
13701
13711
  }
13702
13712
 
13703
13713
  const MAX_STRING_LENGTH_PER_CHUNK = 10000;
13714
+ //Salesforce/Akamai cdn uri max size is 8898 bytes, short than normal. Per
13715
+ //https://help.salesforce.com/s/articleView?id=sf.community_builder_cdn_considerations.htm&type=5
13716
+ //Due to we don't know the domain ResourceRequest, here we give 8000
13717
+ const MAX_URL_LENGTH = 8000;
13704
13718
  const PARSE_ERROR = 'PARSE_AGGREGATE_UI_RESPONSE_ERROR';
13705
13719
  function isErrorResponse(response) {
13706
13720
  return response.httpStatusCode >= 400;
@@ -13779,8 +13793,8 @@ function buildAggregateUiUrl(params, resourceRequest) {
13779
13793
  }
13780
13794
  return `${resourceRequest.baseUri}${resourceRequest.basePath}?${join$1.call(queryString, '&')}`;
13781
13795
  }
13782
- function shouldUseAggregateUiForFields(fieldsArray, optionalFieldsArray) {
13783
- return fieldsArray.length + optionalFieldsArray.length >= MAX_STRING_LENGTH_PER_CHUNK;
13796
+ function shouldUseAggregateUiForFields(fieldsArray, optionalFieldsArray, maxLengthPerChunk) {
13797
+ return fieldsArray.length + optionalFieldsArray.length >= maxLengthPerChunk;
13784
13798
  }
13785
13799
  function isSpanningRecord(fieldValue) {
13786
13800
  return fieldValue !== null && typeof fieldValue === 'object';
@@ -13843,14 +13857,15 @@ function createAggregateBatchRequestInfo(resourceRequest, endpoint) {
13843
13857
  if (fieldsArray.length === 0 && optionalFieldsArray.length === 0) {
13844
13858
  return undefined;
13845
13859
  }
13860
+ const allowedMaxStringLengthPerChunk = getMaxLengthPerChunkAllowed(resourceRequest);
13846
13861
  const fieldsString = fieldsArray.join(',');
13847
13862
  const optionalFieldsString = optionalFieldsArray.join(',');
13848
- const shouldUseAggregate = shouldUseAggregateUiForFields(fieldsString, optionalFieldsString);
13863
+ const shouldUseAggregate = shouldUseAggregateUiForFields(fieldsString, optionalFieldsString, allowedMaxStringLengthPerChunk);
13849
13864
  if (!shouldUseAggregate) {
13850
13865
  return undefined;
13851
13866
  }
13852
- const fieldCollection = ScopedFieldsCollection.fromQueryParameterValue(fieldsString).split(MAX_STRING_LENGTH_PER_CHUNK);
13853
- const optionalFieldCollection = ScopedFieldsCollection.fromQueryParameterValue(optionalFieldsString).split(MAX_STRING_LENGTH_PER_CHUNK);
13867
+ const fieldCollection = ScopedFieldsCollection.fromQueryParameterValue(fieldsString).split(allowedMaxStringLengthPerChunk);
13868
+ const optionalFieldCollection = ScopedFieldsCollection.fromQueryParameterValue(optionalFieldsString).split(allowedMaxStringLengthPerChunk);
13854
13869
  return {
13855
13870
  fieldCollection,
13856
13871
  optionalFieldCollection,
@@ -13923,6 +13938,25 @@ function isGetRequestForEndpoint(endpoint, request) {
13923
13938
  function arrayOrEmpty(array) {
13924
13939
  return array !== undefined && isArray(array) ? array : [];
13925
13940
  }
13941
+ /**
13942
+ * Calculate the max lengh per chunk.
13943
+ * If useShortUrlGate is open, allow max chunk size is MAX_URL_LENGTH - the url without fields and optional fields in url.
13944
+ * Otherwise MAX_STRING_LENGTH_PER_CHUNK
13945
+ * @param resourceRequest
13946
+ * @returns
13947
+ */
13948
+ function getMaxLengthPerChunkAllowed(request) {
13949
+ if (!ldsUseShortUrlGate.isOpen({ fallback: false })) {
13950
+ return MAX_STRING_LENGTH_PER_CHUNK;
13951
+ }
13952
+ // Too much work to get exact length of the final url, so use stringified json to get the rough length.
13953
+ const roughUrlLengthWithoutFieldsAndOptionFields = request.basePath.length +
13954
+ request.baseUri.length +
13955
+ (request.urlParams ? stringify$1(request.urlParams).length : 0) +
13956
+ stringify$1({ ...request.queryParams, fields: {}, optionalFields: {} }).length;
13957
+ // MAX_URL_LENGTH - full lenght without fields, optionalFields
13958
+ return MAX_URL_LENGTH - roughUrlLengthWithoutFieldsAndOptionFields;
13959
+ }
13926
13960
 
13927
13961
  const RECORD_ENDPOINT_REGEX = /^\/ui-api\/records\/?(([a-zA-Z0-9]+))?$/;
13928
13962
  const referenceId$3 = 'LDS_Records_AggregateUi';
@@ -16134,4 +16168,4 @@ register({
16134
16168
  });
16135
16169
 
16136
16170
  export { getRuntime, registerReportObserver, reportGraphqlQueryParseError };
16137
- // version: 1.163.0-02054d65d
16171
+ // version: 1.163.2-1950176a9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/lds-runtime-mobile",
3
- "version": "1.163.0",
3
+ "version": "1.163.2",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "LDS runtime for mobile/hybrid environments.",
6
6
  "main": "dist/main.js",
package/sfdc/main.js CHANGED
@@ -19,6 +19,7 @@ import { parseAndVisit, Kind, visit, execute, buildSchema, isObjectType, default
19
19
  import { getRecordId18, keyBuilderQuickActionExecutionRepresentation, ingestQuickActionExecutionRepresentation, keyBuilderContentDocumentCompositeRepresentation, getResponseCacheKeysContentDocumentCompositeRepresentation, keyBuilderFromTypeContentDocumentCompositeRepresentation, ingestContentDocumentCompositeRepresentation, keyBuilderRecord, getTypeCacheKeysRecord, keyBuilderFromTypeRecordRepresentation, ingestRecord, RecordRepresentationRepresentationType, ObjectInfoRepresentationType, getRecordAdapterFactory, getObjectInfoAdapterFactory, getObjectInfosAdapterFactory, UiApiNamespace, RecordRepresentationType, RecordRepresentationTTL, RecordRepresentationVersion } from 'force/ldsAdaptersUiapi';
20
20
  import caseSensitiveUserId from '@salesforce/user/Id';
21
21
  import { idleDetector, getInstrumentation } from 'o11y/client';
22
+ import ldsUseShortUrlGate from '@salesforce/gate/lds.useShortUrl';
22
23
  import { instrument as instrument$1 } from 'force/ldsBindings';
23
24
  import LOCALE from '@salesforce/i18n/locale';
24
25
  import CURRENCY from '@salesforce/i18n/currency';
@@ -10795,6 +10796,14 @@ function getRecordKeyFromRecordRequest(luvio, resourceRequest) {
10795
10796
  function getRecordKeyForId(luvio, recordId) {
10796
10797
  return keyBuilderRecord(luvio, { recordId });
10797
10798
  }
10799
+ /**
10800
+ * Drafts are stored with denormalized fields and normalized field links. This method
10801
+ * filters out the field links and returns a flattened record representation.
10802
+ *
10803
+ * Note that reference field links get re-applied during draft record ingestion
10804
+ * @param record draft record representation
10805
+ * @returns flattened record representation
10806
+ */
10798
10807
  function filterOutReferenceFieldsAndLinks(record) {
10799
10808
  const filteredFields = {};
10800
10809
  const fieldNames = keys$2(record.fields);
@@ -10813,32 +10822,6 @@ function filterOutReferenceFieldsAndLinks(record) {
10813
10822
  delete filteredRecords.links;
10814
10823
  return filteredRecords;
10815
10824
  }
10816
- async function resolveReferencesOneLevelDeep(record, getRecordFromKey) {
10817
- const fieldNames = keys$2(record.fields);
10818
- const resolvedFields = {};
10819
- for (const fieldName of fieldNames) {
10820
- const field = record.fields[fieldName];
10821
- if (isFieldLink(field)) {
10822
- const denormalizedRecord = await getRecordFromKey(field.value.__ref);
10823
- if (denormalizedRecord !== undefined) {
10824
- resolvedFields[fieldName] = {
10825
- value: filterOutReferenceFieldsAndLinks(denormalizedRecord),
10826
- displayValue: null,
10827
- };
10828
- }
10829
- else {
10830
- resolvedFields[fieldName] = {
10831
- value: null,
10832
- displayValue: null,
10833
- };
10834
- }
10835
- }
10836
- else {
10837
- resolvedFields[fieldName] = field;
10838
- }
10839
- }
10840
- return { ...record, fields: resolvedFields };
10841
- }
10842
10825
 
10843
10826
  /**
10844
10827
  * Checks if a resource request is a GET method on the record endpoint
@@ -11135,11 +11118,15 @@ const DEFAULT_FIELD_RECORD_TYPE_ID = 'RecordTypeId';
11135
11118
  */
11136
11119
  function replayDraftsOnRecord(record, draftMetadata) {
11137
11120
  let objectInfo;
11121
+ let luvio;
11138
11122
  if (record && draftMetadata) {
11139
11123
  objectInfo = draftMetadata.objectInfos.get(record.apiName);
11140
11124
  }
11125
+ if (draftMetadata) {
11126
+ luvio = draftMetadata.luvio;
11127
+ }
11141
11128
  // remove drafts before reapply
11142
- const baseRecord = record === undefined ? undefined : removeDrafts(record, objectInfo);
11129
+ const baseRecord = record === undefined ? undefined : removeDrafts(record, luvio, objectInfo);
11143
11130
  // record is a draft create
11144
11131
  if (baseRecord === undefined) {
11145
11132
  if (draftMetadata === undefined) {
@@ -11262,7 +11249,7 @@ function recursivelyApplyDraftsToRecord(record, draftMetadata, recordOperations)
11262
11249
  * @param record record with drafts applied
11263
11250
  * @returns
11264
11251
  */
11265
- function removeDrafts(record, objectInfo) {
11252
+ function removeDrafts(record, luvio, objectInfo) {
11266
11253
  const { drafts, fields } = record;
11267
11254
  if (drafts === undefined) {
11268
11255
  return record;
@@ -11278,6 +11265,12 @@ function removeDrafts(record, objectInfo) {
11278
11265
  const originalField = drafts.serverValues[fieldName];
11279
11266
  if (originalField !== undefined) {
11280
11267
  updatedFields[fieldName] = originalField;
11268
+ if (objectInfo && luvio) {
11269
+ const reference = getReferenceInfoForKey(fieldName, originalField, luvio, objectInfo);
11270
+ if (reference) {
11271
+ updatedFields[reference.referenceFieldName] = reference.field;
11272
+ }
11273
+ }
11281
11274
  // restore the record type id on the root of the record
11282
11275
  if (fieldName === DEFAULT_FIELD_RECORD_TYPE_ID) {
11283
11276
  const originalRecordTypeId = originalField.value;
@@ -11315,7 +11308,6 @@ function removeDrafts(record, objectInfo) {
11315
11308
  * @param fields List of draft record fields
11316
11309
  */
11317
11310
  function buildRecordFieldValueRepresentationsFromDraftFields(luvio, apiName, fields, objectInfos, referencedRecords, formatDisplayValue) {
11318
- var _a;
11319
11311
  const fieldNames = keys$2(fields);
11320
11312
  const recordFields = {};
11321
11313
  const objectInfo = objectInfos.get(apiName);
@@ -11329,7 +11321,7 @@ function buildRecordFieldValueRepresentationsFromDraftFields(luvio, apiName, fie
11329
11321
  if (objectInfo !== undefined) {
11330
11322
  const fieldInfo = objectInfo.fields[fieldName];
11331
11323
  if (fieldInfo !== undefined) {
11332
- const { dataType, relationshipName, referenceToInfos } = fieldInfo;
11324
+ const { dataType } = fieldInfo;
11333
11325
  recordFields[fieldName].displayValue = formatDisplayValue(draftField, dataType);
11334
11326
  if (dataType === 'DateTime' &&
11335
11327
  draftField !== null &&
@@ -11341,46 +11333,6 @@ function buildRecordFieldValueRepresentationsFromDraftFields(luvio, apiName, fie
11341
11333
  throw Error('date field value not valid');
11342
11334
  }
11343
11335
  }
11344
- if (dataType === 'Reference' && relationshipName !== null && draftField !== null) {
11345
- if (typeof draftField !== 'string') {
11346
- throw Error('reference field value is not a string');
11347
- }
11348
- const key = getRecordKeyForId(luvio, draftField);
11349
- const referencedRecord = referencedRecords.get(key);
11350
- if (referencedRecord) {
11351
- recordFields[relationshipName] = {
11352
- displayValue: null,
11353
- value: createLink(key),
11354
- };
11355
- }
11356
- else {
11357
- recordFields[relationshipName] = {
11358
- displayValue: null,
11359
- value: null,
11360
- };
11361
- }
11362
- // for custom objects, we select the 'Name' field
11363
- // otherwise we check the object info for name fields.
11364
- //if there are multiple we select 'Name' if it exists, otherwise the first one
11365
- if (referencedRecord !== undefined && referenceToInfos.length > 0) {
11366
- let nameField;
11367
- const referenceToInfo = referenceToInfos[0];
11368
- const nameFields = referenceToInfo.nameFields;
11369
- if (nameFields.length !== 0) {
11370
- nameField = nameFields.find((x) => x === 'Name');
11371
- if (nameField === undefined) {
11372
- nameField = nameFields[0];
11373
- }
11374
- }
11375
- if (nameField !== undefined) {
11376
- const nameFieldRef = referencedRecord.fields[nameField];
11377
- if (nameFieldRef) {
11378
- recordFields[relationshipName].displayValue =
11379
- (_a = nameFieldRef.displayValue) !== null && _a !== void 0 ? _a : nameFieldRef.value;
11380
- }
11381
- }
11382
- }
11383
- }
11384
11336
  }
11385
11337
  }
11386
11338
  }
@@ -11454,9 +11406,78 @@ function buildSyntheticRecordRepresentation(luvio, createOperation, userId, obje
11454
11406
  },
11455
11407
  };
11456
11408
  }
11409
+ function applyReferenceLinksToDraft(record, draftMetadata) {
11410
+ var _a;
11411
+ const { objectInfos, referencedRecords, luvio } = draftMetadata;
11412
+ const objectInfo = objectInfos.get(record.apiName);
11413
+ if (objectInfo === undefined) {
11414
+ return record;
11415
+ }
11416
+ let fieldNames = Object.keys(record.fields);
11417
+ const recordFields = { ...record.fields };
11418
+ for (const draftField of fieldNames) {
11419
+ const fieldInfo = objectInfo.fields[draftField];
11420
+ if (fieldInfo === undefined) {
11421
+ continue;
11422
+ }
11423
+ const { dataType, relationshipName, referenceToInfos } = fieldInfo;
11424
+ const draftFieldValue = record.fields[draftField].value;
11425
+ if (dataType === 'Reference' && relationshipName !== null && draftFieldValue !== null) {
11426
+ if (typeof draftFieldValue !== 'string') {
11427
+ throw Error('reference field value is not a string');
11428
+ }
11429
+ const key = getRecordKeyForId(luvio, draftFieldValue);
11430
+ const referencedRecord = referencedRecords.get(key);
11431
+ recordFields[relationshipName] = {
11432
+ displayValue: null,
11433
+ value: createLink(key),
11434
+ };
11435
+ // for custom objects, we select the 'Name' field
11436
+ // otherwise we check the object info for name fields.
11437
+ //if there are multiple we select 'Name' if it exists, otherwise the first one
11438
+ if (referencedRecord !== undefined && referenceToInfos.length > 0) {
11439
+ let nameField;
11440
+ const referenceToInfo = referenceToInfos[0];
11441
+ const nameFields = referenceToInfo.nameFields;
11442
+ if (nameFields.length !== 0) {
11443
+ nameField = nameFields.find((x) => x === 'Name');
11444
+ if (nameField === undefined) {
11445
+ nameField = nameFields[0];
11446
+ }
11447
+ }
11448
+ if (nameField !== undefined) {
11449
+ const nameFieldRef = referencedRecord.fields[nameField];
11450
+ if (nameFieldRef) {
11451
+ recordFields[relationshipName].displayValue =
11452
+ (_a = nameFieldRef.displayValue) !== null && _a !== void 0 ? _a : nameFieldRef.value;
11453
+ }
11454
+ }
11455
+ }
11456
+ }
11457
+ }
11458
+ return { ...record, fields: recordFields };
11459
+ }
11457
11460
  function createLink(key) {
11458
11461
  return { __ref: key };
11459
11462
  }
11463
+ function getReferenceInfoForKey(fieldName, field, luvio, objectInfo) {
11464
+ const { dataType, relationshipName } = objectInfo.fields[fieldName];
11465
+ const draftFieldValue = field.value;
11466
+ if (dataType === 'Reference' && relationshipName !== null && draftFieldValue !== null) {
11467
+ if (typeof draftFieldValue !== 'string') {
11468
+ throw Error('reference field value is not a string');
11469
+ }
11470
+ const key = getRecordKeyForId(luvio, draftFieldValue);
11471
+ return {
11472
+ referenceFieldName: relationshipName,
11473
+ field: {
11474
+ displayValue: null,
11475
+ value: createLink(key),
11476
+ },
11477
+ };
11478
+ }
11479
+ return undefined;
11480
+ }
11460
11481
 
11461
11482
  async function getAdapterData(adapter, config) {
11462
11483
  const snapshot = await adapter(config);
@@ -11648,8 +11669,7 @@ class UiApiActionHandler extends AbstractResourceRequestActionHandler {
11648
11669
  *
11649
11670
  * @param action The draft action related to this record
11650
11671
  * @param _queue The draft queue
11651
- * @returns The record with the updated draft queue applied. This record is resolved with references one-level
11652
- * deep to ensure that reference links are properly established during ingestion to it
11672
+ * @returns The record with the updated draft queue applied. References are not included and must be applied at ingest.
11653
11673
  *
11654
11674
  * or
11655
11675
  *
@@ -11673,7 +11693,7 @@ class UiApiActionHandler extends AbstractResourceRequestActionHandler {
11673
11693
  if (recordWithDrafts === undefined) {
11674
11694
  return undefined;
11675
11695
  }
11676
- return resolveReferencesOneLevelDeep(recordWithDrafts, this.durableStore.getDenormalizedRecord.bind(this.durableStore));
11696
+ return filterOutReferenceFieldsAndLinks(recordWithDrafts);
11677
11697
  }
11678
11698
  const record = await this.durableStore.getDenormalizedRecord(key);
11679
11699
  if (record === undefined) {
@@ -11684,7 +11704,7 @@ class UiApiActionHandler extends AbstractResourceRequestActionHandler {
11684
11704
  if (recordWithDrafts === undefined) {
11685
11705
  return recordWithDrafts;
11686
11706
  }
11687
- return resolveReferencesOneLevelDeep(recordWithDrafts, this.durableStore.getDenormalizedRecord.bind(this.durableStore));
11707
+ return filterOutReferenceFieldsAndLinks(recordWithDrafts);
11688
11708
  }
11689
11709
  applyDraftsToIncomingData(key, data, draftMetadata, publishData) {
11690
11710
  if (isField(key)) {
@@ -11711,19 +11731,26 @@ class UiApiActionHandler extends AbstractResourceRequestActionHandler {
11711
11731
  }
11712
11732
  }
11713
11733
  const recordWithDrafts = replayDraftsOnRecord(partialRecord, draftMetadata);
11734
+ const recordWithSpanningRefLinks = applyReferenceLinksToDraft(recordWithDrafts, draftMetadata);
11714
11735
  // publish the normalized fields
11715
11736
  const normalizedRecord = {
11716
- ...recordWithDrafts,
11737
+ ...recordWithSpanningRefLinks,
11717
11738
  ...data,
11718
11739
  fields: { ...data.fields },
11719
11740
  };
11720
- for (const fieldName of recordFieldNames) {
11741
+ for (const fieldName of keys$2(recordWithSpanningRefLinks.fields)) {
11721
11742
  const fieldKey = buildRecordFieldStoreKey(key, fieldName);
11722
11743
  if (this.collectedFields[fieldKey] !== undefined) {
11723
- const fieldData = recordWithDrafts.fields[fieldName];
11744
+ const fieldData = recordWithSpanningRefLinks.fields[fieldName];
11724
11745
  normalizedRecord.fields[fieldName] = { __ref: fieldKey };
11725
11746
  publishData(fieldKey, fieldData);
11726
11747
  }
11748
+ else if (recordWithSpanningRefLinks.fields[fieldName] &&
11749
+ recordWithSpanningRefLinks.fields[fieldName].value &&
11750
+ recordWithSpanningRefLinks.fields[fieldName].value.__ref !== undefined) {
11751
+ normalizedRecord.fields[fieldName] = { __ref: fieldKey };
11752
+ publishData(fieldKey, recordWithSpanningRefLinks.fields[fieldName]);
11753
+ }
11727
11754
  }
11728
11755
  // publish the normalized record
11729
11756
  publishData(key, normalizedRecord);
@@ -12901,27 +12928,10 @@ class ContentDocumentCompositeRepresentationActionHandler extends AbstractResour
12901
12928
  if (contentVersion === undefined) {
12902
12929
  return undefined;
12903
12930
  }
12904
- // this lambda can be shared across the calls to resolveReferencesOneLevelDeep
12905
- const luvio = this.getLuvio();
12906
- const contentDocumentKey = getRecordKeyForId(luvio, contentDocumentId);
12907
- const contentDocumentLinkKey = getRecordKeyForId(luvio, contentDocumentLinkId);
12908
- const contentVersionKey = getRecordKeyForId(luvio, contentVersionId);
12909
- const getRecordFromKey = async (key) => {
12910
- if (key === contentDocumentKey) {
12911
- return contentDocRecord;
12912
- }
12913
- if (key === contentDocumentLinkKey) {
12914
- return contentDocLink;
12915
- }
12916
- if (key === contentVersionKey) {
12917
- return contentVersion;
12918
- }
12919
- return this.durableStore.getDenormalizedRecord(key);
12920
- };
12921
12931
  // finally we resolve all references for each record
12922
- const contentDocResolved = await resolveReferencesOneLevelDeep(contentDocRecord, getRecordFromKey);
12923
- const contentDocLinkResolved = await resolveReferencesOneLevelDeep(contentDocLink, getRecordFromKey);
12924
- const contentVersionResolved = await resolveReferencesOneLevelDeep(contentVersion, getRecordFromKey);
12932
+ const contentDocResolved = await filterOutReferenceFieldsAndLinks(contentDocRecord);
12933
+ const contentDocLinkResolved = await filterOutReferenceFieldsAndLinks(contentDocLink);
12934
+ const contentVersionResolved = await filterOutReferenceFieldsAndLinks(contentVersion);
12925
12935
  return {
12926
12936
  contentDocument: contentDocResolved,
12927
12937
  contentDocumentLinks: [contentDocLinkResolved],
@@ -13701,6 +13711,10 @@ class ScopedFieldsCollection {
13701
13711
  }
13702
13712
 
13703
13713
  const MAX_STRING_LENGTH_PER_CHUNK = 10000;
13714
+ //Salesforce/Akamai cdn uri max size is 8898 bytes, short than normal. Per
13715
+ //https://help.salesforce.com/s/articleView?id=sf.community_builder_cdn_considerations.htm&type=5
13716
+ //Due to we don't know the domain ResourceRequest, here we give 8000
13717
+ const MAX_URL_LENGTH = 8000;
13704
13718
  const PARSE_ERROR = 'PARSE_AGGREGATE_UI_RESPONSE_ERROR';
13705
13719
  function isErrorResponse(response) {
13706
13720
  return response.httpStatusCode >= 400;
@@ -13779,8 +13793,8 @@ function buildAggregateUiUrl(params, resourceRequest) {
13779
13793
  }
13780
13794
  return `${resourceRequest.baseUri}${resourceRequest.basePath}?${join$1.call(queryString, '&')}`;
13781
13795
  }
13782
- function shouldUseAggregateUiForFields(fieldsArray, optionalFieldsArray) {
13783
- return fieldsArray.length + optionalFieldsArray.length >= MAX_STRING_LENGTH_PER_CHUNK;
13796
+ function shouldUseAggregateUiForFields(fieldsArray, optionalFieldsArray, maxLengthPerChunk) {
13797
+ return fieldsArray.length + optionalFieldsArray.length >= maxLengthPerChunk;
13784
13798
  }
13785
13799
  function isSpanningRecord(fieldValue) {
13786
13800
  return fieldValue !== null && typeof fieldValue === 'object';
@@ -13843,14 +13857,15 @@ function createAggregateBatchRequestInfo(resourceRequest, endpoint) {
13843
13857
  if (fieldsArray.length === 0 && optionalFieldsArray.length === 0) {
13844
13858
  return undefined;
13845
13859
  }
13860
+ const allowedMaxStringLengthPerChunk = getMaxLengthPerChunkAllowed(resourceRequest);
13846
13861
  const fieldsString = fieldsArray.join(',');
13847
13862
  const optionalFieldsString = optionalFieldsArray.join(',');
13848
- const shouldUseAggregate = shouldUseAggregateUiForFields(fieldsString, optionalFieldsString);
13863
+ const shouldUseAggregate = shouldUseAggregateUiForFields(fieldsString, optionalFieldsString, allowedMaxStringLengthPerChunk);
13849
13864
  if (!shouldUseAggregate) {
13850
13865
  return undefined;
13851
13866
  }
13852
- const fieldCollection = ScopedFieldsCollection.fromQueryParameterValue(fieldsString).split(MAX_STRING_LENGTH_PER_CHUNK);
13853
- const optionalFieldCollection = ScopedFieldsCollection.fromQueryParameterValue(optionalFieldsString).split(MAX_STRING_LENGTH_PER_CHUNK);
13867
+ const fieldCollection = ScopedFieldsCollection.fromQueryParameterValue(fieldsString).split(allowedMaxStringLengthPerChunk);
13868
+ const optionalFieldCollection = ScopedFieldsCollection.fromQueryParameterValue(optionalFieldsString).split(allowedMaxStringLengthPerChunk);
13854
13869
  return {
13855
13870
  fieldCollection,
13856
13871
  optionalFieldCollection,
@@ -13923,6 +13938,25 @@ function isGetRequestForEndpoint(endpoint, request) {
13923
13938
  function arrayOrEmpty(array) {
13924
13939
  return array !== undefined && isArray(array) ? array : [];
13925
13940
  }
13941
+ /**
13942
+ * Calculate the max lengh per chunk.
13943
+ * If useShortUrlGate is open, allow max chunk size is MAX_URL_LENGTH - the url without fields and optional fields in url.
13944
+ * Otherwise MAX_STRING_LENGTH_PER_CHUNK
13945
+ * @param resourceRequest
13946
+ * @returns
13947
+ */
13948
+ function getMaxLengthPerChunkAllowed(request) {
13949
+ if (!ldsUseShortUrlGate.isOpen({ fallback: false })) {
13950
+ return MAX_STRING_LENGTH_PER_CHUNK;
13951
+ }
13952
+ // Too much work to get exact length of the final url, so use stringified json to get the rough length.
13953
+ const roughUrlLengthWithoutFieldsAndOptionFields = request.basePath.length +
13954
+ request.baseUri.length +
13955
+ (request.urlParams ? stringify$1(request.urlParams).length : 0) +
13956
+ stringify$1({ ...request.queryParams, fields: {}, optionalFields: {} }).length;
13957
+ // MAX_URL_LENGTH - full lenght without fields, optionalFields
13958
+ return MAX_URL_LENGTH - roughUrlLengthWithoutFieldsAndOptionFields;
13959
+ }
13926
13960
 
13927
13961
  const RECORD_ENDPOINT_REGEX = /^\/ui-api\/records\/?(([a-zA-Z0-9]+))?$/;
13928
13962
  const referenceId$3 = 'LDS_Records_AggregateUi';
@@ -16134,4 +16168,4 @@ register({
16134
16168
  });
16135
16169
 
16136
16170
  export { getRuntime, registerReportObserver, reportGraphqlQueryParseError };
16137
- // version: 1.163.0-02054d65d
16171
+ // version: 1.163.2-1950176a9