@financial-times/cmp-client 2.0.2 → 2.0.3

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.
@@ -0,0 +1,2657 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const properties = require("./properties.cjs");
4
+ const request = (url, { credentials = "omit" } = {}) => {
5
+ return fetch(`https://session-next.ft.com${url}`, {
6
+ credentials,
7
+ useCorsProxy: true
8
+ }).then((response) => {
9
+ if (response.ok) {
10
+ return response.json();
11
+ } else {
12
+ return response.text().then((text) => {
13
+ throw new Error(`Next session responded with "${text}" (${response.status})`);
14
+ });
15
+ }
16
+ }).catch((err) => {
17
+ document.body.dispatchEvent(new CustomEvent("oErrors.log", {
18
+ bubbles: true,
19
+ detail: {
20
+ error: err,
21
+ info: {
22
+ component: "next-session-client"
23
+ }
24
+ }
25
+ }));
26
+ });
27
+ };
28
+ let detailsCache = {};
29
+ const cache = (name, value) => {
30
+ if (typeof name === "object") {
31
+ detailsCache = name;
32
+ return;
33
+ }
34
+ if (typeof name === "string" && typeof value === "string") {
35
+ detailsCache[name] = value;
36
+ return;
37
+ }
38
+ if (typeof name === "string" && typeof value === "undefined") {
39
+ return detailsCache[name] || null;
40
+ }
41
+ if (typeof name === "undefined" && typeof value === "undefined") {
42
+ return detailsCache;
43
+ }
44
+ throw new Error("Invalid arguments");
45
+ };
46
+ cache.clear = () => {
47
+ detailsCache = {};
48
+ };
49
+ const requests = {};
50
+ const getSessionId = () => {
51
+ const [, sessionId] = /FTSession_s=([^;]+)/.exec(document.cookie) || [];
52
+ return sessionId;
53
+ };
54
+ const getUuid = () => {
55
+ const cachedUUID = cache("uuid");
56
+ if (cachedUUID) {
57
+ return Promise.resolve({ uuid: cachedUUID });
58
+ }
59
+ const sessionId = getSessionId();
60
+ if (!sessionId) {
61
+ return Promise.resolve({ uuid: void 0 });
62
+ }
63
+ if (!requests.uuid) {
64
+ requests.uuid = request(`/sessions/s/${sessionId}`).then(({ uuid } = {}) => {
65
+ delete requests.uuid;
66
+ if (uuid) {
67
+ cache("uuid", uuid);
68
+ }
69
+ return { uuid };
70
+ });
71
+ }
72
+ return requests.uuid;
73
+ };
74
+ function encodeConfig(obj) {
75
+ let str = "";
76
+ for (const [key, val] of Object.entries(obj)) {
77
+ switch (typeof obj[key]) {
78
+ case "function":
79
+ str += `${key}:${val.toString().replace(/"/g, "'").replace(/\s/g, "")},`;
80
+ break;
81
+ case "string":
82
+ str += `${key}:"${val.replace(/"/g, "'").replace(/\s/g, "")}",`;
83
+ break;
84
+ case "object":
85
+ str += `${key}:{${encodeConfig(val)}},`;
86
+ break;
87
+ default:
88
+ str += `${key}:${val},`;
89
+ break;
90
+ }
91
+ }
92
+ return str.slice(0, -1);
93
+ }
94
+ function getSPConfig(config) {
95
+ return `window._sp_queue=[];window._sp_={config:{${encodeConfig(config)}}}`;
96
+ }
97
+ const scriptSources = {
98
+ cmpFrames: "https://cdn.privacy-mgmt.com/unified/wrapperMessagingWithoutDetection.js"
99
+ };
100
+ const scriptContent = {
101
+ getSPConfig,
102
+ 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()}();`,
103
+ 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) } })();`
104
+ };
105
+ var __defProp = Object.defineProperty;
106
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
107
+ var __publicField = (obj, key, value) => {
108
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
109
+ return value;
110
+ };
111
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
112
+ class DecodingError extends Error {
113
+ /**
114
+ * constructor - constructs an DecodingError
115
+ *
116
+ * @param {string} msg - Decoding Error Message
117
+ * @return {undefined}
118
+ */
119
+ constructor(msg) {
120
+ super(msg);
121
+ this.name = "DecodingError";
122
+ }
123
+ }
124
+ class EncodingError extends Error {
125
+ /**
126
+ * constructor - constructs an EncodingError
127
+ *
128
+ * @param {string} msg - Encoding Error Message
129
+ * @return {undefined}
130
+ */
131
+ constructor(msg) {
132
+ super(msg);
133
+ this.name = "EncodingError";
134
+ }
135
+ }
136
+ class GVLError extends Error {
137
+ /**
138
+ * constructor - constructs a GVLError
139
+ *
140
+ * @param {string} msg - Error message to display
141
+ * @return {undefined}
142
+ */
143
+ constructor(msg) {
144
+ super(msg);
145
+ this.name = "GVLError";
146
+ }
147
+ }
148
+ class TCModelError extends Error {
149
+ /**
150
+ * constructor - constructs an TCModelError
151
+ *
152
+ * @param {string} fieldName - the errored field
153
+ * @param {string} passedValue - what was passed
154
+ * @return {undefined}
155
+ */
156
+ constructor(fieldName, passedValue, msg = "") {
157
+ super(`invalid value ${passedValue} passed for ${fieldName} ${msg}`);
158
+ this.name = "TCModelError";
159
+ }
160
+ }
161
+ class Base64Url {
162
+ /**
163
+ * encodes an arbitrary-length bitfield string into base64url
164
+ *
165
+ * @static
166
+ * @param {string} str - arbitrary-length bitfield string to be encoded to base64url
167
+ * @return {string} - base64url encoded result
168
+ */
169
+ static encode(str) {
170
+ if (!/^[0-1]+$/.test(str)) {
171
+ throw new EncodingError("Invalid bitField");
172
+ }
173
+ const padding = str.length % this.LCM;
174
+ str += padding ? "0".repeat(this.LCM - padding) : "";
175
+ let result = "";
176
+ for (let i = 0; i < str.length; i += this.BASIS) {
177
+ result += this.DICT[parseInt(str.substr(i, this.BASIS), 2)];
178
+ }
179
+ return result;
180
+ }
181
+ /**
182
+ * decodes a base64url encoded bitfield string
183
+ *
184
+ * @static
185
+ * @param {string} str - base64url encoded bitfield string to be decoded
186
+ * @return {string} - bitfield string
187
+ */
188
+ static decode(str) {
189
+ if (!/^[A-Za-z0-9\-_]+$/.test(str)) {
190
+ throw new DecodingError("Invalidly encoded Base64URL string");
191
+ }
192
+ let result = "";
193
+ for (let i = 0; i < str.length; i++) {
194
+ const strBits = this.REVERSE_DICT.get(str[i]).toString(2);
195
+ result += "0".repeat(this.BASIS - strBits.length) + strBits;
196
+ }
197
+ return result;
198
+ }
199
+ }
200
+ __publicField(Base64Url, "DICT", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
201
+ __publicField(Base64Url, "REVERSE_DICT", /* @__PURE__ */ new Map([
202
+ ["A", 0],
203
+ ["B", 1],
204
+ ["C", 2],
205
+ ["D", 3],
206
+ ["E", 4],
207
+ ["F", 5],
208
+ ["G", 6],
209
+ ["H", 7],
210
+ ["I", 8],
211
+ ["J", 9],
212
+ ["K", 10],
213
+ ["L", 11],
214
+ ["M", 12],
215
+ ["N", 13],
216
+ ["O", 14],
217
+ ["P", 15],
218
+ ["Q", 16],
219
+ ["R", 17],
220
+ ["S", 18],
221
+ ["T", 19],
222
+ ["U", 20],
223
+ ["V", 21],
224
+ ["W", 22],
225
+ ["X", 23],
226
+ ["Y", 24],
227
+ ["Z", 25],
228
+ ["a", 26],
229
+ ["b", 27],
230
+ ["c", 28],
231
+ ["d", 29],
232
+ ["e", 30],
233
+ ["f", 31],
234
+ ["g", 32],
235
+ ["h", 33],
236
+ ["i", 34],
237
+ ["j", 35],
238
+ ["k", 36],
239
+ ["l", 37],
240
+ ["m", 38],
241
+ ["n", 39],
242
+ ["o", 40],
243
+ ["p", 41],
244
+ ["q", 42],
245
+ ["r", 43],
246
+ ["s", 44],
247
+ ["t", 45],
248
+ ["u", 46],
249
+ ["v", 47],
250
+ ["w", 48],
251
+ ["x", 49],
252
+ ["y", 50],
253
+ ["z", 51],
254
+ ["0", 52],
255
+ ["1", 53],
256
+ ["2", 54],
257
+ ["3", 55],
258
+ ["4", 56],
259
+ ["5", 57],
260
+ ["6", 58],
261
+ ["7", 59],
262
+ ["8", 60],
263
+ ["9", 61],
264
+ ["-", 62],
265
+ ["_", 63]
266
+ ]));
267
+ __publicField(Base64Url, "BASIS", 6);
268
+ __publicField(Base64Url, "LCM", 24);
269
+ const _ConsentLanguages = class _ConsentLanguages2 {
270
+ has(key) {
271
+ return _ConsentLanguages2.langSet.has(key);
272
+ }
273
+ parseLanguage(lang) {
274
+ lang = lang.toUpperCase();
275
+ const primaryLanguage = lang.split("-")[0];
276
+ if (lang.length >= 2 && primaryLanguage.length == 2) {
277
+ if (_ConsentLanguages2.langSet.has(lang)) {
278
+ return lang;
279
+ } else if (_ConsentLanguages2.langSet.has(primaryLanguage)) {
280
+ return primaryLanguage;
281
+ }
282
+ const fullPrimaryLang = primaryLanguage + "-" + primaryLanguage;
283
+ if (_ConsentLanguages2.langSet.has(fullPrimaryLang)) {
284
+ return fullPrimaryLang;
285
+ }
286
+ for (const supportedLang of _ConsentLanguages2.langSet) {
287
+ if (supportedLang.indexOf(lang) !== -1 || supportedLang.indexOf(primaryLanguage) !== -1) {
288
+ return supportedLang;
289
+ }
290
+ }
291
+ }
292
+ throw new Error(`unsupported language ${lang}`);
293
+ }
294
+ forEach(callback) {
295
+ _ConsentLanguages2.langSet.forEach(callback);
296
+ }
297
+ get size() {
298
+ return _ConsentLanguages2.langSet.size;
299
+ }
300
+ };
301
+ __publicField(_ConsentLanguages, "langSet", /* @__PURE__ */ new Set([
302
+ "AR",
303
+ "BG",
304
+ "BS",
305
+ "CA",
306
+ "CS",
307
+ "DA",
308
+ "DE",
309
+ "EL",
310
+ "EN",
311
+ "ES",
312
+ "ET",
313
+ "EU",
314
+ "FI",
315
+ "FR",
316
+ "GL",
317
+ "HR",
318
+ "HU",
319
+ "IT",
320
+ "JA",
321
+ "LT",
322
+ "LV",
323
+ "MT",
324
+ "NL",
325
+ "NO",
326
+ "PL",
327
+ "PT-BR",
328
+ "PT-PT",
329
+ "RO",
330
+ "RU",
331
+ "SK",
332
+ "SL",
333
+ "SR-LATN",
334
+ "SR-CYRL",
335
+ "SV",
336
+ "TR",
337
+ "ZH"
338
+ ]));
339
+ let ConsentLanguages = _ConsentLanguages;
340
+ class Fields {
341
+ }
342
+ __publicField(Fields, "cmpId", "cmpId");
343
+ __publicField(Fields, "cmpVersion", "cmpVersion");
344
+ __publicField(Fields, "consentLanguage", "consentLanguage");
345
+ __publicField(Fields, "consentScreen", "consentScreen");
346
+ __publicField(Fields, "created", "created");
347
+ __publicField(Fields, "supportOOB", "supportOOB");
348
+ __publicField(Fields, "isServiceSpecific", "isServiceSpecific");
349
+ __publicField(Fields, "lastUpdated", "lastUpdated");
350
+ __publicField(Fields, "numCustomPurposes", "numCustomPurposes");
351
+ __publicField(Fields, "policyVersion", "policyVersion");
352
+ __publicField(Fields, "publisherCountryCode", "publisherCountryCode");
353
+ __publicField(Fields, "publisherCustomConsents", "publisherCustomConsents");
354
+ __publicField(Fields, "publisherCustomLegitimateInterests", "publisherCustomLegitimateInterests");
355
+ __publicField(Fields, "publisherLegitimateInterests", "publisherLegitimateInterests");
356
+ __publicField(Fields, "publisherConsents", "publisherConsents");
357
+ __publicField(Fields, "publisherRestrictions", "publisherRestrictions");
358
+ __publicField(Fields, "purposeConsents", "purposeConsents");
359
+ __publicField(Fields, "purposeLegitimateInterests", "purposeLegitimateInterests");
360
+ __publicField(Fields, "purposeOneTreatment", "purposeOneTreatment");
361
+ __publicField(Fields, "specialFeatureOptins", "specialFeatureOptins");
362
+ __publicField(Fields, "useNonStandardTexts", "useNonStandardTexts");
363
+ __publicField(Fields, "vendorConsents", "vendorConsents");
364
+ __publicField(Fields, "vendorLegitimateInterests", "vendorLegitimateInterests");
365
+ __publicField(Fields, "vendorListVersion", "vendorListVersion");
366
+ __publicField(Fields, "vendorsAllowed", "vendorsAllowed");
367
+ __publicField(Fields, "vendorsDisclosed", "vendorsDisclosed");
368
+ __publicField(Fields, "version", "version");
369
+ class Cloneable {
370
+ /**
371
+ * clone - returns a copy of the classes with new values and not references
372
+ *
373
+ * @return {T}
374
+ */
375
+ clone() {
376
+ const myClone = new this.constructor();
377
+ const keys = Object.keys(this);
378
+ keys.forEach((key) => {
379
+ const value = this.deepClone(this[key]);
380
+ if (value !== void 0) {
381
+ myClone[key] = value;
382
+ }
383
+ });
384
+ return myClone;
385
+ }
386
+ /**
387
+ * deepClone - recursive function that makes copies of reference values
388
+ *
389
+ * @param {unknown} item
390
+ * @return {unknown}
391
+ */
392
+ deepClone(item) {
393
+ const itsType = typeof item;
394
+ if (itsType === "number" || itsType === "string" || itsType === "boolean") {
395
+ return item;
396
+ } else if (item !== null && itsType === "object") {
397
+ if (typeof item.clone === "function") {
398
+ return item.clone();
399
+ } else if (item instanceof Date) {
400
+ return new Date(item.getTime());
401
+ } else if (item[Symbol.iterator] !== void 0) {
402
+ const ar = [];
403
+ for (const subItem of item) {
404
+ ar.push(this.deepClone(subItem));
405
+ }
406
+ if (item instanceof Array) {
407
+ return ar;
408
+ } else {
409
+ return new item.constructor(ar);
410
+ }
411
+ } else {
412
+ const retr = {};
413
+ for (const prop in item) {
414
+ if (item.hasOwnProperty(prop)) {
415
+ retr[prop] = this.deepClone(item[prop]);
416
+ }
417
+ }
418
+ return retr;
419
+ }
420
+ }
421
+ }
422
+ }
423
+ var RestrictionType;
424
+ (function(RestrictionType2) {
425
+ RestrictionType2[RestrictionType2["NOT_ALLOWED"] = 0] = "NOT_ALLOWED";
426
+ RestrictionType2[RestrictionType2["REQUIRE_CONSENT"] = 1] = "REQUIRE_CONSENT";
427
+ RestrictionType2[RestrictionType2["REQUIRE_LI"] = 2] = "REQUIRE_LI";
428
+ })(RestrictionType || (RestrictionType = {}));
429
+ const _PurposeRestriction = class _PurposeRestriction2 extends Cloneable {
430
+ /**
431
+ * constructor
432
+ *
433
+ * @param {number} purposeId? - may optionally pass the purposeId into the
434
+ * constructor
435
+ * @param {RestrictionType} restrictionType? - may
436
+ * optionally pass the restrictionType into the constructor
437
+ * @return {undefined}
438
+ */
439
+ constructor(purposeId, restrictionType) {
440
+ super();
441
+ __publicField(this, "purposeId_");
442
+ __publicField(this, "restrictionType");
443
+ if (purposeId !== void 0) {
444
+ this.purposeId = purposeId;
445
+ }
446
+ if (restrictionType !== void 0) {
447
+ this.restrictionType = restrictionType;
448
+ }
449
+ }
450
+ static unHash(hash) {
451
+ const splitUp = hash.split(this.hashSeparator);
452
+ const purpRestriction = new _PurposeRestriction2();
453
+ if (splitUp.length !== 2) {
454
+ throw new TCModelError("hash", hash);
455
+ }
456
+ purpRestriction.purposeId = parseInt(splitUp[0], 10);
457
+ purpRestriction.restrictionType = parseInt(splitUp[1], 10);
458
+ return purpRestriction;
459
+ }
460
+ get hash() {
461
+ if (!this.isValid()) {
462
+ throw new Error("cannot hash invalid PurposeRestriction");
463
+ }
464
+ return `${this.purposeId}${_PurposeRestriction2.hashSeparator}${this.restrictionType}`;
465
+ }
466
+ /**
467
+ * @return {number} The purpose Id associated with a publisher
468
+ * purpose-by-vendor restriction that resulted in a different consent or LI
469
+ * status than the consent or LI purposes allowed lists.
470
+ */
471
+ get purposeId() {
472
+ return this.purposeId_;
473
+ }
474
+ /**
475
+ * @param {number} idNum - The purpose Id associated with a publisher
476
+ * purpose-by-vendor restriction that resulted in a different consent or LI
477
+ * status than the consent or LI purposes allowed lists.
478
+ */
479
+ set purposeId(idNum) {
480
+ this.purposeId_ = idNum;
481
+ }
482
+ isValid() {
483
+ return Number.isInteger(this.purposeId) && this.purposeId > 0 && (this.restrictionType === RestrictionType.NOT_ALLOWED || this.restrictionType === RestrictionType.REQUIRE_CONSENT || this.restrictionType === RestrictionType.REQUIRE_LI);
484
+ }
485
+ isSameAs(otherPR) {
486
+ return this.purposeId === otherPR.purposeId && this.restrictionType === otherPR.restrictionType;
487
+ }
488
+ };
489
+ __publicField(_PurposeRestriction, "hashSeparator", "-");
490
+ let PurposeRestriction = _PurposeRestriction;
491
+ class PurposeRestrictionVector extends Cloneable {
492
+ constructor() {
493
+ super(...arguments);
494
+ __publicField(this, "bitLength", 0);
495
+ __publicField(this, "map", /* @__PURE__ */ new Map());
496
+ __publicField(this, "gvl_");
497
+ }
498
+ has(hash) {
499
+ return this.map.has(hash);
500
+ }
501
+ isOkToHave(restrictionType, purposeId, vendorId) {
502
+ var _a2;
503
+ let result = true;
504
+ if ((_a2 = this.gvl) == null ? void 0 : _a2.vendors) {
505
+ const vendor = this.gvl.vendors[vendorId];
506
+ if (vendor) {
507
+ if (restrictionType === RestrictionType.NOT_ALLOWED) {
508
+ result = vendor.legIntPurposes.includes(purposeId) || vendor.purposes.includes(purposeId);
509
+ } else if (vendor.flexiblePurposes.length) {
510
+ switch (restrictionType) {
511
+ case RestrictionType.REQUIRE_CONSENT:
512
+ result = vendor.flexiblePurposes.includes(purposeId) && vendor.legIntPurposes.includes(purposeId);
513
+ break;
514
+ case RestrictionType.REQUIRE_LI:
515
+ result = vendor.flexiblePurposes.includes(purposeId) && vendor.purposes.includes(purposeId);
516
+ break;
517
+ }
518
+ } else {
519
+ result = false;
520
+ }
521
+ } else {
522
+ result = false;
523
+ }
524
+ }
525
+ return result;
526
+ }
527
+ /**
528
+ * add - adds a given Vendor ID under a given Purpose Restriction
529
+ *
530
+ * @param {number} vendorId
531
+ * @param {PurposeRestriction} purposeRestriction
532
+ * @return {void}
533
+ */
534
+ add(vendorId, purposeRestriction) {
535
+ if (this.isOkToHave(purposeRestriction.restrictionType, purposeRestriction.purposeId, vendorId)) {
536
+ const hash = purposeRestriction.hash;
537
+ if (!this.has(hash)) {
538
+ this.map.set(hash, /* @__PURE__ */ new Set());
539
+ this.bitLength = 0;
540
+ }
541
+ this.map.get(hash).add(vendorId);
542
+ }
543
+ }
544
+ /**
545
+ * restrictPurposeToLegalBasis - adds all Vendors under a given Purpose Restriction
546
+ *
547
+ * @param {PurposeRestriction} purposeRestriction
548
+ * @return {void}
549
+ */
550
+ restrictPurposeToLegalBasis(purposeRestriction) {
551
+ const vendors = Array.from(this.gvl.vendorIds);
552
+ const hash = purposeRestriction.hash;
553
+ const lastEntry = vendors[vendors.length - 1];
554
+ const values = [...Array(lastEntry).keys()].map((i) => i + 1);
555
+ if (!this.has(hash)) {
556
+ this.map.set(hash, new Set(values));
557
+ this.bitLength = 0;
558
+ } else {
559
+ for (let i = 1; i <= lastEntry; i++) {
560
+ this.map.get(hash).add(i);
561
+ }
562
+ }
563
+ }
564
+ /**
565
+ * getVendors - returns array of vendor ids optionally narrowed by a given
566
+ * Purpose Restriction. If no purpose restriction is passed then all vendor
567
+ * ids will be returned. One can expect this result to be a unique set of
568
+ * ids no duplicates.
569
+ *
570
+ * @param {PurposeRestriction} [purposeRestriction] - optionally passed to
571
+ * get only Vendor IDs restricted under the given Purpose Restriction
572
+ * @return {number[]} - Unique ID set of vendors
573
+ */
574
+ getVendors(purposeRestriction) {
575
+ let vendorIds = [];
576
+ if (purposeRestriction) {
577
+ const hash = purposeRestriction.hash;
578
+ if (this.has(hash)) {
579
+ vendorIds = Array.from(this.map.get(hash));
580
+ }
581
+ } else {
582
+ const vendorSet = /* @__PURE__ */ new Set();
583
+ this.map.forEach((set) => {
584
+ set.forEach((vendorId) => {
585
+ vendorSet.add(vendorId);
586
+ });
587
+ });
588
+ vendorIds = Array.from(vendorSet);
589
+ }
590
+ return vendorIds.sort((a, b) => a - b);
591
+ }
592
+ getRestrictionType(vendorId, purposeId) {
593
+ let rType;
594
+ this.getRestrictions(vendorId).forEach((purposeRestriction) => {
595
+ if (purposeRestriction.purposeId === purposeId) {
596
+ if (rType === void 0 || rType > purposeRestriction.restrictionType) {
597
+ rType = purposeRestriction.restrictionType;
598
+ }
599
+ }
600
+ });
601
+ return rType;
602
+ }
603
+ /**
604
+ * vendorHasRestriction - determines whether a given Vendor ID is under a
605
+ * given Purpose Restriction
606
+ *
607
+ * @param {number} vendorId
608
+ * @param {PurposeRestriction} purposeRestriction
609
+ * @return {boolean} - true if the give Vendor ID is under the given Purpose
610
+ * Restriction
611
+ */
612
+ vendorHasRestriction(vendorId, purposeRestriction) {
613
+ let has = false;
614
+ const restrictions = this.getRestrictions(vendorId);
615
+ for (let i = 0; i < restrictions.length && !has; i++) {
616
+ has = purposeRestriction.isSameAs(restrictions[i]);
617
+ }
618
+ return has;
619
+ }
620
+ /**
621
+ * getMaxVendorId - gets the Maximum Vendor ID regardless of Purpose
622
+ * Restriction
623
+ *
624
+ * @return {number} - maximum Vendor ID
625
+ */
626
+ getMaxVendorId() {
627
+ let retr = 0;
628
+ this.map.forEach((set) => {
629
+ retr = Math.max(Array.from(set)[set.size - 1], retr);
630
+ });
631
+ return retr;
632
+ }
633
+ getRestrictions(vendorId) {
634
+ const retr = [];
635
+ this.map.forEach((set, hash) => {
636
+ if (vendorId) {
637
+ if (set.has(vendorId)) {
638
+ retr.push(PurposeRestriction.unHash(hash));
639
+ }
640
+ } else {
641
+ retr.push(PurposeRestriction.unHash(hash));
642
+ }
643
+ });
644
+ return retr;
645
+ }
646
+ getPurposes() {
647
+ const purposeIds = /* @__PURE__ */ new Set();
648
+ this.map.forEach((set, hash) => {
649
+ purposeIds.add(PurposeRestriction.unHash(hash).purposeId);
650
+ });
651
+ return Array.from(purposeIds);
652
+ }
653
+ /**
654
+ * remove - removes Vendor ID from a Purpose Restriction
655
+ *
656
+ * @param {number} vendorId
657
+ * @param {PurposeRestriction} purposeRestriction
658
+ * @return {void}
659
+ */
660
+ remove(vendorId, purposeRestriction) {
661
+ const hash = purposeRestriction.hash;
662
+ const set = this.map.get(hash);
663
+ if (set) {
664
+ set.delete(vendorId);
665
+ if (set.size == 0) {
666
+ this.map.delete(hash);
667
+ this.bitLength = 0;
668
+ }
669
+ }
670
+ }
671
+ /**
672
+ * Essential for being able to determine whether we can actually set a
673
+ * purpose restriction since they have to have a flexible legal basis
674
+ *
675
+ * @param {GVL} value - the GVL instance
676
+ */
677
+ set gvl(value) {
678
+ if (!this.gvl_) {
679
+ this.gvl_ = value;
680
+ this.map.forEach((set, hash) => {
681
+ const purposeRestriction = PurposeRestriction.unHash(hash);
682
+ const vendors = Array.from(set);
683
+ vendors.forEach((vendorId) => {
684
+ if (!this.isOkToHave(purposeRestriction.restrictionType, purposeRestriction.purposeId, vendorId)) {
685
+ set.delete(vendorId);
686
+ }
687
+ });
688
+ });
689
+ }
690
+ }
691
+ /**
692
+ * gvl returns local copy of the GVL these restrictions apply to
693
+ *
694
+ * @return {GVL}
695
+ */
696
+ get gvl() {
697
+ return this.gvl_;
698
+ }
699
+ /**
700
+ * isEmpty - whether or not this vector has any restrictions in it
701
+ *
702
+ * @return {boolean}
703
+ */
704
+ isEmpty() {
705
+ return this.map.size === 0;
706
+ }
707
+ /**
708
+ * numRestrictions - returns the number of Purpose Restrictions.
709
+ *
710
+ * @return {number}
711
+ */
712
+ get numRestrictions() {
713
+ return this.map.size;
714
+ }
715
+ }
716
+ var DeviceDisclosureStorageAccessType;
717
+ (function(DeviceDisclosureStorageAccessType2) {
718
+ DeviceDisclosureStorageAccessType2["COOKIE"] = "cookie";
719
+ DeviceDisclosureStorageAccessType2["WEB"] = "web";
720
+ DeviceDisclosureStorageAccessType2["APP"] = "app";
721
+ })(DeviceDisclosureStorageAccessType || (DeviceDisclosureStorageAccessType = {}));
722
+ var Segment;
723
+ (function(Segment2) {
724
+ Segment2["CORE"] = "core";
725
+ Segment2["VENDORS_DISCLOSED"] = "vendorsDisclosed";
726
+ Segment2["VENDORS_ALLOWED"] = "vendorsAllowed";
727
+ Segment2["PUBLISHER_TC"] = "publisherTC";
728
+ })(Segment || (Segment = {}));
729
+ class SegmentIDs {
730
+ }
731
+ __publicField(SegmentIDs, "ID_TO_KEY", [
732
+ Segment.CORE,
733
+ Segment.VENDORS_DISCLOSED,
734
+ Segment.VENDORS_ALLOWED,
735
+ Segment.PUBLISHER_TC
736
+ ]);
737
+ __publicField(SegmentIDs, "KEY_TO_ID", {
738
+ [Segment.CORE]: 0,
739
+ [Segment.VENDORS_DISCLOSED]: 1,
740
+ [Segment.VENDORS_ALLOWED]: 2,
741
+ [Segment.PUBLISHER_TC]: 3
742
+ });
743
+ class Vector extends Cloneable {
744
+ constructor() {
745
+ super(...arguments);
746
+ __publicField(this, "bitLength", 0);
747
+ __publicField(this, "maxId_", 0);
748
+ __publicField(this, "set_", /* @__PURE__ */ new Set());
749
+ }
750
+ *[Symbol.iterator]() {
751
+ for (let i = 1; i <= this.maxId; i++) {
752
+ yield [i, this.has(i)];
753
+ }
754
+ }
755
+ /**
756
+ * values()
757
+ *
758
+ * @return {IterableIterator<number>} - returns an iterator of the positive
759
+ * values in the set
760
+ */
761
+ values() {
762
+ return this.set_.values();
763
+ }
764
+ /**
765
+ * maxId
766
+ *
767
+ * @return {number} - the highest id in this Vector
768
+ */
769
+ get maxId() {
770
+ return this.maxId_;
771
+ }
772
+ /**
773
+ * get
774
+ *
775
+ * @param {number} id - key for value to check
776
+ * @return {boolean} - value of that key, if never set it will be false
777
+ */
778
+ has(id) {
779
+ return this.set_.has(id);
780
+ }
781
+ /**
782
+ * unset
783
+ *
784
+ * @param {SingleIDOrCollection} id - id or ids to unset
785
+ * @return {void}
786
+ */
787
+ unset(id) {
788
+ if (Array.isArray(id)) {
789
+ id.forEach((id2) => this.unset(id2));
790
+ } else if (typeof id === "object") {
791
+ this.unset(Object.keys(id).map((strId) => Number(strId)));
792
+ } else {
793
+ this.set_.delete(Number(id));
794
+ this.bitLength = 0;
795
+ if (id === this.maxId) {
796
+ this.maxId_ = 0;
797
+ this.set_.forEach((id2) => {
798
+ this.maxId_ = Math.max(this.maxId, id2);
799
+ });
800
+ }
801
+ }
802
+ }
803
+ isIntMap(item) {
804
+ let result = typeof item === "object";
805
+ result = result && Object.keys(item).every((key) => {
806
+ let itemResult = Number.isInteger(parseInt(key, 10));
807
+ itemResult = itemResult && this.isValidNumber(item[key].id);
808
+ itemResult = itemResult && item[key].name !== void 0;
809
+ return itemResult;
810
+ });
811
+ return result;
812
+ }
813
+ isValidNumber(item) {
814
+ return parseInt(item, 10) > 0;
815
+ }
816
+ isSet(item) {
817
+ let result = false;
818
+ if (item instanceof Set) {
819
+ result = Array.from(item).every(this.isValidNumber);
820
+ }
821
+ return result;
822
+ }
823
+ /**
824
+ * set - sets an item assumed to be a truthy value by its presence
825
+ *
826
+ * @param {SingleIDOrCollection} item - May be a single id (positive integer)
827
+ * or collection of ids in a set, GVL Int Map, or Array.
828
+ *
829
+ * @return {void}
830
+ */
831
+ set(item) {
832
+ if (Array.isArray(item)) {
833
+ item.forEach((item2) => this.set(item2));
834
+ } else if (this.isSet(item)) {
835
+ this.set(Array.from(item));
836
+ } else if (this.isIntMap(item)) {
837
+ this.set(Object.keys(item).map((strId) => Number(strId)));
838
+ } else if (this.isValidNumber(item)) {
839
+ this.set_.add(item);
840
+ this.maxId_ = Math.max(this.maxId, item);
841
+ this.bitLength = 0;
842
+ } else {
843
+ throw new TCModelError("set()", item, "must be positive integer array, positive integer, Set<number>, or IntMap");
844
+ }
845
+ }
846
+ empty() {
847
+ this.set_ = /* @__PURE__ */ new Set();
848
+ }
849
+ /**
850
+ * forEach - to traverse from id=1 to id=maxId in a sequential non-sparse manner
851
+ *
852
+ *
853
+ * @param {forEachCallback} callback - callback to execute
854
+ * @return {void}
855
+ *
856
+ * @callback forEachCallback
857
+ * @param {boolean} value - whether or not this id exists in the vector
858
+ * @param {number} id - the id number of the current iteration
859
+ */
860
+ forEach(callback) {
861
+ for (let i = 1; i <= this.maxId; i++) {
862
+ callback(this.has(i), i);
863
+ }
864
+ }
865
+ get size() {
866
+ return this.set_.size;
867
+ }
868
+ setAll(intMap) {
869
+ this.set(intMap);
870
+ }
871
+ }
872
+ class BitLength {
873
+ }
874
+ _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;
875
+ __publicField(BitLength, _a, 12);
876
+ __publicField(BitLength, _b, 12);
877
+ __publicField(BitLength, _c, 12);
878
+ __publicField(BitLength, _d, 6);
879
+ __publicField(BitLength, _e, 36);
880
+ __publicField(BitLength, _f, 1);
881
+ __publicField(BitLength, _g, 36);
882
+ __publicField(BitLength, _h, 6);
883
+ __publicField(BitLength, _i, 12);
884
+ __publicField(BitLength, _j, 24);
885
+ __publicField(BitLength, _k, 24);
886
+ __publicField(BitLength, _l, 24);
887
+ __publicField(BitLength, _m, 24);
888
+ __publicField(BitLength, _n, 1);
889
+ __publicField(BitLength, _o, 12);
890
+ __publicField(BitLength, _p, 1);
891
+ __publicField(BitLength, _q, 12);
892
+ __publicField(BitLength, _r, 6);
893
+ __publicField(BitLength, "anyBoolean", 1);
894
+ __publicField(BitLength, "encodingType", 1);
895
+ __publicField(BitLength, "maxId", 16);
896
+ __publicField(BitLength, "numCustomPurposes", 6);
897
+ __publicField(BitLength, "numEntries", 12);
898
+ __publicField(BitLength, "numRestrictions", 12);
899
+ __publicField(BitLength, "purposeId", 6);
900
+ __publicField(BitLength, "restrictionType", 2);
901
+ __publicField(BitLength, "segmentType", 3);
902
+ __publicField(BitLength, "singleOrRange", 1);
903
+ __publicField(BitLength, "vendorId", 16);
904
+ class BooleanEncoder {
905
+ static encode(value) {
906
+ return String(Number(value));
907
+ }
908
+ static decode(value) {
909
+ return value === "1";
910
+ }
911
+ }
912
+ class IntEncoder {
913
+ static encode(value, numBits) {
914
+ let bitString;
915
+ if (typeof value === "string") {
916
+ value = parseInt(value, 10);
917
+ }
918
+ bitString = value.toString(2);
919
+ if (bitString.length > numBits || value < 0) {
920
+ throw new EncodingError(`${value} too large to encode into ${numBits}`);
921
+ }
922
+ if (bitString.length < numBits) {
923
+ bitString = "0".repeat(numBits - bitString.length) + bitString;
924
+ }
925
+ return bitString;
926
+ }
927
+ static decode(value, numBits) {
928
+ if (numBits !== value.length) {
929
+ throw new DecodingError("invalid bit length");
930
+ }
931
+ return parseInt(value, 2);
932
+ }
933
+ }
934
+ class DateEncoder {
935
+ static encode(value, numBits) {
936
+ return IntEncoder.encode(Math.round(value.getTime() / 100), numBits);
937
+ }
938
+ static decode(value, numBits) {
939
+ if (numBits !== value.length) {
940
+ throw new DecodingError("invalid bit length");
941
+ }
942
+ const date = /* @__PURE__ */ new Date();
943
+ date.setTime(IntEncoder.decode(value, numBits) * 100);
944
+ return date;
945
+ }
946
+ }
947
+ class FixedVectorEncoder {
948
+ static encode(value, numBits) {
949
+ let bitString = "";
950
+ for (let i = 1; i <= numBits; i++) {
951
+ bitString += BooleanEncoder.encode(value.has(i));
952
+ }
953
+ return bitString;
954
+ }
955
+ static decode(value, numBits) {
956
+ if (value.length !== numBits) {
957
+ throw new DecodingError("bitfield encoding length mismatch");
958
+ }
959
+ const vector = new Vector();
960
+ for (let i = 1; i <= numBits; i++) {
961
+ if (BooleanEncoder.decode(value[i - 1])) {
962
+ vector.set(i);
963
+ }
964
+ }
965
+ vector.bitLength = value.length;
966
+ return vector;
967
+ }
968
+ }
969
+ class LangEncoder {
970
+ static encode(value, numBits) {
971
+ value = value.toUpperCase();
972
+ const ASCII_START = 65;
973
+ const firstLetter = value.charCodeAt(0) - ASCII_START;
974
+ const secondLetter = value.charCodeAt(1) - ASCII_START;
975
+ if (firstLetter < 0 || firstLetter > 25 || secondLetter < 0 || secondLetter > 25) {
976
+ throw new EncodingError(`invalid language code: ${value}`);
977
+ }
978
+ if (numBits % 2 === 1) {
979
+ throw new EncodingError(`numBits must be even, ${numBits} is not valid`);
980
+ }
981
+ numBits = numBits / 2;
982
+ const firstLetterBString = IntEncoder.encode(firstLetter, numBits);
983
+ const secondLetterBString = IntEncoder.encode(secondLetter, numBits);
984
+ return firstLetterBString + secondLetterBString;
985
+ }
986
+ static decode(value, numBits) {
987
+ let retr;
988
+ if (numBits === value.length && !(value.length % 2)) {
989
+ const ASCII_START = 65;
990
+ const mid = value.length / 2;
991
+ const firstLetter = IntEncoder.decode(value.slice(0, mid), mid) + ASCII_START;
992
+ const secondLetter = IntEncoder.decode(value.slice(mid), mid) + ASCII_START;
993
+ retr = String.fromCharCode(firstLetter) + String.fromCharCode(secondLetter);
994
+ } else {
995
+ throw new DecodingError("invalid bit length for language");
996
+ }
997
+ return retr;
998
+ }
999
+ }
1000
+ class PurposeRestrictionVectorEncoder {
1001
+ static encode(prVector) {
1002
+ let bitString = IntEncoder.encode(prVector.numRestrictions, BitLength.numRestrictions);
1003
+ if (!prVector.isEmpty()) {
1004
+ const nextGvlVendor = (vendorId, lastVendorId) => {
1005
+ for (let nextId = vendorId + 1; nextId <= lastVendorId; nextId++) {
1006
+ if (prVector.gvl.vendorIds.has(nextId)) {
1007
+ return nextId;
1008
+ }
1009
+ }
1010
+ return vendorId;
1011
+ };
1012
+ prVector.getRestrictions().forEach((purpRestriction) => {
1013
+ bitString += IntEncoder.encode(purpRestriction.purposeId, BitLength.purposeId);
1014
+ bitString += IntEncoder.encode(purpRestriction.restrictionType, BitLength.restrictionType);
1015
+ const vendors = prVector.getVendors(purpRestriction);
1016
+ const len = vendors.length;
1017
+ let numEntries = 0;
1018
+ let startId = 0;
1019
+ let rangeField = "";
1020
+ for (let i = 0; i < len; i++) {
1021
+ const vendorId = vendors[i];
1022
+ if (startId === 0) {
1023
+ numEntries++;
1024
+ startId = vendorId;
1025
+ }
1026
+ if (i === len - 1 || vendors[i + 1] > nextGvlVendor(vendorId, vendors[len - 1])) {
1027
+ const isRange = !(vendorId === startId);
1028
+ rangeField += BooleanEncoder.encode(isRange);
1029
+ rangeField += IntEncoder.encode(startId, BitLength.vendorId);
1030
+ if (isRange) {
1031
+ rangeField += IntEncoder.encode(vendorId, BitLength.vendorId);
1032
+ }
1033
+ startId = 0;
1034
+ }
1035
+ }
1036
+ bitString += IntEncoder.encode(numEntries, BitLength.numEntries);
1037
+ bitString += rangeField;
1038
+ });
1039
+ }
1040
+ return bitString;
1041
+ }
1042
+ static decode(encodedString) {
1043
+ let index = 0;
1044
+ const vector = new PurposeRestrictionVector();
1045
+ const numRestrictions = IntEncoder.decode(encodedString.substr(index, BitLength.numRestrictions), BitLength.numRestrictions);
1046
+ index += BitLength.numRestrictions;
1047
+ for (let i = 0; i < numRestrictions; i++) {
1048
+ const purposeId = IntEncoder.decode(encodedString.substr(index, BitLength.purposeId), BitLength.purposeId);
1049
+ index += BitLength.purposeId;
1050
+ const restrictionType = IntEncoder.decode(encodedString.substr(index, BitLength.restrictionType), BitLength.restrictionType);
1051
+ index += BitLength.restrictionType;
1052
+ const purposeRestriction = new PurposeRestriction(purposeId, restrictionType);
1053
+ const numEntries = IntEncoder.decode(encodedString.substr(index, BitLength.numEntries), BitLength.numEntries);
1054
+ index += BitLength.numEntries;
1055
+ for (let j = 0; j < numEntries; j++) {
1056
+ const isARange = BooleanEncoder.decode(encodedString.substr(index, BitLength.anyBoolean));
1057
+ index += BitLength.anyBoolean;
1058
+ const startOrOnlyVendorId = IntEncoder.decode(encodedString.substr(index, BitLength.vendorId), BitLength.vendorId);
1059
+ index += BitLength.vendorId;
1060
+ if (isARange) {
1061
+ const endVendorId = IntEncoder.decode(encodedString.substr(index, BitLength.vendorId), BitLength.vendorId);
1062
+ index += BitLength.vendorId;
1063
+ if (endVendorId < startOrOnlyVendorId) {
1064
+ throw new DecodingError(`Invalid RangeEntry: endVendorId ${endVendorId} is less than ${startOrOnlyVendorId}`);
1065
+ }
1066
+ for (let k = startOrOnlyVendorId; k <= endVendorId; k++) {
1067
+ vector.add(k, purposeRestriction);
1068
+ }
1069
+ } else {
1070
+ vector.add(startOrOnlyVendorId, purposeRestriction);
1071
+ }
1072
+ }
1073
+ }
1074
+ vector.bitLength = index;
1075
+ return vector;
1076
+ }
1077
+ }
1078
+ var VectorEncodingType;
1079
+ (function(VectorEncodingType2) {
1080
+ VectorEncodingType2[VectorEncodingType2["FIELD"] = 0] = "FIELD";
1081
+ VectorEncodingType2[VectorEncodingType2["RANGE"] = 1] = "RANGE";
1082
+ })(VectorEncodingType || (VectorEncodingType = {}));
1083
+ class VendorVectorEncoder {
1084
+ static encode(value) {
1085
+ const ranges = [];
1086
+ let range = [];
1087
+ let retrString = IntEncoder.encode(value.maxId, BitLength.maxId);
1088
+ let bitField = "";
1089
+ let rangeIsSmaller;
1090
+ const headerLength = BitLength.maxId + BitLength.encodingType;
1091
+ const bitFieldLength = headerLength + value.maxId;
1092
+ const minRangeLength = BitLength.vendorId * 2 + BitLength.singleOrRange + BitLength.numEntries;
1093
+ let rangeLength = headerLength + BitLength.numEntries;
1094
+ value.forEach((curValue, i) => {
1095
+ bitField += BooleanEncoder.encode(curValue);
1096
+ rangeIsSmaller = value.maxId > minRangeLength && rangeLength < bitFieldLength;
1097
+ if (rangeIsSmaller && curValue) {
1098
+ const nextValue = value.has(i + 1);
1099
+ if (!nextValue) {
1100
+ range.push(i);
1101
+ rangeLength += BitLength.vendorId;
1102
+ ranges.push(range);
1103
+ range = [];
1104
+ } else if (range.length === 0) {
1105
+ range.push(i);
1106
+ rangeLength += BitLength.singleOrRange;
1107
+ rangeLength += BitLength.vendorId;
1108
+ }
1109
+ }
1110
+ });
1111
+ if (rangeIsSmaller) {
1112
+ retrString += String(VectorEncodingType.RANGE);
1113
+ retrString += this.buildRangeEncoding(ranges);
1114
+ } else {
1115
+ retrString += String(VectorEncodingType.FIELD);
1116
+ retrString += bitField;
1117
+ }
1118
+ return retrString;
1119
+ }
1120
+ static decode(value, version) {
1121
+ let vector;
1122
+ let index = 0;
1123
+ const maxId = IntEncoder.decode(value.substr(index, BitLength.maxId), BitLength.maxId);
1124
+ index += BitLength.maxId;
1125
+ const encodingType = IntEncoder.decode(value.charAt(index), BitLength.encodingType);
1126
+ index += BitLength.encodingType;
1127
+ if (encodingType === VectorEncodingType.RANGE) {
1128
+ vector = new Vector();
1129
+ if (version === 1) {
1130
+ if (value.substr(index, 1) === "1") {
1131
+ throw new DecodingError("Unable to decode default consent=1");
1132
+ }
1133
+ index++;
1134
+ }
1135
+ const numEntries = IntEncoder.decode(value.substr(index, BitLength.numEntries), BitLength.numEntries);
1136
+ index += BitLength.numEntries;
1137
+ for (let i = 0; i < numEntries; i++) {
1138
+ const isIdRange = BooleanEncoder.decode(value.charAt(index));
1139
+ index += BitLength.singleOrRange;
1140
+ const firstId = IntEncoder.decode(value.substr(index, BitLength.vendorId), BitLength.vendorId);
1141
+ index += BitLength.vendorId;
1142
+ if (isIdRange) {
1143
+ const secondId = IntEncoder.decode(value.substr(index, BitLength.vendorId), BitLength.vendorId);
1144
+ index += BitLength.vendorId;
1145
+ for (let j = firstId; j <= secondId; j++) {
1146
+ vector.set(j);
1147
+ }
1148
+ } else {
1149
+ vector.set(firstId);
1150
+ }
1151
+ }
1152
+ } else {
1153
+ const bitField = value.substr(index, maxId);
1154
+ index += maxId;
1155
+ vector = FixedVectorEncoder.decode(bitField, maxId);
1156
+ }
1157
+ vector.bitLength = index;
1158
+ return vector;
1159
+ }
1160
+ static buildRangeEncoding(ranges) {
1161
+ const numEntries = ranges.length;
1162
+ let rangeString = IntEncoder.encode(numEntries, BitLength.numEntries);
1163
+ ranges.forEach((range) => {
1164
+ const single = range.length === 1;
1165
+ rangeString += BooleanEncoder.encode(!single);
1166
+ rangeString += IntEncoder.encode(range[0], BitLength.vendorId);
1167
+ if (!single) {
1168
+ rangeString += IntEncoder.encode(range[1], BitLength.vendorId);
1169
+ }
1170
+ });
1171
+ return rangeString;
1172
+ }
1173
+ }
1174
+ function FieldEncoderMap() {
1175
+ return {
1176
+ [Fields.version]: IntEncoder,
1177
+ [Fields.created]: DateEncoder,
1178
+ [Fields.lastUpdated]: DateEncoder,
1179
+ [Fields.cmpId]: IntEncoder,
1180
+ [Fields.cmpVersion]: IntEncoder,
1181
+ [Fields.consentScreen]: IntEncoder,
1182
+ [Fields.consentLanguage]: LangEncoder,
1183
+ [Fields.vendorListVersion]: IntEncoder,
1184
+ [Fields.policyVersion]: IntEncoder,
1185
+ [Fields.isServiceSpecific]: BooleanEncoder,
1186
+ [Fields.useNonStandardTexts]: BooleanEncoder,
1187
+ [Fields.specialFeatureOptins]: FixedVectorEncoder,
1188
+ [Fields.purposeConsents]: FixedVectorEncoder,
1189
+ [Fields.purposeLegitimateInterests]: FixedVectorEncoder,
1190
+ [Fields.purposeOneTreatment]: BooleanEncoder,
1191
+ [Fields.publisherCountryCode]: LangEncoder,
1192
+ [Fields.vendorConsents]: VendorVectorEncoder,
1193
+ [Fields.vendorLegitimateInterests]: VendorVectorEncoder,
1194
+ [Fields.publisherRestrictions]: PurposeRestrictionVectorEncoder,
1195
+ segmentType: IntEncoder,
1196
+ [Fields.vendorsDisclosed]: VendorVectorEncoder,
1197
+ [Fields.vendorsAllowed]: VendorVectorEncoder,
1198
+ [Fields.publisherConsents]: FixedVectorEncoder,
1199
+ [Fields.publisherLegitimateInterests]: FixedVectorEncoder,
1200
+ [Fields.numCustomPurposes]: IntEncoder,
1201
+ [Fields.publisherCustomConsents]: FixedVectorEncoder,
1202
+ [Fields.publisherCustomLegitimateInterests]: FixedVectorEncoder
1203
+ };
1204
+ }
1205
+ class FieldSequence {
1206
+ constructor() {
1207
+ __publicField(this, "1", {
1208
+ [Segment.CORE]: [
1209
+ Fields.version,
1210
+ Fields.created,
1211
+ Fields.lastUpdated,
1212
+ Fields.cmpId,
1213
+ Fields.cmpVersion,
1214
+ Fields.consentScreen,
1215
+ Fields.consentLanguage,
1216
+ Fields.vendorListVersion,
1217
+ Fields.purposeConsents,
1218
+ Fields.vendorConsents
1219
+ ]
1220
+ });
1221
+ __publicField(this, "2", {
1222
+ [Segment.CORE]: [
1223
+ Fields.version,
1224
+ Fields.created,
1225
+ Fields.lastUpdated,
1226
+ Fields.cmpId,
1227
+ Fields.cmpVersion,
1228
+ Fields.consentScreen,
1229
+ Fields.consentLanguage,
1230
+ Fields.vendorListVersion,
1231
+ Fields.policyVersion,
1232
+ Fields.isServiceSpecific,
1233
+ Fields.useNonStandardTexts,
1234
+ Fields.specialFeatureOptins,
1235
+ Fields.purposeConsents,
1236
+ Fields.purposeLegitimateInterests,
1237
+ Fields.purposeOneTreatment,
1238
+ Fields.publisherCountryCode,
1239
+ Fields.vendorConsents,
1240
+ Fields.vendorLegitimateInterests,
1241
+ Fields.publisherRestrictions
1242
+ ],
1243
+ [Segment.PUBLISHER_TC]: [
1244
+ Fields.publisherConsents,
1245
+ Fields.publisherLegitimateInterests,
1246
+ Fields.numCustomPurposes,
1247
+ Fields.publisherCustomConsents,
1248
+ Fields.publisherCustomLegitimateInterests
1249
+ ],
1250
+ [Segment.VENDORS_ALLOWED]: [
1251
+ Fields.vendorsAllowed
1252
+ ],
1253
+ [Segment.VENDORS_DISCLOSED]: [
1254
+ Fields.vendorsDisclosed
1255
+ ]
1256
+ });
1257
+ }
1258
+ }
1259
+ class SegmentSequence {
1260
+ constructor(tcModel, options) {
1261
+ __publicField(this, "1", [
1262
+ Segment.CORE
1263
+ ]);
1264
+ __publicField(this, "2", [
1265
+ Segment.CORE
1266
+ ]);
1267
+ if (tcModel.version === 2) {
1268
+ if (tcModel.isServiceSpecific) {
1269
+ this["2"].push(Segment.PUBLISHER_TC);
1270
+ } else {
1271
+ const isForVendors = !!(options && options.isForVendors);
1272
+ if (!isForVendors || tcModel[Fields.supportOOB] === true) {
1273
+ this["2"].push(Segment.VENDORS_DISCLOSED);
1274
+ }
1275
+ if (isForVendors) {
1276
+ if (tcModel[Fields.supportOOB] && tcModel[Fields.vendorsAllowed].size > 0) {
1277
+ this["2"].push(Segment.VENDORS_ALLOWED);
1278
+ }
1279
+ this["2"].push(Segment.PUBLISHER_TC);
1280
+ }
1281
+ }
1282
+ }
1283
+ }
1284
+ }
1285
+ class SegmentEncoder {
1286
+ static encode(tcModel, segment) {
1287
+ let sequence;
1288
+ try {
1289
+ sequence = this.fieldSequence[String(tcModel.version)][segment];
1290
+ } catch (err) {
1291
+ throw new EncodingError(`Unable to encode version: ${tcModel.version}, segment: ${segment}`);
1292
+ }
1293
+ let bitField = "";
1294
+ if (segment !== Segment.CORE) {
1295
+ bitField = IntEncoder.encode(SegmentIDs.KEY_TO_ID[segment], BitLength.segmentType);
1296
+ }
1297
+ const fieldEncoderMap = FieldEncoderMap();
1298
+ sequence.forEach((key) => {
1299
+ const value = tcModel[key];
1300
+ const encoder = fieldEncoderMap[key];
1301
+ let numBits = BitLength[key];
1302
+ if (numBits === void 0) {
1303
+ if (this.isPublisherCustom(key)) {
1304
+ numBits = Number(tcModel[Fields.numCustomPurposes]);
1305
+ }
1306
+ }
1307
+ try {
1308
+ bitField += encoder.encode(value, numBits);
1309
+ } catch (err) {
1310
+ throw new EncodingError(`Error encoding ${segment}->${key}: ${err.message}`);
1311
+ }
1312
+ });
1313
+ return Base64Url.encode(bitField);
1314
+ }
1315
+ static decode(encodedString, tcModel, segment) {
1316
+ const bitField = Base64Url.decode(encodedString);
1317
+ let bStringIdx = 0;
1318
+ if (segment === Segment.CORE) {
1319
+ tcModel.version = IntEncoder.decode(bitField.substr(bStringIdx, BitLength[Fields.version]), BitLength[Fields.version]);
1320
+ }
1321
+ if (segment !== Segment.CORE) {
1322
+ bStringIdx += BitLength.segmentType;
1323
+ }
1324
+ const sequence = this.fieldSequence[String(tcModel.version)][segment];
1325
+ const fieldEncoderMap = FieldEncoderMap();
1326
+ sequence.forEach((key) => {
1327
+ const encoder = fieldEncoderMap[key];
1328
+ let numBits = BitLength[key];
1329
+ if (numBits === void 0) {
1330
+ if (this.isPublisherCustom(key)) {
1331
+ numBits = Number(tcModel[Fields.numCustomPurposes]);
1332
+ }
1333
+ }
1334
+ if (numBits !== 0) {
1335
+ const bits = bitField.substr(bStringIdx, numBits);
1336
+ if (encoder === VendorVectorEncoder) {
1337
+ tcModel[key] = encoder.decode(bits, tcModel.version);
1338
+ } else {
1339
+ tcModel[key] = encoder.decode(bits, numBits);
1340
+ }
1341
+ if (Number.isInteger(numBits)) {
1342
+ bStringIdx += numBits;
1343
+ } else if (Number.isInteger(tcModel[key].bitLength)) {
1344
+ bStringIdx += tcModel[key].bitLength;
1345
+ } else {
1346
+ throw new DecodingError(key);
1347
+ }
1348
+ }
1349
+ });
1350
+ return tcModel;
1351
+ }
1352
+ static isPublisherCustom(key) {
1353
+ return key.indexOf("publisherCustom") === 0;
1354
+ }
1355
+ }
1356
+ __publicField(SegmentEncoder, "fieldSequence", new FieldSequence());
1357
+ class SemanticPreEncoder {
1358
+ static process(tcModel, options) {
1359
+ const gvl = tcModel.gvl;
1360
+ if (!gvl) {
1361
+ throw new EncodingError("Unable to encode TCModel without a GVL");
1362
+ }
1363
+ if (!gvl.isReady) {
1364
+ throw new EncodingError("Unable to encode TCModel tcModel.gvl.readyPromise is not resolved");
1365
+ }
1366
+ tcModel = tcModel.clone();
1367
+ tcModel.consentLanguage = gvl.language.slice(0, 2).toUpperCase();
1368
+ if ((options == null ? void 0 : options.version) > 0 && (options == null ? void 0 : options.version) <= this.processor.length) {
1369
+ tcModel.version = options.version;
1370
+ } else {
1371
+ tcModel.version = this.processor.length;
1372
+ }
1373
+ const processorFunctionIndex = tcModel.version - 1;
1374
+ if (!this.processor[processorFunctionIndex]) {
1375
+ throw new EncodingError(`Invalid version: ${tcModel.version}`);
1376
+ }
1377
+ return this.processor[processorFunctionIndex](tcModel, gvl);
1378
+ }
1379
+ }
1380
+ __publicField(SemanticPreEncoder, "processor", [
1381
+ (tcModel) => tcModel,
1382
+ (tcModel, gvl) => {
1383
+ tcModel.publisherRestrictions.gvl = gvl;
1384
+ tcModel.purposeLegitimateInterests.unset([1, 3, 4, 5, 6]);
1385
+ const vectorToIntMap = /* @__PURE__ */ new Map();
1386
+ vectorToIntMap.set("legIntPurposes", tcModel.vendorLegitimateInterests);
1387
+ vectorToIntMap.set("purposes", tcModel.vendorConsents);
1388
+ vectorToIntMap.forEach((vector, gvlVendorKey) => {
1389
+ vector.forEach((value, vendorId) => {
1390
+ if (value) {
1391
+ const vendor = gvl.vendors[vendorId];
1392
+ if (!vendor || vendor.deletedDate) {
1393
+ vector.unset(vendorId);
1394
+ } else if (vendor[gvlVendorKey].length === 0) {
1395
+ if (gvlVendorKey === "legIntPurposes" && vendor["purposes"].length === 0 && vendor["legIntPurposes"].length === 0 && vendor["specialPurposes"].length > 0)
1396
+ ;
1397
+ else {
1398
+ if (tcModel.isServiceSpecific) {
1399
+ if (vendor.flexiblePurposes.length === 0) {
1400
+ vector.unset(vendorId);
1401
+ } else {
1402
+ const restrictions = tcModel.publisherRestrictions.getRestrictions(vendorId);
1403
+ let isValid = false;
1404
+ for (let i = 0, len = restrictions.length; i < len && !isValid; i++) {
1405
+ isValid = restrictions[i].restrictionType === RestrictionType.REQUIRE_CONSENT && gvlVendorKey === "purposes" || restrictions[i].restrictionType === RestrictionType.REQUIRE_LI && gvlVendorKey === "legIntPurposes";
1406
+ }
1407
+ if (!isValid) {
1408
+ vector.unset(vendorId);
1409
+ }
1410
+ }
1411
+ } else {
1412
+ vector.unset(vendorId);
1413
+ }
1414
+ }
1415
+ }
1416
+ }
1417
+ });
1418
+ });
1419
+ tcModel.vendorsDisclosed.set(gvl.vendors);
1420
+ return tcModel;
1421
+ }
1422
+ ]);
1423
+ class Json {
1424
+ static absCall(url, body, sendCookies, timeout) {
1425
+ return new Promise((resolve, reject) => {
1426
+ const req = new XMLHttpRequest();
1427
+ const onLoad = () => {
1428
+ if (req.readyState == XMLHttpRequest.DONE) {
1429
+ if (req.status >= 200 && req.status < 300) {
1430
+ let response = req.response;
1431
+ if (typeof response === "string") {
1432
+ try {
1433
+ response = JSON.parse(response);
1434
+ } catch (e) {
1435
+ }
1436
+ }
1437
+ resolve(response);
1438
+ } else {
1439
+ reject(new Error(`HTTP Status: ${req.status} response type: ${req.responseType}`));
1440
+ }
1441
+ }
1442
+ };
1443
+ const onError = () => {
1444
+ reject(new Error("error"));
1445
+ };
1446
+ const onAbort = () => {
1447
+ reject(new Error("aborted"));
1448
+ };
1449
+ const onTimeout = () => {
1450
+ reject(new Error("Timeout " + timeout + "ms " + url));
1451
+ };
1452
+ req.withCredentials = sendCookies;
1453
+ req.addEventListener("load", onLoad);
1454
+ req.addEventListener("error", onError);
1455
+ req.addEventListener("abort", onAbort);
1456
+ if (body === null) {
1457
+ req.open("GET", url, true);
1458
+ } else {
1459
+ req.open("POST", url, true);
1460
+ }
1461
+ req.responseType = "json";
1462
+ req.timeout = timeout;
1463
+ req.ontimeout = onTimeout;
1464
+ req.send(body);
1465
+ });
1466
+ }
1467
+ /**
1468
+ * @static
1469
+ * @param {string} url - full path to POST to
1470
+ * @param {object} body - JSON object to post
1471
+ * @param {boolean} sendCookies - Whether or not to send the XMLHttpRequest with credentials or not
1472
+ * @param {number} [timeout] - optional timeout in milliseconds
1473
+ * @return {Promise<object>} - if the server responds the response will be returned here
1474
+ */
1475
+ static post(url, body, sendCookies = false, timeout = 0) {
1476
+ return this.absCall(url, JSON.stringify(body), sendCookies, timeout);
1477
+ }
1478
+ /**
1479
+ * @static
1480
+ * @param {string} url - full path to the json
1481
+ * @param {boolean} sendCookies - Whether or not to send the XMLHttpRequest with credentials or not
1482
+ * @param {number} [timeout] - optional timeout in milliseconds
1483
+ * @return {Promise<object>} - resolves with parsed JSON
1484
+ */
1485
+ static fetch(url, sendCookies = false, timeout = 0) {
1486
+ return this.absCall(url, null, sendCookies, timeout);
1487
+ }
1488
+ }
1489
+ const _GVL = class _GVL2 extends Cloneable {
1490
+ /**
1491
+ * @param {VersionOrVendorList} [versionOrVendorList] - can be either a
1492
+ * [[VendorList]] object or a version number represented as a string or
1493
+ * number to download. If nothing is passed the latest version of the GVL
1494
+ * will be loaded
1495
+ */
1496
+ constructor(versionOrVendorList) {
1497
+ super();
1498
+ __publicField(this, "readyPromise");
1499
+ __publicField(this, "gvlSpecificationVersion");
1500
+ __publicField(this, "vendorListVersion");
1501
+ __publicField(this, "tcfPolicyVersion");
1502
+ __publicField(this, "lastUpdated");
1503
+ __publicField(this, "purposes");
1504
+ __publicField(this, "specialPurposes");
1505
+ __publicField(this, "features");
1506
+ __publicField(this, "specialFeatures");
1507
+ __publicField(this, "isReady_", false);
1508
+ __publicField(this, "vendors_");
1509
+ __publicField(this, "vendorIds");
1510
+ __publicField(this, "fullVendorList");
1511
+ __publicField(this, "byPurposeVendorMap");
1512
+ __publicField(this, "bySpecialPurposeVendorMap");
1513
+ __publicField(this, "byFeatureVendorMap");
1514
+ __publicField(this, "bySpecialFeatureVendorMap");
1515
+ __publicField(this, "stacks");
1516
+ __publicField(this, "dataCategories");
1517
+ __publicField(this, "lang_");
1518
+ __publicField(this, "cacheLang_");
1519
+ __publicField(this, "isLatest", false);
1520
+ let url = _GVL2.baseUrl;
1521
+ this.lang_ = _GVL2.DEFAULT_LANGUAGE;
1522
+ this.cacheLang_ = _GVL2.DEFAULT_LANGUAGE;
1523
+ if (this.isVendorList(versionOrVendorList)) {
1524
+ this.populate(versionOrVendorList);
1525
+ this.readyPromise = Promise.resolve();
1526
+ } else {
1527
+ if (!url) {
1528
+ throw new GVLError("must specify GVL.baseUrl before loading GVL json");
1529
+ }
1530
+ if (versionOrVendorList > 0) {
1531
+ const version = versionOrVendorList;
1532
+ if (_GVL2.CACHE.has(version)) {
1533
+ this.populate(_GVL2.CACHE.get(version));
1534
+ this.readyPromise = Promise.resolve();
1535
+ } else {
1536
+ url += _GVL2.versionedFilename.replace("[VERSION]", String(version));
1537
+ this.readyPromise = this.fetchJson(url);
1538
+ }
1539
+ } else {
1540
+ if (_GVL2.CACHE.has(_GVL2.LATEST_CACHE_KEY)) {
1541
+ this.populate(_GVL2.CACHE.get(_GVL2.LATEST_CACHE_KEY));
1542
+ this.readyPromise = Promise.resolve();
1543
+ } else {
1544
+ this.isLatest = true;
1545
+ this.readyPromise = this.fetchJson(url + _GVL2.latestFilename);
1546
+ }
1547
+ }
1548
+ }
1549
+ }
1550
+ /**
1551
+ * baseUrl - Entities using the vendor-list.json are required by the iab to
1552
+ * host their own copy of it to reduce the load on the iab's infrastructure
1553
+ * so a 'base' url must be set to be put together with the versioning scheme
1554
+ * of the filenames.
1555
+ *
1556
+ * @static
1557
+ * @param {string} url - the base url to load the vendor-list.json from. This is
1558
+ * broken out from the filename because it follows a different scheme for
1559
+ * latest file vs versioned files.
1560
+ *
1561
+ * @throws {GVLError} - If the url is http[s]://vendorlist.consensu.org/...
1562
+ * this will throw an error. IAB Europe requires that that CMPs and Vendors
1563
+ * cache their own copies of the GVL to minimize load on their
1564
+ * infrastructure. For more information regarding caching of the
1565
+ * vendor-list.json, please see [the TCF documentation on 'Caching the Global
1566
+ * Vendor List'
1567
+ * ](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)
1568
+ */
1569
+ static set baseUrl(url) {
1570
+ const notValid = /^https?:\/\/vendorlist\.consensu\.org\//;
1571
+ if (notValid.test(url)) {
1572
+ throw new GVLError("Invalid baseUrl! You may not pull directly from vendorlist.consensu.org and must provide your own cache");
1573
+ }
1574
+ if (url.length > 0 && url[url.length - 1] !== "/") {
1575
+ url += "/";
1576
+ }
1577
+ this.baseUrl_ = url;
1578
+ }
1579
+ /**
1580
+ * baseUrl - Entities using the vendor-list.json are required by the iab to
1581
+ * host their own copy of it to reduce the load on the iab's infrastructure
1582
+ * so a 'base' url must be set to be put together with the versioning scheme
1583
+ * of the filenames.
1584
+ *
1585
+ * @static
1586
+ * @return {string} - returns the previously set baseUrl, the default is
1587
+ * `undefined`
1588
+ */
1589
+ static get baseUrl() {
1590
+ return this.baseUrl_;
1591
+ }
1592
+ /**
1593
+ * emptyLanguageCache
1594
+ *
1595
+ * @param {string} [lang] - Optional language code to remove from
1596
+ * the cache. Should be one of the languages in GVL.consentLanguages set.
1597
+ * If not then the whole cache will be deleted.
1598
+ * @return {boolean} - true if anything was deleted from the cache
1599
+ */
1600
+ static emptyLanguageCache(lang) {
1601
+ let result = false;
1602
+ if (lang == null && _GVL2.LANGUAGE_CACHE.size > 0) {
1603
+ _GVL2.LANGUAGE_CACHE = /* @__PURE__ */ new Map();
1604
+ result = true;
1605
+ } else if (typeof lang === "string" && this.consentLanguages.has(lang.toUpperCase())) {
1606
+ _GVL2.LANGUAGE_CACHE.delete(lang.toUpperCase());
1607
+ result = true;
1608
+ }
1609
+ return result;
1610
+ }
1611
+ /**
1612
+ * emptyCache
1613
+ *
1614
+ * @param {number} [vendorListVersion] - version of the vendor list to delete
1615
+ * from the cache. If none is specified then the whole cache is deleted.
1616
+ * @return {boolean} - true if anything was deleted from the cache
1617
+ */
1618
+ static emptyCache(vendorListVersion) {
1619
+ let retr = false;
1620
+ if (Number.isInteger(vendorListVersion) && vendorListVersion >= 0) {
1621
+ _GVL2.CACHE.delete(vendorListVersion);
1622
+ retr = true;
1623
+ } else if (vendorListVersion === void 0) {
1624
+ _GVL2.CACHE = /* @__PURE__ */ new Map();
1625
+ retr = true;
1626
+ }
1627
+ return retr;
1628
+ }
1629
+ cacheLanguage() {
1630
+ if (!_GVL2.LANGUAGE_CACHE.has(this.cacheLang_)) {
1631
+ _GVL2.LANGUAGE_CACHE.set(this.cacheLang_, {
1632
+ purposes: this.purposes,
1633
+ specialPurposes: this.specialPurposes,
1634
+ features: this.features,
1635
+ specialFeatures: this.specialFeatures,
1636
+ stacks: this.stacks,
1637
+ dataCategories: this.dataCategories
1638
+ });
1639
+ }
1640
+ }
1641
+ async fetchJson(url) {
1642
+ try {
1643
+ this.populate(await Json.fetch(url));
1644
+ } catch (err) {
1645
+ throw new GVLError(err.message);
1646
+ }
1647
+ }
1648
+ /**
1649
+ * getJson - Method for getting the JSON that was downloaded to created this
1650
+ * `GVL` object
1651
+ *
1652
+ * @return {VendorList} - The basic JSON structure without the extra
1653
+ * functionality and methods of this class.
1654
+ */
1655
+ getJson() {
1656
+ return JSON.parse(JSON.stringify({
1657
+ gvlSpecificationVersion: this.gvlSpecificationVersion,
1658
+ vendorListVersion: this.vendorListVersion,
1659
+ tcfPolicyVersion: this.tcfPolicyVersion,
1660
+ lastUpdated: this.lastUpdated,
1661
+ purposes: this.purposes,
1662
+ specialPurposes: this.specialPurposes,
1663
+ features: this.features,
1664
+ specialFeatures: this.specialFeatures,
1665
+ stacks: this.stacks,
1666
+ dataCategories: this.dataCategories,
1667
+ vendors: this.fullVendorList
1668
+ }));
1669
+ }
1670
+ /**
1671
+ * changeLanguage - retrieves the purpose language translation and sets the
1672
+ * internal language variable
1673
+ *
1674
+ * @param {string} lang - language code to change language to
1675
+ * @return {Promise<void | GVLError>} - returns the `readyPromise` and
1676
+ * resolves when this GVL is populated with the data from the language file.
1677
+ */
1678
+ async changeLanguage(lang) {
1679
+ let parsedLanguage = lang;
1680
+ try {
1681
+ parsedLanguage = _GVL2.consentLanguages.parseLanguage(lang);
1682
+ } catch (e) {
1683
+ throw new GVLError("Error during parsing the language: " + e.message);
1684
+ }
1685
+ const cacheLang = lang.toUpperCase();
1686
+ if (parsedLanguage.toLowerCase() === _GVL2.DEFAULT_LANGUAGE.toLowerCase() && !_GVL2.LANGUAGE_CACHE.has(cacheLang)) {
1687
+ return;
1688
+ }
1689
+ if (parsedLanguage !== this.lang_) {
1690
+ this.lang_ = parsedLanguage;
1691
+ if (_GVL2.LANGUAGE_CACHE.has(cacheLang)) {
1692
+ const cached = _GVL2.LANGUAGE_CACHE.get(cacheLang);
1693
+ for (const prop in cached) {
1694
+ if (cached.hasOwnProperty(prop)) {
1695
+ this[prop] = cached[prop];
1696
+ }
1697
+ }
1698
+ } else {
1699
+ const url = _GVL2.baseUrl + _GVL2.languageFilename.replace("[LANG]", this.lang_.toLowerCase());
1700
+ try {
1701
+ await this.fetchJson(url);
1702
+ this.cacheLang_ = cacheLang;
1703
+ this.cacheLanguage();
1704
+ } catch (err) {
1705
+ throw new GVLError("unable to load language: " + err.message);
1706
+ }
1707
+ }
1708
+ }
1709
+ }
1710
+ get language() {
1711
+ return this.lang_;
1712
+ }
1713
+ isVendorList(gvlObject) {
1714
+ return gvlObject !== void 0 && gvlObject.vendors !== void 0;
1715
+ }
1716
+ populate(gvlObject) {
1717
+ this.purposes = gvlObject.purposes;
1718
+ this.specialPurposes = gvlObject.specialPurposes;
1719
+ this.features = gvlObject.features;
1720
+ this.specialFeatures = gvlObject.specialFeatures;
1721
+ this.stacks = gvlObject.stacks;
1722
+ this.dataCategories = gvlObject.dataCategories;
1723
+ if (this.isVendorList(gvlObject)) {
1724
+ this.gvlSpecificationVersion = gvlObject.gvlSpecificationVersion;
1725
+ this.tcfPolicyVersion = gvlObject.tcfPolicyVersion;
1726
+ this.vendorListVersion = gvlObject.vendorListVersion;
1727
+ this.lastUpdated = gvlObject.lastUpdated;
1728
+ if (typeof this.lastUpdated === "string") {
1729
+ this.lastUpdated = new Date(this.lastUpdated);
1730
+ }
1731
+ this.vendors_ = gvlObject.vendors;
1732
+ this.fullVendorList = gvlObject.vendors;
1733
+ this.mapVendors();
1734
+ this.isReady_ = true;
1735
+ if (this.isLatest) {
1736
+ _GVL2.CACHE.set(_GVL2.LATEST_CACHE_KEY, this.getJson());
1737
+ }
1738
+ if (!_GVL2.CACHE.has(this.vendorListVersion)) {
1739
+ _GVL2.CACHE.set(this.vendorListVersion, this.getJson());
1740
+ }
1741
+ }
1742
+ this.cacheLanguage();
1743
+ }
1744
+ mapVendors(vendorIds) {
1745
+ this.byPurposeVendorMap = {};
1746
+ this.bySpecialPurposeVendorMap = {};
1747
+ this.byFeatureVendorMap = {};
1748
+ this.bySpecialFeatureVendorMap = {};
1749
+ Object.keys(this.purposes).forEach((purposeId) => {
1750
+ this.byPurposeVendorMap[purposeId] = {
1751
+ legInt: /* @__PURE__ */ new Set(),
1752
+ consent: /* @__PURE__ */ new Set(),
1753
+ flexible: /* @__PURE__ */ new Set()
1754
+ };
1755
+ });
1756
+ Object.keys(this.specialPurposes).forEach((purposeId) => {
1757
+ this.bySpecialPurposeVendorMap[purposeId] = /* @__PURE__ */ new Set();
1758
+ });
1759
+ Object.keys(this.features).forEach((featureId) => {
1760
+ this.byFeatureVendorMap[featureId] = /* @__PURE__ */ new Set();
1761
+ });
1762
+ Object.keys(this.specialFeatures).forEach((featureId) => {
1763
+ this.bySpecialFeatureVendorMap[featureId] = /* @__PURE__ */ new Set();
1764
+ });
1765
+ if (!Array.isArray(vendorIds)) {
1766
+ vendorIds = Object.keys(this.fullVendorList).map((vId) => +vId);
1767
+ }
1768
+ this.vendorIds = new Set(vendorIds);
1769
+ this.vendors_ = vendorIds.reduce((vendors, vendorId) => {
1770
+ const vendor = this.vendors_[String(vendorId)];
1771
+ if (vendor && vendor.deletedDate === void 0) {
1772
+ vendor.purposes.forEach((purposeId) => {
1773
+ const purpGroup = this.byPurposeVendorMap[String(purposeId)];
1774
+ purpGroup.consent.add(vendorId);
1775
+ });
1776
+ vendor.specialPurposes.forEach((purposeId) => {
1777
+ this.bySpecialPurposeVendorMap[String(purposeId)].add(vendorId);
1778
+ });
1779
+ vendor.legIntPurposes.forEach((purposeId) => {
1780
+ this.byPurposeVendorMap[String(purposeId)].legInt.add(vendorId);
1781
+ });
1782
+ if (vendor.flexiblePurposes) {
1783
+ vendor.flexiblePurposes.forEach((purposeId) => {
1784
+ this.byPurposeVendorMap[String(purposeId)].flexible.add(vendorId);
1785
+ });
1786
+ }
1787
+ vendor.features.forEach((featureId) => {
1788
+ this.byFeatureVendorMap[String(featureId)].add(vendorId);
1789
+ });
1790
+ vendor.specialFeatures.forEach((featureId) => {
1791
+ this.bySpecialFeatureVendorMap[String(featureId)].add(vendorId);
1792
+ });
1793
+ vendors[vendorId] = vendor;
1794
+ }
1795
+ return vendors;
1796
+ }, {});
1797
+ }
1798
+ getFilteredVendors(purposeOrFeature, id, subType, special) {
1799
+ const properPurposeOrFeature = purposeOrFeature.charAt(0).toUpperCase() + purposeOrFeature.slice(1);
1800
+ let vendorSet;
1801
+ const retr = {};
1802
+ if (purposeOrFeature === "purpose" && subType) {
1803
+ vendorSet = this["by" + properPurposeOrFeature + "VendorMap"][String(id)][subType];
1804
+ } else {
1805
+ vendorSet = this["by" + (special ? "Special" : "") + properPurposeOrFeature + "VendorMap"][String(id)];
1806
+ }
1807
+ vendorSet.forEach((vendorId) => {
1808
+ retr[String(vendorId)] = this.vendors[String(vendorId)];
1809
+ });
1810
+ return retr;
1811
+ }
1812
+ /**
1813
+ * getVendorsWithConsentPurpose
1814
+ *
1815
+ * @param {number} purposeId
1816
+ * @return {IntMap<Vendor>} - list of vendors that have declared the consent purpose id
1817
+ */
1818
+ getVendorsWithConsentPurpose(purposeId) {
1819
+ return this.getFilteredVendors("purpose", purposeId, "consent");
1820
+ }
1821
+ /**
1822
+ * getVendorsWithLegIntPurpose
1823
+ *
1824
+ * @param {number} purposeId
1825
+ * @return {IntMap<Vendor>} - list of vendors that have declared the legInt (Legitimate Interest) purpose id
1826
+ */
1827
+ getVendorsWithLegIntPurpose(purposeId) {
1828
+ return this.getFilteredVendors("purpose", purposeId, "legInt");
1829
+ }
1830
+ /**
1831
+ * getVendorsWithFlexiblePurpose
1832
+ *
1833
+ * @param {number} purposeId
1834
+ * @return {IntMap<Vendor>} - list of vendors that have declared the flexible purpose id
1835
+ */
1836
+ getVendorsWithFlexiblePurpose(purposeId) {
1837
+ return this.getFilteredVendors("purpose", purposeId, "flexible");
1838
+ }
1839
+ /**
1840
+ * getVendorsWithSpecialPurpose
1841
+ *
1842
+ * @param {number} specialPurposeId
1843
+ * @return {IntMap<Vendor>} - list of vendors that have declared the special purpose id
1844
+ */
1845
+ getVendorsWithSpecialPurpose(specialPurposeId) {
1846
+ return this.getFilteredVendors("purpose", specialPurposeId, void 0, true);
1847
+ }
1848
+ /**
1849
+ * getVendorsWithFeature
1850
+ *
1851
+ * @param {number} featureId
1852
+ * @return {IntMap<Vendor>} - list of vendors that have declared the feature id
1853
+ */
1854
+ getVendorsWithFeature(featureId) {
1855
+ return this.getFilteredVendors("feature", featureId);
1856
+ }
1857
+ /**
1858
+ * getVendorsWithSpecialFeature
1859
+ *
1860
+ * @param {number} specialFeatureId
1861
+ * @return {IntMap<Vendor>} - list of vendors that have declared the special feature id
1862
+ */
1863
+ getVendorsWithSpecialFeature(specialFeatureId) {
1864
+ return this.getFilteredVendors("feature", specialFeatureId, void 0, true);
1865
+ }
1866
+ /**
1867
+ * vendors
1868
+ *
1869
+ * @return {IntMap<Vendor>} - the list of vendors as it would on the JSON file
1870
+ * except if `narrowVendorsTo` was called, it would be that narrowed list
1871
+ */
1872
+ get vendors() {
1873
+ return this.vendors_;
1874
+ }
1875
+ /**
1876
+ * narrowVendorsTo - narrows vendors represented in this GVL to the list of ids passed in
1877
+ *
1878
+ * @param {number[]} vendorIds - list of ids to narrow this GVL to
1879
+ * @return {void}
1880
+ */
1881
+ narrowVendorsTo(vendorIds) {
1882
+ this.mapVendors(vendorIds);
1883
+ }
1884
+ /**
1885
+ * isReady - Whether or not this instance is ready to be used. This will be
1886
+ * immediately and synchronously true if a vendorlist object is passed into
1887
+ * the constructor or once the JSON vendorllist is retrieved.
1888
+ *
1889
+ * @return {boolean} whether or not the instance is ready to be interacted
1890
+ * with and all the data is populated
1891
+ */
1892
+ get isReady() {
1893
+ return this.isReady_;
1894
+ }
1895
+ /**
1896
+ * clone - overrides base `clone()` method since GVL is a special class that
1897
+ * represents a JSON structure with some additional functionality.
1898
+ *
1899
+ * @return {GVL}
1900
+ */
1901
+ clone() {
1902
+ const result = new _GVL2(this.getJson());
1903
+ if (this.lang_ !== _GVL2.DEFAULT_LANGUAGE) {
1904
+ result.changeLanguage(this.lang_);
1905
+ }
1906
+ return result;
1907
+ }
1908
+ static isInstanceOf(questionableInstance) {
1909
+ const isSo = typeof questionableInstance === "object";
1910
+ return isSo && typeof questionableInstance.narrowVendorsTo === "function";
1911
+ }
1912
+ };
1913
+ __publicField(_GVL, "LANGUAGE_CACHE", /* @__PURE__ */ new Map());
1914
+ __publicField(_GVL, "CACHE", /* @__PURE__ */ new Map());
1915
+ __publicField(_GVL, "LATEST_CACHE_KEY", 0);
1916
+ __publicField(_GVL, "DEFAULT_LANGUAGE", "EN");
1917
+ __publicField(_GVL, "consentLanguages", new ConsentLanguages());
1918
+ __publicField(_GVL, "baseUrl_");
1919
+ __publicField(_GVL, "latestFilename", "vendor-list.json");
1920
+ __publicField(_GVL, "versionedFilename", "archives/vendor-list-v[VERSION].json");
1921
+ __publicField(_GVL, "languageFilename", "purposes-[LANG].json");
1922
+ let GVL = _GVL;
1923
+ class TCModel extends Cloneable {
1924
+ /**
1925
+ * Constructs the TCModel. Passing a [[GVL]] is optional when constructing
1926
+ * as this TCModel may be constructed from decoding an existing encoded
1927
+ * TCString.
1928
+ *
1929
+ * @param {GVL} [gvl]
1930
+ */
1931
+ constructor(gvl) {
1932
+ super();
1933
+ __publicField(this, "isServiceSpecific_", false);
1934
+ __publicField(this, "supportOOB_", true);
1935
+ __publicField(this, "useNonStandardTexts_", false);
1936
+ __publicField(this, "purposeOneTreatment_", false);
1937
+ __publicField(this, "publisherCountryCode_", "AA");
1938
+ __publicField(this, "version_", 2);
1939
+ __publicField(this, "consentScreen_", 0);
1940
+ __publicField(this, "policyVersion_", 4);
1941
+ __publicField(this, "consentLanguage_", "EN");
1942
+ __publicField(this, "cmpId_", 0);
1943
+ __publicField(this, "cmpVersion_", 0);
1944
+ __publicField(this, "vendorListVersion_", 0);
1945
+ __publicField(this, "numCustomPurposes_", 0);
1946
+ __publicField(this, "gvl_");
1947
+ __publicField(this, "created");
1948
+ __publicField(this, "lastUpdated");
1949
+ __publicField(this, "specialFeatureOptins", new Vector());
1950
+ __publicField(this, "purposeConsents", new Vector());
1951
+ __publicField(this, "purposeLegitimateInterests", new Vector());
1952
+ __publicField(this, "publisherConsents", new Vector());
1953
+ __publicField(this, "publisherLegitimateInterests", new Vector());
1954
+ __publicField(this, "publisherCustomConsents", new Vector());
1955
+ __publicField(this, "publisherCustomLegitimateInterests", new Vector());
1956
+ __publicField(this, "customPurposes");
1957
+ __publicField(this, "vendorConsents", new Vector());
1958
+ __publicField(this, "vendorLegitimateInterests", new Vector());
1959
+ __publicField(this, "vendorsDisclosed", new Vector());
1960
+ __publicField(this, "vendorsAllowed", new Vector());
1961
+ __publicField(this, "publisherRestrictions", new PurposeRestrictionVector());
1962
+ if (gvl) {
1963
+ this.gvl = gvl;
1964
+ }
1965
+ this.updated();
1966
+ }
1967
+ /**
1968
+ * sets the [[GVL]] with side effects of also setting the `vendorListVersion`, `policyVersion`, and `consentLanguage`
1969
+ * @param {GVL} gvl
1970
+ */
1971
+ set gvl(gvl) {
1972
+ if (!GVL.isInstanceOf(gvl)) {
1973
+ gvl = new GVL(gvl);
1974
+ }
1975
+ this.gvl_ = gvl;
1976
+ this.publisherRestrictions.gvl = gvl;
1977
+ }
1978
+ /**
1979
+ * @return {GVL} the gvl instance set on this TCModel instance
1980
+ */
1981
+ get gvl() {
1982
+ return this.gvl_;
1983
+ }
1984
+ /**
1985
+ * @param {number} integer - A unique ID will be assigned to each Consent
1986
+ * Manager Provider (CMP) from the iab.
1987
+ *
1988
+ * @throws {TCModelError} if the value is not an integer greater than 1 as those are not valid.
1989
+ */
1990
+ set cmpId(integer) {
1991
+ integer = Number(integer);
1992
+ if (Number.isInteger(integer) && integer > 1) {
1993
+ this.cmpId_ = integer;
1994
+ } else {
1995
+ throw new TCModelError("cmpId", integer);
1996
+ }
1997
+ }
1998
+ get cmpId() {
1999
+ return this.cmpId_;
2000
+ }
2001
+ /**
2002
+ * Each change to an operating CMP should receive a
2003
+ * new version number, for logging proof of consent. CmpVersion defined by
2004
+ * each CMP.
2005
+ *
2006
+ * @param {number} integer
2007
+ *
2008
+ * @throws {TCModelError} if the value is not an integer greater than 1 as those are not valid.
2009
+ */
2010
+ set cmpVersion(integer) {
2011
+ integer = Number(integer);
2012
+ if (Number.isInteger(integer) && integer > -1) {
2013
+ this.cmpVersion_ = integer;
2014
+ } else {
2015
+ throw new TCModelError("cmpVersion", integer);
2016
+ }
2017
+ }
2018
+ get cmpVersion() {
2019
+ return this.cmpVersion_;
2020
+ }
2021
+ /**
2022
+ * The screen number is CMP and CmpVersion
2023
+ * specific, and is for logging proof of consent.(For example, a CMP could
2024
+ * keep records so that a publisher can request information about the context
2025
+ * in which consent was gathered.)
2026
+ *
2027
+ * @param {number} integer
2028
+ *
2029
+ * @throws {TCModelError} if the value is not an integer greater than 0 as those are not valid.
2030
+ */
2031
+ set consentScreen(integer) {
2032
+ integer = Number(integer);
2033
+ if (Number.isInteger(integer) && integer > -1) {
2034
+ this.consentScreen_ = integer;
2035
+ } else {
2036
+ throw new TCModelError("consentScreen", integer);
2037
+ }
2038
+ }
2039
+ get consentScreen() {
2040
+ return this.consentScreen_;
2041
+ }
2042
+ /**
2043
+ * @param {string} lang - [two-letter ISO 639-1 language
2044
+ * code](http://www.loc.gov/standards/iso639-2/php/code_list.php) in which
2045
+ * the CMP UI was presented
2046
+ *
2047
+ * @throws {TCModelError} if the value is not a length-2 string of alpha characters
2048
+ */
2049
+ set consentLanguage(lang) {
2050
+ this.consentLanguage_ = lang;
2051
+ }
2052
+ get consentLanguage() {
2053
+ return this.consentLanguage_;
2054
+ }
2055
+ /**
2056
+ * @param {string} countryCode - [two-letter ISO 3166-1 alpha-2 country
2057
+ * code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) of the publisher,
2058
+ * determined by the CMP-settings of the publisher.
2059
+ *
2060
+ * @throws {TCModelError} if the value is not a length-2 string of alpha characters
2061
+ */
2062
+ set publisherCountryCode(countryCode) {
2063
+ if (/^([A-z]){2}$/.test(countryCode)) {
2064
+ this.publisherCountryCode_ = countryCode.toUpperCase();
2065
+ } else {
2066
+ throw new TCModelError("publisherCountryCode", countryCode);
2067
+ }
2068
+ }
2069
+ get publisherCountryCode() {
2070
+ return this.publisherCountryCode_;
2071
+ }
2072
+ /**
2073
+ * Version of the GVL used to create this TCModel. Global
2074
+ * Vendor List versions will be released periodically.
2075
+ *
2076
+ * @param {number} integer
2077
+ *
2078
+ * @throws {TCModelError} if the value is not an integer greater than 0 as those are not valid.
2079
+ */
2080
+ set vendorListVersion(integer) {
2081
+ integer = Number(integer) >> 0;
2082
+ if (integer < 0) {
2083
+ throw new TCModelError("vendorListVersion", integer);
2084
+ } else {
2085
+ this.vendorListVersion_ = integer;
2086
+ }
2087
+ }
2088
+ get vendorListVersion() {
2089
+ if (this.gvl) {
2090
+ return this.gvl.vendorListVersion;
2091
+ } else {
2092
+ return this.vendorListVersion_;
2093
+ }
2094
+ }
2095
+ /**
2096
+ * From the corresponding field in the GVL that was
2097
+ * used for obtaining consent. A new policy version invalidates existing
2098
+ * strings and requires CMPs to re-establish transparency and consent from
2099
+ * users.
2100
+ *
2101
+ * If a TCF policy version number is different from the one from the latest
2102
+ * GVL, the CMP must re-establish transparency and consent.
2103
+ *
2104
+ * @param {number} num - You do not need to set this. This comes
2105
+ * directly from the [[GVL]].
2106
+ *
2107
+ */
2108
+ set policyVersion(num) {
2109
+ this.policyVersion_ = parseInt(num, 10);
2110
+ if (this.policyVersion_ < 0) {
2111
+ throw new TCModelError("policyVersion", num);
2112
+ }
2113
+ }
2114
+ get policyVersion() {
2115
+ if (this.gvl) {
2116
+ return this.gvl.tcfPolicyVersion;
2117
+ } else {
2118
+ return this.policyVersion_;
2119
+ }
2120
+ }
2121
+ set version(num) {
2122
+ this.version_ = parseInt(num, 10);
2123
+ }
2124
+ get version() {
2125
+ return this.version_;
2126
+ }
2127
+ /**
2128
+ * Whether the signals encoded in this TC String were from site-specific
2129
+ * storage `true` versus ‘global’ consensu.org shared storage `false`. A
2130
+ * string intended to be stored in global/shared scope but the CMP is unable
2131
+ * to store due to a user agent not accepting third-party cookies would be
2132
+ * considered site-specific `true`.
2133
+ *
2134
+ * @param {boolean} bool - value to set. Some changes to other fields in this
2135
+ * model will automatically change this value like adding publisher
2136
+ * restrictions.
2137
+ */
2138
+ set isServiceSpecific(bool) {
2139
+ this.isServiceSpecific_ = bool;
2140
+ }
2141
+ get isServiceSpecific() {
2142
+ return this.isServiceSpecific_;
2143
+ }
2144
+ /**
2145
+ * Non-standard stacks means that a CMP is using publisher-customized stack
2146
+ * descriptions. Stacks (in terms of purposes in a stack) are pre-set by the
2147
+ * IAB. As are titles. Descriptions are pre-set, but publishers can customize
2148
+ * them. If they do, they need to set this bit to indicate that they've
2149
+ * customized descriptions.
2150
+ *
2151
+ * @param {boolean} bool - value to set
2152
+ */
2153
+ set useNonStandardTexts(bool) {
2154
+ this.useNonStandardTexts_ = bool;
2155
+ }
2156
+ get useNonStandardTexts() {
2157
+ return this.useNonStandardTexts_;
2158
+ }
2159
+ /**
2160
+ * Whether or not this publisher supports OOB signaling. On Global TC String
2161
+ * OOB Vendors Disclosed will be included if the publish wishes to no allow
2162
+ * these vendors they should set this to false.
2163
+ * @param {boolean} bool - value to set
2164
+ */
2165
+ set supportOOB(bool) {
2166
+ this.supportOOB_ = bool;
2167
+ }
2168
+ get supportOOB() {
2169
+ return this.supportOOB_;
2170
+ }
2171
+ /**
2172
+ * `false` There is no special Purpose 1 status.
2173
+ * Purpose 1 was disclosed normally (consent) as expected by Policy. `true`
2174
+ * Purpose 1 not disclosed at all. CMPs use PublisherCC to indicate the
2175
+ * publisher’s country of establishment to help Vendors determine whether the
2176
+ * vendor requires Purpose 1 consent. In global scope TC strings, this field
2177
+ * must always have a value of `false`. When a CMP encounters a global scope
2178
+ * string with `purposeOneTreatment=true` then that string should be
2179
+ * considered invalid and the CMP must re-establish transparency and consent.
2180
+ *
2181
+ * @param {boolean} bool
2182
+ */
2183
+ set purposeOneTreatment(bool) {
2184
+ this.purposeOneTreatment_ = bool;
2185
+ }
2186
+ get purposeOneTreatment() {
2187
+ return this.purposeOneTreatment_;
2188
+ }
2189
+ /**
2190
+ * setAllVendorConsents - sets all vendors on the GVL Consent (true)
2191
+ *
2192
+ * @return {void}
2193
+ */
2194
+ setAllVendorConsents() {
2195
+ this.vendorConsents.set(this.gvl.vendors);
2196
+ }
2197
+ /**
2198
+ * unsetAllVendorConsents - unsets all vendors on the GVL Consent (false)
2199
+ *
2200
+ * @return {void}
2201
+ */
2202
+ unsetAllVendorConsents() {
2203
+ this.vendorConsents.empty();
2204
+ }
2205
+ /**
2206
+ * setAllVendorsDisclosed - sets all vendors on the GVL Vendors Disclosed (true)
2207
+ *
2208
+ * @return {void}
2209
+ */
2210
+ setAllVendorsDisclosed() {
2211
+ this.vendorsDisclosed.set(this.gvl.vendors);
2212
+ }
2213
+ /**
2214
+ * unsetAllVendorsDisclosed - unsets all vendors on the GVL Consent (false)
2215
+ *
2216
+ * @return {void}
2217
+ */
2218
+ unsetAllVendorsDisclosed() {
2219
+ this.vendorsDisclosed.empty();
2220
+ }
2221
+ /**
2222
+ * setAllVendorsAllowed - sets all vendors on the GVL Consent (true)
2223
+ *
2224
+ * @return {void}
2225
+ */
2226
+ setAllVendorsAllowed() {
2227
+ this.vendorsAllowed.set(this.gvl.vendors);
2228
+ }
2229
+ /**
2230
+ * unsetAllVendorsAllowed - unsets all vendors on the GVL Consent (false)
2231
+ *
2232
+ * @return {void}
2233
+ */
2234
+ unsetAllVendorsAllowed() {
2235
+ this.vendorsAllowed.empty();
2236
+ }
2237
+ /**
2238
+ * setAllVendorLegitimateInterests - sets all vendors on the GVL LegitimateInterests (true)
2239
+ *
2240
+ * @return {void}
2241
+ */
2242
+ setAllVendorLegitimateInterests() {
2243
+ this.vendorLegitimateInterests.set(this.gvl.vendors);
2244
+ }
2245
+ /**
2246
+ * unsetAllVendorLegitimateInterests - unsets all vendors on the GVL LegitimateInterests (false)
2247
+ *
2248
+ * @return {void}
2249
+ */
2250
+ unsetAllVendorLegitimateInterests() {
2251
+ this.vendorLegitimateInterests.empty();
2252
+ }
2253
+ /**
2254
+ * setAllPurposeConsents - sets all purposes on the GVL Consent (true)
2255
+ *
2256
+ * @return {void}
2257
+ */
2258
+ setAllPurposeConsents() {
2259
+ this.purposeConsents.set(this.gvl.purposes);
2260
+ }
2261
+ /**
2262
+ * unsetAllPurposeConsents - unsets all purposes on the GVL Consent (false)
2263
+ *
2264
+ * @return {void}
2265
+ */
2266
+ unsetAllPurposeConsents() {
2267
+ this.purposeConsents.empty();
2268
+ }
2269
+ /**
2270
+ * setAllPurposeLegitimateInterests - sets all purposes on the GVL LI Transparency (true)
2271
+ *
2272
+ * @return {void}
2273
+ */
2274
+ setAllPurposeLegitimateInterests() {
2275
+ this.purposeLegitimateInterests.set(this.gvl.purposes);
2276
+ }
2277
+ /**
2278
+ * unsetAllPurposeLegitimateInterests - unsets all purposes on the GVL LI Transparency (false)
2279
+ *
2280
+ * @return {void}
2281
+ */
2282
+ unsetAllPurposeLegitimateInterests() {
2283
+ this.purposeLegitimateInterests.empty();
2284
+ }
2285
+ /**
2286
+ * setAllSpecialFeatureOptins - sets all special featuresOptins on the GVL (true)
2287
+ *
2288
+ * @return {void}
2289
+ */
2290
+ setAllSpecialFeatureOptins() {
2291
+ this.specialFeatureOptins.set(this.gvl.specialFeatures);
2292
+ }
2293
+ /**
2294
+ * unsetAllSpecialFeatureOptins - unsets all special featuresOptins on the GVL (true)
2295
+ *
2296
+ * @return {void}
2297
+ */
2298
+ unsetAllSpecialFeatureOptins() {
2299
+ this.specialFeatureOptins.empty();
2300
+ }
2301
+ setAll() {
2302
+ this.setAllVendorConsents();
2303
+ this.setAllPurposeLegitimateInterests();
2304
+ this.setAllSpecialFeatureOptins();
2305
+ this.setAllPurposeConsents();
2306
+ this.setAllVendorLegitimateInterests();
2307
+ }
2308
+ unsetAll() {
2309
+ this.unsetAllVendorConsents();
2310
+ this.unsetAllPurposeLegitimateInterests();
2311
+ this.unsetAllSpecialFeatureOptins();
2312
+ this.unsetAllPurposeConsents();
2313
+ this.unsetAllVendorLegitimateInterests();
2314
+ }
2315
+ get numCustomPurposes() {
2316
+ let len = this.numCustomPurposes_;
2317
+ if (typeof this.customPurposes === "object") {
2318
+ const purposeIds = Object.keys(this.customPurposes).sort((a, b) => Number(a) - Number(b));
2319
+ len = parseInt(purposeIds.pop(), 10);
2320
+ }
2321
+ return len;
2322
+ }
2323
+ set numCustomPurposes(num) {
2324
+ this.numCustomPurposes_ = parseInt(num, 10);
2325
+ if (this.numCustomPurposes_ < 0) {
2326
+ throw new TCModelError("numCustomPurposes", num);
2327
+ }
2328
+ }
2329
+ /**
2330
+ * updated - updates the created and lastUpdated dates with a 'now' day-level UTC timestamp
2331
+ *
2332
+ * @return {void}
2333
+ */
2334
+ updated() {
2335
+ const date = /* @__PURE__ */ new Date();
2336
+ const utcDate = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
2337
+ this.created = utcDate;
2338
+ this.lastUpdated = utcDate;
2339
+ }
2340
+ }
2341
+ __publicField(TCModel, "consentLanguages", GVL.consentLanguages);
2342
+ class TCString {
2343
+ /**
2344
+ * encodes a model into a TCString
2345
+ *
2346
+ * @param {TCModel} tcModel - model to convert into encoded string
2347
+ * @param {EncodingOptions} options - for encoding options other than default
2348
+ * @return {string} - base64url encoded Transparency and Consent String
2349
+ */
2350
+ static encode(tcModel, options) {
2351
+ let out = "";
2352
+ let sequence;
2353
+ tcModel = SemanticPreEncoder.process(tcModel, options);
2354
+ if (Array.isArray(options == null ? void 0 : options.segments)) {
2355
+ sequence = options.segments;
2356
+ } else {
2357
+ sequence = new SegmentSequence(tcModel, options)["" + tcModel.version];
2358
+ }
2359
+ sequence.forEach((segment, idx) => {
2360
+ let dotMaybe = "";
2361
+ if (idx < sequence.length - 1) {
2362
+ dotMaybe = ".";
2363
+ }
2364
+ out += SegmentEncoder.encode(tcModel, segment) + dotMaybe;
2365
+ });
2366
+ return out;
2367
+ }
2368
+ /**
2369
+ * Decodes a string into a TCModel
2370
+ *
2371
+ * @param {string} encodedTCString - base64url encoded Transparency and
2372
+ * Consent String to decode - can also be a single or group of segments of
2373
+ * the string
2374
+ * @param {string} [tcModel] - model to enhance with the information. If
2375
+ * none is passed a new instance of TCModel will be created.
2376
+ * @return {TCModel} - Returns populated TCModel
2377
+ */
2378
+ static decode(encodedTCString, tcModel) {
2379
+ const segments = encodedTCString.split(".");
2380
+ const len = segments.length;
2381
+ if (!tcModel) {
2382
+ tcModel = new TCModel();
2383
+ }
2384
+ for (let i = 0; i < len; i++) {
2385
+ const segString = segments[i];
2386
+ const firstChar = Base64Url.decode(segString.charAt(0));
2387
+ const segTypeBits = firstChar.substr(0, BitLength.segmentType);
2388
+ const segment = SegmentIDs.ID_TO_KEY[IntEncoder.decode(segTypeBits, BitLength.segmentType).toString()];
2389
+ SegmentEncoder.decode(segString, tcModel, segment);
2390
+ }
2391
+ return tcModel;
2392
+ }
2393
+ }
2394
+ const iabCustomCategories = {
2395
+ permutiveAds: {
2396
+ purposes: [2, 4, 8, 9],
2397
+ iabVendors: [361],
2398
+ customVendors: [],
2399
+ specialFeatures: []
2400
+ },
2401
+ demographicAds: {
2402
+ purposes: [3, 4, 7, 9, 10],
2403
+ iabVendors: [],
2404
+ customVendors: [],
2405
+ specialFeatures: []
2406
+ }
2407
+ };
2408
+ function isValidGdprValue(val) {
2409
+ if (val === null) {
2410
+ return true;
2411
+ }
2412
+ try {
2413
+ TCString.decode(val);
2414
+ return true;
2415
+ } catch (error) {
2416
+ return false;
2417
+ }
2418
+ }
2419
+ function isValidUspString(val) {
2420
+ if (val === null) {
2421
+ return true;
2422
+ }
2423
+ const regex = /^[1-9][YN-][YN-][YN-]$/;
2424
+ return regex.test(val);
2425
+ }
2426
+ function validateRawConsentState(input) {
2427
+ if (typeof input !== "object" || input === null) {
2428
+ throw new Error("Invalid consent state object");
2429
+ }
2430
+ if (!isValidGdprValue(input.gdpr)) {
2431
+ throw new Error("Invalid TC string provided");
2432
+ }
2433
+ if (!isValidUspString(input.ccpa)) {
2434
+ throw new Error("Invalid USP string provided");
2435
+ }
2436
+ if (!["ccpa", "gdpr"].includes(input.activeLegislation)) {
2437
+ throw new Error("Active legislation is required");
2438
+ }
2439
+ if (input.gdpr === void 0 && input.ccpa === void 0) {
2440
+ throw new Error("Either GDPR or CCPA consent must be provided");
2441
+ }
2442
+ return true;
2443
+ }
2444
+ function validateIabConsentCategory(categoryName) {
2445
+ if (!categoryName || categoryName in iabCustomCategories === false) {
2446
+ throw new Error("Provided custom category identifier does not exist. Please check");
2447
+ }
2448
+ }
2449
+ const legislation = {
2450
+ CCPA: "ccpa",
2451
+ GDPR: "gdpr"
2452
+ };
2453
+ function checkConsentFor(categoryName, consentState) {
2454
+ validateIabConsentCategory(categoryName);
2455
+ validateRawConsentState(consentState);
2456
+ const { gdpr, ccpa, activeLegislation } = consentState;
2457
+ const customCategory = iabCustomCategories[categoryName];
2458
+ if (activeLegislation === legislation.CCPA) {
2459
+ const userHasNotOptedOut = (ccpa == null ? void 0 : ccpa[2]) === "N";
2460
+ return userHasNotOptedOut;
2461
+ }
2462
+ const decodedGdprConsent = TCString.decode(gdpr);
2463
+ const { purposeConsents, vendorConsents, specialFeatureOptins } = decodedGdprConsent;
2464
+ const requiredPurposesConsented = customCategory.purposes.every(
2465
+ (requiredPurpose) => purposeConsents.has(requiredPurpose)
2466
+ );
2467
+ const requiredIabVendorsConsented = customCategory.iabVendors.every(
2468
+ (requiredVendor) => vendorConsents.has(requiredVendor)
2469
+ );
2470
+ const requiredSpecialFeaturesConsented = customCategory.specialFeatures.every(
2471
+ (requiredFeature) => specialFeatureOptins.has(requiredFeature)
2472
+ );
2473
+ return requiredPurposesConsented && requiredIabVendorsConsented && requiredSpecialFeaturesConsented;
2474
+ }
2475
+ function getParsedConsent(rawConsentState) {
2476
+ const categoryNames = Object.keys(iabCustomCategories);
2477
+ return categoryNames.reduce((parsedConsent, categoryName) => {
2478
+ parsedConsent[categoryName] = checkConsentFor(categoryName, rawConsentState);
2479
+ return parsedConsent;
2480
+ }, {});
2481
+ }
2482
+ function updateFooterLinkCMP() {
2483
+ const cookieLink = document.querySelector(
2484
+ "[href='https://www.ft.com/preferences/manage-cookies']"
2485
+ );
2486
+ if (cookieLink) {
2487
+ cookieLink.href = "#";
2488
+ cookieLink.setAttribute("onclick", "window._sp_.gdpr.loadPrivacyManagerModal(827767);");
2489
+ cookieLink.dataset.cmpLink = "updated";
2490
+ return true;
2491
+ } else {
2492
+ console.warn("CMP Footer Link was not found and not updated");
2493
+ return false;
2494
+ }
2495
+ }
2496
+ const SOURCEPOINT_CONSENT_SOURCE = "sourcepoint-cmp";
2497
+ const SOURCEPOINT_FOW_SCOPE = "FTPINK";
2498
+ const CONSENT_COOKIE_NAME = "FTConsent";
2499
+ function getPayload(parsedConsent, { shouldUpdateConsentStore, formOfWordsId, cookieDomain }) {
2500
+ const categoryNames = Object.keys(parsedConsent);
2501
+ const data = categoryNames.reduce((payload, categoryName) => {
2502
+ payload[categoryName] = {
2503
+ onsite: {
2504
+ status: parsedConsent[categoryName],
2505
+ lbi: false,
2506
+ source: SOURCEPOINT_CONSENT_SOURCE,
2507
+ fow: formOfWordsId
2508
+ }
2509
+ };
2510
+ return payload;
2511
+ }, {});
2512
+ if (!shouldUpdateConsentStore) {
2513
+ return { data };
2514
+ } else {
2515
+ return {
2516
+ setConsentCookie: true,
2517
+ formOfWordsId,
2518
+ consentSource: SOURCEPOINT_CONSENT_SOURCE,
2519
+ cookieDomain,
2520
+ data
2521
+ };
2522
+ }
2523
+ }
2524
+ async function saveConsent(consentEndpoint, payload) {
2525
+ try {
2526
+ const response = await fetch(consentEndpoint, {
2527
+ method: "POST",
2528
+ headers: {
2529
+ "Content-Type": "application/json"
2530
+ },
2531
+ body: JSON.stringify(payload),
2532
+ credentials: "include"
2533
+ });
2534
+ if (!response.ok) {
2535
+ console.error("Unable to save consent preferences", response.status);
2536
+ }
2537
+ } catch (error) {
2538
+ console.error("An error occurred while saving consent", error);
2539
+ }
2540
+ }
2541
+ function consentReadyHandlerFn(props) {
2542
+ const { userId, consentProxyHost, cookieDomain, formOfWordsId, useConsentStore } = props;
2543
+ return async (legislation2, _, consentString, consentMeta) => {
2544
+ const activeLegislation = consentMeta.applies ? legislation2 : "gdpr";
2545
+ if (activeLegislation !== legislation2 || !consentString) {
2546
+ return;
2547
+ }
2548
+ const parsedConsent = getParsedConsent({
2549
+ activeLegislation,
2550
+ gdpr: activeLegislation === "gdpr" ? consentString : null,
2551
+ ccpa: activeLegislation === "ccpa" ? consentString : null
2552
+ });
2553
+ const consentHasChanged = hasConsentChanged(parsedConsent);
2554
+ if (!consentHasChanged) {
2555
+ return;
2556
+ }
2557
+ let consentEndpoint = `${consentProxyHost}/__consent/consent-record-cookie?cookieDomain=${cookieDomain}`;
2558
+ const shouldUpdateConsentStore = !!userId && useConsentStore;
2559
+ if (shouldUpdateConsentStore) {
2560
+ consentEndpoint = `${consentProxyHost}/__consent/consent-record/${SOURCEPOINT_FOW_SCOPE}/${userId}`;
2561
+ }
2562
+ const payload = getPayload(parsedConsent, {
2563
+ formOfWordsId,
2564
+ cookieDomain,
2565
+ shouldUpdateConsentStore
2566
+ });
2567
+ await saveConsent(consentEndpoint, payload);
2568
+ document.dispatchEvent(new CustomEvent("oCookieMessage.act", { bubbles: true }));
2569
+ };
2570
+ }
2571
+ function hasConsentChanged(parsedConsent) {
2572
+ const categories = Object.keys(parsedConsent);
2573
+ const previousConsent = getConsentCookieValue();
2574
+ return categories.some((category) => {
2575
+ const adaptedCategoryName = `${category.toLowerCase()}Onsite`;
2576
+ return parsedConsent[category] !== previousConsent[adaptedCategoryName];
2577
+ });
2578
+ }
2579
+ function getConsentCookieValue() {
2580
+ const cookies = Object.fromEntries(
2581
+ document.cookie.split("; ").map((cookie) => cookie.split("="))
2582
+ );
2583
+ const encodedValue = cookies[CONSENT_COOKIE_NAME];
2584
+ if (!encodedValue)
2585
+ return {};
2586
+ const decodedValue = decodeURIComponent(encodedValue);
2587
+ return Object.fromEntries(
2588
+ decodedValue.split(",").map((consent) => {
2589
+ const [category, value] = consent.split(":");
2590
+ const booleanConsent = [category, value === "on" ? true : false];
2591
+ return booleanConsent;
2592
+ })
2593
+ );
2594
+ }
2595
+ const SOURCEPOINT_FOW_ID = "sourcepointCmp/VngD.XycZut.595cp9fWdp5XYP9vlFvk";
2596
+ const FT_COOKIE_DOMAIN = ".ft.com";
2597
+ const FT_CONSENT_PROXY_HOST = "https://consent.ft.com";
2598
+ function createContentScript(content) {
2599
+ const s = document.createElement("script");
2600
+ s.innerHTML = content;
2601
+ return s;
2602
+ }
2603
+ function createSourceScript(src) {
2604
+ const s = document.createElement("script");
2605
+ s.src = src;
2606
+ return s;
2607
+ }
2608
+ function getCmpScripts(config) {
2609
+ const fragment = document.createDocumentFragment();
2610
+ fragment.appendChild(createContentScript(scriptContent.tcfStub));
2611
+ fragment.appendChild(createContentScript(scriptContent.uspStub));
2612
+ fragment.appendChild(createContentScript(scriptContent.getSPConfig(config)));
2613
+ fragment.appendChild(createSourceScript(scriptSources.cmpFrames));
2614
+ return fragment;
2615
+ }
2616
+ async function initSourcepointCmp({
2617
+ propertyConfig = properties.FT_DOTCOM_PROD,
2618
+ userId,
2619
+ useFTSession = true,
2620
+ consentProxyHost = FT_CONSENT_PROXY_HOST,
2621
+ cookieDomain = FT_COOKIE_DOMAIN,
2622
+ formOfWordsId = SOURCEPOINT_FOW_ID,
2623
+ useConsentStore = true
2624
+ }) {
2625
+ let maybeUserId = userId;
2626
+ if (!maybeUserId && useFTSession) {
2627
+ try {
2628
+ const response = await getUuid();
2629
+ maybeUserId = response == null ? void 0 : response.uuid;
2630
+ } catch (error) {
2631
+ console.error(error);
2632
+ }
2633
+ }
2634
+ if (!(propertyConfig == null ? void 0 : propertyConfig.accountId)) {
2635
+ throw new Error("Please pass a valid property config");
2636
+ }
2637
+ if (maybeUserId) {
2638
+ propertyConfig.authId = maybeUserId;
2639
+ }
2640
+ const scripts = getCmpScripts(propertyConfig);
2641
+ document.head.appendChild(scripts);
2642
+ window._sp_queue.push(() => {
2643
+ window._sp_.addEventListener(
2644
+ "onConsentReady",
2645
+ consentReadyHandlerFn({
2646
+ userId: maybeUserId,
2647
+ consentProxyHost,
2648
+ cookieDomain,
2649
+ formOfWordsId,
2650
+ useConsentStore
2651
+ })
2652
+ );
2653
+ });
2654
+ }
2655
+ exports.getCmpScripts = getCmpScripts;
2656
+ exports.initSourcepointCmp = initSourcepointCmp;
2657
+ exports.updateFooterLinkCMP = updateFooterLinkCMP;