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