@devskin/browser-sdk 1.0.39 → 1.0.41
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/collectors/heatmap.d.ts +3 -1
- package/dist/collectors/heatmap.d.ts.map +1 -1
- package/dist/devskin.cjs.js +122 -96
- package/dist/devskin.cjs.js.map +1 -1
- package/dist/devskin.esm.js +122 -96
- package/dist/devskin.esm.js.map +1 -1
- package/dist/devskin.umd.js +122 -96
- package/dist/devskin.umd.js.map +1 -1
- package/dist/devskin.umd.min.js +2 -2
- package/dist/devskin.umd.min.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -3,13 +3,15 @@ import { Transport } from '../transport';
|
|
|
3
3
|
export declare class HeatmapCollector {
|
|
4
4
|
private config;
|
|
5
5
|
private transport;
|
|
6
|
+
private anonymousId;
|
|
7
|
+
private sessionId;
|
|
6
8
|
private clickData;
|
|
7
9
|
private scrollData;
|
|
8
10
|
private mouseMoveData;
|
|
9
11
|
private maxScrollDepth;
|
|
10
12
|
private flushInterval;
|
|
11
13
|
private mouseMoveSampling;
|
|
12
|
-
constructor(config: DevSkinConfig, transport: Transport);
|
|
14
|
+
constructor(config: DevSkinConfig, transport: Transport, anonymousId: string, sessionId: string);
|
|
13
15
|
start(): void;
|
|
14
16
|
stop(): void;
|
|
15
17
|
private trackClicks;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heatmap.d.ts","sourceRoot":"","sources":["../../src/collectors/heatmap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAkCzC,qBAAa,gBAAgB;IASzB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,SAAS;
|
|
1
|
+
{"version":3,"file":"heatmap.d.ts","sourceRoot":"","sources":["../../src/collectors/heatmap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAkCzC,qBAAa,gBAAgB;IASzB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,SAAS;IAXnB,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,aAAa,CAA+C;IACpE,OAAO,CAAC,iBAAiB,CAAO;gBAGtB,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM;IAG3B,KAAK,IAAI,IAAI;IAoCb,IAAI,IAAI,IAAI;IAQZ,OAAO,CAAC,WAAW;IA8CnB,OAAO,CAAC,gBAAgB;IA2CxB,OAAO,CAAC,kBAAkB;IAkC1B,OAAO,CAAC,KAAK;IAyCb,OAAO,CAAC,kBAAkB;CAc3B"}
|
package/dist/devskin.cjs.js
CHANGED
|
@@ -861,9 +861,11 @@ class NetworkCollector {
|
|
|
861
861
|
}
|
|
862
862
|
|
|
863
863
|
class HeatmapCollector {
|
|
864
|
-
constructor(config, transport) {
|
|
864
|
+
constructor(config, transport, anonymousId, sessionId) {
|
|
865
865
|
this.config = config;
|
|
866
866
|
this.transport = transport;
|
|
867
|
+
this.anonymousId = anonymousId;
|
|
868
|
+
this.sessionId = sessionId;
|
|
867
869
|
this.clickData = [];
|
|
868
870
|
this.scrollData = [];
|
|
869
871
|
this.mouseMoveData = [];
|
|
@@ -1007,21 +1009,21 @@ class HeatmapCollector {
|
|
|
1007
1009
|
// Send clicks individually (backend expects one click event per item)
|
|
1008
1010
|
if (this.clickData.length > 0) {
|
|
1009
1011
|
this.clickData.forEach(click => {
|
|
1010
|
-
this.transport.sendHeatmapData(Object.assign({ type: 'click' }, click));
|
|
1012
|
+
this.transport.sendHeatmapData(Object.assign({ type: 'click', anonymousId: this.anonymousId, sessionId: this.sessionId }, click));
|
|
1011
1013
|
});
|
|
1012
1014
|
this.clickData = [];
|
|
1013
1015
|
}
|
|
1014
1016
|
// Send scroll data individually
|
|
1015
1017
|
if (this.scrollData.length > 0) {
|
|
1016
1018
|
this.scrollData.forEach(scroll => {
|
|
1017
|
-
this.transport.sendHeatmapData(Object.assign({ type: 'scroll' }, scroll));
|
|
1019
|
+
this.transport.sendHeatmapData(Object.assign({ type: 'scroll', anonymousId: this.anonymousId, sessionId: this.sessionId }, scroll));
|
|
1018
1020
|
});
|
|
1019
1021
|
this.scrollData = [];
|
|
1020
1022
|
}
|
|
1021
1023
|
// Send mouse moves individually
|
|
1022
1024
|
if (this.mouseMoveData.length > 0) {
|
|
1023
1025
|
this.mouseMoveData.forEach(move => {
|
|
1024
|
-
this.transport.sendHeatmapData(Object.assign({ type: 'mousemove' }, move));
|
|
1026
|
+
this.transport.sendHeatmapData(Object.assign({ type: 'mousemove', anonymousId: this.anonymousId, sessionId: this.sessionId }, move));
|
|
1025
1027
|
});
|
|
1026
1028
|
this.mouseMoveData = [];
|
|
1027
1029
|
}
|
|
@@ -13876,6 +13878,7 @@ class DevSkinSDK {
|
|
|
13876
13878
|
this.anonymousId = null;
|
|
13877
13879
|
this.sessionStartTime = 0;
|
|
13878
13880
|
this.initialized = false;
|
|
13881
|
+
this.initializing = false;
|
|
13879
13882
|
this.heartbeatInterval = null;
|
|
13880
13883
|
// Collectors
|
|
13881
13884
|
this.deviceCollector = null;
|
|
@@ -13891,12 +13894,15 @@ class DevSkinSDK {
|
|
|
13891
13894
|
}
|
|
13892
13895
|
/**
|
|
13893
13896
|
* Initialize the DevSkin SDK
|
|
13897
|
+
* Uses requestIdleCallback to defer heavy initialization without blocking the page
|
|
13894
13898
|
*/
|
|
13895
13899
|
init(config) {
|
|
13896
|
-
if (this.initialized) {
|
|
13897
|
-
console.warn('[DevSkin] SDK already initialized');
|
|
13900
|
+
if (this.initialized || this.initializing) {
|
|
13901
|
+
console.warn('[DevSkin] SDK already initialized or initializing');
|
|
13898
13902
|
return;
|
|
13899
13903
|
}
|
|
13904
|
+
// Mark as initializing to prevent duplicate init() calls
|
|
13905
|
+
this.initializing = true;
|
|
13900
13906
|
this.config = Object.assign({ debug: false, captureWebVitals: true, captureNetworkRequests: true, captureErrors: true, captureUserAgent: true, captureLocation: true, captureDevice: true, heatmapOptions: {
|
|
13901
13907
|
enabled: true,
|
|
13902
13908
|
trackClicks: true,
|
|
@@ -13906,99 +13912,118 @@ class DevSkinSDK {
|
|
|
13906
13912
|
if (this.config.debug) {
|
|
13907
13913
|
console.log('[DevSkin] Initializing SDK with config:', this.config);
|
|
13908
13914
|
}
|
|
13909
|
-
// Initialize
|
|
13915
|
+
// Initialize lightweight components immediately (needed for session context)
|
|
13910
13916
|
this.transport = new Transport(this.config);
|
|
13911
|
-
// Generate anonymous ID if not exists
|
|
13912
13917
|
this.anonymousId = this.getOrCreateAnonymousId();
|
|
13913
|
-
// Initialize collectors BEFORE starting session (so getContextData works)
|
|
13914
13918
|
this.deviceCollector = new DeviceCollector(this.config);
|
|
13915
13919
|
this.locationCollector = new LocationCollector(this.config);
|
|
13916
13920
|
this.browserCollector = new BrowserCollector(this.config);
|
|
13917
|
-
//
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
//
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
this.
|
|
13925
|
-
|
|
13926
|
-
|
|
13927
|
-
|
|
13928
|
-
this.
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
this.
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
|
|
13938
|
-
|
|
13939
|
-
|
|
13940
|
-
|
|
13941
|
-
|
|
13942
|
-
|
|
13943
|
-
|
|
13944
|
-
|
|
13945
|
-
|
|
13946
|
-
|
|
13947
|
-
|
|
13948
|
-
//
|
|
13949
|
-
|
|
13950
|
-
|
|
13951
|
-
|
|
13952
|
-
|
|
13953
|
-
|
|
13954
|
-
|
|
13955
|
-
|
|
13956
|
-
|
|
13957
|
-
:
|
|
13958
|
-
|
|
13959
|
-
|
|
13960
|
-
|
|
13961
|
-
|
|
13962
|
-
|
|
13963
|
-
|
|
13964
|
-
|
|
13965
|
-
|
|
13966
|
-
|
|
13967
|
-
|
|
13968
|
-
|
|
13969
|
-
|
|
13970
|
-
|
|
13971
|
-
|
|
13972
|
-
|
|
13973
|
-
|
|
13974
|
-
|
|
13975
|
-
|
|
13976
|
-
|
|
13977
|
-
|
|
13921
|
+
// Defer heavy initialization to avoid blocking page load/rendering
|
|
13922
|
+
const initHeavyCollectors = () => {
|
|
13923
|
+
// Start session (will now include device/browser/location data)
|
|
13924
|
+
// Wait for session creation to complete before starting collectors
|
|
13925
|
+
this.startSession().then(() => {
|
|
13926
|
+
// Session created, now safe to start collectors that send data
|
|
13927
|
+
var _a, _b;
|
|
13928
|
+
if (this.config.captureWebVitals) {
|
|
13929
|
+
this.performanceCollector = new PerformanceCollector(this.config, this.transport);
|
|
13930
|
+
this.performanceCollector.start();
|
|
13931
|
+
}
|
|
13932
|
+
if (this.config.captureErrors) {
|
|
13933
|
+
this.errorCollector = new ErrorCollector(this.config, this.transport);
|
|
13934
|
+
this.errorCollector.start();
|
|
13935
|
+
}
|
|
13936
|
+
if (this.config.captureNetworkRequests) {
|
|
13937
|
+
this.networkCollector = new NetworkCollector(this.config, this.transport);
|
|
13938
|
+
this.networkCollector.start();
|
|
13939
|
+
}
|
|
13940
|
+
// Initialize heatmap collector - SEMPRE habilitado
|
|
13941
|
+
// Merge default heatmap config with user config
|
|
13942
|
+
const heatmapConfig = Object.assign({ enabled: true, trackClicks: true, trackScroll: true, trackMouseMovement: true, mouseMoveSampling: 0.1 }, this.config.heatmapOptions);
|
|
13943
|
+
this.config.heatmapOptions = heatmapConfig;
|
|
13944
|
+
this.heatmapCollector = new HeatmapCollector(this.config, this.transport, this.anonymousId, this.sessionId);
|
|
13945
|
+
this.heatmapCollector.start();
|
|
13946
|
+
// Initialize screenshot collector and capture page
|
|
13947
|
+
this.screenshotCollector = new ScreenshotCollector(this.config, this.transport);
|
|
13948
|
+
this.screenshotCollector.captureAndSend(this.sessionId, window.location.href);
|
|
13949
|
+
if (this.config.debug) {
|
|
13950
|
+
console.log('[DevSkin] Heatmap collection enabled (always on)');
|
|
13951
|
+
}
|
|
13952
|
+
// Initialize session recording with rrweb
|
|
13953
|
+
if ((_a = this.config.sessionRecording) === null || _a === void 0 ? void 0 : _a.enabled) {
|
|
13954
|
+
// Use RRWebRecorder for complete DOM recording
|
|
13955
|
+
// Pass sessionStartTime to ensure timestamp continuity across page navigations
|
|
13956
|
+
this.rrwebRecorder = new RRWebRecorder(this.sessionId, {
|
|
13957
|
+
enabled: true,
|
|
13958
|
+
sampleRate: this.config.sessionRecording.sampling || 0.5,
|
|
13959
|
+
blockClass: 'rr-block',
|
|
13960
|
+
ignoreClass: this.config.sessionRecording.ignoreClass || 'rr-ignore',
|
|
13961
|
+
maskAllInputs: this.config.sessionRecording.maskAllInputs !== undefined
|
|
13962
|
+
? this.config.sessionRecording.maskAllInputs
|
|
13963
|
+
: true,
|
|
13964
|
+
maskInputOptions: {
|
|
13965
|
+
password: true,
|
|
13966
|
+
email: true,
|
|
13967
|
+
tel: true,
|
|
13968
|
+
},
|
|
13969
|
+
recordCanvas: this.config.sessionRecording.recordCanvas || false,
|
|
13970
|
+
collectFonts: true,
|
|
13971
|
+
inlineStylesheet: true,
|
|
13972
|
+
checkoutEveryNms: 5 * 60 * 1000, // Every 5 minutes
|
|
13973
|
+
checkoutEveryNth: 200, // Every 200 events
|
|
13974
|
+
}, (events) => {
|
|
13975
|
+
var _a;
|
|
13976
|
+
// Send rrweb events to backend
|
|
13977
|
+
(_a = this.transport) === null || _a === void 0 ? void 0 : _a.sendRecordingEvents(this.sessionId, events);
|
|
13978
|
+
}, this.sessionStartTime // Pass session start time for timestamp continuity
|
|
13979
|
+
);
|
|
13980
|
+
// Start recording immediately (session already created)
|
|
13981
|
+
this.rrwebRecorder.start();
|
|
13982
|
+
if ((_b = this.config) === null || _b === void 0 ? void 0 : _b.debug) {
|
|
13983
|
+
console.log('[DevSkin] RRWeb recording started for session:', this.sessionId);
|
|
13984
|
+
}
|
|
13978
13985
|
}
|
|
13986
|
+
// Track initial page view
|
|
13987
|
+
this.trackPageView();
|
|
13988
|
+
// Start heartbeat to update session duration every 30 seconds
|
|
13989
|
+
this.startHeartbeat();
|
|
13990
|
+
}).catch((err) => {
|
|
13991
|
+
console.error('[DevSkin] Failed to create session:', err);
|
|
13992
|
+
});
|
|
13993
|
+
// Track page visibility changes
|
|
13994
|
+
this.setupVisibilityTracking();
|
|
13995
|
+
// Track page unload
|
|
13996
|
+
this.setupUnloadTracking();
|
|
13997
|
+
// Mark as fully initialized only after everything is loaded
|
|
13998
|
+
this.initialized = true;
|
|
13999
|
+
this.initializing = false;
|
|
14000
|
+
};
|
|
14001
|
+
// Use requestIdleCallback to defer heavy initialization (non-blocking)
|
|
14002
|
+
// Falls back to setTimeout for browsers that don't support it
|
|
14003
|
+
if (typeof window !== 'undefined') {
|
|
14004
|
+
if ('requestIdleCallback' in window) {
|
|
14005
|
+
window.requestIdleCallback(initHeavyCollectors, { timeout: 2000 });
|
|
13979
14006
|
}
|
|
13980
|
-
|
|
13981
|
-
|
|
13982
|
-
|
|
13983
|
-
|
|
13984
|
-
}
|
|
13985
|
-
|
|
13986
|
-
|
|
13987
|
-
|
|
13988
|
-
|
|
13989
|
-
// Track page unload
|
|
13990
|
-
this.setupUnloadTracking();
|
|
13991
|
-
this.initialized = true;
|
|
14007
|
+
else {
|
|
14008
|
+
// Fallback for older browsers
|
|
14009
|
+
setTimeout(initHeavyCollectors, 1);
|
|
14010
|
+
}
|
|
14011
|
+
}
|
|
14012
|
+
else {
|
|
14013
|
+
// Node.js environment (SSR)
|
|
14014
|
+
initHeavyCollectors();
|
|
14015
|
+
}
|
|
13992
14016
|
if (this.config.debug) {
|
|
13993
|
-
console.log('[DevSkin] SDK
|
|
14017
|
+
console.log('[DevSkin] SDK initialization started (heavy collectors loading in background)');
|
|
13994
14018
|
}
|
|
13995
14019
|
}
|
|
13996
14020
|
/**
|
|
13997
14021
|
* Track a custom event
|
|
14022
|
+
* Works immediately after init() even if heavy collectors are still loading
|
|
13998
14023
|
*/
|
|
13999
14024
|
track(eventName, properties) {
|
|
14000
|
-
var _a, _b;
|
|
14001
|
-
if (!this.
|
|
14025
|
+
var _a, _b, _c, _d;
|
|
14026
|
+
if (!this.transport) {
|
|
14002
14027
|
console.warn('[DevSkin] SDK not initialized. Call init() first.');
|
|
14003
14028
|
return;
|
|
14004
14029
|
}
|
|
@@ -14006,15 +14031,15 @@ class DevSkinSDK {
|
|
|
14006
14031
|
eventName: eventName,
|
|
14007
14032
|
eventType: 'track',
|
|
14008
14033
|
timestamp: new Date().toISOString(),
|
|
14009
|
-
sessionId: this.sessionId,
|
|
14010
|
-
userId: this.userId
|
|
14011
|
-
anonymousId: this.anonymousId
|
|
14034
|
+
sessionId: (_a = this.sessionId) !== null && _a !== void 0 ? _a : undefined,
|
|
14035
|
+
userId: (_b = this.userId) !== null && _b !== void 0 ? _b : undefined,
|
|
14036
|
+
anonymousId: (_c = this.anonymousId) !== null && _c !== void 0 ? _c : undefined,
|
|
14012
14037
|
properties: Object.assign(Object.assign({}, properties), this.getContextData()),
|
|
14013
14038
|
pageUrl: window.location.href,
|
|
14014
14039
|
pageTitle: document.title,
|
|
14015
14040
|
};
|
|
14016
|
-
|
|
14017
|
-
if ((
|
|
14041
|
+
this.transport.sendEvent(eventData);
|
|
14042
|
+
if ((_d = this.config) === null || _d === void 0 ? void 0 : _d.debug) {
|
|
14018
14043
|
console.log('[DevSkin] Event tracked:', eventData);
|
|
14019
14044
|
}
|
|
14020
14045
|
}
|
|
@@ -14043,23 +14068,24 @@ class DevSkinSDK {
|
|
|
14043
14068
|
}
|
|
14044
14069
|
/**
|
|
14045
14070
|
* Identify a user
|
|
14071
|
+
* Works immediately after init() even if heavy collectors are still loading
|
|
14046
14072
|
*/
|
|
14047
14073
|
identify(userId, traits) {
|
|
14048
|
-
var _a, _b;
|
|
14049
|
-
if (!this.
|
|
14074
|
+
var _a, _b, _c;
|
|
14075
|
+
if (!this.transport) {
|
|
14050
14076
|
console.warn('[DevSkin] SDK not initialized. Call init() first.');
|
|
14051
14077
|
return;
|
|
14052
14078
|
}
|
|
14053
14079
|
this.userId = userId;
|
|
14054
14080
|
const userData = {
|
|
14055
14081
|
userId: userId,
|
|
14056
|
-
anonymousId: this.anonymousId
|
|
14082
|
+
anonymousId: (_a = this.anonymousId) !== null && _a !== void 0 ? _a : undefined,
|
|
14057
14083
|
traits: Object.assign(Object.assign({}, traits), this.getContextData()),
|
|
14058
|
-
sessionId: this.sessionId,
|
|
14084
|
+
sessionId: (_b = this.sessionId) !== null && _b !== void 0 ? _b : undefined,
|
|
14059
14085
|
timestamp: new Date().toISOString(),
|
|
14060
14086
|
};
|
|
14061
|
-
|
|
14062
|
-
if ((
|
|
14087
|
+
this.transport.identifyUser(userData);
|
|
14088
|
+
if ((_c = this.config) === null || _c === void 0 ? void 0 : _c.debug) {
|
|
14063
14089
|
console.log('[DevSkin] User identified:', userData);
|
|
14064
14090
|
}
|
|
14065
14091
|
}
|