@fixback/sdk 0.5.0 โ 0.6.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/README.md +12 -2
- package/dist/capture/extract-dom.d.ts +33 -0
- package/dist/connect.d.ts +47 -0
- package/dist/dom.d.ts +7 -19
- package/dist/element-picker.d.ts +1 -1
- package/dist/error-capture.d.ts +21 -64
- package/dist/fixback.umd.js +36 -202
- package/dist/fixback.umd.js.map +1 -1
- package/dist/identity.d.ts +6 -1
- package/dist/index.d.ts +17 -15
- package/dist/index.mjs +3577 -3683
- package/dist/index.mjs.map +1 -1
- package/dist/init.d.ts +62 -96
- package/dist/mount.d.ts +46 -0
- package/dist/overlay/dom.d.ts +16 -0
- package/dist/overlay/icons.d.ts +23 -0
- package/dist/overlay/marking.d.ts +64 -0
- package/dist/overlay/send.d.ts +65 -0
- package/dist/overlay/view.d.ts +78 -0
- package/dist/overlay-styles.d.ts +1 -1
- package/dist/overlay.d.ts +40 -41
- package/dist/package.json +3 -0
- package/dist/report.d.ts +9 -13
- package/dist/reporter-session-store.d.ts +17 -0
- package/dist/session.d.ts +27 -0
- package/dist/submit.d.ts +51 -8
- package/dist/trace/instrument/beacon.d.ts +16 -0
- package/dist/trace/instrument/console.d.ts +11 -0
- package/dist/trace/instrument/fetch.d.ts +16 -0
- package/dist/trace/instrument/index.d.ts +64 -0
- package/dist/trace/instrument/navigation.d.ts +12 -0
- package/dist/trace/instrument/ui.d.ts +23 -0
- package/dist/trace/instrument/window.d.ts +66 -0
- package/dist/trace/instrument/xhr.d.ts +15 -0
- package/dist/version.d.ts +1 -1
- package/package.json +8 -5
- package/dist/boot.d.ts +0 -74
- package/dist/breadcrumbs.d.ts +0 -327
- package/dist/invite.d.ts +0 -104
- package/dist/onboarding-styles.d.ts +0 -8
- package/dist/onboarding.d.ts +0 -44
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
The Fixback capture SDK โ a tiny, self-isolating on-page feedback widget.
|
|
4
4
|
|
|
5
|
+
> ๐ **Full documentation: [docs.fixback.dev/sdk/web](https://docs.fixback.dev/sdk/web)** โ guides, concepts, and the complete API reference.
|
|
6
|
+
|
|
5
7
|
`init({ key })` asks Fixback whether a submission would be accepted for your
|
|
6
8
|
publishable key, the visitor's origin, and the Project's Gate, and mounts a
|
|
7
9
|
launcher **only when it would**. Nothing renders when the origin isn't
|
|
@@ -58,13 +60,21 @@ global:
|
|
|
58
60
|
| ---------------- | ------------- | -------------------------- | ----------------------------------------------------------------------- |
|
|
59
61
|
| `key` | `string` | โ | Your Project's **publishable** key (an identifier, not a secret). |
|
|
60
62
|
| `apiUrl` | `string` | `https://api.fixback.dev` | The Fixback API origin. Override for a self-hosted or local deployment. |
|
|
61
|
-
| `
|
|
63
|
+
| `hostIdentity` | `string` | โ | A Host-identity token minted by your server, for trusted reporters. |
|
|
62
64
|
| `reporterId` | `string` | โ | The handle returned when a reporter redeems an invite. |
|
|
63
65
|
| `anonymousId` | `string` | a persisted per-browser id | A stable first-party id for an anonymous reporter. |
|
|
64
66
|
| `target` | `HTMLElement` | `document.body` | Where to mount the launcher. |
|
|
65
67
|
| `reduceMotion` | `boolean` | `false` | Still the launcher's pulse and motion (see [The launcher](#the-launcher)). |
|
|
66
68
|
| `autoCapture` | `boolean` | `true` | Automatic error capture โ file uncaught errors with no prompt (see [Automatic error capture](#automatic-error-capture)). Set `false` to turn it off. |
|
|
67
|
-
| `capture` | `{ console?: boolean; network?: boolean }` | served per-project | Console / network
|
|
69
|
+
| `capture` | `{ console?: boolean; network?: boolean; replay?: boolean }` | served per-project | Console / network / session-replay capture. **On by default** and normally governed per-project from the dashboard; set a stream here to override what the server serves (e.g. `{ network: false }`). A stream you leave unset follows the Project's setting. |
|
|
70
|
+
| `enabled` | `boolean` | `true` | Master gate. `false` keeps the SDK completely dormant โ no boot call, nothing instrumented, nothing mounted. |
|
|
71
|
+
| `release` | `string` | โ | The build identifier captured errors symbolicate against; set it to the value `fixback sourcemaps upload --release` used. |
|
|
72
|
+
| `environment` | `string` | โ | The deploy environment (`production` / `staging` / โฆ) stamped on every capture. |
|
|
73
|
+
| `scrub` | `boolean` | `true` | The built-in URL / PII scrubbers, run before `beforeSend`. |
|
|
74
|
+
| `beforeSend` | `(draft) => draft \| null` | โ | The scrub choke point every report passes through. Mutate the draft, or return `null` to drop it. |
|
|
75
|
+
| `beforeBreadcrumb` | `(crumb) => crumb \| null` | โ | Filter or edit each Trace entry at the source; return `null` to drop it. |
|
|
76
|
+
| `trace` | `{ budgets?, maxAgeMs?, consoleLevels? }` | tuned defaults | Trace buffer **tuning** only. Whether a stream is captured is `capture`'s job. |
|
|
77
|
+
| `replay` | `ReplayOptions` | masking on | Session-replay tuning. To turn the recorder off, use `capture: { replay: false }`. |
|
|
68
78
|
|
|
69
79
|
None of the identity fields is a trust tier โ Fixback derives trust on the
|
|
70
80
|
server and never honours a self-declared tier.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Distilling the browser's **two error events** into the shape the shared capture
|
|
3
|
+
* state machine keys on.
|
|
4
|
+
*
|
|
5
|
+
* These are the only genuinely DOM-shaped part of automatic error capture: an
|
|
6
|
+
* `ErrorEvent` and an `unhandledrejection` `PromiseRejectionEvent` carry the
|
|
7
|
+
* throwable in different places and deserve different default type names. Everything
|
|
8
|
+
* after โ fingerprinting, dedup, the burst limiter, the session cap โ is
|
|
9
|
+
* `@fixback/sdk-core`'s (ADR-0028) and shared with the React Native SDK.
|
|
10
|
+
*
|
|
11
|
+
* Both are defensive by construction: a value with no usable message returns `null`
|
|
12
|
+
* rather than filing a Feedback about nothing, which is exactly how a resource-load
|
|
13
|
+
* `error` event (an `<img>`/`<script>` that 404s โ never an uncaught exception) is
|
|
14
|
+
* kept out.
|
|
15
|
+
*/
|
|
16
|
+
import { type ExtractedError } from "@fixback/sdk-core";
|
|
17
|
+
/**
|
|
18
|
+
* Distil an uncaught `error` event into a fingerprint-able shape, or `null` when
|
|
19
|
+
* the event names no error at all (a resource-load failure).
|
|
20
|
+
*/
|
|
21
|
+
export declare function extractFromErrorEvent(event: Event): ExtractedError | null;
|
|
22
|
+
/**
|
|
23
|
+
* Distil an `unhandledrejection` event into a fingerprint-able shape. A rejection
|
|
24
|
+
* with a non-Error reason still files โ `Promise.reject("nope")` is a real bug โ
|
|
25
|
+
* so unlike {@link extractFromErrorEvent} this never returns `null`.
|
|
26
|
+
*/
|
|
27
|
+
export declare function extractFromRejectionEvent(event: Event): ExtractedError;
|
|
28
|
+
/**
|
|
29
|
+
* Distil whichever of the two global error events fired. The browser registers one
|
|
30
|
+
* listener per type, so the event's `type` is an exact discriminator โ and the
|
|
31
|
+
* single `extract` the shared state machine is parameterised over.
|
|
32
|
+
*/
|
|
33
|
+
export declare function extractFromGlobalEvent(event: Event): ExtractedError | null;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser **Connect** flow (ADR-0032) โ the DOM half of the round trip whose pure
|
|
3
|
+
* pieces (URL building, message parsing, the code exchange) live in `@fixback/sdk-core`.
|
|
4
|
+
*
|
|
5
|
+
* Connect opens the platform's connect page in a **popup**; the page signs the person in
|
|
6
|
+
* and posts back a one-time code, which the SDK exchanges for a Reporter session. When a
|
|
7
|
+
* popup is blocked the SDK falls back to a **full-page redirect** to the same URL; the
|
|
8
|
+
* connect page then returns to the site with the code on the `?fixback=` query
|
|
9
|
+
* parameter, which the SDK reads on the next load ({@link readReturnCode}) and exchanges.
|
|
10
|
+
* A Fixback-issued link (e.g. an Invite claim, ticket #250) carries the same parameter,
|
|
11
|
+
* so arriving on it starts a Connect with no popup at all.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* The outcome of starting Connect: `code` when a popup handed one back, `redirected`
|
|
15
|
+
* when a blocked popup sent the page to a full redirect (the page is navigating away and
|
|
16
|
+
* the code will arrive via {@link readReturnCode} on reload), or `cancelled` when the
|
|
17
|
+
* person closed the popup without signing in.
|
|
18
|
+
*/
|
|
19
|
+
export type ConnectStart = {
|
|
20
|
+
readonly kind: "code";
|
|
21
|
+
readonly code: string;
|
|
22
|
+
} | {
|
|
23
|
+
readonly kind: "redirected";
|
|
24
|
+
} | {
|
|
25
|
+
readonly kind: "cancelled";
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Start Connect: open the connect page in a popup and resolve to the one-time code it
|
|
29
|
+
* posts back, or fall back to a full-page redirect when the popup is blocked. `returnUrl`
|
|
30
|
+
* is where the person is sent back โ validated server-side against the Project's allowed
|
|
31
|
+
* origins, so a hostile page cannot redirect the code elsewhere.
|
|
32
|
+
*/
|
|
33
|
+
export declare function startConnect(win: Window, params: {
|
|
34
|
+
connectUrl: string;
|
|
35
|
+
key: string;
|
|
36
|
+
returnUrl: string;
|
|
37
|
+
}): Promise<ConnectStart>;
|
|
38
|
+
/**
|
|
39
|
+
* Read a Connect return code off the current URL's `?fixback=` parameter, or `null`.
|
|
40
|
+
* The connect page's redirect fallback and Fixback-issued links carry it.
|
|
41
|
+
*/
|
|
42
|
+
export declare function readReturnCode(win: Window): string | null;
|
|
43
|
+
/**
|
|
44
|
+
* Strip the `?fixback=` parameter from the current URL without a reload, so the
|
|
45
|
+
* one-time code is not left in the address bar, history, or a shared link.
|
|
46
|
+
*/
|
|
47
|
+
export declare function stripReturnCode(win: Window): void;
|
package/dist/dom.d.ts
CHANGED
|
@@ -1,30 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Recognising the SDK's **own** UI in the host page's DOM.
|
|
3
3
|
*
|
|
4
|
-
* The SDK mounts
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* The SDK mounts host elements into the page โ the launcher and the overlay panel
|
|
5
|
+
* โ each tagged with a `data-fixback-*` marker attribute (the element-picker's
|
|
6
|
+
* highlight lives inside the overlay's shadow, so it is covered by the
|
|
7
|
+
* shadow-boundary walk below). {@link isFixbackNode} is what lets the picker, the
|
|
8
|
+
* masked UI crumbs, and the replay recorder skip Fixback's own chrome, so a report
|
|
9
|
+
* never targets or records the tool that filed it.
|
|
10
10
|
*/
|
|
11
11
|
/** Marker attributes on the SDK's own host elements in the light DOM. */
|
|
12
12
|
export declare const FIXBACK_HOST_MARKERS: readonly ["data-fixback-root", "data-fixback-overlay"];
|
|
13
|
-
/**
|
|
14
|
-
* Is this node itself one of the SDK's own host elements (the launcher / overlay
|
|
15
|
-
* roots)? A self-only check โ the screenshot's clone walk excludes a node's whole
|
|
16
|
-
* subtree once the host is matched, so catching the host is enough to keep all of
|
|
17
|
-
* Fixback's chrome (light DOM and its shadow tree) out of a capture.
|
|
18
|
-
*/
|
|
19
|
-
export declare function isFixbackHostElement(node: Node | null | undefined): boolean;
|
|
20
13
|
/**
|
|
21
14
|
* Is this node part of the SDK's own UI? Walks up parents and out through any
|
|
22
15
|
* Shadow DOM boundary (via `getRootNode().host`), so a click inside the overlay's
|
|
23
16
|
* shadow is recognised as Fixback's own โ not a host-page element to pick.
|
|
24
17
|
*/
|
|
25
18
|
export declare function isFixbackNode(node: EventTarget | null | undefined): boolean;
|
|
26
|
-
/**
|
|
27
|
-
* Remove the SDK's own host elements from a (cloned) subtree, so a captured
|
|
28
|
-
* screenshot never contains the launcher, overlay, or picker highlight.
|
|
29
|
-
*/
|
|
30
|
-
export declare function stripFixbackNodes(root: ParentNode): void;
|
package/dist/element-picker.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SelectedElement } from "
|
|
1
|
+
import type { SelectedElement } from "@fixback/sdk-core";
|
|
2
2
|
/**
|
|
3
3
|
* A stable CSS selector for `el`: its own id when it has one, otherwise a path of
|
|
4
4
|
* tag (with `:nth-of-type` to disambiguate same-tag siblings) climbing until it
|
package/dist/error-capture.d.ts
CHANGED
|
@@ -5,13 +5,17 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Exactly **two capture-phase listeners** (`window` `error` +
|
|
7
7
|
* `unhandledrejection`) turn uncaught exceptions and unhandled rejections into
|
|
8
|
-
* `source: error` Feedback (stamped `Kind = bug` server-side, ADR-0023) for the
|
|
9
|
-
* native-API monkeypatching, no library.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
8
|
+
* `source: error` Feedback (stamped `Kind = bug` server-side, ADR-0023) for the
|
|
9
|
+
* current session's Reporter โ no native-API monkeypatching, no library.
|
|
10
|
+
* `console.error` is **not** promoted; it stays breadcrumb-only Evidence.
|
|
11
|
+
*
|
|
12
|
+
* This module is the **browser binding** over the shared state machine
|
|
13
|
+
* (`createAutoCapture`, `@fixback/sdk-core`, ADR-0028): it supplies the two
|
|
14
|
+
* listeners, the DOM event distillation (`./capture/extract-dom`), the browser
|
|
15
|
+
* report assembly, and the flush hooks (`pagehide` + `visibilitychange`).
|
|
16
|
+
* Everything between โ the per-session fingerprint dedup, the token-bucket burst
|
|
17
|
+
* limiter, the session cap, the causal error crumb, and the `sentCount` rollback โ
|
|
18
|
+
* is the core's, identical to the React Native SDK's.
|
|
15
19
|
*
|
|
16
20
|
* Per-firing order (research ยง7.1): **`canSubmit`/Gate โ dedup โ rate-limit/cap โ
|
|
17
21
|
* `beforeSend` scrub โ enqueue Feedback**. The Gate is honoured by construction:
|
|
@@ -19,71 +23,24 @@
|
|
|
19
23
|
* never filed where a manual report would be refused, and it inherits the session
|
|
20
24
|
* Reporter's server-derived tier.
|
|
21
25
|
*
|
|
22
|
-
* The whole module is defensive โ
|
|
23
|
-
*
|
|
24
|
-
* The fingerprint/`normalize` shape and the limiter numbers are **starting points**
|
|
25
|
-
* from research (ticket #92), exposed as config โ tunable, not frozen.
|
|
26
|
+
* The whole module is defensive โ a Fixback problem (or an error thrown while
|
|
27
|
+
* capturing an error) never surfaces on the host page.
|
|
26
28
|
*/
|
|
27
|
-
import { type BeforeSend, type
|
|
28
|
-
import type { IdentityInputs } from "./boot";
|
|
29
|
-
import { type BreadcrumbBuffer, type Teardown } from "./breadcrumbs";
|
|
30
|
-
import type { ReporterDisplay } from "./invite";
|
|
29
|
+
import { type BeforeSend, type BreadcrumbBuffer, DEFAULT_BURST_CAPACITY, DEFAULT_BURST_REFILL_MS, DEFAULT_MAX_DISTINCT_AUTO, type IdentityInputs, type Teardown } from "@fixback/sdk-core";
|
|
31
30
|
import type { ReplaySource } from "./replay";
|
|
32
|
-
import { type SubmitInput, type SubmitResult } from "./submit";
|
|
31
|
+
import { type SubmitDeps, type SubmitInput, type SubmitResult } from "./submit";
|
|
33
32
|
export type { Teardown };
|
|
34
|
-
export {
|
|
35
|
-
/** Burst limiter capacity โ how many auto-reports may fire back-to-back (ยงE). */
|
|
36
|
-
export declare const DEFAULT_BURST_CAPACITY = 5;
|
|
37
|
-
/** Burst limiter refill โ one token returns every this-many ms (ยงE). */
|
|
38
|
-
export declare const DEFAULT_BURST_REFILL_MS = 2000;
|
|
39
|
-
/** Per-session ceiling on distinct auto-Feedback; beyond it, only a dropped-count (ยงE). */
|
|
40
|
-
export declare const DEFAULT_MAX_DISTINCT_AUTO = 20;
|
|
41
|
-
/**
|
|
42
|
-
* Extract **structured** frames from a stack for the wire (#117, ADR-0024) โ
|
|
43
|
-
* unlike {@link extractTopFrames} (a compact fingerprint signature that drops the
|
|
44
|
-
* origin), these keep the full script URL, because server-side symbolication
|
|
45
|
-
* matches it against uploaded sourcemap paths. URLs are scrubbed (query dropped,
|
|
46
|
-
* PII redacted) before they leave the page; unlocatable frames (`native`,
|
|
47
|
-
* `<anonymous>`, eval) are skipped; the count is capped.
|
|
48
|
-
*/
|
|
49
|
-
export declare function extractStructuredFrames(stack: string | undefined, limit?: number): CapturedFrame[];
|
|
50
|
-
/** Configuration for {@link TokenBucket}. */
|
|
51
|
-
export interface TokenBucketOptions {
|
|
52
|
-
readonly capacity: number;
|
|
53
|
-
readonly refillIntervalMs: number;
|
|
54
|
-
/** Clock source, injectable for tests. Defaults to `Date.now`. */
|
|
55
|
-
readonly now?: () => number;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* A token bucket: starts full at `capacity`, refills one token every
|
|
59
|
-
* `refillIntervalMs`, and refuses (`take() === false`) when empty. So a fast error
|
|
60
|
-
* loop that dodges dedup with distinct fingerprints still can't machine-gun ingest.
|
|
61
|
-
* The clock is injectable so the window is unit-tested deterministically.
|
|
62
|
-
*/
|
|
63
|
-
export declare class TokenBucket {
|
|
64
|
-
private readonly options;
|
|
65
|
-
private tokens;
|
|
66
|
-
private last;
|
|
67
|
-
private readonly now;
|
|
68
|
-
constructor(options: TokenBucketOptions);
|
|
69
|
-
/** Consume a token if one is available (refilling first), else refuse. */
|
|
70
|
-
take(): boolean;
|
|
71
|
-
}
|
|
33
|
+
export { DEFAULT_BURST_CAPACITY, DEFAULT_BURST_REFILL_MS, DEFAULT_MAX_DISTINCT_AUTO };
|
|
72
34
|
/** Injectable collaborators, defaulted to the real implementations. */
|
|
73
35
|
export interface AutoCaptureDeps {
|
|
74
|
-
readonly submitReport: (apiUrl: string, input: SubmitInput,
|
|
36
|
+
readonly submitReport: (apiUrl: string, input: SubmitInput, deps?: SubmitDeps) => Promise<SubmitResult>;
|
|
75
37
|
}
|
|
76
38
|
/** Configuration for {@link installErrorCapture}. */
|
|
77
39
|
export interface AutoCaptureConfig {
|
|
78
40
|
readonly apiUrl: string;
|
|
79
41
|
readonly key: string;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
* The Reporter's self-provided display name / email (spec ยงF). Carried on
|
|
83
|
-
* auto-captured Feedback too, so a machine-filed crash still names whose session it
|
|
84
|
-
* was โ display only, never a trust signal.
|
|
85
|
-
*/
|
|
86
|
-
readonly display?: ReporterDisplay;
|
|
42
|
+
/** Identity evidence, read **live** at capture time (ADR-0032) โ the current session token. */
|
|
43
|
+
readonly getIdentity?: () => IdentityInputs;
|
|
87
44
|
/** The window whose global handlers are installed. Defaults to `window`. */
|
|
88
45
|
readonly win?: Window;
|
|
89
46
|
/** The document used for capture + environment. Defaults to the window's. */
|
|
@@ -95,6 +52,8 @@ export interface AutoCaptureConfig {
|
|
|
95
52
|
* server can symbolicate the captured frames against this build's sourcemaps.
|
|
96
53
|
*/
|
|
97
54
|
readonly release?: string;
|
|
55
|
+
/** The deploy environment (`production` / `staging` / โฆ), stamped on every report. */
|
|
56
|
+
readonly deployEnvironment?: string;
|
|
98
57
|
/** The shared trace buffer; the failing error is added to it before filing. */
|
|
99
58
|
readonly buffer?: BreadcrumbBuffer | null;
|
|
100
59
|
/**
|
|
@@ -130,7 +89,5 @@ export interface AutoCaptureHandle {
|
|
|
130
89
|
/**
|
|
131
90
|
* Install automatic error capture on a window and return a handle whose `destroy`
|
|
132
91
|
* removes every listener it added (the two global handlers plus the flush hooks).
|
|
133
|
-
* The caller (`init`) installs this only after boot returned `canSubmit`, so the
|
|
134
|
-
* Gate is respected and the auto-error inherits the session Reporter's tier.
|
|
135
92
|
*/
|
|
136
93
|
export declare function installErrorCapture(config: AutoCaptureConfig): AutoCaptureHandle;
|