@devskin/browser-sdk 1.0.26 → 1.0.28
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/devskin.cjs.js +78 -37
- package/dist/devskin.cjs.js.map +1 -1
- package/dist/devskin.esm.js +78 -37
- package/dist/devskin.esm.js.map +1 -1
- package/dist/devskin.umd.js +78 -37
- package/dist/devskin.umd.js.map +1 -1
- package/dist/devskin.umd.min.js +3 -3
- package/dist/devskin.umd.min.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/transport.d.ts +1 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/types.d.ts +21 -20
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/devskin.cjs.js
CHANGED
|
@@ -515,7 +515,7 @@ class ErrorCollector {
|
|
|
515
515
|
stack: error.stack,
|
|
516
516
|
type: error.name || 'Error',
|
|
517
517
|
timestamp: new Date().toISOString(),
|
|
518
|
-
|
|
518
|
+
sessionId: '', // Will be set by transport
|
|
519
519
|
url: window.location.href,
|
|
520
520
|
breadcrumbs: [...this.breadcrumbs],
|
|
521
521
|
context: Object.assign(Object.assign({}, context), { userAgent: navigator.userAgent, viewport: {
|
|
@@ -538,7 +538,7 @@ class ErrorCollector {
|
|
|
538
538
|
message: String(error),
|
|
539
539
|
type: 'Error',
|
|
540
540
|
timestamp: new Date().toISOString(),
|
|
541
|
-
|
|
541
|
+
sessionId: '',
|
|
542
542
|
url: window.location.href,
|
|
543
543
|
breadcrumbs: [...this.breadcrumbs],
|
|
544
544
|
context,
|
|
@@ -13484,8 +13484,8 @@ class RRWebRecorder {
|
|
|
13484
13484
|
// Send immediately to ensure FullSnapshot reaches backend first
|
|
13485
13485
|
this.flush();
|
|
13486
13486
|
}
|
|
13487
|
-
else if (this.hasFullSnapshot && this.events.length >=
|
|
13488
|
-
// After FullSnapshot, batch other events
|
|
13487
|
+
else if (this.hasFullSnapshot && this.events.length >= 20) {
|
|
13488
|
+
// After FullSnapshot, batch other events (reduced from 50 to 20)
|
|
13489
13489
|
this.flush();
|
|
13490
13490
|
}
|
|
13491
13491
|
},
|
|
@@ -13524,13 +13524,13 @@ class RRWebRecorder {
|
|
|
13524
13524
|
// Capture iframe content
|
|
13525
13525
|
recordCrossOriginIframes: false, // Security: don't record cross-origin iframes
|
|
13526
13526
|
});
|
|
13527
|
-
// Set up periodic flush (every
|
|
13527
|
+
// Set up periodic flush (every 2 seconds)
|
|
13528
13528
|
// Only flush if we have FullSnapshot to ensure first batch is complete
|
|
13529
13529
|
this.flushInterval = window.setInterval(() => {
|
|
13530
13530
|
if (this.hasFullSnapshot && this.events.length > 0) {
|
|
13531
13531
|
this.flush();
|
|
13532
13532
|
}
|
|
13533
|
-
},
|
|
13533
|
+
}, 2000); // Reduced from 10s to 2s
|
|
13534
13534
|
// Safety check: After 2 seconds, force a full snapshot if none captured
|
|
13535
13535
|
setTimeout(() => {
|
|
13536
13536
|
if (!this.hasFullSnapshot) {
|
|
@@ -13588,8 +13588,8 @@ class Transport {
|
|
|
13588
13588
|
this.config = config;
|
|
13589
13589
|
this.queue = [];
|
|
13590
13590
|
this.flushInterval = null;
|
|
13591
|
-
this.maxQueueSize = 50
|
|
13592
|
-
this.flushIntervalMs =
|
|
13591
|
+
this.maxQueueSize = 20; // Reduced from 50
|
|
13592
|
+
this.flushIntervalMs = 2000; // 2 seconds (reduced from 5s)
|
|
13593
13593
|
this.apiUrl = config.apiUrl || 'https://api.devskin.com';
|
|
13594
13594
|
// Start periodic flush
|
|
13595
13595
|
this.startPeriodicFlush();
|
|
@@ -13614,8 +13614,8 @@ class Transport {
|
|
|
13614
13614
|
this.sendToBackend('/v1/analytics/identify', user);
|
|
13615
13615
|
}
|
|
13616
13616
|
startSession(session) {
|
|
13617
|
-
// Send session start immediately
|
|
13618
|
-
this.sendToBackend('/v1/
|
|
13617
|
+
// Send session start immediately to RUM endpoint
|
|
13618
|
+
this.sendToBackend('/v1/rum/sessions', session);
|
|
13619
13619
|
}
|
|
13620
13620
|
sendError(error) {
|
|
13621
13621
|
this.enqueue('error', error);
|
|
@@ -13626,6 +13626,12 @@ class Transport {
|
|
|
13626
13626
|
sendPerformanceMetric(metric) {
|
|
13627
13627
|
this.enqueue('performance', metric);
|
|
13628
13628
|
}
|
|
13629
|
+
sendPageView(pageViewData) {
|
|
13630
|
+
return __awaiter$1(this, void 0, void 0, function* () {
|
|
13631
|
+
// Send page view immediately to RUM endpoint (don't queue)
|
|
13632
|
+
this.sendToBackend('/v1/rum/page-views', pageViewData);
|
|
13633
|
+
});
|
|
13634
|
+
}
|
|
13629
13635
|
sendRecordingEvents(sessionId, events) {
|
|
13630
13636
|
return __awaiter$1(this, void 0, void 0, function* () {
|
|
13631
13637
|
// Calculate payload size
|
|
@@ -13726,23 +13732,23 @@ class Transport {
|
|
|
13726
13732
|
getEndpointForType(type) {
|
|
13727
13733
|
switch (type) {
|
|
13728
13734
|
case 'event':
|
|
13729
|
-
return '/v1/
|
|
13735
|
+
return '/v1/rum/events';
|
|
13730
13736
|
case 'error':
|
|
13731
|
-
return '/v1/
|
|
13737
|
+
return '/v1/errors/errors';
|
|
13732
13738
|
case 'network':
|
|
13733
|
-
return '/v1/
|
|
13739
|
+
return '/v1/rum/network-requests';
|
|
13734
13740
|
case 'performance':
|
|
13735
|
-
return '/v1/
|
|
13741
|
+
return '/v1/rum/web-vitals';
|
|
13736
13742
|
case 'heatmap':
|
|
13737
13743
|
return '/v1/sdk/heatmap';
|
|
13738
13744
|
default:
|
|
13739
|
-
return '/v1/
|
|
13745
|
+
return '/v1/rum/events';
|
|
13740
13746
|
}
|
|
13741
13747
|
}
|
|
13742
13748
|
sendToBackendXHR(endpoint, data) {
|
|
13743
13749
|
return __awaiter$1(this, void 0, void 0, function* () {
|
|
13744
13750
|
const url = `${this.apiUrl}${endpoint}`;
|
|
13745
|
-
const payload = Object.assign(Object.assign({}, data), { apiKey: this.config.apiKey,
|
|
13751
|
+
const payload = Object.assign(Object.assign({}, data), { apiKey: this.config.apiKey, applicationId: this.config.appId, environment: this.config.environment, release: this.config.release });
|
|
13746
13752
|
// Apply beforeSend hook if provided
|
|
13747
13753
|
if (this.config.beforeSend) {
|
|
13748
13754
|
const processed = this.config.beforeSend(payload);
|
|
@@ -13792,7 +13798,7 @@ class Transport {
|
|
|
13792
13798
|
sendToBackend(endpoint_1, data_1) {
|
|
13793
13799
|
return __awaiter$1(this, arguments, void 0, function* (endpoint, data, useBeacon = false) {
|
|
13794
13800
|
const url = `${this.apiUrl}${endpoint}`;
|
|
13795
|
-
const payload = Object.assign(Object.assign({}, data), { apiKey: this.config.apiKey,
|
|
13801
|
+
const payload = Object.assign(Object.assign({}, data), { apiKey: this.config.apiKey, applicationId: this.config.appId, environment: this.config.environment, release: this.config.release });
|
|
13796
13802
|
// Apply beforeSend hook if provided
|
|
13797
13803
|
if (this.config.beforeSend) {
|
|
13798
13804
|
const processed = this.config.beforeSend(payload);
|
|
@@ -13976,15 +13982,15 @@ class DevSkinSDK {
|
|
|
13976
13982
|
return;
|
|
13977
13983
|
}
|
|
13978
13984
|
const eventData = {
|
|
13979
|
-
|
|
13980
|
-
|
|
13985
|
+
eventName: eventName,
|
|
13986
|
+
eventType: 'track',
|
|
13981
13987
|
timestamp: new Date().toISOString(),
|
|
13982
|
-
|
|
13983
|
-
|
|
13984
|
-
|
|
13988
|
+
sessionId: this.sessionId,
|
|
13989
|
+
userId: this.userId || undefined,
|
|
13990
|
+
anonymousId: this.anonymousId || undefined,
|
|
13985
13991
|
properties: Object.assign(Object.assign({}, properties), this.getContextData()),
|
|
13986
|
-
|
|
13987
|
-
|
|
13992
|
+
pageUrl: window.location.href,
|
|
13993
|
+
pageTitle: document.title,
|
|
13988
13994
|
};
|
|
13989
13995
|
(_a = this.transport) === null || _a === void 0 ? void 0 : _a.sendEvent(eventData);
|
|
13990
13996
|
if ((_b = this.config) === null || _b === void 0 ? void 0 : _b.debug) {
|
|
@@ -13995,7 +14001,24 @@ class DevSkinSDK {
|
|
|
13995
14001
|
* Track a page view
|
|
13996
14002
|
*/
|
|
13997
14003
|
trackPageView(properties) {
|
|
14004
|
+
var _a, _b;
|
|
14005
|
+
if (!this.initialized) {
|
|
14006
|
+
console.warn('[DevSkin] SDK not initialized. Call init() first.');
|
|
14007
|
+
return;
|
|
14008
|
+
}
|
|
14009
|
+
// Generate unique page view ID
|
|
14010
|
+
const pageViewId = this.generateId();
|
|
14011
|
+
// Send to RUM page-views endpoint
|
|
14012
|
+
(_a = this.transport) === null || _a === void 0 ? void 0 : _a.sendPageView(Object.assign({ sessionId: this.sessionId, pageViewId: pageViewId, url: window.location.href, path: window.location.pathname, queryParams: window.location.search, referrer: document.referrer, title: document.title, timestamp: new Date().toISOString() }, properties));
|
|
14013
|
+
// Also track as analytics event for backwards compatibility
|
|
13998
14014
|
this.track('page_view', Object.assign({ path: window.location.pathname, search: window.location.search, hash: window.location.hash, referrer: document.referrer }, properties));
|
|
14015
|
+
if ((_b = this.config) === null || _b === void 0 ? void 0 : _b.debug) {
|
|
14016
|
+
console.log('[DevSkin] Page view tracked:', {
|
|
14017
|
+
sessionId: this.sessionId,
|
|
14018
|
+
pageViewId: pageViewId,
|
|
14019
|
+
url: window.location.href,
|
|
14020
|
+
});
|
|
14021
|
+
}
|
|
13999
14022
|
}
|
|
14000
14023
|
/**
|
|
14001
14024
|
* Identify a user
|
|
@@ -14008,10 +14031,10 @@ class DevSkinSDK {
|
|
|
14008
14031
|
}
|
|
14009
14032
|
this.userId = userId;
|
|
14010
14033
|
const userData = {
|
|
14011
|
-
|
|
14012
|
-
|
|
14034
|
+
userId: userId,
|
|
14035
|
+
anonymousId: this.anonymousId || undefined,
|
|
14013
14036
|
traits: Object.assign(Object.assign({}, traits), this.getContextData()),
|
|
14014
|
-
|
|
14037
|
+
sessionId: this.sessionId,
|
|
14015
14038
|
timestamp: new Date().toISOString(),
|
|
14016
14039
|
};
|
|
14017
14040
|
(_a = this.transport) === null || _a === void 0 ? void 0 : _a.identifyUser(userData);
|
|
@@ -14085,7 +14108,7 @@ class DevSkinSDK {
|
|
|
14085
14108
|
// Store in sessionStorage (persists across page navigations in same tab)
|
|
14086
14109
|
sessionStorage.setItem('devskin_session_id', this.sessionId);
|
|
14087
14110
|
sessionStorage.setItem('devskin_session_start', this.sessionStartTime.toString());
|
|
14088
|
-
const sessionData = Object.assign({
|
|
14111
|
+
const sessionData = Object.assign({ sessionId: this.sessionId, userId: this.userId || undefined, anonymousId: this.anonymousId, startedAt: new Date().toISOString(), platform: 'web' }, this.getContextData());
|
|
14089
14112
|
(_b = this.transport) === null || _b === void 0 ? void 0 : _b.startSession(sessionData);
|
|
14090
14113
|
if ((_c = this.config) === null || _c === void 0 ? void 0 : _c.debug) {
|
|
14091
14114
|
console.log('[DevSkin] New session created:', this.sessionId);
|
|
@@ -14126,27 +14149,45 @@ class DevSkinSDK {
|
|
|
14126
14149
|
});
|
|
14127
14150
|
}
|
|
14128
14151
|
setupUnloadTracking() {
|
|
14129
|
-
//
|
|
14130
|
-
|
|
14152
|
+
// CRITICAL: Flush data BEFORE page unloads to avoid losing final events
|
|
14153
|
+
// 1. visibilitychange - fires when tab is hidden (most reliable)
|
|
14154
|
+
document.addEventListener('visibilitychange', () => {
|
|
14131
14155
|
var _a, _b;
|
|
14132
|
-
|
|
14133
|
-
|
|
14134
|
-
|
|
14156
|
+
if (document.hidden) {
|
|
14157
|
+
// User switched tabs or minimized - flush immediately
|
|
14158
|
+
(_a = this.rrwebRecorder) === null || _a === void 0 ? void 0 : _a.stop(); // Stop recording and flush
|
|
14159
|
+
(_b = this.transport) === null || _b === void 0 ? void 0 : _b.flush(true); // Use beacon
|
|
14160
|
+
}
|
|
14161
|
+
});
|
|
14162
|
+
// 2. pagehide - fires when page is being unloaded
|
|
14163
|
+
window.addEventListener('pagehide', (event) => {
|
|
14164
|
+
var _a, _b, _c;
|
|
14135
14165
|
const isActualClose = !event.persisted;
|
|
14136
14166
|
if (isActualClose) {
|
|
14167
|
+
// Tab is closing - end session
|
|
14137
14168
|
this.track('page_unload');
|
|
14138
|
-
// Only send session end if tab is actually closing
|
|
14139
14169
|
if (this.sessionId && this.sessionStartTime) {
|
|
14140
14170
|
const endedAt = new Date();
|
|
14141
14171
|
const durationMs = Date.now() - this.sessionStartTime;
|
|
14142
|
-
(_a = this.transport) === null || _a === void 0 ? void 0 : _a.startSession(Object.assign({
|
|
14172
|
+
(_a = this.transport) === null || _a === void 0 ? void 0 : _a.startSession(Object.assign({ sessionId: this.sessionId, userId: this.userId || undefined, anonymousId: this.anonymousId, endedAt: endedAt.toISOString(), durationMs: durationMs, platform: 'web' }, this.getContextData()));
|
|
14143
14173
|
// Clear session storage since session is ending
|
|
14144
14174
|
sessionStorage.removeItem('devskin_session_id');
|
|
14145
14175
|
sessionStorage.removeItem('devskin_session_start');
|
|
14146
14176
|
}
|
|
14147
14177
|
}
|
|
14148
|
-
|
|
14149
|
-
|
|
14178
|
+
else {
|
|
14179
|
+
// Navigation - track page change
|
|
14180
|
+
this.track('page_navigation');
|
|
14181
|
+
}
|
|
14182
|
+
// ALWAYS flush (whether navigation or close)
|
|
14183
|
+
(_b = this.rrwebRecorder) === null || _b === void 0 ? void 0 : _b.stop(); // Stop recording and flush remaining events
|
|
14184
|
+
(_c = this.transport) === null || _c === void 0 ? void 0 : _c.flush(true); // Use beacon for reliability
|
|
14185
|
+
});
|
|
14186
|
+
// 3. beforeunload - backup for older browsers
|
|
14187
|
+
window.addEventListener('beforeunload', () => {
|
|
14188
|
+
var _a, _b;
|
|
14189
|
+
(_a = this.rrwebRecorder) === null || _a === void 0 ? void 0 : _a.stop();
|
|
14190
|
+
(_b = this.transport) === null || _b === void 0 ? void 0 : _b.flush(true);
|
|
14150
14191
|
});
|
|
14151
14192
|
}
|
|
14152
14193
|
}
|