@zaplier/sdk 1.3.6 → 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/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,58 +19039,16 @@ 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
+ // Simple event capture - no processing
19046
+ this.events.push(event);
19058
19047
  },
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
19048
  });
19067
19049
  this.isActive = true;
19068
- this.hasFullSnapshot = false;
19069
- this.startTime = Date.now();
19070
19050
  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
- console.log("[Zaplier] Forcing immediate FullSnapshot to ensure correct event order...");
19075
- try {
19076
- takeFullSnapshot(true); // Force a new FullSnapshot immediately
19077
- console.log("[Zaplier] FullSnapshot manually triggered");
19078
- }
19079
- catch (error) {
19080
- console.error("[Zaplier] Failed to force FullSnapshot:", error);
19081
- }
19082
- }, 100); // Very short delay to ensure it comes first
19083
- // Set timeout to check if FullSnapshot was captured
19084
- this.snapshotTimeout = window.setTimeout(() => {
19085
- if (!this.hasFullSnapshot) {
19086
- console.error("[Zaplier] CRITICAL: FullSnapshot not captured after 5 seconds!", {
19087
- eventsReceived: this.events.length,
19088
- eventTypes: this.events.map((e) => e.type).slice(0, 10),
19089
- });
19090
- // Try one more forced snapshot as last resort
19091
- try {
19092
- console.warn("[Zaplier] Last resort: forcing FullSnapshot...");
19093
- takeFullSnapshot(true);
19094
- }
19095
- catch (error) {
19096
- console.error("[Zaplier] Failed to create emergency FullSnapshot:", error);
19097
- }
19098
- }
19099
- else {
19100
- console.log("[Zaplier] ✅ FullSnapshot confirmed captured");
19101
- }
19102
- }, 5000);
19103
- console.log("[Zaplier] Session replay started with rrweb");
19051
+ console.log("[Zaplier] Session replay started - simple mode");
19104
19052
  return true;
19105
19053
  }
19106
19054
  catch (error) {
@@ -19124,87 +19072,9 @@ class SessionReplayEngine {
19124
19072
  clearInterval(this.batchTimer);
19125
19073
  this.batchTimer = undefined;
19126
19074
  }
19127
- if (this.snapshotTimeout) {
19128
- clearTimeout(this.snapshotTimeout);
19129
- this.snapshotTimeout = undefined;
19130
- }
19131
19075
  // Send final batch
19132
19076
  this.sendBatch();
19133
19077
  }
19134
- /**
19135
- * Handle events from rrweb
19136
- */
19137
- handleRRWebEvent(event) {
19138
- try {
19139
- // Log ALL events until we get FullSnapshot, then log first 5
19140
- const shouldLog = !this.hasFullSnapshot || this.events.length < 5;
19141
- if (shouldLog) {
19142
- const eventTypeNames = {
19143
- [EventType.DomContentLoaded]: "DomContentLoaded",
19144
- [EventType.Load]: "Load",
19145
- [EventType.FullSnapshot]: "FullSnapshot",
19146
- [EventType.IncrementalSnapshot]: "IncrementalSnapshot",
19147
- [EventType.Meta]: "Meta",
19148
- [EventType.Custom]: "Custom",
19149
- [EventType.Plugin]: "Plugin",
19150
- };
19151
- console.log(`[Zaplier] Received event type ${event.type} (${eventTypeNames[event.type] || "Unknown"})`, {
19152
- timestamp: new Date(event.timestamp).toISOString(),
19153
- isFirst: this.events.length === 0,
19154
- totalEvents: this.events.length + 1,
19155
- });
19156
- }
19157
- // Check if this is a FullSnapshot
19158
- if (event.type === EventType.FullSnapshot) {
19159
- this.hasFullSnapshot = true;
19160
- console.log("[Zaplier] ✅ FullSnapshot captured! Replay will work correctly.");
19161
- // Clear timeout since we got the snapshot
19162
- if (this.snapshotTimeout) {
19163
- clearTimeout(this.snapshotTimeout);
19164
- this.snapshotTimeout = undefined;
19165
- }
19166
- }
19167
- else if (this.events.length === 0) {
19168
- // First event is NOT a FullSnapshot - this is a problem!
19169
- console.error(`[Zaplier] ⚠️ WARNING: First event is type ${event.type}, not FullSnapshot! Replay may not work.`);
19170
- }
19171
- // Add event to buffer
19172
- this.addEvent(event);
19173
- // If we just got the FullSnapshot and have events, try sending immediately
19174
- if (event.type === EventType.FullSnapshot && this.events.length > 0) {
19175
- // Small delay to ensure all initial events are captured
19176
- setTimeout(() => {
19177
- this.sendBatch();
19178
- }, 100);
19179
- }
19180
- }
19181
- catch (error) {
19182
- // Silently ignore errors from rrweb to prevent breaking the app
19183
- // The error is likely from rrweb's internal processing
19184
- console.warn("[Zaplier] Error handling rrweb event:", error);
19185
- }
19186
- }
19187
- /**
19188
- * Add event to buffer
19189
- */
19190
- addEvent(event) {
19191
- this.events.push(event);
19192
- // Prevent memory overflow
19193
- if (this.events.length > this.config.maxEventBuffer) {
19194
- // Keep FullSnapshot if present
19195
- const fullSnapshotIndex = this.events.findIndex((e) => e.type === EventType.FullSnapshot);
19196
- if (fullSnapshotIndex >= 0 &&
19197
- fullSnapshotIndex < this.events.length - this.config.maxEventBuffer) {
19198
- // Keep snapshot and recent events
19199
- const snapshot = this.events[fullSnapshotIndex];
19200
- const recentEvents = this.events.slice(-this.config.maxEventBuffer + 1);
19201
- this.events = [snapshot, ...recentEvents];
19202
- }
19203
- else {
19204
- this.events = this.events.slice(-this.config.maxEventBuffer);
19205
- }
19206
- }
19207
- }
19208
19078
  /**
19209
19079
  * Start batch timer
19210
19080
  */
@@ -19214,39 +19084,29 @@ class SessionReplayEngine {
19214
19084
  }, this.config.batchInterval);
19215
19085
  }
19216
19086
  /**
19217
- * Send batch of events
19087
+ * Send batch of events - Simplified like official example
19218
19088
  */
19219
19089
  sendBatch() {
19220
19090
  if (this.events.length === 0) {
19221
19091
  return;
19222
19092
  }
19223
- // CRITICAL: Never send batches without FullSnapshot - replay won't work!
19224
- if (!this.hasFullSnapshot) {
19225
- const waitTime = Date.now() - this.startTime;
19226
- // Only log every 2 seconds to avoid spam
19227
- if (waitTime % 2000 < 100) {
19228
- 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));
19229
- }
19230
- return; // Don't send without FullSnapshot
19231
- }
19232
- const batch = [...this.events];
19233
- this.events = [];
19234
- // Verify batch has FullSnapshot
19235
- const hasSnapshot = batch.some((e) => e.type === EventType.FullSnapshot);
19236
- if (!hasSnapshot && this.hasFullSnapshot) {
19237
- console.warn("[Zaplier] Batch missing FullSnapshot, but one was captured earlier");
19238
- }
19239
- console.log(`[Zaplier] Sending batch with ${batch.length} events for session ${this.sessionId}`, { hasSnapshot, firstEventType: batch[0]?.type });
19093
+ // Simple payload structure like official example
19240
19094
  const payload = {
19241
19095
  sessionId: this.sessionId,
19242
- events: batch,
19096
+ events: [...this.events], // Copy events array
19243
19097
  metadata: {
19244
19098
  userAgent: navigator.userAgent,
19245
19099
  timestamp: Date.now(),
19246
- compression: this.config.compressionEnabled,
19100
+ startUrl: window.location.href,
19101
+ duration: Date.now() - (performance.timeOrigin || Date.now()),
19102
+ funnelSteps: [],
19103
+ hasConversion: false,
19247
19104
  },
19248
19105
  };
19249
- // This will be handled by the anti-adblock manager
19106
+ // Reset events array like official example
19107
+ this.events = [];
19108
+ console.log(`[Zaplier] Sending batch with ${payload.events.length} events`);
19109
+ // Send to backend
19250
19110
  this.sendToBackend(payload);
19251
19111
  }
19252
19112
  /**
@@ -19264,24 +19124,8 @@ class SessionReplayEngine {
19264
19124
  console.error("[Zaplier] No SDK instance available for replay transport");
19265
19125
  return;
19266
19126
  }
19267
- console.log(`[Zaplier] Sending replay batch via SDK transport`);
19268
- console.log(`[Zaplier] Payload:`, {
19269
- sessionId: payload.sessionId,
19270
- eventCount: payload.events.length,
19271
- hasMetadata: !!payload.metadata,
19272
- });
19273
- // Use SDK's sendReplayBatch method
19274
- const result = await this.sdkInstance.sendReplayBatch({
19275
- sessionId: payload.sessionId,
19276
- events: payload.events,
19277
- metadata: {
19278
- startUrl: window.location.href,
19279
- duration: Date.now() - (performance.timeOrigin || Date.now()),
19280
- funnelSteps: [],
19281
- hasConversion: false,
19282
- ...payload.metadata,
19283
- },
19284
- });
19127
+ // Use SDK's sendReplayBatch method with simplified payload
19128
+ const result = await this.sdkInstance.sendReplayBatch(payload);
19285
19129
  if (result && result.success) {
19286
19130
  console.log("[Zaplier] Session replay batch sent successfully");
19287
19131
  }
@@ -19338,7 +19182,7 @@ const DEFAULT_CONFIG = {
19338
19182
  */
19339
19183
  class ZaplierSDK {
19340
19184
  constructor(userConfig) {
19341
- this.version = "1.3.5";
19185
+ this.version = "1.3.7";
19342
19186
  this.isInitialized = false;
19343
19187
  this.eventQueue = [];
19344
19188
  /**
@@ -19411,8 +19255,6 @@ class ZaplierSDK {
19411
19255
  // When explicitly enabled, use 100% sample rate
19412
19256
  this.replayEngine = new SessionReplayEngine(sessionId, {
19413
19257
  sampleRate: 1.0, // Force 100% when explicitly enabled
19414
- maskSensitiveFields: this.config.replayMaskInputs,
19415
- compressionEnabled: true,
19416
19258
  });
19417
19259
  // Connect to anti-adblock manager
19418
19260
  if (this.antiAdblockManager) {
@@ -19439,8 +19281,6 @@ class ZaplierSDK {
19439
19281
  const sessionId = this.sessionId;
19440
19282
  this.replayEngine = new SessionReplayEngine(sessionId, {
19441
19283
  sampleRate: 1.0, // Force 100% when explicitly enabled
19442
- maskSensitiveFields: this.config.replayMaskInputs,
19443
- compressionEnabled: true,
19444
19284
  });
19445
19285
  // Connect to anti-adblock manager
19446
19286
  if (this.antiAdblockManager) {
@@ -19481,8 +19321,6 @@ class ZaplierSDK {
19481
19321
  const sessionId = this.sessionId;
19482
19322
  this.replayEngine = new SessionReplayEngine(sessionId, {
19483
19323
  sampleRate: 1.0, // Force recording when manually started
19484
- maskSensitiveFields: this.config.replayMaskInputs,
19485
- compressionEnabled: true,
19486
19324
  });
19487
19325
  // Connect to anti-adblock manager
19488
19326
  if (this.antiAdblockManager) {
@@ -19587,8 +19425,6 @@ class ZaplierSDK {
19587
19425
  const sampleRate = this.config.replay === true ? 1.0 : this.config.replaySampling;
19588
19426
  this.replayEngine = new SessionReplayEngine(this.sessionId, {
19589
19427
  sampleRate: sampleRate,
19590
- maskSensitiveFields: this.config.replayMaskInputs,
19591
- compressionEnabled: true,
19592
19428
  });
19593
19429
  // Connect SDK instance for transport
19594
19430
  this.replayEngine.setSDKInstance(this);