@fixback/expo 0.9.0 → 0.9.1
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/adapters.js +5 -4
- package/dist/adapters.js.map +1 -1
- package/dist/breadcrumbs.d.ts +15 -51
- package/dist/breadcrumbs.js +22 -169
- package/dist/breadcrumbs.js.map +1 -1
- package/dist/client-boot.d.ts +40 -0
- package/dist/client-boot.js +269 -0
- package/dist/client-boot.js.map +1 -0
- package/dist/client-connect.d.ts +33 -0
- package/dist/client-connect.js +306 -0
- package/dist/client-connect.js.map +1 -0
- package/dist/client-replay.d.ts +31 -0
- package/dist/client-replay.js +165 -0
- package/dist/client-replay.js.map +1 -0
- package/dist/client-state.d.ts +131 -0
- package/dist/client-state.js +158 -0
- package/dist/client-state.js.map +1 -0
- package/dist/client.d.ts +10 -253
- package/dist/client.js +73 -865
- package/dist/client.js.map +1 -1
- package/dist/error-capture.js +6 -26
- package/dist/error-capture.js.map +1 -1
- package/dist/identity.d.ts +0 -2
- package/dist/identity.js +0 -3
- package/dist/identity.js.map +1 -1
- package/dist/options.d.ts +263 -0
- package/dist/options.js +12 -0
- package/dist/options.js.map +1 -0
- package/dist/report.d.ts +13 -12
- package/dist/report.js +19 -38
- package/dist/report.js.map +1 -1
- package/dist/submit.d.ts +10 -46
- package/dist/submit.js +14 -79
- package/dist/submit.js.map +1 -1
- package/dist/tokens.d.ts +5 -3
- package/dist/tokens.js +8 -6
- package/dist/tokens.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -3
package/dist/adapters.js
CHANGED
|
@@ -167,12 +167,13 @@ function createNativeAdapters() {
|
|
|
167
167
|
captureScreenshot,
|
|
168
168
|
releaseScreenshot,
|
|
169
169
|
// Session replay (ADR-0044): frame capture through the same view-shot module, and
|
|
170
|
-
// the encode through our own Expo module
|
|
171
|
-
//
|
|
172
|
-
//
|
|
170
|
+
// the encode through our own Expo module — handed over only when its native half is
|
|
171
|
+
// linked. In Expo Go, or a build that never ran `expo prebuild`, there is none, so
|
|
172
|
+
// the client records no frames it could never encode, says why in a development
|
|
173
|
+
// build, and reports without replay (#661).
|
|
173
174
|
captureReplayFrame,
|
|
174
175
|
releaseReplayFrame: releaseScreenshot,
|
|
175
|
-
encodeReplaySegment: expo_replay_encoder_1.encodeSegment,
|
|
176
|
+
encodeReplaySegment: expo_replay_encoder_1.isEncoderAvailable ? expo_replay_encoder_1.encodeSegment : undefined,
|
|
176
177
|
consoleObj: (0, breadcrumbs_1.globalConsole)() ?? null,
|
|
177
178
|
xhr: (0, breadcrumbs_1.globalXhr)() ?? null,
|
|
178
179
|
errorUtils: (0, error_capture_1.globalErrorUtils)() ?? null,
|
package/dist/adapters.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqGH,
|
|
1
|
+
{"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"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"}
|
package/dist/breadcrumbs.d.ts
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* The Expo SDK's **React Native capture instrumentation** — the runtime seams, and
|
|
3
3
|
* nothing else.
|
|
4
4
|
*
|
|
5
|
-
* The trace buffer, the crumb builders, the caps and eviction rules,
|
|
6
|
-
* `
|
|
5
|
+
* The trace buffer, the crumb builders, the caps and eviction rules, the `console`
|
|
6
|
+
* wrapper, and the `XMLHttpRequest` patch are all shared with the browser SDK through
|
|
7
7
|
* `@fixback/sdk-core` (ADR-0028, replacing the file-parallel port ADR-0021
|
|
8
8
|
* described), so the server and dashboard cannot tell a mobile trace from a web one.
|
|
9
|
-
* What is left here is genuinely mobile: how to find React Native's globals, and
|
|
10
|
-
* the
|
|
9
|
+
* What is left here is genuinely mobile: how to find React Native's globals, and how
|
|
10
|
+
* the shared XHR patch is bound to them.
|
|
11
11
|
*
|
|
12
12
|
* Mobile mappings (spec 0004 §D): network capture patches `XMLHttpRequest` **only**
|
|
13
13
|
* — React Native's `fetch` is a polyfill over XHR, so wrapping both would
|
|
@@ -16,60 +16,24 @@
|
|
|
16
16
|
* yet and simply never occur.
|
|
17
17
|
*
|
|
18
18
|
* Everything private is kept out at the source: network crumbs carry method + URL +
|
|
19
|
-
* status metadata only, **never** bodies
|
|
20
|
-
*
|
|
21
|
-
* id**'s W3C `traceparent` (grill 2026-09-24
|
|
22
|
-
* app lists in `propagateTo` (`./propagation`)
|
|
19
|
+
* status metadata only, **never** bodies (the web-only body opt-in is never passed
|
|
20
|
+
* here), and URLs are scrubbed as the crumb is built. The one header the patch touches
|
|
21
|
+
* is the one it mints — the **Correlation id**'s W3C `traceparent` (grill 2026-09-24
|
|
22
|
+
* D2; #540), sent only to the origins the app lists in `propagateTo` (`./propagation`)
|
|
23
|
+
* — and no header value is ever read. The patch carries it under React Native's
|
|
24
|
+
* `"per-request"` rule: the app's header always wins — one set before `send` means
|
|
25
|
+
* Fixback adds none, and one set after ours (a `send` wrapper installed before
|
|
26
|
+
* Fixback's) replaces it, because React Native's XHR sends the last value a header was
|
|
27
|
+
* given — so the crumb then records no id rather than one the request did not carry.
|
|
23
28
|
* The SDK must never throw into the host app, so every hook is wrapped: a capture
|
|
24
29
|
* failure is swallowed and the original behaviour always runs.
|
|
25
30
|
*/
|
|
26
|
-
import { type BreadcrumbBuffer, type BreadcrumbLevel, type ConsoleLike, type Teardown } from "@fixback/sdk-core";
|
|
27
|
-
|
|
28
|
-
export type { ConsoleLike, Teardown };
|
|
31
|
+
import { type BreadcrumbBuffer, type BreadcrumbLevel, type ConsoleLike, type Teardown, type XhrConstructor, type XhrInstance } from "@fixback/sdk-core";
|
|
32
|
+
export type { ConsoleLike, Teardown, XhrConstructor, XhrInstance };
|
|
29
33
|
/** React Native's global `console`, when present. */
|
|
30
34
|
export declare function globalConsole(): ConsoleLike | undefined;
|
|
31
|
-
/** The XHR instance surface the network instrumentation touches. */
|
|
32
|
-
export interface XhrInstance {
|
|
33
|
-
status: number;
|
|
34
|
-
statusText?: string;
|
|
35
|
-
open(method: string, url: string | {
|
|
36
|
-
toString(): string;
|
|
37
|
-
}, ...rest: unknown[]): void;
|
|
38
|
-
send(body?: unknown): void;
|
|
39
|
-
/** How the Correlation id's `traceparent` goes on. Absent ⇒ no header and no id. */
|
|
40
|
-
setRequestHeader?(name: string, value: string): void;
|
|
41
|
-
getResponseHeader?(name: string): string | null;
|
|
42
|
-
addEventListener(type: string, listener: () => void): void;
|
|
43
|
-
removeEventListener(type: string, listener: () => void): void;
|
|
44
|
-
}
|
|
45
|
-
/** The XHR constructor whose prototype is patched — injectable for tests. */
|
|
46
|
-
export interface XhrConstructor {
|
|
47
|
-
new (): XhrInstance;
|
|
48
|
-
prototype: XhrInstance;
|
|
49
|
-
}
|
|
50
35
|
/** React Native's global `XMLHttpRequest`, when present. */
|
|
51
36
|
export declare function globalXhr(): XhrConstructor | undefined;
|
|
52
|
-
/**
|
|
53
|
-
* Patch `XMLHttpRequest` to record a rich network crumb when a request settles.
|
|
54
|
-
* On React Native this is the **single** network hook: the built-in `fetch` is
|
|
55
|
-
* a polyfill over XHR, so its traffic is captured here too (as `xhr` crumbs)
|
|
56
|
-
* and `fetch` itself is deliberately not wrapped — wrapping both would record
|
|
57
|
-
* every request twice (spec 0004 §D). The `send` body argument is **never read
|
|
58
|
-
* for content** — only its trivially-known size.
|
|
59
|
-
*
|
|
60
|
-
* It also carries the **Correlation id** (grill 2026-09-24 D2; #540), so one patch
|
|
61
|
-
* covers `fetch` too: on `send`, a request whose origin the app listed in
|
|
62
|
-
* `propagateTo` (`./propagation`; nothing by default) gets a freshly minted W3C
|
|
63
|
-
* `traceparent` through the original `setRequestHeader`, and its crumb records the
|
|
64
|
-
* trace id as `requestId`. The patched `setRequestHeader` notes only a header's
|
|
65
|
-
* **name** — whether the app set its own `traceparent` — never a value, and the app's
|
|
66
|
-
* header always wins: one set before `send` means Fixback adds none, and one set after
|
|
67
|
-
* ours (a `send` wrapper installed before Fixback's) replaces it, because React
|
|
68
|
-
* Native's XHR sends the last value a header was given — so the crumb then records no
|
|
69
|
-
* id rather than one the request did not carry. A `setRequestHeader` that is missing
|
|
70
|
-
* or throws degrades to "no header, no id", and the original `send` always runs.
|
|
71
|
-
*/
|
|
72
|
-
export declare function instrumentXhr(buffer: BreadcrumbBuffer, ctor: XhrConstructor | undefined, ignoreUrl: (url: string) => boolean, now: () => number, mono?: () => number, propagate?: PropagationFilter): Teardown;
|
|
73
37
|
/** Options for {@link instrumentBreadcrumbs}. */
|
|
74
38
|
export interface InstrumentOptions {
|
|
75
39
|
readonly consoleObj?: ConsoleLike | null;
|
package/dist/breadcrumbs.js
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
* The Expo SDK's **React Native capture instrumentation** — the runtime seams, and
|
|
4
4
|
* nothing else.
|
|
5
5
|
*
|
|
6
|
-
* The trace buffer, the crumb builders, the caps and eviction rules,
|
|
7
|
-
* `
|
|
6
|
+
* The trace buffer, the crumb builders, the caps and eviction rules, the `console`
|
|
7
|
+
* wrapper, and the `XMLHttpRequest` patch are all shared with the browser SDK through
|
|
8
8
|
* `@fixback/sdk-core` (ADR-0028, replacing the file-parallel port ADR-0021
|
|
9
9
|
* described), so the server and dashboard cannot tell a mobile trace from a web one.
|
|
10
|
-
* What is left here is genuinely mobile: how to find React Native's globals, and
|
|
11
|
-
* the
|
|
10
|
+
* What is left here is genuinely mobile: how to find React Native's globals, and how
|
|
11
|
+
* the shared XHR patch is bound to them.
|
|
12
12
|
*
|
|
13
13
|
* Mobile mappings (spec 0004 §D): network capture patches `XMLHttpRequest` **only**
|
|
14
14
|
* — React Native's `fetch` is a polyfill over XHR, so wrapping both would
|
|
@@ -17,23 +17,24 @@
|
|
|
17
17
|
* yet and simply never occur.
|
|
18
18
|
*
|
|
19
19
|
* Everything private is kept out at the source: network crumbs carry method + URL +
|
|
20
|
-
* status metadata only, **never** bodies
|
|
21
|
-
*
|
|
22
|
-
* id**'s W3C `traceparent` (grill 2026-09-24
|
|
23
|
-
* app lists in `propagateTo` (`./propagation`)
|
|
20
|
+
* status metadata only, **never** bodies (the web-only body opt-in is never passed
|
|
21
|
+
* here), and URLs are scrubbed as the crumb is built. The one header the patch touches
|
|
22
|
+
* is the one it mints — the **Correlation id**'s W3C `traceparent` (grill 2026-09-24
|
|
23
|
+
* D2; #540), sent only to the origins the app lists in `propagateTo` (`./propagation`)
|
|
24
|
+
* — and no header value is ever read. The patch carries it under React Native's
|
|
25
|
+
* `"per-request"` rule: the app's header always wins — one set before `send` means
|
|
26
|
+
* Fixback adds none, and one set after ours (a `send` wrapper installed before
|
|
27
|
+
* Fixback's) replaces it, because React Native's XHR sends the last value a header was
|
|
28
|
+
* given — so the crumb then records no id rather than one the request did not carry.
|
|
24
29
|
* The SDK must never throw into the host app, so every hook is wrapped: a capture
|
|
25
30
|
* failure is swallowed and the original behaviour always runs.
|
|
26
31
|
*/
|
|
27
32
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
33
|
exports.globalConsole = globalConsole;
|
|
29
34
|
exports.globalXhr = globalXhr;
|
|
30
|
-
exports.instrumentXhr = instrumentXhr;
|
|
31
35
|
exports.instrumentBreadcrumbs = instrumentBreadcrumbs;
|
|
32
36
|
const sdk_core_1 = require("@fixback/sdk-core");
|
|
33
37
|
const propagation_1 = require("./propagation");
|
|
34
|
-
function noop() {
|
|
35
|
-
/* nothing installed */
|
|
36
|
-
}
|
|
37
38
|
/** React Native's global `console`, when present. */
|
|
38
39
|
function globalConsole() {
|
|
39
40
|
const g = globalThis;
|
|
@@ -44,162 +45,6 @@ function globalXhr() {
|
|
|
44
45
|
const g = globalThis;
|
|
45
46
|
return typeof g.XMLHttpRequest === "function" ? g.XMLHttpRequest : undefined;
|
|
46
47
|
}
|
|
47
|
-
/** Read one XHR response header defensively — `null` when unavailable or on any throw. */
|
|
48
|
-
function safeXhrHeader(xhr, name) {
|
|
49
|
-
try {
|
|
50
|
-
return typeof xhr.getResponseHeader === "function"
|
|
51
|
-
? xhr.getResponseHeader(name)
|
|
52
|
-
: null;
|
|
53
|
-
}
|
|
54
|
-
catch {
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
/** Read an XHR's `statusText` defensively — `undefined` when empty or on any throw. */
|
|
59
|
-
function safeXhrStatusText(xhr) {
|
|
60
|
-
try {
|
|
61
|
-
return xhr.statusText || undefined;
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
return undefined;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Patch `XMLHttpRequest` to record a rich network crumb when a request settles.
|
|
69
|
-
* On React Native this is the **single** network hook: the built-in `fetch` is
|
|
70
|
-
* a polyfill over XHR, so its traffic is captured here too (as `xhr` crumbs)
|
|
71
|
-
* and `fetch` itself is deliberately not wrapped — wrapping both would record
|
|
72
|
-
* every request twice (spec 0004 §D). The `send` body argument is **never read
|
|
73
|
-
* for content** — only its trivially-known size.
|
|
74
|
-
*
|
|
75
|
-
* It also carries the **Correlation id** (grill 2026-09-24 D2; #540), so one patch
|
|
76
|
-
* covers `fetch` too: on `send`, a request whose origin the app listed in
|
|
77
|
-
* `propagateTo` (`./propagation`; nothing by default) gets a freshly minted W3C
|
|
78
|
-
* `traceparent` through the original `setRequestHeader`, and its crumb records the
|
|
79
|
-
* trace id as `requestId`. The patched `setRequestHeader` notes only a header's
|
|
80
|
-
* **name** — whether the app set its own `traceparent` — never a value, and the app's
|
|
81
|
-
* header always wins: one set before `send` means Fixback adds none, and one set after
|
|
82
|
-
* ours (a `send` wrapper installed before Fixback's) replaces it, because React
|
|
83
|
-
* Native's XHR sends the last value a header was given — so the crumb then records no
|
|
84
|
-
* id rather than one the request did not carry. A `setRequestHeader` that is missing
|
|
85
|
-
* or throws degrades to "no header, no id", and the original `send` always runs.
|
|
86
|
-
*/
|
|
87
|
-
function instrumentXhr(buffer, ctor, ignoreUrl, now, mono = sdk_core_1.nowMono,
|
|
88
|
-
// Which requests carry the Correlation id: the origins the app listed in
|
|
89
|
-
// `propagateTo`, threaded in by the composite — nothing by default.
|
|
90
|
-
propagate = (0, propagation_1.createPropagationFilter)()) {
|
|
91
|
-
if (typeof ctor !== "function")
|
|
92
|
-
return noop;
|
|
93
|
-
const proto = ctor.prototype;
|
|
94
|
-
const originalOpen = proto.open;
|
|
95
|
-
const originalSend = proto.send;
|
|
96
|
-
const originalSetRequestHeader = proto.setRequestHeader;
|
|
97
|
-
const canSetHeader = typeof originalSetRequestHeader === "function";
|
|
98
|
-
proto.open = function (method, url, ...rest) {
|
|
99
|
-
// A new request: nothing the app set on an earlier one, and no id yet.
|
|
100
|
-
this.__fixbackMeta = {
|
|
101
|
-
method: String(method).toUpperCase(),
|
|
102
|
-
url: String(url),
|
|
103
|
-
appTraceparent: false,
|
|
104
|
-
};
|
|
105
|
-
return originalOpen.call(this, method, url, ...rest);
|
|
106
|
-
};
|
|
107
|
-
if (canSetHeader) {
|
|
108
|
-
proto.setRequestHeader = function (name, value) {
|
|
109
|
-
try {
|
|
110
|
-
const meta = this.__fixbackMeta;
|
|
111
|
-
if (meta && (0, sdk_core_1.isTraceparentHeader)(name))
|
|
112
|
-
meta.appTraceparent = true;
|
|
113
|
-
}
|
|
114
|
-
catch {
|
|
115
|
-
/* noting a header name must never break the app's own call */
|
|
116
|
-
}
|
|
117
|
-
return originalSetRequestHeader.call(this, name, value);
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Put a freshly minted `traceparent` on a request about to be sent, remembering the
|
|
122
|
-
* Correlation id its crumb records — unless the request is not one to propagate to,
|
|
123
|
-
* the app set its own, this request already carries ours (a repeated `send`), or
|
|
124
|
-
* setting it throws. Calls the original `setRequestHeader`, so Fixback's own header is
|
|
125
|
-
* never mistaken for the app's.
|
|
126
|
-
*/
|
|
127
|
-
const stampCorrelationId = (xhr, meta) => {
|
|
128
|
-
if (!canSetHeader || meta.appTraceparent || meta.correlationId !== undefined)
|
|
129
|
-
return;
|
|
130
|
-
try {
|
|
131
|
-
if (!propagate(meta.url))
|
|
132
|
-
return;
|
|
133
|
-
const minted = (0, sdk_core_1.mintTraceparent)();
|
|
134
|
-
originalSetRequestHeader.call(xhr, sdk_core_1.TRACEPARENT_HEADER, minted.header);
|
|
135
|
-
meta.correlationId = minted.correlationId;
|
|
136
|
-
}
|
|
137
|
-
catch {
|
|
138
|
-
/* no header, no id — and the request still goes out */
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
proto.send = function (body) {
|
|
142
|
-
const meta = this.__fixbackMeta;
|
|
143
|
-
if (meta && !ignoreUrl(meta.url)) {
|
|
144
|
-
stampCorrelationId(this, meta);
|
|
145
|
-
const started = mono();
|
|
146
|
-
const reqSize = (0, sdk_core_1.trivialBodySize)(body);
|
|
147
|
-
// The terminal event names the outcome; `loadend` always follows exactly
|
|
148
|
-
// one of load/error/timeout/abort, so by record time `settled` is set.
|
|
149
|
-
let settled;
|
|
150
|
-
const onLoad = () => {
|
|
151
|
-
settled = (0, sdk_core_1.outcomeFromStatus)(this.status || undefined);
|
|
152
|
-
};
|
|
153
|
-
const onError = () => {
|
|
154
|
-
settled = "network-error";
|
|
155
|
-
};
|
|
156
|
-
const onTimeout = () => {
|
|
157
|
-
settled = "timeout";
|
|
158
|
-
};
|
|
159
|
-
const onAbort = () => {
|
|
160
|
-
settled = "aborted";
|
|
161
|
-
};
|
|
162
|
-
const onDone = () => {
|
|
163
|
-
try {
|
|
164
|
-
buffer.add((0, sdk_core_1.networkCrumb)({
|
|
165
|
-
api: "xhr",
|
|
166
|
-
method: meta.method,
|
|
167
|
-
url: meta.url,
|
|
168
|
-
status: this.status || undefined,
|
|
169
|
-
statusText: safeXhrStatusText(this),
|
|
170
|
-
durationMs: Math.max(0, mono() - started),
|
|
171
|
-
reqSize,
|
|
172
|
-
respSize: (0, sdk_core_1.parseContentLength)(safeXhrHeader(this, "content-length")),
|
|
173
|
-
contentType: (0, sdk_core_1.contentTypeOf)(safeXhrHeader(this, "content-type")),
|
|
174
|
-
outcome: settled ?? (0, sdk_core_1.outcomeFromStatus)(this.status || undefined),
|
|
175
|
-
// Read at settle time: an app header set after ours replaced it.
|
|
176
|
-
requestId: meta.appTraceparent ? undefined : meta.correlationId,
|
|
177
|
-
}, now()));
|
|
178
|
-
}
|
|
179
|
-
catch {
|
|
180
|
-
/* never throw into the host app */
|
|
181
|
-
}
|
|
182
|
-
this.removeEventListener("load", onLoad);
|
|
183
|
-
this.removeEventListener("error", onError);
|
|
184
|
-
this.removeEventListener("timeout", onTimeout);
|
|
185
|
-
this.removeEventListener("abort", onAbort);
|
|
186
|
-
this.removeEventListener("loadend", onDone);
|
|
187
|
-
};
|
|
188
|
-
this.addEventListener("load", onLoad);
|
|
189
|
-
this.addEventListener("error", onError);
|
|
190
|
-
this.addEventListener("timeout", onTimeout);
|
|
191
|
-
this.addEventListener("abort", onAbort);
|
|
192
|
-
this.addEventListener("loadend", onDone);
|
|
193
|
-
}
|
|
194
|
-
return originalSend.call(this, body);
|
|
195
|
-
};
|
|
196
|
-
return () => {
|
|
197
|
-
proto.open = originalOpen;
|
|
198
|
-
proto.send = originalSend;
|
|
199
|
-
if (canSetHeader)
|
|
200
|
-
proto.setRequestHeader = originalSetRequestHeader;
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
48
|
/**
|
|
204
49
|
* Install the React Native capture hooks — the shared console wrapper and the XHR
|
|
205
50
|
* patch — and return a single teardown that removes them all. Each hook is
|
|
@@ -220,7 +65,15 @@ function instrumentBreadcrumbs(buffer, options = {}) {
|
|
|
220
65
|
teardowns.push((0, sdk_core_1.instrumentConsole)(buffer, consoleObj, levels, now));
|
|
221
66
|
}
|
|
222
67
|
if (captureNetwork) {
|
|
223
|
-
teardowns.push(instrumentXhr(buffer, xhr,
|
|
68
|
+
teardowns.push((0, sdk_core_1.instrumentXhr)(buffer, xhr, {
|
|
69
|
+
ignoreUrl,
|
|
70
|
+
now,
|
|
71
|
+
mono,
|
|
72
|
+
// Which requests carry the Correlation id: the origins the app listed in
|
|
73
|
+
// `propagateTo` — nothing by default — under React Native's rule (see above).
|
|
74
|
+
propagate: (0, propagation_1.createPropagationFilter)(options.propagateTo),
|
|
75
|
+
correlation: "per-request",
|
|
76
|
+
}));
|
|
224
77
|
}
|
|
225
78
|
return () => {
|
|
226
79
|
for (const teardown of teardowns) {
|
package/dist/breadcrumbs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"breadcrumbs.js","sourceRoot":"","sources":["../src/breadcrumbs.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"breadcrumbs.js","sourceRoot":"","sources":["../src/breadcrumbs.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;;AAoBH,sCAGC;AAGD,8BAGC;AA8BD,sDAyCC;AAlGD,gDAW2B;AAE3B,+CAAwD;AAIxD,qDAAqD;AACrD,SAAgB,aAAa;IAC3B,MAAM,CAAC,GAAG,UAAuC,CAAC;IAClD,OAAO,CAAC,CAAC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5E,CAAC;AAED,4DAA4D;AAC5D,SAAgB,SAAS;IACvB,MAAM,CAAC,GAAG,UAAiD,CAAC;IAC5D,OAAO,OAAO,CAAC,CAAC,cAAc,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/E,CAAC;AAwBD;;;;;GAKG;AACH,SAAgB,qBAAqB,CACnC,MAAwB,EACxB,UAA6B,EAAE;IAE/B,MAAM,UAAU,GACd,OAAO,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,IAAI,aAAa,EAAE,CAAC;IAClF,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,IAAI,SAAS,EAAE,CAAC;IAC1E,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,IAAI,iCAAsB,CAAC;IAC/D,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,kBAAO,CAAC;IACrC,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,KAAK,KAAK,CAAC;IACxD,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,KAAK,KAAK,CAAC;IAExD,MAAM,SAAS,GAAe,EAAE,CAAC;IACjC,IAAI,UAAU,IAAI,cAAc,EAAE,CAAC;QACjC,SAAS,CAAC,IAAI,CAAC,IAAA,4BAAiB,EAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,cAAc,EAAE,CAAC;QACnB,SAAS,CAAC,IAAI,CACZ,IAAA,wBAAa,EAAC,MAAM,EAAE,GAAG,EAAE;YACzB,SAAS;YACT,GAAG;YACH,IAAI;YACJ,yEAAyE;YACzE,8EAA8E;YAC9E,SAAS,EAAE,IAAA,qCAAuB,EAAC,OAAO,CAAC,WAAW,CAAC;YACvD,WAAW,EAAE,aAAa;SAC3B,CAAC,CACH,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,EAAE;QACV,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,QAAQ,EAAE,CAAC;YACb,CAAC;YAAC,MAAM,CAAC;gBACP,6BAA6B;YAC/B,CAAC;QACH,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boot, and the capture its answer arms (spec 0003 §G ported to mobile, spec 0004).
|
|
3
|
+
*
|
|
4
|
+
* {@link Boot.bootAndArm} is the round trip `start`, `signIn` and `signOut` all end in:
|
|
5
|
+
* it swaps in the refreshed Reporter session, records the Account and tier for the
|
|
6
|
+
* identity row, raises or lowers maintenance mode's notice (and schedules its
|
|
7
|
+
* recheck), and arms capture only while a submission would be accepted — the trace
|
|
8
|
+
* hooks, mobile replay (`./client-replay`), and automatic error capture — or says why
|
|
9
|
+
* the SDK is dormant.
|
|
10
|
+
*
|
|
11
|
+
* One piece of the headless client (`./client`), created over the state every piece
|
|
12
|
+
* shares (`./client-state`).
|
|
13
|
+
*/
|
|
14
|
+
import { type CaptureConfig, type MaintenanceNotice } from "@fixback/sdk-core";
|
|
15
|
+
import type { ReplayArming } from "./client-replay";
|
|
16
|
+
import { type ClientState } from "./client-state";
|
|
17
|
+
/** The per-stream trace flags capture is armed with. */
|
|
18
|
+
export interface TraceStreams {
|
|
19
|
+
readonly console: boolean;
|
|
20
|
+
readonly network: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** Boot and capture arming, as {@link createBoot} builds them. */
|
|
23
|
+
export interface Boot {
|
|
24
|
+
/** Boot with the current identity and reconcile capture + the identity row. */
|
|
25
|
+
bootAndArm(gen: number, options?: {
|
|
26
|
+
readonly recheck?: boolean;
|
|
27
|
+
}): Promise<void>;
|
|
28
|
+
/** The effective per-stream capture flags for a served config (or none yet). */
|
|
29
|
+
resolveStreams(served: CaptureConfig | undefined): TraceStreams;
|
|
30
|
+
/** Install the trace instrumentation for the given flags, replacing what is installed. */
|
|
31
|
+
armTrace(streams: TraceStreams): void;
|
|
32
|
+
/** Tear down the trace, replay and auto-capture hooks (best-effort). */
|
|
33
|
+
disarmCapture(): void;
|
|
34
|
+
/** Raise, change or lower maintenance mode's notice, telling its listeners. */
|
|
35
|
+
setMaintenance(next: MaintenanceNotice | null): void;
|
|
36
|
+
/** Cancel the pending maintenance recheck, if any. */
|
|
37
|
+
clearMaintenanceRecheck(): void;
|
|
38
|
+
}
|
|
39
|
+
/** Boot and capture arming over the client's shared state, with replay's arming. */
|
|
40
|
+
export declare function createBoot(s: ClientState, replay: ReplayArming): Boot;
|