@flareapp/core 2.8.0 → 2.10.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.cjs CHANGED
@@ -26,7 +26,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  }) : target, mod));
27
27
 
28
28
  //#endregion
29
- const require_urlAttributes = require('./urlAttributes-CNGTgOJp.cjs');
29
+ const require_urlAttributes = require('./urlAttributes-B37JykP3.cjs');
30
30
  let error_stack_parser = require("error-stack-parser");
31
31
  error_stack_parser = __toESM(error_stack_parser);
32
32
 
@@ -66,6 +66,11 @@ const BrowserSpanType = {
66
66
  Component: "browser_component",
67
67
  WebVital: "browser_web_vital"
68
68
  };
69
+ const BrowserSpanEventType = {
70
+ Click: "browser_click",
71
+ Input: "browser_input",
72
+ RouteChange: "browser_route_change"
73
+ };
69
74
 
70
75
  //#endregion
71
76
  //#region src/types.ts
@@ -175,6 +180,23 @@ var Api = class {
175
180
  }
176
181
  };
177
182
 
183
+ //#endregion
184
+ //#region src/breadcrumbs/recordBreadcrumb.ts
185
+ const MAX_BREADCRUMB_URL_LENGTH = 256;
186
+ function breadcrumbUrl(href, denylist) {
187
+ const redacted = require_urlAttributes.redactUrlQuery(href, denylist);
188
+ return redacted.length > MAX_BREADCRUMB_URL_LENGTH ? redacted.slice(0, MAX_BREADCRUMB_URL_LENGTH) : redacted;
189
+ }
190
+ function recordBreadcrumb(scopeProvider, config, type, attributes, startTimeUnixNano) {
191
+ if (!config.enableBreadcrumbs) return;
192
+ scopeProvider.active().addBreadcrumb({
193
+ type,
194
+ startTimeUnixNano,
195
+ endTimeUnixNano: null,
196
+ attributes
197
+ }, config.maxBreadcrumbs);
198
+ }
199
+
178
200
  //#endregion
179
201
  //#region src/telemetry/TelemetryBuffer.ts
180
202
  /**
@@ -198,6 +220,7 @@ var TelemetryBuffer = class {
198
220
  }
199
221
  add(record) {
200
222
  const config = this.deps.getConfig();
223
+ if (config.hasConsent === false) return;
201
224
  const limits = this.policy.limits(config);
202
225
  const bytes = this.policy.estimateBytes(record);
203
226
  if (bytes > limits.maxBytes) {
@@ -217,6 +240,10 @@ var TelemetryBuffer = class {
217
240
  const config = this.deps.getConfig();
218
241
  if (!this.policy.enabled(config)) return;
219
242
  if (this.entries.length === 0) return;
243
+ if (config.hasConsent === false) {
244
+ this.clearTimer();
245
+ return;
246
+ }
220
247
  if (!require_urlAttributes.assertKey(config.key, config.debug)) {
221
248
  this.clearTimer();
222
249
  return;
@@ -552,6 +579,7 @@ var Logger = class {
552
579
  }
553
580
  record(level, message, context, attributes) {
554
581
  const config = this.deps.getConfig();
582
+ if (config.hasConsent === false) return;
555
583
  if (!config.enableLogs) return;
556
584
  if (config.minimumLogLevel && !isAtOrAboveMinimum(level, config.minimumLogLevel)) return;
557
585
  const userAttributes = {
@@ -633,6 +661,7 @@ function userIdentityAttributes(scope) {
633
661
  */
634
662
  var Scope = class {
635
663
  glows = [];
664
+ breadcrumbs = [];
636
665
  pendingAttributes = {};
637
666
  entryPoint = null;
638
667
  /** Caps at `maxGlowsPerReport` by dropping the oldest, so the payload stays bounded. */
@@ -643,6 +672,15 @@ var Scope = class {
643
672
  clearGlows() {
644
673
  this.glows = [];
645
674
  }
675
+ /** Drops the oldest when full. */
676
+ addBreadcrumb(breadcrumb, maxBreadcrumbs) {
677
+ if (maxBreadcrumbs <= 0) return;
678
+ this.breadcrumbs.push(breadcrumb);
679
+ if (this.breadcrumbs.length > maxBreadcrumbs) this.breadcrumbs = this.breadcrumbs.slice(this.breadcrumbs.length - maxBreadcrumbs);
680
+ }
681
+ clearBreadcrumbs() {
682
+ this.breadcrumbs = [];
683
+ }
646
684
  setAttribute(key, value) {
647
685
  this.pendingAttributes[key] = value;
648
686
  }
@@ -1409,10 +1447,13 @@ var Flare = class {
1409
1447
  _tracer;
1410
1448
  _config = {
1411
1449
  key: null,
1450
+ hasConsent: true,
1412
1451
  version: "",
1413
1452
  sourcemapVersionId: require_urlAttributes.SOURCEMAP_VERSION,
1414
1453
  stage: "",
1415
1454
  maxGlowsPerReport: 30,
1455
+ enableBreadcrumbs: false,
1456
+ maxBreadcrumbs: 100,
1416
1457
  ingestUrl: "https://ingress.flareapp.io/v1/errors",
1417
1458
  reportBrowserExtensionErrors: false,
1418
1459
  debug: false,
@@ -1548,9 +1589,25 @@ var Flare = class {
1548
1589
  this._tracer.flush();
1549
1590
  return this;
1550
1591
  }
1592
+ /**
1593
+ * Turn sending on or off for consent. Off blocks errors, logs, and traces, and drops telemetry
1594
+ * captured earlier so a later grant cannot ship it. On re-grant, flushes anything still buffered.
1595
+ */
1596
+ setConsent(granted) {
1597
+ this._config.hasConsent = granted;
1598
+ if (granted) {
1599
+ this._logger.flush();
1600
+ this._tracer.flush();
1601
+ } else {
1602
+ this._logger.clear();
1603
+ this._tracer.clear();
1604
+ }
1605
+ return this;
1606
+ }
1551
1607
  configure(config) {
1552
1608
  const wasLogsEnabled = this._config.enableLogs;
1553
1609
  const wasTracingEnabled = this._config.enableTracing;
1610
+ const wasBreadcrumbsEnabled = this._config.enableBreadcrumbs;
1554
1611
  this._config = {
1555
1612
  ...this._config,
1556
1613
  ...config
@@ -1560,6 +1617,7 @@ var Flare = class {
1560
1617
  if (config.urlDenylist !== void 0 || config.replaceDefaultUrlDenylist !== void 0) this._config.urlDenylist = require_urlAttributes.resolveDenylist(config.urlDenylist, config.replaceDefaultUrlDenylist ?? this._config.replaceDefaultUrlDenylist);
1561
1618
  if (wasLogsEnabled && this._config.enableLogs === false) this._logger.clear();
1562
1619
  if (config.key !== void 0) this._logger.flush();
1620
+ if (wasBreadcrumbsEnabled && this._config.enableBreadcrumbs === false) this.scopeProvider.active().clearBreadcrumbs();
1563
1621
  if (wasTracingEnabled && this._config.enableTracing === false) this._tracer.clear();
1564
1622
  if (config.key !== void 0) this._tracer.flush();
1565
1623
  return this;
@@ -1583,6 +1641,9 @@ var Flare = class {
1583
1641
  }, this._config.maxGlowsPerReport);
1584
1642
  return this;
1585
1643
  }
1644
+ addBreadcrumb(type, attributes, startTimeUnixNano) {
1645
+ recordBreadcrumb(this.scopeProvider, this._config, type, attributes, startTimeUnixNano);
1646
+ }
1586
1647
  clearGlows() {
1587
1648
  this.scopeProvider.active().clearGlows();
1588
1649
  return this;
@@ -1629,11 +1690,19 @@ var Flare = class {
1629
1690
  this.framework = framework;
1630
1691
  return this;
1631
1692
  }
1693
+ /**
1694
+ * True when a report must not be captured: consent withdrawn, or dropped by sampling. Consent is
1695
+ * checked first, so a blocked report never runs the sampler or assembles a report (no cookie read).
1696
+ */
1697
+ shouldSkipCapture() {
1698
+ if (this._config.hasConsent === false) return true;
1699
+ return this._config.sampleRate < 1 && Math.random() >= this._config.sampleRate;
1700
+ }
1632
1701
  report(error, attributes = {}) {
1633
1702
  return this.track(this.reportInternal(error, attributes));
1634
1703
  }
1635
1704
  async reportInternal(error, attributes = {}) {
1636
- if (this._config.sampleRate < 1 && Math.random() >= this._config.sampleRate) return;
1705
+ if (this.shouldSkipCapture()) return;
1637
1706
  const seenAtUnixNano = Date.now() * 1e6;
1638
1707
  const coerced = error instanceof Error ? error : new Error(String(error));
1639
1708
  const errorToReport = await this._config.beforeEvaluate(coerced);
@@ -1649,7 +1718,7 @@ var Flare = class {
1649
1718
  return this.track(this.reportUnhandledRejectionInternal(message, attributes));
1650
1719
  }
1651
1720
  async reportUnhandledRejectionInternal(message, attributes = {}) {
1652
- if (this._config.sampleRate < 1 && Math.random() >= this._config.sampleRate) return;
1721
+ if (this.shouldSkipCapture()) return;
1653
1722
  const seenAtUnixNano = Date.now() * 1e6;
1654
1723
  const report = this.buildReport({
1655
1724
  exceptionClass: "UnhandledRejection",
@@ -1667,7 +1736,7 @@ var Flare = class {
1667
1736
  return this.track(this.reportMessageInternal(message, level, attributes));
1668
1737
  }
1669
1738
  async reportMessageInternal(message, level, attributes = {}) {
1670
- if (this._config.sampleRate < 1 && Math.random() >= this._config.sampleRate) return;
1739
+ if (this.shouldSkipCapture()) return;
1671
1740
  const seenAtUnixNano = Date.now() * 1e6;
1672
1741
  const stackTrace = await createStackTrace(/* @__PURE__ */ new Error(), this._config.debug, this.fileReader);
1673
1742
  stackTrace.shift();
@@ -1774,7 +1843,7 @@ var Flare = class {
1774
1843
  message: input.message,
1775
1844
  seenAtUnixNano: input.seenAtUnixNano,
1776
1845
  stacktrace: input.stacktrace,
1777
- events: require_urlAttributes.glowsToEvents(activeScope.glows),
1846
+ events: require_urlAttributes.timelineEvents(activeScope.glows, activeScope.breadcrumbs),
1778
1847
  attributes
1779
1848
  };
1780
1849
  if (input.isLog) report.isLog = true;
@@ -1784,6 +1853,7 @@ var Flare = class {
1784
1853
  return report;
1785
1854
  }
1786
1855
  async sendReport(report) {
1856
+ if (this._config.hasConsent === false) return;
1787
1857
  if (!require_urlAttributes.assertKey(this._config.key, this._config.debug)) return;
1788
1858
  const reportToSubmit = await this._config.beforeSubmit(report);
1789
1859
  if (!reportToSubmit) return;
@@ -1793,6 +1863,7 @@ var Flare = class {
1793
1863
 
1794
1864
  //#endregion
1795
1865
  exports.Api = Api;
1866
+ exports.BrowserSpanEventType = BrowserSpanEventType;
1796
1867
  exports.BrowserSpanType = BrowserSpanType;
1797
1868
  exports.DEFAULT_MAX_LIVE_TRACES = DEFAULT_MAX_LIVE_TRACES;
1798
1869
  exports.DEFAULT_URL_DENYLIST = require_urlAttributes.DEFAULT_URL_DENYLIST;
@@ -1801,6 +1872,7 @@ exports.FrameworkName = FrameworkName;
1801
1872
  exports.GlobalScopeProvider = GlobalScopeProvider;
1802
1873
  exports.InMemoryActiveSpanHolder = InMemoryActiveSpanHolder;
1803
1874
  exports.Logger = Logger;
1875
+ exports.MAX_BREADCRUMB_URL_LENGTH = MAX_BREADCRUMB_URL_LENGTH;
1804
1876
  exports.NoopFlushScheduler = NoopFlushScheduler;
1805
1877
  exports.NullFileReader = NullFileReader;
1806
1878
  exports.Scope = Scope;
@@ -1809,6 +1881,7 @@ exports.Tracer = Tracer;
1809
1881
  exports.USER_IDENTITY_KEYS = USER_IDENTITY_KEYS;
1810
1882
  exports.assert = require_urlAttributes.assert;
1811
1883
  exports.assertKey = require_urlAttributes.assertKey;
1884
+ exports.breadcrumbUrl = breadcrumbUrl;
1812
1885
  exports.buildTraceparent = buildTraceparent;
1813
1886
  exports.buildTracesEnvelope = buildTracesEnvelope;
1814
1887
  exports.convertToError = require_urlAttributes.convertToError;
@@ -1823,6 +1896,7 @@ exports.glowsToEvents = require_urlAttributes.glowsToEvents;
1823
1896
  exports.now = require_urlAttributes.now;
1824
1897
  exports.parseTraceparent = parseTraceparent;
1825
1898
  exports.readLinesFromFile = readLinesFromFile;
1899
+ exports.recordBreadcrumb = recordBreadcrumb;
1826
1900
  exports.redactObjectValues = require_urlAttributes.redactObjectValues;
1827
1901
  exports.redactUrlQuery = require_urlAttributes.redactUrlQuery;
1828
1902
  exports.resolveDenylist = require_urlAttributes.resolveDenylist;
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as User, A as BufferedSpan, B as OtelSpan, D as AttributeValue, E as AnyValue, F as Glow, G as Span, H as Report, I as KeyValue, J as SpanStatus, K as SpanEvent, L as LogsEnvelope, M as EntryPointHandler, N as EntryPointType, O as Attributes, P as Framework, Q as TracesSampler, R as MessageLevel, T as assert, U as SamplingContext, V as OverriddenGrouping, W as SdkInfo, X as StackFrame, Y as SpanStatusCode, Z as TracesEnvelope, _ as flatJsonStringify, a as SafeCloneOptions, b as createIdentityTagger, c as describeRejectionReason, d as redactObjectValues, et as BrowserSpanType, f as redactUrlQuery, g as glowsToEvents, h as now, j as Config, k as BufferedLog, l as routeRejection, m as safeDecode, n as urlAttributes, nt as FrameworkName, o as safeClone, p as resolveDenylist, q as SpanOptions, r as toCustomContext, s as RejectionReporter, tt as SpanTypeName, u as DEFAULT_URL_DENYLIST, v as extractCode, w as assertKey, x as convertToError, y as SdkTaggable, z as OtelLogRecord } from "./urlAttributes-CvOw6tU3.cjs";
1
+ import { $ as TracesSampler, A as BufferedLog, B as OtelLogRecord, D as AnyValue, E as assert, F as Framework, G as SdkInfo, H as OverriddenGrouping, I as Glow, J as SpanOptions, K as Span, L as KeyValue, M as Config, N as EntryPointHandler, O as AttributeValue, P as EntryPointType, Q as TracesEnvelope, R as LogsEnvelope, S as convertToError, T as assertKey, U as Report, V as OtelSpan, W as SamplingContext, X as SpanStatusCode, Y as SpanStatus, Z as StackFrame, _ as glowsToEvents, a as SafeCloneOptions, b as SdkTaggable, c as describeRejectionReason, d as redactObjectValues, et as User, f as redactUrlQuery, h as now, it as FrameworkName, j as BufferedSpan, k as Attributes, l as routeRejection, m as safeDecode, n as urlAttributes, nt as BrowserSpanType, o as safeClone, p as resolveDenylist, q as SpanEvent, r as toCustomContext, rt as SpanTypeName, s as RejectionReporter, tt as BrowserSpanEventType, u as DEFAULT_URL_DENYLIST, v as flatJsonStringify, x as createIdentityTagger, y as extractCode, z as MessageLevel } from "./urlAttributes-DW_i-YQ3.cjs";
2
2
 
3
3
  //#region src/api/Api.d.ts
4
4
  declare class Api {
@@ -82,11 +82,15 @@ declare function userIdentityAttributes(scope: Scope): Attributes;
82
82
  */
83
83
  declare class Scope {
84
84
  glows: Glow[];
85
+ breadcrumbs: SpanEvent[];
85
86
  pendingAttributes: Attributes;
86
87
  entryPoint: EntryPointHandler | null;
87
88
  /** Caps at `maxGlowsPerReport` by dropping the oldest, so the payload stays bounded. */
88
89
  addGlow(glow: Glow, maxGlowsPerReport: number): void;
89
90
  clearGlows(): void;
91
+ /** Drops the oldest when full. */
92
+ addBreadcrumb(breadcrumb: SpanEvent, maxBreadcrumbs: number): void;
93
+ clearBreadcrumbs(): void;
90
94
  setAttribute(key: string, value: AttributeValue): void;
91
95
  /** Shallow: last write wins per key, nested objects are not deep-merged. */
92
96
  mergeAttributes(partial: Attributes): void;
@@ -273,10 +277,16 @@ declare class Flare {
273
277
  */
274
278
  withSpan<T>(name: string, fn: (span: Span) => T, opts?: SpanOptions): T;
275
279
  light(key?: string, debug?: boolean): this;
280
+ /**
281
+ * Turn sending on or off for consent. Off blocks errors, logs, and traces, and drops telemetry
282
+ * captured earlier so a later grant cannot ship it. On re-grant, flushes anything still buffered.
283
+ */
284
+ setConsent(granted: boolean): this;
276
285
  configure(config: Partial<Config>): this;
277
286
  test(): Promise<void>;
278
287
  private testInternal;
279
288
  glow(name: string, level?: MessageLevel, data?: Record<string, unknown> | Record<string, unknown>[]): this;
289
+ protected addBreadcrumb(type: string, attributes: Attributes, startTimeUnixNano: number): void;
280
290
  clearGlows(): this;
281
291
  addContext(name: string, value: AttributeValue): this;
282
292
  addContextGroup(groupName: string, value: Record<string, AttributeValue>): this;
@@ -288,6 +298,11 @@ declare class Flare {
288
298
  setEntryPoint(handler: EntryPointHandler): this;
289
299
  setSdkInfo(info: SdkInfo): this;
290
300
  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
+ private shouldSkipCapture;
291
306
  report(error: Error, attributes?: Attributes): Promise<void>;
292
307
  private reportInternal;
293
308
  reportSilently(error: Error, attributes?: Attributes): void;
@@ -314,6 +329,11 @@ declare class Flare {
314
329
  sendReport(report: Report): Promise<void>;
315
330
  }
316
331
  //#endregion
332
+ //#region src/breadcrumbs/recordBreadcrumb.d.ts
333
+ declare const MAX_BREADCRUMB_URL_LENGTH = 256;
334
+ declare function breadcrumbUrl(href: string, denylist: RegExp): string;
335
+ declare function recordBreadcrumb(scopeProvider: ScopeProvider, config: Config, type: string, attributes: Attributes, startTimeUnixNano: number): void;
336
+ //#endregion
317
337
  //#region src/tracing/envelope.d.ts
318
338
  declare function buildTracesEnvelope(spans: BufferedSpan[], resourceAttributes: Attributes, scopeName: string, scopeVersion: string): TracesEnvelope;
319
339
  //#endregion
@@ -343,4 +363,4 @@ declare class NullFileReader implements FileReader {
343
363
  //#region src/stacktrace/createStackTrace.d.ts
344
364
  declare function createStackTrace(error: Error, debug: boolean, fileReader: FileReader): Promise<Array<StackFrame>>;
345
365
  //#endregion
346
- export { type ActiveSpanHolder, type AnyValue, Api, type AttributeValue, type Attributes, BrowserSpanType, type BufferedLog, type BufferedSpan, type Config, type ContextCollector, DEFAULT_MAX_LIVE_TRACES, DEFAULT_URL_DENYLIST, 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, type MessageLevel, NoopFlushScheduler, 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, buildTraceparent, buildTracesEnvelope, convertToError, createIdentityTagger, createStackTrace, defaultNowNano, describeRejectionReason, extractCode, flatJsonStringify, getCodeSnippet, glowsToEvents, now, parseTraceparent, readLinesFromFile, redactObjectValues, redactUrlQuery, resolveDenylist, routeRejection, safeClone, safeDecode, spanId, toCustomContext, urlAttributes, userIdentityAttributes };
366
+ 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 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, 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, buildTraceparent, buildTracesEnvelope, convertToError, createIdentityTagger, createStackTrace, defaultNowNano, describeRejectionReason, extractCode, flatJsonStringify, getCodeSnippet, glowsToEvents, now, parseTraceparent, readLinesFromFile, recordBreadcrumb, redactObjectValues, redactUrlQuery, resolveDenylist, routeRejection, safeClone, safeDecode, spanId, toCustomContext, urlAttributes, userIdentityAttributes };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as User, A as BufferedSpan, B as OtelSpan, D as AttributeValue, E as AnyValue, F as Glow, G as Span, H as Report, I as KeyValue, J as SpanStatus, K as SpanEvent, L as LogsEnvelope, M as EntryPointHandler, N as EntryPointType, O as Attributes, P as Framework, Q as TracesSampler, R as MessageLevel, T as assert, U as SamplingContext, V as OverriddenGrouping, W as SdkInfo, X as StackFrame, Y as SpanStatusCode, Z as TracesEnvelope, _ as flatJsonStringify, a as SafeCloneOptions, b as createIdentityTagger, c as describeRejectionReason, d as redactObjectValues, et as BrowserSpanType, f as redactUrlQuery, g as glowsToEvents, h as now, j as Config, k as BufferedLog, l as routeRejection, m as safeDecode, n as urlAttributes, nt as FrameworkName, o as safeClone, p as resolveDenylist, q as SpanOptions, r as toCustomContext, s as RejectionReporter, tt as SpanTypeName, u as DEFAULT_URL_DENYLIST, v as extractCode, w as assertKey, x as convertToError, y as SdkTaggable, z as OtelLogRecord } from "./urlAttributes-B9BlkrfW.mjs";
1
+ import { $ as TracesSampler, A as BufferedLog, B as OtelLogRecord, D as AnyValue, E as assert, F as Framework, G as SdkInfo, H as OverriddenGrouping, I as Glow, J as SpanOptions, K as Span, L as KeyValue, M as Config, N as EntryPointHandler, O as AttributeValue, P as EntryPointType, Q as TracesEnvelope, R as LogsEnvelope, S as convertToError, T as assertKey, U as Report, V as OtelSpan, W as SamplingContext, X as SpanStatusCode, Y as SpanStatus, Z as StackFrame, _ as glowsToEvents, a as SafeCloneOptions, b as SdkTaggable, c as describeRejectionReason, d as redactObjectValues, et as User, f as redactUrlQuery, h as now, it as FrameworkName, j as BufferedSpan, k as Attributes, l as routeRejection, m as safeDecode, n as urlAttributes, nt as BrowserSpanType, o as safeClone, p as resolveDenylist, q as SpanEvent, r as toCustomContext, rt as SpanTypeName, s as RejectionReporter, tt as BrowserSpanEventType, u as DEFAULT_URL_DENYLIST, v as flatJsonStringify, x as createIdentityTagger, y as extractCode, z as MessageLevel } from "./urlAttributes-CYsfTfi9.mjs";
2
2
 
3
3
  //#region src/api/Api.d.ts
4
4
  declare class Api {
@@ -82,11 +82,15 @@ declare function userIdentityAttributes(scope: Scope): Attributes;
82
82
  */
83
83
  declare class Scope {
84
84
  glows: Glow[];
85
+ breadcrumbs: SpanEvent[];
85
86
  pendingAttributes: Attributes;
86
87
  entryPoint: EntryPointHandler | null;
87
88
  /** Caps at `maxGlowsPerReport` by dropping the oldest, so the payload stays bounded. */
88
89
  addGlow(glow: Glow, maxGlowsPerReport: number): void;
89
90
  clearGlows(): void;
91
+ /** Drops the oldest when full. */
92
+ addBreadcrumb(breadcrumb: SpanEvent, maxBreadcrumbs: number): void;
93
+ clearBreadcrumbs(): void;
90
94
  setAttribute(key: string, value: AttributeValue): void;
91
95
  /** Shallow: last write wins per key, nested objects are not deep-merged. */
92
96
  mergeAttributes(partial: Attributes): void;
@@ -273,10 +277,16 @@ declare class Flare {
273
277
  */
274
278
  withSpan<T>(name: string, fn: (span: Span) => T, opts?: SpanOptions): T;
275
279
  light(key?: string, debug?: boolean): this;
280
+ /**
281
+ * Turn sending on or off for consent. Off blocks errors, logs, and traces, and drops telemetry
282
+ * captured earlier so a later grant cannot ship it. On re-grant, flushes anything still buffered.
283
+ */
284
+ setConsent(granted: boolean): this;
276
285
  configure(config: Partial<Config>): this;
277
286
  test(): Promise<void>;
278
287
  private testInternal;
279
288
  glow(name: string, level?: MessageLevel, data?: Record<string, unknown> | Record<string, unknown>[]): this;
289
+ protected addBreadcrumb(type: string, attributes: Attributes, startTimeUnixNano: number): void;
280
290
  clearGlows(): this;
281
291
  addContext(name: string, value: AttributeValue): this;
282
292
  addContextGroup(groupName: string, value: Record<string, AttributeValue>): this;
@@ -288,6 +298,11 @@ declare class Flare {
288
298
  setEntryPoint(handler: EntryPointHandler): this;
289
299
  setSdkInfo(info: SdkInfo): this;
290
300
  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
+ private shouldSkipCapture;
291
306
  report(error: Error, attributes?: Attributes): Promise<void>;
292
307
  private reportInternal;
293
308
  reportSilently(error: Error, attributes?: Attributes): void;
@@ -314,6 +329,11 @@ declare class Flare {
314
329
  sendReport(report: Report): Promise<void>;
315
330
  }
316
331
  //#endregion
332
+ //#region src/breadcrumbs/recordBreadcrumb.d.ts
333
+ declare const MAX_BREADCRUMB_URL_LENGTH = 256;
334
+ declare function breadcrumbUrl(href: string, denylist: RegExp): string;
335
+ declare function recordBreadcrumb(scopeProvider: ScopeProvider, config: Config, type: string, attributes: Attributes, startTimeUnixNano: number): void;
336
+ //#endregion
317
337
  //#region src/tracing/envelope.d.ts
318
338
  declare function buildTracesEnvelope(spans: BufferedSpan[], resourceAttributes: Attributes, scopeName: string, scopeVersion: string): TracesEnvelope;
319
339
  //#endregion
@@ -343,4 +363,4 @@ declare class NullFileReader implements FileReader {
343
363
  //#region src/stacktrace/createStackTrace.d.ts
344
364
  declare function createStackTrace(error: Error, debug: boolean, fileReader: FileReader): Promise<Array<StackFrame>>;
345
365
  //#endregion
346
- export { type ActiveSpanHolder, type AnyValue, Api, type AttributeValue, type Attributes, BrowserSpanType, type BufferedLog, type BufferedSpan, type Config, type ContextCollector, DEFAULT_MAX_LIVE_TRACES, DEFAULT_URL_DENYLIST, 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, type MessageLevel, NoopFlushScheduler, 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, buildTraceparent, buildTracesEnvelope, convertToError, createIdentityTagger, createStackTrace, defaultNowNano, describeRejectionReason, extractCode, flatJsonStringify, getCodeSnippet, glowsToEvents, now, parseTraceparent, readLinesFromFile, redactObjectValues, redactUrlQuery, resolveDenylist, routeRejection, safeClone, safeDecode, spanId, toCustomContext, urlAttributes, userIdentityAttributes };
366
+ 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 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, 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, buildTraceparent, buildTracesEnvelope, convertToError, createIdentityTagger, createStackTrace, defaultNowNano, describeRejectionReason, extractCode, flatJsonStringify, getCodeSnippet, glowsToEvents, now, parseTraceparent, readLinesFromFile, recordBreadcrumb, redactObjectValues, redactUrlQuery, resolveDenylist, routeRejection, safeClone, safeDecode, spanId, toCustomContext, urlAttributes, userIdentityAttributes };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { D as KEY, E as CLIENT_VERSION, O as SOURCEMAP_VERSION, T as assert, _ as createTraversalBudget, a as routeRejection, b as createIdentityTagger, c as redactUrlQuery, d as now, f as glowsToEvents, g as TRUNCATED, h as MAX_TRAVERSAL_DEPTH, i as describeRejectionReason, l as resolveDenylist, m as safeClone, n as urlAttributes, o as DEFAULT_URL_DENYLIST, p as flatJsonStringify, r as toCustomContext, s as redactObjectValues, u as safeDecode, v as spendNode, w as assertKey, x as convertToError, y as extractCode } from "./urlAttributes-D3gCx23B.mjs";
1
+ import { D as CLIENT_VERSION, E as assert, O as KEY, S as convertToError, T as assertKey, _ as TRUNCATED, a as routeRejection, b as extractCode, c as redactUrlQuery, d as now, f as timelineEvents, g as MAX_TRAVERSAL_DEPTH, h as safeClone, i as describeRejectionReason, k as SOURCEMAP_VERSION, l as resolveDenylist, m as flatJsonStringify, n as urlAttributes, o as DEFAULT_URL_DENYLIST, p as glowsToEvents, r as toCustomContext, s as redactObjectValues, u as safeDecode, v as createTraversalBudget, x as createIdentityTagger, y as spendNode } from "./urlAttributes-DeDN7qtu.mjs";
2
2
  import ErrorStackParser from "error-stack-parser";
3
3
 
4
4
  //#region src/framework.ts
@@ -37,6 +37,11 @@ const BrowserSpanType = {
37
37
  Component: "browser_component",
38
38
  WebVital: "browser_web_vital"
39
39
  };
40
+ const BrowserSpanEventType = {
41
+ Click: "browser_click",
42
+ Input: "browser_input",
43
+ RouteChange: "browser_route_change"
44
+ };
40
45
 
41
46
  //#endregion
42
47
  //#region src/types.ts
@@ -146,6 +151,23 @@ var Api = class {
146
151
  }
147
152
  };
148
153
 
154
+ //#endregion
155
+ //#region src/breadcrumbs/recordBreadcrumb.ts
156
+ const MAX_BREADCRUMB_URL_LENGTH = 256;
157
+ function breadcrumbUrl(href, denylist) {
158
+ const redacted = redactUrlQuery(href, denylist);
159
+ return redacted.length > MAX_BREADCRUMB_URL_LENGTH ? redacted.slice(0, MAX_BREADCRUMB_URL_LENGTH) : redacted;
160
+ }
161
+ function recordBreadcrumb(scopeProvider, config, type, attributes, startTimeUnixNano) {
162
+ if (!config.enableBreadcrumbs) return;
163
+ scopeProvider.active().addBreadcrumb({
164
+ type,
165
+ startTimeUnixNano,
166
+ endTimeUnixNano: null,
167
+ attributes
168
+ }, config.maxBreadcrumbs);
169
+ }
170
+
149
171
  //#endregion
150
172
  //#region src/telemetry/TelemetryBuffer.ts
151
173
  /**
@@ -169,6 +191,7 @@ var TelemetryBuffer = class {
169
191
  }
170
192
  add(record) {
171
193
  const config = this.deps.getConfig();
194
+ if (config.hasConsent === false) return;
172
195
  const limits = this.policy.limits(config);
173
196
  const bytes = this.policy.estimateBytes(record);
174
197
  if (bytes > limits.maxBytes) {
@@ -188,6 +211,10 @@ var TelemetryBuffer = class {
188
211
  const config = this.deps.getConfig();
189
212
  if (!this.policy.enabled(config)) return;
190
213
  if (this.entries.length === 0) return;
214
+ if (config.hasConsent === false) {
215
+ this.clearTimer();
216
+ return;
217
+ }
191
218
  if (!assertKey(config.key, config.debug)) {
192
219
  this.clearTimer();
193
220
  return;
@@ -523,6 +550,7 @@ var Logger = class {
523
550
  }
524
551
  record(level, message, context, attributes) {
525
552
  const config = this.deps.getConfig();
553
+ if (config.hasConsent === false) return;
526
554
  if (!config.enableLogs) return;
527
555
  if (config.minimumLogLevel && !isAtOrAboveMinimum(level, config.minimumLogLevel)) return;
528
556
  const userAttributes = {
@@ -604,6 +632,7 @@ function userIdentityAttributes(scope) {
604
632
  */
605
633
  var Scope = class {
606
634
  glows = [];
635
+ breadcrumbs = [];
607
636
  pendingAttributes = {};
608
637
  entryPoint = null;
609
638
  /** Caps at `maxGlowsPerReport` by dropping the oldest, so the payload stays bounded. */
@@ -614,6 +643,15 @@ var Scope = class {
614
643
  clearGlows() {
615
644
  this.glows = [];
616
645
  }
646
+ /** Drops the oldest when full. */
647
+ addBreadcrumb(breadcrumb, maxBreadcrumbs) {
648
+ if (maxBreadcrumbs <= 0) return;
649
+ this.breadcrumbs.push(breadcrumb);
650
+ if (this.breadcrumbs.length > maxBreadcrumbs) this.breadcrumbs = this.breadcrumbs.slice(this.breadcrumbs.length - maxBreadcrumbs);
651
+ }
652
+ clearBreadcrumbs() {
653
+ this.breadcrumbs = [];
654
+ }
617
655
  setAttribute(key, value) {
618
656
  this.pendingAttributes[key] = value;
619
657
  }
@@ -1380,10 +1418,13 @@ var Flare = class {
1380
1418
  _tracer;
1381
1419
  _config = {
1382
1420
  key: null,
1421
+ hasConsent: true,
1383
1422
  version: "",
1384
1423
  sourcemapVersionId: SOURCEMAP_VERSION,
1385
1424
  stage: "",
1386
1425
  maxGlowsPerReport: 30,
1426
+ enableBreadcrumbs: false,
1427
+ maxBreadcrumbs: 100,
1387
1428
  ingestUrl: "https://ingress.flareapp.io/v1/errors",
1388
1429
  reportBrowserExtensionErrors: false,
1389
1430
  debug: false,
@@ -1519,9 +1560,25 @@ var Flare = class {
1519
1560
  this._tracer.flush();
1520
1561
  return this;
1521
1562
  }
1563
+ /**
1564
+ * Turn sending on or off for consent. Off blocks errors, logs, and traces, and drops telemetry
1565
+ * captured earlier so a later grant cannot ship it. On re-grant, flushes anything still buffered.
1566
+ */
1567
+ setConsent(granted) {
1568
+ this._config.hasConsent = granted;
1569
+ if (granted) {
1570
+ this._logger.flush();
1571
+ this._tracer.flush();
1572
+ } else {
1573
+ this._logger.clear();
1574
+ this._tracer.clear();
1575
+ }
1576
+ return this;
1577
+ }
1522
1578
  configure(config) {
1523
1579
  const wasLogsEnabled = this._config.enableLogs;
1524
1580
  const wasTracingEnabled = this._config.enableTracing;
1581
+ const wasBreadcrumbsEnabled = this._config.enableBreadcrumbs;
1525
1582
  this._config = {
1526
1583
  ...this._config,
1527
1584
  ...config
@@ -1531,6 +1588,7 @@ var Flare = class {
1531
1588
  if (config.urlDenylist !== void 0 || config.replaceDefaultUrlDenylist !== void 0) this._config.urlDenylist = resolveDenylist(config.urlDenylist, config.replaceDefaultUrlDenylist ?? this._config.replaceDefaultUrlDenylist);
1532
1589
  if (wasLogsEnabled && this._config.enableLogs === false) this._logger.clear();
1533
1590
  if (config.key !== void 0) this._logger.flush();
1591
+ if (wasBreadcrumbsEnabled && this._config.enableBreadcrumbs === false) this.scopeProvider.active().clearBreadcrumbs();
1534
1592
  if (wasTracingEnabled && this._config.enableTracing === false) this._tracer.clear();
1535
1593
  if (config.key !== void 0) this._tracer.flush();
1536
1594
  return this;
@@ -1554,6 +1612,9 @@ var Flare = class {
1554
1612
  }, this._config.maxGlowsPerReport);
1555
1613
  return this;
1556
1614
  }
1615
+ addBreadcrumb(type, attributes, startTimeUnixNano) {
1616
+ recordBreadcrumb(this.scopeProvider, this._config, type, attributes, startTimeUnixNano);
1617
+ }
1557
1618
  clearGlows() {
1558
1619
  this.scopeProvider.active().clearGlows();
1559
1620
  return this;
@@ -1600,11 +1661,19 @@ var Flare = class {
1600
1661
  this.framework = framework;
1601
1662
  return this;
1602
1663
  }
1664
+ /**
1665
+ * True when a report must not be captured: consent withdrawn, or dropped by sampling. Consent is
1666
+ * checked first, so a blocked report never runs the sampler or assembles a report (no cookie read).
1667
+ */
1668
+ shouldSkipCapture() {
1669
+ if (this._config.hasConsent === false) return true;
1670
+ return this._config.sampleRate < 1 && Math.random() >= this._config.sampleRate;
1671
+ }
1603
1672
  report(error, attributes = {}) {
1604
1673
  return this.track(this.reportInternal(error, attributes));
1605
1674
  }
1606
1675
  async reportInternal(error, attributes = {}) {
1607
- if (this._config.sampleRate < 1 && Math.random() >= this._config.sampleRate) return;
1676
+ if (this.shouldSkipCapture()) return;
1608
1677
  const seenAtUnixNano = Date.now() * 1e6;
1609
1678
  const coerced = error instanceof Error ? error : new Error(String(error));
1610
1679
  const errorToReport = await this._config.beforeEvaluate(coerced);
@@ -1620,7 +1689,7 @@ var Flare = class {
1620
1689
  return this.track(this.reportUnhandledRejectionInternal(message, attributes));
1621
1690
  }
1622
1691
  async reportUnhandledRejectionInternal(message, attributes = {}) {
1623
- if (this._config.sampleRate < 1 && Math.random() >= this._config.sampleRate) return;
1692
+ if (this.shouldSkipCapture()) return;
1624
1693
  const seenAtUnixNano = Date.now() * 1e6;
1625
1694
  const report = this.buildReport({
1626
1695
  exceptionClass: "UnhandledRejection",
@@ -1638,7 +1707,7 @@ var Flare = class {
1638
1707
  return this.track(this.reportMessageInternal(message, level, attributes));
1639
1708
  }
1640
1709
  async reportMessageInternal(message, level, attributes = {}) {
1641
- if (this._config.sampleRate < 1 && Math.random() >= this._config.sampleRate) return;
1710
+ if (this.shouldSkipCapture()) return;
1642
1711
  const seenAtUnixNano = Date.now() * 1e6;
1643
1712
  const stackTrace = await createStackTrace(/* @__PURE__ */ new Error(), this._config.debug, this.fileReader);
1644
1713
  stackTrace.shift();
@@ -1745,7 +1814,7 @@ var Flare = class {
1745
1814
  message: input.message,
1746
1815
  seenAtUnixNano: input.seenAtUnixNano,
1747
1816
  stacktrace: input.stacktrace,
1748
- events: glowsToEvents(activeScope.glows),
1817
+ events: timelineEvents(activeScope.glows, activeScope.breadcrumbs),
1749
1818
  attributes
1750
1819
  };
1751
1820
  if (input.isLog) report.isLog = true;
@@ -1755,6 +1824,7 @@ var Flare = class {
1755
1824
  return report;
1756
1825
  }
1757
1826
  async sendReport(report) {
1827
+ if (this._config.hasConsent === false) return;
1758
1828
  if (!assertKey(this._config.key, this._config.debug)) return;
1759
1829
  const reportToSubmit = await this._config.beforeSubmit(report);
1760
1830
  if (!reportToSubmit) return;
@@ -1763,4 +1833,4 @@ var Flare = class {
1763
1833
  };
1764
1834
 
1765
1835
  //#endregion
1766
- export { Api, BrowserSpanType, DEFAULT_MAX_LIVE_TRACES, DEFAULT_URL_DENYLIST, Flare, FrameworkName, GlobalScopeProvider, InMemoryActiveSpanHolder, Logger, NoopFlushScheduler, NullFileReader, Scope, SpanStatusCode, Tracer, USER_IDENTITY_KEYS, assert, assertKey, buildTraceparent, buildTracesEnvelope, convertToError, createIdentityTagger, createStackTrace, defaultNowNano, describeRejectionReason, extractCode, flatJsonStringify, getCodeSnippet, glowsToEvents, now, parseTraceparent, readLinesFromFile, redactObjectValues, redactUrlQuery, resolveDenylist, routeRejection, safeClone, safeDecode, spanId, toCustomContext, urlAttributes, userIdentityAttributes };
1836
+ export { Api, BrowserSpanEventType, BrowserSpanType, DEFAULT_MAX_LIVE_TRACES, DEFAULT_URL_DENYLIST, Flare, FrameworkName, GlobalScopeProvider, InMemoryActiveSpanHolder, Logger, MAX_BREADCRUMB_URL_LENGTH, NoopFlushScheduler, NullFileReader, Scope, SpanStatusCode, Tracer, USER_IDENTITY_KEYS, assert, assertKey, breadcrumbUrl, buildTraceparent, buildTracesEnvelope, convertToError, createIdentityTagger, createStackTrace, defaultNowNano, describeRejectionReason, extractCode, flatJsonStringify, getCodeSnippet, glowsToEvents, now, parseTraceparent, readLinesFromFile, recordBreadcrumb, redactObjectValues, redactUrlQuery, resolveDenylist, routeRejection, safeClone, safeDecode, spanId, toCustomContext, urlAttributes, userIdentityAttributes };
@@ -1,6 +1,6 @@
1
1
 
2
2
  //#region src/env/index.ts
3
- const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.8.0" : "?";
3
+ const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.10.0" : "?";
4
4
  const KEY = typeof FLARE_JS_KEY === "undefined" ? "" : FLARE_JS_KEY;
5
5
  const SOURCEMAP_VERSION = typeof FLARE_SOURCEMAP_VERSION === "undefined" ? "" : FLARE_SOURCEMAP_VERSION;
6
6
 
@@ -218,6 +218,15 @@ function glowsToEvents(glows) {
218
218
  }));
219
219
  }
220
220
 
221
+ //#endregion
222
+ //#region src/util/timelineEvents.ts
223
+ function byTime(a, b) {
224
+ return a.startTimeUnixNano - b.startTimeUnixNano;
225
+ }
226
+ function timelineEvents(glows, breadcrumbs) {
227
+ return [...glowsToEvents(glows), ...breadcrumbs].sort(byTime);
228
+ }
229
+
221
230
  //#endregion
222
231
  //#region src/util/now.ts
223
232
  function now() {
@@ -531,6 +540,12 @@ Object.defineProperty(exports, 'spendNode', {
531
540
  return spendNode;
532
541
  }
533
542
  });
543
+ Object.defineProperty(exports, 'timelineEvents', {
544
+ enumerable: true,
545
+ get: function () {
546
+ return timelineEvents;
547
+ }
548
+ });
534
549
  Object.defineProperty(exports, 'toCustomContext', {
535
550
  enumerable: true,
536
551
  get: function () {
@@ -37,6 +37,12 @@ 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
+ declare const BrowserSpanEventType: {
41
+ readonly Click: "browser_click";
42
+ readonly Input: "browser_input";
43
+ readonly RouteChange: "browser_route_change";
44
+ };
45
+ type BrowserSpanEventType = (typeof BrowserSpanEventType)[keyof typeof BrowserSpanEventType];
40
46
  //#endregion
41
47
  //#region src/types.d.ts
42
48
  type MessageLevel = 'debug' | 'info' | 'notice' | 'warning' | 'error' | 'critical' | 'alert' | 'emergency';
@@ -59,10 +65,15 @@ type User = {
59
65
  };
60
66
  type Config = {
61
67
  key: string | null;
68
+ /** When false, the SDK sends nothing: no errors, logs, or traces. Flip it with `setConsent()`.
69
+ * Default true, so setups without a consent tool are unchanged. */
70
+ hasConsent: boolean;
62
71
  version: string;
63
72
  sourcemapVersionId: string;
64
73
  stage: string;
65
74
  maxGlowsPerReport: number;
75
+ enableBreadcrumbs: boolean;
76
+ maxBreadcrumbs: number;
66
77
  reportBrowserExtensionErrors: boolean;
67
78
  ingestUrl: string;
68
79
  debug: boolean;
@@ -366,6 +377,9 @@ declare function flatJsonStringify(json: object): string;
366
377
  //#region src/util/glowsToEvents.d.ts
367
378
  declare function glowsToEvents(glows: Glow[]): SpanEvent[];
368
379
  //#endregion
380
+ //#region src/util/timelineEvents.d.ts
381
+ declare function timelineEvents(glows: Glow[], breadcrumbs: SpanEvent[]): SpanEvent[];
382
+ //#endregion
369
383
  //#region src/util/now.d.ts
370
384
  declare function now(): number;
371
385
  //#endregion
@@ -449,4 +463,4 @@ declare const MAX_URL_LENGTH = 2048;
449
463
  */
450
464
  declare function urlAttributes(url: string, denylist?: RegExp): Attributes;
451
465
  //#endregion
452
- export { User as $, BufferedSpan as A, OtelSpan as B, createComponentMatcher as C, AttributeValue as D, AnyValue as E, Glow as F, Span as G, Report as H, KeyValue as I, SpanStatus as J, SpanEvent as K, LogsEnvelope as L, EntryPointHandler as M, EntryPointType as N, Attributes as O, Framework as P, TracesSampler as Q, MessageLevel as R, ProfileComponentsOption as S, assert as T, SamplingContext as U, OverriddenGrouping as V, SdkInfo as W, StackFrame as X, SpanStatusCode as Y, TracesEnvelope as Z, flatJsonStringify as _, SafeCloneOptions as a, createIdentityTagger as b, describeRejectionReason as c, redactObjectValues as d, BrowserSpanType as et, redactUrlQuery as f, glowsToEvents as g, now as h, withoutStatefulFlags as i, Config as j, BufferedLog as k, routeRejection as l, safeDecode as m, urlAttributes as n, FrameworkName as nt, safeClone as o, resolveDenylist as p, SpanOptions as q, toCustomContext as r, RejectionReporter as s, MAX_URL_LENGTH as t, SpanTypeName as tt, DEFAULT_URL_DENYLIST as u, extractCode as v, assertKey as w, convertToError as x, SdkTaggable as y, OtelLogRecord as z };
466
+ export { TracesSampler as $, BufferedLog as A, OtelLogRecord as B, ProfileComponentsOption as C, AnyValue as D, assert as E, Framework as F, SdkInfo as G, OverriddenGrouping as H, Glow as I, SpanOptions as J, Span as K, KeyValue as L, Config as M, EntryPointHandler as N, AttributeValue as O, EntryPointType as P, TracesEnvelope as Q, LogsEnvelope as R, convertToError as S, assertKey as T, Report as U, OtelSpan as V, SamplingContext as W, SpanStatusCode as X, SpanStatus as Y, StackFrame as Z, glowsToEvents as _, SafeCloneOptions as a, SdkTaggable as b, describeRejectionReason as c, redactObjectValues as d, User as et, redactUrlQuery as f, timelineEvents as g, now as h, withoutStatefulFlags as i, FrameworkName as it, BufferedSpan as j, Attributes as k, routeRejection as l, safeDecode as m, urlAttributes as n, BrowserSpanType as nt, safeClone as o, resolveDenylist as p, SpanEvent as q, toCustomContext as r, SpanTypeName as rt, RejectionReporter as s, MAX_URL_LENGTH as t, BrowserSpanEventType as tt, DEFAULT_URL_DENYLIST as u, flatJsonStringify as v, createComponentMatcher as w, createIdentityTagger as x, extractCode as y, MessageLevel as z };
@@ -37,6 +37,12 @@ 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
+ declare const BrowserSpanEventType: {
41
+ readonly Click: "browser_click";
42
+ readonly Input: "browser_input";
43
+ readonly RouteChange: "browser_route_change";
44
+ };
45
+ type BrowserSpanEventType = (typeof BrowserSpanEventType)[keyof typeof BrowserSpanEventType];
40
46
  //#endregion
41
47
  //#region src/types.d.ts
42
48
  type MessageLevel = 'debug' | 'info' | 'notice' | 'warning' | 'error' | 'critical' | 'alert' | 'emergency';
@@ -59,10 +65,15 @@ type User = {
59
65
  };
60
66
  type Config = {
61
67
  key: string | null;
68
+ /** When false, the SDK sends nothing: no errors, logs, or traces. Flip it with `setConsent()`.
69
+ * Default true, so setups without a consent tool are unchanged. */
70
+ hasConsent: boolean;
62
71
  version: string;
63
72
  sourcemapVersionId: string;
64
73
  stage: string;
65
74
  maxGlowsPerReport: number;
75
+ enableBreadcrumbs: boolean;
76
+ maxBreadcrumbs: number;
66
77
  reportBrowserExtensionErrors: boolean;
67
78
  ingestUrl: string;
68
79
  debug: boolean;
@@ -366,6 +377,9 @@ declare function flatJsonStringify(json: object): string;
366
377
  //#region src/util/glowsToEvents.d.ts
367
378
  declare function glowsToEvents(glows: Glow[]): SpanEvent[];
368
379
  //#endregion
380
+ //#region src/util/timelineEvents.d.ts
381
+ declare function timelineEvents(glows: Glow[], breadcrumbs: SpanEvent[]): SpanEvent[];
382
+ //#endregion
369
383
  //#region src/util/now.d.ts
370
384
  declare function now(): number;
371
385
  //#endregion
@@ -449,4 +463,4 @@ declare const MAX_URL_LENGTH = 2048;
449
463
  */
450
464
  declare function urlAttributes(url: string, denylist?: RegExp): Attributes;
451
465
  //#endregion
452
- export { User as $, BufferedSpan as A, OtelSpan as B, createComponentMatcher as C, AttributeValue as D, AnyValue as E, Glow as F, Span as G, Report as H, KeyValue as I, SpanStatus as J, SpanEvent as K, LogsEnvelope as L, EntryPointHandler as M, EntryPointType as N, Attributes as O, Framework as P, TracesSampler as Q, MessageLevel as R, ProfileComponentsOption as S, assert as T, SamplingContext as U, OverriddenGrouping as V, SdkInfo as W, StackFrame as X, SpanStatusCode as Y, TracesEnvelope as Z, flatJsonStringify as _, SafeCloneOptions as a, createIdentityTagger as b, describeRejectionReason as c, redactObjectValues as d, BrowserSpanType as et, redactUrlQuery as f, glowsToEvents as g, now as h, withoutStatefulFlags as i, Config as j, BufferedLog as k, routeRejection as l, safeDecode as m, urlAttributes as n, FrameworkName as nt, safeClone as o, resolveDenylist as p, SpanOptions as q, toCustomContext as r, RejectionReporter as s, MAX_URL_LENGTH as t, SpanTypeName as tt, DEFAULT_URL_DENYLIST as u, extractCode as v, assertKey as w, convertToError as x, SdkTaggable as y, OtelLogRecord as z };
466
+ export { TracesSampler as $, BufferedLog as A, OtelLogRecord as B, ProfileComponentsOption as C, AnyValue as D, assert as E, Framework as F, SdkInfo as G, OverriddenGrouping as H, Glow as I, SpanOptions as J, Span as K, KeyValue as L, Config as M, EntryPointHandler as N, AttributeValue as O, EntryPointType as P, TracesEnvelope as Q, LogsEnvelope as R, convertToError as S, assertKey as T, Report as U, OtelSpan as V, SamplingContext as W, SpanStatusCode as X, SpanStatus as Y, StackFrame as Z, glowsToEvents as _, SafeCloneOptions as a, SdkTaggable as b, describeRejectionReason as c, redactObjectValues as d, User as et, redactUrlQuery as f, timelineEvents as g, now as h, withoutStatefulFlags as i, FrameworkName as it, BufferedSpan as j, Attributes as k, routeRejection as l, safeDecode as m, urlAttributes as n, BrowserSpanType as nt, safeClone as o, resolveDenylist as p, SpanEvent as q, toCustomContext as r, SpanTypeName as rt, RejectionReporter as s, MAX_URL_LENGTH as t, BrowserSpanEventType as tt, DEFAULT_URL_DENYLIST as u, flatJsonStringify as v, createComponentMatcher as w, createIdentityTagger as x, extractCode as y, MessageLevel as z };
@@ -1,5 +1,5 @@
1
1
  //#region src/env/index.ts
2
- const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.8.0" : "?";
2
+ const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.10.0" : "?";
3
3
  const KEY = typeof FLARE_JS_KEY === "undefined" ? "" : FLARE_JS_KEY;
4
4
  const SOURCEMAP_VERSION = typeof FLARE_SOURCEMAP_VERSION === "undefined" ? "" : FLARE_SOURCEMAP_VERSION;
5
5
 
@@ -217,6 +217,15 @@ function glowsToEvents(glows) {
217
217
  }));
218
218
  }
219
219
 
220
+ //#endregion
221
+ //#region src/util/timelineEvents.ts
222
+ function byTime(a, b) {
223
+ return a.startTimeUnixNano - b.startTimeUnixNano;
224
+ }
225
+ function timelineEvents(glows, breadcrumbs) {
226
+ return [...glowsToEvents(glows), ...breadcrumbs].sort(byTime);
227
+ }
228
+
220
229
  //#endregion
221
230
  //#region src/util/now.ts
222
231
  function now() {
@@ -380,4 +389,4 @@ function urlAttributes(url, denylist = DEFAULT_URL_DENYLIST) {
380
389
  }
381
390
 
382
391
  //#endregion
383
- export { withoutStatefulFlags as C, KEY as D, CLIENT_VERSION as E, SOURCEMAP_VERSION as O, createComponentMatcher as S, assert as T, createTraversalBudget as _, routeRejection as a, createIdentityTagger as b, redactUrlQuery as c, now as d, glowsToEvents as f, TRUNCATED as g, MAX_TRAVERSAL_DEPTH as h, describeRejectionReason as i, resolveDenylist as l, safeClone as m, urlAttributes as n, DEFAULT_URL_DENYLIST as o, flatJsonStringify as p, toCustomContext as r, redactObjectValues as s, MAX_URL_LENGTH as t, safeDecode as u, spendNode as v, assertKey as w, convertToError as x, extractCode as y };
392
+ export { createComponentMatcher as C, CLIENT_VERSION as D, assert as E, KEY as O, convertToError as S, assertKey as T, TRUNCATED as _, routeRejection as a, extractCode as b, redactUrlQuery as c, now as d, timelineEvents as f, MAX_TRAVERSAL_DEPTH as g, safeClone as h, describeRejectionReason as i, SOURCEMAP_VERSION as k, resolveDenylist as l, flatJsonStringify as m, urlAttributes as n, DEFAULT_URL_DENYLIST as o, glowsToEvents as p, toCustomContext as r, redactObjectValues as s, MAX_URL_LENGTH as t, safeDecode as u, createTraversalBudget as v, withoutStatefulFlags as w, createIdentityTagger as x, spendNode as y };
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_urlAttributes = require('../urlAttributes-CNGTgOJp.cjs');
2
+ const require_urlAttributes = require('../urlAttributes-B37JykP3.cjs');
3
3
 
4
4
  exports.DEFAULT_URL_DENYLIST = require_urlAttributes.DEFAULT_URL_DENYLIST;
5
5
  exports.MAX_URL_LENGTH = require_urlAttributes.MAX_URL_LENGTH;
@@ -19,6 +19,7 @@ exports.resolveDenylist = require_urlAttributes.resolveDenylist;
19
19
  exports.routeRejection = require_urlAttributes.routeRejection;
20
20
  exports.safeClone = require_urlAttributes.safeClone;
21
21
  exports.safeDecode = require_urlAttributes.safeDecode;
22
+ exports.timelineEvents = require_urlAttributes.timelineEvents;
22
23
  exports.toCustomContext = require_urlAttributes.toCustomContext;
23
24
  exports.urlAttributes = require_urlAttributes.urlAttributes;
24
25
  exports.withoutStatefulFlags = require_urlAttributes.withoutStatefulFlags;
@@ -1,2 +1,2 @@
1
- import { C as createComponentMatcher, S as ProfileComponentsOption, T as assert, _ as flatJsonStringify, a as SafeCloneOptions, b as createIdentityTagger, c as describeRejectionReason, d as redactObjectValues, f as redactUrlQuery, g as glowsToEvents, h as now, i as withoutStatefulFlags, l as routeRejection, m as safeDecode, n as urlAttributes, o as safeClone, p as resolveDenylist, r as toCustomContext, s as RejectionReporter, t as MAX_URL_LENGTH, u as DEFAULT_URL_DENYLIST, v as extractCode, w as assertKey, x as convertToError, y as SdkTaggable } from "../urlAttributes-CvOw6tU3.cjs";
2
- export { DEFAULT_URL_DENYLIST, MAX_URL_LENGTH, ProfileComponentsOption, RejectionReporter, SafeCloneOptions, SdkTaggable, assert, assertKey, convertToError, createComponentMatcher, createIdentityTagger, describeRejectionReason, extractCode, flatJsonStringify, glowsToEvents, now, redactObjectValues, redactUrlQuery, resolveDenylist, routeRejection, safeClone, safeDecode, toCustomContext, urlAttributes, withoutStatefulFlags };
1
+ import { C as ProfileComponentsOption, E as assert, S as convertToError, T as assertKey, _ as glowsToEvents, a as SafeCloneOptions, b as SdkTaggable, c as describeRejectionReason, d as redactObjectValues, f as redactUrlQuery, g as timelineEvents, h as now, i as withoutStatefulFlags, l as routeRejection, m as safeDecode, n as urlAttributes, o as safeClone, p as resolveDenylist, r as toCustomContext, s as RejectionReporter, t as MAX_URL_LENGTH, u as DEFAULT_URL_DENYLIST, v as flatJsonStringify, w as createComponentMatcher, x as createIdentityTagger, y as extractCode } from "../urlAttributes-DW_i-YQ3.cjs";
2
+ export { DEFAULT_URL_DENYLIST, MAX_URL_LENGTH, ProfileComponentsOption, RejectionReporter, SafeCloneOptions, SdkTaggable, assert, assertKey, convertToError, createComponentMatcher, createIdentityTagger, describeRejectionReason, extractCode, flatJsonStringify, glowsToEvents, now, redactObjectValues, redactUrlQuery, resolveDenylist, routeRejection, safeClone, safeDecode, timelineEvents, toCustomContext, urlAttributes, withoutStatefulFlags };
@@ -1,2 +1,2 @@
1
- import { C as createComponentMatcher, S as ProfileComponentsOption, T as assert, _ as flatJsonStringify, a as SafeCloneOptions, b as createIdentityTagger, c as describeRejectionReason, d as redactObjectValues, f as redactUrlQuery, g as glowsToEvents, h as now, i as withoutStatefulFlags, l as routeRejection, m as safeDecode, n as urlAttributes, o as safeClone, p as resolveDenylist, r as toCustomContext, s as RejectionReporter, t as MAX_URL_LENGTH, u as DEFAULT_URL_DENYLIST, v as extractCode, w as assertKey, x as convertToError, y as SdkTaggable } from "../urlAttributes-B9BlkrfW.mjs";
2
- export { DEFAULT_URL_DENYLIST, MAX_URL_LENGTH, ProfileComponentsOption, RejectionReporter, SafeCloneOptions, SdkTaggable, assert, assertKey, convertToError, createComponentMatcher, createIdentityTagger, describeRejectionReason, extractCode, flatJsonStringify, glowsToEvents, now, redactObjectValues, redactUrlQuery, resolveDenylist, routeRejection, safeClone, safeDecode, toCustomContext, urlAttributes, withoutStatefulFlags };
1
+ import { C as ProfileComponentsOption, E as assert, S as convertToError, T as assertKey, _ as glowsToEvents, a as SafeCloneOptions, b as SdkTaggable, c as describeRejectionReason, d as redactObjectValues, f as redactUrlQuery, g as timelineEvents, h as now, i as withoutStatefulFlags, l as routeRejection, m as safeDecode, n as urlAttributes, o as safeClone, p as resolveDenylist, r as toCustomContext, s as RejectionReporter, t as MAX_URL_LENGTH, u as DEFAULT_URL_DENYLIST, v as flatJsonStringify, w as createComponentMatcher, x as createIdentityTagger, y as extractCode } from "../urlAttributes-CYsfTfi9.mjs";
2
+ export { DEFAULT_URL_DENYLIST, MAX_URL_LENGTH, ProfileComponentsOption, RejectionReporter, SafeCloneOptions, SdkTaggable, assert, assertKey, convertToError, createComponentMatcher, createIdentityTagger, describeRejectionReason, extractCode, flatJsonStringify, glowsToEvents, now, redactObjectValues, redactUrlQuery, resolveDenylist, routeRejection, safeClone, safeDecode, timelineEvents, toCustomContext, urlAttributes, withoutStatefulFlags };
@@ -1,3 +1,3 @@
1
- import { C as withoutStatefulFlags, S as createComponentMatcher, T as assert, a as routeRejection, b as createIdentityTagger, c as redactUrlQuery, d as now, f as glowsToEvents, i as describeRejectionReason, l as resolveDenylist, m as safeClone, n as urlAttributes, o as DEFAULT_URL_DENYLIST, p as flatJsonStringify, r as toCustomContext, s as redactObjectValues, t as MAX_URL_LENGTH, u as safeDecode, w as assertKey, x as convertToError, y as extractCode } from "../urlAttributes-D3gCx23B.mjs";
1
+ import { C as createComponentMatcher, E as assert, S as convertToError, T as assertKey, a as routeRejection, b as extractCode, c as redactUrlQuery, d as now, f as timelineEvents, h as safeClone, i as describeRejectionReason, l as resolveDenylist, m as flatJsonStringify, n as urlAttributes, o as DEFAULT_URL_DENYLIST, p as glowsToEvents, r as toCustomContext, s as redactObjectValues, t as MAX_URL_LENGTH, u as safeDecode, w as withoutStatefulFlags, x as createIdentityTagger } from "../urlAttributes-DeDN7qtu.mjs";
2
2
 
3
- export { DEFAULT_URL_DENYLIST, MAX_URL_LENGTH, assert, assertKey, convertToError, createComponentMatcher, createIdentityTagger, describeRejectionReason, extractCode, flatJsonStringify, glowsToEvents, now, redactObjectValues, redactUrlQuery, resolveDenylist, routeRejection, safeClone, safeDecode, toCustomContext, urlAttributes, withoutStatefulFlags };
3
+ export { DEFAULT_URL_DENYLIST, MAX_URL_LENGTH, assert, assertKey, convertToError, createComponentMatcher, createIdentityTagger, describeRejectionReason, extractCode, flatJsonStringify, glowsToEvents, now, redactObjectValues, redactUrlQuery, resolveDenylist, routeRejection, safeClone, safeDecode, timelineEvents, toCustomContext, urlAttributes, withoutStatefulFlags };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flareapp/core",
3
- "version": "2.8.0",
3
+ "version": "2.10.0",
4
4
  "description": "Environment-agnostic core for the Flare JS SDK",
5
5
  "homepage": "https://flareapp.io",
6
6
  "bugs": {