@zaplier/sdk 1.2.6 → 1.2.7

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,8 +7280,8 @@
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);
@@ -7285,23 +7299,23 @@
7285
7299
  try {
7286
7300
  // Try WebRTC first if anti-adblock manager is available
7287
7301
  if (this.antiAdblockManager) {
7288
- console.log('[Zaplier] Trying WebRTC transport...');
7289
- const result = await this.antiAdblockManager.send(payload, '/replays/record');
7302
+ console.log("[Zaplier] Trying WebRTC transport...");
7303
+ const result = await this.antiAdblockManager.send(payload, "/replays/record");
7290
7304
  if (result.success) {
7291
- console.log('[Zaplier] Session replay sent via WebRTC');
7305
+ console.log("[Zaplier] Session replay sent via WebRTC");
7292
7306
  return; // Success via WebRTC
7293
7307
  }
7294
- console.log('[Zaplier] WebRTC failed, falling back to fetch');
7308
+ console.log("[Zaplier] WebRTC failed, falling back to fetch");
7295
7309
  }
7296
7310
  // 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';
7311
+ const apiEndpoint = window.zaplier_config?.apiEndpoint || "http://localhost:3001";
7312
+ const token = window.zaplier_config?.token || "ws_demo_token";
7299
7313
  const url = `${apiEndpoint}/replays/record?token=${token}`;
7300
7314
  console.log(`[Zaplier] Sending replay batch to ${url}`);
7301
7315
  console.log(`[Zaplier] Payload:`, {
7302
7316
  sessionId: payload.sessionId,
7303
7317
  eventCount: payload.events.length,
7304
- hasMetadata: !!payload.metadata
7318
+ hasMetadata: !!payload.metadata,
7305
7319
  });
7306
7320
  const requestBody = {
7307
7321
  sessionId: payload.sessionId,
@@ -7311,29 +7325,29 @@
7311
7325
  duration: Date.now() - (performance.timeOrigin || Date.now()),
7312
7326
  funnelSteps: [],
7313
7327
  hasConversion: false,
7314
- ...payload.metadata
7315
- }
7328
+ ...payload.metadata,
7329
+ },
7316
7330
  };
7317
7331
  // Fallback to standard fetch
7318
7332
  const response = await fetch(url, {
7319
- method: 'POST',
7320
- headers: { 'Content-Type': 'application/json' },
7321
- body: JSON.stringify(requestBody)
7333
+ method: "POST",
7334
+ headers: { "Content-Type": "application/json" },
7335
+ body: JSON.stringify(requestBody),
7322
7336
  });
7323
7337
  const responseText = await response.text();
7324
7338
  if (!response.ok) {
7325
- console.error('[Zaplier] Session replay batch failed:', {
7339
+ console.error("[Zaplier] Session replay batch failed:", {
7326
7340
  status: response.status,
7327
7341
  statusText: response.statusText,
7328
- response: responseText
7342
+ response: responseText,
7329
7343
  });
7330
7344
  }
7331
7345
  else {
7332
- console.log('[Zaplier] Session replay batch sent successfully:', responseText);
7346
+ console.log("[Zaplier] Session replay batch sent successfully:", responseText);
7333
7347
  }
7334
7348
  }
7335
7349
  catch (error) {
7336
- console.error('[Zaplier] Session replay error:', error);
7350
+ console.error("[Zaplier] Session replay error:", error);
7337
7351
  }
7338
7352
  }
7339
7353
  /**
@@ -7451,8 +7465,9 @@
7451
7465
  this.sessionId = this.generateSessionId();
7452
7466
  }
7453
7467
  const sessionId = this.sessionId;
7468
+ // When explicitly enabled, use 100% sample rate
7454
7469
  this.replayEngine = new SessionReplayEngine(sessionId, {
7455
- sampleRate: this.config.replaySampling,
7470
+ sampleRate: 1.0, // Force 100% when explicitly enabled
7456
7471
  maskSensitiveFields: this.config.replayMaskInputs,
7457
7472
  compressionEnabled: true,
7458
7473
  });
@@ -7460,10 +7475,23 @@
7460
7475
  if (this.antiAdblockManager) {
7461
7476
  this.replayEngine.setAntiAdblockManager(this.antiAdblockManager);
7462
7477
  }
7463
- this.replayEngine.start();
7478
+ const started = this.replayEngine.start();
7479
+ if (this.config.debug) {
7480
+ console.log("[Zaplier] Replay enabled", {
7481
+ started,
7482
+ isRecording: this.replayEngine.isRecording(),
7483
+ });
7484
+ }
7464
7485
  }
7465
- if (this.config.debug) {
7466
- console.log("[Zaplier] Replay enabled");
7486
+ else if (this.replayEngine) {
7487
+ // If engine already exists, try to start it (might have failed due to sampling before)
7488
+ const started = this.replayEngine.start();
7489
+ if (this.config.debug) {
7490
+ console.log("[Zaplier] Replay engine already exists, attempting start", { started });
7491
+ }
7492
+ }
7493
+ if (this.config.debug && !this.replayEngine) {
7494
+ console.log("[Zaplier] Replay enabled (will start when SDK initializes)");
7467
7495
  }
7468
7496
  },
7469
7497
  disable: () => {
@@ -7586,8 +7614,11 @@
7586
7614
  }
7587
7615
  // Initialize Session Replay Engine
7588
7616
  if (this.config.replay) {
7617
+ // When replay is explicitly enabled, use 100% sample rate to ensure recording
7618
+ // The default replaySampling (0.1) is only for automatic/production sampling
7619
+ const sampleRate = this.config.replay === true ? 1.0 : this.config.replaySampling;
7589
7620
  this.replayEngine = new SessionReplayEngine(this.sessionId, {
7590
- sampleRate: this.config.replaySampling,
7621
+ sampleRate: sampleRate,
7591
7622
  maskSensitiveFields: this.config.replayMaskInputs,
7592
7623
  compressionEnabled: true,
7593
7624
  });
@@ -7595,9 +7626,13 @@
7595
7626
  if (this.antiAdblockManager) {
7596
7627
  this.replayEngine.setAntiAdblockManager(this.antiAdblockManager);
7597
7628
  }
7598
- this.replayEngine.start();
7629
+ const started = this.replayEngine.start();
7599
7630
  if (this.config.debug) {
7600
- console.log("[Zaplier] Session Replay started");
7631
+ console.log("[Zaplier] Session Replay started", {
7632
+ started,
7633
+ sampleRate,
7634
+ isRecording: this.replayEngine.isRecording(),
7635
+ });
7601
7636
  }
7602
7637
  }
7603
7638
  // Initialize Heatmap Engine