@salesforce/lds-runtime-mobile 1.428.0-dev14 → 1.428.0-dev15

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.
@@ -25,6 +25,28 @@ export declare abstract class AbstractResourceRequestActionHandler<ResponseType>
25
25
  enqueue(data: ResourceRequest): Promise<PendingDraftAction<ResourceRequest>>;
26
26
  buildPendingAction(request: ResourceRequest, queue: DraftAction<unknown, unknown>[]): Promise<PendingDraftAction<ResourceRequest>>;
27
27
  handleAction(action: DraftAction<ResourceRequest, ResponseType>, actionCompleted: (action: CompletedDraftAction<ResourceRequest, ResponseType>) => Promise<void>, actionErrored: (action: DraftAction<ResourceRequest, ResponseType>, retry: boolean, retryDelayInMs?: number, actionDataChanged?: boolean) => Promise<void>): Promise<ProcessActionResult>;
28
+ /**
29
+ * Reads the persisted upload retry-attempt count from the action's durable metadata
30
+ * bag. The count lives in metadata (rather than in-memory) so it survives app
31
+ * restarts and queue re-creation — the failure modes that let the unbounded retry
32
+ * loop run for days.
33
+ */
34
+ private getUploadRetryCount;
35
+ /**
36
+ * Enforces the upload retry-attempt cap around the queue's `actionErrored` callback.
37
+ * Both retry paths — a retryable HTTP error and a thrown exception — funnel through
38
+ * here.
39
+ *
40
+ * The entire cap behavior is gated behind `lmr.draft-queue-max-retry-attempts`. When
41
+ * the gate is CLOSED this is a transparent passthrough: it issues the same
42
+ * `actionErrored(action, true, ...)` retry the queue made before this change, and
43
+ * writes no extra metadata. When the gate is OPEN it persists an incremented attempt
44
+ * count to the action's durable metadata and, once the action has failed
45
+ * {@link MAX_RETRY_ATTEMPTS} times, transitions it to Error (carrying a
46
+ * FetchResponse-shaped error that names the failure that exhausted the retries)
47
+ * instead of scheduling yet another retry.
48
+ */
49
+ private retryOrCap;
28
50
  handleActionEnqueued(action: PendingDraftAction<ResourceRequest>): Promise<void>;
29
51
  handleActionRemoved(action: DraftAction<ResourceRequest, ResponseType>): Promise<void>;
30
52
  handleActionReplaced(target: DraftAction<ResourceRequest, ResponseType>, source: DraftAction<ResourceRequest, ResponseType>): Promise<void>;
@@ -1,4 +1,33 @@
1
+ import type { FetchResponse } from '@luvio/engine';
1
2
  /**
2
3
  * This function takes an unknown error and normalizes it to an Error object
3
4
  */
4
5
  export declare function normalizeError(error: unknown): Error;
6
+ /**
7
+ * Maximum number of times an action's upload will be retried before the action is
8
+ * transitioned to Error and surfaced to the consumer. Caps the otherwise-unbounded
9
+ * retry loop that can wedge the single-worker draft queue when an upload fails
10
+ * deterministically on every dispatch. Only enforced when the
11
+ * `lmr.draft-queue-max-retry-attempts` gate is open.
12
+ */
13
+ export declare const MAX_RETRY_ATTEMPTS = 5;
14
+ export declare const MAX_RETRY_ERROR_CODE = "MAX_RETRY_ATTEMPTS_EXCEEDED";
15
+ /**
16
+ * The two things that can cause an upload attempt to fail and be retried:
17
+ * - a non-ok `FetchResponse` returned by the network adapter (the HTTP error path), or
18
+ * - an `Error` thrown out of the dispatch and caught by `handleAction` (the catch path;
19
+ * the raw caught value is normalized to an `Error` before it reaches here).
20
+ * Either way the cause is concretely typed — it is never an opaque `unknown`.
21
+ */
22
+ export type UploadFailure = FetchResponse<unknown> | Error;
23
+ /**
24
+ * Builds the FetchResponse-shaped error attached to an action that has exhausted its
25
+ * upload retries. Shaped like a real network error response (status/statusText/ok/
26
+ * headers/body) so downstream consumers (DraftManager, queue instrumentation) that
27
+ * read `action.error.status`/`.body`/etc. behave consistently with a server error.
28
+ *
29
+ * The failure that caused the final attempt — a non-ok response (HTTP path) or a thrown
30
+ * error (catch path) — is folded into the body so the surfaced error says WHAT failed,
31
+ * not merely that the attempt cap was reached.
32
+ */
33
+ export declare function buildMaxRetryError(lastFailure: UploadFailure): FetchResponse<unknown>;
@@ -10,6 +10,20 @@ export declare function reportGraphqlAdapterError(errorCode: string): void;
10
10
  export declare function reportGraphqlQueryInstrumentation(data: QueryInstrumentation): void;
11
11
  export declare function incrementGraphQLRefreshUndfined(): void;
12
12
  export declare function reportDraftActionEvent(state: 'added' | 'uploading' | 'completed' | 'deleted' | 'updated' | 'failed', draftCount: number, message?: string): void;
13
+ /**
14
+ * Reports an exception thrown while uploading a draft action. The thrown error is
15
+ * otherwise swallowed by the upload handler's retry path, leaving the failure
16
+ * invisible in telemetry; this surfaces it to o11y (log + counter) so a deterministic
17
+ * upload failure can be diagnosed instead of silently retried forever.
18
+ *
19
+ * PII: the device log line carries only the handler id, retry attempt, and the error
20
+ * NAME (e.g. "TypeError") — never the free-text error message, which can embed record
21
+ * ids (URL path segments) or server field-validation strings. The full normalized error
22
+ * (message + stack) is handed only to `ldsMobileInstrumentation.error`, the structured
23
+ * o11y error pipeline responsible for scrubbing/handling that detail. Also does NOT log
24
+ * the action's targetId/tag or any request body/field values.
25
+ */
26
+ export declare function reportDraftActionUploadError(error: unknown, handlerId: string, attempt: number): void;
13
27
  export declare function reportDraftQueueState(state: 'started' | 'error' | 'waiting' | 'stopped', draftCount: number): void;
14
28
  export declare function reportDraftAwareContentDocumentVersionSynthesizeError(err: unknown): void;
15
29
  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-dev14",
3
+ "version": "1.428.0-dev15",
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-dev14",
39
- "@salesforce/lds-bindings": "^1.428.0-dev14",
40
- "@salesforce/lds-instrumentation": "^1.428.0-dev14",
41
- "@salesforce/lds-luvio-service": "^1.428.0-dev14",
42
- "@salesforce/lds-luvio-uiapi-records-service": "^1.428.0-dev14",
38
+ "@salesforce/lds-adapters-uiapi": "^1.428.0-dev15",
39
+ "@salesforce/lds-bindings": "^1.428.0-dev15",
40
+ "@salesforce/lds-instrumentation": "^1.428.0-dev15",
41
+ "@salesforce/lds-luvio-service": "^1.428.0-dev15",
42
+ "@salesforce/lds-luvio-uiapi-records-service": "^1.428.0-dev15",
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-dev14",
64
- "@salesforce/lds-drafts": "^1.428.0-dev14",
65
- "@salesforce/lds-durable-records": "^1.428.0-dev14",
66
- "@salesforce/lds-network-adapter": "^1.428.0-dev14",
67
- "@salesforce/lds-network-nimbus": "^1.428.0-dev14",
68
- "@salesforce/lds-store-binary": "^1.428.0-dev14",
69
- "@salesforce/lds-store-nimbus": "^1.428.0-dev14",
70
- "@salesforce/lds-store-sql": "^1.428.0-dev14",
71
- "@salesforce/lds-utils-adapters": "^1.428.0-dev14",
72
- "@salesforce/nimbus-plugin-lds": "^1.428.0-dev14",
63
+ "@salesforce/lds-adapters-graphql": "^1.428.0-dev15",
64
+ "@salesforce/lds-drafts": "^1.428.0-dev15",
65
+ "@salesforce/lds-durable-records": "^1.428.0-dev15",
66
+ "@salesforce/lds-network-adapter": "^1.428.0-dev15",
67
+ "@salesforce/lds-network-nimbus": "^1.428.0-dev15",
68
+ "@salesforce/lds-store-binary": "^1.428.0-dev15",
69
+ "@salesforce/lds-store-nimbus": "^1.428.0-dev15",
70
+ "@salesforce/lds-store-sql": "^1.428.0-dev15",
71
+ "@salesforce/lds-utils-adapters": "^1.428.0-dev15",
72
+ "@salesforce/nimbus-plugin-lds": "^1.428.0-dev15",
73
73
  "babel-plugin-dynamic-import-node": "^2.3.3",
74
74
  "wait-for-expect": "^3.0.2"
75
75
  },
@@ -77,7 +77,7 @@
77
77
  {
78
78
  "path": "./dist/main.js",
79
79
  "maxSize": {
80
- "none": "2.38 MB",
80
+ "none": "2.40 MB",
81
81
  "min": "1000 kB",
82
82
  "compressed": "250 kB"
83
83
  }
@@ -85,7 +85,7 @@
85
85
  {
86
86
  "path": "./sfdc/main.js",
87
87
  "maxSize": {
88
- "none": "2.37 MB",
88
+ "none": "2.40 MB",
89
89
  "min": "1000 kB",
90
90
  "compressed": "250 kB"
91
91
  }