@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.
package/README.md CHANGED
@@ -53,7 +53,9 @@ await Talaria.flush();
53
53
  await Talaria.close();
54
54
  ```
55
55
 
56
- `Talaria.init` also installs `window.onerror` / `unhandledrejection` handlers unless you pass `disableDefaultIntegrations: true`. Opaque cross-origin `"Script error."` events (no usable `Error` object) are ignored by default.
56
+ `Talaria.init` also installs `window.onerror` / `unhandledrejection` handlers unless you pass `disableDefaultIntegrations: true`. Opaque cross-origin `"Script error."` events (no usable `Error` object) are ignored by default. Errors from browser extensions (`chrome-extension://`, `moz-extension://`, etc.) are also ignored.
57
+
58
+ Every ingested event includes browser runtime tags (`browser.name`, `browser.version`, `os.name`, `os.version`, `device`) and `extra.browser` / `extra.sdk` for triage.
57
59
 
58
60
  Optional init `tags` are merged into every captured event (per-call tags win on key conflict).
59
61
 
@@ -95,7 +97,8 @@ You pay for **uploaded + retained** bytes, not for local buffering. Prefer error
95
97
  | Mode | Behavior |
96
98
  | --- | --- |
97
99
  | Session sample hit | `replays/start` immediately; segments upload every ~5s or ~100KB until unload or **5 min** max |
98
- | Session sample miss | Record into a ~60s ring buffer; nothing uploaded until an error sample hits |
100
+ | Session sample miss | Record into a ~60s ring buffer with a FullSnapshot checkout every ~60s; nothing uploaded until an error sample hits |
101
+ | Tab hidden → visible / bfcache restore | Take a checkout FullSnapshot (background timers are throttled; refreshes the paint base so error clips still have lead-up) |
99
102
  | Error sample + `replaysErrorAfterMs > 0` | Upload buffer (≤~960KiB gzip pack target / **1MiB** server cap) + trailing window, hard caps **12 segments** or **2MiB** compressed, attach `replayId` only if segments landed, `finish`, return to buffer mode |
100
103
  | Error sample + `replaysErrorAfterMs = 0` | Upload buffer then continue like session mode until **5 min** / unload / size caps |
101
104
  | Server limit (replay segments / total size / duration) | Stop uploading that replay; no retries |
package/dist/client.d.ts CHANGED
@@ -34,6 +34,8 @@ export declare class TalariaClient {
34
34
  private linkableReplayId;
35
35
  /** Last error-clip paint/upload failure (cleared on successful segment 0). */
36
36
  private lastReplayCaptureFailure;
37
+ /** Cached once per init for event tags/extra. */
38
+ private browserContext;
37
39
  init(options: TalariaInitOptions): void;
38
40
  getReplayId(): string | null;
39
41
  captureException(error: unknown, context?: CaptureContext): Promise<void>;
@@ -70,6 +72,12 @@ export declare class TalariaClient {
70
72
  private resetToBufferMode;
71
73
  /** Emit a checkout FullSnapshot into the ring buffer (sync via rrweb emit). */
72
74
  private checkoutFullSnapshot;
75
+ /**
76
+ * Tab focus / bfcache restore: background timers are throttled, so the
77
+ * buffer-mode checkout interval may not have fired. Refresh the paint base
78
+ * so an error clip still has ~60s of usable lead-up after the user returns.
79
+ */
80
+ private onForegroundResume;
73
81
  /**
74
82
  * Ensure segment 0 begins at Meta+FullSnapshot. Orphan increments alone
75
83
  * produce a blank rrweb player.
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -15,6 +15,21 @@ function createId() {
15
15
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
16
16
  }
17
17
 
18
+ // src/utils/browser_extension_noise.ts
19
+ var EXTENSION_URL = /(?:chrome|moz|safari|safari-web|ms-browser)-extension:\/\//i;
20
+ var WEBKIT_MASKED = /webkit-masked-url:\/\/hidden\//i;
21
+ function isBrowserExtensionNoise(opts) {
22
+ const filename = opts.filename ?? "";
23
+ if (EXTENSION_URL.test(filename) || WEBKIT_MASKED.test(filename)) {
24
+ return true;
25
+ }
26
+ const stack = opts.stack ?? "";
27
+ if (EXTENSION_URL.test(stack) || WEBKIT_MASKED.test(stack)) {
28
+ return true;
29
+ }
30
+ return false;
31
+ }
32
+
18
33
  // src/utils/opaque_script_error.ts
19
34
  function isOpaqueCrossOriginScriptError(event) {
20
35
  const msg = (event.message ?? "").trim();
@@ -23,6 +38,137 @@ function isOpaqueCrossOriginScriptError(event) {
23
38
  return true;
24
39
  }
25
40
 
41
+ // src/utils/browser_context.ts
42
+ function parseBrowserContext(ua = typeof navigator !== "undefined" ? navigator.userAgent : "", language = typeof navigator !== "undefined" ? navigator.language : "") {
43
+ const userAgent = ua || "";
44
+ const lang = language || "";
45
+ let name = "unknown";
46
+ let version = "";
47
+ const rules = [
48
+ { name: "Edge", re: /Edg(?:e|A|iOS)?\/([\d.]+)/ },
49
+ { name: "Opera", re: /OPR\/([\d.]+)/ },
50
+ { name: "Samsung Internet", re: /SamsungBrowser\/([\d.]+)/ },
51
+ { name: "Firefox", re: /Firefox\/([\d.]+)/ },
52
+ { name: "Chrome", re: /(?:Chrome|CriOS)\/([\d.]+)/ },
53
+ { name: "Safari", re: /Version\/([\d.]+).*Safari/ }
54
+ ];
55
+ for (const rule2 of rules) {
56
+ const m = userAgent.match(rule2.re);
57
+ if (m) {
58
+ name = rule2.name;
59
+ version = m[1] ?? "";
60
+ break;
61
+ }
62
+ }
63
+ if (name === "unknown" && /iPhone|iPad|iPod/.test(userAgent) && /AppleWebKit/.test(userAgent)) {
64
+ name = "Safari";
65
+ const m = userAgent.match(/OS ([\d_]+)/);
66
+ if (m?.[1]) version = m[1].replace(/_/g, ".");
67
+ }
68
+ let os = "unknown";
69
+ let osVersion = "";
70
+ const win = userAgent.match(/Windows NT ([\d.]+)/);
71
+ if (win) {
72
+ os = "Windows";
73
+ osVersion = win[1] ?? "";
74
+ } else {
75
+ const android = userAgent.match(/Android ([\d.]+)/);
76
+ if (android) {
77
+ os = "Android";
78
+ osVersion = android[1] ?? "";
79
+ } else {
80
+ const ios = userAgent.match(/(?:iPhone|iPad|iPod).*OS ([\d_]+)/);
81
+ if (ios) {
82
+ os = "iOS";
83
+ osVersion = (ios[1] ?? "").replace(/_/g, ".");
84
+ } else {
85
+ const mac = userAgent.match(/Mac OS X ([\d_]+)/);
86
+ if (mac) {
87
+ os = "macOS";
88
+ osVersion = (mac[1] ?? "").replace(/_/g, ".");
89
+ } else if (/CrOS/.test(userAgent)) {
90
+ os = "Chrome OS";
91
+ } else if (/Linux/.test(userAgent)) {
92
+ os = "Linux";
93
+ }
94
+ }
95
+ }
96
+ }
97
+ let device = "desktop";
98
+ if (/iPad|Tablet|Android(?!.*Mobile)/i.test(userAgent)) {
99
+ device = "tablet";
100
+ } else if (/Mobi|iPhone|iPod|Android.*Mobile/i.test(userAgent)) {
101
+ device = "mobile";
102
+ } else if (!userAgent) {
103
+ device = "unknown";
104
+ }
105
+ return {
106
+ name,
107
+ version,
108
+ os,
109
+ osVersion,
110
+ device,
111
+ language: lang,
112
+ userAgent
113
+ };
114
+ }
115
+ function browserContextTags(ctx) {
116
+ return {
117
+ "browser.name": ctx.name,
118
+ "browser.version": ctx.version || "unknown",
119
+ "os.name": ctx.os,
120
+ "os.version": ctx.osVersion || "unknown",
121
+ device: ctx.device
122
+ };
123
+ }
124
+ async function collectBrowserContext() {
125
+ const base = parseBrowserContext();
126
+ const nav = typeof navigator !== "undefined" ? navigator : void 0;
127
+ const uad = nav?.userAgentData;
128
+ if (!uad) return base;
129
+ if (uad.mobile === true) base.device = "mobile";
130
+ if (uad.platform) {
131
+ const p = uad.platform;
132
+ if (/Windows/i.test(p)) base.os = "Windows";
133
+ else if (/macOS|Mac OS/i.test(p)) base.os = "macOS";
134
+ else if (/Android/i.test(p)) base.os = "Android";
135
+ else if (/iOS|iPhone/i.test(p)) base.os = "iOS";
136
+ else if (/Linux/i.test(p)) base.os = "Linux";
137
+ else if (/Chrome OS|Chromium OS/i.test(p)) base.os = "Chrome OS";
138
+ else base.os = p;
139
+ }
140
+ const brands = uad.brands ?? [];
141
+ const interesting = brands.find(
142
+ (b) => !/Not.?A.?Brand/i.test(b.brand) && !/Chromium/i.test(b.brand)
143
+ );
144
+ if (interesting) {
145
+ base.name = interesting.brand.replace(/^Google /, "");
146
+ base.version = interesting.version;
147
+ }
148
+ try {
149
+ if (typeof uad.getHighEntropyValues === "function") {
150
+ const hi = await uad.getHighEntropyValues([
151
+ "platformVersion",
152
+ "fullVersionList"
153
+ ]);
154
+ if (hi.platformVersion) base.osVersion = hi.platformVersion;
155
+ const full = hi.fullVersionList?.find(
156
+ (b) => !/Not.?A.?Brand/i.test(b.brand) && !/Chromium/i.test(b.brand)
157
+ );
158
+ if (full) {
159
+ base.name = full.brand.replace(/^Google /, "");
160
+ base.version = full.version;
161
+ }
162
+ }
163
+ } catch {
164
+ }
165
+ return base;
166
+ }
167
+
168
+ // src/sdk_meta.ts
169
+ var SDK_NAME = "@newtalaria/browser";
170
+ var SDK_VERSION = "0.1.13";
171
+
26
172
  // src/transport/serverpod.ts
27
173
  var ServerpodTransport = class {
28
174
  constructor(options) {
@@ -138,6 +284,7 @@ var MAX_ERROR_CLIP_COMPRESSED_BYTES = 2 * 1024 * 1024;
138
284
  var ERROR_CLIP_FLUSH_SLACK_MS = 5e3;
139
285
  var SEGMENT_FLUSH_MS = 5e3;
140
286
  var RING_BUFFER_MS = 6e4;
287
+ var RING_BUFFER_CHECKOUT_MS = RING_BUFFER_MS;
141
288
  var RING_BUFFER_MAX_BYTES = 15e5;
142
289
  var ERROR_REPLAY_AFTER_MS = 15e3;
143
290
  var MAX_REPLAY_DURATION_MS = 5 * 60 * 1e3;
@@ -13280,6 +13427,7 @@ function startRecorder(options) {
13280
13427
  inlineStylesheet: options.inlineStylesheet,
13281
13428
  // Shrink DOM snapshots on heavy sites (docs / marketing).
13282
13429
  slimDOMOptions: "all",
13430
+ ...options.checkoutEveryNms != null && options.checkoutEveryNms > 0 ? { checkoutEveryNms: options.checkoutEveryNms } : {},
13283
13431
  sampling: {
13284
13432
  mousemove: 150,
13285
13433
  scroll: 200,
@@ -13300,6 +13448,32 @@ function startRecorder(options) {
13300
13448
  }
13301
13449
 
13302
13450
  // src/replay/hooks.ts
13451
+ function installVisibilityResumeHook(onResume) {
13452
+ if (typeof document === "undefined") {
13453
+ return () => {
13454
+ };
13455
+ }
13456
+ const onVisibility = () => {
13457
+ if (document.visibilityState === "visible") {
13458
+ onResume();
13459
+ }
13460
+ };
13461
+ const onPageShow = (event) => {
13462
+ if (event.persisted) {
13463
+ onResume();
13464
+ }
13465
+ };
13466
+ document.addEventListener("visibilitychange", onVisibility);
13467
+ if (typeof window !== "undefined") {
13468
+ window.addEventListener("pageshow", onPageShow);
13469
+ }
13470
+ return () => {
13471
+ document.removeEventListener("visibilitychange", onVisibility);
13472
+ if (typeof window !== "undefined") {
13473
+ window.removeEventListener("pageshow", onPageShow);
13474
+ }
13475
+ };
13476
+ }
13303
13477
  function safeSerialize(args) {
13304
13478
  try {
13305
13479
  return JSON.stringify(
@@ -13536,6 +13710,8 @@ var TalariaClient = class {
13536
13710
  this.linkableReplayId = null;
13537
13711
  /** Last error-clip paint/upload failure (cleared on successful segment 0). */
13538
13712
  this.lastReplayCaptureFailure = null;
13713
+ /** Cached once per init for event tags/extra. */
13714
+ this.browserContext = null;
13539
13715
  }
13540
13716
  init(options) {
13541
13717
  if (this.options) {
@@ -13558,6 +13734,10 @@ var TalariaClient = class {
13558
13734
  this.errorClipDeadlineMs = null;
13559
13735
  this.linkableReplayId = null;
13560
13736
  this.lastReplayCaptureFailure = null;
13737
+ this.browserContext = parseBrowserContext();
13738
+ void collectBrowserContext().then((ctx) => {
13739
+ if (this.options) this.browserContext = ctx;
13740
+ });
13561
13741
  this.buffer = new SegmentBuffer();
13562
13742
  this.uploadChain = Promise.resolve();
13563
13743
  this.sessionSampled = Math.random() < this.options.replaysSessionSampleRate;
@@ -13566,6 +13746,9 @@ var TalariaClient = class {
13566
13746
  maskAllInputs: this.options.maskAllInputs,
13567
13747
  inlineStylesheet: this.options.inlineStylesheet,
13568
13748
  blockSelector: this.options.blockSelector,
13749
+ // Buffer/error path: keep a FullSnapshot inside the ~60s ring. Session
13750
+ // sample uploads continuously so periodic checkouts are skipped (size).
13751
+ checkoutEveryNms: this.sessionSampled ? void 0 : RING_BUFFER_CHECKOUT_MS,
13569
13752
  onEvent: (event) => this.onRrwebEvent(event)
13570
13753
  });
13571
13754
  this.teardowns.push(
@@ -13595,7 +13778,8 @@ var TalariaClient = class {
13595
13778
  }
13596
13779
  );
13597
13780
  }
13598
- })
13781
+ }),
13782
+ installVisibilityResumeHook(() => this.onForegroundResume())
13599
13783
  );
13600
13784
  if (!this.options.disableDefaultIntegrations) {
13601
13785
  this.installGlobalHandlers();
@@ -13627,6 +13811,14 @@ var TalariaClient = class {
13627
13811
  }
13628
13812
  async captureException(error, context) {
13629
13813
  const err = error instanceof Error ? error : new Error(typeof error === "string" ? error : "Unknown error");
13814
+ const filename = typeof context?.extra?.filename === "string" ? context.extra.filename : void 0;
13815
+ if (isBrowserExtensionNoise({
13816
+ message: err.message,
13817
+ stack: err.stack,
13818
+ filename
13819
+ })) {
13820
+ return;
13821
+ }
13630
13822
  await this.capture({
13631
13823
  message: err.message || err.name || "Error",
13632
13824
  level: "error",
@@ -13720,6 +13912,7 @@ var TalariaClient = class {
13720
13912
  this.closed = false;
13721
13913
  this.linkableReplayId = null;
13722
13914
  this.lastReplayCaptureFailure = null;
13915
+ this.browserContext = null;
13723
13916
  }
13724
13917
  onRrwebEvent(event) {
13725
13918
  if (this.closed || !this.options) return;
@@ -13803,13 +13996,28 @@ var TalariaClient = class {
13803
13996
  }
13804
13997
  const tags = applyReplayCaptureTags(
13805
13998
  {
13999
+ ...this.browserContext ? browserContextTags(this.browserContext) : {},
13806
14000
  ...this.options.tags ?? {},
13807
14001
  ...args.context?.tags ?? {}
13808
14002
  },
13809
14003
  errorClipOutcome
13810
14004
  );
13811
14005
  const extra = mergeReplayCaptureExtra(
13812
- args.context?.extra,
14006
+ {
14007
+ ...this.browserContext ? {
14008
+ browser: {
14009
+ name: this.browserContext.name,
14010
+ version: this.browserContext.version,
14011
+ os: this.browserContext.os,
14012
+ osVersion: this.browserContext.osVersion,
14013
+ device: this.browserContext.device,
14014
+ language: this.browserContext.language,
14015
+ userAgent: this.browserContext.userAgent
14016
+ }
14017
+ } : {},
14018
+ sdk: { name: SDK_NAME, version: SDK_VERSION },
14019
+ ...args.context?.extra
14020
+ },
13813
14021
  errorClipOutcome
13814
14022
  );
13815
14023
  try {
@@ -13965,6 +14173,18 @@ var TalariaClient = class {
13965
14173
  checkoutFullSnapshot() {
13966
14174
  this.recorder?.takeFullSnapshot();
13967
14175
  }
14176
+ /**
14177
+ * Tab focus / bfcache restore: background timers are throttled, so the
14178
+ * buffer-mode checkout interval may not have fired. Refresh the paint base
14179
+ * so an error clip still has ~60s of usable lead-up after the user returns.
14180
+ */
14181
+ onForegroundResume() {
14182
+ if (this.closed || !this.options || !this.recorder) return;
14183
+ if (!this.uploadEnabled) {
14184
+ this.buffer.trimRing();
14185
+ }
14186
+ this.checkoutFullSnapshot();
14187
+ }
13968
14188
  /**
13969
14189
  * Ensure segment 0 begins at Meta+FullSnapshot. Orphan increments alone
13970
14190
  * produce a blank rrweb player.
@@ -14033,6 +14253,13 @@ var TalariaClient = class {
14033
14253
  const onError = (event) => {
14034
14254
  if (isOpaqueCrossOriginScriptError(event)) return;
14035
14255
  const error = event.error instanceof Error ? event.error : new Error(event.message || "window.onerror");
14256
+ if (isBrowserExtensionNoise({
14257
+ message: event.message || error.message,
14258
+ stack: error.stack,
14259
+ filename: event.filename
14260
+ })) {
14261
+ return;
14262
+ }
14036
14263
  void this.captureException(error, {
14037
14264
  extra: {
14038
14265
  filename: event.filename,