@chordcommerce/analytics 1.17.1 → 1.18.1

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 (51) hide show
  1. package/README.md +8 -0
  2. package/dist/cjs/client/cdp.d.ts +3 -0
  3. package/dist/cjs/client/cdp.js +123 -0
  4. package/dist/cjs/client/consent/index.d.ts +11 -0
  5. package/dist/cjs/client/consent/index.js +241 -0
  6. package/dist/cjs/client/consent/ketch.d.ts +16 -0
  7. package/dist/cjs/client/consent/ketch.js +53 -0
  8. package/dist/cjs/client/consent/onetrust.d.ts +22 -0
  9. package/dist/cjs/client/consent/onetrust.js +85 -0
  10. package/dist/cjs/client/consent/segment.d.ts +17 -0
  11. package/dist/cjs/client/consent/segment.js +155 -0
  12. package/dist/cjs/client/consent/shopify.d.ts +21 -0
  13. package/dist/cjs/client/consent/shopify.js +51 -0
  14. package/dist/cjs/client/index.d.ts +111 -0
  15. package/dist/cjs/client/index.js +861 -0
  16. package/dist/cjs/client/utils.d.ts +1 -0
  17. package/dist/cjs/client/utils.js +12 -0
  18. package/dist/cjs/index.d.ts +2 -0
  19. package/dist/cjs/index.js +18 -0
  20. package/dist/cjs/setupTests.d.ts +1 -0
  21. package/dist/cjs/setupTests.js +6 -0
  22. package/dist/cjs/types/client.d.ts +96 -0
  23. package/dist/cjs/types/client.js +2 -0
  24. package/dist/cjs/types/consent.d.ts +11 -0
  25. package/dist/cjs/types/consent.js +2 -0
  26. package/dist/cjs/types/formatters.d.ts +114 -0
  27. package/dist/cjs/types/formatters.js +2 -0
  28. package/dist/cjs/types/index.d.ts +7 -0
  29. package/dist/cjs/types/index.js +22 -0
  30. package/dist/cjs/types/input.d.ts +396 -0
  31. package/dist/cjs/types/input.js +2 -0
  32. package/dist/cjs/types/objects.d.ts +379 -0
  33. package/dist/cjs/types/objects.js +2 -0
  34. package/dist/cjs/types/typewriter.d.ts +6502 -0
  35. package/dist/cjs/types/typewriter.js +5 -0
  36. package/dist/cjs/utils.d.ts +2 -0
  37. package/dist/cjs/utils.js +25 -0
  38. package/dist/cjs/validators/custom.d.ts +43 -0
  39. package/dist/cjs/validators/custom.js +18 -0
  40. package/dist/cjs/validators/index.d.ts +4 -0
  41. package/dist/cjs/validators/index.js +20 -0
  42. package/dist/cjs/validators/objects.d.ts +696 -0
  43. package/dist/cjs/validators/objects.js +128 -0
  44. package/dist/cjs/validators/tracking-plan-map.d.ts +6603 -0
  45. package/dist/cjs/validators/tracking-plan-map.js +72 -0
  46. package/dist/cjs/validators/tracking-plan.d.ts +9275 -0
  47. package/dist/cjs/validators/tracking-plan.js +1682 -0
  48. package/dist/client/consent/index.js +1 -1
  49. package/dist/client/consent/onetrust.d.ts +2 -2
  50. package/dist/client/consent/onetrust.js +30 -6
  51. package/package.json +4 -2
package/README.md CHANGED
@@ -30,6 +30,14 @@ const chord = new ChordAnalytics(options) // see below for configuration options
30
30
  chord.trackCartViewed({ cart }) // sends a "Cart Viewed" event to the CDP
31
31
  ```
32
32
 
33
+ ### CommonJS Import
34
+
35
+ If you are using an older version of NodeJS (<v11) or Webpack, importing using the above ES6 import will probably fail. You can instead import using CommonJS:
36
+
37
+ ```jsx
38
+ const { ChordPixel } = require('@chordcommerce/analytics/dist/cjs')
39
+ ```
40
+
33
41
  ## Configuration
34
42
 
35
43
  `@chordcommerce/analytics` can be initialized with the following options:
@@ -0,0 +1,3 @@
1
+ import type { ChordAnalyticsOptions, ChordAnalyticsQueue } from '../types/index.js';
2
+ export declare const addCdpSnippet: (options: ChordAnalyticsOptions) => Promise<void>;
3
+ export declare const cdpQueue: (namespace: string) => ChordAnalyticsQueue;
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.cdpQueue = exports.addCdpSnippet = void 0;
40
+ var index_js_1 = require("./consent/index.js");
41
+ var utils_js_1 = require("./utils.js");
42
+ /*
43
+ * Adds the Chord CDP snippet to the page.
44
+ */
45
+ var addCdpSnippet = function (options) { return __awaiter(void 0, void 0, void 0, function () {
46
+ var normalizedCDPDomain, cdpReadyPromise, s;
47
+ return __generator(this, function (_a) {
48
+ switch (_a.label) {
49
+ case 0:
50
+ if (!document || typeof document.createElement === 'undefined')
51
+ return [2 /*return*/];
52
+ normalizedCDPDomain = (0, utils_js_1.normalizeCDPDomain)(options.cdpDomain);
53
+ cdpReadyPromise = new Promise(function (resolve) {
54
+ var checkCdpReady = function () {
55
+ var cdp = window["_".concat(options.namespace)];
56
+ if (cdp && typeof cdp.configure === 'function') {
57
+ resolve();
58
+ }
59
+ else {
60
+ setTimeout(checkCdpReady, 50);
61
+ }
62
+ };
63
+ checkCdpReady();
64
+ });
65
+ s = document.createElement('script');
66
+ s.async = true;
67
+ s.src = "".concat(normalizedCDPDomain, "/p.js");
68
+ s.setAttribute('data-debug', "".concat(!!options.debug));
69
+ s.setAttribute('data-init-only', 'true');
70
+ s.setAttribute('data-namespace', "_".concat(options.namespace));
71
+ s.setAttribute('data-write-key', options.cdpWriteKey);
72
+ document.head.appendChild(s);
73
+ // Wait for CDP to be ready before setting up consent
74
+ return [4 /*yield*/, cdpReadyPromise];
75
+ case 1:
76
+ // Wait for CDP to be ready before setting up consent
77
+ _a.sent();
78
+ if (options.consent) {
79
+ (0, index_js_1.addCdpConsent)(options).init();
80
+ }
81
+ return [2 /*return*/];
82
+ }
83
+ });
84
+ }); };
85
+ exports.addCdpSnippet = addCdpSnippet;
86
+ /*
87
+ * Returns the CDP queue to hold events ahead of CDP initialization.
88
+ */
89
+ var cdpQueue = function (namespace) {
90
+ var _a;
91
+ var q = window && (window[_a = "_".concat(namespace, "Q")] || (window[_a] = []));
92
+ return {
93
+ track: function () {
94
+ var args = [];
95
+ for (var _i = 0; _i < arguments.length; _i++) {
96
+ args[_i] = arguments[_i];
97
+ }
98
+ return q.push(function (cdp) { return cdp.track.apply(cdp, args); });
99
+ },
100
+ identify: function () {
101
+ var args = [];
102
+ for (var _i = 0; _i < arguments.length; _i++) {
103
+ args[_i] = arguments[_i];
104
+ }
105
+ return q.push(function (cdp) { return cdp.identify.apply(cdp, args); });
106
+ },
107
+ page: function () {
108
+ var args = [];
109
+ for (var _i = 0; _i < arguments.length; _i++) {
110
+ args[_i] = arguments[_i];
111
+ }
112
+ return q.push(function (cdp) { return cdp.page.apply(cdp, args); });
113
+ },
114
+ reset: function () {
115
+ var args = [];
116
+ for (var _i = 0; _i < arguments.length; _i++) {
117
+ args[_i] = arguments[_i];
118
+ }
119
+ return q.push(function (cdp) { return cdp.reset.apply(cdp, args); });
120
+ },
121
+ };
122
+ };
123
+ exports.cdpQueue = cdpQueue;
@@ -0,0 +1,11 @@
1
+ import type { ChordAnalyticsOptions, ConsentConfiguration } from '../../types/index.js';
2
+ declare global {
3
+ interface Window {
4
+ jitsuConfig: {
5
+ privacy: ConsentConfiguration;
6
+ };
7
+ }
8
+ }
9
+ export declare const addCdpConsent: (options: ChordAnalyticsOptions) => {
10
+ init: () => Promise<boolean>;
11
+ };
@@ -0,0 +1,241 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.addCdpConsent = void 0;
40
+ var ketch_js_1 = require("./ketch.js");
41
+ var onetrust_js_1 = require("./onetrust.js");
42
+ var shopify_js_1 = require("./shopify.js");
43
+ var segment_js_1 = require("./segment.js");
44
+ var addCdpConsent = function (options) {
45
+ var adapter = null;
46
+ var lastProcessedConsent = null;
47
+ var POLLING_INTERVAL_MS = 50;
48
+ var TIMEOUT_MS = options.awaitConsentTimeout
49
+ ? options.awaitConsentTimeout
50
+ : 60000;
51
+ /**
52
+ * Returns the adapter for the specified consent management platform.
53
+ */
54
+ var getAdapter = function () {
55
+ var _a;
56
+ switch ((_a = options.consent) === null || _a === void 0 ? void 0 : _a.toLowerCase()) {
57
+ case 'ketch':
58
+ return (0, ketch_js_1.ketchConsentAdapter)();
59
+ case 'onetrust':
60
+ return (0, onetrust_js_1.onetrustConsentAdapter)(options);
61
+ case 'shopify':
62
+ return (0, shopify_js_1.shopifyConsentAdapter)();
63
+ case 'segment':
64
+ return (0, segment_js_1.segmentConsentAdapter)();
65
+ default:
66
+ return null;
67
+ }
68
+ };
69
+ /**
70
+ * Polls if user can be tracked based on consent
71
+ * @returns Promise that resolves to true if condition is met within timeout, false otherwise
72
+ */
73
+ var checkUserCanBeTracked = function () { return __awaiter(void 0, void 0, void 0, function () {
74
+ return __generator(this, function (_a) {
75
+ return [2 /*return*/, new Promise(function (resolve) {
76
+ // Checking immediately first
77
+ if (adapter === null || adapter === void 0 ? void 0 : adapter.userCanBeTracked()) {
78
+ resolve(true);
79
+ return;
80
+ }
81
+ var interval = setInterval(function () {
82
+ if (adapter === null || adapter === void 0 ? void 0 : adapter.userCanBeTracked()) {
83
+ clearInterval(interval);
84
+ resolve(true);
85
+ }
86
+ }, POLLING_INTERVAL_MS);
87
+ setTimeout(function () {
88
+ clearInterval(interval);
89
+ resolve(false);
90
+ }, TIMEOUT_MS);
91
+ })];
92
+ });
93
+ }); };
94
+ /**
95
+ * Attempts to configure CDP with retry logic.
96
+ */
97
+ var configureCdpWithRetry = function (updatedConsent, maxRetries, baseDelay) {
98
+ if (maxRetries === void 0) { maxRetries = 5; }
99
+ if (baseDelay === void 0) { baseDelay = 100; }
100
+ return __awaiter(void 0, void 0, void 0, function () {
101
+ var attempt, tryConfigure;
102
+ return __generator(this, function (_a) {
103
+ attempt = 0;
104
+ tryConfigure = function () { return __awaiter(void 0, void 0, void 0, function () {
105
+ var cdp, delay_1;
106
+ return __generator(this, function (_a) {
107
+ switch (_a.label) {
108
+ case 0:
109
+ cdp = window["_".concat(options.namespace)];
110
+ if (cdp && typeof cdp.configure === 'function') {
111
+ try {
112
+ if (Object.keys(updatedConsent).length > 0) {
113
+ cdp.configure({ privacy: updatedConsent });
114
+ }
115
+ return [2 /*return*/, true];
116
+ }
117
+ catch (error) {
118
+ // Continue to retry on error
119
+ }
120
+ }
121
+ if (!(attempt < maxRetries)) return [3 /*break*/, 2];
122
+ delay_1 = baseDelay * Math.pow(2, attempt) // Exponential backoff
123
+ ;
124
+ return [4 /*yield*/, new Promise(function (resolve) {
125
+ setTimeout(resolve, delay_1);
126
+ })];
127
+ case 1:
128
+ _a.sent();
129
+ attempt++;
130
+ return [2 /*return*/, tryConfigure()];
131
+ case 2:
132
+ console.warn('CDP configuration failed after all retries, falling back to jitsuConfig');
133
+ return [2 /*return*/, false];
134
+ }
135
+ });
136
+ }); };
137
+ return [2 /*return*/, tryConfigure()];
138
+ });
139
+ });
140
+ };
141
+ /**
142
+ * Updates consent for all future events.
143
+ */
144
+ var updateCdpConsent = function (updatedConsent) { return __awaiter(void 0, void 0, void 0, function () {
145
+ var chordAnalytics, shouldTrackConsentUpdate, cdpConfigured;
146
+ return __generator(this, function (_a) {
147
+ switch (_a.label) {
148
+ case 0:
149
+ if (lastProcessedConsent &&
150
+ JSON.stringify(lastProcessedConsent) === JSON.stringify(updatedConsent)) {
151
+ return [2 /*return*/];
152
+ }
153
+ lastProcessedConsent = updatedConsent;
154
+ chordAnalytics = window[options.namespace];
155
+ shouldTrackConsentUpdate = chordAnalytics &&
156
+ typeof chordAnalytics.track === 'function' &&
157
+ updatedConsent.consentCategories !== undefined;
158
+ if (!(shouldTrackConsentUpdate &&
159
+ // we have to send this BEFORE the CDP is reconfigured or else the track will not be sent, usually in the case of a user opting out
160
+ updatedConsent.dontSend === true)) return [3 /*break*/, 2];
161
+ return [4 /*yield*/, chordAnalytics.track('Consent Preferences Updated', updatedConsent)];
162
+ case 1:
163
+ _a.sent();
164
+ _a.label = 2;
165
+ case 2: return [4 /*yield*/, configureCdpWithRetry(updatedConsent)];
166
+ case 3:
167
+ cdpConfigured = _a.sent();
168
+ if (!cdpConfigured) {
169
+ // CDP has not yet loaded via the snippet or all retries failed.
170
+ window.jitsuConfig = { privacy: updatedConsent };
171
+ }
172
+ if (!(shouldTrackConsentUpdate &&
173
+ // we have to send this AFTER the CDP is reconfigured to ensure the track is sent, usually in the case of a user opting in
174
+ updatedConsent.dontSend === false)) return [3 /*break*/, 5];
175
+ return [4 /*yield*/, chordAnalytics.track('Consent Preferences Updated', updatedConsent)];
176
+ case 4:
177
+ _a.sent();
178
+ _a.label = 5;
179
+ case 5: return [2 /*return*/];
180
+ }
181
+ });
182
+ }); };
183
+ /**
184
+ * Sets up consent management by initializing the adapter and handling consent updates.
185
+ */
186
+ var setupConsentManagement = function () { return __awaiter(void 0, void 0, void 0, function () {
187
+ var initialConsent;
188
+ return __generator(this, function (_a) {
189
+ switch (_a.label) {
190
+ case 0:
191
+ if (!adapter)
192
+ return [2 /*return*/];
193
+ // Set up the consent update handler first to catch any immediate updates
194
+ adapter.handleConsentUpdates(function (updatedConsent) {
195
+ updateCdpConsent(updatedConsent);
196
+ });
197
+ return [4 /*yield*/, adapter.getCurrentConsent()];
198
+ case 1:
199
+ initialConsent = _a.sent();
200
+ return [4 /*yield*/, updateCdpConsent(initialConsent)];
201
+ case 2:
202
+ _a.sent();
203
+ return [2 /*return*/];
204
+ }
205
+ });
206
+ }); };
207
+ /**
208
+ * Initializes consent management.
209
+ * Returns a promise that resolves to true if CDP should be loaded, false otherwise.
210
+ */
211
+ var init = function () { return __awaiter(void 0, void 0, void 0, function () {
212
+ var canBeTracked;
213
+ return __generator(this, function (_a) {
214
+ switch (_a.label) {
215
+ case 0:
216
+ adapter = getAdapter();
217
+ if (adapter === null) {
218
+ console.error("Consent management adapter \"".concat(options.consent, "\" is not supported."));
219
+ return [2 /*return*/, false];
220
+ }
221
+ if (!options.awaitConsent) return [3 /*break*/, 2];
222
+ return [4 /*yield*/, checkUserCanBeTracked()];
223
+ case 1:
224
+ canBeTracked = _a.sent();
225
+ if (!canBeTracked)
226
+ return [2 /*return*/, false];
227
+ _a.label = 2;
228
+ case 2:
229
+ // Set up consent management in the background
230
+ setupConsentManagement().catch(function (error) {
231
+ console.error('Error setting up consent management:', error);
232
+ });
233
+ return [2 /*return*/, true];
234
+ }
235
+ });
236
+ }); };
237
+ return {
238
+ init: init,
239
+ };
240
+ };
241
+ exports.addCdpConsent = addCdpConsent;
@@ -0,0 +1,16 @@
1
+ import type { ConsentConfiguration } from '../../types/index.js';
2
+ declare global {
3
+ interface Window {
4
+ ketch?: (action: string, eventName: string, handler: () => void) => undefined;
5
+ ketchConsent?: KetchConsentCategories;
6
+ }
7
+ }
8
+ interface KetchConsentCategories {
9
+ [key: string]: boolean;
10
+ }
11
+ export declare const ketchConsentAdapter: () => {
12
+ getCurrentConsent: () => ConsentConfiguration;
13
+ handleConsentUpdates: (updateCdpConsent: (consent: ConsentConfiguration) => void) => void;
14
+ userCanBeTracked: () => boolean;
15
+ };
16
+ export {};
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.ketchConsentAdapter = void 0;
15
+ /**
16
+ * Returns Ketch's consent categories.
17
+ */
18
+ var getApi = function () { return window.ketch && window.ketchConsent; };
19
+ /**
20
+ * Returns whether the user can currently be tracked.
21
+ */
22
+ var userCanBeTracked = function () {
23
+ var api = getApi();
24
+ return !!api && !!Object.keys(api).length;
25
+ };
26
+ /**
27
+ * Returns the user's current consent configuration.
28
+ */
29
+ var getCurrentConsent = function () {
30
+ var api = getApi();
31
+ if (!api)
32
+ return {};
33
+ return {
34
+ consentCategories: __assign({}, api),
35
+ dontSend: !userCanBeTracked(),
36
+ };
37
+ };
38
+ /**
39
+ * Handles subsequent changes to consent configuration.
40
+ */
41
+ var handleConsentUpdates = function (updateCdpConsent) {
42
+ window.ketch('addListener', 'consent', function () {
43
+ updateCdpConsent(getCurrentConsent());
44
+ });
45
+ };
46
+ var ketchConsentAdapter = function () {
47
+ return {
48
+ getCurrentConsent: getCurrentConsent,
49
+ handleConsentUpdates: handleConsentUpdates,
50
+ userCanBeTracked: userCanBeTracked,
51
+ };
52
+ };
53
+ exports.ketchConsentAdapter = ketchConsentAdapter;
@@ -0,0 +1,22 @@
1
+ import type { ChordAnalyticsOptions, ConsentConfiguration } from '../../types/index.js';
2
+ declare global {
3
+ interface Window {
4
+ OneTrust?: OneTrustApi;
5
+ OnetrustActiveGroups?: string;
6
+ }
7
+ }
8
+ interface OneTrustApi {
9
+ OnConsentChanged: (callback: () => void) => void;
10
+ GetDomainData: () => {
11
+ Groups: OneTrustGroup[];
12
+ };
13
+ }
14
+ interface OneTrustGroup {
15
+ CustomGroupId: string;
16
+ }
17
+ export declare const onetrustConsentAdapter: (options: ChordAnalyticsOptions) => {
18
+ getCurrentConsent: () => ConsentConfiguration;
19
+ handleConsentUpdates: (updateCdpConsent: (consent: ConsentConfiguration) => void) => void;
20
+ userCanBeTracked: () => boolean;
21
+ };
22
+ export {};
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.onetrustConsentAdapter = void 0;
4
+ /**
5
+ * Returns OneTrust's API.
6
+ */
7
+ var getApi = function () {
8
+ var oneTrust = window.OneTrust;
9
+ if (oneTrust &&
10
+ typeof oneTrust === 'object' &&
11
+ 'OnConsentChanged' in oneTrust &&
12
+ 'GetDomainData' in oneTrust) {
13
+ return oneTrust;
14
+ }
15
+ return undefined;
16
+ };
17
+ /**
18
+ * Returns whether the user can currently be tracked.
19
+ */
20
+ var userCanBeTracked = function () {
21
+ // Always loads, a la `consentModel: 'opt-out'` in the Segment wrapper.
22
+ var api = getApi();
23
+ return !!api;
24
+ };
25
+ /**
26
+ * Returns the user's current consent configuration.
27
+ */
28
+ var getCurrentConsent = function () {
29
+ var api = getApi();
30
+ var activeGroups = window.OnetrustActiveGroups;
31
+ if (!api || !activeGroups || typeof activeGroups !== 'string')
32
+ return {};
33
+ var activeGroupIds = new Set(activeGroups.trim().split(',').filter(Boolean));
34
+ return {
35
+ consentCategories: api
36
+ .GetDomainData()
37
+ .Groups.reduce(function (acc, _a) {
38
+ var CustomGroupId = _a.CustomGroupId;
39
+ var groupId = CustomGroupId.trim();
40
+ acc[groupId] = activeGroupIds.has(groupId);
41
+ return acc;
42
+ }, {}),
43
+ dontSend: !userCanBeTracked(),
44
+ };
45
+ };
46
+ /**
47
+ * Handles subsequent changes to consent configuration.
48
+ */
49
+ var handleConsentUpdates = function (updateCdpConsent, options) {
50
+ var maxRetries = 100;
51
+ var retryInterval = 50;
52
+ var attempts = 0;
53
+ var setupHandler = function () {
54
+ var api = getApi();
55
+ if (!api) {
56
+ attempts++;
57
+ if (attempts < maxRetries) {
58
+ if (options.debug && options.enableLogging) {
59
+ // eslint-disable-next-line no-console
60
+ console.log('OneTrust API not found, retrying...');
61
+ }
62
+ setTimeout(setupHandler, retryInterval);
63
+ }
64
+ return;
65
+ }
66
+ if (options.debug && options.enableLogging) {
67
+ // eslint-disable-next-line no-console
68
+ console.log('OneTrust API found, setting up consent changed handler');
69
+ }
70
+ api.OnConsentChanged(function () {
71
+ updateCdpConsent(getCurrentConsent());
72
+ });
73
+ };
74
+ setupHandler();
75
+ };
76
+ var onetrustConsentAdapter = function (options) {
77
+ return {
78
+ getCurrentConsent: getCurrentConsent,
79
+ handleConsentUpdates: function (updateCdpConsent) {
80
+ handleConsentUpdates(updateCdpConsent, options);
81
+ },
82
+ userCanBeTracked: userCanBeTracked,
83
+ };
84
+ };
85
+ exports.onetrustConsentAdapter = onetrustConsentAdapter;
@@ -0,0 +1,17 @@
1
+ import type { ConsentConfiguration } from '../../types/index.js';
2
+ declare global {
3
+ interface Window {
4
+ segmentConsent?: SegmentConsentCategories;
5
+ }
6
+ }
7
+ interface SegmentConsentCategories {
8
+ [key: string]: {
9
+ [key: string]: boolean;
10
+ };
11
+ }
12
+ export declare const segmentConsentAdapter: () => {
13
+ getCurrentConsent: () => Promise<ConsentConfiguration>;
14
+ handleConsentUpdates: (updateCdpConsent: (consent: ConsentConfiguration) => void) => void;
15
+ userCanBeTracked: () => Promise<boolean>;
16
+ };
17
+ export {};