@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.
@@ -13862,6 +13862,7 @@
13862
13862
  this.anonymousId = null;
13863
13863
  this.sessionStartTime = 0;
13864
13864
  this.initialized = false;
13865
+ this.heartbeatInterval = null;
13865
13866
  // Collectors
13866
13867
  this.deviceCollector = null;
13867
13868
  this.locationCollector = null;
@@ -13962,6 +13963,8 @@
13962
13963
  }
13963
13964
  // Track initial page view
13964
13965
  this.trackPageView();
13966
+ // Start heartbeat to update session duration every 30 seconds
13967
+ this.startHeartbeat();
13965
13968
  }).catch((err) => {
13966
13969
  console.error('[DevSkin] Failed to create session:', err);
13967
13970
  });
@@ -14181,43 +14184,68 @@
14181
14184
  document.addEventListener('visibilitychange', () => {
14182
14185
  var _a, _b;
14183
14186
  if (document.hidden) {
14184
- // User switched tabs or minimized - flush immediately
14187
+ // User switched tabs or minimized - update duration and flush
14188
+ this.updateSessionDuration();
14185
14189
  (_a = this.rrwebRecorder) === null || _a === void 0 ? void 0 : _a.stop(); // Stop recording and flush
14186
14190
  (_b = this.transport) === null || _b === void 0 ? void 0 : _b.flush(true); // Use beacon
14187
14191
  }
14188
14192
  });
14189
14193
  // 2. pagehide - fires when page is being unloaded
14190
14194
  window.addEventListener('pagehide', (event) => {
14191
- var _a, _b, _c;
14195
+ var _a, _b;
14192
14196
  const isActualClose = !event.persisted;
14193
14197
  if (isActualClose) {
14194
14198
  // Tab is closing - end session
14195
14199
  this.track('page_unload');
14196
- if (this.sessionId && this.sessionStartTime) {
14197
- const endedAt = new Date();
14198
- const durationMs = Date.now() - this.sessionStartTime;
14199
- // Use beacon for reliable delivery during page unload
14200
- (_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
14201
- // Clear session storage since session is ending
14202
- sessionStorage.removeItem('devskin_session_id');
14203
- sessionStorage.removeItem('devskin_session_start');
14204
- }
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');
14205
14204
  }
14206
14205
  else {
14207
14206
  // Navigation - track page change
14208
14207
  this.track('page_navigation');
14208
+ this.updateSessionDuration();
14209
14209
  }
14210
14210
  // ALWAYS flush (whether navigation or close)
14211
- (_b = this.rrwebRecorder) === null || _b === void 0 ? void 0 : _b.stop(); // Stop recording and flush remaining events
14212
- (_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
14213
14213
  });
14214
14214
  // 3. beforeunload - backup for older browsers
14215
14215
  window.addEventListener('beforeunload', () => {
14216
14216
  var _a, _b;
14217
+ this.updateSessionDuration(true);
14217
14218
  (_a = this.rrwebRecorder) === null || _a === void 0 ? void 0 : _a.stop();
14218
14219
  (_b = this.transport) === null || _b === void 0 ? void 0 : _b.flush(true);
14219
14220
  });
14220
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
+ }
14221
14249
  }
14222
14250
  // Create singleton instance
14223
14251
  const DevSkin = new DevSkinSDK();