@sailfish-ai/recorder 1.7.8 → 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.
@@ -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
- cacheEvents({
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
- cacheEvents({
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 "./eventCache";
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 { cacheEvents, sendRecordingEvents } from "./eventCache";
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
- cacheEvents(newEvent);
61
+ sendEvent(newEvent);
62
62
  });
63
63
  document.addEventListener("DOMContentLoaded", () => {
64
- cacheEvents({
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
- cacheEvents({
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
- cacheEvents({
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) => cacheEvents({
91
- type: EventType.Plugin,
92
- timestamp: Date.now(),
93
- data: {
94
- plugin: name,
95
- payload,
96
- },
97
- }), window, consoleRecordSettings);
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
- cacheEvents(event);
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);