@fixback/expo 0.1.0 → 0.2.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/auto-report-backoff.d.ts +5 -5
- package/dist/auto-report-backoff.js +5 -5
- package/dist/error-capture.d.ts +2 -2
- package/dist/error-capture.js +4 -4
- package/dist/report.d.ts +5 -5
- package/dist/submit.d.ts +3 -3
- package/dist/submit.js +6 -6
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Client-side backpressure for **automatic** error reports — a verbatim port of
|
|
3
3
|
* `packages/sdk/src/auto-report-backoff.ts` (spec 0003 §E/§H). When ingest
|
|
4
|
-
* sheds `source:
|
|
5
|
-
* honours it by holding a pause window during which further `source:
|
|
4
|
+
* sheds `source: error` load it answers `429` with a `Retry-After`; the SDK
|
|
5
|
+
* honours it by holding a pause window during which further `source: error`
|
|
6
6
|
* reports are dropped without touching the network. **Manual** reports — a
|
|
7
7
|
* human tapping Send — never consult this gate.
|
|
8
8
|
*/
|
|
@@ -19,17 +19,17 @@ export declare const DEFAULT_RETRY_AFTER_SECONDS = 60;
|
|
|
19
19
|
*/
|
|
20
20
|
export declare function parseRetryAfter(header: string | null | undefined, now: number): number;
|
|
21
21
|
/**
|
|
22
|
-
* A single pause window for `source:
|
|
22
|
+
* A single pause window for `source: error` reports. `hold` opens (or extends)
|
|
23
23
|
* it from a `429`'s `Retry-After`; `isPaused` reports whether it is still open.
|
|
24
24
|
* The default instance in `submit.ts` is shared across the app's reports so the
|
|
25
25
|
* hold persists across successive auto submissions.
|
|
26
26
|
*/
|
|
27
27
|
export declare class AutoReportBackoff {
|
|
28
28
|
private readonly now;
|
|
29
|
-
/** Epoch ms until which `source:
|
|
29
|
+
/** Epoch ms until which `source: error` reports are held; `0` when clear. */
|
|
30
30
|
private pausedUntil;
|
|
31
31
|
constructor(now?: Clock);
|
|
32
|
-
/** Is the `source:
|
|
32
|
+
/** Is the `source: error` pause window currently open? */
|
|
33
33
|
isPaused(): boolean;
|
|
34
34
|
/** Whole seconds remaining in the pause window (`0` when clear). */
|
|
35
35
|
retryAfterSeconds(): number;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Client-side backpressure for **automatic** error reports — a verbatim port of
|
|
3
3
|
* `packages/sdk/src/auto-report-backoff.ts` (spec 0003 §E/§H). When ingest
|
|
4
|
-
* sheds `source:
|
|
5
|
-
* honours it by holding a pause window during which further `source:
|
|
4
|
+
* sheds `source: error` load it answers `429` with a `Retry-After`; the SDK
|
|
5
|
+
* honours it by holding a pause window during which further `source: error`
|
|
6
6
|
* reports are dropped without touching the network. **Manual** reports — a
|
|
7
7
|
* human tapping Send — never consult this gate.
|
|
8
8
|
*/
|
|
@@ -31,19 +31,19 @@ export function parseRetryAfter(header, now) {
|
|
|
31
31
|
return DEFAULT_RETRY_AFTER_SECONDS;
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
|
-
* A single pause window for `source:
|
|
34
|
+
* A single pause window for `source: error` reports. `hold` opens (or extends)
|
|
35
35
|
* it from a `429`'s `Retry-After`; `isPaused` reports whether it is still open.
|
|
36
36
|
* The default instance in `submit.ts` is shared across the app's reports so the
|
|
37
37
|
* hold persists across successive auto submissions.
|
|
38
38
|
*/
|
|
39
39
|
export class AutoReportBackoff {
|
|
40
40
|
now;
|
|
41
|
-
/** Epoch ms until which `source:
|
|
41
|
+
/** Epoch ms until which `source: error` reports are held; `0` when clear. */
|
|
42
42
|
pausedUntil = 0;
|
|
43
43
|
constructor(now = Date.now) {
|
|
44
44
|
this.now = now;
|
|
45
45
|
}
|
|
46
|
-
/** Is the `source:
|
|
46
|
+
/** Is the `source: error` pause window currently open? */
|
|
47
47
|
isPaused() {
|
|
48
48
|
return this.now() < this.pausedUntil;
|
|
49
49
|
}
|
package/dist/error-capture.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* triggers (spec 0004 §E), ported from `packages/sdk/src/error-capture.ts`.
|
|
4
4
|
*
|
|
5
5
|
* Uncaught JS errors arrive through `ErrorUtils.setGlobalHandler` — React
|
|
6
|
-
* Native's one global error seam — and become `source:
|
|
6
|
+
* Native's one global error seam — and become `source: error`, `Kind = bug`
|
|
7
7
|
* Feedback for the current session's Reporter. The **previous handler is always
|
|
8
8
|
* chained afterwards**, so dev redboxes and other crash reporters keep working.
|
|
9
9
|
* Each firing is deduped by a per-session fingerprint, rate-limited by a
|
|
@@ -101,7 +101,7 @@ export interface AppStateLike {
|
|
|
101
101
|
/**
|
|
102
102
|
* Injectable collaborators, defaulted to the real implementations.
|
|
103
103
|
*
|
|
104
|
-
* Deliberately screenshot-free: a `source:
|
|
104
|
+
* Deliberately screenshot-free: a `source: error` report on mobile never
|
|
105
105
|
* attaches a screenshot. The composer's compensating privacy controls —
|
|
106
106
|
* preview and removal by the Reporter — cannot exist on a machine-filed
|
|
107
107
|
* report, and there is no client-side masking on mobile, so an auto
|
package/dist/error-capture.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* triggers (spec 0004 §E), ported from `packages/sdk/src/error-capture.ts`.
|
|
4
4
|
*
|
|
5
5
|
* Uncaught JS errors arrive through `ErrorUtils.setGlobalHandler` — React
|
|
6
|
-
* Native's one global error seam — and become `source:
|
|
6
|
+
* Native's one global error seam — and become `source: error`, `Kind = bug`
|
|
7
7
|
* Feedback for the current session's Reporter. The **previous handler is always
|
|
8
8
|
* chained afterwards**, so dev redboxes and other crash reporters keep working.
|
|
9
9
|
* Each firing is deduped by a per-session fingerprint, rate-limited by a
|
|
@@ -235,7 +235,7 @@ export function installErrorCapture(config) {
|
|
|
235
235
|
const seen = new Map();
|
|
236
236
|
/** Distinct auto-Feedback dropped by the burst limiter or the session cap. */
|
|
237
237
|
let dropped = 0;
|
|
238
|
-
/** Build the `source:
|
|
238
|
+
/** Build the `source: error` content for a fingerprint at a given count. */
|
|
239
239
|
function buildContent(fp, occurrences, opts) {
|
|
240
240
|
let environment;
|
|
241
241
|
try {
|
|
@@ -244,7 +244,7 @@ export function installErrorCapture(config) {
|
|
|
244
244
|
catch {
|
|
245
245
|
environment = collectEnvironment({}, sdkVersion);
|
|
246
246
|
}
|
|
247
|
-
// No Kind rides along (ADR-0023): the server stamps a `source:
|
|
247
|
+
// No Kind rides along (ADR-0023): the server stamps a `source: error`
|
|
248
248
|
// Issue `bug` deterministically.
|
|
249
249
|
const base = assembleContent({
|
|
250
250
|
url: config.currentUrl?.(),
|
|
@@ -253,7 +253,7 @@ export function installErrorCapture(config) {
|
|
|
253
253
|
reporterName: config.display?.name,
|
|
254
254
|
reporterEmail: config.display?.email,
|
|
255
255
|
});
|
|
256
|
-
return { ...base, source: "
|
|
256
|
+
return { ...base, source: "error", errorSignature: fp, occurrences };
|
|
257
257
|
}
|
|
258
258
|
/**
|
|
259
259
|
* Assemble, scrub, and ship one auto-Feedback (never a screenshot — see
|
package/dist/report.d.ts
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
import type { Breadcrumb } from "./breadcrumbs";
|
|
9
9
|
/**
|
|
10
10
|
* Where a Feedback came from — a human in the composer (`reporter`, the
|
|
11
|
-
* default) or the SDK's automatic error capture (`
|
|
11
|
+
* default) or the SDK's automatic error capture (`error`). Mirrors the server's
|
|
12
12
|
* `FEEDBACK_SOURCES`; the server derives trust independently.
|
|
13
13
|
*/
|
|
14
|
-
export type FeedbackSource = "reporter" | "
|
|
14
|
+
export type FeedbackSource = "reporter" | "error";
|
|
15
15
|
/** The capture environment recorded alongside a report. */
|
|
16
16
|
export interface CaptureEnvironment {
|
|
17
17
|
readonly viewportWidth?: number;
|
|
@@ -41,12 +41,12 @@ export interface ReportContent {
|
|
|
41
41
|
readonly trace?: readonly Breadcrumb[];
|
|
42
42
|
/**
|
|
43
43
|
* Provenance. Omitted for a manual report — the transport stamps the
|
|
44
|
-
* `reporter` default on the wire; set to `
|
|
44
|
+
* `reporter` default on the wire; set to `error` by the SDK's error capture.
|
|
45
45
|
*/
|
|
46
46
|
readonly source?: FeedbackSource;
|
|
47
|
-
/** For `source:
|
|
47
|
+
/** For `source: error` only — the SDK's per-session error fingerprint. */
|
|
48
48
|
readonly errorSignature?: string;
|
|
49
|
-
/** For `source:
|
|
49
|
+
/** For `source: error` only — the running occurrence count within the session. */
|
|
50
50
|
readonly occurrences?: number;
|
|
51
51
|
}
|
|
52
52
|
/** What the composer hands to {@link assembleContent} when the Reporter sends. */
|
package/dist/submit.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* The content-type header is deliberately not set, so the runtime writes the
|
|
15
15
|
* `multipart/form-data` boundary itself. Like `requestBoot`, this never throws:
|
|
16
16
|
* an unreachable Fixback or a refusal is a quiet result, so a Fixback problem
|
|
17
|
-
* never breaks the host app. Automatic reports (`source:
|
|
17
|
+
* never breaks the host app. Automatic reports (`source: error`) honour ingest's
|
|
18
18
|
* `429` + `Retry-After` backpressure; manual reports are never gated.
|
|
19
19
|
*/
|
|
20
20
|
import { AutoReportBackoff } from "./auto-report-backoff";
|
|
@@ -57,7 +57,7 @@ export type SubmitResult = {
|
|
|
57
57
|
readonly status?: number;
|
|
58
58
|
} | {
|
|
59
59
|
/**
|
|
60
|
-
* A `source:
|
|
60
|
+
* A `source: error` report shed under ingest backpressure — either held
|
|
61
61
|
* locally because the window is still open, or answered `429` by ingest,
|
|
62
62
|
* which opened/extended the window. Manual reports never produce this.
|
|
63
63
|
*/
|
|
@@ -89,7 +89,7 @@ export declare function feedbackEndpoint(apiUrl: string): string;
|
|
|
89
89
|
* and resolves to the recorded Feedback on success or a named failure
|
|
90
90
|
* otherwise.
|
|
91
91
|
*
|
|
92
|
-
* A `source:
|
|
92
|
+
* A `source: error` report first consults the shared backpressure window: while
|
|
93
93
|
* it is open the report is dropped without a request. Ingest's `429` +
|
|
94
94
|
* `Retry-After` opens/extends that window. Manual reports (`source: reporter`,
|
|
95
95
|
* the default) never consult the window and a non-2xx for them stays a plain
|
package/dist/submit.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* The content-type header is deliberately not set, so the runtime writes the
|
|
15
15
|
* `multipart/form-data` boundary itself. Like `requestBoot`, this never throws:
|
|
16
16
|
* an unreachable Fixback or a refusal is a quiet result, so a Fixback problem
|
|
17
|
-
* never breaks the host app. Automatic reports (`source:
|
|
17
|
+
* never breaks the host app. Automatic reports (`source: error`) honour ingest's
|
|
18
18
|
* `429` + `Retry-After` backpressure; manual reports are never gated.
|
|
19
19
|
*/
|
|
20
20
|
import { AutoReportBackoff } from "./auto-report-backoff";
|
|
@@ -29,7 +29,7 @@ const SCREENSHOT_FIELD = "screenshot";
|
|
|
29
29
|
*/
|
|
30
30
|
export const DEFAULT_SUBMIT_TIMEOUT_MS = 30_000;
|
|
31
31
|
/**
|
|
32
|
-
* The shared `source:
|
|
32
|
+
* The shared `source: error` backpressure window for the app. One instance so a
|
|
33
33
|
* `429` from an auto-report holds the auto-reports that follow it.
|
|
34
34
|
*/
|
|
35
35
|
const defaultBackoff = new AutoReportBackoff();
|
|
@@ -66,7 +66,7 @@ function safeHeader(response, name) {
|
|
|
66
66
|
* and resolves to the recorded Feedback on success or a named failure
|
|
67
67
|
* otherwise.
|
|
68
68
|
*
|
|
69
|
-
* A `source:
|
|
69
|
+
* A `source: error` report first consults the shared backpressure window: while
|
|
70
70
|
* it is open the report is dropped without a request. Ingest's `429` +
|
|
71
71
|
* `Retry-After` opens/extends that window. Manual reports (`source: reporter`,
|
|
72
72
|
* the default) never consult the window and a non-2xx for them stays a plain
|
|
@@ -74,11 +74,11 @@ function safeHeader(response, name) {
|
|
|
74
74
|
*/
|
|
75
75
|
export async function submitReport(apiUrl, input, deps = {}) {
|
|
76
76
|
const source = input.content.source ?? "reporter";
|
|
77
|
-
const
|
|
77
|
+
const isError = source === "error";
|
|
78
78
|
const backoff = deps.backoff ?? defaultBackoff;
|
|
79
79
|
// Client-side backpressure: shed auto-reports while the hold window is open,
|
|
80
80
|
// without touching the network. Manual reports are never gated.
|
|
81
|
-
if (
|
|
81
|
+
if (isError && backoff.isPaused()) {
|
|
82
82
|
return {
|
|
83
83
|
ok: false,
|
|
84
84
|
reason: "backpressure",
|
|
@@ -137,7 +137,7 @@ export async function submitReport(apiUrl, input, deps = {}) {
|
|
|
137
137
|
// A `429` for an auto-report is backpressure, not a refusal: open/extend
|
|
138
138
|
// the hold window from `Retry-After` and report the wait. Manual reports
|
|
139
139
|
// never 429 here, so any non-2xx for them stays a plain refusal.
|
|
140
|
-
if (
|
|
140
|
+
if (isError && response.status === 429) {
|
|
141
141
|
const retryAfterSeconds = backoff.hold(safeHeader(response, "Retry-After"));
|
|
142
142
|
return { ok: false, reason: "backpressure", retryAfterSeconds };
|
|
143
143
|
}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/package.json
CHANGED