@reopt-ai/data-sdk-client 0.1.6 → 0.2.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.
Files changed (57) hide show
  1. package/README.md +141 -7
  2. package/dist/client-B1GlWwVq.d.ts +744 -0
  3. package/dist/client-B1GlWwVq.d.ts.map +1 -0
  4. package/dist/client-BCrui21p.d.cts +744 -0
  5. package/dist/client-BCrui21p.d.cts.map +1 -0
  6. package/dist/exceptions-C9Fh0BIR.js +285 -0
  7. package/dist/exceptions-C9Fh0BIR.js.map +1 -0
  8. package/dist/exceptions-CuhGo9A5.cjs +289 -0
  9. package/dist/exceptions-CuhGo9A5.cjs.map +1 -0
  10. package/dist/index.cjs +75 -1874
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +83 -0
  13. package/dist/index.d.cts.map +1 -0
  14. package/dist/index.d.ts +35 -33
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +49 -70
  17. package/dist/index.js.map +1 -1
  18. package/dist/next.cjs +51 -1919
  19. package/dist/next.cjs.map +1 -1
  20. package/dist/next.d.cts +31 -0
  21. package/dist/next.d.cts.map +1 -0
  22. package/dist/next.d.ts +8 -10
  23. package/dist/next.d.ts.map +1 -0
  24. package/dist/next.js +36 -49
  25. package/dist/next.js.map +1 -1
  26. package/dist/observe-D-BHMwrO.cjs +54 -0
  27. package/dist/observe-D-BHMwrO.cjs.map +1 -0
  28. package/dist/observe-D1pNg1qL.js +54 -0
  29. package/dist/observe-D1pNg1qL.js.map +1 -0
  30. package/dist/react.cjs +105 -1863
  31. package/dist/react.cjs.map +1 -1
  32. package/dist/react.d.cts +80 -0
  33. package/dist/react.d.cts.map +1 -0
  34. package/dist/react.d.ts +52 -46
  35. package/dist/react.d.ts.map +1 -0
  36. package/dist/react.js +118 -23
  37. package/dist/react.js.map +1 -1
  38. package/dist/registry-BPhiH_l9.js +1775 -0
  39. package/dist/registry-BPhiH_l9.js.map +1 -0
  40. package/dist/registry-CGqrOtf4.cjs +1810 -0
  41. package/dist/registry-CGqrOtf4.cjs.map +1 -0
  42. package/dist/tracing-DAhaKkl0.cjs +93 -0
  43. package/dist/tracing-DAhaKkl0.cjs.map +1 -0
  44. package/dist/tracing-Dt1RVuQ9.js +93 -0
  45. package/dist/tracing-Dt1RVuQ9.js.map +1 -0
  46. package/package.json +31 -16
  47. package/dist/chunk-4MTDZBRS.js +0 -57
  48. package/dist/chunk-4MTDZBRS.js.map +0 -1
  49. package/dist/chunk-SYCBGBTH.js +0 -1627
  50. package/dist/chunk-SYCBGBTH.js.map +0 -1
  51. package/dist/chunk-YRP3I3OD.js +0 -106
  52. package/dist/chunk-YRP3I3OD.js.map +0 -1
  53. package/dist/client-BCd2fgmx.d.ts +0 -581
  54. package/dist/exceptions-NQHZUDYO.js +0 -9
  55. package/dist/exceptions-NQHZUDYO.js.map +0 -1
  56. package/dist/tracing-LC3NZND7.js +0 -91
  57. package/dist/tracing-LC3NZND7.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-BCrui21p.d.cts","names":[],"sources":["../../data-sdk-core/src/types.ts","../../data-sdk-core/src/consent.ts","../../data-sdk-core/src/transport.ts","../../data-sdk-core/src/client.ts","../src/steps.ts","../src/capture/web-vitals.ts","../src/config.ts","../src/identity/device.ts","../src/client.ts"],"mappings":"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"}
@@ -0,0 +1,285 @@
1
+ import { o as MAX_STACK_CHARS } from "./registry-BPhiH_l9.js";
2
+ import { MAX_EXCEPTION_CHAIN, MAX_EXCEPTION_FRAMES } from "@reopt-ai/data-contract/events";
3
+ //#region ../data-sdk-core/src/stack-parsers/index.ts
4
+ const EXTENSION_PROTOCOLS = [
5
+ "chrome-extension://",
6
+ "moz-extension://",
7
+ "safari-extension://",
8
+ "safari-web-extension://"
9
+ ];
10
+ const WEBKIT_MASKED_URL = "webkit-masked-url://";
11
+ const ANONYMOUS_FILE = "<anonymous>";
12
+ function isInAppFrame(filename) {
13
+ if (!filename || filename === ANONYMOUS_FILE) return false;
14
+ if (filename.startsWith(WEBKIT_MASKED_URL)) return false;
15
+ if (EXTENSION_PROTOCOLS.some((protocol) => filename.startsWith(protocol))) return false;
16
+ return !filename.includes("/node_modules/") && !filename.startsWith("node:");
17
+ }
18
+ function isExtensionOnlyStack(frames) {
19
+ if (frames.length === 0) return false;
20
+ return frames.every((frame) => EXTENSION_PROTOCOLS.some((protocol) => (frame.filename ?? "").startsWith(protocol)));
21
+ }
22
+ const CHROME_LINE = /^\s*at (?:(.+?)\s+\()?(?:(.+?):(\d+):(\d+)|\(?([^)]*)\)?)\)?\s*$/;
23
+ const CHROME_EVAL = /\((\S*)(?::(\d+))(?::(\d+))\)/;
24
+ const GECKO_LINE = /^\s*(?:(.*?)(?:\((.*?)\))?(?:^|@))?((?:file|https?|blob|chrome|webpack|resource|moz-extension|safari-extension|safari-web-extension|capacitor|\[native).*?)(?::(\d+))?(?::(\d+))?\s*$/i;
25
+ function frame(filename, fn, lineno, colno) {
26
+ const name = fn?.trim();
27
+ return {
28
+ ...filename ? { filename } : {},
29
+ ...name ? { function: name } : {},
30
+ ...lineno ? { lineno: Number.parseInt(lineno, 10) } : {},
31
+ ...colno ? { colno: Number.parseInt(colno, 10) } : {},
32
+ in_app: isInAppFrame(filename)
33
+ };
34
+ }
35
+ function cleanV8Name(raw) {
36
+ if (!raw) return void 0;
37
+ return raw.replace(/^async\s+/, "").trim();
38
+ }
39
+ const parseChromeLine = (line) => {
40
+ const match = CHROME_LINE.exec(line);
41
+ if (!match) return void 0;
42
+ let filename = match[2];
43
+ let lineno = match[3];
44
+ let colno = match[4];
45
+ if (filename?.startsWith("eval")) {
46
+ const evalMatch = CHROME_EVAL.exec(filename);
47
+ if (evalMatch) {
48
+ filename = evalMatch[1];
49
+ lineno = evalMatch[2];
50
+ colno = evalMatch[3];
51
+ }
52
+ }
53
+ if (!filename && match[5]) return frame(void 0, cleanV8Name(match[1] ?? match[5]), void 0, void 0);
54
+ if (!filename) return void 0;
55
+ return frame(filename, cleanV8Name(match[1]), lineno, colno);
56
+ };
57
+ const parseGeckoLine = (line) => {
58
+ const match = GECKO_LINE.exec(line);
59
+ if (!match) return void 0;
60
+ const filename = match[3];
61
+ if (!filename) return void 0;
62
+ if (filename.startsWith("[native")) return frame(void 0, match[1], void 0, void 0);
63
+ const fn = match[1]?.replace(/\/[<.].*$/, "");
64
+ return frame(filename, fn, match[4], match[5]);
65
+ };
66
+ const LINE_PARSERS = [parseChromeLine, parseGeckoLine];
67
+ function parseStackString(stack) {
68
+ if (!stack) return [];
69
+ const frames = [];
70
+ for (const line of stack.split("\n")) {
71
+ if (frames.length >= MAX_EXCEPTION_FRAMES) break;
72
+ if (!line.trim()) continue;
73
+ for (const parse of LINE_PARSERS) {
74
+ const parsed = parse(line);
75
+ if (!parsed) continue;
76
+ if (parsed.filename || parsed.function) frames.push(parsed);
77
+ break;
78
+ }
79
+ }
80
+ return frames;
81
+ }
82
+ //#endregion
83
+ //#region ../data-sdk-core/src/stack-parsers/coerce.ts
84
+ const MAX_MESSAGE_CHARS = 1e3;
85
+ function truncate(value) {
86
+ return value.length > MAX_MESSAGE_CHARS ? value.slice(0, MAX_MESSAGE_CHARS) : value;
87
+ }
88
+ function isErrorLike(value) {
89
+ if (value instanceof Error) return true;
90
+ const candidate = value;
91
+ return typeof candidate === "object" && candidate !== null && typeof candidate.name === "string" && typeof candidate.message === "string";
92
+ }
93
+ function constructorName(value) {
94
+ const name = value?.constructor?.name;
95
+ return typeof name === "string" && name ? name : void 0;
96
+ }
97
+ function describeObject(value) {
98
+ try {
99
+ const json = JSON.stringify(value);
100
+ if (json && json !== "{}") return truncate(json);
101
+ } catch {}
102
+ const keys = Object.keys(value);
103
+ return keys.length > 0 ? `Object with keys: ${keys.slice(0, 10).join(", ")}` : "Object";
104
+ }
105
+ function entry(type, value, mechanism, stack) {
106
+ const frames = parseStackString(stack).slice(0, MAX_EXCEPTION_FRAMES);
107
+ return {
108
+ type,
109
+ value: truncate(value),
110
+ mechanism,
111
+ ...frames.length > 0 ? { stacktrace: {
112
+ frames,
113
+ type: "raw"
114
+ } } : {}
115
+ };
116
+ }
117
+ function coerceNonError(value, mechanism) {
118
+ const synthetic = {
119
+ ...mechanism,
120
+ synthetic: true
121
+ };
122
+ if (typeof value === "string") return entry("Error", value, synthetic);
123
+ if (value === null) return entry("Error", "null", synthetic);
124
+ if (value === void 0) return entry("Error", "undefined", synthetic);
125
+ if (typeof value !== "object") return entry("Error", `${typeof value}: ${String(value)}`, synthetic);
126
+ const name = constructorName(value);
127
+ const record = value;
128
+ if (name === "ErrorEvent" && typeof record.message === "string") {
129
+ const where = [
130
+ record.filename,
131
+ record.lineno,
132
+ record.colno
133
+ ].filter(Boolean).join(":");
134
+ return entry("ErrorEvent", where ? `${record.message} (${where})` : record.message, synthetic);
135
+ }
136
+ if (typeof record.type === "string" && typeof record.preventDefault === "function") return entry(name ?? "Event", `Event of type "${record.type}" was thrown`, synthetic);
137
+ return entry(name && name !== "Object" ? name : "Error", describeObject(value), synthetic);
138
+ }
139
+ function coerceToExceptionChain(value, mechanism) {
140
+ const chain = [];
141
+ const seen = new Set();
142
+ let current = value;
143
+ let isOutermost = true;
144
+ while (chain.length < MAX_EXCEPTION_CHAIN) {
145
+ if (!isOutermost && current === void 0) break;
146
+ if (typeof current === "object" && current !== null) {
147
+ if (seen.has(current)) break;
148
+ seen.add(current);
149
+ }
150
+ const linkMechanism = isOutermost ? mechanism : {
151
+ ...mechanism,
152
+ handled: true
153
+ };
154
+ if (isErrorLike(current)) {
155
+ chain.push(entry(current.name || "Error", current.message, linkMechanism, current.stack));
156
+ current = current.cause;
157
+ } else {
158
+ chain.push(coerceNonError(current, linkMechanism));
159
+ break;
160
+ }
161
+ isOutermost = false;
162
+ }
163
+ return chain;
164
+ }
165
+ //#endregion
166
+ //#region src/capture/chunk-ids.ts
167
+ function fileNameOf(filename) {
168
+ const withoutQuery = filename.split(/[?#]/)[0] ?? filename;
169
+ return withoutQuery.split("/").pop() ?? withoutQuery;
170
+ }
171
+ function chunkIds() {
172
+ const map = globalThis._reoptChunkIds;
173
+ return map && typeof map === "object" ? map : void 0;
174
+ }
175
+ function stampChunkIds(chain) {
176
+ const map = chunkIds();
177
+ if (!map) return chain;
178
+ for (const entry of chain) for (const frame of entry.stacktrace?.frames ?? []) {
179
+ if (!frame.filename || frame.chunk_id) continue;
180
+ const id = map[fileNameOf(frame.filename)];
181
+ if (typeof id === "string" && id) frame.chunk_id = id;
182
+ }
183
+ return chain;
184
+ }
185
+ //#endregion
186
+ //#region src/capture/describe-error.ts
187
+ const MECHANISM_TYPES = {
188
+ "window.onerror": "onerror",
189
+ unhandledrejection: "unhandledrejection",
190
+ captureException: "manual"
191
+ };
192
+ function shouldDropException(properties) {
193
+ const chain = properties.$exception_list ?? [];
194
+ if (chain.length === 0) return false;
195
+ return chain.every((entry) => isExtensionOnlyStack(entry.stacktrace?.frames ?? []));
196
+ }
197
+ function describeError(value, source) {
198
+ const path = typeof location !== "undefined" ? location.pathname : "";
199
+ const handled = source === "captureException";
200
+ const chain = stampChunkIds(coerceToExceptionChain(value, {
201
+ handled,
202
+ type: MECHANISM_TYPES[source]
203
+ }));
204
+ const head = chain[0];
205
+ const rawStack = value instanceof Error && value.stack ? value.stack.slice(0, MAX_STACK_CHARS) : void 0;
206
+ return {
207
+ $exception_type: head?.type ?? "Error",
208
+ $exception_message: head?.value ?? "",
209
+ ...rawStack ? { $exception_stack: rawStack } : {},
210
+ $exception_source: source,
211
+ $exception_handled: handled,
212
+ $exception_list: chain,
213
+ path
214
+ };
215
+ }
216
+ //#endregion
217
+ //#region src/capture/exception-rate-limit.ts
218
+ const DEFAULT_EXCEPTION_RATE_LIMIT = {
219
+ bucketSize: 10,
220
+ refillSeconds: 10
221
+ };
222
+ function createExceptionRateLimiter(options = {}) {
223
+ const buckets = new Map();
224
+ const refillMs = Math.max(options.refillSeconds ?? DEFAULT_EXCEPTION_RATE_LIMIT.refillSeconds, .001) * 1e3;
225
+ const size = Math.max(options.bucketSize ?? DEFAULT_EXCEPTION_RATE_LIMIT.bucketSize, 1);
226
+ return { allow(type, now = Date.now()) {
227
+ const bucket = buckets.get(type) ?? {
228
+ tokens: size,
229
+ updatedAt: now
230
+ };
231
+ const earned = Math.floor((now - bucket.updatedAt) / refillMs);
232
+ const tokens = Math.min(size, bucket.tokens + Math.max(earned, 0));
233
+ const updatedAt = earned > 0 ? bucket.updatedAt + earned * refillMs : bucket.updatedAt;
234
+ if (tokens <= 0) {
235
+ buckets.set(type, {
236
+ tokens,
237
+ updatedAt
238
+ });
239
+ return false;
240
+ }
241
+ buckets.set(type, {
242
+ tokens: tokens - 1,
243
+ updatedAt
244
+ });
245
+ return true;
246
+ } };
247
+ }
248
+ //#endregion
249
+ //#region src/capture/exceptions.ts
250
+ function installExceptionCapture(report, options = {}) {
251
+ if (typeof window === "undefined") return () => {};
252
+ const limiter = options.rateLimit === false ? null : createExceptionRateLimiter(options.rateLimit);
253
+ const throttled = new Set();
254
+ const send = (properties) => {
255
+ if (shouldDropException(properties)) return;
256
+ if (limiter && !limiter.allow(properties.$exception_type)) {
257
+ if (!throttled.has(properties.$exception_type)) {
258
+ throttled.add(properties.$exception_type);
259
+ options.onThrottled?.(properties.$exception_type);
260
+ }
261
+ return;
262
+ }
263
+ report(properties);
264
+ };
265
+ const onError = (event) => {
266
+ try {
267
+ send(describeError(event.error ?? new Error(event.message), "window.onerror"));
268
+ } catch {}
269
+ };
270
+ const onRejection = (event) => {
271
+ try {
272
+ send(describeError(event.reason, "unhandledrejection"));
273
+ } catch {}
274
+ };
275
+ window.addEventListener("error", onError);
276
+ window.addEventListener("unhandledrejection", onRejection);
277
+ return () => {
278
+ window.removeEventListener("error", onError);
279
+ window.removeEventListener("unhandledrejection", onRejection);
280
+ };
281
+ }
282
+ //#endregion
283
+ export { DEFAULT_EXCEPTION_RATE_LIMIT, createExceptionRateLimiter, describeError, installExceptionCapture, shouldDropException };
284
+
285
+ //# sourceMappingURL=exceptions-C9Fh0BIR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exceptions-C9Fh0BIR.js","names":[],"sources":["../../data-sdk-core/src/stack-parsers/index.ts","../../data-sdk-core/src/stack-parsers/coerce.ts","../src/capture/chunk-ids.ts","../src/capture/describe-error.ts","../src/capture/exception-rate-limit.ts","../src/capture/exceptions.ts"],"sourcesContent":["/**\n * Turning an `error.stack` string into structured frames.\n *\n * Every JS engine formats a stack differently and none of them documents the\n * format, so this is pattern matching against what the engines actually emit.\n * The regexes descend from Sentry's `stacktrace.ts` by way of posthog-js\n * (`packages/core/src/error-tracking/parsers/`), both MIT — the shapes are the\n * accumulated result of years of field reports, and rewriting them from the\n * specs would mean rediscovering the same edge cases.\n *\n * Lives in `data-sdk-core` because the browser and the server SDK both need it\n * and neither may depend on the other. Core has no build step; both consumers\n * inline this source, so nothing here may reach for a browser or Node global.\n */\nimport { MAX_EXCEPTION_FRAMES, type ExceptionFrame } from \"@reopt-ai/data-contract/events\";\n\n/** A parser turns one stack line into a frame, or returns undefined if it cannot. */\ntype LineParser = (line: string) => ExceptionFrame | undefined;\n\n/** Frames the runtime, not the app: a stack of only these is not worth reporting. */\nconst EXTENSION_PROTOCOLS = [\n \"chrome-extension://\",\n \"moz-extension://\",\n \"safari-extension://\",\n \"safari-web-extension://\",\n];\n\n/** WebKit masks cross-origin URLs; a masked frame names no file anyone can open. */\nconst WEBKIT_MASKED_URL = \"webkit-masked-url://\";\nconst ANONYMOUS_FILE = \"<anonymous>\";\n\n/**\n * Whether a frame is the app's own code.\n *\n * Anything the app did not write — an extension's injected script, a masked\n * cross-origin URL, a frame with no file at all — is not somewhere a developer\n * can go and fix, so the stack panel hides it by default.\n */\nexport function isInAppFrame(filename: string | undefined): boolean {\n if (!filename || filename === ANONYMOUS_FILE) return false;\n if (filename.startsWith(WEBKIT_MASKED_URL)) return false;\n if (EXTENSION_PROTOCOLS.some((protocol) => filename.startsWith(protocol))) return false;\n return !filename.includes(\"/node_modules/\") && !filename.startsWith(\"node:\");\n}\n\n/** True when every frame came from a browser extension — not the site's bug to fix. */\nexport function isExtensionOnlyStack(frames: readonly ExceptionFrame[]): boolean {\n if (frames.length === 0) return false;\n return frames.every((frame) => EXTENSION_PROTOCOLS.some((protocol) => (frame.filename ?? \"\").startsWith(protocol)));\n}\n\n// V8 (Chrome, Edge, Node): ` at fn (file:line:col)`, ` at file:line:col`,\n// plus the `async`, `new`, and `eval` decorations it adds.\nconst CHROME_LINE = /^\\s*at (?:(.+?)\\s+\\()?(?:(.+?):(\\d+):(\\d+)|\\(?([^)]*)\\)?)\\)?\\s*$/;\nconst CHROME_EVAL = /\\((\\S*)(?::(\\d+))(?::(\\d+))\\)/;\n\n// SpiderMonkey (Firefox) and JavaScriptCore (Safari): `fn@file:line:col`.\n// Firefox adds `/<` and `.prototype.` decorations; Safari omits the name for\n// global code and uses `[native code]` for host functions.\nconst GECKO_LINE =\n /^\\s*(?:(.*?)(?:\\((.*?)\\))?(?:^|@))?((?:file|https?|blob|chrome|webpack|resource|moz-extension|safari-extension|safari-web-extension|capacitor|\\[native).*?)(?::(\\d+))?(?::(\\d+))?\\s*$/i;\n\nfunction frame(\n filename: string | undefined,\n fn: string | undefined,\n lineno: string | undefined,\n colno: string | undefined\n): ExceptionFrame {\n const name = fn?.trim();\n return {\n ...(filename ? { filename } : {}),\n ...(name ? { function: name } : {}),\n ...(lineno ? { lineno: Number.parseInt(lineno, 10) } : {}),\n ...(colno ? { colno: Number.parseInt(colno, 10) } : {}),\n in_app: isInAppFrame(filename),\n };\n}\n\n/** V8's `async` and `new` are call decorations, not part of a function's identity. */\nfunction cleanV8Name(raw: string | undefined): string | undefined {\n if (!raw) return undefined;\n return raw.replace(/^async\\s+/, \"\").trim();\n}\n\nexport const parseChromeLine: LineParser = (line) => {\n const match = CHROME_LINE.exec(line);\n if (!match) return undefined;\n\n let filename = match[2];\n let lineno = match[3];\n let colno = match[4];\n\n // `at fn (eval at x (file:1:2), <anonymous>:3:4)` — the useful location is\n // the outer file, not the synthetic eval one.\n if (filename?.startsWith(\"eval\")) {\n const evalMatch = CHROME_EVAL.exec(filename);\n if (evalMatch) {\n filename = evalMatch[1];\n lineno = evalMatch[2];\n colno = evalMatch[3];\n }\n }\n\n // The bare `at <anonymous>` / `at native` form: group 5 holds it and there is\n // no location to report.\n if (!filename && match[5]) return frame(undefined, cleanV8Name(match[1] ?? match[5]), undefined, undefined);\n if (!filename) return undefined;\n\n return frame(filename, cleanV8Name(match[1]), lineno, colno);\n};\n\nexport const parseGeckoLine: LineParser = (line) => {\n const match = GECKO_LINE.exec(line);\n if (!match) return undefined;\n\n const filename = match[3];\n if (!filename) return undefined;\n // `[native code]` names no file; keep the function, drop the location.\n if (filename.startsWith(\"[native\")) return frame(undefined, match[1], undefined, undefined);\n\n // Firefox writes `fn/<` for a nested closure and `fn/name` for a named one;\n // the trailing part is noise for grouping.\n const fn = match[1]?.replace(/\\/[<.].*$/, \"\");\n return frame(filename, fn, match[4], match[5]);\n};\n\nconst LINE_PARSERS: LineParser[] = [parseChromeLine, parseGeckoLine];\n\n/**\n * Parse a stack string into frames, innermost first.\n *\n * Deliberately forgiving: a line no parser recognises is skipped rather than\n * failing the whole stack, so a message header, an `at <anonymous>`, or a\n * format nobody has seen yet costs one frame instead of all of them.\n */\nexport function parseStackString(stack: string | undefined): ExceptionFrame[] {\n if (!stack) return [];\n\n const frames: ExceptionFrame[] = [];\n for (const line of stack.split(\"\\n\")) {\n if (frames.length >= MAX_EXCEPTION_FRAMES) break;\n // A line that is only whitespace or the message header cannot be a frame.\n if (!line.trim()) continue;\n\n for (const parse of LINE_PARSERS) {\n const parsed = parse(line);\n if (!parsed) continue;\n // A frame with neither a file nor a name says nothing — Safari's\n // `[native code]` parses to exactly that, and it would only pad the\n // stack panel and the fingerprint with a blank row.\n if (parsed.filename || parsed.function) frames.push(parsed);\n break;\n }\n }\n\n return frames;\n}\n","/**\n * Turning whatever was thrown into a cause chain of structured exceptions.\n *\n * JavaScript lets you throw anything. In the field the majority are `Error`s,\n * but a meaningful tail are strings, `DOMException`s, `Event`s that a framework\n * passed along, and plain objects from a rejected fetch. Each of those needs a\n * type and a message that mean something in an issue list — `\"[object Object]\"`\n * groups every unrelated bug in the app into one issue.\n *\n * Shared by both SDKs and free of any runtime global: `DOMException` and\n * friends are detected by shape and by `constructor.name`, never by `instanceof`\n * against a global that may not exist.\n */\nimport {\n MAX_EXCEPTION_CHAIN,\n MAX_EXCEPTION_FRAMES,\n type ExceptionEntry,\n type ExceptionMechanism,\n} from \"@reopt-ai/data-contract/events\";\nimport { parseStackString } from \"./index.js\";\n\nconst MAX_MESSAGE_CHARS = 1_000;\n\nfunction truncate(value: string): string {\n return value.length > MAX_MESSAGE_CHARS ? value.slice(0, MAX_MESSAGE_CHARS) : value;\n}\n\nfunction isErrorLike(value: unknown): value is Error {\n if (value instanceof Error) return true;\n // Cross-realm errors (an iframe, a worker) fail `instanceof` but still have\n // the shape, and dropping them would lose exactly the errors that are hardest\n // to reproduce.\n const candidate = value as { name?: unknown; message?: unknown; stack?: unknown } | null;\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof candidate.name === \"string\" &&\n typeof candidate.message === \"string\"\n );\n}\n\nfunction constructorName(value: unknown): string | undefined {\n const name = (value as { constructor?: { name?: unknown } } | null)?.constructor?.name;\n return typeof name === \"string\" && name ? name : undefined;\n}\n\n/** `{\"a\":1}`, or the best available label when the value will not serialize. */\nfunction describeObject(value: object): string {\n try {\n const json = JSON.stringify(value);\n if (json && json !== \"{}\") return truncate(json);\n } catch {\n // Circular, or a getter that throws. Fall through to the shape label.\n }\n const keys = Object.keys(value);\n return keys.length > 0 ? `Object with keys: ${keys.slice(0, 10).join(\", \")}` : \"Object\";\n}\n\nfunction entry(type: string, value: string, mechanism: ExceptionMechanism, stack?: string | undefined): ExceptionEntry {\n const frames = parseStackString(stack).slice(0, MAX_EXCEPTION_FRAMES);\n return {\n type,\n value: truncate(value),\n mechanism,\n ...(frames.length > 0 ? { stacktrace: { frames, type: \"raw\" as const } } : {}),\n };\n}\n\n/**\n * One exception entry for a non-Error throw.\n *\n * Each branch exists because the naive `String(value)` reading of it is\n * useless: a `DOMException` stringifies to its message and loses the `name`\n * that says which DOM operation failed; an `ErrorEvent` stringifies to\n * `[object ErrorEvent]`; a plain object to `[object Object]`.\n */\nfunction coerceNonError(value: unknown, mechanism: ExceptionMechanism): ExceptionEntry {\n const synthetic: ExceptionMechanism = { ...mechanism, synthetic: true };\n\n if (typeof value === \"string\") return entry(\"Error\", value, synthetic);\n if (value === null) return entry(\"Error\", \"null\", synthetic);\n if (value === undefined) return entry(\"Error\", \"undefined\", synthetic);\n if (typeof value !== \"object\") return entry(\"Error\", `${typeof value}: ${String(value)}`, synthetic);\n\n const name = constructorName(value);\n const record = value as Record<string, unknown>;\n\n // `DOMException` is not handled here on purpose: it has a string `name` and\n // `message`, so `isErrorLike` claims it first and reports its own name\n // (`QuotaExceededError`, `AbortError`) as the type — which is the whole\n // diagnosis, and which grouping them all under \"DOMException\" would lose.\n // It is also a genuine thrown error, so it is not `synthetic`.\n\n // An ErrorEvent that reached us without its `error` — the message plus the\n // location is all the browser gave.\n if (name === \"ErrorEvent\" && typeof record.message === \"string\") {\n const where = [record.filename, record.lineno, record.colno].filter(Boolean).join(\":\");\n return entry(\"ErrorEvent\", where ? `${record.message} (${where})` : record.message, synthetic);\n }\n\n // Any other Event: its type is the only thing that distinguishes one from\n // another, and `[object Event]` distinguishes nothing.\n if (\n typeof record.type === \"string\" &&\n typeof (record as { preventDefault?: unknown }).preventDefault === \"function\"\n ) {\n return entry(name ?? \"Event\", `Event of type \"${record.type}\" was thrown`, synthetic);\n }\n\n return entry(name && name !== \"Object\" ? name : \"Error\", describeObject(value), synthetic);\n}\n\n/**\n * The full cause chain for one throw, outermost first.\n *\n * The chain is capped by the contract and by a seen-set: `a.cause = b;\n * b.cause = a` is rare but it is an infinite loop, and an SDK must not be the\n * thing that hangs the page it reports on.\n *\n * Causes are marked `handled: true` — only the outermost exception actually\n * escaped; the ones below it were caught and re-thrown, which is what a `cause`\n * chain means.\n */\nexport function coerceToExceptionChain(value: unknown, mechanism: ExceptionMechanism): ExceptionEntry[] {\n const chain: ExceptionEntry[] = [];\n const seen = new Set<unknown>();\n let current: unknown = value;\n let isOutermost = true;\n\n // The first value is always described, even when it is `undefined` —\n // `Promise.reject()` with no reason is a real thing that happens, and an\n // empty chain would report an exception with no type and no message.\n while (chain.length < MAX_EXCEPTION_CHAIN) {\n if (!isOutermost && current === undefined) break;\n if (typeof current === \"object\" && current !== null) {\n if (seen.has(current)) break;\n seen.add(current);\n }\n\n const linkMechanism: ExceptionMechanism = isOutermost ? mechanism : { ...mechanism, handled: true };\n\n if (isErrorLike(current)) {\n chain.push(entry(current.name || \"Error\", current.message, linkMechanism, current.stack));\n current = (current as { cause?: unknown }).cause;\n } else {\n chain.push(coerceNonError(current, linkMechanism));\n break;\n }\n\n isOutermost = false;\n }\n\n return chain;\n}\n","/**\n * Stamping frames with the chunk id the build injected.\n *\n * A frame's `filename` is a URL, and a URL is a fragile join key: it changes\n * with the CDN host, the base path, and every preview deployment. The build's\n * `reopt-data inject-chunk-ids` writes a content-derived id per chunk into\n * `globalThis._reoptChunkIds`, and this stamps it onto the frames so the\n * server can find the map by identity rather than by address.\n *\n * Lives in the lazily-imported `capture/exceptions` chunk, like the parsers.\n * The main bundle has a few bytes of headroom and this is not worth them —\n * a page that never throws must not pay for it.\n */\nimport type { ExceptionEntry } from \"@reopt-ai/data-contract/events\";\n\ntype ChunkIdMap = Record<string, string>;\n\n/** The file name a frame's URL ends in — the key the injector used. */\nfunction fileNameOf(filename: string): string {\n const withoutQuery = filename.split(/[?#]/)[0] ?? filename;\n return withoutQuery.split(\"/\").pop() ?? withoutQuery;\n}\n\nfunction chunkIds(): ChunkIdMap | undefined {\n const map = (globalThis as { _reoptChunkIds?: unknown })._reoptChunkIds;\n return map && typeof map === \"object\" ? (map as ChunkIdMap) : undefined;\n}\n\n/**\n * Add `chunk_id` to every frame the build stamped.\n *\n * Mutates in place: the chain was just built by the parser and is not shared,\n * and copying a fifty-frame chain per exception buys nothing.\n */\nexport function stampChunkIds(chain: ExceptionEntry[]): ExceptionEntry[] {\n const map = chunkIds();\n if (!map) return chain;\n\n for (const entry of chain) {\n for (const frame of entry.stacktrace?.frames ?? []) {\n if (!frame.filename || frame.chunk_id) continue;\n const id = map[fileNameOf(frame.filename)];\n if (typeof id === \"string\" && id) frame.chunk_id = id;\n }\n }\n return chain;\n}\n","/**\n * What an `$exception` event carries.\n *\n * Two shapes at once, on purpose. `$exception_list` is the structured form the\n * issue page renders and V2 fingerprinting reads; the flat `$exception_*` keys\n * are what every consumer written before it — dashboards, the rollup keys, V1\n * fingerprinting — already reads. Dropping the flat keys would re-group every\n * existing issue, so they stay.\n *\n * Everything here lives in the lazily-imported `capture/exceptions` chunk. It\n * must never be reachable from the main entry, or the parsers land in the\n * initial bundle of every page that never throws.\n */\nimport { coerceToExceptionChain, isExtensionOnlyStack, type ExceptionMechanism } from \"@reopt-ai/data-sdk-core\";\nimport { stampChunkIds } from \"./chunk-ids.js\";\nimport { MAX_STACK_CHARS, type ExceptionProperties, type ExceptionSource } from \"./exception-properties.js\";\n\nexport { type ExceptionProperties, type ExceptionSource } from \"./exception-properties.js\";\n\n/** The wire `mechanism.type` for each place an exception can reach us. */\nconst MECHANISM_TYPES: Record<ExceptionSource, ExceptionMechanism[\"type\"]> = {\n \"window.onerror\": \"onerror\",\n unhandledrejection: \"unhandledrejection\",\n captureException: \"manual\",\n};\n\n/**\n * Whether this error is worth reporting at all.\n *\n * A stack made entirely of extension frames is a bug in somebody's browser\n * extension running on the page. Reporting it puts an issue in the customer's\n * list that they cannot reproduce, cannot fix, and cannot make stop.\n */\nexport function shouldDropException(properties: ExceptionProperties): boolean {\n const chain = properties.$exception_list ?? [];\n if (chain.length === 0) return false;\n return chain.every((entry) => isExtensionOnlyStack(entry.stacktrace?.frames ?? []));\n}\n\nexport function describeError(value: unknown, source: ExceptionSource): ExceptionProperties {\n const path = typeof location !== \"undefined\" ? location.pathname : \"\";\n const handled = source === \"captureException\";\n const chain = stampChunkIds(coerceToExceptionChain(value, { handled, type: MECHANISM_TYPES[source] }));\n const head = chain[0];\n\n // The flat keys describe the outermost exception — the one that escaped —\n // which is what they meant before the chain existed.\n const rawStack = value instanceof Error && value.stack ? value.stack.slice(0, MAX_STACK_CHARS) : undefined;\n\n return {\n $exception_type: head?.type ?? \"Error\",\n $exception_message: head?.value ?? \"\",\n ...(rawStack ? { $exception_stack: rawStack } : {}),\n $exception_source: source,\n $exception_handled: handled,\n $exception_list: chain,\n path,\n };\n}\n","/**\n * Keeping one broken component from becoming a denial of service.\n *\n * An `unhandledrejection` inside a render loop, or an `onerror` from a handler\n * that re-throws, fires as fast as the event loop allows. Unthrottled that is\n * thousands of identical events a second — it fills the visitor's network, the\n * customer's quota, and the issue's occurrence count with one bug.\n *\n * Per exception *type*, not globally: a page that is genuinely throwing two\n * different errors should report both, and a single runaway type must not\n * silence the other one.\n *\n * Lives in the lazily-loaded exception chunk — nothing needs it until something\n * has already thrown.\n */\nexport interface ExceptionRateLimitOptions {\n /** Burst allowance. */\n bucketSize: number;\n /** Seconds to earn one token back. */\n refillSeconds: number;\n}\n\nexport const DEFAULT_EXCEPTION_RATE_LIMIT: ExceptionRateLimitOptions = {\n bucketSize: 10,\n refillSeconds: 10,\n};\n\nexport interface ExceptionRateLimiter {\n /** True when this exception may be reported. */\n allow(type: string, now?: number): boolean;\n}\n\n/**\n * A token bucket per exception type.\n *\n * Tokens are computed from elapsed time rather than a timer: an SDK that keeps\n * an interval alive to refill a counter keeps the page alive too.\n */\nexport function createExceptionRateLimiter(options: Partial<ExceptionRateLimitOptions> = {}): ExceptionRateLimiter {\n const buckets = new Map<string, { tokens: number; updatedAt: number }>();\n const refillMs = Math.max(options.refillSeconds ?? DEFAULT_EXCEPTION_RATE_LIMIT.refillSeconds, 0.001) * 1_000;\n const size = Math.max(options.bucketSize ?? DEFAULT_EXCEPTION_RATE_LIMIT.bucketSize, 1);\n\n return {\n allow(type, now = Date.now()) {\n const bucket = buckets.get(type) ?? { tokens: size, updatedAt: now };\n const earned = Math.floor((now - bucket.updatedAt) / refillMs);\n const tokens = Math.min(size, bucket.tokens + Math.max(earned, 0));\n // Only advance the clock by the whole tokens actually earned, or a\n // steady trickle below the refill interval would never accumulate.\n const updatedAt = earned > 0 ? bucket.updatedAt + earned * refillMs : bucket.updatedAt;\n\n if (tokens <= 0) {\n buckets.set(type, { tokens, updatedAt });\n return false;\n }\n\n buckets.set(type, { tokens: tokens - 1, updatedAt });\n return true;\n },\n };\n}\n","import { describeError, shouldDropException, type ExceptionProperties } from \"./describe-error.js\";\nimport { createExceptionRateLimiter, type ExceptionRateLimitOptions } from \"./exception-rate-limit.js\";\n\n/**\n * Reports uncaught errors and unhandled promise rejections. Errors thrown by\n * the reporter itself are swallowed — an analytics SDK must never turn one\n * crash into two.\n */\nexport interface ExceptionCaptureOptions {\n /** `false` reports every exception; otherwise the token bucket to throttle by type. */\n rateLimit?: Partial<ExceptionRateLimitOptions> | false | undefined;\n /** Called once per type when throttling starts dropping, for the debug log. */\n onThrottled?: ((type: string) => void) | undefined;\n}\n\nexport function installExceptionCapture(\n report: (properties: ExceptionProperties) => void,\n options: ExceptionCaptureOptions = {}\n): () => void {\n if (typeof window === \"undefined\") return () => {};\n\n const limiter = options.rateLimit === false ? null : createExceptionRateLimiter(options.rateLimit);\n const throttled = new Set<string>();\n\n /**\n * Report unless the stack is entirely browser-extension frames, or this type\n * has burned through its budget. The throttle notice fires once per type, so\n * a storm does not also become a console storm.\n */\n const send = (properties: ExceptionProperties) => {\n if (shouldDropException(properties)) return;\n if (limiter && !limiter.allow(properties.$exception_type)) {\n if (!throttled.has(properties.$exception_type)) {\n throttled.add(properties.$exception_type);\n options.onThrottled?.(properties.$exception_type);\n }\n return;\n }\n report(properties);\n };\n const onError = (event: ErrorEvent) => {\n try {\n // Some environments deliver the message but not the Error object.\n send(describeError(event.error ?? new Error(event.message), \"window.onerror\"));\n } catch {\n // see above\n }\n };\n const onRejection = (event: PromiseRejectionEvent) => {\n try {\n send(describeError(event.reason, \"unhandledrejection\"));\n } catch {\n // see above\n }\n };\n window.addEventListener(\"error\", onError);\n window.addEventListener(\"unhandledrejection\", onRejection);\n return () => {\n window.removeEventListener(\"error\", onError);\n window.removeEventListener(\"unhandledrejection\", onRejection);\n };\n}\n\n/** Re-exported so the client can use the full describer once this chunk is loaded. */\nexport { describeError, shouldDropException } from \"./describe-error.js\";\nexport { createExceptionRateLimiter, DEFAULT_EXCEPTION_RATE_LIMIT } from \"./exception-rate-limit.js\";\n"],"mappings":"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"}
@@ -0,0 +1,289 @@
1
+ const require_registry = require("./registry-CGqrOtf4.cjs");
2
+ let _reopt_ai_data_contract_events = require("@reopt-ai/data-contract/events");
3
+ //#region ../data-sdk-core/src/stack-parsers/index.ts
4
+ const EXTENSION_PROTOCOLS = [
5
+ "chrome-extension://",
6
+ "moz-extension://",
7
+ "safari-extension://",
8
+ "safari-web-extension://"
9
+ ];
10
+ const WEBKIT_MASKED_URL = "webkit-masked-url://";
11
+ const ANONYMOUS_FILE = "<anonymous>";
12
+ function isInAppFrame(filename) {
13
+ if (!filename || filename === ANONYMOUS_FILE) return false;
14
+ if (filename.startsWith(WEBKIT_MASKED_URL)) return false;
15
+ if (EXTENSION_PROTOCOLS.some((protocol) => filename.startsWith(protocol))) return false;
16
+ return !filename.includes("/node_modules/") && !filename.startsWith("node:");
17
+ }
18
+ function isExtensionOnlyStack(frames) {
19
+ if (frames.length === 0) return false;
20
+ return frames.every((frame) => EXTENSION_PROTOCOLS.some((protocol) => (frame.filename ?? "").startsWith(protocol)));
21
+ }
22
+ const CHROME_LINE = /^\s*at (?:(.+?)\s+\()?(?:(.+?):(\d+):(\d+)|\(?([^)]*)\)?)\)?\s*$/;
23
+ const CHROME_EVAL = /\((\S*)(?::(\d+))(?::(\d+))\)/;
24
+ const GECKO_LINE = /^\s*(?:(.*?)(?:\((.*?)\))?(?:^|@))?((?:file|https?|blob|chrome|webpack|resource|moz-extension|safari-extension|safari-web-extension|capacitor|\[native).*?)(?::(\d+))?(?::(\d+))?\s*$/i;
25
+ function frame(filename, fn, lineno, colno) {
26
+ const name = fn?.trim();
27
+ return {
28
+ ...filename ? { filename } : {},
29
+ ...name ? { function: name } : {},
30
+ ...lineno ? { lineno: Number.parseInt(lineno, 10) } : {},
31
+ ...colno ? { colno: Number.parseInt(colno, 10) } : {},
32
+ in_app: isInAppFrame(filename)
33
+ };
34
+ }
35
+ function cleanV8Name(raw) {
36
+ if (!raw) return void 0;
37
+ return raw.replace(/^async\s+/, "").trim();
38
+ }
39
+ const parseChromeLine = (line) => {
40
+ const match = CHROME_LINE.exec(line);
41
+ if (!match) return void 0;
42
+ let filename = match[2];
43
+ let lineno = match[3];
44
+ let colno = match[4];
45
+ if (filename?.startsWith("eval")) {
46
+ const evalMatch = CHROME_EVAL.exec(filename);
47
+ if (evalMatch) {
48
+ filename = evalMatch[1];
49
+ lineno = evalMatch[2];
50
+ colno = evalMatch[3];
51
+ }
52
+ }
53
+ if (!filename && match[5]) return frame(void 0, cleanV8Name(match[1] ?? match[5]), void 0, void 0);
54
+ if (!filename) return void 0;
55
+ return frame(filename, cleanV8Name(match[1]), lineno, colno);
56
+ };
57
+ const parseGeckoLine = (line) => {
58
+ const match = GECKO_LINE.exec(line);
59
+ if (!match) return void 0;
60
+ const filename = match[3];
61
+ if (!filename) return void 0;
62
+ if (filename.startsWith("[native")) return frame(void 0, match[1], void 0, void 0);
63
+ const fn = match[1]?.replace(/\/[<.].*$/, "");
64
+ return frame(filename, fn, match[4], match[5]);
65
+ };
66
+ const LINE_PARSERS = [parseChromeLine, parseGeckoLine];
67
+ function parseStackString(stack) {
68
+ if (!stack) return [];
69
+ const frames = [];
70
+ for (const line of stack.split("\n")) {
71
+ if (frames.length >= _reopt_ai_data_contract_events.MAX_EXCEPTION_FRAMES) break;
72
+ if (!line.trim()) continue;
73
+ for (const parse of LINE_PARSERS) {
74
+ const parsed = parse(line);
75
+ if (!parsed) continue;
76
+ if (parsed.filename || parsed.function) frames.push(parsed);
77
+ break;
78
+ }
79
+ }
80
+ return frames;
81
+ }
82
+ //#endregion
83
+ //#region ../data-sdk-core/src/stack-parsers/coerce.ts
84
+ const MAX_MESSAGE_CHARS = 1e3;
85
+ function truncate(value) {
86
+ return value.length > MAX_MESSAGE_CHARS ? value.slice(0, MAX_MESSAGE_CHARS) : value;
87
+ }
88
+ function isErrorLike(value) {
89
+ if (value instanceof Error) return true;
90
+ const candidate = value;
91
+ return typeof candidate === "object" && candidate !== null && typeof candidate.name === "string" && typeof candidate.message === "string";
92
+ }
93
+ function constructorName(value) {
94
+ const name = value?.constructor?.name;
95
+ return typeof name === "string" && name ? name : void 0;
96
+ }
97
+ function describeObject(value) {
98
+ try {
99
+ const json = JSON.stringify(value);
100
+ if (json && json !== "{}") return truncate(json);
101
+ } catch {}
102
+ const keys = Object.keys(value);
103
+ return keys.length > 0 ? `Object with keys: ${keys.slice(0, 10).join(", ")}` : "Object";
104
+ }
105
+ function entry(type, value, mechanism, stack) {
106
+ const frames = parseStackString(stack).slice(0, _reopt_ai_data_contract_events.MAX_EXCEPTION_FRAMES);
107
+ return {
108
+ type,
109
+ value: truncate(value),
110
+ mechanism,
111
+ ...frames.length > 0 ? { stacktrace: {
112
+ frames,
113
+ type: "raw"
114
+ } } : {}
115
+ };
116
+ }
117
+ function coerceNonError(value, mechanism) {
118
+ const synthetic = {
119
+ ...mechanism,
120
+ synthetic: true
121
+ };
122
+ if (typeof value === "string") return entry("Error", value, synthetic);
123
+ if (value === null) return entry("Error", "null", synthetic);
124
+ if (value === void 0) return entry("Error", "undefined", synthetic);
125
+ if (typeof value !== "object") return entry("Error", `${typeof value}: ${String(value)}`, synthetic);
126
+ const name = constructorName(value);
127
+ const record = value;
128
+ if (name === "ErrorEvent" && typeof record.message === "string") {
129
+ const where = [
130
+ record.filename,
131
+ record.lineno,
132
+ record.colno
133
+ ].filter(Boolean).join(":");
134
+ return entry("ErrorEvent", where ? `${record.message} (${where})` : record.message, synthetic);
135
+ }
136
+ if (typeof record.type === "string" && typeof record.preventDefault === "function") return entry(name ?? "Event", `Event of type "${record.type}" was thrown`, synthetic);
137
+ return entry(name && name !== "Object" ? name : "Error", describeObject(value), synthetic);
138
+ }
139
+ function coerceToExceptionChain(value, mechanism) {
140
+ const chain = [];
141
+ const seen = new Set();
142
+ let current = value;
143
+ let isOutermost = true;
144
+ while (chain.length < _reopt_ai_data_contract_events.MAX_EXCEPTION_CHAIN) {
145
+ if (!isOutermost && current === void 0) break;
146
+ if (typeof current === "object" && current !== null) {
147
+ if (seen.has(current)) break;
148
+ seen.add(current);
149
+ }
150
+ const linkMechanism = isOutermost ? mechanism : {
151
+ ...mechanism,
152
+ handled: true
153
+ };
154
+ if (isErrorLike(current)) {
155
+ chain.push(entry(current.name || "Error", current.message, linkMechanism, current.stack));
156
+ current = current.cause;
157
+ } else {
158
+ chain.push(coerceNonError(current, linkMechanism));
159
+ break;
160
+ }
161
+ isOutermost = false;
162
+ }
163
+ return chain;
164
+ }
165
+ //#endregion
166
+ //#region src/capture/chunk-ids.ts
167
+ function fileNameOf(filename) {
168
+ const withoutQuery = filename.split(/[?#]/)[0] ?? filename;
169
+ return withoutQuery.split("/").pop() ?? withoutQuery;
170
+ }
171
+ function chunkIds() {
172
+ const map = globalThis._reoptChunkIds;
173
+ return map && typeof map === "object" ? map : void 0;
174
+ }
175
+ function stampChunkIds(chain) {
176
+ const map = chunkIds();
177
+ if (!map) return chain;
178
+ for (const entry of chain) for (const frame of entry.stacktrace?.frames ?? []) {
179
+ if (!frame.filename || frame.chunk_id) continue;
180
+ const id = map[fileNameOf(frame.filename)];
181
+ if (typeof id === "string" && id) frame.chunk_id = id;
182
+ }
183
+ return chain;
184
+ }
185
+ //#endregion
186
+ //#region src/capture/describe-error.ts
187
+ const MECHANISM_TYPES = {
188
+ "window.onerror": "onerror",
189
+ unhandledrejection: "unhandledrejection",
190
+ captureException: "manual"
191
+ };
192
+ function shouldDropException(properties) {
193
+ const chain = properties.$exception_list ?? [];
194
+ if (chain.length === 0) return false;
195
+ return chain.every((entry) => isExtensionOnlyStack(entry.stacktrace?.frames ?? []));
196
+ }
197
+ function describeError(value, source) {
198
+ const path = typeof location !== "undefined" ? location.pathname : "";
199
+ const handled = source === "captureException";
200
+ const chain = stampChunkIds(coerceToExceptionChain(value, {
201
+ handled,
202
+ type: MECHANISM_TYPES[source]
203
+ }));
204
+ const head = chain[0];
205
+ const rawStack = value instanceof Error && value.stack ? value.stack.slice(0, require_registry.MAX_STACK_CHARS) : void 0;
206
+ return {
207
+ $exception_type: head?.type ?? "Error",
208
+ $exception_message: head?.value ?? "",
209
+ ...rawStack ? { $exception_stack: rawStack } : {},
210
+ $exception_source: source,
211
+ $exception_handled: handled,
212
+ $exception_list: chain,
213
+ path
214
+ };
215
+ }
216
+ //#endregion
217
+ //#region src/capture/exception-rate-limit.ts
218
+ const DEFAULT_EXCEPTION_RATE_LIMIT = {
219
+ bucketSize: 10,
220
+ refillSeconds: 10
221
+ };
222
+ function createExceptionRateLimiter(options = {}) {
223
+ const buckets = new Map();
224
+ const refillMs = Math.max(options.refillSeconds ?? DEFAULT_EXCEPTION_RATE_LIMIT.refillSeconds, .001) * 1e3;
225
+ const size = Math.max(options.bucketSize ?? DEFAULT_EXCEPTION_RATE_LIMIT.bucketSize, 1);
226
+ return { allow(type, now = Date.now()) {
227
+ const bucket = buckets.get(type) ?? {
228
+ tokens: size,
229
+ updatedAt: now
230
+ };
231
+ const earned = Math.floor((now - bucket.updatedAt) / refillMs);
232
+ const tokens = Math.min(size, bucket.tokens + Math.max(earned, 0));
233
+ const updatedAt = earned > 0 ? bucket.updatedAt + earned * refillMs : bucket.updatedAt;
234
+ if (tokens <= 0) {
235
+ buckets.set(type, {
236
+ tokens,
237
+ updatedAt
238
+ });
239
+ return false;
240
+ }
241
+ buckets.set(type, {
242
+ tokens: tokens - 1,
243
+ updatedAt
244
+ });
245
+ return true;
246
+ } };
247
+ }
248
+ //#endregion
249
+ //#region src/capture/exceptions.ts
250
+ function installExceptionCapture(report, options = {}) {
251
+ if (typeof window === "undefined") return () => {};
252
+ const limiter = options.rateLimit === false ? null : createExceptionRateLimiter(options.rateLimit);
253
+ const throttled = new Set();
254
+ const send = (properties) => {
255
+ if (shouldDropException(properties)) return;
256
+ if (limiter && !limiter.allow(properties.$exception_type)) {
257
+ if (!throttled.has(properties.$exception_type)) {
258
+ throttled.add(properties.$exception_type);
259
+ options.onThrottled?.(properties.$exception_type);
260
+ }
261
+ return;
262
+ }
263
+ report(properties);
264
+ };
265
+ const onError = (event) => {
266
+ try {
267
+ send(describeError(event.error ?? new Error(event.message), "window.onerror"));
268
+ } catch {}
269
+ };
270
+ const onRejection = (event) => {
271
+ try {
272
+ send(describeError(event.reason, "unhandledrejection"));
273
+ } catch {}
274
+ };
275
+ window.addEventListener("error", onError);
276
+ window.addEventListener("unhandledrejection", onRejection);
277
+ return () => {
278
+ window.removeEventListener("error", onError);
279
+ window.removeEventListener("unhandledrejection", onRejection);
280
+ };
281
+ }
282
+ //#endregion
283
+ exports.DEFAULT_EXCEPTION_RATE_LIMIT = DEFAULT_EXCEPTION_RATE_LIMIT;
284
+ exports.createExceptionRateLimiter = createExceptionRateLimiter;
285
+ exports.describeError = describeError;
286
+ exports.installExceptionCapture = installExceptionCapture;
287
+ exports.shouldDropException = shouldDropException;
288
+
289
+ //# sourceMappingURL=exceptions-CuhGo9A5.cjs.map