@neroom/nevision 0.1.4 → 0.1.6

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.
Files changed (3) hide show
  1. package/dist/index.js +193 -22
  2. package/dist/index.mjs +193 -22
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -39,6 +39,77 @@ var import_react = require("react");
39
39
  var DEFAULT_API_URL = "https://api.ne-room.io";
40
40
  var CHUNK_INTERVAL = 1e4;
41
41
  var MAX_EVENTS_PER_CHUNK = 100;
42
+ var DB_NAME = "nevision_recordings";
43
+ var STORE_NAME = "pending_events";
44
+ var EventStore = class {
45
+ constructor() {
46
+ this.db = null;
47
+ this.dbReady = this.openDB();
48
+ }
49
+ openDB() {
50
+ return new Promise((resolve, reject) => {
51
+ if (typeof indexedDB === "undefined") {
52
+ reject(new Error("IndexedDB not supported"));
53
+ return;
54
+ }
55
+ const request = indexedDB.open(DB_NAME, 1);
56
+ request.onerror = () => reject(request.error);
57
+ request.onsuccess = () => {
58
+ this.db = request.result;
59
+ resolve(request.result);
60
+ };
61
+ request.onupgradeneeded = (event) => {
62
+ const db = event.target.result;
63
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
64
+ const store = db.createObjectStore(STORE_NAME, { keyPath: "id" });
65
+ store.createIndex("sessionId", "sessionId", { unique: false });
66
+ store.createIndex("timestamp", "timestamp", { unique: false });
67
+ }
68
+ };
69
+ });
70
+ }
71
+ async saveChunk(chunk) {
72
+ const db = await this.dbReady;
73
+ return new Promise((resolve, reject) => {
74
+ const tx = db.transaction(STORE_NAME, "readwrite");
75
+ const store = tx.objectStore(STORE_NAME);
76
+ const request = store.put(chunk);
77
+ request.onerror = () => reject(request.error);
78
+ request.onsuccess = () => resolve();
79
+ });
80
+ }
81
+ async deleteChunk(id) {
82
+ const db = await this.dbReady;
83
+ return new Promise((resolve, reject) => {
84
+ const tx = db.transaction(STORE_NAME, "readwrite");
85
+ const store = tx.objectStore(STORE_NAME);
86
+ const request = store.delete(id);
87
+ request.onerror = () => reject(request.error);
88
+ request.onsuccess = () => resolve();
89
+ });
90
+ }
91
+ async getPendingChunks() {
92
+ const db = await this.dbReady;
93
+ return new Promise((resolve, reject) => {
94
+ const tx = db.transaction(STORE_NAME, "readonly");
95
+ const store = tx.objectStore(STORE_NAME);
96
+ const request = store.getAll();
97
+ request.onerror = () => reject(request.error);
98
+ request.onsuccess = () => resolve(request.result || []);
99
+ });
100
+ }
101
+ async getChunksBySession(sessionId) {
102
+ const db = await this.dbReady;
103
+ return new Promise((resolve, reject) => {
104
+ const tx = db.transaction(STORE_NAME, "readonly");
105
+ const store = tx.objectStore(STORE_NAME);
106
+ const index = store.index("sessionId");
107
+ const request = index.getAll(sessionId);
108
+ request.onerror = () => reject(request.error);
109
+ request.onsuccess = () => resolve(request.result || []);
110
+ });
111
+ }
112
+ };
42
113
  function NevisionRecorder({
43
114
  siteId,
44
115
  apiKey,
@@ -52,10 +123,26 @@ function NevisionRecorder({
52
123
  const eventsBufferRef = (0, import_react.useRef)([]);
53
124
  const stopFnRef = (0, import_react.useRef)(null);
54
125
  const chunkIndexRef = (0, import_react.useRef)(0);
126
+ const eventStoreRef = (0, import_react.useRef)(null);
127
+ const initializedRef = (0, import_react.useRef)(false);
128
+ const onStartRef = (0, import_react.useRef)(onStart);
129
+ const onErrorRef = (0, import_react.useRef)(onError);
130
+ const samplingRef = (0, import_react.useRef)(sampling);
131
+ const privacyRef = (0, import_react.useRef)(privacy);
132
+ onStartRef.current = onStart;
133
+ onErrorRef.current = onError;
134
+ samplingRef.current = sampling;
135
+ privacyRef.current = privacy;
55
136
  (0, import_react.useEffect)(() => {
137
+ if (initializedRef.current) {
138
+ return;
139
+ }
140
+ initializedRef.current = true;
56
141
  let intervalId;
57
142
  const init = async () => {
58
143
  try {
144
+ eventStoreRef.current = new EventStore();
145
+ await retrySendPendingChunks(apiUrl);
59
146
  const { record } = await import("rrweb");
60
147
  const startResponse = await fetch(`${apiUrl}/public/recordings/start`, {
61
148
  method: "POST",
@@ -65,12 +152,13 @@ function NevisionRecorder({
65
152
  body: JSON.stringify({
66
153
  siteId,
67
154
  apiKey,
68
- url: window.location.href,
155
+ initialUrl: window.location.href,
69
156
  userAgent: navigator.userAgent,
70
157
  screenWidth: window.screen.width,
71
158
  screenHeight: window.screen.height,
72
159
  viewportWidth: window.innerWidth,
73
- viewportHeight: window.innerHeight
160
+ viewportHeight: window.innerHeight,
161
+ referrer: document.referrer || ""
74
162
  })
75
163
  });
76
164
  if (!startResponse.ok) {
@@ -78,28 +166,31 @@ function NevisionRecorder({
78
166
  }
79
167
  const { sessionId } = await startResponse.json();
80
168
  sessionIdRef.current = sessionId;
81
- onStart?.(sessionId);
169
+ onStartRef.current?.(sessionId);
170
+ const currentSampling = samplingRef.current;
171
+ const currentPrivacy = privacyRef.current;
82
172
  const recordConfig = {
83
173
  emit: (event) => {
84
174
  eventsBufferRef.current.push(event);
175
+ persistEventsToStorage();
85
176
  },
86
- sampling: sampling ? {
87
- mousemove: sampling.mousemove,
88
- mouseInteraction: sampling.mouseInteraction,
89
- scroll: sampling.scroll,
90
- media: sampling.media,
91
- input: sampling.input
177
+ sampling: currentSampling ? {
178
+ mousemove: currentSampling.mousemove,
179
+ mouseInteraction: currentSampling.mouseInteraction,
180
+ scroll: currentSampling.scroll,
181
+ media: currentSampling.media,
182
+ input: currentSampling.input
92
183
  } : {
93
184
  mousemove: 50,
94
185
  scroll: 150
95
186
  },
96
- maskAllInputs: privacy?.maskAllInputs ?? true,
97
- maskInputOptions: privacy?.maskInputOptions ?? {
187
+ maskAllInputs: currentPrivacy?.maskAllInputs ?? true,
188
+ maskInputOptions: currentPrivacy?.maskInputOptions ?? {
98
189
  password: true,
99
190
  email: true
100
191
  },
101
- maskTextSelector: privacy?.maskTextSelector,
102
- blockSelector: privacy?.blockSelector
192
+ maskTextSelector: currentPrivacy?.maskTextSelector,
193
+ blockSelector: currentPrivacy?.blockSelector
103
194
  };
104
195
  const stopFn = record(recordConfig);
105
196
  if (stopFn) {
@@ -108,26 +199,100 @@ function NevisionRecorder({
108
199
  intervalId = setInterval(() => {
109
200
  sendChunk(apiUrl, sessionId);
110
201
  }, CHUNK_INTERVAL);
111
- const handleUnload = () => {
112
- if (sessionIdRef.current && eventsBufferRef.current.length > 0) {
202
+ let finalSyncDone = false;
203
+ const handleFinalSync = (isPageHiding = false) => {
204
+ if (finalSyncDone || !sessionIdRef.current) return;
205
+ if (eventsBufferRef.current.length > 0) {
113
206
  sendChunk(apiUrl, sessionIdRef.current, true);
207
+ }
208
+ if (isPageHiding) {
209
+ finalSyncDone = true;
114
210
  endSession(apiUrl, sessionIdRef.current);
115
211
  }
116
212
  };
117
- window.addEventListener("beforeunload", handleUnload);
118
213
  document.addEventListener("visibilitychange", () => {
119
214
  if (document.visibilityState === "hidden") {
120
- handleUnload();
215
+ handleFinalSync(false);
121
216
  }
122
217
  });
218
+ window.addEventListener("beforeunload", () => {
219
+ handleFinalSync(true);
220
+ });
221
+ window.addEventListener("pagehide", (e) => {
222
+ handleFinalSync(!e.persisted);
223
+ });
123
224
  } catch (error) {
124
- onError?.(error instanceof Error ? error : new Error(String(error)));
225
+ onErrorRef.current?.(error instanceof Error ? error : new Error(String(error)));
226
+ }
227
+ };
228
+ let persistTimeout = null;
229
+ const persistEventsToStorage = () => {
230
+ if (persistTimeout) return;
231
+ persistTimeout = setTimeout(async () => {
232
+ persistTimeout = null;
233
+ if (!sessionIdRef.current || !eventStoreRef.current) return;
234
+ if (eventsBufferRef.current.length === 0) return;
235
+ const events = [...eventsBufferRef.current];
236
+ const chunkId = `${sessionIdRef.current}_${Date.now()}_${Math.random().toString(36).slice(2)}`;
237
+ try {
238
+ await eventStoreRef.current.saveChunk({
239
+ id: chunkId,
240
+ sessionId: sessionIdRef.current,
241
+ siteId,
242
+ apiKey,
243
+ events,
244
+ chunkIndex: chunkIndexRef.current,
245
+ timestamp: Date.now()
246
+ });
247
+ } catch {
248
+ }
249
+ }, 1e3);
250
+ };
251
+ const retrySendPendingChunks = async (url) => {
252
+ if (!eventStoreRef.current) return;
253
+ try {
254
+ const pendingChunks = await eventStoreRef.current.getPendingChunks();
255
+ for (const chunk of pendingChunks) {
256
+ try {
257
+ const response = await fetch(`${url}/public/recordings/chunk`, {
258
+ method: "POST",
259
+ headers: { "Content-Type": "application/json" },
260
+ body: JSON.stringify({
261
+ sessionId: chunk.sessionId,
262
+ siteId: chunk.siteId,
263
+ apiKey: chunk.apiKey,
264
+ events: chunk.events,
265
+ chunkIndex: chunk.chunkIndex
266
+ })
267
+ });
268
+ if (response.ok) {
269
+ await eventStoreRef.current?.deleteChunk(chunk.id);
270
+ }
271
+ } catch {
272
+ }
273
+ }
274
+ } catch {
125
275
  }
126
276
  };
127
277
  const sendChunk = async (url, sessionId, isBeacon = false) => {
128
278
  if (eventsBufferRef.current.length === 0) return;
129
279
  const events = eventsBufferRef.current.splice(0, MAX_EVENTS_PER_CHUNK);
130
280
  const chunkIndex = chunkIndexRef.current++;
281
+ const chunkId = `${sessionId}_${chunkIndex}_${Date.now()}`;
282
+ if (eventStoreRef.current) {
283
+ try {
284
+ await eventStoreRef.current.saveChunk({
285
+ id: chunkId,
286
+ sessionId,
287
+ siteId,
288
+ apiKey,
289
+ events,
290
+ chunkIndex,
291
+ timestamp: Date.now()
292
+ });
293
+ } catch {
294
+ }
295
+ }
131
296
  const payload = JSON.stringify({
132
297
  sessionId,
133
298
  siteId,
@@ -136,19 +301,25 @@ function NevisionRecorder({
136
301
  chunkIndex
137
302
  });
138
303
  if (isBeacon && navigator.sendBeacon) {
139
- navigator.sendBeacon(
304
+ const sent = navigator.sendBeacon(
140
305
  `${url}/public/recordings/chunk`,
141
306
  new Blob([payload], { type: "application/json" })
142
307
  );
308
+ if (sent && eventStoreRef.current) {
309
+ eventStoreRef.current.deleteChunk(chunkId).catch(() => {
310
+ });
311
+ }
143
312
  } else {
144
313
  try {
145
- await fetch(`${url}/public/recordings/chunk`, {
314
+ const response = await fetch(`${url}/public/recordings/chunk`, {
146
315
  method: "POST",
147
316
  headers: { "Content-Type": "application/json" },
148
317
  body: payload
149
318
  });
319
+ if (response.ok && eventStoreRef.current) {
320
+ await eventStoreRef.current.deleteChunk(chunkId);
321
+ }
150
322
  } catch {
151
- eventsBufferRef.current.unshift(...events);
152
323
  }
153
324
  }
154
325
  };
@@ -170,7 +341,7 @@ function NevisionRecorder({
170
341
  endSession(apiUrl, sessionIdRef.current);
171
342
  }
172
343
  };
173
- }, [siteId, apiKey, apiUrl, sampling, privacy, onStart, onError]);
344
+ }, [siteId, apiKey, apiUrl]);
174
345
  return null;
175
346
  }
176
347
  var index_default = NevisionRecorder;
package/dist/index.mjs CHANGED
@@ -5,6 +5,77 @@ import { useEffect, useRef } from "react";
5
5
  var DEFAULT_API_URL = "https://api.ne-room.io";
6
6
  var CHUNK_INTERVAL = 1e4;
7
7
  var MAX_EVENTS_PER_CHUNK = 100;
8
+ var DB_NAME = "nevision_recordings";
9
+ var STORE_NAME = "pending_events";
10
+ var EventStore = class {
11
+ constructor() {
12
+ this.db = null;
13
+ this.dbReady = this.openDB();
14
+ }
15
+ openDB() {
16
+ return new Promise((resolve, reject) => {
17
+ if (typeof indexedDB === "undefined") {
18
+ reject(new Error("IndexedDB not supported"));
19
+ return;
20
+ }
21
+ const request = indexedDB.open(DB_NAME, 1);
22
+ request.onerror = () => reject(request.error);
23
+ request.onsuccess = () => {
24
+ this.db = request.result;
25
+ resolve(request.result);
26
+ };
27
+ request.onupgradeneeded = (event) => {
28
+ const db = event.target.result;
29
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
30
+ const store = db.createObjectStore(STORE_NAME, { keyPath: "id" });
31
+ store.createIndex("sessionId", "sessionId", { unique: false });
32
+ store.createIndex("timestamp", "timestamp", { unique: false });
33
+ }
34
+ };
35
+ });
36
+ }
37
+ async saveChunk(chunk) {
38
+ const db = await this.dbReady;
39
+ return new Promise((resolve, reject) => {
40
+ const tx = db.transaction(STORE_NAME, "readwrite");
41
+ const store = tx.objectStore(STORE_NAME);
42
+ const request = store.put(chunk);
43
+ request.onerror = () => reject(request.error);
44
+ request.onsuccess = () => resolve();
45
+ });
46
+ }
47
+ async deleteChunk(id) {
48
+ const db = await this.dbReady;
49
+ return new Promise((resolve, reject) => {
50
+ const tx = db.transaction(STORE_NAME, "readwrite");
51
+ const store = tx.objectStore(STORE_NAME);
52
+ const request = store.delete(id);
53
+ request.onerror = () => reject(request.error);
54
+ request.onsuccess = () => resolve();
55
+ });
56
+ }
57
+ async getPendingChunks() {
58
+ const db = await this.dbReady;
59
+ return new Promise((resolve, reject) => {
60
+ const tx = db.transaction(STORE_NAME, "readonly");
61
+ const store = tx.objectStore(STORE_NAME);
62
+ const request = store.getAll();
63
+ request.onerror = () => reject(request.error);
64
+ request.onsuccess = () => resolve(request.result || []);
65
+ });
66
+ }
67
+ async getChunksBySession(sessionId) {
68
+ const db = await this.dbReady;
69
+ return new Promise((resolve, reject) => {
70
+ const tx = db.transaction(STORE_NAME, "readonly");
71
+ const store = tx.objectStore(STORE_NAME);
72
+ const index = store.index("sessionId");
73
+ const request = index.getAll(sessionId);
74
+ request.onerror = () => reject(request.error);
75
+ request.onsuccess = () => resolve(request.result || []);
76
+ });
77
+ }
78
+ };
8
79
  function NevisionRecorder({
9
80
  siteId,
10
81
  apiKey,
@@ -18,10 +89,26 @@ function NevisionRecorder({
18
89
  const eventsBufferRef = useRef([]);
19
90
  const stopFnRef = useRef(null);
20
91
  const chunkIndexRef = useRef(0);
92
+ const eventStoreRef = useRef(null);
93
+ const initializedRef = useRef(false);
94
+ const onStartRef = useRef(onStart);
95
+ const onErrorRef = useRef(onError);
96
+ const samplingRef = useRef(sampling);
97
+ const privacyRef = useRef(privacy);
98
+ onStartRef.current = onStart;
99
+ onErrorRef.current = onError;
100
+ samplingRef.current = sampling;
101
+ privacyRef.current = privacy;
21
102
  useEffect(() => {
103
+ if (initializedRef.current) {
104
+ return;
105
+ }
106
+ initializedRef.current = true;
22
107
  let intervalId;
23
108
  const init = async () => {
24
109
  try {
110
+ eventStoreRef.current = new EventStore();
111
+ await retrySendPendingChunks(apiUrl);
25
112
  const { record } = await import("rrweb");
26
113
  const startResponse = await fetch(`${apiUrl}/public/recordings/start`, {
27
114
  method: "POST",
@@ -31,12 +118,13 @@ function NevisionRecorder({
31
118
  body: JSON.stringify({
32
119
  siteId,
33
120
  apiKey,
34
- url: window.location.href,
121
+ initialUrl: window.location.href,
35
122
  userAgent: navigator.userAgent,
36
123
  screenWidth: window.screen.width,
37
124
  screenHeight: window.screen.height,
38
125
  viewportWidth: window.innerWidth,
39
- viewportHeight: window.innerHeight
126
+ viewportHeight: window.innerHeight,
127
+ referrer: document.referrer || ""
40
128
  })
41
129
  });
42
130
  if (!startResponse.ok) {
@@ -44,28 +132,31 @@ function NevisionRecorder({
44
132
  }
45
133
  const { sessionId } = await startResponse.json();
46
134
  sessionIdRef.current = sessionId;
47
- onStart?.(sessionId);
135
+ onStartRef.current?.(sessionId);
136
+ const currentSampling = samplingRef.current;
137
+ const currentPrivacy = privacyRef.current;
48
138
  const recordConfig = {
49
139
  emit: (event) => {
50
140
  eventsBufferRef.current.push(event);
141
+ persistEventsToStorage();
51
142
  },
52
- sampling: sampling ? {
53
- mousemove: sampling.mousemove,
54
- mouseInteraction: sampling.mouseInteraction,
55
- scroll: sampling.scroll,
56
- media: sampling.media,
57
- input: sampling.input
143
+ sampling: currentSampling ? {
144
+ mousemove: currentSampling.mousemove,
145
+ mouseInteraction: currentSampling.mouseInteraction,
146
+ scroll: currentSampling.scroll,
147
+ media: currentSampling.media,
148
+ input: currentSampling.input
58
149
  } : {
59
150
  mousemove: 50,
60
151
  scroll: 150
61
152
  },
62
- maskAllInputs: privacy?.maskAllInputs ?? true,
63
- maskInputOptions: privacy?.maskInputOptions ?? {
153
+ maskAllInputs: currentPrivacy?.maskAllInputs ?? true,
154
+ maskInputOptions: currentPrivacy?.maskInputOptions ?? {
64
155
  password: true,
65
156
  email: true
66
157
  },
67
- maskTextSelector: privacy?.maskTextSelector,
68
- blockSelector: privacy?.blockSelector
158
+ maskTextSelector: currentPrivacy?.maskTextSelector,
159
+ blockSelector: currentPrivacy?.blockSelector
69
160
  };
70
161
  const stopFn = record(recordConfig);
71
162
  if (stopFn) {
@@ -74,26 +165,100 @@ function NevisionRecorder({
74
165
  intervalId = setInterval(() => {
75
166
  sendChunk(apiUrl, sessionId);
76
167
  }, CHUNK_INTERVAL);
77
- const handleUnload = () => {
78
- if (sessionIdRef.current && eventsBufferRef.current.length > 0) {
168
+ let finalSyncDone = false;
169
+ const handleFinalSync = (isPageHiding = false) => {
170
+ if (finalSyncDone || !sessionIdRef.current) return;
171
+ if (eventsBufferRef.current.length > 0) {
79
172
  sendChunk(apiUrl, sessionIdRef.current, true);
173
+ }
174
+ if (isPageHiding) {
175
+ finalSyncDone = true;
80
176
  endSession(apiUrl, sessionIdRef.current);
81
177
  }
82
178
  };
83
- window.addEventListener("beforeunload", handleUnload);
84
179
  document.addEventListener("visibilitychange", () => {
85
180
  if (document.visibilityState === "hidden") {
86
- handleUnload();
181
+ handleFinalSync(false);
87
182
  }
88
183
  });
184
+ window.addEventListener("beforeunload", () => {
185
+ handleFinalSync(true);
186
+ });
187
+ window.addEventListener("pagehide", (e) => {
188
+ handleFinalSync(!e.persisted);
189
+ });
89
190
  } catch (error) {
90
- onError?.(error instanceof Error ? error : new Error(String(error)));
191
+ onErrorRef.current?.(error instanceof Error ? error : new Error(String(error)));
192
+ }
193
+ };
194
+ let persistTimeout = null;
195
+ const persistEventsToStorage = () => {
196
+ if (persistTimeout) return;
197
+ persistTimeout = setTimeout(async () => {
198
+ persistTimeout = null;
199
+ if (!sessionIdRef.current || !eventStoreRef.current) return;
200
+ if (eventsBufferRef.current.length === 0) return;
201
+ const events = [...eventsBufferRef.current];
202
+ const chunkId = `${sessionIdRef.current}_${Date.now()}_${Math.random().toString(36).slice(2)}`;
203
+ try {
204
+ await eventStoreRef.current.saveChunk({
205
+ id: chunkId,
206
+ sessionId: sessionIdRef.current,
207
+ siteId,
208
+ apiKey,
209
+ events,
210
+ chunkIndex: chunkIndexRef.current,
211
+ timestamp: Date.now()
212
+ });
213
+ } catch {
214
+ }
215
+ }, 1e3);
216
+ };
217
+ const retrySendPendingChunks = async (url) => {
218
+ if (!eventStoreRef.current) return;
219
+ try {
220
+ const pendingChunks = await eventStoreRef.current.getPendingChunks();
221
+ for (const chunk of pendingChunks) {
222
+ try {
223
+ const response = await fetch(`${url}/public/recordings/chunk`, {
224
+ method: "POST",
225
+ headers: { "Content-Type": "application/json" },
226
+ body: JSON.stringify({
227
+ sessionId: chunk.sessionId,
228
+ siteId: chunk.siteId,
229
+ apiKey: chunk.apiKey,
230
+ events: chunk.events,
231
+ chunkIndex: chunk.chunkIndex
232
+ })
233
+ });
234
+ if (response.ok) {
235
+ await eventStoreRef.current?.deleteChunk(chunk.id);
236
+ }
237
+ } catch {
238
+ }
239
+ }
240
+ } catch {
91
241
  }
92
242
  };
93
243
  const sendChunk = async (url, sessionId, isBeacon = false) => {
94
244
  if (eventsBufferRef.current.length === 0) return;
95
245
  const events = eventsBufferRef.current.splice(0, MAX_EVENTS_PER_CHUNK);
96
246
  const chunkIndex = chunkIndexRef.current++;
247
+ const chunkId = `${sessionId}_${chunkIndex}_${Date.now()}`;
248
+ if (eventStoreRef.current) {
249
+ try {
250
+ await eventStoreRef.current.saveChunk({
251
+ id: chunkId,
252
+ sessionId,
253
+ siteId,
254
+ apiKey,
255
+ events,
256
+ chunkIndex,
257
+ timestamp: Date.now()
258
+ });
259
+ } catch {
260
+ }
261
+ }
97
262
  const payload = JSON.stringify({
98
263
  sessionId,
99
264
  siteId,
@@ -102,19 +267,25 @@ function NevisionRecorder({
102
267
  chunkIndex
103
268
  });
104
269
  if (isBeacon && navigator.sendBeacon) {
105
- navigator.sendBeacon(
270
+ const sent = navigator.sendBeacon(
106
271
  `${url}/public/recordings/chunk`,
107
272
  new Blob([payload], { type: "application/json" })
108
273
  );
274
+ if (sent && eventStoreRef.current) {
275
+ eventStoreRef.current.deleteChunk(chunkId).catch(() => {
276
+ });
277
+ }
109
278
  } else {
110
279
  try {
111
- await fetch(`${url}/public/recordings/chunk`, {
280
+ const response = await fetch(`${url}/public/recordings/chunk`, {
112
281
  method: "POST",
113
282
  headers: { "Content-Type": "application/json" },
114
283
  body: payload
115
284
  });
285
+ if (response.ok && eventStoreRef.current) {
286
+ await eventStoreRef.current.deleteChunk(chunkId);
287
+ }
116
288
  } catch {
117
- eventsBufferRef.current.unshift(...events);
118
289
  }
119
290
  }
120
291
  };
@@ -136,7 +307,7 @@ function NevisionRecorder({
136
307
  endSession(apiUrl, sessionIdRef.current);
137
308
  }
138
309
  };
139
- }, [siteId, apiKey, apiUrl, sampling, privacy, onStart, onError]);
310
+ }, [siteId, apiKey, apiUrl]);
140
311
  return null;
141
312
  }
142
313
  var index_default = NevisionRecorder;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neroom/nevision",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "React SDK for NEROOM/NEVISION session recording",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",