@sailfish-ai/recorder 1.11.1 → 1.11.3

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 (49) hide show
  1. package/README.md +94 -0
  2. package/dist/chunks/{chunkSerializer-BiemuRlf.js → chunkSerializer-CV4nkb5-.js} +1 -1
  3. package/dist/chunks/chunkSerializer-CV4nkb5-.js.br +0 -0
  4. package/dist/chunks/chunkSerializer-CV4nkb5-.js.gz +0 -0
  5. package/dist/chunks/{chunkSerializer-CJQCxiLD.js → chunkSerializer-jzbHv2wf.js} +1 -1
  6. package/dist/chunks/chunkSerializer-jzbHv2wf.js.br +0 -0
  7. package/dist/chunks/chunkSerializer-jzbHv2wf.js.gz +0 -0
  8. package/dist/chunks/{index-Cfj4Epfd.js → index-BP-kNUGS.js} +80 -66
  9. package/dist/chunks/index-BP-kNUGS.js.br +0 -0
  10. package/dist/chunks/index-BP-kNUGS.js.gz +0 -0
  11. package/dist/chunks/{index-CuXHImrI.js → index-BynFTRFv.js} +51 -36
  12. package/dist/chunks/index-BynFTRFv.js.br +0 -0
  13. package/dist/chunks/index-BynFTRFv.js.gz +0 -0
  14. package/dist/chunks/rrweb-plugin-performance-record-BYWkWb25.js +188 -0
  15. package/dist/chunks/rrweb-plugin-performance-record-BYWkWb25.js.br +0 -0
  16. package/dist/chunks/rrweb-plugin-performance-record-BYWkWb25.js.gz +0 -0
  17. package/dist/chunks/rrweb-plugin-performance-record-Dekf6xUi.js +186 -0
  18. package/dist/chunks/rrweb-plugin-performance-record-Dekf6xUi.js.br +0 -0
  19. package/dist/chunks/rrweb-plugin-performance-record-Dekf6xUi.js.gz +0 -0
  20. package/dist/constants.js +1 -0
  21. package/dist/constants.js.br +0 -0
  22. package/dist/constants.js.gz +0 -0
  23. package/dist/index.js +14 -3
  24. package/dist/index.js.br +0 -0
  25. package/dist/index.js.gz +0 -0
  26. package/dist/recorder.cjs +2 -2
  27. package/dist/recorder.cjs.br +0 -0
  28. package/dist/recorder.cjs.gz +0 -0
  29. package/dist/recorder.js +19 -18
  30. package/dist/recorder.js.br +0 -0
  31. package/dist/recorder.js.gz +0 -0
  32. package/dist/recorder.umd.cjs +4980 -4788
  33. package/dist/recorder.umd.cjs.br +0 -0
  34. package/dist/recorder.umd.cjs.gz +0 -0
  35. package/dist/recording.js +31 -1
  36. package/dist/recording.js.br +0 -0
  37. package/dist/recording.js.gz +0 -0
  38. package/dist/types/constants.d.ts +1 -0
  39. package/dist/types/index.d.ts +21 -1
  40. package/dist/types/recording.d.ts +1 -0
  41. package/package.json +7 -4
  42. package/dist/chunks/chunkSerializer-BiemuRlf.js.br +0 -0
  43. package/dist/chunks/chunkSerializer-BiemuRlf.js.gz +0 -0
  44. package/dist/chunks/chunkSerializer-CJQCxiLD.js.br +0 -0
  45. package/dist/chunks/chunkSerializer-CJQCxiLD.js.gz +0 -0
  46. package/dist/chunks/index-Cfj4Epfd.js.br +0 -0
  47. package/dist/chunks/index-Cfj4Epfd.js.gz +0 -0
  48. package/dist/chunks/index-CuXHImrI.js.br +0 -0
  49. package/dist/chunks/index-CuXHImrI.js.gz +0 -0
package/README.md CHANGED
@@ -140,6 +140,7 @@ await initRecorder({
140
140
  | `deferRecording` | `boolean` | `true` | Defers the initial DOM snapshot until after first paint / idle. |
141
141
  | `chunkSnapshot` | `boolean` | `false` | Yield to the browser every 500 nodes during the initial snapshot (smoother on very large pages). |
142
142
  | `useWsWorker` | `boolean` | `true` | Run the WebSocket sender in a Web Worker. Disable if your CSP blocks `worker-src blob:`. |
143
+ | `capturePerformanceMetrics` | `boolean` | `true` | Capture FCP / LCP / TBT / DCL / LOAD per `page_visit_uuid` via the performance plugin. Set `false` to skip — the plugin is dynamically imported, so opting out also skips loading `web-vitals` and the observers. |
143
144
  | `reportIssueShortcuts` | `ShortcutsConfig` | — | Custom keyboard shortcuts for the report-issue modal. |
144
145
  | `showEngTicketFieldsInReportIssueModalDefault` | `boolean` | `false` | Pre-expand Jira / Linear fields in the in-app issue modal. |
145
146
 
@@ -185,6 +186,98 @@ if (isFunctionSpanTrackingEnabled()) disableFunctionSpanTracking();
185
186
  enableFunctionSpanTracking();
186
187
  ```
187
188
 
189
+ ## Performance metrics
190
+
191
+ The recorder automatically captures real-user performance metrics per page visit and emits them through the same WebSocket pipeline as everything else. No additional configuration is required; capture is skipped in Lighthouse / headless / WebDriver environments to avoid polluting synthetic audits.
192
+
193
+ | Metric | Meaning | Source |
194
+ |---|---|---|
195
+ | **FCP** — First Contentful Paint | Time to first text/image paint. | `web-vitals` `onFCP` |
196
+ | **LCP** — Largest Contentful Paint | Time to the largest above-the-fold element. Closest proxy for "content is visible". | `web-vitals` `onLCP` |
197
+ | **TBT** — Total Blocking Time | Sum of blocking time from long tasks, emitted at `load`. | `PerformanceObserver({type:'longtask', buffered:true})` summing `max(0, duration − 50)` |
198
+ | **DCL** — DOMContentLoaded | `navigation.domContentLoadedEventEnd` (ms since `timeOrigin`). | Navigation Timing Level 2 |
199
+ | **LOAD** — load event | `navigation.loadEventEnd` (ms since `timeOrigin`). | Navigation Timing Level 2 |
200
+
201
+ FCP and LCP re-emit on SPA soft-navigations (via `web-vitals`' native history-API / BFCache support) — each emission is keyed to the current `page_visit_uuid`. TBT, DCL, and LOAD fire once per hard load.
202
+
203
+ Events arrive on the recorder WebSocket with `type: 28` (the numeric id reserved for performance metrics — see `backend/sailfish/rrweb/enums.py` on the Sailfish backend) and the shape:
204
+
205
+ ```json
206
+ {
207
+ "type": 28,
208
+ "timestamp": 1700000000000,
209
+ "sessionId": "<session_id>",
210
+ "page_visit_uuid": "<uuid>",
211
+ "href": "https://example.com/path",
212
+ "data": {
213
+ "plugin": "@sailfish-rrweb/rrweb/performance@1",
214
+ "payload": {
215
+ "metric": "FCP" | "LCP" | "TBT" | "DCL" | "LOAD",
216
+ "value": 1234.5,
217
+ "rating": "good" | "needs-improvement" | "poor",
218
+ "navigationType": "navigate" | "reload" | "back-forward" | "back-forward-cache" | "prerender" | "restore",
219
+ "pageVisitUuid": "<uuid>",
220
+ "href": "https://example.com/path",
221
+ "timestamp": 1700000000000
222
+ }
223
+ }
224
+ }
225
+ ```
226
+
227
+ ### Disabling capture
228
+
229
+ Pass `capturePerformanceMetrics: false` to `initRecorder` to skip the plugin entirely. Because the plugin code is dynamically imported, this also avoids loading `web-vitals` and the long-task observer:
230
+
231
+ ```ts
232
+ initRecorder({
233
+ apiKey: "YOUR_API_KEY",
234
+ capturePerformanceMetrics: false,
235
+ });
236
+ ```
237
+
238
+ ### Benchmarking the plugin's overhead
239
+
240
+ `scripts/bench-perf.js` loads the same page twice — once with capture on, once with capture off — under headless Chrome, and reports CPU, JS heap, FCP/LCP, long-task time, and total load time side-by-side.
241
+
242
+ #### One-time app change (required before running the bench)
243
+
244
+ The bench needs a way to flip capture on/off without rebuilding your app between variants. Wire `?sf_perf=off` in your `initRecorder` call so the URL controls the option — paste this where you call `initRecorder`:
245
+
246
+ ```ts
247
+ const capturePerformanceMetrics =
248
+ new URLSearchParams(window.location.search).get("sf_perf") !== "off";
249
+
250
+ initRecorder({
251
+ apiKey: "YOUR_API_KEY",
252
+ // …your other options…
253
+ capturePerformanceMetrics,
254
+ });
255
+ ```
256
+
257
+ Anything other than `?sf_perf=off` (including the param being absent) leaves capture enabled, so day-to-day usage is unaffected. The toggle exists only so the bench can switch variants by URL.
258
+
259
+ #### Run the bench
260
+
261
+ ```bash
262
+ # 1. Start your app's dev server (separate terminal). Default port 3000.
263
+ npm run start
264
+
265
+ # 2. Run the bench (defaults to http://localhost:3000, 5 runs/variant):
266
+ cd veritas/jsts-frontend
267
+ npm install # first time only — installs puppeteer
268
+ npm run bench-perf
269
+
270
+ # Override URL or sample count:
271
+ npm run bench-perf -- --url http://localhost:3000/some/page --runs 10
272
+
273
+ # Watch the runs in a real browser window (slower, useful for sanity-checking):
274
+ npm run bench-perf -- --headed
275
+ ```
276
+
277
+ Output is a table of medians, p95, and Δ% between the two variants for: wall load time, DCL, load event, FCP, LCP, long-task total, long-task blocking (the TBT proxy), CDP `TaskDuration` / `ScriptDuration` / `LayoutDuration`, and `usedJSHeapSize` (MB).
278
+
279
+ Sample interpretation: a Δ ≤ noise (typically ±5% on the smaller numbers, ±2 MB on heap) means the plugin is essentially free; anything larger is a regression worth profiling.
280
+
188
281
  ## Framework examples
189
282
 
190
283
  ### React / Vite
@@ -311,4 +404,5 @@ ReferenceError: localStorage is not defined
311
404
 
312
405
  ## License
313
406
 
407
+
314
408
  Proprietary. See [sailfishqa.com/terms](https://sailfishqa.com) for terms of service.
@@ -1,4 +1,4 @@
1
- import { y as e } from "./index-CuXHImrI.js";
1
+ import { y as e } from "./index-BynFTRFv.js";
2
2
  async function chunkedSnapshot(t, n, o = {}) {
3
3
  const s = o.chunkSize ?? 500, r = o.maxChunkMs ?? 16, { blockClass: c, blockSelector: a, maskTextClass: i, maskTextSelector: d } = o;
4
4
  let u = 100001, l = 0, N = performance.now();
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const e = require("./index-Cfj4Epfd.js");
3
+ const e = require("./index-BP-kNUGS.js");
4
4
  exports.chunkedSnapshot = async function chunkedSnapshot(t, n, o = {}) {
5
5
  const s = o.chunkSize ?? 500, r = o.maxChunkMs ?? 16, { blockClass: c, blockSelector: a, maskTextClass: i, maskTextSelector: d } = o;
6
6
  let u = 100001, l = 0, N = performance.now();
@@ -178,7 +178,7 @@ function withAppUrlMetadata(e2) {
178
178
  return { ...e2 ?? {}, appUrl: (e2 == null ? void 0 : e2.appUrl) ?? ((_a = window == null ? void 0 : window.location) == null ? void 0 : _a.href) };
179
179
  }
180
180
  exports.nowTimestamp = Date.now, /[1-9][0-9]{12}/.test(Date.now().toString()) || (exports.nowTimestamp = () => (/* @__PURE__ */ new Date()).getTime());
181
- const S = readDebugFlag(), w = "per_session";
181
+ const w = readDebugFlag(), S = "per_session";
182
182
  let v = null, k = null, x = false, I = null, T = null, E = "", C = "", $ = false;
183
183
  const F = [];
184
184
  function onNavigationChange(e2) {
@@ -222,8 +222,8 @@ function _flushIDBQueue() {
222
222
  });
223
223
  })(L.splice(0));
224
224
  }
225
- let A = false, R = null, D = null, _ = false;
226
- const P = "sailfish_funcspan_global_state";
225
+ let A = false, R = null, D = null, P = false;
226
+ const _ = "sailfish_funcspan_global_state";
227
227
  function wsSendPayload(e2) {
228
228
  if (!isWebSocketOpen(k)) return false;
229
229
  if (v) try {
@@ -254,21 +254,21 @@ function saveGlobalFuncSpanState(e2, t2) {
254
254
  try {
255
255
  if ("undefined" == typeof localStorage) return;
256
256
  const n2 = { enabled: e2, expirationTimestampMs: t2, savedAt: Date.now() };
257
- localStorage.setItem(P, JSON.stringify(n2)), S && console.log("[Sailfish] Saved funcSpan state to localStorage:", n2);
257
+ localStorage.setItem(_, JSON.stringify(n2)), w && console.log("[Sailfish] Saved funcSpan state to localStorage:", n2);
258
258
  } catch (e3) {
259
- S && console.warn("[Sailfish] Failed to save funcSpan state to localStorage:", e3);
259
+ w && console.warn("[Sailfish] Failed to save funcSpan state to localStorage:", e3);
260
260
  }
261
261
  }
262
262
  function clearGlobalFuncSpanState() {
263
263
  try {
264
264
  if ("undefined" == typeof localStorage) return;
265
- localStorage.removeItem(P), S && console.log("[Sailfish] Cleared funcSpan state from localStorage");
265
+ localStorage.removeItem(_), w && console.log("[Sailfish] Cleared funcSpan state from localStorage");
266
266
  } catch (e2) {
267
- S && console.warn("[Sailfish] Failed to clear funcSpan state from localStorage:", e2);
267
+ w && console.warn("[Sailfish] Failed to clear funcSpan state from localStorage:", e2);
268
268
  }
269
269
  }
270
270
  function clearStaleFuncSpanState() {
271
- A = false, D = null, _ = false, clearGlobalFuncSpanState(), S && console.log("[Sailfish] Cleared stale function span tracking state (backend validation failed)");
271
+ A = false, D = null, P = false, clearGlobalFuncSpanState(), w && console.log("[Sailfish] Cleared stale function span tracking state (backend validation failed)");
272
272
  }
273
273
  let B = false;
274
274
  function restoreFuncSpanState() {
@@ -277,17 +277,17 @@ function restoreFuncSpanState() {
277
277
  const e2 = (function loadGlobalFuncSpanState() {
278
278
  try {
279
279
  if ("undefined" == typeof localStorage) return null;
280
- const e3 = localStorage.getItem(P);
280
+ const e3 = localStorage.getItem(_);
281
281
  if (!e3) return null;
282
282
  const t2 = JSON.parse(e3);
283
- return S && console.log("[Sailfish] Loaded funcSpan state from localStorage:", t2), t2;
283
+ return w && console.log("[Sailfish] Loaded funcSpan state from localStorage:", t2), t2;
284
284
  } catch (e3) {
285
- return S && console.warn("[Sailfish] Failed to load funcSpan state from localStorage:", e3), null;
285
+ return w && console.warn("[Sailfish] Failed to load funcSpan state from localStorage:", e3), null;
286
286
  }
287
287
  })();
288
- if (e2 && e2.enabled) if (A = true, D = e2.expirationTimestampMs, _ = false, S && console.log("[Sailfish] Restored global function span tracking from localStorage:", { enabled: true, expirationTime: D }), null !== D) {
289
- Date.now() >= D ? (A = false, D = null, clearGlobalFuncSpanState(), S && console.log("[Sailfish] Persisted tracking already expired, cleared state")) : S && console.log("[Sailfish] Function span tracking is active and valid (temporary until WebSocket confirms)");
290
- } else S && console.log("[Sailfish] Function span tracking is active (no expiration, temporary until WebSocket confirms)");
288
+ if (e2 && e2.enabled) if (A = true, D = e2.expirationTimestampMs, P = false, w && console.log("[Sailfish] Restored global function span tracking from localStorage:", { enabled: true, expirationTime: D }), null !== D) {
289
+ Date.now() >= D ? (A = false, D = null, clearGlobalFuncSpanState(), w && console.log("[Sailfish] Persisted tracking already expired, cleared state")) : w && console.log("[Sailfish] Function span tracking is active and valid (temporary until WebSocket confirms)");
290
+ } else w && console.log("[Sailfish] Function span tracking is active (no expiration, temporary until WebSocket confirms)");
291
291
  }
292
292
  function isWebSocketOpen(e2) {
293
293
  return (e2 == null ? void 0 : e2.readyState) === WebSocket.OPEN;
@@ -345,7 +345,7 @@ function sendEvent(e2) {
345
345
  e2.app_url || (e2.app_url = getCachedHref()), !x && isWebSocketOpen(k) && wsSendPayload({ type: "event", event: e2, mapUuid: window.sfMapUuid }) || queueEventForIDB(e2);
346
346
  }
347
347
  function handleWsOpen() {
348
- S && (console.log("[Sailfish] WebSocket connection opened"), console.log("[Sailfish] Function span tracking state: " + (A ? "ENABLED" : "DISABLED"))), (async () => {
348
+ w && (console.log("[Sailfish] WebSocket connection opened"), console.log("[Sailfish] Function span tracking state: " + (A ? "ENABLED" : "DISABLED"))), (async () => {
349
349
  try {
350
350
  x = true, await flushNotifyQueue(), await flushBufferedEvents();
351
351
  } finally {
@@ -357,29 +357,29 @@ function handleWsOpen() {
357
357
  })();
358
358
  }
359
359
  function handleWsClose() {
360
- null != T && (clearInterval(T), T = null), S && console.log("[Sailfish] WebSocket closed");
360
+ null != T && (clearInterval(T), T = null), w && console.log("[Sailfish] WebSocket closed");
361
361
  }
362
362
  function handleWsMessage(e2) {
363
363
  try {
364
364
  const t2 = JSON.parse(e2);
365
- if ("funcSpanTrackingControl" === t2.type) if (S && console.log("[Sailfish] Received funcSpanTrackingControl message:", { enabled: t2.enabled, timeoutSeconds: t2.timeoutSeconds, expirationTimestampMs: t2.expirationTimestampMs }), null !== R && (window.clearTimeout(R), R = null), A = t2.enabled, _ = false, S && console.log("[Sailfish] Function span tracking " + (t2.enabled ? "ENABLED (GLOBAL)" : "DISABLED (GLOBAL)")), t2.enabled) {
365
+ if ("funcSpanTrackingControl" === t2.type) if (w && console.log("[Sailfish] Received funcSpanTrackingControl message:", { enabled: t2.enabled, timeoutSeconds: t2.timeoutSeconds, expirationTimestampMs: t2.expirationTimestampMs }), null !== R && (window.clearTimeout(R), R = null), A = t2.enabled, P = false, w && console.log("[Sailfish] Function span tracking " + (t2.enabled ? "ENABLED (GLOBAL)" : "DISABLED (GLOBAL)")), t2.enabled) {
366
366
  if (t2.expirationTimestampMs) {
367
367
  D = t2.expirationTimestampMs;
368
368
  const e3 = Date.now(), n2 = D - e3;
369
- S && console.log(`[Sailfish] Server expiration timestamp: ${D}, ms until expiration: ${n2}`), n2 > 0 ? (saveGlobalFuncSpanState(true, D), R = window.setTimeout(() => {
370
- _ || (A = false, D = null, clearGlobalFuncSpanState(), S && console.log("[Sailfish] GLOBAL function span tracking auto-disabled at server expiration time"), wsSendPayload({ type: "funcSpanTrackingExpired", sessionId: getOrSetSessionId(), expiredAt: Date.now() }), S && console.log("[Sailfish] Notified backend that function span tracking expired"));
371
- }, n2)) : (A = false, D = null, clearGlobalFuncSpanState(), S && console.log("[Sailfish] Tracking already expired, not enabling"));
369
+ w && console.log(`[Sailfish] Server expiration timestamp: ${D}, ms until expiration: ${n2}`), n2 > 0 ? (saveGlobalFuncSpanState(true, D), R = window.setTimeout(() => {
370
+ P || (A = false, D = null, clearGlobalFuncSpanState(), w && console.log("[Sailfish] GLOBAL function span tracking auto-disabled at server expiration time"), wsSendPayload({ type: "funcSpanTrackingExpired", sessionId: getOrSetSessionId(), expiredAt: Date.now() }), w && console.log("[Sailfish] Notified backend that function span tracking expired"));
371
+ }, n2)) : (A = false, D = null, clearGlobalFuncSpanState(), w && console.log("[Sailfish] Tracking already expired, not enabling"));
372
372
  } else {
373
373
  const e3 = t2.timeoutSeconds || 3600;
374
374
  e3 > 0 && (D = Date.now() + 1e3 * e3, saveGlobalFuncSpanState(true, D), R = window.setTimeout(() => {
375
- _ || (A = false, D = null, clearGlobalFuncSpanState(), S && console.log(`[Sailfish] GLOBAL function span tracking auto-disabled after ${e3}s (legacy)`), wsSendPayload({ type: "funcSpanTrackingExpired", sessionId: getOrSetSessionId(), expiredAt: Date.now() }), S && console.log("[Sailfish] Notified backend that function span tracking expired (legacy timeout)"));
375
+ P || (A = false, D = null, clearGlobalFuncSpanState(), w && console.log(`[Sailfish] GLOBAL function span tracking auto-disabled after ${e3}s (legacy)`), wsSendPayload({ type: "funcSpanTrackingExpired", sessionId: getOrSetSessionId(), expiredAt: Date.now() }), w && console.log("[Sailfish] Notified backend that function span tracking expired (legacy timeout)"));
376
376
  }, 1e3 * e3));
377
377
  }
378
378
  try {
379
379
  const e3 = getOrSetSessionId();
380
- wsSendPayload({ type: "funcSpanTrackingSessionReport", sessionId: e3, enabled: true, configurationType: "global" }), S && console.log(`[Sailfish] GLOBAL tracking session report sent for session: ${e3}`);
380
+ wsSendPayload({ type: "funcSpanTrackingSessionReport", sessionId: e3, enabled: true, configurationType: "global" }), w && console.log(`[Sailfish] GLOBAL tracking session report sent for session: ${e3}`);
381
381
  } catch (e3) {
382
- S && console.warn("[Sailfish] Failed to send GLOBAL tracking session report:", e3);
382
+ w && console.warn("[Sailfish] Failed to send GLOBAL tracking session report:", e3);
383
383
  }
384
384
  } else D = null, clearGlobalFuncSpanState();
385
385
  } catch (e3) {
@@ -391,7 +391,7 @@ function initializeWebSocket(t2, n2, i2, o2, s2 = false) {
391
391
  const t3 = new URL(e2);
392
392
  return `${t3.hostname}${t3.port ? `:${t3.port}` : ""}`;
393
393
  })(t2);
394
- let a2 = `${"https:" === new URL(t2).protocol ? "wss" : "ws"}://${r2}/ws/notify/?apiKey=${n2}&sessionId=${i2}&sender=JS%2FTS&version=1.11.1`;
394
+ let a2 = `${"https:" === new URL(t2).protocol ? "wss" : "ws"}://${r2}/ws/notify/?apiKey=${n2}&sessionId=${i2}&sender=JS%2FTS&version=1.11.3`;
395
395
  if (o2 && (a2 += `&envValue=${encodeURIComponent(o2)}`), v = s2 ? (function tryCreateWsWorker() {
396
396
  if ("undefined" == typeof Worker) return null;
397
397
  try {
@@ -408,10 +408,10 @@ function initializeWebSocket(t2, n2, i2, o2, s2 = false) {
408
408
  const n3 = e3.data;
409
409
  "open" === n3.type ? (t3.readyState = WebSocket.OPEN, handleWsOpen()) : "close" === n3.type ? (t3.readyState = WebSocket.CLOSED, handleWsClose()) : "message" === n3.type && handleWsMessage(n3.data);
410
410
  }, v.onerror = () => {
411
- S && console.warn("[Sailfish] WebSocket worker error");
412
- }, v.postMessage({ type: "init", wsUrl: a2 }), S && console.log("[Sailfish] WebSocket running in Web Worker (off main thread)"), t3;
411
+ w && console.warn("[Sailfish] WebSocket worker error");
412
+ }, v.postMessage({ type: "init", wsUrl: a2 }), w && console.log("[Sailfish] WebSocket running in Web Worker (off main thread)"), t3;
413
413
  }
414
- S && console.log("[Sailfish] WebSocket running on main thread (Worker unavailable)");
414
+ w && console.log("[Sailfish] WebSocket running on main thread (Worker unavailable)");
415
415
  const l2 = new e(a2, [], { connectionTimeout: 3e4 }), c2 = { get readyState() {
416
416
  return l2.readyState;
417
417
  }, close: () => {
@@ -423,26 +423,26 @@ function sendMessage(e2) {
423
423
  "sessionId" in e2 || (e2.sessionId = getOrSetSessionId()), e2.app_url || (e2.app_url = getCachedHref()), x || !isWebSocketOpen(k) ? saveNotifyMessageToIDB(JSON.stringify(e2)) : wsSendPayload(e2) || saveNotifyMessageToIDB(JSON.stringify(e2));
424
424
  }
425
425
  function enableFunctionSpanTracking() {
426
- if (S && console.log("[Sailfish] enableFunctionSpanTracking() called - Report Issue recording started (LOCAL MODE)"), A = true, _ = true, D = null, null !== R && (window.clearTimeout(R), R = null), isWebSocketOpen(k)) {
427
- wsSendPayload({ type: "funcSpanTrackingSessionReport", sessionId: getOrSetSessionId(), enabled: true, configurationType: w });
428
- } else S && console.warn("[Sailfish] WebSocket not open, cannot report LOCAL tracking session");
426
+ if (w && console.log("[Sailfish] enableFunctionSpanTracking() called - Report Issue recording started (LOCAL MODE)"), A = true, P = true, D = null, null !== R && (window.clearTimeout(R), R = null), isWebSocketOpen(k)) {
427
+ wsSendPayload({ type: "funcSpanTrackingSessionReport", sessionId: getOrSetSessionId(), enabled: true, configurationType: S });
428
+ } else w && console.warn("[Sailfish] WebSocket not open, cannot report LOCAL tracking session");
429
429
  }
430
430
  function disableFunctionSpanTracking() {
431
- if (S && console.log("[Sailfish] disableFunctionSpanTracking() called - Report Issue recording stopped"), isWebSocketOpen(k)) {
432
- wsSendPayload({ type: "funcSpanTrackingSessionReport", sessionId: getOrSetSessionId(), enabled: false, configurationType: w });
431
+ if (w && console.log("[Sailfish] disableFunctionSpanTracking() called - Report Issue recording stopped"), isWebSocketOpen(k)) {
432
+ wsSendPayload({ type: "funcSpanTrackingSessionReport", sessionId: getOrSetSessionId(), enabled: false, configurationType: S });
433
433
  } else console.warn("[FUNCSPAN STOP] ✗ WebSocket not open, cannot notify tracking end");
434
- _ && (A = false, _ = false, D = null, S && console.log("[Sailfish] LOCAL tracking mode disabled")), null !== R && (window.clearTimeout(R), R = null);
434
+ P && (A = false, P = false, D = null, w && console.log("[Sailfish] LOCAL tracking mode disabled")), null !== R && (window.clearTimeout(R), R = null);
435
435
  }
436
436
  function isFunctionSpanTrackingEnabled() {
437
437
  return A;
438
438
  }
439
439
  function initializeFunctionSpanTrackingFromApi(e2) {
440
- e2 && !A ? (A = true, _ = false, D = null, S && console.log("[Sailfish] Function span tracking initialized as ENABLED from API check")) : !e2 && A && (A = false, _ = false, D = null, S && console.log("[Sailfish] Function span tracking initialized as DISABLED from API check"));
440
+ e2 && !A ? (A = true, P = false, D = null, w && console.log("[Sailfish] Function span tracking initialized as ENABLED from API check")) : !e2 && A && (A = false, P = false, D = null, w && console.log("[Sailfish] Function span tracking initialized as DISABLED from API check"));
441
441
  }
442
442
  function getFuncSpanHeader() {
443
443
  if (!A) return null;
444
444
  if (null !== D) {
445
- if (Date.now() >= D) return A = false, D = null, clearGlobalFuncSpanState(), S && console.log("[Sailfish] Function span tracking expired on header check - disabling now"), null;
445
+ if (Date.now() >= D) return A = false, D = null, clearGlobalFuncSpanState(), w && console.log("[Sailfish] Function span tracking expired on header check - disabling now"), null;
446
446
  }
447
447
  return { name: "X-Sf3-FunctionSpanCaptureOverride", value: "1-1-10-10-1-1.0-1-0-0" };
448
448
  }
@@ -671,6 +671,20 @@ function initializeDomContentEvents(e2) {
671
671
  sendEvent({ type: 24, data: { source: r }, timestamp: Date.now(), sessionId: e2, ...getUrlAndStoredUuids() });
672
672
  });
673
673
  }
674
+ async function initializePerformancePlugin(e2) {
675
+ var _a;
676
+ try {
677
+ const { getRecordPerformancePlugin: t2 } = await Promise.resolve().then(() => require("./rrweb-plugin-performance-record-Dekf6xUi.js"));
678
+ await yieldToMain();
679
+ const n2 = t2({ getPageVisitUuid: () => sessionStorage.getItem("pageVisitUUID") });
680
+ (_a = n2.observer) == null ? void 0 : _a.call(n2, (t3) => {
681
+ const i2 = t3;
682
+ sendEvent({ type: 28, timestamp: i2.timestamp, sessionId: e2, data: { plugin: n2.name, payload: i2 }, ...getUrlAndStoredUuids() });
683
+ }, window, n2.options);
684
+ } catch (e3) {
685
+ console.warn("[Sailfish] Performance plugin failed to initialize:", e3);
686
+ }
687
+ }
674
688
  async function initializeConsolePlugin(e2, n2) {
675
689
  const { getRecordConsolePlugin: i2 } = await import("@sailfish-rrweb/rrweb-plugin-console-record");
676
690
  await yieldToMain();
@@ -714,7 +728,7 @@ async function initializeRecording(e2, n2, i2, o2, s2, r2 = true, a2 = false, l2
714
728
  }
715
729
  const { record: n4 } = await import("@sailfish-rrweb/rrweb-record-only");
716
730
  if (Q = n4, await yieldToMain(), l2) {
717
- const { chunkedSnapshot: i3 } = await Promise.resolve().then(() => require("./chunkSerializer-CJQCxiLD.js")), o3 = n4.mirror;
731
+ const { chunkedSnapshot: i3 } = await Promise.resolve().then(() => require("./chunkSerializer-jzbHv2wf.js")), o3 = n4.mirror;
718
732
  let s3 = true;
719
733
  const r3 = [];
720
734
  n4({ emit(e3) {
@@ -1044,7 +1058,7 @@ function renderCustomMultiSelect(e2, t2, n2, i2, o2 = false) {
1044
1058
  }
1045
1059
  const he = { enabled: false, openModalExistingMode: { key: "e", requireCmdCtrl: false }, openModalCaptureNewMode: { key: "n", requireCmdCtrl: false }, closeModal: { key: "escape", requireCmdCtrl: false }, submitReport: { key: "enter", requireCmdCtrl: true }, startRecording: { key: "r", requireCmdCtrl: false }, stopRecording: { key: "escape", requireCmdCtrl: true } }, ye = { shortcuts: { ...he }, resolveSessionId: null, apiKey: null, backendApi: null, triageBaseUrl: "https://app.sailfishqa.com", deactivateIsolation: () => {
1046
1060
  }, integrationData: null, showEngTicketFieldsDefault: false };
1047
- let be = null, Se = false;
1061
+ let be = null, we = false;
1048
1062
  function setupCustomMultiSelectListeners(e2, t2) {
1049
1063
  const n2 = document.getElementById(`${e2}-container`), i2 = document.getElementById(`${e2}-dropdown`);
1050
1064
  if (!n2 || !i2) return;
@@ -1293,7 +1307,7 @@ function getSessionIdSafely() {
1293
1307
  return ye.resolveSessionId();
1294
1308
  }
1295
1309
  function openReportIssueModal(e2) {
1296
- me ? stopRecording() : (Se = (e2 == null ? void 0 : e2.showEngTicketFields) ?? ye.showEngTicketFieldsDefault, injectModalHTML(), be && document.body.appendChild(be));
1310
+ me ? stopRecording() : (we = (e2 == null ? void 0 : e2.showEngTicketFields) ?? ye.showEngTicketFieldsDefault, injectModalHTML(), be && document.body.appendChild(be));
1297
1311
  }
1298
1312
  function closeModal() {
1299
1313
  ye.deactivateIsolation(), document.activeElement instanceof HTMLElement && document.activeElement.blur(), (be == null ? void 0 : be.parentNode) && be.parentNode.removeChild(be), be = null, me || (function resetState() {
@@ -1485,7 +1499,7 @@ function injectModalHTML(e2 = "lookback") {
1485
1499
  Create an Issue
1486
1500
  </label>
1487
1501
 
1488
- <label id="sf-create-eng-ticket-label" style="display:${ye.integrationData && Se ? "flex" : "none"}; align-items:center; gap:8px; font-size:14px; font-weight:500; cursor:pointer;">
1502
+ <label id="sf-create-eng-ticket-label" style="display:${ye.integrationData && we ? "flex" : "none"}; align-items:center; gap:8px; font-size:14px; font-weight:500; cursor:pointer;">
1489
1503
  <input type="checkbox" id="sf-create-eng-ticket-checkbox" ${ue.createEngTicket ? "checked" : ""}
1490
1504
  style="width:16px; height:16px; accent-color:#295DBF; cursor:pointer;">
1491
1505
  Create an Eng Ticket
@@ -1713,7 +1727,7 @@ function injectModalHTML(e2 = "lookback") {
1713
1727
  const e4 = generateEngTicketFieldsHTML();
1714
1728
  e4 && (t3.innerHTML = e4, initializeEngTicketForm(), bindEngTicketListeners(), updateFormWithIntegrationData(ue), renderDynamicFields(ue.engTicketProject, ue.engTicketIssueType));
1715
1729
  }
1716
- if (Se) {
1730
+ if (we) {
1717
1731
  const e4 = document.getElementById("sf-create-eng-ticket-label");
1718
1732
  e4 && (e4.style.display = "flex");
1719
1733
  }
@@ -1910,7 +1924,7 @@ function showStatusModal(e2, t2, n2) {
1910
1924
  function fadeCardAndRemove(e2, t2, n2 = 300) {
1911
1925
  t2.style.opacity = "0", t2.addEventListener("transitionend", () => e2.remove(), { once: true }), setTimeout(() => e2.remove(), n2 + 100);
1912
1926
  }
1913
- const we = Object.freeze(Object.defineProperty({ __proto__: null, ReportIssueContext: ye, openReportIssueModal, setupIssueReporting: function setupIssueReporting(e2) {
1927
+ const Se = Object.freeze(Object.defineProperty({ __proto__: null, ReportIssueContext: ye, openReportIssueModal, setupIssueReporting: function setupIssueReporting(e2) {
1914
1928
  ye.apiKey = e2.apiKey, ye.backendApi = e2.backendApi, ye.resolveSessionId = e2.getSessionId, ye.integrationData = e2.integrationData || null, ye.showEngTicketFieldsDefault = e2.showEngTicketFieldsInReportIssueModalDefault ?? false, e2.customBaseUrl && (ye.triageBaseUrl = e2.customBaseUrl), ye.shortcuts = (function mergeShortcutsConfig(e3) {
1915
1929
  const t3 = { ...he };
1916
1930
  if (!e3) return t3;
@@ -2094,8 +2108,8 @@ function setupFetchInterceptor(e2 = [], t2 = { captureStreamingResponseBody: tru
2094
2108
  delete h2[n];
2095
2109
  const b2 = getFuncSpanHeader();
2096
2110
  b2 && delete h2[b2.name];
2097
- const S2 = `${c3}/${p2.page_visit_uuid}/${u3}`;
2098
- h2[n] = S2, b2 && (h2[b2.name] = b2.value);
2111
+ const w2 = `${c3}/${p2.page_visit_uuid}/${u3}`;
2112
+ h2[n] = w2, b2 && (h2[b2.name] = b2.value);
2099
2113
  maskAuthorizationHeader(h2);
2100
2114
  try {
2101
2115
  let b3 = await (async function injectHeader(e5, t3, i5, o5, s4, r4, a3) {
@@ -2110,7 +2124,7 @@ function setupFetchInterceptor(e2 = [], t2 = { captureStreamingResponseBody: tru
2110
2124
  const c4 = { ...o5 }, d4 = new Headers(o5.headers || {});
2111
2125
  return d4.set(n, `${s4}/${r4}/${a3}`), l3 && (d4.set(l3.name, l3.value), ve && console.log("[Sailfish] Added funcspan header to HTTP fetch:", { url: "string" == typeof i5 ? i5 : i5.href, header: l3.name })), c4.headers = d4, await e5.call(t3, i5, c4);
2112
2126
  }
2113
- })(e4, i4, s3, r3, c3, p2.page_visit_uuid, u3), S3 = false;
2127
+ })(e4, i4, s3, r3, c3, p2.page_visit_uuid, u3), w3 = false;
2114
2128
  Te.includes(b3.status) && (ve && console.log("Perform retry as status was fail:", b3), delete h2[n], b3 = await (async function retryWithoutPropagateHeaders(e5, t3, i5, o5) {
2115
2129
  try {
2116
2130
  let o6 = i5[0], s4 = i5[1] || {};
@@ -2129,8 +2143,8 @@ function setupFetchInterceptor(e2 = [], t2 = { captureStreamingResponseBody: tru
2129
2143
  } catch (e6) {
2130
2144
  throw ve && console.log(`Retry without ${n} for ${o5} also failed:`, e6), e6;
2131
2145
  }
2132
- })(e4, i4, o4, d3), S3 = true);
2133
- const w2 = Date.now(), v2 = b3.status, k2 = b3.ok, x2 = k2 ? "" : `Request Error: ${b3.statusText}`;
2146
+ })(e4, i4, o4, d3), w3 = true);
2147
+ const S2 = Date.now(), v2 = b3.status, k2 = b3.ok, x2 = k2 ? "" : `Request Error: ${b3.statusText}`;
2134
2148
  let I2 = null;
2135
2149
  try {
2136
2150
  I2 = {}, b3.headers.forEach((e5, t3) => {
@@ -2139,7 +2153,7 @@ function setupFetchInterceptor(e2 = [], t2 = { captureStreamingResponseBody: tru
2139
2153
  } catch (e5) {
2140
2154
  ve && console.warn("[Sailfish] Failed to capture response headers:", e5), I2 = null;
2141
2155
  }
2142
- const T2 = { type: 27, timestamp: w2, sessionId: c3, data: { request_id: u3, session_id: c3, timestamp_start: g2, timestamp_end: w2, response_code: v2, success: k2, error: x2, method: f2, url: d3, retry_without_trace_id: S3, request_headers: h2, request_body: m2, response_headers: I2, response_body: null }, ...p2 }, sendEventWithBody = (e5) => {
2156
+ const T2 = { type: 27, timestamp: S2, sessionId: c3, data: { request_id: u3, session_id: c3, timestamp_start: g2, timestamp_end: S2, response_code: v2, success: k2, error: x2, method: f2, url: d3, retry_without_trace_id: w3, request_headers: h2, request_body: m2, response_headers: I2, response_body: null }, ...p2 }, sendEventWithBody = (e5) => {
2143
2157
  T2.data.response_body = e5, y2 ? y2.text().then((e6) => {
2144
2158
  T2.data.request_body = e6, sendEvent(T2);
2145
2159
  }, () => {
@@ -2227,9 +2241,9 @@ function setupFetchInterceptor(e2 = [], t2 = { captureStreamingResponseBody: tru
2227
2241
  })(e3, i3, o3, d2, u2, s2, c2);
2228
2242
  } });
2229
2243
  }
2230
- async function startRecording({ apiKey: e2, backendApi: t2 = "https://api-service.sailfishqa.com", domainsToPropagateHeaderTo: i2 = ["*"], domainsToNotPropagateHeaderTo: o2 = [], serviceVersion: s2, serviceIdentifier: r2, gitSha: a2, serviceAdditionalMetadata: l2, enableIpTracking: c2, captureStreamingResponseBody: d2 = true, captureResponseBodyMaxMb: u2 = 10, captureStreamPrefixKb: p2 = 64, captureStreamTimeoutMs: f2 = 1e4, enableFiberTracking: m2 = false, deferRecording: h2, deferRecordingStart: y2, chunkSnapshot: b2, useWsWorker: S2 = true, maskTextClass: w2, library: v2 }) {
2244
+ async function startRecording({ apiKey: e2, backendApi: t2 = "https://api-service.sailfishqa.com", domainsToPropagateHeaderTo: i2 = ["*"], domainsToNotPropagateHeaderTo: o2 = [], serviceVersion: s2, serviceIdentifier: r2, gitSha: a2, serviceAdditionalMetadata: l2, enableIpTracking: c2, captureStreamingResponseBody: d2 = true, captureResponseBodyMaxMb: u2 = 10, captureStreamPrefixKb: p2 = 64, captureStreamTimeoutMs: f2 = 1e4, enableFiberTracking: m2 = false, deferRecording: h2, deferRecordingStart: y2, chunkSnapshot: b2, useWsWorker: w2 = true, capturePerformanceMetrics: S2 = true, maskTextClass: v2, library: k2, headlessRecording: x2 = false }) {
2231
2245
  var _a, _b;
2232
- if ((function isHeadlessOrLighthouse() {
2246
+ if (!x2 && (function isHeadlessOrLighthouse() {
2233
2247
  try {
2234
2248
  if ("undefined" == typeof navigator) return false;
2235
2249
  const e3 = navigator;
@@ -2240,10 +2254,10 @@ async function startRecording({ apiKey: e2, backendApi: t2 = "https://api-servic
2240
2254
  return false;
2241
2255
  }
2242
2256
  })()) return;
2243
- const k2 = h2 ?? y2 ?? true, x2 = getOrSetSessionId(), I2 = window.__sailfish_recorder || (window.__sailfish_recorder = {});
2244
- if (I2.sessionId = x2, I2.apiKey = e2, I2.backendApi = t2, I2.serviceAdditionalMetadata = l2, I2.initialized && I2.sessionId === x2 && I2.ws && 1 === I2.ws.readyState) return void trackDomainChangesOnce();
2245
- const T2 = { captureStreamingResponseBody: d2, captureResponseBodyMaxMb: u2, captureStreamPrefixKb: p2, captureStreamTimeoutMs: f2 };
2246
- sessionStorage.getItem("pageVisitUUID") || (sessionStorage.setItem("pageVisitUUID", uuidv4()), invalidateUrlCache()), I2.xhrPatched || (!(function setupXMLHttpRequestInterceptor(e3 = [], t3 = { captureStreamingResponseBody: true, captureResponseBodyMaxMb: 10, captureStreamPrefixKb: 64, captureStreamTimeoutMs: 1e4 }, i3 = []) {
2257
+ const I2 = h2 ?? y2 ?? true, T2 = getOrSetSessionId(), E2 = window.__sailfish_recorder || (window.__sailfish_recorder = {});
2258
+ if (E2.sessionId = T2, E2.apiKey = e2, E2.backendApi = t2, E2.serviceAdditionalMetadata = l2, E2.initialized && E2.sessionId === T2 && E2.ws && 1 === E2.ws.readyState) return void trackDomainChangesOnce();
2259
+ const C2 = { captureStreamingResponseBody: d2, captureResponseBodyMaxMb: u2, captureStreamPrefixKb: p2, captureStreamTimeoutMs: f2 };
2260
+ sessionStorage.getItem("pageVisitUUID") || (sessionStorage.setItem("pageVisitUUID", uuidv4()), invalidateUrlCache()), E2.xhrPatched || (!(function setupXMLHttpRequestInterceptor(e3 = [], t3 = { captureStreamingResponseBody: true, captureResponseBodyMaxMb: 10, captureStreamPrefixKb: 64, captureStreamTimeoutMs: 1e4 }, i3 = []) {
2247
2261
  const o3 = XMLHttpRequest.prototype.open, s3 = XMLHttpRequest.prototype.send, r3 = XMLHttpRequest.prototype.setRequestHeader, a3 = getOrSetSessionId(), l3 = createSkipHeadersPropagationChecker(e3, i3);
2248
2262
  XMLHttpRequest.prototype.setRequestHeader = function(e4, t4) {
2249
2263
  return this._capturedRequestHeaders || (this._capturedRequestHeaders = {}), this._capturedRequestHeaders[e4] = t4, r3.call(this, e4, t4);
@@ -2308,22 +2322,22 @@ async function startRecording({ apiKey: e2, backendApi: t2 = "https://api-servic
2308
2322
  emitFinished(false, e5, t4);
2309
2323
  }, { once: true }), s3.apply(this, e4);
2310
2324
  };
2311
- })(o2, T2, i2), I2.xhrPatched = true), I2.fetchPatched || (setupFetchInterceptor(o2, T2, i2), I2.fetchPatched = true), await yieldToMain(), I2.domEventsInit || (initializeDomContentEvents(x2), I2.domEventsInit = true), await yieldToMain(), I2.consoleInit || (initializeConsolePlugin(Le, x2), I2.consoleInit = true), await yieldToMain(), I2.errorInit || (!(function initializeErrorInterceptor() {
2325
+ })(o2, C2, i2), E2.xhrPatched = true), E2.fetchPatched || (setupFetchInterceptor(o2, C2, i2), E2.fetchPatched = true), await yieldToMain(), E2.domEventsInit || (initializeDomContentEvents(T2), E2.domEventsInit = true), await yieldToMain(), E2.consoleInit || (initializeConsolePlugin(Le, T2), E2.consoleInit = true), await yieldToMain(), E2.errorInit || (!(function initializeErrorInterceptor() {
2312
2326
  window.addEventListener("error", (e3) => {
2313
2327
  captureError(e3.error || e3.message);
2314
2328
  }), window.addEventListener("unhandledrejection", (e3) => {
2315
2329
  captureError(e3.reason, true);
2316
2330
  });
2317
- })(), I2.errorInit = true), await yieldToMain(), _ensureModuleSideEffects(), (function storeCredentialsAndConnection({ apiKey: e3, backendApi: t3 }) {
2331
+ })(), E2.errorInit = true), await yieldToMain(), !E2.perfInit && S2 && (initializePerformancePlugin(T2), E2.perfInit = true), await yieldToMain(), _ensureModuleSideEffects(), (function storeCredentialsAndConnection({ apiKey: e3, backendApi: t3 }) {
2318
2332
  g && (sessionStorage.setItem("sailfishApiKey", e3), sessionStorage.setItem("sailfishBackendApi", t3));
2319
- })({ apiKey: e2, backendApi: t2 }), !isFunctionSpanTrackingEnabled() || I2.ws && 1 === I2.ws.readyState || fetchFunctionSpanTrackingEnabled(e2, t2).then((e3) => {
2333
+ })({ apiKey: e2, backendApi: t2 }), !isFunctionSpanTrackingEnabled() || E2.ws && 1 === E2.ws.readyState || fetchFunctionSpanTrackingEnabled(e2, t2).then((e3) => {
2320
2334
  var _a2;
2321
2335
  ((_a2 = e3.data) == null ? void 0 : _a2.isFunctionSpanTrackingEnabledFromApiKey) ?? false ? ve && console.log("[Sailfish] Function span tracking state validated with backend: ACTIVE") : (clearStaleFuncSpanState(), ve && console.log("[Sailfish] Cleared stale function span tracking state - backend validation shows tracking is not active"));
2322
2336
  }).catch((e3) => {
2323
2337
  ve && console.warn("[Sailfish] Failed to validate function span tracking status with backend:", e3);
2324
- }), I2.sentDoNotPropagateOnce || (sendDomainsToNotPropagateHeaderTo(e2, [...o2, ...Ie], t2).catch((e3) => console.error("Failed to send domains to not propagate header to:", e3)), I2.sentDoNotPropagateOnce = true), (async function gatherAndCacheDeviceInfo() {
2338
+ }), E2.sentDoNotPropagateOnce || (sendDomainsToNotPropagateHeaderTo(e2, [...o2, ...Ie], t2).catch((e3) => console.error("Failed to send domains to not propagate header to:", e3)), E2.sentDoNotPropagateOnce = true), (async function gatherAndCacheDeviceInfo() {
2325
2339
  sendMessage({ type: "deviceInfo", data: { deviceInfo: { language: navigator.language, userAgent: navigator.userAgent } } });
2326
- })(), c2 && fetchAndSendIp(x2);
2340
+ })(), c2 && fetchAndSendIp(T2);
2327
2341
  try {
2328
2342
  const n2 = a2 ?? (function readGitSha() {
2329
2343
  var _a2;
@@ -2342,7 +2356,7 @@ async function startRecording({ apiKey: e2, backendApi: t2 = "https://api-servic
2342
2356
  if ("string" == typeof e3 && e3) return e3;
2343
2357
  } catch {
2344
2358
  }
2345
- })(), i3 = r2 ?? "", o3 = s2 ?? "", c3 = v2 ?? "JS/TS", d3 = (function getMapUuidFromWindow() {
2359
+ })(), i3 = r2 ?? "", o3 = s2 ?? "", c3 = k2 ?? "JS/TS", d3 = (function getMapUuidFromWindow() {
2346
2360
  try {
2347
2361
  const e3 = window;
2348
2362
  if (e3 && "string" == typeof e3.sfMapUuid && e3.sfMapUuid) return e3.sfMapUuid;
@@ -2362,15 +2376,15 @@ async function startRecording({ apiKey: e2, backendApi: t2 = "https://api-servic
2362
2376
  return { framework: i4[0] ?? null, additionalFrameworks: i4.slice(1), serviceRole: "frontend" };
2363
2377
  })(), f3 = { ...u3, serviceRole: p3.serviceRole, ...null !== p3.framework && { framework: p3.framework }, ...p3.additionalFrameworks.length > 0 && { additionalFrameworks: p3.additionalFrameworks } };
2364
2378
  await yieldToMain();
2365
- const [g2, h3] = await Promise.all([fetchCaptureSettings(e2, t2), startRecordingSession(e2, x2, t2, i3, o3, d3, n2, c3, f3)]), y3 = { ...Fe, ...(_a = g2.data) == null ? void 0 : _a.captureSettingsFromApiKey, enableFiberTracking: m2, ...void 0 !== w2 ? { maskTextClass: w2 } : {} };
2366
- if (I2.ws && 1 === I2.ws.readyState) return;
2379
+ const [g2, h3] = await Promise.all([fetchCaptureSettings(e2, t2), startRecordingSession(e2, T2, t2, i3, o3, d3, n2, c3, f3)]), y3 = { ...Fe, ...(_a = g2.data) == null ? void 0 : _a.captureSettingsFromApiKey, enableFiberTracking: m2, ...void 0 !== v2 ? { maskTextClass: v2 } : {} };
2380
+ if (E2.ws && 1 === E2.ws.readyState) return;
2367
2381
  if ((_b = h3.data) == null ? void 0 : _b.startRecordingSession) {
2368
2382
  const n3 = (l2 == null ? void 0 : l2.env) || (l2 == null ? void 0 : l2.environment);
2369
2383
  await yieldToMain();
2370
- const i4 = await initializeRecording(y3, t2, e2, x2, n3, k2, S2, b2 ?? false);
2371
- I2.ws = i4, I2.initialized = true, trackDomainChangesOnce(), I2.sentMapUuidOnce || (!(function sendMapUuidIfAvailable(e3 = "", t3 = "") {
2384
+ const i4 = await initializeRecording(y3, t2, e2, T2, n3, I2, w2, b2 ?? false);
2385
+ E2.ws = i4, E2.initialized = true, trackDomainChangesOnce(), E2.sentMapUuidOnce || (!(function sendMapUuidIfAvailable(e3 = "", t3 = "") {
2372
2386
  window.sfMapUuid && sendMessage({ type: "mapUuid", data: { mapUuid: window.sfMapUuid, serviceIdentifier: e3, serviceVersion: t3 } });
2373
- })(r2, s2), I2.sentMapUuidOnce = true);
2387
+ })(r2, s2), E2.sentMapUuidOnce = true);
2374
2388
  } else console.error("Failed to start recording session:", h3.errors || h3);
2375
2389
  } catch (e3) {
2376
2390
  console.error("Error starting recording:", e3);
@@ -2388,7 +2402,7 @@ exports.DEFAULT_CAPTURE_SETTINGS = Fe, exports.DEFAULT_CONSOLE_RECORDING_SETTING
2388
2402
  return clearPageVisitDataFromSessionStorage(), t2.initialized && t2.sessionId === n2 && t2.ws && 1 === t2.ws.readyState ? void 0 : (t2.initPromise || (t2.initPromise = (async () => {
2389
2403
  try {
2390
2404
  if (t2.hasLoggedInitOnce || (console.log("Initializing Sailfish Recorder (first run) …"), t2.hasLoggedInitOnce = true), await startRecording(e2), !t2.issueReportingInit) {
2391
- const n3 = e2.backendApi ?? "https://api-service.sailfishqa.com", [{ setupIssueReporting: i2 }, { fetchIntegrationData: o2, getIntegrationData: s2 }] = await Promise.all([Promise.resolve().then(() => we), Promise.resolve().then(() => le)]);
2405
+ const n3 = e2.backendApi ?? "https://api-service.sailfishqa.com", [{ setupIssueReporting: i2 }, { fetchIntegrationData: o2, getIntegrationData: s2 }] = await Promise.all([Promise.resolve().then(() => Se), Promise.resolve().then(() => le)]);
2392
2406
  let r2 = null;
2393
2407
  try {
2394
2408
  await o2(e2.apiKey, n3), r2 = s2();
@@ -2403,7 +2417,7 @@ exports.DEFAULT_CAPTURE_SETTINGS = Fe, exports.DEFAULT_CONSOLE_RECORDING_SETTING
2403
2417
  })().finally(() => {
2404
2418
  delete t2.initPromise;
2405
2419
  })), t2.initPromise);
2406
- }, exports.initializeConsolePlugin = initializeConsolePlugin, exports.initializeDomContentEvents = initializeDomContentEvents, exports.initializeFunctionSpanTrackingFromApi = initializeFunctionSpanTrackingFromApi, exports.initializeRecording = initializeRecording, exports.initializeWebSocket = initializeWebSocket, exports.invalidateUrlCache = invalidateUrlCache, exports.isFunctionSpanTrackingEnabled = isFunctionSpanTrackingEnabled, exports.matchUrlWithWildcard = function matchUrlWithWildcard(e2, t2) {
2420
+ }, exports.initializeConsolePlugin = initializeConsolePlugin, exports.initializeDomContentEvents = initializeDomContentEvents, exports.initializeFunctionSpanTrackingFromApi = initializeFunctionSpanTrackingFromApi, exports.initializePerformancePlugin = initializePerformancePlugin, exports.initializeRecording = initializeRecording, exports.initializeWebSocket = initializeWebSocket, exports.invalidateUrlCache = invalidateUrlCache, exports.isFunctionSpanTrackingEnabled = isFunctionSpanTrackingEnabled, exports.matchUrlWithWildcard = function matchUrlWithWildcard(e2, t2) {
2407
2421
  let n2, i2;
2408
2422
  if ("string" == typeof e2 ? n2 = e2 : "undefined" != typeof URL && e2 instanceof URL ? n2 = e2.href : "undefined" != typeof Request && e2 instanceof Request ? n2 = e2.url : null != e2 && "function" == typeof e2.toString && (n2 = e2.toString()), !n2) return false;
2409
2423
  try {
Binary file
Binary file