@sailfish-ai/recorder 1.0.3 → 1.0.5

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/graphql.js CHANGED
@@ -52,3 +52,8 @@ export function startRecordingSession(apiKey, recordingId, backendApi) {
52
52
  backendApi,
53
53
  });
54
54
  }
55
+ export function sendDomainsToNotPropagateHeaderTo(apiKey, domains, backendApi) {
56
+ return sendGraphQLRequest("DomainsToNotPassHeaderTo", `mutation DomainsToNotPassHeaderTo($apiKey: String!, $domains: [String!]!) {
57
+ domainsToNotPassHeaderTo(apiKey: $apiKey, domains: $domains)
58
+ }`, { apiKey, domains, backendApi });
59
+ }
package/dist/index.js CHANGED
@@ -1,10 +1,14 @@
1
+ import { parse as parseDomain } from "tldts"; // Importing tldts
1
2
  import { v4 as uuidv4 } from "uuid";
2
3
  import { gatherAndCacheDeviceInfo } from "./deviceInfo";
3
4
  import { sendRecordingEvents } from "./eventCache";
4
- import { fetchCaptureSettings, startRecordingSession } from "./graphql";
5
+ import { fetchCaptureSettings, sendDomainsToNotPropagateHeaderTo, startRecordingSession, } from "./graphql";
5
6
  import { initializeRecording } from "./recording";
6
- // Default Settings
7
- export const DEFAULT_DOMAINS_TO_IGNORE = [];
7
+ // Default list of domains to ignore
8
+ const DOMAINS_TO_NOT_PROPAGATE_HEADER_TO_DEFAULT = [
9
+ "identitytoolkit.googleapis.com",
10
+ ];
11
+ const DOMAINS_TO_NOT_RECORD_NETWORK_REQUESTS_TO = [];
8
12
  export const DEFAULT_CAPTURE_SETTINGS = {
9
13
  recordCanvas: false,
10
14
  recordCrossOriginIframes: false,
@@ -30,8 +34,8 @@ export const DEFAULT_CONSOLE_RECORDING_SETTINGS = {
30
34
  export const DEFAULT_NETWORK_CAPTURE_SETTINGS = {
31
35
  initiatorTypes: ["fetch", "xmlhttprequest"],
32
36
  ignoreRequestFn: (request) => {
33
- const domain = extractHostname(request.url);
34
- return DEFAULT_DOMAINS_TO_IGNORE.includes(domain);
37
+ const domain = getEffectiveDomain(request.url);
38
+ return DOMAINS_TO_NOT_RECORD_NETWORK_REQUESTS_TO.includes(domain);
35
39
  },
36
40
  recordHeaders: true,
37
41
  ignoreHeaders: {
@@ -45,6 +49,14 @@ export const DEFAULT_NETWORK_CAPTURE_SETTINGS = {
45
49
  recordBody: true,
46
50
  recordInitialRequests: false,
47
51
  };
52
+ // Function to strip 'www.' and get the effective domain from a URL using tldts
53
+ function getEffectiveDomain(url) {
54
+ const parsed = parseDomain(url);
55
+ const domain = parsed.subdomain !== ""
56
+ ? `${parsed.subdomain}.${parsed.domain}`
57
+ : parsed.domain;
58
+ return domain.startsWith("www.") ? domain.slice(4) : domain;
59
+ }
48
60
  // Functions
49
61
  // Function to get the current sessionId from sessionStorage
50
62
  function getOrSetSessionId(forceNew = false) {
@@ -71,27 +83,37 @@ function storeCredentialsAndConnection({ apiKey, backendApi, }) {
71
83
  sessionStorage.setItem("sailfishBackendApi", backendApi);
72
84
  }
73
85
  // Intercepting XMLHttpRequest
74
- (function () {
86
+ function setupXMLHttpRequestInterceptor(domainsToNotPropagateHeaderTo) {
75
87
  const originalOpen = XMLHttpRequest.prototype.open;
76
88
  const originalSend = XMLHttpRequest.prototype.send;
77
89
  const sessionId = getOrSetSessionId();
90
+ const combinedIgnoreDomains = [
91
+ ...DOMAINS_TO_NOT_PROPAGATE_HEADER_TO_DEFAULT,
92
+ ...domainsToNotPropagateHeaderTo,
93
+ ].map((domain) => (domain.startsWith("www.") ? domain.slice(4) : domain)); // Remove 'www.' from ignore domains
78
94
  XMLHttpRequest.prototype.open = function (...args) {
79
95
  this._url = args[1]; // Store the request URL
80
96
  originalOpen.apply(this, args);
81
97
  };
82
98
  XMLHttpRequest.prototype.send = function (...args) {
83
- if (sessionId) {
99
+ const domain = getEffectiveDomain(this._url); // Use tldts to get the domain
100
+ if (sessionId && !combinedIgnoreDomains.includes(domain)) {
84
101
  this.setRequestHeader("X-Sf3-Rid", sessionId);
85
102
  }
86
103
  originalSend.apply(this, args);
87
104
  };
88
- })();
105
+ }
89
106
  // Intercepting fetch API
90
- (function () {
107
+ function setupFetchInterceptor(domainsToNotPropagateHeaderTo) {
91
108
  const originalFetch = window.fetch;
92
109
  const sessionId = getOrSetSessionId();
110
+ const combinedIgnoreDomains = [
111
+ ...DOMAINS_TO_NOT_PROPAGATE_HEADER_TO_DEFAULT,
112
+ ...domainsToNotPropagateHeaderTo,
113
+ ].map((domain) => (domain.startsWith("www.") ? domain.slice(4) : domain)); // Remove 'www.' from ignore domains
93
114
  window.fetch = async function (input, init = {}) {
94
- if (sessionId) {
115
+ const domain = typeof input === "string" ? getEffectiveDomain(input) : "";
116
+ if (sessionId && !combinedIgnoreDomains.includes(domain)) {
95
117
  init.headers = {
96
118
  ...init.headers,
97
119
  "X-Sf3-Rid": sessionId,
@@ -99,11 +121,18 @@ function storeCredentialsAndConnection({ apiKey, backendApi, }) {
99
121
  }
100
122
  return originalFetch(input, init);
101
123
  };
102
- })();
124
+ }
103
125
  // Main Recording Function
104
- export async function startRecording({ apiKey, backendApi, }) {
126
+ export async function startRecording({ apiKey, backendApi, domainsToNotPropagateHeaderTo = [], }) {
105
127
  let sessionId = getOrSetSessionId();
106
128
  storeCredentialsAndConnection({ apiKey, backendApi });
129
+ // Non-blocking GraphQL request to send the domains if provided
130
+ if (domainsToNotPropagateHeaderTo.length > 0) {
131
+ sendDomainsToNotPropagateHeaderTo(apiKey, domainsToNotPropagateHeaderTo, backendApi).catch((error) => console.error("Failed to send domains to not propagate header to:", error));
132
+ }
133
+ // Setup interceptors with custom ignore domains
134
+ setupXMLHttpRequestInterceptor(domainsToNotPropagateHeaderTo);
135
+ setupFetchInterceptor(domainsToNotPropagateHeaderTo);
107
136
  gatherAndCacheDeviceInfo();
108
137
  try {
109
138
  const captureSettingsResponse = await fetchCaptureSettings(apiKey, backendApi);
@@ -111,15 +140,11 @@ export async function startRecording({ apiKey, backendApi, }) {
111
140
  DEFAULT_CAPTURE_SETTINGS;
112
141
  const sessionResponse = await startRecordingSession(apiKey, sessionId, backendApi);
113
142
  if (sessionResponse.data?.startRecordingSession) {
114
- // Initialize recording
115
143
  const websocket = await initializeRecording(captureSettings, DEFAULT_CONSOLE_RECORDING_SETTINGS, DEFAULT_NETWORK_CAPTURE_SETTINGS, backendApi, apiKey, sessionId);
116
- // Set up an interval to send recording events
117
144
  setInterval(() => {
118
145
  if (websocket && websocket.readyState === WebSocket.OPEN) {
119
146
  sendRecordingEvents(websocket);
120
147
  }
121
- else {
122
- }
123
148
  }, 10000);
124
149
  }
125
150
  else {
@@ -130,12 +155,6 @@ export async function startRecording({ apiKey, backendApi, }) {
130
155
  console.error("Error starting recording:", error);
131
156
  }
132
157
  }
133
- function extractHostname(url) {
134
- let hostname = url.indexOf("//") > -1 ? url.split("/")[2] : url.split("/")[0];
135
- hostname = hostname.split(":")[0];
136
- hostname = hostname.split("?")[0];
137
- return hostname;
138
- }
139
158
  // Re-export from other modules
140
159
  export * from "./eventCache";
141
160
  export * from "./graphql";
package/dist/recording.js CHANGED
@@ -3,7 +3,6 @@ import { getRecordConsolePlugin, } from "@sailfish-rrweb/rrweb-plugin-console-re
3
3
  import { cacheEvents, sendRecordingEvents } from "./eventCache";
4
4
  import { initializeWebSocket } from "./websocket";
5
5
  const MASK_CLASS = "sailfishSanitize";
6
- const DEFAULT_DOMAINS_TO_IGNORE = [];
7
6
  function maskInputFn(text, node) {
8
7
  // Exclude input[type=hidden] fields
9
8
  if (node.type === "hidden") {