@reopt-ai/data-sdk-client 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +50 -2
  2. package/dist/{client-BCrui21p.d.cts → client-BrtY8ZQB.d.cts} +72 -12
  3. package/dist/client-BrtY8ZQB.d.cts.map +1 -0
  4. package/dist/{client-B1GlWwVq.d.ts → client-BvSE7ErY.d.ts} +72 -12
  5. package/dist/client-BvSE7ErY.d.ts.map +1 -0
  6. package/dist/{exceptions-CuhGo9A5.cjs → exceptions-BPmC4TTt.cjs} +2 -2
  7. package/dist/exceptions-BPmC4TTt.cjs.map +1 -0
  8. package/dist/{exceptions-C9Fh0BIR.js → exceptions-CorACVsv.js} +2 -2
  9. package/dist/exceptions-CorACVsv.js.map +1 -0
  10. package/dist/index.cjs +1 -1
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +2 -2
  13. package/dist/index.d.cts.map +1 -1
  14. package/dist/index.d.ts +2 -2
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +1 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/next.d.cts +1 -1
  19. package/dist/next.d.ts +1 -1
  20. package/dist/react.cjs +1 -1
  21. package/dist/react.d.cts +1 -1
  22. package/dist/react.d.ts +1 -1
  23. package/dist/react.js +1 -1
  24. package/dist/recorder-B993wv6b.js +390 -0
  25. package/dist/recorder-B993wv6b.js.map +1 -0
  26. package/dist/recorder-BSzzSd3Q.cjs +390 -0
  27. package/dist/recorder-BSzzSd3Q.cjs.map +1 -0
  28. package/dist/{registry-CGqrOtf4.cjs → registry-DR1N7wD5.cjs} +17 -4
  29. package/dist/registry-DR1N7wD5.cjs.map +1 -0
  30. package/dist/{registry-BPhiH_l9.js → registry-IzNqE02g.js} +18 -5
  31. package/dist/registry-IzNqE02g.js.map +1 -0
  32. package/package.json +7 -5
  33. package/dist/client-B1GlWwVq.d.ts.map +0 -1
  34. package/dist/client-BCrui21p.d.cts.map +0 -1
  35. package/dist/exceptions-C9Fh0BIR.js.map +0 -1
  36. package/dist/exceptions-CuhGo9A5.cjs.map +0 -1
  37. package/dist/registry-BPhiH_l9.js.map +0 -1
  38. package/dist/registry-CGqrOtf4.cjs.map +0 -1
package/README.md CHANGED
@@ -182,7 +182,7 @@ const writeKey = await resolveBrandWriteKey(brandId);
182
182
  2. Passing the `cookies()` promise as a prop into a cached component does not error; the build **hangs** or the prerender times out.
183
183
  3. Without `cacheComponents` (older apps, `unstable_cache`, fetch caching) the value really does get cached — **every visitor gets the same device id**. In those apps do not pass `bootstrap`; rely on the proxy's cookie seeding and the client's own identity.
184
184
 
185
- ## Size
185
+ ## Exceptions
186
186
 
187
187
  ### `$exception_list` — the structured form
188
188
 
@@ -279,7 +279,9 @@ reports the flat keys only; the server falls back to fingerprinting those, so
279
279
  the event still groups. Turning on `capture.exceptions` loads the chunk at init,
280
280
  which is the usual case.
281
281
 
282
- The production bundle is checked on every build (`scripts/check-size.mjs`): each entry is bundled as a consumer would (minified, `NODE_ENV=production`, framework externals) and must stay under **10.65 KB gzip** for the vanilla entry (10.9 / 11.15 KB for `./react` / `./next`) and carry no zod. Opt-in features (observer formatting, tracing headers, exception capture) are separate chunks. Event validation in production is a hand-written mirror of the contract; the zod schema runs in development only and is dropped by the consumer's bundler.
282
+ ## Size
283
+
284
+ The production bundle is checked on every build (`scripts/check-size.mjs`): each entry is bundled as a consumer would (minified, `NODE_ENV=production`, framework externals) and must stay under the per-entry gzip budget that script declares (`BUDGET_GZIP_BYTES` — tightest for the vanilla entry, looser for `./react` and `./next`, which add the provider, hooks and page-view component on top) and carry no zod. Opt-in features (observer formatting, tracing headers, exception capture) are separate chunks. Event validation in production is a hand-written mirror of the contract; the zod schema runs in development only and is dropped by the consumer's bundler.
283
285
 
284
286
  ## What it does that you would otherwise have to remember
285
287
 
@@ -301,3 +303,49 @@ Names and property keys are exported from `@reopt-ai/data-contract/events` (`AUT
301
303
  | `$pageleave` | `path`, `origin`, `duration` (s), `scroll_depth` (0–100) |
302
304
  | `$web_vitals` | `metric_name`, `metric_id`, `value`, `delta`, `rating`, `navigation_type`, `path` |
303
305
  | `$exception` | `$exception_type`, `$exception_message`, `$exception_stack`, `$exception_source`, `$exception_handled`, `$exception_list`, `path` |
306
+
307
+ ## Session replay (workspace; npm release pending)
308
+
309
+ Replay is opt-in and loads `@rrweb/record` only after project sampling and consent. Enable replay for the project in the Data console, then configure the browser client:
310
+
311
+ ```ts
312
+ const client = init({
313
+ writeKey: publicWriteKey,
314
+ baseUrl: "/ingest",
315
+ sessionReplay: { enabled: true },
316
+ });
317
+ // Call only after your consent UI receives the visitor's recording decision.
318
+ client.setConsent("replay", true);
319
+ await client.flushReplay();
320
+ client.setConsent("replay", false);
321
+ ```
322
+
323
+ Both analytics and replay consent must be granted. Keep `replay` out of default-granted consent categories. `consentCategory` can select an existing category only when that category represents recording consent. `flushReplay()` attempts buffered delivery; it does not override sampling, consent, retry delay, or prove that a recording exists. Use the collector response/request ID or console to verify acceptance.
324
+
325
+ Chunks are gzipped in the browser with `CompressionStream` when available (`Content-Encoding: gzip`), which cuts the visitor's upload roughly tenfold; browsers without it send JSON. A session the server does not sample is remembered until the analytics session changes, so an unsampled visitor sends one start request per session rather than one per minute. A stream that fails three times in a row on the same page (for example a page whose DOM never fits the event limit) stops recording until the next page load instead of retrying forever.
326
+
327
+ `blockSelector` adds private subtrees to the built-in blocks. `data-reopt-replay-block`, `data-reopt-private`, password fields, iframes, objects and embeds are always blocked. Inputs and visible text are masked, including CSS-generated text in snapshots and incremental style updates; DOM attributes are allowlisted. URLs lose queries/fragments and image/font resources are excluded by default. Console/network bodies, canvas, custom recorder plugins and persistent offline DOM queues are unsupported. Never add an unmasking workaround to pass sensitive content into replay.
328
+
329
+ ### Explicit public images and fonts
330
+
331
+ `sessionReplay.publicAssets` optionally maps public static URLs to build-time data URLs:
332
+
333
+ ```ts
334
+ sessionReplay: {
335
+ enabled: true,
336
+ publicAssets: [
337
+ { url: "/brand/logo.webp", dataUrl: publicLogoDataUrl },
338
+ { url: "/fonts/public.woff2", dataUrl: publicFontDataUrl },
339
+ ],
340
+ }
341
+ ```
342
+
343
+ Generate these values from reviewed application-owned files during your build. The example's `scripts/build-replay-assets.mjs` shows this pattern. Do not fetch arbitrary page URLs, rasterize the visitor's page, or include uploads, avatars, authenticated/personalized files, or images containing private text. Pixels and font metadata are **not masked**. Only deliberately public assets belong here.
344
+
345
+ The recorder matches exact resolved HTTP(S) URLs; configured URLs with credentials, queries or fragments are rejected. Signed variants and unlisted inline images remain excluded. PNG, JPEG, WebP and WOFF2 are supported with MIME/signature checks. At most 16 entries are inspected, each file is at most 128 KiB decoded, and accepted data URL strings total at most 256 KiB. Invalid or over-budget entries are ignored. Font loading uses captured `@font-face` CSS; the FontFace API, SVG, srcset selection, canvas and automatic asset discovery are not supported.
346
+
347
+ Approved files replace image `src` and CSS `url()` references in full snapshots and incremental updates. The server revalidates embedded formats. Playback needs no request to the source site: the existing sandbox/CSP permits only embedded images/fonts. Assets share the recording's transport, private storage, quotas, retention and deletion; they are not uploaded to a separate public bucket. Repeated CSS references and snapshots repeat bytes, so subset fonts and small images are preferable. Existing recordings cannot regain previously removed resources.
348
+
349
+ Each page load/visibility restart has a distinct stream linked to the server's current analytics session. Tabs never share DOM mirrors. One eligible recorder owns each document when several SDK clients coexist. Pause, reset, consent withdrawal and close stop observers and cancel pending replay work. Idle pages suspend after 60 seconds; activity starts a fresh snapshot. `idleTimeoutMs` accepts 10–300 seconds and `flushIntervalMs` accepts 1–30 seconds (default 20; each flush is one upload and one stored object, and page hide/unload flushes regardless). Full DOM snapshots are retaken every five minutes.
350
+
351
+ Uploads use `/api/replay/start` and `/api/replay/chunk` under `baseUrl`; the server SDK's existing `/ingest` proxy forwards them. Replay requests omit cookies and use the write-key/device headers plus a short-lived project/device/session/stream-bound grant. A 1 MiB request, 900 KiB single event, 4 MiB queue and 32 MiB / 30-minute stream bound resource use. Oversized snapshots stop the stream; mutations never continue with a broken snapshot. The next eligible attempt starts a fresh stream.
@@ -8,7 +8,7 @@ import { ConsentCookieState, DeviceCookieState, ReoptBootstrap } from "@reopt-ai
8
8
  * {@link ReoptRuntime}.
9
9
  */
10
10
  /** Consent categories. `analytics` is the one whose refusal stops everything. */
11
- type ConsentCategory = "analytics" | "marketing" | "functional" | "performance";
11
+ type ConsentCategory = "analytics" | "marketing" | "functional" | "performance" | "replay";
12
12
  interface ConsentConfig {
13
13
  /** Default decision for every configured category. Default: `true` (opt-out model). */
14
14
  defaultConsent?: boolean | undefined;
@@ -65,8 +65,12 @@ type FetchLike = (input: string, init: FetchInit) => Promise<FetchResponseLike>;
65
65
  interface FetchInit {
66
66
  method: string;
67
67
  headers: Record<string, string>;
68
- body: string;
68
+ /** JSON text, or gzip bytes when replay delivery compressed a chunk (`Content-Encoding: gzip`). */
69
+ body: string | Uint8Array;
69
70
  keepalive?: boolean | undefined;
71
+ /** Optional cancellation, used by consent-sensitive replay delivery. */
72
+ signal?: AbortSignal | undefined;
73
+ credentials?: "omit" | undefined;
70
74
  }
71
75
  interface FetchResponseLike {
72
76
  ok: boolean;
@@ -282,6 +286,39 @@ interface FlushOptions {
282
286
  //#endregion
283
287
  //#region ../data-sdk-core/src/consent.d.ts
284
288
  type ConsentState = Record<string, boolean>;
289
+ /**
290
+ * Per-category consent with two gates:
291
+ *
292
+ * - **enqueue** — an event whose category is refused never enters the queue,
293
+ * so nothing about it is persisted either;
294
+ * - **flush** — if tracking is paused or every category is refused, queued
295
+ * events stay queued (they were accepted under earlier consent).
296
+ *
297
+ * Persistence goes through whatever storage the runtime provides; the
298
+ * browser package hands in a cookie-backed store so the server can read the
299
+ * same decision.
300
+ */
301
+ declare class ConsentManager {
302
+ private state;
303
+ private paused;
304
+ private readonly storage;
305
+ private readonly onChange;
306
+ constructor(config: ConsentConfig | undefined, storage: StorageBackend | undefined, onChange?: (state: ConsentState) => void);
307
+ get(category: ConsentCategory): boolean;
308
+ set(category: ConsentCategory, allowed: boolean): void;
309
+ setAll(allowed: boolean): void;
310
+ snapshot(): ConsentState;
311
+ /** Overlay decisions from elsewhere (a server bootstrap) on the current state. */
312
+ replace(state: ConsentState): void;
313
+ pause(): void;
314
+ resume(): void;
315
+ isPaused(): boolean;
316
+ /** Why an event in `category` may not be queued right now, or `null`. */
317
+ enqueueBlockReason(category: ConsentCategory): QueueDropReason | null;
318
+ /** Why nothing may be sent right now, or `null`. */
319
+ flushBlockReason(): QueueDropReason | null;
320
+ private persist;
321
+ }
285
322
  //#endregion
286
323
  //#region ../data-sdk-core/src/transport.d.ts
287
324
  interface BatchDelivery {
@@ -315,7 +352,7 @@ declare class ReoptCore {
315
352
  protected readonly runtime: ReoptRuntime;
316
353
  protected readonly transport: Transport;
317
354
  private readonly queue;
318
- private readonly consent;
355
+ protected readonly consent: ConsentManager;
319
356
  private readonly breaker;
320
357
  private readonly retry;
321
358
  private readonly batch;
@@ -427,6 +464,25 @@ type WebVitalProperties = {
427
464
  path: string;
428
465
  };
429
466
  //#endregion
467
+ //#region src/replay/types.d.ts
468
+ interface SessionReplayConfig {
469
+ enabled: boolean;
470
+ /** Explicit public static images/fonts embedded without runtime fetching; see README limits. */
471
+ publicAssets?: readonly import("@reopt-ai/data-contract/replay").ReplayPublicAsset[];
472
+ /** Defaults to `replay`; both this category and analytics must be granted. */
473
+ consentCategory?: ConsentCategory;
474
+ /** Additional subtree selector; built-in sensitive and blocked regions remain blocked. */
475
+ blockSelector?: string;
476
+ /**
477
+ * Flush buffered mutations. Default 20 seconds (1–30 accepted). Each flush is
478
+ * one upload and one stored object, so shorter intervals raise request and
479
+ * storage counts; unload flushes are not affected by this interval.
480
+ */
481
+ flushIntervalMs?: number;
482
+ /** Suspend DOM observers after no user interaction. Default 60 seconds. */
483
+ idleTimeoutMs?: number;
484
+ }
485
+ //#endregion
430
486
  //#region src/config.d.ts
431
487
  type ReoptObservedEventType = "track" | "identify" | "increment" | "decrement";
432
488
  /**
@@ -545,6 +601,8 @@ interface ReoptClientConfig {
545
601
  bootstrap?: ReoptBootstrap | null | undefined;
546
602
  identity?: IdentityConfig | undefined;
547
603
  capture?: CaptureConfig | undefined;
604
+ /** Opt-in DOM replay. Requires both analytics and replay consent; disabled by default. */
605
+ sessionReplay?: SessionReplayConfig | undefined;
548
606
  /**
549
607
  * Hosts that receive the `reopt-device-id` header on outgoing `fetch`/XHR,
550
608
  * so a server-side `track()` lands on the same device. `true` = the page's
@@ -636,7 +694,6 @@ interface IdentityStore {
636
694
  writeDevice(state: DeviceCookieState): void;
637
695
  clearDevice(): void;
638
696
  readConsent(): ConsentCookieState | null;
639
- writeConsent(state: ConsentCookieState): void;
640
697
  /** Engine-facing backend for the consent key, so consent decisions land in the same place. */
641
698
  consentBackend(): StorageBackend;
642
699
  }
@@ -646,12 +703,6 @@ interface ReoptClientDefaults {
646
703
  /** Whether `init()` sends the first `$pageview`. The Next entry says no. */
647
704
  pageview: boolean;
648
705
  }
649
- /**
650
- * The browser client: the shared engine plus everything that only makes
651
- * sense in a document — cookie identity, tracing headers, page leave,
652
- * scroll depth, exception capture, and a clock corrected against the
653
- * server's.
654
- */
655
706
  /**
656
707
  * What to attach to a manual `captureException`.
657
708
  *
@@ -665,7 +716,14 @@ interface CaptureExceptionOptions {
665
716
  level?: ExceptionLevel | undefined;
666
717
  properties?: Record<string, unknown> | undefined;
667
718
  }
719
+ /**
720
+ * The browser client: the shared engine plus everything that only makes
721
+ * sense in a document — cookie identity, tracing headers, page leave,
722
+ * scroll depth, exception capture, and a clock corrected against the
723
+ * server's.
724
+ */
668
725
  declare class ReoptClient extends ReoptCore {
726
+ private replay;
669
727
  readonly writeKey: string;
670
728
  readonly capture: ResolvedCaptureConfig;
671
729
  private readonly store;
@@ -737,8 +795,10 @@ declare class ReoptClient extends ReoptCore {
737
795
  * history.
738
796
  */
739
797
  reset(): void;
798
+ /** Flush currently buffered replay chunks; never overrides consent or retry limits. */
799
+ flushReplay(): Promise<void>;
740
800
  close(): Promise<FlushResult>;
741
801
  }
742
802
  //#endregion
743
- export { QueueDropReason as A, FetchInit as C, IdentifyOptions as D, FlushResult as E, UTMParams as F, RetryConfig as M, StorageBackend as N, IncrementOptions as O, TrackEventOptions as P, EventPayload as S, FetchResponseLike as T, CircuitBreakerConfig as _, IdentityConfig as a, DecrementOptions as b, ReoptBootstrap as c, ReoptClientObserver as d, ReoptObservedEventType as f, BatchConfig as g, ExceptionStepInput as h, CaptureConfig as i, QueueResult as j, PageViewOptions as k, ReoptClientConfig as l, WebVitalProperties as m, ReoptClient as n, IdentityStorageKind as o, WebVitalMetric as p, ReoptClientDefaults as r, NormalizePath as s, CaptureExceptionOptions as t, ReoptClientObservation as u, ConsentCategory as v, FetchLike as w, EventIdentity as x, ConsentConfig as y };
744
- //# sourceMappingURL=client-BCrui21p.d.cts.map
803
+ export { PageViewOptions as A, EventPayload as C, FlushResult as D, FetchResponseLike as E, TrackEventOptions as F, UTMParams as I, QueueResult as M, RetryConfig as N, IdentifyOptions as O, StorageBackend as P, EventIdentity as S, FetchLike as T, BatchConfig as _, IdentityConfig as a, ConsentConfig as b, ReoptBootstrap as c, ReoptClientObserver as d, ReoptObservedEventType as f, ExceptionStepInput as g, WebVitalProperties as h, CaptureConfig as i, QueueDropReason as j, IncrementOptions as k, ReoptClientConfig as l, WebVitalMetric as m, ReoptClient as n, IdentityStorageKind as o, SessionReplayConfig as p, ReoptClientDefaults as r, NormalizePath as s, CaptureExceptionOptions as t, ReoptClientObservation as u, CircuitBreakerConfig as v, FetchInit as w, DecrementOptions as x, ConsentCategory as y };
804
+ //# sourceMappingURL=client-BrtY8ZQB.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-BrtY8ZQB.d.cts","names":[],"sources":["../../data-sdk-core/src/types.ts","../../data-sdk-core/src/consent.ts","../../data-sdk-core/src/transport.ts","../../data-sdk-core/src/client.ts","../src/steps.ts","../src/capture/web-vitals.ts","../src/replay/types.ts","../src/config.ts","../src/identity/device.ts","../src/client.ts"],"mappings":"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"}
@@ -8,7 +8,7 @@ import { ExceptionEntry, ExceptionLevel, ExceptionStep } from "@reopt-ai/data-co
8
8
  * {@link ReoptRuntime}.
9
9
  */
10
10
  /** Consent categories. `analytics` is the one whose refusal stops everything. */
11
- type ConsentCategory = "analytics" | "marketing" | "functional" | "performance";
11
+ type ConsentCategory = "analytics" | "marketing" | "functional" | "performance" | "replay";
12
12
  interface ConsentConfig {
13
13
  /** Default decision for every configured category. Default: `true` (opt-out model). */
14
14
  defaultConsent?: boolean | undefined;
@@ -65,8 +65,12 @@ type FetchLike = (input: string, init: FetchInit) => Promise<FetchResponseLike>;
65
65
  interface FetchInit {
66
66
  method: string;
67
67
  headers: Record<string, string>;
68
- body: string;
68
+ /** JSON text, or gzip bytes when replay delivery compressed a chunk (`Content-Encoding: gzip`). */
69
+ body: string | Uint8Array;
69
70
  keepalive?: boolean | undefined;
71
+ /** Optional cancellation, used by consent-sensitive replay delivery. */
72
+ signal?: AbortSignal | undefined;
73
+ credentials?: "omit" | undefined;
70
74
  }
71
75
  interface FetchResponseLike {
72
76
  ok: boolean;
@@ -282,6 +286,39 @@ interface FlushOptions {
282
286
  //#endregion
283
287
  //#region ../data-sdk-core/src/consent.d.ts
284
288
  type ConsentState = Record<string, boolean>;
289
+ /**
290
+ * Per-category consent with two gates:
291
+ *
292
+ * - **enqueue** — an event whose category is refused never enters the queue,
293
+ * so nothing about it is persisted either;
294
+ * - **flush** — if tracking is paused or every category is refused, queued
295
+ * events stay queued (they were accepted under earlier consent).
296
+ *
297
+ * Persistence goes through whatever storage the runtime provides; the
298
+ * browser package hands in a cookie-backed store so the server can read the
299
+ * same decision.
300
+ */
301
+ declare class ConsentManager {
302
+ private state;
303
+ private paused;
304
+ private readonly storage;
305
+ private readonly onChange;
306
+ constructor(config: ConsentConfig | undefined, storage: StorageBackend | undefined, onChange?: (state: ConsentState) => void);
307
+ get(category: ConsentCategory): boolean;
308
+ set(category: ConsentCategory, allowed: boolean): void;
309
+ setAll(allowed: boolean): void;
310
+ snapshot(): ConsentState;
311
+ /** Overlay decisions from elsewhere (a server bootstrap) on the current state. */
312
+ replace(state: ConsentState): void;
313
+ pause(): void;
314
+ resume(): void;
315
+ isPaused(): boolean;
316
+ /** Why an event in `category` may not be queued right now, or `null`. */
317
+ enqueueBlockReason(category: ConsentCategory): QueueDropReason | null;
318
+ /** Why nothing may be sent right now, or `null`. */
319
+ flushBlockReason(): QueueDropReason | null;
320
+ private persist;
321
+ }
285
322
  //#endregion
286
323
  //#region ../data-sdk-core/src/transport.d.ts
287
324
  interface BatchDelivery {
@@ -315,7 +352,7 @@ declare class ReoptCore {
315
352
  protected readonly runtime: ReoptRuntime;
316
353
  protected readonly transport: Transport;
317
354
  private readonly queue;
318
- private readonly consent;
355
+ protected readonly consent: ConsentManager;
319
356
  private readonly breaker;
320
357
  private readonly retry;
321
358
  private readonly batch;
@@ -427,6 +464,25 @@ type WebVitalProperties = {
427
464
  path: string;
428
465
  };
429
466
  //#endregion
467
+ //#region src/replay/types.d.ts
468
+ interface SessionReplayConfig {
469
+ enabled: boolean;
470
+ /** Explicit public static images/fonts embedded without runtime fetching; see README limits. */
471
+ publicAssets?: readonly import("@reopt-ai/data-contract/replay").ReplayPublicAsset[];
472
+ /** Defaults to `replay`; both this category and analytics must be granted. */
473
+ consentCategory?: ConsentCategory;
474
+ /** Additional subtree selector; built-in sensitive and blocked regions remain blocked. */
475
+ blockSelector?: string;
476
+ /**
477
+ * Flush buffered mutations. Default 20 seconds (1–30 accepted). Each flush is
478
+ * one upload and one stored object, so shorter intervals raise request and
479
+ * storage counts; unload flushes are not affected by this interval.
480
+ */
481
+ flushIntervalMs?: number;
482
+ /** Suspend DOM observers after no user interaction. Default 60 seconds. */
483
+ idleTimeoutMs?: number;
484
+ }
485
+ //#endregion
430
486
  //#region src/config.d.ts
431
487
  type ReoptObservedEventType = "track" | "identify" | "increment" | "decrement";
432
488
  /**
@@ -545,6 +601,8 @@ interface ReoptClientConfig {
545
601
  bootstrap?: ReoptBootstrap | null | undefined;
546
602
  identity?: IdentityConfig | undefined;
547
603
  capture?: CaptureConfig | undefined;
604
+ /** Opt-in DOM replay. Requires both analytics and replay consent; disabled by default. */
605
+ sessionReplay?: SessionReplayConfig | undefined;
548
606
  /**
549
607
  * Hosts that receive the `reopt-device-id` header on outgoing `fetch`/XHR,
550
608
  * so a server-side `track()` lands on the same device. `true` = the page's
@@ -636,7 +694,6 @@ interface IdentityStore {
636
694
  writeDevice(state: DeviceCookieState): void;
637
695
  clearDevice(): void;
638
696
  readConsent(): ConsentCookieState | null;
639
- writeConsent(state: ConsentCookieState): void;
640
697
  /** Engine-facing backend for the consent key, so consent decisions land in the same place. */
641
698
  consentBackend(): StorageBackend;
642
699
  }
@@ -646,12 +703,6 @@ interface ReoptClientDefaults {
646
703
  /** Whether `init()` sends the first `$pageview`. The Next entry says no. */
647
704
  pageview: boolean;
648
705
  }
649
- /**
650
- * The browser client: the shared engine plus everything that only makes
651
- * sense in a document — cookie identity, tracing headers, page leave,
652
- * scroll depth, exception capture, and a clock corrected against the
653
- * server's.
654
- */
655
706
  /**
656
707
  * What to attach to a manual `captureException`.
657
708
  *
@@ -665,7 +716,14 @@ interface CaptureExceptionOptions {
665
716
  level?: ExceptionLevel | undefined;
666
717
  properties?: Record<string, unknown> | undefined;
667
718
  }
719
+ /**
720
+ * The browser client: the shared engine plus everything that only makes
721
+ * sense in a document — cookie identity, tracing headers, page leave,
722
+ * scroll depth, exception capture, and a clock corrected against the
723
+ * server's.
724
+ */
668
725
  declare class ReoptClient extends ReoptCore {
726
+ private replay;
669
727
  readonly writeKey: string;
670
728
  readonly capture: ResolvedCaptureConfig;
671
729
  private readonly store;
@@ -737,8 +795,10 @@ declare class ReoptClient extends ReoptCore {
737
795
  * history.
738
796
  */
739
797
  reset(): void;
798
+ /** Flush currently buffered replay chunks; never overrides consent or retry limits. */
799
+ flushReplay(): Promise<void>;
740
800
  close(): Promise<FlushResult>;
741
801
  }
742
802
  //#endregion
743
- export { QueueDropReason as A, FetchInit as C, IdentifyOptions as D, FlushResult as E, UTMParams as F, RetryConfig as M, StorageBackend as N, IncrementOptions as O, TrackEventOptions as P, EventPayload as S, FetchResponseLike as T, CircuitBreakerConfig as _, IdentityConfig as a, DecrementOptions as b, ReoptBootstrap as c, ReoptClientObserver as d, ReoptObservedEventType as f, BatchConfig as g, ExceptionStepInput as h, CaptureConfig as i, QueueResult as j, PageViewOptions as k, ReoptClientConfig as l, WebVitalProperties as m, ReoptClient as n, IdentityStorageKind as o, WebVitalMetric as p, ReoptClientDefaults as r, NormalizePath as s, CaptureExceptionOptions as t, ReoptClientObservation as u, ConsentCategory as v, FetchLike as w, EventIdentity as x, ConsentConfig as y };
744
- //# sourceMappingURL=client-B1GlWwVq.d.ts.map
803
+ export { PageViewOptions as A, EventPayload as C, FlushResult as D, FetchResponseLike as E, TrackEventOptions as F, UTMParams as I, QueueResult as M, RetryConfig as N, IdentifyOptions as O, StorageBackend as P, EventIdentity as S, FetchLike as T, BatchConfig as _, IdentityConfig as a, ConsentConfig as b, ReoptBootstrap as c, ReoptClientObserver as d, ReoptObservedEventType as f, ExceptionStepInput as g, WebVitalProperties as h, CaptureConfig as i, QueueDropReason as j, IncrementOptions as k, ReoptClientConfig as l, WebVitalMetric as m, ReoptClient as n, IdentityStorageKind as o, SessionReplayConfig as p, ReoptClientDefaults as r, NormalizePath as s, CaptureExceptionOptions as t, ReoptClientObservation as u, CircuitBreakerConfig as v, FetchInit as w, DecrementOptions as x, ConsentCategory as y };
804
+ //# sourceMappingURL=client-BvSE7ErY.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-BvSE7ErY.d.ts","names":[],"sources":["../../data-sdk-core/src/types.ts","../../data-sdk-core/src/consent.ts","../../data-sdk-core/src/transport.ts","../../data-sdk-core/src/client.ts","../src/steps.ts","../src/capture/web-vitals.ts","../src/replay/types.ts","../src/config.ts","../src/identity/device.ts","../src/client.ts"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- const require_registry = require("./registry-CGqrOtf4.cjs");
1
+ const require_registry = require("./registry-DR1N7wD5.cjs");
2
2
  let _reopt_ai_data_contract_events = require("@reopt-ai/data-contract/events");
3
3
  //#region ../data-sdk-core/src/stack-parsers/index.ts
4
4
  const EXTENSION_PROTOCOLS = [
@@ -286,4 +286,4 @@ exports.describeError = describeError;
286
286
  exports.installExceptionCapture = installExceptionCapture;
287
287
  exports.shouldDropException = shouldDropException;
288
288
 
289
- //# sourceMappingURL=exceptions-CuhGo9A5.cjs.map
289
+ //# sourceMappingURL=exceptions-BPmC4TTt.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exceptions-BPmC4TTt.cjs","names":["MAX_EXCEPTION_FRAMES","MAX_EXCEPTION_FRAMES","MAX_EXCEPTION_CHAIN","MAX_STACK_CHARS"],"sources":["../../data-sdk-core/src/stack-parsers/index.ts","../../data-sdk-core/src/stack-parsers/coerce.ts","../src/capture/chunk-ids.ts","../src/capture/describe-error.ts","../src/capture/exception-rate-limit.ts","../src/capture/exceptions.ts"],"sourcesContent":["/**\n * Turning an `error.stack` string into structured frames.\n *\n * Every JS engine formats a stack differently and none of them documents the\n * format, so this is pattern matching against what the engines actually emit.\n * The regexes descend from Sentry's `stacktrace.ts` by way of posthog-js\n * (`packages/core/src/error-tracking/parsers/`), both MIT — the shapes are the\n * accumulated result of years of field reports, and rewriting them from the\n * specs would mean rediscovering the same edge cases.\n *\n * Lives in `data-sdk-core` because the browser and the server SDK both need it\n * and neither may depend on the other. Core has no build step; both consumers\n * inline this source, so nothing here may reach for a browser or Node global.\n */\nimport { MAX_EXCEPTION_FRAMES, type ExceptionFrame } from \"@reopt-ai/data-contract/events\";\n\n/** A parser turns one stack line into a frame, or returns undefined if it cannot. */\ntype LineParser = (line: string) => ExceptionFrame | undefined;\n\n/** Frames the runtime, not the app: a stack of only these is not worth reporting. */\nconst EXTENSION_PROTOCOLS = [\n \"chrome-extension://\",\n \"moz-extension://\",\n \"safari-extension://\",\n \"safari-web-extension://\",\n];\n\n/** WebKit masks cross-origin URLs; a masked frame names no file anyone can open. */\nconst WEBKIT_MASKED_URL = \"webkit-masked-url://\";\nconst ANONYMOUS_FILE = \"<anonymous>\";\n\n/**\n * Whether a frame is the app's own code.\n *\n * Anything the app did not write — an extension's injected script, a masked\n * cross-origin URL, a frame with no file at all — is not somewhere a developer\n * can go and fix, so the stack panel hides it by default.\n */\nexport function isInAppFrame(filename: string | undefined): boolean {\n if (!filename || filename === ANONYMOUS_FILE) return false;\n if (filename.startsWith(WEBKIT_MASKED_URL)) return false;\n if (EXTENSION_PROTOCOLS.some((protocol) => filename.startsWith(protocol))) return false;\n return !filename.includes(\"/node_modules/\") && !filename.startsWith(\"node:\");\n}\n\n/** True when every frame came from a browser extension — not the site's bug to fix. */\nexport function isExtensionOnlyStack(frames: readonly ExceptionFrame[]): boolean {\n if (frames.length === 0) return false;\n return frames.every((frame) => EXTENSION_PROTOCOLS.some((protocol) => (frame.filename ?? \"\").startsWith(protocol)));\n}\n\n// V8 (Chrome, Edge, Node): ` at fn (file:line:col)`, ` at file:line:col`,\n// plus the `async`, `new`, and `eval` decorations it adds.\nconst CHROME_LINE = /^\\s*at (?:(.+?)\\s+\\()?(?:(.+?):(\\d+):(\\d+)|\\(?([^)]*)\\)?)\\)?\\s*$/;\nconst CHROME_EVAL = /\\((\\S*)(?::(\\d+))(?::(\\d+))\\)/;\n\n// SpiderMonkey (Firefox) and JavaScriptCore (Safari): `fn@file:line:col`.\n// Firefox adds `/<` and `.prototype.` decorations; Safari omits the name for\n// global code and uses `[native code]` for host functions.\nconst GECKO_LINE =\n /^\\s*(?:(.*?)(?:\\((.*?)\\))?(?:^|@))?((?:file|https?|blob|chrome|webpack|resource|moz-extension|safari-extension|safari-web-extension|capacitor|\\[native).*?)(?::(\\d+))?(?::(\\d+))?\\s*$/i;\n\nfunction frame(\n filename: string | undefined,\n fn: string | undefined,\n lineno: string | undefined,\n colno: string | undefined\n): ExceptionFrame {\n const name = fn?.trim();\n return {\n ...(filename ? { filename } : {}),\n ...(name ? { function: name } : {}),\n ...(lineno ? { lineno: Number.parseInt(lineno, 10) } : {}),\n ...(colno ? { colno: Number.parseInt(colno, 10) } : {}),\n in_app: isInAppFrame(filename),\n };\n}\n\n/** V8's `async` and `new` are call decorations, not part of a function's identity. */\nfunction cleanV8Name(raw: string | undefined): string | undefined {\n if (!raw) return undefined;\n return raw.replace(/^async\\s+/, \"\").trim();\n}\n\nconst parseChromeLine: LineParser = (line) => {\n const match = CHROME_LINE.exec(line);\n if (!match) return undefined;\n\n let filename = match[2];\n let lineno = match[3];\n let colno = match[4];\n\n // `at fn (eval at x (file:1:2), <anonymous>:3:4)` — the useful location is\n // the outer file, not the synthetic eval one.\n if (filename?.startsWith(\"eval\")) {\n const evalMatch = CHROME_EVAL.exec(filename);\n if (evalMatch) {\n filename = evalMatch[1];\n lineno = evalMatch[2];\n colno = evalMatch[3];\n }\n }\n\n // The bare `at <anonymous>` / `at native` form: group 5 holds it and there is\n // no location to report.\n if (!filename && match[5]) return frame(undefined, cleanV8Name(match[1] ?? match[5]), undefined, undefined);\n if (!filename) return undefined;\n\n return frame(filename, cleanV8Name(match[1]), lineno, colno);\n};\n\nconst parseGeckoLine: LineParser = (line) => {\n const match = GECKO_LINE.exec(line);\n if (!match) return undefined;\n\n const filename = match[3];\n if (!filename) return undefined;\n // `[native code]` names no file; keep the function, drop the location.\n if (filename.startsWith(\"[native\")) return frame(undefined, match[1], undefined, undefined);\n\n // Firefox writes `fn/<` for a nested closure and `fn/name` for a named one;\n // the trailing part is noise for grouping.\n const fn = match[1]?.replace(/\\/[<.].*$/, \"\");\n return frame(filename, fn, match[4], match[5]);\n};\n\nconst LINE_PARSERS: LineParser[] = [parseChromeLine, parseGeckoLine];\n\n/**\n * Parse a stack string into frames, innermost first.\n *\n * Deliberately forgiving: a line no parser recognises is skipped rather than\n * failing the whole stack, so a message header, an `at <anonymous>`, or a\n * format nobody has seen yet costs one frame instead of all of them.\n */\nexport function parseStackString(stack: string | undefined): ExceptionFrame[] {\n if (!stack) return [];\n\n const frames: ExceptionFrame[] = [];\n for (const line of stack.split(\"\\n\")) {\n if (frames.length >= MAX_EXCEPTION_FRAMES) break;\n // A line that is only whitespace or the message header cannot be a frame.\n if (!line.trim()) continue;\n\n for (const parse of LINE_PARSERS) {\n const parsed = parse(line);\n if (!parsed) continue;\n // A frame with neither a file nor a name says nothing — Safari's\n // `[native code]` parses to exactly that, and it would only pad the\n // stack panel and the fingerprint with a blank row.\n if (parsed.filename || parsed.function) frames.push(parsed);\n break;\n }\n }\n\n return frames;\n}\n","/**\n * Turning whatever was thrown into a cause chain of structured exceptions.\n *\n * JavaScript lets you throw anything. In the field the majority are `Error`s,\n * but a meaningful tail are strings, `DOMException`s, `Event`s that a framework\n * passed along, and plain objects from a rejected fetch. Each of those needs a\n * type and a message that mean something in an issue list — `\"[object Object]\"`\n * groups every unrelated bug in the app into one issue.\n *\n * Shared by both SDKs and free of any runtime global: `DOMException` and\n * friends are detected by shape and by `constructor.name`, never by `instanceof`\n * against a global that may not exist.\n */\nimport {\n MAX_EXCEPTION_CHAIN,\n MAX_EXCEPTION_FRAMES,\n type ExceptionEntry,\n type ExceptionMechanism,\n} from \"@reopt-ai/data-contract/events\";\nimport { parseStackString } from \"./index.js\";\n\nconst MAX_MESSAGE_CHARS = 1_000;\n\nfunction truncate(value: string): string {\n return value.length > MAX_MESSAGE_CHARS ? value.slice(0, MAX_MESSAGE_CHARS) : value;\n}\n\nfunction isErrorLike(value: unknown): value is Error {\n if (value instanceof Error) return true;\n // Cross-realm errors (an iframe, a worker) fail `instanceof` but still have\n // the shape, and dropping them would lose exactly the errors that are hardest\n // to reproduce.\n const candidate = value as { name?: unknown; message?: unknown; stack?: unknown } | null;\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof candidate.name === \"string\" &&\n typeof candidate.message === \"string\"\n );\n}\n\nfunction constructorName(value: unknown): string | undefined {\n const name = (value as { constructor?: { name?: unknown } } | null)?.constructor?.name;\n return typeof name === \"string\" && name ? name : undefined;\n}\n\n/** `{\"a\":1}`, or the best available label when the value will not serialize. */\nfunction describeObject(value: object): string {\n try {\n const json = JSON.stringify(value);\n if (json && json !== \"{}\") return truncate(json);\n } catch {\n // Circular, or a getter that throws. Fall through to the shape label.\n }\n const keys = Object.keys(value);\n return keys.length > 0 ? `Object with keys: ${keys.slice(0, 10).join(\", \")}` : \"Object\";\n}\n\nfunction entry(type: string, value: string, mechanism: ExceptionMechanism, stack?: string | undefined): ExceptionEntry {\n const frames = parseStackString(stack).slice(0, MAX_EXCEPTION_FRAMES);\n return {\n type,\n value: truncate(value),\n mechanism,\n ...(frames.length > 0 ? { stacktrace: { frames, type: \"raw\" as const } } : {}),\n };\n}\n\n/**\n * One exception entry for a non-Error throw.\n *\n * Each branch exists because the naive `String(value)` reading of it is\n * useless: a `DOMException` stringifies to its message and loses the `name`\n * that says which DOM operation failed; an `ErrorEvent` stringifies to\n * `[object ErrorEvent]`; a plain object to `[object Object]`.\n */\nfunction coerceNonError(value: unknown, mechanism: ExceptionMechanism): ExceptionEntry {\n const synthetic: ExceptionMechanism = { ...mechanism, synthetic: true };\n\n if (typeof value === \"string\") return entry(\"Error\", value, synthetic);\n if (value === null) return entry(\"Error\", \"null\", synthetic);\n if (value === undefined) return entry(\"Error\", \"undefined\", synthetic);\n if (typeof value !== \"object\") return entry(\"Error\", `${typeof value}: ${String(value)}`, synthetic);\n\n const name = constructorName(value);\n const record = value as Record<string, unknown>;\n\n // `DOMException` is not handled here on purpose: it has a string `name` and\n // `message`, so `isErrorLike` claims it first and reports its own name\n // (`QuotaExceededError`, `AbortError`) as the type — which is the whole\n // diagnosis, and which grouping them all under \"DOMException\" would lose.\n // It is also a genuine thrown error, so it is not `synthetic`.\n\n // An ErrorEvent that reached us without its `error` — the message plus the\n // location is all the browser gave.\n if (name === \"ErrorEvent\" && typeof record.message === \"string\") {\n const where = [record.filename, record.lineno, record.colno].filter(Boolean).join(\":\");\n return entry(\"ErrorEvent\", where ? `${record.message} (${where})` : record.message, synthetic);\n }\n\n // Any other Event: its type is the only thing that distinguishes one from\n // another, and `[object Event]` distinguishes nothing.\n if (\n typeof record.type === \"string\" &&\n typeof (record as { preventDefault?: unknown }).preventDefault === \"function\"\n ) {\n return entry(name ?? \"Event\", `Event of type \"${record.type}\" was thrown`, synthetic);\n }\n\n return entry(name && name !== \"Object\" ? name : \"Error\", describeObject(value), synthetic);\n}\n\n/**\n * The full cause chain for one throw, outermost first.\n *\n * The chain is capped by the contract and by a seen-set: `a.cause = b;\n * b.cause = a` is rare but it is an infinite loop, and an SDK must not be the\n * thing that hangs the page it reports on.\n *\n * Causes are marked `handled: true` — only the outermost exception actually\n * escaped; the ones below it were caught and re-thrown, which is what a `cause`\n * chain means.\n */\nexport function coerceToExceptionChain(value: unknown, mechanism: ExceptionMechanism): ExceptionEntry[] {\n const chain: ExceptionEntry[] = [];\n const seen = new Set<unknown>();\n let current: unknown = value;\n let isOutermost = true;\n\n // The first value is always described, even when it is `undefined` —\n // `Promise.reject()` with no reason is a real thing that happens, and an\n // empty chain would report an exception with no type and no message.\n while (chain.length < MAX_EXCEPTION_CHAIN) {\n if (!isOutermost && current === undefined) break;\n if (typeof current === \"object\" && current !== null) {\n if (seen.has(current)) break;\n seen.add(current);\n }\n\n const linkMechanism: ExceptionMechanism = isOutermost ? mechanism : { ...mechanism, handled: true };\n\n if (isErrorLike(current)) {\n chain.push(entry(current.name || \"Error\", current.message, linkMechanism, current.stack));\n current = (current as { cause?: unknown }).cause;\n } else {\n chain.push(coerceNonError(current, linkMechanism));\n break;\n }\n\n isOutermost = false;\n }\n\n return chain;\n}\n","/**\n * Stamping frames with the chunk id the build injected.\n *\n * A frame's `filename` is a URL, and a URL is a fragile join key: it changes\n * with the CDN host, the base path, and every preview deployment. The build's\n * `reopt-data inject-chunk-ids` writes a content-derived id per chunk into\n * `globalThis._reoptChunkIds`, and this stamps it onto the frames so the\n * server can find the map by identity rather than by address.\n *\n * Lives in the lazily-imported `capture/exceptions` chunk, like the parsers.\n * The main bundle has a few bytes of headroom and this is not worth them —\n * a page that never throws must not pay for it.\n */\nimport type { ExceptionEntry } from \"@reopt-ai/data-contract/events\";\n\ntype ChunkIdMap = Record<string, string>;\n\n/** The file name a frame's URL ends in — the key the injector used. */\nfunction fileNameOf(filename: string): string {\n const withoutQuery = filename.split(/[?#]/)[0] ?? filename;\n return withoutQuery.split(\"/\").pop() ?? withoutQuery;\n}\n\nfunction chunkIds(): ChunkIdMap | undefined {\n const map = (globalThis as { _reoptChunkIds?: unknown })._reoptChunkIds;\n return map && typeof map === \"object\" ? (map as ChunkIdMap) : undefined;\n}\n\n/**\n * Add `chunk_id` to every frame the build stamped.\n *\n * Mutates in place: the chain was just built by the parser and is not shared,\n * and copying a fifty-frame chain per exception buys nothing.\n */\nexport function stampChunkIds(chain: ExceptionEntry[]): ExceptionEntry[] {\n const map = chunkIds();\n if (!map) return chain;\n\n for (const entry of chain) {\n for (const frame of entry.stacktrace?.frames ?? []) {\n if (!frame.filename || frame.chunk_id) continue;\n const id = map[fileNameOf(frame.filename)];\n if (typeof id === \"string\" && id) frame.chunk_id = id;\n }\n }\n return chain;\n}\n","/**\n * What an `$exception` event carries.\n *\n * Two shapes at once, on purpose. `$exception_list` is the structured form the\n * issue page renders and V2 fingerprinting reads; the flat `$exception_*` keys\n * are what every consumer written before it — dashboards, the rollup keys, V1\n * fingerprinting — already reads. Dropping the flat keys would re-group every\n * existing issue, so they stay.\n *\n * Everything here lives in the lazily-imported `capture/exceptions` chunk. It\n * must never be reachable from the main entry, or the parsers land in the\n * initial bundle of every page that never throws.\n */\nimport { coerceToExceptionChain, isExtensionOnlyStack, type ExceptionMechanism } from \"@reopt-ai/data-sdk-core\";\nimport { stampChunkIds } from \"./chunk-ids.js\";\nimport { MAX_STACK_CHARS, type ExceptionProperties, type ExceptionSource } from \"./exception-properties.js\";\n\nexport { type ExceptionProperties, type ExceptionSource } from \"./exception-properties.js\";\n\n/** The wire `mechanism.type` for each place an exception can reach us. */\nconst MECHANISM_TYPES: Record<ExceptionSource, ExceptionMechanism[\"type\"]> = {\n \"window.onerror\": \"onerror\",\n unhandledrejection: \"unhandledrejection\",\n captureException: \"manual\",\n};\n\n/**\n * Whether this error is worth reporting at all.\n *\n * A stack made entirely of extension frames is a bug in somebody's browser\n * extension running on the page. Reporting it puts an issue in the customer's\n * list that they cannot reproduce, cannot fix, and cannot make stop.\n */\nexport function shouldDropException(properties: ExceptionProperties): boolean {\n const chain = properties.$exception_list ?? [];\n if (chain.length === 0) return false;\n return chain.every((entry) => isExtensionOnlyStack(entry.stacktrace?.frames ?? []));\n}\n\nexport function describeError(value: unknown, source: ExceptionSource): ExceptionProperties {\n const path = typeof location !== \"undefined\" ? location.pathname : \"\";\n const handled = source === \"captureException\";\n const chain = stampChunkIds(coerceToExceptionChain(value, { handled, type: MECHANISM_TYPES[source] }));\n const head = chain[0];\n\n // The flat keys describe the outermost exception — the one that escaped —\n // which is what they meant before the chain existed.\n const rawStack = value instanceof Error && value.stack ? value.stack.slice(0, MAX_STACK_CHARS) : undefined;\n\n return {\n $exception_type: head?.type ?? \"Error\",\n $exception_message: head?.value ?? \"\",\n ...(rawStack ? { $exception_stack: rawStack } : {}),\n $exception_source: source,\n $exception_handled: handled,\n $exception_list: chain,\n path,\n };\n}\n","/**\n * Keeping one broken component from becoming a denial of service.\n *\n * An `unhandledrejection` inside a render loop, or an `onerror` from a handler\n * that re-throws, fires as fast as the event loop allows. Unthrottled that is\n * thousands of identical events a second — it fills the visitor's network, the\n * customer's quota, and the issue's occurrence count with one bug.\n *\n * Per exception *type*, not globally: a page that is genuinely throwing two\n * different errors should report both, and a single runaway type must not\n * silence the other one.\n *\n * Lives in the lazily-loaded exception chunk — nothing needs it until something\n * has already thrown.\n */\nexport interface ExceptionRateLimitOptions {\n /** Burst allowance. */\n bucketSize: number;\n /** Seconds to earn one token back. */\n refillSeconds: number;\n}\n\nexport const DEFAULT_EXCEPTION_RATE_LIMIT: ExceptionRateLimitOptions = {\n bucketSize: 10,\n refillSeconds: 10,\n};\n\nexport interface ExceptionRateLimiter {\n /** True when this exception may be reported. */\n allow(type: string, now?: number): boolean;\n}\n\n/**\n * A token bucket per exception type.\n *\n * Tokens are computed from elapsed time rather than a timer: an SDK that keeps\n * an interval alive to refill a counter keeps the page alive too.\n */\nexport function createExceptionRateLimiter(options: Partial<ExceptionRateLimitOptions> = {}): ExceptionRateLimiter {\n const buckets = new Map<string, { tokens: number; updatedAt: number }>();\n const refillMs = Math.max(options.refillSeconds ?? DEFAULT_EXCEPTION_RATE_LIMIT.refillSeconds, 0.001) * 1_000;\n const size = Math.max(options.bucketSize ?? DEFAULT_EXCEPTION_RATE_LIMIT.bucketSize, 1);\n\n return {\n allow(type, now = Date.now()) {\n const bucket = buckets.get(type) ?? { tokens: size, updatedAt: now };\n const earned = Math.floor((now - bucket.updatedAt) / refillMs);\n const tokens = Math.min(size, bucket.tokens + Math.max(earned, 0));\n // Only advance the clock by the whole tokens actually earned, or a\n // steady trickle below the refill interval would never accumulate.\n const updatedAt = earned > 0 ? bucket.updatedAt + earned * refillMs : bucket.updatedAt;\n\n if (tokens <= 0) {\n buckets.set(type, { tokens, updatedAt });\n return false;\n }\n\n buckets.set(type, { tokens: tokens - 1, updatedAt });\n return true;\n },\n };\n}\n","import { describeError, shouldDropException, type ExceptionProperties } from \"./describe-error.js\";\nimport { createExceptionRateLimiter, type ExceptionRateLimitOptions } from \"./exception-rate-limit.js\";\n\n/**\n * Reports uncaught errors and unhandled promise rejections. Errors thrown by\n * the reporter itself are swallowed — an analytics SDK must never turn one\n * crash into two.\n */\nexport interface ExceptionCaptureOptions {\n /** `false` reports every exception; otherwise the token bucket to throttle by type. */\n rateLimit?: Partial<ExceptionRateLimitOptions> | false | undefined;\n /** Called once per type when throttling starts dropping, for the debug log. */\n onThrottled?: ((type: string) => void) | undefined;\n}\n\nexport function installExceptionCapture(\n report: (properties: ExceptionProperties) => void,\n options: ExceptionCaptureOptions = {}\n): () => void {\n if (typeof window === \"undefined\") return () => {};\n\n const limiter = options.rateLimit === false ? null : createExceptionRateLimiter(options.rateLimit);\n const throttled = new Set<string>();\n\n /**\n * Report unless the stack is entirely browser-extension frames, or this type\n * has burned through its budget. The throttle notice fires once per type, so\n * a storm does not also become a console storm.\n */\n const send = (properties: ExceptionProperties) => {\n if (shouldDropException(properties)) return;\n if (limiter && !limiter.allow(properties.$exception_type)) {\n if (!throttled.has(properties.$exception_type)) {\n throttled.add(properties.$exception_type);\n options.onThrottled?.(properties.$exception_type);\n }\n return;\n }\n report(properties);\n };\n const onError = (event: ErrorEvent) => {\n try {\n // Some environments deliver the message but not the Error object.\n send(describeError(event.error ?? new Error(event.message), \"window.onerror\"));\n } catch {\n // see above\n }\n };\n const onRejection = (event: PromiseRejectionEvent) => {\n try {\n send(describeError(event.reason, \"unhandledrejection\"));\n } catch {\n // see above\n }\n };\n window.addEventListener(\"error\", onError);\n window.addEventListener(\"unhandledrejection\", onRejection);\n return () => {\n window.removeEventListener(\"error\", onError);\n window.removeEventListener(\"unhandledrejection\", onRejection);\n };\n}\n\n/** Re-exported so the client can use the full describer once this chunk is loaded. */\nexport { describeError, shouldDropException } from \"./describe-error.js\";\nexport { createExceptionRateLimiter, DEFAULT_EXCEPTION_RATE_LIMIT } from \"./exception-rate-limit.js\";\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { o as MAX_STACK_CHARS } from "./registry-BPhiH_l9.js";
1
+ import { o as MAX_STACK_CHARS } from "./registry-IzNqE02g.js";
2
2
  import { MAX_EXCEPTION_CHAIN, MAX_EXCEPTION_FRAMES } from "@reopt-ai/data-contract/events";
3
3
  //#region ../data-sdk-core/src/stack-parsers/index.ts
4
4
  const EXTENSION_PROTOCOLS = [
@@ -282,4 +282,4 @@ function installExceptionCapture(report, options = {}) {
282
282
  //#endregion
283
283
  export { DEFAULT_EXCEPTION_RATE_LIMIT, createExceptionRateLimiter, describeError, installExceptionCapture, shouldDropException };
284
284
 
285
- //# sourceMappingURL=exceptions-C9Fh0BIR.js.map
285
+ //# sourceMappingURL=exceptions-CorACVsv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exceptions-CorACVsv.js","names":[],"sources":["../../data-sdk-core/src/stack-parsers/index.ts","../../data-sdk-core/src/stack-parsers/coerce.ts","../src/capture/chunk-ids.ts","../src/capture/describe-error.ts","../src/capture/exception-rate-limit.ts","../src/capture/exceptions.ts"],"sourcesContent":["/**\n * Turning an `error.stack` string into structured frames.\n *\n * Every JS engine formats a stack differently and none of them documents the\n * format, so this is pattern matching against what the engines actually emit.\n * The regexes descend from Sentry's `stacktrace.ts` by way of posthog-js\n * (`packages/core/src/error-tracking/parsers/`), both MIT — the shapes are the\n * accumulated result of years of field reports, and rewriting them from the\n * specs would mean rediscovering the same edge cases.\n *\n * Lives in `data-sdk-core` because the browser and the server SDK both need it\n * and neither may depend on the other. Core has no build step; both consumers\n * inline this source, so nothing here may reach for a browser or Node global.\n */\nimport { MAX_EXCEPTION_FRAMES, type ExceptionFrame } from \"@reopt-ai/data-contract/events\";\n\n/** A parser turns one stack line into a frame, or returns undefined if it cannot. */\ntype LineParser = (line: string) => ExceptionFrame | undefined;\n\n/** Frames the runtime, not the app: a stack of only these is not worth reporting. */\nconst EXTENSION_PROTOCOLS = [\n \"chrome-extension://\",\n \"moz-extension://\",\n \"safari-extension://\",\n \"safari-web-extension://\",\n];\n\n/** WebKit masks cross-origin URLs; a masked frame names no file anyone can open. */\nconst WEBKIT_MASKED_URL = \"webkit-masked-url://\";\nconst ANONYMOUS_FILE = \"<anonymous>\";\n\n/**\n * Whether a frame is the app's own code.\n *\n * Anything the app did not write — an extension's injected script, a masked\n * cross-origin URL, a frame with no file at all — is not somewhere a developer\n * can go and fix, so the stack panel hides it by default.\n */\nexport function isInAppFrame(filename: string | undefined): boolean {\n if (!filename || filename === ANONYMOUS_FILE) return false;\n if (filename.startsWith(WEBKIT_MASKED_URL)) return false;\n if (EXTENSION_PROTOCOLS.some((protocol) => filename.startsWith(protocol))) return false;\n return !filename.includes(\"/node_modules/\") && !filename.startsWith(\"node:\");\n}\n\n/** True when every frame came from a browser extension — not the site's bug to fix. */\nexport function isExtensionOnlyStack(frames: readonly ExceptionFrame[]): boolean {\n if (frames.length === 0) return false;\n return frames.every((frame) => EXTENSION_PROTOCOLS.some((protocol) => (frame.filename ?? \"\").startsWith(protocol)));\n}\n\n// V8 (Chrome, Edge, Node): ` at fn (file:line:col)`, ` at file:line:col`,\n// plus the `async`, `new`, and `eval` decorations it adds.\nconst CHROME_LINE = /^\\s*at (?:(.+?)\\s+\\()?(?:(.+?):(\\d+):(\\d+)|\\(?([^)]*)\\)?)\\)?\\s*$/;\nconst CHROME_EVAL = /\\((\\S*)(?::(\\d+))(?::(\\d+))\\)/;\n\n// SpiderMonkey (Firefox) and JavaScriptCore (Safari): `fn@file:line:col`.\n// Firefox adds `/<` and `.prototype.` decorations; Safari omits the name for\n// global code and uses `[native code]` for host functions.\nconst GECKO_LINE =\n /^\\s*(?:(.*?)(?:\\((.*?)\\))?(?:^|@))?((?:file|https?|blob|chrome|webpack|resource|moz-extension|safari-extension|safari-web-extension|capacitor|\\[native).*?)(?::(\\d+))?(?::(\\d+))?\\s*$/i;\n\nfunction frame(\n filename: string | undefined,\n fn: string | undefined,\n lineno: string | undefined,\n colno: string | undefined\n): ExceptionFrame {\n const name = fn?.trim();\n return {\n ...(filename ? { filename } : {}),\n ...(name ? { function: name } : {}),\n ...(lineno ? { lineno: Number.parseInt(lineno, 10) } : {}),\n ...(colno ? { colno: Number.parseInt(colno, 10) } : {}),\n in_app: isInAppFrame(filename),\n };\n}\n\n/** V8's `async` and `new` are call decorations, not part of a function's identity. */\nfunction cleanV8Name(raw: string | undefined): string | undefined {\n if (!raw) return undefined;\n return raw.replace(/^async\\s+/, \"\").trim();\n}\n\nconst parseChromeLine: LineParser = (line) => {\n const match = CHROME_LINE.exec(line);\n if (!match) return undefined;\n\n let filename = match[2];\n let lineno = match[3];\n let colno = match[4];\n\n // `at fn (eval at x (file:1:2), <anonymous>:3:4)` — the useful location is\n // the outer file, not the synthetic eval one.\n if (filename?.startsWith(\"eval\")) {\n const evalMatch = CHROME_EVAL.exec(filename);\n if (evalMatch) {\n filename = evalMatch[1];\n lineno = evalMatch[2];\n colno = evalMatch[3];\n }\n }\n\n // The bare `at <anonymous>` / `at native` form: group 5 holds it and there is\n // no location to report.\n if (!filename && match[5]) return frame(undefined, cleanV8Name(match[1] ?? match[5]), undefined, undefined);\n if (!filename) return undefined;\n\n return frame(filename, cleanV8Name(match[1]), lineno, colno);\n};\n\nconst parseGeckoLine: LineParser = (line) => {\n const match = GECKO_LINE.exec(line);\n if (!match) return undefined;\n\n const filename = match[3];\n if (!filename) return undefined;\n // `[native code]` names no file; keep the function, drop the location.\n if (filename.startsWith(\"[native\")) return frame(undefined, match[1], undefined, undefined);\n\n // Firefox writes `fn/<` for a nested closure and `fn/name` for a named one;\n // the trailing part is noise for grouping.\n const fn = match[1]?.replace(/\\/[<.].*$/, \"\");\n return frame(filename, fn, match[4], match[5]);\n};\n\nconst LINE_PARSERS: LineParser[] = [parseChromeLine, parseGeckoLine];\n\n/**\n * Parse a stack string into frames, innermost first.\n *\n * Deliberately forgiving: a line no parser recognises is skipped rather than\n * failing the whole stack, so a message header, an `at <anonymous>`, or a\n * format nobody has seen yet costs one frame instead of all of them.\n */\nexport function parseStackString(stack: string | undefined): ExceptionFrame[] {\n if (!stack) return [];\n\n const frames: ExceptionFrame[] = [];\n for (const line of stack.split(\"\\n\")) {\n if (frames.length >= MAX_EXCEPTION_FRAMES) break;\n // A line that is only whitespace or the message header cannot be a frame.\n if (!line.trim()) continue;\n\n for (const parse of LINE_PARSERS) {\n const parsed = parse(line);\n if (!parsed) continue;\n // A frame with neither a file nor a name says nothing — Safari's\n // `[native code]` parses to exactly that, and it would only pad the\n // stack panel and the fingerprint with a blank row.\n if (parsed.filename || parsed.function) frames.push(parsed);\n break;\n }\n }\n\n return frames;\n}\n","/**\n * Turning whatever was thrown into a cause chain of structured exceptions.\n *\n * JavaScript lets you throw anything. In the field the majority are `Error`s,\n * but a meaningful tail are strings, `DOMException`s, `Event`s that a framework\n * passed along, and plain objects from a rejected fetch. Each of those needs a\n * type and a message that mean something in an issue list — `\"[object Object]\"`\n * groups every unrelated bug in the app into one issue.\n *\n * Shared by both SDKs and free of any runtime global: `DOMException` and\n * friends are detected by shape and by `constructor.name`, never by `instanceof`\n * against a global that may not exist.\n */\nimport {\n MAX_EXCEPTION_CHAIN,\n MAX_EXCEPTION_FRAMES,\n type ExceptionEntry,\n type ExceptionMechanism,\n} from \"@reopt-ai/data-contract/events\";\nimport { parseStackString } from \"./index.js\";\n\nconst MAX_MESSAGE_CHARS = 1_000;\n\nfunction truncate(value: string): string {\n return value.length > MAX_MESSAGE_CHARS ? value.slice(0, MAX_MESSAGE_CHARS) : value;\n}\n\nfunction isErrorLike(value: unknown): value is Error {\n if (value instanceof Error) return true;\n // Cross-realm errors (an iframe, a worker) fail `instanceof` but still have\n // the shape, and dropping them would lose exactly the errors that are hardest\n // to reproduce.\n const candidate = value as { name?: unknown; message?: unknown; stack?: unknown } | null;\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof candidate.name === \"string\" &&\n typeof candidate.message === \"string\"\n );\n}\n\nfunction constructorName(value: unknown): string | undefined {\n const name = (value as { constructor?: { name?: unknown } } | null)?.constructor?.name;\n return typeof name === \"string\" && name ? name : undefined;\n}\n\n/** `{\"a\":1}`, or the best available label when the value will not serialize. */\nfunction describeObject(value: object): string {\n try {\n const json = JSON.stringify(value);\n if (json && json !== \"{}\") return truncate(json);\n } catch {\n // Circular, or a getter that throws. Fall through to the shape label.\n }\n const keys = Object.keys(value);\n return keys.length > 0 ? `Object with keys: ${keys.slice(0, 10).join(\", \")}` : \"Object\";\n}\n\nfunction entry(type: string, value: string, mechanism: ExceptionMechanism, stack?: string | undefined): ExceptionEntry {\n const frames = parseStackString(stack).slice(0, MAX_EXCEPTION_FRAMES);\n return {\n type,\n value: truncate(value),\n mechanism,\n ...(frames.length > 0 ? { stacktrace: { frames, type: \"raw\" as const } } : {}),\n };\n}\n\n/**\n * One exception entry for a non-Error throw.\n *\n * Each branch exists because the naive `String(value)` reading of it is\n * useless: a `DOMException` stringifies to its message and loses the `name`\n * that says which DOM operation failed; an `ErrorEvent` stringifies to\n * `[object ErrorEvent]`; a plain object to `[object Object]`.\n */\nfunction coerceNonError(value: unknown, mechanism: ExceptionMechanism): ExceptionEntry {\n const synthetic: ExceptionMechanism = { ...mechanism, synthetic: true };\n\n if (typeof value === \"string\") return entry(\"Error\", value, synthetic);\n if (value === null) return entry(\"Error\", \"null\", synthetic);\n if (value === undefined) return entry(\"Error\", \"undefined\", synthetic);\n if (typeof value !== \"object\") return entry(\"Error\", `${typeof value}: ${String(value)}`, synthetic);\n\n const name = constructorName(value);\n const record = value as Record<string, unknown>;\n\n // `DOMException` is not handled here on purpose: it has a string `name` and\n // `message`, so `isErrorLike` claims it first and reports its own name\n // (`QuotaExceededError`, `AbortError`) as the type — which is the whole\n // diagnosis, and which grouping them all under \"DOMException\" would lose.\n // It is also a genuine thrown error, so it is not `synthetic`.\n\n // An ErrorEvent that reached us without its `error` — the message plus the\n // location is all the browser gave.\n if (name === \"ErrorEvent\" && typeof record.message === \"string\") {\n const where = [record.filename, record.lineno, record.colno].filter(Boolean).join(\":\");\n return entry(\"ErrorEvent\", where ? `${record.message} (${where})` : record.message, synthetic);\n }\n\n // Any other Event: its type is the only thing that distinguishes one from\n // another, and `[object Event]` distinguishes nothing.\n if (\n typeof record.type === \"string\" &&\n typeof (record as { preventDefault?: unknown }).preventDefault === \"function\"\n ) {\n return entry(name ?? \"Event\", `Event of type \"${record.type}\" was thrown`, synthetic);\n }\n\n return entry(name && name !== \"Object\" ? name : \"Error\", describeObject(value), synthetic);\n}\n\n/**\n * The full cause chain for one throw, outermost first.\n *\n * The chain is capped by the contract and by a seen-set: `a.cause = b;\n * b.cause = a` is rare but it is an infinite loop, and an SDK must not be the\n * thing that hangs the page it reports on.\n *\n * Causes are marked `handled: true` — only the outermost exception actually\n * escaped; the ones below it were caught and re-thrown, which is what a `cause`\n * chain means.\n */\nexport function coerceToExceptionChain(value: unknown, mechanism: ExceptionMechanism): ExceptionEntry[] {\n const chain: ExceptionEntry[] = [];\n const seen = new Set<unknown>();\n let current: unknown = value;\n let isOutermost = true;\n\n // The first value is always described, even when it is `undefined` —\n // `Promise.reject()` with no reason is a real thing that happens, and an\n // empty chain would report an exception with no type and no message.\n while (chain.length < MAX_EXCEPTION_CHAIN) {\n if (!isOutermost && current === undefined) break;\n if (typeof current === \"object\" && current !== null) {\n if (seen.has(current)) break;\n seen.add(current);\n }\n\n const linkMechanism: ExceptionMechanism = isOutermost ? mechanism : { ...mechanism, handled: true };\n\n if (isErrorLike(current)) {\n chain.push(entry(current.name || \"Error\", current.message, linkMechanism, current.stack));\n current = (current as { cause?: unknown }).cause;\n } else {\n chain.push(coerceNonError(current, linkMechanism));\n break;\n }\n\n isOutermost = false;\n }\n\n return chain;\n}\n","/**\n * Stamping frames with the chunk id the build injected.\n *\n * A frame's `filename` is a URL, and a URL is a fragile join key: it changes\n * with the CDN host, the base path, and every preview deployment. The build's\n * `reopt-data inject-chunk-ids` writes a content-derived id per chunk into\n * `globalThis._reoptChunkIds`, and this stamps it onto the frames so the\n * server can find the map by identity rather than by address.\n *\n * Lives in the lazily-imported `capture/exceptions` chunk, like the parsers.\n * The main bundle has a few bytes of headroom and this is not worth them —\n * a page that never throws must not pay for it.\n */\nimport type { ExceptionEntry } from \"@reopt-ai/data-contract/events\";\n\ntype ChunkIdMap = Record<string, string>;\n\n/** The file name a frame's URL ends in — the key the injector used. */\nfunction fileNameOf(filename: string): string {\n const withoutQuery = filename.split(/[?#]/)[0] ?? filename;\n return withoutQuery.split(\"/\").pop() ?? withoutQuery;\n}\n\nfunction chunkIds(): ChunkIdMap | undefined {\n const map = (globalThis as { _reoptChunkIds?: unknown })._reoptChunkIds;\n return map && typeof map === \"object\" ? (map as ChunkIdMap) : undefined;\n}\n\n/**\n * Add `chunk_id` to every frame the build stamped.\n *\n * Mutates in place: the chain was just built by the parser and is not shared,\n * and copying a fifty-frame chain per exception buys nothing.\n */\nexport function stampChunkIds(chain: ExceptionEntry[]): ExceptionEntry[] {\n const map = chunkIds();\n if (!map) return chain;\n\n for (const entry of chain) {\n for (const frame of entry.stacktrace?.frames ?? []) {\n if (!frame.filename || frame.chunk_id) continue;\n const id = map[fileNameOf(frame.filename)];\n if (typeof id === \"string\" && id) frame.chunk_id = id;\n }\n }\n return chain;\n}\n","/**\n * What an `$exception` event carries.\n *\n * Two shapes at once, on purpose. `$exception_list` is the structured form the\n * issue page renders and V2 fingerprinting reads; the flat `$exception_*` keys\n * are what every consumer written before it — dashboards, the rollup keys, V1\n * fingerprinting — already reads. Dropping the flat keys would re-group every\n * existing issue, so they stay.\n *\n * Everything here lives in the lazily-imported `capture/exceptions` chunk. It\n * must never be reachable from the main entry, or the parsers land in the\n * initial bundle of every page that never throws.\n */\nimport { coerceToExceptionChain, isExtensionOnlyStack, type ExceptionMechanism } from \"@reopt-ai/data-sdk-core\";\nimport { stampChunkIds } from \"./chunk-ids.js\";\nimport { MAX_STACK_CHARS, type ExceptionProperties, type ExceptionSource } from \"./exception-properties.js\";\n\nexport { type ExceptionProperties, type ExceptionSource } from \"./exception-properties.js\";\n\n/** The wire `mechanism.type` for each place an exception can reach us. */\nconst MECHANISM_TYPES: Record<ExceptionSource, ExceptionMechanism[\"type\"]> = {\n \"window.onerror\": \"onerror\",\n unhandledrejection: \"unhandledrejection\",\n captureException: \"manual\",\n};\n\n/**\n * Whether this error is worth reporting at all.\n *\n * A stack made entirely of extension frames is a bug in somebody's browser\n * extension running on the page. Reporting it puts an issue in the customer's\n * list that they cannot reproduce, cannot fix, and cannot make stop.\n */\nexport function shouldDropException(properties: ExceptionProperties): boolean {\n const chain = properties.$exception_list ?? [];\n if (chain.length === 0) return false;\n return chain.every((entry) => isExtensionOnlyStack(entry.stacktrace?.frames ?? []));\n}\n\nexport function describeError(value: unknown, source: ExceptionSource): ExceptionProperties {\n const path = typeof location !== \"undefined\" ? location.pathname : \"\";\n const handled = source === \"captureException\";\n const chain = stampChunkIds(coerceToExceptionChain(value, { handled, type: MECHANISM_TYPES[source] }));\n const head = chain[0];\n\n // The flat keys describe the outermost exception — the one that escaped —\n // which is what they meant before the chain existed.\n const rawStack = value instanceof Error && value.stack ? value.stack.slice(0, MAX_STACK_CHARS) : undefined;\n\n return {\n $exception_type: head?.type ?? \"Error\",\n $exception_message: head?.value ?? \"\",\n ...(rawStack ? { $exception_stack: rawStack } : {}),\n $exception_source: source,\n $exception_handled: handled,\n $exception_list: chain,\n path,\n };\n}\n","/**\n * Keeping one broken component from becoming a denial of service.\n *\n * An `unhandledrejection` inside a render loop, or an `onerror` from a handler\n * that re-throws, fires as fast as the event loop allows. Unthrottled that is\n * thousands of identical events a second — it fills the visitor's network, the\n * customer's quota, and the issue's occurrence count with one bug.\n *\n * Per exception *type*, not globally: a page that is genuinely throwing two\n * different errors should report both, and a single runaway type must not\n * silence the other one.\n *\n * Lives in the lazily-loaded exception chunk — nothing needs it until something\n * has already thrown.\n */\nexport interface ExceptionRateLimitOptions {\n /** Burst allowance. */\n bucketSize: number;\n /** Seconds to earn one token back. */\n refillSeconds: number;\n}\n\nexport const DEFAULT_EXCEPTION_RATE_LIMIT: ExceptionRateLimitOptions = {\n bucketSize: 10,\n refillSeconds: 10,\n};\n\nexport interface ExceptionRateLimiter {\n /** True when this exception may be reported. */\n allow(type: string, now?: number): boolean;\n}\n\n/**\n * A token bucket per exception type.\n *\n * Tokens are computed from elapsed time rather than a timer: an SDK that keeps\n * an interval alive to refill a counter keeps the page alive too.\n */\nexport function createExceptionRateLimiter(options: Partial<ExceptionRateLimitOptions> = {}): ExceptionRateLimiter {\n const buckets = new Map<string, { tokens: number; updatedAt: number }>();\n const refillMs = Math.max(options.refillSeconds ?? DEFAULT_EXCEPTION_RATE_LIMIT.refillSeconds, 0.001) * 1_000;\n const size = Math.max(options.bucketSize ?? DEFAULT_EXCEPTION_RATE_LIMIT.bucketSize, 1);\n\n return {\n allow(type, now = Date.now()) {\n const bucket = buckets.get(type) ?? { tokens: size, updatedAt: now };\n const earned = Math.floor((now - bucket.updatedAt) / refillMs);\n const tokens = Math.min(size, bucket.tokens + Math.max(earned, 0));\n // Only advance the clock by the whole tokens actually earned, or a\n // steady trickle below the refill interval would never accumulate.\n const updatedAt = earned > 0 ? bucket.updatedAt + earned * refillMs : bucket.updatedAt;\n\n if (tokens <= 0) {\n buckets.set(type, { tokens, updatedAt });\n return false;\n }\n\n buckets.set(type, { tokens: tokens - 1, updatedAt });\n return true;\n },\n };\n}\n","import { describeError, shouldDropException, type ExceptionProperties } from \"./describe-error.js\";\nimport { createExceptionRateLimiter, type ExceptionRateLimitOptions } from \"./exception-rate-limit.js\";\n\n/**\n * Reports uncaught errors and unhandled promise rejections. Errors thrown by\n * the reporter itself are swallowed — an analytics SDK must never turn one\n * crash into two.\n */\nexport interface ExceptionCaptureOptions {\n /** `false` reports every exception; otherwise the token bucket to throttle by type. */\n rateLimit?: Partial<ExceptionRateLimitOptions> | false | undefined;\n /** Called once per type when throttling starts dropping, for the debug log. */\n onThrottled?: ((type: string) => void) | undefined;\n}\n\nexport function installExceptionCapture(\n report: (properties: ExceptionProperties) => void,\n options: ExceptionCaptureOptions = {}\n): () => void {\n if (typeof window === \"undefined\") return () => {};\n\n const limiter = options.rateLimit === false ? null : createExceptionRateLimiter(options.rateLimit);\n const throttled = new Set<string>();\n\n /**\n * Report unless the stack is entirely browser-extension frames, or this type\n * has burned through its budget. The throttle notice fires once per type, so\n * a storm does not also become a console storm.\n */\n const send = (properties: ExceptionProperties) => {\n if (shouldDropException(properties)) return;\n if (limiter && !limiter.allow(properties.$exception_type)) {\n if (!throttled.has(properties.$exception_type)) {\n throttled.add(properties.$exception_type);\n options.onThrottled?.(properties.$exception_type);\n }\n return;\n }\n report(properties);\n };\n const onError = (event: ErrorEvent) => {\n try {\n // Some environments deliver the message but not the Error object.\n send(describeError(event.error ?? new Error(event.message), \"window.onerror\"));\n } catch {\n // see above\n }\n };\n const onRejection = (event: PromiseRejectionEvent) => {\n try {\n send(describeError(event.reason, \"unhandledrejection\"));\n } catch {\n // see above\n }\n };\n window.addEventListener(\"error\", onError);\n window.addEventListener(\"unhandledrejection\", onRejection);\n return () => {\n window.removeEventListener(\"error\", onError);\n window.removeEventListener(\"unhandledrejection\", onRejection);\n };\n}\n\n/** Re-exported so the client can use the full describer once this chunk is loaded. */\nexport { describeError, shouldDropException } from \"./describe-error.js\";\nexport { createExceptionRateLimiter, DEFAULT_EXCEPTION_RATE_LIMIT } from \"./exception-rate-limit.js\";\n"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_registry = require("./registry-CGqrOtf4.cjs");
2
+ const require_registry = require("./registry-DR1N7wD5.cjs");
3
3
  //#region src/index.ts
4
4
  function init(config) {
5
5
  return require_registry.getOrCreateClient(config);