@flareapp/core 2.11.0 → 2.12.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/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as TracesEnvelope, A as Attributes, B as MessageLevel, C as convertToError, D as assert, E as assertKey, F as EntryPointType, G as SamplingContext, H as OtelSpan, I as Framework, J as SpanEvent, K as SdkInfo, L as Glow, M as BufferedSpan, N as Config, O as AnyValue, P as EntryPointHandler, Q as StackFrame, R as KeyValue, S as createIdentityTagger, U as OverriddenGrouping, V as OtelLogRecord, W as Report, X as SpanStatus, Y as SpanOptions, Z as SpanStatusCode, at as FrameworkName, b as extractCode, c as RejectionReporter, d as DEFAULT_URL_DENYLIST, et as TracesSampler, f as redactObjectValues, g as now, h as safeDecode, it as SpanTypeName, j as BufferedLog, k as AttributeValue, l as describeRejectionReason, m as resolveDenylist, n as urlAttributes, nt as BrowserSpanEventType, o as SafeCloneOptions, p as redactUrlQuery, q as Span, r as toCustomContext, rt as BrowserSpanType, s as safeClone, tt as User, u as routeRejection, v as glowsToEvents, x as SdkTaggable, y as flatJsonStringify, z as LogsEnvelope } from "./urlAttributes-DhkRD7pA.mjs";
1
+ import { $ as StackFrame, A as AttributeValue, B as LogsEnvelope, C as createIdentityTagger, D as assertKey, F as EntryPointHandler, G as Report, H as OtelLogRecord, I as EntryPointType, J as Span, K as SamplingContext, L as Framework, M as BufferedLog, N as BufferedSpan, O as assert, P as Config, Q as SpanStatusCode, R as Glow, S as SdkTaggable, U as OtelSpan, V as MessageLevel, W as OverriddenGrouping, X as SpanOptions, Y as SpanEvent, Z as SpanStatus, at as SpanTypeName, b as extractCode, c as RejectionReporter, d as DEFAULT_URL_DENYLIST, et as TracesEnvelope, f as redactObjectValues, g as now, h as safeDecode, it as BrowserSpanType, j as Attributes, k as AnyValue, l as describeRejectionReason, m as resolveDenylist, n as urlAttributes, nt as User, o as SafeCloneOptions, ot as FrameworkName, p as redactUrlQuery, q as SdkInfo, r as toCustomContext, rt as BrowserSpanEventType, s as safeClone, tt as TracesSampler, u as routeRejection, v as glowsToEvents, w as convertToError, x as evictLruIfNew, y as flatJsonStringify, z as KeyValue } from "./urlAttributes-rWoVW31H.mjs";
2
2
 
3
3
  //#region src/api/Api.d.ts
4
4
  declare class Api {
@@ -6,8 +6,7 @@ declare class Api {
6
6
  private pendingKeepaliveRequests;
7
7
  /**
8
8
  * How many keepalive bytes are still available. Logs and traces share one browser allowance and both
9
- * flush on page hide, so whichever goes second has to pack against what is left rather than assume the
10
- * whole budget, or it exceeds the gate in send() and silently degrades to a cancellable fetch.
9
+ * flush on page hide, so whichever goes second must pack against what is left, not the whole budget.
11
10
  */
12
11
  keepaliveBudgetRemaining(): number;
13
12
  report(report: Report, url: string, key: string | null, reportBrowserExtensionErrors: boolean, debug?: boolean): Promise<void>;
@@ -127,14 +126,13 @@ declare function readLinesFromFile(fileText: string, lineNumber: number, columnN
127
126
  interface ActiveSpanHolder {
128
127
  getActive(): Span | undefined;
129
128
  /**
130
- * Run `fn` with `span` active, restoring the prior active span afterward. A callback (not a bare setter) so a Node
131
- * holder can back it with AsyncLocalStorage.run(...) to preserve async-scoped context.
129
+ * Runs `fn` with `span` active, then restores the previous active span. Takes a callback, not a
130
+ * setter, so a Node holder can implement it with `AsyncLocalStorage.run(...)`.
132
131
  */
133
132
  withActive<T>(span: Span, fn: () => T): T;
134
133
  /**
135
- * Persistent "active root" that getActive() falls back to when no withActive scope is on the stack. Used by
136
- * long-lived pageload/navigation roots so child spans (e.g. fetches) auto-parent to them. Optional; a holder that
137
- * omits it simply has no active-root support.
134
+ * Fallback span that getActive() returns when no withActive scope is active. Long-lived
135
+ * pageload/navigation roots use it so child spans auto-parent to them. Optional.
138
136
  */
139
137
  setActiveRoot?(span: Span | undefined): void;
140
138
  }
@@ -187,10 +185,9 @@ declare class Tracer {
187
185
  getActiveSpan(): Span | undefined;
188
186
  setActiveRoot(span?: Span): void;
189
187
  /**
190
- * Take one span against `traceId`'s cap up front, for a caller that publishes a span id before the
191
- * span exists (the component profilers do; their descendants record first). False means the trace is
192
- * full and the caller should stay transparent instead of handing out an id the cap will refuse.
193
- * Consumed by the matching `startSpan({ claimed: true })`.
188
+ * Claims a span slot before the span exists, for a caller that publishes a span id early (the
189
+ * component profilers do; their descendants record first). Returns false when the trace is full.
190
+ * Paired with `startSpan({ claimed: true })`.
194
191
  */
195
192
  claimSpanSlot(traceId: string): boolean;
196
193
  addSpanListener(fn: SpanLifecycleListener): () => void;
@@ -201,20 +198,20 @@ declare class Tracer {
201
198
  clear(): void;
202
199
  continueFromTraceparent(header: string): void;
203
200
  /**
204
- * Runs `fn` with the span active, so spans started inside auto-parent to it, then ends it.
201
+ * Runs `fn` with the span active, so spans started inside it auto-parent to it, then ends the span.
205
202
  * Records an error status first if `fn` throws or its returned promise rejects.
206
203
  */
207
204
  withSpan<T>(name: string, fn: (span: Span) => T, opts?: SpanOptions): T;
208
- /** Starts a span the caller must end. Unlike `withSpan`, it does not become the active span,
209
- * so spans started after it do not auto-parent to it. */
205
+ /**
206
+ * Starts a span the caller must end. Unlike `withSpan`, it does not become the active span, so spans
207
+ * started after it do not auto-parent to it.
208
+ */
210
209
  startSpan(name: string, opts?: SpanOptions): Span;
211
- /** A real Span handle that records nothing, so callers never have to branch on whether tracing is on. */
212
210
  private startInertSpan;
213
211
  private resolveTrace;
214
212
  private getOrSeedState;
215
213
  private createState;
216
214
  private makeSpan;
217
- /** Bounded, LRU by insertion order, like traceStates. Holds primitives only, never a span. */
218
215
  private rememberClosed;
219
216
  private onSpanEnd;
220
217
  }
@@ -246,22 +243,13 @@ declare class Flare {
246
243
  * default; a platform can back it with AsyncLocalStorage instead.
247
244
  */
248
245
  constructor(api?: Api, contextCollector?: ContextCollector, fileReader?: FileReader, scopeProvider?: ScopeProvider, scheduler?: FlushScheduler, activeSpanHolder?: ActiveSpanHolder);
249
- /**
250
- * Register an in-flight report so `flush()` can wait for it. Every entry point wraps its whole async
251
- * pipeline, from beforeEvaluate through api.report, so flush() waits on all of it.
252
- *
253
- * What goes in the Set is a shadow promise that mirrors `p`'s timing but cannot reject, so a failed
254
- * report never surfaces as an unhandled rejection warning. `p` itself is returned untouched, so the
255
- * caller still observes real success or failure.
256
- */
257
246
  private track;
258
247
  /**
259
- * Wait until every in-flight report settles or `timeoutMs` elapses. Always resolves, never rejects.
260
- * Written for `@flareapp/node`'s fatal handler, which awaits the fatal report itself then flushes to
261
- * drain any other concurrent reports before `process.exit`.
248
+ * Waits until every in-flight report settles, or `timeoutMs` elapses. Always resolves, never rejects.
249
+ * Used by `@flareapp/node`'s fatal handler to drain other reports before `process.exit`.
262
250
  *
263
- * Snapshotting the Set bounds the wait: reports started after this line are not awaited, so a handler
264
- * that keeps emitting during shutdown cannot block the process forever. Call flush again for those.
251
+ * Only reports already in flight are awaited, so a handler still emitting during shutdown cannot block
252
+ * forever. Call flush again to catch those.
265
253
  */
266
254
  flush(timeoutMs?: number): Promise<void>;
267
255
  get config(): Readonly<Config>;
@@ -298,10 +286,6 @@ declare class Flare {
298
286
  setEntryPoint(handler: EntryPointHandler): this;
299
287
  setSdkInfo(info: SdkInfo): this;
300
288
  setFramework(framework: Framework): this;
301
- /**
302
- * True when a report must not be captured: consent withdrawn, or dropped by sampling. Consent is
303
- * checked first, so a blocked report never runs the sampler or assembles a report (no cookie read).
304
- */
305
289
  private shouldSkipCapture;
306
290
  report(error: Error, attributes?: Attributes): Promise<void>;
307
291
  private reportInternal;
@@ -314,15 +298,6 @@ declare class Flare {
314
298
  private buildBaseAttributes;
315
299
  private assembleAttributes;
316
300
  private buildLogAttributes;
317
- /**
318
- * Local roots only, snapshotted by the Tracer at span START so a long-lived root does not drift into
319
- * the next page's scope. Children get none, and no span ever runs the DOM collector.
320
- *
321
- * Everything assembled is inherited except user identity (excluding the opaque `user.id`): a root span
322
- * goes out for every page view, so email, full name, IP and `user.attributes` would turn normal
323
- * browsing into PII traffic. The rest — `context.custom`, `addContextGroup` bags — stays in, because
324
- * the trace viewer renders any span attribute whose key does not start with `flare.`.
325
- */
326
301
  private getScopeAttributes;
327
302
  private spanResourceAttributes;
328
303
  private buildReport;
@@ -350,11 +325,9 @@ declare function spanId(): string;
350
325
  //#endregion
351
326
  //#region src/stacktrace/NullFileReader.d.ts
352
327
  /**
353
- * No-op `FileReader` returning `null` for every URL. Default for `Flare`'s `fileReader` param so `new Flare()` builds
354
- * reports without picking an environment; stack frames just omit source snippets. Consumer packages inject the real
355
- * ones: `@flareapp/js` a fetch-based reader, `@flareapp/node` a disk reader. The `read(url) -> Promise<string | null>`
356
- * interface lets the stack-trace builder treat all three the same (render on text, skip on null), so core needs no
357
- * environment checks.
328
+ * No-op `FileReader` returning `null` for every URL. Default for `Flare`'s `fileReader` param, so
329
+ * `new Flare()` builds reports without picking an environment; stack frames just omit source snippets.
330
+ * `@flareapp/js` and `@flareapp/node` inject a real fetch- or disk-based reader instead.
358
331
  */
359
332
  declare class NullFileReader implements FileReader {
360
333
  read(_url: string): Promise<string | null>;
@@ -422,4 +395,4 @@ declare function buildDeviceContextGroup(info: DeviceInfo): Record<string, Attri
422
395
  //#region src/stacktrace/createStackTrace.d.ts
423
396
  declare function createStackTrace(error: Error, debug: boolean, fileReader: FileReader): Promise<Array<StackFrame>>;
424
397
  //#endregion
425
- export { type ActiveSpanHolder, type AnyValue, Api, type AttributeValue, type Attributes, BrowserSpanEventType, BrowserSpanType, type BufferedLog, type BufferedSpan, type Config, type ContextCollector, DEFAULT_MAX_LIVE_TRACES, DEFAULT_URL_DENYLIST, type DeviceInfo, type DeviceInfoProvider, type EffectiveConnectionType, type EntryPointHandler, type EntryPointType, type FileReader, Flare, type FlushFn, type FlushScheduler, type Framework, FrameworkName, GlobalScopeProvider, type Glow, InMemoryActiveSpanHolder, type KeyValue, Logger, type LoggerDeps, type LogsEnvelope, MAX_BREADCRUMB_URL_LENGTH, type MessageLevel, NoopFlushScheduler, NullDeviceInfoProvider, NullFileReader, type OtelLogRecord, type OtelSpan, type OverriddenGrouping, type RejectionReporter, type Report, type SafeCloneOptions, type SamplingContext, Scope, type ScopeProvider, type SdkInfo, type SdkTaggable, type Span, type SpanEvent, type SpanLifecycleEvent, type SpanLifecycleListener, type SpanOptions, type SpanPhase, type SpanStatus, SpanStatusCode, type SpanTypeName, type StackFrame, Tracer, type TracerDeps, type TracesEnvelope, type TracesSampler, USER_IDENTITY_KEYS, type User, assert, assertKey, breadcrumbUrl, buildDeviceContextGroup, buildTraceparent, buildTracesEnvelope, convertToError, createIdentityTagger, createStackTrace, defaultNowNano, describeRejectionReason, deviceInfoToAttributes, extractCode, flatJsonStringify, getCodeSnippet, glowsToEvents, now, parseTraceparent, readLinesFromFile, recordBreadcrumb, redactObjectValues, redactUrlQuery, resolveDenylist, routeRejection, safeClone, safeDecode, spanId, toCustomContext, urlAttributes, userIdentityAttributes };
398
+ export { type ActiveSpanHolder, type AnyValue, Api, type AttributeValue, type Attributes, BrowserSpanEventType, BrowserSpanType, type BufferedLog, type BufferedSpan, type Config, type ContextCollector, DEFAULT_MAX_LIVE_TRACES, DEFAULT_URL_DENYLIST, type DeviceInfo, type DeviceInfoProvider, type EffectiveConnectionType, type EntryPointHandler, type EntryPointType, type FileReader, Flare, type FlushFn, type FlushScheduler, type Framework, FrameworkName, GlobalScopeProvider, type Glow, InMemoryActiveSpanHolder, type KeyValue, Logger, type LoggerDeps, type LogsEnvelope, MAX_BREADCRUMB_URL_LENGTH, type MessageLevel, NoopFlushScheduler, NullDeviceInfoProvider, NullFileReader, type OtelLogRecord, type OtelSpan, type OverriddenGrouping, type RejectionReporter, type Report, type SafeCloneOptions, type SamplingContext, Scope, type ScopeProvider, type SdkInfo, type SdkTaggable, type Span, type SpanEvent, type SpanLifecycleEvent, type SpanLifecycleListener, type SpanOptions, type SpanPhase, type SpanStatus, SpanStatusCode, type SpanTypeName, type StackFrame, Tracer, type TracerDeps, type TracesEnvelope, type TracesSampler, USER_IDENTITY_KEYS, type User, assert, assertKey, breadcrumbUrl, buildDeviceContextGroup, buildTraceparent, buildTracesEnvelope, convertToError, createIdentityTagger, createStackTrace, defaultNowNano, describeRejectionReason, deviceInfoToAttributes, evictLruIfNew, extractCode, flatJsonStringify, getCodeSnippet, glowsToEvents, now, parseTraceparent, readLinesFromFile, recordBreadcrumb, redactObjectValues, redactUrlQuery, resolveDenylist, routeRejection, safeClone, safeDecode, spanId, toCustomContext, urlAttributes, userIdentityAttributes };
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
- import { A as SOURCEMAP_VERSION, C as convertToError, D as assert, E as assertKey, O as CLIENT_VERSION, S as createIdentityTagger, _ as MAX_TRAVERSAL_DEPTH, a as describeRejectionReason, b as spendNode, c as redactObjectValues, d as safeDecode, f as now, g as safeClone, h as flatJsonStringify, i as setDefined, k as KEY, l as redactUrlQuery, m as glowsToEvents, n as urlAttributes, o as routeRejection, p as timelineEvents, r as toCustomContext, s as DEFAULT_URL_DENYLIST, u as resolveDenylist, v as TRUNCATED, x as extractCode, y as createTraversalBudget } from "./urlAttributes-DmpMd_4O.mjs";
1
+ import { A as KEY, C as createIdentityTagger, D as assertKey, O as assert, S as evictLruIfNew, _ as MAX_TRAVERSAL_DEPTH, a as describeRejectionReason, b as spendNode, c as redactObjectValues, d as safeDecode, f as now, g as safeClone, h as flatJsonStringify, i as setDefined, j as SOURCEMAP_VERSION, k as CLIENT_VERSION, l as redactUrlQuery, m as glowsToEvents, n as urlAttributes, o as routeRejection, p as timelineEvents, r as toCustomContext, s as DEFAULT_URL_DENYLIST, u as resolveDenylist, v as TRUNCATED, w as convertToError, x as extractCode, y as createTraversalBudget } from "./urlAttributes-ggdpIKSS.mjs";
2
2
  import ErrorStackParser from "error-stack-parser";
3
3
 
4
4
  //#region src/framework.ts
5
5
  /**
6
- * Framework names the Flare backend recognises. Wire format, so the values never change: they ship as
7
- * `flare.framework.name` and (lowercased) as `context.custom.framework`.
6
+ * Framework names the Flare backend recognizes. Wire format: these values never change, since they
7
+ * ship as `flare.framework.name` and (lowercased) as `context.custom.framework`.
8
8
  *
9
- * `Js` and `Node` are the base SDKs' fallback claim, overwritten when a framework package tags its
10
- * own name. `NodeElectron` is an Electron main process; its renderers report their own.
9
+ * `Js` and `Node` are fallback claims from the base SDKs, overwritten when a framework package sets
10
+ * its own name. `NodeElectron` is the Electron main process; renderers report their own name.
11
11
  */
12
12
  const FrameworkName = {
13
13
  Js: "js",
@@ -23,7 +23,7 @@ const FrameworkName = {
23
23
  //#endregion
24
24
  //#region src/spanTypes.ts
25
25
  /**
26
- * Span types the Flare backend recognises. Wire format, so the values never change: they ship as the
26
+ * Span types the Flare backend recognizes. Wire format, so the values never change: they ship as the
27
27
  * `flare.span_type` attribute and the backend groups performance data by them.
28
28
  *
29
29
  * These are the browser client's set. They live in core because core's `SpanOptions.spanType` needs
@@ -37,6 +37,10 @@ const BrowserSpanType = {
37
37
  Component: "browser_component",
38
38
  WebVital: "browser_web_vital"
39
39
  };
40
+ /**
41
+ * Span event types on an error report. Kept apart from `BrowserSpanType`: these are points in time,
42
+ * not spans with a duration. That is also why a route change is not called `browser_navigation`.
43
+ */
40
44
  const BrowserSpanEventType = {
41
45
  Click: "browser_click",
42
46
  Input: "browser_input",
@@ -55,7 +59,6 @@ const SpanStatusCode = {
55
59
  //#endregion
56
60
  //#region src/util/utf8Bytes.ts
57
61
  const textEncoder = new TextEncoder();
58
- /** UTF-8 byte length of `value`. */
59
62
  function utf8Bytes(value) {
60
63
  return textEncoder.encode(value).length;
61
64
  }
@@ -69,8 +72,7 @@ var Api = class {
69
72
  pendingKeepaliveRequests = 0;
70
73
  /**
71
74
  * How many keepalive bytes are still available. Logs and traces share one browser allowance and both
72
- * flush on page hide, so whichever goes second has to pack against what is left rather than assume the
73
- * whole budget, or it exceeds the gate in send() and silently degrades to a cancellable fetch.
75
+ * flush on page hide, so whichever goes second must pack against what is left, not the whole budget.
74
76
  */
75
77
  keepaliveBudgetRemaining() {
76
78
  if (this.pendingKeepaliveRequests >= MAX_PENDING_KEEPALIVE_REQUESTS) return 0;
@@ -170,11 +172,6 @@ function recordBreadcrumb(scopeProvider, config, type, attributes, startTimeUnix
170
172
 
171
173
  //#endregion
172
174
  //#region src/telemetry/TelemetryBuffer.ts
173
- /**
174
- * The batching machine behind both telemetry signals: hold records, ship them when a size, weight or time
175
- * trigger fires, and shed the oldest when nothing can drain. One instance owns one signal; what that signal
176
- * is comes entirely from the policy.
177
- */
178
175
  var TelemetryBuffer = class {
179
176
  entries = [];
180
177
  bufferedBytes = 0;
@@ -284,11 +281,6 @@ var TelemetryBuffer = class {
284
281
  if (dropped) this.bufferedBytes -= dropped.bytes;
285
282
  }
286
283
  }
287
- /**
288
- * Newest-wins. An over-budget record is skipped, not a stop signal, so a smaller older record behind a fat
289
- * one still ships. Runs on visibilitychange:hidden, which fires on plain backgrounding too, so the tail this
290
- * leaves behind is retained and re-armed rather than dropped (see flush).
291
- */
292
284
  packForKeepalive(config, resource) {
293
285
  const fixedBytes = this.policy.emptyEnvelopeBytes(resource);
294
286
  const budget = Math.min(config.keepaliveMaxBytes, this.policy.keepaliveBudget?.(config) ?? config.keepaliveMaxBytes);
@@ -317,11 +309,6 @@ var TelemetryBuffer = class {
317
309
 
318
310
  //#endregion
319
311
  //#region src/telemetry/resourceIdentity.ts
320
- /**
321
- * Builds the attributes that go on every logs or traces envelope: the caller's own attributes in `base`, with
322
- * our SDK, service and framework identity on top. Our keys win, so a user value cannot overwrite something
323
- * like `telemetry.sdk.name`.
324
- */
325
312
  function buildResourceIdentity(base, config, sdk, framework) {
326
313
  const identity = {
327
314
  "telemetry.sdk.language": "javascript",
@@ -342,18 +329,6 @@ function buildResourceIdentity(base, config, sdk, framework) {
342
329
 
343
330
  //#endregion
344
331
  //#region src/logging/otel.ts
345
- /**
346
- * Converts one attribute value into the OpenTelemetry `AnyValue` shape. Strings, numbers and booleans become
347
- * leaves, arrays and objects are walked recursively. Anything OpenTelemetry cannot carry (null, undefined,
348
- * NaN, functions) returns null and the caller drops that key.
349
- *
350
- * A value that contains itself becomes the string `[Circular]`. `inPath` only holds the parents of the value
351
- * being converted right now, so the same object used twice side by side is converted twice instead of being
352
- * wrongly called circular.
353
- *
354
- * The walk also stops at a maximum depth and a maximum number of nodes, see traversalBudget.ts. Pass `budget`
355
- * to let several calls share one allowance, otherwise every call gets its own.
356
- */
357
332
  function valueToOpenTelemetry(value, inPath = /* @__PURE__ */ new WeakSet(), budget = createTraversalBudget()) {
358
333
  return convert(value, inPath, 0, budget);
359
334
  }
@@ -438,17 +413,9 @@ function buildLogsEnvelope(records, resourceAttributes, scopeName, scopeVersion)
438
413
  }]
439
414
  }] };
440
415
  }
441
- /**
442
- * How many UTF-8 bytes one record adds to an envelope. We measure the real toOtelLogRecord output instead of
443
- * reusing the cached BufferedLog estimate, because keepaliveMaxBytes is a hard browser limit and an estimate
444
- * is not good enough.
445
- *
446
- * Uses flatJsonStringify to match Api.logs, which sends the envelope through the same encoder.
447
- */
448
416
  function otelLogRecordBytes(record) {
449
417
  return utf8Bytes(flatJsonStringify(toOtelLogRecord(record)));
450
418
  }
451
- /** UTF-8 bytes of an empty envelope: the fixed overhead every batch has, before any records are added. */
452
419
  function emptyLogsEnvelopeBytes(resourceAttributes, scopeName, scopeVersion) {
453
420
  return utf8Bytes(flatJsonStringify(buildLogsEnvelope([], resourceAttributes, scopeName, scopeVersion)));
454
421
  }
@@ -608,7 +575,6 @@ function partitionAttributes(attributes) {
608
575
 
609
576
  //#endregion
610
577
  //#region src/Scope.ts
611
- /** `USER_IDENTITY_KEYS` derives from this, so adding a field here can never leave the clear pass stale. */
612
578
  const USER_FIELD_KEYS = {
613
579
  id: "user.id",
614
580
  email: "user.email",
@@ -788,11 +754,9 @@ function isApplicationFrame(fileName) {
788
754
  //#endregion
789
755
  //#region src/stacktrace/NullFileReader.ts
790
756
  /**
791
- * No-op `FileReader` returning `null` for every URL. Default for `Flare`'s `fileReader` param so `new Flare()` builds
792
- * reports without picking an environment; stack frames just omit source snippets. Consumer packages inject the real
793
- * ones: `@flareapp/js` a fetch-based reader, `@flareapp/node` a disk reader. The `read(url) -> Promise<string | null>`
794
- * interface lets the stack-trace builder treat all three the same (render on text, skip on null), so core needs no
795
- * environment checks.
757
+ * No-op `FileReader` returning `null` for every URL. Default for `Flare`'s `fileReader` param, so
758
+ * `new Flare()` builds reports without picking an environment; stack frames just omit source snippets.
759
+ * `@flareapp/js` and `@flareapp/node` inject a real fetch- or disk-based reader instead.
796
760
  */
797
761
  var NullFileReader = class {
798
762
  read(_url) {
@@ -978,28 +942,15 @@ function buildTracesEnvelope(spans, resourceAttributes, scopeName, scopeVersion)
978
942
  }]
979
943
  }] };
980
944
  }
981
- /**
982
- * How many UTF-8 bytes one span adds to an envelope. We measure the real toOtelSpan output instead of reusing
983
- * the cached BufferedSpan estimate, because keepaliveMaxBytes is a hard browser limit and an estimate is not
984
- * good enough.
985
- *
986
- * We use flatJsonStringify instead of JSON.stringify because a span keeps values the caller still owns, like
987
- * status.message, and those can turn unserializable after the span ended. This runs from a visibilitychange
988
- * listener with no try/catch around it, so a throw here loses the flush. flatJsonStringify handles the usual
989
- * suspects (circular references, BigInt, a getter that throws on a plain object) but is not bulletproof: a
990
- * class instance with a throwing getter goes through untouched and can still throw.
991
- */
992
945
  function otelSpanBytes(span) {
993
946
  return utf8Bytes(flatJsonStringify(toOtelSpan(span)));
994
947
  }
995
- /** UTF-8 bytes of an empty envelope: the fixed overhead every batch has, before any spans are added. */
996
948
  function emptyTracesEnvelopeBytes(resourceAttributes, scopeName, scopeVersion) {
997
949
  return utf8Bytes(JSON.stringify(buildTracesEnvelope([], resourceAttributes, scopeName, scopeVersion)));
998
950
  }
999
951
 
1000
952
  //#endregion
1001
953
  //#region src/tracing/SpanBuffer.ts
1002
- /** The span half of the shared telemetry buffer: names the config keys, the envelope and the ingest call. */
1003
954
  var SpanBuffer = class {
1004
955
  inner;
1005
956
  constructor(deps) {
@@ -1084,11 +1035,9 @@ function parseTraceparent(header) {
1084
1035
  function isPromiseLike(value) {
1085
1036
  return (typeof value === "object" || typeof value === "function") && value !== null && typeof value.then === "function";
1086
1037
  }
1087
- /** `SpanOptions.parent` is a structurally overlapping union; `isRecording` is what tells a real Span apart. */
1088
1038
  function isSpan(parent) {
1089
1039
  return "isRecording" in parent;
1090
1040
  }
1091
- /** A SpanImpl carries the epoch it was created under; a hand-stitched `{traceId, spanId}` parent does not. */
1092
1041
  function hasEpoch(parent) {
1093
1042
  return "epoch" in parent && typeof parent.epoch === "number";
1094
1043
  }
@@ -1097,16 +1046,6 @@ function defaultNowNano() {
1097
1046
  const ms = performanceApi && typeof performanceApi.now === "function" && typeof performanceApi.timeOrigin === "number" ? performanceApi.timeOrigin + performanceApi.now() : Date.now();
1098
1047
  return Math.round(ms * 1e6);
1099
1048
  }
1100
- /**
1101
- * Both trace maps cap their size the same way: insertion order is LRU, so the first key is the one to drop.
1102
- * Only evicts when `key` is not already in the map. A set() that overwrites an existing key does not grow the
1103
- * map, so it must not evict an unrelated entry to make room for it.
1104
- */
1105
- function evictLruIfNew(map, key, cap) {
1106
- if (map.has(key) || map.size < cap) return;
1107
- const lru = map.keys().next().value;
1108
- if (lru !== void 0) map.delete(lru);
1109
- }
1110
1049
  const MAX_CLOSED_TRACES = 100;
1111
1050
  /** Bounded backstop for the live TraceState map: an app that never ends spans must not grow it forever. */
1112
1051
  const DEFAULT_MAX_LIVE_TRACES = 1e3;
@@ -1145,10 +1084,9 @@ var Tracer = class {
1145
1084
  this.holder.setActiveRoot?.(span);
1146
1085
  }
1147
1086
  /**
1148
- * Take one span against `traceId`'s cap up front, for a caller that publishes a span id before the
1149
- * span exists (the component profilers do; their descendants record first). False means the trace is
1150
- * full and the caller should stay transparent instead of handing out an id the cap will refuse.
1151
- * Consumed by the matching `startSpan({ claimed: true })`.
1087
+ * Claims a span slot before the span exists, for a caller that publishes a span id early (the
1088
+ * component profilers do; their descendants record first). Returns false when the trace is full.
1089
+ * Paired with `startSpan({ claimed: true })`.
1152
1090
  */
1153
1091
  claimSpanSlot(traceId) {
1154
1092
  const config = this.deps.getConfig();
@@ -1187,7 +1125,7 @@ var Tracer = class {
1187
1125
  this.pendingContinuation = parseTraceparent(header);
1188
1126
  }
1189
1127
  /**
1190
- * Runs `fn` with the span active, so spans started inside auto-parent to it, then ends it.
1128
+ * Runs `fn` with the span active, so spans started inside it auto-parent to it, then ends the span.
1191
1129
  * Records an error status first if `fn` throws or its returned promise rejects.
1192
1130
  */
1193
1131
  withSpan(name, fn, opts = {}) {
@@ -1217,8 +1155,10 @@ var Tracer = class {
1217
1155
  }
1218
1156
  });
1219
1157
  }
1220
- /** Starts a span the caller must end. Unlike `withSpan`, it does not become the active span,
1221
- * so spans started after it do not auto-parent to it. */
1158
+ /**
1159
+ * Starts a span the caller must end. Unlike `withSpan`, it does not become the active span, so spans
1160
+ * started after it do not auto-parent to it.
1161
+ */
1222
1162
  startSpan(name, opts = {}) {
1223
1163
  const config = this.deps.getConfig();
1224
1164
  const spanId$1 = opts.spanId ?? spanId();
@@ -1248,7 +1188,6 @@ var Tracer = class {
1248
1188
  this.emitSpanEvent("start", span);
1249
1189
  return span;
1250
1190
  }
1251
- /** A real Span handle that records nothing, so callers never have to branch on whether tracing is on. */
1252
1191
  startInertSpan(name, spanId, opts, config) {
1253
1192
  const span = this.makeSpan({
1254
1193
  traceId: traceId(),
@@ -1355,7 +1294,6 @@ var Tracer = class {
1355
1294
  if (opts.attributes) for (const [key, value] of Object.entries(opts.attributes)) span.setAttribute(key, value);
1356
1295
  return span;
1357
1296
  }
1358
- /** Bounded, LRU by insertion order, like traceStates. Holds primitives only, never a span. */
1359
1297
  rememberClosed(state) {
1360
1298
  evictLruIfNew(this.closedTraces, state.traceId, MAX_CLOSED_TRACES);
1361
1299
  this.closedTraces.set(state.traceId, {
@@ -1410,8 +1348,6 @@ var Tracer = class {
1410
1348
 
1411
1349
  //#endregion
1412
1350
  //#region src/Flare.ts
1413
- /** Scope attributes a span never inherits. Derived from `USER_IDENTITY_KEYS` so a future user field is
1414
- * excluded automatically, without anyone needing to remember to list it here. See `getScopeAttributes`. */
1415
1351
  const SPAN_SCOPE_EXCLUDED_KEYS = USER_IDENTITY_KEYS.filter((key) => key !== USER_FIELD_KEYS.id);
1416
1352
  const DEFAULT_SDK_NAME = "@flareapp/core";
1417
1353
  var Flare = class {
@@ -1496,14 +1432,6 @@ var Flare = class {
1496
1432
  activeSpanHolder
1497
1433
  });
1498
1434
  }
1499
- /**
1500
- * Register an in-flight report so `flush()` can wait for it. Every entry point wraps its whole async
1501
- * pipeline, from beforeEvaluate through api.report, so flush() waits on all of it.
1502
- *
1503
- * What goes in the Set is a shadow promise that mirrors `p`'s timing but cannot reject, so a failed
1504
- * report never surfaces as an unhandled rejection warning. `p` itself is returned untouched, so the
1505
- * caller still observes real success or failure.
1506
- */
1507
1435
  track(p) {
1508
1436
  const tracked = p.then(() => void 0, () => void 0);
1509
1437
  this.inflight.add(tracked);
@@ -1511,12 +1439,11 @@ var Flare = class {
1511
1439
  return p;
1512
1440
  }
1513
1441
  /**
1514
- * Wait until every in-flight report settles or `timeoutMs` elapses. Always resolves, never rejects.
1515
- * Written for `@flareapp/node`'s fatal handler, which awaits the fatal report itself then flushes to
1516
- * drain any other concurrent reports before `process.exit`.
1442
+ * Waits until every in-flight report settles, or `timeoutMs` elapses. Always resolves, never rejects.
1443
+ * Used by `@flareapp/node`'s fatal handler to drain other reports before `process.exit`.
1517
1444
  *
1518
- * Snapshotting the Set bounds the wait: reports started after this line are not awaited, so a handler
1519
- * that keeps emitting during shutdown cannot block the process forever. Call flush again for those.
1445
+ * Only reports already in flight are awaited, so a handler still emitting during shutdown cannot block
1446
+ * forever. Call flush again to catch those.
1520
1447
  */
1521
1448
  flush(timeoutMs = 2e3) {
1522
1449
  this._logger.flush();
@@ -1663,10 +1590,6 @@ var Flare = class {
1663
1590
  this.framework = framework;
1664
1591
  return this;
1665
1592
  }
1666
- /**
1667
- * True when a report must not be captured: consent withdrawn, or dropped by sampling. Consent is
1668
- * checked first, so a blocked report never runs the sampler or assembles a report (no cookie read).
1669
- */
1670
1593
  shouldSkipCapture() {
1671
1594
  if (this._config.hasConsent === false) return true;
1672
1595
  return this._config.sampleRate < 1 && Math.random() >= this._config.sampleRate;
@@ -1791,15 +1714,6 @@ var Flare = class {
1791
1714
  record: this.assembleAttributes(collectorRecord, userAttributes, false)
1792
1715
  };
1793
1716
  }
1794
- /**
1795
- * Local roots only, snapshotted by the Tracer at span START so a long-lived root does not drift into
1796
- * the next page's scope. Children get none, and no span ever runs the DOM collector.
1797
- *
1798
- * Everything assembled is inherited except user identity (excluding the opaque `user.id`): a root span
1799
- * goes out for every page view, so email, full name, IP and `user.attributes` would turn normal
1800
- * browsing into PII traffic. The rest — `context.custom`, `addContextGroup` bags — stays in, because
1801
- * the trace viewer renders any span attribute whose key does not start with `flare.`.
1802
- */
1803
1717
  getScopeAttributes() {
1804
1718
  const scoped = { ...this.assembleAttributes({}, {}, false) };
1805
1719
  for (const key of SPAN_SCOPE_EXCLUDED_KEYS) delete scoped[key];
@@ -1902,4 +1816,4 @@ function hasNetworkSignal(network) {
1902
1816
  }
1903
1817
 
1904
1818
  //#endregion
1905
- export { Api, BrowserSpanEventType, BrowserSpanType, DEFAULT_MAX_LIVE_TRACES, DEFAULT_URL_DENYLIST, Flare, FrameworkName, GlobalScopeProvider, InMemoryActiveSpanHolder, Logger, MAX_BREADCRUMB_URL_LENGTH, NoopFlushScheduler, NullDeviceInfoProvider, NullFileReader, Scope, SpanStatusCode, Tracer, USER_IDENTITY_KEYS, assert, assertKey, breadcrumbUrl, buildDeviceContextGroup, buildTraceparent, buildTracesEnvelope, convertToError, createIdentityTagger, createStackTrace, defaultNowNano, describeRejectionReason, deviceInfoToAttributes, extractCode, flatJsonStringify, getCodeSnippet, glowsToEvents, now, parseTraceparent, readLinesFromFile, recordBreadcrumb, redactObjectValues, redactUrlQuery, resolveDenylist, routeRejection, safeClone, safeDecode, spanId, toCustomContext, urlAttributes, userIdentityAttributes };
1819
+ export { Api, BrowserSpanEventType, BrowserSpanType, DEFAULT_MAX_LIVE_TRACES, DEFAULT_URL_DENYLIST, Flare, FrameworkName, GlobalScopeProvider, InMemoryActiveSpanHolder, Logger, MAX_BREADCRUMB_URL_LENGTH, NoopFlushScheduler, NullDeviceInfoProvider, NullFileReader, Scope, SpanStatusCode, Tracer, USER_IDENTITY_KEYS, assert, assertKey, breadcrumbUrl, buildDeviceContextGroup, buildTraceparent, buildTracesEnvelope, convertToError, createIdentityTagger, createStackTrace, defaultNowNano, describeRejectionReason, deviceInfoToAttributes, evictLruIfNew, extractCode, flatJsonStringify, getCodeSnippet, glowsToEvents, now, parseTraceparent, readLinesFromFile, recordBreadcrumb, redactObjectValues, redactUrlQuery, resolveDenylist, routeRejection, safeClone, safeDecode, spanId, toCustomContext, urlAttributes, userIdentityAttributes };
@@ -1,10 +1,10 @@
1
1
  //#region src/framework.d.ts
2
2
  /**
3
- * Framework names the Flare backend recognises. Wire format, so the values never change: they ship as
4
- * `flare.framework.name` and (lowercased) as `context.custom.framework`.
3
+ * Framework names the Flare backend recognizes. Wire format: these values never change, since they
4
+ * ship as `flare.framework.name` and (lowercased) as `context.custom.framework`.
5
5
  *
6
- * `Js` and `Node` are the base SDKs' fallback claim, overwritten when a framework package tags its
7
- * own name. `NodeElectron` is an Electron main process; its renderers report their own.
6
+ * `Js` and `Node` are fallback claims from the base SDKs, overwritten when a framework package sets
7
+ * its own name. `NodeElectron` is the Electron main process; renderers report their own name.
8
8
  */
9
9
  declare const FrameworkName: {
10
10
  readonly Js: "js";
@@ -20,7 +20,7 @@ type FrameworkName = (typeof FrameworkName)[keyof typeof FrameworkName];
20
20
  //#endregion
21
21
  //#region src/spanTypes.d.ts
22
22
  /**
23
- * Span types the Flare backend recognises. Wire format, so the values never change: they ship as the
23
+ * Span types the Flare backend recognizes. Wire format, so the values never change: they ship as the
24
24
  * `flare.span_type` attribute and the backend groups performance data by them.
25
25
  *
26
26
  * These are the browser client's set. They live in core because core's `SpanOptions.spanType` needs
@@ -37,6 +37,10 @@ declare const BrowserSpanType: {
37
37
  type BrowserSpanType = (typeof BrowserSpanType)[keyof typeof BrowserSpanType];
38
38
  /** Any other value stays legal, so a host SDK can stamp its own without a core release. */
39
39
  type SpanTypeName = BrowserSpanType | (string & {});
40
+ /**
41
+ * Span event types on an error report. Kept apart from `BrowserSpanType`: these are points in time,
42
+ * not spans with a duration. That is also why a route change is not called `browser_navigation`.
43
+ */
40
44
  declare const BrowserSpanEventType: {
41
45
  readonly Click: "browser_click";
42
46
  readonly Input: "browser_input";
@@ -363,6 +367,9 @@ declare function createIdentityTagger(config: {
363
367
  tagFramework(flare: SdkTaggable, frameworkVersion?: string): void;
364
368
  };
365
369
  //#endregion
370
+ //#region src/util/evictLruIfNew.d.ts
371
+ declare function evictLruIfNew<V>(map: Map<string, V>, key: string, cap: number): void;
372
+ //#endregion
366
373
  //#region src/util/extractCode.d.ts
367
374
  declare function extractCode(error: Error): string | undefined;
368
375
  //#endregion
@@ -384,6 +391,10 @@ declare function timelineEvents(glows: Glow[], breadcrumbs: SpanEvent[]): SpanEv
384
391
  declare function now(): number;
385
392
  //#endregion
386
393
  //#region src/util/redactUrl.d.ts
394
+ /**
395
+ * Matched against query-string keys, cookie names, and (in framework SDKs) prop/route-param keys. Values for
396
+ * matching keys are replaced with [redacted] before sending so credentials/PII don't leak in error reports.
397
+ */
387
398
  declare const DEFAULT_URL_DENYLIST: RegExp;
388
399
  declare function resolveDenylist(custom?: RegExp, replaceDefault?: boolean, defaultDenylist?: RegExp): RegExp;
389
400
  /**
@@ -411,9 +422,9 @@ type RejectionReporter = {
411
422
  declare function describeRejectionReason(reason: unknown): string;
412
423
  /**
413
424
  * Routes by whether `reason` carries a stack: stack-bearing reasons go to `reportSilently`, stackless
414
- * ones to `reportUnhandledRejection`.
415
- * The `.catch` is what stops a transport failure from surfacing as a second unhandled rejection.
416
- * `reportSilently` is assumed async and left unwrapped, so a synchronous throw there still propagates.
425
+ * ones to `reportUnhandledRejection`. The `.catch` stops a transport failure from surfacing as a second
426
+ * unhandled rejection. `reportSilently` is assumed async and left unwrapped, so a synchronous throw there
427
+ * still propagates.
417
428
  */
418
429
  declare function routeRejection(reporter: RejectionReporter, reason: unknown): void;
419
430
  //#endregion
@@ -467,4 +478,4 @@ declare const MAX_URL_LENGTH = 2048;
467
478
  */
468
479
  declare function urlAttributes(url: string, denylist?: RegExp): Attributes;
469
480
  //#endregion
470
- export { TracesEnvelope as $, Attributes as A, MessageLevel as B, convertToError as C, assert as D, assertKey as E, EntryPointType as F, SamplingContext as G, OtelSpan as H, Framework as I, SpanEvent as J, SdkInfo as K, Glow as L, BufferedSpan as M, Config as N, AnyValue as O, EntryPointHandler as P, StackFrame as Q, KeyValue as R, createIdentityTagger as S, createComponentMatcher as T, OverriddenGrouping as U, OtelLogRecord as V, Report as W, SpanStatus as X, SpanOptions as Y, SpanStatusCode as Z, timelineEvents as _, setDefined as a, FrameworkName as at, extractCode as b, RejectionReporter as c, DEFAULT_URL_DENYLIST as d, TracesSampler as et, redactObjectValues as f, now as g, safeDecode as h, withoutStatefulFlags as i, SpanTypeName as it, BufferedLog as j, AttributeValue as k, describeRejectionReason as l, resolveDenylist as m, urlAttributes as n, BrowserSpanEventType as nt, SafeCloneOptions as o, redactUrlQuery as p, Span as q, toCustomContext as r, BrowserSpanType as rt, safeClone as s, MAX_URL_LENGTH as t, User as tt, routeRejection as u, glowsToEvents as v, ProfileComponentsOption as w, SdkTaggable as x, flatJsonStringify as y, LogsEnvelope as z };
481
+ export { StackFrame as $, AttributeValue as A, LogsEnvelope as B, createIdentityTagger as C, assertKey as D, createComponentMatcher as E, EntryPointHandler as F, Report as G, OtelLogRecord as H, EntryPointType as I, Span as J, SamplingContext as K, Framework as L, BufferedLog as M, BufferedSpan as N, assert as O, Config as P, SpanStatusCode as Q, Glow as R, SdkTaggable as S, ProfileComponentsOption as T, OtelSpan as U, MessageLevel as V, OverriddenGrouping as W, SpanOptions as X, SpanEvent as Y, SpanStatus as Z, timelineEvents as _, setDefined as a, SpanTypeName as at, extractCode as b, RejectionReporter as c, DEFAULT_URL_DENYLIST as d, TracesEnvelope as et, redactObjectValues as f, now as g, safeDecode as h, withoutStatefulFlags as i, BrowserSpanType as it, Attributes as j, AnyValue as k, describeRejectionReason as l, resolveDenylist as m, urlAttributes as n, User as nt, SafeCloneOptions as o, FrameworkName as ot, redactUrlQuery as p, SdkInfo as q, toCustomContext as r, BrowserSpanEventType as rt, safeClone as s, MAX_URL_LENGTH as t, TracesSampler as tt, routeRejection as u, glowsToEvents as v, convertToError as w, evictLruIfNew as x, flatJsonStringify as y, KeyValue as z };