@sailfish-ai/recorder 1.0.0-alpha-1

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.
@@ -0,0 +1,26 @@
1
+ let eventCache = [];
2
+ export function cacheEvents(event) {
3
+ eventCache.push(event);
4
+ }
5
+ export function sendCachedEvents(webSocket) {
6
+ if (eventCache.length > 0 && webSocket.readyState === WebSocket.OPEN) {
7
+ const message = {
8
+ type: "events",
9
+ events: eventCache,
10
+ };
11
+ webSocket.send(JSON.stringify(message));
12
+ eventCache = [];
13
+ }
14
+ }
15
+ export function sendRecordingEvents(webSocket, sessionId) {
16
+ if (webSocket && webSocket.readyState === WebSocket.OPEN && sessionId) {
17
+ if (eventCache.length > 0) {
18
+ const message = {
19
+ type: "events",
20
+ events: eventCache,
21
+ };
22
+ webSocket.send(JSON.stringify(message));
23
+ eventCache = [];
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,38 @@
1
+ export function sendGraphQLRequest(operationName, query, variables) {
2
+ return fetch(`${variables["backendApi"]}/graphql/?apiKey=${variables["apiKey"]}`, {
3
+ method: "POST",
4
+ headers: {
5
+ "Content-Type": "application/json",
6
+ },
7
+ body: JSON.stringify({ operationName, query, variables }),
8
+ }).then((response) => response.json());
9
+ }
10
+ export function fetchCaptureSettings(apiKey, backendApi) {
11
+ return sendGraphQLRequest("GetCaptureSettingsFromApiKey", `
12
+ query GetCaptureSettingsFromApiKey($apiKey: String!) {
13
+ captureSettingsFromApiKey(apiKey: $apiKey) {
14
+ recordCanvas
15
+ recordCrossOriginIframes
16
+ collectFonts
17
+ inlineImages
18
+ recordPassword
19
+ recordRealName
20
+ recordCreditCardInfo
21
+ recordSsn
22
+ recordDob
23
+ sampling
24
+ }
25
+ }
26
+ `, { apiKey, backendApi });
27
+ }
28
+ export function startRecordingSession(apiKey, recordingId, backendApi) {
29
+ return sendGraphQLRequest("StartSession", `mutation StartSession($apiKey: UUID!, $recordingSessionId: UUID!) {
30
+ startRecordingSession(companyApiKey: $apiKey, sessionId: $recordingSessionId) {
31
+ id
32
+ }
33
+ }`, {
34
+ apiKey,
35
+ recordingSessionId: recordingId,
36
+ backendApi,
37
+ });
38
+ }
package/dist/index.js ADDED
@@ -0,0 +1,85 @@
1
+ import { v4 as uuidv4 } from "uuid";
2
+ import { sendRecordingEvents } from "./eventCache";
3
+ import { fetchCaptureSettings, startRecordingSession } from "./graphql";
4
+ import { initializeRecording } from "./recording";
5
+ import { initializeWebSocket } from "./websocket";
6
+ // Default Settings
7
+ export const DEFAULT_DOMAINS_TO_IGNORE = [];
8
+ export const DEFAULT_CAPTURE_SETTINGS = {
9
+ recordCanvas: false,
10
+ recordCrossOriginIframes: false,
11
+ collectFonts: false,
12
+ inlineImages: false,
13
+ recordPassword: false,
14
+ recordRealName: true,
15
+ recordCreditCardInfo: false,
16
+ recordSsn: false,
17
+ recordDob: false,
18
+ sampling: {},
19
+ };
20
+ export const DEFAULT_CONSOLE_RECORDING_SETTINGS = {
21
+ level: ["info", "log", "warn", "error"],
22
+ lengthThreshold: 10000,
23
+ stringifyOptions: {
24
+ stringLengthLimit: 1000,
25
+ numOfKeysLimit: 20,
26
+ depthOfLimit: 1,
27
+ },
28
+ logger: "console",
29
+ };
30
+ export const DEFAULT_NETWORK_CAPTURE_SETTINGS = {
31
+ initiatorTypes: ["fetch", "xmlhttprequest"],
32
+ ignoreRequestFn: (request) => {
33
+ const domain = extractHostname(request.url);
34
+ return DEFAULT_DOMAINS_TO_IGNORE.includes(domain);
35
+ },
36
+ recordHeaders: true,
37
+ ignoreHeaders: {
38
+ request: ["authorization"],
39
+ response: [],
40
+ },
41
+ ignoreBodyParts: {
42
+ request: ["variables.token"],
43
+ response: ["data.token"],
44
+ },
45
+ recordBody: true,
46
+ recordInitialRequests: false,
47
+ };
48
+ // Functions
49
+ export async function startRecording({ apiKey, backendApi, }) {
50
+ const sessionId = uuidv4(); // Use the same value for recordingId and sessionId
51
+ try {
52
+ const captureSettingsResponse = await fetchCaptureSettings(apiKey, backendApi);
53
+ const captureSettings = captureSettingsResponse.data?.captureSettingsFromApiKey ||
54
+ DEFAULT_CAPTURE_SETTINGS;
55
+ const sessionResponse = await startRecordingSession(apiKey, sessionId, backendApi);
56
+ if (sessionResponse.data?.startRecordingSession) {
57
+ const webSocket = initializeWebSocket(backendApi, apiKey, sessionId);
58
+ initializeRecording(captureSettings, DEFAULT_CONSOLE_RECORDING_SETTINGS, DEFAULT_NETWORK_CAPTURE_SETTINGS, backendApi, apiKey, sessionId);
59
+ setInterval(() => sendRecordingEvents(webSocket, sessionId), 10000);
60
+ }
61
+ else {
62
+ console.error("Failed to start recording session:", sessionResponse.errors || sessionResponse);
63
+ }
64
+ }
65
+ catch (error) {
66
+ console.error("Error starting recording:", error);
67
+ }
68
+ }
69
+ function extractHostname(url) {
70
+ let hostname = url.indexOf("//") > -1 ? url.split("/")[2] : url.split("/")[0];
71
+ hostname = hostname.split(":")[0];
72
+ hostname = hostname.split("?")[0];
73
+ return hostname;
74
+ }
75
+ function getWebSocketHost(url) {
76
+ const parser = document.createElement("a");
77
+ parser.href = url;
78
+ return `${parser.hostname}${parser.port ? `:${parser.port}` : ""}`;
79
+ }
80
+ // Re-export from other modules
81
+ export * from "./eventCache";
82
+ export * from "./graphql";
83
+ export * from "./recording";
84
+ export * from "./types";
85
+ export * from "./websocket";
@@ -0,0 +1,34 @@
1
+ import { record } from "@sailfish-rrweb/record";
2
+ import { getRecordConsolePlugin, } from "@sailfish-rrweb/rrweb-plugin-console-record";
3
+ import { getRecordNetworkPlugin, } from "@sailfish-rrweb/rrweb-plugin-network-record";
4
+ import { cacheEvents, sendRecordingEvents } from "./eventCache";
5
+ import { initializeWebSocket } from "./websocket";
6
+ const MASK_CLASS = "sailfishSanitize";
7
+ const DEFAULT_DOMAINS_TO_IGNORE = [];
8
+ function maskInputFn(text, node) {
9
+ // The maskInputFn logic here
10
+ return text; // Placeholder return
11
+ }
12
+ export async function initializeRecording(captureSettings, // TODO - Sibyl launch - replace type
13
+ consoleRecordSettings, networkRecordSettings, backendApi, apiKey, sessionId) {
14
+ try {
15
+ record({
16
+ emit(event) {
17
+ cacheEvents(event);
18
+ },
19
+ plugins: [
20
+ getRecordConsolePlugin(consoleRecordSettings),
21
+ getRecordNetworkPlugin(networkRecordSettings),
22
+ ],
23
+ maskInputOptions: { text: true }, // Fix the incorrect property name
24
+ maskInputFn,
25
+ maskTextClass: MASK_CLASS,
26
+ ...captureSettings,
27
+ });
28
+ const webSocket = initializeWebSocket(backendApi, apiKey, sessionId);
29
+ setInterval(() => sendRecordingEvents(webSocket, sessionId), 10000);
30
+ }
31
+ catch (error) {
32
+ console.error("Error importing plugins!", error);
33
+ }
34
+ }