@bugban/js 1.0.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 +162 -0
- package/dist/index.cjs +1700 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +349 -0
- package/dist/index.d.ts +349 -0
- package/dist/index.js +1678 -0
- package/dist/index.js.map +1 -0
- package/dist/standalone/bugban.global.js +5 -0
- package/dist/standalone/bugban.global.js.map +1 -0
- package/package.json +34 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for the Bugban JavaScript SDK.
|
|
3
|
+
*
|
|
4
|
+
* Field names on the wire mirror the PHP SDK exactly, because both talk to the
|
|
5
|
+
* same ingest endpoints and the same server-side fingerprinting. Renaming a
|
|
6
|
+
* field here silently changes how errors group — don't.
|
|
7
|
+
*/
|
|
8
|
+
type Level = 'error' | 'warning' | 'info' | 'debug' | 'fatal';
|
|
9
|
+
type BreadcrumbType = 'console' | 'navigation' | 'click' | 'http' | 'error' | 'manual';
|
|
10
|
+
interface Breadcrumb {
|
|
11
|
+
type: BreadcrumbType;
|
|
12
|
+
/** Short human label, e.g. "GET /api/orders → 500". */
|
|
13
|
+
message: string;
|
|
14
|
+
level?: Level;
|
|
15
|
+
/** ISO-8601. */
|
|
16
|
+
timestamp: string;
|
|
17
|
+
data?: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
interface StackFrame {
|
|
20
|
+
file?: string;
|
|
21
|
+
line?: number;
|
|
22
|
+
column?: number;
|
|
23
|
+
function?: string;
|
|
24
|
+
/** false for node_modules / framework frames — the panel collapses those. */
|
|
25
|
+
in_app?: boolean;
|
|
26
|
+
}
|
|
27
|
+
interface UserInfo {
|
|
28
|
+
id?: string | number;
|
|
29
|
+
email?: string;
|
|
30
|
+
name?: string;
|
|
31
|
+
[key: string]: unknown;
|
|
32
|
+
}
|
|
33
|
+
/** What the browser measured about page load and responsiveness. */
|
|
34
|
+
interface VitalMetric {
|
|
35
|
+
/** LCP | FCP | CLS | INP | TTFB | LONG_TASK | RESOURCE */
|
|
36
|
+
name: string;
|
|
37
|
+
value: number;
|
|
38
|
+
/** Google's good/needs-improvement/poor bucket, computed SDK-side. */
|
|
39
|
+
rating?: 'good' | 'needs-improvement' | 'poor';
|
|
40
|
+
url?: string;
|
|
41
|
+
/** Element selector or resource URL the metric is attributed to. */
|
|
42
|
+
target?: string;
|
|
43
|
+
navigation_type?: string;
|
|
44
|
+
occurred_at?: string;
|
|
45
|
+
data?: Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
/** A serialized DOM snapshot taken at error time (never a pixel image). */
|
|
48
|
+
interface Snapshot {
|
|
49
|
+
kind: 'dom';
|
|
50
|
+
html: string;
|
|
51
|
+
/** Inlined same-origin stylesheet text, so the replay renders standalone. */
|
|
52
|
+
css?: string;
|
|
53
|
+
viewport?: {
|
|
54
|
+
width: number;
|
|
55
|
+
height: number;
|
|
56
|
+
scrollX: number;
|
|
57
|
+
scrollY: number;
|
|
58
|
+
};
|
|
59
|
+
url?: string;
|
|
60
|
+
taken_at?: string;
|
|
61
|
+
}
|
|
62
|
+
interface BugbanEvent {
|
|
63
|
+
exception_class?: string;
|
|
64
|
+
message?: string;
|
|
65
|
+
level?: Level;
|
|
66
|
+
type?: string;
|
|
67
|
+
file?: string;
|
|
68
|
+
line?: number;
|
|
69
|
+
handled?: boolean;
|
|
70
|
+
stacktrace?: StackFrame[];
|
|
71
|
+
release?: string;
|
|
72
|
+
environment?: string;
|
|
73
|
+
request?: Record<string, unknown>;
|
|
74
|
+
user?: UserInfo | null;
|
|
75
|
+
session?: Record<string, unknown>;
|
|
76
|
+
device?: Record<string, unknown>;
|
|
77
|
+
context?: Record<string, unknown>;
|
|
78
|
+
breadcrumbs?: Breadcrumb[];
|
|
79
|
+
snapshot?: Snapshot | null;
|
|
80
|
+
/** Server groups by this when present; otherwise it derives one. */
|
|
81
|
+
fingerprint?: string;
|
|
82
|
+
}
|
|
83
|
+
interface ConsoleOptions {
|
|
84
|
+
/** Which console methods become breadcrumbs. */
|
|
85
|
+
levels?: Array<'log' | 'info' | 'warn' | 'error' | 'debug'>;
|
|
86
|
+
/**
|
|
87
|
+
* Which console methods ALSO report a standalone error event.
|
|
88
|
+
* Defaults to ['error'] — console.error is how most apps surface a
|
|
89
|
+
* swallowed failure that never reaches window.onerror.
|
|
90
|
+
*/
|
|
91
|
+
captureAsEvent?: Array<'warn' | 'error'>;
|
|
92
|
+
}
|
|
93
|
+
interface NetworkOptions {
|
|
94
|
+
/** Record fetch/XHR calls as breadcrumbs. */
|
|
95
|
+
enabled?: boolean;
|
|
96
|
+
/** Report failed requests (>=500, or network error) as their own event. */
|
|
97
|
+
captureFailures?: boolean;
|
|
98
|
+
/** Substrings; matching URLs are never recorded (in addition to our own). */
|
|
99
|
+
ignoreUrls?: Array<string | RegExp>;
|
|
100
|
+
}
|
|
101
|
+
interface SnapshotOptions {
|
|
102
|
+
enabled?: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Replace the value of every input/textarea/select before serializing.
|
|
105
|
+
* NON-NEGOTIABLE DEFAULT: true. Turning it off ships whatever the user had
|
|
106
|
+
* typed — including passwords and card numbers — to the Bugban server.
|
|
107
|
+
*/
|
|
108
|
+
maskInputs?: boolean;
|
|
109
|
+
/** Extra CSS selectors whose text content is replaced with •. */
|
|
110
|
+
maskSelectors?: string[];
|
|
111
|
+
/** Skip the snapshot entirely once the HTML exceeds this many bytes. */
|
|
112
|
+
maxBytes?: number;
|
|
113
|
+
}
|
|
114
|
+
interface VitalsOptions {
|
|
115
|
+
enabled?: boolean;
|
|
116
|
+
/** 0..1 — fraction of sessions that report vitals. 1 = every session. */
|
|
117
|
+
sampleRate?: number;
|
|
118
|
+
/** Report tasks blocking the main thread longer than this (ms). */
|
|
119
|
+
longTaskMs?: number;
|
|
120
|
+
/** Report individual resources slower than this (ms). */
|
|
121
|
+
slowResourceMs?: number;
|
|
122
|
+
}
|
|
123
|
+
interface BugbanOptions {
|
|
124
|
+
/** Project API key. Without it the SDK is a silent no-op. */
|
|
125
|
+
apiKey?: string;
|
|
126
|
+
/** Bugban host, e.g. https://bugban.online */
|
|
127
|
+
host?: string;
|
|
128
|
+
/** Your app version — shown on the event and used for release grouping. */
|
|
129
|
+
release?: string;
|
|
130
|
+
environment?: string;
|
|
131
|
+
/** Framework name reported on the install ping (adapters set this). */
|
|
132
|
+
framework?: string;
|
|
133
|
+
frameworkVersion?: string;
|
|
134
|
+
/** Turn the whole SDK off without removing the code (e.g. in dev). */
|
|
135
|
+
enabled?: boolean;
|
|
136
|
+
debug?: boolean;
|
|
137
|
+
/** Max breadcrumbs kept in the ring buffer. */
|
|
138
|
+
maxBreadcrumbs?: number;
|
|
139
|
+
/** 0..1 — fraction of errors actually sent. */
|
|
140
|
+
sampleRate?: number;
|
|
141
|
+
console?: boolean | ConsoleOptions;
|
|
142
|
+
network?: boolean | NetworkOptions;
|
|
143
|
+
snapshot?: boolean | SnapshotOptions;
|
|
144
|
+
vitals?: boolean | VitalsOptions;
|
|
145
|
+
/** Capture window.onerror / unhandledrejection (browser) and the Node equivalents. */
|
|
146
|
+
globalHandlers?: boolean;
|
|
147
|
+
/** Record clicks and route changes as breadcrumbs. */
|
|
148
|
+
domBreadcrumbs?: boolean;
|
|
149
|
+
/** Send the one-time install ping so the panel shows "SDK connected". */
|
|
150
|
+
installPing?: boolean;
|
|
151
|
+
/** Extra request-header/body keys to redact, on top of the built-ins. */
|
|
152
|
+
redactKeys?: string[];
|
|
153
|
+
/** Drop an event (return null) or edit it before it is sent. */
|
|
154
|
+
beforeSend?: (event: BugbanEvent) => BugbanEvent | null;
|
|
155
|
+
/** Drop or edit a breadcrumb before it enters the buffer. */
|
|
156
|
+
beforeBreadcrumb?: (crumb: Breadcrumb) => Breadcrumb | null;
|
|
157
|
+
/** Errors whose message matches any of these are never sent. */
|
|
158
|
+
ignoreErrors?: Array<string | RegExp>;
|
|
159
|
+
}
|
|
160
|
+
/** Fully-resolved options — every optional field has a value. */
|
|
161
|
+
interface ResolvedOptions extends BugbanOptions {
|
|
162
|
+
apiKey: string;
|
|
163
|
+
host: string;
|
|
164
|
+
enabled: boolean;
|
|
165
|
+
debug: boolean;
|
|
166
|
+
maxBreadcrumbs: number;
|
|
167
|
+
sampleRate: number;
|
|
168
|
+
console: Required<ConsoleOptions> | false;
|
|
169
|
+
network: Required<NetworkOptions> | false;
|
|
170
|
+
snapshot: Required<SnapshotOptions> | false;
|
|
171
|
+
vitals: Required<VitalsOptions> | false;
|
|
172
|
+
globalHandlers: boolean;
|
|
173
|
+
domBreadcrumbs: boolean;
|
|
174
|
+
installPing: boolean;
|
|
175
|
+
redactKeys: string[];
|
|
176
|
+
ignoreErrors: Array<string | RegExp>;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* The SDK client.
|
|
181
|
+
*
|
|
182
|
+
* One rule governs every method here: nothing may throw into the host
|
|
183
|
+
* application, and nothing may block it. Every public entry point is wrapped,
|
|
184
|
+
* every optional browser API is feature-detected, and delivery is
|
|
185
|
+
* fire-and-forget. A monitoring tool that can take down the app it monitors is
|
|
186
|
+
* worse than no monitoring at all.
|
|
187
|
+
*/
|
|
188
|
+
declare class BugbanClient {
|
|
189
|
+
private opts;
|
|
190
|
+
private transport;
|
|
191
|
+
private crumbs;
|
|
192
|
+
private vitals?;
|
|
193
|
+
private teardown;
|
|
194
|
+
private user;
|
|
195
|
+
private context;
|
|
196
|
+
private sessionId;
|
|
197
|
+
private startedAt;
|
|
198
|
+
/** Events waiting to be sent, coalesced so an error storm is one request. */
|
|
199
|
+
private queue;
|
|
200
|
+
private flushTimer;
|
|
201
|
+
/** Guard against reporting an error that our own reporting caused. */
|
|
202
|
+
private sending;
|
|
203
|
+
private started;
|
|
204
|
+
constructor(options?: BugbanOptions);
|
|
205
|
+
get options(): ResolvedOptions;
|
|
206
|
+
/** Wire up integrations. Safe to call twice — the second call is ignored. */
|
|
207
|
+
start(): void;
|
|
208
|
+
private installIntegrations;
|
|
209
|
+
/**
|
|
210
|
+
* Send whatever is queued before the page goes away.
|
|
211
|
+
*
|
|
212
|
+
* Events are batched with a short debounce so an error loop becomes one
|
|
213
|
+
* request instead of hundreds. That debounce loses the last batch whenever
|
|
214
|
+
* the user navigates immediately after the error — which is the common
|
|
215
|
+
* case, not an edge case: click a link, something throws, the document is
|
|
216
|
+
* torn down before the timer fires. Observed exactly that while testing:
|
|
217
|
+
* an uncaught TypeError never arrived while the beacon-based vitals from the
|
|
218
|
+
* same page did.
|
|
219
|
+
*
|
|
220
|
+
* `visibilitychange` is the reliable signal (mobile Safari often skips
|
|
221
|
+
* `beforeunload`), and `pagehide` covers the bfcache case. Both drain with
|
|
222
|
+
* `beacon: true`, the only delivery a closing document is guaranteed to
|
|
223
|
+
* complete.
|
|
224
|
+
*/
|
|
225
|
+
private installUnloadFlush;
|
|
226
|
+
addBreadcrumb(crumb: Omit<Breadcrumb, 'timestamp'> & {
|
|
227
|
+
timestamp?: string;
|
|
228
|
+
}): void;
|
|
229
|
+
setUser(user: UserInfo | null): void;
|
|
230
|
+
setContext(key: string, value: unknown): void;
|
|
231
|
+
captureMessage(message: string, level?: Level): void;
|
|
232
|
+
/** Report an error. Never throws, never blocks. */
|
|
233
|
+
capture(error: unknown, extra?: {
|
|
234
|
+
handled?: boolean;
|
|
235
|
+
level?: Level;
|
|
236
|
+
type?: string;
|
|
237
|
+
context?: Record<string, unknown>;
|
|
238
|
+
request?: Record<string, unknown>;
|
|
239
|
+
}): void;
|
|
240
|
+
/** Flush anything queued. Await it before a process exits. */
|
|
241
|
+
flush(): Promise<void>;
|
|
242
|
+
/** Remove every hook the SDK installed. */
|
|
243
|
+
close(): void;
|
|
244
|
+
/** Adapters use this to report render timings alongside browser vitals. */
|
|
245
|
+
recordMetric(metric: VitalMetric): void;
|
|
246
|
+
private requestInfo;
|
|
247
|
+
private enqueue;
|
|
248
|
+
private drain;
|
|
249
|
+
private sendVitals;
|
|
250
|
+
private debug;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
declare function parseStack(stack: unknown, limit?: number): StackFrame[];
|
|
254
|
+
/**
|
|
255
|
+
* Normalise anything a JS app can throw into an error-shaped object.
|
|
256
|
+
* `throw 'a string'` and `Promise.reject({code: 500})` are both common; both
|
|
257
|
+
* must produce a usable event rather than "undefined".
|
|
258
|
+
*/
|
|
259
|
+
declare function normalizeError(input: unknown): {
|
|
260
|
+
name: string;
|
|
261
|
+
message: string;
|
|
262
|
+
stack?: string;
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Deep-redact an object by key name. Depth-limited so a pathological structure
|
|
267
|
+
* cannot lock up the main thread.
|
|
268
|
+
*/
|
|
269
|
+
declare function redact<T>(value: T, extraKeys?: string[], depth?: number): T;
|
|
270
|
+
/**
|
|
271
|
+
* Strip credentials out of a URL: query params named like secrets, plus any
|
|
272
|
+
* user:pass@ prefix. Returns the input unchanged if it cannot be parsed.
|
|
273
|
+
*/
|
|
274
|
+
declare function redactUrl(url: string, extraKeys?: string[]): string;
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Runtime detection and environment facts.
|
|
278
|
+
*
|
|
279
|
+
* Every lookup is defensive: this file runs in browsers, in Node, in edge
|
|
280
|
+
* runtimes, and during SSR where `window` exists but `document` does not.
|
|
281
|
+
* Nothing here may throw — a crash in environment detection would take down
|
|
282
|
+
* the host application on import, which is exactly the failure the PHP SDK
|
|
283
|
+
* learned to avoid the hard way.
|
|
284
|
+
*/
|
|
285
|
+
declare const SDK_NAME = "bugban-js";
|
|
286
|
+
declare const SDK_VERSION = "1.0.0";
|
|
287
|
+
/** 'browser' | 'node' | 'unknown' — reported on the install ping. */
|
|
288
|
+
declare function runtimeName(): string;
|
|
289
|
+
/**
|
|
290
|
+
* The runtime's own version: Node's `v22.13.1`, or the browser's UA string.
|
|
291
|
+
* The panel shows this next to the framework version, the same way it shows
|
|
292
|
+
* the PHP version for the PHP SDKs.
|
|
293
|
+
*/
|
|
294
|
+
declare function runtimeVersion(): string | undefined;
|
|
295
|
+
/**
|
|
296
|
+
* Read a dependency's version out of the host app's node_modules, so an
|
|
297
|
+
* adapter can report "react 19.0.0" without importing react itself.
|
|
298
|
+
*/
|
|
299
|
+
declare function dependencyVersion(pkg: string): Promise<string | undefined>;
|
|
300
|
+
|
|
301
|
+
declare function init(options?: BugbanOptions): BugbanClient;
|
|
302
|
+
/** The active client, or null when init() has not been called. */
|
|
303
|
+
declare function getClient(): BugbanClient | null;
|
|
304
|
+
/**
|
|
305
|
+
* Every helper below is a no-op before init(). That is deliberate: a component
|
|
306
|
+
* that calls captureError must not crash because the app forgot to configure
|
|
307
|
+
* monitoring, or because it is running in a test.
|
|
308
|
+
*/
|
|
309
|
+
declare function capture(error: unknown, extra?: {
|
|
310
|
+
handled?: boolean;
|
|
311
|
+
level?: Level;
|
|
312
|
+
type?: string;
|
|
313
|
+
context?: Record<string, unknown>;
|
|
314
|
+
}): void;
|
|
315
|
+
declare function captureMessage(message: string, level?: Level): void;
|
|
316
|
+
declare function setUser(user: UserInfo | null): void;
|
|
317
|
+
declare function setContext(key: string, value: unknown): void;
|
|
318
|
+
declare function addBreadcrumb(crumb: Omit<Breadcrumb, 'timestamp'> & {
|
|
319
|
+
timestamp?: string;
|
|
320
|
+
}): void;
|
|
321
|
+
declare function recordMetric(metric: VitalMetric): void;
|
|
322
|
+
declare function flush(): Promise<void>;
|
|
323
|
+
declare function close(): void;
|
|
324
|
+
/**
|
|
325
|
+
* Namespace form, so `Bugban.capture(e)` reads the same as the PHP facade.
|
|
326
|
+
*
|
|
327
|
+
* Deliberately NOT also a default export: mixing default and named exports
|
|
328
|
+
* makes the CommonJS build require `.default`, which is exactly the kind of
|
|
329
|
+
* "works in one install shape, breaks in another" trap that took a customer's
|
|
330
|
+
* site down on the PHP side. One import style, everywhere:
|
|
331
|
+
*
|
|
332
|
+
* import { Bugban } from '@bugban/js';
|
|
333
|
+
* const { Bugban } = require('@bugban/js');
|
|
334
|
+
*/
|
|
335
|
+
declare const Bugban: {
|
|
336
|
+
VERSION: string;
|
|
337
|
+
init: typeof init;
|
|
338
|
+
getClient: typeof getClient;
|
|
339
|
+
capture: typeof capture;
|
|
340
|
+
captureMessage: typeof captureMessage;
|
|
341
|
+
setUser: typeof setUser;
|
|
342
|
+
setContext: typeof setContext;
|
|
343
|
+
addBreadcrumb: typeof addBreadcrumb;
|
|
344
|
+
recordMetric: typeof recordMetric;
|
|
345
|
+
flush: typeof flush;
|
|
346
|
+
close: typeof close;
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
export { type Breadcrumb, type BreadcrumbType, Bugban, BugbanClient, type BugbanEvent, type BugbanOptions, type ConsoleOptions, type Level, type NetworkOptions, SDK_NAME, SDK_VERSION, type Snapshot, type SnapshotOptions, type StackFrame, type UserInfo, type VitalMetric, type VitalsOptions, addBreadcrumb, capture, captureMessage, close, dependencyVersion, flush, getClient, init, normalizeError, parseStack, recordMetric, redact, redactUrl, runtimeName, runtimeVersion, setContext, setUser };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for the Bugban JavaScript SDK.
|
|
3
|
+
*
|
|
4
|
+
* Field names on the wire mirror the PHP SDK exactly, because both talk to the
|
|
5
|
+
* same ingest endpoints and the same server-side fingerprinting. Renaming a
|
|
6
|
+
* field here silently changes how errors group — don't.
|
|
7
|
+
*/
|
|
8
|
+
type Level = 'error' | 'warning' | 'info' | 'debug' | 'fatal';
|
|
9
|
+
type BreadcrumbType = 'console' | 'navigation' | 'click' | 'http' | 'error' | 'manual';
|
|
10
|
+
interface Breadcrumb {
|
|
11
|
+
type: BreadcrumbType;
|
|
12
|
+
/** Short human label, e.g. "GET /api/orders → 500". */
|
|
13
|
+
message: string;
|
|
14
|
+
level?: Level;
|
|
15
|
+
/** ISO-8601. */
|
|
16
|
+
timestamp: string;
|
|
17
|
+
data?: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
interface StackFrame {
|
|
20
|
+
file?: string;
|
|
21
|
+
line?: number;
|
|
22
|
+
column?: number;
|
|
23
|
+
function?: string;
|
|
24
|
+
/** false for node_modules / framework frames — the panel collapses those. */
|
|
25
|
+
in_app?: boolean;
|
|
26
|
+
}
|
|
27
|
+
interface UserInfo {
|
|
28
|
+
id?: string | number;
|
|
29
|
+
email?: string;
|
|
30
|
+
name?: string;
|
|
31
|
+
[key: string]: unknown;
|
|
32
|
+
}
|
|
33
|
+
/** What the browser measured about page load and responsiveness. */
|
|
34
|
+
interface VitalMetric {
|
|
35
|
+
/** LCP | FCP | CLS | INP | TTFB | LONG_TASK | RESOURCE */
|
|
36
|
+
name: string;
|
|
37
|
+
value: number;
|
|
38
|
+
/** Google's good/needs-improvement/poor bucket, computed SDK-side. */
|
|
39
|
+
rating?: 'good' | 'needs-improvement' | 'poor';
|
|
40
|
+
url?: string;
|
|
41
|
+
/** Element selector or resource URL the metric is attributed to. */
|
|
42
|
+
target?: string;
|
|
43
|
+
navigation_type?: string;
|
|
44
|
+
occurred_at?: string;
|
|
45
|
+
data?: Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
/** A serialized DOM snapshot taken at error time (never a pixel image). */
|
|
48
|
+
interface Snapshot {
|
|
49
|
+
kind: 'dom';
|
|
50
|
+
html: string;
|
|
51
|
+
/** Inlined same-origin stylesheet text, so the replay renders standalone. */
|
|
52
|
+
css?: string;
|
|
53
|
+
viewport?: {
|
|
54
|
+
width: number;
|
|
55
|
+
height: number;
|
|
56
|
+
scrollX: number;
|
|
57
|
+
scrollY: number;
|
|
58
|
+
};
|
|
59
|
+
url?: string;
|
|
60
|
+
taken_at?: string;
|
|
61
|
+
}
|
|
62
|
+
interface BugbanEvent {
|
|
63
|
+
exception_class?: string;
|
|
64
|
+
message?: string;
|
|
65
|
+
level?: Level;
|
|
66
|
+
type?: string;
|
|
67
|
+
file?: string;
|
|
68
|
+
line?: number;
|
|
69
|
+
handled?: boolean;
|
|
70
|
+
stacktrace?: StackFrame[];
|
|
71
|
+
release?: string;
|
|
72
|
+
environment?: string;
|
|
73
|
+
request?: Record<string, unknown>;
|
|
74
|
+
user?: UserInfo | null;
|
|
75
|
+
session?: Record<string, unknown>;
|
|
76
|
+
device?: Record<string, unknown>;
|
|
77
|
+
context?: Record<string, unknown>;
|
|
78
|
+
breadcrumbs?: Breadcrumb[];
|
|
79
|
+
snapshot?: Snapshot | null;
|
|
80
|
+
/** Server groups by this when present; otherwise it derives one. */
|
|
81
|
+
fingerprint?: string;
|
|
82
|
+
}
|
|
83
|
+
interface ConsoleOptions {
|
|
84
|
+
/** Which console methods become breadcrumbs. */
|
|
85
|
+
levels?: Array<'log' | 'info' | 'warn' | 'error' | 'debug'>;
|
|
86
|
+
/**
|
|
87
|
+
* Which console methods ALSO report a standalone error event.
|
|
88
|
+
* Defaults to ['error'] — console.error is how most apps surface a
|
|
89
|
+
* swallowed failure that never reaches window.onerror.
|
|
90
|
+
*/
|
|
91
|
+
captureAsEvent?: Array<'warn' | 'error'>;
|
|
92
|
+
}
|
|
93
|
+
interface NetworkOptions {
|
|
94
|
+
/** Record fetch/XHR calls as breadcrumbs. */
|
|
95
|
+
enabled?: boolean;
|
|
96
|
+
/** Report failed requests (>=500, or network error) as their own event. */
|
|
97
|
+
captureFailures?: boolean;
|
|
98
|
+
/** Substrings; matching URLs are never recorded (in addition to our own). */
|
|
99
|
+
ignoreUrls?: Array<string | RegExp>;
|
|
100
|
+
}
|
|
101
|
+
interface SnapshotOptions {
|
|
102
|
+
enabled?: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Replace the value of every input/textarea/select before serializing.
|
|
105
|
+
* NON-NEGOTIABLE DEFAULT: true. Turning it off ships whatever the user had
|
|
106
|
+
* typed — including passwords and card numbers — to the Bugban server.
|
|
107
|
+
*/
|
|
108
|
+
maskInputs?: boolean;
|
|
109
|
+
/** Extra CSS selectors whose text content is replaced with •. */
|
|
110
|
+
maskSelectors?: string[];
|
|
111
|
+
/** Skip the snapshot entirely once the HTML exceeds this many bytes. */
|
|
112
|
+
maxBytes?: number;
|
|
113
|
+
}
|
|
114
|
+
interface VitalsOptions {
|
|
115
|
+
enabled?: boolean;
|
|
116
|
+
/** 0..1 — fraction of sessions that report vitals. 1 = every session. */
|
|
117
|
+
sampleRate?: number;
|
|
118
|
+
/** Report tasks blocking the main thread longer than this (ms). */
|
|
119
|
+
longTaskMs?: number;
|
|
120
|
+
/** Report individual resources slower than this (ms). */
|
|
121
|
+
slowResourceMs?: number;
|
|
122
|
+
}
|
|
123
|
+
interface BugbanOptions {
|
|
124
|
+
/** Project API key. Without it the SDK is a silent no-op. */
|
|
125
|
+
apiKey?: string;
|
|
126
|
+
/** Bugban host, e.g. https://bugban.online */
|
|
127
|
+
host?: string;
|
|
128
|
+
/** Your app version — shown on the event and used for release grouping. */
|
|
129
|
+
release?: string;
|
|
130
|
+
environment?: string;
|
|
131
|
+
/** Framework name reported on the install ping (adapters set this). */
|
|
132
|
+
framework?: string;
|
|
133
|
+
frameworkVersion?: string;
|
|
134
|
+
/** Turn the whole SDK off without removing the code (e.g. in dev). */
|
|
135
|
+
enabled?: boolean;
|
|
136
|
+
debug?: boolean;
|
|
137
|
+
/** Max breadcrumbs kept in the ring buffer. */
|
|
138
|
+
maxBreadcrumbs?: number;
|
|
139
|
+
/** 0..1 — fraction of errors actually sent. */
|
|
140
|
+
sampleRate?: number;
|
|
141
|
+
console?: boolean | ConsoleOptions;
|
|
142
|
+
network?: boolean | NetworkOptions;
|
|
143
|
+
snapshot?: boolean | SnapshotOptions;
|
|
144
|
+
vitals?: boolean | VitalsOptions;
|
|
145
|
+
/** Capture window.onerror / unhandledrejection (browser) and the Node equivalents. */
|
|
146
|
+
globalHandlers?: boolean;
|
|
147
|
+
/** Record clicks and route changes as breadcrumbs. */
|
|
148
|
+
domBreadcrumbs?: boolean;
|
|
149
|
+
/** Send the one-time install ping so the panel shows "SDK connected". */
|
|
150
|
+
installPing?: boolean;
|
|
151
|
+
/** Extra request-header/body keys to redact, on top of the built-ins. */
|
|
152
|
+
redactKeys?: string[];
|
|
153
|
+
/** Drop an event (return null) or edit it before it is sent. */
|
|
154
|
+
beforeSend?: (event: BugbanEvent) => BugbanEvent | null;
|
|
155
|
+
/** Drop or edit a breadcrumb before it enters the buffer. */
|
|
156
|
+
beforeBreadcrumb?: (crumb: Breadcrumb) => Breadcrumb | null;
|
|
157
|
+
/** Errors whose message matches any of these are never sent. */
|
|
158
|
+
ignoreErrors?: Array<string | RegExp>;
|
|
159
|
+
}
|
|
160
|
+
/** Fully-resolved options — every optional field has a value. */
|
|
161
|
+
interface ResolvedOptions extends BugbanOptions {
|
|
162
|
+
apiKey: string;
|
|
163
|
+
host: string;
|
|
164
|
+
enabled: boolean;
|
|
165
|
+
debug: boolean;
|
|
166
|
+
maxBreadcrumbs: number;
|
|
167
|
+
sampleRate: number;
|
|
168
|
+
console: Required<ConsoleOptions> | false;
|
|
169
|
+
network: Required<NetworkOptions> | false;
|
|
170
|
+
snapshot: Required<SnapshotOptions> | false;
|
|
171
|
+
vitals: Required<VitalsOptions> | false;
|
|
172
|
+
globalHandlers: boolean;
|
|
173
|
+
domBreadcrumbs: boolean;
|
|
174
|
+
installPing: boolean;
|
|
175
|
+
redactKeys: string[];
|
|
176
|
+
ignoreErrors: Array<string | RegExp>;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* The SDK client.
|
|
181
|
+
*
|
|
182
|
+
* One rule governs every method here: nothing may throw into the host
|
|
183
|
+
* application, and nothing may block it. Every public entry point is wrapped,
|
|
184
|
+
* every optional browser API is feature-detected, and delivery is
|
|
185
|
+
* fire-and-forget. A monitoring tool that can take down the app it monitors is
|
|
186
|
+
* worse than no monitoring at all.
|
|
187
|
+
*/
|
|
188
|
+
declare class BugbanClient {
|
|
189
|
+
private opts;
|
|
190
|
+
private transport;
|
|
191
|
+
private crumbs;
|
|
192
|
+
private vitals?;
|
|
193
|
+
private teardown;
|
|
194
|
+
private user;
|
|
195
|
+
private context;
|
|
196
|
+
private sessionId;
|
|
197
|
+
private startedAt;
|
|
198
|
+
/** Events waiting to be sent, coalesced so an error storm is one request. */
|
|
199
|
+
private queue;
|
|
200
|
+
private flushTimer;
|
|
201
|
+
/** Guard against reporting an error that our own reporting caused. */
|
|
202
|
+
private sending;
|
|
203
|
+
private started;
|
|
204
|
+
constructor(options?: BugbanOptions);
|
|
205
|
+
get options(): ResolvedOptions;
|
|
206
|
+
/** Wire up integrations. Safe to call twice — the second call is ignored. */
|
|
207
|
+
start(): void;
|
|
208
|
+
private installIntegrations;
|
|
209
|
+
/**
|
|
210
|
+
* Send whatever is queued before the page goes away.
|
|
211
|
+
*
|
|
212
|
+
* Events are batched with a short debounce so an error loop becomes one
|
|
213
|
+
* request instead of hundreds. That debounce loses the last batch whenever
|
|
214
|
+
* the user navigates immediately after the error — which is the common
|
|
215
|
+
* case, not an edge case: click a link, something throws, the document is
|
|
216
|
+
* torn down before the timer fires. Observed exactly that while testing:
|
|
217
|
+
* an uncaught TypeError never arrived while the beacon-based vitals from the
|
|
218
|
+
* same page did.
|
|
219
|
+
*
|
|
220
|
+
* `visibilitychange` is the reliable signal (mobile Safari often skips
|
|
221
|
+
* `beforeunload`), and `pagehide` covers the bfcache case. Both drain with
|
|
222
|
+
* `beacon: true`, the only delivery a closing document is guaranteed to
|
|
223
|
+
* complete.
|
|
224
|
+
*/
|
|
225
|
+
private installUnloadFlush;
|
|
226
|
+
addBreadcrumb(crumb: Omit<Breadcrumb, 'timestamp'> & {
|
|
227
|
+
timestamp?: string;
|
|
228
|
+
}): void;
|
|
229
|
+
setUser(user: UserInfo | null): void;
|
|
230
|
+
setContext(key: string, value: unknown): void;
|
|
231
|
+
captureMessage(message: string, level?: Level): void;
|
|
232
|
+
/** Report an error. Never throws, never blocks. */
|
|
233
|
+
capture(error: unknown, extra?: {
|
|
234
|
+
handled?: boolean;
|
|
235
|
+
level?: Level;
|
|
236
|
+
type?: string;
|
|
237
|
+
context?: Record<string, unknown>;
|
|
238
|
+
request?: Record<string, unknown>;
|
|
239
|
+
}): void;
|
|
240
|
+
/** Flush anything queued. Await it before a process exits. */
|
|
241
|
+
flush(): Promise<void>;
|
|
242
|
+
/** Remove every hook the SDK installed. */
|
|
243
|
+
close(): void;
|
|
244
|
+
/** Adapters use this to report render timings alongside browser vitals. */
|
|
245
|
+
recordMetric(metric: VitalMetric): void;
|
|
246
|
+
private requestInfo;
|
|
247
|
+
private enqueue;
|
|
248
|
+
private drain;
|
|
249
|
+
private sendVitals;
|
|
250
|
+
private debug;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
declare function parseStack(stack: unknown, limit?: number): StackFrame[];
|
|
254
|
+
/**
|
|
255
|
+
* Normalise anything a JS app can throw into an error-shaped object.
|
|
256
|
+
* `throw 'a string'` and `Promise.reject({code: 500})` are both common; both
|
|
257
|
+
* must produce a usable event rather than "undefined".
|
|
258
|
+
*/
|
|
259
|
+
declare function normalizeError(input: unknown): {
|
|
260
|
+
name: string;
|
|
261
|
+
message: string;
|
|
262
|
+
stack?: string;
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Deep-redact an object by key name. Depth-limited so a pathological structure
|
|
267
|
+
* cannot lock up the main thread.
|
|
268
|
+
*/
|
|
269
|
+
declare function redact<T>(value: T, extraKeys?: string[], depth?: number): T;
|
|
270
|
+
/**
|
|
271
|
+
* Strip credentials out of a URL: query params named like secrets, plus any
|
|
272
|
+
* user:pass@ prefix. Returns the input unchanged if it cannot be parsed.
|
|
273
|
+
*/
|
|
274
|
+
declare function redactUrl(url: string, extraKeys?: string[]): string;
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Runtime detection and environment facts.
|
|
278
|
+
*
|
|
279
|
+
* Every lookup is defensive: this file runs in browsers, in Node, in edge
|
|
280
|
+
* runtimes, and during SSR where `window` exists but `document` does not.
|
|
281
|
+
* Nothing here may throw — a crash in environment detection would take down
|
|
282
|
+
* the host application on import, which is exactly the failure the PHP SDK
|
|
283
|
+
* learned to avoid the hard way.
|
|
284
|
+
*/
|
|
285
|
+
declare const SDK_NAME = "bugban-js";
|
|
286
|
+
declare const SDK_VERSION = "1.0.0";
|
|
287
|
+
/** 'browser' | 'node' | 'unknown' — reported on the install ping. */
|
|
288
|
+
declare function runtimeName(): string;
|
|
289
|
+
/**
|
|
290
|
+
* The runtime's own version: Node's `v22.13.1`, or the browser's UA string.
|
|
291
|
+
* The panel shows this next to the framework version, the same way it shows
|
|
292
|
+
* the PHP version for the PHP SDKs.
|
|
293
|
+
*/
|
|
294
|
+
declare function runtimeVersion(): string | undefined;
|
|
295
|
+
/**
|
|
296
|
+
* Read a dependency's version out of the host app's node_modules, so an
|
|
297
|
+
* adapter can report "react 19.0.0" without importing react itself.
|
|
298
|
+
*/
|
|
299
|
+
declare function dependencyVersion(pkg: string): Promise<string | undefined>;
|
|
300
|
+
|
|
301
|
+
declare function init(options?: BugbanOptions): BugbanClient;
|
|
302
|
+
/** The active client, or null when init() has not been called. */
|
|
303
|
+
declare function getClient(): BugbanClient | null;
|
|
304
|
+
/**
|
|
305
|
+
* Every helper below is a no-op before init(). That is deliberate: a component
|
|
306
|
+
* that calls captureError must not crash because the app forgot to configure
|
|
307
|
+
* monitoring, or because it is running in a test.
|
|
308
|
+
*/
|
|
309
|
+
declare function capture(error: unknown, extra?: {
|
|
310
|
+
handled?: boolean;
|
|
311
|
+
level?: Level;
|
|
312
|
+
type?: string;
|
|
313
|
+
context?: Record<string, unknown>;
|
|
314
|
+
}): void;
|
|
315
|
+
declare function captureMessage(message: string, level?: Level): void;
|
|
316
|
+
declare function setUser(user: UserInfo | null): void;
|
|
317
|
+
declare function setContext(key: string, value: unknown): void;
|
|
318
|
+
declare function addBreadcrumb(crumb: Omit<Breadcrumb, 'timestamp'> & {
|
|
319
|
+
timestamp?: string;
|
|
320
|
+
}): void;
|
|
321
|
+
declare function recordMetric(metric: VitalMetric): void;
|
|
322
|
+
declare function flush(): Promise<void>;
|
|
323
|
+
declare function close(): void;
|
|
324
|
+
/**
|
|
325
|
+
* Namespace form, so `Bugban.capture(e)` reads the same as the PHP facade.
|
|
326
|
+
*
|
|
327
|
+
* Deliberately NOT also a default export: mixing default and named exports
|
|
328
|
+
* makes the CommonJS build require `.default`, which is exactly the kind of
|
|
329
|
+
* "works in one install shape, breaks in another" trap that took a customer's
|
|
330
|
+
* site down on the PHP side. One import style, everywhere:
|
|
331
|
+
*
|
|
332
|
+
* import { Bugban } from '@bugban/js';
|
|
333
|
+
* const { Bugban } = require('@bugban/js');
|
|
334
|
+
*/
|
|
335
|
+
declare const Bugban: {
|
|
336
|
+
VERSION: string;
|
|
337
|
+
init: typeof init;
|
|
338
|
+
getClient: typeof getClient;
|
|
339
|
+
capture: typeof capture;
|
|
340
|
+
captureMessage: typeof captureMessage;
|
|
341
|
+
setUser: typeof setUser;
|
|
342
|
+
setContext: typeof setContext;
|
|
343
|
+
addBreadcrumb: typeof addBreadcrumb;
|
|
344
|
+
recordMetric: typeof recordMetric;
|
|
345
|
+
flush: typeof flush;
|
|
346
|
+
close: typeof close;
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
export { type Breadcrumb, type BreadcrumbType, Bugban, BugbanClient, type BugbanEvent, type BugbanOptions, type ConsoleOptions, type Level, type NetworkOptions, SDK_NAME, SDK_VERSION, type Snapshot, type SnapshotOptions, type StackFrame, type UserInfo, type VitalMetric, type VitalsOptions, addBreadcrumb, capture, captureMessage, close, dependencyVersion, flush, getClient, init, normalizeError, parseStack, recordMetric, redact, redactUrl, runtimeName, runtimeVersion, setContext, setUser };
|