@financial-times/cmp-client 2.2.1 → 2.2.3-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +91 -35
  2. package/dist/index.cjs +114 -122
  3. package/dist/index.js +114 -122
  4. package/dist/src/client.d.ts.map +1 -0
  5. package/dist/{consent-ready → src/consent-ready}/index.d.ts +1 -1
  6. package/dist/src/consent-ready/index.d.ts.map +1 -0
  7. package/dist/src/consent-ready/utils/__fixtures__/strings.d.ts.map +1 -0
  8. package/dist/src/consent-ready/utils/__tests__/check-consent.test.d.ts.map +1 -0
  9. package/dist/src/consent-ready/utils/__tests__/get-parsed-consent.test.d.ts.map +1 -0
  10. package/dist/src/consent-ready/utils/__tests__/validators.test.d.ts.map +1 -0
  11. package/dist/{consent-ready → src/consent-ready}/utils/get-consent-payload.d.ts +1 -1
  12. package/dist/src/consent-ready/utils/get-consent-payload.d.ts.map +1 -0
  13. package/dist/src/consent-ready/utils/get-parsed-consent.d.ts.map +1 -0
  14. package/dist/src/consent-ready/utils/has-consent-changed.d.ts.map +1 -0
  15. package/dist/src/consent-ready/utils/validators.d.ts.map +1 -0
  16. package/dist/src/html/__tests__/cmp-footer-links.test.d.ts.map +1 -0
  17. package/dist/src/html/__tests__/cmp-scripts.test.d.ts +2 -0
  18. package/dist/src/html/__tests__/cmp-scripts.test.d.ts.map +1 -0
  19. package/dist/src/html/cmp-footer-link.d.ts.map +1 -0
  20. package/dist/src/html/cmp-scripts.d.ts +7 -0
  21. package/dist/src/html/cmp-scripts.d.ts.map +1 -0
  22. package/dist/{index.d.ts → src/index.d.ts} +1 -2
  23. package/dist/src/index.d.ts.map +1 -0
  24. package/dist/src/lib/constants.d.ts.map +1 -0
  25. package/dist/src/lib/debug.d.ts +15 -0
  26. package/dist/src/lib/debug.d.ts.map +1 -0
  27. package/dist/src/lib/properties.d.ts +22 -0
  28. package/dist/src/lib/properties.d.ts.map +1 -0
  29. package/dist/src/utils/dom.d.ts +3 -0
  30. package/dist/src/utils/dom.d.ts.map +1 -0
  31. package/package.json +2 -2
  32. package/typings/globals.d.ts +4 -12
  33. package/typings/types.d.ts +11 -1
  34. package/dist/client.d.ts.map +0 -1
  35. package/dist/consent-ready/index.d.ts.map +0 -1
  36. package/dist/consent-ready/utils/__fixtures__/strings.d.ts.map +0 -1
  37. package/dist/consent-ready/utils/__tests__/check-consent.test.d.ts.map +0 -1
  38. package/dist/consent-ready/utils/__tests__/get-parsed-consent.test.d.ts.map +0 -1
  39. package/dist/consent-ready/utils/__tests__/validators.test.d.ts.map +0 -1
  40. package/dist/consent-ready/utils/get-consent-payload.d.ts.map +0 -1
  41. package/dist/consent-ready/utils/get-parsed-consent.d.ts.map +0 -1
  42. package/dist/consent-ready/utils/has-consent-changed.d.ts.map +0 -1
  43. package/dist/consent-ready/utils/validators.d.ts.map +0 -1
  44. package/dist/html/__tests__/cmp-footer-links.test.d.ts.map +0 -1
  45. package/dist/html/cmp-footer-link.d.ts.map +0 -1
  46. package/dist/html/cmp-scripts.d.ts +0 -16
  47. package/dist/html/cmp-scripts.d.ts.map +0 -1
  48. package/dist/index.d.ts.map +0 -1
  49. package/dist/lib/constants.d.ts.map +0 -1
  50. package/dist/lib/debug.d.ts +0 -12
  51. package/dist/lib/debug.d.ts.map +0 -1
  52. package/dist/lib/properties.d.ts +0 -17
  53. package/dist/lib/properties.d.ts.map +0 -1
  54. package/dist/utils/dom.d.ts +0 -3
  55. package/dist/utils/dom.d.ts.map +0 -1
  56. /package/dist/{client.d.ts → src/client.d.ts} +0 -0
  57. /package/dist/{consent-ready → src/consent-ready}/utils/__fixtures__/strings.d.ts +0 -0
  58. /package/dist/{consent-ready → src/consent-ready}/utils/__tests__/check-consent.test.d.ts +0 -0
  59. /package/dist/{consent-ready → src/consent-ready}/utils/__tests__/get-parsed-consent.test.d.ts +0 -0
  60. /package/dist/{consent-ready → src/consent-ready}/utils/__tests__/validators.test.d.ts +0 -0
  61. /package/dist/{consent-ready → src/consent-ready}/utils/get-parsed-consent.d.ts +0 -0
  62. /package/dist/{consent-ready → src/consent-ready}/utils/has-consent-changed.d.ts +0 -0
  63. /package/dist/{consent-ready → src/consent-ready}/utils/validators.d.ts +0 -0
  64. /package/dist/{html → src/html}/__tests__/cmp-footer-links.test.d.ts +0 -0
  65. /package/dist/{html → src/html}/cmp-footer-link.d.ts +0 -0
  66. /package/dist/{lib → src/lib}/constants.d.ts +0 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # CMP Client
2
2
 
3
- A package to help you add a CMP (currently provided by Sourcepoint) to your application.
3
+ A client-side package to help you add a CMP (currently provided by Sourcepoint) to your application.
4
4
 
5
5
  ## Installation
6
6
 
@@ -24,64 +24,120 @@ Visit https://localhost:5173 (see setup details in `src/examples/cmp-client`) to
24
24
 
25
25
  ```js
26
26
  import { initSourcepointCmp } from "@financial-times/cmp-client/client";
27
- import { FT_DOTCOM_LOCAL } from "@financial-times/cmp-client/properties";
27
+ import { FT_DOTCOM_TEST } from "@financial-times/cmp-client/properties";
28
28
 
29
29
  // we suggest using a feature flag to disable the existing cookie banner and enable the new one
30
30
  if (flagsClient.get("adsDisableInternalCMP")) {
31
31
  initSourcepointCmp({
32
- propertyConfig: FT_DOTCOM_LOCAL,
33
- // useConsentStore: false (set to false e.g for non-FT.com properties or websites)
32
+ propertyConfig: FT_DOTCOM_TEST,
33
+ // useConsentStore: false (set to false for non-FT.com properties or websites)
34
34
  });
35
35
  }
36
36
  ```
37
37
 
38
- We will be adding new properties and their configs as we start rolling out. Please reach out to the Ads & Privacy team if you think you need to create a new property for your domain e.g it is on a different domain from the `ft.com` domain
38
+ We will be adding new properties (websites under FT group) and their configs as we start rolling out. Please reach out to the Ads & Privacy team if you think you need to create a new property for your domain - for example, if it is on a different domain from the `ft.com` domain.
39
39
 
40
40
  ### CMP configuration options:
41
41
 
42
- | Option | Description |
43
- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
44
- | `propertyConfig` (SourcepointConfig) | This config object is directly passed to Sourcepoint (our external CMP) and presets (imported like example usage) will be made available for different properties/titles under the FT group. This currently defaults to the FT_DOTCOM_PROD preset |
45
- | `userId` (string) | Please provide a userId if the user is a logged in user. If your app uses the FT Secure Session token, you can leave empty and set `useFTSession` to true instead. Defaults to `undefined` for anonymous users |
46
- | `useFTSession` (boolean) | Set this flag if you want the user's Id to be automatically derived from their FT Secure Session . Defaults to `true` |
47
- | `consentProxyHost` (string) | The fully qualified domain name for your consent proxy instance e.g `https://consent.thebanker.com`. Defaults to `https://consent.ft.com` |
48
- | `cookieDomain` (string) | The domain (and subdomains) that the FTConsent cookie will apply to e.g `.thebanker.com`. Defaults to `.ft.com` |
49
- | `formOfWordsId` (string) | The IAB custom categories that you have adapted might be tracked under a different FOW ID. At the moment, all custom categories are tracked under the `sourcepointCmp` form-of-words and its ID is default value |
50
- | `useConsentStore` (boolean) | Specifies whether the user's consent record should also be backed by the Single Consent Store. Properties like Specialist titles will need to explicitly set this to `false` as `true` is the default behavior |
42
+ <table>
43
+ <thead>
44
+ <tr>
45
+ <th>Option</th>
46
+ <th>Description</th>
47
+ </tr>
48
+ <thead/>
49
+ <tbody>
50
+ <tr>
51
+ <td><code>propertyConfig</code> (SourcepointConfig)</td>
52
+ <td>This config object is directly passed to Sourcepoint (our external CMP) and presets (imported like example usage) will be made available for different properties/titles under the FT group. This currently defaults to the <code>FT_DOTCOM_PROD</code> preset</td>
53
+ </tr>
54
+ <tr>
55
+ <td><code>userId</code> (string)</td>
56
+ <td>Please provide a userId if the user is a logged in user. If your app uses the FT Secure Session token, you can leave empty and set <code>useFTSession</code> to true instead. Defaults to <code>undefined</code> for anonymous users</td>
57
+ </tr>
58
+ <tr>
59
+ <td><code>useFTSession</code> (boolean)</td>
60
+ <td>Set this flag if you want the user's Id to be automatically derived from their FT Secure Session. Set to <code>false</code> if your app doesn't use FT Secure Session. Defaults to <code>true</code></td>
61
+ </tr>
62
+ <tr>
63
+ <td><code>consentProxyHost</code> (string)</td>
64
+ <td>The fully qualified domain name for your consent proxy instance e.g <code>https://consent.thebanker.com</code>. Defaults to <code>https://consent.ft.com</code></td>
65
+ </tr>
66
+ <tr>
67
+ <td><code>cookieDomain</code> (string)</td>
68
+ <td>The domain (and subdomains) that the FTConsent cookie will apply to e.g <code>.thebanker.com</code>. Defaults to <code>.ft.com</code></td>
69
+ </tr>
70
+ <tr>
71
+ <td><code>formOfWordsId</code> (string)</td>
72
+ <td>The IAB custom categories that you have adapted might be tracked under a different FOW ID. At the moment, all custom categories are tracked under the <code>sourcepointCmp</code> form-of-words and it defaults to <code>sourcepointCmp/VngD.XycZut.595cp9fWdp5XYP9vlFvk</code>. Properties using the consent banner as presented should use the default value</td>
73
+ </tr>
74
+ <tr>
75
+ <td><code>useConsentStore</code> (boolean)</td>
76
+ <td>Specifies whether the user's consent record should also be backed by the Single Consent Store. Properties like Specialist titles will need to explicitly set this to <code>false</code> as <code>true</code> is the default behavior</td>
77
+ </tr>
78
+ <tr>
79
+ <td><code>events</code> (object)</td>
80
+ <td>Used internally to define handlers for events emitted by the Vendor-supplied CMP module. See notes on "Responding to CMP events" below for details on how to define custom event handlers</td>
81
+ </tr>
82
+ </tbody>
83
+ <table/>
84
+
85
+ ## Responding to CMP events
86
+
87
+ If you need to do additional work in response to events emitted by the CMP Vendor module you can do so via the `window._sp_.addEventListener` method:
51
88
 
52
- ### Available Properties (constantly being updated)
53
-
54
- | Property Key | Details |
55
- | ----------------- | ------------------------------------------------------------------------------------------------------------------- |
56
- | `FT_DOTCOM_LOCAL` | Configuration preset for all properties on FT.com domain operating in a local environment - `https://local.ft.com` |
57
- | `FT_DOTCOM_PROD` | Configuration preset for all properties on FT.com domain operating in a production environment - `https://*.ft.com` |
89
+ ```js
90
+ window._sp_.addEventListener("onMessageReady", (messageType) => {... });
91
+ window._sp_.addEventListener("onConsentReady", (legislation, consentUUID, consentString, consentMeta) => { ... });
92
+ ```
58
93
 
59
- ## Consent Banner scripts only
94
+ > [!Note]
95
+ > The `onConsentReady` event is fired
96
+ >
97
+ > 1. As soon as the CMP has finished loading and the user's consent choices are available
98
+ > 1. Subsequently, whenever the user's consent choices change
60
99
 
61
- If you only want the scripts to setup the consent banner for your page with interacting without interacting with the FT's consent APIs, the package also exposes a `getCmpScripts` method, which returns a `DocumentFragment` containing block of scripts that you can to your page's `<head>` element.
100
+ See the [Sourcepoint docs](https://docs.sourcepoint.com/hc/en-us/articles/4412176150035-Queue-event-callbacks) for a full listing of the events you can listen for and the arguments passed to the callbacks.
62
101
 
63
- ```js
64
- import { getCmpScripts } from "@financial-times/cmp-client/client";
65
- import { FT_DOTCOM_LOCAL } from "@financial-times/cmp-client/properties";
102
+ ### Available Properties (constantly being updated)
66
103
 
67
- const cmpScripts = getCmpScripts(FT_DOTCOM_LOCAL);
68
- document.head.appendChild(cmpScripts);
69
- ```
104
+ <table>
105
+ <thead>
106
+ <tr>
107
+ <th>Property Key</th>
108
+ <th>Details</th>
109
+ </tr>
110
+ <thead/>
111
+ <tbody>
112
+ <tr>
113
+ <td><code>FT_DOTCOM_TEST</code></td>
114
+ <td>
115
+ <p>Use this configuration preset for testing the CMP on a property that has not yet been registered in the Sourcepoint portal.</p>
116
+ <p>All <code>*.ft.com</code> are currently registered and this config will spoof your request as coming from <code>https://local.ft.com</code>
117
+ </p>
118
+ </td>
119
+ </tr>
120
+ <tr>
121
+ <td><code>FT_DOTCOM_PROD</code></td>
122
+ <td>Configuration preset for all properties on FT.com domain operating in a production environment - <code>https://*.ft.com</code></td>
123
+ </tr>
124
+ </tbody>
125
+ <table/>
70
126
 
71
127
  ## Debugging
72
128
 
73
- You can verify that the CMP is correctly configured by adding an `events` map to your configuration: the `debug` module used in the examples provides a sample implementation:
129
+ You can verify that the CMP is correctly configured with the `debug` module, as deomstrated in [the CMP Client example](src/examples/src/scripts/cmp-client.ts):
74
130
 
75
131
  ```js
76
- import { getCmpScripts } from "@financial-times/cmp-client/client";
77
- import { ft } from "@financial-times/cmp-client/properties";
78
- import { events } from "@financial-times/cmp-client/debug";
132
+ import { debug } from "@financial-times/cmp-client";
79
133
 
80
- // Merge the events map into the domain configuration
81
- const config = { ...ft, events };
82
- document.head.appendChild(getCmpScripts(config));
134
+ debug.logCmpEvents();
83
135
  ```
84
136
 
85
137
  If everything's working then when running the demo app you'll see the CMP log its lifecycle events to the console, _even if its UI isn't displayed_.
86
138
 
87
139
  This can easily happen when you've made a previous consent choice and the CMP is now picking it up from local storage. We recommend running in an incognito window during development.
140
+
141
+ ## How it works
142
+
143
+ The overview of how the CMP client works is diagrammatically [presented here](https://financialtimes.atlassian.net/wiki/spaces/ADS/pages/8151990292/New+Consent+Migration+Guide+for+teams#What-happens-when-a-user-visits-%5BinlineCard%5D--in-the-new-consent-framework%3F)
package/dist/index.cjs CHANGED
@@ -7,6 +7,87 @@ var __publicField = (obj, key, value) => {
7
7
  };
8
8
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
9
9
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
10
+ const version = "2.2.3-alpha";
11
+ const events = {
12
+ onMessageChoiceSelect: (...args) => {
13
+ console.log("[debug] onMessageChoiceSelect", args);
14
+ },
15
+ onMessageReady: (...args) => {
16
+ console.log("[debug] onMessageReady", args);
17
+ },
18
+ onMessageChoiceError: (...args) => {
19
+ console.log("[debug] onMessageChoiceError", args);
20
+ },
21
+ onPrivacyManagerAction: (...args) => {
22
+ console.log("[debug] onPrivacyManagerAction", args);
23
+ },
24
+ onPMCancel: (...args) => {
25
+ console.log("[debug] onPMCancel", args);
26
+ },
27
+ onMessageReceiveData: (...args) => {
28
+ console.log("[debug] onMessageReceiveData", args);
29
+ },
30
+ onSPPMObjectReady: (...args) => {
31
+ console.log("[debug] onSPPMObjectReady", args);
32
+ },
33
+ onConsentReady: async (...args) => {
34
+ const [legislation2, consentUUID, consentString, consentMeta] = args;
35
+ console.log("[debug] onConsentReady", { legislation: legislation2, consentString, consentMeta, consentUUID });
36
+ },
37
+ onError: (...args) => {
38
+ console.log("[debug] onError", args);
39
+ }
40
+ };
41
+ function logCmpEvents() {
42
+ window._sp_queue = window._sp_queue ?? [];
43
+ window._sp_queue.push(() => {
44
+ var _a2, _b2;
45
+ for (const [eventId, eventHandler] of Object.entries(events)) {
46
+ (_b2 = (_a2 = window._sp_).addEventListener) == null ? void 0 : _b2.call(_a2, eventId, eventHandler);
47
+ }
48
+ });
49
+ }
50
+ const debug = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
51
+ __proto__: null,
52
+ events,
53
+ logCmpEvents
54
+ }, Symbol.toStringTag, { value: "Module" }));
55
+ const defaults = {
56
+ joinHref: true,
57
+ gdpr: {},
58
+ ccpa: {}
59
+ };
60
+ const FT_DOTCOM_TEST = {
61
+ ...defaults,
62
+ accountId: 1906,
63
+ baseEndpoint: "https://consent-manager.ft.com",
64
+ propertyHref: "https://local.ft.com"
65
+ };
66
+ const FT_DOTCOM_PROD = {
67
+ ...defaults,
68
+ accountId: 1906,
69
+ baseEndpoint: "https://consent-manager.ft.com",
70
+ propertyId: 31642
71
+ };
72
+ const properties = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
73
+ __proto__: null,
74
+ FT_DOTCOM_PROD,
75
+ FT_DOTCOM_TEST
76
+ }, Symbol.toStringTag, { value: "Module" }));
77
+ function updateFooterLinkCMP() {
78
+ const cookieLink = document.querySelector(
79
+ "[href='https://www.ft.com/preferences/manage-cookies']"
80
+ );
81
+ if (cookieLink) {
82
+ cookieLink.href = "#";
83
+ cookieLink.setAttribute("onclick", "window._sp_.gdpr.loadPrivacyManagerModal(827767);");
84
+ cookieLink.dataset.cmpLink = "updated";
85
+ return true;
86
+ } else {
87
+ console.warn("CMP Footer Link was not found and not updated");
88
+ return false;
89
+ }
90
+ }
10
91
  const request = (url, { credentials = "omit" } = {}) => {
11
92
  return fetch(`https://session-next.ft.com${url}`, {
12
93
  credentials,
@@ -113,30 +194,9 @@ const iabCustomCategories = {
113
194
  specialFeatures: []
114
195
  }
115
196
  };
116
- const defaults = {
117
- joinHref: true,
118
- gdpr: {},
119
- ccpa: {}
120
- };
121
- const FT_DOTCOM_LOCAL = {
122
- ...defaults,
123
- accountId: 1906,
124
- baseEndpoint: "https://consent-manager.ft.com",
125
- propertyHref: "https://local.ft.com"
126
- };
127
- const FT_DOTCOM_PROD = {
128
- ...defaults,
129
- accountId: 1906,
130
- baseEndpoint: "https://consent-manager.ft.com",
131
- propertyId: 31642
132
- };
133
- const properties = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
134
- __proto__: null,
135
- FT_DOTCOM_LOCAL,
136
- FT_DOTCOM_PROD
137
- }, Symbol.toStringTag, { value: "Module" }));
138
- function createContentScript(content) {
197
+ function createContentScript(cmpScript, content) {
139
198
  const s = document.createElement("script");
199
+ s.dataset.cmpScript = cmpScript;
140
200
  s.innerHTML = content;
141
201
  return s;
142
202
  }
@@ -145,47 +205,25 @@ function createSourceScript(src) {
145
205
  s.src = src;
146
206
  return s;
147
207
  }
148
- function encodeConfig(obj) {
149
- let str = "";
150
- if (!obj)
151
- return str;
152
- for (const [key, val] of Object.entries(obj)) {
153
- switch (typeof val) {
154
- case "function":
155
- str += `${key}:${val.toString().replace(/"/g, "'").replace(/\s/g, "")},`;
156
- break;
157
- case "string":
158
- str += `${key}:"${val.replace(/"/g, "'").replace(/\s/g, "")}",`;
159
- break;
160
- case "object":
161
- str += `${key}:{${encodeConfig(val)}},`;
162
- break;
163
- default:
164
- str += `${key}:${val},`;
165
- break;
166
- }
167
- }
168
- return str.slice(0, -1);
169
- }
170
- function getSPConfig(config) {
171
- return `window._sp_queue=[];window._sp_={config:{${encodeConfig(config)}}}`;
172
- }
173
208
  const scriptSources = {
174
209
  cmpFrames: "https://consent-manager.ft.com/unified/wrapperMessagingWithoutDetection.js"
175
210
  };
176
211
  const scriptContent = {
177
- getSPConfig,
178
212
  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()}();`,
179
213
  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) } })();`
180
214
  };
181
- function getCmpScripts(config) {
215
+ function getCmpScripts() {
182
216
  const fragment = document.createDocumentFragment();
183
- fragment.appendChild(createContentScript(scriptContent.tcfStub));
184
- fragment.appendChild(createContentScript(scriptContent.uspStub));
185
- fragment.appendChild(createContentScript(scriptContent.getSPConfig(config)));
217
+ fragment.appendChild(createContentScript("tcf", scriptContent.tcfStub));
218
+ fragment.appendChild(createContentScript("usp", scriptContent.uspStub));
186
219
  fragment.appendChild(createSourceScript(scriptSources.cmpFrames));
187
220
  return fragment;
188
221
  }
222
+ function bootstrapCmp(config) {
223
+ window._sp_ = { config };
224
+ window._sp_queue ?? (window._sp_queue = []);
225
+ document.head.appendChild(getCmpScripts());
226
+ }
189
227
  function getConsentPayload(parsedConsent, { shouldUpdateConsentStore, formOfWordsId, cookieDomain }) {
190
228
  const categoryNames = Object.keys(parsedConsent);
191
229
  const data = categoryNames.reduce(
@@ -203,7 +241,7 @@ function getConsentPayload(parsedConsent, { shouldUpdateConsentStore, formOfWord
203
241
  {}
204
242
  );
205
243
  if (!shouldUpdateConsentStore) {
206
- return { data };
244
+ return { data, cookieDomain };
207
245
  } else {
208
246
  return {
209
247
  setConsentCookie: true,
@@ -1247,7 +1285,7 @@ class VendorVectorEncoder {
1247
1285
  }
1248
1286
  return retrString;
1249
1287
  }
1250
- static decode(value, version) {
1288
+ static decode(value, version2) {
1251
1289
  let vector;
1252
1290
  let index = 0;
1253
1291
  const maxId = IntEncoder.decode(value.substr(index, BitLength.maxId), BitLength.maxId);
@@ -1256,7 +1294,7 @@ class VendorVectorEncoder {
1256
1294
  index += BitLength.encodingType;
1257
1295
  if (encodingType === VectorEncodingType.RANGE) {
1258
1296
  vector = new Vector();
1259
- if (version === 1) {
1297
+ if (version2 === 1) {
1260
1298
  if (value.substr(index, 1) === "1") {
1261
1299
  throw new DecodingError("Unable to decode default consent=1");
1262
1300
  }
@@ -1721,12 +1759,12 @@ const _GVL = class _GVL extends Cloneable {
1721
1759
  throw new GVLError("must specify GVL.baseUrl before loading GVL json");
1722
1760
  }
1723
1761
  if (versionOrVendorList > 0) {
1724
- const version = versionOrVendorList;
1725
- if (_GVL.CACHE.has(version)) {
1726
- this.populate(_GVL.CACHE.get(version));
1762
+ const version2 = versionOrVendorList;
1763
+ if (_GVL.CACHE.has(version2)) {
1764
+ this.populate(_GVL.CACHE.get(version2));
1727
1765
  this.readyPromise = Promise.resolve();
1728
1766
  } else {
1729
- url += _GVL.versionedFilename.replace("[VERSION]", String(version));
1767
+ url += _GVL.versionedFilename.replace("[VERSION]", String(version2));
1730
1768
  this.readyPromise = this.fetchJson(url);
1731
1769
  }
1732
1770
  } else {
@@ -2800,7 +2838,7 @@ async function saveConsent(consentEndpoint, payload) {
2800
2838
  }
2801
2839
  function consentReadyHandlerFn(props) {
2802
2840
  const { userId, consentProxyHost, cookieDomain, formOfWordsId, useConsentStore } = props;
2803
- return async function consentReadyHandler(legislation2, _, consentString, consentMeta) {
2841
+ return async function consentReadyHandler(legislation2, _consentUUID, consentString, consentMeta) {
2804
2842
  const activeLegislation = consentMeta.applies ? legislation2 : "gdpr";
2805
2843
  if (activeLegislation !== legislation2 || !consentString) {
2806
2844
  return;
@@ -2837,6 +2875,7 @@ async function initSourcepointCmp({
2837
2875
  formOfWordsId = SOURCEPOINT_FOW_ID,
2838
2876
  useConsentStore = true
2839
2877
  } = {}) {
2878
+ var _a2;
2840
2879
  if (!userId && useFTSession) {
2841
2880
  try {
2842
2881
  const response = await getUuid();
@@ -2851,70 +2890,23 @@ async function initSourcepointCmp({
2851
2890
  if (userId) {
2852
2891
  propertyConfig.authId = userId;
2853
2892
  }
2854
- const scripts = getCmpScripts(propertyConfig);
2855
- document.head.appendChild(scripts);
2856
- window._sp_queue.push(() => {
2857
- window._sp_.addEventListener(
2858
- "onConsentReady",
2859
- consentReadyHandlerFn({
2860
- userId,
2861
- consentProxyHost,
2862
- cookieDomain,
2863
- formOfWordsId,
2864
- useConsentStore
2865
- })
2866
- );
2867
- });
2868
- }
2869
- const events = {
2870
- onMessageChoiceSelect: (...args) => {
2871
- console.log("[event] onMessageChoiceSelect", args);
2872
- },
2873
- onMessageReady: (...args) => {
2874
- console.log("[event] onMessageReady", args);
2875
- },
2876
- onMessageChoiceError: (...args) => {
2877
- console.log("[event] onMessageChoiceError", args);
2878
- },
2879
- onPrivacyManagerAction: (...args) => {
2880
- console.log("[event] onPrivacyManagerAction", args);
2881
- },
2882
- onPMCancel: (...args) => {
2883
- console.log("[event] onPMCancel", args);
2884
- },
2885
- onMessageReceiveData: (...args) => {
2886
- console.log("[event] onMessageReceiveData", args);
2887
- },
2888
- onSPPMObjectReady: (...args) => {
2889
- console.log("[event] onSPPMObjectReady", args);
2890
- },
2891
- onConsentReady: (...args) => {
2892
- console.log("[event] onConsentReady", args);
2893
- },
2894
- onError: (...args) => {
2895
- console.log("[event] onError", args);
2896
- }
2897
- };
2898
- const debug = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2899
- __proto__: null,
2900
- events
2901
- }, Symbol.toStringTag, { value: "Module" }));
2902
- function updateFooterLinkCMP() {
2903
- const cookieLink = document.querySelector(
2904
- "[href='https://www.ft.com/preferences/manage-cookies']"
2905
- );
2906
- if (cookieLink) {
2907
- cookieLink.href = "#";
2908
- cookieLink.setAttribute("onclick", "window._sp_.gdpr.loadPrivacyManagerModal(827767);");
2909
- cookieLink.dataset.cmpLink = "updated";
2910
- return true;
2911
- } else {
2912
- console.warn("CMP Footer Link was not found and not updated");
2913
- return false;
2893
+ if ((_a2 = propertyConfig.events) == null ? void 0 : _a2.onConsentReady) {
2894
+ console.warn("[cmp-client] The supplied 'onConsentReady' event handler will be overwritten.");
2914
2895
  }
2896
+ const events2 = {
2897
+ ...propertyConfig.events ?? {},
2898
+ onConsentReady: consentReadyHandlerFn({
2899
+ userId,
2900
+ consentProxyHost,
2901
+ cookieDomain,
2902
+ formOfWordsId,
2903
+ useConsentStore
2904
+ })
2905
+ };
2906
+ bootstrapCmp({ ...propertyConfig, events: events2 });
2915
2907
  }
2908
+ window.FT_CMP_CLIENT_VERSION = version;
2916
2909
  exports.debug = debug;
2917
- exports.getCmpScripts = getCmpScripts;
2918
2910
  exports.initSourcepointCmp = initSourcepointCmp;
2919
2911
  exports.properties = properties;
2920
2912
  exports.updateFooterLinkCMP = updateFooterLinkCMP;