@zaplier/sdk 1.3.7 → 1.4.0

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