@newtalaria/browser 0.1.10 → 0.1.13

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.
@@ -1,5 +1,11 @@
1
1
  import type { FailedRequestStatusCode } from '../types.js';
2
2
  export type Teardown = () => void;
3
+ /**
4
+ * Fire when the document becomes visible again (tab focus) or is restored
5
+ * from the back/forward cache. Used to refresh the rrweb paint base after
6
+ * background throttling would have skipped periodic checkouts.
7
+ */
8
+ export declare function installVisibilityResumeHook(onResume: () => void): Teardown;
3
9
  export interface NetworkMeta {
4
10
  method: string;
5
11
  url: string;
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/replay/hooks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC;AAElC,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,EAAE,CAAC,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IACxC;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACnE,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,wBAAwB,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACrD,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;IACnC,qFAAqF;IACrF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAiBD,2EAA2E;AAC3E,wBAAgB,kBAAkB,IAAI,QAAQ,CA2B7C;AAcD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,uBAAuB,EAAE,GAC/B,OAAO,CAUT;AAED,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE;IACJ,qBAAqB,EAAE,OAAO,CAAC;IAC/B,wBAAwB,EAAE,uBAAuB,EAAE,CAAC;IACpD,uBAAuB,EAAE,MAAM,EAAE,CAAC;IAClC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GACA,IAAI,IAAI,WAAW,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAoB1C;AAED,8FAA8F;AAC9F,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,kBAAuB,GAAG,QAAQ,CA+F7E"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/replay/hooks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC;AAElC;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,QAAQ,CA4B1E;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,EAAE,CAAC,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IACxC;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACnE,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,wBAAwB,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACrD,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;IACnC,qFAAqF;IACrF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAiBD,2EAA2E;AAC3E,wBAAgB,kBAAkB,IAAI,QAAQ,CA2B7C;AAcD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,uBAAuB,EAAE,GAC/B,OAAO,CAUT;AAED,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE;IACJ,qBAAqB,EAAE,OAAO,CAAC;IAC/B,wBAAwB,EAAE,uBAAuB,EAAE,CAAC;IACpD,uBAAuB,EAAE,MAAM,EAAE,CAAC;IAClC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GACA,IAAI,IAAI,WAAW,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAoB1C;AAED,8FAA8F;AAC9F,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,kBAAuB,GAAG,QAAQ,CA+F7E"}
@@ -4,6 +4,11 @@ export interface RecorderOptions {
4
4
  /** Embed accessible stylesheet rules into the snapshot. Default false at resolve time. */
5
5
  inlineStylesheet: boolean;
6
6
  blockSelector?: string;
7
+ /**
8
+ * Periodic Meta+FullSnapshot while recording (rrweb `checkoutEveryNms`).
9
+ * Set in buffer/error-sample mode so the ring never ages out its paint base.
10
+ */
11
+ checkoutEveryNms?: number;
7
12
  onEvent: (event: RrwebEvent) => void;
8
13
  }
9
14
  export interface RecorderHandle {
@@ -1 +1 @@
1
- {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/replay/recorder.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,OAAO,CAAC;IACvB,0FAA0F;IAC1F,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,qEAAqE;IACrE,gBAAgB,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,cAAc,CA0CtE"}
1
+ {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/replay/recorder.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,OAAO,CAAC;IACvB,0FAA0F;IAC1F,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,qEAAqE;IACrE,gBAAgB,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,cAAc,CA6CtE"}
@@ -34,6 +34,11 @@ export declare const ERROR_CLIP_FLUSH_SLACK_MS = 5000;
34
34
  export declare const SEGMENT_FLUSH_MS = 5000;
35
35
  /** Keep ~60s of events while buffering (error-only sample path). */
36
36
  export declare const RING_BUFFER_MS = 60000;
37
+ /**
38
+ * rrweb checkout interval in buffer mode — must be ≤ {@link RING_BUFFER_MS}
39
+ * so a FullSnapshot always remains inside the ring after idle/away trim.
40
+ */
41
+ export declare const RING_BUFFER_CHECKOUT_MS = 60000;
37
42
  /** Cap ring buffer size so one error flush stays bounded. */
38
43
  export declare const RING_BUFFER_MAX_BYTES = 1500000;
39
44
  /** Default post-error upload window (cheap error clip). */
@@ -1 +1 @@
1
- {"version":3,"file":"segment_buffer.d.ts","sourceRoot":"","sources":["../../src/replay/segment_buffer.ts"],"names":[],"mappings":"AAEA,oDAAoD;AACpD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,SAAU,CAAC;AAC1C;;;GAGG;AACH,eAAO,MAAM,4BAA4B,QAAc,CAAC;AACxD,iFAAiF;AACjF,eAAO,MAAM,+BAA+B,QACF,CAAC;AAC3C;;;GAGG;AACH,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C;;GAEG;AACH,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C,uEAAuE;AACvE,eAAO,MAAM,+BAA+B,QAAkB,CAAC;AAC/D,8DAA8D;AAC9D,eAAO,MAAM,yBAAyB,OAAQ,CAAC;AAC/C,+BAA+B;AAC/B,eAAO,MAAM,gBAAgB,OAAQ,CAAC;AACtC,oEAAoE;AACpE,eAAO,MAAM,cAAc,QAAS,CAAC;AACrC,6DAA6D;AAC7D,eAAO,MAAM,qBAAqB,UAAY,CAAC;AAC/C,2DAA2D;AAC3D,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAC5C;;;GAGG;AACH,eAAO,MAAM,sBAAsB,QAAgB,CAAC;AAEpD,mCAAmC;AACnC,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,2BAA2B;AAC3B,eAAO,MAAM,UAAU,IAAI,CAAC;AAE5B,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,YAAY,CAAK;IAEzB,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAK7B,eAAe,IAAI,OAAO;IAI1B,4DAA4D;IAC5D,gBAAgB,IAAI,UAAU,GAAG,SAAS;IAI1C;;;OAGG;IACH,kBAAkB,IAAI,OAAO;IAc7B;;;OAGG;IACH,QAAQ,CAAC,GAAG,SAAa,EAAE,QAAQ,SAAwB,GAAG,IAAI;IAiBlE,iBAAiB,IAAI,OAAO;IAI5B;;;OAGG;IACH,eAAe,IAAI,MAAM;IAczB;;;;;;;;OAQG;IACH,oBAAoB,CAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;QAAE,qBAAqB,CAAC,EAAE,OAAO,CAAA;KAAE,GACzC,UAAU,EAAE;IAqCf,OAAO,IAAI,UAAU,EAAE;IAOvB,6EAA6E;IAC7E,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI;IAMnC,KAAK,IAAI,IAAI;IAKb,SAAS,IAAI;QAAE,SAAS,EAAE,IAAI,CAAC;QAAC,OAAO,EAAE,IAAI,CAAA;KAAE,GAAG,IAAI;IAUtD,OAAO,CAAC,cAAc;CAGvB"}
1
+ {"version":3,"file":"segment_buffer.d.ts","sourceRoot":"","sources":["../../src/replay/segment_buffer.ts"],"names":[],"mappings":"AAEA,oDAAoD;AACpD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,SAAU,CAAC;AAC1C;;;GAGG;AACH,eAAO,MAAM,4BAA4B,QAAc,CAAC;AACxD,iFAAiF;AACjF,eAAO,MAAM,+BAA+B,QACF,CAAC;AAC3C;;;GAGG;AACH,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C;;GAEG;AACH,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C,uEAAuE;AACvE,eAAO,MAAM,+BAA+B,QAAkB,CAAC;AAC/D,8DAA8D;AAC9D,eAAO,MAAM,yBAAyB,OAAQ,CAAC;AAC/C,+BAA+B;AAC/B,eAAO,MAAM,gBAAgB,OAAQ,CAAC;AACtC,oEAAoE;AACpE,eAAO,MAAM,cAAc,QAAS,CAAC;AACrC;;;GAGG;AACH,eAAO,MAAM,uBAAuB,QAAiB,CAAC;AACtD,6DAA6D;AAC7D,eAAO,MAAM,qBAAqB,UAAY,CAAC;AAC/C,2DAA2D;AAC3D,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAC5C;;;GAGG;AACH,eAAO,MAAM,sBAAsB,QAAgB,CAAC;AAEpD,mCAAmC;AACnC,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,2BAA2B;AAC3B,eAAO,MAAM,UAAU,IAAI,CAAC;AAE5B,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,YAAY,CAAK;IAEzB,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAK7B,eAAe,IAAI,OAAO;IAI1B,4DAA4D;IAC5D,gBAAgB,IAAI,UAAU,GAAG,SAAS;IAI1C;;;OAGG;IACH,kBAAkB,IAAI,OAAO;IAc7B;;;OAGG;IACH,QAAQ,CAAC,GAAG,SAAa,EAAE,QAAQ,SAAwB,GAAG,IAAI;IAiBlE,iBAAiB,IAAI,OAAO;IAI5B;;;OAGG;IACH,eAAe,IAAI,MAAM;IAczB;;;;;;;;OAQG;IACH,oBAAoB,CAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;QAAE,qBAAqB,CAAC,EAAE,OAAO,CAAA;KAAE,GACzC,UAAU,EAAE;IAqCf,OAAO,IAAI,UAAU,EAAE;IAOvB,6EAA6E;IAC7E,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI;IAMnC,KAAK,IAAI,IAAI;IAKb,SAAS,IAAI;QAAE,SAAS,EAAE,IAAI,CAAC;QAAC,OAAO,EAAE,IAAI,CAAA;KAAE,GAAG,IAAI;IAUtD,OAAO,CAAC,cAAc;CAGvB"}
@@ -0,0 +1,4 @@
1
+ /** Bumped with package.json version for event metadata. */
2
+ export declare const SDK_NAME = "@newtalaria/browser";
3
+ export declare const SDK_VERSION = "0.1.13";
4
+ //# sourceMappingURL=sdk_meta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk_meta.d.ts","sourceRoot":"","sources":["../src/sdk_meta.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,eAAO,MAAM,QAAQ,wBAAwB,CAAC;AAC9C,eAAO,MAAM,WAAW,WAAW,CAAC"}
@@ -17,6 +17,21 @@
17
17
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
18
18
  }
19
19
 
20
+ // src/utils/browser_extension_noise.ts
21
+ var EXTENSION_URL = /(?:chrome|moz|safari|safari-web|ms-browser)-extension:\/\//i;
22
+ var WEBKIT_MASKED = /webkit-masked-url:\/\/hidden\//i;
23
+ function isBrowserExtensionNoise(opts) {
24
+ const filename = opts.filename ?? "";
25
+ if (EXTENSION_URL.test(filename) || WEBKIT_MASKED.test(filename)) {
26
+ return true;
27
+ }
28
+ const stack = opts.stack ?? "";
29
+ if (EXTENSION_URL.test(stack) || WEBKIT_MASKED.test(stack)) {
30
+ return true;
31
+ }
32
+ return false;
33
+ }
34
+
20
35
  // src/utils/opaque_script_error.ts
21
36
  function isOpaqueCrossOriginScriptError(event) {
22
37
  const msg = (event.message ?? "").trim();
@@ -25,6 +40,137 @@
25
40
  return true;
26
41
  }
27
42
 
43
+ // src/utils/browser_context.ts
44
+ function parseBrowserContext(ua = typeof navigator !== "undefined" ? navigator.userAgent : "", language = typeof navigator !== "undefined" ? navigator.language : "") {
45
+ const userAgent = ua || "";
46
+ const lang = language || "";
47
+ let name = "unknown";
48
+ let version = "";
49
+ const rules = [
50
+ { name: "Edge", re: /Edg(?:e|A|iOS)?\/([\d.]+)/ },
51
+ { name: "Opera", re: /OPR\/([\d.]+)/ },
52
+ { name: "Samsung Internet", re: /SamsungBrowser\/([\d.]+)/ },
53
+ { name: "Firefox", re: /Firefox\/([\d.]+)/ },
54
+ { name: "Chrome", re: /(?:Chrome|CriOS)\/([\d.]+)/ },
55
+ { name: "Safari", re: /Version\/([\d.]+).*Safari/ }
56
+ ];
57
+ for (const rule2 of rules) {
58
+ const m = userAgent.match(rule2.re);
59
+ if (m) {
60
+ name = rule2.name;
61
+ version = m[1] ?? "";
62
+ break;
63
+ }
64
+ }
65
+ if (name === "unknown" && /iPhone|iPad|iPod/.test(userAgent) && /AppleWebKit/.test(userAgent)) {
66
+ name = "Safari";
67
+ const m = userAgent.match(/OS ([\d_]+)/);
68
+ if (m?.[1]) version = m[1].replace(/_/g, ".");
69
+ }
70
+ let os = "unknown";
71
+ let osVersion = "";
72
+ const win = userAgent.match(/Windows NT ([\d.]+)/);
73
+ if (win) {
74
+ os = "Windows";
75
+ osVersion = win[1] ?? "";
76
+ } else {
77
+ const android = userAgent.match(/Android ([\d.]+)/);
78
+ if (android) {
79
+ os = "Android";
80
+ osVersion = android[1] ?? "";
81
+ } else {
82
+ const ios = userAgent.match(/(?:iPhone|iPad|iPod).*OS ([\d_]+)/);
83
+ if (ios) {
84
+ os = "iOS";
85
+ osVersion = (ios[1] ?? "").replace(/_/g, ".");
86
+ } else {
87
+ const mac = userAgent.match(/Mac OS X ([\d_]+)/);
88
+ if (mac) {
89
+ os = "macOS";
90
+ osVersion = (mac[1] ?? "").replace(/_/g, ".");
91
+ } else if (/CrOS/.test(userAgent)) {
92
+ os = "Chrome OS";
93
+ } else if (/Linux/.test(userAgent)) {
94
+ os = "Linux";
95
+ }
96
+ }
97
+ }
98
+ }
99
+ let device = "desktop";
100
+ if (/iPad|Tablet|Android(?!.*Mobile)/i.test(userAgent)) {
101
+ device = "tablet";
102
+ } else if (/Mobi|iPhone|iPod|Android.*Mobile/i.test(userAgent)) {
103
+ device = "mobile";
104
+ } else if (!userAgent) {
105
+ device = "unknown";
106
+ }
107
+ return {
108
+ name,
109
+ version,
110
+ os,
111
+ osVersion,
112
+ device,
113
+ language: lang,
114
+ userAgent
115
+ };
116
+ }
117
+ function browserContextTags(ctx) {
118
+ return {
119
+ "browser.name": ctx.name,
120
+ "browser.version": ctx.version || "unknown",
121
+ "os.name": ctx.os,
122
+ "os.version": ctx.osVersion || "unknown",
123
+ device: ctx.device
124
+ };
125
+ }
126
+ async function collectBrowserContext() {
127
+ const base = parseBrowserContext();
128
+ const nav = typeof navigator !== "undefined" ? navigator : void 0;
129
+ const uad = nav?.userAgentData;
130
+ if (!uad) return base;
131
+ if (uad.mobile === true) base.device = "mobile";
132
+ if (uad.platform) {
133
+ const p = uad.platform;
134
+ if (/Windows/i.test(p)) base.os = "Windows";
135
+ else if (/macOS|Mac OS/i.test(p)) base.os = "macOS";
136
+ else if (/Android/i.test(p)) base.os = "Android";
137
+ else if (/iOS|iPhone/i.test(p)) base.os = "iOS";
138
+ else if (/Linux/i.test(p)) base.os = "Linux";
139
+ else if (/Chrome OS|Chromium OS/i.test(p)) base.os = "Chrome OS";
140
+ else base.os = p;
141
+ }
142
+ const brands = uad.brands ?? [];
143
+ const interesting = brands.find(
144
+ (b) => !/Not.?A.?Brand/i.test(b.brand) && !/Chromium/i.test(b.brand)
145
+ );
146
+ if (interesting) {
147
+ base.name = interesting.brand.replace(/^Google /, "");
148
+ base.version = interesting.version;
149
+ }
150
+ try {
151
+ if (typeof uad.getHighEntropyValues === "function") {
152
+ const hi = await uad.getHighEntropyValues([
153
+ "platformVersion",
154
+ "fullVersionList"
155
+ ]);
156
+ if (hi.platformVersion) base.osVersion = hi.platformVersion;
157
+ const full = hi.fullVersionList?.find(
158
+ (b) => !/Not.?A.?Brand/i.test(b.brand) && !/Chromium/i.test(b.brand)
159
+ );
160
+ if (full) {
161
+ base.name = full.brand.replace(/^Google /, "");
162
+ base.version = full.version;
163
+ }
164
+ }
165
+ } catch {
166
+ }
167
+ return base;
168
+ }
169
+
170
+ // src/sdk_meta.ts
171
+ var SDK_NAME = "@newtalaria/browser";
172
+ var SDK_VERSION = "0.1.13";
173
+
28
174
  // src/transport/serverpod.ts
29
175
  var ServerpodTransport = class {
30
176
  constructor(options) {
@@ -140,6 +286,7 @@
140
286
  var ERROR_CLIP_FLUSH_SLACK_MS = 5e3;
141
287
  var SEGMENT_FLUSH_MS = 5e3;
142
288
  var RING_BUFFER_MS = 6e4;
289
+ var RING_BUFFER_CHECKOUT_MS = RING_BUFFER_MS;
143
290
  var RING_BUFFER_MAX_BYTES = 15e5;
144
291
  var ERROR_REPLAY_AFTER_MS = 15e3;
145
292
  var MAX_REPLAY_DURATION_MS = 5 * 60 * 1e3;
@@ -13282,6 +13429,7 @@
13282
13429
  inlineStylesheet: options.inlineStylesheet,
13283
13430
  // Shrink DOM snapshots on heavy sites (docs / marketing).
13284
13431
  slimDOMOptions: "all",
13432
+ ...options.checkoutEveryNms != null && options.checkoutEveryNms > 0 ? { checkoutEveryNms: options.checkoutEveryNms } : {},
13285
13433
  sampling: {
13286
13434
  mousemove: 150,
13287
13435
  scroll: 200,
@@ -13302,6 +13450,32 @@
13302
13450
  }
13303
13451
 
13304
13452
  // src/replay/hooks.ts
13453
+ function installVisibilityResumeHook(onResume) {
13454
+ if (typeof document === "undefined") {
13455
+ return () => {
13456
+ };
13457
+ }
13458
+ const onVisibility = () => {
13459
+ if (document.visibilityState === "visible") {
13460
+ onResume();
13461
+ }
13462
+ };
13463
+ const onPageShow = (event) => {
13464
+ if (event.persisted) {
13465
+ onResume();
13466
+ }
13467
+ };
13468
+ document.addEventListener("visibilitychange", onVisibility);
13469
+ if (typeof window !== "undefined") {
13470
+ window.addEventListener("pageshow", onPageShow);
13471
+ }
13472
+ return () => {
13473
+ document.removeEventListener("visibilitychange", onVisibility);
13474
+ if (typeof window !== "undefined") {
13475
+ window.removeEventListener("pageshow", onPageShow);
13476
+ }
13477
+ };
13478
+ }
13305
13479
  function safeSerialize(args) {
13306
13480
  try {
13307
13481
  return JSON.stringify(
@@ -13538,6 +13712,8 @@
13538
13712
  this.linkableReplayId = null;
13539
13713
  /** Last error-clip paint/upload failure (cleared on successful segment 0). */
13540
13714
  this.lastReplayCaptureFailure = null;
13715
+ /** Cached once per init for event tags/extra. */
13716
+ this.browserContext = null;
13541
13717
  }
13542
13718
  init(options) {
13543
13719
  if (this.options) {
@@ -13560,6 +13736,10 @@
13560
13736
  this.errorClipDeadlineMs = null;
13561
13737
  this.linkableReplayId = null;
13562
13738
  this.lastReplayCaptureFailure = null;
13739
+ this.browserContext = parseBrowserContext();
13740
+ void collectBrowserContext().then((ctx) => {
13741
+ if (this.options) this.browserContext = ctx;
13742
+ });
13563
13743
  this.buffer = new SegmentBuffer();
13564
13744
  this.uploadChain = Promise.resolve();
13565
13745
  this.sessionSampled = Math.random() < this.options.replaysSessionSampleRate;
@@ -13568,6 +13748,9 @@
13568
13748
  maskAllInputs: this.options.maskAllInputs,
13569
13749
  inlineStylesheet: this.options.inlineStylesheet,
13570
13750
  blockSelector: this.options.blockSelector,
13751
+ // Buffer/error path: keep a FullSnapshot inside the ~60s ring. Session
13752
+ // sample uploads continuously so periodic checkouts are skipped (size).
13753
+ checkoutEveryNms: this.sessionSampled ? void 0 : RING_BUFFER_CHECKOUT_MS,
13571
13754
  onEvent: (event) => this.onRrwebEvent(event)
13572
13755
  });
13573
13756
  this.teardowns.push(
@@ -13597,7 +13780,8 @@
13597
13780
  }
13598
13781
  );
13599
13782
  }
13600
- })
13783
+ }),
13784
+ installVisibilityResumeHook(() => this.onForegroundResume())
13601
13785
  );
13602
13786
  if (!this.options.disableDefaultIntegrations) {
13603
13787
  this.installGlobalHandlers();
@@ -13629,6 +13813,14 @@
13629
13813
  }
13630
13814
  async captureException(error, context) {
13631
13815
  const err = error instanceof Error ? error : new Error(typeof error === "string" ? error : "Unknown error");
13816
+ const filename = typeof context?.extra?.filename === "string" ? context.extra.filename : void 0;
13817
+ if (isBrowserExtensionNoise({
13818
+ message: err.message,
13819
+ stack: err.stack,
13820
+ filename
13821
+ })) {
13822
+ return;
13823
+ }
13632
13824
  await this.capture({
13633
13825
  message: err.message || err.name || "Error",
13634
13826
  level: "error",
@@ -13722,6 +13914,7 @@
13722
13914
  this.closed = false;
13723
13915
  this.linkableReplayId = null;
13724
13916
  this.lastReplayCaptureFailure = null;
13917
+ this.browserContext = null;
13725
13918
  }
13726
13919
  onRrwebEvent(event) {
13727
13920
  if (this.closed || !this.options) return;
@@ -13805,13 +13998,28 @@
13805
13998
  }
13806
13999
  const tags = applyReplayCaptureTags(
13807
14000
  {
14001
+ ...this.browserContext ? browserContextTags(this.browserContext) : {},
13808
14002
  ...this.options.tags ?? {},
13809
14003
  ...args.context?.tags ?? {}
13810
14004
  },
13811
14005
  errorClipOutcome
13812
14006
  );
13813
14007
  const extra = mergeReplayCaptureExtra(
13814
- args.context?.extra,
14008
+ {
14009
+ ...this.browserContext ? {
14010
+ browser: {
14011
+ name: this.browserContext.name,
14012
+ version: this.browserContext.version,
14013
+ os: this.browserContext.os,
14014
+ osVersion: this.browserContext.osVersion,
14015
+ device: this.browserContext.device,
14016
+ language: this.browserContext.language,
14017
+ userAgent: this.browserContext.userAgent
14018
+ }
14019
+ } : {},
14020
+ sdk: { name: SDK_NAME, version: SDK_VERSION },
14021
+ ...args.context?.extra
14022
+ },
13815
14023
  errorClipOutcome
13816
14024
  );
13817
14025
  try {
@@ -13967,6 +14175,18 @@
13967
14175
  checkoutFullSnapshot() {
13968
14176
  this.recorder?.takeFullSnapshot();
13969
14177
  }
14178
+ /**
14179
+ * Tab focus / bfcache restore: background timers are throttled, so the
14180
+ * buffer-mode checkout interval may not have fired. Refresh the paint base
14181
+ * so an error clip still has ~60s of usable lead-up after the user returns.
14182
+ */
14183
+ onForegroundResume() {
14184
+ if (this.closed || !this.options || !this.recorder) return;
14185
+ if (!this.uploadEnabled) {
14186
+ this.buffer.trimRing();
14187
+ }
14188
+ this.checkoutFullSnapshot();
14189
+ }
13970
14190
  /**
13971
14191
  * Ensure segment 0 begins at Meta+FullSnapshot. Orphan increments alone
13972
14192
  * produce a blank rrweb player.
@@ -14035,6 +14255,13 @@
14035
14255
  const onError = (event) => {
14036
14256
  if (isOpaqueCrossOriginScriptError(event)) return;
14037
14257
  const error = event.error instanceof Error ? event.error : new Error(event.message || "window.onerror");
14258
+ if (isBrowserExtensionNoise({
14259
+ message: event.message || error.message,
14260
+ stack: error.stack,
14261
+ filename: event.filename
14262
+ })) {
14263
+ return;
14264
+ }
14038
14265
  void this.captureException(error, {
14039
14266
  extra: {
14040
14267
  filename: event.filename,