@financial-times/cmp-client 3.2.0 → 3.3.0-beta.5

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 (50) hide show
  1. package/README.md +17 -2
  2. package/dist/cmp-static.js +660 -0
  3. package/dist/index.cjs +205 -2761
  4. package/dist/index.js +205 -2761
  5. package/dist/src/client.d.ts.map +1 -1
  6. package/dist/src/cmp-static.d.ts +2 -0
  7. package/dist/src/cmp-static.d.ts.map +1 -0
  8. package/dist/src/consent-ready/index.d.ts.map +1 -1
  9. package/dist/src/consent-ready/utils/__fixtures__/helpers.d.ts +27 -0
  10. package/dist/src/consent-ready/utils/__fixtures__/helpers.d.ts.map +1 -0
  11. package/dist/src/consent-ready/utils/__fixtures__/strings.d.ts +4 -8
  12. package/dist/src/consent-ready/utils/__fixtures__/strings.d.ts.map +1 -1
  13. package/dist/src/consent-ready/utils/__tests__/consent.test.d.ts +2 -0
  14. package/dist/src/consent-ready/utils/__tests__/consent.test.d.ts.map +1 -0
  15. package/dist/src/consent-ready/utils/consent.d.ts +6 -0
  16. package/dist/src/consent-ready/utils/consent.d.ts.map +1 -0
  17. package/dist/src/consent-ready/utils/get-consent-payload.d.ts +7 -7
  18. package/dist/src/consent-ready/utils/get-consent-payload.d.ts.map +1 -1
  19. package/dist/src/consent-ready/utils/get-parsed-consent.d.ts +6 -5
  20. package/dist/src/consent-ready/utils/get-parsed-consent.d.ts.map +1 -1
  21. package/dist/src/consent-ready/utils/validators.d.ts +0 -1
  22. package/dist/src/consent-ready/utils/validators.d.ts.map +1 -1
  23. package/dist/src/html/cmp-footer-link.d.ts +8 -4
  24. package/dist/src/html/cmp-footer-link.d.ts.map +1 -1
  25. package/dist/src/html/cmp-scripts.d.ts.map +1 -1
  26. package/dist/src/index.d.ts +1 -1
  27. package/dist/src/index.d.ts.map +1 -1
  28. package/dist/src/lib/constants.d.ts +33 -2
  29. package/dist/src/lib/constants.d.ts.map +1 -1
  30. package/dist/src/lib/properties.d.ts +36 -0
  31. package/dist/src/lib/properties.d.ts.map +1 -1
  32. package/dist/src/tracking/index.d.ts +1 -1
  33. package/dist/src/tracking/index.d.ts.map +1 -1
  34. package/dist/src/tracking/state.d.ts +6 -0
  35. package/dist/src/tracking/state.d.ts.map +1 -1
  36. package/dist/src/utils/__tests__/url.test.d.ts +2 -0
  37. package/dist/src/utils/__tests__/url.test.d.ts.map +1 -0
  38. package/dist/src/utils/url.d.ts +126 -0
  39. package/dist/src/utils/url.d.ts.map +1 -0
  40. package/package.json +11 -11
  41. package/typings/globals.d.ts +4 -0
  42. package/typings/types.d.ts +54 -4
  43. package/dist/src/consent-ready/utils/has-consent-changed.d.ts +0 -3
  44. package/dist/src/consent-ready/utils/has-consent-changed.d.ts.map +0 -1
  45. package/dist/src/html/__tests__/cmp-footer-links.test.d.ts +0 -2
  46. package/dist/src/html/__tests__/cmp-footer-links.test.d.ts.map +0 -1
  47. package/dist/src/lib/enableNonEssentialCookiesOption.d.ts +0 -2
  48. package/dist/src/lib/enableNonEssentialCookiesOption.d.ts.map +0 -1
  49. package/dist/src/utils/cookie.d.ts +0 -2
  50. package/dist/src/utils/cookie.d.ts.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,13 +1,5 @@
1
1
  "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
- var __publicField = (obj, key, value) => {
5
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
6
- return value;
7
- };
8
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
9
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
10
- const version = "3.2.0";
11
3
  const events = {
12
4
  onMessageChoiceSelect: (...args) => {
13
5
  console.log("[debug] onMessageChoiceSelect", args);
@@ -31,8 +23,8 @@ const events = {
31
23
  console.log("[debug] onSPPMObjectReady", args);
32
24
  },
33
25
  onConsentReady: async (...args) => {
34
- const [legislation2, consentUUID, consentString, consentMeta] = args;
35
- console.log("[debug] onConsentReady", { legislation: legislation2, consentString, consentMeta, consentUUID });
26
+ const [legislation, consentUUID, consentString, consentMeta] = args;
27
+ console.log("[debug] onConsentReady", { legislation, consentString, consentMeta, consentUUID });
36
28
  },
37
29
  onError: (...args) => {
38
30
  console.log("[debug] onError", args);
@@ -41,9 +33,9 @@ const events = {
41
33
  function logCmpEvents() {
42
34
  window._sp_queue = window._sp_queue ?? [];
43
35
  window._sp_queue.push(() => {
44
- var _a2, _b2;
36
+ var _a, _b;
45
37
  for (const [eventId, eventHandler] of Object.entries(events)) {
46
- (_b2 = (_a2 = window._sp_).addEventListener) == null ? void 0 : _b2.call(_a2, eventId, eventHandler);
38
+ (_b = (_a = window._sp_).addEventListener) == null ? void 0 : _b.call(_a, eventId, eventHandler);
47
39
  }
48
40
  });
49
41
  }
@@ -61,67 +53,103 @@ const FT_DOTCOM_TEST = {
61
53
  ...defaults,
62
54
  accountId: 1906,
63
55
  baseEndpoint: "https://consent-manager.ft.com",
64
- propertyHref: "https://local.ft.com"
56
+ propertyHref: "https://local.ft.com",
57
+ _clientOptions: {
58
+ privacyManagerId: 827767,
59
+ manageCookiesLinkOverride: "ft.com/preferences/manage-cookies"
60
+ }
65
61
  };
66
62
  const FT_DOTCOM_PROD = {
67
63
  ...defaults,
68
64
  accountId: 1906,
69
65
  baseEndpoint: "https://consent-manager.ft.com",
70
- propertyId: 31642
66
+ propertyId: 31642,
67
+ _clientOptions: {
68
+ privacyManagerId: 827767,
69
+ manageCookiesLinkOverride: "ft.com/preferences/manage-cookies",
70
+ rootDomain: "ft.com"
71
+ }
71
72
  };
72
73
  const SP_PWMNET = {
73
74
  ...defaults,
74
75
  accountId: 1906,
75
76
  baseEndpoint: "https://consent-manager.pwmnet.com",
76
- propertyId: 33414
77
+ propertyId: 33414,
78
+ _clientOptions: {
79
+ rootDomain: "pwmnet.com"
80
+ }
77
81
  };
78
82
  const SP_FDI_INTELLIGENCE = {
79
83
  ...defaults,
80
84
  accountId: 1906,
81
85
  baseEndpoint: "https://consent-manager.fdiintelligence.com",
82
- propertyId: 34061
86
+ propertyId: 34061,
87
+ _clientOptions: {
88
+ rootDomain: "fdiintelligence.com"
89
+ }
83
90
  };
84
91
  const SP_THE_BANKER = {
85
92
  ...defaults,
86
93
  accountId: 1906,
87
94
  baseEndpoint: "https://consent-manager.thebanker.com",
88
- propertyId: 34060
95
+ propertyId: 34060,
96
+ _clientOptions: {
97
+ rootDomain: "thebanker.com"
98
+ }
89
99
  };
90
100
  const SP_BANKING_RR = {
91
101
  ...defaults,
92
102
  accountId: 1906,
93
103
  baseEndpoint: "https://consent-manager.bankingriskandregulation.com",
94
- propertyId: 34059
104
+ propertyId: 34059,
105
+ _clientOptions: {
106
+ rootDomain: "bankingriskandregulation.com"
107
+ }
95
108
  };
96
109
  const SP_SUSTAINABLE_VIEWS = {
97
110
  ...defaults,
98
111
  accountId: 1906,
99
112
  baseEndpoint: "https://consent-manager.sustainableviews.com",
100
- propertyId: 34058
113
+ propertyId: 34058,
114
+ _clientOptions: {
115
+ rootDomain: "sustainableviews.com"
116
+ }
101
117
  };
102
118
  const SP_FT_ADVISER = {
103
119
  ...defaults,
104
120
  accountId: 1906,
105
121
  baseEndpoint: "https://consent-manager.ftadviser.com",
106
- propertyId: 33416
122
+ propertyId: 33416,
123
+ _clientOptions: {
124
+ rootDomain: "ftadviser.com"
125
+ }
107
126
  };
108
127
  const SP_INVESTORS_CHRONICLE = {
109
128
  ...defaults,
110
129
  accountId: 1906,
111
130
  baseEndpoint: "https://consent-manager.investorschronicle.co.uk",
112
- propertyId: 33415
131
+ propertyId: 33415,
132
+ _clientOptions: {
133
+ rootDomain: "investorschronicle.co.uk"
134
+ }
113
135
  };
114
136
  const MM_IGNITES_ASIA = {
115
137
  ...defaults,
116
138
  accountId: 1906,
117
139
  baseEndpoint: "https://cdn.privacy-mgmt.com",
118
- propertyId: 33947
140
+ propertyId: 33947,
141
+ _clientOptions: {
142
+ rootDomain: "ignitesasia.com"
143
+ }
119
144
  };
120
145
  const MM_IGNITES_EUROPE = {
121
146
  ...defaults,
122
147
  accountId: 1906,
123
148
  baseEndpoint: "https://cdn.privacy-mgmt.com",
124
- propertyId: 33946
149
+ propertyId: 33946,
150
+ _clientOptions: {
151
+ rootDomain: "igniteseurope.com"
152
+ }
125
153
  };
126
154
  const properties = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
127
155
  __proto__: null,
@@ -137,18 +165,20 @@ const properties = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
137
165
  SP_SUSTAINABLE_VIEWS,
138
166
  SP_THE_BANKER
139
167
  }, Symbol.toStringTag, { value: "Module" }));
140
- function updateFooterLinkCMP() {
141
- const cookieLink = document.querySelector(
142
- "[href='https://www.ft.com/preferences/manage-cookies']"
143
- );
144
- if (cookieLink) {
145
- cookieLink.href = "#";
146
- cookieLink.setAttribute("onclick", "window._sp_.gdpr.loadPrivacyManagerModal(827767);");
147
- cookieLink.dataset.cmpLink = "updated";
148
- return true;
168
+ function updateFooterLinkCMP(propertyConfig = FT_DOTCOM_PROD) {
169
+ const { privacyManagerId, manageCookiesLinkOverride, manageCookiesSelector } = propertyConfig._clientOptions || {};
170
+ const footer = document.querySelector(manageCookiesSelector ?? "#site-footer");
171
+ if (footer && manageCookiesLinkOverride) {
172
+ footer.addEventListener("click", (event) => {
173
+ var _a, _b, _c;
174
+ const link = event.target.closest("a");
175
+ if ((_a = link == null ? void 0 : link.getAttribute("href")) == null ? void 0 : _a.endsWith(manageCookiesLinkOverride)) {
176
+ event.preventDefault();
177
+ (_c = (_b = window._sp_) == null ? void 0 : _b.gdpr) == null ? void 0 : _c.loadPrivacyManagerModal(privacyManagerId);
178
+ }
179
+ });
149
180
  } else {
150
- console.warn("CMP Footer Link was not found and not updated");
151
- return false;
181
+ console.warn("No footer found for", manageCookiesSelector);
152
182
  }
153
183
  }
154
184
  const request = (url, { credentials = "omit" } = {}) => {
@@ -227,10 +257,6 @@ const CONSENT_COOKIE_NAME = "FTConsent";
227
257
  const SOURCEPOINT_FOW_ID = "sourcepointCmp/VngD.XycZut.595cp9fWdp5XYP9vlFvk";
228
258
  const FT_COOKIE_DOMAIN = ".ft.com";
229
259
  const FT_CONSENT_PROXY_HOST = "https://consent.ft.com";
230
- const legislation = {
231
- CCPA: "ccpa",
232
- GDPR: "gdpr"
233
- };
234
260
  const iabCustomCategories = {
235
261
  permutiveAds: {
236
262
  purposes: [2, 4, 8, 9],
@@ -250,6 +276,12 @@ const iabCustomCategories = {
250
276
  customVendors: [],
251
277
  specialFeatures: []
252
278
  },
279
+ programmaticAds: {
280
+ purposes: [2],
281
+ iabVendors: [],
282
+ customVendors: [],
283
+ specialFeatures: []
284
+ },
253
285
  personalisedMarketing: {
254
286
  purposes: [1, 4, 8, 9, 10],
255
287
  iabVendors: [],
@@ -257,6 +289,7 @@ const iabCustomCategories = {
257
289
  specialFeatures: []
258
290
  }
259
291
  };
292
+ const iabCategoryNames = Object.keys(iabCustomCategories);
260
293
  function createContentScript(cmpScript, content) {
261
294
  const s = document.createElement("script");
262
295
  s.dataset.cmpScript = cmpScript;
@@ -272,8 +305,8 @@ const scriptSources = {
272
305
  cmpFrames: "https://consent-manager.ft.com/unified/wrapperMessagingWithoutDetection.js"
273
306
  };
274
307
  const scriptContent = {
275
- tcfStub: `"use strict";function _typeof(t){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}!function(){var t=function(){var t,e,o=[],n=window,r=n;for(;r;){try{if(r.frames.__tcfapiLocator){t=r;break}}catch(t){}if(r===n.top)break;r=r.parent}t||(!function t(){var e=n.document,o=!!n.frames.__tcfapiLocator;if(!o)if(e.body){var r=e.createElement("iframe");r.style.cssText="display:none",r.name="__tcfapiLocator",e.body.appendChild(r)}else setTimeout(t,5);return!o}(),n.__tcfapi=function(){for(var t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];if(!n.length)return o;"setGdprApplies"===n[0]?n.length>3&&2===parseInt(n[1],10)&&"boolean"==typeof n[3]&&(e=n[3],"function"==typeof n[2]&&n[2]("set",!0)):"ping"===n[0]?"function"==typeof n[2]&&n[2]({gdprApplies:e,cmpLoaded:!1,cmpStatus:"stub"}):o.push(n)},n.addEventListener("message",(function(t){var e="string"==typeof t.data,o={};if(e)try{o=JSON.parse(t.data)}catch(t){}else o=t.data;var n="object"===_typeof(o)&&null!==o?o.__tcfapiCall:null;n&&window.__tcfapi(n.command,n.version,(function(o,r){var a={__tcfapiReturn:{returnValue:o,success:r,callId:n.callId}};t&&t.source&&t.source.postMessage&&t.source.postMessage(e?JSON.stringify(a):a,"*")}),n.parameter)}),!1))};"undefined"!=typeof module?module.exports=t:t()}();`,
276
- uspStub: `"use strict";(function () { var e = false; var c = window; var t = document; function r() { if (!c.frames["__uspapiLocator"]) { if (t.body) { var a = t.body; var e = t.createElement("iframe"); e.style.cssText = "display:none"; e.name = "__uspapiLocator"; a.appendChild(e) } else { setTimeout(r, 5) } } } r(); function p() { var a = arguments; __uspapi.a = __uspapi.a || []; if (!a.length) { return __uspapi.a } else if (a[0] === "ping") { a[2]({ gdprAppliesGlobally: e, cmpLoaded: false }, true) } else { __uspapi.a.push([].slice.apply(a)) } } function l(t) { var r = typeof t.data === "string"; try { var a = r ? JSON.parse(t.data) : t.data; if (a.__cmpCall) { var n = a.__cmpCall; c.__uspapi(n.command, n.parameter, function (a, e) { var c = { __cmpReturn: { returnValue: a, success: e, callId: n.callId } }; t.source.postMessage(r ? JSON.stringify(c) : c, "*") }) } } catch (a) { } } if (typeof __uspapi !== "function") { c.__uspapi = p; __uspapi.msgHandler = l; c.addEventListener("message", l, false) } })();`
308
+ tcfStub: `"use strict";function _typeof(t){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}!function(){var t=function(){var t,e,o=[],n=window,r=n;for(;r;){try{if(r.frames.__tcfapiLocator){t=r;break}}catch(t){}if(r===n.top)break;r=r.parent}t||(!function t(){var e=n.document,o=!!n.frames.__tcfapiLocator;if(!o)if(e.body){var r=e.createElement("iframe");r.style.cssText="display:none",r.name="__tcfapiLocator",r.title = "__tcfapiLocator",e.body.appendChild(r)}else setTimeout(t,5);return!o}(),n.__tcfapi=function(){for(var t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];if(!n.length)return o;"setGdprApplies"===n[0]?n.length>3&&2===parseInt(n[1],10)&&"boolean"==typeof n[3]&&(e=n[3],"function"==typeof n[2]&&n[2]("set",!0)):"ping"===n[0]?"function"==typeof n[2]&&n[2]({gdprApplies:e,cmpLoaded:!1,cmpStatus:"stub"}):o.push(n)},n.addEventListener("message",(function(t){var e="string"==typeof t.data,o={};if(e)try{o=JSON.parse(t.data)}catch(t){}else o=t.data;var n="object"===_typeof(o)&&null!==o?o.__tcfapiCall:null;n&&window.__tcfapi(n.command,n.version,(function(o,r){var a={__tcfapiReturn:{returnValue:o,success:r,callId:n.callId}};t&&t.source&&t.source.postMessage&&t.source.postMessage(e?JSON.stringify(a):a,"*")}),n.parameter)}),!1))};"undefined"!=typeof module?module.exports=t:t()}();`,
309
+ uspStub: `"use strict";(function () { var e = false; var c = window; var t = document; function r() { if (!c.frames["__uspapiLocator"]) { if (t.body) { var a = t.body; var e = t.createElement("iframe"); e.style.cssText = "display:none"; e.name = "__uspapiLocator"; e.title = "__uspapiLocator";a.appendChild(e) } else { setTimeout(r, 5) } } } r(); function p() { var a = arguments; __uspapi.a = __uspapi.a || []; if (!a.length) { return __uspapi.a } else if (a[0] === "ping") { a[2]({ gdprAppliesGlobally: e, cmpLoaded: false }, true) } else { __uspapi.a.push([].slice.apply(a)) } } function l(t) { var r = typeof t.data === "string"; try { var a = r ? JSON.parse(t.data) : t.data; if (a.__cmpCall) { var n = a.__cmpCall; c.__uspapi(n.command, n.parameter, function (a, e) { var c = { __cmpReturn: { returnValue: a, success: e, callId: n.callId } }; t.source.postMessage(r ? JSON.stringify(c) : c, "*") }) } } catch (a) { } } if (typeof __uspapi !== "function") { c.__uspapi = p; __uspapi.msgHandler = l; c.addEventListener("message", l, false) } })();`
277
310
  };
278
311
  function getCmpScripts() {
279
312
  const fragment = document.createDocumentFragment();
@@ -283,11 +316,12 @@ function getCmpScripts() {
283
316
  return fragment;
284
317
  }
285
318
  function bootstrapCmp(config) {
286
- window._sp_ = { config };
319
+ const { _clientOptions, ...spConfig } = config;
320
+ window._sp_ = { config: spConfig };
287
321
  window._sp_queue ?? (window._sp_queue = []);
288
322
  document.head.appendChild(getCmpScripts());
289
323
  }
290
- function getConsentPayload(parsedConsent, { shouldUpdateConsentStore, formOfWordsId, cookieDomain }) {
324
+ function getConsentPayload(parsedConsent, updateConsentStore, { formOfWordsId, cookieDomain }) {
291
325
  const categoryNames = Object.keys(parsedConsent);
292
326
  const data = categoryNames.reduce(
293
327
  (payload, categoryName) => {
@@ -303,9 +337,7 @@ function getConsentPayload(parsedConsent, { shouldUpdateConsentStore, formOfWord
303
337
  },
304
338
  {}
305
339
  );
306
- if (!shouldUpdateConsentStore) {
307
- return { data, cookieDomain };
308
- } else {
340
+ if (updateConsentStore) {
309
341
  return {
310
342
  setConsentCookie: true,
311
343
  formOfWordsId,
@@ -314,2549 +346,46 @@ function getConsentPayload(parsedConsent, { shouldUpdateConsentStore, formOfWord
314
346
  data
315
347
  };
316
348
  }
349
+ return { data, cookieDomain };
317
350
  }
318
- class DecodingError extends Error {
319
- /**
320
- * constructor - constructs an DecodingError
321
- *
322
- * @param {string} msg - Decoding Error Message
323
- * @return {undefined}
324
- */
325
- constructor(msg) {
326
- super(msg);
327
- this.name = "DecodingError";
328
- }
329
- }
330
- class EncodingError extends Error {
331
- /**
332
- * constructor - constructs an EncodingError
333
- *
334
- * @param {string} msg - Encoding Error Message
335
- * @return {undefined}
336
- */
337
- constructor(msg) {
338
- super(msg);
339
- this.name = "EncodingError";
340
- }
341
- }
342
- class GVLError extends Error {
343
- /**
344
- * constructor - constructs a GVLError
345
- *
346
- * @param {string} msg - Error message to display
347
- * @return {undefined}
348
- */
349
- constructor(msg) {
350
- super(msg);
351
- this.name = "GVLError";
352
- }
353
- }
354
- class TCModelError extends Error {
355
- /**
356
- * constructor - constructs an TCModelError
357
- *
358
- * @param {string} fieldName - the errored field
359
- * @param {string} passedValue - what was passed
360
- * @return {undefined}
361
- */
362
- constructor(fieldName, passedValue, msg = "") {
363
- super(`invalid value ${passedValue} passed for ${fieldName} ${msg}`);
364
- this.name = "TCModelError";
365
- }
366
- }
367
- class Base64Url {
368
- /**
369
- * encodes an arbitrary-length bitfield string into base64url
370
- *
371
- * @static
372
- * @param {string} str - arbitrary-length bitfield string to be encoded to base64url
373
- * @return {string} - base64url encoded result
374
- */
375
- static encode(str) {
376
- if (!/^[0-1]+$/.test(str)) {
377
- throw new EncodingError("Invalid bitField");
378
- }
379
- const padding = str.length % this.LCM;
380
- str += padding ? "0".repeat(this.LCM - padding) : "";
381
- let result = "";
382
- for (let i = 0; i < str.length; i += this.BASIS) {
383
- result += this.DICT[parseInt(str.substr(i, this.BASIS), 2)];
384
- }
385
- return result;
386
- }
387
- /**
388
- * decodes a base64url encoded bitfield string
389
- *
390
- * @static
391
- * @param {string} str - base64url encoded bitfield string to be decoded
392
- * @return {string} - bitfield string
393
- */
394
- static decode(str) {
395
- if (!/^[A-Za-z0-9\-_]+$/.test(str)) {
396
- throw new DecodingError("Invalidly encoded Base64URL string");
397
- }
398
- let result = "";
399
- for (let i = 0; i < str.length; i++) {
400
- const strBits = this.REVERSE_DICT.get(str[i]).toString(2);
401
- result += "0".repeat(this.BASIS - strBits.length) + strBits;
402
- }
403
- return result;
404
- }
405
- }
406
- /**
407
- * Base 64 URL character set. Different from standard Base64 char set
408
- * in that '+' and '/' are replaced with '-' and '_'.
409
- */
410
- __publicField(Base64Url, "DICT", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
411
- __publicField(Base64Url, "REVERSE_DICT", /* @__PURE__ */ new Map([
412
- ["A", 0],
413
- ["B", 1],
414
- ["C", 2],
415
- ["D", 3],
416
- ["E", 4],
417
- ["F", 5],
418
- ["G", 6],
419
- ["H", 7],
420
- ["I", 8],
421
- ["J", 9],
422
- ["K", 10],
423
- ["L", 11],
424
- ["M", 12],
425
- ["N", 13],
426
- ["O", 14],
427
- ["P", 15],
428
- ["Q", 16],
429
- ["R", 17],
430
- ["S", 18],
431
- ["T", 19],
432
- ["U", 20],
433
- ["V", 21],
434
- ["W", 22],
435
- ["X", 23],
436
- ["Y", 24],
437
- ["Z", 25],
438
- ["a", 26],
439
- ["b", 27],
440
- ["c", 28],
441
- ["d", 29],
442
- ["e", 30],
443
- ["f", 31],
444
- ["g", 32],
445
- ["h", 33],
446
- ["i", 34],
447
- ["j", 35],
448
- ["k", 36],
449
- ["l", 37],
450
- ["m", 38],
451
- ["n", 39],
452
- ["o", 40],
453
- ["p", 41],
454
- ["q", 42],
455
- ["r", 43],
456
- ["s", 44],
457
- ["t", 45],
458
- ["u", 46],
459
- ["v", 47],
460
- ["w", 48],
461
- ["x", 49],
462
- ["y", 50],
463
- ["z", 51],
464
- ["0", 52],
465
- ["1", 53],
466
- ["2", 54],
467
- ["3", 55],
468
- ["4", 56],
469
- ["5", 57],
470
- ["6", 58],
471
- ["7", 59],
472
- ["8", 60],
473
- ["9", 61],
474
- ["-", 62],
475
- ["_", 63]
476
- ]));
477
- /**
478
- * log2(64) = 6
479
- */
480
- __publicField(Base64Url, "BASIS", 6);
481
- __publicField(Base64Url, "LCM", 24);
482
- const _ConsentLanguages = class _ConsentLanguages {
483
- has(key) {
484
- return _ConsentLanguages.langSet.has(key);
485
- }
486
- parseLanguage(lang) {
487
- lang = lang.toUpperCase();
488
- const primaryLanguage = lang.split("-")[0];
489
- if (lang.length >= 2 && primaryLanguage.length == 2) {
490
- if (_ConsentLanguages.langSet.has(lang)) {
491
- return lang;
492
- } else if (_ConsentLanguages.langSet.has(primaryLanguage)) {
493
- return primaryLanguage;
494
- }
495
- const fullPrimaryLang = primaryLanguage + "-" + primaryLanguage;
496
- if (_ConsentLanguages.langSet.has(fullPrimaryLang)) {
497
- return fullPrimaryLang;
498
- }
499
- for (const supportedLang of _ConsentLanguages.langSet) {
500
- if (supportedLang.indexOf(lang) !== -1 || supportedLang.indexOf(primaryLanguage) !== -1) {
501
- return supportedLang;
502
- }
503
- }
504
- }
505
- throw new Error(`unsupported language ${lang}`);
506
- }
507
- forEach(callback) {
508
- _ConsentLanguages.langSet.forEach(callback);
509
- }
510
- get size() {
511
- return _ConsentLanguages.langSet.size;
512
- }
513
- };
514
- __publicField(_ConsentLanguages, "langSet", /* @__PURE__ */ new Set([
515
- "AR",
516
- "BG",
517
- "BS",
518
- "CA",
519
- "CS",
520
- "DA",
521
- "DE",
522
- "EL",
523
- "EN",
524
- "ES",
525
- "ET",
526
- "EU",
527
- "FI",
528
- "FR",
529
- "GL",
530
- "HR",
531
- "HU",
532
- "IT",
533
- "JA",
534
- "LT",
535
- "LV",
536
- "MT",
537
- "NL",
538
- "NO",
539
- "PL",
540
- "PT-BR",
541
- "PT-PT",
542
- "RO",
543
- "RU",
544
- "SK",
545
- "SL",
546
- "SR-LATN",
547
- "SR-CYRL",
548
- "SV",
549
- "TR",
550
- "ZH"
551
- ]));
552
- let ConsentLanguages = _ConsentLanguages;
553
- class Fields {
554
- }
555
- __publicField(Fields, "cmpId", "cmpId");
556
- __publicField(Fields, "cmpVersion", "cmpVersion");
557
- __publicField(Fields, "consentLanguage", "consentLanguage");
558
- __publicField(Fields, "consentScreen", "consentScreen");
559
- __publicField(Fields, "created", "created");
560
- __publicField(Fields, "supportOOB", "supportOOB");
561
- __publicField(Fields, "isServiceSpecific", "isServiceSpecific");
562
- __publicField(Fields, "lastUpdated", "lastUpdated");
563
- __publicField(Fields, "numCustomPurposes", "numCustomPurposes");
564
- __publicField(Fields, "policyVersion", "policyVersion");
565
- __publicField(Fields, "publisherCountryCode", "publisherCountryCode");
566
- __publicField(Fields, "publisherCustomConsents", "publisherCustomConsents");
567
- __publicField(Fields, "publisherCustomLegitimateInterests", "publisherCustomLegitimateInterests");
568
- __publicField(Fields, "publisherLegitimateInterests", "publisherLegitimateInterests");
569
- __publicField(Fields, "publisherConsents", "publisherConsents");
570
- __publicField(Fields, "publisherRestrictions", "publisherRestrictions");
571
- __publicField(Fields, "purposeConsents", "purposeConsents");
572
- __publicField(Fields, "purposeLegitimateInterests", "purposeLegitimateInterests");
573
- __publicField(Fields, "purposeOneTreatment", "purposeOneTreatment");
574
- __publicField(Fields, "specialFeatureOptins", "specialFeatureOptins");
575
- __publicField(Fields, "useNonStandardTexts", "useNonStandardTexts");
576
- __publicField(Fields, "vendorConsents", "vendorConsents");
577
- __publicField(Fields, "vendorLegitimateInterests", "vendorLegitimateInterests");
578
- __publicField(Fields, "vendorListVersion", "vendorListVersion");
579
- __publicField(Fields, "vendorsAllowed", "vendorsAllowed");
580
- __publicField(Fields, "vendorsDisclosed", "vendorsDisclosed");
581
- __publicField(Fields, "version", "version");
582
- class Cloneable {
583
- /**
584
- * clone - returns a copy of the classes with new values and not references
585
- *
586
- * @return {T}
587
- */
588
- clone() {
589
- const myClone = new this.constructor();
590
- const keys = Object.keys(this);
591
- keys.forEach((key) => {
592
- const value = this.deepClone(this[key]);
593
- if (value !== void 0) {
594
- myClone[key] = value;
595
- }
596
- });
597
- return myClone;
598
- }
599
- /**
600
- * deepClone - recursive function that makes copies of reference values
601
- *
602
- * @param {unknown} item
603
- * @return {unknown}
604
- */
605
- deepClone(item) {
606
- const itsType = typeof item;
607
- if (itsType === "number" || itsType === "string" || itsType === "boolean") {
608
- return item;
609
- } else if (item !== null && itsType === "object") {
610
- if (typeof item.clone === "function") {
611
- return item.clone();
612
- } else if (item instanceof Date) {
613
- return new Date(item.getTime());
614
- } else if (item[Symbol.iterator] !== void 0) {
615
- const ar = [];
616
- for (const subItem of item) {
617
- ar.push(this.deepClone(subItem));
618
- }
619
- if (item instanceof Array) {
620
- return ar;
621
- } else {
622
- return new item.constructor(ar);
623
- }
624
- } else {
625
- const retr = {};
626
- for (const prop in item) {
627
- if (item.hasOwnProperty(prop)) {
628
- retr[prop] = this.deepClone(item[prop]);
629
- }
630
- }
631
- return retr;
632
- }
633
- }
634
- }
635
- }
636
- var RestrictionType;
637
- (function(RestrictionType2) {
638
- RestrictionType2[RestrictionType2["NOT_ALLOWED"] = 0] = "NOT_ALLOWED";
639
- RestrictionType2[RestrictionType2["REQUIRE_CONSENT"] = 1] = "REQUIRE_CONSENT";
640
- RestrictionType2[RestrictionType2["REQUIRE_LI"] = 2] = "REQUIRE_LI";
641
- })(RestrictionType || (RestrictionType = {}));
642
- const _PurposeRestriction = class _PurposeRestriction extends Cloneable {
643
- /**
644
- * constructor
645
- *
646
- * @param {number} purposeId? - may optionally pass the purposeId into the
647
- * constructor
648
- * @param {RestrictionType} restrictionType? - may
649
- * optionally pass the restrictionType into the constructor
650
- * @return {undefined}
651
- */
652
- constructor(purposeId, restrictionType) {
653
- super();
654
- __publicField(this, "purposeId_");
655
- __publicField(this, "restrictionType");
656
- if (purposeId !== void 0) {
657
- this.purposeId = purposeId;
658
- }
659
- if (restrictionType !== void 0) {
660
- this.restrictionType = restrictionType;
661
- }
662
- }
663
- static unHash(hash) {
664
- const splitUp = hash.split(this.hashSeparator);
665
- const purpRestriction = new _PurposeRestriction();
666
- if (splitUp.length !== 2) {
667
- throw new TCModelError("hash", hash);
668
- }
669
- purpRestriction.purposeId = parseInt(splitUp[0], 10);
670
- purpRestriction.restrictionType = parseInt(splitUp[1], 10);
671
- return purpRestriction;
672
- }
673
- get hash() {
674
- if (!this.isValid()) {
675
- throw new Error("cannot hash invalid PurposeRestriction");
676
- }
677
- return `${this.purposeId}${_PurposeRestriction.hashSeparator}${this.restrictionType}`;
678
- }
679
- /**
680
- * @return {number} The purpose Id associated with a publisher
681
- * purpose-by-vendor restriction that resulted in a different consent or LI
682
- * status than the consent or LI purposes allowed lists.
683
- */
684
- get purposeId() {
685
- return this.purposeId_;
686
- }
687
- /**
688
- * @param {number} idNum - The purpose Id associated with a publisher
689
- * purpose-by-vendor restriction that resulted in a different consent or LI
690
- * status than the consent or LI purposes allowed lists.
691
- */
692
- set purposeId(idNum) {
693
- this.purposeId_ = idNum;
694
- }
695
- isValid() {
696
- return Number.isInteger(this.purposeId) && this.purposeId > 0 && (this.restrictionType === RestrictionType.NOT_ALLOWED || this.restrictionType === RestrictionType.REQUIRE_CONSENT || this.restrictionType === RestrictionType.REQUIRE_LI);
697
- }
698
- isSameAs(otherPR) {
699
- return this.purposeId === otherPR.purposeId && this.restrictionType === otherPR.restrictionType;
700
- }
701
- };
702
- __publicField(_PurposeRestriction, "hashSeparator", "-");
703
- let PurposeRestriction = _PurposeRestriction;
704
- class PurposeRestrictionVector extends Cloneable {
705
- constructor() {
706
- super(...arguments);
707
- /**
708
- * if this originatd from an encoded string we'll need a place to store the
709
- * bit length; it can be set and got from here
710
- */
711
- __publicField(this, "bitLength", 0);
712
- /**
713
- * a map indexed by a string which will be a 'hash' of the purpose and
714
- * restriction type.
715
- */
716
- __publicField(this, "map", /* @__PURE__ */ new Map());
717
- __publicField(this, "gvl_");
718
- }
719
- has(hash) {
720
- return this.map.has(hash);
721
- }
722
- isOkToHave(restrictionType, purposeId, vendorId) {
723
- var _a2;
724
- let result = true;
725
- if ((_a2 = this.gvl) == null ? void 0 : _a2.vendors) {
726
- const vendor = this.gvl.vendors[vendorId];
727
- if (vendor) {
728
- if (restrictionType === RestrictionType.NOT_ALLOWED) {
729
- result = vendor.legIntPurposes.includes(purposeId) || vendor.purposes.includes(purposeId);
730
- } else if (vendor.flexiblePurposes.length) {
731
- switch (restrictionType) {
732
- case RestrictionType.REQUIRE_CONSENT:
733
- result = vendor.flexiblePurposes.includes(purposeId) && vendor.legIntPurposes.includes(purposeId);
734
- break;
735
- case RestrictionType.REQUIRE_LI:
736
- result = vendor.flexiblePurposes.includes(purposeId) && vendor.purposes.includes(purposeId);
737
- break;
738
- }
739
- } else {
740
- result = false;
741
- }
742
- } else {
743
- result = false;
744
- }
745
- }
746
- return result;
747
- }
748
- /**
749
- * add - adds a given Vendor ID under a given Purpose Restriction
750
- *
751
- * @param {number} vendorId
752
- * @param {PurposeRestriction} purposeRestriction
753
- * @return {void}
754
- */
755
- add(vendorId, purposeRestriction) {
756
- if (this.isOkToHave(purposeRestriction.restrictionType, purposeRestriction.purposeId, vendorId)) {
757
- const hash = purposeRestriction.hash;
758
- if (!this.has(hash)) {
759
- this.map.set(hash, /* @__PURE__ */ new Set());
760
- this.bitLength = 0;
761
- }
762
- this.map.get(hash).add(vendorId);
763
- }
764
- }
765
- /**
766
- * restrictPurposeToLegalBasis - adds all Vendors under a given Purpose Restriction
767
- *
768
- * @param {PurposeRestriction} purposeRestriction
769
- * @return {void}
770
- */
771
- restrictPurposeToLegalBasis(purposeRestriction) {
772
- const vendors = Array.from(this.gvl.vendorIds);
773
- const hash = purposeRestriction.hash;
774
- const lastEntry = vendors[vendors.length - 1];
775
- const values = [...Array(lastEntry).keys()].map((i) => i + 1);
776
- if (!this.has(hash)) {
777
- this.map.set(hash, new Set(values));
778
- this.bitLength = 0;
779
- } else {
780
- for (let i = 1; i <= lastEntry; i++) {
781
- this.map.get(hash).add(i);
782
- }
783
- }
784
- }
785
- /**
786
- * getVendors - returns array of vendor ids optionally narrowed by a given
787
- * Purpose Restriction. If no purpose restriction is passed then all vendor
788
- * ids will be returned. One can expect this result to be a unique set of
789
- * ids no duplicates.
790
- *
791
- * @param {PurposeRestriction} [purposeRestriction] - optionally passed to
792
- * get only Vendor IDs restricted under the given Purpose Restriction
793
- * @return {number[]} - Unique ID set of vendors
794
- */
795
- getVendors(purposeRestriction) {
796
- let vendorIds = [];
797
- if (purposeRestriction) {
798
- const hash = purposeRestriction.hash;
799
- if (this.has(hash)) {
800
- vendorIds = Array.from(this.map.get(hash));
801
- }
802
- } else {
803
- const vendorSet = /* @__PURE__ */ new Set();
804
- this.map.forEach((set) => {
805
- set.forEach((vendorId) => {
806
- vendorSet.add(vendorId);
807
- });
808
- });
809
- vendorIds = Array.from(vendorSet);
810
- }
811
- return vendorIds.sort((a, b) => a - b);
812
- }
813
- getRestrictionType(vendorId, purposeId) {
814
- let rType;
815
- this.getRestrictions(vendorId).forEach((purposeRestriction) => {
816
- if (purposeRestriction.purposeId === purposeId) {
817
- if (rType === void 0 || rType > purposeRestriction.restrictionType) {
818
- rType = purposeRestriction.restrictionType;
819
- }
820
- }
821
- });
822
- return rType;
823
- }
824
- /**
825
- * vendorHasRestriction - determines whether a given Vendor ID is under a
826
- * given Purpose Restriction
827
- *
828
- * @param {number} vendorId
829
- * @param {PurposeRestriction} purposeRestriction
830
- * @return {boolean} - true if the give Vendor ID is under the given Purpose
831
- * Restriction
832
- */
833
- vendorHasRestriction(vendorId, purposeRestriction) {
834
- let has = false;
835
- const restrictions = this.getRestrictions(vendorId);
836
- for (let i = 0; i < restrictions.length && !has; i++) {
837
- has = purposeRestriction.isSameAs(restrictions[i]);
838
- }
839
- return has;
840
- }
841
- /**
842
- * getMaxVendorId - gets the Maximum Vendor ID regardless of Purpose
843
- * Restriction
844
- *
845
- * @return {number} - maximum Vendor ID
846
- */
847
- getMaxVendorId() {
848
- let retr = 0;
849
- this.map.forEach((set) => {
850
- retr = Math.max(Array.from(set)[set.size - 1], retr);
851
- });
852
- return retr;
853
- }
854
- getRestrictions(vendorId) {
855
- const retr = [];
856
- this.map.forEach((set, hash) => {
857
- if (vendorId) {
858
- if (set.has(vendorId)) {
859
- retr.push(PurposeRestriction.unHash(hash));
860
- }
861
- } else {
862
- retr.push(PurposeRestriction.unHash(hash));
863
- }
864
- });
865
- return retr;
866
- }
867
- getPurposes() {
868
- const purposeIds = /* @__PURE__ */ new Set();
869
- this.map.forEach((set, hash) => {
870
- purposeIds.add(PurposeRestriction.unHash(hash).purposeId);
871
- });
872
- return Array.from(purposeIds);
873
- }
874
- /**
875
- * remove - removes Vendor ID from a Purpose Restriction
876
- *
877
- * @param {number} vendorId
878
- * @param {PurposeRestriction} purposeRestriction
879
- * @return {void}
880
- */
881
- remove(vendorId, purposeRestriction) {
882
- const hash = purposeRestriction.hash;
883
- const set = this.map.get(hash);
884
- if (set) {
885
- set.delete(vendorId);
886
- if (set.size == 0) {
887
- this.map.delete(hash);
888
- this.bitLength = 0;
889
- }
890
- }
891
- }
892
- /**
893
- * Essential for being able to determine whether we can actually set a
894
- * purpose restriction since they have to have a flexible legal basis
895
- *
896
- * @param {GVL} value - the GVL instance
897
- */
898
- set gvl(value) {
899
- if (!this.gvl_) {
900
- this.gvl_ = value;
901
- this.map.forEach((set, hash) => {
902
- const purposeRestriction = PurposeRestriction.unHash(hash);
903
- const vendors = Array.from(set);
904
- vendors.forEach((vendorId) => {
905
- if (!this.isOkToHave(purposeRestriction.restrictionType, purposeRestriction.purposeId, vendorId)) {
906
- set.delete(vendorId);
907
- }
908
- });
909
- });
910
- }
911
- }
912
- /**
913
- * gvl returns local copy of the GVL these restrictions apply to
914
- *
915
- * @return {GVL}
916
- */
917
- get gvl() {
918
- return this.gvl_;
919
- }
920
- /**
921
- * isEmpty - whether or not this vector has any restrictions in it
922
- *
923
- * @return {boolean}
924
- */
925
- isEmpty() {
926
- return this.map.size === 0;
927
- }
928
- /**
929
- * numRestrictions - returns the number of Purpose Restrictions.
930
- *
931
- * @return {number}
932
- */
933
- get numRestrictions() {
934
- return this.map.size;
935
- }
936
- }
937
- var DeviceDisclosureStorageAccessType;
938
- (function(DeviceDisclosureStorageAccessType2) {
939
- DeviceDisclosureStorageAccessType2["COOKIE"] = "cookie";
940
- DeviceDisclosureStorageAccessType2["WEB"] = "web";
941
- DeviceDisclosureStorageAccessType2["APP"] = "app";
942
- })(DeviceDisclosureStorageAccessType || (DeviceDisclosureStorageAccessType = {}));
943
- var Segment;
944
- (function(Segment2) {
945
- Segment2["CORE"] = "core";
946
- Segment2["VENDORS_DISCLOSED"] = "vendorsDisclosed";
947
- Segment2["VENDORS_ALLOWED"] = "vendorsAllowed";
948
- Segment2["PUBLISHER_TC"] = "publisherTC";
949
- })(Segment || (Segment = {}));
950
- class SegmentIDs {
951
- }
952
- /**
953
- * 0 = default - reserved for core string (does not need to be present in the core string)
954
- * 1 = OOB vendors disclosed
955
- * 2 = OOB vendors allowed
956
- * 3 = PublisherTC
957
- */
958
- __publicField(SegmentIDs, "ID_TO_KEY", [
959
- Segment.CORE,
960
- Segment.VENDORS_DISCLOSED,
961
- Segment.VENDORS_ALLOWED,
962
- Segment.PUBLISHER_TC
963
- ]);
964
- __publicField(SegmentIDs, "KEY_TO_ID", {
965
- [Segment.CORE]: 0,
966
- [Segment.VENDORS_DISCLOSED]: 1,
967
- [Segment.VENDORS_ALLOWED]: 2,
968
- [Segment.PUBLISHER_TC]: 3
969
- });
970
- class Vector extends Cloneable {
971
- constructor() {
972
- super(...arguments);
973
- /**
974
- * if this originatd from an encoded string we'll need a place to store the
975
- * bit length; it can be set and got from here
976
- */
977
- __publicField(this, "bitLength", 0);
978
- __publicField(this, "maxId_", 0);
979
- __publicField(this, "set_", /* @__PURE__ */ new Set());
980
- }
981
- *[Symbol.iterator]() {
982
- for (let i = 1; i <= this.maxId; i++) {
983
- yield [i, this.has(i)];
984
- }
985
- }
986
- /**
987
- * values()
988
- *
989
- * @return {IterableIterator<number>} - returns an iterator of the positive
990
- * values in the set
991
- */
992
- values() {
993
- return this.set_.values();
994
- }
995
- /**
996
- * maxId
997
- *
998
- * @return {number} - the highest id in this Vector
999
- */
1000
- get maxId() {
1001
- return this.maxId_;
1002
- }
1003
- /**
1004
- * get
1005
- *
1006
- * @param {number} id - key for value to check
1007
- * @return {boolean} - value of that key, if never set it will be false
1008
- */
1009
- has(id) {
1010
- return this.set_.has(id);
1011
- }
1012
- /**
1013
- * unset
1014
- *
1015
- * @param {SingleIDOrCollection} id - id or ids to unset
1016
- * @return {void}
1017
- */
1018
- unset(id) {
1019
- if (Array.isArray(id)) {
1020
- id.forEach((id2) => this.unset(id2));
1021
- } else if (typeof id === "object") {
1022
- this.unset(Object.keys(id).map((strId) => Number(strId)));
1023
- } else {
1024
- this.set_.delete(Number(id));
1025
- this.bitLength = 0;
1026
- if (id === this.maxId) {
1027
- this.maxId_ = 0;
1028
- this.set_.forEach((id2) => {
1029
- this.maxId_ = Math.max(this.maxId, id2);
1030
- });
1031
- }
1032
- }
1033
- }
1034
- isIntMap(item) {
1035
- let result = typeof item === "object";
1036
- result = result && Object.keys(item).every((key) => {
1037
- let itemResult = Number.isInteger(parseInt(key, 10));
1038
- itemResult = itemResult && this.isValidNumber(item[key].id);
1039
- itemResult = itemResult && item[key].name !== void 0;
1040
- return itemResult;
1041
- });
1042
- return result;
1043
- }
1044
- isValidNumber(item) {
1045
- return parseInt(item, 10) > 0;
1046
- }
1047
- isSet(item) {
1048
- let result = false;
1049
- if (item instanceof Set) {
1050
- result = Array.from(item).every(this.isValidNumber);
1051
- }
1052
- return result;
1053
- }
1054
- /**
1055
- * set - sets an item assumed to be a truthy value by its presence
1056
- *
1057
- * @param {SingleIDOrCollection} item - May be a single id (positive integer)
1058
- * or collection of ids in a set, GVL Int Map, or Array.
1059
- *
1060
- * @return {void}
1061
- */
1062
- set(item) {
1063
- if (Array.isArray(item)) {
1064
- item.forEach((item2) => this.set(item2));
1065
- } else if (this.isSet(item)) {
1066
- this.set(Array.from(item));
1067
- } else if (this.isIntMap(item)) {
1068
- this.set(Object.keys(item).map((strId) => Number(strId)));
1069
- } else if (this.isValidNumber(item)) {
1070
- this.set_.add(item);
1071
- this.maxId_ = Math.max(this.maxId, item);
1072
- this.bitLength = 0;
1073
- } else {
1074
- throw new TCModelError("set()", item, "must be positive integer array, positive integer, Set<number>, or IntMap");
1075
- }
1076
- }
1077
- empty() {
1078
- this.set_ = /* @__PURE__ */ new Set();
1079
- }
1080
- /**
1081
- * forEach - to traverse from id=1 to id=maxId in a sequential non-sparse manner
1082
- *
1083
- *
1084
- * @param {forEachCallback} callback - callback to execute
1085
- * @return {void}
1086
- *
1087
- * @callback forEachCallback
1088
- * @param {boolean} value - whether or not this id exists in the vector
1089
- * @param {number} id - the id number of the current iteration
1090
- */
1091
- forEach(callback) {
1092
- for (let i = 1; i <= this.maxId; i++) {
1093
- callback(this.has(i), i);
1094
- }
1095
- }
1096
- get size() {
1097
- return this.set_.size;
1098
- }
1099
- setAll(intMap) {
1100
- this.set(intMap);
1101
- }
1102
- }
1103
- class BitLength {
1104
- }
1105
- _a = Fields.cmpId, _b = Fields.cmpVersion, _c = Fields.consentLanguage, _d = Fields.consentScreen, _e = Fields.created, _f = Fields.isServiceSpecific, _g = Fields.lastUpdated, _h = Fields.policyVersion, _i = Fields.publisherCountryCode, _j = Fields.publisherLegitimateInterests, _k = Fields.publisherConsents, _l = Fields.purposeConsents, _m = Fields.purposeLegitimateInterests, _n = Fields.purposeOneTreatment, _o = Fields.specialFeatureOptins, _p = Fields.useNonStandardTexts, _q = Fields.vendorListVersion, _r = Fields.version;
1106
- __publicField(BitLength, _a, 12);
1107
- __publicField(BitLength, _b, 12);
1108
- __publicField(BitLength, _c, 12);
1109
- __publicField(BitLength, _d, 6);
1110
- __publicField(BitLength, _e, 36);
1111
- __publicField(BitLength, _f, 1);
1112
- __publicField(BitLength, _g, 36);
1113
- __publicField(BitLength, _h, 6);
1114
- __publicField(BitLength, _i, 12);
1115
- __publicField(BitLength, _j, 24);
1116
- __publicField(BitLength, _k, 24);
1117
- __publicField(BitLength, _l, 24);
1118
- __publicField(BitLength, _m, 24);
1119
- __publicField(BitLength, _n, 1);
1120
- __publicField(BitLength, _o, 12);
1121
- __publicField(BitLength, _p, 1);
1122
- __publicField(BitLength, _q, 12);
1123
- __publicField(BitLength, _r, 6);
1124
- __publicField(BitLength, "anyBoolean", 1);
1125
- __publicField(BitLength, "encodingType", 1);
1126
- __publicField(BitLength, "maxId", 16);
1127
- __publicField(BitLength, "numCustomPurposes", 6);
1128
- __publicField(BitLength, "numEntries", 12);
1129
- __publicField(BitLength, "numRestrictions", 12);
1130
- __publicField(BitLength, "purposeId", 6);
1131
- __publicField(BitLength, "restrictionType", 2);
1132
- __publicField(BitLength, "segmentType", 3);
1133
- __publicField(BitLength, "singleOrRange", 1);
1134
- __publicField(BitLength, "vendorId", 16);
1135
- class BooleanEncoder {
1136
- static encode(value) {
1137
- return String(Number(value));
1138
- }
1139
- static decode(value) {
1140
- return value === "1";
1141
- }
1142
- }
1143
- class IntEncoder {
1144
- static encode(value, numBits) {
1145
- let bitString;
1146
- if (typeof value === "string") {
1147
- value = parseInt(value, 10);
1148
- }
1149
- bitString = value.toString(2);
1150
- if (bitString.length > numBits || value < 0) {
1151
- throw new EncodingError(`${value} too large to encode into ${numBits}`);
1152
- }
1153
- if (bitString.length < numBits) {
1154
- bitString = "0".repeat(numBits - bitString.length) + bitString;
1155
- }
1156
- return bitString;
1157
- }
1158
- static decode(value, numBits) {
1159
- if (numBits !== value.length) {
1160
- throw new DecodingError("invalid bit length");
1161
- }
1162
- return parseInt(value, 2);
1163
- }
1164
- }
1165
- class DateEncoder {
1166
- static encode(value, numBits) {
1167
- return IntEncoder.encode(Math.round(value.getTime() / 100), numBits);
1168
- }
1169
- static decode(value, numBits) {
1170
- if (numBits !== value.length) {
1171
- throw new DecodingError("invalid bit length");
1172
- }
1173
- const date = /* @__PURE__ */ new Date();
1174
- date.setTime(IntEncoder.decode(value, numBits) * 100);
1175
- return date;
1176
- }
1177
- }
1178
- class FixedVectorEncoder {
1179
- static encode(value, numBits) {
1180
- let bitString = "";
1181
- for (let i = 1; i <= numBits; i++) {
1182
- bitString += BooleanEncoder.encode(value.has(i));
1183
- }
1184
- return bitString;
1185
- }
1186
- static decode(value, numBits) {
1187
- if (value.length !== numBits) {
1188
- throw new DecodingError("bitfield encoding length mismatch");
1189
- }
1190
- const vector = new Vector();
1191
- for (let i = 1; i <= numBits; i++) {
1192
- if (BooleanEncoder.decode(value[i - 1])) {
1193
- vector.set(i);
1194
- }
1195
- }
1196
- vector.bitLength = value.length;
1197
- return vector;
1198
- }
1199
- }
1200
- class LangEncoder {
1201
- static encode(value, numBits) {
1202
- value = value.toUpperCase();
1203
- const ASCII_START = 65;
1204
- const firstLetter = value.charCodeAt(0) - ASCII_START;
1205
- const secondLetter = value.charCodeAt(1) - ASCII_START;
1206
- if (firstLetter < 0 || firstLetter > 25 || secondLetter < 0 || secondLetter > 25) {
1207
- throw new EncodingError(`invalid language code: ${value}`);
1208
- }
1209
- if (numBits % 2 === 1) {
1210
- throw new EncodingError(`numBits must be even, ${numBits} is not valid`);
1211
- }
1212
- numBits = numBits / 2;
1213
- const firstLetterBString = IntEncoder.encode(firstLetter, numBits);
1214
- const secondLetterBString = IntEncoder.encode(secondLetter, numBits);
1215
- return firstLetterBString + secondLetterBString;
1216
- }
1217
- static decode(value, numBits) {
1218
- let retr;
1219
- if (numBits === value.length && !(value.length % 2)) {
1220
- const ASCII_START = 65;
1221
- const mid = value.length / 2;
1222
- const firstLetter = IntEncoder.decode(value.slice(0, mid), mid) + ASCII_START;
1223
- const secondLetter = IntEncoder.decode(value.slice(mid), mid) + ASCII_START;
1224
- retr = String.fromCharCode(firstLetter) + String.fromCharCode(secondLetter);
1225
- } else {
1226
- throw new DecodingError("invalid bit length for language");
1227
- }
1228
- return retr;
1229
- }
1230
- }
1231
- class PurposeRestrictionVectorEncoder {
1232
- static encode(prVector) {
1233
- let bitString = IntEncoder.encode(prVector.numRestrictions, BitLength.numRestrictions);
1234
- if (!prVector.isEmpty()) {
1235
- const nextGvlVendor = (vendorId, lastVendorId) => {
1236
- for (let nextId = vendorId + 1; nextId <= lastVendorId; nextId++) {
1237
- if (prVector.gvl.vendorIds.has(nextId)) {
1238
- return nextId;
1239
- }
1240
- }
1241
- return vendorId;
1242
- };
1243
- prVector.getRestrictions().forEach((purpRestriction) => {
1244
- bitString += IntEncoder.encode(purpRestriction.purposeId, BitLength.purposeId);
1245
- bitString += IntEncoder.encode(purpRestriction.restrictionType, BitLength.restrictionType);
1246
- const vendors = prVector.getVendors(purpRestriction);
1247
- const len = vendors.length;
1248
- let numEntries = 0;
1249
- let startId = 0;
1250
- let rangeField = "";
1251
- for (let i = 0; i < len; i++) {
1252
- const vendorId = vendors[i];
1253
- if (startId === 0) {
1254
- numEntries++;
1255
- startId = vendorId;
1256
- }
1257
- if (i === len - 1 || vendors[i + 1] > nextGvlVendor(vendorId, vendors[len - 1])) {
1258
- const isRange = !(vendorId === startId);
1259
- rangeField += BooleanEncoder.encode(isRange);
1260
- rangeField += IntEncoder.encode(startId, BitLength.vendorId);
1261
- if (isRange) {
1262
- rangeField += IntEncoder.encode(vendorId, BitLength.vendorId);
1263
- }
1264
- startId = 0;
1265
- }
1266
- }
1267
- bitString += IntEncoder.encode(numEntries, BitLength.numEntries);
1268
- bitString += rangeField;
1269
- });
1270
- }
1271
- return bitString;
1272
- }
1273
- static decode(encodedString) {
1274
- let index = 0;
1275
- const vector = new PurposeRestrictionVector();
1276
- const numRestrictions = IntEncoder.decode(encodedString.substr(index, BitLength.numRestrictions), BitLength.numRestrictions);
1277
- index += BitLength.numRestrictions;
1278
- for (let i = 0; i < numRestrictions; i++) {
1279
- const purposeId = IntEncoder.decode(encodedString.substr(index, BitLength.purposeId), BitLength.purposeId);
1280
- index += BitLength.purposeId;
1281
- const restrictionType = IntEncoder.decode(encodedString.substr(index, BitLength.restrictionType), BitLength.restrictionType);
1282
- index += BitLength.restrictionType;
1283
- const purposeRestriction = new PurposeRestriction(purposeId, restrictionType);
1284
- const numEntries = IntEncoder.decode(encodedString.substr(index, BitLength.numEntries), BitLength.numEntries);
1285
- index += BitLength.numEntries;
1286
- for (let j = 0; j < numEntries; j++) {
1287
- const isARange = BooleanEncoder.decode(encodedString.substr(index, BitLength.anyBoolean));
1288
- index += BitLength.anyBoolean;
1289
- const startOrOnlyVendorId = IntEncoder.decode(encodedString.substr(index, BitLength.vendorId), BitLength.vendorId);
1290
- index += BitLength.vendorId;
1291
- if (isARange) {
1292
- const endVendorId = IntEncoder.decode(encodedString.substr(index, BitLength.vendorId), BitLength.vendorId);
1293
- index += BitLength.vendorId;
1294
- if (endVendorId < startOrOnlyVendorId) {
1295
- throw new DecodingError(`Invalid RangeEntry: endVendorId ${endVendorId} is less than ${startOrOnlyVendorId}`);
1296
- }
1297
- for (let k = startOrOnlyVendorId; k <= endVendorId; k++) {
1298
- vector.add(k, purposeRestriction);
1299
- }
1300
- } else {
1301
- vector.add(startOrOnlyVendorId, purposeRestriction);
1302
- }
1303
- }
1304
- }
1305
- vector.bitLength = index;
1306
- return vector;
1307
- }
1308
- }
1309
- var VectorEncodingType;
1310
- (function(VectorEncodingType2) {
1311
- VectorEncodingType2[VectorEncodingType2["FIELD"] = 0] = "FIELD";
1312
- VectorEncodingType2[VectorEncodingType2["RANGE"] = 1] = "RANGE";
1313
- })(VectorEncodingType || (VectorEncodingType = {}));
1314
- class VendorVectorEncoder {
1315
- static encode(value) {
1316
- const ranges = [];
1317
- let range = [];
1318
- let retrString = IntEncoder.encode(value.maxId, BitLength.maxId);
1319
- let bitField = "";
1320
- let rangeIsSmaller;
1321
- const headerLength = BitLength.maxId + BitLength.encodingType;
1322
- const bitFieldLength = headerLength + value.maxId;
1323
- const minRangeLength = BitLength.vendorId * 2 + BitLength.singleOrRange + BitLength.numEntries;
1324
- let rangeLength = headerLength + BitLength.numEntries;
1325
- value.forEach((curValue, i) => {
1326
- bitField += BooleanEncoder.encode(curValue);
1327
- rangeIsSmaller = value.maxId > minRangeLength && rangeLength < bitFieldLength;
1328
- if (rangeIsSmaller && curValue) {
1329
- const nextValue = value.has(i + 1);
1330
- if (!nextValue) {
1331
- range.push(i);
1332
- rangeLength += BitLength.vendorId;
1333
- ranges.push(range);
1334
- range = [];
1335
- } else if (range.length === 0) {
1336
- range.push(i);
1337
- rangeLength += BitLength.singleOrRange;
1338
- rangeLength += BitLength.vendorId;
1339
- }
1340
- }
1341
- });
1342
- if (rangeIsSmaller) {
1343
- retrString += String(VectorEncodingType.RANGE);
1344
- retrString += this.buildRangeEncoding(ranges);
1345
- } else {
1346
- retrString += String(VectorEncodingType.FIELD);
1347
- retrString += bitField;
1348
- }
1349
- return retrString;
1350
- }
1351
- static decode(value, version2) {
1352
- let vector;
1353
- let index = 0;
1354
- const maxId = IntEncoder.decode(value.substr(index, BitLength.maxId), BitLength.maxId);
1355
- index += BitLength.maxId;
1356
- const encodingType = IntEncoder.decode(value.charAt(index), BitLength.encodingType);
1357
- index += BitLength.encodingType;
1358
- if (encodingType === VectorEncodingType.RANGE) {
1359
- vector = new Vector();
1360
- if (version2 === 1) {
1361
- if (value.substr(index, 1) === "1") {
1362
- throw new DecodingError("Unable to decode default consent=1");
1363
- }
1364
- index++;
1365
- }
1366
- const numEntries = IntEncoder.decode(value.substr(index, BitLength.numEntries), BitLength.numEntries);
1367
- index += BitLength.numEntries;
1368
- for (let i = 0; i < numEntries; i++) {
1369
- const isIdRange = BooleanEncoder.decode(value.charAt(index));
1370
- index += BitLength.singleOrRange;
1371
- const firstId = IntEncoder.decode(value.substr(index, BitLength.vendorId), BitLength.vendorId);
1372
- index += BitLength.vendorId;
1373
- if (isIdRange) {
1374
- const secondId = IntEncoder.decode(value.substr(index, BitLength.vendorId), BitLength.vendorId);
1375
- index += BitLength.vendorId;
1376
- for (let j = firstId; j <= secondId; j++) {
1377
- vector.set(j);
1378
- }
1379
- } else {
1380
- vector.set(firstId);
1381
- }
1382
- }
1383
- } else {
1384
- const bitField = value.substr(index, maxId);
1385
- index += maxId;
1386
- vector = FixedVectorEncoder.decode(bitField, maxId);
1387
- }
1388
- vector.bitLength = index;
1389
- return vector;
1390
- }
1391
- static buildRangeEncoding(ranges) {
1392
- const numEntries = ranges.length;
1393
- let rangeString = IntEncoder.encode(numEntries, BitLength.numEntries);
1394
- ranges.forEach((range) => {
1395
- const single = range.length === 1;
1396
- rangeString += BooleanEncoder.encode(!single);
1397
- rangeString += IntEncoder.encode(range[0], BitLength.vendorId);
1398
- if (!single) {
1399
- rangeString += IntEncoder.encode(range[1], BitLength.vendorId);
1400
- }
1401
- });
1402
- return rangeString;
1403
- }
1404
- }
1405
- function FieldEncoderMap() {
1406
- return {
1407
- [Fields.version]: IntEncoder,
1408
- [Fields.created]: DateEncoder,
1409
- [Fields.lastUpdated]: DateEncoder,
1410
- [Fields.cmpId]: IntEncoder,
1411
- [Fields.cmpVersion]: IntEncoder,
1412
- [Fields.consentScreen]: IntEncoder,
1413
- [Fields.consentLanguage]: LangEncoder,
1414
- [Fields.vendorListVersion]: IntEncoder,
1415
- [Fields.policyVersion]: IntEncoder,
1416
- [Fields.isServiceSpecific]: BooleanEncoder,
1417
- [Fields.useNonStandardTexts]: BooleanEncoder,
1418
- [Fields.specialFeatureOptins]: FixedVectorEncoder,
1419
- [Fields.purposeConsents]: FixedVectorEncoder,
1420
- [Fields.purposeLegitimateInterests]: FixedVectorEncoder,
1421
- [Fields.purposeOneTreatment]: BooleanEncoder,
1422
- [Fields.publisherCountryCode]: LangEncoder,
1423
- [Fields.vendorConsents]: VendorVectorEncoder,
1424
- [Fields.vendorLegitimateInterests]: VendorVectorEncoder,
1425
- [Fields.publisherRestrictions]: PurposeRestrictionVectorEncoder,
1426
- segmentType: IntEncoder,
1427
- [Fields.vendorsDisclosed]: VendorVectorEncoder,
1428
- [Fields.vendorsAllowed]: VendorVectorEncoder,
1429
- [Fields.publisherConsents]: FixedVectorEncoder,
1430
- [Fields.publisherLegitimateInterests]: FixedVectorEncoder,
1431
- [Fields.numCustomPurposes]: IntEncoder,
1432
- [Fields.publisherCustomConsents]: FixedVectorEncoder,
1433
- [Fields.publisherCustomLegitimateInterests]: FixedVectorEncoder
1434
- };
1435
- }
1436
- class FieldSequence {
1437
- constructor() {
1438
- __publicField(this, "1", {
1439
- [Segment.CORE]: [
1440
- Fields.version,
1441
- Fields.created,
1442
- Fields.lastUpdated,
1443
- Fields.cmpId,
1444
- Fields.cmpVersion,
1445
- Fields.consentScreen,
1446
- Fields.consentLanguage,
1447
- Fields.vendorListVersion,
1448
- Fields.purposeConsents,
1449
- Fields.vendorConsents
1450
- ]
1451
- });
1452
- __publicField(this, "2", {
1453
- [Segment.CORE]: [
1454
- Fields.version,
1455
- Fields.created,
1456
- Fields.lastUpdated,
1457
- Fields.cmpId,
1458
- Fields.cmpVersion,
1459
- Fields.consentScreen,
1460
- Fields.consentLanguage,
1461
- Fields.vendorListVersion,
1462
- Fields.policyVersion,
1463
- Fields.isServiceSpecific,
1464
- Fields.useNonStandardTexts,
1465
- Fields.specialFeatureOptins,
1466
- Fields.purposeConsents,
1467
- Fields.purposeLegitimateInterests,
1468
- Fields.purposeOneTreatment,
1469
- Fields.publisherCountryCode,
1470
- Fields.vendorConsents,
1471
- Fields.vendorLegitimateInterests,
1472
- Fields.publisherRestrictions
1473
- ],
1474
- [Segment.PUBLISHER_TC]: [
1475
- Fields.publisherConsents,
1476
- Fields.publisherLegitimateInterests,
1477
- Fields.numCustomPurposes,
1478
- Fields.publisherCustomConsents,
1479
- Fields.publisherCustomLegitimateInterests
1480
- ],
1481
- [Segment.VENDORS_ALLOWED]: [
1482
- Fields.vendorsAllowed
1483
- ],
1484
- [Segment.VENDORS_DISCLOSED]: [
1485
- Fields.vendorsDisclosed
1486
- ]
1487
- });
1488
- }
1489
- }
1490
- class SegmentSequence {
1491
- constructor(tcModel, options) {
1492
- __publicField(this, "1", [
1493
- Segment.CORE
1494
- ]);
1495
- __publicField(this, "2", [
1496
- Segment.CORE
1497
- ]);
1498
- if (tcModel.version === 2) {
1499
- if (tcModel.isServiceSpecific) {
1500
- this["2"].push(Segment.PUBLISHER_TC);
1501
- } else {
1502
- const isForVendors = !!(options && options.isForVendors);
1503
- if (!isForVendors || tcModel[Fields.supportOOB] === true) {
1504
- this["2"].push(Segment.VENDORS_DISCLOSED);
1505
- }
1506
- if (isForVendors) {
1507
- if (tcModel[Fields.supportOOB] && tcModel[Fields.vendorsAllowed].size > 0) {
1508
- this["2"].push(Segment.VENDORS_ALLOWED);
1509
- }
1510
- this["2"].push(Segment.PUBLISHER_TC);
1511
- }
1512
- }
1513
- }
1514
- }
1515
- }
1516
- class SegmentEncoder {
1517
- static encode(tcModel, segment) {
1518
- let sequence;
1519
- try {
1520
- sequence = this.fieldSequence[String(tcModel.version)][segment];
1521
- } catch (err) {
1522
- throw new EncodingError(`Unable to encode version: ${tcModel.version}, segment: ${segment}`);
1523
- }
1524
- let bitField = "";
1525
- if (segment !== Segment.CORE) {
1526
- bitField = IntEncoder.encode(SegmentIDs.KEY_TO_ID[segment], BitLength.segmentType);
1527
- }
1528
- const fieldEncoderMap = FieldEncoderMap();
1529
- sequence.forEach((key) => {
1530
- const value = tcModel[key];
1531
- const encoder = fieldEncoderMap[key];
1532
- let numBits = BitLength[key];
1533
- if (numBits === void 0) {
1534
- if (this.isPublisherCustom(key)) {
1535
- numBits = Number(tcModel[Fields.numCustomPurposes]);
1536
- }
1537
- }
1538
- try {
1539
- bitField += encoder.encode(value, numBits);
1540
- } catch (err) {
1541
- throw new EncodingError(`Error encoding ${segment}->${key}: ${err.message}`);
1542
- }
1543
- });
1544
- return Base64Url.encode(bitField);
1545
- }
1546
- static decode(encodedString, tcModel, segment) {
1547
- const bitField = Base64Url.decode(encodedString);
1548
- let bStringIdx = 0;
1549
- if (segment === Segment.CORE) {
1550
- tcModel.version = IntEncoder.decode(bitField.substr(bStringIdx, BitLength[Fields.version]), BitLength[Fields.version]);
1551
- }
1552
- if (segment !== Segment.CORE) {
1553
- bStringIdx += BitLength.segmentType;
1554
- }
1555
- const sequence = this.fieldSequence[String(tcModel.version)][segment];
1556
- const fieldEncoderMap = FieldEncoderMap();
1557
- sequence.forEach((key) => {
1558
- const encoder = fieldEncoderMap[key];
1559
- let numBits = BitLength[key];
1560
- if (numBits === void 0) {
1561
- if (this.isPublisherCustom(key)) {
1562
- numBits = Number(tcModel[Fields.numCustomPurposes]);
1563
- }
1564
- }
1565
- if (numBits !== 0) {
1566
- const bits = bitField.substr(bStringIdx, numBits);
1567
- if (encoder === VendorVectorEncoder) {
1568
- tcModel[key] = encoder.decode(bits, tcModel.version);
1569
- } else {
1570
- tcModel[key] = encoder.decode(bits, numBits);
1571
- }
1572
- if (Number.isInteger(numBits)) {
1573
- bStringIdx += numBits;
1574
- } else if (Number.isInteger(tcModel[key].bitLength)) {
1575
- bStringIdx += tcModel[key].bitLength;
1576
- } else {
1577
- throw new DecodingError(key);
1578
- }
1579
- }
1580
- });
1581
- return tcModel;
1582
- }
1583
- static isPublisherCustom(key) {
1584
- return key.indexOf("publisherCustom") === 0;
1585
- }
1586
- }
1587
- __publicField(SegmentEncoder, "fieldSequence", new FieldSequence());
1588
- class SemanticPreEncoder {
1589
- static process(tcModel, options) {
1590
- const gvl = tcModel.gvl;
1591
- if (!gvl) {
1592
- throw new EncodingError("Unable to encode TCModel without a GVL");
1593
- }
1594
- if (!gvl.isReady) {
1595
- throw new EncodingError("Unable to encode TCModel tcModel.gvl.readyPromise is not resolved");
1596
- }
1597
- tcModel = tcModel.clone();
1598
- tcModel.consentLanguage = gvl.language.slice(0, 2).toUpperCase();
1599
- if ((options == null ? void 0 : options.version) > 0 && (options == null ? void 0 : options.version) <= this.processor.length) {
1600
- tcModel.version = options.version;
1601
- } else {
1602
- tcModel.version = this.processor.length;
1603
- }
1604
- const processorFunctionIndex = tcModel.version - 1;
1605
- if (!this.processor[processorFunctionIndex]) {
1606
- throw new EncodingError(`Invalid version: ${tcModel.version}`);
1607
- }
1608
- return this.processor[processorFunctionIndex](tcModel, gvl);
1609
- }
1610
- }
1611
- __publicField(SemanticPreEncoder, "processor", [
1612
- (tcModel) => tcModel,
1613
- (tcModel, gvl) => {
1614
- tcModel.publisherRestrictions.gvl = gvl;
1615
- tcModel.purposeLegitimateInterests.unset([1, 3, 4, 5, 6]);
1616
- const vectorToIntMap = /* @__PURE__ */ new Map();
1617
- vectorToIntMap.set("legIntPurposes", tcModel.vendorLegitimateInterests);
1618
- vectorToIntMap.set("purposes", tcModel.vendorConsents);
1619
- vectorToIntMap.forEach((vector, gvlVendorKey) => {
1620
- vector.forEach((value, vendorId) => {
1621
- if (value) {
1622
- const vendor = gvl.vendors[vendorId];
1623
- if (!vendor || vendor.deletedDate) {
1624
- vector.unset(vendorId);
1625
- } else if (vendor[gvlVendorKey].length === 0) {
1626
- if (gvlVendorKey === "legIntPurposes" && vendor["purposes"].length === 0 && vendor["legIntPurposes"].length === 0 && vendor["specialPurposes"].length > 0)
1627
- ;
1628
- else {
1629
- if (tcModel.isServiceSpecific) {
1630
- if (vendor.flexiblePurposes.length === 0) {
1631
- vector.unset(vendorId);
1632
- } else {
1633
- const restrictions = tcModel.publisherRestrictions.getRestrictions(vendorId);
1634
- let isValid = false;
1635
- for (let i = 0, len = restrictions.length; i < len && !isValid; i++) {
1636
- isValid = restrictions[i].restrictionType === RestrictionType.REQUIRE_CONSENT && gvlVendorKey === "purposes" || restrictions[i].restrictionType === RestrictionType.REQUIRE_LI && gvlVendorKey === "legIntPurposes";
1637
- }
1638
- if (!isValid) {
1639
- vector.unset(vendorId);
1640
- }
1641
- }
1642
- } else {
1643
- vector.unset(vendorId);
1644
- }
1645
- }
1646
- }
1647
- }
1648
- });
1649
- });
1650
- tcModel.vendorsDisclosed.set(gvl.vendors);
1651
- return tcModel;
1652
- }
1653
- ]);
1654
- class Json {
1655
- static absCall(url, body, sendCookies, timeout) {
1656
- return new Promise((resolve, reject) => {
1657
- const req = new XMLHttpRequest();
1658
- const onLoad = () => {
1659
- if (req.readyState == XMLHttpRequest.DONE) {
1660
- if (req.status >= 200 && req.status < 300) {
1661
- let response = req.response;
1662
- if (typeof response === "string") {
1663
- try {
1664
- response = JSON.parse(response);
1665
- } catch (e) {
1666
- }
1667
- }
1668
- resolve(response);
1669
- } else {
1670
- reject(new Error(`HTTP Status: ${req.status} response type: ${req.responseType}`));
1671
- }
1672
- }
1673
- };
1674
- const onError = () => {
1675
- reject(new Error("error"));
1676
- };
1677
- const onAbort = () => {
1678
- reject(new Error("aborted"));
1679
- };
1680
- const onTimeout = () => {
1681
- reject(new Error("Timeout " + timeout + "ms " + url));
1682
- };
1683
- req.withCredentials = sendCookies;
1684
- req.addEventListener("load", onLoad);
1685
- req.addEventListener("error", onError);
1686
- req.addEventListener("abort", onAbort);
1687
- if (body === null) {
1688
- req.open("GET", url, true);
1689
- } else {
1690
- req.open("POST", url, true);
1691
- }
1692
- req.responseType = "json";
1693
- req.timeout = timeout;
1694
- req.ontimeout = onTimeout;
1695
- req.send(body);
1696
- });
1697
- }
1698
- /**
1699
- * @static
1700
- * @param {string} url - full path to POST to
1701
- * @param {object} body - JSON object to post
1702
- * @param {boolean} sendCookies - Whether or not to send the XMLHttpRequest with credentials or not
1703
- * @param {number} [timeout] - optional timeout in milliseconds
1704
- * @return {Promise<object>} - if the server responds the response will be returned here
1705
- */
1706
- static post(url, body, sendCookies = false, timeout = 0) {
1707
- return this.absCall(url, JSON.stringify(body), sendCookies, timeout);
1708
- }
1709
- /**
1710
- * @static
1711
- * @param {string} url - full path to the json
1712
- * @param {boolean} sendCookies - Whether or not to send the XMLHttpRequest with credentials or not
1713
- * @param {number} [timeout] - optional timeout in milliseconds
1714
- * @return {Promise<object>} - resolves with parsed JSON
1715
- */
1716
- static fetch(url, sendCookies = false, timeout = 0) {
1717
- return this.absCall(url, null, sendCookies, timeout);
1718
- }
1719
- }
1720
- const _GVL = class _GVL extends Cloneable {
1721
- /**
1722
- * @param {VersionOrVendorList} [versionOrVendorList] - can be either a
1723
- * [[VendorList]] object or a version number represented as a string or
1724
- * number to download. If nothing is passed the latest version of the GVL
1725
- * will be loaded
1726
- */
1727
- constructor(versionOrVendorList) {
1728
- super();
1729
- /**
1730
- * @param {Promise} resolved when this GVL object is populated with the data
1731
- * or rejected if there is an error.
1732
- */
1733
- __publicField(this, "readyPromise");
1734
- /**
1735
- * @param {number} gvlSpecificationVersion - schema version for the GVL that is used
1736
- */
1737
- __publicField(this, "gvlSpecificationVersion");
1738
- /**
1739
- * @param {number} incremented with each published file change
1740
- */
1741
- __publicField(this, "vendorListVersion");
1742
- /**
1743
- * @param {number} tcfPolicyVersion - The TCF MO will increment this value
1744
- * whenever a GVL change (such as adding a new Purpose or Feature or a change
1745
- * in Purpose wording) legally invalidates existing TC Strings and requires
1746
- * CMPs to re-establish transparency and consent from users. If the policy
1747
- * version number in the latest GVL is different from the value in your TC
1748
- * String, then you need to re-establish transparency and consent for that
1749
- * user. A version 1 format TC String is considered to have a version value
1750
- * of 1.
1751
- */
1752
- __publicField(this, "tcfPolicyVersion");
1753
- /**
1754
- * @param {string | Date} lastUpdated - the date in which the vendor list
1755
- * json file was last updated.
1756
- */
1757
- __publicField(this, "lastUpdated");
1758
- /**
1759
- * @param {IntMap<Purpose>} a collection of [[Purpose]]s
1760
- */
1761
- __publicField(this, "purposes");
1762
- /**
1763
- * @param {IntMap<Purpose>} a collection of [[Purpose]]s
1764
- */
1765
- __publicField(this, "specialPurposes");
1766
- /**
1767
- * @param {IntMap<Feature>} a collection of [[Feature]]s
1768
- */
1769
- __publicField(this, "features");
1770
- /**
1771
- * @param {IntMap<Feature>} a collection of [[Feature]]s
1772
- */
1773
- __publicField(this, "specialFeatures");
1774
- /**
1775
- * @param {boolean} internal reference of when the GVL is ready to be used
1776
- */
1777
- __publicField(this, "isReady_", false);
1778
- /**
1779
- * @param {IntMap<Vendor>} a collection of [[Vendor]]s
1780
- */
1781
- __publicField(this, "vendors_");
1782
- __publicField(this, "vendorIds");
1783
- /**
1784
- * @param {IntMap<Vendor>} a collection of [[Vendor]]. Used as a backup if a whitelist is sets
1785
- */
1786
- __publicField(this, "fullVendorList");
1787
- /**
1788
- * @param {ByPurposeVendorMap} vendors by purpose
1789
- */
1790
- __publicField(this, "byPurposeVendorMap");
1791
- /**
1792
- * @param {IDSetMap} vendors by special purpose
1793
- */
1794
- __publicField(this, "bySpecialPurposeVendorMap");
1795
- /**
1796
- * @param {IDSetMap} vendors by feature
1797
- */
1798
- __publicField(this, "byFeatureVendorMap");
1799
- /**
1800
- * @param {IDSetMap} vendors by special feature
1801
- */
1802
- __publicField(this, "bySpecialFeatureVendorMap");
1803
- /**
1804
- * @param {IntMap<Stack>} a collection of [[Stack]]s
1805
- */
1806
- __publicField(this, "stacks");
1807
- /**
1808
- * @param {IntMap<DataCategory>} a collection of [[DataCategory]]s
1809
- */
1810
- __publicField(this, "dataCategories");
1811
- __publicField(this, "lang_");
1812
- __publicField(this, "cacheLang_");
1813
- __publicField(this, "isLatest", false);
1814
- let url = _GVL.baseUrl;
1815
- this.lang_ = _GVL.DEFAULT_LANGUAGE;
1816
- this.cacheLang_ = _GVL.DEFAULT_LANGUAGE;
1817
- if (this.isVendorList(versionOrVendorList)) {
1818
- this.populate(versionOrVendorList);
1819
- this.readyPromise = Promise.resolve();
1820
- } else {
1821
- if (!url) {
1822
- throw new GVLError("must specify GVL.baseUrl before loading GVL json");
1823
- }
1824
- if (versionOrVendorList > 0) {
1825
- const version2 = versionOrVendorList;
1826
- if (_GVL.CACHE.has(version2)) {
1827
- this.populate(_GVL.CACHE.get(version2));
1828
- this.readyPromise = Promise.resolve();
1829
- } else {
1830
- url += _GVL.versionedFilename.replace("[VERSION]", String(version2));
1831
- this.readyPromise = this.fetchJson(url);
1832
- }
1833
- } else {
1834
- if (_GVL.CACHE.has(_GVL.LATEST_CACHE_KEY)) {
1835
- this.populate(_GVL.CACHE.get(_GVL.LATEST_CACHE_KEY));
1836
- this.readyPromise = Promise.resolve();
1837
- } else {
1838
- this.isLatest = true;
1839
- this.readyPromise = this.fetchJson(url + _GVL.latestFilename);
1840
- }
1841
- }
1842
- }
1843
- }
1844
- /**
1845
- * baseUrl - Entities using the vendor-list.json are required by the iab to
1846
- * host their own copy of it to reduce the load on the iab's infrastructure
1847
- * so a 'base' url must be set to be put together with the versioning scheme
1848
- * of the filenames.
1849
- *
1850
- * @static
1851
- * @param {string} url - the base url to load the vendor-list.json from. This is
1852
- * broken out from the filename because it follows a different scheme for
1853
- * latest file vs versioned files.
1854
- *
1855
- * @throws {GVLError} - If the url is http[s]://vendorlist.consensu.org/...
1856
- * this will throw an error. IAB Europe requires that that CMPs and Vendors
1857
- * cache their own copies of the GVL to minimize load on their
1858
- * infrastructure. For more information regarding caching of the
1859
- * vendor-list.json, please see [the TCF documentation on 'Caching the Global
1860
- * Vendor List'
1861
- * ](https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20Consent%20string%20and%20vendor%20list%20formats%20v2.md#caching-the-global-vendor-list)
1862
- */
1863
- static set baseUrl(url) {
1864
- const notValid = /^https?:\/\/vendorlist\.consensu\.org\//;
1865
- if (notValid.test(url)) {
1866
- throw new GVLError("Invalid baseUrl! You may not pull directly from vendorlist.consensu.org and must provide your own cache");
1867
- }
1868
- if (url.length > 0 && url[url.length - 1] !== "/") {
1869
- url += "/";
1870
- }
1871
- this.baseUrl_ = url;
1872
- }
1873
- /**
1874
- * baseUrl - Entities using the vendor-list.json are required by the iab to
1875
- * host their own copy of it to reduce the load on the iab's infrastructure
1876
- * so a 'base' url must be set to be put together with the versioning scheme
1877
- * of the filenames.
1878
- *
1879
- * @static
1880
- * @return {string} - returns the previously set baseUrl, the default is
1881
- * `undefined`
1882
- */
1883
- static get baseUrl() {
1884
- return this.baseUrl_;
1885
- }
1886
- /**
1887
- * emptyLanguageCache
1888
- *
1889
- * @param {string} [lang] - Optional language code to remove from
1890
- * the cache. Should be one of the languages in GVL.consentLanguages set.
1891
- * If not then the whole cache will be deleted.
1892
- * @return {boolean} - true if anything was deleted from the cache
1893
- */
1894
- static emptyLanguageCache(lang) {
1895
- let result = false;
1896
- if (lang == null && _GVL.LANGUAGE_CACHE.size > 0) {
1897
- _GVL.LANGUAGE_CACHE = /* @__PURE__ */ new Map();
1898
- result = true;
1899
- } else if (typeof lang === "string" && this.consentLanguages.has(lang.toUpperCase())) {
1900
- _GVL.LANGUAGE_CACHE.delete(lang.toUpperCase());
1901
- result = true;
1902
- }
1903
- return result;
1904
- }
1905
- /**
1906
- * emptyCache
1907
- *
1908
- * @param {number} [vendorListVersion] - version of the vendor list to delete
1909
- * from the cache. If none is specified then the whole cache is deleted.
1910
- * @return {boolean} - true if anything was deleted from the cache
1911
- */
1912
- static emptyCache(vendorListVersion) {
1913
- let retr = false;
1914
- if (Number.isInteger(vendorListVersion) && vendorListVersion >= 0) {
1915
- _GVL.CACHE.delete(vendorListVersion);
1916
- retr = true;
1917
- } else if (vendorListVersion === void 0) {
1918
- _GVL.CACHE = /* @__PURE__ */ new Map();
1919
- retr = true;
1920
- }
1921
- return retr;
1922
- }
1923
- cacheLanguage() {
1924
- if (!_GVL.LANGUAGE_CACHE.has(this.cacheLang_)) {
1925
- _GVL.LANGUAGE_CACHE.set(this.cacheLang_, {
1926
- purposes: this.purposes,
1927
- specialPurposes: this.specialPurposes,
1928
- features: this.features,
1929
- specialFeatures: this.specialFeatures,
1930
- stacks: this.stacks,
1931
- dataCategories: this.dataCategories
1932
- });
1933
- }
1934
- }
1935
- async fetchJson(url) {
1936
- try {
1937
- this.populate(await Json.fetch(url));
1938
- } catch (err) {
1939
- throw new GVLError(err.message);
1940
- }
1941
- }
1942
- /**
1943
- * getJson - Method for getting the JSON that was downloaded to created this
1944
- * `GVL` object
1945
- *
1946
- * @return {VendorList} - The basic JSON structure without the extra
1947
- * functionality and methods of this class.
1948
- */
1949
- getJson() {
1950
- return JSON.parse(JSON.stringify({
1951
- gvlSpecificationVersion: this.gvlSpecificationVersion,
1952
- vendorListVersion: this.vendorListVersion,
1953
- tcfPolicyVersion: this.tcfPolicyVersion,
1954
- lastUpdated: this.lastUpdated,
1955
- purposes: this.purposes,
1956
- specialPurposes: this.specialPurposes,
1957
- features: this.features,
1958
- specialFeatures: this.specialFeatures,
1959
- stacks: this.stacks,
1960
- dataCategories: this.dataCategories,
1961
- vendors: this.fullVendorList
1962
- }));
1963
- }
1964
- /**
1965
- * changeLanguage - retrieves the purpose language translation and sets the
1966
- * internal language variable
1967
- *
1968
- * @param {string} lang - language code to change language to
1969
- * @return {Promise<void | GVLError>} - returns the `readyPromise` and
1970
- * resolves when this GVL is populated with the data from the language file.
1971
- */
1972
- async changeLanguage(lang) {
1973
- let parsedLanguage = lang;
1974
- try {
1975
- parsedLanguage = _GVL.consentLanguages.parseLanguage(lang);
1976
- } catch (e) {
1977
- throw new GVLError("Error during parsing the language: " + e.message);
1978
- }
1979
- const cacheLang = lang.toUpperCase();
1980
- if (parsedLanguage.toLowerCase() === _GVL.DEFAULT_LANGUAGE.toLowerCase() && !_GVL.LANGUAGE_CACHE.has(cacheLang)) {
1981
- return;
1982
- }
1983
- if (parsedLanguage !== this.lang_) {
1984
- this.lang_ = parsedLanguage;
1985
- if (_GVL.LANGUAGE_CACHE.has(cacheLang)) {
1986
- const cached = _GVL.LANGUAGE_CACHE.get(cacheLang);
1987
- for (const prop in cached) {
1988
- if (cached.hasOwnProperty(prop)) {
1989
- this[prop] = cached[prop];
1990
- }
1991
- }
1992
- } else {
1993
- const url = _GVL.baseUrl + _GVL.languageFilename.replace("[LANG]", this.lang_.toLowerCase());
1994
- try {
1995
- await this.fetchJson(url);
1996
- this.cacheLang_ = cacheLang;
1997
- this.cacheLanguage();
1998
- } catch (err) {
1999
- throw new GVLError("unable to load language: " + err.message);
2000
- }
2001
- }
2002
- }
2003
- }
2004
- get language() {
2005
- return this.lang_;
2006
- }
2007
- isVendorList(gvlObject) {
2008
- return gvlObject !== void 0 && gvlObject.vendors !== void 0;
2009
- }
2010
- populate(gvlObject) {
2011
- this.purposes = gvlObject.purposes;
2012
- this.specialPurposes = gvlObject.specialPurposes;
2013
- this.features = gvlObject.features;
2014
- this.specialFeatures = gvlObject.specialFeatures;
2015
- this.stacks = gvlObject.stacks;
2016
- this.dataCategories = gvlObject.dataCategories;
2017
- if (this.isVendorList(gvlObject)) {
2018
- this.gvlSpecificationVersion = gvlObject.gvlSpecificationVersion;
2019
- this.tcfPolicyVersion = gvlObject.tcfPolicyVersion;
2020
- this.vendorListVersion = gvlObject.vendorListVersion;
2021
- this.lastUpdated = gvlObject.lastUpdated;
2022
- if (typeof this.lastUpdated === "string") {
2023
- this.lastUpdated = new Date(this.lastUpdated);
2024
- }
2025
- this.vendors_ = gvlObject.vendors;
2026
- this.fullVendorList = gvlObject.vendors;
2027
- this.mapVendors();
2028
- this.isReady_ = true;
2029
- if (this.isLatest) {
2030
- _GVL.CACHE.set(_GVL.LATEST_CACHE_KEY, this.getJson());
2031
- }
2032
- if (!_GVL.CACHE.has(this.vendorListVersion)) {
2033
- _GVL.CACHE.set(this.vendorListVersion, this.getJson());
2034
- }
2035
- }
2036
- this.cacheLanguage();
2037
- }
2038
- mapVendors(vendorIds) {
2039
- this.byPurposeVendorMap = {};
2040
- this.bySpecialPurposeVendorMap = {};
2041
- this.byFeatureVendorMap = {};
2042
- this.bySpecialFeatureVendorMap = {};
2043
- Object.keys(this.purposes).forEach((purposeId) => {
2044
- this.byPurposeVendorMap[purposeId] = {
2045
- legInt: /* @__PURE__ */ new Set(),
2046
- consent: /* @__PURE__ */ new Set(),
2047
- flexible: /* @__PURE__ */ new Set()
2048
- };
2049
- });
2050
- Object.keys(this.specialPurposes).forEach((purposeId) => {
2051
- this.bySpecialPurposeVendorMap[purposeId] = /* @__PURE__ */ new Set();
2052
- });
2053
- Object.keys(this.features).forEach((featureId) => {
2054
- this.byFeatureVendorMap[featureId] = /* @__PURE__ */ new Set();
2055
- });
2056
- Object.keys(this.specialFeatures).forEach((featureId) => {
2057
- this.bySpecialFeatureVendorMap[featureId] = /* @__PURE__ */ new Set();
2058
- });
2059
- if (!Array.isArray(vendorIds)) {
2060
- vendorIds = Object.keys(this.fullVendorList).map((vId) => +vId);
2061
- }
2062
- this.vendorIds = new Set(vendorIds);
2063
- this.vendors_ = vendorIds.reduce((vendors, vendorId) => {
2064
- const vendor = this.vendors_[String(vendorId)];
2065
- if (vendor && vendor.deletedDate === void 0) {
2066
- vendor.purposes.forEach((purposeId) => {
2067
- const purpGroup = this.byPurposeVendorMap[String(purposeId)];
2068
- purpGroup.consent.add(vendorId);
2069
- });
2070
- vendor.specialPurposes.forEach((purposeId) => {
2071
- this.bySpecialPurposeVendorMap[String(purposeId)].add(vendorId);
2072
- });
2073
- vendor.legIntPurposes.forEach((purposeId) => {
2074
- this.byPurposeVendorMap[String(purposeId)].legInt.add(vendorId);
2075
- });
2076
- if (vendor.flexiblePurposes) {
2077
- vendor.flexiblePurposes.forEach((purposeId) => {
2078
- this.byPurposeVendorMap[String(purposeId)].flexible.add(vendorId);
2079
- });
2080
- }
2081
- vendor.features.forEach((featureId) => {
2082
- this.byFeatureVendorMap[String(featureId)].add(vendorId);
2083
- });
2084
- vendor.specialFeatures.forEach((featureId) => {
2085
- this.bySpecialFeatureVendorMap[String(featureId)].add(vendorId);
2086
- });
2087
- vendors[vendorId] = vendor;
2088
- }
2089
- return vendors;
2090
- }, {});
2091
- }
2092
- getFilteredVendors(purposeOrFeature, id, subType, special) {
2093
- const properPurposeOrFeature = purposeOrFeature.charAt(0).toUpperCase() + purposeOrFeature.slice(1);
2094
- let vendorSet;
2095
- const retr = {};
2096
- if (purposeOrFeature === "purpose" && subType) {
2097
- vendorSet = this["by" + properPurposeOrFeature + "VendorMap"][String(id)][subType];
2098
- } else {
2099
- vendorSet = this["by" + (special ? "Special" : "") + properPurposeOrFeature + "VendorMap"][String(id)];
2100
- }
2101
- vendorSet.forEach((vendorId) => {
2102
- retr[String(vendorId)] = this.vendors[String(vendorId)];
2103
- });
2104
- return retr;
2105
- }
2106
- /**
2107
- * getVendorsWithConsentPurpose
2108
- *
2109
- * @param {number} purposeId
2110
- * @return {IntMap<Vendor>} - list of vendors that have declared the consent purpose id
2111
- */
2112
- getVendorsWithConsentPurpose(purposeId) {
2113
- return this.getFilteredVendors("purpose", purposeId, "consent");
2114
- }
2115
- /**
2116
- * getVendorsWithLegIntPurpose
2117
- *
2118
- * @param {number} purposeId
2119
- * @return {IntMap<Vendor>} - list of vendors that have declared the legInt (Legitimate Interest) purpose id
2120
- */
2121
- getVendorsWithLegIntPurpose(purposeId) {
2122
- return this.getFilteredVendors("purpose", purposeId, "legInt");
2123
- }
2124
- /**
2125
- * getVendorsWithFlexiblePurpose
2126
- *
2127
- * @param {number} purposeId
2128
- * @return {IntMap<Vendor>} - list of vendors that have declared the flexible purpose id
2129
- */
2130
- getVendorsWithFlexiblePurpose(purposeId) {
2131
- return this.getFilteredVendors("purpose", purposeId, "flexible");
2132
- }
2133
- /**
2134
- * getVendorsWithSpecialPurpose
2135
- *
2136
- * @param {number} specialPurposeId
2137
- * @return {IntMap<Vendor>} - list of vendors that have declared the special purpose id
2138
- */
2139
- getVendorsWithSpecialPurpose(specialPurposeId) {
2140
- return this.getFilteredVendors("purpose", specialPurposeId, void 0, true);
2141
- }
2142
- /**
2143
- * getVendorsWithFeature
2144
- *
2145
- * @param {number} featureId
2146
- * @return {IntMap<Vendor>} - list of vendors that have declared the feature id
2147
- */
2148
- getVendorsWithFeature(featureId) {
2149
- return this.getFilteredVendors("feature", featureId);
2150
- }
2151
- /**
2152
- * getVendorsWithSpecialFeature
2153
- *
2154
- * @param {number} specialFeatureId
2155
- * @return {IntMap<Vendor>} - list of vendors that have declared the special feature id
2156
- */
2157
- getVendorsWithSpecialFeature(specialFeatureId) {
2158
- return this.getFilteredVendors("feature", specialFeatureId, void 0, true);
2159
- }
2160
- /**
2161
- * vendors
2162
- *
2163
- * @return {IntMap<Vendor>} - the list of vendors as it would on the JSON file
2164
- * except if `narrowVendorsTo` was called, it would be that narrowed list
2165
- */
2166
- get vendors() {
2167
- return this.vendors_;
2168
- }
2169
- /**
2170
- * narrowVendorsTo - narrows vendors represented in this GVL to the list of ids passed in
2171
- *
2172
- * @param {number[]} vendorIds - list of ids to narrow this GVL to
2173
- * @return {void}
2174
- */
2175
- narrowVendorsTo(vendorIds) {
2176
- this.mapVendors(vendorIds);
2177
- }
2178
- /**
2179
- * isReady - Whether or not this instance is ready to be used. This will be
2180
- * immediately and synchronously true if a vendorlist object is passed into
2181
- * the constructor or once the JSON vendorllist is retrieved.
2182
- *
2183
- * @return {boolean} whether or not the instance is ready to be interacted
2184
- * with and all the data is populated
2185
- */
2186
- get isReady() {
2187
- return this.isReady_;
2188
- }
2189
- /**
2190
- * clone - overrides base `clone()` method since GVL is a special class that
2191
- * represents a JSON structure with some additional functionality.
2192
- *
2193
- * @return {GVL}
2194
- */
2195
- clone() {
2196
- const result = new _GVL(this.getJson());
2197
- if (this.lang_ !== _GVL.DEFAULT_LANGUAGE) {
2198
- result.changeLanguage(this.lang_);
2199
- }
2200
- return result;
2201
- }
2202
- static isInstanceOf(questionableInstance) {
2203
- const isSo = typeof questionableInstance === "object";
2204
- return isSo && typeof questionableInstance.narrowVendorsTo === "function";
2205
- }
2206
- };
2207
- __publicField(_GVL, "LANGUAGE_CACHE", /* @__PURE__ */ new Map());
2208
- __publicField(_GVL, "CACHE", /* @__PURE__ */ new Map());
2209
- __publicField(_GVL, "LATEST_CACHE_KEY", 0);
2210
- __publicField(_GVL, "DEFAULT_LANGUAGE", "EN");
2211
- /**
2212
- * Set of available consent languages published by the IAB
2213
- */
2214
- __publicField(_GVL, "consentLanguages", new ConsentLanguages());
2215
- __publicField(_GVL, "baseUrl_");
2216
- /**
2217
- * @static
2218
- * @param {string} - the latest is assumed to be vendor-list.json because
2219
- * that is what the iab uses, but it could be different... if you want
2220
- */
2221
- __publicField(_GVL, "latestFilename", "vendor-list.json");
2222
- /**
2223
- * @static
2224
- * @param {string} - the versioned name is assumed to be
2225
- * vendor-list-v[VERSION].json where [VERSION] will be replaced with the
2226
- * specified version. But it could be different... if you want just make
2227
- * sure to include the [VERSION] macro if you have a numbering scheme, it's a
2228
- * simple string substitution.
2229
- *
2230
- * eg.
2231
- * ```javascript
2232
- * GVL.baseUrl = "http://www.mydomain.com/iabcmp/";
2233
- * GVL.versionedFilename = "vendorlist?getVersion=[VERSION]";
2234
- * ```
2235
- */
2236
- __publicField(_GVL, "versionedFilename", "archives/vendor-list-v[VERSION].json");
2237
- /**
2238
- * @param {string} - Translations of the names and descriptions for Purposes,
2239
- * Special Purposes, Features, and Special Features to non-English languages
2240
- * are contained in a file where attributes containing English content
2241
- * (except vendor declaration information) are translated. The iab publishes
2242
- * one following the scheme below where the LANG is the iso639-1 language
2243
- * code. For a list of available translations
2244
- * [please go here](https://register.consensu.org/Translation).
2245
- *
2246
- * eg.
2247
- * ```javascript
2248
- * GVL.baseUrl = "http://www.mydomain.com/iabcmp/";
2249
- * GVL.languageFilename = "purposes?getPurposes=[LANG]";
2250
- * ```
2251
- */
2252
- __publicField(_GVL, "languageFilename", "purposes-[LANG].json");
2253
- let GVL = _GVL;
2254
- class TCModel extends Cloneable {
2255
- /**
2256
- * Constructs the TCModel. Passing a [[GVL]] is optional when constructing
2257
- * as this TCModel may be constructed from decoding an existing encoded
2258
- * TCString.
2259
- *
2260
- * @param {GVL} [gvl]
2261
- */
2262
- constructor(gvl) {
2263
- super();
2264
- __publicField(this, "isServiceSpecific_", false);
2265
- __publicField(this, "supportOOB_", true);
2266
- __publicField(this, "useNonStandardTexts_", false);
2267
- __publicField(this, "purposeOneTreatment_", false);
2268
- __publicField(this, "publisherCountryCode_", "AA");
2269
- __publicField(this, "version_", 2);
2270
- __publicField(this, "consentScreen_", 0);
2271
- __publicField(this, "policyVersion_", 4);
2272
- __publicField(this, "consentLanguage_", "EN");
2273
- __publicField(this, "cmpId_", 0);
2274
- __publicField(this, "cmpVersion_", 0);
2275
- __publicField(this, "vendorListVersion_", 0);
2276
- __publicField(this, "numCustomPurposes_", 0);
2277
- // Member Variable for GVL
2278
- __publicField(this, "gvl_");
2279
- __publicField(this, "created");
2280
- __publicField(this, "lastUpdated");
2281
- /**
2282
- * The TCF designates certain Features as special, that is, a CMP must afford
2283
- * the user a means to opt in to their use. These Special Features are
2284
- * published and numbered in the GVL separately from normal Features.
2285
- * Provides for up to 12 special features.
2286
- */
2287
- __publicField(this, "specialFeatureOptins", new Vector());
2288
- /**
2289
- * Renamed from `PurposesAllowed` in TCF v1.1
2290
- * The user’s consent value for each Purpose established on the legal basis
2291
- * of consent. Purposes are published in the Global Vendor List (see. [[GVL]]).
2292
- */
2293
- __publicField(this, "purposeConsents", new Vector());
2294
- /**
2295
- * The user’s permission for each Purpose established on the legal basis of
2296
- * legitimate interest. If the user has exercised right-to-object for a
2297
- * purpose.
2298
- */
2299
- __publicField(this, "purposeLegitimateInterests", new Vector());
2300
- /**
2301
- * The user’s consent value for each Purpose established on the legal basis
2302
- * of consent, for the publisher. Purposes are published in the Global
2303
- * Vendor List.
2304
- */
2305
- __publicField(this, "publisherConsents", new Vector());
2306
- /**
2307
- * The user’s permission for each Purpose established on the legal basis of
2308
- * legitimate interest. If the user has exercised right-to-object for a
2309
- * purpose.
2310
- */
2311
- __publicField(this, "publisherLegitimateInterests", new Vector());
2312
- /**
2313
- * The user’s consent value for each Purpose established on the legal basis
2314
- * of consent, for the publisher. Purposes are published in the Global
2315
- * Vendor List.
2316
- */
2317
- __publicField(this, "publisherCustomConsents", new Vector());
2318
- /**
2319
- * The user’s permission for each Purpose established on the legal basis of
2320
- * legitimate interest. If the user has exercised right-to-object for a
2321
- * purpose that is established in the publisher's custom purposes.
2322
- */
2323
- __publicField(this, "publisherCustomLegitimateInterests", new Vector());
2324
- /**
2325
- * set by a publisher if they wish to collect consent and LI Transparency for
2326
- * purposes outside of the TCF
2327
- */
2328
- __publicField(this, "customPurposes");
2329
- /**
2330
- * Each [[Vendor]] is keyed by id. Their consent value is true if it is in
2331
- * the Vector
2332
- */
2333
- __publicField(this, "vendorConsents", new Vector());
2334
- /**
2335
- * Each [[Vendor]] is keyed by id. Whether their Legitimate Interests
2336
- * Disclosures have been established is stored as boolean.
2337
- * see: [[Vector]]
2338
- */
2339
- __publicField(this, "vendorLegitimateInterests", new Vector());
2340
- /**
2341
- * The value included for disclosed vendors signals which vendors have been
2342
- * disclosed to the user in the interface surfaced by the CMP. This section
2343
- * content is required when writing a TC string to the global (consensu)
2344
- * scope. When a CMP has read from and is updating a TC string from the
2345
- * global consensu.org storage, the CMP MUST retain the existing disclosure
2346
- * information and only add information for vendors that it has disclosed
2347
- * that had not been disclosed by other CMPs in prior interactions with this
2348
- * device/user agent.
2349
- */
2350
- __publicField(this, "vendorsDisclosed", new Vector());
2351
- /**
2352
- * Signals which vendors the publisher permits to use OOB legal bases.
2353
- */
2354
- __publicField(this, "vendorsAllowed", new Vector());
2355
- __publicField(this, "publisherRestrictions", new PurposeRestrictionVector());
2356
- if (gvl) {
2357
- this.gvl = gvl;
2358
- }
2359
- this.updated();
2360
- }
2361
- /**
2362
- * sets the [[GVL]] with side effects of also setting the `vendorListVersion`, `policyVersion`, and `consentLanguage`
2363
- * @param {GVL} gvl
2364
- */
2365
- set gvl(gvl) {
2366
- if (!GVL.isInstanceOf(gvl)) {
2367
- gvl = new GVL(gvl);
2368
- }
2369
- this.gvl_ = gvl;
2370
- this.publisherRestrictions.gvl = gvl;
2371
- }
2372
- /**
2373
- * @return {GVL} the gvl instance set on this TCModel instance
2374
- */
2375
- get gvl() {
2376
- return this.gvl_;
2377
- }
2378
- /**
2379
- * @param {number} integer - A unique ID will be assigned to each Consent
2380
- * Manager Provider (CMP) from the iab.
2381
- *
2382
- * @throws {TCModelError} if the value is not an integer greater than 1 as those are not valid.
2383
- */
2384
- set cmpId(integer) {
2385
- integer = Number(integer);
2386
- if (Number.isInteger(integer) && integer > 1) {
2387
- this.cmpId_ = integer;
2388
- } else {
2389
- throw new TCModelError("cmpId", integer);
2390
- }
2391
- }
2392
- get cmpId() {
2393
- return this.cmpId_;
2394
- }
2395
- /**
2396
- * Each change to an operating CMP should receive a
2397
- * new version number, for logging proof of consent. CmpVersion defined by
2398
- * each CMP.
2399
- *
2400
- * @param {number} integer
2401
- *
2402
- * @throws {TCModelError} if the value is not an integer greater than 1 as those are not valid.
2403
- */
2404
- set cmpVersion(integer) {
2405
- integer = Number(integer);
2406
- if (Number.isInteger(integer) && integer > -1) {
2407
- this.cmpVersion_ = integer;
2408
- } else {
2409
- throw new TCModelError("cmpVersion", integer);
2410
- }
2411
- }
2412
- get cmpVersion() {
2413
- return this.cmpVersion_;
2414
- }
2415
- /**
2416
- * The screen number is CMP and CmpVersion
2417
- * specific, and is for logging proof of consent.(For example, a CMP could
2418
- * keep records so that a publisher can request information about the context
2419
- * in which consent was gathered.)
2420
- *
2421
- * @param {number} integer
2422
- *
2423
- * @throws {TCModelError} if the value is not an integer greater than 0 as those are not valid.
2424
- */
2425
- set consentScreen(integer) {
2426
- integer = Number(integer);
2427
- if (Number.isInteger(integer) && integer > -1) {
2428
- this.consentScreen_ = integer;
2429
- } else {
2430
- throw new TCModelError("consentScreen", integer);
2431
- }
2432
- }
2433
- get consentScreen() {
2434
- return this.consentScreen_;
2435
- }
2436
- /**
2437
- * @param {string} lang - [two-letter ISO 639-1 language
2438
- * code](http://www.loc.gov/standards/iso639-2/php/code_list.php) in which
2439
- * the CMP UI was presented
2440
- *
2441
- * @throws {TCModelError} if the value is not a length-2 string of alpha characters
2442
- */
2443
- set consentLanguage(lang) {
2444
- this.consentLanguage_ = lang;
2445
- }
2446
- get consentLanguage() {
2447
- return this.consentLanguage_;
2448
- }
2449
- /**
2450
- * @param {string} countryCode - [two-letter ISO 3166-1 alpha-2 country
2451
- * code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) of the publisher,
2452
- * determined by the CMP-settings of the publisher.
2453
- *
2454
- * @throws {TCModelError} if the value is not a length-2 string of alpha characters
2455
- */
2456
- set publisherCountryCode(countryCode) {
2457
- if (/^([A-z]){2}$/.test(countryCode)) {
2458
- this.publisherCountryCode_ = countryCode.toUpperCase();
2459
- } else {
2460
- throw new TCModelError("publisherCountryCode", countryCode);
2461
- }
2462
- }
2463
- get publisherCountryCode() {
2464
- return this.publisherCountryCode_;
2465
- }
2466
- /**
2467
- * Version of the GVL used to create this TCModel. Global
2468
- * Vendor List versions will be released periodically.
2469
- *
2470
- * @param {number} integer
2471
- *
2472
- * @throws {TCModelError} if the value is not an integer greater than 0 as those are not valid.
2473
- */
2474
- set vendorListVersion(integer) {
2475
- integer = Number(integer) >> 0;
2476
- if (integer < 0) {
2477
- throw new TCModelError("vendorListVersion", integer);
2478
- } else {
2479
- this.vendorListVersion_ = integer;
2480
- }
2481
- }
2482
- get vendorListVersion() {
2483
- if (this.gvl) {
2484
- return this.gvl.vendorListVersion;
2485
- } else {
2486
- return this.vendorListVersion_;
2487
- }
2488
- }
2489
- /**
2490
- * From the corresponding field in the GVL that was
2491
- * used for obtaining consent. A new policy version invalidates existing
2492
- * strings and requires CMPs to re-establish transparency and consent from
2493
- * users.
2494
- *
2495
- * If a TCF policy version number is different from the one from the latest
2496
- * GVL, the CMP must re-establish transparency and consent.
2497
- *
2498
- * @param {number} num - You do not need to set this. This comes
2499
- * directly from the [[GVL]].
2500
- *
2501
- */
2502
- set policyVersion(num) {
2503
- this.policyVersion_ = parseInt(num, 10);
2504
- if (this.policyVersion_ < 0) {
2505
- throw new TCModelError("policyVersion", num);
2506
- }
2507
- }
2508
- get policyVersion() {
2509
- if (this.gvl) {
2510
- return this.gvl.tcfPolicyVersion;
2511
- } else {
2512
- return this.policyVersion_;
2513
- }
2514
- }
2515
- set version(num) {
2516
- this.version_ = parseInt(num, 10);
2517
- }
2518
- get version() {
2519
- return this.version_;
2520
- }
2521
- /**
2522
- * Whether the signals encoded in this TC String were from site-specific
2523
- * storage `true` versus ‘global’ consensu.org shared storage `false`. A
2524
- * string intended to be stored in global/shared scope but the CMP is unable
2525
- * to store due to a user agent not accepting third-party cookies would be
2526
- * considered site-specific `true`.
2527
- *
2528
- * @param {boolean} bool - value to set. Some changes to other fields in this
2529
- * model will automatically change this value like adding publisher
2530
- * restrictions.
2531
- */
2532
- set isServiceSpecific(bool) {
2533
- this.isServiceSpecific_ = bool;
2534
- }
2535
- get isServiceSpecific() {
2536
- return this.isServiceSpecific_;
2537
- }
2538
- /**
2539
- * Non-standard stacks means that a CMP is using publisher-customized stack
2540
- * descriptions. Stacks (in terms of purposes in a stack) are pre-set by the
2541
- * IAB. As are titles. Descriptions are pre-set, but publishers can customize
2542
- * them. If they do, they need to set this bit to indicate that they've
2543
- * customized descriptions.
2544
- *
2545
- * @param {boolean} bool - value to set
2546
- */
2547
- set useNonStandardTexts(bool) {
2548
- this.useNonStandardTexts_ = bool;
2549
- }
2550
- get useNonStandardTexts() {
2551
- return this.useNonStandardTexts_;
2552
- }
2553
- /**
2554
- * Whether or not this publisher supports OOB signaling. On Global TC String
2555
- * OOB Vendors Disclosed will be included if the publish wishes to no allow
2556
- * these vendors they should set this to false.
2557
- * @param {boolean} bool - value to set
2558
- */
2559
- set supportOOB(bool) {
2560
- this.supportOOB_ = bool;
2561
- }
2562
- get supportOOB() {
2563
- return this.supportOOB_;
2564
- }
2565
- /**
2566
- * `false` There is no special Purpose 1 status.
2567
- * Purpose 1 was disclosed normally (consent) as expected by Policy. `true`
2568
- * Purpose 1 not disclosed at all. CMPs use PublisherCC to indicate the
2569
- * publisher’s country of establishment to help Vendors determine whether the
2570
- * vendor requires Purpose 1 consent. In global scope TC strings, this field
2571
- * must always have a value of `false`. When a CMP encounters a global scope
2572
- * string with `purposeOneTreatment=true` then that string should be
2573
- * considered invalid and the CMP must re-establish transparency and consent.
2574
- *
2575
- * @param {boolean} bool
2576
- */
2577
- set purposeOneTreatment(bool) {
2578
- this.purposeOneTreatment_ = bool;
2579
- }
2580
- get purposeOneTreatment() {
2581
- return this.purposeOneTreatment_;
2582
- }
2583
- /**
2584
- * setAllVendorConsents - sets all vendors on the GVL Consent (true)
2585
- *
2586
- * @return {void}
2587
- */
2588
- setAllVendorConsents() {
2589
- this.vendorConsents.set(this.gvl.vendors);
2590
- }
2591
- /**
2592
- * unsetAllVendorConsents - unsets all vendors on the GVL Consent (false)
2593
- *
2594
- * @return {void}
2595
- */
2596
- unsetAllVendorConsents() {
2597
- this.vendorConsents.empty();
2598
- }
2599
- /**
2600
- * setAllVendorsDisclosed - sets all vendors on the GVL Vendors Disclosed (true)
2601
- *
2602
- * @return {void}
2603
- */
2604
- setAllVendorsDisclosed() {
2605
- this.vendorsDisclosed.set(this.gvl.vendors);
2606
- }
2607
- /**
2608
- * unsetAllVendorsDisclosed - unsets all vendors on the GVL Consent (false)
2609
- *
2610
- * @return {void}
2611
- */
2612
- unsetAllVendorsDisclosed() {
2613
- this.vendorsDisclosed.empty();
2614
- }
2615
- /**
2616
- * setAllVendorsAllowed - sets all vendors on the GVL Consent (true)
2617
- *
2618
- * @return {void}
2619
- */
2620
- setAllVendorsAllowed() {
2621
- this.vendorsAllowed.set(this.gvl.vendors);
2622
- }
2623
- /**
2624
- * unsetAllVendorsAllowed - unsets all vendors on the GVL Consent (false)
2625
- *
2626
- * @return {void}
2627
- */
2628
- unsetAllVendorsAllowed() {
2629
- this.vendorsAllowed.empty();
2630
- }
2631
- /**
2632
- * setAllVendorLegitimateInterests - sets all vendors on the GVL LegitimateInterests (true)
2633
- *
2634
- * @return {void}
2635
- */
2636
- setAllVendorLegitimateInterests() {
2637
- this.vendorLegitimateInterests.set(this.gvl.vendors);
2638
- }
2639
- /**
2640
- * unsetAllVendorLegitimateInterests - unsets all vendors on the GVL LegitimateInterests (false)
2641
- *
2642
- * @return {void}
2643
- */
2644
- unsetAllVendorLegitimateInterests() {
2645
- this.vendorLegitimateInterests.empty();
2646
- }
2647
- /**
2648
- * setAllPurposeConsents - sets all purposes on the GVL Consent (true)
2649
- *
2650
- * @return {void}
2651
- */
2652
- setAllPurposeConsents() {
2653
- this.purposeConsents.set(this.gvl.purposes);
2654
- }
2655
- /**
2656
- * unsetAllPurposeConsents - unsets all purposes on the GVL Consent (false)
2657
- *
2658
- * @return {void}
2659
- */
2660
- unsetAllPurposeConsents() {
2661
- this.purposeConsents.empty();
2662
- }
2663
- /**
2664
- * setAllPurposeLegitimateInterests - sets all purposes on the GVL LI Transparency (true)
2665
- *
2666
- * @return {void}
2667
- */
2668
- setAllPurposeLegitimateInterests() {
2669
- this.purposeLegitimateInterests.set(this.gvl.purposes);
2670
- }
2671
- /**
2672
- * unsetAllPurposeLegitimateInterests - unsets all purposes on the GVL LI Transparency (false)
2673
- *
2674
- * @return {void}
2675
- */
2676
- unsetAllPurposeLegitimateInterests() {
2677
- this.purposeLegitimateInterests.empty();
2678
- }
2679
- /**
2680
- * setAllSpecialFeatureOptins - sets all special featuresOptins on the GVL (true)
2681
- *
2682
- * @return {void}
2683
- */
2684
- setAllSpecialFeatureOptins() {
2685
- this.specialFeatureOptins.set(this.gvl.specialFeatures);
2686
- }
2687
- /**
2688
- * unsetAllSpecialFeatureOptins - unsets all special featuresOptins on the GVL (true)
2689
- *
2690
- * @return {void}
2691
- */
2692
- unsetAllSpecialFeatureOptins() {
2693
- this.specialFeatureOptins.empty();
2694
- }
2695
- setAll() {
2696
- this.setAllVendorConsents();
2697
- this.setAllPurposeLegitimateInterests();
2698
- this.setAllSpecialFeatureOptins();
2699
- this.setAllPurposeConsents();
2700
- this.setAllVendorLegitimateInterests();
2701
- }
2702
- unsetAll() {
2703
- this.unsetAllVendorConsents();
2704
- this.unsetAllPurposeLegitimateInterests();
2705
- this.unsetAllSpecialFeatureOptins();
2706
- this.unsetAllPurposeConsents();
2707
- this.unsetAllVendorLegitimateInterests();
2708
- }
2709
- get numCustomPurposes() {
2710
- let len = this.numCustomPurposes_;
2711
- if (typeof this.customPurposes === "object") {
2712
- const purposeIds = Object.keys(this.customPurposes).sort((a, b) => Number(a) - Number(b));
2713
- len = parseInt(purposeIds.pop(), 10);
2714
- }
2715
- return len;
2716
- }
2717
- set numCustomPurposes(num) {
2718
- this.numCustomPurposes_ = parseInt(num, 10);
2719
- if (this.numCustomPurposes_ < 0) {
2720
- throw new TCModelError("numCustomPurposes", num);
2721
- }
2722
- }
2723
- /**
2724
- * updated - updates the created and lastUpdated dates with a 'now' day-level UTC timestamp
2725
- *
2726
- * @return {void}
2727
- */
2728
- updated() {
2729
- const date = /* @__PURE__ */ new Date();
2730
- const utcDate = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
2731
- this.created = utcDate;
2732
- this.lastUpdated = utcDate;
2733
- }
2734
- }
2735
- /**
2736
- * Set of available consent languages published by the IAB
2737
- */
2738
- __publicField(TCModel, "consentLanguages", GVL.consentLanguages);
2739
- class TCString {
2740
- /**
2741
- * encodes a model into a TCString
2742
- *
2743
- * @param {TCModel} tcModel - model to convert into encoded string
2744
- * @param {EncodingOptions} options - for encoding options other than default
2745
- * @return {string} - base64url encoded Transparency and Consent String
2746
- */
2747
- static encode(tcModel, options) {
2748
- let out = "";
2749
- let sequence;
2750
- tcModel = SemanticPreEncoder.process(tcModel, options);
2751
- if (Array.isArray(options == null ? void 0 : options.segments)) {
2752
- sequence = options.segments;
2753
- } else {
2754
- sequence = new SegmentSequence(tcModel, options)["" + tcModel.version];
2755
- }
2756
- sequence.forEach((segment, idx) => {
2757
- let dotMaybe = "";
2758
- if (idx < sequence.length - 1) {
2759
- dotMaybe = ".";
2760
- }
2761
- out += SegmentEncoder.encode(tcModel, segment) + dotMaybe;
2762
- });
2763
- return out;
2764
- }
2765
- /**
2766
- * Decodes a string into a TCModel
2767
- *
2768
- * @param {string} encodedTCString - base64url encoded Transparency and
2769
- * Consent String to decode - can also be a single or group of segments of
2770
- * the string
2771
- * @param {string} [tcModel] - model to enhance with the information. If
2772
- * none is passed a new instance of TCModel will be created.
2773
- * @return {TCModel} - Returns populated TCModel
2774
- */
2775
- static decode(encodedTCString, tcModel) {
2776
- const segments = encodedTCString.split(".");
2777
- const len = segments.length;
2778
- if (!tcModel) {
2779
- tcModel = new TCModel();
2780
- }
2781
- for (let i = 0; i < len; i++) {
2782
- const segString = segments[i];
2783
- const firstChar = Base64Url.decode(segString.charAt(0));
2784
- const segTypeBits = firstChar.substr(0, BitLength.segmentType);
2785
- const segment = SegmentIDs.ID_TO_KEY[IntEncoder.decode(segTypeBits, BitLength.segmentType).toString()];
2786
- SegmentEncoder.decode(segString, tcModel, segment);
2787
- }
2788
- return tcModel;
2789
- }
2790
- }
2791
- function isValidGdprValue(val) {
2792
- if (val === null) {
2793
- return true;
2794
- }
2795
- try {
2796
- TCString.decode(val);
2797
- return true;
2798
- } catch (error) {
2799
- return false;
2800
- }
2801
- }
2802
- function isValidUspString(val) {
2803
- if (val === null) {
2804
- return true;
2805
- }
2806
- const regex = /^[1-9][YN-][YN-][YN-]$/;
2807
- return regex.test(val);
2808
- }
2809
- function validateRawConsentState(input) {
2810
- if (typeof input !== "object" || input === null) {
2811
- throw new Error("Invalid consent state object");
2812
- }
2813
- if (!isValidGdprValue(input.gdpr)) {
2814
- throw new Error("Invalid TC string provided");
2815
- }
2816
- if (!isValidUspString(input.ccpa)) {
2817
- throw new Error("Invalid USP string provided");
2818
- }
2819
- if (!["ccpa", "gdpr"].includes(input.activeLegislation)) {
2820
- throw new Error("Active legislation is required");
2821
- }
2822
- if (input.gdpr === void 0 && input.ccpa === void 0) {
2823
- throw new Error("Either GDPR or CCPA consent must be provided");
2824
- }
2825
- return true;
2826
- }
2827
- function validateIabConsentCategory(categoryName) {
2828
- if (!categoryName || categoryName in iabCustomCategories === false) {
2829
- throw new Error("Provided custom category identifier does not exist. Please check");
2830
- }
2831
- }
2832
- function checkConsentFor(categoryName, consentState) {
2833
- validateIabConsentCategory(categoryName);
2834
- validateRawConsentState(consentState);
2835
- const { gdpr, ccpa, activeLegislation } = consentState;
351
+ function checkConsentFor(categoryName, { purpose, vendor, specialFeatureOptins }) {
2836
352
  const customCategory = iabCustomCategories[categoryName];
2837
- if (activeLegislation === legislation.CCPA) {
2838
- const userHasNotOptedOut = (ccpa == null ? void 0 : ccpa[2]) === "N";
2839
- return userHasNotOptedOut;
2840
- }
2841
- const decodedGdprConsent = TCString.decode(gdpr);
2842
- const { purposeConsents, vendorConsents, specialFeatureOptins } = decodedGdprConsent;
2843
353
  const requiredPurposesConsented = customCategory.purposes.every(
2844
- (requiredPurpose) => purposeConsents.has(requiredPurpose)
354
+ (requiredPurpose) => (purpose == null ? void 0 : purpose.consents[requiredPurpose]) === true
2845
355
  );
2846
356
  const requiredIabVendorsConsented = customCategory.iabVendors.every(
2847
- (requiredVendor) => vendorConsents.has(requiredVendor)
357
+ (requiredVendor) => (vendor == null ? void 0 : vendor.consents[requiredVendor]) === true
2848
358
  );
2849
359
  const requiredSpecialFeaturesConsented = customCategory.specialFeatures.every(
2850
- (requiredFeature) => specialFeatureOptins.has(requiredFeature)
360
+ (requiredFeature) => (specialFeatureOptins == null ? void 0 : specialFeatureOptins[requiredFeature]) === true
2851
361
  );
2852
362
  return requiredPurposesConsented && requiredIabVendorsConsented && requiredSpecialFeaturesConsented;
2853
363
  }
2854
- function getParsedConsent(rawConsentState) {
2855
- const categoryNames = Object.keys(iabCustomCategories);
2856
- return categoryNames.reduce((parsedConsent, categoryName) => {
2857
- parsedConsent[categoryName] = checkConsentFor(categoryName, rawConsentState);
2858
- return parsedConsent;
2859
- }, {});
364
+ function parseCCPAConsent(ccpa) {
365
+ const userHasNotOptedOut = (ccpa == null ? void 0 : ccpa[2]) === "N";
366
+ const parsedConsent = {};
367
+ for (const categoryName of iabCategoryNames) {
368
+ parsedConsent[categoryName] = userHasNotOptedOut;
369
+ }
370
+ return parsedConsent;
371
+ }
372
+ async function parseGDPRConsent() {
373
+ const tcData = await new Promise((resolve, reject) => {
374
+ var _a;
375
+ try {
376
+ (_a = window.__tcfapi) == null ? void 0 : _a.call(window, "addEventListener", 2, resolve);
377
+ } catch (error) {
378
+ reject(error);
379
+ }
380
+ });
381
+ const parsedConsent = {};
382
+ for (const categoryName of iabCategoryNames) {
383
+ parsedConsent[categoryName] = checkConsentFor(categoryName, tcData);
384
+ }
385
+ return parsedConsent;
386
+ }
387
+ async function getParsedConsent(activeLegislation, consentString) {
388
+ return activeLegislation === "ccpa" ? parseCCPAConsent(consentString) : await parseGDPRConsent();
2860
389
  }
2861
390
  function getConsentCookieValue() {
2862
391
  const cookies = Object.fromEntries(
@@ -2874,14 +403,22 @@ function getConsentCookieValue() {
2874
403
  })
2875
404
  );
2876
405
  }
2877
- function hasConsentChanged(parsedConsent) {
406
+ function hasConsentChanged(parsedConsent, previousConsent) {
2878
407
  const categories = Object.keys(parsedConsent);
2879
- const previousConsent = getConsentCookieValue();
2880
408
  return categories.some((category) => {
2881
409
  const adaptedCategoryName = `${category.toLowerCase()}Onsite`;
2882
410
  return parsedConsent[category] !== previousConsent[adaptedCategoryName];
2883
411
  });
2884
412
  }
413
+ function shouldUpdateConsentStore({ userId, useConsentStore }) {
414
+ return !!userId && useConsentStore === true;
415
+ }
416
+ function getConsentEndpoint(updateConsentStore, props) {
417
+ if (updateConsentStore) {
418
+ return `${props.consentProxyHost}/__consent/consent-record/${SOURCEPOINT_FOW_SCOPE}/${props.userId}`;
419
+ }
420
+ return `${props.consentProxyHost}/__consent/consent-record-cookie?cookieDomain=${props.cookieDomain}`;
421
+ }
2885
422
  async function saveConsent(consentEndpoint, payload) {
2886
423
  try {
2887
424
  const response = await fetch(consentEndpoint, {
@@ -2900,78 +437,29 @@ async function saveConsent(consentEndpoint, payload) {
2900
437
  }
2901
438
  }
2902
439
  function consentReadyHandlerFn(props) {
2903
- const { userId, consentProxyHost, cookieDomain, formOfWordsId, useConsentStore } = props;
2904
- return async function consentReadyHandler(legislation2, _consentUUID, consentString, consentMeta) {
2905
- const activeLegislation = consentMeta.applies ? legislation2 : "gdpr";
2906
- if (activeLegislation !== legislation2 || !consentString) {
440
+ return async function consentReadyHandler(legislation, _consentUUID, consentString, consentMeta) {
441
+ const activeLegislation = consentMeta.applies ? legislation : "gdpr";
442
+ if (activeLegislation !== legislation || !consentString) {
2907
443
  return;
2908
444
  }
2909
- const parsedConsent = getParsedConsent({
2910
- activeLegislation,
2911
- gdpr: activeLegislation === "gdpr" ? consentString : null,
2912
- ccpa: activeLegislation === "ccpa" ? consentString : null
2913
- });
2914
- const consentHasChanged = hasConsentChanged(parsedConsent);
445
+ const parsedConsent = await getParsedConsent(activeLegislation, consentString);
446
+ const consentHasChanged = hasConsentChanged(parsedConsent, getConsentCookieValue());
2915
447
  if (!consentHasChanged) {
2916
448
  return;
2917
449
  }
2918
- let consentEndpoint = `${consentProxyHost}/__consent/consent-record-cookie?cookieDomain=${cookieDomain}`;
2919
- const shouldUpdateConsentStore = !!userId && useConsentStore;
2920
- if (shouldUpdateConsentStore) {
2921
- consentEndpoint = `${consentProxyHost}/__consent/consent-record/${SOURCEPOINT_FOW_SCOPE}/${userId}`;
2922
- }
2923
- const payload = getConsentPayload(parsedConsent, {
2924
- formOfWordsId,
2925
- cookieDomain,
2926
- shouldUpdateConsentStore
2927
- });
450
+ const updateConsentStore = shouldUpdateConsentStore(props);
451
+ const consentEndpoint = getConsentEndpoint(updateConsentStore, props);
452
+ const payload = getConsentPayload(parsedConsent, updateConsentStore, props);
2928
453
  await saveConsent(consentEndpoint, payload);
2929
454
  document.dispatchEvent(new CustomEvent("oCookieMessage.act", { bubbles: true }));
2930
455
  };
2931
456
  }
2932
- let getRandomValues;
2933
- const rnds8 = new Uint8Array(16);
2934
- function rng() {
2935
- if (!getRandomValues) {
2936
- getRandomValues = typeof crypto !== "undefined" && crypto.getRandomValues && crypto.getRandomValues.bind(crypto);
2937
- if (!getRandomValues) {
2938
- throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
2939
- }
2940
- }
2941
- return getRandomValues(rnds8);
2942
- }
2943
- const byteToHex = [];
2944
- for (let i = 0; i < 256; ++i) {
2945
- byteToHex.push((i + 256).toString(16).slice(1));
2946
- }
2947
- function unsafeStringify(arr, offset = 0) {
2948
- return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
2949
- }
2950
- const randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
2951
- const native = {
2952
- randomUUID
2953
- };
2954
- function v4(options, buf, offset) {
2955
- if (native.randomUUID && !buf && !options) {
2956
- return native.randomUUID();
2957
- }
2958
- options = options || {};
2959
- const rnds = options.random || (options.rng || rng)();
2960
- rnds[6] = rnds[6] & 15 | 64;
2961
- rnds[8] = rnds[8] & 63 | 128;
2962
- if (buf) {
2963
- offset = offset || 0;
2964
- for (let i = 0; i < 16; ++i) {
2965
- buf[offset + i] = rnds[i];
2966
- }
2967
- return buf;
2968
- }
2969
- return unsafeStringify(rnds);
2970
- }
2971
457
  const COOKIE_MESSAGE = "cookie-message";
2972
458
  const PRIVACY_MANAGER = "manage-cookies";
2973
459
  const INITIAL_STATE = Object.freeze({
2974
- activeComponent: COOKIE_MESSAGE
460
+ activeComponent: COOKIE_MESSAGE,
461
+ messageId: 0,
462
+ privacyManagerId: 0
2975
463
  });
2976
464
  let privateState = INITIAL_STATE;
2977
465
  function isPlainObject(obj) {
@@ -2985,20 +473,17 @@ const setState = (newState) => {
2985
473
  }
2986
474
  privateState = { ...privateState, ...newState };
2987
475
  };
2988
- const ACCEPT_ALL_CHOICE = 11;
2989
- const MANAGE_PREFS_CHOICE = 12;
2990
- const REJECT_ALL_CHOICE = 13;
2991
476
  const cookieToggleFlags = ["adsDisableInternalCMP", "pwm.cmp", "messageSlotBottom"];
2992
- function initTracking(context) {
2993
- const componentId = v4();
477
+ function initTracking(context, cmpBaseEndpoint) {
2994
478
  const flags = extractRelevantFlags(context.flags);
2995
479
  window._sp_queue = window._sp_queue ?? [];
2996
480
  window._sp_queue.push(() => {
2997
- var _a2, _b2;
481
+ var _a, _b;
2998
482
  for (const [eventId, eventHandler] of Object.entries(trackingEventHandlers)) {
2999
- (_b2 = (_a2 = window._sp_).addEventListener) == null ? void 0 : _b2.call(_a2, eventId, eventHandler({ ...context, flags, componentId }));
483
+ (_b = (_a = window._sp_).addEventListener) == null ? void 0 : _b.call(_a, eventId, eventHandler({ ...context, flags }));
3000
484
  }
3001
485
  });
486
+ setupPmTracking({ ...context, flags }, cmpBaseEndpoint);
3002
487
  }
3003
488
  function extractRelevantFlags(flags) {
3004
489
  const output = {};
@@ -3025,19 +510,23 @@ function track(payload) {
3025
510
  function dispatchComponentEvent({
3026
511
  trackingProps,
3027
512
  action,
3028
- triggerAction,
3029
- messageType
513
+ triggerAction
3030
514
  }) {
515
+ let componentId;
3031
516
  const state = getState();
3032
- const { componentId, product, app, flags } = trackingProps;
517
+ const { product, app, flags } = trackingProps;
518
+ if (state.activeComponent === COOKIE_MESSAGE) {
519
+ componentId = state.messageId;
520
+ } else {
521
+ componentId = state.privacyManagerId;
522
+ }
3033
523
  const event = {
3034
524
  detail: {
3035
525
  component: {
3036
526
  id: componentId,
3037
527
  name: state.activeComponent,
3038
528
  type: "overlay",
3039
- subtype: "cmp",
3040
- componentContentId: state[messageType]
529
+ subtype: "cmp"
3041
530
  },
3042
531
  category: "component",
3043
532
  action,
@@ -3048,127 +537,87 @@ function dispatchComponentEvent({
3048
537
  {
3049
538
  cookie_toggle_flag: flags
3050
539
  }
3051
- ]
540
+ ],
541
+ url: window.document.location.href || null
3052
542
  }
3053
543
  };
3054
544
  track(event);
3055
545
  }
3056
546
  const trackingEventHandlers = {
3057
- onMessageChoiceSelect: (trackingProps) => (messageType, _choiceId, choiceTypeId) => {
3058
- if (choiceTypeId === ACCEPT_ALL_CHOICE) {
3059
- dispatchComponentEvent({
3060
- trackingProps,
3061
- action: "click",
3062
- triggerAction: "accept_all",
3063
- messageType
3064
- });
3065
- }
3066
- if (choiceTypeId === MANAGE_PREFS_CHOICE) {
3067
- dispatchComponentEvent({
3068
- trackingProps,
3069
- action: "click",
3070
- triggerAction: "manage_cookies",
3071
- messageType
3072
- });
3073
- setState({
3074
- activeComponent: PRIVACY_MANAGER
3075
- });
3076
- }
3077
- if (choiceTypeId === REJECT_ALL_CHOICE) {
547
+ onMessageChoiceSelect: (trackingProps) => (_messageType, _choiceId, choiceTypeId) => {
548
+ const choiceTypeTriggerMap = {
549
+ 11: "accept_all",
550
+ 12: "manage_cookies",
551
+ 13: "reject_all"
552
+ };
553
+ const triggerAction = choiceTypeTriggerMap[choiceTypeId];
554
+ if (triggerAction) {
3078
555
  dispatchComponentEvent({
3079
556
  trackingProps,
3080
557
  action: "click",
3081
- triggerAction: "reject_all",
3082
- messageType
558
+ triggerAction
3083
559
  });
3084
560
  }
3085
561
  },
3086
- onMessageReady: (trackingProps) => (messageType) => {
562
+ onMessageReady: (trackingProps) => () => {
3087
563
  dispatchComponentEvent({
3088
564
  trackingProps,
3089
- action: "view",
3090
- messageType
565
+ action: "view"
3091
566
  });
3092
567
  },
3093
- onPrivacyManagerAction: (trackingProps) => (messageType, pmData) => {
3094
- const { purposeConsent, vendorConsent } = pmData;
3095
- const isAcceptAll = purposeConsent === "all" && vendorConsent === "all";
3096
- const isRejectAll = purposeConsent === "none" && vendorConsent === "none";
3097
- setState({
3098
- activeComponent: PRIVACY_MANAGER
3099
- });
3100
- if (isAcceptAll) {
3101
- dispatchComponentEvent({
3102
- trackingProps,
3103
- action: "click",
3104
- triggerAction: "accept_all",
3105
- messageType
3106
- });
3107
- } else if (isRejectAll) {
3108
- dispatchComponentEvent({
3109
- trackingProps,
3110
- action: "click",
3111
- triggerAction: "reject_all",
3112
- messageType
3113
- });
3114
- } else {
3115
- dispatchComponentEvent({
3116
- trackingProps,
3117
- action: "click",
3118
- triggerAction: "save_and_close",
3119
- messageType
568
+ onMessageReceiveData: () => (_messageType, data) => {
569
+ const { messageId } = data;
570
+ if (messageId) {
571
+ setState({
572
+ messageId
3120
573
  });
3121
574
  }
3122
575
  },
3123
- onMessageReceiveData: () => (messageType, data) => {
3124
- const { messageId } = data;
3125
- setState({
3126
- [messageType]: messageId
3127
- });
3128
- },
3129
- onError: (trackingProps) => (messageType, errorCode) => {
576
+ onError: (trackingProps) => (_messageType, errorCode) => {
3130
577
  dispatchComponentEvent({
3131
578
  trackingProps,
3132
579
  action: "error",
3133
- triggerAction: errorCode,
3134
- messageType
580
+ triggerAction: errorCode
581
+ });
582
+ },
583
+ onPMCancel: () => () => {
584
+ setState({
585
+ activeComponent: COOKIE_MESSAGE
3135
586
  });
3136
587
  }
3137
588
  };
3138
- function getCookie(name) {
3139
- var _a2, _b2;
3140
- const value = `; ${document.cookie}`;
3141
- const parts = value.split(`; ${name}=`);
3142
- if (parts.length === 2)
3143
- return (_b2 = (_a2 = parts.pop()) == null ? void 0 : _a2.split(";")) == null ? void 0 : _b2.shift();
3144
- }
3145
- function enableNonEssentialCookiesOption() {
3146
- window._sp_queue ?? (window._sp_queue = []);
3147
- window._sp_queue.push(() => {
3148
- var _a2, _b2;
3149
- (_b2 = (_a2 = window._sp_) == null ? void 0 : _a2.addEventListener) == null ? void 0 : _b2.call(
3150
- _a2,
3151
- "onMessageChoiceSelect",
3152
- (_messageType, _choiceId, choiceTypeId) => {
3153
- if (choiceTypeId === 9) {
3154
- document.cookie = "sp_cw=dismissed; expires=Thu, 18 Dec 2023 12:00:00 UTC";
3155
- }
3156
- }
3157
- );
3158
- });
3159
- window._sp_queue.push(() => {
3160
- var _a2, _b2;
3161
- (_b2 = (_a2 = window._sp_) == null ? void 0 : _a2.addEventListener) == null ? void 0 : _b2.call(
3162
- _a2,
3163
- "onPrivacyManagerAction",
3164
- (_messageType, pmData) => {
3165
- if (pmData.purposeConsent == "none" && pmData.vendorConsent == "none") {
3166
- document.cookie = "sp_cw=dismissed; expires=Thu, 18 Dec 2023 12:00:00 UTC";
3167
- }
589
+ function setupPmTracking(trackingProps, cmpBaseEndpoint) {
590
+ window.addEventListener(
591
+ "message",
592
+ function(event) {
593
+ if (event.origin !== cmpBaseEndpoint)
594
+ return;
595
+ const actionTypeMap = {
596
+ 1: "save_and_close",
597
+ 11: "accept_all",
598
+ 13: "reject_all"
599
+ };
600
+ const { data: { fromPM, actionType, messageId = "0" } = {} } = event;
601
+ if (!fromPM)
602
+ return;
603
+ if (+messageId) {
604
+ setState({
605
+ activeComponent: PRIVACY_MANAGER,
606
+ privacyManagerId: +messageId
607
+ });
3168
608
  }
3169
- );
3170
- });
609
+ if (!actionType || !actionTypeMap[actionType])
610
+ return;
611
+ dispatchComponentEvent({
612
+ trackingProps,
613
+ action: "click",
614
+ triggerAction: actionTypeMap[actionType]
615
+ });
616
+ },
617
+ false
618
+ );
3171
619
  }
620
+ const version = "3.3.0-beta.5";
3172
621
  async function initSourcepointCmp({
3173
622
  propertyConfig = FT_DOTCOM_PROD,
3174
623
  userId,
@@ -3179,6 +628,11 @@ async function initSourcepointCmp({
3179
628
  useConsentStore = true,
3180
629
  trackingContext = {}
3181
630
  } = {}) {
631
+ if (typeof window === "undefined") {
632
+ console.error("The CMP client can only be initialised in a browser context");
633
+ return;
634
+ }
635
+ window.FT_CMP_CLIENT_VERSION = version;
3182
636
  if (!userId && useFTSession) {
3183
637
  try {
3184
638
  const response = await getUuid();
@@ -3199,19 +653,11 @@ async function initSourcepointCmp({
3199
653
  );
3200
654
  delete propertyConfig.events;
3201
655
  }
3202
- propertyConfig = {
3203
- ...propertyConfig,
3204
- gdpr: {
3205
- targetingParams: {
3206
- cookiew: getCookie("cw")
3207
- }
3208
- }
3209
- };
3210
656
  bootstrapCmp(propertyConfig);
3211
657
  window._sp_queue.push(() => {
3212
- var _a2, _b2;
3213
- (_b2 = (_a2 = window._sp_) == null ? void 0 : _a2.addEventListener) == null ? void 0 : _b2.call(
3214
- _a2,
658
+ var _a, _b;
659
+ (_b = (_a = window._sp_) == null ? void 0 : _a.addEventListener) == null ? void 0 : _b.call(
660
+ _a,
3215
661
  "onConsentReady",
3216
662
  consentReadyHandlerFn({
3217
663
  userId,
@@ -3222,10 +668,8 @@ async function initSourcepointCmp({
3222
668
  })
3223
669
  );
3224
670
  });
3225
- enableNonEssentialCookiesOption();
3226
- initTracking(trackingContext);
671
+ initTracking(trackingContext, propertyConfig.baseEndpoint);
3227
672
  }
3228
- window.FT_CMP_CLIENT_VERSION = version;
3229
673
  exports.debug = debug;
3230
674
  exports.initSourcepointCmp = initSourcepointCmp;
3231
675
  exports.properties = properties;