@sailfish-ai/recorder 1.7.9 → 1.7.11
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/eventStore.js +42 -0
- package/dist/index.js +12 -10
- package/dist/notifyEventStore.js +26 -0
- package/dist/recording.js +25 -18
- package/dist/sailfish-recorder.cjs.js +1 -1
- package/dist/sailfish-recorder.cjs.js.br +0 -0
- package/dist/sailfish-recorder.cjs.js.gz +0 -0
- package/dist/sailfish-recorder.es.js +1 -1
- package/dist/sailfish-recorder.es.js.br +0 -0
- package/dist/sailfish-recorder.es.js.gz +0 -0
- package/dist/sailfish-recorder.umd.js +1 -1
- package/dist/sailfish-recorder.umd.js.br +0 -0
- package/dist/sailfish-recorder.umd.js.gz +0 -0
- package/dist/types/eventStore.d.ts +10 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/notifyEventStore.d.ts +7 -0
- package/dist/types/recording.d.ts +2 -2
- package/dist/types/utils.d.ts +6 -0
- package/dist/types/websocket.d.ts +2 -0
- package/dist/utils.js +41 -0
- package/dist/websocket.js +77 -13
- package/package.json +2 -1
- package/dist/eventCache.js +0 -43
- package/dist/types/eventCache.d.ts +0 -2
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { openDB } from 'idb';
|
|
2
|
+
const DB_NAME = 'leapsEventDB';
|
|
3
|
+
const STORE_NAME = 'recordingEvents';
|
|
4
|
+
const dbPromise = openDB(DB_NAME, 1, {
|
|
5
|
+
upgrade(db) {
|
|
6
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
7
|
+
db.createObjectStore(STORE_NAME, { keyPath: 'id', autoIncrement: true });
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
export async function saveEventToIDB(event) {
|
|
12
|
+
const db = await dbPromise;
|
|
13
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
14
|
+
await tx.store.add({ timestamp: Date.now(), data: event });
|
|
15
|
+
await tx.done;
|
|
16
|
+
}
|
|
17
|
+
export async function saveEventsToIDB(events) {
|
|
18
|
+
const db = await dbPromise;
|
|
19
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
20
|
+
for (const event of events) {
|
|
21
|
+
await tx.store.add({ timestamp: Date.now(), data: event });
|
|
22
|
+
}
|
|
23
|
+
await tx.done;
|
|
24
|
+
}
|
|
25
|
+
export async function getAllIndexedEvents() {
|
|
26
|
+
const db = await dbPromise;
|
|
27
|
+
return await db.getAll(STORE_NAME);
|
|
28
|
+
}
|
|
29
|
+
export async function deleteEventById(id) {
|
|
30
|
+
const db = await dbPromise;
|
|
31
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
32
|
+
await tx.store.delete(id);
|
|
33
|
+
await tx.done;
|
|
34
|
+
}
|
|
35
|
+
export async function deleteEventsByIds(ids) {
|
|
36
|
+
const db = await dbPromise;
|
|
37
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
38
|
+
for (const id of ids) {
|
|
39
|
+
await tx.store.delete(id);
|
|
40
|
+
}
|
|
41
|
+
await tx.done;
|
|
42
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
// import { NetworkRecordOptions } from "@sailfish-rrweb/rrweb-plugin-network-record";
|
|
2
2
|
import { v4 as uuidv4 } from "uuid";
|
|
3
3
|
import { gatherAndCacheDeviceInfo } from "./deviceInfo";
|
|
4
|
-
import { cacheEvents, sendRecordingEvents } from "./eventCache";
|
|
5
4
|
import { fetchCaptureSettings, sendDomainsToNotPropagateHeaderTo, startRecordingSession, } from "./graphql";
|
|
6
5
|
import { sendMapUuidIfAvailable } from "./mapUuid";
|
|
7
6
|
import { initializeDomContentEvents, initializeConsolePlugin, initializeRecording, getUrlAndStoredUuids, } from "./recording";
|
|
8
|
-
import { sendMessage } from "./websocket";
|
|
7
|
+
import { sendEvent, sendMessage } from "./websocket";
|
|
9
8
|
import { NetworkRequestEventId, xSf3RidHeader } from "./constants";
|
|
10
9
|
// Default list of domains to ignore
|
|
11
10
|
const DOMAINS_TO_NOT_PROPAGATE_HEADER_TO_DEFAULT = [
|
|
@@ -322,9 +321,10 @@ function setupFetchInterceptor(domainsToNotPropagateHeadersTo, domainsToPropagat
|
|
|
322
321
|
const success = response.ok;
|
|
323
322
|
const error = success ? '' : `Request Error: ${response.statusText}`;
|
|
324
323
|
// Emit 'networkRequestFinished' event
|
|
325
|
-
|
|
324
|
+
const eventData = {
|
|
326
325
|
type: NetworkRequestEventId,
|
|
327
326
|
timestamp: endTime,
|
|
327
|
+
sessionId,
|
|
328
328
|
data: {
|
|
329
329
|
request_id: networkUUID,
|
|
330
330
|
session_id: sessionId,
|
|
@@ -337,7 +337,8 @@ function setupFetchInterceptor(domainsToNotPropagateHeadersTo, domainsToPropagat
|
|
|
337
337
|
url,
|
|
338
338
|
},
|
|
339
339
|
...urlAndStoredUuids,
|
|
340
|
-
}
|
|
340
|
+
};
|
|
341
|
+
sendEvent(eventData);
|
|
341
342
|
return response;
|
|
342
343
|
}
|
|
343
344
|
catch (error) {
|
|
@@ -346,9 +347,10 @@ function setupFetchInterceptor(domainsToNotPropagateHeadersTo, domainsToPropagat
|
|
|
346
347
|
const responseCode = error.response?.status || 500;
|
|
347
348
|
const errorMessage = error.message || "Fetch request failed";
|
|
348
349
|
// Emit 'networkRequestFinished' event with error
|
|
349
|
-
|
|
350
|
+
const eventData = {
|
|
350
351
|
type: NetworkRequestEventId,
|
|
351
352
|
timestamp: endTime,
|
|
353
|
+
sessionId,
|
|
352
354
|
data: {
|
|
353
355
|
request_id: networkUUID,
|
|
354
356
|
session_id: sessionId,
|
|
@@ -361,7 +363,8 @@ function setupFetchInterceptor(domainsToNotPropagateHeadersTo, domainsToPropagat
|
|
|
361
363
|
url,
|
|
362
364
|
},
|
|
363
365
|
...urlAndStoredUuids
|
|
364
|
-
}
|
|
366
|
+
};
|
|
367
|
+
sendEvent(eventData);
|
|
365
368
|
throw error;
|
|
366
369
|
}
|
|
367
370
|
}
|
|
@@ -393,9 +396,9 @@ function setupFetchInterceptor(domainsToNotPropagateHeadersTo, domainsToPropagat
|
|
|
393
396
|
}
|
|
394
397
|
// Main Recording Function
|
|
395
398
|
export async function startRecording({ apiKey, backendApi = "https://api-service.sailfishqa.com", domainsToPropagateHeaderTo = [], domainsToNotPropagateHeaderTo = [], serviceVersion = "", serviceIdentifier = "", }) {
|
|
396
|
-
initializeDomContentEvents();
|
|
397
|
-
initializeConsolePlugin(DEFAULT_CONSOLE_RECORDING_SETTINGS);
|
|
398
399
|
let sessionId = getOrSetSessionId();
|
|
400
|
+
initializeDomContentEvents(sessionId);
|
|
401
|
+
initializeConsolePlugin(DEFAULT_CONSOLE_RECORDING_SETTINGS, sessionId);
|
|
399
402
|
storeCredentialsAndConnection({ apiKey, backendApi });
|
|
400
403
|
trackDomainChanges();
|
|
401
404
|
// Non-blocking GraphQL request to send the domains if provided
|
|
@@ -417,7 +420,6 @@ export async function startRecording({ apiKey, backendApi = "https://api-service
|
|
|
417
420
|
backendApi, apiKey, sessionId);
|
|
418
421
|
// Send parameters once before starting interval
|
|
419
422
|
sendMapUuidIfAvailable(serviceIdentifier, serviceVersion);
|
|
420
|
-
setInterval(() => sendRecordingEvents(websocket), 10000);
|
|
421
423
|
}
|
|
422
424
|
else {
|
|
423
425
|
console.error("Failed to start recording session:", sessionResponse.errors || sessionResponse);
|
|
@@ -436,7 +438,7 @@ export const initRecorder = async (options) => {
|
|
|
436
438
|
return startRecording(options);
|
|
437
439
|
};
|
|
438
440
|
// Re-export from other modules
|
|
439
|
-
export * from "./
|
|
441
|
+
export * from "./utils";
|
|
440
442
|
export * from "./graphql";
|
|
441
443
|
export * from "./recording";
|
|
442
444
|
export * from "./sendSailfishMessages";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { openDB } from 'idb';
|
|
2
|
+
const DB_NAME = 'leapsNotifyDB';
|
|
3
|
+
const STORE_NAME = 'notifyMessages';
|
|
4
|
+
const dbPromise = openDB(DB_NAME, 1, {
|
|
5
|
+
upgrade(db) {
|
|
6
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
7
|
+
db.createObjectStore(STORE_NAME, { keyPath: 'id', autoIncrement: true });
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
export async function saveNotifyMessageToIDB(message) {
|
|
12
|
+
const db = await dbPromise;
|
|
13
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
14
|
+
await tx.store.add({ value: message });
|
|
15
|
+
await tx.done;
|
|
16
|
+
}
|
|
17
|
+
export async function getAllNotifyMessages() {
|
|
18
|
+
const db = await dbPromise;
|
|
19
|
+
return await db.getAll(STORE_NAME);
|
|
20
|
+
}
|
|
21
|
+
export async function deleteNotifyMessageById(id) {
|
|
22
|
+
const db = await dbPromise;
|
|
23
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
24
|
+
await tx.store.delete(id);
|
|
25
|
+
await tx.done;
|
|
26
|
+
}
|
package/dist/recording.js
CHANGED
|
@@ -3,8 +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 { ZendeskAPI } from "react-zendesk";
|
|
6
|
-
import {
|
|
7
|
-
import { initializeWebSocket } from "./websocket";
|
|
6
|
+
import { initializeWebSocket, sendEvent } from "./websocket";
|
|
8
7
|
import { DomContentEventId, DomContentSource, Loading, Complete } from "./constants";
|
|
9
8
|
const MASK_CLASS = "sailfishSanitize";
|
|
10
9
|
const ZENDESK_ELEMENT_ID = "zendesk_chat";
|
|
@@ -40,13 +39,14 @@ export const getUrlAndStoredUuids = () => ({
|
|
|
40
39
|
prev_page_visit_uuid: sessionStorage.getItem("prevPageVisitUUID"),
|
|
41
40
|
href: location.origin + location.pathname,
|
|
42
41
|
});
|
|
43
|
-
export function initializeDomContentEvents() {
|
|
42
|
+
export function initializeDomContentEvents(sessionId) {
|
|
44
43
|
document.addEventListener("readystatechange", () => {
|
|
45
44
|
const timestamp = Date.now();
|
|
46
45
|
const newEvent = {
|
|
47
46
|
type: DomContentEventId,
|
|
48
47
|
data: { source: 0, info: "" },
|
|
49
48
|
timestamp,
|
|
49
|
+
sessionId,
|
|
50
50
|
...getUrlAndStoredUuids(),
|
|
51
51
|
};
|
|
52
52
|
switch (document.readyState) {
|
|
@@ -58,43 +58,51 @@ export function initializeDomContentEvents() {
|
|
|
58
58
|
break;
|
|
59
59
|
}
|
|
60
60
|
if (newEvent.data.info)
|
|
61
|
-
|
|
61
|
+
sendEvent(newEvent);
|
|
62
62
|
});
|
|
63
63
|
document.addEventListener("DOMContentLoaded", () => {
|
|
64
|
-
|
|
64
|
+
sendEvent({
|
|
65
65
|
type: DomContentEventId,
|
|
66
66
|
data: { source: DomContentSource.contentLoaded },
|
|
67
67
|
timestamp: Date.now(),
|
|
68
|
+
sessionId,
|
|
68
69
|
...getUrlAndStoredUuids(),
|
|
69
70
|
});
|
|
70
71
|
});
|
|
71
72
|
window.addEventListener("beforeunload", () => {
|
|
72
|
-
|
|
73
|
+
sendEvent({
|
|
73
74
|
type: DomContentEventId,
|
|
74
75
|
data: { source: DomContentSource.beforeunload },
|
|
75
76
|
timestamp: Date.now(),
|
|
77
|
+
sessionId,
|
|
76
78
|
...getUrlAndStoredUuids(),
|
|
77
79
|
});
|
|
78
80
|
});
|
|
79
81
|
window.addEventListener("unload", () => {
|
|
80
|
-
|
|
82
|
+
sendEvent({
|
|
81
83
|
type: DomContentEventId,
|
|
82
84
|
data: { source: DomContentSource.unload },
|
|
83
85
|
timestamp: Date.now(),
|
|
86
|
+
sessionId,
|
|
84
87
|
...getUrlAndStoredUuids(),
|
|
85
88
|
});
|
|
86
89
|
});
|
|
87
90
|
}
|
|
88
|
-
export function initializeConsolePlugin(consoleRecordSettings) {
|
|
91
|
+
export function initializeConsolePlugin(consoleRecordSettings, sessionId) {
|
|
89
92
|
const { name, observer } = getRecordConsolePlugin(consoleRecordSettings);
|
|
90
|
-
observer((payload) =>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
93
|
+
observer((payload) => {
|
|
94
|
+
const eventData = {
|
|
95
|
+
type: EventType.Plugin,
|
|
96
|
+
timestamp: Date.now(),
|
|
97
|
+
data: {
|
|
98
|
+
plugin: name,
|
|
99
|
+
payload,
|
|
100
|
+
},
|
|
101
|
+
sessionId: sessionId,
|
|
102
|
+
...getUrlAndStoredUuids(),
|
|
103
|
+
};
|
|
104
|
+
sendEvent(eventData);
|
|
105
|
+
}, window, consoleRecordSettings);
|
|
98
106
|
}
|
|
99
107
|
export async function initializeRecording(captureSettings, // TODO - Sibyl post-launch - replace type
|
|
100
108
|
// networkRecordSettings: NetworkRecordOptions,
|
|
@@ -106,7 +114,7 @@ backendApi, apiKey, sessionId) {
|
|
|
106
114
|
Object.assign(event, getUrlAndStoredUuids());
|
|
107
115
|
// Attach sessionId to each event
|
|
108
116
|
event.sessionId = sessionId;
|
|
109
|
-
|
|
117
|
+
sendEvent(event);
|
|
110
118
|
},
|
|
111
119
|
maskInputOptions: { text: true }, // Fix the incorrect property name
|
|
112
120
|
maskInputFn,
|
|
@@ -140,7 +148,6 @@ backendApi, apiKey, sessionId) {
|
|
|
140
148
|
ZendeskAPI("messenger:on", "open", handleWidgetOpen);
|
|
141
149
|
ZendeskAPI("messenger:on", "close", handleWidgetClose);
|
|
142
150
|
ZendeskAPI("messenger:on", "unreadMessages", handleUnreadMessages);
|
|
143
|
-
setInterval(() => sendRecordingEvents(webSocket), 10000);
|
|
144
151
|
}
|
|
145
152
|
catch (error) {
|
|
146
153
|
console.error("Error importing plugins!", error);
|