@sailfish-ai/recorder 1.0.5 → 1.0.7
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/index.js +73 -8
- package/dist/sailfish-recorder.es.js +47 -7
- package/dist/sailfish-recorder.umd.js +47 -7
- package/dist/types/index.d.ts +1 -0
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -82,38 +82,103 @@ function storeCredentialsAndConnection({ apiKey, backendApi, }) {
|
|
|
82
82
|
sessionStorage.setItem("sailfishApiKey", apiKey);
|
|
83
83
|
sessionStorage.setItem("sailfishBackendApi", backendApi);
|
|
84
84
|
}
|
|
85
|
-
//
|
|
85
|
+
// Utility function to match domains or paths with wildcard support
|
|
86
|
+
export function matchUrlWithWildcard(url, patterns) {
|
|
87
|
+
// Strip any protocol (e.g., http, https, ws, wss, ftp, etc.) from the URL
|
|
88
|
+
const strippedUrl = url.replace(/^[a-zA-Z]+:\/\//, "");
|
|
89
|
+
const parsedUrl = new URL("http://" + strippedUrl); // Add a dummy protocol for URL parsing
|
|
90
|
+
const { hostname, pathname } = parsedUrl;
|
|
91
|
+
const domain = hostname.toLowerCase();
|
|
92
|
+
return patterns.some((pattern) => {
|
|
93
|
+
// Strip any protocol from the pattern
|
|
94
|
+
const strippedPattern = pattern.replace(/^[a-zA-Z]+:\/\//, "");
|
|
95
|
+
let [patternDomain, patternPath] = strippedPattern.split("/", 2);
|
|
96
|
+
// Handle domain wildcards
|
|
97
|
+
const normalizedPatternDomain = patternDomain
|
|
98
|
+
.replace(/\./g, "\\.") // Escape dots for regex
|
|
99
|
+
.replace(/\*/g, ".*"); // Replace '*' with regex to match any characters
|
|
100
|
+
// Create regex for the domain pattern
|
|
101
|
+
const domainRegex = new RegExp(`^${normalizedPatternDomain}$`, "i");
|
|
102
|
+
// Strip 'www.' from both the input domain and the pattern domain for comparison
|
|
103
|
+
const strippedDomain = domain.startsWith("www.") ? domain.slice(4) : domain;
|
|
104
|
+
// Handle subdomain wildcard (*.) to match both base and subdomains
|
|
105
|
+
if (patternDomain.startsWith("*.") &&
|
|
106
|
+
(domain === patternDomain.slice(2) ||
|
|
107
|
+
strippedDomain === patternDomain.slice(2))) {
|
|
108
|
+
// Check for path match if the pattern includes a path
|
|
109
|
+
if (patternPath) {
|
|
110
|
+
const normalizedPatternPath = patternPath
|
|
111
|
+
.replace(/\*/g, ".*") // Replace '*' with regex to match any characters
|
|
112
|
+
.replace(/\/$/, ""); // Remove trailing slashes from pattern
|
|
113
|
+
const pathRegex = new RegExp(`^/${normalizedPatternPath}`, "i");
|
|
114
|
+
return pathRegex.test(pathname); // Match the path
|
|
115
|
+
}
|
|
116
|
+
return true; // Domain matched, no path required
|
|
117
|
+
}
|
|
118
|
+
// Check if the domain matches (include check for base domain without www)
|
|
119
|
+
if (!domainRegex.test(strippedDomain) && !domainRegex.test(domain)) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
// If there's a path in the pattern, match the path
|
|
123
|
+
if (patternPath) {
|
|
124
|
+
const normalizedPatternPath = patternPath
|
|
125
|
+
.replace(/\*/g, ".*") // Replace '*' with regex to match any characters
|
|
126
|
+
.replace(/\/$/, ""); // Remove trailing slashes from pattern
|
|
127
|
+
const pathRegex = new RegExp(`^/${normalizedPatternPath}`, "i");
|
|
128
|
+
return pathRegex.test(pathname); // Match the path
|
|
129
|
+
}
|
|
130
|
+
// If no path pattern, only the domain needs to match
|
|
131
|
+
return true;
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
// Updated XMLHttpRequest interceptor with single check function
|
|
86
135
|
function setupXMLHttpRequestInterceptor(domainsToNotPropagateHeaderTo) {
|
|
87
136
|
const originalOpen = XMLHttpRequest.prototype.open;
|
|
88
137
|
const originalSend = XMLHttpRequest.prototype.send;
|
|
89
138
|
const sessionId = getOrSetSessionId();
|
|
139
|
+
// Combine default and passed domains
|
|
90
140
|
const combinedIgnoreDomains = [
|
|
91
141
|
...DOMAINS_TO_NOT_PROPAGATE_HEADER_TO_DEFAULT,
|
|
92
142
|
...domainsToNotPropagateHeaderTo,
|
|
93
|
-
]
|
|
143
|
+
];
|
|
94
144
|
XMLHttpRequest.prototype.open = function (...args) {
|
|
95
145
|
this._url = args[1]; // Store the request URL
|
|
96
146
|
originalOpen.apply(this, args);
|
|
97
147
|
};
|
|
98
148
|
XMLHttpRequest.prototype.send = function (...args) {
|
|
99
|
-
const
|
|
100
|
-
if
|
|
149
|
+
const url = this._url;
|
|
150
|
+
// Check if URL matches any domain or path pattern
|
|
151
|
+
const shouldSkipHeader = matchUrlWithWildcard(url, combinedIgnoreDomains);
|
|
152
|
+
if (sessionId && !shouldSkipHeader) {
|
|
101
153
|
this.setRequestHeader("X-Sf3-Rid", sessionId);
|
|
102
154
|
}
|
|
103
155
|
originalSend.apply(this, args);
|
|
104
156
|
};
|
|
105
157
|
}
|
|
106
|
-
//
|
|
158
|
+
// Updated fetch interceptor with single check function
|
|
107
159
|
function setupFetchInterceptor(domainsToNotPropagateHeaderTo) {
|
|
108
160
|
const originalFetch = window.fetch;
|
|
109
161
|
const sessionId = getOrSetSessionId();
|
|
162
|
+
// Combine default and passed domains
|
|
110
163
|
const combinedIgnoreDomains = [
|
|
111
164
|
...DOMAINS_TO_NOT_PROPAGATE_HEADER_TO_DEFAULT,
|
|
112
165
|
...domainsToNotPropagateHeaderTo,
|
|
113
|
-
]
|
|
166
|
+
];
|
|
114
167
|
window.fetch = async function (input, init = {}) {
|
|
115
|
-
|
|
116
|
-
if
|
|
168
|
+
let url;
|
|
169
|
+
// Check if input is a string (URL) or a Request object
|
|
170
|
+
if (typeof input === "string") {
|
|
171
|
+
url = input;
|
|
172
|
+
}
|
|
173
|
+
else if (input instanceof Request) {
|
|
174
|
+
url = input.url;
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
throw new Error("Invalid input type for fetch");
|
|
178
|
+
}
|
|
179
|
+
// Check if URL matches any domain or path pattern
|
|
180
|
+
const shouldSkipHeader = matchUrlWithWildcard(url, combinedIgnoreDomains);
|
|
181
|
+
if (sessionId && !shouldSkipHeader) {
|
|
117
182
|
init.headers = {
|
|
118
183
|
...init.headers,
|
|
119
184
|
"X-Sf3-Rid": sessionId,
|
|
@@ -1002,7 +1002,7 @@ var ReconnectingWebSocket = (
|
|
|
1002
1002
|
return ReconnectingWebSocket2;
|
|
1003
1003
|
}()
|
|
1004
1004
|
);
|
|
1005
|
-
const version = "1.0.
|
|
1005
|
+
const version = "1.0.7";
|
|
1006
1006
|
let webSocket = null;
|
|
1007
1007
|
const messageQueue = [];
|
|
1008
1008
|
function flushMessageQueue() {
|
|
@@ -21107,6 +21107,36 @@ function storeCredentialsAndConnection({
|
|
|
21107
21107
|
sessionStorage.setItem("sailfishApiKey", apiKey);
|
|
21108
21108
|
sessionStorage.setItem("sailfishBackendApi", backendApi);
|
|
21109
21109
|
}
|
|
21110
|
+
function matchUrlWithWildcard(url, patterns) {
|
|
21111
|
+
const strippedUrl = url.replace(/^[a-zA-Z]+:\/\//, "");
|
|
21112
|
+
const parsedUrl = new URL("http://" + strippedUrl);
|
|
21113
|
+
const { hostname, pathname } = parsedUrl;
|
|
21114
|
+
const domain = hostname.toLowerCase();
|
|
21115
|
+
return patterns.some((pattern) => {
|
|
21116
|
+
const strippedPattern = pattern.replace(/^[a-zA-Z]+:\/\//, "");
|
|
21117
|
+
let [patternDomain, patternPath] = strippedPattern.split("/", 2);
|
|
21118
|
+
const normalizedPatternDomain = patternDomain.replace(/\./g, "\\.").replace(/\*/g, ".*");
|
|
21119
|
+
const domainRegex = new RegExp(`^${normalizedPatternDomain}$`, "i");
|
|
21120
|
+
const strippedDomain = domain.startsWith("www.") ? domain.slice(4) : domain;
|
|
21121
|
+
if (patternDomain.startsWith("*.") && (domain === patternDomain.slice(2) || strippedDomain === patternDomain.slice(2))) {
|
|
21122
|
+
if (patternPath) {
|
|
21123
|
+
const normalizedPatternPath = patternPath.replace(/\*/g, ".*").replace(/\/$/, "");
|
|
21124
|
+
const pathRegex = new RegExp(`^/${normalizedPatternPath}`, "i");
|
|
21125
|
+
return pathRegex.test(pathname);
|
|
21126
|
+
}
|
|
21127
|
+
return true;
|
|
21128
|
+
}
|
|
21129
|
+
if (!domainRegex.test(strippedDomain) && !domainRegex.test(domain)) {
|
|
21130
|
+
return false;
|
|
21131
|
+
}
|
|
21132
|
+
if (patternPath) {
|
|
21133
|
+
const normalizedPatternPath = patternPath.replace(/\*/g, ".*").replace(/\/$/, "");
|
|
21134
|
+
const pathRegex = new RegExp(`^/${normalizedPatternPath}`, "i");
|
|
21135
|
+
return pathRegex.test(pathname);
|
|
21136
|
+
}
|
|
21137
|
+
return true;
|
|
21138
|
+
});
|
|
21139
|
+
}
|
|
21110
21140
|
function setupXMLHttpRequestInterceptor(domainsToNotPropagateHeaderTo) {
|
|
21111
21141
|
const originalOpen = XMLHttpRequest.prototype.open;
|
|
21112
21142
|
const originalSend = XMLHttpRequest.prototype.send;
|
|
@@ -21114,14 +21144,15 @@ function setupXMLHttpRequestInterceptor(domainsToNotPropagateHeaderTo) {
|
|
|
21114
21144
|
const combinedIgnoreDomains = [
|
|
21115
21145
|
...DOMAINS_TO_NOT_PROPAGATE_HEADER_TO_DEFAULT,
|
|
21116
21146
|
...domainsToNotPropagateHeaderTo
|
|
21117
|
-
]
|
|
21147
|
+
];
|
|
21118
21148
|
XMLHttpRequest.prototype.open = function(...args) {
|
|
21119
21149
|
this._url = args[1];
|
|
21120
21150
|
originalOpen.apply(this, args);
|
|
21121
21151
|
};
|
|
21122
21152
|
XMLHttpRequest.prototype.send = function(...args) {
|
|
21123
|
-
const
|
|
21124
|
-
|
|
21153
|
+
const url = this._url;
|
|
21154
|
+
const shouldSkipHeader = matchUrlWithWildcard(url, combinedIgnoreDomains);
|
|
21155
|
+
if (sessionId && !shouldSkipHeader) {
|
|
21125
21156
|
this.setRequestHeader("X-Sf3-Rid", sessionId);
|
|
21126
21157
|
}
|
|
21127
21158
|
originalSend.apply(this, args);
|
|
@@ -21133,10 +21164,18 @@ function setupFetchInterceptor(domainsToNotPropagateHeaderTo) {
|
|
|
21133
21164
|
const combinedIgnoreDomains = [
|
|
21134
21165
|
...DOMAINS_TO_NOT_PROPAGATE_HEADER_TO_DEFAULT,
|
|
21135
21166
|
...domainsToNotPropagateHeaderTo
|
|
21136
|
-
]
|
|
21167
|
+
];
|
|
21137
21168
|
window.fetch = async function(input2, init = {}) {
|
|
21138
|
-
|
|
21139
|
-
if (
|
|
21169
|
+
let url;
|
|
21170
|
+
if (typeof input2 === "string") {
|
|
21171
|
+
url = input2;
|
|
21172
|
+
} else if (input2 instanceof Request) {
|
|
21173
|
+
url = input2.url;
|
|
21174
|
+
} else {
|
|
21175
|
+
throw new Error("Invalid input type for fetch");
|
|
21176
|
+
}
|
|
21177
|
+
const shouldSkipHeader = matchUrlWithWildcard(url, combinedIgnoreDomains);
|
|
21178
|
+
if (sessionId && !shouldSkipHeader) {
|
|
21140
21179
|
init.headers = {
|
|
21141
21180
|
...init.headers,
|
|
21142
21181
|
"X-Sf3-Rid": sessionId
|
|
@@ -21213,6 +21252,7 @@ export {
|
|
|
21213
21252
|
identify,
|
|
21214
21253
|
initializeRecording,
|
|
21215
21254
|
initializeWebSocket,
|
|
21255
|
+
matchUrlWithWildcard,
|
|
21216
21256
|
sendDomainsToNotPropagateHeaderTo,
|
|
21217
21257
|
sendGraphQLRequest,
|
|
21218
21258
|
sendMessage,
|
|
@@ -1006,7 +1006,7 @@
|
|
|
1006
1006
|
return ReconnectingWebSocket2;
|
|
1007
1007
|
}()
|
|
1008
1008
|
);
|
|
1009
|
-
const version = "1.0.
|
|
1009
|
+
const version = "1.0.7";
|
|
1010
1010
|
let webSocket = null;
|
|
1011
1011
|
const messageQueue = [];
|
|
1012
1012
|
function flushMessageQueue() {
|
|
@@ -21111,6 +21111,36 @@
|
|
|
21111
21111
|
sessionStorage.setItem("sailfishApiKey", apiKey);
|
|
21112
21112
|
sessionStorage.setItem("sailfishBackendApi", backendApi);
|
|
21113
21113
|
}
|
|
21114
|
+
function matchUrlWithWildcard(url, patterns) {
|
|
21115
|
+
const strippedUrl = url.replace(/^[a-zA-Z]+:\/\//, "");
|
|
21116
|
+
const parsedUrl = new URL("http://" + strippedUrl);
|
|
21117
|
+
const { hostname, pathname } = parsedUrl;
|
|
21118
|
+
const domain = hostname.toLowerCase();
|
|
21119
|
+
return patterns.some((pattern) => {
|
|
21120
|
+
const strippedPattern = pattern.replace(/^[a-zA-Z]+:\/\//, "");
|
|
21121
|
+
let [patternDomain, patternPath] = strippedPattern.split("/", 2);
|
|
21122
|
+
const normalizedPatternDomain = patternDomain.replace(/\./g, "\\.").replace(/\*/g, ".*");
|
|
21123
|
+
const domainRegex = new RegExp(`^${normalizedPatternDomain}$`, "i");
|
|
21124
|
+
const strippedDomain = domain.startsWith("www.") ? domain.slice(4) : domain;
|
|
21125
|
+
if (patternDomain.startsWith("*.") && (domain === patternDomain.slice(2) || strippedDomain === patternDomain.slice(2))) {
|
|
21126
|
+
if (patternPath) {
|
|
21127
|
+
const normalizedPatternPath = patternPath.replace(/\*/g, ".*").replace(/\/$/, "");
|
|
21128
|
+
const pathRegex = new RegExp(`^/${normalizedPatternPath}`, "i");
|
|
21129
|
+
return pathRegex.test(pathname);
|
|
21130
|
+
}
|
|
21131
|
+
return true;
|
|
21132
|
+
}
|
|
21133
|
+
if (!domainRegex.test(strippedDomain) && !domainRegex.test(domain)) {
|
|
21134
|
+
return false;
|
|
21135
|
+
}
|
|
21136
|
+
if (patternPath) {
|
|
21137
|
+
const normalizedPatternPath = patternPath.replace(/\*/g, ".*").replace(/\/$/, "");
|
|
21138
|
+
const pathRegex = new RegExp(`^/${normalizedPatternPath}`, "i");
|
|
21139
|
+
return pathRegex.test(pathname);
|
|
21140
|
+
}
|
|
21141
|
+
return true;
|
|
21142
|
+
});
|
|
21143
|
+
}
|
|
21114
21144
|
function setupXMLHttpRequestInterceptor(domainsToNotPropagateHeaderTo) {
|
|
21115
21145
|
const originalOpen = XMLHttpRequest.prototype.open;
|
|
21116
21146
|
const originalSend = XMLHttpRequest.prototype.send;
|
|
@@ -21118,14 +21148,15 @@
|
|
|
21118
21148
|
const combinedIgnoreDomains = [
|
|
21119
21149
|
...DOMAINS_TO_NOT_PROPAGATE_HEADER_TO_DEFAULT,
|
|
21120
21150
|
...domainsToNotPropagateHeaderTo
|
|
21121
|
-
]
|
|
21151
|
+
];
|
|
21122
21152
|
XMLHttpRequest.prototype.open = function(...args) {
|
|
21123
21153
|
this._url = args[1];
|
|
21124
21154
|
originalOpen.apply(this, args);
|
|
21125
21155
|
};
|
|
21126
21156
|
XMLHttpRequest.prototype.send = function(...args) {
|
|
21127
|
-
const
|
|
21128
|
-
|
|
21157
|
+
const url = this._url;
|
|
21158
|
+
const shouldSkipHeader = matchUrlWithWildcard(url, combinedIgnoreDomains);
|
|
21159
|
+
if (sessionId && !shouldSkipHeader) {
|
|
21129
21160
|
this.setRequestHeader("X-Sf3-Rid", sessionId);
|
|
21130
21161
|
}
|
|
21131
21162
|
originalSend.apply(this, args);
|
|
@@ -21137,10 +21168,18 @@
|
|
|
21137
21168
|
const combinedIgnoreDomains = [
|
|
21138
21169
|
...DOMAINS_TO_NOT_PROPAGATE_HEADER_TO_DEFAULT,
|
|
21139
21170
|
...domainsToNotPropagateHeaderTo
|
|
21140
|
-
]
|
|
21171
|
+
];
|
|
21141
21172
|
window.fetch = async function(input2, init = {}) {
|
|
21142
|
-
|
|
21143
|
-
if (
|
|
21173
|
+
let url;
|
|
21174
|
+
if (typeof input2 === "string") {
|
|
21175
|
+
url = input2;
|
|
21176
|
+
} else if (input2 instanceof Request) {
|
|
21177
|
+
url = input2.url;
|
|
21178
|
+
} else {
|
|
21179
|
+
throw new Error("Invalid input type for fetch");
|
|
21180
|
+
}
|
|
21181
|
+
const shouldSkipHeader = matchUrlWithWildcard(url, combinedIgnoreDomains);
|
|
21182
|
+
if (sessionId && !shouldSkipHeader) {
|
|
21144
21183
|
init.headers = {
|
|
21145
21184
|
...init.headers,
|
|
21146
21185
|
"X-Sf3-Rid": sessionId
|
|
@@ -21216,6 +21255,7 @@
|
|
|
21216
21255
|
exports2.identify = identify;
|
|
21217
21256
|
exports2.initializeRecording = initializeRecording;
|
|
21218
21257
|
exports2.initializeWebSocket = initializeWebSocket;
|
|
21258
|
+
exports2.matchUrlWithWildcard = matchUrlWithWildcard;
|
|
21219
21259
|
exports2.sendDomainsToNotPropagateHeaderTo = sendDomainsToNotPropagateHeaderTo;
|
|
21220
21260
|
exports2.sendGraphQLRequest = sendGraphQLRequest;
|
|
21221
21261
|
exports2.sendMessage = sendMessage;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { CaptureSettings } from "./types";
|
|
|
4
4
|
export declare const DEFAULT_CAPTURE_SETTINGS: CaptureSettings;
|
|
5
5
|
export declare const DEFAULT_CONSOLE_RECORDING_SETTINGS: LogRecordOptions;
|
|
6
6
|
export declare const DEFAULT_NETWORK_CAPTURE_SETTINGS: NetworkRecordOptions;
|
|
7
|
+
export declare function matchUrlWithWildcard(url: string, patterns: string[]): boolean;
|
|
7
8
|
export declare function startRecording({ apiKey, backendApi, domainsToNotPropagateHeaderTo, }: {
|
|
8
9
|
apiKey: string;
|
|
9
10
|
backendApi: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sailfish-ai/recorder",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"publishPublicly": true,
|
|
5
5
|
"main": "dist/sailfish-recorder.umd.js",
|
|
6
6
|
"types": "dist/types/index.d.ts",
|
|
@@ -38,8 +38,10 @@
|
|
|
38
38
|
"@vitejs/plugin-vue": "^5.1.3",
|
|
39
39
|
"jest": "^29.7.0",
|
|
40
40
|
"jest-transform-stub": "^2.0.0",
|
|
41
|
+
"jsdom": "^25.0.0",
|
|
41
42
|
"ts-jest": "^29.2.3",
|
|
42
43
|
"typescript": "^5.0.0",
|
|
44
|
+
"vitest": "^2.1.1",
|
|
43
45
|
"vue": "^3.4.33"
|
|
44
46
|
}
|
|
45
47
|
}
|