@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/sdk.js CHANGED
@@ -6880,7 +6880,7 @@
6880
6880
  const target = event.target;
6881
6881
  const path = this.getElementPath(target);
6882
6882
  this.addEvent({
6883
- type: 'click',
6883
+ type: "click",
6884
6884
  timestamp: Date.now(),
6885
6885
  data: {
6886
6886
  x: event.clientX,
@@ -6889,9 +6889,9 @@
6889
6889
  button: event.button,
6890
6890
  ctrlKey: event.ctrlKey,
6891
6891
  shiftKey: event.shiftKey,
6892
- altKey: event.altKey
6892
+ altKey: event.altKey,
6893
6893
  },
6894
- sequence: this.sequence++
6894
+ sequence: this.sequence++,
6895
6895
  });
6896
6896
  };
6897
6897
  /**
@@ -6899,13 +6899,13 @@
6899
6899
  */
6900
6900
  this.handleScroll = () => {
6901
6901
  this.addEvent({
6902
- type: 'scroll',
6902
+ type: "scroll",
6903
6903
  timestamp: Date.now(),
6904
6904
  data: {
6905
6905
  x: window.pageXOffset || document.documentElement.scrollLeft,
6906
- y: window.pageYOffset || document.documentElement.scrollTop
6906
+ y: window.pageYOffset || document.documentElement.scrollTop,
6907
6907
  },
6908
- sequence: this.sequence++
6908
+ sequence: this.sequence++,
6909
6909
  });
6910
6910
  };
6911
6911
  /**
@@ -6917,17 +6917,17 @@
6917
6917
  let value = target.value;
6918
6918
  // Mask sensitive fields
6919
6919
  if (this.config.maskSensitiveFields && this.isSensitiveField(target)) {
6920
- value = '*'.repeat(value.length);
6920
+ value = "*".repeat(value.length);
6921
6921
  }
6922
6922
  this.addEvent({
6923
- type: 'input',
6923
+ type: "input",
6924
6924
  timestamp: Date.now(),
6925
6925
  data: {
6926
6926
  element: path,
6927
6927
  value: value,
6928
- inputType: event.inputType
6928
+ inputType: event.inputType,
6929
6929
  },
6930
- sequence: this.sequence++
6930
+ sequence: this.sequence++,
6931
6931
  });
6932
6932
  };
6933
6933
  /**
@@ -6938,17 +6938,17 @@
6938
6938
  const path = this.getElementPath(target);
6939
6939
  let value = target.value;
6940
6940
  if (this.config.maskSensitiveFields && this.isSensitiveField(target)) {
6941
- value = '*'.repeat(value.length);
6941
+ value = "*".repeat(value.length);
6942
6942
  }
6943
6943
  this.addEvent({
6944
- type: 'input',
6944
+ type: "input",
6945
6945
  timestamp: Date.now(),
6946
6946
  data: {
6947
6947
  element: path,
6948
6948
  value: value,
6949
- type: 'change'
6949
+ type: "change",
6950
6950
  },
6951
- sequence: this.sequence++
6951
+ sequence: this.sequence++,
6952
6952
  });
6953
6953
  };
6954
6954
  /**
@@ -6961,13 +6961,13 @@
6961
6961
  }
6962
6962
  this.lastMouseMove = now;
6963
6963
  this.addEvent({
6964
- type: 'mouse',
6964
+ type: "mouse",
6965
6965
  timestamp: now,
6966
6966
  data: {
6967
6967
  x: event.clientX,
6968
- y: event.clientY
6968
+ y: event.clientY,
6969
6969
  },
6970
- sequence: this.sequence++
6970
+ sequence: this.sequence++,
6971
6971
  });
6972
6972
  };
6973
6973
  /**
@@ -6975,13 +6975,13 @@
6975
6975
  */
6976
6976
  this.handleViewportChange = () => {
6977
6977
  this.addEvent({
6978
- type: 'viewport',
6978
+ type: "viewport",
6979
6979
  timestamp: Date.now(),
6980
6980
  data: {
6981
6981
  width: window.innerWidth,
6982
- height: window.innerHeight
6982
+ height: window.innerHeight,
6983
6983
  },
6984
- sequence: this.sequence++
6984
+ sequence: this.sequence++,
6985
6985
  });
6986
6986
  };
6987
6987
  /**
@@ -7003,7 +7003,7 @@
7003
7003
  captureInputs: true,
7004
7004
  captureMouseMoves: false, // Disabled by default for performance
7005
7005
  compressionEnabled: true,
7006
- ...config
7006
+ ...config,
7007
7007
  };
7008
7008
  }
7009
7009
  /**
@@ -7048,18 +7048,18 @@
7048
7048
  * Setup DOM mutation observer
7049
7049
  */
7050
7050
  setupDOMObserver() {
7051
- if (typeof MutationObserver === 'undefined')
7051
+ if (typeof MutationObserver === "undefined")
7052
7052
  return;
7053
7053
  this.observer = new MutationObserver((mutations) => {
7054
7054
  const serializedMutations = mutations
7055
- .map(mutation => this.serializeMutation(mutation))
7055
+ .map((mutation) => this.serializeMutation(mutation))
7056
7056
  .filter(Boolean);
7057
7057
  if (serializedMutations.length > 0) {
7058
7058
  this.addEvent({
7059
- type: 'mutation',
7059
+ type: "mutation",
7060
7060
  timestamp: Date.now(),
7061
7061
  data: { mutations: serializedMutations },
7062
- sequence: this.sequence++
7062
+ sequence: this.sequence++,
7063
7063
  });
7064
7064
  }
7065
7065
  });
@@ -7069,7 +7069,7 @@
7069
7069
  attributes: true,
7070
7070
  attributeOldValue: true,
7071
7071
  characterData: true,
7072
- characterDataOldValue: true
7072
+ characterDataOldValue: true,
7073
7073
  });
7074
7074
  }
7075
7075
  /**
@@ -7077,47 +7077,49 @@
7077
7077
  */
7078
7078
  setupEventListeners() {
7079
7079
  if (this.config.captureClicks) {
7080
- document.addEventListener('click', this.handleClick, true);
7080
+ document.addEventListener("click", this.handleClick, true);
7081
7081
  }
7082
7082
  if (this.config.captureScrolls) {
7083
- window.addEventListener('scroll', this.handleScroll, { passive: true });
7084
- document.addEventListener('scroll', this.handleScroll, { passive: true });
7083
+ window.addEventListener("scroll", this.handleScroll, { passive: true });
7084
+ document.addEventListener("scroll", this.handleScroll, { passive: true });
7085
7085
  }
7086
7086
  if (this.config.captureInputs) {
7087
- document.addEventListener('input', this.handleInput, true);
7088
- document.addEventListener('change', this.handleChange, true);
7087
+ document.addEventListener("input", this.handleInput, true);
7088
+ document.addEventListener("change", this.handleChange, true);
7089
7089
  }
7090
7090
  if (this.config.captureMouseMoves) {
7091
- document.addEventListener('mousemove', this.handleMouseMove, { passive: true });
7091
+ document.addEventListener("mousemove", this.handleMouseMove, {
7092
+ passive: true,
7093
+ });
7092
7094
  }
7093
7095
  // Viewport changes
7094
- window.addEventListener('resize', this.handleViewportChange);
7095
- window.addEventListener('orientationchange', this.handleViewportChange);
7096
+ window.addEventListener("resize", this.handleViewportChange);
7097
+ window.addEventListener("orientationchange", this.handleViewportChange);
7096
7098
  // Navigation
7097
- window.addEventListener('beforeunload', this.handleNavigation);
7098
- window.addEventListener('pagehide', this.handleNavigation);
7099
+ window.addEventListener("beforeunload", this.handleNavigation);
7100
+ window.addEventListener("pagehide", this.handleNavigation);
7099
7101
  }
7100
7102
  /**
7101
7103
  * Remove event listeners
7102
7104
  */
7103
7105
  removeEventListeners() {
7104
- document.removeEventListener('click', this.handleClick, true);
7105
- window.removeEventListener('scroll', this.handleScroll);
7106
- document.removeEventListener('scroll', this.handleScroll);
7107
- document.removeEventListener('input', this.handleInput, true);
7108
- document.removeEventListener('change', this.handleChange, true);
7109
- document.removeEventListener('mousemove', this.handleMouseMove);
7110
- window.removeEventListener('resize', this.handleViewportChange);
7111
- window.removeEventListener('orientationchange', this.handleViewportChange);
7112
- window.removeEventListener('beforeunload', this.handleNavigation);
7113
- window.removeEventListener('pagehide', this.handleNavigation);
7106
+ document.removeEventListener("click", this.handleClick, true);
7107
+ window.removeEventListener("scroll", this.handleScroll);
7108
+ document.removeEventListener("scroll", this.handleScroll);
7109
+ document.removeEventListener("input", this.handleInput, true);
7110
+ document.removeEventListener("change", this.handleChange, true);
7111
+ document.removeEventListener("mousemove", this.handleMouseMove);
7112
+ window.removeEventListener("resize", this.handleViewportChange);
7113
+ window.removeEventListener("orientationchange", this.handleViewportChange);
7114
+ window.removeEventListener("beforeunload", this.handleNavigation);
7115
+ window.removeEventListener("pagehide", this.handleNavigation);
7114
7116
  }
7115
7117
  /**
7116
7118
  * Record initial DOM state
7117
7119
  */
7118
7120
  recordInitialState() {
7119
7121
  this.addEvent({
7120
- type: 'navigation',
7122
+ type: "navigation",
7121
7123
  timestamp: Date.now(),
7122
7124
  data: {
7123
7125
  url: window.location.href,
@@ -7125,14 +7127,14 @@
7125
7127
  title: document.title,
7126
7128
  viewport: {
7127
7129
  width: window.innerWidth,
7128
- height: window.innerHeight
7130
+ height: window.innerHeight,
7129
7131
  },
7130
7132
  screen: {
7131
7133
  width: window.screen?.width || 0,
7132
- height: window.screen?.height || 0
7133
- }
7134
+ height: window.screen?.height || 0,
7135
+ },
7134
7136
  },
7135
- sequence: this.sequence++
7137
+ sequence: this.sequence++,
7136
7138
  });
7137
7139
  }
7138
7140
  /**
@@ -7141,25 +7143,25 @@
7141
7143
  serializeMutation(mutation) {
7142
7144
  const result = {
7143
7145
  type: mutation.type,
7144
- target: this.getElementPath(mutation.target)
7146
+ target: this.getElementPath(mutation.target),
7145
7147
  };
7146
7148
  switch (mutation.type) {
7147
- case 'childList':
7149
+ case "childList":
7148
7150
  result.addedNodes = Array.from(mutation.addedNodes)
7149
- .filter(node => node.nodeType === Node.ELEMENT_NODE)
7150
- .map(node => this.serializeElement(node))
7151
+ .filter((node) => node.nodeType === Node.ELEMENT_NODE)
7152
+ .map((node) => this.serializeElement(node))
7151
7153
  .slice(0, 10); // Limit to prevent huge payloads
7152
7154
  result.removedNodes = Array.from(mutation.removedNodes)
7153
- .filter(node => node.nodeType === Node.ELEMENT_NODE)
7154
- .map(node => this.getElementPath(node))
7155
+ .filter((node) => node.nodeType === Node.ELEMENT_NODE)
7156
+ .map((node) => this.getElementPath(node))
7155
7157
  .slice(0, 10);
7156
7158
  break;
7157
- case 'attributes':
7159
+ case "attributes":
7158
7160
  result.attributeName = mutation.attributeName;
7159
7161
  result.oldValue = mutation.oldValue;
7160
7162
  result.newValue = mutation.target.getAttribute(mutation.attributeName);
7161
7163
  break;
7162
- case 'characterData':
7164
+ case "characterData":
7163
7165
  result.oldValue = mutation.oldValue;
7164
7166
  result.newValue = mutation.target.textContent;
7165
7167
  break;
@@ -7180,7 +7182,7 @@
7180
7182
  return {
7181
7183
  tagName: element.tagName.toLowerCase(),
7182
7184
  attributes,
7183
- textContent: element.textContent?.substring(0, 1000) || '' // Limit text content
7185
+ textContent: element.textContent?.substring(0, 1000) || "", // Limit text content
7184
7186
  };
7185
7187
  }
7186
7188
  /**
@@ -7198,7 +7200,7 @@
7198
7200
  }
7199
7201
  if (current.className) {
7200
7202
  const classes = current.className.toString().split(/\s+/).slice(0, 2);
7201
- selector += `.${classes.join('.')}`;
7203
+ selector += `.${classes.join(".")}`;
7202
7204
  }
7203
7205
  // Add nth-child if no unique identifier
7204
7206
  if (!current.id && !current.className) {
@@ -7209,26 +7211,38 @@
7209
7211
  path.unshift(selector);
7210
7212
  current = current.parentElement;
7211
7213
  }
7212
- return path.join(' > ');
7214
+ return path.join(" > ");
7213
7215
  }
7214
7216
  /**
7215
7217
  * Check if field should be masked
7216
7218
  */
7217
7219
  isSensitiveField(element) {
7218
- const sensitiveTypes = ['password', 'email', 'tel', 'ssn', 'cc'];
7219
- const sensitiveNames = ['password', 'email', 'phone', 'credit', 'card', 'ssn', 'social'];
7220
- const type = element.getAttribute('type')?.toLowerCase();
7221
- const name = element.getAttribute('name')?.toLowerCase();
7220
+ const sensitiveTypes = ["password", "email", "tel", "ssn", "cc"];
7221
+ const sensitiveNames = [
7222
+ "password",
7223
+ "email",
7224
+ "phone",
7225
+ "credit",
7226
+ "card",
7227
+ "ssn",
7228
+ "social",
7229
+ ];
7230
+ const type = element.getAttribute("type")?.toLowerCase();
7231
+ const name = element.getAttribute("name")?.toLowerCase();
7222
7232
  const className = element.className.toLowerCase();
7223
- return sensitiveTypes.includes(type || '') ||
7224
- sensitiveNames.some(term => (name && name.includes(term)) ||
7225
- className.includes(term));
7233
+ return (sensitiveTypes.includes(type || "") ||
7234
+ sensitiveNames.some((term) => (name && name.includes(term)) || className.includes(term)));
7226
7235
  }
7227
7236
  /**
7228
7237
  * Check if attribute should be masked
7229
7238
  */
7230
7239
  isSensitiveAttribute(attrName) {
7231
- const sensitiveAttrs = ['data-token', 'data-key', 'data-secret', 'authorization'];
7240
+ const sensitiveAttrs = [
7241
+ "data-token",
7242
+ "data-key",
7243
+ "data-secret",
7244
+ "authorization",
7245
+ ];
7232
7246
  return sensitiveAttrs.includes(attrName.toLowerCase());
7233
7247
  }
7234
7248
  /**
@@ -7254,7 +7268,7 @@
7254
7268
  */
7255
7269
  sendBatch() {
7256
7270
  if (this.events.length === 0) {
7257
- console.log('[Zaplier] No events to send in batch');
7271
+ console.log("[Zaplier] No events to send in batch");
7258
7272
  return;
7259
7273
  }
7260
7274
  const batch = [...this.events];
@@ -7266,44 +7280,35 @@
7266
7280
  metadata: {
7267
7281
  userAgent: navigator.userAgent,
7268
7282
  timestamp: Date.now(),
7269
- compression: this.config.compressionEnabled
7270
- }
7283
+ compression: this.config.compressionEnabled,
7284
+ },
7271
7285
  };
7272
7286
  // This will be handled by the anti-adblock manager
7273
7287
  this.sendToBackend(payload);
7274
7288
  }
7275
7289
  /**
7276
- * Set anti-adblock manager for WebRTC transport
7290
+ * Set SDK instance for transport
7277
7291
  */
7278
- setAntiAdblockManager(manager) {
7279
- this.antiAdblockManager = manager;
7292
+ setSDKInstance(sdk) {
7293
+ this.sdkInstance = sdk;
7280
7294
  }
7281
7295
  /**
7282
- * Send data via WebRTC (anti-adblock) or fallback to standard fetch
7296
+ * Send replay batch via SDK's transport system
7283
7297
  */
7284
7298
  async sendToBackend(payload) {
7285
7299
  try {
7286
- // Try WebRTC first if anti-adblock manager is available
7287
- if (this.antiAdblockManager) {
7288
- console.log('[Zaplier] Trying WebRTC transport...');
7289
- const result = await this.antiAdblockManager.send(payload, '/replays/record');
7290
- if (result.success) {
7291
- console.log('[Zaplier] Session replay sent via WebRTC');
7292
- return; // Success via WebRTC
7293
- }
7294
- console.log('[Zaplier] WebRTC failed, falling back to fetch');
7300
+ if (!this.sdkInstance) {
7301
+ console.error("[Zaplier] No SDK instance available for replay transport");
7302
+ return;
7295
7303
  }
7296
- // Get API endpoint from global config
7297
- const apiEndpoint = window.zaplier_config?.apiEndpoint || 'http://localhost:3001';
7298
- const token = window.zaplier_config?.token || 'ws_demo_token';
7299
- const url = `${apiEndpoint}/replays/record?token=${token}`;
7300
- console.log(`[Zaplier] Sending replay batch to ${url}`);
7304
+ console.log(`[Zaplier] Sending replay batch via SDK transport`);
7301
7305
  console.log(`[Zaplier] Payload:`, {
7302
7306
  sessionId: payload.sessionId,
7303
7307
  eventCount: payload.events.length,
7304
- hasMetadata: !!payload.metadata
7308
+ hasMetadata: !!payload.metadata,
7305
7309
  });
7306
- const requestBody = {
7310
+ // Use SDK's sendReplayBatch method
7311
+ const result = await this.sdkInstance.sendReplayBatch({
7307
7312
  sessionId: payload.sessionId,
7308
7313
  events: payload.events,
7309
7314
  metadata: {
@@ -7311,29 +7316,18 @@
7311
7316
  duration: Date.now() - (performance.timeOrigin || Date.now()),
7312
7317
  funnelSteps: [],
7313
7318
  hasConversion: false,
7314
- ...payload.metadata
7315
- }
7316
- };
7317
- // Fallback to standard fetch
7318
- const response = await fetch(url, {
7319
- method: 'POST',
7320
- headers: { 'Content-Type': 'application/json' },
7321
- body: JSON.stringify(requestBody)
7319
+ ...payload.metadata,
7320
+ },
7322
7321
  });
7323
- const responseText = await response.text();
7324
- if (!response.ok) {
7325
- console.error('[Zaplier] Session replay batch failed:', {
7326
- status: response.status,
7327
- statusText: response.statusText,
7328
- response: responseText
7329
- });
7322
+ if (result && result.success) {
7323
+ console.log("[Zaplier] Session replay batch sent successfully");
7330
7324
  }
7331
7325
  else {
7332
- console.log('[Zaplier] Session replay batch sent successfully:', responseText);
7326
+ console.error("[Zaplier] Session replay batch failed:", result);
7333
7327
  }
7334
7328
  }
7335
7329
  catch (error) {
7336
- console.error('[Zaplier] Session replay error:', error);
7330
+ console.error("[Zaplier] Session replay error:", error);
7337
7331
  }
7338
7332
  }
7339
7333
  /**
@@ -7381,7 +7375,7 @@
7381
7375
  */
7382
7376
  class ZaplierSDK {
7383
7377
  constructor(userConfig) {
7384
- this.version = "3.0.0";
7378
+ this.version = "1.3.0";
7385
7379
  this.isInitialized = false;
7386
7380
  this.eventQueue = [];
7387
7381
  /**
@@ -7451,19 +7445,58 @@
7451
7445
  this.sessionId = this.generateSessionId();
7452
7446
  }
7453
7447
  const sessionId = this.sessionId;
7448
+ // When explicitly enabled, use 100% sample rate
7454
7449
  this.replayEngine = new SessionReplayEngine(sessionId, {
7455
- sampleRate: this.config.replaySampling,
7450
+ sampleRate: 1.0, // Force 100% when explicitly enabled
7456
7451
  maskSensitiveFields: this.config.replayMaskInputs,
7457
7452
  compressionEnabled: true,
7458
7453
  });
7459
7454
  // Connect to anti-adblock manager
7460
7455
  if (this.antiAdblockManager) {
7461
- this.replayEngine.setAntiAdblockManager(this.antiAdblockManager);
7456
+ this.replayEngine.setSDKInstance(this);
7457
+ }
7458
+ const started = this.replayEngine.start();
7459
+ if (this.config.debug) {
7460
+ console.log("[Zaplier] Replay enabled", {
7461
+ started,
7462
+ isRecording: this.replayEngine.isRecording(),
7463
+ });
7462
7464
  }
7463
- this.replayEngine.start();
7464
7465
  }
7465
- if (this.config.debug) {
7466
- console.log("[Zaplier] Replay enabled");
7466
+ else if (this.replayEngine) {
7467
+ // If engine already exists but isn't recording, recreate it with 100% sample rate
7468
+ if (!this.replayEngine.isRecording()) {
7469
+ // Stop and recreate with 100% sample rate
7470
+ this.replayEngine.stop();
7471
+ this.replayEngine = undefined;
7472
+ // Recreate with 100% sample rate
7473
+ if (!this.sessionId) {
7474
+ this.sessionId = this.generateSessionId();
7475
+ }
7476
+ const sessionId = this.sessionId;
7477
+ this.replayEngine = new SessionReplayEngine(sessionId, {
7478
+ sampleRate: 1.0, // Force 100% when explicitly enabled
7479
+ maskSensitiveFields: this.config.replayMaskInputs,
7480
+ compressionEnabled: true,
7481
+ });
7482
+ // Connect to anti-adblock manager
7483
+ if (this.antiAdblockManager) {
7484
+ this.replayEngine.setSDKInstance(this);
7485
+ }
7486
+ const started = this.replayEngine.start();
7487
+ if (this.config.debug) {
7488
+ console.log("[Zaplier] Replay engine recreated with 100% sample rate", { started, isRecording: this.replayEngine.isRecording() });
7489
+ }
7490
+ }
7491
+ else {
7492
+ // Already recording, just log
7493
+ if (this.config.debug) {
7494
+ console.log("[Zaplier] Replay already recording");
7495
+ }
7496
+ }
7497
+ }
7498
+ if (this.config.debug && !this.replayEngine) {
7499
+ console.log("[Zaplier] Replay enabled (will start when SDK initializes)");
7467
7500
  }
7468
7501
  },
7469
7502
  disable: () => {
@@ -7490,7 +7523,7 @@
7490
7523
  });
7491
7524
  // Connect to anti-adblock manager
7492
7525
  if (this.antiAdblockManager) {
7493
- this.replayEngine.setAntiAdblockManager(this.antiAdblockManager);
7526
+ this.replayEngine.setSDKInstance(this);
7494
7527
  }
7495
7528
  return this.replayEngine.start();
7496
7529
  }
@@ -7586,18 +7619,23 @@
7586
7619
  }
7587
7620
  // Initialize Session Replay Engine
7588
7621
  if (this.config.replay) {
7622
+ // When replay is explicitly enabled, use 100% sample rate to ensure recording
7623
+ // The default replaySampling (0.1) is only for automatic/production sampling
7624
+ const sampleRate = this.config.replay === true ? 1.0 : this.config.replaySampling;
7589
7625
  this.replayEngine = new SessionReplayEngine(this.sessionId, {
7590
- sampleRate: this.config.replaySampling,
7626
+ sampleRate: sampleRate,
7591
7627
  maskSensitiveFields: this.config.replayMaskInputs,
7592
7628
  compressionEnabled: true,
7593
7629
  });
7594
- // Connect to anti-adblock manager for WebRTC transport
7595
- if (this.antiAdblockManager) {
7596
- this.replayEngine.setAntiAdblockManager(this.antiAdblockManager);
7597
- }
7598
- this.replayEngine.start();
7630
+ // Connect SDK instance for transport
7631
+ this.replayEngine.setSDKInstance(this);
7632
+ const started = this.replayEngine.start();
7599
7633
  if (this.config.debug) {
7600
- console.log("[Zaplier] Session Replay started");
7634
+ console.log("[Zaplier] Session Replay started", {
7635
+ started,
7636
+ sampleRate,
7637
+ isRecording: this.replayEngine.isRecording(),
7638
+ });
7601
7639
  }
7602
7640
  }
7603
7641
  // Initialize Heatmap Engine
@@ -7876,6 +7914,46 @@
7876
7914
  }
7877
7915
  }
7878
7916
  }
7917
+ /**
7918
+ * Send session replay batch to backend
7919
+ */
7920
+ async sendReplayBatch(replayData) {
7921
+ if (!this.isInitialized) {
7922
+ console.error("[Zaplier] SDK not initialized for replay batch sending");
7923
+ return { success: false, error: "SDK not initialized" };
7924
+ }
7925
+ try {
7926
+ const payload = {
7927
+ sessionId: replayData.sessionId,
7928
+ userId: this.backendVisitorId,
7929
+ events: replayData.events,
7930
+ metadata: {
7931
+ ...replayData.metadata,
7932
+ visitorId: this.backendVisitorId,
7933
+ fingerprintHash: this.fingerprint?.hash,
7934
+ },
7935
+ };
7936
+ if (this.config.debug) {
7937
+ console.log("[Zaplier] Sending replay batch:", {
7938
+ sessionId: payload.sessionId,
7939
+ eventCount: payload.events.length,
7940
+ hasMetadata: !!payload.metadata,
7941
+ });
7942
+ }
7943
+ // Use anti-adblock transport or standard HTTP
7944
+ const result = await this.makeRequest(`/replays/record?token=${encodeURIComponent(this.config.token)}`, payload, "POST");
7945
+ if (this.config.debug) {
7946
+ console.log("[Zaplier] Replay batch result:", result);
7947
+ }
7948
+ return result;
7949
+ }
7950
+ catch (error) {
7951
+ if (this.config.debug) {
7952
+ console.error("[Zaplier] Replay batch sending failed:", error);
7953
+ }
7954
+ return { success: false, error: error instanceof Error ? error.message : "Unknown error" };
7955
+ }
7956
+ }
7879
7957
  /**
7880
7958
  * Make HTTP request to backend using anti-adblock system
7881
7959
  */