@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.cjs +202 -124
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.esm.js +202 -124
- package/dist/index.esm.js.map +1 -1
- package/dist/sdk.js +202 -124
- package/dist/sdk.js.map +1 -1
- package/dist/sdk.min.js +1 -1
- package/dist/src/modules/session-replay.d.ts +5 -5
- package/dist/src/modules/session-replay.d.ts.map +1 -1
- package/dist/src/sdk.d.ts +8 -0
- package/dist/src/sdk.d.ts.map +1 -1
- package/package.json +1 -1
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:
|
|
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:
|
|
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 =
|
|
6914
|
+
value = "*".repeat(value.length);
|
|
6915
6915
|
}
|
|
6916
6916
|
this.addEvent({
|
|
6917
|
-
type:
|
|
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 =
|
|
6935
|
+
value = "*".repeat(value.length);
|
|
6936
6936
|
}
|
|
6937
6937
|
this.addEvent({
|
|
6938
|
-
type:
|
|
6938
|
+
type: "input",
|
|
6939
6939
|
timestamp: Date.now(),
|
|
6940
6940
|
data: {
|
|
6941
6941
|
element: path,
|
|
6942
6942
|
value: value,
|
|
6943
|
-
type:
|
|
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:
|
|
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:
|
|
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 ===
|
|
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:
|
|
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(
|
|
7074
|
+
document.addEventListener("click", this.handleClick, true);
|
|
7075
7075
|
}
|
|
7076
7076
|
if (this.config.captureScrolls) {
|
|
7077
|
-
window.addEventListener(
|
|
7078
|
-
document.addEventListener(
|
|
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(
|
|
7082
|
-
document.addEventListener(
|
|
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(
|
|
7085
|
+
document.addEventListener("mousemove", this.handleMouseMove, {
|
|
7086
|
+
passive: true,
|
|
7087
|
+
});
|
|
7086
7088
|
}
|
|
7087
7089
|
// Viewport changes
|
|
7088
|
-
window.addEventListener(
|
|
7089
|
-
window.addEventListener(
|
|
7090
|
+
window.addEventListener("resize", this.handleViewportChange);
|
|
7091
|
+
window.addEventListener("orientationchange", this.handleViewportChange);
|
|
7090
7092
|
// Navigation
|
|
7091
|
-
window.addEventListener(
|
|
7092
|
-
window.addEventListener(
|
|
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(
|
|
7099
|
-
window.removeEventListener(
|
|
7100
|
-
document.removeEventListener(
|
|
7101
|
-
document.removeEventListener(
|
|
7102
|
-
document.removeEventListener(
|
|
7103
|
-
document.removeEventListener(
|
|
7104
|
-
window.removeEventListener(
|
|
7105
|
-
window.removeEventListener(
|
|
7106
|
-
window.removeEventListener(
|
|
7107
|
-
window.removeEventListener(
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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) ||
|
|
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 = [
|
|
7213
|
-
const sensitiveNames = [
|
|
7214
|
-
|
|
7215
|
-
|
|
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 = [
|
|
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(
|
|
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
|
|
7284
|
+
* Set SDK instance for transport
|
|
7271
7285
|
*/
|
|
7272
|
-
|
|
7273
|
-
this.
|
|
7286
|
+
setSDKInstance(sdk) {
|
|
7287
|
+
this.sdkInstance = sdk;
|
|
7274
7288
|
}
|
|
7275
7289
|
/**
|
|
7276
|
-
* Send
|
|
7290
|
+
* Send replay batch via SDK's transport system
|
|
7277
7291
|
*/
|
|
7278
7292
|
async sendToBackend(payload) {
|
|
7279
7293
|
try {
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
7318
|
-
|
|
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.
|
|
7320
|
+
console.error("[Zaplier] Session replay batch failed:", result);
|
|
7327
7321
|
}
|
|
7328
7322
|
}
|
|
7329
7323
|
catch (error) {
|
|
7330
|
-
console.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
|
|
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:
|
|
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.
|
|
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.
|
|
7460
|
-
|
|
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.
|
|
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:
|
|
7620
|
+
sampleRate: sampleRate,
|
|
7585
7621
|
maskSensitiveFields: this.config.replayMaskInputs,
|
|
7586
7622
|
compressionEnabled: true,
|
|
7587
7623
|
});
|
|
7588
|
-
// Connect
|
|
7589
|
-
|
|
7590
|
-
|
|
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
|
*/
|