@sailfish-ai/recorder 1.8.18 → 1.8.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/recorder.cjs CHANGED
@@ -465,7 +465,7 @@ function initializeWebSocket(e, a, u, m2) {
465
465
  const a2 = document.createElement("a");
466
466
  return a2.href = e2, `${a2.hostname}${a2.port ? `:${a2.port}` : ""}`;
467
467
  })(e);
468
- let b2 = `${"https:" === new URL(e).protocol ? "wss" : "ws"}://${w2}/ws/notify/?apiKey=${a}&sessionId=${u}&sender=JS%2FTS&version=1.8.18`;
468
+ let b2 = `${"https:" === new URL(e).protocol ? "wss" : "ws"}://${w2}/ws/notify/?apiKey=${a}&sessionId=${u}&sender=JS%2FTS&version=1.8.19`;
469
469
  m2 && (b2 += `&envValue=${encodeURIComponent(m2)}`);
470
470
  return oe = new U(b2, [], { connectionTimeout: 3e4 }), oe.addEventListener("open", () => {
471
471
  ne && (console.log("[Sailfish] WebSocket connection opened"), console.log("[Sailfish] Function span tracking state: " + (ce ? "ENABLED" : "DISABLED"))), (async () => {
@@ -7622,6 +7622,58 @@ function R(e, a, u) {
7622
7622
  }
7623
7623
  }
7624
7624
  var hd = ((e) => (e[e.DomContentLoaded = 0] = "DomContentLoaded", e[e.Load = 1] = "Load", e[e.FullSnapshot = 2] = "FullSnapshot", e[e.IncrementalSnapshot = 3] = "IncrementalSnapshot", e[e.Meta = 4] = "Meta", e[e.Custom = 5] = "Custom", e[e.Plugin = 6] = "Plugin", e[e.Device = 24] = "Device", e[e.SailfishCustom = 25] = "SailfishCustom", e))(hd || {});
7625
+ const fd = ["/node_modules/", "/@sailfish-ai/", "/@sailfish-rrweb/", "/dist/", "/webpack/", "/vite/", "/__vite", "/react-dom/", "/react/", "/scheduler/", "/<", "/chrome-extension://", "/extensions/"];
7626
+ function shouldSkipFrame(e) {
7627
+ return fd.some((a) => e.includes(a));
7628
+ }
7629
+ function normalizeFilePath(e) {
7630
+ let a = e;
7631
+ if (a.startsWith("file://") && (a = a.substring(7)), a.startsWith("webpack-internal:///") && (a = a.substring(20)), a.startsWith("webpack:///") && (a = a.substring(11)), a.startsWith("/@fs/") && (a = a.substring(5)), a.startsWith("http://") || a.startsWith("https://")) try {
7632
+ a = new URL(a).pathname || a, "/" === a && (a = "index.html");
7633
+ } catch {
7634
+ }
7635
+ return a;
7636
+ }
7637
+ function getCallerLocationFromTrace(e, a = 0) {
7638
+ if (!Array.isArray(e) || 0 === e.length) return [null, null];
7639
+ const u = (function parseRrwebTraceFrames(e2) {
7640
+ const a2 = [];
7641
+ for (const u2 of e2) {
7642
+ if (!u2) continue;
7643
+ const e3 = u2.startsWith("at ") ? u2.slice(3) : u2;
7644
+ let m2 = /^(.*?)\s+\((.+?):(\d+):(\d+)\)$/.exec(e3);
7645
+ m2 ? a2.push({ functionName: m2[1] || "<anonymous>", file: m2[2], line: parseInt(m2[3], 10), column: parseInt(m2[4], 10) }) : (m2 = /^(.+?):(\d+):(\d+)$/.exec(e3), m2 && a2.push({ functionName: "<anonymous>", file: m2[1], line: parseInt(m2[2], 10), column: parseInt(m2[3], 10) }));
7646
+ }
7647
+ return a2;
7648
+ })(e);
7649
+ for (let e2 = a; e2 < Math.min(u.length, a + 20); e2++) {
7650
+ const a2 = u[e2];
7651
+ if (!(a2 == null ? void 0 : a2.file)) continue;
7652
+ const m2 = normalizeFilePath(a2.file);
7653
+ if (!shouldSkipFrame(m2)) return [m2, a2.line];
7654
+ }
7655
+ return [null, null];
7656
+ }
7657
+ function getCallerLocation(e = 0) {
7658
+ const a = new Error().stack;
7659
+ if (!a) return [null, null];
7660
+ const u = (function parseV8Stack(e2) {
7661
+ if (!e2) return [];
7662
+ const a2 = e2.split("\n").slice(1), u2 = [];
7663
+ for (const e3 of a2) {
7664
+ let a3 = /at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/.exec(e3);
7665
+ a3 ? u2.push({ functionName: a3[1], file: a3[2], line: parseInt(a3[3], 10), column: parseInt(a3[4], 10) }) : (a3 = /at\s+(.+?):(\d+):(\d+)/.exec(e3), a3 && u2.push({ functionName: "<anonymous>", file: a3[1], line: parseInt(a3[2], 10), column: parseInt(a3[3], 10) }));
7666
+ }
7667
+ return u2;
7668
+ })(a), m2 = 1 + e;
7669
+ for (let e2 = m2; e2 < Math.min(u.length, m2 + 20); e2++) {
7670
+ const a2 = u[e2];
7671
+ if (!(a2 == null ? void 0 : a2.file)) continue;
7672
+ const m3 = normalizeFilePath(a2.file);
7673
+ if (!shouldSkipFrame(m3)) return [m3, a2.line];
7674
+ }
7675
+ return [null, null];
7676
+ }
7625
7677
  function suppressConsoleLogsDuringCall(e) {
7626
7678
  const a = console.log, u = console.warn, m2 = console.error;
7627
7679
  console.log = () => {
@@ -7634,7 +7686,7 @@ function suppressConsoleLogsDuringCall(e) {
7634
7686
  console.log = a, console.warn = u, console.error = m2;
7635
7687
  }
7636
7688
  }
7637
- const fd = "zendesk_chat", md = "Zendesk";
7689
+ const md = "zendesk_chat", gd = "Zendesk";
7638
7690
  function zE_safe(...e) {
7639
7691
  try {
7640
7692
  if ((function hasZendesk() {
@@ -7673,7 +7725,8 @@ function initializeDomContentEvents(e) {
7673
7725
  function initializeConsolePlugin(e, a) {
7674
7726
  const { name: u, observer: m2 } = /* @__PURE__ */ ((e2) => ({ name: "@sailfish-rrweb/rrweb/console@1", observer: R, options: e2 }))(e);
7675
7727
  m2((e2) => {
7676
- sendEvent({ type: hd.Plugin, timestamp: Date.now(), data: { plugin: u, payload: e2 }, sessionId: a, ...getUrlAndStoredUuids() });
7728
+ const m3 = e2, [w2, b2] = getCallerLocationFromTrace(m3 == null ? void 0 : m3.trace, 0), [x2, C2] = getCallerLocation(2), I2 = w2 ?? x2, E2 = b2 ?? C2, _2 = { ...m3, sourceFile: I2, sourceLine: E2 };
7729
+ sendEvent({ type: hd.Plugin, timestamp: Date.now(), data: { plugin: u, payload: _2 }, sessionId: a, ...getUrlAndStoredUuids() });
7677
7730
  }, window, e);
7678
7731
  }
7679
7732
  async function initializeRecording(e, a, u, m2, w2) {
@@ -7693,11 +7746,11 @@ async function initializeRecording(e, a, u, m2, w2) {
7693
7746
  zE_safe("messenger:set", "conversationTags", [`sailfish-session-${m2}`]);
7694
7747
  });
7695
7748
  const handleWidgetOpen = () => {
7696
- ae.addSailfishEvent(hd.SailfishCustom, { action: "customer support chat opened", element_id: fd, provider: md });
7749
+ ae.addSailfishEvent(hd.SailfishCustom, { action: "customer support chat opened", element_id: md, provider: gd });
7697
7750
  }, handleWidgetClose = () => {
7698
- ae.addSailfishEvent(hd.SailfishCustom, { action: "customer support chat closed", element_id: fd, provider: md });
7751
+ ae.addSailfishEvent(hd.SailfishCustom, { action: "customer support chat closed", element_id: md, provider: gd });
7699
7752
  }, handleUnreadMessages = (e2) => {
7700
- ae.addSailfishEvent(hd.SailfishCustom, { action: "zendesk unreadmessages", element_id: fd, provider: md });
7753
+ ae.addSailfishEvent(hd.SailfishCustom, { action: "zendesk unreadmessages", element_id: md, provider: gd });
7701
7754
  };
7702
7755
  suppressConsoleLogsDuringCall(() => {
7703
7756
  zE_safe("messenger:on", "open", handleWidgetOpen), zE_safe("messenger:on", "close", handleWidgetClose), zE_safe("messenger:on", "unreadMessages", handleUnreadMessages);
@@ -7708,8 +7761,8 @@ async function initializeRecording(e, a, u, m2, w2) {
7708
7761
  }
7709
7762
  return b2;
7710
7763
  }
7711
- let gd = null, yd = null;
7712
- const wd = readDebugFlag(), bd = ["t.co", "*.twitter.com", "*.gravatar.com", "*.googleapis.com", "*.amazonaws.com", "*.smooch.io", "*.zendesk.com", "*.zdassets.com"], Sd = [400, 403], vd = "CORS", kd = { recordCanvas: false, recordCrossOriginIframes: false, collectFonts: false, inlineImages: false, recordPassword: false, recordRealName: true, recordCreditCardInfo: false, recordSsn: false, recordDob: false, sampling: {} }, xd = { level: ["info", "log", "warn", "error"], lengthThreshold: 1e4, stringifyOptions: { stringLengthLimit: 1e3, numOfKeysLimit: 20, depthOfLimit: 4 }, logger: "console" };
7764
+ let yd = null, wd = null;
7765
+ const bd = readDebugFlag(), Sd = ["t.co", "*.twitter.com", "*.gravatar.com", "*.googleapis.com", "*.amazonaws.com", "*.smooch.io", "*.zendesk.com", "*.zdassets.com"], vd = [400, 403], kd = "CORS", xd = { recordCanvas: false, recordCrossOriginIframes: false, collectFonts: false, inlineImages: false, recordPassword: false, recordRealName: true, recordCreditCardInfo: false, recordSsn: false, recordDob: false, sampling: {} }, Cd = { level: ["info", "log", "warn", "error"], lengthThreshold: 1e4, stringifyOptions: { stringLengthLimit: 1e3, numOfKeysLimit: 20, depthOfLimit: 4 }, logger: "console" };
7713
7766
  function trackDomainChangesOnce() {
7714
7767
  const e = window.__sailfish_recorder || (window.__sailfish_recorder = {});
7715
7768
  if (e.routeWatcherIntervalId) return;
@@ -7776,7 +7829,7 @@ function shouldSkipHeadersPropagation(e, a = []) {
7776
7829
  return true;
7777
7830
  }
7778
7831
  for (const e2 of O) if (u.pathname.toLowerCase().endsWith(e2)) return true;
7779
- return !!matchUrlWithWildcard(e, [...bd, ...a]);
7832
+ return !!matchUrlWithWildcard(e, [...Sd, ...a]);
7780
7833
  }
7781
7834
  function setupFetchInterceptor(e = []) {
7782
7835
  const a = window.fetch, u = getOrSetSessionId();
@@ -7811,7 +7864,7 @@ function setupFetchInterceptor(e = []) {
7811
7864
  D2[e3] = a4;
7812
7865
  }) : D2 = { ...w3.headers }), F2 = w3.body;
7813
7866
  } catch (e3) {
7814
- wd && console.warn("[Sailfish] Failed to capture request data:", e3);
7867
+ bd && console.warn("[Sailfish] Failed to capture request data:", e3);
7815
7868
  }
7816
7869
  delete D2[b];
7817
7870
  const $2 = (_a2 = getFuncSpanHeader()) == null ? void 0 : _a2.name;
@@ -7821,16 +7874,16 @@ function setupFetchInterceptor(e = []) {
7821
7874
  const I4 = getFuncSpanHeader();
7822
7875
  if (u3 instanceof Request) {
7823
7876
  const E3 = u3.clone(), _3 = new Headers(E3.headers);
7824
- _3.set(b, `${w4}/${x4}/${C4}`), I4 && (_3.set(I4.name, I4.value), wd && console.log("[Sailfish] Added funcspan header to HTTP Request:", { url: u3.url, header: I4.name }));
7877
+ _3.set(b, `${w4}/${x4}/${C4}`), I4 && (_3.set(I4.name, I4.value), bd && console.log("[Sailfish] Added funcspan header to HTTP Request:", { url: u3.url, header: I4.name }));
7825
7878
  const O3 = new Request(E3, { headers: _3 });
7826
7879
  return await e3.call(a4, O3, m4);
7827
7880
  }
7828
7881
  {
7829
7882
  const E3 = { ...m4 }, _3 = new Headers(m4.headers || {});
7830
- return _3.set(b, `${w4}/${x4}/${C4}`), I4 && (_3.set(I4.name, I4.value), wd && console.log("[Sailfish] Added funcspan header to HTTP fetch:", { url: "string" == typeof u3 ? u3 : u3.href, header: I4.name })), E3.headers = _3, await e3.call(a4, u3, E3);
7883
+ return _3.set(b, `${w4}/${x4}/${C4}`), I4 && (_3.set(I4.name, I4.value), bd && console.log("[Sailfish] Added funcspan header to HTTP fetch:", { url: "string" == typeof u3 ? u3 : u3.href, header: I4.name })), E3.headers = _3, await e3.call(a4, u3, E3);
7831
7884
  }
7832
7885
  })(e2, a3, m3, w3, x3, E2.page_visit_uuid, I3), B2 = false;
7833
- Sd.includes($3.status) && (wd && console.log("Perform retry as status was fail:", $3), I3 = v4(), $3 = await (async function retryWithoutPropagateHeaders(e3, a4, u3, m4) {
7886
+ vd.includes($3.status) && (bd && console.log("Perform retry as status was fail:", $3), I3 = v4(), $3 = await (async function retryWithoutPropagateHeaders(e3, a4, u3, m4) {
7834
7887
  try {
7835
7888
  let m5 = u3[0], w4 = u3[1] || {};
7836
7889
  if ("string" == typeof m5 || m5 instanceof URL) {
@@ -7846,7 +7899,7 @@ function setupFetchInterceptor(e = []) {
7846
7899
  }
7847
7900
  return e3.apply(a4, u3);
7848
7901
  } catch (e4) {
7849
- throw wd && console.log(`Retry without ${b} for ${m4} also failed:`, e4), e4;
7902
+ throw bd && console.log(`Retry without ${b} for ${m4} also failed:`, e4), e4;
7850
7903
  }
7851
7904
  })(e2, a3, u2, C3), B2 = true);
7852
7905
  const U2 = Date.now(), j2 = $3.status, z2 = $3.ok, q2 = z2 ? "" : `Request Error: ${$3.statusText}`;
@@ -7855,7 +7908,7 @@ function setupFetchInterceptor(e = []) {
7855
7908
  const e3 = $3.clone();
7856
7909
  V2 = await e3.text();
7857
7910
  } catch (e3) {
7858
- wd && console.warn("[Sailfish] Failed to capture response data:", e3), V2 = null;
7911
+ bd && console.warn("[Sailfish] Failed to capture response data:", e3), V2 = null;
7859
7912
  }
7860
7913
  let H2 = null;
7861
7914
  try {
@@ -7863,12 +7916,12 @@ function setupFetchInterceptor(e = []) {
7863
7916
  H2[a4] = e3;
7864
7917
  });
7865
7918
  } catch (e3) {
7866
- wd && console.warn("[Sailfish] Failed to capture response headers:", e3), H2 = null;
7919
+ bd && console.warn("[Sailfish] Failed to capture response headers:", e3), H2 = null;
7867
7920
  }
7868
7921
  return sendEvent({ type: 27, timestamp: U2, sessionId: x3, data: { request_id: I3, session_id: x3, timestamp_start: O2, timestamp_end: U2, response_code: j2, success: z2, error: q2, method: _2, url: C3, retry_without_trace_id: B2, request_headers: D2, request_body: F2, response_headers: H2, response_body: V2 }, ...E2 }), $3;
7869
7922
  } catch (m4) {
7870
7923
  const w4 = Date.now(), b2 = false, $3 = ((_b = m4.response) == null ? void 0 : _b.status) || 500, B2 = m4.message || "Fetch request failed";
7871
- if (m4 instanceof TypeError && ((_c2 = m4 == null ? void 0 : m4.message) == null ? void 0 : _c2.toLowerCase().includes(vd.toLowerCase()))) return e2.apply(a3, u2);
7924
+ if (m4 instanceof TypeError && ((_c2 = m4 == null ? void 0 : m4.message) == null ? void 0 : _c2.toLowerCase().includes(kd.toLowerCase()))) return e2.apply(a3, u2);
7872
7925
  throw sendEvent({ type: 27, timestamp: w4, sessionId: x3, data: { request_id: I3, session_id: x3, timestamp_start: O2, timestamp_end: w4, response_code: $3, success: b2, error: B2, method: _2, url: C3, request_headers: D2, request_body: F2, response_body: null }, ...E2 }), m4;
7873
7926
  }
7874
7927
  })(a2, m2, w2, C2, I2, u, x2);
@@ -7902,7 +7955,7 @@ async function startRecording({ apiKey: e, backendApi: a = "https://api-service.
7902
7955
  })(), D2 = getOrSetSessionId(), $2 = window.__sailfish_recorder || (window.__sailfish_recorder = {});
7903
7956
  if ($2.sessionId = D2, $2.apiKey = e, $2.backendApi = a, $2.serviceAdditionalMetadata = I2, $2.initialized && $2.sessionId === D2 && $2.ws && 1 === $2.ws.readyState) trackDomainChangesOnce();
7904
7957
  else {
7905
- $2.domEventsInit || (initializeDomContentEvents(D2), $2.domEventsInit = true), $2.consoleInit || (initializeConsolePlugin(xd, D2), $2.consoleInit = true), $2.errorInit || (!(function initializeErrorInterceptor() {
7958
+ $2.domEventsInit || (initializeDomContentEvents(D2), $2.domEventsInit = true), $2.consoleInit || (initializeConsolePlugin(Cd, D2), $2.consoleInit = true), $2.errorInit || (!(function initializeErrorInterceptor() {
7906
7959
  window.addEventListener("error", (e2) => {
7907
7960
  captureError(e2.error || e2.message);
7908
7961
  }), window.addEventListener("unhandledrejection", (e2) => {
@@ -7912,10 +7965,10 @@ async function startRecording({ apiKey: e, backendApi: a = "https://api-service.
7912
7965
  X && (sessionStorage.setItem("sailfishApiKey", e2), sessionStorage.setItem("sailfishBackendApi", a2));
7913
7966
  })({ apiKey: e, backendApi: a }), trackDomainChangesOnce(), sessionStorage.setItem("sailfishApiKey", e), sessionStorage.setItem("sailfishBackendApi", a), !isFunctionSpanTrackingEnabled() || $2.ws && 1 === $2.ws.readyState || fetchFunctionSpanTrackingEnabled(e, a).then((e2) => {
7914
7967
  var _a3;
7915
- ((_a3 = e2.data) == null ? void 0 : _a3.isFunctionSpanTrackingEnabledFromApiKey) ?? false ? wd && console.log("[Sailfish] Function span tracking state validated with backend: ACTIVE") : (clearStaleFuncSpanState(), wd && console.log("[Sailfish] Cleared stale function span tracking state - backend validation shows tracking is not active"));
7968
+ ((_a3 = e2.data) == null ? void 0 : _a3.isFunctionSpanTrackingEnabledFromApiKey) ?? false ? bd && console.log("[Sailfish] Function span tracking state validated with backend: ACTIVE") : (clearStaleFuncSpanState(), bd && console.log("[Sailfish] Cleared stale function span tracking state - backend validation shows tracking is not active"));
7916
7969
  }).catch((e2) => {
7917
- wd && console.warn("[Sailfish] Failed to validate function span tracking status with backend:", e2);
7918
- }), $2.sentDoNotPropagateOnce || (sendDomainsToNotPropagateHeaderTo(e, [...m2, ...bd], a).catch((e2) => console.error("Failed to send domains to not propagate header to:", e2)), $2.sentDoNotPropagateOnce = true), $2.xhrPatched || (!(function setupXMLHttpRequestInterceptor(e2 = []) {
7970
+ bd && console.warn("[Sailfish] Failed to validate function span tracking status with backend:", e2);
7971
+ }), $2.sentDoNotPropagateOnce || (sendDomainsToNotPropagateHeaderTo(e, [...m2, ...Sd], a).catch((e2) => console.error("Failed to send domains to not propagate header to:", e2)), $2.sentDoNotPropagateOnce = true), $2.xhrPatched || (!(function setupXMLHttpRequestInterceptor(e2 = []) {
7919
7972
  const a2 = XMLHttpRequest.prototype.open, u2 = XMLHttpRequest.prototype.send, m3 = XMLHttpRequest.prototype.setRequestHeader, w3 = getOrSetSessionId();
7920
7973
  XMLHttpRequest.prototype.setRequestHeader = function(e3, a3) {
7921
7974
  return this._capturedRequestHeaders || (this._capturedRequestHeaders = {}), this._capturedRequestHeaders[e3] = a3, m3.call(this, e3, a3);
@@ -7933,9 +7986,9 @@ async function startRecording({ apiKey: e, backendApi: a = "https://api-service.
7933
7986
  }
7934
7987
  const E3 = getFuncSpanHeader();
7935
7988
  if (E3) try {
7936
- this.setRequestHeader(E3.name, E3.value), wd && console.log("[Sailfish] Added funcspan header to XMLHttpRequest:", { url: m4, header: E3.name });
7989
+ this.setRequestHeader(E3.name, E3.value), bd && console.log("[Sailfish] Added funcspan header to XMLHttpRequest:", { url: m4, header: E3.name });
7937
7990
  } catch (e3) {
7938
- wd && console.warn(`[Sailfish] Could not set funcspan header for ${m4}`, e3);
7991
+ bd && console.warn(`[Sailfish] Could not set funcspan header for ${m4}`, e3);
7939
7992
  }
7940
7993
  const _3 = Date.now();
7941
7994
  let O3 = false;
@@ -7963,7 +8016,7 @@ async function startRecording({ apiKey: e, backendApi: a = "https://api-service.
7963
8016
  2 === a5.length && (u3[a5[0]] = a5[1]);
7964
8017
  });
7965
8018
  } catch (e4) {
7966
- wd && console.warn("[Sailfish] Failed to capture XHR response headers:", e4), u3 = null;
8019
+ bd && console.warn("[Sailfish] Failed to capture XHR response headers:", e4), u3 = null;
7967
8020
  }
7968
8021
  if (e3 >= 200 && e3 < 300) emitFinished(true, e3, "", a4, u3);
7969
8022
  else {
@@ -7979,7 +8032,7 @@ async function startRecording({ apiKey: e, backendApi: a = "https://api-service.
7979
8032
  sendMessage({ type: "deviceInfo", data: { deviceInfo: { language: navigator.language, userAgent: navigator.userAgent } } });
7980
8033
  })();
7981
8034
  try {
7982
- const u2 = await fetchCaptureSettings(e, a), m3 = ((_a2 = u2.data) == null ? void 0 : _a2.captureSettingsFromApiKey) || kd;
8035
+ const u2 = await fetchCaptureSettings(e, a), m3 = ((_a2 = u2.data) == null ? void 0 : _a2.captureSettingsFromApiKey) || xd;
7983
8036
  if ($2.ws && 1 === $2.ws.readyState) return;
7984
8037
  const b2 = withAppUrlMetadata(I2), C3 = await startRecordingSession(e, D2, a, _2, O2, F2, E2, "JS/TS", b2);
7985
8038
  if ((_b = C3.data) == null ? void 0 : _b.startRecordingSession) {
@@ -8015,7 +8068,7 @@ H && (!(function sendUserDeviceUuid() {
8015
8068
  const e = document.visibilityState, a = Date.now();
8016
8069
  "visible" === e && getOrSetSessionId();
8017
8070
  try {
8018
- sendMessage({ type: "visibilityChange", data: { state: e, url: window.location.href.split("?")[0], timestamp: a, ...getUrlAndStoredUuids() } }), wd && console.log(`[Sailfish] Tab became ${e}, sent visibility change event`);
8071
+ sendMessage({ type: "visibilityChange", data: { state: e, url: window.location.href.split("?")[0], timestamp: a, ...getUrlAndStoredUuids() } }), bd && console.log(`[Sailfish] Tab became ${e}, sent visibility change event`);
8019
8072
  } catch (e2) {
8020
8073
  console.warn("[Sailfish] Failed to send visibility change event:", e2);
8021
8074
  }
@@ -8023,12 +8076,12 @@ H && (!(function sendUserDeviceUuid() {
8023
8076
  }), H && window.addEventListener("beforeunload", () => {
8024
8077
  clearPageVisitDataFromSessionStorage();
8025
8078
  });
8026
- exports.DEFAULT_CAPTURE_SETTINGS = kd, exports.DEFAULT_CONSOLE_RECORDING_SETTINGS = xd, exports.STORAGE_VERSION = 1, exports.addOrUpdateMetadata = function addOrUpdateMetadata(e) {
8079
+ exports.DEFAULT_CAPTURE_SETTINGS = xd, exports.DEFAULT_CONSOLE_RECORDING_SETTINGS = Cd, exports.STORAGE_VERSION = 1, exports.addOrUpdateMetadata = function addOrUpdateMetadata(e) {
8027
8080
  const a = { type: "addOrUpdateMetadata", metadata: e };
8028
- yd && JSON.stringify(yd) === JSON.stringify(e) || (yd = e, sendMessage(a));
8081
+ wd && JSON.stringify(wd) === JSON.stringify(e) || (wd = e, sendMessage(a));
8029
8082
  }, exports.buildBatches = buildBatches, exports.clearStaleFuncSpanState = clearStaleFuncSpanState, exports.createTriageAndIssueFromRecorder = createTriageAndIssueFromRecorder, exports.createTriageFromRecorder = createTriageFromRecorder, exports.disableFunctionSpanTracking = disableFunctionSpanTracking, exports.enableFunctionSpanTracking = enableFunctionSpanTracking, exports.eventSize = eventSize, exports.fetchCaptureSettings = fetchCaptureSettings, exports.fetchEngineeringTicketPlatformIntegrations = fetchEngineeringTicketPlatformIntegrations, exports.fetchFunctionSpanTrackingEnabled = fetchFunctionSpanTrackingEnabled, exports.flushBufferedEvents = flushBufferedEvents, exports.getFuncSpanHeader = getFuncSpanHeader, exports.getOrSetSessionId = getOrSetSessionId, exports.getUrlAndStoredUuids = getUrlAndStoredUuids, exports.identify = function identify(e, a = {}, u = false) {
8030
8083
  const m2 = { type: "identify", userId: e, traits: a };
8031
- gd && gd.userId === e && JSON.stringify(gd.traits) === JSON.stringify(a) || (gd = { userId: e, traits: a, overwrite: u }, sendMessage(m2));
8084
+ yd && yd.userId === e && JSON.stringify(yd.traits) === JSON.stringify(a) || (yd = { userId: e, traits: a, overwrite: u }, sendMessage(m2));
8032
8085
  }, exports.initRecorder = async (e) => {
8033
8086
  if ("undefined" == typeof window) return;
8034
8087
  const a = window.__sailfish_recorder || (window.__sailfish_recorder = {}), u = getOrSetSessionId();
package/dist/recorder.js CHANGED
@@ -465,7 +465,7 @@ function initializeWebSocket(e, a, u, m2) {
465
465
  const a2 = document.createElement("a");
466
466
  return a2.href = e2, `${a2.hostname}${a2.port ? `:${a2.port}` : ""}`;
467
467
  })(e);
468
- let b2 = `${"https:" === new URL(e).protocol ? "wss" : "ws"}://${w2}/ws/notify/?apiKey=${a}&sessionId=${u}&sender=JS%2FTS&version=1.8.18`;
468
+ let b2 = `${"https:" === new URL(e).protocol ? "wss" : "ws"}://${w2}/ws/notify/?apiKey=${a}&sessionId=${u}&sender=JS%2FTS&version=1.8.19`;
469
469
  m2 && (b2 += `&envValue=${encodeURIComponent(m2)}`);
470
470
  return se = new U(b2, [], { connectionTimeout: 3e4 }), se.addEventListener("open", () => {
471
471
  re && (console.log("[Sailfish] WebSocket connection opened"), console.log("[Sailfish] Function span tracking state: " + (de ? "ENABLED" : "DISABLED"))), (async () => {
@@ -7625,6 +7625,58 @@ function R(e, a, u) {
7625
7625
  }
7626
7626
  }
7627
7627
  var fd = ((e) => (e[e.DomContentLoaded = 0] = "DomContentLoaded", e[e.Load = 1] = "Load", e[e.FullSnapshot = 2] = "FullSnapshot", e[e.IncrementalSnapshot = 3] = "IncrementalSnapshot", e[e.Meta = 4] = "Meta", e[e.Custom = 5] = "Custom", e[e.Plugin = 6] = "Plugin", e[e.Device = 24] = "Device", e[e.SailfishCustom = 25] = "SailfishCustom", e))(fd || {});
7628
+ const md = ["/node_modules/", "/@sailfish-ai/", "/@sailfish-rrweb/", "/dist/", "/webpack/", "/vite/", "/__vite", "/react-dom/", "/react/", "/scheduler/", "/<", "/chrome-extension://", "/extensions/"];
7629
+ function shouldSkipFrame(e) {
7630
+ return md.some((a) => e.includes(a));
7631
+ }
7632
+ function normalizeFilePath(e) {
7633
+ let a = e;
7634
+ if (a.startsWith("file://") && (a = a.substring(7)), a.startsWith("webpack-internal:///") && (a = a.substring(20)), a.startsWith("webpack:///") && (a = a.substring(11)), a.startsWith("/@fs/") && (a = a.substring(5)), a.startsWith("http://") || a.startsWith("https://")) try {
7635
+ a = new URL(a).pathname || a, "/" === a && (a = "index.html");
7636
+ } catch {
7637
+ }
7638
+ return a;
7639
+ }
7640
+ function getCallerLocationFromTrace(e, a = 0) {
7641
+ if (!Array.isArray(e) || 0 === e.length) return [null, null];
7642
+ const u = (function parseRrwebTraceFrames(e2) {
7643
+ const a2 = [];
7644
+ for (const u2 of e2) {
7645
+ if (!u2) continue;
7646
+ const e3 = u2.startsWith("at ") ? u2.slice(3) : u2;
7647
+ let m2 = /^(.*?)\s+\((.+?):(\d+):(\d+)\)$/.exec(e3);
7648
+ m2 ? a2.push({ functionName: m2[1] || "<anonymous>", file: m2[2], line: parseInt(m2[3], 10), column: parseInt(m2[4], 10) }) : (m2 = /^(.+?):(\d+):(\d+)$/.exec(e3), m2 && a2.push({ functionName: "<anonymous>", file: m2[1], line: parseInt(m2[2], 10), column: parseInt(m2[3], 10) }));
7649
+ }
7650
+ return a2;
7651
+ })(e);
7652
+ for (let e2 = a; e2 < Math.min(u.length, a + 20); e2++) {
7653
+ const a2 = u[e2];
7654
+ if (!(a2 == null ? void 0 : a2.file)) continue;
7655
+ const m2 = normalizeFilePath(a2.file);
7656
+ if (!shouldSkipFrame(m2)) return [m2, a2.line];
7657
+ }
7658
+ return [null, null];
7659
+ }
7660
+ function getCallerLocation(e = 0) {
7661
+ const a = new Error().stack;
7662
+ if (!a) return [null, null];
7663
+ const u = (function parseV8Stack(e2) {
7664
+ if (!e2) return [];
7665
+ const a2 = e2.split("\n").slice(1), u2 = [];
7666
+ for (const e3 of a2) {
7667
+ let a3 = /at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/.exec(e3);
7668
+ a3 ? u2.push({ functionName: a3[1], file: a3[2], line: parseInt(a3[3], 10), column: parseInt(a3[4], 10) }) : (a3 = /at\s+(.+?):(\d+):(\d+)/.exec(e3), a3 && u2.push({ functionName: "<anonymous>", file: a3[1], line: parseInt(a3[2], 10), column: parseInt(a3[3], 10) }));
7669
+ }
7670
+ return u2;
7671
+ })(a), m2 = 1 + e;
7672
+ for (let e2 = m2; e2 < Math.min(u.length, m2 + 20); e2++) {
7673
+ const a2 = u[e2];
7674
+ if (!(a2 == null ? void 0 : a2.file)) continue;
7675
+ const m3 = normalizeFilePath(a2.file);
7676
+ if (!shouldSkipFrame(m3)) return [m3, a2.line];
7677
+ }
7678
+ return [null, null];
7679
+ }
7628
7680
  function suppressConsoleLogsDuringCall(e) {
7629
7681
  const a = console.log, u = console.warn, m2 = console.error;
7630
7682
  console.log = () => {
@@ -7637,7 +7689,7 @@ function suppressConsoleLogsDuringCall(e) {
7637
7689
  console.log = a, console.warn = u, console.error = m2;
7638
7690
  }
7639
7691
  }
7640
- const md = "zendesk_chat", gd = "Zendesk";
7692
+ const gd = "zendesk_chat", yd = "Zendesk";
7641
7693
  function zE_safe(...e) {
7642
7694
  try {
7643
7695
  if ((function hasZendesk() {
@@ -7676,7 +7728,8 @@ function initializeDomContentEvents(e) {
7676
7728
  function initializeConsolePlugin(e, a) {
7677
7729
  const { name: u, observer: m2 } = /* @__PURE__ */ ((e2) => ({ name: "@sailfish-rrweb/rrweb/console@1", observer: R, options: e2 }))(e);
7678
7730
  m2((e2) => {
7679
- sendEvent({ type: fd.Plugin, timestamp: Date.now(), data: { plugin: u, payload: e2 }, sessionId: a, ...getUrlAndStoredUuids() });
7731
+ const m3 = e2, [w2, b2] = getCallerLocationFromTrace(m3 == null ? void 0 : m3.trace, 0), [C2, x2] = getCallerLocation(2), I2 = w2 ?? C2, E2 = b2 ?? x2, _2 = { ...m3, sourceFile: I2, sourceLine: E2 };
7732
+ sendEvent({ type: fd.Plugin, timestamp: Date.now(), data: { plugin: u, payload: _2 }, sessionId: a, ...getUrlAndStoredUuids() });
7680
7733
  }, window, e);
7681
7734
  }
7682
7735
  async function initializeRecording(e, a, u, m2, w2) {
@@ -7696,11 +7749,11 @@ async function initializeRecording(e, a, u, m2, w2) {
7696
7749
  zE_safe("messenger:set", "conversationTags", [`sailfish-session-${m2}`]);
7697
7750
  });
7698
7751
  const handleWidgetOpen = () => {
7699
- ae.addSailfishEvent(fd.SailfishCustom, { action: "customer support chat opened", element_id: md, provider: gd });
7752
+ ae.addSailfishEvent(fd.SailfishCustom, { action: "customer support chat opened", element_id: gd, provider: yd });
7700
7753
  }, handleWidgetClose = () => {
7701
- ae.addSailfishEvent(fd.SailfishCustom, { action: "customer support chat closed", element_id: md, provider: gd });
7754
+ ae.addSailfishEvent(fd.SailfishCustom, { action: "customer support chat closed", element_id: gd, provider: yd });
7702
7755
  }, handleUnreadMessages = (e2) => {
7703
- ae.addSailfishEvent(fd.SailfishCustom, { action: "zendesk unreadmessages", element_id: md, provider: gd });
7756
+ ae.addSailfishEvent(fd.SailfishCustom, { action: "zendesk unreadmessages", element_id: gd, provider: yd });
7704
7757
  };
7705
7758
  suppressConsoleLogsDuringCall(() => {
7706
7759
  zE_safe("messenger:on", "open", handleWidgetOpen), zE_safe("messenger:on", "close", handleWidgetClose), zE_safe("messenger:on", "unreadMessages", handleUnreadMessages);
@@ -7711,19 +7764,19 @@ async function initializeRecording(e, a, u, m2, w2) {
7711
7764
  }
7712
7765
  return b2;
7713
7766
  }
7714
- let yd = null, wd = null;
7767
+ let wd = null, bd = null;
7715
7768
  function identify(e, a = {}, u = false) {
7716
7769
  const m2 = { type: "identify", userId: e, traits: a };
7717
- yd && yd.userId === e && JSON.stringify(yd.traits) === JSON.stringify(a) || (yd = { userId: e, traits: a, overwrite: u }, sendMessage(m2));
7770
+ wd && wd.userId === e && JSON.stringify(wd.traits) === JSON.stringify(a) || (wd = { userId: e, traits: a, overwrite: u }, sendMessage(m2));
7718
7771
  }
7719
7772
  function addOrUpdateMetadata(e) {
7720
7773
  const a = { type: "addOrUpdateMetadata", metadata: e };
7721
- wd && JSON.stringify(wd) === JSON.stringify(e) || (wd = e, sendMessage(a));
7774
+ bd && JSON.stringify(bd) === JSON.stringify(e) || (bd = e, sendMessage(a));
7722
7775
  }
7723
7776
  function trackingEvent(e) {
7724
7777
  sendMessage({ type: "trackingEvent", trackingData: e, timestamp: ne() });
7725
7778
  }
7726
- const bd = readDebugFlag(), Sd = ["t.co", "*.twitter.com", "*.gravatar.com", "*.googleapis.com", "*.amazonaws.com", "*.smooch.io", "*.zendesk.com", "*.zdassets.com"], vd = [400, 403], kd = "CORS", Cd = 1, xd = { recordCanvas: false, recordCrossOriginIframes: false, collectFonts: false, inlineImages: false, recordPassword: false, recordRealName: true, recordCreditCardInfo: false, recordSsn: false, recordDob: false, sampling: {} }, Id = { level: ["info", "log", "warn", "error"], lengthThreshold: 1e4, stringifyOptions: { stringLengthLimit: 1e3, numOfKeysLimit: 20, depthOfLimit: 4 }, logger: "console" };
7779
+ const Sd = readDebugFlag(), vd = ["t.co", "*.twitter.com", "*.gravatar.com", "*.googleapis.com", "*.amazonaws.com", "*.smooch.io", "*.zendesk.com", "*.zdassets.com"], kd = [400, 403], Cd = "CORS", xd = 1, Id = { recordCanvas: false, recordCrossOriginIframes: false, collectFonts: false, inlineImages: false, recordPassword: false, recordRealName: true, recordCreditCardInfo: false, recordSsn: false, recordDob: false, sampling: {} }, Md = { level: ["info", "log", "warn", "error"], lengthThreshold: 1e4, stringifyOptions: { stringLengthLimit: 1e3, numOfKeysLimit: 20, depthOfLimit: 4 }, logger: "console" };
7727
7780
  function trackDomainChangesOnce() {
7728
7781
  const e = window.__sailfish_recorder || (window.__sailfish_recorder = {});
7729
7782
  if (e.routeWatcherIntervalId) return;
@@ -7790,7 +7843,7 @@ function shouldSkipHeadersPropagation(e, a = []) {
7790
7843
  return true;
7791
7844
  }
7792
7845
  for (const e2 of O) if (u.pathname.toLowerCase().endsWith(e2)) return true;
7793
- return !!matchUrlWithWildcard(e, [...Sd, ...a]);
7846
+ return !!matchUrlWithWildcard(e, [...vd, ...a]);
7794
7847
  }
7795
7848
  function setupFetchInterceptor(e = []) {
7796
7849
  const a = window.fetch, u = getOrSetSessionId();
@@ -7825,7 +7878,7 @@ function setupFetchInterceptor(e = []) {
7825
7878
  D2[e3] = a4;
7826
7879
  }) : D2 = { ...w3.headers }), F2 = w3.body;
7827
7880
  } catch (e3) {
7828
- bd && console.warn("[Sailfish] Failed to capture request data:", e3);
7881
+ Sd && console.warn("[Sailfish] Failed to capture request data:", e3);
7829
7882
  }
7830
7883
  delete D2[b];
7831
7884
  const $2 = (_a2 = getFuncSpanHeader()) == null ? void 0 : _a2.name;
@@ -7835,16 +7888,16 @@ function setupFetchInterceptor(e = []) {
7835
7888
  const I4 = getFuncSpanHeader();
7836
7889
  if (u3 instanceof Request) {
7837
7890
  const E3 = u3.clone(), _3 = new Headers(E3.headers);
7838
- _3.set(b, `${w4}/${C4}/${x4}`), I4 && (_3.set(I4.name, I4.value), bd && console.log("[Sailfish] Added funcspan header to HTTP Request:", { url: u3.url, header: I4.name }));
7891
+ _3.set(b, `${w4}/${C4}/${x4}`), I4 && (_3.set(I4.name, I4.value), Sd && console.log("[Sailfish] Added funcspan header to HTTP Request:", { url: u3.url, header: I4.name }));
7839
7892
  const O3 = new Request(E3, { headers: _3 });
7840
7893
  return await e3.call(a4, O3, m4);
7841
7894
  }
7842
7895
  {
7843
7896
  const E3 = { ...m4 }, _3 = new Headers(m4.headers || {});
7844
- return _3.set(b, `${w4}/${C4}/${x4}`), I4 && (_3.set(I4.name, I4.value), bd && console.log("[Sailfish] Added funcspan header to HTTP fetch:", { url: "string" == typeof u3 ? u3 : u3.href, header: I4.name })), E3.headers = _3, await e3.call(a4, u3, E3);
7897
+ return _3.set(b, `${w4}/${C4}/${x4}`), I4 && (_3.set(I4.name, I4.value), Sd && console.log("[Sailfish] Added funcspan header to HTTP fetch:", { url: "string" == typeof u3 ? u3 : u3.href, header: I4.name })), E3.headers = _3, await e3.call(a4, u3, E3);
7845
7898
  }
7846
7899
  })(e2, a3, m3, w3, C3, E2.page_visit_uuid, I3), B2 = false;
7847
- vd.includes($3.status) && (bd && console.log("Perform retry as status was fail:", $3), I3 = v4(), $3 = await (async function retryWithoutPropagateHeaders(e3, a4, u3, m4) {
7900
+ kd.includes($3.status) && (Sd && console.log("Perform retry as status was fail:", $3), I3 = v4(), $3 = await (async function retryWithoutPropagateHeaders(e3, a4, u3, m4) {
7848
7901
  try {
7849
7902
  let m5 = u3[0], w4 = u3[1] || {};
7850
7903
  if ("string" == typeof m5 || m5 instanceof URL) {
@@ -7860,7 +7913,7 @@ function setupFetchInterceptor(e = []) {
7860
7913
  }
7861
7914
  return e3.apply(a4, u3);
7862
7915
  } catch (e4) {
7863
- throw bd && console.log(`Retry without ${b} for ${m4} also failed:`, e4), e4;
7916
+ throw Sd && console.log(`Retry without ${b} for ${m4} also failed:`, e4), e4;
7864
7917
  }
7865
7918
  })(e2, a3, u2, x3), B2 = true);
7866
7919
  const U2 = Date.now(), j2 = $3.status, z2 = $3.ok, q2 = z2 ? "" : `Request Error: ${$3.statusText}`;
@@ -7869,7 +7922,7 @@ function setupFetchInterceptor(e = []) {
7869
7922
  const e3 = $3.clone();
7870
7923
  V2 = await e3.text();
7871
7924
  } catch (e3) {
7872
- bd && console.warn("[Sailfish] Failed to capture response data:", e3), V2 = null;
7925
+ Sd && console.warn("[Sailfish] Failed to capture response data:", e3), V2 = null;
7873
7926
  }
7874
7927
  let H2 = null;
7875
7928
  try {
@@ -7877,12 +7930,12 @@ function setupFetchInterceptor(e = []) {
7877
7930
  H2[a4] = e3;
7878
7931
  });
7879
7932
  } catch (e3) {
7880
- bd && console.warn("[Sailfish] Failed to capture response headers:", e3), H2 = null;
7933
+ Sd && console.warn("[Sailfish] Failed to capture response headers:", e3), H2 = null;
7881
7934
  }
7882
7935
  return sendEvent({ type: 27, timestamp: U2, sessionId: C3, data: { request_id: I3, session_id: C3, timestamp_start: O2, timestamp_end: U2, response_code: j2, success: z2, error: q2, method: _2, url: x3, retry_without_trace_id: B2, request_headers: D2, request_body: F2, response_headers: H2, response_body: V2 }, ...E2 }), $3;
7883
7936
  } catch (m4) {
7884
7937
  const w4 = Date.now(), b2 = false, $3 = ((_b = m4.response) == null ? void 0 : _b.status) || 500, B2 = m4.message || "Fetch request failed";
7885
- if (m4 instanceof TypeError && ((_c2 = m4 == null ? void 0 : m4.message) == null ? void 0 : _c2.toLowerCase().includes(kd.toLowerCase()))) return e2.apply(a3, u2);
7938
+ if (m4 instanceof TypeError && ((_c2 = m4 == null ? void 0 : m4.message) == null ? void 0 : _c2.toLowerCase().includes(Cd.toLowerCase()))) return e2.apply(a3, u2);
7886
7939
  throw sendEvent({ type: 27, timestamp: w4, sessionId: C3, data: { request_id: I3, session_id: C3, timestamp_start: O2, timestamp_end: w4, response_code: $3, success: b2, error: B2, method: _2, url: x3, request_headers: D2, request_body: F2, response_body: null }, ...E2 }), m4;
7887
7940
  }
7888
7941
  })(a2, m2, w2, x2, I2, u, C2);
@@ -7916,7 +7969,7 @@ async function startRecording({ apiKey: e, backendApi: a = "https://api-service.
7916
7969
  })(), D2 = getOrSetSessionId(), $2 = window.__sailfish_recorder || (window.__sailfish_recorder = {});
7917
7970
  if ($2.sessionId = D2, $2.apiKey = e, $2.backendApi = a, $2.serviceAdditionalMetadata = I2, $2.initialized && $2.sessionId === D2 && $2.ws && 1 === $2.ws.readyState) trackDomainChangesOnce();
7918
7971
  else {
7919
- $2.domEventsInit || (initializeDomContentEvents(D2), $2.domEventsInit = true), $2.consoleInit || (initializeConsolePlugin(Id, D2), $2.consoleInit = true), $2.errorInit || (!(function initializeErrorInterceptor() {
7972
+ $2.domEventsInit || (initializeDomContentEvents(D2), $2.domEventsInit = true), $2.consoleInit || (initializeConsolePlugin(Md, D2), $2.consoleInit = true), $2.errorInit || (!(function initializeErrorInterceptor() {
7920
7973
  window.addEventListener("error", (e2) => {
7921
7974
  captureError(e2.error || e2.message);
7922
7975
  }), window.addEventListener("unhandledrejection", (e2) => {
@@ -7926,10 +7979,10 @@ async function startRecording({ apiKey: e, backendApi: a = "https://api-service.
7926
7979
  X && (sessionStorage.setItem("sailfishApiKey", e2), sessionStorage.setItem("sailfishBackendApi", a2));
7927
7980
  })({ apiKey: e, backendApi: a }), trackDomainChangesOnce(), sessionStorage.setItem("sailfishApiKey", e), sessionStorage.setItem("sailfishBackendApi", a), !isFunctionSpanTrackingEnabled() || $2.ws && 1 === $2.ws.readyState || fetchFunctionSpanTrackingEnabled(e, a).then((e2) => {
7928
7981
  var _a3;
7929
- ((_a3 = e2.data) == null ? void 0 : _a3.isFunctionSpanTrackingEnabledFromApiKey) ?? false ? bd && console.log("[Sailfish] Function span tracking state validated with backend: ACTIVE") : (clearStaleFuncSpanState(), bd && console.log("[Sailfish] Cleared stale function span tracking state - backend validation shows tracking is not active"));
7982
+ ((_a3 = e2.data) == null ? void 0 : _a3.isFunctionSpanTrackingEnabledFromApiKey) ?? false ? Sd && console.log("[Sailfish] Function span tracking state validated with backend: ACTIVE") : (clearStaleFuncSpanState(), Sd && console.log("[Sailfish] Cleared stale function span tracking state - backend validation shows tracking is not active"));
7930
7983
  }).catch((e2) => {
7931
- bd && console.warn("[Sailfish] Failed to validate function span tracking status with backend:", e2);
7932
- }), $2.sentDoNotPropagateOnce || (sendDomainsToNotPropagateHeaderTo(e, [...m2, ...Sd], a).catch((e2) => console.error("Failed to send domains to not propagate header to:", e2)), $2.sentDoNotPropagateOnce = true), $2.xhrPatched || (!(function setupXMLHttpRequestInterceptor(e2 = []) {
7984
+ Sd && console.warn("[Sailfish] Failed to validate function span tracking status with backend:", e2);
7985
+ }), $2.sentDoNotPropagateOnce || (sendDomainsToNotPropagateHeaderTo(e, [...m2, ...vd], a).catch((e2) => console.error("Failed to send domains to not propagate header to:", e2)), $2.sentDoNotPropagateOnce = true), $2.xhrPatched || (!(function setupXMLHttpRequestInterceptor(e2 = []) {
7933
7986
  const a2 = XMLHttpRequest.prototype.open, u2 = XMLHttpRequest.prototype.send, m3 = XMLHttpRequest.prototype.setRequestHeader, w3 = getOrSetSessionId();
7934
7987
  XMLHttpRequest.prototype.setRequestHeader = function(e3, a3) {
7935
7988
  return this._capturedRequestHeaders || (this._capturedRequestHeaders = {}), this._capturedRequestHeaders[e3] = a3, m3.call(this, e3, a3);
@@ -7947,9 +8000,9 @@ async function startRecording({ apiKey: e, backendApi: a = "https://api-service.
7947
8000
  }
7948
8001
  const E3 = getFuncSpanHeader();
7949
8002
  if (E3) try {
7950
- this.setRequestHeader(E3.name, E3.value), bd && console.log("[Sailfish] Added funcspan header to XMLHttpRequest:", { url: m4, header: E3.name });
8003
+ this.setRequestHeader(E3.name, E3.value), Sd && console.log("[Sailfish] Added funcspan header to XMLHttpRequest:", { url: m4, header: E3.name });
7951
8004
  } catch (e3) {
7952
- bd && console.warn(`[Sailfish] Could not set funcspan header for ${m4}`, e3);
8005
+ Sd && console.warn(`[Sailfish] Could not set funcspan header for ${m4}`, e3);
7953
8006
  }
7954
8007
  const _3 = Date.now();
7955
8008
  let O3 = false;
@@ -7977,7 +8030,7 @@ async function startRecording({ apiKey: e, backendApi: a = "https://api-service.
7977
8030
  2 === a5.length && (u3[a5[0]] = a5[1]);
7978
8031
  });
7979
8032
  } catch (e4) {
7980
- bd && console.warn("[Sailfish] Failed to capture XHR response headers:", e4), u3 = null;
8033
+ Sd && console.warn("[Sailfish] Failed to capture XHR response headers:", e4), u3 = null;
7981
8034
  }
7982
8035
  if (e3 >= 200 && e3 < 300) emitFinished(true, e3, "", a4, u3);
7983
8036
  else {
@@ -7993,7 +8046,7 @@ async function startRecording({ apiKey: e, backendApi: a = "https://api-service.
7993
8046
  sendMessage({ type: "deviceInfo", data: { deviceInfo: { language: navigator.language, userAgent: navigator.userAgent } } });
7994
8047
  })();
7995
8048
  try {
7996
- const u2 = await fetchCaptureSettings(e, a), m3 = ((_a2 = u2.data) == null ? void 0 : _a2.captureSettingsFromApiKey) || xd;
8049
+ const u2 = await fetchCaptureSettings(e, a), m3 = ((_a2 = u2.data) == null ? void 0 : _a2.captureSettingsFromApiKey) || Id;
7997
8050
  if ($2.ws && 1 === $2.ws.readyState) return;
7998
8051
  const b2 = withAppUrlMetadata(I2), x3 = await startRecordingSession(e, D2, a, _2, O2, F2, E2, "JS/TS", b2);
7999
8052
  if ((_b = x3.data) == null ? void 0 : _b.startRecordingSession) {
@@ -8029,7 +8082,7 @@ H && (!(function sendUserDeviceUuid() {
8029
8082
  const e = document.visibilityState, a = Date.now();
8030
8083
  "visible" === e && getOrSetSessionId();
8031
8084
  try {
8032
- sendMessage({ type: "visibilityChange", data: { state: e, url: window.location.href.split("?")[0], timestamp: a, ...getUrlAndStoredUuids() } }), bd && console.log(`[Sailfish] Tab became ${e}, sent visibility change event`);
8085
+ sendMessage({ type: "visibilityChange", data: { state: e, url: window.location.href.split("?")[0], timestamp: a, ...getUrlAndStoredUuids() } }), Sd && console.log(`[Sailfish] Tab became ${e}, sent visibility change event`);
8033
8086
  } catch (e2) {
8034
8087
  console.warn("[Sailfish] Failed to send visibility change event:", e2);
8035
8088
  }
@@ -8056,9 +8109,9 @@ const initRecorder = async (e) => {
8056
8109
  })), a.initPromise);
8057
8110
  };
8058
8111
  export {
8059
- xd as DEFAULT_CAPTURE_SETTINGS,
8060
- Id as DEFAULT_CONSOLE_RECORDING_SETTINGS,
8061
- Cd as STORAGE_VERSION,
8112
+ Id as DEFAULT_CAPTURE_SETTINGS,
8113
+ Md as DEFAULT_CONSOLE_RECORDING_SETTINGS,
8114
+ xd as STORAGE_VERSION,
8062
8115
  addOrUpdateMetadata,
8063
8116
  buildBatches,
8064
8117
  clearStaleFuncSpanState,
Binary file
Binary file
@@ -467,7 +467,7 @@
467
467
  const a3 = document.createElement("a");
468
468
  return a3.href = e3, `${a3.hostname}${a3.port ? `:${a3.port}` : ""}`;
469
469
  })(e2);
470
- let b2 = `${"https:" === new URL(e2).protocol ? "wss" : "ws"}://${w2}/ws/notify/?apiKey=${a2}&sessionId=${u2}&sender=JS%2FTS&version=1.8.18`;
470
+ let b2 = `${"https:" === new URL(e2).protocol ? "wss" : "ws"}://${w2}/ws/notify/?apiKey=${a2}&sessionId=${u2}&sender=JS%2FTS&version=1.8.19`;
471
471
  m2 && (b2 += `&envValue=${encodeURIComponent(m2)}`);
472
472
  return se = new j(b2, [], { connectionTimeout: 3e4 }), se.addEventListener("open", () => {
473
473
  re && (console.log("[Sailfish] WebSocket connection opened"), console.log("[Sailfish] Function span tracking state: " + (de ? "ENABLED" : "DISABLED"))), (async () => {
@@ -7624,6 +7624,58 @@
7624
7624
  }
7625
7625
  }
7626
7626
  var fd = ((e2) => (e2[e2.DomContentLoaded = 0] = "DomContentLoaded", e2[e2.Load = 1] = "Load", e2[e2.FullSnapshot = 2] = "FullSnapshot", e2[e2.IncrementalSnapshot = 3] = "IncrementalSnapshot", e2[e2.Meta = 4] = "Meta", e2[e2.Custom = 5] = "Custom", e2[e2.Plugin = 6] = "Plugin", e2[e2.Device = 24] = "Device", e2[e2.SailfishCustom = 25] = "SailfishCustom", e2))(fd || {});
7627
+ const md = ["/node_modules/", "/@sailfish-ai/", "/@sailfish-rrweb/", "/dist/", "/webpack/", "/vite/", "/__vite", "/react-dom/", "/react/", "/scheduler/", "/<", "/chrome-extension://", "/extensions/"];
7628
+ function shouldSkipFrame(e2) {
7629
+ return md.some((a2) => e2.includes(a2));
7630
+ }
7631
+ function normalizeFilePath(e2) {
7632
+ let a2 = e2;
7633
+ if (a2.startsWith("file://") && (a2 = a2.substring(7)), a2.startsWith("webpack-internal:///") && (a2 = a2.substring(20)), a2.startsWith("webpack:///") && (a2 = a2.substring(11)), a2.startsWith("/@fs/") && (a2 = a2.substring(5)), a2.startsWith("http://") || a2.startsWith("https://")) try {
7634
+ a2 = new URL(a2).pathname || a2, "/" === a2 && (a2 = "index.html");
7635
+ } catch {
7636
+ }
7637
+ return a2;
7638
+ }
7639
+ function getCallerLocationFromTrace(e2, a2 = 0) {
7640
+ if (!Array.isArray(e2) || 0 === e2.length) return [null, null];
7641
+ const u2 = (function parseRrwebTraceFrames(e3) {
7642
+ const a3 = [];
7643
+ for (const u3 of e3) {
7644
+ if (!u3) continue;
7645
+ const e4 = u3.startsWith("at ") ? u3.slice(3) : u3;
7646
+ let m2 = /^(.*?)\s+\((.+?):(\d+):(\d+)\)$/.exec(e4);
7647
+ m2 ? a3.push({ functionName: m2[1] || "<anonymous>", file: m2[2], line: parseInt(m2[3], 10), column: parseInt(m2[4], 10) }) : (m2 = /^(.+?):(\d+):(\d+)$/.exec(e4), m2 && a3.push({ functionName: "<anonymous>", file: m2[1], line: parseInt(m2[2], 10), column: parseInt(m2[3], 10) }));
7648
+ }
7649
+ return a3;
7650
+ })(e2);
7651
+ for (let e3 = a2; e3 < Math.min(u2.length, a2 + 20); e3++) {
7652
+ const a3 = u2[e3];
7653
+ if (!(a3 == null ? void 0 : a3.file)) continue;
7654
+ const m2 = normalizeFilePath(a3.file);
7655
+ if (!shouldSkipFrame(m2)) return [m2, a3.line];
7656
+ }
7657
+ return [null, null];
7658
+ }
7659
+ function getCallerLocation(e2 = 0) {
7660
+ const a2 = new Error().stack;
7661
+ if (!a2) return [null, null];
7662
+ const u2 = (function parseV8Stack(e3) {
7663
+ if (!e3) return [];
7664
+ const a3 = e3.split("\n").slice(1), u3 = [];
7665
+ for (const e4 of a3) {
7666
+ let a4 = /at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/.exec(e4);
7667
+ a4 ? u3.push({ functionName: a4[1], file: a4[2], line: parseInt(a4[3], 10), column: parseInt(a4[4], 10) }) : (a4 = /at\s+(.+?):(\d+):(\d+)/.exec(e4), a4 && u3.push({ functionName: "<anonymous>", file: a4[1], line: parseInt(a4[2], 10), column: parseInt(a4[3], 10) }));
7668
+ }
7669
+ return u3;
7670
+ })(a2), m2 = 1 + e2;
7671
+ for (let e3 = m2; e3 < Math.min(u2.length, m2 + 20); e3++) {
7672
+ const a3 = u2[e3];
7673
+ if (!(a3 == null ? void 0 : a3.file)) continue;
7674
+ const m3 = normalizeFilePath(a3.file);
7675
+ if (!shouldSkipFrame(m3)) return [m3, a3.line];
7676
+ }
7677
+ return [null, null];
7678
+ }
7627
7679
  function suppressConsoleLogsDuringCall(e2) {
7628
7680
  const a2 = console.log, u2 = console.warn, m2 = console.error;
7629
7681
  console.log = () => {
@@ -7636,7 +7688,7 @@
7636
7688
  console.log = a2, console.warn = u2, console.error = m2;
7637
7689
  }
7638
7690
  }
7639
- const md = "zendesk_chat", gd = "Zendesk";
7691
+ const gd = "zendesk_chat", yd = "Zendesk";
7640
7692
  function zE_safe(...e2) {
7641
7693
  try {
7642
7694
  if ((function hasZendesk() {
@@ -7675,7 +7727,8 @@
7675
7727
  function initializeConsolePlugin(e2, a2) {
7676
7728
  const { name: u2, observer: m2 } = /* @__PURE__ */ ((e3) => ({ name: "@sailfish-rrweb/rrweb/console@1", observer: R, options: e3 }))(e2);
7677
7729
  m2((e3) => {
7678
- sendEvent({ type: fd.Plugin, timestamp: Date.now(), data: { plugin: u2, payload: e3 }, sessionId: a2, ...getUrlAndStoredUuids() });
7730
+ const m3 = e3, [w2, b2] = getCallerLocationFromTrace(m3 == null ? void 0 : m3.trace, 0), [C2, x2] = getCallerLocation(2), I2 = w2 ?? C2, E2 = b2 ?? x2, _2 = { ...m3, sourceFile: I2, sourceLine: E2 };
7731
+ sendEvent({ type: fd.Plugin, timestamp: Date.now(), data: { plugin: u2, payload: _2 }, sessionId: a2, ...getUrlAndStoredUuids() });
7679
7732
  }, window, e2);
7680
7733
  }
7681
7734
  async function initializeRecording(e2, a2, u2, m2, w2) {
@@ -7695,11 +7748,11 @@
7695
7748
  zE_safe("messenger:set", "conversationTags", [`sailfish-session-${m2}`]);
7696
7749
  });
7697
7750
  const handleWidgetOpen = () => {
7698
- ae.addSailfishEvent(fd.SailfishCustom, { action: "customer support chat opened", element_id: md, provider: gd });
7751
+ ae.addSailfishEvent(fd.SailfishCustom, { action: "customer support chat opened", element_id: gd, provider: yd });
7699
7752
  }, handleWidgetClose = () => {
7700
- ae.addSailfishEvent(fd.SailfishCustom, { action: "customer support chat closed", element_id: md, provider: gd });
7753
+ ae.addSailfishEvent(fd.SailfishCustom, { action: "customer support chat closed", element_id: gd, provider: yd });
7701
7754
  }, handleUnreadMessages = (e3) => {
7702
- ae.addSailfishEvent(fd.SailfishCustom, { action: "zendesk unreadmessages", element_id: md, provider: gd });
7755
+ ae.addSailfishEvent(fd.SailfishCustom, { action: "zendesk unreadmessages", element_id: gd, provider: yd });
7703
7756
  };
7704
7757
  suppressConsoleLogsDuringCall(() => {
7705
7758
  zE_safe("messenger:on", "open", handleWidgetOpen), zE_safe("messenger:on", "close", handleWidgetClose), zE_safe("messenger:on", "unreadMessages", handleUnreadMessages);
@@ -7710,8 +7763,8 @@
7710
7763
  }
7711
7764
  return b2;
7712
7765
  }
7713
- let yd = null, wd = null;
7714
- const bd = readDebugFlag(), Sd = ["t.co", "*.twitter.com", "*.gravatar.com", "*.googleapis.com", "*.amazonaws.com", "*.smooch.io", "*.zendesk.com", "*.zdassets.com"], vd = [400, 403], kd = "CORS", Cd = { recordCanvas: false, recordCrossOriginIframes: false, collectFonts: false, inlineImages: false, recordPassword: false, recordRealName: true, recordCreditCardInfo: false, recordSsn: false, recordDob: false, sampling: {} }, xd = { level: ["info", "log", "warn", "error"], lengthThreshold: 1e4, stringifyOptions: { stringLengthLimit: 1e3, numOfKeysLimit: 20, depthOfLimit: 4 }, logger: "console" };
7766
+ let wd = null, bd = null;
7767
+ const Sd = readDebugFlag(), vd = ["t.co", "*.twitter.com", "*.gravatar.com", "*.googleapis.com", "*.amazonaws.com", "*.smooch.io", "*.zendesk.com", "*.zdassets.com"], kd = [400, 403], Cd = "CORS", xd = { recordCanvas: false, recordCrossOriginIframes: false, collectFonts: false, inlineImages: false, recordPassword: false, recordRealName: true, recordCreditCardInfo: false, recordSsn: false, recordDob: false, sampling: {} }, Id = { level: ["info", "log", "warn", "error"], lengthThreshold: 1e4, stringifyOptions: { stringLengthLimit: 1e3, numOfKeysLimit: 20, depthOfLimit: 4 }, logger: "console" };
7715
7768
  function trackDomainChangesOnce() {
7716
7769
  const e2 = window.__sailfish_recorder || (window.__sailfish_recorder = {});
7717
7770
  if (e2.routeWatcherIntervalId) return;
@@ -7778,7 +7831,7 @@
7778
7831
  return true;
7779
7832
  }
7780
7833
  for (const e3 of F) if (u2.pathname.toLowerCase().endsWith(e3)) return true;
7781
- return !!matchUrlWithWildcard(e2, [...Sd, ...a2]);
7834
+ return !!matchUrlWithWildcard(e2, [...vd, ...a2]);
7782
7835
  }
7783
7836
  function setupFetchInterceptor(e2 = []) {
7784
7837
  const a2 = window.fetch, u2 = getOrSetSessionId();
@@ -7813,7 +7866,7 @@
7813
7866
  D2[e4] = a5;
7814
7867
  }) : D2 = { ...w3.headers }), F2 = w3.body;
7815
7868
  } catch (e4) {
7816
- bd && console.warn("[Sailfish] Failed to capture request data:", e4);
7869
+ Sd && console.warn("[Sailfish] Failed to capture request data:", e4);
7817
7870
  }
7818
7871
  delete D2[C];
7819
7872
  const $2 = (_a2 = getFuncSpanHeader()) == null ? void 0 : _a2.name;
@@ -7823,16 +7876,16 @@
7823
7876
  const I4 = getFuncSpanHeader();
7824
7877
  if (u4 instanceof Request) {
7825
7878
  const E3 = u4.clone(), _3 = new Headers(E3.headers);
7826
- _3.set(C, `${w4}/${b4}/${x4}`), I4 && (_3.set(I4.name, I4.value), bd && console.log("[Sailfish] Added funcspan header to HTTP Request:", { url: u4.url, header: I4.name }));
7879
+ _3.set(C, `${w4}/${b4}/${x4}`), I4 && (_3.set(I4.name, I4.value), Sd && console.log("[Sailfish] Added funcspan header to HTTP Request:", { url: u4.url, header: I4.name }));
7827
7880
  const O3 = new Request(E3, { headers: _3 });
7828
7881
  return await e4.call(a5, O3, m4);
7829
7882
  }
7830
7883
  {
7831
7884
  const E3 = { ...m4 }, _3 = new Headers(m4.headers || {});
7832
- return _3.set(C, `${w4}/${b4}/${x4}`), I4 && (_3.set(I4.name, I4.value), bd && console.log("[Sailfish] Added funcspan header to HTTP fetch:", { url: "string" == typeof u4 ? u4 : u4.href, header: I4.name })), E3.headers = _3, await e4.call(a5, u4, E3);
7885
+ return _3.set(C, `${w4}/${b4}/${x4}`), I4 && (_3.set(I4.name, I4.value), Sd && console.log("[Sailfish] Added funcspan header to HTTP fetch:", { url: "string" == typeof u4 ? u4 : u4.href, header: I4.name })), E3.headers = _3, await e4.call(a5, u4, E3);
7833
7886
  }
7834
7887
  })(e3, a4, m3, w3, b3, E2.page_visit_uuid, I3), B2 = false;
7835
- vd.includes($3.status) && (bd && console.log("Perform retry as status was fail:", $3), I3 = v4(), $3 = await (async function retryWithoutPropagateHeaders(e4, a5, u4, m4) {
7888
+ kd.includes($3.status) && (Sd && console.log("Perform retry as status was fail:", $3), I3 = v4(), $3 = await (async function retryWithoutPropagateHeaders(e4, a5, u4, m4) {
7836
7889
  try {
7837
7890
  let m5 = u4[0], w4 = u4[1] || {};
7838
7891
  if ("string" == typeof m5 || m5 instanceof URL) {
@@ -7848,7 +7901,7 @@
7848
7901
  }
7849
7902
  return e4.apply(a5, u4);
7850
7903
  } catch (e5) {
7851
- throw bd && console.log(`Retry without ${C} for ${m4} also failed:`, e5), e5;
7904
+ throw Sd && console.log(`Retry without ${C} for ${m4} also failed:`, e5), e5;
7852
7905
  }
7853
7906
  })(e3, a4, u3, x3), B2 = true);
7854
7907
  const U2 = Date.now(), j2 = $3.status, z2 = $3.ok, q2 = z2 ? "" : `Request Error: ${$3.statusText}`;
@@ -7857,7 +7910,7 @@
7857
7910
  const e4 = $3.clone();
7858
7911
  V2 = await e4.text();
7859
7912
  } catch (e4) {
7860
- bd && console.warn("[Sailfish] Failed to capture response data:", e4), V2 = null;
7913
+ Sd && console.warn("[Sailfish] Failed to capture response data:", e4), V2 = null;
7861
7914
  }
7862
7915
  let H2 = null;
7863
7916
  try {
@@ -7865,12 +7918,12 @@
7865
7918
  H2[a5] = e4;
7866
7919
  });
7867
7920
  } catch (e4) {
7868
- bd && console.warn("[Sailfish] Failed to capture response headers:", e4), H2 = null;
7921
+ Sd && console.warn("[Sailfish] Failed to capture response headers:", e4), H2 = null;
7869
7922
  }
7870
7923
  return sendEvent({ type: 27, timestamp: U2, sessionId: b3, data: { request_id: I3, session_id: b3, timestamp_start: O2, timestamp_end: U2, response_code: j2, success: z2, error: q2, method: _2, url: x3, retry_without_trace_id: B2, request_headers: D2, request_body: F2, response_headers: H2, response_body: V2 }, ...E2 }), $3;
7871
7924
  } catch (m4) {
7872
7925
  const w4 = Date.now(), C2 = false, $3 = ((_b = m4.response) == null ? void 0 : _b.status) || 500, B2 = m4.message || "Fetch request failed";
7873
- if (m4 instanceof TypeError && ((_c2 = m4 == null ? void 0 : m4.message) == null ? void 0 : _c2.toLowerCase().includes(kd.toLowerCase()))) return e3.apply(a4, u3);
7926
+ if (m4 instanceof TypeError && ((_c2 = m4 == null ? void 0 : m4.message) == null ? void 0 : _c2.toLowerCase().includes(Cd.toLowerCase()))) return e3.apply(a4, u3);
7874
7927
  throw sendEvent({ type: 27, timestamp: w4, sessionId: b3, data: { request_id: I3, session_id: b3, timestamp_start: O2, timestamp_end: w4, response_code: $3, success: C2, error: B2, method: _2, url: x3, request_headers: D2, request_body: F2, response_body: null }, ...E2 }), m4;
7875
7928
  }
7876
7929
  })(a3, m2, w2, x2, I2, u2, b2);
@@ -7904,7 +7957,7 @@
7904
7957
  })(), D2 = getOrSetSessionId(), $2 = window.__sailfish_recorder || (window.__sailfish_recorder = {});
7905
7958
  if ($2.sessionId = D2, $2.apiKey = e2, $2.backendApi = a2, $2.serviceAdditionalMetadata = I2, $2.initialized && $2.sessionId === D2 && $2.ws && 1 === $2.ws.readyState) trackDomainChangesOnce();
7906
7959
  else {
7907
- $2.domEventsInit || (initializeDomContentEvents(D2), $2.domEventsInit = true), $2.consoleInit || (initializeConsolePlugin(xd, D2), $2.consoleInit = true), $2.errorInit || (!(function initializeErrorInterceptor() {
7960
+ $2.domEventsInit || (initializeDomContentEvents(D2), $2.domEventsInit = true), $2.consoleInit || (initializeConsolePlugin(Id, D2), $2.consoleInit = true), $2.errorInit || (!(function initializeErrorInterceptor() {
7908
7961
  window.addEventListener("error", (e3) => {
7909
7962
  captureError(e3.error || e3.message);
7910
7963
  }), window.addEventListener("unhandledrejection", (e3) => {
@@ -7914,10 +7967,10 @@
7914
7967
  Q && (sessionStorage.setItem("sailfishApiKey", e3), sessionStorage.setItem("sailfishBackendApi", a3));
7915
7968
  })({ apiKey: e2, backendApi: a2 }), trackDomainChangesOnce(), sessionStorage.setItem("sailfishApiKey", e2), sessionStorage.setItem("sailfishBackendApi", a2), !isFunctionSpanTrackingEnabled() || $2.ws && 1 === $2.ws.readyState || fetchFunctionSpanTrackingEnabled(e2, a2).then((e3) => {
7916
7969
  var _a3;
7917
- ((_a3 = e3.data) == null ? void 0 : _a3.isFunctionSpanTrackingEnabledFromApiKey) ?? false ? bd && console.log("[Sailfish] Function span tracking state validated with backend: ACTIVE") : (clearStaleFuncSpanState(), bd && console.log("[Sailfish] Cleared stale function span tracking state - backend validation shows tracking is not active"));
7970
+ ((_a3 = e3.data) == null ? void 0 : _a3.isFunctionSpanTrackingEnabledFromApiKey) ?? false ? Sd && console.log("[Sailfish] Function span tracking state validated with backend: ACTIVE") : (clearStaleFuncSpanState(), Sd && console.log("[Sailfish] Cleared stale function span tracking state - backend validation shows tracking is not active"));
7918
7971
  }).catch((e3) => {
7919
- bd && console.warn("[Sailfish] Failed to validate function span tracking status with backend:", e3);
7920
- }), $2.sentDoNotPropagateOnce || (sendDomainsToNotPropagateHeaderTo(e2, [...m2, ...Sd], a2).catch((e3) => console.error("Failed to send domains to not propagate header to:", e3)), $2.sentDoNotPropagateOnce = true), $2.xhrPatched || (!(function setupXMLHttpRequestInterceptor(e3 = []) {
7972
+ Sd && console.warn("[Sailfish] Failed to validate function span tracking status with backend:", e3);
7973
+ }), $2.sentDoNotPropagateOnce || (sendDomainsToNotPropagateHeaderTo(e2, [...m2, ...vd], a2).catch((e3) => console.error("Failed to send domains to not propagate header to:", e3)), $2.sentDoNotPropagateOnce = true), $2.xhrPatched || (!(function setupXMLHttpRequestInterceptor(e3 = []) {
7921
7974
  const a3 = XMLHttpRequest.prototype.open, u3 = XMLHttpRequest.prototype.send, m3 = XMLHttpRequest.prototype.setRequestHeader, w3 = getOrSetSessionId();
7922
7975
  XMLHttpRequest.prototype.setRequestHeader = function(e4, a4) {
7923
7976
  return this._capturedRequestHeaders || (this._capturedRequestHeaders = {}), this._capturedRequestHeaders[e4] = a4, m3.call(this, e4, a4);
@@ -7935,9 +7988,9 @@
7935
7988
  }
7936
7989
  const E3 = getFuncSpanHeader();
7937
7990
  if (E3) try {
7938
- this.setRequestHeader(E3.name, E3.value), bd && console.log("[Sailfish] Added funcspan header to XMLHttpRequest:", { url: m4, header: E3.name });
7991
+ this.setRequestHeader(E3.name, E3.value), Sd && console.log("[Sailfish] Added funcspan header to XMLHttpRequest:", { url: m4, header: E3.name });
7939
7992
  } catch (e4) {
7940
- bd && console.warn(`[Sailfish] Could not set funcspan header for ${m4}`, e4);
7993
+ Sd && console.warn(`[Sailfish] Could not set funcspan header for ${m4}`, e4);
7941
7994
  }
7942
7995
  const _3 = Date.now();
7943
7996
  let O3 = false;
@@ -7965,7 +8018,7 @@
7965
8018
  2 === a6.length && (u4[a6[0]] = a6[1]);
7966
8019
  });
7967
8020
  } catch (e5) {
7968
- bd && console.warn("[Sailfish] Failed to capture XHR response headers:", e5), u4 = null;
8021
+ Sd && console.warn("[Sailfish] Failed to capture XHR response headers:", e5), u4 = null;
7969
8022
  }
7970
8023
  if (e4 >= 200 && e4 < 300) emitFinished(true, e4, "", a5, u4);
7971
8024
  else {
@@ -7981,7 +8034,7 @@
7981
8034
  sendMessage({ type: "deviceInfo", data: { deviceInfo: { language: navigator.language, userAgent: navigator.userAgent } } });
7982
8035
  })();
7983
8036
  try {
7984
- const u3 = await fetchCaptureSettings(e2, a2), m3 = ((_a2 = u3.data) == null ? void 0 : _a2.captureSettingsFromApiKey) || Cd;
8037
+ const u3 = await fetchCaptureSettings(e2, a2), m3 = ((_a2 = u3.data) == null ? void 0 : _a2.captureSettingsFromApiKey) || xd;
7985
8038
  if ($2.ws && 1 === $2.ws.readyState) return;
7986
8039
  const C2 = withAppUrlMetadata(I2), x3 = await startRecordingSession(e2, D2, a2, _2, O2, F2, E2, "JS/TS", C2);
7987
8040
  if ((_b = x3.data) == null ? void 0 : _b.startRecordingSession) {
@@ -8017,7 +8070,7 @@
8017
8070
  const e2 = document.visibilityState, a2 = Date.now();
8018
8071
  "visible" === e2 && getOrSetSessionId();
8019
8072
  try {
8020
- sendMessage({ type: "visibilityChange", data: { state: e2, url: window.location.href.split("?")[0], timestamp: a2, ...getUrlAndStoredUuids() } }), bd && console.log(`[Sailfish] Tab became ${e2}, sent visibility change event`);
8073
+ sendMessage({ type: "visibilityChange", data: { state: e2, url: window.location.href.split("?")[0], timestamp: a2, ...getUrlAndStoredUuids() } }), Sd && console.log(`[Sailfish] Tab became ${e2}, sent visibility change event`);
8021
8074
  } catch (e3) {
8022
8075
  console.warn("[Sailfish] Failed to send visibility change event:", e3);
8023
8076
  }
@@ -8025,12 +8078,12 @@
8025
8078
  }), J && window.addEventListener("beforeunload", () => {
8026
8079
  clearPageVisitDataFromSessionStorage();
8027
8080
  });
8028
- e.DEFAULT_CAPTURE_SETTINGS = Cd, e.DEFAULT_CONSOLE_RECORDING_SETTINGS = xd, e.STORAGE_VERSION = 1, e.addOrUpdateMetadata = function addOrUpdateMetadata(e2) {
8081
+ e.DEFAULT_CAPTURE_SETTINGS = xd, e.DEFAULT_CONSOLE_RECORDING_SETTINGS = Id, e.STORAGE_VERSION = 1, e.addOrUpdateMetadata = function addOrUpdateMetadata(e2) {
8029
8082
  const a2 = { type: "addOrUpdateMetadata", metadata: e2 };
8030
- wd && JSON.stringify(wd) === JSON.stringify(e2) || (wd = e2, sendMessage(a2));
8083
+ bd && JSON.stringify(bd) === JSON.stringify(e2) || (bd = e2, sendMessage(a2));
8031
8084
  }, e.buildBatches = buildBatches, e.clearStaleFuncSpanState = clearStaleFuncSpanState, e.createTriageAndIssueFromRecorder = createTriageAndIssueFromRecorder, e.createTriageFromRecorder = createTriageFromRecorder, e.disableFunctionSpanTracking = disableFunctionSpanTracking, e.enableFunctionSpanTracking = enableFunctionSpanTracking, e.eventSize = eventSize, e.fetchCaptureSettings = fetchCaptureSettings, e.fetchEngineeringTicketPlatformIntegrations = fetchEngineeringTicketPlatformIntegrations, e.fetchFunctionSpanTrackingEnabled = fetchFunctionSpanTrackingEnabled, e.flushBufferedEvents = flushBufferedEvents, e.getFuncSpanHeader = getFuncSpanHeader, e.getOrSetSessionId = getOrSetSessionId, e.getUrlAndStoredUuids = getUrlAndStoredUuids, e.identify = function identify(e2, a2 = {}, u2 = false) {
8032
8085
  const m2 = { type: "identify", userId: e2, traits: a2 };
8033
- yd && yd.userId === e2 && JSON.stringify(yd.traits) === JSON.stringify(a2) || (yd = { userId: e2, traits: a2, overwrite: u2 }, sendMessage(m2));
8086
+ wd && wd.userId === e2 && JSON.stringify(wd.traits) === JSON.stringify(a2) || (wd = { userId: e2, traits: a2, overwrite: u2 }, sendMessage(m2));
8034
8087
  }, e.initRecorder = async (e2) => {
8035
8088
  if ("undefined" == typeof window) return;
8036
8089
  const a2 = window.__sailfish_recorder || (window.__sailfish_recorder = {}), u2 = getOrSetSessionId();
package/dist/recording.js CHANGED
@@ -3,6 +3,7 @@ import { getRecordConsolePlugin, } from "@sailfish-rrweb/rrweb-plugin-console-re
3
3
  // import { NetworkRecordOptions } from "@sailfish-rrweb/rrweb-plugin-network-record";
4
4
  import { EventType } from "@sailfish-rrweb/types";
5
5
  import { Complete, DomContentEventId, DomContentSource, Loading, } from "./constants";
6
+ import { getCallerLocation, getCallerLocationFromTrace, } from "./sourceLocation";
6
7
  import suppressConsoleLogsDuringCall from "./suppressConsoleLogsDuringCall";
7
8
  import { initializeWebSocket, sendEvent } from "./websocket";
8
9
  const MASK_CLASS = "sailfishSanitize";
@@ -140,12 +141,24 @@ export function initializeDomContentEvents(sessionId) {
140
141
  export function initializeConsolePlugin(consoleRecordSettings, sessionId) {
141
142
  const { name, observer } = getRecordConsolePlugin(consoleRecordSettings);
142
143
  observer((payload) => {
144
+ const anyPayload = payload;
145
+ // rrweb console record plugin includes `trace` for logs (stack frames). :contentReference[oaicite:1]{index=1}
146
+ const [sourceFileFromTrace, sourceLineFromTrace] = getCallerLocationFromTrace(anyPayload?.trace, 0);
147
+ // Fallback (less accurate when inside wrappers)
148
+ const [sourceFileFallback, sourceLineFallback] = getCallerLocation(2);
149
+ const sourceFile = sourceFileFromTrace ?? sourceFileFallback;
150
+ const sourceLine = sourceLineFromTrace ?? sourceLineFallback;
151
+ const enhancedPayload = {
152
+ ...anyPayload,
153
+ sourceFile,
154
+ sourceLine,
155
+ };
143
156
  const eventData = {
144
157
  type: EventType.Plugin,
145
158
  timestamp: Date.now(),
146
159
  data: {
147
160
  plugin: name,
148
- payload,
161
+ payload: enhancedPayload, // Use enhanced payload
149
162
  },
150
163
  sessionId: sessionId,
151
164
  ...getUrlAndStoredUuids(),
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Browser-compatible source location capture for console logs.
3
+ *
4
+ * Prefer using rrweb's captured "trace" (stack) when available:
5
+ * - It is captured at the moment console.X was invoked (best chance to get true callsite)
6
+ * - It is often already source-mapped by the browser (webpack-internal:///src/..., etc.)
7
+ */
8
+ const SKIP_PATTERNS = [
9
+ "/node_modules/",
10
+ "/@sailfish-ai/",
11
+ "/@sailfish-rrweb/",
12
+ "/dist/",
13
+ "/webpack/",
14
+ "/vite/",
15
+ "/__vite",
16
+ "/react-dom/",
17
+ "/react/",
18
+ "/scheduler/",
19
+ "/<",
20
+ "/chrome-extension://",
21
+ "/extensions/",
22
+ ];
23
+ const MAX_FRAME_WALK = 20;
24
+ function shouldSkipFrame(file) {
25
+ return SKIP_PATTERNS.some((pattern) => file.includes(pattern));
26
+ }
27
+ /**
28
+ * Normalize file path for browser environment.
29
+ */
30
+ function normalizeFilePath(rawPath) {
31
+ let path = rawPath;
32
+ // Some stacks include "eval at ..." or "blob:" — keep but normalize what we can.
33
+ // file:// URLs (local dev)
34
+ if (path.startsWith("file://")) {
35
+ path = path.substring("file://".length);
36
+ }
37
+ // webpack internal urls
38
+ if (path.startsWith("webpack-internal:///")) {
39
+ path = path.substring("webpack-internal:///".length);
40
+ }
41
+ if (path.startsWith("webpack:///")) {
42
+ path = path.substring("webpack:///".length);
43
+ }
44
+ // Vite sometimes uses "/@fs/..." to represent absolute paths
45
+ if (path.startsWith("/@fs/")) {
46
+ path = path.substring("/@fs/".length);
47
+ }
48
+ // http(s) URLs -> pathname
49
+ if (path.startsWith("http://") || path.startsWith("https://")) {
50
+ try {
51
+ const url = new URL(path);
52
+ path = url.pathname || path;
53
+ if (path === "/")
54
+ path = "index.html";
55
+ }
56
+ catch {
57
+ // ignore
58
+ }
59
+ }
60
+ return path;
61
+ }
62
+ /**
63
+ * Parse V8 stack lines (Error.stack format).
64
+ */
65
+ function parseV8Stack(stack) {
66
+ if (!stack)
67
+ return [];
68
+ const stackLines = stack.split("\n").slice(1);
69
+ const frames = [];
70
+ for (const line of stackLines) {
71
+ let match = /at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/.exec(line);
72
+ if (match) {
73
+ frames.push({
74
+ functionName: match[1],
75
+ file: match[2],
76
+ line: parseInt(match[3], 10),
77
+ column: parseInt(match[4], 10),
78
+ });
79
+ continue;
80
+ }
81
+ match = /at\s+(.+?):(\d+):(\d+)/.exec(line);
82
+ if (match) {
83
+ frames.push({
84
+ functionName: "<anonymous>",
85
+ file: match[1],
86
+ line: parseInt(match[2], 10),
87
+ column: parseInt(match[3], 10),
88
+ });
89
+ }
90
+ }
91
+ return frames;
92
+ }
93
+ /**
94
+ * rrweb "trace" entries are typically stack-frame-like strings.
95
+ * They may look like:
96
+ * - "myFn (http://localhost:5173/src/App.tsx:42:17)"
97
+ * - "http://localhost:5173/src/App.tsx:42:17"
98
+ * - "myFn (webpack-internal:///./src/App.tsx:42:17)"
99
+ *
100
+ * We'll parse these into StackFrame and then apply your skip rules.
101
+ */
102
+ function parseRrwebTraceFrames(trace) {
103
+ const frames = [];
104
+ for (const entry of trace) {
105
+ if (!entry)
106
+ continue;
107
+ // Trim leading "at " if present
108
+ const line = entry.startsWith("at ") ? entry.slice(3) : entry;
109
+ // "fn (file:line:col)"
110
+ let match = /^(.*?)\s+\((.+?):(\d+):(\d+)\)$/.exec(line);
111
+ if (match) {
112
+ frames.push({
113
+ functionName: match[1] || "<anonymous>",
114
+ file: match[2],
115
+ line: parseInt(match[3], 10),
116
+ column: parseInt(match[4], 10),
117
+ });
118
+ continue;
119
+ }
120
+ // "file:line:col"
121
+ match = /^(.+?):(\d+):(\d+)$/.exec(line);
122
+ if (match) {
123
+ frames.push({
124
+ functionName: "<anonymous>",
125
+ file: match[1],
126
+ line: parseInt(match[2], 10),
127
+ column: parseInt(match[3], 10),
128
+ });
129
+ continue;
130
+ }
131
+ // If it doesn't match, ignore it (some environments add noise)
132
+ }
133
+ return frames;
134
+ }
135
+ /**
136
+ * Prefer rrweb's trace when provided.
137
+ * Returns first "user" frame after filtering.
138
+ */
139
+ export function getCallerLocationFromTrace(trace, skipFrames = 0) {
140
+ if (!Array.isArray(trace) || trace.length === 0)
141
+ return [null, null];
142
+ const frames = parseRrwebTraceFrames(trace);
143
+ for (let i = skipFrames; i < Math.min(frames.length, skipFrames + MAX_FRAME_WALK); i++) {
144
+ const frame = frames[i];
145
+ if (!frame?.file)
146
+ continue;
147
+ const normalized = normalizeFilePath(frame.file);
148
+ if (shouldSkipFrame(normalized))
149
+ continue;
150
+ return [normalized, frame.line];
151
+ }
152
+ return [null, null];
153
+ }
154
+ /**
155
+ * Fallback: compute location from current stack.
156
+ * This is less reliable when called inside wrappers.
157
+ */
158
+ export function getCallerLocation(skipFrames = 0) {
159
+ const err = new Error();
160
+ const stack = err.stack;
161
+ if (!stack)
162
+ return [null, null];
163
+ const frames = parseV8Stack(stack);
164
+ const frameOffset = 1 + skipFrames;
165
+ for (let i = frameOffset; i < Math.min(frames.length, frameOffset + MAX_FRAME_WALK); i++) {
166
+ const frame = frames[i];
167
+ if (!frame?.file)
168
+ continue;
169
+ const normalized = normalizeFilePath(frame.file);
170
+ if (shouldSkipFrame(normalized))
171
+ continue;
172
+ return [normalized, frame.line];
173
+ }
174
+ return [null, null];
175
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Browser-compatible source location capture for console logs.
3
+ *
4
+ * Prefer using rrweb's captured "trace" (stack) when available:
5
+ * - It is captured at the moment console.X was invoked (best chance to get true callsite)
6
+ * - It is often already source-mapped by the browser (webpack-internal:///src/..., etc.)
7
+ */
8
+ /**
9
+ * Prefer rrweb's trace when provided.
10
+ * Returns first "user" frame after filtering.
11
+ */
12
+ export declare function getCallerLocationFromTrace(trace: unknown, skipFrames?: number): [string | null, number | null];
13
+ /**
14
+ * Fallback: compute location from current stack.
15
+ * This is less reliable when called inside wrappers.
16
+ */
17
+ export declare function getCallerLocation(skipFrames?: number): [string | null, number | null];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sailfish-ai/recorder",
3
- "version": "1.8.18",
3
+ "version": "1.8.19",
4
4
  "publishPublicly": true,
5
5
  "type": "module",
6
6
  "main": "dist/recorder.cjs",