@salesforce/lds-runtime-mobile 1.352.0 → 1.353.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
@@ -53,7 +53,7 @@ const { entries: entries$3, keys: keys$5 } = Object;
53
53
 
54
54
  const UI_API_BASE_URI = '/services/data/v64.0/ui-api';
55
55
 
56
- let instrumentation$1 = {
56
+ let instrumentation$2 = {
57
57
  aggregateUiChunkCount: (_cb) => { },
58
58
  aggregateUiConnectError: () => { },
59
59
  duplicateRequest: (_cb) => { },
@@ -65,7 +65,7 @@ let instrumentation$1 = {
65
65
  networkRateLimitExceeded: () => { },
66
66
  };
67
67
  function instrument(newInstrumentation) {
68
- instrumentation$1 = Object.assign(instrumentation$1, newInstrumentation);
68
+ instrumentation$2 = Object.assign(instrumentation$2, newInstrumentation);
69
69
  }
70
70
 
71
71
  const LDS_RECORDS_AGGREGATE_UI = 'LDS_Records_AggregateUi';
@@ -135,7 +135,7 @@ function mergeRecordFields$2(first, second) {
135
135
  * would otherwise cause a query length exception.
136
136
  */
137
137
  function dispatchSplitRecordAggregateUiAction(recordId, networkAdapter, resourceRequest, resourceRequestContext) {
138
- instrumentation$1.getRecordAggregateInvoke();
138
+ instrumentation$2.getRecordAggregateInvoke();
139
139
  return networkAdapter(resourceRequest, resourceRequestContext).then((resp) => {
140
140
  const { body } = resp;
141
141
  // This response body could be an executeAggregateUi, which we don't natively support.
@@ -151,7 +151,7 @@ function dispatchSplitRecordAggregateUiAction(recordId, networkAdapter, resource
151
151
  }
152
152
  const merged = body.compositeResponse.reduce((seed, response) => {
153
153
  if (response.httpStatusCode !== HttpStatusCode.Ok) {
154
- instrumentation$1.getRecordAggregateReject(() => recordId);
154
+ instrumentation$2.getRecordAggregateReject(() => recordId);
155
155
  throw createErrorResponse(HttpStatusCode.ServerError, {
156
156
  error: response.message,
157
157
  });
@@ -161,7 +161,7 @@ function dispatchSplitRecordAggregateUiAction(recordId, networkAdapter, resource
161
161
  }
162
162
  return mergeRecordFields$2(seed, response.body);
163
163
  }, null);
164
- instrumentation$1.getRecordAggregateResolve(() => {
164
+ instrumentation$2.getRecordAggregateResolve(() => {
165
165
  return {
166
166
  recordId,
167
167
  apiName: merged.apiName,
@@ -169,7 +169,7 @@ function dispatchSplitRecordAggregateUiAction(recordId, networkAdapter, resource
169
169
  });
170
170
  return createOkResponse$1(merged);
171
171
  }, (err) => {
172
- instrumentation$1.getRecordAggregateReject(() => recordId);
172
+ instrumentation$2.getRecordAggregateReject(() => recordId);
173
173
  // rethrow error
174
174
  throw err;
175
175
  });
@@ -247,7 +247,7 @@ function buildAndDispatchGetRecordAggregateUi(recordId, req, params) {
247
247
  const { networkAdapter, resourceRequest, resourceRequestContext } = req;
248
248
  const compositeRequest = buildGetRecordByFieldsCompositeRequest(resourceRequest, params);
249
249
  // W-12245125: Emit chunk size metrics
250
- instrumentation$1.aggregateUiChunkCount(() => compositeRequest.length);
250
+ instrumentation$2.aggregateUiChunkCount(() => compositeRequest.length);
251
251
  const aggregateUiParams = {
252
252
  compositeRequest,
253
253
  };
@@ -491,7 +491,7 @@ function platformNetworkAdapter(baseNetworkAdapter) {
491
491
  return (resourceRequest, resourceRequestContext) => {
492
492
  if (!tokenBucket.take(1)) {
493
493
  // We are hitting rate limiting, add some metrics
494
- instrumentation$1.networkRateLimitExceeded();
494
+ instrumentation$2.networkRateLimitExceeded();
495
495
  }
496
496
  const salesforceRequest = {
497
497
  networkAdapter: baseNetworkAdapter,
@@ -52402,6 +52402,8 @@ const NimbusBinaryStore = {
52402
52402
  },
52403
52403
  };
52404
52404
 
52405
+ const priming_session_batch={namespace:"sf.lds",name:"PrimingSessionBatch",pbjsSchema:{"nested":{"sf":{"nested":{"lds":{"nested":{"PrimingSessionBatch":{"fields":{"container":{"id":8,"type":"string"},"idCount":{"id":1,"type":"uint32"},"missingCount":{"id":3,"type":"uint32"},"wasFromPagination":{"id":5,"type":"bool"},"successCount":{"id":2,"type":"uint32"},"paginationCount":{"id":6,"type":"uint32"},"conflictedCount":{"id":4,"type":"uint32"},"ingestDuration":{"id":7,"type":"double"}}}}}}}}}};
52406
+
52405
52407
  class EventEmitter {
52406
52408
  constructor() {
52407
52409
  // @ts-ignore typescript doesn't like us setting this to an empty object for some reason
@@ -52515,6 +52517,12 @@ function buildFieldUnionArray(existingRecord, incomingRecord, objectInfo) {
52515
52517
  fieldUnion.push(`${fieldName}.Id`);
52516
52518
  includesSpanningFields = true;
52517
52519
  }
52520
+ else {
52521
+ // Field exists on record but not in object info.
52522
+ // Fall back to getRecords resolver in this case.
52523
+ fieldUnion.push(fieldName);
52524
+ includesSpanningFields = true;
52525
+ }
52518
52526
  }
52519
52527
  else {
52520
52528
  fieldUnion.push(fieldName);
@@ -52740,8 +52748,17 @@ class ConflictPool {
52740
52748
  }
52741
52749
  }
52742
52750
 
52751
+ const instrumentation$1 = getInstrumentation(O11Y_NAMESPACE_LDS_MOBILE);
52743
52752
  const DEFAULT_BATCH_SIZE = 500;
52744
52753
  const DEFAULT_CONCURRENCY = 6;
52754
+ const MAX_RETRY_COUNT = 2;
52755
+ const SESSION_BATCH_SIZE = 'priming-session-batch-size';
52756
+ const SESSION_CONCURRENCY_LIMIT = 'priming-session-concurrency-limit';
52757
+ const SESSION_ENQUEUE_RECORD_COUNT = 'priming-session-enqueue-record-count';
52758
+ const SESSION_INGEST_WRITTEN = 'priming-session-ingest-written-count';
52759
+ const SESSION_INGEST_CONFLICTED = 'priming-session-ingest-conflicted-count';
52760
+ const SESSION_INGEST_ERRORS = 'priming-session-ingest-error-count';
52761
+ const SESSION_INGEST_DURATION = 'priming-session-ingest-duration';
52745
52762
  class PrimingSession extends EventEmitter {
52746
52763
  constructor(config) {
52747
52764
  super();
@@ -52753,6 +52770,9 @@ class PrimingSession extends EventEmitter {
52753
52770
  this.ldsRecordRefresher = config.ldsRecordRefresher;
52754
52771
  this.networkWorkerPool = new AsyncWorkerPool(this.concurrency);
52755
52772
  this.conflictPool = new ConflictPool(config.store, this.objectInfoLoader);
52773
+ this.retryTracker = new Map();
52774
+ instrumentation$1.trackValue(SESSION_BATCH_SIZE, config.batchSize ? config.batchSize : 0);
52775
+ instrumentation$1.trackValue(SESSION_CONCURRENCY_LIMIT, config.concurrency ? config.concurrency : 0);
52756
52776
  }
52757
52777
  // function that enqueues priming work
52758
52778
  async enqueue(work) {
@@ -52771,6 +52791,9 @@ class PrimingSession extends EventEmitter {
52771
52791
  unavailableTypes,
52772
52792
  });
52773
52793
  if (unavailableIds.length > 0) {
52794
+ for (const id of unavailableIds) {
52795
+ this.retryTracker.delete(id);
52796
+ }
52774
52797
  this.emit('error', {
52775
52798
  ids: unavailableIds,
52776
52799
  code: 'precondition-error',
@@ -52784,8 +52807,40 @@ class PrimingSession extends EventEmitter {
52784
52807
  cancel() {
52785
52808
  this.networkWorkerPool.cancel();
52786
52809
  }
52787
- enqueueBatches(batches) {
52810
+ handleInstrumentation(activity, stats, errors) {
52811
+ const schema = priming_session_batch;
52812
+ const userData = {
52813
+ ...stats,
52814
+ };
52815
+ if (errors.length) {
52816
+ for (const error in errors) {
52817
+ activity.error(error, schema, userData);
52818
+ }
52819
+ }
52820
+ else {
52821
+ activity.stop(schema, userData);
52822
+ }
52823
+ }
52824
+ enqueueBatches(batches, paginationCount = 0) {
52788
52825
  for (const batch of batches) {
52826
+ instrumentation$1.trackValue(SESSION_ENQUEUE_RECORD_COUNT, batch.ids.length);
52827
+ const o11yActivity = instrumentation$1.startActivity('primingSessionBatch');
52828
+ let stats = {
52829
+ idCount: 0,
52830
+ successCount: 0,
52831
+ missingCount: 0,
52832
+ conflictedCount: 0,
52833
+ wasFromPagination: false,
52834
+ paginationCount: 0,
52835
+ ingestDuration: 0,
52836
+ container: '',
52837
+ };
52838
+ let errors = [];
52839
+ if (paginationCount > 0) {
52840
+ stats.wasFromPagination = true;
52841
+ stats.paginationCount = paginationCount;
52842
+ }
52843
+ stats.idCount = batch.ids.length;
52789
52844
  const queuedTime = Date.now();
52790
52845
  this.networkWorkerPool.push({
52791
52846
  workFn: (abortController) => {
@@ -52795,6 +52850,9 @@ class PrimingSession extends EventEmitter {
52795
52850
  .fetchRecordData(batch, abortController)
52796
52851
  .then(async (results) => {
52797
52852
  if (abortController.aborted) {
52853
+ for (const id of batch.ids) {
52854
+ this.retryTracker.delete(id);
52855
+ }
52798
52856
  return;
52799
52857
  }
52800
52858
  this.emit('batch-fetched', {
@@ -52802,12 +52860,20 @@ class PrimingSession extends EventEmitter {
52802
52860
  duration: Date.now() - workTime,
52803
52861
  });
52804
52862
  for (const result of results) {
52805
- this.processFetchedRecords(result, abortController);
52863
+ const returnedError = this.processFetchedRecords(result, abortController, stats);
52864
+ if (returnedError) {
52865
+ errors.push(returnedError);
52866
+ }
52806
52867
  }
52807
- this.handlePaginations(results, batch);
52868
+ this.handlePaginations(results, batch, paginationCount);
52869
+ })
52870
+ .finally(() => {
52871
+ this.handleInstrumentation(o11yActivity, stats, errors);
52808
52872
  });
52809
52873
  },
52810
52874
  cancelFn: () => {
52875
+ errors.push('cancelled');
52876
+ this.handleInstrumentation(o11yActivity, stats, errors);
52811
52877
  this.emit('error', {
52812
52878
  ids: batch.ids,
52813
52879
  code: 'canceled',
@@ -52817,7 +52883,7 @@ class PrimingSession extends EventEmitter {
52817
52883
  });
52818
52884
  }
52819
52885
  }
52820
- handlePaginations(results, batch) {
52886
+ handlePaginations(results, batch, paginationCount) {
52821
52887
  const ids = this.recordLoader.getMissingIdsWithPagination(results);
52822
52888
  if (ids.size > 0) {
52823
52889
  const batches = chunk(Array.from(ids), this.batchSize).map((chunkOfIds) => ({
@@ -52826,10 +52892,10 @@ class PrimingSession extends EventEmitter {
52826
52892
  fields: batch.fields,
52827
52893
  objectInfo: batch.objectInfo,
52828
52894
  }));
52829
- this.enqueueBatches(batches);
52895
+ this.enqueueBatches(batches, paginationCount + 1);
52830
52896
  }
52831
52897
  }
52832
- processFetchedRecords(result, abortController) {
52898
+ processFetchedRecords(result, abortController, stats) {
52833
52899
  if (result.ok === false) {
52834
52900
  const { error } = result;
52835
52901
  let primingError = 'unknown';
@@ -52844,10 +52910,14 @@ class PrimingSession extends EventEmitter {
52844
52910
  code: primingError,
52845
52911
  message: `${result.messages.join(',')}`,
52846
52912
  });
52847
- return;
52913
+ for (const id of result.missingIds) {
52914
+ this.retryTracker.delete(id);
52915
+ }
52916
+ return error;
52848
52917
  }
52849
52918
  const { missingIds } = result;
52850
52919
  if (missingIds.length > 0 && !this.recordLoader.isResultWithPagination(result)) {
52920
+ stats.missingCount = missingIds.length;
52851
52921
  this.emit('error', {
52852
52922
  ids: missingIds,
52853
52923
  code: 'not-found',
@@ -52855,11 +52925,17 @@ class PrimingSession extends EventEmitter {
52855
52925
  });
52856
52926
  }
52857
52927
  const { records } = result;
52928
+ stats.successCount = records.length;
52858
52929
  const beforeWrite = Date.now();
52859
52930
  // dispatch the write but DO NOT wait on it to unblock the network pool
52860
52931
  this.recordIngestor
52861
52932
  .insertRecords(records, false)
52862
52933
  .then(({ written, conflicted, errors }) => {
52934
+ instrumentation$1.trackValue(SESSION_INGEST_WRITTEN, written.length);
52935
+ instrumentation$1.trackValue(SESSION_INGEST_CONFLICTED, conflicted.length);
52936
+ instrumentation$1.trackValue(SESSION_INGEST_ERRORS, errors.length);
52937
+ instrumentation$1.trackValue(SESSION_INGEST_DURATION, Date.now() - beforeWrite);
52938
+ stats.conflictedCount = conflicted.length;
52863
52939
  this.emit('batch-written', {
52864
52940
  written,
52865
52941
  conflicted,
@@ -52867,6 +52943,17 @@ class PrimingSession extends EventEmitter {
52867
52943
  duration: Date.now() - beforeWrite,
52868
52944
  });
52869
52945
  if (abortController.aborted) {
52946
+ for (const id of written) {
52947
+ this.retryTracker.delete(id);
52948
+ }
52949
+ for (const id of conflicted) {
52950
+ this.retryTracker.delete(id);
52951
+ }
52952
+ for (const error of errors) {
52953
+ for (const id of error.ids) {
52954
+ this.retryTracker.delete(id);
52955
+ }
52956
+ }
52870
52957
  return;
52871
52958
  }
52872
52959
  if (errors.length > 0) {
@@ -52876,11 +52963,17 @@ class PrimingSession extends EventEmitter {
52876
52963
  code: 'unknown',
52877
52964
  message: message,
52878
52965
  });
52966
+ for (const id of ids) {
52967
+ this.retryTracker.delete(id);
52968
+ }
52879
52969
  });
52880
52970
  }
52881
52971
  // now that the records are persisted, emit the primed event
52882
52972
  if (written.length > 0) {
52883
52973
  this.emit('primed', Array.from(written));
52974
+ for (const id of written) {
52975
+ this.retryTracker.delete(id);
52976
+ }
52884
52977
  }
52885
52978
  // if any records could not be written to the store because there were conflicts, handle the conflicts
52886
52979
  if (conflicted.length > 0) {
@@ -52891,14 +52984,39 @@ class PrimingSession extends EventEmitter {
52891
52984
  async handleWriteConflicts(records, conflicted, abortController) {
52892
52985
  const result = await this.conflictPool.enqueueConflictedRecords(records.filter((x) => conflicted.includes(x.id)), abortController);
52893
52986
  if (abortController.aborted) {
52987
+ for (const id of conflicted) {
52988
+ this.retryTracker.delete(id);
52989
+ }
52894
52990
  return;
52895
52991
  }
52896
- if (Object.keys(result.additionalWork.records).length > 0) {
52992
+ if (keys$2(result.additionalWork.records).length > 0) {
52897
52993
  this.emit('conflict', {
52898
52994
  ids: Object.values(result.additionalWork.records).flatMap((record) => record.ids),
52899
52995
  resolution: 'priming-refresh',
52900
52996
  });
52901
- this.enqueue(result.additionalWork);
52997
+ // we're re-enqueuing here, so apply retry limits which may change the batches
52998
+ let limitedResult = this.applyRetryLimits(result.additionalWork);
52999
+ this.enqueue(limitedResult.additionalWork);
53000
+ if (limitedResult.recordsNeedingRefetch.size > 0) {
53001
+ for (const key in keys$2(limitedResult.recordsNeedingRefetch)) {
53002
+ const value = limitedResult.recordsNeedingRefetch.get(key);
53003
+ if (result.recordsNeedingRefetch.has(key)) {
53004
+ let existing = result.recordsNeedingRefetch.get(key);
53005
+ existing = {
53006
+ // merge the ids
53007
+ ids: [...existing.ids, ...value.ids],
53008
+ // This is safe because they derive from the same
53009
+ // input, no chance of getting a new field in the
53010
+ // limited result
53011
+ fields: existing.fields,
53012
+ };
53013
+ result.recordsNeedingRefetch.set(key, existing);
53014
+ }
53015
+ else {
53016
+ result.recordsNeedingRefetch.set(key, value);
53017
+ }
53018
+ }
53019
+ }
52902
53020
  }
52903
53021
  if (result.resolvedRecords.length > 0) {
52904
53022
  this.emit('conflict', {
@@ -52906,8 +53024,14 @@ class PrimingSession extends EventEmitter {
52906
53024
  resolution: 'priming-merge',
52907
53025
  });
52908
53026
  this.emit('primed', result.resolvedRecords);
53027
+ for (const id of result.resolvedRecords) {
53028
+ this.retryTracker.delete(id);
53029
+ }
52909
53030
  }
52910
53031
  if (result.recordsToWrite.length > 0) {
53032
+ for (const record of result.recordsToWrite) {
53033
+ this.retryTracker.delete(record.id);
53034
+ }
52911
53035
  const { written, errors, conflicted } = await this.recordIngestor.insertRecords(result.recordsToWrite, true);
52912
53036
  if (written.length > 0) {
52913
53037
  const ids = Array.from(written);
@@ -52934,10 +53058,16 @@ class PrimingSession extends EventEmitter {
52934
53058
  if (result.recordsNeedingRefetch.size > 0) {
52935
53059
  const { loaded, errored } = await this.ldsRecordRefresher.loadRecords(result.recordsNeedingRefetch);
52936
53060
  if (loaded.length > 0) {
53061
+ for (const id of loaded) {
53062
+ this.retryTracker.delete(id);
53063
+ }
52937
53064
  this.emit('conflict', { resolution: 'lds-refresh', ids: loaded });
52938
53065
  this.emit('primed', loaded);
52939
53066
  }
52940
53067
  if (errored.length > 0) {
53068
+ for (const id of errored) {
53069
+ this.retryTracker.delete(id);
53070
+ }
52941
53071
  this.emit('error', {
52942
53072
  ids: errored,
52943
53073
  code: 'unknown',
@@ -52946,6 +53076,50 @@ class PrimingSession extends EventEmitter {
52946
53076
  }
52947
53077
  }
52948
53078
  }
53079
+ applyRetryLimits(primingWork) {
53080
+ // retryable work goes back into priming session
53081
+ let retryableWork = {
53082
+ type: 'record-fields',
53083
+ records: {},
53084
+ };
53085
+ // refetchable work gets delegated to getRecords
53086
+ let refetchableWork = new Map();
53087
+ for (const key of keys$2(primingWork.records)) {
53088
+ let work = primingWork.records[key];
53089
+ let limitedIds = [];
53090
+ for (const id of work.ids) {
53091
+ let retryCount = this.retryTracker.get(id) || 0;
53092
+ retryCount += 1;
53093
+ if (retryCount > MAX_RETRY_COUNT) {
53094
+ limitedIds.push(id);
53095
+ this.retryTracker.delete(id);
53096
+ }
53097
+ else {
53098
+ this.retryTracker.set(id, retryCount);
53099
+ }
53100
+ }
53101
+ if (limitedIds.length < work.ids.length) {
53102
+ retryableWork.records[key] = {
53103
+ ids: work.ids.filter((id) => limitedIds.indexOf(id) === -1),
53104
+ fields: work.fields,
53105
+ };
53106
+ }
53107
+ if (limitedIds.length > 0) {
53108
+ this.emit('retry-limit-reached', { ids: limitedIds });
53109
+ refetchableWork.set(key, {
53110
+ ids: limitedIds,
53111
+ fields: work.fields,
53112
+ });
53113
+ }
53114
+ }
53115
+ return {
53116
+ additionalWork: retryableWork,
53117
+ recordsNeedingRefetch: refetchableWork,
53118
+ resolvedRecords: [],
53119
+ recordsToWrite: [],
53120
+ errors: [],
53121
+ };
53122
+ }
52949
53123
  async fetchMetadata(batches) {
52950
53124
  const apiNames = Array.from(batches.reduce((acc, x) => {
52951
53125
  return acc.add(x.type);
@@ -52953,20 +53127,20 @@ class PrimingSession extends EventEmitter {
52953
53127
  const objectInfoMap = await this.objectInfoLoader.getObjectInfos(apiNames);
52954
53128
  const unavailableTypes = apiNames.filter((x) => !objectInfoMap[x]);
52955
53129
  const availableTypes = apiNames.filter((x) => objectInfoMap[x]);
52956
- const unavilableBatches = batches.filter((x) => unavailableTypes.includes(x.type));
53130
+ const unavailableBatches = batches.filter((x) => unavailableTypes.includes(x.type));
52957
53131
  const availableBatches = batches
52958
53132
  .filter((x) => !unavailableTypes.includes(x.type))
52959
53133
  .map((x) => {
52960
53134
  return { ...x, objectInfo: objectInfoMap[x.type] };
52961
53135
  });
52962
- const unavailableIds = unavilableBatches.reduce((acc, x) => {
53136
+ const unavailableIds = unavailableBatches.reduce((acc, x) => {
52963
53137
  acc.push(...x.ids);
52964
53138
  return acc;
52965
53139
  }, []);
52966
53140
  return {
52967
53141
  apiNames,
52968
53142
  availableBatches,
52969
- unavilableBatches,
53143
+ unavailableBatches,
52970
53144
  unavailableTypes,
52971
53145
  availableTypes,
52972
53146
  unavailableIds,
@@ -53196,7 +53370,9 @@ class RecordLoaderGraphQL extends NetworkRecordLoader {
53196
53370
  return acc;
53197
53371
  }, {});
53198
53372
  fields['Id'] = { value: id, displayValue: null };
53199
- fields['RecordTypeId'] = { value: recordTypeId, displayValue: null };
53373
+ if (objectInfo.fields['RecordTypeId'] !== undefined) {
53374
+ fields['RecordTypeId'] = { value: recordTypeId, displayValue: null };
53375
+ }
53200
53376
  let recordTypeInfo = null;
53201
53377
  if (recordTypeId !== null &&
53202
53378
  objectInfo.recordTypeInfos &&
@@ -55496,4 +55672,4 @@ register({
55496
55672
  });
55497
55673
 
55498
55674
  export { O11Y_NAMESPACE_LDS_MOBILE, getRuntime, ingest$1o as ingestDenormalizedRecordRepresentation, registerReportObserver, reportGraphqlQueryParseError };
55499
- // version: 1.352.0-9307541b03
55675
+ // version: 1.353.0-cc9b469dc4
@@ -4,7 +4,7 @@ import type { PrimingStore } from './PrimingStore';
4
4
  import type { PrimingWork } from './types';
5
5
  import type { ObjectInfoLoader } from './ObjectInfoLoader';
6
6
  type ConflictResolutionError = 'object-info-missing';
7
- interface ConflictResolutionResult {
7
+ export interface ConflictResolutionResult {
8
8
  additionalWork: PrimingWork;
9
9
  recordsToWrite: DurableRecordRepresentation[];
10
10
  resolvedRecords: string[];
@@ -5,6 +5,7 @@ import type { ObjectInfoLoader } from './ObjectInfoLoader';
5
5
  import type { PrimingStore } from './PrimingStore';
6
6
  import type { LdsRecordRefresher } from './LdsRecordRefresher';
7
7
  import { EventEmitter } from './Emitter';
8
+ export declare const instrumentation: import("o11y/dist/modules/o11y/client/interfaces").Instrumentation;
8
9
  export interface PrimingSessionConfig {
9
10
  store: PrimingStore;
10
11
  recordLoader: RecordLoader;
@@ -36,6 +37,9 @@ export interface PrimingEvents {
36
37
  errors: string[];
37
38
  duration: number;
38
39
  };
40
+ 'retry-limit-reached': {
41
+ ids: string[];
42
+ };
39
43
  }
40
44
  interface EventErrorPayload {
41
45
  ids: string[];
@@ -56,13 +60,16 @@ export declare class PrimingSession extends EventEmitter<PrimingEvents> {
56
60
  private networkWorkerPool;
57
61
  private conflictPool;
58
62
  private ldsRecordRefresher;
63
+ private retryTracker;
59
64
  constructor(config: PrimingSessionConfig);
60
65
  enqueue(work: PrimingWork): Promise<void>;
61
66
  cancel(): void;
67
+ private handleInstrumentation;
62
68
  private enqueueBatches;
63
69
  private handlePaginations;
64
70
  private processFetchedRecords;
65
71
  private handleWriteConflicts;
72
+ private applyRetryLimits;
66
73
  private fetchMetadata;
67
74
  }
68
75
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/lds-runtime-mobile",
3
- "version": "1.352.0",
3
+ "version": "1.353.0",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "LDS runtime for mobile/hybrid environments.",
6
6
  "main": "dist/main.js",
@@ -32,23 +32,24 @@
32
32
  "release:corejar": "yarn build && ../core-build/scripts/core.js --name=lds-runtime-mobile"
33
33
  },
34
34
  "dependencies": {
35
- "@salesforce/lds-adapters-uiapi": "^1.352.0",
36
- "@salesforce/lds-bindings": "^1.352.0",
37
- "@salesforce/lds-instrumentation": "^1.352.0",
35
+ "@salesforce/lds-adapters-uiapi": "^1.353.0",
36
+ "@salesforce/lds-bindings": "^1.353.0",
37
+ "@salesforce/lds-instrumentation": "^1.353.0",
38
38
  "@salesforce/user": "0.0.21",
39
- "o11y": "250.7.0"
39
+ "o11y": "250.7.0",
40
+ "o11y_schema": "256.126.0"
40
41
  },
41
42
  "devDependencies": {
42
- "@salesforce/lds-adapters-graphql": "^1.352.0",
43
- "@salesforce/lds-drafts": "^1.352.0",
44
- "@salesforce/lds-durable-records": "^1.352.0",
45
- "@salesforce/lds-network-adapter": "^1.352.0",
46
- "@salesforce/lds-network-nimbus": "^1.352.0",
47
- "@salesforce/lds-store-binary": "^1.352.0",
48
- "@salesforce/lds-store-nimbus": "^1.352.0",
49
- "@salesforce/lds-store-sql": "^1.352.0",
50
- "@salesforce/lds-utils-adapters": "^1.352.0",
51
- "@salesforce/nimbus-plugin-lds": "^1.352.0",
43
+ "@salesforce/lds-adapters-graphql": "^1.353.0",
44
+ "@salesforce/lds-drafts": "^1.353.0",
45
+ "@salesforce/lds-durable-records": "^1.353.0",
46
+ "@salesforce/lds-network-adapter": "^1.353.0",
47
+ "@salesforce/lds-network-nimbus": "^1.353.0",
48
+ "@salesforce/lds-store-binary": "^1.353.0",
49
+ "@salesforce/lds-store-nimbus": "^1.353.0",
50
+ "@salesforce/lds-store-sql": "^1.353.0",
51
+ "@salesforce/lds-utils-adapters": "^1.353.0",
52
+ "@salesforce/nimbus-plugin-lds": "^1.353.0",
52
53
  "babel-plugin-dynamic-import-node": "^2.3.3",
53
54
  "wait-for-expect": "^3.0.2"
54
55
  },
package/sfdc/main.js CHANGED
@@ -53,7 +53,7 @@ const { entries: entries$3, keys: keys$5 } = Object;
53
53
 
54
54
  const UI_API_BASE_URI = '/services/data/v64.0/ui-api';
55
55
 
56
- let instrumentation$1 = {
56
+ let instrumentation$2 = {
57
57
  aggregateUiChunkCount: (_cb) => { },
58
58
  aggregateUiConnectError: () => { },
59
59
  duplicateRequest: (_cb) => { },
@@ -65,7 +65,7 @@ let instrumentation$1 = {
65
65
  networkRateLimitExceeded: () => { },
66
66
  };
67
67
  function instrument(newInstrumentation) {
68
- instrumentation$1 = Object.assign(instrumentation$1, newInstrumentation);
68
+ instrumentation$2 = Object.assign(instrumentation$2, newInstrumentation);
69
69
  }
70
70
 
71
71
  const LDS_RECORDS_AGGREGATE_UI = 'LDS_Records_AggregateUi';
@@ -135,7 +135,7 @@ function mergeRecordFields$2(first, second) {
135
135
  * would otherwise cause a query length exception.
136
136
  */
137
137
  function dispatchSplitRecordAggregateUiAction(recordId, networkAdapter, resourceRequest, resourceRequestContext) {
138
- instrumentation$1.getRecordAggregateInvoke();
138
+ instrumentation$2.getRecordAggregateInvoke();
139
139
  return networkAdapter(resourceRequest, resourceRequestContext).then((resp) => {
140
140
  const { body } = resp;
141
141
  // This response body could be an executeAggregateUi, which we don't natively support.
@@ -151,7 +151,7 @@ function dispatchSplitRecordAggregateUiAction(recordId, networkAdapter, resource
151
151
  }
152
152
  const merged = body.compositeResponse.reduce((seed, response) => {
153
153
  if (response.httpStatusCode !== HttpStatusCode.Ok) {
154
- instrumentation$1.getRecordAggregateReject(() => recordId);
154
+ instrumentation$2.getRecordAggregateReject(() => recordId);
155
155
  throw createErrorResponse(HttpStatusCode.ServerError, {
156
156
  error: response.message,
157
157
  });
@@ -161,7 +161,7 @@ function dispatchSplitRecordAggregateUiAction(recordId, networkAdapter, resource
161
161
  }
162
162
  return mergeRecordFields$2(seed, response.body);
163
163
  }, null);
164
- instrumentation$1.getRecordAggregateResolve(() => {
164
+ instrumentation$2.getRecordAggregateResolve(() => {
165
165
  return {
166
166
  recordId,
167
167
  apiName: merged.apiName,
@@ -169,7 +169,7 @@ function dispatchSplitRecordAggregateUiAction(recordId, networkAdapter, resource
169
169
  });
170
170
  return createOkResponse$1(merged);
171
171
  }, (err) => {
172
- instrumentation$1.getRecordAggregateReject(() => recordId);
172
+ instrumentation$2.getRecordAggregateReject(() => recordId);
173
173
  // rethrow error
174
174
  throw err;
175
175
  });
@@ -247,7 +247,7 @@ function buildAndDispatchGetRecordAggregateUi(recordId, req, params) {
247
247
  const { networkAdapter, resourceRequest, resourceRequestContext } = req;
248
248
  const compositeRequest = buildGetRecordByFieldsCompositeRequest(resourceRequest, params);
249
249
  // W-12245125: Emit chunk size metrics
250
- instrumentation$1.aggregateUiChunkCount(() => compositeRequest.length);
250
+ instrumentation$2.aggregateUiChunkCount(() => compositeRequest.length);
251
251
  const aggregateUiParams = {
252
252
  compositeRequest,
253
253
  };
@@ -491,7 +491,7 @@ function platformNetworkAdapter(baseNetworkAdapter) {
491
491
  return (resourceRequest, resourceRequestContext) => {
492
492
  if (!tokenBucket.take(1)) {
493
493
  // We are hitting rate limiting, add some metrics
494
- instrumentation$1.networkRateLimitExceeded();
494
+ instrumentation$2.networkRateLimitExceeded();
495
495
  }
496
496
  const salesforceRequest = {
497
497
  networkAdapter: baseNetworkAdapter,
@@ -52402,6 +52402,8 @@ const NimbusBinaryStore = {
52402
52402
  },
52403
52403
  };
52404
52404
 
52405
+ const priming_session_batch={namespace:"sf.lds",name:"PrimingSessionBatch",pbjsSchema:{"nested":{"sf":{"nested":{"lds":{"nested":{"PrimingSessionBatch":{"fields":{"container":{"id":8,"type":"string"},"idCount":{"id":1,"type":"uint32"},"missingCount":{"id":3,"type":"uint32"},"wasFromPagination":{"id":5,"type":"bool"},"successCount":{"id":2,"type":"uint32"},"paginationCount":{"id":6,"type":"uint32"},"conflictedCount":{"id":4,"type":"uint32"},"ingestDuration":{"id":7,"type":"double"}}}}}}}}}};
52406
+
52405
52407
  class EventEmitter {
52406
52408
  constructor() {
52407
52409
  // @ts-ignore typescript doesn't like us setting this to an empty object for some reason
@@ -52515,6 +52517,12 @@ function buildFieldUnionArray(existingRecord, incomingRecord, objectInfo) {
52515
52517
  fieldUnion.push(`${fieldName}.Id`);
52516
52518
  includesSpanningFields = true;
52517
52519
  }
52520
+ else {
52521
+ // Field exists on record but not in object info.
52522
+ // Fall back to getRecords resolver in this case.
52523
+ fieldUnion.push(fieldName);
52524
+ includesSpanningFields = true;
52525
+ }
52518
52526
  }
52519
52527
  else {
52520
52528
  fieldUnion.push(fieldName);
@@ -52740,8 +52748,17 @@ class ConflictPool {
52740
52748
  }
52741
52749
  }
52742
52750
 
52751
+ const instrumentation$1 = getInstrumentation(O11Y_NAMESPACE_LDS_MOBILE);
52743
52752
  const DEFAULT_BATCH_SIZE = 500;
52744
52753
  const DEFAULT_CONCURRENCY = 6;
52754
+ const MAX_RETRY_COUNT = 2;
52755
+ const SESSION_BATCH_SIZE = 'priming-session-batch-size';
52756
+ const SESSION_CONCURRENCY_LIMIT = 'priming-session-concurrency-limit';
52757
+ const SESSION_ENQUEUE_RECORD_COUNT = 'priming-session-enqueue-record-count';
52758
+ const SESSION_INGEST_WRITTEN = 'priming-session-ingest-written-count';
52759
+ const SESSION_INGEST_CONFLICTED = 'priming-session-ingest-conflicted-count';
52760
+ const SESSION_INGEST_ERRORS = 'priming-session-ingest-error-count';
52761
+ const SESSION_INGEST_DURATION = 'priming-session-ingest-duration';
52745
52762
  class PrimingSession extends EventEmitter {
52746
52763
  constructor(config) {
52747
52764
  super();
@@ -52753,6 +52770,9 @@ class PrimingSession extends EventEmitter {
52753
52770
  this.ldsRecordRefresher = config.ldsRecordRefresher;
52754
52771
  this.networkWorkerPool = new AsyncWorkerPool(this.concurrency);
52755
52772
  this.conflictPool = new ConflictPool(config.store, this.objectInfoLoader);
52773
+ this.retryTracker = new Map();
52774
+ instrumentation$1.trackValue(SESSION_BATCH_SIZE, config.batchSize ? config.batchSize : 0);
52775
+ instrumentation$1.trackValue(SESSION_CONCURRENCY_LIMIT, config.concurrency ? config.concurrency : 0);
52756
52776
  }
52757
52777
  // function that enqueues priming work
52758
52778
  async enqueue(work) {
@@ -52771,6 +52791,9 @@ class PrimingSession extends EventEmitter {
52771
52791
  unavailableTypes,
52772
52792
  });
52773
52793
  if (unavailableIds.length > 0) {
52794
+ for (const id of unavailableIds) {
52795
+ this.retryTracker.delete(id);
52796
+ }
52774
52797
  this.emit('error', {
52775
52798
  ids: unavailableIds,
52776
52799
  code: 'precondition-error',
@@ -52784,8 +52807,40 @@ class PrimingSession extends EventEmitter {
52784
52807
  cancel() {
52785
52808
  this.networkWorkerPool.cancel();
52786
52809
  }
52787
- enqueueBatches(batches) {
52810
+ handleInstrumentation(activity, stats, errors) {
52811
+ const schema = priming_session_batch;
52812
+ const userData = {
52813
+ ...stats,
52814
+ };
52815
+ if (errors.length) {
52816
+ for (const error in errors) {
52817
+ activity.error(error, schema, userData);
52818
+ }
52819
+ }
52820
+ else {
52821
+ activity.stop(schema, userData);
52822
+ }
52823
+ }
52824
+ enqueueBatches(batches, paginationCount = 0) {
52788
52825
  for (const batch of batches) {
52826
+ instrumentation$1.trackValue(SESSION_ENQUEUE_RECORD_COUNT, batch.ids.length);
52827
+ const o11yActivity = instrumentation$1.startActivity('primingSessionBatch');
52828
+ let stats = {
52829
+ idCount: 0,
52830
+ successCount: 0,
52831
+ missingCount: 0,
52832
+ conflictedCount: 0,
52833
+ wasFromPagination: false,
52834
+ paginationCount: 0,
52835
+ ingestDuration: 0,
52836
+ container: '',
52837
+ };
52838
+ let errors = [];
52839
+ if (paginationCount > 0) {
52840
+ stats.wasFromPagination = true;
52841
+ stats.paginationCount = paginationCount;
52842
+ }
52843
+ stats.idCount = batch.ids.length;
52789
52844
  const queuedTime = Date.now();
52790
52845
  this.networkWorkerPool.push({
52791
52846
  workFn: (abortController) => {
@@ -52795,6 +52850,9 @@ class PrimingSession extends EventEmitter {
52795
52850
  .fetchRecordData(batch, abortController)
52796
52851
  .then(async (results) => {
52797
52852
  if (abortController.aborted) {
52853
+ for (const id of batch.ids) {
52854
+ this.retryTracker.delete(id);
52855
+ }
52798
52856
  return;
52799
52857
  }
52800
52858
  this.emit('batch-fetched', {
@@ -52802,12 +52860,20 @@ class PrimingSession extends EventEmitter {
52802
52860
  duration: Date.now() - workTime,
52803
52861
  });
52804
52862
  for (const result of results) {
52805
- this.processFetchedRecords(result, abortController);
52863
+ const returnedError = this.processFetchedRecords(result, abortController, stats);
52864
+ if (returnedError) {
52865
+ errors.push(returnedError);
52866
+ }
52806
52867
  }
52807
- this.handlePaginations(results, batch);
52868
+ this.handlePaginations(results, batch, paginationCount);
52869
+ })
52870
+ .finally(() => {
52871
+ this.handleInstrumentation(o11yActivity, stats, errors);
52808
52872
  });
52809
52873
  },
52810
52874
  cancelFn: () => {
52875
+ errors.push('cancelled');
52876
+ this.handleInstrumentation(o11yActivity, stats, errors);
52811
52877
  this.emit('error', {
52812
52878
  ids: batch.ids,
52813
52879
  code: 'canceled',
@@ -52817,7 +52883,7 @@ class PrimingSession extends EventEmitter {
52817
52883
  });
52818
52884
  }
52819
52885
  }
52820
- handlePaginations(results, batch) {
52886
+ handlePaginations(results, batch, paginationCount) {
52821
52887
  const ids = this.recordLoader.getMissingIdsWithPagination(results);
52822
52888
  if (ids.size > 0) {
52823
52889
  const batches = chunk(Array.from(ids), this.batchSize).map((chunkOfIds) => ({
@@ -52826,10 +52892,10 @@ class PrimingSession extends EventEmitter {
52826
52892
  fields: batch.fields,
52827
52893
  objectInfo: batch.objectInfo,
52828
52894
  }));
52829
- this.enqueueBatches(batches);
52895
+ this.enqueueBatches(batches, paginationCount + 1);
52830
52896
  }
52831
52897
  }
52832
- processFetchedRecords(result, abortController) {
52898
+ processFetchedRecords(result, abortController, stats) {
52833
52899
  if (result.ok === false) {
52834
52900
  const { error } = result;
52835
52901
  let primingError = 'unknown';
@@ -52844,10 +52910,14 @@ class PrimingSession extends EventEmitter {
52844
52910
  code: primingError,
52845
52911
  message: `${result.messages.join(',')}`,
52846
52912
  });
52847
- return;
52913
+ for (const id of result.missingIds) {
52914
+ this.retryTracker.delete(id);
52915
+ }
52916
+ return error;
52848
52917
  }
52849
52918
  const { missingIds } = result;
52850
52919
  if (missingIds.length > 0 && !this.recordLoader.isResultWithPagination(result)) {
52920
+ stats.missingCount = missingIds.length;
52851
52921
  this.emit('error', {
52852
52922
  ids: missingIds,
52853
52923
  code: 'not-found',
@@ -52855,11 +52925,17 @@ class PrimingSession extends EventEmitter {
52855
52925
  });
52856
52926
  }
52857
52927
  const { records } = result;
52928
+ stats.successCount = records.length;
52858
52929
  const beforeWrite = Date.now();
52859
52930
  // dispatch the write but DO NOT wait on it to unblock the network pool
52860
52931
  this.recordIngestor
52861
52932
  .insertRecords(records, false)
52862
52933
  .then(({ written, conflicted, errors }) => {
52934
+ instrumentation$1.trackValue(SESSION_INGEST_WRITTEN, written.length);
52935
+ instrumentation$1.trackValue(SESSION_INGEST_CONFLICTED, conflicted.length);
52936
+ instrumentation$1.trackValue(SESSION_INGEST_ERRORS, errors.length);
52937
+ instrumentation$1.trackValue(SESSION_INGEST_DURATION, Date.now() - beforeWrite);
52938
+ stats.conflictedCount = conflicted.length;
52863
52939
  this.emit('batch-written', {
52864
52940
  written,
52865
52941
  conflicted,
@@ -52867,6 +52943,17 @@ class PrimingSession extends EventEmitter {
52867
52943
  duration: Date.now() - beforeWrite,
52868
52944
  });
52869
52945
  if (abortController.aborted) {
52946
+ for (const id of written) {
52947
+ this.retryTracker.delete(id);
52948
+ }
52949
+ for (const id of conflicted) {
52950
+ this.retryTracker.delete(id);
52951
+ }
52952
+ for (const error of errors) {
52953
+ for (const id of error.ids) {
52954
+ this.retryTracker.delete(id);
52955
+ }
52956
+ }
52870
52957
  return;
52871
52958
  }
52872
52959
  if (errors.length > 0) {
@@ -52876,11 +52963,17 @@ class PrimingSession extends EventEmitter {
52876
52963
  code: 'unknown',
52877
52964
  message: message,
52878
52965
  });
52966
+ for (const id of ids) {
52967
+ this.retryTracker.delete(id);
52968
+ }
52879
52969
  });
52880
52970
  }
52881
52971
  // now that the records are persisted, emit the primed event
52882
52972
  if (written.length > 0) {
52883
52973
  this.emit('primed', Array.from(written));
52974
+ for (const id of written) {
52975
+ this.retryTracker.delete(id);
52976
+ }
52884
52977
  }
52885
52978
  // if any records could not be written to the store because there were conflicts, handle the conflicts
52886
52979
  if (conflicted.length > 0) {
@@ -52891,14 +52984,39 @@ class PrimingSession extends EventEmitter {
52891
52984
  async handleWriteConflicts(records, conflicted, abortController) {
52892
52985
  const result = await this.conflictPool.enqueueConflictedRecords(records.filter((x) => conflicted.includes(x.id)), abortController);
52893
52986
  if (abortController.aborted) {
52987
+ for (const id of conflicted) {
52988
+ this.retryTracker.delete(id);
52989
+ }
52894
52990
  return;
52895
52991
  }
52896
- if (Object.keys(result.additionalWork.records).length > 0) {
52992
+ if (keys$2(result.additionalWork.records).length > 0) {
52897
52993
  this.emit('conflict', {
52898
52994
  ids: Object.values(result.additionalWork.records).flatMap((record) => record.ids),
52899
52995
  resolution: 'priming-refresh',
52900
52996
  });
52901
- this.enqueue(result.additionalWork);
52997
+ // we're re-enqueuing here, so apply retry limits which may change the batches
52998
+ let limitedResult = this.applyRetryLimits(result.additionalWork);
52999
+ this.enqueue(limitedResult.additionalWork);
53000
+ if (limitedResult.recordsNeedingRefetch.size > 0) {
53001
+ for (const key in keys$2(limitedResult.recordsNeedingRefetch)) {
53002
+ const value = limitedResult.recordsNeedingRefetch.get(key);
53003
+ if (result.recordsNeedingRefetch.has(key)) {
53004
+ let existing = result.recordsNeedingRefetch.get(key);
53005
+ existing = {
53006
+ // merge the ids
53007
+ ids: [...existing.ids, ...value.ids],
53008
+ // This is safe because they derive from the same
53009
+ // input, no chance of getting a new field in the
53010
+ // limited result
53011
+ fields: existing.fields,
53012
+ };
53013
+ result.recordsNeedingRefetch.set(key, existing);
53014
+ }
53015
+ else {
53016
+ result.recordsNeedingRefetch.set(key, value);
53017
+ }
53018
+ }
53019
+ }
52902
53020
  }
52903
53021
  if (result.resolvedRecords.length > 0) {
52904
53022
  this.emit('conflict', {
@@ -52906,8 +53024,14 @@ class PrimingSession extends EventEmitter {
52906
53024
  resolution: 'priming-merge',
52907
53025
  });
52908
53026
  this.emit('primed', result.resolvedRecords);
53027
+ for (const id of result.resolvedRecords) {
53028
+ this.retryTracker.delete(id);
53029
+ }
52909
53030
  }
52910
53031
  if (result.recordsToWrite.length > 0) {
53032
+ for (const record of result.recordsToWrite) {
53033
+ this.retryTracker.delete(record.id);
53034
+ }
52911
53035
  const { written, errors, conflicted } = await this.recordIngestor.insertRecords(result.recordsToWrite, true);
52912
53036
  if (written.length > 0) {
52913
53037
  const ids = Array.from(written);
@@ -52934,10 +53058,16 @@ class PrimingSession extends EventEmitter {
52934
53058
  if (result.recordsNeedingRefetch.size > 0) {
52935
53059
  const { loaded, errored } = await this.ldsRecordRefresher.loadRecords(result.recordsNeedingRefetch);
52936
53060
  if (loaded.length > 0) {
53061
+ for (const id of loaded) {
53062
+ this.retryTracker.delete(id);
53063
+ }
52937
53064
  this.emit('conflict', { resolution: 'lds-refresh', ids: loaded });
52938
53065
  this.emit('primed', loaded);
52939
53066
  }
52940
53067
  if (errored.length > 0) {
53068
+ for (const id of errored) {
53069
+ this.retryTracker.delete(id);
53070
+ }
52941
53071
  this.emit('error', {
52942
53072
  ids: errored,
52943
53073
  code: 'unknown',
@@ -52946,6 +53076,50 @@ class PrimingSession extends EventEmitter {
52946
53076
  }
52947
53077
  }
52948
53078
  }
53079
+ applyRetryLimits(primingWork) {
53080
+ // retryable work goes back into priming session
53081
+ let retryableWork = {
53082
+ type: 'record-fields',
53083
+ records: {},
53084
+ };
53085
+ // refetchable work gets delegated to getRecords
53086
+ let refetchableWork = new Map();
53087
+ for (const key of keys$2(primingWork.records)) {
53088
+ let work = primingWork.records[key];
53089
+ let limitedIds = [];
53090
+ for (const id of work.ids) {
53091
+ let retryCount = this.retryTracker.get(id) || 0;
53092
+ retryCount += 1;
53093
+ if (retryCount > MAX_RETRY_COUNT) {
53094
+ limitedIds.push(id);
53095
+ this.retryTracker.delete(id);
53096
+ }
53097
+ else {
53098
+ this.retryTracker.set(id, retryCount);
53099
+ }
53100
+ }
53101
+ if (limitedIds.length < work.ids.length) {
53102
+ retryableWork.records[key] = {
53103
+ ids: work.ids.filter((id) => limitedIds.indexOf(id) === -1),
53104
+ fields: work.fields,
53105
+ };
53106
+ }
53107
+ if (limitedIds.length > 0) {
53108
+ this.emit('retry-limit-reached', { ids: limitedIds });
53109
+ refetchableWork.set(key, {
53110
+ ids: limitedIds,
53111
+ fields: work.fields,
53112
+ });
53113
+ }
53114
+ }
53115
+ return {
53116
+ additionalWork: retryableWork,
53117
+ recordsNeedingRefetch: refetchableWork,
53118
+ resolvedRecords: [],
53119
+ recordsToWrite: [],
53120
+ errors: [],
53121
+ };
53122
+ }
52949
53123
  async fetchMetadata(batches) {
52950
53124
  const apiNames = Array.from(batches.reduce((acc, x) => {
52951
53125
  return acc.add(x.type);
@@ -52953,20 +53127,20 @@ class PrimingSession extends EventEmitter {
52953
53127
  const objectInfoMap = await this.objectInfoLoader.getObjectInfos(apiNames);
52954
53128
  const unavailableTypes = apiNames.filter((x) => !objectInfoMap[x]);
52955
53129
  const availableTypes = apiNames.filter((x) => objectInfoMap[x]);
52956
- const unavilableBatches = batches.filter((x) => unavailableTypes.includes(x.type));
53130
+ const unavailableBatches = batches.filter((x) => unavailableTypes.includes(x.type));
52957
53131
  const availableBatches = batches
52958
53132
  .filter((x) => !unavailableTypes.includes(x.type))
52959
53133
  .map((x) => {
52960
53134
  return { ...x, objectInfo: objectInfoMap[x.type] };
52961
53135
  });
52962
- const unavailableIds = unavilableBatches.reduce((acc, x) => {
53136
+ const unavailableIds = unavailableBatches.reduce((acc, x) => {
52963
53137
  acc.push(...x.ids);
52964
53138
  return acc;
52965
53139
  }, []);
52966
53140
  return {
52967
53141
  apiNames,
52968
53142
  availableBatches,
52969
- unavilableBatches,
53143
+ unavailableBatches,
52970
53144
  unavailableTypes,
52971
53145
  availableTypes,
52972
53146
  unavailableIds,
@@ -53196,7 +53370,9 @@ class RecordLoaderGraphQL extends NetworkRecordLoader {
53196
53370
  return acc;
53197
53371
  }, {});
53198
53372
  fields['Id'] = { value: id, displayValue: null };
53199
- fields['RecordTypeId'] = { value: recordTypeId, displayValue: null };
53373
+ if (objectInfo.fields['RecordTypeId'] !== undefined) {
53374
+ fields['RecordTypeId'] = { value: recordTypeId, displayValue: null };
53375
+ }
53200
53376
  let recordTypeInfo = null;
53201
53377
  if (recordTypeId !== null &&
53202
53378
  objectInfo.recordTypeInfos &&
@@ -55496,4 +55672,4 @@ register({
55496
55672
  });
55497
55673
 
55498
55674
  export { O11Y_NAMESPACE_LDS_MOBILE, getRuntime, ingest$1o as ingestDenormalizedRecordRepresentation, registerReportObserver, reportGraphqlQueryParseError };
55499
- // version: 1.352.0-9307541b03
55675
+ // version: 1.353.0-cc9b469dc4
@@ -4,7 +4,7 @@ import type { PrimingStore } from './PrimingStore';
4
4
  import type { PrimingWork } from './types';
5
5
  import type { ObjectInfoLoader } from './ObjectInfoLoader';
6
6
  type ConflictResolutionError = 'object-info-missing';
7
- interface ConflictResolutionResult {
7
+ export interface ConflictResolutionResult {
8
8
  additionalWork: PrimingWork;
9
9
  recordsToWrite: DurableRecordRepresentation[];
10
10
  resolvedRecords: string[];
@@ -5,6 +5,7 @@ import type { ObjectInfoLoader } from './ObjectInfoLoader';
5
5
  import type { PrimingStore } from './PrimingStore';
6
6
  import type { LdsRecordRefresher } from './LdsRecordRefresher';
7
7
  import { EventEmitter } from './Emitter';
8
+ export declare const instrumentation: import("o11y/dist/modules/o11y/client/interfaces").Instrumentation;
8
9
  export interface PrimingSessionConfig {
9
10
  store: PrimingStore;
10
11
  recordLoader: RecordLoader;
@@ -36,6 +37,9 @@ export interface PrimingEvents {
36
37
  errors: string[];
37
38
  duration: number;
38
39
  };
40
+ 'retry-limit-reached': {
41
+ ids: string[];
42
+ };
39
43
  }
40
44
  interface EventErrorPayload {
41
45
  ids: string[];
@@ -56,13 +60,16 @@ export declare class PrimingSession extends EventEmitter<PrimingEvents> {
56
60
  private networkWorkerPool;
57
61
  private conflictPool;
58
62
  private ldsRecordRefresher;
63
+ private retryTracker;
59
64
  constructor(config: PrimingSessionConfig);
60
65
  enqueue(work: PrimingWork): Promise<void>;
61
66
  cancel(): void;
67
+ private handleInstrumentation;
62
68
  private enqueueBatches;
63
69
  private handlePaginations;
64
70
  private processFetchedRecords;
65
71
  private handleWriteConflicts;
72
+ private applyRetryLimits;
66
73
  private fetchMetadata;
67
74
  }
68
75
  export {};