@codecademy/tracking 1.0.2 → 1.0.3-alpha.37044bcdd.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.
Files changed (34) hide show
  1. package/dist/README.md +100 -0
  2. package/dist/events/index.d.ts +3 -3
  3. package/dist/events/track.d.ts +12 -12
  4. package/dist/events/types.d.ts +250 -250
  5. package/dist/events/user.d.ts +2 -2
  6. package/dist/index.cjs +711 -0
  7. package/dist/index.d.ts +3 -3
  8. package/dist/index.js +595 -3
  9. package/dist/integrations/conditionallyLoadAnalytics.d.ts +9 -9
  10. package/dist/integrations/consent.d.ts +9 -9
  11. package/dist/integrations/device.d.ts +13 -13
  12. package/dist/integrations/fetchDestinationsForWriteKey.d.ts +6 -6
  13. package/dist/integrations/getConsentDecision.d.ts +8 -8
  14. package/dist/integrations/index.d.ts +31 -31
  15. package/dist/integrations/mapDestinations.d.ts +13 -13
  16. package/dist/integrations/onetrust.d.ts +6 -6
  17. package/dist/integrations/runSegmentSnippet.d.ts +7 -7
  18. package/dist/integrations/types.d.ts +24 -24
  19. package/dist/package.json +21 -0
  20. package/package.json +2 -2
  21. package/dist/events/index.js +0 -3
  22. package/dist/events/track.js +0 -115
  23. package/dist/events/types.js +0 -1
  24. package/dist/events/user.js +0 -41
  25. package/dist/integrations/conditionallyLoadAnalytics.js +0 -27
  26. package/dist/integrations/consent.js +0 -11
  27. package/dist/integrations/device.js +0 -25
  28. package/dist/integrations/fetchDestinationsForWriteKey.js +0 -88
  29. package/dist/integrations/getConsentDecision.js +0 -32
  30. package/dist/integrations/index.js +0 -90
  31. package/dist/integrations/mapDestinations.js +0 -55
  32. package/dist/integrations/onetrust.js +0 -53
  33. package/dist/integrations/runSegmentSnippet.js +0 -64
  34. package/dist/integrations/types.js +0 -1
package/dist/index.cjs ADDED
@@ -0,0 +1,711 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ /**
6
+ * @returns Whether the site is running both in ChromeOS and in PWA mode.
7
+ */
8
+ const isChromeOSPWA = () => isChromeOS() && 'getDigitalGoodsService' in window && // https://stackoverflow.com/questions/41742390/javascript-to-check-if-pwa-or-mobile-web
9
+ window.matchMedia('(display-mode: standalone)').matches;
10
+ /**
11
+ * @returns Whether the site is running in ChromeOS
12
+ */
13
+
14
+ const isChromeOS = () => typeof navigator !== 'undefined' && // https://stackoverflow.com/questions/29657165/detecting-chrome-os-with-javascript
15
+ /\bCrOS\b/.test(navigator.userAgent);
16
+ var ClientTypes;
17
+
18
+ (function (ClientTypes) {
19
+ ClientTypes["PWA"] = "pwa";
20
+ ClientTypes["Default"] = "default";
21
+ })(ClientTypes || (ClientTypes = {}));
22
+
23
+ const getClientType = () => isChromeOSPWA() ? ClientTypes.PWA : ClientTypes.Default;
24
+
25
+ const conditionallyLoadAnalytics = ({
26
+ analytics,
27
+ destinationPreferences,
28
+ identifyPreferences,
29
+ user,
30
+ writeKey
31
+ }) => {
32
+ if (analytics.initialize) {
33
+ return;
34
+ }
35
+
36
+ analytics.load(writeKey, {
37
+ integrations: destinationPreferences
38
+ });
39
+ analytics.page();
40
+
41
+ if (user) {
42
+ const identifyParams = {
43
+ email: user.email,
44
+ client: getClientType()
45
+ };
46
+ analytics.identify(user.id, identifyParams, {
47
+ integrations: identifyPreferences
48
+ });
49
+ }
50
+ };
51
+
52
+ function _await$2(value, then, direct) {
53
+ if (direct) {
54
+ return then ? then(value) : value;
55
+ }
56
+
57
+ if (!value || !value.then) {
58
+ value = Promise.resolve(value);
59
+ }
60
+
61
+ return then ? value.then(then) : value;
62
+ }
63
+
64
+ const knownFetchFailures = ['Failed to fetch', 'Load failed', 'NetworkError when attempting to fetch resource', 'Resource blocked by content blocker'];
65
+
66
+ function _catch(body, recover) {
67
+ try {
68
+ var result = body();
69
+ } catch (e) {
70
+ return recover(e);
71
+ }
72
+
73
+ if (result && result.then) {
74
+ return result.then(void 0, recover);
75
+ }
76
+
77
+ return result;
78
+ }
79
+
80
+ function _async$3(f) {
81
+ return function () {
82
+ for (var args = [], i = 0; i < arguments.length; i++) {
83
+ args[i] = arguments[i];
84
+ }
85
+
86
+ try {
87
+ return Promise.resolve(f.apply(this, args));
88
+ } catch (e) {
89
+ return Promise.reject(e);
90
+ }
91
+ };
92
+ }
93
+
94
+ const fetchDestinationsForWriteKey = _async$3(function ({
95
+ writeKey,
96
+ onError
97
+ }) {
98
+ const filteredOnError = error => {
99
+ if (!knownFetchFailures.some(failure => error.includes(failure))) {
100
+ onError(error);
101
+ }
102
+ };
103
+
104
+ return _catch(function () {
105
+ return _await$2(fetch(`https://cdn.segment.com/v1/projects/${writeKey}/integrations`), function (response) {
106
+ if (!response.ok) {
107
+ filteredOnError(`Failed to fetch integrations for write key ${writeKey}: HTTP ${response.status} ${response.statusText}`);
108
+ return [];
109
+ }
110
+
111
+ return _await$2(response.json(), function (destinations) {
112
+ for (const destination of destinations) {
113
+ destination.id = destination.creationName;
114
+ delete destination.creationName;
115
+ }
116
+
117
+ return destinations;
118
+ });
119
+ });
120
+ }, function (error) {
121
+ filteredOnError(`Unknown error fetching Segment destinations for write key ${writeKey}: ${error}`);
122
+ return [];
123
+ });
124
+ });
125
+
126
+ /**
127
+ * @see https://www.notion.so/codecademy/GDPR-Compliance-141ebcc7ffa542daa0da56e35f482b41
128
+ */
129
+ var Consent;
130
+
131
+ (function (Consent) {
132
+ Consent["Functional"] = "C0003";
133
+ Consent["Performance"] = "C0002";
134
+ Consent["StrictlyNecessary"] = "C0001";
135
+ Consent["Targeting"] = "C0004";
136
+ })(Consent || (Consent = {}));
137
+
138
+ const OPT_OUT_DATALAYER_VAR = 'user_opted_out_external_tracking';
139
+ const getConsentDecision = ({
140
+ scope,
141
+ optedOutExternalTracking
142
+ }) => {
143
+ let consentDecision = [];
144
+
145
+ if (typeof scope.OnetrustActiveGroups === 'string') {
146
+ consentDecision = scope.OnetrustActiveGroups.split(',').filter(Boolean);
147
+ } else if (scope.OnetrustActiveGroups) {
148
+ consentDecision = scope.OnetrustActiveGroups;
149
+ }
150
+
151
+ if (optedOutExternalTracking) {
152
+ var _scope$dataLayer;
153
+
154
+ /**
155
+ * If user has already opted out of everything but the essentials
156
+ * don't force them to consent to Functional & Performance trackers
157
+ */
158
+ if (consentDecision.length > 2) {
159
+ consentDecision = [Consent.StrictlyNecessary, Consent.Functional, Consent.Performance];
160
+ }
161
+
162
+ (_scope$dataLayer = scope.dataLayer) != null ? _scope$dataLayer : scope.dataLayer = [];
163
+ scope.dataLayer.push({
164
+ [OPT_OUT_DATALAYER_VAR]: true
165
+ });
166
+ }
167
+
168
+ return consentDecision;
169
+ };
170
+
171
+ const targetingCategories = ['Advertising', 'Attribution', 'Email Marketing'];
172
+ const performanceCategories = ['Analytics', 'Customer Success', 'Surveys', 'Heatmaps & Recording'];
173
+ const functionalCategories = ['SMS & Push Notifications'];
174
+ /**
175
+ * @see https://www.notion.so/codecademy/GDPR-Compliance-141ebcc7ffa542daa0da56e35f482b41
176
+ */
177
+
178
+ const mapDestinations = ({
179
+ consentDecision: _consentDecision = [Consent.StrictlyNecessary],
180
+ destinations
181
+ }) => {
182
+ const destinationPreferences = Object.assign({
183
+ 'Segment.io': _consentDecision.includes(Consent.Functional)
184
+ }, ...destinations.map(dest => {
185
+ if (targetingCategories.includes(dest.category)) {
186
+ return {
187
+ [dest.id]: _consentDecision.includes(Consent.Targeting)
188
+ };
189
+ }
190
+
191
+ if (performanceCategories.includes(dest.category)) {
192
+ return {
193
+ [dest.id]: _consentDecision.includes(Consent.Performance)
194
+ };
195
+ }
196
+
197
+ if (functionalCategories.includes(dest.category)) {
198
+ return {
199
+ [dest.id]: _consentDecision.includes(Consent.Functional)
200
+ };
201
+ }
202
+
203
+ return {
204
+ [dest.id]: true
205
+ };
206
+ }));
207
+ const identifyPreferences = {
208
+ All: false,
209
+ FullStory: _consentDecision.includes(Consent.Performance),
210
+ Hindsight: _consentDecision.includes(Consent.Targeting),
211
+ UserLeap: _consentDecision.includes(Consent.Performance)
212
+ };
213
+ return {
214
+ destinationPreferences,
215
+ identifyPreferences
216
+ };
217
+ };
218
+
219
+ function _async$2(f) {
220
+ return function () {
221
+ for (var args = [], i = 0; i < arguments.length; i++) {
222
+ args[i] = arguments[i];
223
+ }
224
+
225
+ try {
226
+ return Promise.resolve(f.apply(this, args));
227
+ } catch (e) {
228
+ return Promise.reject(e);
229
+ }
230
+ };
231
+ } // For now, these three values duplicate theme colors from gamut-styles
232
+ // We don't want to take a full dependency on that package here...
233
+
234
+
235
+ const initializeOneTrust = _async$2(function ({
236
+ production,
237
+ scope
238
+ }) {
239
+ const script = document.createElement('script');
240
+ script.setAttribute('async', 'true');
241
+ script.setAttribute('src', 'https://cdn.cookielaw.org/scripttemplates/otSDKStub.js');
242
+ script.setAttribute('type', 'text/javascript');
243
+ script.setAttribute('data-domain-script', `cfa7b129-f37b-4f5a-9991-3f75ba7b85fb${production ? '' : '-test'}`);
244
+ document.body.appendChild(script);
245
+ const style = document.createElement('style');
246
+ style.textContent = rawStyles;
247
+ document.body.appendChild(style);
248
+ return new Promise(resolve => {
249
+ scope.OptanonWrapper = () => {
250
+ var _scope$dataLayer, _script$parentNode;
251
+
252
+ (_scope$dataLayer = scope.dataLayer) != null ? _scope$dataLayer : scope.dataLayer = [];
253
+ scope.dataLayer.push({
254
+ event: 'OneTrustGroupsUpdated'
255
+ });
256
+ resolve();
257
+ (_script$parentNode = script.parentNode) == null ? void 0 : _script$parentNode.removeChild(script);
258
+ };
259
+ });
260
+ });
261
+ const rawStyles = `
262
+ :root {
263
+ --onetrust-brand-purple: #3A10E5;
264
+ --onetrust-color-gray-500: #828285;
265
+ --onetrust-color-white: #fff;
266
+ }
267
+
268
+ #onetrust-banner-sdk {
269
+ padding: 1rem !important;
270
+ }
271
+ #onetrust-banner-sdk > .ot-sdk-container {
272
+ width: 100% !important;
273
+ }
274
+ #onetrust-banner-sdk > .ot-sdk-container > .ot-sdk-row {
275
+ display: flex !important;
276
+ flex-direction: column !important;
277
+ align-items: center !important;
278
+ max-width: 1436px !important;
279
+ margin: 0 auto !important;
280
+ }
281
+ #onetrust-banner-sdk > .ot-sdk-container > .ot-sdk-row:after {
282
+ content: none !important;
283
+ }
284
+ #onetrust-group-container {
285
+ display: flex !important;
286
+ justify-content: center;
287
+ float: none !important;
288
+ width: 100% !important;
289
+ max-width: 1148px !important;
290
+ margin-left: 0 !important;
291
+ margin-bottom: 0.625rem !important;
292
+ }
293
+ #onetrust-policy,
294
+ #onetrust-policy-text {
295
+ margin: 0 !important;
296
+ font-size: 0.875rem !important;
297
+ line-height: 1.375rem !important;
298
+ text-align: center !important;
299
+ float: none !important;
300
+ }
301
+ #onetrust-policy-text a {
302
+ text-decoration: none;
303
+ line-height: 26px !important;
304
+ margin-left: 0 !important;
305
+ }
306
+ #onetrust-button-group-parent {
307
+ position: relative !important;
308
+ top: initial !important;
309
+ left: initial !important;
310
+ transform: initial !important;
311
+ width: 264px !important;
312
+ margin: 0 !important;
313
+ padding: 0 !important;
314
+ float: none !important;
315
+ }
316
+ #onetrust-button-group {
317
+ display: flex !important;
318
+ margin: 0 !important;
319
+ }
320
+ #onetrust-pc-btn-handler, #onetrust-accept-btn-handler {
321
+ min-width: initial !important;
322
+ padding: 0.375rem 1rem !important;
323
+ margin: 0 !important;
324
+ opacity: 1 !important;
325
+ border-radius: 2px !important;
326
+ line-height: 1.5 !important;
327
+ user-select: none !important;
328
+ font-size: 1rem !important;
329
+ }
330
+ #onetrust-pc-btn-handler:focus, #onetrust-accept-btn-handler:focus {
331
+ box-shadow: 0 0 0 2px var(--onetrust-color-white), 0 0 0 4px var(--onetrust-brand-purple);
332
+ text-decoration: none !important;
333
+ outline: none !important;
334
+ }
335
+ #onetrust-pc-btn-handler{
336
+ color: var(--onetrust-brand-purple) !important;
337
+ border: 1px solid var(--onetrust-brand-purple)!important;
338
+ background: var(--onetrust-color-white) !important
339
+ }
340
+ #onetrust-accept-btn-handler {
341
+ color: var(--onetrust-color-white) !important;
342
+ background: var(--onetrust-brand-purple)!important;
343
+ margin-left: 1rem !important;
344
+ }
345
+ #onetrust-close-btn-container {
346
+ display: none !important;
347
+ }
348
+
349
+ .pc-logo {
350
+ display: none !important;
351
+ }
352
+
353
+ #accept-recommended-btn-handler,
354
+ .ot-pc-refuse-all-handler,
355
+ .save-preference-btn-handler {
356
+ margin-left: 4px !important;
357
+ font-size: 14px !important;
358
+ }
359
+
360
+ #accept-recommended-btn-handler:focus,
361
+ #onetrust-pc-sdk .ot-pc-refuse-all-handler:focus,
362
+ #onetrust-pc-sdk .save-preference-btn-handler:focus {
363
+ box-shadow: 0 0 0 2px var(--onetrust-color-white), 0 0 0 4px var(--onetrust-brand-purple);
364
+ text-decoration: none !important;
365
+ outline: none !important;
366
+ opacity: 1 !important;
367
+ }
368
+
369
+ .ot-switch-label {
370
+ border: 1px solid var(--onetrust-color-gray-500) !important;
371
+ background-color: var(--onetrust-color-gray-500) !important;
372
+ }
373
+
374
+ .ot-switch-nob {
375
+ background: var(--onetrust-color-white) !important;
376
+ }
377
+
378
+ .ot-switch-inner:before {
379
+ background-color: var(--onetrust-brand-purple) !important;
380
+ }
381
+
382
+ .switch-checkbox:checked+.ot-switch-label .ot-switch-nob {
383
+ border-color: var(--onetrust-brand-purple) !important;
384
+ }
385
+
386
+ .ot-pc-footer-logo {
387
+ display: none !important;
388
+ }
389
+
390
+ #onetrust-banner-sdk>.ot-sdk-container {
391
+ overflow: visible !important;
392
+ }
393
+
394
+ @media (max-width: 30rem) {
395
+ #accept-recommended-btn-handler,
396
+ .ot-pc-refuse-all-handler,
397
+ .save-preference-btn-handler {
398
+ width: 96% !important;
399
+ }
400
+ }
401
+
402
+ @media (min-width: 37.5rem) {
403
+ #onetrust-banner-sdk {
404
+ padding: 0.875rem 1rem !important;
405
+ }
406
+ }
407
+ @media (min-width: 48rem) {
408
+ #onetrust-banner-sdk {
409
+ padding: 0.875rem 1.25rem !important;
410
+ }
411
+ }
412
+ @media (min-width: 1650px) {
413
+ #onetrust-banner-sdk > .ot-sdk-container > .ot-sdk-row {
414
+ flex-direction: row !important;
415
+ justify-content: space-between !important;
416
+ }
417
+ #onetrust-group-container {
418
+ margin-bottom: 0 !important;
419
+ }
420
+ #onetrust-button-group {
421
+ flex-direction: row !important;
422
+ }
423
+ }
424
+ `;
425
+
426
+ // @ts-nocheck
427
+
428
+ /**
429
+ * This code is copypasta from the Segment documentation.
430
+ * It creates the global analytics object and loads the Segment Analytics API that uses it.
431
+ *
432
+ * @see https://segment.com/docs/connections/sources/catalog/libraries/website/javascript/quickstart/#step-2-copy-the-segment-snippet
433
+ */
434
+ const runSegmentSnippet = () => {
435
+ var _window;
436
+
437
+ // Create a queue, but don't obliterate an existing one!
438
+ (_window = window).analytics || (_window.analytics = []);
439
+ const {
440
+ analytics
441
+ } = window; // If the real analytics.js is already on the page return.
442
+
443
+ if (analytics.initialize) return; // If the snippet was invoked already show an error.
444
+
445
+ if (analytics.invoked) {
446
+ console.error('Segment snippet included twice.');
447
+ return;
448
+ } // Invoked flag, to make sure the snippet
449
+ // is never invoked twice.
450
+
451
+
452
+ analytics.invoked = true; // A list of the methods in Analytics.js to stub.
453
+
454
+ analytics.methods = ['trackSubmit', 'trackClick', 'trackLink', 'trackForm', 'pageview', 'identify', 'reset', 'group', 'track', 'ready', 'alias', 'debug', 'page', 'once', 'off', 'on', 'addSourceMiddleware', 'addIntegrationMiddleware', 'setAnonymousId', 'addDestinationMiddleware']; // Define a factory to create stubs. These are placeholders
455
+ // for methods in Analytics.js so that you never have to wait
456
+ // for it to load to actually record data. The `method` is
457
+ // stored as the first argument, so we can replay the data.
458
+
459
+ analytics.factory = function (method) {
460
+ return function () {
461
+ const args = Array.prototype.slice.call(arguments);
462
+ args.unshift(method);
463
+ analytics.push(args);
464
+ return analytics;
465
+ };
466
+ }; // For each of our methods, generate a queueing stub.
467
+
468
+
469
+ for (let i = 0; i < analytics.methods.length; i += 1) {
470
+ const key = analytics.methods[i];
471
+ analytics[key] = analytics.factory(key);
472
+ } // Define a method to load Analytics.js from our CDN,
473
+ // and that will be sure to only ever load it once.
474
+
475
+
476
+ analytics.load = function (key, options) {
477
+ // Create an async script element based on your key.
478
+ const script = document.createElement('script');
479
+ script.type = 'text/javascript';
480
+ script.async = true;
481
+ script.src = 'https://cdn.segment.com/analytics.js/v1/' + key + '/analytics.min.js'; // Insert our script next to the first script element.
482
+
483
+ const first = document.getElementsByTagName('script')[0];
484
+ first.parentNode.insertBefore(script, first);
485
+ analytics._loadOptions = options;
486
+ }; // Add a version to keep track of what's in the wild.
487
+
488
+
489
+ analytics.SNIPPET_VERSION = '4.1.0';
490
+ };
491
+
492
+ /**
493
+ * @see README.md for details and usage.
494
+ */
495
+
496
+ function _await$1(value, then, direct) {
497
+ if (direct) {
498
+ return then ? then(value) : value;
499
+ }
500
+
501
+ if (!value || !value.then) {
502
+ value = Promise.resolve(value);
503
+ }
504
+
505
+ return then ? value.then(then) : value;
506
+ }
507
+
508
+ function _async$1(f) {
509
+ return function () {
510
+ for (var args = [], i = 0; i < arguments.length; i++) {
511
+ args[i] = arguments[i];
512
+ }
513
+
514
+ try {
515
+ return Promise.resolve(f.apply(this, args));
516
+ } catch (e) {
517
+ return Promise.reject(e);
518
+ }
519
+ };
520
+ }
521
+
522
+ const initializeTrackingIntegrations = _async$1(function ({
523
+ onError,
524
+ production,
525
+ scope,
526
+ user,
527
+ optedOutExternalTracking,
528
+ writeKey
529
+ }) {
530
+ // 1. Wait 1000ms to allow any other post-hydration logic to run first
531
+ return _await$1(new Promise(resolve => setTimeout(resolve, 1000)), function () {
532
+ // 2. Load in OneTrust's banner and wait for its `OptanonWrapper` callback
533
+ return _await$1(initializeOneTrust({
534
+ scope,
535
+ production
536
+ }), function () {
537
+ // 3. Segment's copy-and-paste snippet is run to load the Segment global library
538
+ runSegmentSnippet(); // 4. Destination integrations for Segment are fetched
539
+
540
+ return _await$1(fetchDestinationsForWriteKey({
541
+ onError,
542
+ writeKey
543
+ }), function (destinations) {
544
+ if (!destinations) {
545
+ return;
546
+ }
547
+
548
+ const consentDecision = getConsentDecision({
549
+ scope,
550
+ optedOutExternalTracking
551
+ }); // 5. Those integrations are compared against the user's consent decisions into a list of allowed destinations
552
+
553
+ const {
554
+ destinationPreferences,
555
+ identifyPreferences
556
+ } = mapDestinations({
557
+ consentDecision,
558
+ destinations
559
+ }); // 6. We load only those allowed destinations using Segment's `analytics.load`
560
+
561
+ conditionallyLoadAnalytics({
562
+ analytics: scope.analytics,
563
+ destinationPreferences,
564
+ identifyPreferences,
565
+ user,
566
+ writeKey
567
+ });
568
+ });
569
+ });
570
+ });
571
+ });
572
+
573
+ function _extends() {
574
+ _extends = Object.assign ? Object.assign.bind() : function (target) {
575
+ for (var i = 1; i < arguments.length; i++) {
576
+ var source = arguments[i];
577
+
578
+ for (var key in source) {
579
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
580
+ target[key] = source[key];
581
+ }
582
+ }
583
+ }
584
+
585
+ return target;
586
+ };
587
+ return _extends.apply(this, arguments);
588
+ }
589
+
590
+ const browserSupportsKeepalive = () => 'keepalive' in window.Request.prototype;
591
+
592
+ const createTracker = ({
593
+ apiBaseUrl,
594
+ verbose
595
+ }) => {
596
+ const beacon = (endpoint, data) => {
597
+ const uri = new URL(endpoint, apiBaseUrl).toString();
598
+ const form = new FormData();
599
+
600
+ for (const [k, v] of Object.entries(data)) {
601
+ form.append(k, v.toString());
602
+ }
603
+
604
+ try {
605
+ // Firefox allows users to disable navigator.sendBeacon, and very old Safari versions don't have it.
606
+ // [WEB-1700]: Additionally, Chrome 79-80 gives "Illegal invocation" with ?., so through 2022 we should support them.
607
+ // It seems similar to this: https://github.com/vercel/next.js/issues/23856
608
+ if (navigator.sendBeacon && navigator.sendBeacon(uri, form)) {
609
+ return;
610
+ }
611
+ } catch (_unused) {// Even with the proper scoping, Chrome 79-80 still gives "Illegal invocation" crashes. Sigh.
612
+ } // Either way, we fall back to standard fetch if sendBeacon fails.
613
+ // We don't mind this rejecting with an error because it's tracking, and we'll know if that starts to fail.
614
+
615
+
616
+ window.fetch(uri, _extends({
617
+ method: 'POST',
618
+ body: form
619
+ }, browserSupportsKeepalive() && {
620
+ keepalive: true
621
+ }));
622
+ };
623
+
624
+ const event = (category, event, userData, options = {}) => {
625
+ const properties = _extends({}, userData, {
626
+ fullpath: window.location.pathname + window.location.search,
627
+ search: window.location.search,
628
+ path: window.location.pathname,
629
+ title: window.document.title,
630
+ url: window.location.href,
631
+ referrer: userData.referrer || window.document.referrer,
632
+ client: getClientType()
633
+ });
634
+
635
+ if (verbose) {
636
+ console.groupCollapsed(`%cTracking Event Fired: ${category}:${event}`, 'color: #4b35ef; font-style: italic;');
637
+ console.log({
638
+ category,
639
+ event,
640
+ properties
641
+ });
642
+ console.groupEnd();
643
+ } // This allows the UTM query params to get registered in the user session.
644
+
645
+
646
+ const queryParams = window.location.search;
647
+ beacon(`/analytics/${category}${queryParams}`, {
648
+ category,
649
+ event,
650
+ properties: JSON.stringify(properties),
651
+ gdpr_safe: `${options.gdprSafe}`
652
+ });
653
+ };
654
+
655
+ return {
656
+ event,
657
+ click: data => event('user', 'click', data),
658
+ impression: data => event('user', 'impression', data),
659
+ visit: data => event('user', 'visit', data),
660
+ pushDataLayerEvent: eventName => {
661
+ var _window;
662
+
663
+ ((_window = window).dataLayer || (_window.dataLayer = [])).push({
664
+ event: eventName
665
+ });
666
+ }
667
+ };
668
+ };
669
+
670
+ function _await(value, then, direct) {
671
+ if (direct) {
672
+ return then ? then(value) : value;
673
+ }
674
+
675
+ if (!value || !value.then) {
676
+ value = Promise.resolve(value);
677
+ }
678
+
679
+ return then ? value.then(then) : value;
680
+ }
681
+
682
+ function _async(f) {
683
+ return function () {
684
+ for (var args = [], i = 0; i < arguments.length; i++) {
685
+ args[i] = arguments[i];
686
+ }
687
+
688
+ try {
689
+ return Promise.resolve(f.apply(this, args));
690
+ } catch (e) {
691
+ return Promise.reject(e);
692
+ }
693
+ };
694
+ }
695
+
696
+ const fetchUser = _async(function (apiBaseUrl) {
697
+ return _await(fetch(`${apiBaseUrl}/users/web`, {
698
+ method: 'GET',
699
+ headers: {
700
+ 'Content-type': 'application/json',
701
+ Accept: 'application/json'
702
+ },
703
+ credentials: 'include'
704
+ }), function (response) {
705
+ return response.json();
706
+ });
707
+ });
708
+
709
+ exports.createTracker = createTracker;
710
+ exports.fetchUser = fetchUser;
711
+ exports.initializeTrackingIntegrations = initializeTrackingIntegrations;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export * from './integrations';
2
- export type { TrackingWindow } from './integrations/types';
3
- export * from './events';
1
+ export * from './integrations';
2
+ export type { TrackingWindow } from './integrations/types';
3
+ export * from './events';