@zaplier/sdk 1.3.7 → 1.4.1

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.
package/dist/index.cjs CHANGED
@@ -19010,35 +19010,25 @@ var n;
19010
19010
  !function(t2) {
19011
19011
  t2[t2.NotStarted = 0] = "NotStarted", t2[t2.Running = 1] = "Running", t2[t2.Stopped = 2] = "Stopped";
19012
19012
  }(n || (n = {}));
19013
- const { takeFullSnapshot } = record;
19014
19013
 
19015
19014
  /**
19016
- * Session Replay Engine
19017
- * Uses rrweb to capture DOM snapshots and events for session replay
19015
+ * Session Replay Engine - Simplified Implementation
19016
+ * Based on official rrweb example for maximum compatibility
19018
19017
  */
19019
19018
  class SessionReplayEngine {
19020
19019
  constructor(sessionId, config = {}) {
19021
19020
  this.events = [];
19022
19021
  this.isActive = false;
19023
- this.hasFullSnapshot = false;
19024
- this.startTime = 0;
19025
19022
  this.sessionId = sessionId;
19026
19023
  this.config = {
19027
19024
  enabled: true,
19028
- sampleRate: 1.0, // 100% for development/testing
19029
- maskSensitiveFields: true,
19030
- maxEventBuffer: 1000,
19031
- batchInterval: 2000, // Send every 2 seconds for faster testing
19032
- captureClicks: true,
19033
- captureScrolls: true,
19034
- captureInputs: true,
19035
- captureMouseMoves: false, // Disabled by default for performance
19036
- compressionEnabled: true,
19025
+ sampleRate: 1.0,
19026
+ batchInterval: 10000, // 10 seconds like official example
19037
19027
  ...config,
19038
19028
  };
19039
19029
  }
19040
19030
  /**
19041
- * Start session replay recording using rrweb
19031
+ * Start session replay recording - Simplified like official example
19042
19032
  */
19043
19033
  start() {
19044
19034
  if (!this.config.enabled || this.isActive) {
@@ -19049,60 +19039,24 @@ class SessionReplayEngine {
19049
19039
  return false;
19050
19040
  }
19051
19041
  try {
19052
- // Start rrweb recording
19053
- // Using minimal configuration to avoid known bugs in alpha versions
19054
- // blockSelector and maskTextSelector removed due to node.matches error
19042
+ // Simple rrweb recording configuration like official example
19055
19043
  this.rrwebStopRecord = record({
19056
19044
  emit: (event) => {
19057
- this.handleRRWebEvent(event);
19045
+ // CRITICAL: Ensure FullSnapshot is always first event
19046
+ if (this.events.length === 0 && event.type !== 2) {
19047
+ console.warn(`[Zaplier] First event is type ${event.type}, not FullSnapshot (2). Skipping until FullSnapshot.`);
19048
+ return; // Skip non-FullSnapshot events if no FullSnapshot captured yet
19049
+ }
19050
+ // Simple event capture
19051
+ this.events.push(event);
19052
+ if (event.type === 2) {
19053
+ console.log(`[Zaplier] ✅ FullSnapshot captured as event #${this.events.length}`);
19054
+ }
19058
19055
  },
19059
- maskAllInputs: this.config.maskSensitiveFields,
19060
- // maskTextSelector removed - causes node.matches error in some cases
19061
- // blockSelector removed - causes node.matches error
19062
- recordCanvas: false, // Disable canvas recording for performance
19063
- recordCrossOriginIframes: false,
19064
- inlineStylesheet: true,
19065
- collectFonts: false, // Disable font collection for smaller payloads
19066
19056
  });
19067
19057
  this.isActive = true;
19068
- this.hasFullSnapshot = false;
19069
- this.startTime = Date.now();
19070
19058
  this.startBatchTimer();
19071
- // WORKAROUND: Force FullSnapshot creation IMMEDIATELY to fix rrweb 2.0.0-alpha bug
19072
- // where FullSnapshot is sometimes not created as the first event
19073
- setTimeout(() => {
19074
- if (!this.hasFullSnapshot) {
19075
- console.log("[Zaplier] Forcing immediate FullSnapshot to ensure correct event order...");
19076
- try {
19077
- takeFullSnapshot(true); // Force a new FullSnapshot immediately
19078
- console.log("[Zaplier] FullSnapshot manually triggered");
19079
- }
19080
- catch (error) {
19081
- console.error("[Zaplier] Failed to force FullSnapshot:", error);
19082
- }
19083
- }
19084
- }, 50); // Very short delay but let natural events come first
19085
- // Set timeout to check if FullSnapshot was captured
19086
- this.snapshotTimeout = window.setTimeout(() => {
19087
- if (!this.hasFullSnapshot) {
19088
- console.error("[Zaplier] CRITICAL: FullSnapshot not captured after 5 seconds!", {
19089
- eventsReceived: this.events.length,
19090
- eventTypes: this.events.map((e) => e.type).slice(0, 10),
19091
- });
19092
- // Try one more forced snapshot as last resort
19093
- try {
19094
- console.warn("[Zaplier] Last resort: forcing FullSnapshot...");
19095
- takeFullSnapshot(true);
19096
- }
19097
- catch (error) {
19098
- console.error("[Zaplier] Failed to create emergency FullSnapshot:", error);
19099
- }
19100
- }
19101
- else {
19102
- console.log("[Zaplier] ✅ FullSnapshot confirmed captured");
19103
- }
19104
- }, 5000);
19105
- console.log("[Zaplier] Session replay started with rrweb");
19059
+ console.log("[Zaplier] Session replay started - simple mode");
19106
19060
  return true;
19107
19061
  }
19108
19062
  catch (error) {
@@ -19126,87 +19080,9 @@ class SessionReplayEngine {
19126
19080
  clearInterval(this.batchTimer);
19127
19081
  this.batchTimer = undefined;
19128
19082
  }
19129
- if (this.snapshotTimeout) {
19130
- clearTimeout(this.snapshotTimeout);
19131
- this.snapshotTimeout = undefined;
19132
- }
19133
19083
  // Send final batch
19134
19084
  this.sendBatch();
19135
19085
  }
19136
- /**
19137
- * Handle events from rrweb
19138
- */
19139
- handleRRWebEvent(event) {
19140
- try {
19141
- // Log ALL events until we get FullSnapshot, then log first 5
19142
- const shouldLog = !this.hasFullSnapshot || this.events.length < 5;
19143
- if (shouldLog) {
19144
- const eventTypeNames = {
19145
- [EventType.DomContentLoaded]: "DomContentLoaded",
19146
- [EventType.Load]: "Load",
19147
- [EventType.FullSnapshot]: "FullSnapshot",
19148
- [EventType.IncrementalSnapshot]: "IncrementalSnapshot",
19149
- [EventType.Meta]: "Meta",
19150
- [EventType.Custom]: "Custom",
19151
- [EventType.Plugin]: "Plugin",
19152
- };
19153
- console.log(`[Zaplier] Received event type ${event.type} (${eventTypeNames[event.type] || "Unknown"})`, {
19154
- timestamp: new Date(event.timestamp).toISOString(),
19155
- isFirst: this.events.length === 0,
19156
- totalEvents: this.events.length + 1,
19157
- });
19158
- }
19159
- // Check if this is a FullSnapshot
19160
- if (event.type === EventType.FullSnapshot) {
19161
- this.hasFullSnapshot = true;
19162
- console.log("[Zaplier] ✅ FullSnapshot captured! Replay will work correctly.");
19163
- // Clear timeout since we got the snapshot
19164
- if (this.snapshotTimeout) {
19165
- clearTimeout(this.snapshotTimeout);
19166
- this.snapshotTimeout = undefined;
19167
- }
19168
- }
19169
- else if (this.events.length === 0) {
19170
- // First event is NOT a FullSnapshot - this is a problem!
19171
- console.error(`[Zaplier] ⚠️ WARNING: First event is type ${event.type}, not FullSnapshot! Replay may not work.`);
19172
- }
19173
- // Add event to buffer
19174
- this.addEvent(event);
19175
- // If we just got the FullSnapshot and have events, try sending immediately
19176
- if (event.type === EventType.FullSnapshot && this.events.length > 0) {
19177
- // Small delay to ensure all initial events are captured
19178
- setTimeout(() => {
19179
- this.sendBatch();
19180
- }, 100);
19181
- }
19182
- }
19183
- catch (error) {
19184
- // Silently ignore errors from rrweb to prevent breaking the app
19185
- // The error is likely from rrweb's internal processing
19186
- console.warn("[Zaplier] Error handling rrweb event:", error);
19187
- }
19188
- }
19189
- /**
19190
- * Add event to buffer
19191
- */
19192
- addEvent(event) {
19193
- this.events.push(event);
19194
- // Prevent memory overflow
19195
- if (this.events.length > this.config.maxEventBuffer) {
19196
- // Keep FullSnapshot if present
19197
- const fullSnapshotIndex = this.events.findIndex((e) => e.type === EventType.FullSnapshot);
19198
- if (fullSnapshotIndex >= 0 &&
19199
- fullSnapshotIndex < this.events.length - this.config.maxEventBuffer) {
19200
- // Keep snapshot and recent events
19201
- const snapshot = this.events[fullSnapshotIndex];
19202
- const recentEvents = this.events.slice(-this.config.maxEventBuffer + 1);
19203
- this.events = [snapshot, ...recentEvents];
19204
- }
19205
- else {
19206
- this.events = this.events.slice(-this.config.maxEventBuffer);
19207
- }
19208
- }
19209
- }
19210
19086
  /**
19211
19087
  * Start batch timer
19212
19088
  */
@@ -19216,48 +19092,29 @@ class SessionReplayEngine {
19216
19092
  }, this.config.batchInterval);
19217
19093
  }
19218
19094
  /**
19219
- * Send batch of events
19095
+ * Send batch of events - Simplified like official example
19220
19096
  */
19221
19097
  sendBatch() {
19222
19098
  if (this.events.length === 0) {
19223
19099
  return;
19224
19100
  }
19225
- // CRITICAL: Never send batches without FullSnapshot - replay won't work!
19226
- if (!this.hasFullSnapshot) {
19227
- const waitTime = Date.now() - this.startTime;
19228
- // Only log every 2 seconds to avoid spam
19229
- if (waitTime % 2000 < 100) {
19230
- console.warn(`[Zaplier] Waiting for FullSnapshot before sending batch... (${Math.floor(waitTime / 1000)}s). Events so far: ${this.events.length}, types:`, this.events.map((e) => e.type).slice(0, 5));
19231
- }
19232
- return; // Don't send without FullSnapshot
19233
- }
19234
- const batch = [...this.events];
19235
- this.events = [];
19236
- // IMPORTANT: Ensure FullSnapshot comes first in the batch
19237
- const fullSnapshotIndex = batch.findIndex((e) => e.type === EventType.FullSnapshot);
19238
- if (fullSnapshotIndex > 0) {
19239
- console.log("[Zaplier] Reordering events - moving FullSnapshot to first position");
19240
- const fullSnapshot = batch.splice(fullSnapshotIndex, 1)[0];
19241
- if (fullSnapshot) {
19242
- batch.unshift(fullSnapshot);
19243
- }
19244
- }
19245
- // Verify batch has FullSnapshot
19246
- const hasSnapshot = batch.some((e) => e.type === EventType.FullSnapshot);
19247
- if (!hasSnapshot && this.hasFullSnapshot) {
19248
- console.warn("[Zaplier] Batch missing FullSnapshot, but one was captured earlier");
19249
- }
19250
- console.log(`[Zaplier] Sending batch with ${batch.length} events for session ${this.sessionId}`, { hasSnapshot, firstEventType: batch[0]?.type, eventTypes: batch.slice(0, 5).map(e => e.type) });
19101
+ // Simple payload structure like official example
19251
19102
  const payload = {
19252
19103
  sessionId: this.sessionId,
19253
- events: batch,
19104
+ events: [...this.events], // Copy events array
19254
19105
  metadata: {
19255
19106
  userAgent: navigator.userAgent,
19256
19107
  timestamp: Date.now(),
19257
- compression: this.config.compressionEnabled,
19108
+ startUrl: window.location.href,
19109
+ duration: Date.now() - (performance.timeOrigin || Date.now()),
19110
+ funnelSteps: [],
19111
+ hasConversion: false,
19258
19112
  },
19259
19113
  };
19260
- // This will be handled by the anti-adblock manager
19114
+ // Reset events array like official example
19115
+ this.events = [];
19116
+ console.log(`[Zaplier] Sending batch with ${payload.events.length} events`);
19117
+ // Send to backend
19261
19118
  this.sendToBackend(payload);
19262
19119
  }
19263
19120
  /**
@@ -19275,24 +19132,8 @@ class SessionReplayEngine {
19275
19132
  console.error("[Zaplier] No SDK instance available for replay transport");
19276
19133
  return;
19277
19134
  }
19278
- console.log(`[Zaplier] Sending replay batch via SDK transport`);
19279
- console.log(`[Zaplier] Payload:`, {
19280
- sessionId: payload.sessionId,
19281
- eventCount: payload.events.length,
19282
- hasMetadata: !!payload.metadata,
19283
- });
19284
- // Use SDK's sendReplayBatch method
19285
- const result = await this.sdkInstance.sendReplayBatch({
19286
- sessionId: payload.sessionId,
19287
- events: payload.events,
19288
- metadata: {
19289
- startUrl: window.location.href,
19290
- duration: Date.now() - (performance.timeOrigin || Date.now()),
19291
- funnelSteps: [],
19292
- hasConversion: false,
19293
- ...payload.metadata,
19294
- },
19295
- });
19135
+ // Use SDK's sendReplayBatch method with simplified payload
19136
+ const result = await this.sdkInstance.sendReplayBatch(payload);
19296
19137
  if (result && result.success) {
19297
19138
  console.log("[Zaplier] Session replay batch sent successfully");
19298
19139
  }
@@ -19422,8 +19263,6 @@ class ZaplierSDK {
19422
19263
  // When explicitly enabled, use 100% sample rate
19423
19264
  this.replayEngine = new SessionReplayEngine(sessionId, {
19424
19265
  sampleRate: 1.0, // Force 100% when explicitly enabled
19425
- maskSensitiveFields: this.config.replayMaskInputs,
19426
- compressionEnabled: true,
19427
19266
  });
19428
19267
  // Connect to anti-adblock manager
19429
19268
  if (this.antiAdblockManager) {
@@ -19450,8 +19289,6 @@ class ZaplierSDK {
19450
19289
  const sessionId = this.sessionId;
19451
19290
  this.replayEngine = new SessionReplayEngine(sessionId, {
19452
19291
  sampleRate: 1.0, // Force 100% when explicitly enabled
19453
- maskSensitiveFields: this.config.replayMaskInputs,
19454
- compressionEnabled: true,
19455
19292
  });
19456
19293
  // Connect to anti-adblock manager
19457
19294
  if (this.antiAdblockManager) {
@@ -19492,8 +19329,6 @@ class ZaplierSDK {
19492
19329
  const sessionId = this.sessionId;
19493
19330
  this.replayEngine = new SessionReplayEngine(sessionId, {
19494
19331
  sampleRate: 1.0, // Force recording when manually started
19495
- maskSensitiveFields: this.config.replayMaskInputs,
19496
- compressionEnabled: true,
19497
19332
  });
19498
19333
  // Connect to anti-adblock manager
19499
19334
  if (this.antiAdblockManager) {
@@ -19598,8 +19433,6 @@ class ZaplierSDK {
19598
19433
  const sampleRate = this.config.replay === true ? 1.0 : this.config.replaySampling;
19599
19434
  this.replayEngine = new SessionReplayEngine(this.sessionId, {
19600
19435
  sampleRate: sampleRate,
19601
- maskSensitiveFields: this.config.replayMaskInputs,
19602
- compressionEnabled: true,
19603
19436
  });
19604
19437
  // Connect SDK instance for transport
19605
19438
  this.replayEngine.setSDKInstance(this);