@watchforge/browser 0.1.20 → 0.1.22
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/package.json +1 -1
- package/src/client.js +82 -0
- package/src/index.d.ts +8 -0
- package/src/replay.js +7 -1
package/package.json
CHANGED
package/src/client.js
CHANGED
|
@@ -97,6 +97,71 @@ function captureGlobalException(error, context = {}) {
|
|
|
97
97
|
void captureException(normalizeException(error, context.message), context);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
function normalizeStackFramePath(path) {
|
|
101
|
+
if (!path) return "";
|
|
102
|
+
try {
|
|
103
|
+
if (isBrowser) {
|
|
104
|
+
const url = new URL(String(path), window.location.href);
|
|
105
|
+
if (url.origin === window.location.origin) {
|
|
106
|
+
return url.pathname.replace(/^\/+/, "");
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
} catch {
|
|
110
|
+
// keep original path
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return String(path)
|
|
114
|
+
.replace(/^webpack-internal:\/\/\/?/, "")
|
|
115
|
+
.replace(/^webpack:\/\/(?:\([^)]*\)\/)?/, "")
|
|
116
|
+
.replace(/^webpack:\/\/[^/]+\//, "")
|
|
117
|
+
.replace(/^\([^)]*\)\//, "")
|
|
118
|
+
.replace(/^file:\/\//, "")
|
|
119
|
+
.split("?")[0]
|
|
120
|
+
.split("#")[0]
|
|
121
|
+
.replace(/\\/g, "/")
|
|
122
|
+
.replace(/^\/+/, "")
|
|
123
|
+
.replace(/^\.\//, "");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function isOriginalSourcePath(path) {
|
|
127
|
+
const normalized = normalizeStackFramePath(path);
|
|
128
|
+
return /(?:^|\/)src\/.+\.(?:tsx?|jsx?)$/.test(normalized);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function applyBrowserLocationOverride(stacktrace, location) {
|
|
132
|
+
if (!stacktrace?.frames?.length || !location?.filename || !location?.lineno) {
|
|
133
|
+
return stacktrace;
|
|
134
|
+
}
|
|
135
|
+
if (!isOriginalSourcePath(location.filename)) return stacktrace;
|
|
136
|
+
|
|
137
|
+
const normalizedLocation = normalizeStackFramePath(location.filename);
|
|
138
|
+
const matchingFrames = stacktrace.frames.filter((frame) => {
|
|
139
|
+
const framePath = normalizeStackFramePath(
|
|
140
|
+
frame.abs_path || frame.module || frame.raw_abs_path || frame.filename
|
|
141
|
+
);
|
|
142
|
+
return (
|
|
143
|
+
frame.in_app &&
|
|
144
|
+
(framePath === normalizedLocation ||
|
|
145
|
+
framePath.endsWith(`/${normalizedLocation}`) ||
|
|
146
|
+
normalizedLocation.endsWith(`/${framePath}`))
|
|
147
|
+
);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const target = matchingFrames[matchingFrames.length - 1] || stacktrace.frames.find((f) => f.in_app);
|
|
151
|
+
if (!target) return stacktrace;
|
|
152
|
+
|
|
153
|
+
target.abs_path = normalizedLocation;
|
|
154
|
+
target.raw_abs_path = location.filename;
|
|
155
|
+
target.module = normalizedLocation;
|
|
156
|
+
target.filename = normalizedLocation.split("/").pop() || target.filename;
|
|
157
|
+
target.lineno = Number(location.lineno);
|
|
158
|
+
if (location.colno != null) target.colno = Number(location.colno);
|
|
159
|
+
target.function = target.function || "<anonymous>";
|
|
160
|
+
target.browser_location_override = true;
|
|
161
|
+
|
|
162
|
+
return stacktrace;
|
|
163
|
+
}
|
|
164
|
+
|
|
100
165
|
function getElementDescriptor(element) {
|
|
101
166
|
if (!element || typeof element !== "object") return null;
|
|
102
167
|
const tag = element.tagName ? String(element.tagName).toLowerCase() : "unknown";
|
|
@@ -236,6 +301,11 @@ function setupBrowserInstrumentation() {
|
|
|
236
301
|
mechanism: "window.onerror",
|
|
237
302
|
},
|
|
238
303
|
extra: { url, line, col },
|
|
304
|
+
stackFrame: {
|
|
305
|
+
filename: url,
|
|
306
|
+
lineno: line,
|
|
307
|
+
colno: col,
|
|
308
|
+
},
|
|
239
309
|
message: String(msg),
|
|
240
310
|
});
|
|
241
311
|
};
|
|
@@ -591,6 +661,9 @@ export function register({
|
|
|
591
661
|
blockClass = "rr-block",
|
|
592
662
|
ignoreClass = "rr-ignore",
|
|
593
663
|
maskTextClass = "rr-mask",
|
|
664
|
+
inlineImages = true,
|
|
665
|
+
inlineStylesheet = true,
|
|
666
|
+
collectFonts = true,
|
|
594
667
|
captureConsoleErrors = true,
|
|
595
668
|
captureResourceErrors = true,
|
|
596
669
|
captureFailedRequests = true,
|
|
@@ -610,6 +683,9 @@ export function register({
|
|
|
610
683
|
blockClass,
|
|
611
684
|
ignoreClass,
|
|
612
685
|
maskTextClass,
|
|
686
|
+
inlineImages,
|
|
687
|
+
inlineStylesheet,
|
|
688
|
+
collectFonts,
|
|
613
689
|
captureConsoleErrors,
|
|
614
690
|
captureResourceErrors,
|
|
615
691
|
captureFailedRequests,
|
|
@@ -667,6 +743,9 @@ export function register({
|
|
|
667
743
|
blockClass,
|
|
668
744
|
ignoreClass,
|
|
669
745
|
maskTextClass,
|
|
746
|
+
inlineImages,
|
|
747
|
+
inlineStylesheet,
|
|
748
|
+
collectFonts,
|
|
670
749
|
debug,
|
|
671
750
|
});
|
|
672
751
|
}
|
|
@@ -742,6 +821,9 @@ export async function captureException(error, context = {}) {
|
|
|
742
821
|
if (!DSN) return;
|
|
743
822
|
|
|
744
823
|
let stacktrace = buildStacktraceFromError(error);
|
|
824
|
+
if (stacktrace && context.stackFrame) {
|
|
825
|
+
stacktrace = applyBrowserLocationOverride(stacktrace, context.stackFrame);
|
|
826
|
+
}
|
|
745
827
|
if (stacktrace) {
|
|
746
828
|
stacktrace = await enrichStacktraceAsync(
|
|
747
829
|
stacktrace,
|
package/src/index.d.ts
CHANGED
|
@@ -9,6 +9,9 @@ export interface WatchForgeRegisterOptions {
|
|
|
9
9
|
blockClass?: string;
|
|
10
10
|
ignoreClass?: string;
|
|
11
11
|
maskTextClass?: string;
|
|
12
|
+
inlineImages?: boolean;
|
|
13
|
+
inlineStylesheet?: boolean;
|
|
14
|
+
collectFonts?: boolean;
|
|
12
15
|
captureConsoleErrors?: boolean;
|
|
13
16
|
captureResourceErrors?: boolean;
|
|
14
17
|
captureFailedRequests?: boolean;
|
|
@@ -23,6 +26,11 @@ export interface WatchForgeCaptureContext {
|
|
|
23
26
|
tags?: Record<string, unknown>;
|
|
24
27
|
extra?: Record<string, unknown>;
|
|
25
28
|
contexts?: Record<string, unknown>;
|
|
29
|
+
stackFrame?: {
|
|
30
|
+
filename?: string;
|
|
31
|
+
lineno?: number;
|
|
32
|
+
colno?: number;
|
|
33
|
+
};
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
export function register(options: WatchForgeRegisterOptions): void;
|
package/src/replay.js
CHANGED
|
@@ -13,6 +13,9 @@ let options = {
|
|
|
13
13
|
blockClass: "rr-block",
|
|
14
14
|
ignoreClass: "rr-ignore",
|
|
15
15
|
maskTextClass: "rr-mask",
|
|
16
|
+
inlineImages: true,
|
|
17
|
+
inlineStylesheet: true,
|
|
18
|
+
collectFonts: true,
|
|
16
19
|
};
|
|
17
20
|
let stopRecording = null;
|
|
18
21
|
let events = [];
|
|
@@ -112,6 +115,9 @@ export async function initReplay(config = {}) {
|
|
|
112
115
|
tel: true,
|
|
113
116
|
text: Boolean(options.maskAllInputs),
|
|
114
117
|
},
|
|
118
|
+
inlineImages: options.inlineImages !== false,
|
|
119
|
+
inlineStylesheet: options.inlineStylesheet !== false,
|
|
120
|
+
collectFonts: options.collectFonts !== false,
|
|
115
121
|
});
|
|
116
122
|
} catch (error) {
|
|
117
123
|
if (options.debug) {
|
|
@@ -172,7 +178,7 @@ export function flushReplayForEvent(dsn, eventId) {
|
|
|
172
178
|
events,
|
|
173
179
|
sdk: {
|
|
174
180
|
name: "@watchforge/browser",
|
|
175
|
-
version: "0.1.
|
|
181
|
+
version: "0.1.22",
|
|
176
182
|
},
|
|
177
183
|
};
|
|
178
184
|
|