@salesforce/lds-runtime-mobile 1.244.0 → 1.246.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -16,7 +16,7 @@ import { setupInstrumentation, instrumentAdapter as instrumentAdapter$1, instrum
16
16
  import { HttpStatusCode, StoreKeySet, serializeStructuredKey, StringKeyInMemoryStore, Reader, deepFreeze, emitAdapterEvent, createCustomAdapterEventEmitter, StoreKeyMap, isFileReference, Environment, Luvio, InMemoryStore } from '@luvio/engine';
17
17
  import excludeStaleRecordsGate from '@salesforce/gate/lds.graphqlEvalExcludeStaleRecords';
18
18
  import { parseAndVisit, Kind, visit, execute, buildSchema, isObjectType, defaultFieldResolver } from '@luvio/graphql-parser';
19
- import { RECORD_ID_PREFIX, RECORD_FIELDS_KEY_JUNCTION, isStoreKeyRecordViewEntity, getRecordId18, RECORD_REPRESENTATION_NAME, extractRecordIdFromStoreKey, keyBuilderQuickActionExecutionRepresentation, ingestQuickActionExecutionRepresentation, keyBuilderContentDocumentCompositeRepresentation, getResponseCacheKeysContentDocumentCompositeRepresentation, keyBuilderFromTypeContentDocumentCompositeRepresentation, ingestContentDocumentCompositeRepresentation, keyBuilderRecord, RECORD_VIEW_ENTITY_ID_PREFIX, getTypeCacheKeysRecord, keyBuilderFromTypeRecordRepresentation, ingestRecord, RecordRepresentationRepresentationType, ObjectInfoRepresentationType, getRecordAdapterFactory, getObjectInfoAdapterFactory, getObjectInfosAdapterFactory, UiApiNamespace, RecordRepresentationType, RecordRepresentationTTL, RecordRepresentationVersion, getRecordsAdapterFactory } from '@salesforce/lds-adapters-uiapi';
19
+ import { RECORD_ID_PREFIX, RECORD_FIELDS_KEY_JUNCTION, isStoreKeyRecordViewEntity, getRecordId18, RECORD_REPRESENTATION_NAME, extractRecordIdFromStoreKey, keyBuilderQuickActionExecutionRepresentation, ingestQuickActionExecutionRepresentation, keyBuilderContentDocumentCompositeRepresentation, getResponseCacheKeysContentDocumentCompositeRepresentation, keyBuilderFromTypeContentDocumentCompositeRepresentation, ingestContentDocumentCompositeRepresentation, keyBuilderRecord, RECORD_VIEW_ENTITY_ID_PREFIX, getTypeCacheKeysRecord, keyBuilderFromTypeRecordRepresentation, ingestRecord, RecordRepresentationRepresentationType, ObjectInfoRepresentationType, getRecordAdapterFactory, getObjectInfoAdapterFactory, getObjectInfosAdapterFactory, getObjectInfoDirectoryAdapterFactory, UiApiNamespace, RecordRepresentationType, RecordRepresentationTTL, RecordRepresentationVersion, keyBuilderObjectInfo, ObjectInfoDirectoryEntryRepresentationType, getRecordsAdapterFactory } from '@salesforce/lds-adapters-uiapi';
20
20
  import caseSensitiveUserId from '@salesforce/user/Id';
21
21
  import { idleDetector, getInstrumentation } from 'o11y/client';
22
22
  import ldsUseShortUrlGate from '@salesforce/gate/lds.useShortUrl';
@@ -10316,16 +10316,18 @@ function injectFilter(filterNode, idState, parentPath, isParentPolymorphic, obje
10316
10316
  if (!isIdField) {
10317
10317
  let subSelectionNodes = [];
10318
10318
  let subFieldsHasId = false;
10319
- filterNode.value.fields.forEach((subFieldNode) => {
10320
- // Check if the filter field has the 'Id'
10321
- if (isFieldAnIdField(subFieldNode.name.value, objectInfos[objectInfoName])) {
10322
- subFieldsHasId = true;
10323
- updateIDInfo(subFieldNode, idState, draftFunctions);
10324
- }
10325
- // try injecting the fields within predicate no matter it has relation or not.
10326
- let subResults = injectFilter(subFieldNode, idState, curPath, isPolymorphicField, objectInfos, pathToObjectApiNamesMap, draftFunctions, existingFields ? existingFields[0] : undefined);
10327
- subSelectionNodes = subSelectionNodes.concat(subResults);
10328
- });
10319
+ if (isSpanning) {
10320
+ filterNode.value.fields.forEach((subFieldNode) => {
10321
+ // Check if the filter field has the 'Id'
10322
+ if (isFieldAnIdField(subFieldNode.name.value, objectInfos[objectInfoName])) {
10323
+ subFieldsHasId = true;
10324
+ updateIDInfo(subFieldNode, idState, draftFunctions);
10325
+ }
10326
+ // try injecting the fields within predicate no matter it has relation or not.
10327
+ let subResults = injectFilter(subFieldNode, idState, curPath, isPolymorphicField, objectInfos, pathToObjectApiNamesMap, draftFunctions, existingFields ? existingFields[0] : undefined);
10328
+ subSelectionNodes = subSelectionNodes.concat(subResults);
10329
+ });
10330
+ }
10329
10331
  if (!subFieldsHasId) {
10330
10332
  // Check if the query field has the 'Id'
10331
10333
  const existingIdsInQuery = existingFields &&
@@ -10354,6 +10356,7 @@ function injectFilter(filterNode, idState, parentPath, isParentPolymorphic, obje
10354
10356
  }
10355
10357
  //Inject Conditions: 1. Same field does not exist 2. Same fields has different children. 3. Filter spanning field does not have Id. 4. InLineFragment does not have the '__typename' field
10356
10358
  if (!existingFields ||
10359
+ existingFields.length === 0 ||
10357
10360
  subSelectionNodes.length > 0 ||
10358
10361
  (isSpanning && !subFieldsHasId) ||
10359
10362
  (isInlineFragment && !isTypeNameExisting)) {
@@ -12481,30 +12484,36 @@ function makeRecordDenormalizingDurableStore(luvio, durableStore, getStoreRecord
12481
12484
  const operationsWithDenormedRecords = [];
12482
12485
  for (let i = 0, len = operations.length; i < len; i++) {
12483
12486
  const operation = operations[i];
12484
- if (durableStore.plugin !== undefined &&
12485
- durableStore.plugin.supportsBatchUpdates !== undefined &&
12486
- durableStore.plugin.supportsBatchUpdates() === true) {
12487
- if (operation.segment !== DefaultDurableSegment ||
12488
- operation.type !== 'setEntries') {
12489
- operationsWithDenormedRecords.push(operation);
12490
- continue;
12487
+ if (operation.type === 'setMetadata') {
12488
+ // if setMetadata also contains entry data then it needs to be denormalized.
12489
+ const keys$1 = keys$3(operation.entries);
12490
+ if (keys$1.length > 0) {
12491
+ const firstKey = keys$1[0];
12492
+ // casted to any to check if data exists
12493
+ const firstEntry = operation.entries[firstKey];
12494
+ // it is not possible for setMetadata to contain entries with both data and no data in the same operation.
12495
+ // this is determined by the plugin supporting update batch calls before it gets to this HOF.
12496
+ // so we only need to check one entry to confirm this for performance
12497
+ if (firstEntry.data !== undefined) {
12498
+ operationsWithDenormedRecords.push({
12499
+ ...operation,
12500
+ entries: denormalizeEntries(operation.entries),
12501
+ });
12502
+ }
12503
+ else {
12504
+ operationsWithDenormedRecords.push(operation);
12505
+ }
12491
12506
  }
12492
- operationsWithDenormedRecords.push({
12493
- ...operation,
12494
- entries: denormalizeEntries(operation.entries),
12495
- });
12507
+ continue;
12496
12508
  }
12497
- else {
12498
- if (operation.segment !== DefaultDurableSegment ||
12499
- operation.type === 'evictEntries') {
12500
- operationsWithDenormedRecords.push(operation);
12501
- continue;
12502
- }
12503
- operationsWithDenormedRecords.push({
12504
- ...operation,
12505
- entries: denormalizeEntries(operation.entries),
12506
- });
12509
+ if (operation.segment !== DefaultDurableSegment || operation.type === 'evictEntries') {
12510
+ operationsWithDenormedRecords.push(operation);
12511
+ continue;
12507
12512
  }
12513
+ operationsWithDenormedRecords.push({
12514
+ ...operation,
12515
+ entries: denormalizeEntries(operation.entries),
12516
+ });
12508
12517
  }
12509
12518
  return durableStore.batchOperations(operationsWithDenormedRecords);
12510
12519
  };
@@ -13073,7 +13082,7 @@ function draftAwareGraphQLAdapterFactory(userId, objectInfoService, store, luvio
13073
13082
  // Fulfilled snapshot (this only happens in this code path if
13074
13083
  // the error is network error or 504), otherwise we spread over
13075
13084
  // the non-eval'ed snapshot (which will be either Fulfilled or Stale)
13076
- return nonEvaluatedSnapshot.state === 'Error'
13085
+ const resultSnapshot = nonEvaluatedSnapshot.state === 'Error'
13077
13086
  ? createLocalEvalSnapshot(gqlResult, seenRecords, recordId, rebuildWithLocalEval)
13078
13087
  : {
13079
13088
  ...nonEvaluatedSnapshot,
@@ -13082,6 +13091,22 @@ function draftAwareGraphQLAdapterFactory(userId, objectInfoService, store, luvio
13082
13091
  seenRecords,
13083
13092
  rebuildWithLocalEval,
13084
13093
  };
13094
+ const { refresh, state } = resultSnapshot;
13095
+ if (state !== 'Error' && refresh) {
13096
+ // after refreshing a graphql snapshot, we want to force a rebuild regardless
13097
+ // of if the call failed or not or if the data changed or not because we want
13098
+ // to make sure any potential new drafts are picked up
13099
+ resultSnapshot.refresh = {
13100
+ ...refresh,
13101
+ resolve: (config) => {
13102
+ return refresh.resolve(config).finally(() => {
13103
+ luvio.storePublish(resultSnapshot.recordId, undefined);
13104
+ luvio.storeBroadcast();
13105
+ });
13106
+ },
13107
+ };
13108
+ }
13109
+ return resultSnapshot;
13085
13110
  };
13086
13111
  }
13087
13112
 
@@ -15023,6 +15048,7 @@ function buildInternalAdapters(store, networkAdapter, durableStore, ensureObject
15023
15048
  const getRecord = getRecordAdapterFactory(luvio);
15024
15049
  const getObjectInfo = getObjectInfoAdapterFactory(luvio);
15025
15050
  const getObjectInfos = getObjectInfosAdapterFactory(luvio);
15051
+ const getObjectInfoDirectory = getObjectInfoDirectoryAdapterFactory(luvio);
15026
15052
  return {
15027
15053
  luvio,
15028
15054
  durableEnvironment,
@@ -15030,37 +15056,37 @@ function buildInternalAdapters(store, networkAdapter, durableStore, ensureObject
15030
15056
  getRecord,
15031
15057
  getObjectInfo,
15032
15058
  getObjectInfos,
15059
+ getObjectInfoDirectory,
15033
15060
  },
15034
15061
  };
15035
15062
  }
15036
15063
 
15037
- const OBJECT_INFO_PREFIX_SEGMENT = 'OBJECT_INFO_PREFIX_SEGMENT';
15038
15064
  class ObjectInfoService {
15039
- constructor(getObjectInfoAdapter, getObjectInfosAdapter, durableStore) {
15065
+ constructor(getObjectInfoAdapter, getObjectInfosAdapter, getObjectInfoDirectoryAdapter, durableStore) {
15066
+ this.getObjectInfoAdapter = getObjectInfoAdapter;
15067
+ this.getObjectInfosAdapter = getObjectInfosAdapter;
15068
+ this.getObjectInfoDirectoryAdapter = getObjectInfoDirectoryAdapter;
15069
+ this.durableStore = durableStore;
15040
15070
  this.apiNameForPrefix = async (prefix) => {
15041
- const entries = await this.durableStore.getAllEntries(OBJECT_INFO_PREFIX_SEGMENT);
15042
- const missingError = new Error(`ObjectInfo for ${prefix} prefix is not primed into the durable store`);
15043
- if (entries === undefined) {
15044
- throw missingError;
15071
+ if (this.keyPrefixToApiNameMemoryCache[prefix] !== undefined) {
15072
+ return this.keyPrefixToApiNameMemoryCache[prefix];
15045
15073
  }
15046
- const keys = Object.keys(entries);
15047
- for (let i = 0, len = keys.length; i < len; i++) {
15048
- const entry = entries[keys[i]];
15049
- if (prefix === entry.data.keyPrefix) {
15050
- return entry.data.apiName;
15051
- }
15074
+ await this.loadObjectInfoMaps();
15075
+ const apiName = this.keyPrefixToApiNameMemoryCache[prefix];
15076
+ if (apiName === undefined) {
15077
+ throw Error(`ObjectInfo for ${prefix} prefix is not primed into the durable store`);
15052
15078
  }
15053
- throw missingError;
15079
+ return apiName;
15054
15080
  };
15055
15081
  this.ensureObjectInfoCached = async (apiName, entry) => {
15082
+ if (entry !== undefined) {
15083
+ const { keyPrefix, apiName } = entry;
15084
+ return this.updateObjectInfoMapping(keyPrefix, apiName);
15085
+ }
15056
15086
  const exists = await this.isObjectInfoInDurableStore(apiName);
15057
15087
  if (exists) {
15058
15088
  return;
15059
15089
  }
15060
- if (entry !== undefined) {
15061
- // Since ObjectInfo is provided, no need to fetch the snapshot
15062
- return this.createObjectInfoMapping(apiName, entry);
15063
- }
15064
15090
  // ObjectInfo is not present in Durable store. Fetch
15065
15091
  const snapshot = await this.getObjectInfoAdapter({
15066
15092
  objectApiName: apiName,
@@ -15069,46 +15095,34 @@ class ObjectInfoService {
15069
15095
  throw Error(`No snapshot found for apiName ${apiName}`);
15070
15096
  }
15071
15097
  if (snapshot.data !== null && snapshot.data !== undefined) {
15072
- return this.createObjectInfoMapping(apiName, snapshot.data);
15098
+ const { keyPrefix, apiName } = snapshot.data;
15099
+ return this.updateObjectInfoMapping(keyPrefix, apiName);
15073
15100
  }
15074
15101
  };
15075
- /**
15076
- * Caches ObjectInfo(ApiName and KeyPrefix) in Durable Store
15077
- *
15078
- * @param apiName eg: 'Account'
15079
- * @param objectInfo Object Info
15080
- *
15081
- * @returns Promise
15082
- */
15083
- this.createObjectInfoMapping = (apiName, objectInfo) => {
15084
- const { keyPrefix } = objectInfo;
15085
- const entries = {
15086
- [apiName]: {
15087
- data: {
15088
- apiName,
15089
- keyPrefix,
15090
- },
15091
- },
15092
- };
15093
- this.objectInfoMemoryCache[apiName] = keyPrefix;
15094
- return this.durableStore.setEntries(entries, OBJECT_INFO_PREFIX_SEGMENT);
15095
- };
15096
15102
  this.isObjectInfoInDurableStore = async (apiName) => {
15097
- if (this.objectInfoMemoryCache[apiName] !== undefined) {
15103
+ if (this.apiNameToKeyPrefixMemoryCache[apiName] !== undefined) {
15098
15104
  return Promise.resolve(true);
15099
15105
  }
15100
- const entries = await this.durableStore.getEntries([apiName], OBJECT_INFO_PREFIX_SEGMENT);
15101
- if (entries === undefined || entries[apiName] === undefined) {
15102
- return false;
15106
+ await this.loadObjectInfoMaps();
15107
+ return this.apiNameToKeyPrefixMemoryCache[apiName] !== undefined;
15108
+ };
15109
+ this.loadObjectInfoMaps = async () => {
15110
+ const rows = (await this.durableStore.query(`SELECT json_extract(data, '$.apiName') as ApiName, json_extract(data, '$.keyPrefix') as keyPrefix from lds_data where key like '%ObjectInfoRepresentation%'`, [])).rows;
15111
+ for (const row of rows) {
15112
+ const apiName = row[0];
15113
+ const keyPrefix = row[1];
15114
+ this.updateObjectInfoMapping(keyPrefix, apiName);
15103
15115
  }
15104
- this.objectInfoMemoryCache[apiName] = entries[apiName].data.keyPrefix;
15105
- return true;
15106
15116
  };
15107
- this.getObjectInfoAdapter = getObjectInfoAdapter;
15108
- this.getObjectInfosAdapter = getObjectInfosAdapter;
15109
- this.durableStore = durableStore;
15110
- // Local in-memory cache for ObjectInfo entries seen in DurableStore eg: {'Account': 001}
15111
- this.objectInfoMemoryCache = create$1(null);
15117
+ this.updateObjectInfoMapping = (keyPrefix, apiName) => {
15118
+ this.apiNameToKeyPrefixMemoryCache[apiName] = keyPrefix;
15119
+ if (keyPrefix !== null) {
15120
+ this.keyPrefixToApiNameMemoryCache[keyPrefix] = apiName;
15121
+ }
15122
+ };
15123
+ // Local in-memory cache for apiName to key prefixes
15124
+ this.apiNameToKeyPrefixMemoryCache = create$1(null);
15125
+ this.keyPrefixToApiNameMemoryCache = create$1(null);
15112
15126
  }
15113
15127
  /**
15114
15128
  * Size of return map not necessarily correlated with number of inputs. The
@@ -15128,10 +15142,20 @@ class ObjectInfoService {
15128
15142
  for (const result of snapshot.data.results) {
15129
15143
  if (result.statusCode === 200) {
15130
15144
  objectInfos[result.result.apiName] = result.result;
15145
+ this.updateObjectInfoMapping(result.result.keyPrefix, result.result.apiName);
15131
15146
  }
15132
15147
  }
15133
15148
  return objectInfos;
15134
15149
  }
15150
+ async getObjectInfoDirectory() {
15151
+ const snapshot = await this.getObjectInfoDirectoryAdapter({});
15152
+ if (!snapshot ||
15153
+ !snapshot.data ||
15154
+ (snapshot.state !== 'Fulfilled' && snapshot.state !== 'Stale')) {
15155
+ return undefined;
15156
+ }
15157
+ return snapshot.data;
15158
+ }
15135
15159
  }
15136
15160
 
15137
15161
  function instrumentGraphQLEval(adapter) {
@@ -15475,6 +15499,7 @@ class NimbusSqliteStore {
15475
15499
  ...additionalTableMap,
15476
15500
  [DefaultDurableSegment]: new LdsDataTable(plugin),
15477
15501
  };
15502
+ this.supportsBatchUpdates = plugin.supportsBatchUpdates !== undefined;
15478
15503
  }
15479
15504
  isEvalSupported() {
15480
15505
  return true;
@@ -15509,16 +15534,15 @@ class NimbusSqliteStore {
15509
15534
  setMetadata(entries, segment) {
15510
15535
  const table = this.getTable(segment);
15511
15536
  let operation;
15512
- if (this.plugin.supportsBatchUpdates === undefined ||
15513
- this.plugin.supportsBatchUpdates() === false) {
15537
+ if (this.supportsBatchUpdates) {
15538
+ operation = table.metadataToUpdateOperations(entries, segment);
15539
+ }
15540
+ else {
15514
15541
  operation = table.entriesToUpsertOperations(entries, segment);
15515
15542
  // manually set the context type on the upsert so notifications do not notify rebuilds without
15516
15543
  // plugin updates
15517
15544
  operation.context.type = 'setMetadata';
15518
15545
  }
15519
- else {
15520
- operation = table.metadataToUpdateOperations(entries, segment);
15521
- }
15522
15546
  return this.batchOperationAsPromise([operation]);
15523
15547
  }
15524
15548
  batchOperations(operations) {
@@ -15529,17 +15553,16 @@ class NimbusSqliteStore {
15529
15553
  }
15530
15554
  else if (cur.type === 'setMetadata') {
15531
15555
  const table = this.getTable(cur.segment);
15532
- if (this.plugin.supportsBatchUpdates === undefined ||
15533
- this.plugin.supportsBatchUpdates() === false) {
15556
+ if (this.supportsBatchUpdates) {
15557
+ acc.push(table.metadataToUpdateOperations(cur.entries, cur.segment));
15558
+ }
15559
+ else {
15534
15560
  const upsert = table.entriesToUpsertOperations(cur.entries, cur.segment);
15535
15561
  // manually set the context type on the upsert so notifications do not notify rebuilds without
15536
15562
  // plugin updates
15537
15563
  upsert.context.type = 'setMetadata';
15538
15564
  acc.push(upsert);
15539
15565
  }
15540
- else {
15541
- acc.push(table.metadataToUpdateOperations(cur.entries, cur.segment));
15542
- }
15543
15566
  }
15544
15567
  else {
15545
15568
  acc.push(this.idsToDeleteOperation(cur.ids, cur.segment));
@@ -16715,17 +16738,34 @@ function instrumentPrimingSession(session) {
16715
16738
  const apiVersion = `v60.0`;
16716
16739
  const batchEndPointPath = `/services/data/${apiVersion}/graphql/batch`;
16717
16740
  const endPointPath = `/services/data/${apiVersion}/graphql`;
16741
+ const batchObjectInfoEndpoint = `/services/data/${apiVersion}/ui-api/object-info/batch`;
16742
+ const objectInfoDirectoryEndpoint = `/services/data/${apiVersion}/ui-api/object-info`;
16718
16743
  class NimbusPrimingNetworkAdapter {
16744
+ sendRequestWithAbort(request, abortController, onResponse, onError) {
16745
+ let listener;
16746
+ const unregisterListener = () => {
16747
+ if (listener) {
16748
+ abortController.removeEventListener(listener);
16749
+ }
16750
+ };
16751
+ return __nimbus.plugins.LdsNetworkAdapter
16752
+ .sendRequest(request, (response) => {
16753
+ unregisterListener();
16754
+ onResponse(response);
16755
+ }, (error) => {
16756
+ unregisterListener();
16757
+ onError(error);
16758
+ })
16759
+ .then((cancellationToken) => {
16760
+ listener = () => {
16761
+ __nimbus.plugins.LdsNetworkAdapter.cancelRequest(cancellationToken);
16762
+ };
16763
+ abortController.addEventListener(listener);
16764
+ });
16765
+ }
16719
16766
  postBatchGraphQL(configs, abortController) {
16720
16767
  return new Promise((resolve, reject) => {
16721
- let listener;
16722
- const unregisterListener = () => {
16723
- if (listener) {
16724
- abortController.removeEventListener(listener);
16725
- }
16726
- };
16727
- __nimbus.plugins.LdsNetworkAdapter
16728
- .sendRequest({
16768
+ this.sendRequestWithAbort({
16729
16769
  method: 'POST',
16730
16770
  path: batchEndPointPath,
16731
16771
  body: JSON.stringify({
@@ -16735,8 +16775,7 @@ class NimbusPrimingNetworkAdapter {
16735
16775
  queryParams: {},
16736
16776
  priority: 'background',
16737
16777
  observabilityContext: {},
16738
- }, (response) => {
16739
- unregisterListener();
16778
+ }, abortController, (response) => {
16740
16779
  const { body } = response;
16741
16780
  if (body) {
16742
16781
  const { results } = JSON.parse(body);
@@ -16752,27 +16791,13 @@ class NimbusPrimingNetworkAdapter {
16752
16791
  reject(new Error(`No body returned from ${batchEndPointPath} endpoint`));
16753
16792
  }
16754
16793
  }, (error) => {
16755
- unregisterListener();
16756
16794
  reject(error);
16757
- })
16758
- .then((cancellationToken) => {
16759
- listener = () => {
16760
- __nimbus.plugins.LdsNetworkAdapter.cancelRequest(cancellationToken);
16761
- };
16762
- abortController.addEventListener(listener);
16763
16795
  });
16764
16796
  });
16765
16797
  }
16766
16798
  postGraphQL(query, variables, abortController) {
16767
16799
  return new Promise((resolve, reject) => {
16768
- let listener;
16769
- const unregisterListener = () => {
16770
- if (listener) {
16771
- abortController.removeEventListener(listener);
16772
- }
16773
- };
16774
- __nimbus.plugins.LdsNetworkAdapter
16775
- .sendRequest({
16800
+ this.sendRequestWithAbort({
16776
16801
  method: 'POST',
16777
16802
  path: endPointPath,
16778
16803
  body: JSON.stringify({
@@ -16783,8 +16808,7 @@ class NimbusPrimingNetworkAdapter {
16783
16808
  queryParams: {},
16784
16809
  priority: 'background',
16785
16810
  observabilityContext: {},
16786
- }, (response) => {
16787
- unregisterListener();
16811
+ }, abortController, (response) => {
16788
16812
  const { body } = response;
16789
16813
  if (body) {
16790
16814
  resolve(JSON.parse(body));
@@ -16793,14 +16817,64 @@ class NimbusPrimingNetworkAdapter {
16793
16817
  reject(new Error(`No body returned from ${endPointPath} endpoint`));
16794
16818
  }
16795
16819
  }, (error) => {
16796
- unregisterListener();
16797
16820
  reject(error);
16798
- })
16799
- .then((cancellationToken) => {
16800
- listener = () => {
16801
- __nimbus.plugins.LdsNetworkAdapter.cancelRequest(cancellationToken);
16802
- };
16803
- abortController.addEventListener(listener);
16821
+ });
16822
+ });
16823
+ }
16824
+ getObjectInfoDirectory(abortController) {
16825
+ return new Promise((resolve, reject) => {
16826
+ this.sendRequestWithAbort({
16827
+ method: 'GET',
16828
+ path: objectInfoDirectoryEndpoint,
16829
+ body: null,
16830
+ headers: {},
16831
+ queryParams: {},
16832
+ priority: 'background',
16833
+ observabilityContext: {},
16834
+ }, abortController, (response) => {
16835
+ const { body } = response;
16836
+ if (body) {
16837
+ resolve(JSON.parse(body).objects);
16838
+ }
16839
+ else {
16840
+ reject(new Error(`No body returned from ${endPointPath} endpoint`));
16841
+ }
16842
+ }, (error) => {
16843
+ reject(error);
16844
+ });
16845
+ });
16846
+ }
16847
+ getObjectInfos(apiName, abortController) {
16848
+ return new Promise((resolve, reject) => {
16849
+ const map = new Map();
16850
+ if (apiName.length === 0) {
16851
+ resolve(map);
16852
+ }
16853
+ this.sendRequestWithAbort({
16854
+ method: 'GET',
16855
+ path: `${batchObjectInfoEndpoint}/${apiName.join(',')}`,
16856
+ body: null,
16857
+ headers: {},
16858
+ queryParams: {},
16859
+ priority: 'background',
16860
+ observabilityContext: {},
16861
+ }, abortController, (response) => {
16862
+ const { body } = response;
16863
+ if (body) {
16864
+ const results = JSON.parse(body).results;
16865
+ results.forEach((result) => {
16866
+ // only populate the map if the status code is 200, caller needs to check for missing keys
16867
+ if (result.statusCode === 200) {
16868
+ map.set(result.result.apiName, result.result);
16869
+ }
16870
+ });
16871
+ resolve(map);
16872
+ }
16873
+ else {
16874
+ reject(new Error(`No body returned from ${endPointPath} endpoint`));
16875
+ }
16876
+ }, (error) => {
16877
+ reject(error);
16804
16878
  });
16805
16879
  });
16806
16880
  }
@@ -16809,6 +16883,10 @@ class NimbusPrimingNetworkAdapter {
16809
16883
  // ref: https://gnome.pages.gitlab.gnome.org/tracker/docs/developer/limits.html?gi-language=c
16810
16884
  const SQLITE_MAX_VARIABLE_NUMBER = 999;
16811
16885
  const PARAMS_PER_RECORD = 3;
16886
+ /**
16887
+ * No key builder (or adapter) exists for the object info directory, we need to build the key manually
16888
+ */
16889
+ const ObjectInfoDirectoryKey = `${UiApiNamespace}::${ObjectInfoDirectoryEntryRepresentationType}:`;
16812
16890
  // We need to batch the records to avoid hitting the SQLITE_MAX_VARIABLE_NUMBER limit. Each record has 3 parameters
16813
16891
  const BATCH_SIZE = Math.floor(SQLITE_MAX_VARIABLE_NUMBER / PARAMS_PER_RECORD);
16814
16892
  class SqlitePrimingStore {
@@ -16873,6 +16951,44 @@ class SqlitePrimingStore {
16873
16951
  };
16874
16952
  }
16875
16953
  }
16954
+ async readObjectInfoDirectory() {
16955
+ const sql = 'SELECT data FROM lds_data WHERE key = ?';
16956
+ const params = [ObjectInfoDirectoryKey];
16957
+ const result = await this.store.query(sql, params);
16958
+ if (result.rows.length === 1) {
16959
+ return JSON.parse(result.rows[0][0]);
16960
+ }
16961
+ return undefined;
16962
+ }
16963
+ async readObjectApiNames() {
16964
+ const sql = 'SELECT key FROM lds_data WHERE key like ?';
16965
+ const params = [`%${ObjectInfoRepresentationType}%`];
16966
+ const result = await this.store.query(sql, params);
16967
+ const apiNames = new Set();
16968
+ result.rows.forEach((row) => {
16969
+ const key = row[0];
16970
+ const parts = key.split(':');
16971
+ apiNames.add(parts[parts.length - 1]);
16972
+ });
16973
+ return apiNames;
16974
+ }
16975
+ writeObjectInfoDirectory(directory) {
16976
+ const sql = 'INSERT or IGNORE into lds_data (key, data) values (?, ?)';
16977
+ const params = [ObjectInfoDirectoryKey, JSON.stringify(directory)];
16978
+ return this.store.query(sql, params).then(() => { });
16979
+ }
16980
+ writeObjectInfos(objectInfos) {
16981
+ const sql = `INSERT or IGNORE into lds_data (key, data) values ${objectInfos
16982
+ .map(() => '(?, ?)')
16983
+ .join(',')};`;
16984
+ const params = [];
16985
+ objectInfos.forEach((objectInfo) => {
16986
+ const key = keyBuilderObjectInfo(this.getLuvio(), { apiName: objectInfo.apiName });
16987
+ params.push(key);
16988
+ params.push(JSON.stringify(objectInfo));
16989
+ });
16990
+ return this.store.query(sql, params).then(() => { });
16991
+ }
16876
16992
  }
16877
16993
  function batchArray(arr, batchSize = BATCH_SIZE) {
16878
16994
  const batches = [];
@@ -16997,13 +17113,13 @@ function getRuntime() {
16997
17113
  : {}, () => getIngestMetadataForInternalAdapters !== undefined
16998
17114
  ? getIngestMetadataForInternalAdapters()
16999
17115
  : {});
17000
- const { adapters: { getObjectInfo, getObjectInfos, getRecord }, durableEnvironment: internalAdapterDurableEnvironment, luvio: internalLuvio, } = buildInternalAdapters(internalAdapterStore, lazyNetworkAdapter, internalAdapterDurableStore, (apiName, objectInfo) => lazyObjectInfoService.ensureObjectInfoCached(apiName, objectInfo));
17116
+ const { adapters: { getObjectInfo, getObjectInfos, getRecord, getObjectInfoDirectory }, durableEnvironment: internalAdapterDurableEnvironment, luvio: internalLuvio, } = buildInternalAdapters(internalAdapterStore, lazyNetworkAdapter, internalAdapterDurableStore, (apiName, objectInfo) => lazyObjectInfoService.ensureObjectInfoCached(apiName, objectInfo));
17001
17117
  lazyInternalLuvio = internalLuvio;
17002
17118
  getIngestRecordsForInternalAdapters =
17003
17119
  internalAdapterDurableEnvironment.getIngestStagingStoreRecords;
17004
17120
  getIngestMetadataForInternalAdapters =
17005
17121
  internalAdapterDurableEnvironment.getIngestStagingStoreRecords;
17006
- lazyObjectInfoService = new ObjectInfoService(getObjectInfo, getObjectInfos, internalAdapterDurableStore);
17122
+ lazyObjectInfoService = new ObjectInfoService(getObjectInfo, getObjectInfos, getObjectInfoDirectory, lazyBaseDurableStore);
17007
17123
  // creates a durable store that denormalizes scalar fields for records
17008
17124
  let getIngestRecords;
17009
17125
  let getIngestMetadata;
@@ -17098,6 +17214,7 @@ function getRuntime() {
17098
17214
  getRecords: lazyGetRecords,
17099
17215
  });
17100
17216
  },
17217
+ nimbusSqliteStore: lazyBaseDurableStore,
17101
17218
  };
17102
17219
  }
17103
17220
 
@@ -17114,4 +17231,4 @@ register({
17114
17231
  });
17115
17232
 
17116
17233
  export { getRuntime, registerReportObserver, reportGraphqlQueryParseError };
17117
- // version: 1.244.0-72e322fff
17234
+ // version: 1.246.0-8357100fc
@@ -1,7 +1,10 @@
1
1
  import type { PrimingNetworkAdapter } from '@salesforce/lds-priming';
2
- import type { GraphQLRepresentation, GraphQLInputRepresentation } from '@salesforce/lds-adapters-uiapi';
2
+ import type { GraphQLRepresentation, GraphQLInputRepresentation, ObjectInfoRepresentation, ObjectInfoDirectoryRepresentation } from '@salesforce/lds-adapters-uiapi';
3
3
  import type { LdsAbortController } from '@salesforce/lds-utils-adapters';
4
4
  export declare class NimbusPrimingNetworkAdapter implements PrimingNetworkAdapter {
5
+ private sendRequestWithAbort;
5
6
  postBatchGraphQL(configs: GraphQLInputRepresentation[], abortController: LdsAbortController): Promise<GraphQLRepresentation[]>;
6
7
  postGraphQL(query: string, variables: Record<string, any>, abortController: LdsAbortController): Promise<GraphQLRepresentation>;
8
+ getObjectInfoDirectory(abortController: LdsAbortController): Promise<ObjectInfoDirectoryRepresentation>;
9
+ getObjectInfos(apiName: string[], abortController: LdsAbortController): Promise<Map<string, ObjectInfoRepresentation>>;
7
10
  }
@@ -1,5 +1,6 @@
1
1
  import type { PrimingStore, RecordWithMetadata, WriteResult } from '@salesforce/lds-priming';
2
2
  import type { Luvio } from '@luvio/engine';
3
+ import type { ObjectInfoDirectoryRepresentation, ObjectInfoRepresentation } from '@salesforce/lds-adapters-uiapi';
3
4
  import type { SqliteStore } from '@salesforce/lds-store-sql';
4
5
  export declare class SqlitePrimingStore implements PrimingStore {
5
6
  private readonly getLuvio;
@@ -8,4 +9,8 @@ export declare class SqlitePrimingStore implements PrimingStore {
8
9
  readRecords(ids: string[]): Promise<RecordWithMetadata[]>;
9
10
  writeRecords(records: RecordWithMetadata[], overwrite: boolean): Promise<WriteResult>;
10
11
  private writeBatch;
12
+ readObjectInfoDirectory(): Promise<ObjectInfoDirectoryRepresentation | undefined>;
13
+ readObjectApiNames(): Promise<Set<string>>;
14
+ writeObjectInfoDirectory(directory: ObjectInfoDirectoryRepresentation): Promise<void>;
15
+ writeObjectInfos(objectInfos: ObjectInfoRepresentation[]): Promise<void>;
11
16
  }
@@ -1,6 +1,7 @@
1
1
  import { Luvio, Environment } from '@luvio/engine';
2
2
  import { DraftManager } from '@salesforce/lds-drafts';
3
3
  import type { DraftQueue } from '@salesforce/lds-drafts';
4
+ import type { NimbusSqliteStore } from '@salesforce/lds-store-nimbus';
4
5
  import type { PrimingSession } from '@salesforce/lds-priming';
5
6
  export interface Runtime {
6
7
  luvio: Luvio;
@@ -12,6 +13,7 @@ export interface Runtime {
12
13
  concurrency?: number;
13
14
  batchSize?: number;
14
15
  }) => PrimingSession;
16
+ nimbusSqliteStore: NimbusSqliteStore;
15
17
  }
16
18
  /**
17
19
  * This returns the LDS on Mobile Runtime singleton object.