@devskin/browser-sdk 1.0.32 → 1.0.34

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.
@@ -13587,11 +13587,12 @@
13587
13587
  // Send user identification immediately (don't queue)
13588
13588
  this.sendToBackend('/v1/analytics/identify', user);
13589
13589
  }
13590
- startSession(session) {
13591
- return __awaiter$1(this, void 0, void 0, function* () {
13590
+ startSession(session_1) {
13591
+ return __awaiter$1(this, arguments, void 0, function* (session, useBeacon = false) {
13592
13592
  // Send session start immediately to RUM endpoint
13593
13593
  // MUST await to ensure session is created before other requests
13594
- yield this.sendToBackend('/v1/rum/sessions', session);
13594
+ // Use beacon for page unload events (more reliable)
13595
+ yield this.sendToBackend('/v1/rum/sessions', session, useBeacon);
13595
13596
  });
13596
13597
  }
13597
13598
  sendError(error) {
@@ -13861,6 +13862,7 @@
13861
13862
  this.anonymousId = null;
13862
13863
  this.sessionStartTime = 0;
13863
13864
  this.initialized = false;
13865
+ this.heartbeatInterval = null;
13864
13866
  // Collectors
13865
13867
  this.deviceCollector = null;
13866
13868
  this.locationCollector = null;
@@ -13961,6 +13963,8 @@
13961
13963
  }
13962
13964
  // Track initial page view
13963
13965
  this.trackPageView();
13966
+ // Start heartbeat to update session duration every 30 seconds
13967
+ this.startHeartbeat();
13964
13968
  }).catch((err) => {
13965
13969
  console.error('[DevSkin] Failed to create session:', err);
13966
13970
  });
@@ -14180,42 +14184,68 @@
14180
14184
  document.addEventListener('visibilitychange', () => {
14181
14185
  var _a, _b;
14182
14186
  if (document.hidden) {
14183
- // User switched tabs or minimized - flush immediately
14187
+ // User switched tabs or minimized - update duration and flush
14188
+ this.updateSessionDuration();
14184
14189
  (_a = this.rrwebRecorder) === null || _a === void 0 ? void 0 : _a.stop(); // Stop recording and flush
14185
14190
  (_b = this.transport) === null || _b === void 0 ? void 0 : _b.flush(true); // Use beacon
14186
14191
  }
14187
14192
  });
14188
14193
  // 2. pagehide - fires when page is being unloaded
14189
14194
  window.addEventListener('pagehide', (event) => {
14190
- var _a, _b, _c;
14195
+ var _a, _b;
14191
14196
  const isActualClose = !event.persisted;
14192
14197
  if (isActualClose) {
14193
14198
  // Tab is closing - end session
14194
14199
  this.track('page_unload');
14195
- if (this.sessionId && this.sessionStartTime) {
14196
- const endedAt = new Date();
14197
- const durationMs = Date.now() - this.sessionStartTime;
14198
- (_a = this.transport) === null || _a === void 0 ? void 0 : _a.startSession(Object.assign({ sessionId: this.sessionId, userId: this.userId || undefined, anonymousId: this.anonymousId, endedAt: endedAt.toISOString(), durationMs: durationMs, platform: 'web' }, this.getContextData()));
14199
- // Clear session storage since session is ending
14200
- sessionStorage.removeItem('devskin_session_id');
14201
- sessionStorage.removeItem('devskin_session_start');
14202
- }
14200
+ this.updateSessionDuration(true); // true = session ending
14201
+ // Clear session storage since session is ending
14202
+ sessionStorage.removeItem('devskin_session_id');
14203
+ sessionStorage.removeItem('devskin_session_start');
14203
14204
  }
14204
14205
  else {
14205
14206
  // Navigation - track page change
14206
14207
  this.track('page_navigation');
14208
+ this.updateSessionDuration();
14207
14209
  }
14208
14210
  // ALWAYS flush (whether navigation or close)
14209
- (_b = this.rrwebRecorder) === null || _b === void 0 ? void 0 : _b.stop(); // Stop recording and flush remaining events
14210
- (_c = this.transport) === null || _c === void 0 ? void 0 : _c.flush(true); // Use beacon for reliability
14211
+ (_a = this.rrwebRecorder) === null || _a === void 0 ? void 0 : _a.stop(); // Stop recording and flush remaining events
14212
+ (_b = this.transport) === null || _b === void 0 ? void 0 : _b.flush(true); // Use beacon for reliability
14211
14213
  });
14212
14214
  // 3. beforeunload - backup for older browsers
14213
14215
  window.addEventListener('beforeunload', () => {
14214
14216
  var _a, _b;
14217
+ this.updateSessionDuration(true);
14215
14218
  (_a = this.rrwebRecorder) === null || _a === void 0 ? void 0 : _a.stop();
14216
14219
  (_b = this.transport) === null || _b === void 0 ? void 0 : _b.flush(true);
14217
14220
  });
14218
14221
  }
14222
+ /**
14223
+ * Start heartbeat to update session duration periodically
14224
+ */
14225
+ startHeartbeat() {
14226
+ // Update duration every 30 seconds
14227
+ this.heartbeatInterval = setInterval(() => {
14228
+ this.updateSessionDuration();
14229
+ }, 30000); // 30 seconds
14230
+ }
14231
+ /**
14232
+ * Update session duration
14233
+ */
14234
+ updateSessionDuration(isEnding = false) {
14235
+ var _a, _b;
14236
+ if (!this.sessionId || !this.sessionStartTime)
14237
+ return;
14238
+ const durationMs = Date.now() - this.sessionStartTime;
14239
+ const payload = Object.assign({ sessionId: this.sessionId, userId: this.userId || undefined, anonymousId: this.anonymousId, durationMs: durationMs, platform: 'web' }, this.getContextData());
14240
+ if (isEnding) {
14241
+ payload.endedAt = new Date().toISOString();
14242
+ }
14243
+ // Use beacon if ending, otherwise regular request
14244
+ (_a = this.transport) === null || _a === void 0 ? void 0 : _a.startSession(payload, isEnding);
14245
+ if ((_b = this.config) === null || _b === void 0 ? void 0 : _b.debug) {
14246
+ console.log('[DevSkin] Session duration updated:', durationMs, 'ms', isEnding ? '(ending)' : '');
14247
+ }
14248
+ }
14219
14249
  }
14220
14250
  // Create singleton instance
14221
14251
  const DevSkin = new DevSkinSDK();