@devskin/browser-sdk 1.0.33 → 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.
@@ -13860,6 +13860,7 @@ class DevSkinSDK {
13860
13860
  this.anonymousId = null;
13861
13861
  this.sessionStartTime = 0;
13862
13862
  this.initialized = false;
13863
+ this.heartbeatInterval = null;
13863
13864
  // Collectors
13864
13865
  this.deviceCollector = null;
13865
13866
  this.locationCollector = null;
@@ -13960,6 +13961,8 @@ class DevSkinSDK {
13960
13961
  }
13961
13962
  // Track initial page view
13962
13963
  this.trackPageView();
13964
+ // Start heartbeat to update session duration every 30 seconds
13965
+ this.startHeartbeat();
13963
13966
  }).catch((err) => {
13964
13967
  console.error('[DevSkin] Failed to create session:', err);
13965
13968
  });
@@ -14179,43 +14182,68 @@ class DevSkinSDK {
14179
14182
  document.addEventListener('visibilitychange', () => {
14180
14183
  var _a, _b;
14181
14184
  if (document.hidden) {
14182
- // User switched tabs or minimized - flush immediately
14185
+ // User switched tabs or minimized - update duration and flush
14186
+ this.updateSessionDuration();
14183
14187
  (_a = this.rrwebRecorder) === null || _a === void 0 ? void 0 : _a.stop(); // Stop recording and flush
14184
14188
  (_b = this.transport) === null || _b === void 0 ? void 0 : _b.flush(true); // Use beacon
14185
14189
  }
14186
14190
  });
14187
14191
  // 2. pagehide - fires when page is being unloaded
14188
14192
  window.addEventListener('pagehide', (event) => {
14189
- var _a, _b, _c;
14193
+ var _a, _b;
14190
14194
  const isActualClose = !event.persisted;
14191
14195
  if (isActualClose) {
14192
14196
  // Tab is closing - end session
14193
14197
  this.track('page_unload');
14194
- if (this.sessionId && this.sessionStartTime) {
14195
- const endedAt = new Date();
14196
- const durationMs = Date.now() - this.sessionStartTime;
14197
- // Use beacon for reliable delivery during page unload
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()), true); // true = use sendBeacon
14199
- // Clear session storage since session is ending
14200
- sessionStorage.removeItem('devskin_session_id');
14201
- sessionStorage.removeItem('devskin_session_start');
14202
- }
14198
+ this.updateSessionDuration(true); // true = session ending
14199
+ // Clear session storage since session is ending
14200
+ sessionStorage.removeItem('devskin_session_id');
14201
+ sessionStorage.removeItem('devskin_session_start');
14203
14202
  }
14204
14203
  else {
14205
14204
  // Navigation - track page change
14206
14205
  this.track('page_navigation');
14206
+ this.updateSessionDuration();
14207
14207
  }
14208
14208
  // 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
14209
+ (_a = this.rrwebRecorder) === null || _a === void 0 ? void 0 : _a.stop(); // Stop recording and flush remaining events
14210
+ (_b = this.transport) === null || _b === void 0 ? void 0 : _b.flush(true); // Use beacon for reliability
14211
14211
  });
14212
14212
  // 3. beforeunload - backup for older browsers
14213
14213
  window.addEventListener('beforeunload', () => {
14214
14214
  var _a, _b;
14215
+ this.updateSessionDuration(true);
14215
14216
  (_a = this.rrwebRecorder) === null || _a === void 0 ? void 0 : _a.stop();
14216
14217
  (_b = this.transport) === null || _b === void 0 ? void 0 : _b.flush(true);
14217
14218
  });
14218
14219
  }
14220
+ /**
14221
+ * Start heartbeat to update session duration periodically
14222
+ */
14223
+ startHeartbeat() {
14224
+ // Update duration every 30 seconds
14225
+ this.heartbeatInterval = setInterval(() => {
14226
+ this.updateSessionDuration();
14227
+ }, 30000); // 30 seconds
14228
+ }
14229
+ /**
14230
+ * Update session duration
14231
+ */
14232
+ updateSessionDuration(isEnding = false) {
14233
+ var _a, _b;
14234
+ if (!this.sessionId || !this.sessionStartTime)
14235
+ return;
14236
+ const durationMs = Date.now() - this.sessionStartTime;
14237
+ const payload = Object.assign({ sessionId: this.sessionId, userId: this.userId || undefined, anonymousId: this.anonymousId, durationMs: durationMs, platform: 'web' }, this.getContextData());
14238
+ if (isEnding) {
14239
+ payload.endedAt = new Date().toISOString();
14240
+ }
14241
+ // Use beacon if ending, otherwise regular request
14242
+ (_a = this.transport) === null || _a === void 0 ? void 0 : _a.startSession(payload, isEnding);
14243
+ if ((_b = this.config) === null || _b === void 0 ? void 0 : _b.debug) {
14244
+ console.log('[DevSkin] Session duration updated:', durationMs, 'ms', isEnding ? '(ending)' : '');
14245
+ }
14246
+ }
14219
14247
  }
14220
14248
  // Create singleton instance
14221
14249
  const DevSkin = new DevSkinSDK();