@zaplier/sdk 1.2.6 → 1.3.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.d.ts CHANGED
@@ -769,6 +769,14 @@ declare class ZaplierSDK implements ZaplierSDK$1 {
769
769
  * Send event to backend
770
770
  */
771
771
  private sendEvent;
772
+ /**
773
+ * Send session replay batch to backend
774
+ */
775
+ sendReplayBatch(replayData: {
776
+ sessionId: string;
777
+ events: any[];
778
+ metadata: any;
779
+ }): Promise<any>;
772
780
  /**
773
781
  * Make HTTP request to backend using anti-adblock system
774
782
  */
package/dist/index.esm.js CHANGED
@@ -6874,7 +6874,7 @@ class SessionReplayEngine {
6874
6874
  const target = event.target;
6875
6875
  const path = this.getElementPath(target);
6876
6876
  this.addEvent({
6877
- type: 'click',
6877
+ type: "click",
6878
6878
  timestamp: Date.now(),
6879
6879
  data: {
6880
6880
  x: event.clientX,
@@ -6883,9 +6883,9 @@ class SessionReplayEngine {
6883
6883
  button: event.button,
6884
6884
  ctrlKey: event.ctrlKey,
6885
6885
  shiftKey: event.shiftKey,
6886
- altKey: event.altKey
6886
+ altKey: event.altKey,
6887
6887
  },
6888
- sequence: this.sequence++
6888
+ sequence: this.sequence++,
6889
6889
  });
6890
6890
  };
6891
6891
  /**
@@ -6893,13 +6893,13 @@ class SessionReplayEngine {
6893
6893
  */
6894
6894
  this.handleScroll = () => {
6895
6895
  this.addEvent({
6896
- type: 'scroll',
6896
+ type: "scroll",
6897
6897
  timestamp: Date.now(),
6898
6898
  data: {
6899
6899
  x: window.pageXOffset || document.documentElement.scrollLeft,
6900
- y: window.pageYOffset || document.documentElement.scrollTop
6900
+ y: window.pageYOffset || document.documentElement.scrollTop,
6901
6901
  },
6902
- sequence: this.sequence++
6902
+ sequence: this.sequence++,
6903
6903
  });
6904
6904
  };
6905
6905
  /**
@@ -6911,17 +6911,17 @@ class SessionReplayEngine {
6911
6911
  let value = target.value;
6912
6912
  // Mask sensitive fields
6913
6913
  if (this.config.maskSensitiveFields && this.isSensitiveField(target)) {
6914
- value = '*'.repeat(value.length);
6914
+ value = "*".repeat(value.length);
6915
6915
  }
6916
6916
  this.addEvent({
6917
- type: 'input',
6917
+ type: "input",
6918
6918
  timestamp: Date.now(),
6919
6919
  data: {
6920
6920
  element: path,
6921
6921
  value: value,
6922
- inputType: event.inputType
6922
+ inputType: event.inputType,
6923
6923
  },
6924
- sequence: this.sequence++
6924
+ sequence: this.sequence++,
6925
6925
  });
6926
6926
  };
6927
6927
  /**
@@ -6932,17 +6932,17 @@ class SessionReplayEngine {
6932
6932
  const path = this.getElementPath(target);
6933
6933
  let value = target.value;
6934
6934
  if (this.config.maskSensitiveFields && this.isSensitiveField(target)) {
6935
- value = '*'.repeat(value.length);
6935
+ value = "*".repeat(value.length);
6936
6936
  }
6937
6937
  this.addEvent({
6938
- type: 'input',
6938
+ type: "input",
6939
6939
  timestamp: Date.now(),
6940
6940
  data: {
6941
6941
  element: path,
6942
6942
  value: value,
6943
- type: 'change'
6943
+ type: "change",
6944
6944
  },
6945
- sequence: this.sequence++
6945
+ sequence: this.sequence++,
6946
6946
  });
6947
6947
  };
6948
6948
  /**
@@ -6955,13 +6955,13 @@ class SessionReplayEngine {
6955
6955
  }
6956
6956
  this.lastMouseMove = now;
6957
6957
  this.addEvent({
6958
- type: 'mouse',
6958
+ type: "mouse",
6959
6959
  timestamp: now,
6960
6960
  data: {
6961
6961
  x: event.clientX,
6962
- y: event.clientY
6962
+ y: event.clientY,
6963
6963
  },
6964
- sequence: this.sequence++
6964
+ sequence: this.sequence++,
6965
6965
  });
6966
6966
  };
6967
6967
  /**
@@ -6969,13 +6969,13 @@ class SessionReplayEngine {
6969
6969
  */
6970
6970
  this.handleViewportChange = () => {
6971
6971
  this.addEvent({
6972
- type: 'viewport',
6972
+ type: "viewport",
6973
6973
  timestamp: Date.now(),
6974
6974
  data: {
6975
6975
  width: window.innerWidth,
6976
- height: window.innerHeight
6976
+ height: window.innerHeight,
6977
6977
  },
6978
- sequence: this.sequence++
6978
+ sequence: this.sequence++,
6979
6979
  });
6980
6980
  };
6981
6981
  /**
@@ -6997,7 +6997,7 @@ class SessionReplayEngine {
6997
6997
  captureInputs: true,
6998
6998
  captureMouseMoves: false, // Disabled by default for performance
6999
6999
  compressionEnabled: true,
7000
- ...config
7000
+ ...config,
7001
7001
  };
7002
7002
  }
7003
7003
  /**
@@ -7042,18 +7042,18 @@ class SessionReplayEngine {
7042
7042
  * Setup DOM mutation observer
7043
7043
  */
7044
7044
  setupDOMObserver() {
7045
- if (typeof MutationObserver === 'undefined')
7045
+ if (typeof MutationObserver === "undefined")
7046
7046
  return;
7047
7047
  this.observer = new MutationObserver((mutations) => {
7048
7048
  const serializedMutations = mutations
7049
- .map(mutation => this.serializeMutation(mutation))
7049
+ .map((mutation) => this.serializeMutation(mutation))
7050
7050
  .filter(Boolean);
7051
7051
  if (serializedMutations.length > 0) {
7052
7052
  this.addEvent({
7053
- type: 'mutation',
7053
+ type: "mutation",
7054
7054
  timestamp: Date.now(),
7055
7055
  data: { mutations: serializedMutations },
7056
- sequence: this.sequence++
7056
+ sequence: this.sequence++,
7057
7057
  });
7058
7058
  }
7059
7059
  });
@@ -7063,7 +7063,7 @@ class SessionReplayEngine {
7063
7063
  attributes: true,
7064
7064
  attributeOldValue: true,
7065
7065
  characterData: true,
7066
- characterDataOldValue: true
7066
+ characterDataOldValue: true,
7067
7067
  });
7068
7068
  }
7069
7069
  /**
@@ -7071,47 +7071,49 @@ class SessionReplayEngine {
7071
7071
  */
7072
7072
  setupEventListeners() {
7073
7073
  if (this.config.captureClicks) {
7074
- document.addEventListener('click', this.handleClick, true);
7074
+ document.addEventListener("click", this.handleClick, true);
7075
7075
  }
7076
7076
  if (this.config.captureScrolls) {
7077
- window.addEventListener('scroll', this.handleScroll, { passive: true });
7078
- document.addEventListener('scroll', this.handleScroll, { passive: true });
7077
+ window.addEventListener("scroll", this.handleScroll, { passive: true });
7078
+ document.addEventListener("scroll", this.handleScroll, { passive: true });
7079
7079
  }
7080
7080
  if (this.config.captureInputs) {
7081
- document.addEventListener('input', this.handleInput, true);
7082
- document.addEventListener('change', this.handleChange, true);
7081
+ document.addEventListener("input", this.handleInput, true);
7082
+ document.addEventListener("change", this.handleChange, true);
7083
7083
  }
7084
7084
  if (this.config.captureMouseMoves) {
7085
- document.addEventListener('mousemove', this.handleMouseMove, { passive: true });
7085
+ document.addEventListener("mousemove", this.handleMouseMove, {
7086
+ passive: true,
7087
+ });
7086
7088
  }
7087
7089
  // Viewport changes
7088
- window.addEventListener('resize', this.handleViewportChange);
7089
- window.addEventListener('orientationchange', this.handleViewportChange);
7090
+ window.addEventListener("resize", this.handleViewportChange);
7091
+ window.addEventListener("orientationchange", this.handleViewportChange);
7090
7092
  // Navigation
7091
- window.addEventListener('beforeunload', this.handleNavigation);
7092
- window.addEventListener('pagehide', this.handleNavigation);
7093
+ window.addEventListener("beforeunload", this.handleNavigation);
7094
+ window.addEventListener("pagehide", this.handleNavigation);
7093
7095
  }
7094
7096
  /**
7095
7097
  * Remove event listeners
7096
7098
  */
7097
7099
  removeEventListeners() {
7098
- document.removeEventListener('click', this.handleClick, true);
7099
- window.removeEventListener('scroll', this.handleScroll);
7100
- document.removeEventListener('scroll', this.handleScroll);
7101
- document.removeEventListener('input', this.handleInput, true);
7102
- document.removeEventListener('change', this.handleChange, true);
7103
- document.removeEventListener('mousemove', this.handleMouseMove);
7104
- window.removeEventListener('resize', this.handleViewportChange);
7105
- window.removeEventListener('orientationchange', this.handleViewportChange);
7106
- window.removeEventListener('beforeunload', this.handleNavigation);
7107
- window.removeEventListener('pagehide', this.handleNavigation);
7100
+ document.removeEventListener("click", this.handleClick, true);
7101
+ window.removeEventListener("scroll", this.handleScroll);
7102
+ document.removeEventListener("scroll", this.handleScroll);
7103
+ document.removeEventListener("input", this.handleInput, true);
7104
+ document.removeEventListener("change", this.handleChange, true);
7105
+ document.removeEventListener("mousemove", this.handleMouseMove);
7106
+ window.removeEventListener("resize", this.handleViewportChange);
7107
+ window.removeEventListener("orientationchange", this.handleViewportChange);
7108
+ window.removeEventListener("beforeunload", this.handleNavigation);
7109
+ window.removeEventListener("pagehide", this.handleNavigation);
7108
7110
  }
7109
7111
  /**
7110
7112
  * Record initial DOM state
7111
7113
  */
7112
7114
  recordInitialState() {
7113
7115
  this.addEvent({
7114
- type: 'navigation',
7116
+ type: "navigation",
7115
7117
  timestamp: Date.now(),
7116
7118
  data: {
7117
7119
  url: window.location.href,
@@ -7119,14 +7121,14 @@ class SessionReplayEngine {
7119
7121
  title: document.title,
7120
7122
  viewport: {
7121
7123
  width: window.innerWidth,
7122
- height: window.innerHeight
7124
+ height: window.innerHeight,
7123
7125
  },
7124
7126
  screen: {
7125
7127
  width: window.screen?.width || 0,
7126
- height: window.screen?.height || 0
7127
- }
7128
+ height: window.screen?.height || 0,
7129
+ },
7128
7130
  },
7129
- sequence: this.sequence++
7131
+ sequence: this.sequence++,
7130
7132
  });
7131
7133
  }
7132
7134
  /**
@@ -7135,25 +7137,25 @@ class SessionReplayEngine {
7135
7137
  serializeMutation(mutation) {
7136
7138
  const result = {
7137
7139
  type: mutation.type,
7138
- target: this.getElementPath(mutation.target)
7140
+ target: this.getElementPath(mutation.target),
7139
7141
  };
7140
7142
  switch (mutation.type) {
7141
- case 'childList':
7143
+ case "childList":
7142
7144
  result.addedNodes = Array.from(mutation.addedNodes)
7143
- .filter(node => node.nodeType === Node.ELEMENT_NODE)
7144
- .map(node => this.serializeElement(node))
7145
+ .filter((node) => node.nodeType === Node.ELEMENT_NODE)
7146
+ .map((node) => this.serializeElement(node))
7145
7147
  .slice(0, 10); // Limit to prevent huge payloads
7146
7148
  result.removedNodes = Array.from(mutation.removedNodes)
7147
- .filter(node => node.nodeType === Node.ELEMENT_NODE)
7148
- .map(node => this.getElementPath(node))
7149
+ .filter((node) => node.nodeType === Node.ELEMENT_NODE)
7150
+ .map((node) => this.getElementPath(node))
7149
7151
  .slice(0, 10);
7150
7152
  break;
7151
- case 'attributes':
7153
+ case "attributes":
7152
7154
  result.attributeName = mutation.attributeName;
7153
7155
  result.oldValue = mutation.oldValue;
7154
7156
  result.newValue = mutation.target.getAttribute(mutation.attributeName);
7155
7157
  break;
7156
- case 'characterData':
7158
+ case "characterData":
7157
7159
  result.oldValue = mutation.oldValue;
7158
7160
  result.newValue = mutation.target.textContent;
7159
7161
  break;
@@ -7174,7 +7176,7 @@ class SessionReplayEngine {
7174
7176
  return {
7175
7177
  tagName: element.tagName.toLowerCase(),
7176
7178
  attributes,
7177
- textContent: element.textContent?.substring(0, 1000) || '' // Limit text content
7179
+ textContent: element.textContent?.substring(0, 1000) || "", // Limit text content
7178
7180
  };
7179
7181
  }
7180
7182
  /**
@@ -7192,7 +7194,7 @@ class SessionReplayEngine {
7192
7194
  }
7193
7195
  if (current.className) {
7194
7196
  const classes = current.className.toString().split(/\s+/).slice(0, 2);
7195
- selector += `.${classes.join('.')}`;
7197
+ selector += `.${classes.join(".")}`;
7196
7198
  }
7197
7199
  // Add nth-child if no unique identifier
7198
7200
  if (!current.id && !current.className) {
@@ -7203,26 +7205,38 @@ class SessionReplayEngine {
7203
7205
  path.unshift(selector);
7204
7206
  current = current.parentElement;
7205
7207
  }
7206
- return path.join(' > ');
7208
+ return path.join(" > ");
7207
7209
  }
7208
7210
  /**
7209
7211
  * Check if field should be masked
7210
7212
  */
7211
7213
  isSensitiveField(element) {
7212
- const sensitiveTypes = ['password', 'email', 'tel', 'ssn', 'cc'];
7213
- const sensitiveNames = ['password', 'email', 'phone', 'credit', 'card', 'ssn', 'social'];
7214
- const type = element.getAttribute('type')?.toLowerCase();
7215
- const name = element.getAttribute('name')?.toLowerCase();
7214
+ const sensitiveTypes = ["password", "email", "tel", "ssn", "cc"];
7215
+ const sensitiveNames = [
7216
+ "password",
7217
+ "email",
7218
+ "phone",
7219
+ "credit",
7220
+ "card",
7221
+ "ssn",
7222
+ "social",
7223
+ ];
7224
+ const type = element.getAttribute("type")?.toLowerCase();
7225
+ const name = element.getAttribute("name")?.toLowerCase();
7216
7226
  const className = element.className.toLowerCase();
7217
- return sensitiveTypes.includes(type || '') ||
7218
- sensitiveNames.some(term => (name && name.includes(term)) ||
7219
- className.includes(term));
7227
+ return (sensitiveTypes.includes(type || "") ||
7228
+ sensitiveNames.some((term) => (name && name.includes(term)) || className.includes(term)));
7220
7229
  }
7221
7230
  /**
7222
7231
  * Check if attribute should be masked
7223
7232
  */
7224
7233
  isSensitiveAttribute(attrName) {
7225
- const sensitiveAttrs = ['data-token', 'data-key', 'data-secret', 'authorization'];
7234
+ const sensitiveAttrs = [
7235
+ "data-token",
7236
+ "data-key",
7237
+ "data-secret",
7238
+ "authorization",
7239
+ ];
7226
7240
  return sensitiveAttrs.includes(attrName.toLowerCase());
7227
7241
  }
7228
7242
  /**
@@ -7248,7 +7262,7 @@ class SessionReplayEngine {
7248
7262
  */
7249
7263
  sendBatch() {
7250
7264
  if (this.events.length === 0) {
7251
- console.log('[Zaplier] No events to send in batch');
7265
+ console.log("[Zaplier] No events to send in batch");
7252
7266
  return;
7253
7267
  }
7254
7268
  const batch = [...this.events];
@@ -7260,44 +7274,35 @@ class SessionReplayEngine {
7260
7274
  metadata: {
7261
7275
  userAgent: navigator.userAgent,
7262
7276
  timestamp: Date.now(),
7263
- compression: this.config.compressionEnabled
7264
- }
7277
+ compression: this.config.compressionEnabled,
7278
+ },
7265
7279
  };
7266
7280
  // This will be handled by the anti-adblock manager
7267
7281
  this.sendToBackend(payload);
7268
7282
  }
7269
7283
  /**
7270
- * Set anti-adblock manager for WebRTC transport
7284
+ * Set SDK instance for transport
7271
7285
  */
7272
- setAntiAdblockManager(manager) {
7273
- this.antiAdblockManager = manager;
7286
+ setSDKInstance(sdk) {
7287
+ this.sdkInstance = sdk;
7274
7288
  }
7275
7289
  /**
7276
- * Send data via WebRTC (anti-adblock) or fallback to standard fetch
7290
+ * Send replay batch via SDK's transport system
7277
7291
  */
7278
7292
  async sendToBackend(payload) {
7279
7293
  try {
7280
- // Try WebRTC first if anti-adblock manager is available
7281
- if (this.antiAdblockManager) {
7282
- console.log('[Zaplier] Trying WebRTC transport...');
7283
- const result = await this.antiAdblockManager.send(payload, '/replays/record');
7284
- if (result.success) {
7285
- console.log('[Zaplier] Session replay sent via WebRTC');
7286
- return; // Success via WebRTC
7287
- }
7288
- console.log('[Zaplier] WebRTC failed, falling back to fetch');
7294
+ if (!this.sdkInstance) {
7295
+ console.error("[Zaplier] No SDK instance available for replay transport");
7296
+ return;
7289
7297
  }
7290
- // Get API endpoint from global config
7291
- const apiEndpoint = window.zaplier_config?.apiEndpoint || 'http://localhost:3001';
7292
- const token = window.zaplier_config?.token || 'ws_demo_token';
7293
- const url = `${apiEndpoint}/replays/record?token=${token}`;
7294
- console.log(`[Zaplier] Sending replay batch to ${url}`);
7298
+ console.log(`[Zaplier] Sending replay batch via SDK transport`);
7295
7299
  console.log(`[Zaplier] Payload:`, {
7296
7300
  sessionId: payload.sessionId,
7297
7301
  eventCount: payload.events.length,
7298
- hasMetadata: !!payload.metadata
7302
+ hasMetadata: !!payload.metadata,
7299
7303
  });
7300
- const requestBody = {
7304
+ // Use SDK's sendReplayBatch method
7305
+ const result = await this.sdkInstance.sendReplayBatch({
7301
7306
  sessionId: payload.sessionId,
7302
7307
  events: payload.events,
7303
7308
  metadata: {
@@ -7305,29 +7310,18 @@ class SessionReplayEngine {
7305
7310
  duration: Date.now() - (performance.timeOrigin || Date.now()),
7306
7311
  funnelSteps: [],
7307
7312
  hasConversion: false,
7308
- ...payload.metadata
7309
- }
7310
- };
7311
- // Fallback to standard fetch
7312
- const response = await fetch(url, {
7313
- method: 'POST',
7314
- headers: { 'Content-Type': 'application/json' },
7315
- body: JSON.stringify(requestBody)
7313
+ ...payload.metadata,
7314
+ },
7316
7315
  });
7317
- const responseText = await response.text();
7318
- if (!response.ok) {
7319
- console.error('[Zaplier] Session replay batch failed:', {
7320
- status: response.status,
7321
- statusText: response.statusText,
7322
- response: responseText
7323
- });
7316
+ if (result && result.success) {
7317
+ console.log("[Zaplier] Session replay batch sent successfully");
7324
7318
  }
7325
7319
  else {
7326
- console.log('[Zaplier] Session replay batch sent successfully:', responseText);
7320
+ console.error("[Zaplier] Session replay batch failed:", result);
7327
7321
  }
7328
7322
  }
7329
7323
  catch (error) {
7330
- console.error('[Zaplier] Session replay error:', error);
7324
+ console.error("[Zaplier] Session replay error:", error);
7331
7325
  }
7332
7326
  }
7333
7327
  /**
@@ -7375,7 +7369,7 @@ const DEFAULT_CONFIG = {
7375
7369
  */
7376
7370
  class ZaplierSDK {
7377
7371
  constructor(userConfig) {
7378
- this.version = "3.0.0";
7372
+ this.version = "1.3.0";
7379
7373
  this.isInitialized = false;
7380
7374
  this.eventQueue = [];
7381
7375
  /**
@@ -7445,19 +7439,58 @@ class ZaplierSDK {
7445
7439
  this.sessionId = this.generateSessionId();
7446
7440
  }
7447
7441
  const sessionId = this.sessionId;
7442
+ // When explicitly enabled, use 100% sample rate
7448
7443
  this.replayEngine = new SessionReplayEngine(sessionId, {
7449
- sampleRate: this.config.replaySampling,
7444
+ sampleRate: 1.0, // Force 100% when explicitly enabled
7450
7445
  maskSensitiveFields: this.config.replayMaskInputs,
7451
7446
  compressionEnabled: true,
7452
7447
  });
7453
7448
  // Connect to anti-adblock manager
7454
7449
  if (this.antiAdblockManager) {
7455
- this.replayEngine.setAntiAdblockManager(this.antiAdblockManager);
7450
+ this.replayEngine.setSDKInstance(this);
7451
+ }
7452
+ const started = this.replayEngine.start();
7453
+ if (this.config.debug) {
7454
+ console.log("[Zaplier] Replay enabled", {
7455
+ started,
7456
+ isRecording: this.replayEngine.isRecording(),
7457
+ });
7456
7458
  }
7457
- this.replayEngine.start();
7458
7459
  }
7459
- if (this.config.debug) {
7460
- console.log("[Zaplier] Replay enabled");
7460
+ else if (this.replayEngine) {
7461
+ // If engine already exists but isn't recording, recreate it with 100% sample rate
7462
+ if (!this.replayEngine.isRecording()) {
7463
+ // Stop and recreate with 100% sample rate
7464
+ this.replayEngine.stop();
7465
+ this.replayEngine = undefined;
7466
+ // Recreate with 100% sample rate
7467
+ if (!this.sessionId) {
7468
+ this.sessionId = this.generateSessionId();
7469
+ }
7470
+ const sessionId = this.sessionId;
7471
+ this.replayEngine = new SessionReplayEngine(sessionId, {
7472
+ sampleRate: 1.0, // Force 100% when explicitly enabled
7473
+ maskSensitiveFields: this.config.replayMaskInputs,
7474
+ compressionEnabled: true,
7475
+ });
7476
+ // Connect to anti-adblock manager
7477
+ if (this.antiAdblockManager) {
7478
+ this.replayEngine.setSDKInstance(this);
7479
+ }
7480
+ const started = this.replayEngine.start();
7481
+ if (this.config.debug) {
7482
+ console.log("[Zaplier] Replay engine recreated with 100% sample rate", { started, isRecording: this.replayEngine.isRecording() });
7483
+ }
7484
+ }
7485
+ else {
7486
+ // Already recording, just log
7487
+ if (this.config.debug) {
7488
+ console.log("[Zaplier] Replay already recording");
7489
+ }
7490
+ }
7491
+ }
7492
+ if (this.config.debug && !this.replayEngine) {
7493
+ console.log("[Zaplier] Replay enabled (will start when SDK initializes)");
7461
7494
  }
7462
7495
  },
7463
7496
  disable: () => {
@@ -7484,7 +7517,7 @@ class ZaplierSDK {
7484
7517
  });
7485
7518
  // Connect to anti-adblock manager
7486
7519
  if (this.antiAdblockManager) {
7487
- this.replayEngine.setAntiAdblockManager(this.antiAdblockManager);
7520
+ this.replayEngine.setSDKInstance(this);
7488
7521
  }
7489
7522
  return this.replayEngine.start();
7490
7523
  }
@@ -7580,18 +7613,23 @@ class ZaplierSDK {
7580
7613
  }
7581
7614
  // Initialize Session Replay Engine
7582
7615
  if (this.config.replay) {
7616
+ // When replay is explicitly enabled, use 100% sample rate to ensure recording
7617
+ // The default replaySampling (0.1) is only for automatic/production sampling
7618
+ const sampleRate = this.config.replay === true ? 1.0 : this.config.replaySampling;
7583
7619
  this.replayEngine = new SessionReplayEngine(this.sessionId, {
7584
- sampleRate: this.config.replaySampling,
7620
+ sampleRate: sampleRate,
7585
7621
  maskSensitiveFields: this.config.replayMaskInputs,
7586
7622
  compressionEnabled: true,
7587
7623
  });
7588
- // Connect to anti-adblock manager for WebRTC transport
7589
- if (this.antiAdblockManager) {
7590
- this.replayEngine.setAntiAdblockManager(this.antiAdblockManager);
7591
- }
7592
- this.replayEngine.start();
7624
+ // Connect SDK instance for transport
7625
+ this.replayEngine.setSDKInstance(this);
7626
+ const started = this.replayEngine.start();
7593
7627
  if (this.config.debug) {
7594
- console.log("[Zaplier] Session Replay started");
7628
+ console.log("[Zaplier] Session Replay started", {
7629
+ started,
7630
+ sampleRate,
7631
+ isRecording: this.replayEngine.isRecording(),
7632
+ });
7595
7633
  }
7596
7634
  }
7597
7635
  // Initialize Heatmap Engine
@@ -7870,6 +7908,46 @@ class ZaplierSDK {
7870
7908
  }
7871
7909
  }
7872
7910
  }
7911
+ /**
7912
+ * Send session replay batch to backend
7913
+ */
7914
+ async sendReplayBatch(replayData) {
7915
+ if (!this.isInitialized) {
7916
+ console.error("[Zaplier] SDK not initialized for replay batch sending");
7917
+ return { success: false, error: "SDK not initialized" };
7918
+ }
7919
+ try {
7920
+ const payload = {
7921
+ sessionId: replayData.sessionId,
7922
+ userId: this.backendVisitorId,
7923
+ events: replayData.events,
7924
+ metadata: {
7925
+ ...replayData.metadata,
7926
+ visitorId: this.backendVisitorId,
7927
+ fingerprintHash: this.fingerprint?.hash,
7928
+ },
7929
+ };
7930
+ if (this.config.debug) {
7931
+ console.log("[Zaplier] Sending replay batch:", {
7932
+ sessionId: payload.sessionId,
7933
+ eventCount: payload.events.length,
7934
+ hasMetadata: !!payload.metadata,
7935
+ });
7936
+ }
7937
+ // Use anti-adblock transport or standard HTTP
7938
+ const result = await this.makeRequest(`/replays/record?token=${encodeURIComponent(this.config.token)}`, payload, "POST");
7939
+ if (this.config.debug) {
7940
+ console.log("[Zaplier] Replay batch result:", result);
7941
+ }
7942
+ return result;
7943
+ }
7944
+ catch (error) {
7945
+ if (this.config.debug) {
7946
+ console.error("[Zaplier] Replay batch sending failed:", error);
7947
+ }
7948
+ return { success: false, error: error instanceof Error ? error.message : "Unknown error" };
7949
+ }
7950
+ }
7873
7951
  /**
7874
7952
  * Make HTTP request to backend using anti-adblock system
7875
7953
  */