@diegotsi/flint-core 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +239 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +65 -1
- package/dist/index.d.ts +65 -1
- package/dist/index.js +238 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -75,6 +75,32 @@ interface FormErrorEntry {
|
|
|
75
75
|
url: string;
|
|
76
76
|
timestamp: number;
|
|
77
77
|
}
|
|
78
|
+
interface ErrorBreadcrumbs {
|
|
79
|
+
consoleLogs: ConsoleEntry[];
|
|
80
|
+
networkErrors: NetworkEntry[];
|
|
81
|
+
}
|
|
82
|
+
interface ErrorEventPayload {
|
|
83
|
+
type: "error" | "unhandledrejection";
|
|
84
|
+
message: string;
|
|
85
|
+
errorClass: string;
|
|
86
|
+
stack?: string;
|
|
87
|
+
/** Page URL where the error occurred */
|
|
88
|
+
url: string;
|
|
89
|
+
/** Client time — orders breadcrumbs only; the server buckets by receive time */
|
|
90
|
+
timestamp: number;
|
|
91
|
+
release?: string;
|
|
92
|
+
appVersion?: string;
|
|
93
|
+
userId?: string;
|
|
94
|
+
/** Anonymous per-page-load session hash when no user is set */
|
|
95
|
+
sessionId?: string;
|
|
96
|
+
browser?: string;
|
|
97
|
+
os?: string;
|
|
98
|
+
/** In-batch dedup count — identical errors merged client-side before flush */
|
|
99
|
+
count: number;
|
|
100
|
+
breadcrumbs?: ErrorBreadcrumbs;
|
|
101
|
+
/** @internal client-side throttle/dedup key — stripped before sending */
|
|
102
|
+
_localKey?: string;
|
|
103
|
+
}
|
|
78
104
|
type Locale = "pt-BR" | "en-US";
|
|
79
105
|
type Theme = "light" | "dark" | ThemeOverride;
|
|
80
106
|
interface ThemeOverride {
|
|
@@ -128,6 +154,16 @@ interface FlintConfig {
|
|
|
128
154
|
enableDeadClicks?: boolean;
|
|
129
155
|
};
|
|
130
156
|
onFrustration?: (event: FrustrationEvent) => void;
|
|
157
|
+
/** Capture uncaught errors & unhandled rejections automatically. Default: true */
|
|
158
|
+
enableErrorMonitoring?: boolean;
|
|
159
|
+
errorMonitoring?: {
|
|
160
|
+
/** Fraction of captured errors to report, 0..1. Default: 1.0 */
|
|
161
|
+
sampleRate?: number;
|
|
162
|
+
/** Errors whose message matches any entry are dropped (string = substring match) */
|
|
163
|
+
ignoreErrors?: (string | RegExp)[];
|
|
164
|
+
/** Mutate or drop (return null) an event before it is sent */
|
|
165
|
+
beforeSend?: (event: ErrorEventPayload) => ErrorEventPayload | null;
|
|
166
|
+
};
|
|
131
167
|
/** Application version string, e.g. "2.1.0" */
|
|
132
168
|
appVersion?: string;
|
|
133
169
|
/** Release/deploy identifier, e.g. "v2.1.0-rc1" or a commit SHA */
|
|
@@ -185,6 +221,33 @@ declare function submitReplay(serverUrl: string, projectKey: string, reportId: s
|
|
|
185
221
|
|
|
186
222
|
declare function collectEnvironment(): EnvironmentInfo;
|
|
187
223
|
|
|
224
|
+
interface ErrorCaptureCollector {
|
|
225
|
+
start(): void;
|
|
226
|
+
stop(): void;
|
|
227
|
+
/** Flush pending events immediately (also called on pagehide/interval). */
|
|
228
|
+
flush(): void;
|
|
229
|
+
}
|
|
230
|
+
interface ErrorCaptureOptions {
|
|
231
|
+
serverUrl: string;
|
|
232
|
+
projectKey: string;
|
|
233
|
+
release?: string;
|
|
234
|
+
appVersion?: string;
|
|
235
|
+
/** Fraction of captured errors to report, 0..1. Default 1.0 */
|
|
236
|
+
sampleRate?: number;
|
|
237
|
+
/** Errors whose message matches any entry are dropped (string = substring match) */
|
|
238
|
+
ignoreErrors?: (string | RegExp)[];
|
|
239
|
+
/** Mutate or drop (return null) an event before it is queued for sending */
|
|
240
|
+
beforeSend?: (event: ErrorEventPayload) => ErrorEventPayload | null;
|
|
241
|
+
getUser?: () => FlintUser | undefined;
|
|
242
|
+
getBreadcrumbs?: () => {
|
|
243
|
+
consoleLogs: ConsoleEntry[];
|
|
244
|
+
networkErrors: NetworkEntry[];
|
|
245
|
+
};
|
|
246
|
+
getEnvironment?: () => EnvironmentInfo;
|
|
247
|
+
debug?: boolean;
|
|
248
|
+
}
|
|
249
|
+
declare function createErrorCaptureCollector(options: ErrorCaptureOptions): ErrorCaptureCollector;
|
|
250
|
+
|
|
188
251
|
interface FormErrorCollector {
|
|
189
252
|
start(): void;
|
|
190
253
|
stop(): void;
|
|
@@ -233,6 +296,7 @@ interface FlintInstance {
|
|
|
233
296
|
network: NetworkCollector | null;
|
|
234
297
|
formErrors: FormErrorCollector | null;
|
|
235
298
|
frustration: FrustrationCollector | null;
|
|
299
|
+
errorCapture: ErrorCaptureCollector | null;
|
|
236
300
|
replayEvents: unknown[];
|
|
237
301
|
stopReplay: (() => void) | null;
|
|
238
302
|
}
|
|
@@ -282,4 +346,4 @@ interface ResolvedTheme {
|
|
|
282
346
|
}
|
|
283
347
|
declare function resolveTheme(theme: Theme): ResolvedTheme;
|
|
284
348
|
|
|
285
|
-
export { type CollectedMeta, type ConsoleCollector, type ConsoleEntry, DATADOG_BLOCKED_HOSTS, type EnvironmentInfo, Flint, type FlintConfig, type FlintState, type FlintUser, type FlintWidgetProps, type FormErrorCollector, type FormErrorEntry, type FrustrationCollector, type FrustrationEvent, type Locale, type NetworkCollector, type NetworkEntry, type ReportPayload, type ReportResult, type ResolvedTheme, type Severity, type Theme, type ThemeOverride, _setFormErrorCollector, collectEnvironment, createConsoleCollector, createDatadogReplayProvider, createFormErrorCollector, createFrustrationCollector, createNetworkCollector, getSnapshot, resolveTheme, submitReplay, submitReport, subscribe };
|
|
349
|
+
export { type CollectedMeta, type ConsoleCollector, type ConsoleEntry, DATADOG_BLOCKED_HOSTS, type EnvironmentInfo, type ErrorBreadcrumbs, type ErrorCaptureCollector, type ErrorCaptureOptions, type ErrorEventPayload, Flint, type FlintConfig, type FlintState, type FlintUser, type FlintWidgetProps, type FormErrorCollector, type FormErrorEntry, type FrustrationCollector, type FrustrationEvent, type Locale, type NetworkCollector, type NetworkEntry, type ReportPayload, type ReportResult, type ResolvedTheme, type Severity, type Theme, type ThemeOverride, _setFormErrorCollector, collectEnvironment, createConsoleCollector, createDatadogReplayProvider, createErrorCaptureCollector, createFormErrorCollector, createFrustrationCollector, createNetworkCollector, getSnapshot, resolveTheme, submitReplay, submitReport, subscribe };
|
package/dist/index.js
CHANGED
|
@@ -69,8 +69,7 @@ async function submitReplay(serverUrl, projectKey, reportId, events) {
|
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
// src/
|
|
73
|
-
var MAX_ENTRIES = 50;
|
|
72
|
+
// src/sanitize.ts
|
|
74
73
|
var SENSITIVE_PATTERNS = [
|
|
75
74
|
/(?:password|passwd|pwd|secret|token|api[_-]?key|access[_-]?key|authorization|bearer)\s*[:=]\s*["']?[^\s"',]{4,}/gi,
|
|
76
75
|
/\b(sk-[a-zA-Z0-9_-]{20,})\b/g,
|
|
@@ -89,6 +88,9 @@ function sanitize(str) {
|
|
|
89
88
|
}
|
|
90
89
|
return result;
|
|
91
90
|
}
|
|
91
|
+
|
|
92
|
+
// src/collectors/console.ts
|
|
93
|
+
var MAX_ENTRIES = 50;
|
|
92
94
|
function createConsoleCollector() {
|
|
93
95
|
const entries = [];
|
|
94
96
|
let active = false;
|
|
@@ -208,6 +210,216 @@ function collectEnvironment() {
|
|
|
208
210
|
};
|
|
209
211
|
}
|
|
210
212
|
|
|
213
|
+
// src/collectors/errorCapture.ts
|
|
214
|
+
var MAX_MESSAGE = 1e3;
|
|
215
|
+
var MAX_STACK = 8e3;
|
|
216
|
+
var MAX_BATCH = 20;
|
|
217
|
+
var MAX_PAYLOAD_BYTES = 6e4;
|
|
218
|
+
var PER_KEY_PER_MINUTE = 10;
|
|
219
|
+
var GLOBAL_PAGE_CAP = 100;
|
|
220
|
+
var FLUSH_INTERVAL_MS = 5e3;
|
|
221
|
+
var THROTTLE_WINDOW_MS = 6e4;
|
|
222
|
+
var BREADCRUMB_CONSOLE = 10;
|
|
223
|
+
var BREADCRUMB_NETWORK = 10;
|
|
224
|
+
var DEFAULT_IGNORE = [/ResizeObserver loop/i, /^Script error\.?$/];
|
|
225
|
+
var EXTENSION_URL = /(chrome|moz|safari|safari-web)-extension:\/\//;
|
|
226
|
+
function normalizeForKey(message) {
|
|
227
|
+
return message.toLowerCase().replace(/\d+/g, "#").replace(/\s+/g, " ").trim().slice(0, 200);
|
|
228
|
+
}
|
|
229
|
+
function topFrame(stack) {
|
|
230
|
+
if (!stack) return "";
|
|
231
|
+
const lines = stack.split("\n").map((l) => l.trim());
|
|
232
|
+
return lines.find((l) => l.startsWith("at ") || /@/.test(l)) ?? "";
|
|
233
|
+
}
|
|
234
|
+
function createErrorCaptureCollector(options) {
|
|
235
|
+
const sampleRate = options.sampleRate ?? 1;
|
|
236
|
+
const ignoreList = [...DEFAULT_IGNORE, ...options.ignoreErrors ?? []];
|
|
237
|
+
const sessionId = `s_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
|
|
238
|
+
let active = false;
|
|
239
|
+
let queue = [];
|
|
240
|
+
let interval = null;
|
|
241
|
+
let sentCount = 0;
|
|
242
|
+
let environment;
|
|
243
|
+
const keyTimestamps = /* @__PURE__ */ new Map();
|
|
244
|
+
function debugLog2(...args) {
|
|
245
|
+
if (options.debug) console.log("[Flint]", ...args);
|
|
246
|
+
}
|
|
247
|
+
function isIgnored(message, stack, frameUrl) {
|
|
248
|
+
for (const entry of ignoreList) {
|
|
249
|
+
if (typeof entry === "string") {
|
|
250
|
+
if (message.includes(entry)) return true;
|
|
251
|
+
} else if (entry.test(message)) {
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (EXTENSION_URL.test(frameUrl ?? "") || EXTENSION_URL.test(stack ?? "")) return true;
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
function isThrottled(localKey) {
|
|
259
|
+
const now = Date.now();
|
|
260
|
+
const stamps = (keyTimestamps.get(localKey) ?? []).filter((t) => now - t < THROTTLE_WINDOW_MS);
|
|
261
|
+
if (stamps.length >= PER_KEY_PER_MINUTE) {
|
|
262
|
+
keyTimestamps.set(localKey, stamps);
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
stamps.push(now);
|
|
266
|
+
keyTimestamps.set(localKey, stamps);
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
function capture(input) {
|
|
270
|
+
try {
|
|
271
|
+
if (sentCount + queue.length >= GLOBAL_PAGE_CAP) return;
|
|
272
|
+
let message = input.message.slice(0, MAX_MESSAGE);
|
|
273
|
+
if (isIgnored(message, input.stack, input.frameUrl)) return;
|
|
274
|
+
if (sampleRate < 1 && Math.random() >= sampleRate) return;
|
|
275
|
+
const localKey = `${input.type}|${normalizeForKey(message)}|${topFrame(input.stack)}`;
|
|
276
|
+
if (isThrottled(localKey)) return;
|
|
277
|
+
const pending = queue.find((e) => e._localKey === localKey);
|
|
278
|
+
if (pending) {
|
|
279
|
+
pending.count += 1;
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
message = sanitize(message);
|
|
283
|
+
const stack = input.stack ? sanitize(input.stack.slice(0, MAX_STACK)) : void 0;
|
|
284
|
+
if (!environment && options.getEnvironment) {
|
|
285
|
+
try {
|
|
286
|
+
environment = options.getEnvironment();
|
|
287
|
+
} catch {
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
const user = options.getUser?.();
|
|
291
|
+
let event = {
|
|
292
|
+
type: input.type,
|
|
293
|
+
message,
|
|
294
|
+
errorClass: input.errorClass,
|
|
295
|
+
stack,
|
|
296
|
+
url: typeof location !== "undefined" ? location.href : "",
|
|
297
|
+
timestamp: Date.now(),
|
|
298
|
+
release: options.release,
|
|
299
|
+
appVersion: options.appVersion,
|
|
300
|
+
userId: user?.id,
|
|
301
|
+
sessionId,
|
|
302
|
+
browser: environment?.browser,
|
|
303
|
+
os: environment?.os,
|
|
304
|
+
count: 1,
|
|
305
|
+
breadcrumbs: options.getBreadcrumbs ? {
|
|
306
|
+
consoleLogs: options.getBreadcrumbs().consoleLogs.slice(-BREADCRUMB_CONSOLE),
|
|
307
|
+
networkErrors: options.getBreadcrumbs().networkErrors.slice(-BREADCRUMB_NETWORK)
|
|
308
|
+
} : void 0,
|
|
309
|
+
_localKey: localKey
|
|
310
|
+
};
|
|
311
|
+
if (options.beforeSend) {
|
|
312
|
+
try {
|
|
313
|
+
const result = options.beforeSend(event);
|
|
314
|
+
if (!result) return;
|
|
315
|
+
event = { ...result, _localKey: localKey };
|
|
316
|
+
} catch {
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
queue.push(event);
|
|
320
|
+
debugLog2("Error captured", input.errorClass, message);
|
|
321
|
+
if (queue.length >= MAX_BATCH) flush(false);
|
|
322
|
+
} catch {
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
function serialize(events) {
|
|
326
|
+
const wire = events.map(({ _localKey, ...e }) => e);
|
|
327
|
+
let body = JSON.stringify(wire);
|
|
328
|
+
if (body.length > MAX_PAYLOAD_BYTES) {
|
|
329
|
+
body = JSON.stringify(wire.map((e) => ({ ...e, breadcrumbs: void 0 })));
|
|
330
|
+
if (body.length > MAX_PAYLOAD_BYTES) {
|
|
331
|
+
body = JSON.stringify(wire.map((e) => ({ ...e, breadcrumbs: void 0, stack: e.stack?.slice(0, 2e3) })));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return body;
|
|
335
|
+
}
|
|
336
|
+
function flush(unloading) {
|
|
337
|
+
if (queue.length === 0) return;
|
|
338
|
+
const events = queue;
|
|
339
|
+
queue = [];
|
|
340
|
+
sentCount += events.length;
|
|
341
|
+
const base = options.serverUrl.replace(/\/$/, "");
|
|
342
|
+
const url = `${base}/api/v1/error-events?project_key=${encodeURIComponent(options.projectKey)}`;
|
|
343
|
+
const body = serialize(events);
|
|
344
|
+
if (unloading && typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function") {
|
|
345
|
+
const ok = navigator.sendBeacon(url, body);
|
|
346
|
+
debugLog2("Flushed via beacon", events.length, ok);
|
|
347
|
+
if (ok) return;
|
|
348
|
+
}
|
|
349
|
+
fetch(url, {
|
|
350
|
+
method: "POST",
|
|
351
|
+
headers: { "Content-Type": "text/plain;charset=UTF-8" },
|
|
352
|
+
body,
|
|
353
|
+
keepalive: unloading
|
|
354
|
+
}).catch(() => {
|
|
355
|
+
});
|
|
356
|
+
debugLog2("Flushed via fetch", events.length);
|
|
357
|
+
}
|
|
358
|
+
function onError(event) {
|
|
359
|
+
const e = event;
|
|
360
|
+
if (typeof e.message !== "string" && !(e.error instanceof Error)) return;
|
|
361
|
+
const err = e.error instanceof Error ? e.error : void 0;
|
|
362
|
+
capture({
|
|
363
|
+
type: "error",
|
|
364
|
+
message: err?.message ?? (e.message || "Unknown error"),
|
|
365
|
+
errorClass: err?.name ?? "Error",
|
|
366
|
+
stack: err?.stack,
|
|
367
|
+
frameUrl: e.filename
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
function onRejection(event) {
|
|
371
|
+
const reason = event.reason;
|
|
372
|
+
const err = reason instanceof Error ? reason : void 0;
|
|
373
|
+
let message;
|
|
374
|
+
if (err) {
|
|
375
|
+
message = err.message;
|
|
376
|
+
} else {
|
|
377
|
+
try {
|
|
378
|
+
message = typeof reason === "string" ? reason : JSON.stringify(reason);
|
|
379
|
+
} catch {
|
|
380
|
+
message = String(reason);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
capture({
|
|
384
|
+
type: "unhandledrejection",
|
|
385
|
+
message: message || "Unhandled promise rejection",
|
|
386
|
+
errorClass: err?.name ?? "UnhandledRejection",
|
|
387
|
+
stack: err?.stack
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
function onPageHide() {
|
|
391
|
+
flush(true);
|
|
392
|
+
}
|
|
393
|
+
function onVisibilityChange() {
|
|
394
|
+
if (document.visibilityState === "hidden") flush(true);
|
|
395
|
+
}
|
|
396
|
+
return {
|
|
397
|
+
start() {
|
|
398
|
+
if (active) return;
|
|
399
|
+
active = true;
|
|
400
|
+
window.addEventListener("error", onError, { capture: true });
|
|
401
|
+
window.addEventListener("unhandledrejection", onRejection, { capture: true });
|
|
402
|
+
window.addEventListener("pagehide", onPageHide);
|
|
403
|
+
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
404
|
+
interval = setInterval(() => flush(false), FLUSH_INTERVAL_MS);
|
|
405
|
+
},
|
|
406
|
+
stop() {
|
|
407
|
+
if (!active) return;
|
|
408
|
+
active = false;
|
|
409
|
+
window.removeEventListener("error", onError, { capture: true });
|
|
410
|
+
window.removeEventListener("unhandledrejection", onRejection, { capture: true });
|
|
411
|
+
window.removeEventListener("pagehide", onPageHide);
|
|
412
|
+
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
413
|
+
if (interval) clearInterval(interval);
|
|
414
|
+
interval = null;
|
|
415
|
+
flush(false);
|
|
416
|
+
},
|
|
417
|
+
flush() {
|
|
418
|
+
flush(false);
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
|
|
211
423
|
// src/collectors/formErrors.ts
|
|
212
424
|
var MAX_ENTRIES2 = 30;
|
|
213
425
|
var POST_SUBMIT_CHECK_MS = 300;
|
|
@@ -902,6 +1114,8 @@ function init(config) {
|
|
|
902
1114
|
enableFormErrors = true,
|
|
903
1115
|
enableFrustration = false,
|
|
904
1116
|
autoReportFrustration = false,
|
|
1117
|
+
enableErrorMonitoring = true,
|
|
1118
|
+
errorMonitoring: errorMonitoringOpts,
|
|
905
1119
|
enableReplay = false,
|
|
906
1120
|
replayBufferMs = DEFAULT_REPLAY_BUFFER_MS,
|
|
907
1121
|
blockedHosts = [],
|
|
@@ -937,6 +1151,23 @@ function init(config) {
|
|
|
937
1151
|
}
|
|
938
1152
|
const frustrationCol = enableFrustration ? createFrustrationCollector(frustrationOpts) : null;
|
|
939
1153
|
frustrationCol?.start();
|
|
1154
|
+
const errorCaptureCol = enableErrorMonitoring ? createErrorCaptureCollector({
|
|
1155
|
+
serverUrl: config.serverUrl,
|
|
1156
|
+
projectKey: config.projectKey,
|
|
1157
|
+
release: config.release,
|
|
1158
|
+
appVersion: config.appVersion,
|
|
1159
|
+
debug: config.debug,
|
|
1160
|
+
sampleRate: errorMonitoringOpts?.sampleRate,
|
|
1161
|
+
ignoreErrors: errorMonitoringOpts?.ignoreErrors,
|
|
1162
|
+
beforeSend: errorMonitoringOpts?.beforeSend,
|
|
1163
|
+
getUser: () => getSnapshot().user ?? config.user,
|
|
1164
|
+
getBreadcrumbs: () => ({
|
|
1165
|
+
consoleLogs: consoleCol?.getEntries() ?? [],
|
|
1166
|
+
networkErrors: networkCol?.getEntries() ?? []
|
|
1167
|
+
}),
|
|
1168
|
+
getEnvironment: _collectors?.environment ?? collectEnvironment
|
|
1169
|
+
}) : null;
|
|
1170
|
+
errorCaptureCol?.start();
|
|
940
1171
|
if (config.user) {
|
|
941
1172
|
flint.setUser(config.user);
|
|
942
1173
|
}
|
|
@@ -946,7 +1177,8 @@ function init(config) {
|
|
|
946
1177
|
console: !!consoleCol,
|
|
947
1178
|
network: !!networkCol,
|
|
948
1179
|
formErrors: !!formErrorsCol,
|
|
949
|
-
frustration: !!frustrationCol
|
|
1180
|
+
frustration: !!frustrationCol,
|
|
1181
|
+
errorCapture: !!errorCaptureCol
|
|
950
1182
|
});
|
|
951
1183
|
instance = {
|
|
952
1184
|
config,
|
|
@@ -954,6 +1186,7 @@ function init(config) {
|
|
|
954
1186
|
network: networkCol,
|
|
955
1187
|
formErrors: formErrorsCol,
|
|
956
1188
|
frustration: frustrationCol,
|
|
1189
|
+
errorCapture: errorCaptureCol,
|
|
957
1190
|
replayEvents,
|
|
958
1191
|
stopReplay: null
|
|
959
1192
|
};
|
|
@@ -1034,6 +1267,7 @@ function shutdown() {
|
|
|
1034
1267
|
instance.formErrors?.stop();
|
|
1035
1268
|
_setFormErrorCollector(null);
|
|
1036
1269
|
instance.frustration?.stop();
|
|
1270
|
+
instance.errorCapture?.stop();
|
|
1037
1271
|
instance.stopReplay?.();
|
|
1038
1272
|
instance = null;
|
|
1039
1273
|
}
|
|
@@ -1124,6 +1358,7 @@ export {
|
|
|
1124
1358
|
collectEnvironment,
|
|
1125
1359
|
createConsoleCollector,
|
|
1126
1360
|
createDatadogReplayProvider,
|
|
1361
|
+
createErrorCaptureCollector,
|
|
1127
1362
|
createFormErrorCollector,
|
|
1128
1363
|
createFrustrationCollector,
|
|
1129
1364
|
createNetworkCollector,
|