@fixback/sdk-core 0.2.0 → 0.3.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 +28 -9
- package/{src/annotation.ts → dist/annotation.d.ts} +36 -47
- package/dist/anonymous-id.d.ts +23 -0
- package/dist/anonymous-id.js +39 -0
- package/dist/anonymous-id.js.map +1 -0
- package/dist/auto-capture.d.ts +129 -0
- package/dist/auto-capture.js +210 -0
- package/dist/auto-capture.js.map +1 -0
- package/{src/backoff.ts → dist/backoff.d.ts} +17 -52
- package/dist/boot.d.ts +148 -0
- package/dist/boot.js +113 -0
- package/dist/boot.js.map +1 -0
- package/dist/breadcrumb.d.ts +133 -0
- package/dist/connect.d.ts +110 -0
- package/dist/connect.js +147 -0
- package/dist/connect.js.map +1 -0
- package/dist/env.d.ts +37 -0
- package/dist/env.js +83 -0
- package/dist/env.js.map +1 -0
- package/dist/fingerprint.d.ts +39 -0
- package/dist/fingerprint.js +10 -15
- package/dist/fingerprint.js.map +1 -1
- package/dist/http.d.ts +51 -0
- package/dist/http.js +42 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +115 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1057 -0
- package/dist/index.mjs.map +7 -0
- package/dist/options.d.ts +82 -0
- package/dist/options.js +22 -0
- package/dist/options.js.map +1 -0
- package/dist/release.d.ts +19 -0
- package/dist/release.js +36 -0
- package/dist/release.js.map +1 -0
- package/dist/scrub.d.ts +62 -0
- package/dist/stack.d.ts +51 -0
- package/dist/stack.js +97 -0
- package/dist/stack.js.map +1 -0
- package/dist/trace/buffer.d.ts +121 -0
- package/dist/trace/buffer.js +230 -0
- package/dist/trace/buffer.js.map +1 -0
- package/dist/trace/console-args.d.ts +60 -0
- package/dist/trace/console-args.js +189 -0
- package/dist/trace/console-args.js.map +1 -0
- package/dist/trace/console.d.ts +42 -0
- package/dist/trace/console.js +71 -0
- package/dist/trace/console.js.map +1 -0
- package/dist/trace/crumbs.d.ts +88 -0
- package/dist/trace/crumbs.js +164 -0
- package/dist/trace/crumbs.js.map +1 -0
- package/dist/trace/source.d.ts +30 -0
- package/dist/trace/source.js +59 -0
- package/dist/trace/source.js.map +1 -0
- package/dist/version.d.ts +13 -0
- package/dist/version.js +17 -0
- package/dist/version.js.map +1 -0
- package/dist/wire.d.ts +101 -0
- package/package.json +12 -8
- package/src/backoff.test.ts +0 -94
- package/src/breadcrumb.ts +0 -169
- package/src/fingerprint.test.ts +0 -96
- package/src/fingerprint.ts +0 -112
- package/src/index.ts +0 -63
- package/src/scrub.test.ts +0 -215
- package/src/scrub.ts +0 -226
- package/src/wire.ts +0 -116
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Structured **console arguments** (spec #122 §C, decision D7) — the shared,
|
|
4
|
+
* runtime-agnostic assembly that turns a `console.*` call's arguments into
|
|
5
|
+
* type-tagged, JSON-safe, size-capped {@link ConsoleArg} values, plus the one-line
|
|
6
|
+
* preview the crumb's `message` carries.
|
|
7
|
+
*
|
|
8
|
+
* Preserving arguments type-tagged rather than flattening them to a string is what
|
|
9
|
+
* lets the Console tab render an object or an Error expandably instead of
|
|
10
|
+
* `[object Object]`. Every cap is applied **at assembly**, so a single console
|
|
11
|
+
* crumb can never bloat a report and an exotic or circular value can never reach
|
|
12
|
+
* the wire unserialized.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.MAX_CONSOLE_ARGS_BYTES = exports.MAX_ARG_STRING_LENGTH = exports.MAX_ARG_ITEMS = exports.MAX_ARG_DEPTH = exports.MAX_MESSAGE_LENGTH = void 0;
|
|
16
|
+
exports.capLength = capLength;
|
|
17
|
+
exports.stringifyArg = stringifyArg;
|
|
18
|
+
exports.joinArgs = joinArgs;
|
|
19
|
+
exports.describeErrorValue = describeErrorValue;
|
|
20
|
+
exports.safeCloneValue = safeCloneValue;
|
|
21
|
+
exports.toConsoleArg = toConsoleArg;
|
|
22
|
+
exports.capConsoleArgs = capConsoleArgs;
|
|
23
|
+
const env_1 = require("../env");
|
|
24
|
+
/** Longest crumb message kept; a huge log line is truncated, never dropped. */
|
|
25
|
+
exports.MAX_MESSAGE_LENGTH = 300;
|
|
26
|
+
/**
|
|
27
|
+
* Structured console argument caps (spec #122 §C/§F), all applied **at assembly** so a
|
|
28
|
+
* single console crumb can never bloat a report:
|
|
29
|
+
* - {@link MAX_ARG_DEPTH} bounds how deep a `json` argument is cloned (deeper nodes
|
|
30
|
+
* collapse to an `[Object]`/`[Array]` marker);
|
|
31
|
+
* - {@link MAX_ARG_ITEMS} bounds how many keys/elements are kept at each level;
|
|
32
|
+
* - {@link MAX_ARG_STRING_LENGTH} truncates a single over-long string value;
|
|
33
|
+
* - {@link MAX_CONSOLE_ARGS_BYTES} bounds the serialized size of the whole args array
|
|
34
|
+
* (trailing args are dropped to fit), kept well under ingest's per-entry byte cap.
|
|
35
|
+
*/
|
|
36
|
+
exports.MAX_ARG_DEPTH = 4;
|
|
37
|
+
exports.MAX_ARG_ITEMS = 100;
|
|
38
|
+
exports.MAX_ARG_STRING_LENGTH = 1024;
|
|
39
|
+
exports.MAX_CONSOLE_ARGS_BYTES = 4096;
|
|
40
|
+
/** Longest Error `stack` kept on a structured `error` arg, truncated never dropped. */
|
|
41
|
+
const MAX_ERROR_STACK_LENGTH = 2048;
|
|
42
|
+
/** Truncate a string to `max` with an ellipsis marker; keeps the value, never drops it. */
|
|
43
|
+
function capLength(value, max) {
|
|
44
|
+
return value.length > max ? `${value.slice(0, max)}…` : value;
|
|
45
|
+
}
|
|
46
|
+
/** Render one console argument to the flat text of the crumb's preview line. */
|
|
47
|
+
function stringifyArg(arg) {
|
|
48
|
+
if (typeof arg === "string")
|
|
49
|
+
return arg;
|
|
50
|
+
if (arg instanceof Error)
|
|
51
|
+
return `${arg.name}: ${arg.message}`;
|
|
52
|
+
if (arg === null || arg === undefined)
|
|
53
|
+
return String(arg);
|
|
54
|
+
if (typeof arg === "number" || typeof arg === "boolean")
|
|
55
|
+
return String(arg);
|
|
56
|
+
try {
|
|
57
|
+
return JSON.stringify(arg) ?? String(arg);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return "[object]";
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** The one-line preview a console crumb's `message` carries, length-capped. */
|
|
64
|
+
function joinArgs(args) {
|
|
65
|
+
const text = args.map(stringifyArg).join(" ");
|
|
66
|
+
return text.length > exports.MAX_MESSAGE_LENGTH
|
|
67
|
+
? `${text.slice(0, exports.MAX_MESSAGE_LENGTH)}…`
|
|
68
|
+
: text;
|
|
69
|
+
}
|
|
70
|
+
/** An Error rendered to a structured, size-capped `{ name, message, stack? }`. */
|
|
71
|
+
function describeErrorValue(error) {
|
|
72
|
+
const out = {
|
|
73
|
+
name: error.name || "Error",
|
|
74
|
+
message: capLength(String(error.message ?? ""), exports.MAX_ARG_STRING_LENGTH),
|
|
75
|
+
};
|
|
76
|
+
if (typeof error.stack === "string" && error.stack.length > 0) {
|
|
77
|
+
out.stack = capLength(error.stack, MAX_ERROR_STACK_LENGTH);
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Build a JSON-safe, depth-/breadth-/string-capped clone of a value for a `json`
|
|
83
|
+
* console argument. Beyond {@link MAX_ARG_DEPTH} the node collapses to a marker;
|
|
84
|
+
* at each level at most {@link MAX_ARG_ITEMS} keys/elements are kept; strings are
|
|
85
|
+
* truncated to {@link MAX_ARG_STRING_LENGTH}; circular references become
|
|
86
|
+
* `"[Circular]"`; and exotic values (bigint / symbol / function / undefined) are
|
|
87
|
+
* rendered to safe text — so the result is always serializable and bounded.
|
|
88
|
+
*/
|
|
89
|
+
function safeCloneValue(value, depth, seen) {
|
|
90
|
+
if (value === null)
|
|
91
|
+
return null;
|
|
92
|
+
const type = typeof value;
|
|
93
|
+
if (type === "string")
|
|
94
|
+
return capLength(value, exports.MAX_ARG_STRING_LENGTH);
|
|
95
|
+
if (type === "number")
|
|
96
|
+
return Number.isFinite(value) ? value : String(value);
|
|
97
|
+
if (type === "boolean")
|
|
98
|
+
return value;
|
|
99
|
+
if (type === "bigint")
|
|
100
|
+
return `${value.toString()}n`;
|
|
101
|
+
if (type === "symbol")
|
|
102
|
+
return value.toString();
|
|
103
|
+
if (type === "function")
|
|
104
|
+
return "[Function]";
|
|
105
|
+
if (type === "undefined")
|
|
106
|
+
return null;
|
|
107
|
+
const obj = value;
|
|
108
|
+
if (value instanceof Error) {
|
|
109
|
+
const { name, message } = describeErrorValue(value);
|
|
110
|
+
return { name, message };
|
|
111
|
+
}
|
|
112
|
+
if (seen.has(obj))
|
|
113
|
+
return "[Circular]";
|
|
114
|
+
if (depth <= 0)
|
|
115
|
+
return Array.isArray(value) ? "[Array]" : "[Object]";
|
|
116
|
+
seen.add(obj);
|
|
117
|
+
try {
|
|
118
|
+
if (Array.isArray(value)) {
|
|
119
|
+
const items = value
|
|
120
|
+
.slice(0, exports.MAX_ARG_ITEMS)
|
|
121
|
+
.map((item) => safeCloneValue(item, depth - 1, seen));
|
|
122
|
+
if (value.length > exports.MAX_ARG_ITEMS) {
|
|
123
|
+
items.push(`… ${value.length - exports.MAX_ARG_ITEMS} more`);
|
|
124
|
+
}
|
|
125
|
+
return items;
|
|
126
|
+
}
|
|
127
|
+
const source = value;
|
|
128
|
+
const keys = Object.keys(source);
|
|
129
|
+
const out = {};
|
|
130
|
+
for (const key of keys.slice(0, exports.MAX_ARG_ITEMS)) {
|
|
131
|
+
const child = source[key];
|
|
132
|
+
// Undefined / function values JSON drops anyway — omit them for a clean clone.
|
|
133
|
+
if (typeof child === "undefined" || typeof child === "function")
|
|
134
|
+
continue;
|
|
135
|
+
out[key] = safeCloneValue(child, depth - 1, seen);
|
|
136
|
+
}
|
|
137
|
+
if (keys.length > exports.MAX_ARG_ITEMS)
|
|
138
|
+
out["…"] = `${keys.length - exports.MAX_ARG_ITEMS} more`;
|
|
139
|
+
return out;
|
|
140
|
+
}
|
|
141
|
+
finally {
|
|
142
|
+
seen.delete(obj);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** Classify one console argument into a type-tagged {@link ConsoleArg} (spec #122 §C). */
|
|
146
|
+
function toConsoleArg(value) {
|
|
147
|
+
if (value === null || value === undefined)
|
|
148
|
+
return { t: "null", v: null };
|
|
149
|
+
const type = typeof value;
|
|
150
|
+
if (type === "string") {
|
|
151
|
+
return { t: "string", v: capLength(value, exports.MAX_ARG_STRING_LENGTH) };
|
|
152
|
+
}
|
|
153
|
+
if (type === "number") {
|
|
154
|
+
return Number.isFinite(value)
|
|
155
|
+
? { t: "number", v: value }
|
|
156
|
+
: { t: "string", v: String(value) };
|
|
157
|
+
}
|
|
158
|
+
if (type === "boolean")
|
|
159
|
+
return { t: "bool", v: value };
|
|
160
|
+
if (type === "bigint")
|
|
161
|
+
return { t: "string", v: `${value.toString()}n` };
|
|
162
|
+
if (type === "symbol")
|
|
163
|
+
return { t: "string", v: value.toString() };
|
|
164
|
+
if (type === "function")
|
|
165
|
+
return { t: "string", v: "[Function]" };
|
|
166
|
+
if (value instanceof Error)
|
|
167
|
+
return { t: "error", v: describeErrorValue(value) };
|
|
168
|
+
return { t: "json", v: safeCloneValue(value, exports.MAX_ARG_DEPTH, new Set()) };
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Cap an entry's structured args to {@link MAX_CONSOLE_ARGS_BYTES} (spec #122 §F):
|
|
172
|
+
* drop trailing args until the array fits, keeping the earliest (usually the format
|
|
173
|
+
* string / main message); if even a single arg is over budget, keep one honest
|
|
174
|
+
* placeholder rather than an unbounded value. Per-arg depth/breadth/string caps bound
|
|
175
|
+
* most cases already — this is the whole-entry backstop.
|
|
176
|
+
*/
|
|
177
|
+
function capConsoleArgs(args) {
|
|
178
|
+
if ((0, env_1.serializedBytes)(args) <= exports.MAX_CONSOLE_ARGS_BYTES)
|
|
179
|
+
return args;
|
|
180
|
+
let out = args.slice();
|
|
181
|
+
while (out.length > 1 && (0, env_1.serializedBytes)(out) > exports.MAX_CONSOLE_ARGS_BYTES) {
|
|
182
|
+
out = out.slice(0, -1);
|
|
183
|
+
}
|
|
184
|
+
if (out.length === 1 && (0, env_1.serializedBytes)(out) > exports.MAX_CONSOLE_ARGS_BYTES) {
|
|
185
|
+
return [{ t: "string", v: "[trace: console argument omitted (too large)]" }];
|
|
186
|
+
}
|
|
187
|
+
return out;
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=console-args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console-args.js","sourceRoot":"","sources":["../../src/trace/console-args.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The **console instrumentation** (spec #122 §C) — the one wrapper both the browser
|
|
3
|
+
* and React Native SDKs install (ADR-0028).
|
|
4
|
+
*
|
|
5
|
+
* It patches the injected `console` object's level methods so each call becomes a
|
|
6
|
+
* crumb before the original runs. The console surface is a parameter, never read
|
|
7
|
+
* off a global here, so the core stays runtime-agnostic and tests pass a plain
|
|
8
|
+
* object. Capture must never throw into the host app: a failure recording a crumb
|
|
9
|
+
* is swallowed and the original `console` method always runs.
|
|
10
|
+
*/
|
|
11
|
+
import type { BreadcrumbLevel } from "../breadcrumb";
|
|
12
|
+
import { type BreadcrumbBuffer } from "./buffer";
|
|
13
|
+
/** Detaches an installed instrumentation, restoring the original behaviour. */
|
|
14
|
+
export type Teardown = () => void;
|
|
15
|
+
/**
|
|
16
|
+
* The `console` surface the wrapper patches — injected, never read off a global
|
|
17
|
+
* here.
|
|
18
|
+
*
|
|
19
|
+
* Declared as optional **methods** rather than a `Partial<Record<Level, Fn>>` of
|
|
20
|
+
* function-typed properties, deliberately: method signatures are bivariant in
|
|
21
|
+
* their parameters, so a real DOM `Console` — whose `assert` is overloaded with a
|
|
22
|
+
* leading `condition?: boolean` — satisfies this directly. That is what lets the
|
|
23
|
+
* browser SDK pass `console` with no cast at all.
|
|
24
|
+
*/
|
|
25
|
+
export interface ConsoleLike {
|
|
26
|
+
log?(...args: unknown[]): unknown;
|
|
27
|
+
info?(...args: unknown[]): unknown;
|
|
28
|
+
warn?(...args: unknown[]): unknown;
|
|
29
|
+
error?(...args: unknown[]): unknown;
|
|
30
|
+
assert?(...args: unknown[]): unknown;
|
|
31
|
+
debug?(...args: unknown[]): unknown;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Wrap `console` methods so calls at the captured levels become crumbs, returning a
|
|
35
|
+
* teardown that restores every method it replaced.
|
|
36
|
+
*
|
|
37
|
+
* Whether a level pays the source-capture cost is decided **once per level**, not per
|
|
38
|
+
* call: only `warn`/`error`/`assert` construct a `new Error()` to read the call site,
|
|
39
|
+
* so a tight `log` loop stays cheap (ticket #159; see `SOURCE_CAPTURE_LEVELS`).
|
|
40
|
+
* `console.assert` records only when the asserted condition is falsy.
|
|
41
|
+
*/
|
|
42
|
+
export declare function instrumentConsole(buffer: BreadcrumbBuffer, consoleObj: ConsoleLike, levels: readonly BreadcrumbLevel[], now: () => number): Teardown;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The **console instrumentation** (spec #122 §C) — the one wrapper both the browser
|
|
4
|
+
* and React Native SDKs install (ADR-0028).
|
|
5
|
+
*
|
|
6
|
+
* It patches the injected `console` object's level methods so each call becomes a
|
|
7
|
+
* crumb before the original runs. The console surface is a parameter, never read
|
|
8
|
+
* off a global here, so the core stays runtime-agnostic and tests pass a plain
|
|
9
|
+
* object. Capture must never throw into the host app: a failure recording a crumb
|
|
10
|
+
* is swallowed and the original `console` method always runs.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.instrumentConsole = instrumentConsole;
|
|
14
|
+
const buffer_1 = require("./buffer");
|
|
15
|
+
const crumbs_1 = require("./crumbs");
|
|
16
|
+
const source_1 = require("./source");
|
|
17
|
+
/**
|
|
18
|
+
* Wrap `console` methods so calls at the captured levels become crumbs, returning a
|
|
19
|
+
* teardown that restores every method it replaced.
|
|
20
|
+
*
|
|
21
|
+
* Whether a level pays the source-capture cost is decided **once per level**, not per
|
|
22
|
+
* call: only `warn`/`error`/`assert` construct a `new Error()` to read the call site,
|
|
23
|
+
* so a tight `log` loop stays cheap (ticket #159; see `SOURCE_CAPTURE_LEVELS`).
|
|
24
|
+
* `console.assert` records only when the asserted condition is falsy.
|
|
25
|
+
*/
|
|
26
|
+
function instrumentConsole(buffer, consoleObj, levels, now) {
|
|
27
|
+
const restores = [];
|
|
28
|
+
for (const level of levels) {
|
|
29
|
+
const original = consoleObj[level];
|
|
30
|
+
if (typeof original !== "function")
|
|
31
|
+
continue;
|
|
32
|
+
const withSource = (0, buffer_1.capturesSource)(level);
|
|
33
|
+
const wrapper = (...args) => {
|
|
34
|
+
// Capture the call site before anything else so the wrapper is the top frame —
|
|
35
|
+
// but only for the levels that keep a source (the hot-page budget, ticket #159).
|
|
36
|
+
let source;
|
|
37
|
+
if (withSource) {
|
|
38
|
+
try {
|
|
39
|
+
source = (0, source_1.sourceFromStack)(new Error().stack, source_1.CONSOLE_SOURCE_SKIP_FRAMES);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
source = undefined;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
if (level === "assert") {
|
|
47
|
+
// console.assert records only when the asserted condition is falsy.
|
|
48
|
+
if (!args[0]) {
|
|
49
|
+
buffer.add((0, crumbs_1.consoleCrumb)("assert", args.slice(1), now(), source));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
buffer.add((0, crumbs_1.consoleCrumb)(level, args, now(), source));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Capture must never throw into the host app.
|
|
58
|
+
}
|
|
59
|
+
return original.apply(consoleObj, args);
|
|
60
|
+
};
|
|
61
|
+
consoleObj[level] = wrapper;
|
|
62
|
+
restores.push(() => {
|
|
63
|
+
consoleObj[level] = original;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return () => {
|
|
67
|
+
for (const restore of restores)
|
|
68
|
+
restore();
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=console.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console.js","sourceRoot":"","sources":["../../src/trace/console.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;AAuCH,8CA4CC;AA/ED,qCAAiE;AACjE,qCAAwC;AACxC,qCAAuE;AAwBvE;;;;;;;;GAQG;AACH,SAAgB,iBAAiB,CAC/B,MAAwB,EACxB,UAAuB,EACvB,MAAkC,EAClC,GAAiB;IAEjB,MAAM,QAAQ,GAAe,EAAE,CAAC;IAChC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,OAAO,QAAQ,KAAK,UAAU;YAAE,SAAS;QAC7C,MAAM,UAAU,GAAG,IAAA,uBAAc,EAAC,KAAK,CAAC,CAAC;QACzC,MAAM,OAAO,GAAG,CAAC,GAAG,IAAe,EAAW,EAAE;YAC9C,+EAA+E;YAC/E,iFAAiF;YACjF,IAAI,MAAkC,CAAC;YACvC,IAAI,UAAU,EAAE,CAAC;gBACf,IAAI,CAAC;oBACH,MAAM,GAAG,IAAA,wBAAe,EAAC,IAAI,KAAK,EAAE,CAAC,KAAK,EAAE,mCAA0B,CAAC,CAAC;gBAC1E,CAAC;gBAAC,MAAM,CAAC;oBACP,MAAM,GAAG,SAAS,CAAC;gBACrB,CAAC;YACH,CAAC;YACD,IAAI,CAAC;gBACH,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;oBACvB,oEAAoE;oBACpE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;wBACb,MAAM,CAAC,GAAG,CAAC,IAAA,qBAAY,EAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;oBACnE,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,GAAG,CAAC,IAAA,qBAAY,EAAC,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;gBACvD,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,8CAA8C;YAChD,CAAC;YACD,OAAO,QAAQ,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC1C,CAAC,CAAC;QACF,UAAU,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC;QAC5B,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE;YACjB,UAAU,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC;QAC/B,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,EAAE;QACV,KAAK,MAAM,OAAO,IAAI,QAAQ;YAAE,OAAO,EAAE,CAAC;IAC5C,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pure **crumb builders** (spec #122 §C/§D/§F) — the shared, runtime-agnostic
|
|
3
|
+
* constructors every capture SDK assembles trace entries with (ADR-0028), so the
|
|
4
|
+
* server and dashboard cannot tell a mobile trace from a web one.
|
|
5
|
+
*
|
|
6
|
+
* Everything private is kept out **at the source**: a network crumb has no field
|
|
7
|
+
* for a request/response body or an arbitrary header, and every URL is scrubbed
|
|
8
|
+
* (query dropped, path PII redacted) and length-capped as the crumb is built. The
|
|
9
|
+
* `beforeSend` choke point (`../scrub`) is the final gate over the whole report.
|
|
10
|
+
*
|
|
11
|
+
* The two DOM-shaped builders — `ui.click` and `ui.input`, which need an `Element`
|
|
12
|
+
* to derive a masked selector from — stay in the browser SDK; every crumb kind a
|
|
13
|
+
* non-browser runtime can also produce lives here.
|
|
14
|
+
*/
|
|
15
|
+
import type { Breadcrumb, BreadcrumbLevel, NetworkApi, NetworkOutcome, SourceLocation } from "../breadcrumb";
|
|
16
|
+
/**
|
|
17
|
+
* Longest scrubbed URL kept on a crumb (spec #122 §F): capped at assembly so an
|
|
18
|
+
* over-long URL is truncated, never dropped and never allowed to bloat a report.
|
|
19
|
+
*/
|
|
20
|
+
export declare const MAX_URL_LENGTH = 2048;
|
|
21
|
+
/**
|
|
22
|
+
* A `console` crumb from a captured call's level and arguments (spec #122 §C). The
|
|
23
|
+
* `message` is the one-line preview (flattened, truncated); `args` preserves each
|
|
24
|
+
* argument as a structured, type-tagged, size-capped value so the Console tab can
|
|
25
|
+
* render objects/errors expandably; `source` is the best-effort `file:line`, attached
|
|
26
|
+
* only when the stack yielded one. Args are omitted entirely for a no-argument call.
|
|
27
|
+
*/
|
|
28
|
+
export declare function consoleCrumb(level: BreadcrumbLevel, args: readonly unknown[], timestamp: number, source?: SourceLocation): Breadcrumb;
|
|
29
|
+
/**
|
|
30
|
+
* A `navigation` crumb; both URLs are scrubbed and length-capped as the crumb is
|
|
31
|
+
* built. In a browser these come from `history`/`hashchange`; on mobile from the
|
|
32
|
+
* host app's `trackScreen` calls (spec 0004 §D), where the values are screen URLs
|
|
33
|
+
* derived from the configured origin.
|
|
34
|
+
*/
|
|
35
|
+
export declare function navigationCrumb(from: string, to: string, timestamp: number): Breadcrumb;
|
|
36
|
+
/**
|
|
37
|
+
* Classify an HTTP status into a {@link NetworkOutcome} (spec #122 §D). A missing or
|
|
38
|
+
* `0` status is a `network-error` (a request that never got a response); otherwise
|
|
39
|
+
* the 4xx/5xx classes flag failures and everything else is `ok`. Used both as the
|
|
40
|
+
* fallback outcome and by the thin {@link fetchCrumb} / {@link xhrCrumb} builders.
|
|
41
|
+
*/
|
|
42
|
+
export declare function outcomeFromStatus(status: number | undefined): NetworkOutcome;
|
|
43
|
+
/** Parse a `content-length` header into a non-negative byte count, or `undefined`. */
|
|
44
|
+
export declare function parseContentLength(value: string | null | undefined): number | undefined;
|
|
45
|
+
/** The media type from a `content-type` header (the part before any `;` parameters). */
|
|
46
|
+
export declare function contentTypeOf(value: string | null | undefined): string | undefined;
|
|
47
|
+
/** The rich metadata a network crumb records (spec #122 §D) — never a body or header. */
|
|
48
|
+
export interface NetworkCrumbInput {
|
|
49
|
+
readonly api: NetworkApi;
|
|
50
|
+
readonly method: string;
|
|
51
|
+
/** The raw request URL — scrubbed (query dropped, path PII redacted) as the crumb is built. */
|
|
52
|
+
readonly url: string;
|
|
53
|
+
readonly status?: number;
|
|
54
|
+
readonly statusText?: string;
|
|
55
|
+
readonly durationMs?: number;
|
|
56
|
+
readonly reqSize?: number;
|
|
57
|
+
readonly respSize?: number;
|
|
58
|
+
readonly contentType?: string;
|
|
59
|
+
readonly outcome: NetworkOutcome;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A network crumb (`fetch` / `xhr` / `beacon`) with the rich, metadata-only fields
|
|
63
|
+
* the Network tab renders (spec #122 §D, ticket #139): api, method, scrubbed URL,
|
|
64
|
+
* status + statusText, duration, request/response sizes, content type, and a failure
|
|
65
|
+
* outcome. The URL is scrubbed and length-capped at assembly. The shape has **no field
|
|
66
|
+
* for a request/response body or an arbitrary header**, so neither can ever be
|
|
67
|
+
* recorded; only a positive status, and fields that were actually supplied, ride along.
|
|
68
|
+
*/
|
|
69
|
+
export declare function networkCrumb(input: NetworkCrumbInput, timestamp: number): Breadcrumb;
|
|
70
|
+
/**
|
|
71
|
+
* A thin `fetch` crumb from method + URL + status (outcome derived from the status).
|
|
72
|
+
* The instrumentation uses {@link networkCrumb} directly to carry the full metadata;
|
|
73
|
+
* this convenience builder seeds a network crumb from a status alone.
|
|
74
|
+
*/
|
|
75
|
+
export declare function fetchCrumb(method: string, url: string, status: number | undefined, timestamp: number): Breadcrumb;
|
|
76
|
+
/** A thin `xhr` crumb from method + URL + status (outcome derived from the status). */
|
|
77
|
+
export declare function xhrCrumb(method: string, url: string, status: number | undefined, timestamp: number): Breadcrumb;
|
|
78
|
+
/** Distil any thrown value into the `{ name, message }` an error crumb reads. */
|
|
79
|
+
export declare function describeError(error: unknown): {
|
|
80
|
+
name: string;
|
|
81
|
+
message: string;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* An `error` crumb for the failing exception or rejection that ends the trace. When
|
|
85
|
+
* `causedBy` is given (an auto-captured error), it rides on the crumb as the causal
|
|
86
|
+
* pointer to the ids of the entries immediately preceding the throw (spec #122 §F).
|
|
87
|
+
*/
|
|
88
|
+
export declare function errorCrumb(error: unknown, timestamp: number, causedBy?: readonly string[]): Breadcrumb;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The pure **crumb builders** (spec #122 §C/§D/§F) — the shared, runtime-agnostic
|
|
4
|
+
* constructors every capture SDK assembles trace entries with (ADR-0028), so the
|
|
5
|
+
* server and dashboard cannot tell a mobile trace from a web one.
|
|
6
|
+
*
|
|
7
|
+
* Everything private is kept out **at the source**: a network crumb has no field
|
|
8
|
+
* for a request/response body or an arbitrary header, and every URL is scrubbed
|
|
9
|
+
* (query dropped, path PII redacted) and length-capped as the crumb is built. The
|
|
10
|
+
* `beforeSend` choke point (`../scrub`) is the final gate over the whole report.
|
|
11
|
+
*
|
|
12
|
+
* The two DOM-shaped builders — `ui.click` and `ui.input`, which need an `Element`
|
|
13
|
+
* to derive a masked selector from — stay in the browser SDK; every crumb kind a
|
|
14
|
+
* non-browser runtime can also produce lives here.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.MAX_URL_LENGTH = void 0;
|
|
18
|
+
exports.consoleCrumb = consoleCrumb;
|
|
19
|
+
exports.navigationCrumb = navigationCrumb;
|
|
20
|
+
exports.outcomeFromStatus = outcomeFromStatus;
|
|
21
|
+
exports.parseContentLength = parseContentLength;
|
|
22
|
+
exports.contentTypeOf = contentTypeOf;
|
|
23
|
+
exports.networkCrumb = networkCrumb;
|
|
24
|
+
exports.fetchCrumb = fetchCrumb;
|
|
25
|
+
exports.xhrCrumb = xhrCrumb;
|
|
26
|
+
exports.describeError = describeError;
|
|
27
|
+
exports.errorCrumb = errorCrumb;
|
|
28
|
+
const scrub_1 = require("../scrub");
|
|
29
|
+
const console_args_1 = require("./console-args");
|
|
30
|
+
/**
|
|
31
|
+
* Longest scrubbed URL kept on a crumb (spec #122 §F): capped at assembly so an
|
|
32
|
+
* over-long URL is truncated, never dropped and never allowed to bloat a report.
|
|
33
|
+
*/
|
|
34
|
+
exports.MAX_URL_LENGTH = 2048;
|
|
35
|
+
/**
|
|
36
|
+
* A `console` crumb from a captured call's level and arguments (spec #122 §C). The
|
|
37
|
+
* `message` is the one-line preview (flattened, truncated); `args` preserves each
|
|
38
|
+
* argument as a structured, type-tagged, size-capped value so the Console tab can
|
|
39
|
+
* render objects/errors expandably; `source` is the best-effort `file:line`, attached
|
|
40
|
+
* only when the stack yielded one. Args are omitted entirely for a no-argument call.
|
|
41
|
+
*/
|
|
42
|
+
function consoleCrumb(level, args, timestamp, source) {
|
|
43
|
+
const structured = (0, console_args_1.capConsoleArgs)(args.map(console_args_1.toConsoleArg));
|
|
44
|
+
return {
|
|
45
|
+
category: "console",
|
|
46
|
+
level,
|
|
47
|
+
message: (0, console_args_1.joinArgs)(args),
|
|
48
|
+
timestamp,
|
|
49
|
+
...(structured.length > 0 ? { args: structured } : {}),
|
|
50
|
+
...(source ? { source } : {}),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A `navigation` crumb; both URLs are scrubbed and length-capped as the crumb is
|
|
55
|
+
* built. In a browser these come from `history`/`hashchange`; on mobile from the
|
|
56
|
+
* host app's `trackScreen` calls (spec 0004 §D), where the values are screen URLs
|
|
57
|
+
* derived from the configured origin.
|
|
58
|
+
*/
|
|
59
|
+
function navigationCrumb(from, to, timestamp) {
|
|
60
|
+
const fromUrl = (0, console_args_1.capLength)((0, scrub_1.scrubUrl)(from), exports.MAX_URL_LENGTH);
|
|
61
|
+
const toUrl = (0, console_args_1.capLength)((0, scrub_1.scrubUrl)(to), exports.MAX_URL_LENGTH);
|
|
62
|
+
return {
|
|
63
|
+
category: "navigation",
|
|
64
|
+
message: `${fromUrl} → ${toUrl}`,
|
|
65
|
+
timestamp,
|
|
66
|
+
data: { from: fromUrl, to: toUrl },
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Classify an HTTP status into a {@link NetworkOutcome} (spec #122 §D). A missing or
|
|
71
|
+
* `0` status is a `network-error` (a request that never got a response); otherwise
|
|
72
|
+
* the 4xx/5xx classes flag failures and everything else is `ok`. Used both as the
|
|
73
|
+
* fallback outcome and by the thin {@link fetchCrumb} / {@link xhrCrumb} builders.
|
|
74
|
+
*/
|
|
75
|
+
function outcomeFromStatus(status) {
|
|
76
|
+
if (typeof status !== "number" || status <= 0)
|
|
77
|
+
return "network-error";
|
|
78
|
+
if (status >= 500)
|
|
79
|
+
return "http-5xx";
|
|
80
|
+
if (status >= 400)
|
|
81
|
+
return "http-4xx";
|
|
82
|
+
return "ok";
|
|
83
|
+
}
|
|
84
|
+
/** Parse a `content-length` header into a non-negative byte count, or `undefined`. */
|
|
85
|
+
function parseContentLength(value) {
|
|
86
|
+
if (typeof value !== "string")
|
|
87
|
+
return undefined;
|
|
88
|
+
const bytes = Number.parseInt(value, 10);
|
|
89
|
+
return Number.isFinite(bytes) && bytes >= 0 ? bytes : undefined;
|
|
90
|
+
}
|
|
91
|
+
/** The media type from a `content-type` header (the part before any `;` parameters). */
|
|
92
|
+
function contentTypeOf(value) {
|
|
93
|
+
if (typeof value !== "string" || value.length === 0)
|
|
94
|
+
return undefined;
|
|
95
|
+
const media = value.split(";")[0]?.trim();
|
|
96
|
+
return media && media.length > 0 ? media : undefined;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* A network crumb (`fetch` / `xhr` / `beacon`) with the rich, metadata-only fields
|
|
100
|
+
* the Network tab renders (spec #122 §D, ticket #139): api, method, scrubbed URL,
|
|
101
|
+
* status + statusText, duration, request/response sizes, content type, and a failure
|
|
102
|
+
* outcome. The URL is scrubbed and length-capped at assembly. The shape has **no field
|
|
103
|
+
* for a request/response body or an arbitrary header**, so neither can ever be
|
|
104
|
+
* recorded; only a positive status, and fields that were actually supplied, ride along.
|
|
105
|
+
*/
|
|
106
|
+
function networkCrumb(input, timestamp) {
|
|
107
|
+
const url = (0, console_args_1.capLength)((0, scrub_1.scrubUrl)(input.url), exports.MAX_URL_LENGTH);
|
|
108
|
+
const hasStatus = typeof input.status === "number" && input.status > 0;
|
|
109
|
+
const statusPart = hasStatus ? ` → ${input.status}` : "";
|
|
110
|
+
const outcomePart = input.outcome !== "ok" ? ` (${input.outcome})` : "";
|
|
111
|
+
return {
|
|
112
|
+
category: input.api,
|
|
113
|
+
api: input.api,
|
|
114
|
+
method: input.method,
|
|
115
|
+
url,
|
|
116
|
+
message: `${input.method} ${url}${statusPart}${outcomePart}`,
|
|
117
|
+
timestamp,
|
|
118
|
+
...(hasStatus ? { status: input.status } : {}),
|
|
119
|
+
...(input.statusText ? { statusText: input.statusText } : {}),
|
|
120
|
+
...(typeof input.durationMs === "number" ? { durationMs: input.durationMs } : {}),
|
|
121
|
+
...(typeof input.reqSize === "number" ? { reqSize: input.reqSize } : {}),
|
|
122
|
+
...(typeof input.respSize === "number" ? { respSize: input.respSize } : {}),
|
|
123
|
+
...(input.contentType ? { contentType: input.contentType } : {}),
|
|
124
|
+
outcome: input.outcome,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* A thin `fetch` crumb from method + URL + status (outcome derived from the status).
|
|
129
|
+
* The instrumentation uses {@link networkCrumb} directly to carry the full metadata;
|
|
130
|
+
* this convenience builder seeds a network crumb from a status alone.
|
|
131
|
+
*/
|
|
132
|
+
function fetchCrumb(method, url, status, timestamp) {
|
|
133
|
+
return networkCrumb({ api: "fetch", method, url, status, outcome: outcomeFromStatus(status) }, timestamp);
|
|
134
|
+
}
|
|
135
|
+
/** A thin `xhr` crumb from method + URL + status (outcome derived from the status). */
|
|
136
|
+
function xhrCrumb(method, url, status, timestamp) {
|
|
137
|
+
return networkCrumb({ api: "xhr", method, url, status, outcome: outcomeFromStatus(status) }, timestamp);
|
|
138
|
+
}
|
|
139
|
+
/** Distil any thrown value into the `{ name, message }` an error crumb reads. */
|
|
140
|
+
function describeError(error) {
|
|
141
|
+
if (error instanceof Error) {
|
|
142
|
+
return { name: error.name || "Error", message: error.message };
|
|
143
|
+
}
|
|
144
|
+
if (typeof error === "string")
|
|
145
|
+
return { name: "Error", message: error };
|
|
146
|
+
return { name: "Error", message: (0, console_args_1.stringifyArg)(error) };
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* An `error` crumb for the failing exception or rejection that ends the trace. When
|
|
150
|
+
* `causedBy` is given (an auto-captured error), it rides on the crumb as the causal
|
|
151
|
+
* pointer to the ids of the entries immediately preceding the throw (spec #122 §F).
|
|
152
|
+
*/
|
|
153
|
+
function errorCrumb(error, timestamp, causedBy) {
|
|
154
|
+
const { name, message } = describeError(error);
|
|
155
|
+
const crumb = {
|
|
156
|
+
category: "error",
|
|
157
|
+
level: "error",
|
|
158
|
+
message: message ? `${name}: ${message}` : name,
|
|
159
|
+
timestamp,
|
|
160
|
+
data: { errorType: name },
|
|
161
|
+
};
|
|
162
|
+
return causedBy && causedBy.length > 0 ? { ...crumb, causedBy } : crumb;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=crumbs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crumbs.js","sourceRoot":"","sources":["../../src/trace/crumbs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The console crumb's **call site** (spec #122 §C) — the best-effort `file:line` a
|
|
3
|
+
* `console.*` call was made from, shared runtime-agnostically (ADR-0028).
|
|
4
|
+
*
|
|
5
|
+
* Frames are tokenized by the core's single stack parser (`stack.ts`), so a stack
|
|
6
|
+
* that yields a fingerprint frame yields a source location too — the browser's V8
|
|
7
|
+
* and Firefox/Safari dialects and React Native's Hermes/JSC ones alike. A query
|
|
8
|
+
* string on the asset URL is dropped, both for parse safety and privacy (it may be
|
|
9
|
+
* a cache-buster, or defensively a token).
|
|
10
|
+
*/
|
|
11
|
+
import type { SourceLocation } from "../breadcrumb";
|
|
12
|
+
/**
|
|
13
|
+
* Parse a single **trimmed** stack line into a `{ file, line }` location, or
|
|
14
|
+
* `undefined` when the line names no locatable file:line.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseStackFrame(line: string): SourceLocation | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* The best-effort `file:line` a console call was made from (spec #122 §C). Parses the
|
|
19
|
+
* frames of a stack, skipping `skipFrames` leading (SDK-internal) frames so the source
|
|
20
|
+
* points at the host code that called `console.*`. Returns `undefined` when no frame
|
|
21
|
+
* yields a usable location — the crumb then simply omits `source`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function sourceFromStack(stack: string | undefined, skipFrames?: number): SourceLocation | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Frames between `new Error()` (created inside the console wrapper) and the host
|
|
26
|
+
* caller: just the wrapper frame itself. Skipping it points {@link sourceFromStack}
|
|
27
|
+
* at the app code. The wrapper is called through the console object's property, so
|
|
28
|
+
* it is not a direct-call inlining candidate — keeping this skip count stable.
|
|
29
|
+
*/
|
|
30
|
+
export declare const CONSOLE_SOURCE_SKIP_FRAMES = 1;
|