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.
@@ -66,9 +66,33 @@ var getReferrer = function () {
66
66
  var getUTMSource = function () { return findInSearch(utmSourceRegex); };
67
67
  var getUTMMedium = function () { return findInSearch(utmMediumRegex); };
68
68
  var getUTMCampaign = function () { return findInSearch(utmCampaignRegex); };
69
- var getPath = function () {
70
- // TODO: Maybe we should also include such data as location.hash or location.search
71
- return location.pathname || '';
69
+ /**
70
+ * Function used to track the current page (path) of the application.
71
+ * Will work in cases where the path looks like:
72
+ * - /path
73
+ * - /#/path
74
+ * - /path?search
75
+ * - /path?search#hash
76
+ * - /path#hash?search
77
+ *
78
+ * @param options - Options for the function.
79
+ * @param options.hash - Whether to trigger on hash change.
80
+ * @param options.search - Whether to trigger on search change.
81
+ * @returns The path of the current page.
82
+ */
83
+ var getPath = function (options) {
84
+ var result = location.pathname || '';
85
+ if (options.hash) {
86
+ var hashIndex = location.hash.indexOf('?');
87
+ var hashString = hashIndex > -1 ? location.hash.substring(0, hashIndex) : location.hash;
88
+ result += hashString;
89
+ }
90
+ if (options.search) {
91
+ var hashIndex = location.hash.indexOf('?');
92
+ var searchString = location.search || (hashIndex > -1 ? location.hash.substring(hashIndex) : '');
93
+ result += searchString;
94
+ }
95
+ return result;
72
96
  };
73
97
 
74
98
  var defaultPageActions = {
@@ -90,7 +114,7 @@ var Lib = /** @class */ (function () {
90
114
  if (!this.canTrack()) {
91
115
  return;
92
116
  }
93
- var data = __assign({ pid: this.projectID, pg: this.activePage, lc: getLocale(), tz: getTimezone(), ref: getReferrer(), so: getUTMSource(), me: getUTMMedium(), ca: getUTMCampaign() }, event);
117
+ var data = __assign(__assign({}, event), { pid: this.projectID, pg: this.activePage, lc: getLocale(), tz: getTimezone(), ref: getReferrer(), so: getUTMSource(), me: getUTMMedium(), ca: getUTMCampaign() });
94
118
  this.sendRequest('custom', data);
95
119
  };
96
120
  Lib.prototype.trackPageViews = function (options) {
@@ -101,15 +125,16 @@ var Lib = /** @class */ (function () {
101
125
  return this.pageData.actions;
102
126
  }
103
127
  this.pageViewsOptions = options;
104
- var hbInterval, interval;
128
+ var interval;
105
129
  if (!(options === null || options === void 0 ? void 0 : options.unique)) {
106
130
  interval = setInterval(this.trackPathChange, 2000);
107
131
  }
108
- if (!(options === null || options === void 0 ? void 0 : options.noHeartbeat)) {
109
- setTimeout(this.heartbeat, 3000);
110
- hbInterval = setInterval(this.heartbeat, 28000);
111
- }
112
- var path = getPath();
132
+ setTimeout(this.heartbeat, 3000);
133
+ var hbInterval = setInterval(this.heartbeat, 28000);
134
+ var path = getPath({
135
+ hash: options === null || options === void 0 ? void 0 : options.hash,
136
+ search: options === null || options === void 0 ? void 0 : options.search,
137
+ });
113
138
  this.pageData = {
114
139
  path: path,
115
140
  actions: {
@@ -134,23 +159,17 @@ var Lib = /** @class */ (function () {
134
159
  this.perfStatsCollected = true;
135
160
  return {
136
161
  // Network
137
- // @ts-ignore
138
- dns: perf.domainLookupEnd - perf.domainLookupStart,
139
- // @ts-ignore
140
- tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0,
141
- // @ts-ignore
142
- conn: perf.secureConnectionStart ? perf.secureConnectionStart - perf.connectStart : perf.connectEnd - perf.connectStart,
143
- // @ts-ignore
144
- response: perf.responseEnd - perf.responseStart,
162
+ dns: perf.domainLookupEnd - perf.domainLookupStart, // DNS Resolution
163
+ tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0, // TLS Setup; checking if secureConnectionStart is not 0 (it's 0 for non-https websites)
164
+ conn: perf.secureConnectionStart
165
+ ? perf.secureConnectionStart - perf.connectStart
166
+ : perf.connectEnd - perf.connectStart, // Connection time
167
+ response: perf.responseEnd - perf.responseStart, // Response Time (Download)
145
168
  // Frontend
146
- // @ts-ignore
147
- render: perf.domComplete - perf.domContentLoadedEventEnd,
148
- // @ts-ignore
149
- dom_load: perf.domContentLoadedEventEnd - perf.responseEnd,
150
- // @ts-ignore
151
- page_load: perf.loadEventStart,
169
+ render: perf.domComplete - perf.domContentLoadedEventEnd, // Browser rendering the HTML time
170
+ dom_load: perf.domContentLoadedEventEnd - perf.responseEnd, // DOM loading timing
171
+ page_load: perf.loadEventStart, // Page load time
152
172
  // Backend
153
- // @ts-ignore
154
173
  ttfb: perf.responseStart - perf.requestStart,
155
174
  };
156
175
  };
@@ -164,40 +183,25 @@ var Lib = /** @class */ (function () {
164
183
  };
165
184
  this.sendRequest('hb', data);
166
185
  };
167
- Lib.prototype.checkIgnore = function (path) {
168
- var _a;
169
- var ignore = (_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.ignore;
170
- if (Array.isArray(ignore)) {
171
- for (var i = 0; i < ignore.length; ++i) {
172
- if (ignore[i] === path)
173
- return true;
174
- // @ts-ignore
175
- if (ignore[i] instanceof RegExp && ignore[i].test(path))
176
- return true;
177
- }
178
- }
179
- return false;
180
- };
181
186
  // Tracking path changes. If path changes -> calling this.trackPage method
182
187
  Lib.prototype.trackPathChange = function () {
188
+ var _a, _b;
183
189
  if (!this.pageData)
184
190
  return;
185
- var newPath = getPath();
191
+ var newPath = getPath({
192
+ hash: (_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.hash,
193
+ search: (_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.search,
194
+ });
186
195
  var path = this.pageData.path;
187
196
  if (path !== newPath) {
188
197
  this.trackPage(newPath, false);
189
198
  }
190
199
  };
191
200
  Lib.prototype.getPreviousPage = function () {
192
- var _a, _b;
193
201
  // Assuming that this function is called in trackPage and this.activePage is not overwritten by new value yet
194
202
  // That method of getting previous page works for SPA websites
195
203
  if (this.activePage) {
196
- var shouldIgnore = this.checkIgnore(this.activePage);
197
- if (shouldIgnore && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.doNotAnonymise)) {
198
- return null;
199
- }
200
- return shouldIgnore ? null : this.activePage;
204
+ return this.activePage;
201
205
  }
202
206
  // Checking if URL is supported by the browser (for example, IE11 does not support it)
203
207
  if (typeof URL === 'function') {
@@ -213,73 +217,60 @@ var Lib = /** @class */ (function () {
213
217
  if (host !== refHost) {
214
218
  return null;
215
219
  }
216
- var shouldIgnore = this.checkIgnore(pathname);
217
- if (shouldIgnore && ((_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.doNotAnonymise)) {
218
- return null;
219
- }
220
- return shouldIgnore ? null : pathname;
220
+ return pathname;
221
221
  }
222
- catch (_c) {
222
+ catch (_a) {
223
223
  return null;
224
224
  }
225
225
  }
226
226
  return null;
227
227
  };
228
228
  Lib.prototype.trackPage = function (pg, unique) {
229
- var _a, _b;
230
229
  if (unique === void 0) { unique = false; }
231
230
  if (!this.pageData)
232
231
  return;
233
232
  this.pageData.path = pg;
234
- var shouldIgnore = this.checkIgnore(pg);
235
- if (shouldIgnore && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.doNotAnonymise))
236
- return;
237
233
  var perf = this.getPerformanceStats();
238
- var prev;
239
- if (!((_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.noUserFlow)) {
240
- prev = this.getPreviousPage();
241
- }
242
- var data = {
234
+ var prev = this.getPreviousPage();
235
+ this.activePage = pg;
236
+ this.submitPageView(pg, prev, unique, perf, true);
237
+ };
238
+ Lib.prototype.submitPageView = function (pg, prev, unique, perf, evokeCallback) {
239
+ var _a;
240
+ var privateData = {
243
241
  pid: this.projectID,
242
+ perf: perf,
243
+ unique: unique,
244
+ };
245
+ var pvPayload = {
244
246
  lc: getLocale(),
245
247
  tz: getTimezone(),
246
248
  ref: getReferrer(),
247
249
  so: getUTMSource(),
248
250
  me: getUTMMedium(),
249
251
  ca: getUTMCampaign(),
250
- unique: unique,
251
- pg: shouldIgnore ? null : pg,
252
- perf: perf,
252
+ pg: pg,
253
253
  prev: prev,
254
254
  };
255
- this.activePage = pg;
256
- this.sendRequest('', data);
257
- };
258
- Lib.prototype.debug = function (message) {
259
- var _a;
260
- if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.debug) {
261
- console.log('[Swetrix]', message);
255
+ if (evokeCallback && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.callback)) {
256
+ var callbackResult = this.pageViewsOptions.callback(pvPayload);
257
+ if (callbackResult === false) {
258
+ return;
259
+ }
260
+ if (callbackResult && typeof callbackResult === 'object') {
261
+ Object.assign(pvPayload, callbackResult);
262
+ }
262
263
  }
264
+ Object.assign(pvPayload, privateData);
265
+ this.sendRequest('', pvPayload);
263
266
  };
264
267
  Lib.prototype.canTrack = function () {
265
268
  var _a, _b, _c, _d;
266
- if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.disabled) {
267
- this.debug('Tracking disabled: the \'disabled\' setting is set to true.');
268
- return false;
269
- }
270
- if (!isInBrowser()) {
271
- this.debug('Tracking disabled: script does not run in browser environment.');
272
- return false;
273
- }
274
- if (((_b = this.options) === null || _b === void 0 ? void 0 : _b.respectDNT) && ((_c = window.navigator) === null || _c === void 0 ? void 0 : _c.doNotTrack) === '1') {
275
- this.debug('Tracking disabled: respecting user\'s \'Do Not Track\' preference.');
276
- return false;
277
- }
278
- if (!((_d = this.options) === null || _d === void 0 ? void 0 : _d.debug) && isLocalhost()) {
279
- return false;
280
- }
281
- if (isAutomated()) {
282
- this.debug('Tracking disabled: navigation is automated by WebDriver.');
269
+ if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.disabled) ||
270
+ !isInBrowser() ||
271
+ (((_b = this.options) === null || _b === void 0 ? void 0 : _b.respectDNT) && ((_c = window.navigator) === null || _c === void 0 ? void 0 : _c.doNotTrack) === '1') ||
272
+ (!((_d = this.options) === null || _d === void 0 ? void 0 : _d.devMode) && isLocalhost()) ||
273
+ isAutomated()) {
283
274
  return false;
284
275
  }
285
276
  return true;
@@ -347,7 +338,22 @@ function trackViews(options) {
347
338
  }
348
339
  });
349
340
  }
341
+ /**
342
+ * This function is used to manually track a page view event.
343
+ * It's useful if your application uses esoteric routing which is not supported by Swetrix by default.
344
+ *
345
+ * @param path Path of the page to track (this will be sent to the Swetrix API and displayed in the dashboard).
346
+ * @param prev Path of the previous page.
347
+ * @param unique If set to `true`, only 1 event with the same ID will be saved per user session.
348
+ * @returns void
349
+ */
350
+ function trackPageview(path, prev, unique) {
351
+ if (!exports.LIB_INSTANCE)
352
+ return;
353
+ exports.LIB_INSTANCE.submitPageView(path, prev || null, Boolean(unique), {});
354
+ }
350
355
 
351
356
  exports.init = init;
352
357
  exports.track = track;
358
+ exports.trackPageview = trackPageview;
353
359
  exports.trackViews = trackViews;
@@ -62,9 +62,33 @@ var getReferrer = function () {
62
62
  var getUTMSource = function () { return findInSearch(utmSourceRegex); };
63
63
  var getUTMMedium = function () { return findInSearch(utmMediumRegex); };
64
64
  var getUTMCampaign = function () { return findInSearch(utmCampaignRegex); };
65
- var getPath = function () {
66
- // TODO: Maybe we should also include such data as location.hash or location.search
67
- return location.pathname || '';
65
+ /**
66
+ * Function used to track the current page (path) of the application.
67
+ * Will work in cases where the path looks like:
68
+ * - /path
69
+ * - /#/path
70
+ * - /path?search
71
+ * - /path?search#hash
72
+ * - /path#hash?search
73
+ *
74
+ * @param options - Options for the function.
75
+ * @param options.hash - Whether to trigger on hash change.
76
+ * @param options.search - Whether to trigger on search change.
77
+ * @returns The path of the current page.
78
+ */
79
+ var getPath = function (options) {
80
+ var result = location.pathname || '';
81
+ if (options.hash) {
82
+ var hashIndex = location.hash.indexOf('?');
83
+ var hashString = hashIndex > -1 ? location.hash.substring(0, hashIndex) : location.hash;
84
+ result += hashString;
85
+ }
86
+ if (options.search) {
87
+ var hashIndex = location.hash.indexOf('?');
88
+ var searchString = location.search || (hashIndex > -1 ? location.hash.substring(hashIndex) : '');
89
+ result += searchString;
90
+ }
91
+ return result;
68
92
  };
69
93
 
70
94
  var defaultPageActions = {
@@ -86,7 +110,7 @@ var Lib = /** @class */ (function () {
86
110
  if (!this.canTrack()) {
87
111
  return;
88
112
  }
89
- var data = __assign({ pid: this.projectID, pg: this.activePage, lc: getLocale(), tz: getTimezone(), ref: getReferrer(), so: getUTMSource(), me: getUTMMedium(), ca: getUTMCampaign() }, event);
113
+ var data = __assign(__assign({}, event), { pid: this.projectID, pg: this.activePage, lc: getLocale(), tz: getTimezone(), ref: getReferrer(), so: getUTMSource(), me: getUTMMedium(), ca: getUTMCampaign() });
90
114
  this.sendRequest('custom', data);
91
115
  };
92
116
  Lib.prototype.trackPageViews = function (options) {
@@ -97,15 +121,16 @@ var Lib = /** @class */ (function () {
97
121
  return this.pageData.actions;
98
122
  }
99
123
  this.pageViewsOptions = options;
100
- var hbInterval, interval;
124
+ var interval;
101
125
  if (!(options === null || options === void 0 ? void 0 : options.unique)) {
102
126
  interval = setInterval(this.trackPathChange, 2000);
103
127
  }
104
- if (!(options === null || options === void 0 ? void 0 : options.noHeartbeat)) {
105
- setTimeout(this.heartbeat, 3000);
106
- hbInterval = setInterval(this.heartbeat, 28000);
107
- }
108
- var path = getPath();
128
+ setTimeout(this.heartbeat, 3000);
129
+ var hbInterval = setInterval(this.heartbeat, 28000);
130
+ var path = getPath({
131
+ hash: options === null || options === void 0 ? void 0 : options.hash,
132
+ search: options === null || options === void 0 ? void 0 : options.search,
133
+ });
109
134
  this.pageData = {
110
135
  path: path,
111
136
  actions: {
@@ -130,23 +155,17 @@ var Lib = /** @class */ (function () {
130
155
  this.perfStatsCollected = true;
131
156
  return {
132
157
  // Network
133
- // @ts-ignore
134
- dns: perf.domainLookupEnd - perf.domainLookupStart,
135
- // @ts-ignore
136
- tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0,
137
- // @ts-ignore
138
- conn: perf.secureConnectionStart ? perf.secureConnectionStart - perf.connectStart : perf.connectEnd - perf.connectStart,
139
- // @ts-ignore
140
- response: perf.responseEnd - perf.responseStart,
158
+ dns: perf.domainLookupEnd - perf.domainLookupStart, // DNS Resolution
159
+ tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0, // TLS Setup; checking if secureConnectionStart is not 0 (it's 0 for non-https websites)
160
+ conn: perf.secureConnectionStart
161
+ ? perf.secureConnectionStart - perf.connectStart
162
+ : perf.connectEnd - perf.connectStart, // Connection time
163
+ response: perf.responseEnd - perf.responseStart, // Response Time (Download)
141
164
  // Frontend
142
- // @ts-ignore
143
- render: perf.domComplete - perf.domContentLoadedEventEnd,
144
- // @ts-ignore
145
- dom_load: perf.domContentLoadedEventEnd - perf.responseEnd,
146
- // @ts-ignore
147
- page_load: perf.loadEventStart,
165
+ render: perf.domComplete - perf.domContentLoadedEventEnd, // Browser rendering the HTML time
166
+ dom_load: perf.domContentLoadedEventEnd - perf.responseEnd, // DOM loading timing
167
+ page_load: perf.loadEventStart, // Page load time
148
168
  // Backend
149
- // @ts-ignore
150
169
  ttfb: perf.responseStart - perf.requestStart,
151
170
  };
152
171
  };
@@ -160,40 +179,25 @@ var Lib = /** @class */ (function () {
160
179
  };
161
180
  this.sendRequest('hb', data);
162
181
  };
163
- Lib.prototype.checkIgnore = function (path) {
164
- var _a;
165
- var ignore = (_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.ignore;
166
- if (Array.isArray(ignore)) {
167
- for (var i = 0; i < ignore.length; ++i) {
168
- if (ignore[i] === path)
169
- return true;
170
- // @ts-ignore
171
- if (ignore[i] instanceof RegExp && ignore[i].test(path))
172
- return true;
173
- }
174
- }
175
- return false;
176
- };
177
182
  // Tracking path changes. If path changes -> calling this.trackPage method
178
183
  Lib.prototype.trackPathChange = function () {
184
+ var _a, _b;
179
185
  if (!this.pageData)
180
186
  return;
181
- var newPath = getPath();
187
+ var newPath = getPath({
188
+ hash: (_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.hash,
189
+ search: (_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.search,
190
+ });
182
191
  var path = this.pageData.path;
183
192
  if (path !== newPath) {
184
193
  this.trackPage(newPath, false);
185
194
  }
186
195
  };
187
196
  Lib.prototype.getPreviousPage = function () {
188
- var _a, _b;
189
197
  // Assuming that this function is called in trackPage and this.activePage is not overwritten by new value yet
190
198
  // That method of getting previous page works for SPA websites
191
199
  if (this.activePage) {
192
- var shouldIgnore = this.checkIgnore(this.activePage);
193
- if (shouldIgnore && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.doNotAnonymise)) {
194
- return null;
195
- }
196
- return shouldIgnore ? null : this.activePage;
200
+ return this.activePage;
197
201
  }
198
202
  // Checking if URL is supported by the browser (for example, IE11 does not support it)
199
203
  if (typeof URL === 'function') {
@@ -209,73 +213,60 @@ var Lib = /** @class */ (function () {
209
213
  if (host !== refHost) {
210
214
  return null;
211
215
  }
212
- var shouldIgnore = this.checkIgnore(pathname);
213
- if (shouldIgnore && ((_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.doNotAnonymise)) {
214
- return null;
215
- }
216
- return shouldIgnore ? null : pathname;
216
+ return pathname;
217
217
  }
218
- catch (_c) {
218
+ catch (_a) {
219
219
  return null;
220
220
  }
221
221
  }
222
222
  return null;
223
223
  };
224
224
  Lib.prototype.trackPage = function (pg, unique) {
225
- var _a, _b;
226
225
  if (unique === void 0) { unique = false; }
227
226
  if (!this.pageData)
228
227
  return;
229
228
  this.pageData.path = pg;
230
- var shouldIgnore = this.checkIgnore(pg);
231
- if (shouldIgnore && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.doNotAnonymise))
232
- return;
233
229
  var perf = this.getPerformanceStats();
234
- var prev;
235
- if (!((_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.noUserFlow)) {
236
- prev = this.getPreviousPage();
237
- }
238
- var data = {
230
+ var prev = this.getPreviousPage();
231
+ this.activePage = pg;
232
+ this.submitPageView(pg, prev, unique, perf, true);
233
+ };
234
+ Lib.prototype.submitPageView = function (pg, prev, unique, perf, evokeCallback) {
235
+ var _a;
236
+ var privateData = {
239
237
  pid: this.projectID,
238
+ perf: perf,
239
+ unique: unique,
240
+ };
241
+ var pvPayload = {
240
242
  lc: getLocale(),
241
243
  tz: getTimezone(),
242
244
  ref: getReferrer(),
243
245
  so: getUTMSource(),
244
246
  me: getUTMMedium(),
245
247
  ca: getUTMCampaign(),
246
- unique: unique,
247
- pg: shouldIgnore ? null : pg,
248
- perf: perf,
248
+ pg: pg,
249
249
  prev: prev,
250
250
  };
251
- this.activePage = pg;
252
- this.sendRequest('', data);
253
- };
254
- Lib.prototype.debug = function (message) {
255
- var _a;
256
- if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.debug) {
257
- console.log('[Swetrix]', message);
251
+ if (evokeCallback && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.callback)) {
252
+ var callbackResult = this.pageViewsOptions.callback(pvPayload);
253
+ if (callbackResult === false) {
254
+ return;
255
+ }
256
+ if (callbackResult && typeof callbackResult === 'object') {
257
+ Object.assign(pvPayload, callbackResult);
258
+ }
258
259
  }
260
+ Object.assign(pvPayload, privateData);
261
+ this.sendRequest('', pvPayload);
259
262
  };
260
263
  Lib.prototype.canTrack = function () {
261
264
  var _a, _b, _c, _d;
262
- if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.disabled) {
263
- this.debug('Tracking disabled: the \'disabled\' setting is set to true.');
264
- return false;
265
- }
266
- if (!isInBrowser()) {
267
- this.debug('Tracking disabled: script does not run in browser environment.');
268
- return false;
269
- }
270
- if (((_b = this.options) === null || _b === void 0 ? void 0 : _b.respectDNT) && ((_c = window.navigator) === null || _c === void 0 ? void 0 : _c.doNotTrack) === '1') {
271
- this.debug('Tracking disabled: respecting user\'s \'Do Not Track\' preference.');
272
- return false;
273
- }
274
- if (!((_d = this.options) === null || _d === void 0 ? void 0 : _d.debug) && isLocalhost()) {
275
- return false;
276
- }
277
- if (isAutomated()) {
278
- this.debug('Tracking disabled: navigation is automated by WebDriver.');
265
+ if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.disabled) ||
266
+ !isInBrowser() ||
267
+ (((_b = this.options) === null || _b === void 0 ? void 0 : _b.respectDNT) && ((_c = window.navigator) === null || _c === void 0 ? void 0 : _c.doNotTrack) === '1') ||
268
+ (!((_d = this.options) === null || _d === void 0 ? void 0 : _d.devMode) && isLocalhost()) ||
269
+ isAutomated()) {
279
270
  return false;
280
271
  }
281
272
  return true;
@@ -343,5 +334,19 @@ function trackViews(options) {
343
334
  }
344
335
  });
345
336
  }
337
+ /**
338
+ * This function is used to manually track a page view event.
339
+ * It's useful if your application uses esoteric routing which is not supported by Swetrix by default.
340
+ *
341
+ * @param path Path of the page to track (this will be sent to the Swetrix API and displayed in the dashboard).
342
+ * @param prev Path of the previous page.
343
+ * @param unique If set to `true`, only 1 event with the same ID will be saved per user session.
344
+ * @returns void
345
+ */
346
+ function trackPageview(path, prev, unique) {
347
+ if (!LIB_INSTANCE)
348
+ return;
349
+ LIB_INSTANCE.submitPageView(path, prev || null, Boolean(unique), {});
350
+ }
346
351
 
347
- export { LIB_INSTANCE, init, track, trackViews };
352
+ export { LIB_INSTANCE, init, track, trackPageview, trackViews };
package/dist/swetrix.js CHANGED
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).swetrix={})}(this,function(n){"use strict";function t(t){return(t=location.search.match(t))&&t[2]||void 0}function r(){return void 0!==navigator.languages?navigator.languages[0]:navigator.language}function s(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone}catch(t){}}function c(){return document.referrer||void 0}function u(){return t(o)}function l(){return t(d)}function p(){return t(a)}function i(){return location.pathname||""}var e=function(){return(e=Object.assign||function(t){for(var e,n=1,o=arguments.length;n<o;n++)for(var i in e=arguments[n])Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t}).apply(this,arguments)},o=/[?&](ref|source|utm_source)=([^?&]+)/,a=/[?&](utm_campaign)=([^?&]+)/,d=/[?&](utm_medium)=([^?&]+)/,h={stop:function(){}},g=(f.prototype.track=function(t){this.canTrack()&&(t=e({pid:this.projectID,pg:this.activePage,lc:r(),tz:s(),ref:c(),so:u(),me:l(),ca:p()},t),this.sendRequest("custom",t))},f.prototype.trackPageViews=function(t){var e,n,o;return this.canTrack()?(this.pageData||(null!=(this.pageViewsOptions=t)&&t.unique||(n=setInterval(this.trackPathChange,2e3)),null!=t&&t.noHeartbeat||(setTimeout(this.heartbeat,3e3),e=setInterval(this.heartbeat,28e3)),o=i(),this.pageData={path:o,actions:{stop:function(){clearInterval(n),clearInterval(e)}}},this.trackPage(o,null==t?void 0:t.unique)),this.pageData.actions):h},f.prototype.getPerformanceStats=function(){var t;return this.canTrack()&&!this.perfStatsCollected&&null!=(t=window.performance)&&t.getEntriesByType&&(t=window.performance.getEntriesByType("navigation")[0])?(this.perfStatsCollected=!0,{dns:t.domainLookupEnd-t.domainLookupStart,tls:t.secureConnectionStart?t.requestStart-t.secureConnectionStart:0,conn:t.secureConnectionStart?t.secureConnectionStart-t.connectStart:t.connectEnd-t.connectStart,response:t.responseEnd-t.responseStart,render:t.domComplete-t.domContentLoadedEventEnd,dom_load:t.domContentLoadedEventEnd-t.responseEnd,page_load:t.loadEventStart,ttfb:t.responseStart-t.requestStart}):{}},f.prototype.heartbeat=function(){var t;(null!=(t=this.pageViewsOptions)&&t.heartbeatOnBackground||"hidden"!==document.visibilityState)&&(t={pid:this.projectID},this.sendRequest("hb",t))},f.prototype.checkIgnore=function(t){var e,n=null==(e=this.pageViewsOptions)?void 0:e.ignore;if(Array.isArray(n))for(var o=0;o<n.length;++o){if(n[o]===t)return!0;if(n[o]instanceof RegExp&&n[o].test(t))return!0}return!1},f.prototype.trackPathChange=function(){var t;this.pageData&&(t=i(),this.pageData.path!==t)&&this.trackPage(t,!1)},f.prototype.getPreviousPage=function(){var t;if(this.activePage)return(o=this.checkIgnore(this.activePage))&&null!=(e=this.pageViewsOptions)&&e.doNotAnonymise||o?null:this.activePage;if("function"==typeof URL){var e=c();if(!e)return null;var n=location.host;try{var o,i=new URL(e),a=i.host,r=i.pathname;return n!==a?null:(o=this.checkIgnore(r))&&null!=(t=this.pageViewsOptions)&&t.doNotAnonymise||o?null:r}catch(t){}}return null},f.prototype.trackPage=function(t,e){var n,o,i,a;void 0===e&&(e=!1),this.pageData&&(this.pageData.path=t,(n=this.checkIgnore(t))&&null!=(o=this.pageViewsOptions)&&o.doNotAnonymise||(o=this.getPerformanceStats(),null!=(a=this.pageViewsOptions)&&a.noUserFlow||(i=this.getPreviousPage()),a={pid:this.projectID,lc:r(),tz:s(),ref:c(),so:u(),me:l(),ca:p(),unique:e,pg:n?null:t,perf:o,prev:i},this.activePage=t,this.sendRequest("",a)))},f.prototype.debug=function(t){var e;null!=(e=this.options)&&e.debug&&console.log("[Swetrix]",t)},f.prototype.canTrack=function(){var t;return null!=(t=this.options)&&t.disabled?(this.debug("Tracking disabled: the 'disabled' setting is set to true."),!1):"undefined"==typeof window?(this.debug("Tracking disabled: script does not run in browser environment."),!1):null!=(t=this.options)&&t.respectDNT&&"1"===(null==(t=window.navigator)?void 0:t.doNotTrack)?(this.debug("Tracking disabled: respecting user's 'Do Not Track' preference."),!1):!(!(null!=(t=this.options)&&t.debug||"localhost"!==(null===location||void 0===location?void 0:location.hostname)&&"127.0.0.1"!==(null===location||void 0===location?void 0:location.hostname)&&""!==(null===location||void 0===location?void 0:location.hostname))||null!==navigator&&void 0!==navigator&&navigator.webdriver&&(this.debug("Tracking disabled: navigation is automated by WebDriver."),1))},f.prototype.sendRequest=function(t,e){var n=(null==(n=this.options)?void 0:n.apiURL)||"https://api.swetrix.com/log",o=new XMLHttpRequest;o.open("POST","".concat(n,"/").concat(t),!0),o.setRequestHeader("Content-Type","application/json"),o.send(JSON.stringify(e))},f);function f(t,e){this.projectID=t,this.options=e,this.pageData=null,this.pageViewsOptions=null,this.perfStatsCollected=!1,this.activePage=null,this.trackPathChange=this.trackPathChange.bind(this),this.heartbeat=this.heartbeat.bind(this)}n.LIB_INSTANCE=null,n.init=function(t,e){return n.LIB_INSTANCE||(n.LIB_INSTANCE=new g(t,e)),n.LIB_INSTANCE},n.track=function(t){n.LIB_INSTANCE&&n.LIB_INSTANCE.track(t)},n.trackViews=function(e){return new Promise(function(t){n.LIB_INSTANCE?"undefined"==typeof document||"complete"===document.readyState?t(n.LIB_INSTANCE.trackPageViews(e)):window.addEventListener("load",function(){t(n.LIB_INSTANCE.trackPageViews(e))}):t(h)})},Object.defineProperty(n,"__esModule",{value:!0})});
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).swetrix={})}(this,function(a){"use strict";function t(t){return(t=location.search.match(t))&&t[2]||void 0}function i(){return void 0!==navigator.languages?navigator.languages[0]:navigator.language}function r(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone}catch(t){}}function s(){return document.referrer||void 0}function c(){return t(n)}function u(){return t(p)}function l(){return t(h)}function o(t){var e,n=location.pathname||"";return t.hash&&(n+=-1<(e=location.hash.indexOf("?"))?location.hash.substring(0,e):location.hash),t.search&&(e=location.hash.indexOf("?"),n+=location.search||(-1<e?location.hash.substring(e):"")),n}var e=function(){return(e=Object.assign||function(t){for(var e,n=1,a=arguments.length;n<a;n++)for(var o in e=arguments[n])Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o]);return t}).apply(this,arguments)},n=/[?&](ref|source|utm_source)=([^?&]+)/,h=/[?&](utm_campaign)=([^?&]+)/,p=/[?&](utm_medium)=([^?&]+)/,d={stop:function(){}},f=(g.prototype.track=function(t){this.canTrack()&&(t=e(e({},t),{pid:this.projectID,pg:this.activePage,lc:i(),tz:r(),ref:s(),so:c(),me:u(),ca:l()}),this.sendRequest("custom",t))},g.prototype.trackPageViews=function(t){var e,n,a;return this.canTrack()?(this.pageData||(null!=(this.pageViewsOptions=t)&&t.unique||(e=setInterval(this.trackPathChange,2e3)),setTimeout(this.heartbeat,3e3),n=setInterval(this.heartbeat,28e3),a=o({hash:null==t?void 0:t.hash,search:null==t?void 0:t.search}),this.pageData={path:a,actions:{stop:function(){clearInterval(e),clearInterval(n)}}},this.trackPage(a,null==t?void 0:t.unique)),this.pageData.actions):d},g.prototype.getPerformanceStats=function(){var t;return this.canTrack()&&!this.perfStatsCollected&&null!=(t=window.performance)&&t.getEntriesByType&&(t=window.performance.getEntriesByType("navigation")[0])?(this.perfStatsCollected=!0,{dns:t.domainLookupEnd-t.domainLookupStart,tls:t.secureConnectionStart?t.requestStart-t.secureConnectionStart:0,conn:t.secureConnectionStart?t.secureConnectionStart-t.connectStart:t.connectEnd-t.connectStart,response:t.responseEnd-t.responseStart,render:t.domComplete-t.domContentLoadedEventEnd,dom_load:t.domContentLoadedEventEnd-t.responseEnd,page_load:t.loadEventStart,ttfb:t.responseStart-t.requestStart}):{}},g.prototype.heartbeat=function(){var t;(null!=(t=this.pageViewsOptions)&&t.heartbeatOnBackground||"hidden"!==document.visibilityState)&&(t={pid:this.projectID},this.sendRequest("hb",t))},g.prototype.trackPathChange=function(){var t;this.pageData&&(t=o({hash:null==(t=this.pageViewsOptions)?void 0:t.hash,search:null==(t=this.pageViewsOptions)?void 0:t.search}),this.pageData.path!==t)&&this.trackPage(t,!1)},g.prototype.getPreviousPage=function(){if(this.activePage)return this.activePage;if("function"==typeof URL){var t=s();if(!t)return null;var e=location.host;try{var n=new URL(t),a=n.host,o=n.pathname;return e!==a?null:o}catch(t){}}return null},g.prototype.trackPage=function(t,e){var n,a;void 0===e&&(e=!1),this.pageData&&(this.pageData.path=t,n=this.getPerformanceStats(),a=this.getPreviousPage(),this.activePage=t,this.submitPageView(t,a,e,n,!0))},g.prototype.submitPageView=function(t,e,n,a,o){a={pid:this.projectID,perf:a,unique:n},n={lc:i(),tz:r(),ref:s(),so:c(),me:u(),ca:l(),pg:t,prev:e};if(o&&null!=(t=this.pageViewsOptions)&&t.callback){e=this.pageViewsOptions.callback(n);if(!1===e)return;e&&"object"==typeof e&&Object.assign(n,e)}Object.assign(n,a),this.sendRequest("",n)},g.prototype.canTrack=function(){var t;return!(null!=(t=this.options)&&t.disabled||"undefined"==typeof window||null!=(t=this.options)&&t.respectDNT&&"1"===(null==(t=window.navigator)?void 0:t.doNotTrack)||(null==(t=this.options)||!t.devMode)&&("localhost"===(null===location||void 0===location?void 0:location.hostname)||"127.0.0.1"===(null===location||void 0===location?void 0:location.hostname)||""===(null===location||void 0===location?void 0:location.hostname))||null!==navigator&&void 0!==navigator&&navigator.webdriver)},g.prototype.sendRequest=function(t,e){var n=(null==(n=this.options)?void 0:n.apiURL)||"https://api.swetrix.com/log",a=new XMLHttpRequest;a.open("POST","".concat(n,"/").concat(t),!0),a.setRequestHeader("Content-Type","application/json"),a.send(JSON.stringify(e))},g);function g(t,e){this.projectID=t,this.options=e,this.pageData=null,this.pageViewsOptions=null,this.perfStatsCollected=!1,this.activePage=null,this.trackPathChange=this.trackPathChange.bind(this),this.heartbeat=this.heartbeat.bind(this)}a.LIB_INSTANCE=null,a.init=function(t,e){return a.LIB_INSTANCE||(a.LIB_INSTANCE=new f(t,e)),a.LIB_INSTANCE},a.track=function(t){a.LIB_INSTANCE&&a.LIB_INSTANCE.track(t)},a.trackPageview=function(t,e,n){a.LIB_INSTANCE&&a.LIB_INSTANCE.submitPageView(t,e||null,Boolean(n),{})},a.trackViews=function(e){return new Promise(function(t){a.LIB_INSTANCE?"undefined"==typeof document||"complete"===document.readyState?t(a.LIB_INSTANCE.trackPageViews(e)):window.addEventListener("load",function(){t(a.LIB_INSTANCE.trackPageViews(e))}):t(d)})},Object.defineProperty(a,"__esModule",{value:!0})});