@salesforce/lds-runtime-mobile 1.172.0 → 1.174.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/main.js +86 -15
  2. package/package.json +3 -3
  3. package/sfdc/main.js +86 -15
package/dist/main.js CHANGED
@@ -4948,13 +4948,40 @@ function uuidv4() {
4948
4948
  return uuid.join('');
4949
4949
  }
4950
4950
 
4951
- const IdempotencyKey = 'Idempotency-Key';
4951
+ const HTTP_HEADER_RETRY_AFTER = 'Retry-After';
4952
+ const HTTP_HEADER_IDEMPOTENCY_KEY = 'Idempotency-Key';
4953
+ const ERROR_CODE_IDEMPOTENCY_KEY_USED_DIFFERENT_USER = 'IDEMPOTENCY_KEY_USED_DIFFERENT_USER';
4954
+ const ERROR_CODE_IDEMPOTENCY_CONCURRENT_REQUEST = 'IDEMPOTENCY_CONCURRENT_REQUEST';
4955
+ /**
4956
+ * Get the retry after in milliseconds from the response headers, undefined if not specified.
4957
+ * The header could have two different format.
4958
+ * Retry-After: <http-date>, like Wed, 21 Oct 2015 07:28:00 GMT
4959
+ * Retry-After: <delay-seconds>, like 1.5s
4960
+ * @param headers http headers
4961
+ * @returns the time to delat in millisconds.
4962
+ */
4963
+ function getRetryAfterInMs(headers) {
4964
+ const retryAfterHeader = headers && headers[HTTP_HEADER_RETRY_AFTER];
4965
+ if (retryAfterHeader === undefined) {
4966
+ return undefined;
4967
+ }
4968
+ const delayInSecond = parseFloat(retryAfterHeader);
4969
+ if (retryAfterHeader === delayInSecond.toString()) {
4970
+ return Math.round(delayInSecond * 1000);
4971
+ }
4972
+ const delayUntilDateTime = Date.parse(retryAfterHeader);
4973
+ if (isNaN(delayUntilDateTime)) {
4974
+ return undefined;
4975
+ }
4976
+ return delayUntilDateTime - Date.now();
4977
+ }
4978
+
4952
4979
  function buildLuvioOverrideForDraftAdapters(luvio, handler, extractTargetIdFromCacheKey, options = {}) {
4953
4980
  // override this to create and enqueue a new draft action, and return synthetic response
4954
4981
  const dispatchResourceRequest = async function (resourceRequest, _context) {
4955
4982
  const resourceRequestCopy = clone$1(resourceRequest);
4956
4983
  resourceRequestCopy.headers = resourceRequestCopy.headers || {};
4957
- resourceRequestCopy.headers[IdempotencyKey] = uuidv4();
4984
+ resourceRequestCopy.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
4958
4985
  const { data } = await handler.enqueue(resourceRequestCopy).catch((err) => {
4959
4986
  throw transformErrorToDraftSynthesisError(err);
4960
4987
  });
@@ -5317,11 +5344,19 @@ class DurableDraftQueue {
5317
5344
  },
5318
5345
  });
5319
5346
  }
5320
- async actionFailed(action, retry) {
5347
+ async actionFailed(action, retry, retryDelayInMs, actionDataChanged) {
5348
+ if (actionDataChanged === true) {
5349
+ await this.draftStore.writeAction({
5350
+ ...action,
5351
+ status: DraftActionStatus.Pending,
5352
+ });
5353
+ }
5321
5354
  this.uploadingActionId = undefined;
5322
5355
  if (retry && this.state !== DraftQueueState.Stopped) {
5323
5356
  this.state = DraftQueueState.Waiting;
5324
- this.scheduleRetry();
5357
+ return retryDelayInMs !== undefined
5358
+ ? this.scheduleRetryWithSpecifiedDelay(retryDelayInMs)
5359
+ : this.scheduleRetry();
5325
5360
  }
5326
5361
  else if (isDraftError(action)) {
5327
5362
  return this.handleServerError(action, action.error);
@@ -5467,14 +5502,17 @@ class DurableDraftQueue {
5467
5502
  });
5468
5503
  return action;
5469
5504
  }
5470
- scheduleRetry() {
5471
- const newInterval = this.retryIntervalMilliseconds * 2;
5472
- this.retryIntervalMilliseconds = Math.min(Math.max(newInterval, this.minimumRetryInterval), this.maximumRetryInterval);
5505
+ scheduleRetryWithSpecifiedDelay(retryDelayInMs) {
5473
5506
  this.timeoutHandler = setTimeout(() => {
5474
5507
  if (this.state !== DraftQueueState.Stopped) {
5475
5508
  this.processNextAction();
5476
5509
  }
5477
- }, this.retryIntervalMilliseconds);
5510
+ }, retryDelayInMs);
5511
+ }
5512
+ scheduleRetry() {
5513
+ const newInterval = this.retryIntervalMilliseconds * 2;
5514
+ this.retryIntervalMilliseconds = Math.min(Math.max(newInterval, this.minimumRetryInterval), this.maximumRetryInterval);
5515
+ this.scheduleRetryWithSpecifiedDelay(this.retryIntervalMilliseconds);
5478
5516
  }
5479
5517
  async getActionsForReplaceOrMerge(targetActionId, sourceActionId) {
5480
5518
  const actions = await this.getQueueActions();
@@ -5790,14 +5828,47 @@ class AbstractResourceRequestActionHandler {
5790
5828
  });
5791
5829
  return ProcessActionResult.ACTION_SUCCEEDED;
5792
5830
  }
5793
- await actionErrored({
5794
- ...action,
5795
- error: response,
5796
- status: DraftActionStatus.Error,
5797
- }, false);
5831
+ let shouldRetry = false;
5832
+ let retryDelayInMs = undefined;
5833
+ let actionDataChanged = false;
5834
+ let updatedAction = action;
5835
+ if (request && request.headers && request.headers[HTTP_HEADER_IDEMPOTENCY_KEY]) {
5836
+ const status = response.status;
5837
+ switch (status) {
5838
+ case 408 /* IdempotentWriteSpecificHttpStatusCode.RequestTimeout */:
5839
+ case 503 /* IdempotentWriteSpecificHttpStatusCode.ServiceUnavailable */:
5840
+ retryDelayInMs = getRetryAfterInMs(response.headers);
5841
+ shouldRetry = true;
5842
+ break;
5843
+ case HttpStatusCode.ServerError:
5844
+ shouldRetry = true;
5845
+ break;
5846
+ case 409 /* IdempotentWriteSpecificHttpStatusCode.Conflict */: {
5847
+ const errorCode = JSON.parse(response.body)[0].errorCode;
5848
+ if (errorCode === ERROR_CODE_IDEMPOTENCY_KEY_USED_DIFFERENT_USER) {
5849
+ updatedAction.data.headers = updatedAction.data.headers || {};
5850
+ updatedAction.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
5851
+ retryDelayInMs = 0;
5852
+ actionDataChanged = true;
5853
+ }
5854
+ else if (errorCode === ERROR_CODE_IDEMPOTENCY_CONCURRENT_REQUEST) {
5855
+ retryDelayInMs = getRetryAfterInMs(response.headers);
5856
+ }
5857
+ shouldRetry = true;
5858
+ break;
5859
+ }
5860
+ }
5861
+ }
5862
+ await actionErrored(shouldRetry
5863
+ ? updatedAction
5864
+ : {
5865
+ ...updatedAction,
5866
+ error: response,
5867
+ status: DraftActionStatus.Error,
5868
+ }, shouldRetry, retryDelayInMs, actionDataChanged);
5798
5869
  return ProcessActionResult.ACTION_ERRORED;
5799
5870
  }
5800
- catch (_a) {
5871
+ catch (e) {
5801
5872
  await actionErrored(action, true);
5802
5873
  return ProcessActionResult.NETWORK_ERROR;
5803
5874
  }
@@ -16218,4 +16289,4 @@ register({
16218
16289
  });
16219
16290
 
16220
16291
  export { getRuntime, registerReportObserver, reportGraphqlQueryParseError };
16221
- // version: 1.172.0-54479eea8
16292
+ // version: 1.174.0-5f6c9e1e8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/lds-runtime-mobile",
3
- "version": "1.172.0",
3
+ "version": "1.174.0",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "LDS runtime for mobile/hybrid environments.",
6
6
  "main": "dist/main.js",
@@ -58,7 +58,7 @@
58
58
  "path": "./dist/main.js",
59
59
  "maxSize": {
60
60
  "none": "700 kB",
61
- "min": "282 kB",
61
+ "min": "283 kB",
62
62
  "compressed": "110 kB"
63
63
  }
64
64
  },
@@ -66,7 +66,7 @@
66
66
  "path": "./sfdc/main.js",
67
67
  "maxSize": {
68
68
  "none": "700 kB",
69
- "min": "282 kB",
69
+ "min": "283 kB",
70
70
  "compressed": "110 kB"
71
71
  }
72
72
  }
package/sfdc/main.js CHANGED
@@ -4948,13 +4948,40 @@ function uuidv4() {
4948
4948
  return uuid.join('');
4949
4949
  }
4950
4950
 
4951
- const IdempotencyKey = 'Idempotency-Key';
4951
+ const HTTP_HEADER_RETRY_AFTER = 'Retry-After';
4952
+ const HTTP_HEADER_IDEMPOTENCY_KEY = 'Idempotency-Key';
4953
+ const ERROR_CODE_IDEMPOTENCY_KEY_USED_DIFFERENT_USER = 'IDEMPOTENCY_KEY_USED_DIFFERENT_USER';
4954
+ const ERROR_CODE_IDEMPOTENCY_CONCURRENT_REQUEST = 'IDEMPOTENCY_CONCURRENT_REQUEST';
4955
+ /**
4956
+ * Get the retry after in milliseconds from the response headers, undefined if not specified.
4957
+ * The header could have two different format.
4958
+ * Retry-After: <http-date>, like Wed, 21 Oct 2015 07:28:00 GMT
4959
+ * Retry-After: <delay-seconds>, like 1.5s
4960
+ * @param headers http headers
4961
+ * @returns the time to delat in millisconds.
4962
+ */
4963
+ function getRetryAfterInMs(headers) {
4964
+ const retryAfterHeader = headers && headers[HTTP_HEADER_RETRY_AFTER];
4965
+ if (retryAfterHeader === undefined) {
4966
+ return undefined;
4967
+ }
4968
+ const delayInSecond = parseFloat(retryAfterHeader);
4969
+ if (retryAfterHeader === delayInSecond.toString()) {
4970
+ return Math.round(delayInSecond * 1000);
4971
+ }
4972
+ const delayUntilDateTime = Date.parse(retryAfterHeader);
4973
+ if (isNaN(delayUntilDateTime)) {
4974
+ return undefined;
4975
+ }
4976
+ return delayUntilDateTime - Date.now();
4977
+ }
4978
+
4952
4979
  function buildLuvioOverrideForDraftAdapters(luvio, handler, extractTargetIdFromCacheKey, options = {}) {
4953
4980
  // override this to create and enqueue a new draft action, and return synthetic response
4954
4981
  const dispatchResourceRequest = async function (resourceRequest, _context) {
4955
4982
  const resourceRequestCopy = clone$1(resourceRequest);
4956
4983
  resourceRequestCopy.headers = resourceRequestCopy.headers || {};
4957
- resourceRequestCopy.headers[IdempotencyKey] = uuidv4();
4984
+ resourceRequestCopy.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
4958
4985
  const { data } = await handler.enqueue(resourceRequestCopy).catch((err) => {
4959
4986
  throw transformErrorToDraftSynthesisError(err);
4960
4987
  });
@@ -5317,11 +5344,19 @@ class DurableDraftQueue {
5317
5344
  },
5318
5345
  });
5319
5346
  }
5320
- async actionFailed(action, retry) {
5347
+ async actionFailed(action, retry, retryDelayInMs, actionDataChanged) {
5348
+ if (actionDataChanged === true) {
5349
+ await this.draftStore.writeAction({
5350
+ ...action,
5351
+ status: DraftActionStatus.Pending,
5352
+ });
5353
+ }
5321
5354
  this.uploadingActionId = undefined;
5322
5355
  if (retry && this.state !== DraftQueueState.Stopped) {
5323
5356
  this.state = DraftQueueState.Waiting;
5324
- this.scheduleRetry();
5357
+ return retryDelayInMs !== undefined
5358
+ ? this.scheduleRetryWithSpecifiedDelay(retryDelayInMs)
5359
+ : this.scheduleRetry();
5325
5360
  }
5326
5361
  else if (isDraftError(action)) {
5327
5362
  return this.handleServerError(action, action.error);
@@ -5467,14 +5502,17 @@ class DurableDraftQueue {
5467
5502
  });
5468
5503
  return action;
5469
5504
  }
5470
- scheduleRetry() {
5471
- const newInterval = this.retryIntervalMilliseconds * 2;
5472
- this.retryIntervalMilliseconds = Math.min(Math.max(newInterval, this.minimumRetryInterval), this.maximumRetryInterval);
5505
+ scheduleRetryWithSpecifiedDelay(retryDelayInMs) {
5473
5506
  this.timeoutHandler = setTimeout(() => {
5474
5507
  if (this.state !== DraftQueueState.Stopped) {
5475
5508
  this.processNextAction();
5476
5509
  }
5477
- }, this.retryIntervalMilliseconds);
5510
+ }, retryDelayInMs);
5511
+ }
5512
+ scheduleRetry() {
5513
+ const newInterval = this.retryIntervalMilliseconds * 2;
5514
+ this.retryIntervalMilliseconds = Math.min(Math.max(newInterval, this.minimumRetryInterval), this.maximumRetryInterval);
5515
+ this.scheduleRetryWithSpecifiedDelay(this.retryIntervalMilliseconds);
5478
5516
  }
5479
5517
  async getActionsForReplaceOrMerge(targetActionId, sourceActionId) {
5480
5518
  const actions = await this.getQueueActions();
@@ -5790,14 +5828,47 @@ class AbstractResourceRequestActionHandler {
5790
5828
  });
5791
5829
  return ProcessActionResult.ACTION_SUCCEEDED;
5792
5830
  }
5793
- await actionErrored({
5794
- ...action,
5795
- error: response,
5796
- status: DraftActionStatus.Error,
5797
- }, false);
5831
+ let shouldRetry = false;
5832
+ let retryDelayInMs = undefined;
5833
+ let actionDataChanged = false;
5834
+ let updatedAction = action;
5835
+ if (request && request.headers && request.headers[HTTP_HEADER_IDEMPOTENCY_KEY]) {
5836
+ const status = response.status;
5837
+ switch (status) {
5838
+ case 408 /* IdempotentWriteSpecificHttpStatusCode.RequestTimeout */:
5839
+ case 503 /* IdempotentWriteSpecificHttpStatusCode.ServiceUnavailable */:
5840
+ retryDelayInMs = getRetryAfterInMs(response.headers);
5841
+ shouldRetry = true;
5842
+ break;
5843
+ case HttpStatusCode.ServerError:
5844
+ shouldRetry = true;
5845
+ break;
5846
+ case 409 /* IdempotentWriteSpecificHttpStatusCode.Conflict */: {
5847
+ const errorCode = JSON.parse(response.body)[0].errorCode;
5848
+ if (errorCode === ERROR_CODE_IDEMPOTENCY_KEY_USED_DIFFERENT_USER) {
5849
+ updatedAction.data.headers = updatedAction.data.headers || {};
5850
+ updatedAction.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
5851
+ retryDelayInMs = 0;
5852
+ actionDataChanged = true;
5853
+ }
5854
+ else if (errorCode === ERROR_CODE_IDEMPOTENCY_CONCURRENT_REQUEST) {
5855
+ retryDelayInMs = getRetryAfterInMs(response.headers);
5856
+ }
5857
+ shouldRetry = true;
5858
+ break;
5859
+ }
5860
+ }
5861
+ }
5862
+ await actionErrored(shouldRetry
5863
+ ? updatedAction
5864
+ : {
5865
+ ...updatedAction,
5866
+ error: response,
5867
+ status: DraftActionStatus.Error,
5868
+ }, shouldRetry, retryDelayInMs, actionDataChanged);
5798
5869
  return ProcessActionResult.ACTION_ERRORED;
5799
5870
  }
5800
- catch (_a) {
5871
+ catch (e) {
5801
5872
  await actionErrored(action, true);
5802
5873
  return ProcessActionResult.NETWORK_ERROR;
5803
5874
  }
@@ -16218,4 +16289,4 @@ register({
16218
16289
  });
16219
16290
 
16220
16291
  export { getRuntime, registerReportObserver, reportGraphqlQueryParseError };
16221
- // version: 1.172.0-54479eea8
16292
+ // version: 1.174.0-5f6c9e1e8