@salesforce/lds-runtime-mobile 1.428.0-dev20 → 1.428.0-dev21

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
@@ -42261,6 +42261,10 @@ const DRAFT_QUEUE_ACTION_UPDATED = 'draft-queue-action-updated';
42261
42261
  const DRAFT_QUEUE_ACTION_FAILED = 'draft-queue-action-failed';
42262
42262
  const DRAFT_QUEUE_ACTION_UPLOAD_ERROR = 'draft-queue-action-upload-error';
42263
42263
  const DRAFT_QUEUE_TOTAL_MERGE_ACTIONS_CALLS = 'draft-queue-total-mergeActions-calls';
42264
+ // Emitted every time a draft's Idempotency-Key is rotated (replaced with a fresh uuid).
42265
+ // Used to triage the WOLI duplicate-record investigation in Splunk — correlate by draftId
42266
+ // with the other draft-queue events. @W-23428669
42267
+ const DRAFT_QUEUE_IDEMPOTENCY_KEY_ROTATED = 'draft-queue-idempotency-key-rotated';
42264
42268
  /** Content Document */
42265
42269
  const CREATE_CONTENT_DOCUMENT_AND_VERSION_TOTAL_SYNTHESIZE_CALLS = 'content-document-version-total-synthesize-calls';
42266
42270
  const CREATE_CONTENT_DOCUMENT_AND_VERSION_DRAFT_SYNTHESIZE_ERROR = 'create-content-document-version-draft-synthesize-error';
@@ -42376,6 +42380,34 @@ function reportDraftActionUploadError(error, handlerId, attempt) {
42376
42380
  });
42377
42381
  ldsMobileInstrumentation.error(normalized, DRAFT_QUEUE_ACTION_UPLOAD_ERROR);
42378
42382
  }
42383
+ /**
42384
+ * Emits a single greppable Splunk log line (and an o11y counter) every time a draft's
42385
+ * Idempotency-Key is rotated — i.e. replaced with a fresh uuid rather than reused on
42386
+ * retry. This is the instrumentation for the WOLI duplicate-record investigation
42387
+ * (@W-23428669): a rotation mid-flight is the mechanism by which an already-committed
42388
+ * write can be re-sent under a new key and duplicated on the server, so recording every
42389
+ * rotation lets us reconstruct, on a future reproduction, exactly where and how often a
42390
+ * key changed for a given draft.
42391
+ *
42392
+ * The message is prefixed with a stable literal ("Idempotency key rotated") so it can be
42393
+ * pulled out of Splunk with a substring match, and carries:
42394
+ * - draftId: the local (client-synthesized) draft-action target id, so this event can be
42395
+ * correlated with the other draft-queue events for the same draft. This is NOT a server
42396
+ * record id or any field value — it is the same local id already surfaced by the queue's
42397
+ * other lifecycle logs, so it introduces no new PII.
42398
+ * - reason: which rotation call site fired, to disambiguate the distinct rotation paths.
42399
+ *
42400
+ * @param draftId the local draft-action target id whose key was rotated
42401
+ * @param reason the rotation call site (see IdempotencyKeyRotationReason)
42402
+ */
42403
+ function reportIdempotencyKeyRotated(draftId, reason) {
42404
+ if (nimbusLogger) {
42405
+ nimbusLogger.logInfo(`Idempotency key rotated: draftId=${draftId}, reason=${reason}`);
42406
+ }
42407
+ ldsMobileInstrumentation.incrementCounter(DRAFT_QUEUE_IDEMPOTENCY_KEY_ROTATED, 1, undefined, {
42408
+ reason,
42409
+ });
42410
+ }
42379
42411
  function reportDraftQueueState(state, draftCount) {
42380
42412
  if (nimbusLogger) {
42381
42413
  nimbusLogger.logInfo(`Draft state changed: ${state}, depth: ${draftCount}`);
@@ -42612,6 +42644,7 @@ class AbstractResourceRequestActionHandler {
42612
42644
  // error (shouldRetry stays false). Retained as the default until the fix is
42613
42645
  // enabled; this is the path that duplicated already-committed writes.
42614
42646
  updatedAction.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
42647
+ reportIdempotencyKeyRotated(updatedAction.targetId, 'generic-400-killswitch');
42615
42648
  actionDataChanged = true;
42616
42649
  }
42617
42650
  else if (!this.isServerGeneratedError(response.body)) {
@@ -42643,6 +42676,7 @@ class AbstractResourceRequestActionHandler {
42643
42676
  if (this.hasIdempotencySupport() &&
42644
42677
  updatedAction.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY] !== undefined) {
42645
42678
  updatedAction.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
42679
+ reportIdempotencyKeyRotated(updatedAction.targetId, 'backdating-collision');
42646
42680
  }
42647
42681
  shouldRetry = true;
42648
42682
  actionDataChanged = true;
@@ -42936,6 +42970,7 @@ class AbstractResourceRequestActionHandler {
42936
42970
  // Updates Idempotency key if target has one
42937
42971
  if (targetData.headers && targetData.headers[HTTP_HEADER_IDEMPOTENCY_KEY]) {
42938
42972
  merged.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
42973
+ reportIdempotencyKeyRotated(merged.targetId, 'merge-actions');
42939
42974
  }
42940
42975
  // overlay metadata
42941
42976
  merged.metadata = { ...targetMetadata, ...sourceMetadata };
@@ -42965,6 +43000,7 @@ class AbstractResourceRequestActionHandler {
42965
43000
  action.data.headers = action.data.headers || {};
42966
43001
  if (updateIdempotencyKey) {
42967
43002
  action.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
43003
+ reportIdempotencyKeyRotated(action.targetId, 'idempotency-error');
42968
43004
  }
42969
43005
  else {
42970
43006
  delete action.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY];
@@ -59188,7 +59224,7 @@ function buildServiceDescriptor$b(luvio) {
59188
59224
  },
59189
59225
  };
59190
59226
  }
59191
- // version: 1.428.0-dev20-d72ac06681
59227
+ // version: 1.428.0-dev21-133a7da4f5
59192
59228
 
59193
59229
  /**
59194
59230
  * Copyright (c) 2022, Salesforce, Inc.,
@@ -59214,7 +59250,7 @@ function buildServiceDescriptor$a(notifyRecordUpdateAvailable, getNormalizedLuvi
59214
59250
  },
59215
59251
  };
59216
59252
  }
59217
- // version: 1.428.0-dev20-d72ac06681
59253
+ // version: 1.428.0-dev21-133a7da4f5
59218
59254
 
59219
59255
  /*!
59220
59256
  * Copyright (c) 2022, Salesforce, Inc.,
@@ -61951,4 +61987,4 @@ register({
61951
61987
  });
61952
61988
 
61953
61989
  export { O11Y_NAMESPACE_LDS_MOBILE, getRuntime, ingest$1o as ingestDenormalizedRecordRepresentation, initializeOneStore, registerReportObserver, reportGraphqlQueryParseError };
61954
- // version: 1.428.0-dev20-1b319a0432
61990
+ // version: 1.428.0-dev21-c9faba50c9
@@ -24,6 +24,28 @@ export declare function reportDraftActionEvent(state: 'added' | 'uploading' | 'c
24
24
  * the action's targetId/tag or any request body/field values.
25
25
  */
26
26
  export declare function reportDraftActionUploadError(error: unknown, handlerId: string, attempt: number): void;
27
+ export type IdempotencyKeyRotationReason = 'idempotency-error' | 'backdating-collision' | 'merge-actions' | 'generic-400-killswitch';
28
+ /**
29
+ * Emits a single greppable Splunk log line (and an o11y counter) every time a draft's
30
+ * Idempotency-Key is rotated — i.e. replaced with a fresh uuid rather than reused on
31
+ * retry. This is the instrumentation for the WOLI duplicate-record investigation
32
+ * (@W-23428669): a rotation mid-flight is the mechanism by which an already-committed
33
+ * write can be re-sent under a new key and duplicated on the server, so recording every
34
+ * rotation lets us reconstruct, on a future reproduction, exactly where and how often a
35
+ * key changed for a given draft.
36
+ *
37
+ * The message is prefixed with a stable literal ("Idempotency key rotated") so it can be
38
+ * pulled out of Splunk with a substring match, and carries:
39
+ * - draftId: the local (client-synthesized) draft-action target id, so this event can be
40
+ * correlated with the other draft-queue events for the same draft. This is NOT a server
41
+ * record id or any field value — it is the same local id already surfaced by the queue's
42
+ * other lifecycle logs, so it introduces no new PII.
43
+ * - reason: which rotation call site fired, to disambiguate the distinct rotation paths.
44
+ *
45
+ * @param draftId the local draft-action target id whose key was rotated
46
+ * @param reason the rotation call site (see IdempotencyKeyRotationReason)
47
+ */
48
+ export declare function reportIdempotencyKeyRotated(draftId: string, reason: IdempotencyKeyRotationReason): void;
27
49
  export declare function reportDraftQueueState(state: 'started' | 'error' | 'waiting' | 'stopped', draftCount: number): void;
28
50
  export declare function reportDraftAwareContentDocumentVersionSynthesizeError(err: unknown): void;
29
51
  export declare function reportDraftAwareContentVersionSynthesizeCalls(mimeType: string): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/lds-runtime-mobile",
3
- "version": "1.428.0-dev20",
3
+ "version": "1.428.0-dev21",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "LDS runtime for mobile/hybrid environments.",
6
6
  "main": "dist/main.js",
@@ -35,11 +35,11 @@
35
35
  "@conduit-client/service-bindings-imperative": "3.19.0-dev3",
36
36
  "@conduit-client/service-bindings-lwc": "3.19.0-dev3",
37
37
  "@conduit-client/service-provisioner": "3.19.0-dev3",
38
- "@salesforce/lds-adapters-uiapi": "^1.428.0-dev20",
39
- "@salesforce/lds-bindings": "^1.428.0-dev20",
40
- "@salesforce/lds-instrumentation": "^1.428.0-dev20",
41
- "@salesforce/lds-luvio-service": "^1.428.0-dev20",
42
- "@salesforce/lds-luvio-uiapi-records-service": "^1.428.0-dev20",
38
+ "@salesforce/lds-adapters-uiapi": "^1.428.0-dev21",
39
+ "@salesforce/lds-bindings": "^1.428.0-dev21",
40
+ "@salesforce/lds-instrumentation": "^1.428.0-dev21",
41
+ "@salesforce/lds-luvio-service": "^1.428.0-dev21",
42
+ "@salesforce/lds-luvio-uiapi-records-service": "^1.428.0-dev21",
43
43
  "@salesforce/user": "0.0.21",
44
44
  "o11y": "250.7.0",
45
45
  "o11y_schema": "256.126.0"
@@ -60,16 +60,16 @@
60
60
  "@conduit-client/service-pubsub": "3.19.0-dev3",
61
61
  "@conduit-client/service-store": "3.19.0-dev3",
62
62
  "@conduit-client/utils": "3.19.0-dev3",
63
- "@salesforce/lds-adapters-graphql": "^1.428.0-dev20",
64
- "@salesforce/lds-drafts": "^1.428.0-dev20",
65
- "@salesforce/lds-durable-records": "^1.428.0-dev20",
66
- "@salesforce/lds-network-adapter": "^1.428.0-dev20",
67
- "@salesforce/lds-network-nimbus": "^1.428.0-dev20",
68
- "@salesforce/lds-store-binary": "^1.428.0-dev20",
69
- "@salesforce/lds-store-nimbus": "^1.428.0-dev20",
70
- "@salesforce/lds-store-sql": "^1.428.0-dev20",
71
- "@salesforce/lds-utils-adapters": "^1.428.0-dev20",
72
- "@salesforce/nimbus-plugin-lds": "^1.428.0-dev20",
63
+ "@salesforce/lds-adapters-graphql": "^1.428.0-dev21",
64
+ "@salesforce/lds-drafts": "^1.428.0-dev21",
65
+ "@salesforce/lds-durable-records": "^1.428.0-dev21",
66
+ "@salesforce/lds-network-adapter": "^1.428.0-dev21",
67
+ "@salesforce/lds-network-nimbus": "^1.428.0-dev21",
68
+ "@salesforce/lds-store-binary": "^1.428.0-dev21",
69
+ "@salesforce/lds-store-nimbus": "^1.428.0-dev21",
70
+ "@salesforce/lds-store-sql": "^1.428.0-dev21",
71
+ "@salesforce/lds-utils-adapters": "^1.428.0-dev21",
72
+ "@salesforce/nimbus-plugin-lds": "^1.428.0-dev21",
73
73
  "babel-plugin-dynamic-import-node": "^2.3.3",
74
74
  "wait-for-expect": "^3.0.2"
75
75
  },
package/sfdc/main.js CHANGED
@@ -42261,6 +42261,10 @@ const DRAFT_QUEUE_ACTION_UPDATED = 'draft-queue-action-updated';
42261
42261
  const DRAFT_QUEUE_ACTION_FAILED = 'draft-queue-action-failed';
42262
42262
  const DRAFT_QUEUE_ACTION_UPLOAD_ERROR = 'draft-queue-action-upload-error';
42263
42263
  const DRAFT_QUEUE_TOTAL_MERGE_ACTIONS_CALLS = 'draft-queue-total-mergeActions-calls';
42264
+ // Emitted every time a draft's Idempotency-Key is rotated (replaced with a fresh uuid).
42265
+ // Used to triage the WOLI duplicate-record investigation in Splunk — correlate by draftId
42266
+ // with the other draft-queue events. @W-23428669
42267
+ const DRAFT_QUEUE_IDEMPOTENCY_KEY_ROTATED = 'draft-queue-idempotency-key-rotated';
42264
42268
  /** Content Document */
42265
42269
  const CREATE_CONTENT_DOCUMENT_AND_VERSION_TOTAL_SYNTHESIZE_CALLS = 'content-document-version-total-synthesize-calls';
42266
42270
  const CREATE_CONTENT_DOCUMENT_AND_VERSION_DRAFT_SYNTHESIZE_ERROR = 'create-content-document-version-draft-synthesize-error';
@@ -42376,6 +42380,34 @@ function reportDraftActionUploadError(error, handlerId, attempt) {
42376
42380
  });
42377
42381
  ldsMobileInstrumentation.error(normalized, DRAFT_QUEUE_ACTION_UPLOAD_ERROR);
42378
42382
  }
42383
+ /**
42384
+ * Emits a single greppable Splunk log line (and an o11y counter) every time a draft's
42385
+ * Idempotency-Key is rotated — i.e. replaced with a fresh uuid rather than reused on
42386
+ * retry. This is the instrumentation for the WOLI duplicate-record investigation
42387
+ * (@W-23428669): a rotation mid-flight is the mechanism by which an already-committed
42388
+ * write can be re-sent under a new key and duplicated on the server, so recording every
42389
+ * rotation lets us reconstruct, on a future reproduction, exactly where and how often a
42390
+ * key changed for a given draft.
42391
+ *
42392
+ * The message is prefixed with a stable literal ("Idempotency key rotated") so it can be
42393
+ * pulled out of Splunk with a substring match, and carries:
42394
+ * - draftId: the local (client-synthesized) draft-action target id, so this event can be
42395
+ * correlated with the other draft-queue events for the same draft. This is NOT a server
42396
+ * record id or any field value — it is the same local id already surfaced by the queue's
42397
+ * other lifecycle logs, so it introduces no new PII.
42398
+ * - reason: which rotation call site fired, to disambiguate the distinct rotation paths.
42399
+ *
42400
+ * @param draftId the local draft-action target id whose key was rotated
42401
+ * @param reason the rotation call site (see IdempotencyKeyRotationReason)
42402
+ */
42403
+ function reportIdempotencyKeyRotated(draftId, reason) {
42404
+ if (nimbusLogger) {
42405
+ nimbusLogger.logInfo(`Idempotency key rotated: draftId=${draftId}, reason=${reason}`);
42406
+ }
42407
+ ldsMobileInstrumentation.incrementCounter(DRAFT_QUEUE_IDEMPOTENCY_KEY_ROTATED, 1, undefined, {
42408
+ reason,
42409
+ });
42410
+ }
42379
42411
  function reportDraftQueueState(state, draftCount) {
42380
42412
  if (nimbusLogger) {
42381
42413
  nimbusLogger.logInfo(`Draft state changed: ${state}, depth: ${draftCount}`);
@@ -42612,6 +42644,7 @@ class AbstractResourceRequestActionHandler {
42612
42644
  // error (shouldRetry stays false). Retained as the default until the fix is
42613
42645
  // enabled; this is the path that duplicated already-committed writes.
42614
42646
  updatedAction.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
42647
+ reportIdempotencyKeyRotated(updatedAction.targetId, 'generic-400-killswitch');
42615
42648
  actionDataChanged = true;
42616
42649
  }
42617
42650
  else if (!this.isServerGeneratedError(response.body)) {
@@ -42643,6 +42676,7 @@ class AbstractResourceRequestActionHandler {
42643
42676
  if (this.hasIdempotencySupport() &&
42644
42677
  updatedAction.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY] !== undefined) {
42645
42678
  updatedAction.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
42679
+ reportIdempotencyKeyRotated(updatedAction.targetId, 'backdating-collision');
42646
42680
  }
42647
42681
  shouldRetry = true;
42648
42682
  actionDataChanged = true;
@@ -42936,6 +42970,7 @@ class AbstractResourceRequestActionHandler {
42936
42970
  // Updates Idempotency key if target has one
42937
42971
  if (targetData.headers && targetData.headers[HTTP_HEADER_IDEMPOTENCY_KEY]) {
42938
42972
  merged.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
42973
+ reportIdempotencyKeyRotated(merged.targetId, 'merge-actions');
42939
42974
  }
42940
42975
  // overlay metadata
42941
42976
  merged.metadata = { ...targetMetadata, ...sourceMetadata };
@@ -42965,6 +43000,7 @@ class AbstractResourceRequestActionHandler {
42965
43000
  action.data.headers = action.data.headers || {};
42966
43001
  if (updateIdempotencyKey) {
42967
43002
  action.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
43003
+ reportIdempotencyKeyRotated(action.targetId, 'idempotency-error');
42968
43004
  }
42969
43005
  else {
42970
43006
  delete action.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY];
@@ -59188,7 +59224,7 @@ function buildServiceDescriptor$b(luvio) {
59188
59224
  },
59189
59225
  };
59190
59226
  }
59191
- // version: 1.428.0-dev20-d72ac06681
59227
+ // version: 1.428.0-dev21-133a7da4f5
59192
59228
 
59193
59229
  /**
59194
59230
  * Copyright (c) 2022, Salesforce, Inc.,
@@ -59214,7 +59250,7 @@ function buildServiceDescriptor$a(notifyRecordUpdateAvailable, getNormalizedLuvi
59214
59250
  },
59215
59251
  };
59216
59252
  }
59217
- // version: 1.428.0-dev20-d72ac06681
59253
+ // version: 1.428.0-dev21-133a7da4f5
59218
59254
 
59219
59255
  /*!
59220
59256
  * Copyright (c) 2022, Salesforce, Inc.,
@@ -61951,4 +61987,4 @@ register({
61951
61987
  });
61952
61988
 
61953
61989
  export { O11Y_NAMESPACE_LDS_MOBILE, getRuntime, ingest$1o as ingestDenormalizedRecordRepresentation, initializeOneStore, registerReportObserver, reportGraphqlQueryParseError };
61954
- // version: 1.428.0-dev20-1b319a0432
61990
+ // version: 1.428.0-dev21-c9faba50c9
@@ -24,6 +24,28 @@ export declare function reportDraftActionEvent(state: 'added' | 'uploading' | 'c
24
24
  * the action's targetId/tag or any request body/field values.
25
25
  */
26
26
  export declare function reportDraftActionUploadError(error: unknown, handlerId: string, attempt: number): void;
27
+ export type IdempotencyKeyRotationReason = 'idempotency-error' | 'backdating-collision' | 'merge-actions' | 'generic-400-killswitch';
28
+ /**
29
+ * Emits a single greppable Splunk log line (and an o11y counter) every time a draft's
30
+ * Idempotency-Key is rotated — i.e. replaced with a fresh uuid rather than reused on
31
+ * retry. This is the instrumentation for the WOLI duplicate-record investigation
32
+ * (@W-23428669): a rotation mid-flight is the mechanism by which an already-committed
33
+ * write can be re-sent under a new key and duplicated on the server, so recording every
34
+ * rotation lets us reconstruct, on a future reproduction, exactly where and how often a
35
+ * key changed for a given draft.
36
+ *
37
+ * The message is prefixed with a stable literal ("Idempotency key rotated") so it can be
38
+ * pulled out of Splunk with a substring match, and carries:
39
+ * - draftId: the local (client-synthesized) draft-action target id, so this event can be
40
+ * correlated with the other draft-queue events for the same draft. This is NOT a server
41
+ * record id or any field value — it is the same local id already surfaced by the queue's
42
+ * other lifecycle logs, so it introduces no new PII.
43
+ * - reason: which rotation call site fired, to disambiguate the distinct rotation paths.
44
+ *
45
+ * @param draftId the local draft-action target id whose key was rotated
46
+ * @param reason the rotation call site (see IdempotencyKeyRotationReason)
47
+ */
48
+ export declare function reportIdempotencyKeyRotated(draftId: string, reason: IdempotencyKeyRotationReason): void;
27
49
  export declare function reportDraftQueueState(state: 'started' | 'error' | 'waiting' | 'stopped', draftCount: number): void;
28
50
  export declare function reportDraftAwareContentDocumentVersionSynthesizeError(err: unknown): void;
29
51
  export declare function reportDraftAwareContentVersionSynthesizeCalls(mimeType: string): void;