@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/dist/breadcrumbs.d.ts
DELETED
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The thin trace **breadcrumb ring buffer** and its capture instrumentation
|
|
3
|
-
* (spec 0003 §C; research `sentry-error-capture-findings.md` §7.5).
|
|
4
|
-
*
|
|
5
|
-
* A fixed-size FIFO buffer of the most recent activity — console, navigation,
|
|
6
|
-
* network metadata, masked user actions, and the failing error — that rides on a
|
|
7
|
-
* report as Evidence. It is trimmed exactly like Sentry (`crumbs.slice(-N)`),
|
|
8
|
-
* defaults to a deliberately thin `N ≈ 30` because it ships on **every** payload,
|
|
9
|
-
* and takes an optional age cap. A `beforeBreadcrumb(crumb) => crumb | null`
|
|
10
|
-
* filter lets a Project mute or edit crumbs before they enter the buffer.
|
|
11
|
-
*
|
|
12
|
-
* Everything private is kept out **at the source**: `ui.input` records that an
|
|
13
|
-
* input changed, never its value; `fetch`/`xhr` crumbs carry method + URL +
|
|
14
|
-
* status only, **never** bodies; URLs are scrubbed as the crumb is built. The
|
|
15
|
-
* `beforeSend` choke point (`scrub.ts`) is the final gate over the whole report.
|
|
16
|
-
*
|
|
17
|
-
* The SDK stays dependency-free and must never throw into the host page, so every
|
|
18
|
-
* instrumentation hook is wrapped: a capture failure is swallowed and the original
|
|
19
|
-
* behaviour (the real `console`, `fetch`, navigation) always runs.
|
|
20
|
-
*/
|
|
21
|
-
import { type Breadcrumb, type BreadcrumbCategory, type BreadcrumbData, type BreadcrumbLevel, type ConsoleArg, type ConsoleArgType, type NetworkApi, type NetworkOutcome, type SourceLocation } from "@fixback/sdk-core";
|
|
22
|
-
export type { Breadcrumb, BreadcrumbCategory, BreadcrumbData, BreadcrumbLevel, ConsoleArg, ConsoleArgType, NetworkApi, NetworkOutcome, SourceLocation, };
|
|
23
|
-
/**
|
|
24
|
-
* The three independent trace streams (spec #122 §A, decision D6). Each is its own
|
|
25
|
-
* FIFO ring with its own size budget, so a chatty stream can't evict another's
|
|
26
|
-
* lead-up. Every {@link BreadcrumbCategory} maps to exactly one stream via
|
|
27
|
-
* {@link streamOf}.
|
|
28
|
-
*/
|
|
29
|
-
export type TraceStream = "network" | "console" | "breadcrumbs";
|
|
30
|
-
/**
|
|
31
|
-
* Per-stream ring budgets — starting points from the grill (D6): network is the
|
|
32
|
-
* chattiest, breadcrumbs the sparsest. Per-project tunable, never frozen.
|
|
33
|
-
*/
|
|
34
|
-
export declare const DEFAULT_STREAM_BUDGETS: Readonly<Record<TraceStream, number>>;
|
|
35
|
-
/**
|
|
36
|
-
* The shared age cap (spec #122 §A): entries older than this are pruned from every
|
|
37
|
-
* stream, whichever trims first. ~3 minutes and — unlike the thin buffer's
|
|
38
|
-
* off-by-default cap — **on** by default, so an idle tab never ships stale context.
|
|
39
|
-
*/
|
|
40
|
-
export declare const DEFAULT_MAX_AGE_MS: number;
|
|
41
|
-
/**
|
|
42
|
-
* Console levels captured by default (spec #122 §C, decision D7): **all** of them, so
|
|
43
|
-
* the Console tab is a real console and not just an error log. Eviction priority (not
|
|
44
|
-
* capture) is what keeps a chatty app's `log`/`info`/`debug` from burying the signal —
|
|
45
|
-
* see {@link PINNED_CONSOLE_LEVELS}.
|
|
46
|
-
*/
|
|
47
|
-
export declare const DEFAULT_CONSOLE_LEVELS: readonly BreadcrumbLevel[];
|
|
48
|
-
/**
|
|
49
|
-
* The console levels **pinned** against eviction (spec #122 §C, decision D7). When the
|
|
50
|
-
* console stream overflows its budget, `warn`/`error`/`assert` are retained ahead of
|
|
51
|
-
* `log`/`info`/`debug`, so an error is never evicted by a burst of chatter — the
|
|
52
|
-
* low-priority levels fill the remainder and are dropped first.
|
|
53
|
-
*/
|
|
54
|
-
export declare const PINNED_CONSOLE_LEVELS: readonly BreadcrumbLevel[];
|
|
55
|
-
/**
|
|
56
|
-
* The console levels for which `source` (`file:line`) is captured (ticket #159).
|
|
57
|
-
*
|
|
58
|
-
* Capturing a call site constructs a `new Error()` to read its stack on **every** console
|
|
59
|
-
* call — a measurable hot-page cost when a chatty app logs in a tight loop (spec #122's
|
|
60
|
-
* "hot-page performance budget" open question, handed onward from the grill). The
|
|
61
|
-
* spec-sanctioned mitigation (decision D7) narrows source capture to the **levels that
|
|
62
|
-
* matter for debugging** — the same `warn`/`error`/`assert` that are pinned against
|
|
63
|
-
* eviction — so `log`/`info`/`debug` pay no per-call stack cost and simply omit `source`.
|
|
64
|
-
* Full-fidelity `source` is preserved exactly where it earns its keep: on warnings,
|
|
65
|
-
* errors, and failed assertions. Per-project tunability of this set is future work; today
|
|
66
|
-
* it deliberately mirrors {@link PINNED_CONSOLE_LEVELS} so "what survives eviction" and
|
|
67
|
-
* "what carries a call site" stay one idea.
|
|
68
|
-
*/
|
|
69
|
-
export declare const SOURCE_CAPTURE_LEVELS: readonly BreadcrumbLevel[];
|
|
70
|
-
/**
|
|
71
|
-
* Which stream a crumb's category belongs to (spec #122 §A). Network APIs
|
|
72
|
-
* (`fetch` / `xhr` / `beacon`) form the network stream, `console` its own, and
|
|
73
|
-
* everything else (navigation, masked UI events, the failing error) breadcrumbs.
|
|
74
|
-
*/
|
|
75
|
-
export declare function streamOf(category: string): TraceStream;
|
|
76
|
-
/** Filters or edits each crumb before it enters the buffer; `null` drops it. */
|
|
77
|
-
export type BeforeBreadcrumb = (crumb: Breadcrumb) => Breadcrumb | null;
|
|
78
|
-
/** Configuration for {@link createBreadcrumbBuffer}. All values are optional. */
|
|
79
|
-
export interface BreadcrumbBufferConfig {
|
|
80
|
-
/**
|
|
81
|
-
* Per-stream size budgets (oldest drop, independently per stream). Any stream
|
|
82
|
-
* omitted falls back to {@link DEFAULT_STREAM_BUDGETS}.
|
|
83
|
-
*/
|
|
84
|
-
readonly budgets?: Partial<Record<TraceStream, number>>;
|
|
85
|
-
/**
|
|
86
|
-
* Shared age cap in ms: entries older than this are dropped from every stream.
|
|
87
|
-
* Defaults to {@link DEFAULT_MAX_AGE_MS} (on); pass `0` (or a non-positive value)
|
|
88
|
-
* to disable age pruning.
|
|
89
|
-
*/
|
|
90
|
-
readonly maxAgeMs?: number;
|
|
91
|
-
/** A per-crumb filter (mute a category, edit, or drop by returning `null`). */
|
|
92
|
-
readonly beforeBreadcrumb?: BeforeBreadcrumb | null;
|
|
93
|
-
/** Epoch clock source, injectable for tests. Defaults to `Date.now`. */
|
|
94
|
-
readonly now?: () => number;
|
|
95
|
-
/** High-res monotonic clock, injectable for tests. Defaults to `performance.now`. */
|
|
96
|
-
readonly mono?: () => number;
|
|
97
|
-
/** Stable id generator, injectable for tests. Defaults to a per-buffer sequence. */
|
|
98
|
-
readonly nextId?: () => string;
|
|
99
|
-
}
|
|
100
|
-
/** A live trace buffer. */
|
|
101
|
-
export interface BreadcrumbBuffer {
|
|
102
|
-
/** Record a crumb (subject to `beforeBreadcrumb`, id/mono stamping, size, and age trimming). */
|
|
103
|
-
add(crumb: Breadcrumb): void;
|
|
104
|
-
/** The current crumbs, merged across streams and ordered in time — a fresh array. */
|
|
105
|
-
snapshot(): Breadcrumb[];
|
|
106
|
-
/** Drop every crumb. */
|
|
107
|
-
clear(): void;
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Create the per-stream trace buffer (spec #122 §A/§B). It holds **three
|
|
111
|
-
* independent FIFO rings** — `network`, `console`, `breadcrumbs` — each trimmed to
|
|
112
|
-
* its own budget so a chatty stream never evicts another's lead-up, plus a shared
|
|
113
|
-
* age cap. On `add`, a crumb passes through `beforeBreadcrumb`, is stamped with a
|
|
114
|
-
* stable `id` and a high-res `mono` timestamp (and an epoch `timestamp` if it has
|
|
115
|
-
* none), routed to its stream, then that stream is pruned by age and trimmed to its
|
|
116
|
-
* budget. `snapshot` prunes by age again, then merges the three streams into one
|
|
117
|
-
* `mono`-ordered array for transport — so the wire keeps its single `trace` field.
|
|
118
|
-
*/
|
|
119
|
-
export declare function createBreadcrumbBuffer(config?: BreadcrumbBufferConfig): BreadcrumbBuffer;
|
|
120
|
-
/**
|
|
121
|
-
* Longest scrubbed URL kept on a crumb (spec #122 §F): capped at assembly so an
|
|
122
|
-
* over-long URL is truncated, never dropped and never allowed to bloat a report.
|
|
123
|
-
*/
|
|
124
|
-
export declare const MAX_URL_LENGTH = 2048;
|
|
125
|
-
/**
|
|
126
|
-
* Structured console argument caps (spec #122 §C/§F), all applied **at assembly** so a
|
|
127
|
-
* single console crumb can never bloat a report:
|
|
128
|
-
* - {@link MAX_ARG_DEPTH} bounds how deep a `json` argument is cloned (deeper nodes
|
|
129
|
-
* collapse to an `[Object]`/`[Array]` marker);
|
|
130
|
-
* - {@link MAX_ARG_ITEMS} bounds how many keys/elements are kept at each level;
|
|
131
|
-
* - {@link MAX_ARG_STRING_LENGTH} truncates a single over-long string value;
|
|
132
|
-
* - {@link MAX_CONSOLE_ARGS_BYTES} bounds the serialized size of the whole args array
|
|
133
|
-
* (trailing args are dropped to fit), kept well under ingest's per-entry byte cap.
|
|
134
|
-
*/
|
|
135
|
-
export declare const MAX_ARG_DEPTH = 4;
|
|
136
|
-
export declare const MAX_ARG_ITEMS = 100;
|
|
137
|
-
export declare const MAX_ARG_STRING_LENGTH = 1024;
|
|
138
|
-
export declare const MAX_CONSOLE_ARGS_BYTES = 4096;
|
|
139
|
-
/** Classify one console argument into a type-tagged {@link ConsoleArg} (spec #122 §C). */
|
|
140
|
-
export declare function toConsoleArg(value: unknown): ConsoleArg;
|
|
141
|
-
/**
|
|
142
|
-
* A `console` crumb from a captured call's level and arguments (spec #122 §C). The
|
|
143
|
-
* `message` is the one-line preview (flattened, truncated); `args` preserves each
|
|
144
|
-
* argument as a structured, type-tagged, size-capped value so the Console tab can
|
|
145
|
-
* render objects/errors expandably; `source` is the best-effort `file:line`, attached
|
|
146
|
-
* only when the stack yielded one. Args are omitted entirely for a no-argument call.
|
|
147
|
-
*/
|
|
148
|
-
export declare function consoleCrumb(level: BreadcrumbLevel, args: readonly unknown[], timestamp: number, source?: SourceLocation): Breadcrumb;
|
|
149
|
-
/** A `navigation` crumb; both URLs are scrubbed and length-capped as the crumb is built. */
|
|
150
|
-
export declare function navigationCrumb(from: string, to: string, timestamp: number): Breadcrumb;
|
|
151
|
-
/**
|
|
152
|
-
* Classify an HTTP status into a {@link NetworkOutcome} (spec #122 §D). A missing or
|
|
153
|
-
* `0` status is a `network-error` (a request that never got a response); otherwise
|
|
154
|
-
* the 4xx/5xx classes flag failures and everything else is `ok`. Used both as the
|
|
155
|
-
* fallback outcome and by the thin {@link fetchCrumb} / {@link xhrCrumb} builders.
|
|
156
|
-
*/
|
|
157
|
-
export declare function outcomeFromStatus(status: number | undefined): NetworkOutcome;
|
|
158
|
-
/**
|
|
159
|
-
* The trivially-known byte size of a request body (spec #122 §D) — a string's UTF-8
|
|
160
|
-
* length, a `Blob`'s `.size`, or an `ArrayBuffer`/typed-array `.byteLength`. Anything
|
|
161
|
-
* that would require **reading** the body (a `ReadableStream`, `FormData`, a `Request`
|
|
162
|
-
* with a stream body) returns `undefined` — the "never read the body" line holds.
|
|
163
|
-
*/
|
|
164
|
-
export declare function trivialBodySize(body: unknown): number | undefined;
|
|
165
|
-
/** Parse a `content-length` header into a non-negative byte count, or `undefined`. */
|
|
166
|
-
export declare function parseContentLength(value: string | null | undefined): number | undefined;
|
|
167
|
-
/** The media type from a `content-type` header (the part before any `;` parameters). */
|
|
168
|
-
export declare function contentTypeOf(value: string | null | undefined): string | undefined;
|
|
169
|
-
/** The rich metadata a network crumb records (spec #122 §D) — never a body or header. */
|
|
170
|
-
export interface NetworkCrumbInput {
|
|
171
|
-
readonly api: NetworkApi;
|
|
172
|
-
readonly method: string;
|
|
173
|
-
/** The raw request URL — scrubbed (query dropped, path PII redacted) as the crumb is built. */
|
|
174
|
-
readonly url: string;
|
|
175
|
-
readonly status?: number;
|
|
176
|
-
readonly statusText?: string;
|
|
177
|
-
readonly durationMs?: number;
|
|
178
|
-
readonly reqSize?: number;
|
|
179
|
-
readonly respSize?: number;
|
|
180
|
-
readonly contentType?: string;
|
|
181
|
-
readonly outcome: NetworkOutcome;
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* A network crumb (`fetch` / `xhr` / `beacon`) with the rich, metadata-only fields
|
|
185
|
-
* the Network tab renders (spec #122 §D, ticket #139): api, method, scrubbed URL,
|
|
186
|
-
* status + statusText, duration, request/response sizes, content type, and a failure
|
|
187
|
-
* outcome. The URL is scrubbed and length-capped at assembly. The shape has **no field
|
|
188
|
-
* for a request/response body or an arbitrary header**, so neither can ever be
|
|
189
|
-
* recorded; only a positive status, and fields that were actually supplied, ride along.
|
|
190
|
-
*/
|
|
191
|
-
export declare function networkCrumb(input: NetworkCrumbInput, timestamp: number): Breadcrumb;
|
|
192
|
-
/**
|
|
193
|
-
* A thin `fetch` crumb from method + URL + status (outcome derived from the status).
|
|
194
|
-
* The instrumentation uses {@link networkCrumb} directly to carry the full metadata;
|
|
195
|
-
* this convenience builder seeds a network crumb from a status alone.
|
|
196
|
-
*/
|
|
197
|
-
export declare function fetchCrumb(method: string, url: string, status: number | undefined, timestamp: number): Breadcrumb;
|
|
198
|
-
/** A thin `xhr` crumb from method + URL + status (outcome derived from the status). */
|
|
199
|
-
export declare function xhrCrumb(method: string, url: string, status: number | undefined, timestamp: number): Breadcrumb;
|
|
200
|
-
/** A `ui.click` crumb: a masked target selector only — no text or value. */
|
|
201
|
-
export declare function clickCrumb(target: Element, timestamp: number): Breadcrumb;
|
|
202
|
-
/**
|
|
203
|
-
* A `ui.input` crumb: records **that** an input changed and which field, never
|
|
204
|
-
* the value typed into it. The `target` element's `.value` is never read.
|
|
205
|
-
*/
|
|
206
|
-
export declare function inputCrumb(target: Element, timestamp: number): Breadcrumb;
|
|
207
|
-
/**
|
|
208
|
-
* An `error` crumb for the failing exception or rejection that ends the trace. When
|
|
209
|
-
* `causedBy` is given (an auto-captured error), it rides on the crumb as the causal
|
|
210
|
-
* pointer to the ids of the entries immediately preceding the throw (spec #122 §F).
|
|
211
|
-
*/
|
|
212
|
-
export declare function errorCrumb(error: unknown, timestamp: number, causedBy?: readonly string[]): Breadcrumb;
|
|
213
|
-
/** Detaches an installed instrumentation, restoring the original behaviour. */
|
|
214
|
-
export type Teardown = () => void;
|
|
215
|
-
type AnyFn = (...args: unknown[]) => unknown;
|
|
216
|
-
type ConsoleLike = Partial<Record<BreadcrumbLevel, AnyFn>>;
|
|
217
|
-
type FetchFn = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
218
|
-
interface HistoryLike {
|
|
219
|
-
pushState(data: unknown, unused: string, url?: string | URL | null): void;
|
|
220
|
-
replaceState(data: unknown, unused: string, url?: string | URL | null): void;
|
|
221
|
-
}
|
|
222
|
-
interface XhrInstance {
|
|
223
|
-
status: number;
|
|
224
|
-
statusText?: string;
|
|
225
|
-
open(method: string, url: string | URL, ...rest: unknown[]): void;
|
|
226
|
-
send(body?: unknown): void;
|
|
227
|
-
getResponseHeader?(name: string): string | null;
|
|
228
|
-
addEventListener(type: string, listener: () => void): void;
|
|
229
|
-
removeEventListener(type: string, listener: () => void): void;
|
|
230
|
-
}
|
|
231
|
-
interface XhrConstructor {
|
|
232
|
-
new (): XhrInstance;
|
|
233
|
-
prototype: XhrInstance;
|
|
234
|
-
}
|
|
235
|
-
/** The `navigator.sendBeacon` surface the beacon instrumentation wraps. */
|
|
236
|
-
export interface BeaconNavigator {
|
|
237
|
-
sendBeacon?: (url: string | URL, data?: BodyInit | null) => boolean;
|
|
238
|
-
}
|
|
239
|
-
/** The structural window surface the instrumentation reaches into. */
|
|
240
|
-
export interface InstrumentWindow {
|
|
241
|
-
fetch?: FetchFn;
|
|
242
|
-
history?: HistoryLike;
|
|
243
|
-
location?: {
|
|
244
|
-
href: string;
|
|
245
|
-
};
|
|
246
|
-
XMLHttpRequest?: XhrConstructor;
|
|
247
|
-
navigator?: BeaconNavigator;
|
|
248
|
-
addEventListener(type: string, listener: (event: Event) => void, options?: boolean | AddEventListenerOptions): void;
|
|
249
|
-
removeEventListener(type: string, listener: (event: Event) => void, options?: boolean | EventListenerOptions): void;
|
|
250
|
-
}
|
|
251
|
-
/** Options for {@link instrumentBreadcrumbs} and the individual installers. */
|
|
252
|
-
export interface InstrumentOptions {
|
|
253
|
-
readonly win?: InstrumentWindow;
|
|
254
|
-
readonly doc?: Document;
|
|
255
|
-
readonly consoleObj?: ConsoleLike;
|
|
256
|
-
readonly consoleLevels?: readonly BreadcrumbLevel[];
|
|
257
|
-
/** Skip URLs (e.g. the SDK's own ingest calls) so they never become crumbs. */
|
|
258
|
-
readonly ignoreUrl?: (url: string) => boolean;
|
|
259
|
-
readonly now?: () => number;
|
|
260
|
-
/**
|
|
261
|
-
* High-res monotonic clock (spec #122 §D) — used to measure a request's duration as
|
|
262
|
-
* a delta around the wrapped call. Defaults to `performance.now`; injectable for tests.
|
|
263
|
-
*/
|
|
264
|
-
readonly mono?: () => number;
|
|
265
|
-
/**
|
|
266
|
-
* Whether to instrument the **console** stream (spec #122 §L; ticket #138).
|
|
267
|
-
* Defaults to `true`; pass `false` and `console` is never wrapped, so no console
|
|
268
|
-
* entry is ever recorded — the per-project toggle stops the stream at its source.
|
|
269
|
-
*/
|
|
270
|
-
readonly captureConsole?: boolean;
|
|
271
|
-
/**
|
|
272
|
-
* Whether to instrument the **network** stream — `fetch` and `XHR` (spec #122 §L;
|
|
273
|
-
* ticket #138). Defaults to `true`; pass `false` and neither is wrapped, so no
|
|
274
|
-
* network entry is ever recorded. Navigation and masked UI events are unaffected.
|
|
275
|
-
*/
|
|
276
|
-
readonly captureNetwork?: boolean;
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* The best-effort `file:line` a console call was made from (spec #122 §C). Parses the
|
|
280
|
-
* frames of a stack, skipping `skipFrames` leading (SDK-internal) frames so the source
|
|
281
|
-
* points at the host code that called `console.*`. Returns `undefined` when no frame
|
|
282
|
-
* yields a usable location — the crumb then simply omits `source`.
|
|
283
|
-
*/
|
|
284
|
-
export declare function sourceFromStack(stack: string | undefined, skipFrames?: number): SourceLocation | undefined;
|
|
285
|
-
/** Wrap `console` methods so calls at the captured levels become crumbs. */
|
|
286
|
-
export declare function instrumentConsole(buffer: BreadcrumbBuffer, consoleObj: ConsoleLike, levels: readonly BreadcrumbLevel[], now: () => number): Teardown;
|
|
287
|
-
/**
|
|
288
|
-
* Wrap `fetch` to record a rich network crumb on settlement (spec #122 §D, ticket
|
|
289
|
-
* #139): method, scrubbed URL, status + statusText, a `performance.now()` duration,
|
|
290
|
-
* request size (only when the body is trivially sized), response size (from the
|
|
291
|
-
* `content-length` header only), content type, and a failure outcome. The **original**
|
|
292
|
-
* outcome is returned untouched — the response is passed through **without its body
|
|
293
|
-
* being read** (only two metadata headers are inspected), and a rejection is re-thrown
|
|
294
|
-
* so the caller's `unhandledrejection` semantics are preserved.
|
|
295
|
-
*/
|
|
296
|
-
export declare function instrumentFetch(buffer: BreadcrumbBuffer, win: InstrumentWindow, ignoreUrl: (url: string) => boolean, now: () => number, mono?: () => number): Teardown;
|
|
297
|
-
/**
|
|
298
|
-
* Patch `XMLHttpRequest` to record a rich network crumb when a request settles (spec
|
|
299
|
-
* #122 §D, ticket #139): method, scrubbed URL, status + statusText, a `performance.now()`
|
|
300
|
-
* duration, request size (only when the body is trivially sized), response size (from
|
|
301
|
-
* the `content-length` header only), content type, and a failure outcome distinguished
|
|
302
|
-
* by which terminal event fired (`error` / `timeout` / `abort` / `load`). The `send`
|
|
303
|
-
* body argument is **never read for content** — only its trivially-known size — so a body
|
|
304
|
-
* can never reach the buffer.
|
|
305
|
-
*/
|
|
306
|
-
export declare function instrumentXhr(buffer: BreadcrumbBuffer, win: InstrumentWindow, ignoreUrl: (url: string) => boolean, now: () => number, mono?: () => number): Teardown;
|
|
307
|
-
/**
|
|
308
|
-
* Wrap `navigator.sendBeacon` to record a network crumb for each beacon (spec #122 §D,
|
|
309
|
-
* ticket #139). `sendBeacon` is fire-and-forget with a **synchronous boolean** return —
|
|
310
|
-
* `true` when the user agent queued the beacon, `false` when it declined — so wrapping
|
|
311
|
-
* must return that boolean unchanged: the original is called first and its result both
|
|
312
|
-
* classifies the crumb (`ok` / `network-error`) and is returned to the caller. Only the
|
|
313
|
-
* URL and the trivially-known request size are recorded (no response exists to read);
|
|
314
|
-
* capture failure is swallowed and the boolean still returned, and if the original itself
|
|
315
|
-
* throws we record best-effort and re-throw so the contract is preserved exactly.
|
|
316
|
-
*/
|
|
317
|
-
export declare function instrumentBeacon(buffer: BreadcrumbBuffer, win: InstrumentWindow, ignoreUrl: (url: string) => boolean, now: () => number): Teardown;
|
|
318
|
-
/** Record a `navigation` crumb on `pushState`/`replaceState`/pop/hash changes. */
|
|
319
|
-
export declare function instrumentNavigation(buffer: BreadcrumbBuffer, win: InstrumentWindow, now: () => number): Teardown;
|
|
320
|
-
/** Listen (capture-phase) for clicks and input changes as masked crumbs. */
|
|
321
|
-
export declare function instrumentUiEvents(buffer: BreadcrumbBuffer, doc: Document, now: () => number): Teardown;
|
|
322
|
-
/**
|
|
323
|
-
* Install every capture hook onto a window/document and return a single teardown
|
|
324
|
-
* that removes them all. Each hook is independent and defensive: a failure in one
|
|
325
|
-
* never blocks the others, and none can throw into the host page.
|
|
326
|
-
*/
|
|
327
|
-
export declare function instrumentBreadcrumbs(buffer: BreadcrumbBuffer, options?: InstrumentOptions): Teardown;
|
package/dist/invite.d.ts
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Invite redemption & reporter identity (spec §F).
|
|
3
|
-
*
|
|
4
|
-
* The zero-integration path for an invited tester: detect an invite token on the
|
|
5
|
-
* page (`?fixback_invite=<token>`) or an explicit `redeem()` call, read the
|
|
6
|
-
* Invite's public status, and — on confirmation — redeem it into a persisted
|
|
7
|
-
* `reporterId` the SDK thereafter presents as an identity input.
|
|
8
|
-
*
|
|
9
|
-
* This module is the wire + storage half (pure enough to unit-test directly): the
|
|
10
|
-
* two invite endpoints, the localStorage persistence scoped by publishable key,
|
|
11
|
-
* and the URL token detection / one-time consumption. The onboarding modal is
|
|
12
|
-
* `onboarding.ts`; `init` wires the two together.
|
|
13
|
-
*
|
|
14
|
-
* Like `boot.ts`, the wire types are a **vendored** slice of the server contract
|
|
15
|
-
* (`apps/api/src/invites/invite-redemption.controller.ts`) — the SDK never imports
|
|
16
|
-
* the private server package. Keep them in lock-step with that controller.
|
|
17
|
-
*/
|
|
18
|
-
import type { ReporterTier } from "./boot";
|
|
19
|
-
/** The Invite's shape. Mirrors the server's `InviteKind`. */
|
|
20
|
-
export type InviteKind = "targeted" | "shared";
|
|
21
|
-
/** The dead/unknown states a status or redeem read can resolve to. */
|
|
22
|
-
export type InviteDeadStatus = "revoked" | "expired" | "exhausted" | "not_found";
|
|
23
|
-
/**
|
|
24
|
-
* The public status of an Invite (`GET /api/invites/:token`). A live (`pending`)
|
|
25
|
-
* Invite reveals the minimal facts the onboarding modal needs — the Project, the
|
|
26
|
-
* Invite's shape, and the **server-derived** tier the redemption would grant; a
|
|
27
|
-
* dead or unknown token reveals only its state.
|
|
28
|
-
*/
|
|
29
|
-
export type InviteStatusAnswer = {
|
|
30
|
-
readonly status: "pending";
|
|
31
|
-
readonly projectId: string;
|
|
32
|
-
readonly kind: InviteKind;
|
|
33
|
-
readonly tier: ReporterTier;
|
|
34
|
-
} | {
|
|
35
|
-
readonly status: InviteDeadStatus;
|
|
36
|
-
};
|
|
37
|
-
/**
|
|
38
|
-
* The result of redeeming an Invite (`POST /api/invites/:token/redeem`): the
|
|
39
|
-
* minted Reporter (its handle + server-derived tier + Project), or why it was
|
|
40
|
-
* refused.
|
|
41
|
-
*/
|
|
42
|
-
export type RedeemAnswer = {
|
|
43
|
-
readonly status: "redeemed";
|
|
44
|
-
readonly reporterId: string;
|
|
45
|
-
readonly tier: ReporterTier;
|
|
46
|
-
readonly projectId: string;
|
|
47
|
-
} | {
|
|
48
|
-
readonly status: InviteDeadStatus;
|
|
49
|
-
};
|
|
50
|
-
/**
|
|
51
|
-
* The self-provided display fields captured in the onboarding modal. They ride
|
|
52
|
-
* along as a Reporter's chosen name / email — **never** a trust signal (the tier
|
|
53
|
-
* is always server-derived, spec §F).
|
|
54
|
-
*/
|
|
55
|
-
export interface ReporterDisplay {
|
|
56
|
-
readonly name?: string;
|
|
57
|
-
readonly email?: string;
|
|
58
|
-
}
|
|
59
|
-
/** A persisted redeemed Reporter: the server handle plus the display fields. */
|
|
60
|
-
export interface StoredReporter extends ReporterDisplay {
|
|
61
|
-
readonly reporterId: string;
|
|
62
|
-
}
|
|
63
|
-
/** The URL query parameter that carries an invite token. */
|
|
64
|
-
export declare const INVITE_QUERY_PARAM = "fixback_invite";
|
|
65
|
-
/**
|
|
66
|
-
* Read the invite token from a page URL's `?fixback_invite=` param. Returns the
|
|
67
|
-
* token, or `null` when absent, empty, or the URL cannot be parsed — never throws.
|
|
68
|
-
*/
|
|
69
|
-
export declare function readInviteToken(href: string): string | null;
|
|
70
|
-
/**
|
|
71
|
-
* Strip the invite token from the address bar (one-time consumption, spec §F) via
|
|
72
|
-
* `history.replaceState`, so a reload or a shared link cannot re-trigger — or
|
|
73
|
-
* re-consume — an already-redeemed Invite. Other params, the path, and the hash
|
|
74
|
-
* are preserved. Best-effort: it never throws into the host page.
|
|
75
|
-
*/
|
|
76
|
-
export declare function stripInviteToken(win: Window): void;
|
|
77
|
-
/**
|
|
78
|
-
* Persist a redeemed Reporter for `key`. The `reporterId` is the identity the SDK
|
|
79
|
-
* presents on later boots; the display name / email ride along as chosen fields.
|
|
80
|
-
* Best-effort — storage being unavailable (private mode) is never fatal.
|
|
81
|
-
*/
|
|
82
|
-
export declare function persistReporter(key: string, reporter: StoredReporter, store?: Storage | null): void;
|
|
83
|
-
/**
|
|
84
|
-
* Read the redeemed Reporter persisted for `key`, or `null` when none is stored,
|
|
85
|
-
* the record is malformed, or it carries no `reporterId`. Never throws.
|
|
86
|
-
*/
|
|
87
|
-
export declare function readStoredReporter(key: string, store?: Storage | null): StoredReporter | null;
|
|
88
|
-
/** Join an API base URL with the invite status path, tolerating a trailing slash. */
|
|
89
|
-
export declare function inviteStatusEndpoint(apiUrl: string, token: string): string;
|
|
90
|
-
/** Join an API base URL with the redeem path for a token. */
|
|
91
|
-
export declare function redeemEndpoint(apiUrl: string, token: string): string;
|
|
92
|
-
/**
|
|
93
|
-
* Read an Invite's public status. Resolves to the answer, or `null` when Fixback
|
|
94
|
-
* could not be reached or the body was not a recognised answer. The endpoint
|
|
95
|
-
* answers 200 for a live or dead Invite and 404 (with a JSON body) for an unknown
|
|
96
|
-
* token, so the body — not the HTTP status — is what the caller narrows on. Never
|
|
97
|
-
* throws: an outage stays invisible to the host page.
|
|
98
|
-
*/
|
|
99
|
-
export declare function fetchInviteStatus(apiUrl: string, token: string, fetchImpl?: typeof fetch): Promise<InviteStatusAnswer | null>;
|
|
100
|
-
/**
|
|
101
|
-
* Redeem an Invite by token, minting and returning a Reporter. Resolves to the
|
|
102
|
-
* answer, or `null` on an unreachable API or an unrecognised body. Never throws.
|
|
103
|
-
*/
|
|
104
|
-
export declare function redeemInviteToken(apiUrl: string, token: string, fetchImpl?: typeof fetch): Promise<RedeemAnswer | null>;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Styles for the invite onboarding modal (spec §F) — the Signal look of the
|
|
3
|
-
* frozen Reporter prototype (`docs/design/Fixback Reporter.dc.html`), scoped to
|
|
4
|
-
* the modal's own Shadow DOM so the host page is never touched and never touches
|
|
5
|
-
* it. Tokens mirror `overlay-styles.ts` so launcher, overlay, and modal read as
|
|
6
|
-
* one system.
|
|
7
|
-
*/
|
|
8
|
-
export declare const ONBOARDING_STYLES = "\n:host {\n --fb-color-accent: #2f6fed;\n --fb-color-accent-hover: #245fd0;\n --fb-color-on-emphasis: #ffffff;\n --fb-color-ink: #0f1720;\n --fb-color-text: #1a2530;\n --fb-color-muted: #5a6875;\n --fb-color-faint: #9aa7b2;\n --fb-color-hint: #b7c1cb;\n --fb-color-border: #dce3ea;\n --fb-color-border-soft: #e6ebf0;\n --fb-color-surface: #ffffff;\n --fb-color-card: #f6f8fa;\n --fb-color-accent-bg: #eaf1fe;\n --fb-color-success: #2f9e5b;\n --fb-font-sans: \"IBM Plex Sans\", system-ui, -apple-system, \"Segoe UI\", Roboto,\n Helvetica, Arial, sans-serif;\n --fb-font-mono: \"IBM Plex Mono\", ui-monospace, \"SFMono-Regular\", Menlo, Consolas,\n monospace;\n all: initial;\n}\n\n*, *::before, *::after { box-sizing: border-box; }\n\n.fb-ob-backdrop {\n position: fixed;\n inset: 0;\n z-index: 2147483010;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n background: rgba(15, 23, 32, 0.55);\n backdrop-filter: blur(3px);\n font-family: var(--fb-font-sans);\n color: var(--fb-color-text);\n animation: fb-ob-fade 0.25s ease both;\n}\n\n.fb-ob-panel {\n width: 400px;\n max-width: 100%;\n background: var(--fb-color-surface);\n border-radius: 16px;\n box-shadow: 0 30px 70px rgba(15, 40, 70, 0.4);\n overflow: hidden;\n animation: fb-ob-pop 0.32s cubic-bezier(0.2, 0.8, 0.3, 1) both;\n}\n\n.fb-ob-head {\n padding: 22px 24px 0;\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.fb-ob-mark {\n width: 22px;\n height: 22px;\n border-radius: 6px;\n background: var(--fb-color-accent);\n flex: none;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.fb-ob-mark::after {\n content: \"\";\n width: 7px;\n height: 7px;\n border-radius: 2px;\n background: #fff;\n}\n.fb-ob-brand { font-size: 15px; font-weight: 600; color: var(--fb-color-ink); }\n.fb-ob-chip {\n margin-left: auto;\n font-family: var(--fb-font-mono);\n font-size: 10px;\n color: #8a97a3;\n border: 1px solid var(--fb-color-border-soft);\n border-radius: 6px;\n padding: 2px 7px;\n}\n\n.fb-ob-body { padding: 16px 24px 8px; }\n.fb-ob-title {\n font-size: 19px;\n font-weight: 700;\n color: var(--fb-color-ink);\n letter-spacing: -0.01em;\n}\n.fb-ob-lede {\n font-size: 13.5px;\n color: var(--fb-color-muted);\n line-height: 1.5;\n margin: 7px 0 0;\n}\n.fb-ob-lede strong { color: var(--fb-color-text); }\n\n.fb-ob-card {\n margin: 16px 0;\n padding: 13px 14px;\n background: var(--fb-color-card);\n border: 1px solid var(--fb-color-border-soft);\n border-radius: 10px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n.fb-ob-row { display: flex; align-items: center; gap: 10px; }\n.fb-ob-row + .fb-ob-row {\n border-top: 1px solid #eef2f6;\n padding-top: 10px;\n}\n.fb-ob-rowlabel {\n font-family: var(--fb-font-mono);\n font-size: 10px;\n color: var(--fb-color-faint);\n width: 70px;\n flex: none;\n}\n.fb-ob-site { font-size: 13px; color: var(--fb-color-text); font-weight: 500; }\n.fb-ob-tier {\n font-size: 11px;\n font-weight: 600;\n color: var(--fb-color-accent);\n background: var(--fb-color-accent-bg);\n padding: 3px 9px;\n border-radius: 6px;\n}\n.fb-ob-tiernote { font-size: 11.5px; color: #8a97a3; }\n\n.fb-ob-fieldlabel {\n display: block;\n font-family: var(--fb-font-mono);\n font-size: 10px;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n color: var(--fb-color-faint);\n margin-bottom: 6px;\n}\n.fb-ob-fields { display: flex; gap: 8px; }\n.fb-ob-input {\n height: 38px;\n padding: 0 12px;\n border: 1px solid var(--fb-color-border);\n border-radius: 9px;\n font-family: inherit;\n font-size: 13px;\n color: var(--fb-color-text);\n outline: none;\n min-width: 0;\n}\n.fb-ob-input:focus { border-color: var(--fb-color-accent); }\n.fb-ob-name { flex: 1; }\n.fb-ob-email { flex: 1.3; font-family: var(--fb-font-mono); font-size: 12.5px; color: var(--fb-color-muted); }\n\n.fb-ob-privacy {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n margin-top: 14px;\n font-size: 11.5px;\n color: #8a97a3;\n line-height: 1.5;\n}\n.fb-ob-privacy svg { flex: none; margin-top: 1px; }\n.fb-ob-privacy strong { color: var(--fb-color-muted); }\n\n.fb-ob-foot { padding: 16px 24px 22px; }\n.fb-ob-confirm {\n width: 100%;\n height: 44px;\n border: 0;\n border-radius: 11px;\n background: var(--fb-color-accent);\n color: var(--fb-color-on-emphasis);\n font-family: inherit;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n}\n.fb-ob-confirm:hover { background: var(--fb-color-accent-hover); }\n.fb-ob-confirm:disabled { opacity: 0.6; cursor: default; }\n\n@keyframes fb-ob-fade { from { opacity: 0; } to { opacity: 1; } }\n@keyframes fb-ob-pop {\n from { opacity: 0; transform: translateY(8px) scale(0.98); }\n to { opacity: 1; transform: none; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .fb-ob-backdrop, .fb-ob-panel { animation: none; }\n}\n";
|
package/dist/onboarding.d.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The invite onboarding modal (spec §F) — the SDK-rendered redemption screen an
|
|
3
|
-
* invited tester sees when a page carries an invite token. It shows the site
|
|
4
|
-
* they were invited to, the **server-derived** access tier the redemption grants,
|
|
5
|
-
* a private-by-default note, and a "Continue as" name / email, then confirms.
|
|
6
|
-
*
|
|
7
|
-
* Built to the frozen Signal Reporter prototype
|
|
8
|
-
* (`docs/design/Fixback Reporter.dc.html`). It mounts lazily inside its own open
|
|
9
|
-
* Shadow DOM so the host page is fully isolated, and — like the launcher and
|
|
10
|
-
* overlay — never throws into the host page. It renders only data the SDK
|
|
11
|
-
* truthfully holds: the site's own origin and the server-derived tier. The name /
|
|
12
|
-
* email are **self-provided display fields**, never a trust signal (§F).
|
|
13
|
-
*/
|
|
14
|
-
import type { ReporterTier } from "./boot";
|
|
15
|
-
import type { ReporterDisplay } from "./invite";
|
|
16
|
-
/** Marks the modal's host element in the light DOM, so it is findable and unique. */
|
|
17
|
-
export declare const ONBOARDING_ATTRIBUTE = "data-fixback-onboard";
|
|
18
|
-
/** Configuration for {@link createOnboardingModal}. */
|
|
19
|
-
export interface OnboardingConfig {
|
|
20
|
-
/** The site the tester was invited to — its origin (`window.location.host`). */
|
|
21
|
-
readonly origin: string;
|
|
22
|
-
/** The **server-derived** tier the redemption grants (from the invite status). */
|
|
23
|
-
readonly tier: ReporterTier;
|
|
24
|
-
/** Prefill the Continue-as fields from a previously stored display identity. */
|
|
25
|
-
readonly defaults?: ReporterDisplay;
|
|
26
|
-
/** Called with the self-provided display fields when the tester confirms. */
|
|
27
|
-
readonly onConfirm: (display: ReporterDisplay) => void;
|
|
28
|
-
/** Where to mount the modal host. Defaults to `document.body`. */
|
|
29
|
-
readonly target?: HTMLElement;
|
|
30
|
-
/** The document to build in. Defaults to the target's owner document. */
|
|
31
|
-
readonly doc?: Document;
|
|
32
|
-
}
|
|
33
|
-
/** A mounted onboarding modal. */
|
|
34
|
-
export interface OnboardingModal {
|
|
35
|
-
destroy(): void;
|
|
36
|
-
readonly host: HTMLElement;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Render the onboarding modal into `target` (default `document.body`) and return a
|
|
40
|
-
* handle to remove it. Confirming reads the name / email, fires `onConfirm` once
|
|
41
|
-
* (further clicks are ignored while the caller redeems), and leaves teardown to
|
|
42
|
-
* the caller so it can strip the token and mount the launcher first.
|
|
43
|
-
*/
|
|
44
|
-
export declare function createOnboardingModal(config: OnboardingConfig): OnboardingModal;
|