@sailfish-ai/recorder 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,3 @@
1
1
  # JS/TS Record-Only Package
2
2
 
3
- ## TODO - Rename all Sailfish to GrepLion!
3
+ ## TODO - Rename all Sailfish to GrepLion
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ import { fetchCaptureSettings, sendDomainsToNotPropagateHeaderTo, startRecording
6
6
  import { initializeRecording } from "./recording";
7
7
  // Default list of domains to ignore
8
8
  const DOMAINS_TO_NOT_PROPAGATE_HEADER_TO_DEFAULT = [
9
+ "t.co",
9
10
  "identitytoolkit.googleapis.com",
10
11
  ];
11
12
  const DOMAINS_TO_NOT_RECORD_NETWORK_REQUESTS_TO = [];
@@ -92,7 +93,12 @@ function storeCredentialsAndConnection({ apiKey, backendApi, }) {
92
93
  }
93
94
  // Utility function to match domains or paths with wildcard support
94
95
  export function matchUrlWithWildcard(url, patterns) {
95
- const strippedUrl = url.replace(/^[a-zA-Z]+:\/\//, "");
96
+ if (!url || typeof url !== "string") {
97
+ throw new Error("Invalid URL input");
98
+ }
99
+ // Ensure the URL has a protocol. If not, prepend "http://"
100
+ const formattedUrl = url.match(/^[a-zA-Z]+:\/\//) ? url : `http://${url}`;
101
+ const strippedUrl = formattedUrl.replace(/^[a-zA-Z]+:\/\//, "");
96
102
  const parsedUrl = new URL("http://" + strippedUrl); // Add a dummy protocol for URL parsing
97
103
  const { hostname, pathname, port } = parsedUrl;
98
104
  // Handle stripping 'www.' and port
@@ -151,26 +157,49 @@ export function matchUrlWithWildcard(url, patterns) {
151
157
  });
152
158
  }
153
159
  // Updated XMLHttpRequest interceptor with single check function
160
+ // Updated XMLHttpRequest interceptor to bypass for CORS-sensitive domains
154
161
  function setupXMLHttpRequestInterceptor(domainsToNotPropagateHeaderTo, domainsToPropagateHeadersTo = []) {
162
+ const originalOpen = XMLHttpRequest.prototype.open;
155
163
  const originalSend = XMLHttpRequest.prototype.send;
156
164
  const sessionId = getOrSetSessionId();
165
+ // Combine default and passed ignore domains
157
166
  const combinedIgnoreDomains = [
158
167
  ...DOMAINS_TO_NOT_PROPAGATE_HEADER_TO_DEFAULT,
159
168
  ...domainsToNotPropagateHeaderTo,
160
169
  ];
170
+ // Store URL during open()
171
+ XMLHttpRequest.prototype.open = function (method, url, ...args) {
172
+ // Ensure the URL is a string, otherwise handle gracefully
173
+ if (typeof url === "string" && url.length > 0) {
174
+ this._requestUrl = url; // Capture the valid URL
175
+ }
176
+ else {
177
+ console.warn("Invalid or non-string URL passed to XMLHttpRequest:", url);
178
+ this._requestUrl = null; // Handle invalid or non-string URL
179
+ }
180
+ return originalOpen.apply(this, [method, url, ...args]);
181
+ };
182
+ // Intercept send()
161
183
  XMLHttpRequest.prototype.send = function (...args) {
162
- const url = this._url;
163
- // Check if URL matches the propagation and exclusion patterns
164
- const shouldSkipHeader = matchUrlWithWildcard(url, combinedIgnoreDomains);
184
+ const url = this._requestUrl;
185
+ // If no valid URL was captured, proceed without modification
186
+ if (!url) {
187
+ return originalSend.apply(this, args);
188
+ }
189
+ // Bypass logic for domains listed in the combinedIgnoreDomains
190
+ if (matchUrlWithWildcard(url, combinedIgnoreDomains)) {
191
+ return originalSend.apply(this, args);
192
+ }
193
+ // Check if the domain should propagate headers
165
194
  const shouldPropagateHeader = domainsToPropagateHeadersTo.length === 0 ||
166
195
  matchUrlWithWildcard(url, domainsToPropagateHeadersTo);
167
- if (sessionId && shouldPropagateHeader && !shouldSkipHeader) {
196
+ if (sessionId && shouldPropagateHeader) {
168
197
  this.setRequestHeader("X-Sf3-Rid", sessionId);
169
198
  }
170
- originalSend.apply(this, args);
199
+ return originalSend.apply(this, args);
171
200
  };
172
201
  }
173
- // Updated fetch interceptor with single check function
202
+ // Updated fetch interceptor to bypass for CORS-sensitive domains
174
203
  function setupFetchInterceptor(domainsToNotPropagateHeaderTo, domainsToPropagateHeadersTo = []) {
175
204
  const originalFetch = window.fetch;
176
205
  const sessionId = getOrSetSessionId();
@@ -181,22 +210,35 @@ function setupFetchInterceptor(domainsToNotPropagateHeaderTo, domainsToPropagate
181
210
  ];
182
211
  window.fetch = function (input, init) {
183
212
  let url;
213
+ // Handle different types of `input` for fetch
184
214
  if (typeof input === "string") {
215
+ // String URL
185
216
  url = input;
186
217
  }
187
218
  else if (input instanceof Request) {
219
+ // Request object (we extract the URL)
188
220
  url = input.url;
189
221
  }
222
+ else if (input instanceof URL) {
223
+ // URL object
224
+ url = input.href;
225
+ }
190
226
  else {
227
+ // Unsupported input type, skip interception
228
+ console.warn("Unsupported input type for fetch:", input);
191
229
  return originalFetch.apply(this, arguments);
192
230
  }
193
- // Check if URL matches the propagation and exclusion patterns
194
- const shouldSkipHeader = matchUrlWithWildcard(url, combinedIgnoreDomains);
231
+ // Bypass logic for domains listed in the combinedIgnoreDomains
232
+ if (matchUrlWithWildcard(url, combinedIgnoreDomains)) {
233
+ return originalFetch.apply(this, arguments);
234
+ }
235
+ // Check if the domain should propagate headers
195
236
  const shouldPropagateHeader = domainsToPropagateHeadersTo.length === 0 ||
196
237
  matchUrlWithWildcard(url, domainsToPropagateHeadersTo);
197
238
  // Proceed with fetch if header should propagate and not be excluded
198
- if (sessionId && shouldPropagateHeader && !shouldSkipHeader) {
239
+ if (sessionId && shouldPropagateHeader) {
199
240
  if (input instanceof Request) {
241
+ // If input is a Request, clone it and modify the headers
200
242
  const clonedRequest = input.clone();
201
243
  const newHeaders = new Headers(clonedRequest.headers);
202
244
  newHeaders.set("X-Sf3-Rid", sessionId);
@@ -206,6 +248,7 @@ function setupFetchInterceptor(domainsToNotPropagateHeaderTo, domainsToPropagate
206
248
  return originalFetch.call(this, modifiedRequest);
207
249
  }
208
250
  else {
251
+ // For string or URL input, modify init to add headers
209
252
  const modifiedInit = { ...init };
210
253
  const newHeaders = new Headers(init?.headers || {});
211
254
  newHeaders.set("X-Sf3-Rid", sessionId);
@@ -214,12 +257,12 @@ function setupFetchInterceptor(domainsToNotPropagateHeaderTo, domainsToPropagate
214
257
  }
215
258
  }
216
259
  else {
260
+ // No header propagation required, proceed with original fetch
217
261
  return originalFetch.apply(this, arguments);
218
262
  }
219
263
  };
220
264
  }
221
265
  // Main Recording Function
222
- // Main Recording Function
223
266
  export async function startRecording({ apiKey, backendApi, domainsToPropagateHeaderTo = [], domainsToNotPropagateHeaderTo = [], }) {
224
267
  let sessionId = getOrSetSessionId();
225
268
  storeCredentialsAndConnection({ apiKey, backendApi });