@devskin/browser-sdk 1.0.3 → 1.0.5

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.
@@ -4989,6 +4989,7 @@
4989
4989
  this.events = [];
4990
4990
  this.onEventsReady = null;
4991
4991
  this.flushInterval = null;
4992
+ this.hasFullSnapshot = false;
4992
4993
  this.sessionId = sessionId;
4993
4994
  this.config = config;
4994
4995
  this.onEventsReady = onEventsReady;
@@ -5006,9 +5007,15 @@
5006
5007
  console.log('[RRWeb] Starting session recording:', this.sessionId);
5007
5008
  this.stopFn = record({
5008
5009
  emit: (event) => {
5010
+ // Check if this is a FullSnapshot (type 2)
5011
+ if (event.type === 2) {
5012
+ this.hasFullSnapshot = true;
5013
+ console.log('[RRWeb] FullSnapshot captured! Recording is ready.');
5014
+ }
5009
5015
  this.events.push(event);
5010
- // Flush events periodically to avoid memory buildup
5011
- if (this.events.length >= 50) {
5016
+ // Only flush if we have the FullSnapshot
5017
+ // This ensures the first batch always contains the full DOM
5018
+ if (this.hasFullSnapshot && this.events.length >= 50) {
5012
5019
  this.flush();
5013
5020
  }
5014
5021
  },
@@ -5048,8 +5055,9 @@
5048
5055
  recordCrossOriginIframes: false, // Security: don't record cross-origin iframes
5049
5056
  });
5050
5057
  // Set up periodic flush (every 10 seconds)
5058
+ // Only flush if we have FullSnapshot to ensure first batch is complete
5051
5059
  this.flushInterval = window.setInterval(() => {
5052
- if (this.events.length > 0) {
5060
+ if (this.hasFullSnapshot && this.events.length > 0) {
5053
5061
  this.flush();
5054
5062
  }
5055
5063
  }, 10000);
@@ -5069,8 +5077,11 @@
5069
5077
  clearInterval(this.flushInterval);
5070
5078
  this.flushInterval = null;
5071
5079
  }
5072
- // Flush remaining events
5080
+ // Flush remaining events (even without FullSnapshot, to not lose data)
5073
5081
  if (this.events.length > 0) {
5082
+ if (!this.hasFullSnapshot) {
5083
+ console.warn('[RRWeb] Flushing events without FullSnapshot - recording may not replay correctly');
5084
+ }
5074
5085
  this.flush();
5075
5086
  }
5076
5087
  }
@@ -5135,6 +5146,13 @@
5135
5146
  this.enqueue('performance', metric);
5136
5147
  }
5137
5148
  sendRecordingEvents(sessionId, events) {
5149
+ // DEBUG: Log event types being sent
5150
+ const eventTypes = events.reduce((acc, e) => {
5151
+ acc[e.type] = (acc[e.type] || 0) + 1;
5152
+ return acc;
5153
+ }, {});
5154
+ console.log(`[DevSkin SDK] Sending ${events.length} recording events:`, eventTypes);
5155
+ console.log(`[DevSkin SDK] First 3 events:`, events.slice(0, 3).map(e => ({ type: e.type, timestamp: e.timestamp })));
5138
5156
  // Recording events can be large, send immediately
5139
5157
  this.sendToBackend('/v1/rum/recordings', {
5140
5158
  session_id: sessionId,
@@ -5264,6 +5282,7 @@
5264
5282
  this.sessionId = null;
5265
5283
  this.userId = null;
5266
5284
  this.anonymousId = null;
5285
+ this.sessionStartTime = 0;
5267
5286
  this.initialized = false;
5268
5287
  // Collectors
5269
5288
  this.deviceCollector = null;
@@ -5293,12 +5312,12 @@
5293
5312
  this.transport = new Transport(this.config);
5294
5313
  // Generate anonymous ID if not exists
5295
5314
  this.anonymousId = this.getOrCreateAnonymousId();
5296
- // Start session
5297
- this.startSession();
5298
- // Initialize collectors
5315
+ // Initialize collectors BEFORE starting session (so getContextData works)
5299
5316
  this.deviceCollector = new DeviceCollector(this.config);
5300
5317
  this.locationCollector = new LocationCollector(this.config);
5301
5318
  this.browserCollector = new BrowserCollector(this.config);
5319
+ // Start session (will now include device/browser/location data)
5320
+ this.startSession();
5302
5321
  if (this.config.captureWebVitals) {
5303
5322
  this.performanceCollector = new PerformanceCollector(this.config, this.transport);
5304
5323
  this.performanceCollector.start();
@@ -5458,6 +5477,7 @@
5458
5477
  startSession() {
5459
5478
  var _a;
5460
5479
  this.sessionId = this.generateId();
5480
+ this.sessionStartTime = Date.now();
5461
5481
  const sessionData = Object.assign({ session_id: this.sessionId, user_id: this.userId || undefined, anonymous_id: this.anonymousId, started_at: new Date().toISOString() }, this.getContextData());
5462
5482
  (_a = this.transport) === null || _a === void 0 ? void 0 : _a.startSession(sessionData);
5463
5483
  }
@@ -5497,10 +5517,20 @@
5497
5517
  }
5498
5518
  setupUnloadTracking() {
5499
5519
  window.addEventListener('beforeunload', () => {
5500
- var _a;
5520
+ var _a, _b;
5501
5521
  this.track('page_unload');
5522
+ // Send session end update with duration
5523
+ if (this.sessionId && this.sessionStartTime) {
5524
+ const endedAt = new Date();
5525
+ const durationMs = Date.now() - this.sessionStartTime;
5526
+ (_a = this.transport) === null || _a === void 0 ? void 0 : _a.startSession({
5527
+ session_id: this.sessionId,
5528
+ ended_at: endedAt.toISOString(),
5529
+ duration_ms: durationMs,
5530
+ });
5531
+ }
5502
5532
  // Send any pending data
5503
- (_a = this.transport) === null || _a === void 0 ? void 0 : _a.flush();
5533
+ (_b = this.transport) === null || _b === void 0 ? void 0 : _b.flush(true); // Use beacon for reliability
5504
5534
  });
5505
5535
  }
5506
5536
  }