swetrix 2.3.1 → 3.0.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/.prettierrc.js +13 -0
- package/dist/esnext/Lib.d.ts +42 -13
- package/dist/esnext/Lib.js +49 -80
- package/dist/esnext/Lib.js.map +1 -1
- package/dist/esnext/index.d.ts +10 -0
- package/dist/esnext/index.js +15 -1
- package/dist/esnext/index.js.map +1 -1
- package/dist/esnext/utils.d.ts +20 -1
- package/dist/esnext/utils.js +27 -3
- package/dist/esnext/utils.js.map +1 -1
- package/dist/swetrix.cjs.js +94 -88
- package/dist/swetrix.es5.js +94 -89
- package/dist/swetrix.js +1 -1
- package/dist/swetrix.orig.js +94 -88
- package/package.json +5 -5
- package/src/Lib.ts +110 -99
- package/src/index.ts +16 -3
- package/src/utils.ts +35 -3
package/dist/swetrix.orig.js
CHANGED
|
@@ -68,9 +68,33 @@
|
|
|
68
68
|
var getUTMSource = function () { return findInSearch(utmSourceRegex); };
|
|
69
69
|
var getUTMMedium = function () { return findInSearch(utmMediumRegex); };
|
|
70
70
|
var getUTMCampaign = function () { return findInSearch(utmCampaignRegex); };
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Function used to track the current page (path) of the application.
|
|
73
|
+
* Will work in cases where the path looks like:
|
|
74
|
+
* - /path
|
|
75
|
+
* - /#/path
|
|
76
|
+
* - /path?search
|
|
77
|
+
* - /path?search#hash
|
|
78
|
+
* - /path#hash?search
|
|
79
|
+
*
|
|
80
|
+
* @param options - Options for the function.
|
|
81
|
+
* @param options.hash - Whether to trigger on hash change.
|
|
82
|
+
* @param options.search - Whether to trigger on search change.
|
|
83
|
+
* @returns The path of the current page.
|
|
84
|
+
*/
|
|
85
|
+
var getPath = function (options) {
|
|
86
|
+
var result = location.pathname || '';
|
|
87
|
+
if (options.hash) {
|
|
88
|
+
var hashIndex = location.hash.indexOf('?');
|
|
89
|
+
var hashString = hashIndex > -1 ? location.hash.substring(0, hashIndex) : location.hash;
|
|
90
|
+
result += hashString;
|
|
91
|
+
}
|
|
92
|
+
if (options.search) {
|
|
93
|
+
var hashIndex = location.hash.indexOf('?');
|
|
94
|
+
var searchString = location.search || (hashIndex > -1 ? location.hash.substring(hashIndex) : '');
|
|
95
|
+
result += searchString;
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
74
98
|
};
|
|
75
99
|
|
|
76
100
|
var defaultPageActions = {
|
|
@@ -92,7 +116,7 @@
|
|
|
92
116
|
if (!this.canTrack()) {
|
|
93
117
|
return;
|
|
94
118
|
}
|
|
95
|
-
var data = __assign({ pid: this.projectID, pg: this.activePage, lc: getLocale(), tz: getTimezone(), ref: getReferrer(), so: getUTMSource(), me: getUTMMedium(), ca: getUTMCampaign() }
|
|
119
|
+
var data = __assign(__assign({}, event), { pid: this.projectID, pg: this.activePage, lc: getLocale(), tz: getTimezone(), ref: getReferrer(), so: getUTMSource(), me: getUTMMedium(), ca: getUTMCampaign() });
|
|
96
120
|
this.sendRequest('custom', data);
|
|
97
121
|
};
|
|
98
122
|
Lib.prototype.trackPageViews = function (options) {
|
|
@@ -103,15 +127,16 @@
|
|
|
103
127
|
return this.pageData.actions;
|
|
104
128
|
}
|
|
105
129
|
this.pageViewsOptions = options;
|
|
106
|
-
var
|
|
130
|
+
var interval;
|
|
107
131
|
if (!(options === null || options === void 0 ? void 0 : options.unique)) {
|
|
108
132
|
interval = setInterval(this.trackPathChange, 2000);
|
|
109
133
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
134
|
+
setTimeout(this.heartbeat, 3000);
|
|
135
|
+
var hbInterval = setInterval(this.heartbeat, 28000);
|
|
136
|
+
var path = getPath({
|
|
137
|
+
hash: options === null || options === void 0 ? void 0 : options.hash,
|
|
138
|
+
search: options === null || options === void 0 ? void 0 : options.search,
|
|
139
|
+
});
|
|
115
140
|
this.pageData = {
|
|
116
141
|
path: path,
|
|
117
142
|
actions: {
|
|
@@ -136,23 +161,17 @@
|
|
|
136
161
|
this.perfStatsCollected = true;
|
|
137
162
|
return {
|
|
138
163
|
// Network
|
|
139
|
-
//
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
// @ts-ignore
|
|
146
|
-
response: perf.responseEnd - perf.responseStart,
|
|
164
|
+
dns: perf.domainLookupEnd - perf.domainLookupStart, // DNS Resolution
|
|
165
|
+
tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0, // TLS Setup; checking if secureConnectionStart is not 0 (it's 0 for non-https websites)
|
|
166
|
+
conn: perf.secureConnectionStart
|
|
167
|
+
? perf.secureConnectionStart - perf.connectStart
|
|
168
|
+
: perf.connectEnd - perf.connectStart, // Connection time
|
|
169
|
+
response: perf.responseEnd - perf.responseStart, // Response Time (Download)
|
|
147
170
|
// Frontend
|
|
148
|
-
//
|
|
149
|
-
|
|
150
|
-
//
|
|
151
|
-
dom_load: perf.domContentLoadedEventEnd - perf.responseEnd,
|
|
152
|
-
// @ts-ignore
|
|
153
|
-
page_load: perf.loadEventStart,
|
|
171
|
+
render: perf.domComplete - perf.domContentLoadedEventEnd, // Browser rendering the HTML time
|
|
172
|
+
dom_load: perf.domContentLoadedEventEnd - perf.responseEnd, // DOM loading timing
|
|
173
|
+
page_load: perf.loadEventStart, // Page load time
|
|
154
174
|
// Backend
|
|
155
|
-
// @ts-ignore
|
|
156
175
|
ttfb: perf.responseStart - perf.requestStart,
|
|
157
176
|
};
|
|
158
177
|
};
|
|
@@ -166,40 +185,25 @@
|
|
|
166
185
|
};
|
|
167
186
|
this.sendRequest('hb', data);
|
|
168
187
|
};
|
|
169
|
-
Lib.prototype.checkIgnore = function (path) {
|
|
170
|
-
var _a;
|
|
171
|
-
var ignore = (_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.ignore;
|
|
172
|
-
if (Array.isArray(ignore)) {
|
|
173
|
-
for (var i = 0; i < ignore.length; ++i) {
|
|
174
|
-
if (ignore[i] === path)
|
|
175
|
-
return true;
|
|
176
|
-
// @ts-ignore
|
|
177
|
-
if (ignore[i] instanceof RegExp && ignore[i].test(path))
|
|
178
|
-
return true;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
return false;
|
|
182
|
-
};
|
|
183
188
|
// Tracking path changes. If path changes -> calling this.trackPage method
|
|
184
189
|
Lib.prototype.trackPathChange = function () {
|
|
190
|
+
var _a, _b;
|
|
185
191
|
if (!this.pageData)
|
|
186
192
|
return;
|
|
187
|
-
var newPath = getPath(
|
|
193
|
+
var newPath = getPath({
|
|
194
|
+
hash: (_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.hash,
|
|
195
|
+
search: (_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.search,
|
|
196
|
+
});
|
|
188
197
|
var path = this.pageData.path;
|
|
189
198
|
if (path !== newPath) {
|
|
190
199
|
this.trackPage(newPath, false);
|
|
191
200
|
}
|
|
192
201
|
};
|
|
193
202
|
Lib.prototype.getPreviousPage = function () {
|
|
194
|
-
var _a, _b;
|
|
195
203
|
// Assuming that this function is called in trackPage and this.activePage is not overwritten by new value yet
|
|
196
204
|
// That method of getting previous page works for SPA websites
|
|
197
205
|
if (this.activePage) {
|
|
198
|
-
|
|
199
|
-
if (shouldIgnore && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.doNotAnonymise)) {
|
|
200
|
-
return null;
|
|
201
|
-
}
|
|
202
|
-
return shouldIgnore ? null : this.activePage;
|
|
206
|
+
return this.activePage;
|
|
203
207
|
}
|
|
204
208
|
// Checking if URL is supported by the browser (for example, IE11 does not support it)
|
|
205
209
|
if (typeof URL === 'function') {
|
|
@@ -215,73 +219,60 @@
|
|
|
215
219
|
if (host !== refHost) {
|
|
216
220
|
return null;
|
|
217
221
|
}
|
|
218
|
-
|
|
219
|
-
if (shouldIgnore && ((_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.doNotAnonymise)) {
|
|
220
|
-
return null;
|
|
221
|
-
}
|
|
222
|
-
return shouldIgnore ? null : pathname;
|
|
222
|
+
return pathname;
|
|
223
223
|
}
|
|
224
|
-
catch (
|
|
224
|
+
catch (_a) {
|
|
225
225
|
return null;
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
228
|
return null;
|
|
229
229
|
};
|
|
230
230
|
Lib.prototype.trackPage = function (pg, unique) {
|
|
231
|
-
var _a, _b;
|
|
232
231
|
if (unique === void 0) { unique = false; }
|
|
233
232
|
if (!this.pageData)
|
|
234
233
|
return;
|
|
235
234
|
this.pageData.path = pg;
|
|
236
|
-
var shouldIgnore = this.checkIgnore(pg);
|
|
237
|
-
if (shouldIgnore && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.doNotAnonymise))
|
|
238
|
-
return;
|
|
239
235
|
var perf = this.getPerformanceStats();
|
|
240
|
-
var prev;
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
236
|
+
var prev = this.getPreviousPage();
|
|
237
|
+
this.activePage = pg;
|
|
238
|
+
this.submitPageView(pg, prev, unique, perf, true);
|
|
239
|
+
};
|
|
240
|
+
Lib.prototype.submitPageView = function (pg, prev, unique, perf, evokeCallback) {
|
|
241
|
+
var _a;
|
|
242
|
+
var privateData = {
|
|
245
243
|
pid: this.projectID,
|
|
244
|
+
perf: perf,
|
|
245
|
+
unique: unique,
|
|
246
|
+
};
|
|
247
|
+
var pvPayload = {
|
|
246
248
|
lc: getLocale(),
|
|
247
249
|
tz: getTimezone(),
|
|
248
250
|
ref: getReferrer(),
|
|
249
251
|
so: getUTMSource(),
|
|
250
252
|
me: getUTMMedium(),
|
|
251
253
|
ca: getUTMCampaign(),
|
|
252
|
-
|
|
253
|
-
pg: shouldIgnore ? null : pg,
|
|
254
|
-
perf: perf,
|
|
254
|
+
pg: pg,
|
|
255
255
|
prev: prev,
|
|
256
256
|
};
|
|
257
|
-
this.
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
257
|
+
if (evokeCallback && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.callback)) {
|
|
258
|
+
var callbackResult = this.pageViewsOptions.callback(pvPayload);
|
|
259
|
+
if (callbackResult === false) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (callbackResult && typeof callbackResult === 'object') {
|
|
263
|
+
Object.assign(pvPayload, callbackResult);
|
|
264
|
+
}
|
|
264
265
|
}
|
|
266
|
+
Object.assign(pvPayload, privateData);
|
|
267
|
+
this.sendRequest('', pvPayload);
|
|
265
268
|
};
|
|
266
269
|
Lib.prototype.canTrack = function () {
|
|
267
270
|
var _a, _b, _c, _d;
|
|
268
|
-
if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.disabled)
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
this.debug('Tracking disabled: script does not run in browser environment.');
|
|
274
|
-
return false;
|
|
275
|
-
}
|
|
276
|
-
if (((_b = this.options) === null || _b === void 0 ? void 0 : _b.respectDNT) && ((_c = window.navigator) === null || _c === void 0 ? void 0 : _c.doNotTrack) === '1') {
|
|
277
|
-
this.debug('Tracking disabled: respecting user\'s \'Do Not Track\' preference.');
|
|
278
|
-
return false;
|
|
279
|
-
}
|
|
280
|
-
if (!((_d = this.options) === null || _d === void 0 ? void 0 : _d.debug) && isLocalhost()) {
|
|
281
|
-
return false;
|
|
282
|
-
}
|
|
283
|
-
if (isAutomated()) {
|
|
284
|
-
this.debug('Tracking disabled: navigation is automated by WebDriver.');
|
|
271
|
+
if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.disabled) ||
|
|
272
|
+
!isInBrowser() ||
|
|
273
|
+
(((_b = this.options) === null || _b === void 0 ? void 0 : _b.respectDNT) && ((_c = window.navigator) === null || _c === void 0 ? void 0 : _c.doNotTrack) === '1') ||
|
|
274
|
+
(!((_d = this.options) === null || _d === void 0 ? void 0 : _d.devMode) && isLocalhost()) ||
|
|
275
|
+
isAutomated()) {
|
|
285
276
|
return false;
|
|
286
277
|
}
|
|
287
278
|
return true;
|
|
@@ -349,9 +340,24 @@
|
|
|
349
340
|
}
|
|
350
341
|
});
|
|
351
342
|
}
|
|
343
|
+
/**
|
|
344
|
+
* This function is used to manually track a page view event.
|
|
345
|
+
* It's useful if your application uses esoteric routing which is not supported by Swetrix by default.
|
|
346
|
+
*
|
|
347
|
+
* @param path Path of the page to track (this will be sent to the Swetrix API and displayed in the dashboard).
|
|
348
|
+
* @param prev Path of the previous page.
|
|
349
|
+
* @param unique If set to `true`, only 1 event with the same ID will be saved per user session.
|
|
350
|
+
* @returns void
|
|
351
|
+
*/
|
|
352
|
+
function trackPageview(path, prev, unique) {
|
|
353
|
+
if (!exports.LIB_INSTANCE)
|
|
354
|
+
return;
|
|
355
|
+
exports.LIB_INSTANCE.submitPageView(path, prev || null, Boolean(unique), {});
|
|
356
|
+
}
|
|
352
357
|
|
|
353
358
|
exports.init = init;
|
|
354
359
|
exports.track = track;
|
|
360
|
+
exports.trackPageview = trackPageview;
|
|
355
361
|
exports.trackViews = trackViews;
|
|
356
362
|
|
|
357
363
|
Object.defineProperty(exports, '__esModule', { value: true });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "swetrix",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "The JavaScript analytics client for Swetrix Analytics",
|
|
5
5
|
"main": "dist/swetrix.cjs.js",
|
|
6
6
|
"module": "dist/swetrix.es5.js",
|
|
@@ -32,13 +32,13 @@
|
|
|
32
32
|
"bugs": {
|
|
33
33
|
"url": "https://github.com/Swetrix/swetrix-js/issues"
|
|
34
34
|
},
|
|
35
|
-
"homepage": "https://swetrix.com
|
|
35
|
+
"homepage": "https://docs.swetrix.com",
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@types/node": "^20.8
|
|
37
|
+
"@types/node": "^20.11.8",
|
|
38
38
|
"tslib": "^2.6.2"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@rollup/plugin-commonjs": "^25.0.
|
|
41
|
+
"@rollup/plugin-commonjs": "^25.0.7",
|
|
42
42
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
43
43
|
"rimraf": "^4.4.1",
|
|
44
44
|
"rollup": "^2.79.1",
|
|
@@ -46,6 +46,6 @@
|
|
|
46
46
|
"rollup-plugin-sourcemaps": "^0.6.3",
|
|
47
47
|
"rollup-plugin-typescript2": "^0.36.0",
|
|
48
48
|
"rollup-plugin-uglify": "^6.0.4",
|
|
49
|
-
"typescript": "^5.
|
|
49
|
+
"typescript": "^5.3.3"
|
|
50
50
|
}
|
|
51
51
|
}
|
package/src/Lib.ts
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
|
-
isInBrowser,
|
|
3
|
-
|
|
2
|
+
isInBrowser,
|
|
3
|
+
isLocalhost,
|
|
4
|
+
isAutomated,
|
|
5
|
+
getLocale,
|
|
6
|
+
getTimezone,
|
|
7
|
+
getReferrer,
|
|
8
|
+
getUTMCampaign,
|
|
9
|
+
getUTMMedium,
|
|
10
|
+
getUTMSource,
|
|
11
|
+
getPath,
|
|
4
12
|
} from './utils'
|
|
5
13
|
|
|
6
14
|
export interface LibOptions {
|
|
7
15
|
/**
|
|
8
|
-
* When set to `true`,
|
|
16
|
+
* When set to `true`, localhost events will be sent to server.
|
|
9
17
|
*/
|
|
10
|
-
|
|
18
|
+
devMode?: boolean
|
|
11
19
|
|
|
12
20
|
/**
|
|
13
21
|
* When set to `true`, the tracking library won't send any data to server.
|
|
@@ -37,6 +45,29 @@ export interface TrackEventOptions {
|
|
|
37
45
|
}
|
|
38
46
|
}
|
|
39
47
|
|
|
48
|
+
// Partial user-editable pageview payload
|
|
49
|
+
export interface IPageViewPayload {
|
|
50
|
+
lc: string | undefined
|
|
51
|
+
tz: string | undefined
|
|
52
|
+
ref: string | undefined
|
|
53
|
+
so: string | undefined
|
|
54
|
+
me: string | undefined
|
|
55
|
+
ca: string | undefined
|
|
56
|
+
pg: string
|
|
57
|
+
prev: string | null | undefined
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface IPerfPayload {
|
|
61
|
+
dns: number
|
|
62
|
+
tls: number
|
|
63
|
+
conn: number
|
|
64
|
+
response: number
|
|
65
|
+
render: number
|
|
66
|
+
dom_load: number
|
|
67
|
+
page_load: number
|
|
68
|
+
ttfb: number
|
|
69
|
+
}
|
|
70
|
+
|
|
40
71
|
/**
|
|
41
72
|
* The object returned by `trackPageViews()`, used to stop tracking pages.
|
|
42
73
|
*/
|
|
@@ -60,20 +91,28 @@ export interface PageViewsOptions {
|
|
|
60
91
|
*/
|
|
61
92
|
unique?: boolean
|
|
62
93
|
|
|
63
|
-
/** A list of Regular Expressions or string pathes to ignore. */
|
|
64
|
-
ignore?: Array<string | RegExp>
|
|
65
|
-
|
|
66
|
-
/** Do not send paths from ignore list to API. If set to `false`, the page view information will be sent to the Swetrix API, but the page will be displayed as a 'Redacted page' in the dashboard. */
|
|
67
|
-
doNotAnonymise?: boolean
|
|
68
|
-
|
|
69
|
-
/** Do not send Heartbeat requests to the server. */
|
|
70
|
-
noHeartbeat?: boolean
|
|
71
|
-
|
|
72
94
|
/** Send Heartbeat requests when the website tab is not active in the browser. */
|
|
73
95
|
heartbeatOnBackground?: boolean
|
|
74
96
|
|
|
75
|
-
/**
|
|
76
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Set to `true` to enable hash-based routing.
|
|
99
|
+
* For example if you have pages like /#/path or want to track pages like /path#hash
|
|
100
|
+
*/
|
|
101
|
+
hash?: boolean
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Set to `true` to enable search-based routing.
|
|
105
|
+
* For example if you have pages like /path?search
|
|
106
|
+
*/
|
|
107
|
+
search?: boolean
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Callback to edit / prevent sending pageviews.
|
|
111
|
+
*
|
|
112
|
+
* @param payload - The pageview payload.
|
|
113
|
+
* @returns The edited payload or `false` to prevent sending the pageview. If `true` is returned, the payload will be sent as-is.
|
|
114
|
+
*/
|
|
115
|
+
callback?: (payload: IPageViewPayload) => IPageViewPayload | boolean
|
|
77
116
|
}
|
|
78
117
|
|
|
79
118
|
export const defaultPageActions = {
|
|
@@ -99,6 +138,7 @@ export class Lib {
|
|
|
99
138
|
}
|
|
100
139
|
|
|
101
140
|
const data = {
|
|
141
|
+
...event,
|
|
102
142
|
pid: this.projectID,
|
|
103
143
|
pg: this.activePage,
|
|
104
144
|
lc: getLocale(),
|
|
@@ -107,7 +147,6 @@ export class Lib {
|
|
|
107
147
|
so: getUTMSource(),
|
|
108
148
|
me: getUTMMedium(),
|
|
109
149
|
ca: getUTMCampaign(),
|
|
110
|
-
...event,
|
|
111
150
|
}
|
|
112
151
|
this.sendRequest('custom', data)
|
|
113
152
|
}
|
|
@@ -122,17 +161,19 @@ export class Lib {
|
|
|
122
161
|
}
|
|
123
162
|
|
|
124
163
|
this.pageViewsOptions = options
|
|
125
|
-
let
|
|
164
|
+
let interval: NodeJS.Timeout
|
|
165
|
+
|
|
126
166
|
if (!options?.unique) {
|
|
127
167
|
interval = setInterval(this.trackPathChange, 2000)
|
|
128
168
|
}
|
|
129
169
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
hbInterval = setInterval(this.heartbeat, 28000)
|
|
133
|
-
}
|
|
170
|
+
setTimeout(this.heartbeat, 3000)
|
|
171
|
+
const hbInterval = setInterval(this.heartbeat, 28000)
|
|
134
172
|
|
|
135
|
-
const path = getPath(
|
|
173
|
+
const path = getPath({
|
|
174
|
+
hash: options?.hash,
|
|
175
|
+
search: options?.search,
|
|
176
|
+
})
|
|
136
177
|
|
|
137
178
|
this.pageData = {
|
|
138
179
|
path,
|
|
@@ -148,12 +189,12 @@ export class Lib {
|
|
|
148
189
|
return this.pageData.actions
|
|
149
190
|
}
|
|
150
191
|
|
|
151
|
-
getPerformanceStats():
|
|
192
|
+
getPerformanceStats(): IPerfPayload | {} {
|
|
152
193
|
if (!this.canTrack() || this.perfStatsCollected || !window.performance?.getEntriesByType) {
|
|
153
194
|
return {}
|
|
154
195
|
}
|
|
155
196
|
|
|
156
|
-
const perf = window.performance.getEntriesByType('navigation')[0]
|
|
197
|
+
const perf = window.performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming
|
|
157
198
|
|
|
158
199
|
if (!perf) {
|
|
159
200
|
return {}
|
|
@@ -163,25 +204,19 @@ export class Lib {
|
|
|
163
204
|
|
|
164
205
|
return {
|
|
165
206
|
// Network
|
|
166
|
-
// @ts-ignore
|
|
167
207
|
dns: perf.domainLookupEnd - perf.domainLookupStart, // DNS Resolution
|
|
168
|
-
// @ts-ignore
|
|
169
208
|
tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0, // TLS Setup; checking if secureConnectionStart is not 0 (it's 0 for non-https websites)
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
209
|
+
conn: perf.secureConnectionStart
|
|
210
|
+
? perf.secureConnectionStart - perf.connectStart
|
|
211
|
+
: perf.connectEnd - perf.connectStart, // Connection time
|
|
173
212
|
response: perf.responseEnd - perf.responseStart, // Response Time (Download)
|
|
174
213
|
|
|
175
214
|
// Frontend
|
|
176
|
-
// @ts-ignore
|
|
177
215
|
render: perf.domComplete - perf.domContentLoadedEventEnd, // Browser rendering the HTML time
|
|
178
|
-
// @ts-ignore
|
|
179
216
|
dom_load: perf.domContentLoadedEventEnd - perf.responseEnd, // DOM loading timing
|
|
180
|
-
// @ts-ignore
|
|
181
217
|
page_load: perf.loadEventStart, // Page load time
|
|
182
218
|
|
|
183
219
|
// Backend
|
|
184
|
-
// @ts-ignore
|
|
185
220
|
ttfb: perf.responseStart - perf.requestStart,
|
|
186
221
|
}
|
|
187
222
|
}
|
|
@@ -198,23 +233,13 @@ export class Lib {
|
|
|
198
233
|
this.sendRequest('hb', data)
|
|
199
234
|
}
|
|
200
235
|
|
|
201
|
-
private checkIgnore(path: string): boolean {
|
|
202
|
-
const ignore = this.pageViewsOptions?.ignore
|
|
203
|
-
|
|
204
|
-
if (Array.isArray(ignore)) {
|
|
205
|
-
for (let i = 0; i < ignore.length; ++i) {
|
|
206
|
-
if (ignore[i] === path) return true
|
|
207
|
-
// @ts-ignore
|
|
208
|
-
if (ignore[i] instanceof RegExp && ignore[i].test(path)) return true
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
return false
|
|
212
|
-
}
|
|
213
|
-
|
|
214
236
|
// Tracking path changes. If path changes -> calling this.trackPage method
|
|
215
237
|
private trackPathChange(): void {
|
|
216
238
|
if (!this.pageData) return
|
|
217
|
-
const newPath = getPath(
|
|
239
|
+
const newPath = getPath({
|
|
240
|
+
hash: this.pageViewsOptions?.hash,
|
|
241
|
+
search: this.pageViewsOptions?.search,
|
|
242
|
+
})
|
|
218
243
|
const { path } = this.pageData
|
|
219
244
|
|
|
220
245
|
if (path !== newPath) {
|
|
@@ -226,13 +251,7 @@ export class Lib {
|
|
|
226
251
|
// Assuming that this function is called in trackPage and this.activePage is not overwritten by new value yet
|
|
227
252
|
// That method of getting previous page works for SPA websites
|
|
228
253
|
if (this.activePage) {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (shouldIgnore && this.pageViewsOptions?.doNotAnonymise) {
|
|
232
|
-
return null
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
return shouldIgnore ? null : this.activePage
|
|
254
|
+
return this.activePage
|
|
236
255
|
}
|
|
237
256
|
|
|
238
257
|
// Checking if URL is supported by the browser (for example, IE11 does not support it)
|
|
@@ -254,13 +273,7 @@ export class Lib {
|
|
|
254
273
|
return null
|
|
255
274
|
}
|
|
256
275
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
if (shouldIgnore && this.pageViewsOptions?.doNotAnonymise) {
|
|
260
|
-
return null
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
return shouldIgnore ? null : pathname
|
|
276
|
+
return pathname
|
|
264
277
|
} catch {
|
|
265
278
|
return null
|
|
266
279
|
}
|
|
@@ -273,64 +286,62 @@ export class Lib {
|
|
|
273
286
|
if (!this.pageData) return
|
|
274
287
|
this.pageData.path = pg
|
|
275
288
|
|
|
276
|
-
const shouldIgnore = this.checkIgnore(pg)
|
|
277
|
-
|
|
278
|
-
if (shouldIgnore && this.pageViewsOptions?.doNotAnonymise) return
|
|
279
|
-
|
|
280
289
|
const perf = this.getPerformanceStats()
|
|
281
290
|
|
|
282
|
-
|
|
291
|
+
const prev = this.getPreviousPage()
|
|
283
292
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
293
|
+
this.activePage = pg
|
|
294
|
+
this.submitPageView(pg, prev, unique, perf, true)
|
|
295
|
+
}
|
|
287
296
|
|
|
288
|
-
|
|
297
|
+
submitPageView(
|
|
298
|
+
pg: string,
|
|
299
|
+
prev: string | null | undefined,
|
|
300
|
+
unique: boolean,
|
|
301
|
+
perf: IPerfPayload | {},
|
|
302
|
+
evokeCallback?: boolean,
|
|
303
|
+
): void {
|
|
304
|
+
const privateData = {
|
|
289
305
|
pid: this.projectID,
|
|
306
|
+
perf,
|
|
307
|
+
unique,
|
|
308
|
+
}
|
|
309
|
+
const pvPayload = {
|
|
290
310
|
lc: getLocale(),
|
|
291
311
|
tz: getTimezone(),
|
|
292
312
|
ref: getReferrer(),
|
|
293
313
|
so: getUTMSource(),
|
|
294
314
|
me: getUTMMedium(),
|
|
295
315
|
ca: getUTMCampaign(),
|
|
296
|
-
|
|
297
|
-
pg: shouldIgnore ? null : pg,
|
|
298
|
-
perf,
|
|
316
|
+
pg,
|
|
299
317
|
prev,
|
|
300
318
|
}
|
|
301
319
|
|
|
302
|
-
this.
|
|
303
|
-
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
private debug(message: string): void {
|
|
307
|
-
if (this.options?.debug) {
|
|
308
|
-
console.log('[Swetrix]', message)
|
|
309
|
-
}
|
|
310
|
-
}
|
|
320
|
+
if (evokeCallback && this.pageViewsOptions?.callback) {
|
|
321
|
+
const callbackResult = this.pageViewsOptions.callback(pvPayload)
|
|
311
322
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
return false
|
|
316
|
-
}
|
|
323
|
+
if (callbackResult === false) {
|
|
324
|
+
return
|
|
325
|
+
}
|
|
317
326
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
327
|
+
if (callbackResult && typeof callbackResult === 'object') {
|
|
328
|
+
Object.assign(pvPayload, callbackResult)
|
|
329
|
+
}
|
|
321
330
|
}
|
|
322
331
|
|
|
323
|
-
|
|
324
|
-
this.debug('Tracking disabled: respecting user\'s \'Do Not Track\' preference.')
|
|
325
|
-
return false
|
|
326
|
-
}
|
|
332
|
+
Object.assign(pvPayload, privateData)
|
|
327
333
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
}
|
|
334
|
+
this.sendRequest('', pvPayload)
|
|
335
|
+
}
|
|
331
336
|
|
|
332
|
-
|
|
333
|
-
|
|
337
|
+
private canTrack(): boolean {
|
|
338
|
+
if (
|
|
339
|
+
this.options?.disabled ||
|
|
340
|
+
!isInBrowser() ||
|
|
341
|
+
(this.options?.respectDNT && window.navigator?.doNotTrack === '1') ||
|
|
342
|
+
(!this.options?.devMode && isLocalhost()) ||
|
|
343
|
+
isAutomated()
|
|
344
|
+
) {
|
|
334
345
|
return false
|
|
335
346
|
}
|
|
336
347
|
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Lib, LibOptions, TrackEventOptions, PageViewsOptions, PageActions, defaultPageActions,
|
|
3
|
-
} from './Lib'
|
|
1
|
+
import { Lib, LibOptions, TrackEventOptions, PageViewsOptions, PageActions, defaultPageActions } from './Lib'
|
|
4
2
|
|
|
5
3
|
export let LIB_INSTANCE: Lib | null = null
|
|
6
4
|
|
|
@@ -58,3 +56,18 @@ export function trackViews(options?: PageViewsOptions): Promise<PageActions> {
|
|
|
58
56
|
}
|
|
59
57
|
})
|
|
60
58
|
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* This function is used to manually track a page view event.
|
|
62
|
+
* It's useful if your application uses esoteric routing which is not supported by Swetrix by default.
|
|
63
|
+
*
|
|
64
|
+
* @param path Path of the page to track (this will be sent to the Swetrix API and displayed in the dashboard).
|
|
65
|
+
* @param prev Path of the previous page.
|
|
66
|
+
* @param unique If set to `true`, only 1 event with the same ID will be saved per user session.
|
|
67
|
+
* @returns void
|
|
68
|
+
*/
|
|
69
|
+
export function trackPageview(path: string, prev?: string, unique?: boolean): void {
|
|
70
|
+
if (!LIB_INSTANCE) return
|
|
71
|
+
|
|
72
|
+
LIB_INSTANCE.submitPageView(path, prev || null, Boolean(unique), {})
|
|
73
|
+
}
|