@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.
Files changed (68) hide show
  1. package/README.md +28 -9
  2. package/{src/annotation.ts → dist/annotation.d.ts} +36 -47
  3. package/dist/anonymous-id.d.ts +23 -0
  4. package/dist/anonymous-id.js +39 -0
  5. package/dist/anonymous-id.js.map +1 -0
  6. package/dist/auto-capture.d.ts +129 -0
  7. package/dist/auto-capture.js +210 -0
  8. package/dist/auto-capture.js.map +1 -0
  9. package/{src/backoff.ts → dist/backoff.d.ts} +17 -52
  10. package/dist/boot.d.ts +148 -0
  11. package/dist/boot.js +113 -0
  12. package/dist/boot.js.map +1 -0
  13. package/dist/breadcrumb.d.ts +133 -0
  14. package/dist/connect.d.ts +110 -0
  15. package/dist/connect.js +147 -0
  16. package/dist/connect.js.map +1 -0
  17. package/dist/env.d.ts +37 -0
  18. package/dist/env.js +83 -0
  19. package/dist/env.js.map +1 -0
  20. package/dist/fingerprint.d.ts +39 -0
  21. package/dist/fingerprint.js +10 -15
  22. package/dist/fingerprint.js.map +1 -1
  23. package/dist/http.d.ts +51 -0
  24. package/dist/http.js +42 -0
  25. package/dist/http.js.map +1 -0
  26. package/dist/index.d.ts +28 -0
  27. package/dist/index.js +115 -3
  28. package/dist/index.js.map +1 -1
  29. package/dist/index.mjs +1057 -0
  30. package/dist/index.mjs.map +7 -0
  31. package/dist/options.d.ts +82 -0
  32. package/dist/options.js +22 -0
  33. package/dist/options.js.map +1 -0
  34. package/dist/release.d.ts +19 -0
  35. package/dist/release.js +36 -0
  36. package/dist/release.js.map +1 -0
  37. package/dist/scrub.d.ts +62 -0
  38. package/dist/stack.d.ts +51 -0
  39. package/dist/stack.js +97 -0
  40. package/dist/stack.js.map +1 -0
  41. package/dist/trace/buffer.d.ts +121 -0
  42. package/dist/trace/buffer.js +230 -0
  43. package/dist/trace/buffer.js.map +1 -0
  44. package/dist/trace/console-args.d.ts +60 -0
  45. package/dist/trace/console-args.js +189 -0
  46. package/dist/trace/console-args.js.map +1 -0
  47. package/dist/trace/console.d.ts +42 -0
  48. package/dist/trace/console.js +71 -0
  49. package/dist/trace/console.js.map +1 -0
  50. package/dist/trace/crumbs.d.ts +88 -0
  51. package/dist/trace/crumbs.js +164 -0
  52. package/dist/trace/crumbs.js.map +1 -0
  53. package/dist/trace/source.d.ts +30 -0
  54. package/dist/trace/source.js +59 -0
  55. package/dist/trace/source.js.map +1 -0
  56. package/dist/version.d.ts +13 -0
  57. package/dist/version.js +17 -0
  58. package/dist/version.js.map +1 -0
  59. package/dist/wire.d.ts +101 -0
  60. package/package.json +12 -8
  61. package/src/backoff.test.ts +0 -94
  62. package/src/breadcrumb.ts +0 -169
  63. package/src/fingerprint.test.ts +0 -96
  64. package/src/fingerprint.ts +0 -112
  65. package/src/index.ts +0 -63
  66. package/src/scrub.test.ts +0 -215
  67. package/src/scrub.ts +0 -226
  68. package/src/wire.ts +0 -116
package/dist/stack.js ADDED
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ /**
3
+ * The **one stack parser** every Fixback SDK shares (ADR-0028): a single frame
4
+ * tokenizer ({@link parseStackLine}) and the structured-frame extraction the wire
5
+ * carries ({@link extractStructuredFrames}).
6
+ *
7
+ * Three consumers read a stack, and each used to carry its own copy of the same
8
+ * regexes: the fingerprint's compact top-frames signature (`fingerprint.ts`), the
9
+ * console crumb's `file:line` source (`trace/source.ts`), and the structured
10
+ * frames server-side symbolication matches against uploaded sourcemaps
11
+ * (`extractStructuredFrames`, #117 / ADR-0024). They now all tokenize a frame the
12
+ * same way, so a stack that parses on one surface parses identically on every
13
+ * other — the parity guarantee the shared fingerprint depends on.
14
+ *
15
+ * Both engine dialects are handled: V8/Hermes (`at fn (loc)` / `at loc`) and
16
+ * JSC/SpiderMonkey (`fn@loc` / `@loc`).
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.parseStackLine = parseStackLine;
20
+ exports.parseFrameLocation = parseFrameLocation;
21
+ exports.extractStructuredFrames = extractStructuredFrames;
22
+ const scrub_1 = require("./scrub");
23
+ /** The most structured frames shipped per report (mirrors the server's cap). */
24
+ const STRUCTURED_FRAME_LIMIT = 30;
25
+ /**
26
+ * Tokenize one **trimmed** stack line into its function name and raw location, or
27
+ * `null` when the line is not a frame at all (the leading `Error: message`, a
28
+ * blank line). The single place the two engine dialects are recognised — every
29
+ * other stack reader in the core builds on this.
30
+ */
31
+ function parseStackLine(line) {
32
+ // V8 / Hermes: "at fn (loc)"
33
+ const v8Named = line.match(/^at\s+(.+?)\s+\((.+)\)$/);
34
+ if (v8Named)
35
+ return { fn: v8Named[1] ?? null, location: v8Named[2] ?? "" };
36
+ // V8 / Hermes: "at loc"
37
+ const v8Bare = line.match(/^at\s+(.+)$/);
38
+ if (v8Bare)
39
+ return { fn: null, location: v8Bare[1] ?? "" };
40
+ // JSC / SpiderMonkey: "fn@loc" | "@loc"
41
+ const at = line.indexOf("@");
42
+ if (at >= 0) {
43
+ return { fn: at > 0 ? line.slice(0, at) : null, location: line.slice(at + 1) };
44
+ }
45
+ return null;
46
+ }
47
+ /**
48
+ * Split a `file:line:col` location into its parts; `null` when it carries no line
49
+ * number or names no locatable file. The file may itself contain colons
50
+ * (`https://…`, `node:internal/…`), so the numeric groups are taken from the right.
51
+ * Unlocatable frames (`native`, `<anonymous>`, eval) are rejected here.
52
+ */
53
+ function parseFrameLocation(location) {
54
+ const match = location.match(/^(.*?):(\d+)(?::(\d+))?$/);
55
+ if (!match)
56
+ return null;
57
+ const file = match[1] ?? "";
58
+ if (file.length === 0 || file === "native" || file.includes("<anonymous>")) {
59
+ return null;
60
+ }
61
+ const line = Number(match[2]);
62
+ if (!Number.isFinite(line))
63
+ return null;
64
+ const column = match[3] !== undefined ? Number(match[3]) : null;
65
+ return { file, line, column };
66
+ }
67
+ /**
68
+ * Extract **structured** frames from a stack for the wire (#117, ADR-0024), top of
69
+ * stack first — unlike the fingerprint's compact signature (which drops the origin
70
+ * so a per-deploy asset hash cannot split a bug), these keep the full script path,
71
+ * because server-side symbolication matches it against uploaded sourcemap paths.
72
+ * Each URL is scrubbed (query dropped, path PII redacted) before it can leave the
73
+ * process; unlocatable frames are skipped; the count is capped.
74
+ */
75
+ function extractStructuredFrames(stack, limit = STRUCTURED_FRAME_LIMIT) {
76
+ if (typeof stack !== "string" || stack.length === 0)
77
+ return [];
78
+ const frames = [];
79
+ for (const raw of stack.split("\n")) {
80
+ if (frames.length >= limit)
81
+ break;
82
+ const tokens = parseStackLine(raw.trim());
83
+ if (!tokens || !tokens.location)
84
+ continue;
85
+ const parsed = parseFrameLocation(tokens.location);
86
+ if (!parsed)
87
+ continue;
88
+ frames.push({
89
+ file: (0, scrub_1.scrubUrl)(parsed.file),
90
+ line: parsed.line,
91
+ column: parsed.column,
92
+ function: tokens.fn && tokens.fn.length > 0 ? tokens.fn : null,
93
+ });
94
+ }
95
+ return frames;
96
+ }
97
+ //# sourceMappingURL=stack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stack.js","sourceRoot":"","sources":["../src/stack.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * The trace **ring buffer** (spec #122 §A/§B, decision D6) — the shared,
3
+ * runtime-agnostic store every Fixback capture SDK records crumbs into (ADR-0028).
4
+ *
5
+ * It holds **three independent FIFO rings** — `network`, `console`,
6
+ * `breadcrumbs` — each trimmed to its own budget so a chatty stream never evicts
7
+ * another's lead-up, plus a shared age cap. On `add`, a crumb passes through
8
+ * `beforeBreadcrumb`, is stamped with a stable `id` and a high-res `mono`
9
+ * timestamp (and an epoch `timestamp` if it has none), routed to its stream, then
10
+ * that stream is pruned by age and trimmed to its budget. `snapshot` prunes by age
11
+ * again, then merges the three streams into one `mono`-ordered array for transport
12
+ * — so the wire keeps its single `trace` field.
13
+ *
14
+ * Nothing here touches a DOM or a Node built-in: the instrumentation that *produces*
15
+ * crumbs lives in the consuming SDK, and the clocks are injectable so the buffer is
16
+ * unit-tested deterministically.
17
+ */
18
+ import type { Breadcrumb, BreadcrumbLevel } from "../breadcrumb";
19
+ /**
20
+ * The three independent trace streams (spec #122 §A, decision D6). Each is its own
21
+ * FIFO ring with its own size budget, so a chatty stream can't evict another's
22
+ * lead-up. Every crumb category maps to exactly one stream via {@link streamOf}.
23
+ */
24
+ export type TraceStream = "network" | "console" | "breadcrumbs";
25
+ /**
26
+ * Per-stream ring budgets — starting points from the grill (D6): network is the
27
+ * chattiest, breadcrumbs the sparsest. Per-project tunable, never frozen.
28
+ */
29
+ export declare const DEFAULT_STREAM_BUDGETS: Readonly<Record<TraceStream, number>>;
30
+ /**
31
+ * The shared age cap (spec #122 §A): entries older than this are pruned from every
32
+ * stream, whichever trims first. ~3 minutes and **on** by default, so an idle tab
33
+ * (or a backgrounded app) never ships stale context.
34
+ */
35
+ export declare const DEFAULT_MAX_AGE_MS: number;
36
+ /**
37
+ * Console levels captured by default (spec #122 §C, decision D7): **all** of them, so
38
+ * the Console tab is a real console and not just an error log. Eviction priority (not
39
+ * capture) is what keeps a chatty app's `log`/`info`/`debug` from burying the signal —
40
+ * see {@link PINNED_CONSOLE_LEVELS}.
41
+ */
42
+ export declare const DEFAULT_CONSOLE_LEVELS: readonly BreadcrumbLevel[];
43
+ /**
44
+ * The console levels **pinned** against eviction (spec #122 §C, decision D7). When the
45
+ * console stream overflows its budget, `warn`/`error`/`assert` are retained ahead of
46
+ * `log`/`info`/`debug`, so an error is never evicted by a burst of chatter — the
47
+ * low-priority levels fill the remainder and are dropped first.
48
+ */
49
+ export declare const PINNED_CONSOLE_LEVELS: readonly BreadcrumbLevel[];
50
+ /** Whether a console level is pinned against eviction (see {@link PINNED_CONSOLE_LEVELS}). */
51
+ export declare function isPinnedConsoleLevel(level: BreadcrumbLevel | undefined): boolean;
52
+ /**
53
+ * The console levels for which `source` (`file:line`) is captured (ticket #159).
54
+ *
55
+ * Capturing a call site constructs a `new Error()` to read its stack on **every** console
56
+ * call — a measurable hot-page cost when a chatty app logs in a tight loop. The
57
+ * spec-sanctioned mitigation (decision D7) narrows source capture to the **levels that
58
+ * matter for debugging** — the same `warn`/`error`/`assert` that are pinned against
59
+ * eviction — so `log`/`info`/`debug` pay no per-call stack cost and simply omit `source`.
60
+ * Per-project tunability of this set is future work; today it deliberately mirrors
61
+ * {@link PINNED_CONSOLE_LEVELS} so "what survives eviction" and "what carries a call
62
+ * site" stay one idea.
63
+ */
64
+ export declare const SOURCE_CAPTURE_LEVELS: readonly BreadcrumbLevel[];
65
+ /** Whether a console level captures `source` `file:line` (see {@link SOURCE_CAPTURE_LEVELS}). */
66
+ export declare function capturesSource(level: BreadcrumbLevel): boolean;
67
+ /**
68
+ * Which stream a crumb's category belongs to (spec #122 §A). Network APIs
69
+ * (`fetch` / `xhr` / `beacon`) form the network stream, `console` its own, and
70
+ * everything else (navigation, masked UI events, the failing error) breadcrumbs.
71
+ */
72
+ export declare function streamOf(category: string): TraceStream;
73
+ /** Filters or edits each crumb before it enters the buffer; `null` drops it. */
74
+ export type BeforeBreadcrumb = (crumb: Breadcrumb) => Breadcrumb | null;
75
+ /** Configuration for {@link createBreadcrumbBuffer}. All values are optional. */
76
+ export interface BreadcrumbBufferConfig {
77
+ /**
78
+ * Per-stream size budgets (oldest drop, independently per stream). Any stream
79
+ * omitted falls back to {@link DEFAULT_STREAM_BUDGETS}.
80
+ */
81
+ readonly budgets?: Partial<Record<TraceStream, number>>;
82
+ /**
83
+ * Shared age cap in ms: entries older than this are dropped from every stream.
84
+ * Defaults to {@link DEFAULT_MAX_AGE_MS} (on); pass `0` (or a non-positive value)
85
+ * to disable age pruning.
86
+ */
87
+ readonly maxAgeMs?: number;
88
+ /** A per-crumb filter (mute a category, edit, or drop by returning `null`). */
89
+ readonly beforeBreadcrumb?: BeforeBreadcrumb | null;
90
+ /** Epoch clock source, injectable for tests. Defaults to `Date.now`. */
91
+ readonly now?: () => number;
92
+ /** High-res monotonic clock, injectable for tests. Defaults to {@link nowMono}. */
93
+ readonly mono?: () => number;
94
+ /** Stable id generator, injectable for tests. Defaults to a per-buffer sequence. */
95
+ readonly nextId?: () => string;
96
+ }
97
+ /** A live trace buffer. */
98
+ export interface BreadcrumbBuffer {
99
+ /** Record a crumb (subject to `beforeBreadcrumb`, id/mono stamping, size, and age trimming). */
100
+ add(crumb: Breadcrumb): void;
101
+ /** The current crumbs, merged across streams and ordered in time — a fresh array. */
102
+ snapshot(): Breadcrumb[];
103
+ /** Drop every crumb. */
104
+ clear(): void;
105
+ }
106
+ /** Coerce a configured budget to a usable positive integer, else the default. */
107
+ export declare function normalizeBudget(value: number | undefined, fallback: number): number;
108
+ /** A per-buffer id factory: a short random salt + a base-36 sequence, stable once assigned. */
109
+ export declare function createIdFactory(): () => string;
110
+ /**
111
+ * Trim the **console** stream to its budget with eviction priority (spec #122 §C,
112
+ * decision D7): `warn`/`error`/`assert` are pinned, so the oldest `log`/`info`/`debug`
113
+ * entries are dropped first; a pinned entry is evicted only when dropping every
114
+ * low-priority one still leaves the stream over budget (oldest pinned first). Survivors
115
+ * keep their insertion order. A plain FIFO `slice(-budget)` handles every other stream.
116
+ */
117
+ export declare function trimConsoleStream<T extends {
118
+ readonly crumb: Breadcrumb;
119
+ }>(held: T[], budget: number): T[];
120
+ /** Create the per-stream trace buffer. See the module doc. */
121
+ export declare function createBreadcrumbBuffer(config?: BreadcrumbBufferConfig): BreadcrumbBuffer;
@@ -0,0 +1,230 @@
1
+ "use strict";
2
+ /**
3
+ * The trace **ring buffer** (spec #122 §A/§B, decision D6) — the shared,
4
+ * runtime-agnostic store every Fixback capture SDK records crumbs into (ADR-0028).
5
+ *
6
+ * It holds **three independent FIFO rings** — `network`, `console`,
7
+ * `breadcrumbs` — each trimmed to its own budget so a chatty stream never evicts
8
+ * another's lead-up, plus a shared age cap. On `add`, a crumb passes through
9
+ * `beforeBreadcrumb`, is stamped with a stable `id` and a high-res `mono`
10
+ * timestamp (and an epoch `timestamp` if it has none), routed to its stream, then
11
+ * that stream is pruned by age and trimmed to its budget. `snapshot` prunes by age
12
+ * again, then merges the three streams into one `mono`-ordered array for transport
13
+ * — so the wire keeps its single `trace` field.
14
+ *
15
+ * Nothing here touches a DOM or a Node built-in: the instrumentation that *produces*
16
+ * crumbs lives in the consuming SDK, and the clocks are injectable so the buffer is
17
+ * unit-tested deterministically.
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.SOURCE_CAPTURE_LEVELS = exports.PINNED_CONSOLE_LEVELS = exports.DEFAULT_CONSOLE_LEVELS = exports.DEFAULT_MAX_AGE_MS = exports.DEFAULT_STREAM_BUDGETS = void 0;
21
+ exports.isPinnedConsoleLevel = isPinnedConsoleLevel;
22
+ exports.capturesSource = capturesSource;
23
+ exports.streamOf = streamOf;
24
+ exports.normalizeBudget = normalizeBudget;
25
+ exports.createIdFactory = createIdFactory;
26
+ exports.trimConsoleStream = trimConsoleStream;
27
+ exports.createBreadcrumbBuffer = createBreadcrumbBuffer;
28
+ const env_1 = require("../env");
29
+ /**
30
+ * Per-stream ring budgets — starting points from the grill (D6): network is the
31
+ * chattiest, breadcrumbs the sparsest. Per-project tunable, never frozen.
32
+ */
33
+ exports.DEFAULT_STREAM_BUDGETS = {
34
+ network: 100,
35
+ console: 80,
36
+ breadcrumbs: 40,
37
+ };
38
+ /**
39
+ * The shared age cap (spec #122 §A): entries older than this are pruned from every
40
+ * stream, whichever trims first. ~3 minutes and **on** by default, so an idle tab
41
+ * (or a backgrounded app) never ships stale context.
42
+ */
43
+ exports.DEFAULT_MAX_AGE_MS = 3 * 60 * 1000;
44
+ /**
45
+ * Console levels captured by default (spec #122 §C, decision D7): **all** of them, so
46
+ * the Console tab is a real console and not just an error log. Eviction priority (not
47
+ * capture) is what keeps a chatty app's `log`/`info`/`debug` from burying the signal —
48
+ * see {@link PINNED_CONSOLE_LEVELS}.
49
+ */
50
+ exports.DEFAULT_CONSOLE_LEVELS = [
51
+ "log",
52
+ "info",
53
+ "warn",
54
+ "error",
55
+ "assert",
56
+ "debug",
57
+ ];
58
+ /**
59
+ * The console levels **pinned** against eviction (spec #122 §C, decision D7). When the
60
+ * console stream overflows its budget, `warn`/`error`/`assert` are retained ahead of
61
+ * `log`/`info`/`debug`, so an error is never evicted by a burst of chatter — the
62
+ * low-priority levels fill the remainder and are dropped first.
63
+ */
64
+ exports.PINNED_CONSOLE_LEVELS = [
65
+ "warn",
66
+ "error",
67
+ "assert",
68
+ ];
69
+ /** Whether a console level is pinned against eviction (see {@link PINNED_CONSOLE_LEVELS}). */
70
+ function isPinnedConsoleLevel(level) {
71
+ return level !== undefined && exports.PINNED_CONSOLE_LEVELS.includes(level);
72
+ }
73
+ /**
74
+ * The console levels for which `source` (`file:line`) is captured (ticket #159).
75
+ *
76
+ * Capturing a call site constructs a `new Error()` to read its stack on **every** console
77
+ * call — a measurable hot-page cost when a chatty app logs in a tight loop. The
78
+ * spec-sanctioned mitigation (decision D7) narrows source capture to the **levels that
79
+ * matter for debugging** — the same `warn`/`error`/`assert` that are pinned against
80
+ * eviction — so `log`/`info`/`debug` pay no per-call stack cost and simply omit `source`.
81
+ * Per-project tunability of this set is future work; today it deliberately mirrors
82
+ * {@link PINNED_CONSOLE_LEVELS} so "what survives eviction" and "what carries a call
83
+ * site" stay one idea.
84
+ */
85
+ exports.SOURCE_CAPTURE_LEVELS = exports.PINNED_CONSOLE_LEVELS;
86
+ /** Whether a console level captures `source` `file:line` (see {@link SOURCE_CAPTURE_LEVELS}). */
87
+ function capturesSource(level) {
88
+ return exports.SOURCE_CAPTURE_LEVELS.includes(level);
89
+ }
90
+ /**
91
+ * Which stream a crumb's category belongs to (spec #122 §A). Network APIs
92
+ * (`fetch` / `xhr` / `beacon`) form the network stream, `console` its own, and
93
+ * everything else (navigation, masked UI events, the failing error) breadcrumbs.
94
+ */
95
+ function streamOf(category) {
96
+ if (category === "console")
97
+ return "console";
98
+ if (category === "fetch" || category === "xhr" || category === "beacon") {
99
+ return "network";
100
+ }
101
+ return "breadcrumbs";
102
+ }
103
+ /** Coerce a configured budget to a usable positive integer, else the default. */
104
+ function normalizeBudget(value, fallback) {
105
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 1) {
106
+ return fallback;
107
+ }
108
+ return Math.floor(value);
109
+ }
110
+ /** A per-buffer id factory: a short random salt + a base-36 sequence, stable once assigned. */
111
+ function createIdFactory() {
112
+ const salt = Math.random().toString(36).slice(2, 8);
113
+ let seq = 0;
114
+ return () => `${salt}${(seq++).toString(36)}`;
115
+ }
116
+ /** The streams, in a fixed order for a deterministic merge. */
117
+ const STREAMS = ["network", "console", "breadcrumbs"];
118
+ /**
119
+ * Trim the **console** stream to its budget with eviction priority (spec #122 §C,
120
+ * decision D7): `warn`/`error`/`assert` are pinned, so the oldest `log`/`info`/`debug`
121
+ * entries are dropped first; a pinned entry is evicted only when dropping every
122
+ * low-priority one still leaves the stream over budget (oldest pinned first). Survivors
123
+ * keep their insertion order. A plain FIFO `slice(-budget)` handles every other stream.
124
+ */
125
+ function trimConsoleStream(held, budget) {
126
+ const over = held.length - budget;
127
+ if (over <= 0)
128
+ return held;
129
+ const drop = new Set();
130
+ // First: oldest low-priority (not pinned) entries, until enough room is freed.
131
+ for (let i = 0; i < held.length && drop.size < over; i += 1) {
132
+ if (!isPinnedConsoleLevel(held[i].crumb.level))
133
+ drop.add(i);
134
+ }
135
+ // Then, only if the low-priority ones weren't enough: oldest pinned entries.
136
+ for (let i = 0; i < held.length && drop.size < over; i += 1) {
137
+ if (!drop.has(i))
138
+ drop.add(i);
139
+ }
140
+ return held.filter((_, i) => !drop.has(i));
141
+ }
142
+ /** Create the per-stream trace buffer. See the module doc. */
143
+ function createBreadcrumbBuffer(config = {}) {
144
+ const budgets = {
145
+ network: normalizeBudget(config.budgets?.network, exports.DEFAULT_STREAM_BUDGETS.network),
146
+ console: normalizeBudget(config.budgets?.console, exports.DEFAULT_STREAM_BUDGETS.console),
147
+ breadcrumbs: normalizeBudget(config.budgets?.breadcrumbs, exports.DEFAULT_STREAM_BUDGETS.breadcrumbs),
148
+ };
149
+ const maxAgeMs = config.maxAgeMs === undefined ? exports.DEFAULT_MAX_AGE_MS : config.maxAgeMs;
150
+ const beforeBreadcrumb = config.beforeBreadcrumb;
151
+ const now = config.now ?? Date.now;
152
+ const mono = config.mono ?? env_1.nowMono;
153
+ const nextId = config.nextId ?? createIdFactory();
154
+ const streams = {
155
+ network: [],
156
+ console: [],
157
+ breadcrumbs: [],
158
+ };
159
+ let seq = 0;
160
+ function pruneByAge() {
161
+ if (typeof maxAgeMs !== "number" || maxAgeMs <= 0)
162
+ return;
163
+ const cutoff = now() - maxAgeMs;
164
+ for (const stream of STREAMS) {
165
+ const held = streams[stream];
166
+ if (held.length > 0) {
167
+ streams[stream] = held.filter((h) => h.crumb.timestamp >= cutoff);
168
+ }
169
+ }
170
+ }
171
+ return {
172
+ add(crumb) {
173
+ let entry = crumb;
174
+ if (beforeBreadcrumb) {
175
+ try {
176
+ entry = beforeBreadcrumb(crumb);
177
+ }
178
+ catch {
179
+ // A throwing filter must never break capture; keep the (already
180
+ // masked) crumb rather than silently erasing the trace.
181
+ entry = crumb;
182
+ }
183
+ }
184
+ if (!entry)
185
+ return;
186
+ // Stamp a stable id + high-res mono (and an epoch timestamp if absent) so
187
+ // every entry orders and cross-links exactly, whatever stream it lands in.
188
+ const stamped = {
189
+ ...entry,
190
+ id: entry.id ?? nextId(),
191
+ timestamp: typeof entry.timestamp === "number" ? entry.timestamp : now(),
192
+ mono: typeof entry.mono === "number" ? entry.mono : mono(),
193
+ };
194
+ const stream = streamOf(stamped.category);
195
+ streams[stream].push({ crumb: stamped, seq: seq++ });
196
+ // Age-prune every stream first (it may reassign the array), then trim this
197
+ // stream to its own budget — a flood here never evicts another stream.
198
+ pruneByAge();
199
+ const held = streams[stream];
200
+ const budget = budgets[stream];
201
+ if (held.length > budget) {
202
+ streams[stream] =
203
+ stream === "console"
204
+ ? trimConsoleStream(held, budget)
205
+ : held.slice(-budget);
206
+ }
207
+ },
208
+ snapshot() {
209
+ pruneByAge();
210
+ const merged = [];
211
+ for (const stream of STREAMS)
212
+ merged.push(...streams[stream]);
213
+ // Order in time by the high-res mono clock (every entry has one), with the
214
+ // insertion sequence as a stable tiebreak so equal clocks never scramble.
215
+ merged.sort((a, b) => {
216
+ const am = typeof a.crumb.mono === "number" ? a.crumb.mono : a.crumb.timestamp;
217
+ const bm = typeof b.crumb.mono === "number" ? b.crumb.mono : b.crumb.timestamp;
218
+ return am - bm || a.seq - b.seq;
219
+ });
220
+ return merged.map((h) => h.crumb);
221
+ },
222
+ clear() {
223
+ streams.network = [];
224
+ streams.console = [];
225
+ streams.breadcrumbs = [];
226
+ seq = 0;
227
+ },
228
+ };
229
+ }
230
+ //# sourceMappingURL=buffer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffer.js","sourceRoot":"","sources":["../../src/trace/buffer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Structured **console arguments** (spec #122 §C, decision D7) — the shared,
3
+ * runtime-agnostic assembly that turns a `console.*` call's arguments into
4
+ * type-tagged, JSON-safe, size-capped {@link ConsoleArg} values, plus the one-line
5
+ * preview the crumb's `message` carries.
6
+ *
7
+ * Preserving arguments type-tagged rather than flattening them to a string is what
8
+ * lets the Console tab render an object or an Error expandably instead of
9
+ * `[object Object]`. Every cap is applied **at assembly**, so a single console
10
+ * crumb can never bloat a report and an exotic or circular value can never reach
11
+ * the wire unserialized.
12
+ */
13
+ import type { ConsoleArg } from "../breadcrumb";
14
+ /** Longest crumb message kept; a huge log line is truncated, never dropped. */
15
+ export declare const MAX_MESSAGE_LENGTH = 300;
16
+ /**
17
+ * Structured console argument caps (spec #122 §C/§F), all applied **at assembly** so a
18
+ * single console crumb can never bloat a report:
19
+ * - {@link MAX_ARG_DEPTH} bounds how deep a `json` argument is cloned (deeper nodes
20
+ * collapse to an `[Object]`/`[Array]` marker);
21
+ * - {@link MAX_ARG_ITEMS} bounds how many keys/elements are kept at each level;
22
+ * - {@link MAX_ARG_STRING_LENGTH} truncates a single over-long string value;
23
+ * - {@link MAX_CONSOLE_ARGS_BYTES} bounds the serialized size of the whole args array
24
+ * (trailing args are dropped to fit), kept well under ingest's per-entry byte cap.
25
+ */
26
+ export declare const MAX_ARG_DEPTH = 4;
27
+ export declare const MAX_ARG_ITEMS = 100;
28
+ export declare const MAX_ARG_STRING_LENGTH = 1024;
29
+ export declare const MAX_CONSOLE_ARGS_BYTES = 4096;
30
+ /** Truncate a string to `max` with an ellipsis marker; keeps the value, never drops it. */
31
+ export declare function capLength(value: string, max: number): string;
32
+ /** Render one console argument to the flat text of the crumb's preview line. */
33
+ export declare function stringifyArg(arg: unknown): string;
34
+ /** The one-line preview a console crumb's `message` carries, length-capped. */
35
+ export declare function joinArgs(args: readonly unknown[]): string;
36
+ /** An Error rendered to a structured, size-capped `{ name, message, stack? }`. */
37
+ export declare function describeErrorValue(error: Error): {
38
+ name: string;
39
+ message: string;
40
+ stack?: string;
41
+ };
42
+ /**
43
+ * Build a JSON-safe, depth-/breadth-/string-capped clone of a value for a `json`
44
+ * console argument. Beyond {@link MAX_ARG_DEPTH} the node collapses to a marker;
45
+ * at each level at most {@link MAX_ARG_ITEMS} keys/elements are kept; strings are
46
+ * truncated to {@link MAX_ARG_STRING_LENGTH}; circular references become
47
+ * `"[Circular]"`; and exotic values (bigint / symbol / function / undefined) are
48
+ * rendered to safe text — so the result is always serializable and bounded.
49
+ */
50
+ export declare function safeCloneValue(value: unknown, depth: number, seen: Set<object>): unknown;
51
+ /** Classify one console argument into a type-tagged {@link ConsoleArg} (spec #122 §C). */
52
+ export declare function toConsoleArg(value: unknown): ConsoleArg;
53
+ /**
54
+ * Cap an entry's structured args to {@link MAX_CONSOLE_ARGS_BYTES} (spec #122 §F):
55
+ * drop trailing args until the array fits, keeping the earliest (usually the format
56
+ * string / main message); if even a single arg is over budget, keep one honest
57
+ * placeholder rather than an unbounded value. Per-arg depth/breadth/string caps bound
58
+ * most cases already — this is the whole-entry backstop.
59
+ */
60
+ export declare function capConsoleArgs(args: ConsoleArg[]): ConsoleArg[];