@orbitai/orbitrace 1.2.1 → 1.4.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 +55 -5
- package/bin/orbitrace-sourcemaps.js +191 -0
- package/dist/browser.cjs +520 -0
- package/dist/browser.mjs +525 -0
- package/dist/index.js +480 -503
- package/package.json +21 -5
- package/dist/index.mjs +0 -131
package/dist/browser.mjs
ADDED
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
|
+
var __typeError = (msg) => {
|
|
3
|
+
throw TypeError(msg);
|
|
4
|
+
};
|
|
5
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
6
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
7
|
+
};
|
|
8
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
9
|
+
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
10
|
+
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
11
|
+
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
12
|
+
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
13
|
+
|
|
14
|
+
// src/shared.js
|
|
15
|
+
var require_shared = __commonJS({
|
|
16
|
+
"src/shared.js"(exports, module) {
|
|
17
|
+
var REQUEST_TIMEOUT_MS = 5e3;
|
|
18
|
+
var DEDUPE_WINDOW_MS = 1e4;
|
|
19
|
+
var MAX_IN_FLIGHT = 10;
|
|
20
|
+
var DEFAULT_RETRY_AFTER_SECONDS = 60;
|
|
21
|
+
var MAX_BREADCRUMBS = 30;
|
|
22
|
+
var MAX_BREADCRUMB_MESSAGE_LENGTH = 200;
|
|
23
|
+
var BREADCRUMB_LEVELS = ["debug", "info", "warning", "error"];
|
|
24
|
+
var CONSOLE_LEVELS = { debug: "debug", log: "info", info: "info", warn: "warning", error: "error" };
|
|
25
|
+
var SENSITIVE_KEY_PARTS = [
|
|
26
|
+
"password",
|
|
27
|
+
"passwd",
|
|
28
|
+
"secret",
|
|
29
|
+
"token",
|
|
30
|
+
"authorization",
|
|
31
|
+
"cookie",
|
|
32
|
+
"apikey",
|
|
33
|
+
"privatekey",
|
|
34
|
+
"credential",
|
|
35
|
+
"session"
|
|
36
|
+
];
|
|
37
|
+
var FILTERED_VALUE = "[Filtered]";
|
|
38
|
+
function isSensitiveKey(key) {
|
|
39
|
+
const normalized = key.toLowerCase().replace(/[-_]/g, "");
|
|
40
|
+
return SENSITIVE_KEY_PARTS.some((part) => normalized.includes(part));
|
|
41
|
+
}
|
|
42
|
+
function filterSensitive(value, ancestors = /* @__PURE__ */ new WeakSet()) {
|
|
43
|
+
if (value === null || typeof value !== "object") {
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
if (ancestors.has(value)) {
|
|
47
|
+
return "[Circular]";
|
|
48
|
+
}
|
|
49
|
+
const isArray = Array.isArray(value);
|
|
50
|
+
const prototype = Object.getPrototypeOf(value);
|
|
51
|
+
if (!isArray && prototype !== Object.prototype && prototype !== null) {
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
ancestors.add(value);
|
|
55
|
+
const filtered = isArray ? value.map((item) => filterSensitive(item, ancestors)) : Object.fromEntries(
|
|
56
|
+
Object.entries(value).map(([key, item]) => [
|
|
57
|
+
key,
|
|
58
|
+
isSensitiveKey(key) ? FILTERED_VALUE : filterSensitive(item, ancestors)
|
|
59
|
+
])
|
|
60
|
+
);
|
|
61
|
+
ancestors.delete(value);
|
|
62
|
+
return filtered;
|
|
63
|
+
}
|
|
64
|
+
function truncate(value, maxLength) {
|
|
65
|
+
return value.length > maxLength ? `${value.slice(0, maxLength)}...` : value;
|
|
66
|
+
}
|
|
67
|
+
function cleanUrl(url) {
|
|
68
|
+
try {
|
|
69
|
+
const parsed = new URL(url);
|
|
70
|
+
return `${parsed.origin}${parsed.pathname}`;
|
|
71
|
+
} catch {
|
|
72
|
+
return String(url).split(/[?#]/)[0];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function pushBreadcrumb(breadcrumbs, { category = "manual", message = "", level = "info", data } = {}) {
|
|
76
|
+
try {
|
|
77
|
+
breadcrumbs.push({
|
|
78
|
+
timestamp: Date.now(),
|
|
79
|
+
category: String(category).slice(0, 64),
|
|
80
|
+
level: BREADCRUMB_LEVELS.includes(level) ? level : "info",
|
|
81
|
+
message: truncate(String(message), MAX_BREADCRUMB_MESSAGE_LENGTH),
|
|
82
|
+
...data !== void 0 && { data: filterSensitive(data) }
|
|
83
|
+
});
|
|
84
|
+
if (breadcrumbs.length > MAX_BREADCRUMBS) {
|
|
85
|
+
breadcrumbs.shift();
|
|
86
|
+
}
|
|
87
|
+
} catch {
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function httpBreadcrumb({ method, url, status, error, started }) {
|
|
91
|
+
const data = { method, url: cleanUrl(url), durationMs: Date.now() - started };
|
|
92
|
+
if (error) {
|
|
93
|
+
return { category: "http", level: "error", message: `${method} ${data.url} failed`, data: { ...data, error } };
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
category: "http",
|
|
97
|
+
level: status >= 500 ? "error" : status >= 400 ? "warning" : "info",
|
|
98
|
+
message: `${method} ${data.url} ${status}`,
|
|
99
|
+
data: { ...data, status }
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function recordFetch({ endpoint, addBreadcrumb, restore }) {
|
|
103
|
+
if (typeof globalThis.fetch !== "function") {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
const originalFetch = globalThis.fetch;
|
|
107
|
+
globalThis.fetch = async function orbitraceFetch(input, init) {
|
|
108
|
+
const url = typeof input === "string" || input instanceof URL ? String(input) : input?.url;
|
|
109
|
+
if (!url || url.startsWith(endpoint)) {
|
|
110
|
+
return originalFetch.call(this, input, init);
|
|
111
|
+
}
|
|
112
|
+
const method = String(init?.method || input?.method || "GET").toUpperCase();
|
|
113
|
+
const started = Date.now();
|
|
114
|
+
try {
|
|
115
|
+
const response = await originalFetch.call(this, input, init);
|
|
116
|
+
addBreadcrumb(httpBreadcrumb({ method, url, status: response.status, started }));
|
|
117
|
+
return response;
|
|
118
|
+
} catch (error) {
|
|
119
|
+
addBreadcrumb(httpBreadcrumb({ method, url, error: error?.message, started }));
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
restore.push(() => {
|
|
124
|
+
globalThis.fetch = originalFetch;
|
|
125
|
+
});
|
|
126
|
+
return originalFetch;
|
|
127
|
+
}
|
|
128
|
+
function recordConsole({ format, addBreadcrumb, restore }) {
|
|
129
|
+
let recording = false;
|
|
130
|
+
for (const [method, level] of Object.entries(CONSOLE_LEVELS)) {
|
|
131
|
+
const original = console[method];
|
|
132
|
+
if (typeof original !== "function") {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
console[method] = function orbitraceConsole(...args) {
|
|
136
|
+
if (!recording) {
|
|
137
|
+
recording = true;
|
|
138
|
+
try {
|
|
139
|
+
const message = format(args);
|
|
140
|
+
if (!message.startsWith("Orbitrace:")) {
|
|
141
|
+
addBreadcrumb({ category: "console", level, message });
|
|
142
|
+
}
|
|
143
|
+
} catch {
|
|
144
|
+
} finally {
|
|
145
|
+
recording = false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return original.apply(this, args);
|
|
149
|
+
};
|
|
150
|
+
restore.push(() => {
|
|
151
|
+
console[method] = original;
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
var _endpoint, _headers, _getFetch, _requestOptions, _pending, _inFlight, _pausedUntil, _Sender_instances, flushPending_fn, canSend_fn, send_fn, post_fn;
|
|
156
|
+
var Sender = class {
|
|
157
|
+
// `getFetch` returns the fetch to use at send time, so a wrapped global fetch is never recorded.
|
|
158
|
+
// `requestOptions(body)` adds fetch options for one request, such as keepalive in browsers.
|
|
159
|
+
constructor({ endpoint, headers, getFetch = () => globalThis.fetch, requestOptions = () => ({}) }) {
|
|
160
|
+
__privateAdd(this, _Sender_instances);
|
|
161
|
+
__privateAdd(this, _endpoint);
|
|
162
|
+
__privateAdd(this, _headers);
|
|
163
|
+
__privateAdd(this, _getFetch);
|
|
164
|
+
__privateAdd(this, _requestOptions);
|
|
165
|
+
__privateAdd(this, _pending, /* @__PURE__ */ new Map());
|
|
166
|
+
__privateAdd(this, _inFlight, /* @__PURE__ */ new Set());
|
|
167
|
+
__privateAdd(this, _pausedUntil, 0);
|
|
168
|
+
__privateSet(this, _endpoint, endpoint);
|
|
169
|
+
__privateSet(this, _headers, headers);
|
|
170
|
+
__privateSet(this, _getFetch, getFetch);
|
|
171
|
+
__privateSet(this, _requestOptions, requestOptions);
|
|
172
|
+
}
|
|
173
|
+
// Queues the event and returns at once; it is sent in the background. flush() waits for delivery.
|
|
174
|
+
capture(event, payload) {
|
|
175
|
+
const key = JSON.stringify([event, payload.message, payload.stack ?? null]);
|
|
176
|
+
const pending = __privateGet(this, _pending).get(key);
|
|
177
|
+
if (pending) {
|
|
178
|
+
pending.count++;
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (!__privateMethod(this, _Sender_instances, canSend_fn).call(this)) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const entry = { event, payload, count: 0 };
|
|
185
|
+
entry.timer = setTimeout(() => __privateMethod(this, _Sender_instances, flushPending_fn).call(this, key), DEDUPE_WINDOW_MS);
|
|
186
|
+
entry.timer.unref?.();
|
|
187
|
+
__privateGet(this, _pending).set(key, entry);
|
|
188
|
+
__privateMethod(this, _Sender_instances, send_fn).call(this, event, payload, 1);
|
|
189
|
+
}
|
|
190
|
+
// Sends counts still held by the dedupe window and waits for in-flight requests.
|
|
191
|
+
async flush() {
|
|
192
|
+
await Promise.all([...__privateGet(this, _pending).keys()].map((key) => __privateMethod(this, _Sender_instances, flushPending_fn).call(this, key)));
|
|
193
|
+
await Promise.all(__privateGet(this, _inFlight));
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
_endpoint = new WeakMap();
|
|
197
|
+
_headers = new WeakMap();
|
|
198
|
+
_getFetch = new WeakMap();
|
|
199
|
+
_requestOptions = new WeakMap();
|
|
200
|
+
_pending = new WeakMap();
|
|
201
|
+
_inFlight = new WeakMap();
|
|
202
|
+
_pausedUntil = new WeakMap();
|
|
203
|
+
_Sender_instances = new WeakSet();
|
|
204
|
+
flushPending_fn = async function(key) {
|
|
205
|
+
const entry = __privateGet(this, _pending).get(key);
|
|
206
|
+
if (!entry) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
__privateGet(this, _pending).delete(key);
|
|
210
|
+
clearTimeout(entry.timer);
|
|
211
|
+
if (entry.count > 0 && __privateMethod(this, _Sender_instances, canSend_fn).call(this)) {
|
|
212
|
+
await __privateMethod(this, _Sender_instances, send_fn).call(this, entry.event, entry.payload, entry.count);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
canSend_fn = function() {
|
|
216
|
+
return Date.now() >= __privateGet(this, _pausedUntil) && __privateGet(this, _inFlight).size < MAX_IN_FLIGHT;
|
|
217
|
+
};
|
|
218
|
+
send_fn = function(event, payload, count) {
|
|
219
|
+
const request = __privateMethod(this, _Sender_instances, post_fn).call(this, event, payload, count).finally(() => __privateGet(this, _inFlight).delete(request));
|
|
220
|
+
__privateGet(this, _inFlight).add(request);
|
|
221
|
+
return request;
|
|
222
|
+
};
|
|
223
|
+
post_fn = async function(event, payload, count) {
|
|
224
|
+
try {
|
|
225
|
+
const body = JSON.stringify({ event, ...count > 1 && { count }, payload });
|
|
226
|
+
const response = await __privateGet(this, _getFetch).call(this)(__privateGet(this, _endpoint), {
|
|
227
|
+
method: "POST",
|
|
228
|
+
headers: { "Content-Type": "application/json", ...__privateGet(this, _headers) },
|
|
229
|
+
body,
|
|
230
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
231
|
+
...__privateGet(this, _requestOptions).call(this, body)
|
|
232
|
+
});
|
|
233
|
+
if (response.status === 429) {
|
|
234
|
+
const retryAfterSeconds = Number(response.headers.get("retry-after")) || DEFAULT_RETRY_AFTER_SECONDS;
|
|
235
|
+
__privateSet(this, _pausedUntil, Date.now() + retryAfterSeconds * 1e3);
|
|
236
|
+
console.warn(`Orbitrace: rate limited, dropping events for ${retryAfterSeconds}s`);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (!response.ok) {
|
|
240
|
+
console.error(`Orbitrace: API responded with status ${response.status}`);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
return await response.json();
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.error("Orbitrace: Error sending data to API", error.message);
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
module.exports = {
|
|
249
|
+
MAX_BREADCRUMB_MESSAGE_LENGTH,
|
|
250
|
+
Sender,
|
|
251
|
+
cleanUrl,
|
|
252
|
+
filterSensitive,
|
|
253
|
+
pushBreadcrumb,
|
|
254
|
+
recordConsole,
|
|
255
|
+
recordFetch,
|
|
256
|
+
truncate
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// src/browser.js
|
|
262
|
+
var require_browser = __commonJS({
|
|
263
|
+
"src/browser.js"(exports, module) {
|
|
264
|
+
var { Sender, cleanUrl, filterSensitive, pushBreadcrumb, recordConsole, recordFetch, truncate } = require_shared();
|
|
265
|
+
var MAX_KEEPALIVE_BODY_BYTES = 60 * 1024;
|
|
266
|
+
var MAX_CONSOLE_ARG_LENGTH = 200;
|
|
267
|
+
function formatConsoleArgs(args) {
|
|
268
|
+
return args.map((arg) => {
|
|
269
|
+
if (typeof arg === "string") {
|
|
270
|
+
return arg;
|
|
271
|
+
}
|
|
272
|
+
if (arg instanceof Error) {
|
|
273
|
+
return arg.stack || arg.message;
|
|
274
|
+
}
|
|
275
|
+
try {
|
|
276
|
+
return truncate(JSON.stringify(arg), MAX_CONSOLE_ARG_LENGTH);
|
|
277
|
+
} catch {
|
|
278
|
+
return String(arg);
|
|
279
|
+
}
|
|
280
|
+
}).join(" ");
|
|
281
|
+
}
|
|
282
|
+
function describeElement(element) {
|
|
283
|
+
if (!element || typeof element.tagName !== "string") {
|
|
284
|
+
return "unknown";
|
|
285
|
+
}
|
|
286
|
+
const tag = element.tagName.toLowerCase();
|
|
287
|
+
const id = element.id ? `#${element.id}` : "";
|
|
288
|
+
const classes = typeof element.className === "string" && element.className.trim() ? `.${element.className.trim().split(/\s+/).slice(0, 3).join(".")}` : "";
|
|
289
|
+
return `${tag}${id}${classes}`;
|
|
290
|
+
}
|
|
291
|
+
var _config, _sender, _breadcrumbs, _user, _restore, _fetch, _Orbitrace_static, autoCaptureOptions_fn, installAutoCapture_fn, capture_fn;
|
|
292
|
+
var _Orbitrace = class _Orbitrace {
|
|
293
|
+
// Automatic capture is on unless autoCapture is false or parts of it are switched off.
|
|
294
|
+
static init(config) {
|
|
295
|
+
this.assertBrowserRuntime();
|
|
296
|
+
this.validateConfig(config);
|
|
297
|
+
this.close();
|
|
298
|
+
__privateSet(this, _config, {
|
|
299
|
+
orgId: config.orgId,
|
|
300
|
+
projectId: config.projectId,
|
|
301
|
+
endpoint: config.endpoint,
|
|
302
|
+
environment: config.environment || "production",
|
|
303
|
+
version: config.version || "1.0.0",
|
|
304
|
+
service: config.service || "browser",
|
|
305
|
+
disabled: config.disabled || false
|
|
306
|
+
});
|
|
307
|
+
__privateSet(this, _sender, new Sender({
|
|
308
|
+
endpoint: config.endpoint,
|
|
309
|
+
headers: {
|
|
310
|
+
"x-orbitrace-api-key": config.publicKey,
|
|
311
|
+
"x-orbitrace-org-id": config.orgId,
|
|
312
|
+
"x-orbitrace-project-id": config.projectId
|
|
313
|
+
},
|
|
314
|
+
// Orbitrace's own requests use the original fetch, so they are never recorded.
|
|
315
|
+
getFetch: () => __privateGet(this, _fetch) || window.fetch.bind(window),
|
|
316
|
+
requestOptions: (body) => ({ keepalive: body.length <= MAX_KEEPALIVE_BODY_BYTES })
|
|
317
|
+
}));
|
|
318
|
+
const autoCapture = __privateMethod(this, _Orbitrace_static, autoCaptureOptions_fn).call(this, config.autoCapture);
|
|
319
|
+
if (autoCapture && !__privateGet(this, _config).disabled) {
|
|
320
|
+
__privateMethod(this, _Orbitrace_static, installAutoCapture_fn).call(this, autoCapture);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
static validateConfig(config) {
|
|
324
|
+
if (config.apiKey) {
|
|
325
|
+
throw new Error(
|
|
326
|
+
"Orbitrace: apiKey is a server secret and must not ship in a browser bundle; use the project's publicKey"
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
const requiredFields = ["publicKey", "orgId", "projectId", "endpoint"];
|
|
330
|
+
const missingFields = requiredFields.filter((field) => !config[field]);
|
|
331
|
+
if (missingFields.length > 0) {
|
|
332
|
+
throw new Error(`Missing required configuration fields: ${missingFields.join(", ")}`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
static assertBrowserRuntime() {
|
|
336
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
337
|
+
throw new Error("Orbitrace: @orbitai/orbitrace/browser runs in browsers; use @orbitai/orbitrace on servers");
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
// Queues the event and returns at once; it is sent in the background. flush() waits for delivery.
|
|
341
|
+
static captureException(error, metadata = {}) {
|
|
342
|
+
const message = error?.message || error?.name || String(error);
|
|
343
|
+
__privateMethod(this, _Orbitrace_static, capture_fn).call(this, "capture_exception", {
|
|
344
|
+
message,
|
|
345
|
+
stack: error?.stack || message,
|
|
346
|
+
metadata
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
static captureMessage(message, metadata = {}) {
|
|
350
|
+
__privateMethod(this, _Orbitrace_static, capture_fn).call(this, "capture_message", { message, metadata });
|
|
351
|
+
}
|
|
352
|
+
// Records something that happened, sent with the next event.
|
|
353
|
+
static addBreadcrumb(breadcrumb) {
|
|
354
|
+
pushBreadcrumb(__privateGet(this, _breadcrumbs), breadcrumb);
|
|
355
|
+
}
|
|
356
|
+
// Identifies the signed-in user on every following event. Send a stable id, not personal data.
|
|
357
|
+
// Pass null when the user signs out.
|
|
358
|
+
static setUser(user) {
|
|
359
|
+
__privateSet(this, _user, user ? filterSensitive(user) : null);
|
|
360
|
+
}
|
|
361
|
+
// Sends counts still held by the dedupe window and waits for in-flight requests.
|
|
362
|
+
static async flush() {
|
|
363
|
+
await __privateGet(this, _sender)?.flush();
|
|
364
|
+
}
|
|
365
|
+
// Removes the listeners and wrappers automatic capture installed and forgets breadcrumbs and the user.
|
|
366
|
+
static close() {
|
|
367
|
+
for (const undo of __privateGet(this, _restore).splice(0).reverse()) {
|
|
368
|
+
try {
|
|
369
|
+
undo();
|
|
370
|
+
} catch {
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
__privateSet(this, _fetch, null);
|
|
374
|
+
__privateSet(this, _breadcrumbs, []);
|
|
375
|
+
__privateSet(this, _user, null);
|
|
376
|
+
}
|
|
377
|
+
// Vue 3 plugin: app.use(Orbitrace.vue). Errors Vue catches in components are captured with the component
|
|
378
|
+
// name and where Vue caught them, then passed to the handler the app had, or logged as Vue would.
|
|
379
|
+
static get vue() {
|
|
380
|
+
return {
|
|
381
|
+
install(app) {
|
|
382
|
+
const previous = app.config.errorHandler;
|
|
383
|
+
app.config.errorHandler = (error, instance, info) => {
|
|
384
|
+
_Orbitrace.captureException(error, {
|
|
385
|
+
mechanism: "vue",
|
|
386
|
+
component: instance?.$options?.name || instance?.$?.type?.__name || "anonymous",
|
|
387
|
+
info
|
|
388
|
+
});
|
|
389
|
+
if (previous) {
|
|
390
|
+
previous(error, instance, info);
|
|
391
|
+
} else {
|
|
392
|
+
console.error(error);
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
_config = new WeakMap();
|
|
400
|
+
_sender = new WeakMap();
|
|
401
|
+
_breadcrumbs = new WeakMap();
|
|
402
|
+
_user = new WeakMap();
|
|
403
|
+
_restore = new WeakMap();
|
|
404
|
+
_fetch = new WeakMap();
|
|
405
|
+
_Orbitrace_static = new WeakSet();
|
|
406
|
+
autoCaptureOptions_fn = function(value) {
|
|
407
|
+
if (value === false) {
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
const options = value === true || value === void 0 ? {} : value;
|
|
411
|
+
return {
|
|
412
|
+
exceptions: options.exceptions !== false,
|
|
413
|
+
console: options.console !== false,
|
|
414
|
+
fetch: options.fetch !== false,
|
|
415
|
+
clicks: options.clicks !== false,
|
|
416
|
+
navigation: options.navigation !== false
|
|
417
|
+
};
|
|
418
|
+
};
|
|
419
|
+
installAutoCapture_fn = function(options) {
|
|
420
|
+
const addBreadcrumb = (breadcrumb) => this.addBreadcrumb(breadcrumb);
|
|
421
|
+
const listen = (target, type, listener, capture = false) => {
|
|
422
|
+
target.addEventListener(type, listener, capture);
|
|
423
|
+
__privateGet(this, _restore).push(() => target.removeEventListener(type, listener, capture));
|
|
424
|
+
};
|
|
425
|
+
if (options.exceptions) {
|
|
426
|
+
listen(window, "error", (event) => {
|
|
427
|
+
const error = event.error ?? new Error(event.message || "Unknown error");
|
|
428
|
+
this.captureException(error, {
|
|
429
|
+
mechanism: "onerror",
|
|
430
|
+
...event.filename && { source: `${cleanUrl(event.filename)}:${event.lineno}:${event.colno}` }
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
listen(window, "unhandledrejection", (event) => {
|
|
434
|
+
const reason = event.reason;
|
|
435
|
+
const error = reason instanceof Error ? reason : new Error(`Unhandled rejection: ${formatConsoleArgs([reason])}`);
|
|
436
|
+
this.captureException(error, { mechanism: "unhandledrejection" });
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
if (options.console) {
|
|
440
|
+
recordConsole({ addBreadcrumb, restore: __privateGet(this, _restore), format: formatConsoleArgs });
|
|
441
|
+
}
|
|
442
|
+
if (options.fetch) {
|
|
443
|
+
__privateSet(this, _fetch, recordFetch({ endpoint: __privateGet(this, _config).endpoint, addBreadcrumb, restore: __privateGet(this, _restore) }));
|
|
444
|
+
}
|
|
445
|
+
if (options.clicks) {
|
|
446
|
+
listen(
|
|
447
|
+
document,
|
|
448
|
+
"click",
|
|
449
|
+
(event) => addBreadcrumb({ category: "ui.click", message: describeElement(event.target) }),
|
|
450
|
+
true
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
if (options.navigation) {
|
|
454
|
+
let from = cleanUrl(window.location.href);
|
|
455
|
+
const navigated = () => {
|
|
456
|
+
const to = cleanUrl(window.location.href);
|
|
457
|
+
if (to !== from) {
|
|
458
|
+
addBreadcrumb({ category: "navigation", message: `${from} -> ${to}`, data: { from, to } });
|
|
459
|
+
from = to;
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
for (const method of ["pushState", "replaceState"]) {
|
|
463
|
+
const original = window.history[method];
|
|
464
|
+
if (typeof original !== "function") {
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
window.history[method] = function orbitraceHistory(...args) {
|
|
468
|
+
const result = original.apply(this, args);
|
|
469
|
+
navigated();
|
|
470
|
+
return result;
|
|
471
|
+
};
|
|
472
|
+
__privateGet(this, _restore).push(() => {
|
|
473
|
+
window.history[method] = original;
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
listen(window, "popstate", navigated);
|
|
477
|
+
listen(window, "hashchange", navigated);
|
|
478
|
+
}
|
|
479
|
+
listen(window, "pagehide", () => __privateGet(this, _sender).flush());
|
|
480
|
+
};
|
|
481
|
+
capture_fn = function(event, { metadata, ...fields }) {
|
|
482
|
+
if (!__privateGet(this, _config)) {
|
|
483
|
+
console.error("Orbitrace: call Orbitrace.init() before capturing events");
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
if (__privateGet(this, _config).disabled) {
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
try {
|
|
490
|
+
const breadcrumbs = [...__privateGet(this, _breadcrumbs)];
|
|
491
|
+
__privateGet(this, _sender).capture(event, {
|
|
492
|
+
...fields,
|
|
493
|
+
metadata: {
|
|
494
|
+
...filterSensitive(metadata),
|
|
495
|
+
env: __privateGet(this, _config).environment,
|
|
496
|
+
version: __privateGet(this, _config).version,
|
|
497
|
+
service: __privateGet(this, _config).service,
|
|
498
|
+
...__privateGet(this, _user) && { user: __privateGet(this, _user) },
|
|
499
|
+
// Where it happened. URLs lose their query string and fragment.
|
|
500
|
+
page: {
|
|
501
|
+
url: cleanUrl(window.location.href),
|
|
502
|
+
...document.referrer && { referrer: cleanUrl(document.referrer) },
|
|
503
|
+
viewport: `${window.innerWidth}x${window.innerHeight}`,
|
|
504
|
+
language: window.navigator?.language
|
|
505
|
+
}
|
|
506
|
+
},
|
|
507
|
+
...breadcrumbs.length > 0 && { breadcrumbs }
|
|
508
|
+
});
|
|
509
|
+
} catch (error) {
|
|
510
|
+
console.error("Orbitrace: could not capture the event", error?.message);
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
__privateAdd(_Orbitrace, _Orbitrace_static);
|
|
514
|
+
__privateAdd(_Orbitrace, _config, null);
|
|
515
|
+
__privateAdd(_Orbitrace, _sender, null);
|
|
516
|
+
__privateAdd(_Orbitrace, _breadcrumbs, []);
|
|
517
|
+
__privateAdd(_Orbitrace, _user, null);
|
|
518
|
+
// Undo functions for everything automatic capture installed; close() runs them.
|
|
519
|
+
__privateAdd(_Orbitrace, _restore, []);
|
|
520
|
+
__privateAdd(_Orbitrace, _fetch, null);
|
|
521
|
+
var Orbitrace = _Orbitrace;
|
|
522
|
+
module.exports = Orbitrace;
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
export default require_browser();
|