@codecademy/tracking 0.25.1-alpha.42681.0 → 0.25.1-alpha.5b36ce.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.
@@ -1,6 +1,11 @@
1
- @codecademy/tracking:build: cache hit, replaying output f545e66ede74e142
1
+ @codecademy/tracking:build: cache hit, replaying output 53b2821e10cf2062
2
2
  @codecademy/tracking:build: $ yarn build:clean && yarn build:compile && yarn build:types
3
3
  @codecademy/tracking:build: $ rm -rf dist
4
4
  @codecademy/tracking:build: $ babel ./src --out-dir ./dist --copy-files --extensions ".ts,.tsx"
5
- @codecademy/tracking:build: Successfully compiled 18 files with Babel (2184ms).
5
+ @codecademy/tracking:build: Browserslist: caniuse-lite is outdated. Please run:
6
+ @codecademy/tracking:build: npx browserslist@latest --update-db
7
+ @codecademy/tracking:build: 
8
+ @codecademy/tracking:build: Why you should do it regularly:
9
+ @codecademy/tracking:build: https://github.com/browserslist/browserslist#browsers-data-updating
10
+ @codecademy/tracking:build: Successfully compiled 18 files with Babel (2060ms).
6
11
  @codecademy/tracking:build: $ tsc --emitDeclarationOnly
package/CHANGELOG.md CHANGED
@@ -3,7 +3,7 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- ### [0.25.1-alpha.42681.0](https://github.com/Codecademy/client-modules/compare/@codecademy/tracking@0.25.0...@codecademy/tracking@0.25.1-alpha.42681.0) (2022-10-21)
6
+ ### [0.25.1-alpha.5b36ce.0](https://github.com/Codecademy/client-modules/compare/@codecademy/tracking@0.25.0...@codecademy/tracking@0.25.1-alpha.5b36ce.0) (2022-10-24)
7
7
 
8
8
  **Note:** Version bump only for package @codecademy/tracking
9
9
 
@@ -1,8 +1,13 @@
1
- var _class;
2
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
3
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
1
+ var _class, _temp;
2
+
3
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
4
+
5
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
6
+
4
7
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
8
+
5
9
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
10
+
6
11
  import { createTracker } from '../track';
7
12
  var apiBaseUrl = 'https://www.codecademy.com';
8
13
  var fakeWindow = {
@@ -24,9 +29,9 @@ Object.defineProperties(window, {
24
29
  value: fakeWindow.location
25
30
  },
26
31
  Request: {
27
- value: (_class = function MockRequest() {
32
+ value: (_temp = _class = function MockRequest() {
28
33
  _classCallCheck(this, MockRequest);
29
- }, _defineProperty(_class, "keepalive", true), _class)
34
+ }, _defineProperty(_class, "keepalive", true), _temp)
30
35
  }
31
36
  });
32
37
  Object.defineProperty(window.document, 'title', {
@@ -41,6 +46,7 @@ jest.mock('../../integrations/device', function () {
41
46
  get getClientType() {
42
47
  return mockClientType;
43
48
  }
49
+
44
50
  };
45
51
  });
46
52
  describe('createTracker', function () {
@@ -123,6 +129,7 @@ describe('createTracker', function () {
123
129
  });
124
130
  });
125
131
  };
132
+
126
133
  describeEvent('click');
127
134
  describeEvent('impression');
128
135
  describeEvent('visit');
@@ -1,6 +1,9 @@
1
1
  import _regeneratorRuntime from "@babel/runtime/regenerator";
2
+
2
3
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
4
+
3
5
  function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
6
+
4
7
  import fetch from 'fetch-mock';
5
8
  import { fetchUser } from '../user';
6
9
  var apiBaseUrl = 'https://www.codecademy.com';
@@ -20,6 +23,7 @@ describe('fetchUser', function () {
20
23
  fetch.getOnce('*', JSON.stringify(authUser));
21
24
  _context.next = 3;
22
25
  return fetchUser(apiBaseUrl);
26
+
23
27
  case 3:
24
28
  user = _context.sent;
25
29
  expect(user).toEqual(authUser);
@@ -27,6 +31,7 @@ describe('fetchUser', function () {
27
31
  expect(fetch.calls()[0][0]).toBe("".concat(apiBaseUrl, "/users/web"));
28
32
  expect(fetch.calls()[0][1].method).toBe('GET');
29
33
  expect(fetch.calls()[0][1].credentials).toBe('include');
34
+
30
35
  case 9:
31
36
  case "end":
32
37
  return _context.stop();
@@ -1,31 +1,46 @@
1
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
2
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
1
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
2
+
3
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
4
+
3
5
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
+
4
7
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
8
+
5
9
  function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
10
+
6
11
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
12
+
7
13
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
8
- function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
14
+
15
+ function _iterableToArrayLimit(arr, i) { var _i = arr && (typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]); if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
16
+
9
17
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
18
+
10
19
  import { getClientType } from '../integrations/device';
11
20
  /* eslint-disable no-console */
12
21
 
13
22
  var browserSupportsKeepalive = function browserSupportsKeepalive() {
14
23
  return 'keepalive' in window.Request.prototype;
15
24
  };
25
+
16
26
  export var createTracker = function createTracker(_ref) {
17
27
  var apiBaseUrl = _ref.apiBaseUrl,
18
- verbose = _ref.verbose;
28
+ verbose = _ref.verbose;
29
+
19
30
  var beacon = function beacon(endpoint, data) {
20
31
  var uri = new URL(endpoint, apiBaseUrl).toString();
21
32
  var form = new FormData();
33
+
22
34
  for (var _i2 = 0, _Object$entries = Object.entries(data); _i2 < _Object$entries.length; _i2++) {
23
35
  var _ref4 = _Object$entries[_i2];
36
+
24
37
  var _ref3 = _slicedToArray(_ref4, 2);
38
+
25
39
  var k = _ref3[0];
26
40
  var v = _ref3[1];
27
41
  form.append(k, v.toString());
28
42
  }
43
+
29
44
  try {
30
45
  // Firefox allows users to disable navigator.sendBeacon, and very old Safari versions don't have it.
31
46
  // [WEB-1700]: Additionally, Chrome 79-80 gives "Illegal invocation" with ?., so through 2022 we should support them.
@@ -34,13 +49,12 @@ export var createTracker = function createTracker(_ref) {
34
49
  if (navigator.sendBeacon && navigator.sendBeacon(uri, form)) {
35
50
  return;
36
51
  }
37
- } catch (_unused) {
38
- // Even with the proper scoping, Chrome 79-80 still gives "Illegal invocation" crashes. Sigh.
39
- }
40
-
41
- // Either way, we fall back to standard fetch if sendBeacon fails.
52
+ } catch (_unused) {// Even with the proper scoping, Chrome 79-80 still gives "Illegal invocation" crashes. Sigh.
53
+ } // Either way, we fall back to standard fetch if sendBeacon fails.
42
54
  // We don't mind this rejecting with an error because it's tracking, and we'll know if that starts to fail.
43
55
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
56
+
57
+
44
58
  window.fetch(uri, _objectSpread({
45
59
  method: 'POST',
46
60
  body: form
@@ -48,8 +62,10 @@ export var createTracker = function createTracker(_ref) {
48
62
  keepalive: true
49
63
  }));
50
64
  };
65
+
51
66
  var event = function event(category, _event, userData) {
52
67
  var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
68
+
53
69
  var properties = _objectSpread(_objectSpread({}, userData), {}, {
54
70
  fullpath: window.location.pathname + window.location.search,
55
71
  search: window.location.search,
@@ -59,6 +75,7 @@ export var createTracker = function createTracker(_ref) {
59
75
  referrer: userData.referrer || window.document.referrer,
60
76
  client: getClientType()
61
77
  });
78
+
62
79
  if (verbose) {
63
80
  console.groupCollapsed("%cTracking Event Fired: ".concat(category, ":").concat(_event), 'color: #4b35ef; font-style: italic;');
64
81
  console.log({
@@ -67,9 +84,9 @@ export var createTracker = function createTracker(_ref) {
67
84
  properties: properties
68
85
  });
69
86
  console.groupEnd();
70
- }
87
+ } // This allows the UTM query params to get registered in the user session.
88
+
71
89
 
72
- // This allows the UTM query params to get registered in the user session.
73
90
  var queryParams = window.location.search;
74
91
  beacon("/analytics/".concat(category).concat(queryParams), {
75
92
  category: category,
@@ -78,6 +95,7 @@ export var createTracker = function createTracker(_ref) {
78
95
  gdpr_safe: "".concat(options.gdprSafe)
79
96
  });
80
97
  };
98
+
81
99
  return {
82
100
  event: event,
83
101
  click: function click(data) {
@@ -91,6 +109,7 @@ export var createTracker = function createTracker(_ref) {
91
109
  },
92
110
  pushDataLayerEvent: function pushDataLayerEvent(eventName) {
93
111
  var _ref5;
112
+
94
113
  ((_ref5 = window).dataLayer || (_ref5.dataLayer = [])).push({
95
114
  event: eventName
96
115
  });
@@ -1 +0,0 @@
1
- export {};
@@ -1,6 +1,9 @@
1
1
  import _regeneratorRuntime from "@babel/runtime/regenerator";
2
+
2
3
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
4
+
3
5
  function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
6
+
4
7
  export var fetchUser = /*#__PURE__*/function () {
5
8
  var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(apiBaseUrl) {
6
9
  var response;
@@ -17,9 +20,11 @@ export var fetchUser = /*#__PURE__*/function () {
17
20
  },
18
21
  credentials: 'include'
19
22
  });
23
+
20
24
  case 2:
21
25
  response = _context.sent;
22
26
  return _context.abrupt("return", response.json());
27
+
23
28
  case 4:
24
29
  case "end":
25
30
  return _context.stop();
@@ -27,6 +32,7 @@ export var fetchUser = /*#__PURE__*/function () {
27
32
  }
28
33
  }, _callee);
29
34
  }));
35
+
30
36
  return function fetchUser(_x) {
31
37
  return _ref.apply(this, arguments);
32
38
  };
@@ -1,17 +1,20 @@
1
1
  import { getClientType } from './device';
2
2
  export var conditionallyLoadAnalytics = function conditionallyLoadAnalytics(_ref) {
3
3
  var analytics = _ref.analytics,
4
- destinationPreferences = _ref.destinationPreferences,
5
- identifyPreferences = _ref.identifyPreferences,
6
- user = _ref.user,
7
- writeKey = _ref.writeKey;
4
+ destinationPreferences = _ref.destinationPreferences,
5
+ identifyPreferences = _ref.identifyPreferences,
6
+ user = _ref.user,
7
+ writeKey = _ref.writeKey;
8
+
8
9
  if (analytics.initialize) {
9
10
  return;
10
11
  }
12
+
11
13
  analytics.load(writeKey, {
12
14
  integrations: destinationPreferences
13
15
  });
14
16
  analytics.page();
17
+
15
18
  if (user) {
16
19
  var identifyParams = {
17
20
  email: user.email,
@@ -2,6 +2,7 @@
2
2
  * @see https://www.notion.so/codecademy/GDPR-Compliance-141ebcc7ffa542daa0da56e35f482b41
3
3
  */
4
4
  export var Consent;
5
+
5
6
  (function (Consent) {
6
7
  Consent["Functional"] = "C0003";
7
8
  Consent["Performance"] = "C0002";
@@ -2,24 +2,24 @@
2
2
  * @returns Whether the site is running both in ChromeOS and in PWA mode.
3
3
  */
4
4
  export var isChromeOSPWA = function isChromeOSPWA() {
5
- return isChromeOS() && 'getDigitalGoodsService' in window &&
6
- // https://stackoverflow.com/questions/41742390/javascript-to-check-if-pwa-or-mobile-web
5
+ return isChromeOS() && 'getDigitalGoodsService' in window && // https://stackoverflow.com/questions/41742390/javascript-to-check-if-pwa-or-mobile-web
7
6
  window.matchMedia('(display-mode: standalone)').matches;
8
7
  };
9
-
10
8
  /**
11
9
  * @returns Whether the site is running in ChromeOS
12
10
  */
11
+
13
12
  export var isChromeOS = function isChromeOS() {
14
- return typeof navigator !== 'undefined' &&
15
- // https://stackoverflow.com/questions/29657165/detecting-chrome-os-with-javascript
13
+ return typeof navigator !== 'undefined' && // https://stackoverflow.com/questions/29657165/detecting-chrome-os-with-javascript
16
14
  /\bCrOS\b/.test(navigator.userAgent);
17
15
  };
18
16
  export var ClientTypes;
17
+
19
18
  (function (ClientTypes) {
20
19
  ClientTypes["PWA"] = "pwa";
21
20
  ClientTypes["Default"] = "default";
22
21
  })(ClientTypes || (ClientTypes = {}));
22
+
23
23
  export var getClientType = function getClientType() {
24
24
  return isChromeOSPWA() ? ClientTypes.PWA : ClientTypes.Default;
25
25
  };
@@ -1,18 +1,26 @@
1
1
  import _regeneratorRuntime from "@babel/runtime/regenerator";
2
+
2
3
  function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
4
+
3
5
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
6
+
4
7
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
8
+
5
9
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
10
+
6
11
  function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
12
+
7
13
  var knownFetchFailures = ['Failed to fetch', 'Load failed', 'NetworkError when attempting to fetch resource', 'Resource blocked by content blocker'];
8
14
  export var fetchDestinationsForWriteKey = /*#__PURE__*/function () {
9
15
  var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref) {
10
16
  var writeKey, onError, filteredOnError, response, destinations, _iterator, _step, destination;
17
+
11
18
  return _regeneratorRuntime.wrap(function _callee$(_context) {
12
19
  while (1) {
13
20
  switch (_context.prev = _context.next) {
14
21
  case 0:
15
22
  writeKey = _ref.writeKey, onError = _ref.onError;
23
+
16
24
  filteredOnError = function filteredOnError(error) {
17
25
  if (!knownFetchFailures.some(function (failure) {
18
26
  return error.includes(failure);
@@ -20,23 +28,30 @@ export var fetchDestinationsForWriteKey = /*#__PURE__*/function () {
20
28
  onError(error);
21
29
  }
22
30
  };
31
+
23
32
  _context.prev = 2;
24
33
  _context.next = 5;
25
34
  return fetch("https://cdn.segment.com/v1/projects/".concat(writeKey, "/integrations"));
35
+
26
36
  case 5:
27
37
  response = _context.sent;
38
+
28
39
  if (response.ok) {
29
40
  _context.next = 9;
30
41
  break;
31
42
  }
43
+
32
44
  filteredOnError("Failed to fetch integrations for write key ".concat(writeKey, ": HTTP ").concat(response.status, " ").concat(response.statusText));
33
45
  return _context.abrupt("return", []);
46
+
34
47
  case 9:
35
48
  _context.next = 11;
36
49
  return response.json();
50
+
37
51
  case 11:
38
52
  destinations = _context.sent;
39
53
  _iterator = _createForOfIteratorHelper(destinations);
54
+
40
55
  try {
41
56
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
42
57
  destination = _step.value;
@@ -48,12 +63,15 @@ export var fetchDestinationsForWriteKey = /*#__PURE__*/function () {
48
63
  } finally {
49
64
  _iterator.f();
50
65
  }
66
+
51
67
  return _context.abrupt("return", destinations);
68
+
52
69
  case 17:
53
70
  _context.prev = 17;
54
71
  _context.t0 = _context["catch"](2);
55
72
  filteredOnError("Unknown error fetching Segment destinations for write key ".concat(writeKey, ": ").concat(_context.t0));
56
73
  return _context.abrupt("return", []);
74
+
57
75
  case 21:
58
76
  case "end":
59
77
  return _context.stop();
@@ -61,6 +79,7 @@ export var fetchDestinationsForWriteKey = /*#__PURE__*/function () {
61
79
  }
62
80
  }, _callee, null, [[2, 17]]);
63
81
  }));
82
+
64
83
  return function fetchDestinationsForWriteKey(_x) {
65
84
  return _ref2.apply(this, arguments);
66
85
  };
@@ -1,55 +1,73 @@
1
1
  import _regeneratorRuntime from "@babel/runtime/regenerator";
2
+
2
3
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
4
+
3
5
  function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
6
+
4
7
  import { conditionallyLoadAnalytics } from './conditionallyLoadAnalytics';
8
+ import { Consent } from './consent';
5
9
  import { fetchDestinationsForWriteKey } from './fetchDestinationsForWriteKey';
6
10
  import { mapDestinations } from './mapDestinations';
7
11
  import { initializeOneTrust } from './onetrust';
8
12
  import { runSegmentSnippet } from './runSegmentSnippet';
13
+
9
14
  /**
10
15
  * @see README.md for details and usage.
11
16
  */
12
17
  export var initializeTrackingIntegrations = /*#__PURE__*/function () {
13
18
  var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref) {
14
- var onError, production, scope, user, writeKey, destinations, _mapDestinations, destinationPreferences, identifyPreferences;
19
+ var onError, production, scope, user, writeKey, optedOut, destinations, _mapDestinations, destinationPreferences, identifyPreferences;
20
+
15
21
  return _regeneratorRuntime.wrap(function _callee$(_context) {
16
22
  while (1) {
17
23
  switch (_context.prev = _context.next) {
18
24
  case 0:
19
25
  onError = _ref.onError, production = _ref.production, scope = _ref.scope, user = _ref.user, writeKey = _ref.writeKey;
20
- _context.next = 3;
26
+ optedOut = user === null || user === void 0 ? void 0 : user.opted_out_external_tracking; // 1. Wait 1000ms to allow any other post-hydration logic to run first
27
+
28
+ _context.next = 4;
21
29
  return new Promise(function (resolve) {
22
30
  return setTimeout(resolve, 1000);
23
31
  });
24
- case 3:
25
- _context.next = 5;
32
+
33
+ case 4:
34
+ _context.next = 6;
26
35
  return initializeOneTrust({
27
36
  scope: scope,
28
37
  production: production
29
38
  });
30
- case 5:
31
- // 3. Segment's copy-and-paste snippet is run to load the Segment global library
32
- runSegmentSnippet();
33
39
 
34
- // 4. Destination integrations for Segment are fetched
35
- _context.next = 8;
40
+ case 6:
41
+ if (optedOut) {
42
+ scope.OnetrustActiveGroups = [Consent.StrictlyNecessary, Consent.Functional];
43
+ } // 3. Segment's copy-and-paste snippet is run to load the Segment global library
44
+
45
+
46
+ runSegmentSnippet(); // 4. Destination integrations for Segment are fetched
47
+
48
+ _context.next = 10;
36
49
  return fetchDestinationsForWriteKey({
37
50
  onError: onError,
38
51
  writeKey: writeKey
39
52
  });
40
- case 8:
53
+
54
+ case 10:
41
55
  destinations = _context.sent;
56
+
42
57
  if (destinations) {
43
- _context.next = 11;
58
+ _context.next = 13;
44
59
  break;
45
60
  }
61
+
46
62
  return _context.abrupt("return");
47
- case 11:
63
+
64
+ case 13:
48
65
  // 5. Those integrations are compared against the user's consent decisions into a list of allowed destinations
49
66
  _mapDestinations = mapDestinations({
50
67
  consentDecision: scope.OnetrustActiveGroups,
51
68
  destinations: destinations
52
69
  }), destinationPreferences = _mapDestinations.destinationPreferences, identifyPreferences = _mapDestinations.identifyPreferences; // 6. We load only those allowed destinations using Segment's `analytics.load`
70
+
53
71
  conditionallyLoadAnalytics({
54
72
  analytics: scope.analytics,
55
73
  destinationPreferences: destinationPreferences,
@@ -57,13 +75,15 @@ export var initializeTrackingIntegrations = /*#__PURE__*/function () {
57
75
  user: user,
58
76
  writeKey: writeKey
59
77
  });
60
- case 13:
78
+
79
+ case 15:
61
80
  case "end":
62
81
  return _context.stop();
63
82
  }
64
83
  }
65
84
  }, _callee);
66
85
  }));
86
+
67
87
  return function initializeTrackingIntegrations(_x) {
68
88
  return _ref2.apply(this, arguments);
69
89
  };
@@ -1,35 +1,45 @@
1
1
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
2
+
2
3
  function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
4
+
3
5
  function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
6
+
4
7
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
8
+
5
9
  function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
10
+
6
11
  function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
12
+
7
13
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
14
+
8
15
  import { Consent } from './consent';
9
16
  // The Functional category may need to be added here in the future.
10
17
  var targetingCategories = ['Advertising', 'Attribution', 'Email Marketing'];
11
18
  var performanceCategories = ['Analytics', 'Customer Success', 'Surveys', 'Heatmaps & Recording'];
12
19
  var functionalCategories = ['SMS & Push Notifications'];
13
-
14
20
  /**
15
21
  * @see https://www.notion.so/codecademy/GDPR-Compliance-141ebcc7ffa542daa0da56e35f482b41
16
22
  */
23
+
17
24
  export var mapDestinations = function mapDestinations(_ref) {
18
25
  var _ref$consentDecision = _ref.consentDecision,
19
- consentDecision = _ref$consentDecision === void 0 ? [Consent.StrictlyNecessary] : _ref$consentDecision,
20
- destinations = _ref.destinations;
26
+ consentDecision = _ref$consentDecision === void 0 ? [Consent.StrictlyNecessary] : _ref$consentDecision,
27
+ destinations = _ref.destinations;
21
28
  var destinationPreferences = Object.assign.apply(Object, [{
22
29
  'Segment.io': consentDecision.includes(Consent.Functional)
23
30
  }].concat(_toConsumableArray(destinations.map(function (dest) {
24
31
  if (targetingCategories.includes(dest.category)) {
25
32
  return _defineProperty({}, dest.id, consentDecision.includes(Consent.Targeting));
26
33
  }
34
+
27
35
  if (performanceCategories.includes(dest.category)) {
28
36
  return _defineProperty({}, dest.id, consentDecision.includes(Consent.Performance));
29
37
  }
38
+
30
39
  if (functionalCategories.includes(dest.category)) {
31
40
  return _defineProperty({}, dest.id, consentDecision.includes(Consent.Functional));
32
41
  }
42
+
33
43
  return _defineProperty({}, dest.id, true);
34
44
  }))));
35
45
  var identifyPreferences = {
@@ -1,6 +1,9 @@
1
1
  import _regeneratorRuntime from "@babel/runtime/regenerator";
2
+
2
3
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
4
+
3
5
  function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
6
+
4
7
  export var initializeOneTrust = /*#__PURE__*/function () {
5
8
  var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref) {
6
9
  var production, scope, script, style;
@@ -21,6 +24,7 @@ export var initializeOneTrust = /*#__PURE__*/function () {
21
24
  return _context.abrupt("return", new Promise(function (resolve) {
22
25
  scope.OptanonWrapper = function () {
23
26
  var _scope$dataLayer, _script$parentNode;
27
+
24
28
  (_scope$dataLayer = scope.dataLayer) !== null && _scope$dataLayer !== void 0 ? _scope$dataLayer : scope.dataLayer = [];
25
29
  scope.dataLayer.push({
26
30
  event: 'OneTrustGroupsUpdated'
@@ -29,6 +33,7 @@ export var initializeOneTrust = /*#__PURE__*/function () {
29
33
  (_script$parentNode = script.parentNode) === null || _script$parentNode === void 0 ? void 0 : _script$parentNode.removeChild(script);
30
34
  };
31
35
  }));
36
+
32
37
  case 11:
33
38
  case "end":
34
39
  return _context.stop();
@@ -36,11 +41,11 @@ export var initializeOneTrust = /*#__PURE__*/function () {
36
41
  }
37
42
  }, _callee);
38
43
  }));
44
+
39
45
  return function initializeOneTrust(_x) {
40
46
  return _ref2.apply(this, arguments);
41
47
  };
42
- }();
43
-
44
- // For now, these three values duplicate theme colors from gamut-styles
48
+ }(); // For now, these three values duplicate theme colors from gamut-styles
45
49
  // We don't want to take a full dependency on that package here...
50
+
46
51
  var rawStyles = "\n:root {\n --onetrust-brand-purple: #3A10E5;\n --onetrust-color-gray-500: #828285;\n --onetrust-color-white: #fff;\n}\n\n#onetrust-banner-sdk {\n padding: 1rem !important;\n}\n#onetrust-banner-sdk > .ot-sdk-container {\n width: 100% !important;\n}\n#onetrust-banner-sdk > .ot-sdk-container > .ot-sdk-row {\n display: flex !important;\n flex-direction: column !important;\n align-items: center !important;\n max-width: 1436px !important;\n margin: 0 auto !important;\n}\n#onetrust-banner-sdk > .ot-sdk-container > .ot-sdk-row:after {\n content: none !important;\n}\n#onetrust-group-container {\n display: flex !important;\n justify-content: center;\n float: none !important;\n width: 100% !important;\n max-width: 1148px !important;\n margin-left: 0 !important;\n margin-bottom: 0.625rem !important;\n}\n#onetrust-policy,\n#onetrust-policy-text {\n margin: 0 !important;\n font-size: 0.875rem !important;\n line-height: 1.375rem !important;\n text-align: center !important;\n float: none !important;\n}\n#onetrust-policy-text a {\n text-decoration: none;\n line-height: 26px !important;\n margin-left: 0 !important;\n}\n#onetrust-button-group-parent {\n position: relative !important;\n top: initial !important;\n left: initial !important;\n transform: initial !important;\n width: 264px !important;\n margin: 0 !important;\n padding: 0 !important;\n float: none !important;\n}\n#onetrust-button-group {\n display: flex !important;\n margin: 0 !important;\n}\n#onetrust-pc-btn-handler, #onetrust-accept-btn-handler {\n min-width: initial !important;\n padding: 0.375rem 1rem !important;\n margin: 0 !important;\n opacity: 1 !important;\n border-radius: 2px !important;\n line-height: 1.5 !important;\n user-select: none !important;\n font-size: 1rem !important;\n}\n#onetrust-pc-btn-handler:focus, #onetrust-accept-btn-handler:focus {\n box-shadow: 0 0 0 2px var(--onetrust-color-white), 0 0 0 4px var(--onetrust-brand-purple);\n text-decoration: none !important;\n outline: none !important;\n}\n#onetrust-pc-btn-handler{\n color: var(--onetrust-brand-purple) !important;\n border: 1px solid var(--onetrust-brand-purple)!important;\n background: var(--onetrust-color-white) !important\n}\n#onetrust-accept-btn-handler {\n color: var(--onetrust-color-white) !important;\n background: var(--onetrust-brand-purple)!important;\n margin-left: 1rem !important;\n}\n#onetrust-close-btn-container {\n display: none !important;\n}\n\n.pc-logo {\n display: none !important;\n}\n\n#accept-recommended-btn-handler,\n.ot-pc-refuse-all-handler,\n.save-preference-btn-handler {\n margin-left: 4px !important;\n font-size: 14px !important;\n}\n\n#accept-recommended-btn-handler:focus,\n#onetrust-pc-sdk .ot-pc-refuse-all-handler:focus,\n#onetrust-pc-sdk .save-preference-btn-handler:focus {\n box-shadow: 0 0 0 2px var(--onetrust-color-white), 0 0 0 4px var(--onetrust-brand-purple);\n text-decoration: none !important;\n outline: none !important;\n opacity: 1 !important;\n}\n\n.ot-switch-label {\n border: 1px solid var(--onetrust-color-gray-500) !important;\n background-color: var(--onetrust-color-gray-500) !important;\n}\n\n.ot-switch-nob {\n background: var(--onetrust-color-white) !important;\n}\n\n.ot-switch-inner:before {\n background-color: var(--onetrust-brand-purple) !important;\n}\n\n.switch-checkbox:checked+.ot-switch-label .ot-switch-nob {\n border-color: var(--onetrust-brand-purple) !important;\n}\n\n.ot-pc-footer-logo {\n display: none !important;\n}\n\n#onetrust-banner-sdk>.ot-sdk-container {\n overflow: visible !important;\n}\n\n@media (max-width: 30rem) {\n #accept-recommended-btn-handler,\n .ot-pc-refuse-all-handler,\n .save-preference-btn-handler {\n width: 96% !important;\n }\n}\n\n@media (min-width: 37.5rem) {\n #onetrust-banner-sdk {\n padding: 0.875rem 1rem !important;\n }\n}\n@media (min-width: 48rem) {\n #onetrust-banner-sdk {\n padding: 0.875rem 1.25rem !important;\n }\n}\n@media (min-width: 1650px) {\n #onetrust-banner-sdk > .ot-sdk-container > .ot-sdk-row {\n flex-direction: row !important;\n justify-content: space-between !important;\n }\n #onetrust-group-container {\n margin-bottom: 0 !important;\n }\n #onetrust-button-group {\n flex-direction: row !important;\n }\n}\n";
@@ -2,6 +2,7 @@ import { Consent } from './consent';
2
2
  export interface UserIntegrationSummary {
3
3
  email: string;
4
4
  id: string;
5
+ opted_out_external_tracking: boolean;
5
6
  }
6
7
  export interface SegmentAnalytics {
7
8
  identify(id: string, details: Record<string, string>, options: SegmentAnalyticsOptions): void;
@@ -1 +0,0 @@
1
- export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@codecademy/tracking",
3
3
  "description": "Tracking library for Codecademy apps.",
4
- "version": "0.25.1-alpha.042681.0",
4
+ "version": "0.25.1-alpha.5b36ce.0",
5
5
  "author": "Codecademy Engineering <dev@codecademy.com>",
6
6
  "module": "./dist/index.js",
7
7
  "main": "./dist/index.js",
@@ -16,7 +16,7 @@
16
16
  "@babel/cli": "^7.13.10",
17
17
  "@types/fetch-mock": "^7.3.3",
18
18
  "@types/jest": "^26.0.15",
19
- "babel-preset-codecademy": "6.0.1-alpha.042681.0",
19
+ "babel-preset-codecademy": "^6.0.0",
20
20
  "fetch-mock": "^9.11.0",
21
21
  "jest-fetch-mock": "^3.0.3",
22
22
  "ts-jest": "^26.4.1",
@@ -35,5 +35,5 @@
35
35
  "publishConfig": {
36
36
  "access": "public"
37
37
  },
38
- "gitHead": "a8c6b1ac467efb23d472d456a9779cb84c42eb18"
38
+ "gitHead": "29503baa2905555fad928184d58a78776afdad0c"
39
39
  }