@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/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,24 @@
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
+ // CRITICAL: Ensure FullSnapshot is always first event
19048
+ if (this.events.length === 0 && event.type !== 2) {
19049
+ console.warn(`[Zaplier] First event is type ${event.type}, not FullSnapshot (2). Skipping until FullSnapshot.`);
19050
+ return; // Skip non-FullSnapshot events if no FullSnapshot captured yet
19051
+ }
19052
+ // Simple event capture
19053
+ this.events.push(event);
19054
+ if (event.type === 2) {
19055
+ console.log(`[Zaplier] ✅ FullSnapshot captured as event #${this.events.length}`);
19056
+ }
19060
19057
  },
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
19058
  });
19069
19059
  this.isActive = true;
19070
- this.hasFullSnapshot = false;
19071
- this.startTime = Date.now();
19072
19060
  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");
19061
+ console.log("[Zaplier] Session replay started - simple mode");
19108
19062
  return true;
19109
19063
  }
19110
19064
  catch (error) {
@@ -19128,87 +19082,9 @@
19128
19082
  clearInterval(this.batchTimer);
19129
19083
  this.batchTimer = undefined;
19130
19084
  }
19131
- if (this.snapshotTimeout) {
19132
- clearTimeout(this.snapshotTimeout);
19133
- this.snapshotTimeout = undefined;
19134
- }
19135
19085
  // Send final batch
19136
19086
  this.sendBatch();
19137
19087
  }
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
19088
  /**
19213
19089
  * Start batch timer
19214
19090
  */
@@ -19218,48 +19094,29 @@
19218
19094
  }, this.config.batchInterval);
19219
19095
  }
19220
19096
  /**
19221
- * Send batch of events
19097
+ * Send batch of events - Simplified like official example
19222
19098
  */
19223
19099
  sendBatch() {
19224
19100
  if (this.events.length === 0) {
19225
19101
  return;
19226
19102
  }
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) });
19103
+ // Simple payload structure like official example
19253
19104
  const payload = {
19254
19105
  sessionId: this.sessionId,
19255
- events: batch,
19106
+ events: [...this.events], // Copy events array
19256
19107
  metadata: {
19257
19108
  userAgent: navigator.userAgent,
19258
19109
  timestamp: Date.now(),
19259
- compression: this.config.compressionEnabled,
19110
+ startUrl: window.location.href,
19111
+ duration: Date.now() - (performance.timeOrigin || Date.now()),
19112
+ funnelSteps: [],
19113
+ hasConversion: false,
19260
19114
  },
19261
19115
  };
19262
- // This will be handled by the anti-adblock manager
19116
+ // Reset events array like official example
19117
+ this.events = [];
19118
+ console.log(`[Zaplier] Sending batch with ${payload.events.length} events`);
19119
+ // Send to backend
19263
19120
  this.sendToBackend(payload);
19264
19121
  }
19265
19122
  /**
@@ -19277,24 +19134,8 @@
19277
19134
  console.error("[Zaplier] No SDK instance available for replay transport");
19278
19135
  return;
19279
19136
  }
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
- });
19137
+ // Use SDK's sendReplayBatch method with simplified payload
19138
+ const result = await this.sdkInstance.sendReplayBatch(payload);
19298
19139
  if (result && result.success) {
19299
19140
  console.log("[Zaplier] Session replay batch sent successfully");
19300
19141
  }
@@ -19424,8 +19265,6 @@
19424
19265
  // When explicitly enabled, use 100% sample rate
19425
19266
  this.replayEngine = new SessionReplayEngine(sessionId, {
19426
19267
  sampleRate: 1.0, // Force 100% when explicitly enabled
19427
- maskSensitiveFields: this.config.replayMaskInputs,
19428
- compressionEnabled: true,
19429
19268
  });
19430
19269
  // Connect to anti-adblock manager
19431
19270
  if (this.antiAdblockManager) {
@@ -19452,8 +19291,6 @@
19452
19291
  const sessionId = this.sessionId;
19453
19292
  this.replayEngine = new SessionReplayEngine(sessionId, {
19454
19293
  sampleRate: 1.0, // Force 100% when explicitly enabled
19455
- maskSensitiveFields: this.config.replayMaskInputs,
19456
- compressionEnabled: true,
19457
19294
  });
19458
19295
  // Connect to anti-adblock manager
19459
19296
  if (this.antiAdblockManager) {
@@ -19494,8 +19331,6 @@
19494
19331
  const sessionId = this.sessionId;
19495
19332
  this.replayEngine = new SessionReplayEngine(sessionId, {
19496
19333
  sampleRate: 1.0, // Force recording when manually started
19497
- maskSensitiveFields: this.config.replayMaskInputs,
19498
- compressionEnabled: true,
19499
19334
  });
19500
19335
  // Connect to anti-adblock manager
19501
19336
  if (this.antiAdblockManager) {
@@ -19600,8 +19435,6 @@
19600
19435
  const sampleRate = this.config.replay === true ? 1.0 : this.config.replaySampling;
19601
19436
  this.replayEngine = new SessionReplayEngine(this.sessionId, {
19602
19437
  sampleRate: sampleRate,
19603
- maskSensitiveFields: this.config.replayMaskInputs,
19604
- compressionEnabled: true,
19605
19438
  });
19606
19439
  // Connect SDK instance for transport
19607
19440
  this.replayEngine.setSDKInstance(this);