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