@financial-times/cmp-client 0.0.0-beta.1 → 0.0.0-beta.2

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/dist/index.cjs CHANGED
@@ -7,13 +7,10 @@ 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 = "0.0.0-beta.1";
10
+ const version = "0.0.0-beta.2";
11
11
  const events = {
12
12
  onMessageChoiceSelect: (...args) => {
13
13
  console.log("[debug] onMessageChoiceSelect", args);
14
- if (choice_type_id == 9) {
15
- document.cookie = "cw=dismissed; expires=Thu, 18 Dec 2030 12:00:00 UTC";
16
- }
17
14
  },
18
15
  onMessageReady: (...args) => {
19
16
  console.log("[debug] onMessageReady", args);
@@ -23,9 +20,6 @@ const events = {
23
20
  },
24
21
  onPrivacyManagerAction: (...args) => {
25
22
  console.log("[debug] onPrivacyManagerAction", args);
26
- if (pmData.purposeConsent == "none" && pmData.vendorConsent == "none") {
27
- document.cookie = "cw=dismissed; expires=Thu, 18 Dec 2030 12:00:00 UTC";
28
- }
29
23
  },
30
24
  onPMCancel: (...args) => {
31
25
  console.log("[debug] onPMCancel", args);
@@ -2935,6 +2929,212 @@ function consentReadyHandlerFn(props) {
2935
2929
  document.dispatchEvent(new CustomEvent("oCookieMessage.act", { bubbles: true }));
2936
2930
  };
2937
2931
  }
2932
+ let getRandomValues;
2933
+ const rnds8 = new Uint8Array(16);
2934
+ function rng() {
2935
+ if (!getRandomValues) {
2936
+ getRandomValues = typeof crypto !== "undefined" && crypto.getRandomValues && crypto.getRandomValues.bind(crypto);
2937
+ if (!getRandomValues) {
2938
+ throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
2939
+ }
2940
+ }
2941
+ return getRandomValues(rnds8);
2942
+ }
2943
+ const byteToHex = [];
2944
+ for (let i = 0; i < 256; ++i) {
2945
+ byteToHex.push((i + 256).toString(16).slice(1));
2946
+ }
2947
+ function unsafeStringify(arr, offset = 0) {
2948
+ return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
2949
+ }
2950
+ const randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
2951
+ const native = {
2952
+ randomUUID
2953
+ };
2954
+ function v4(options, buf, offset) {
2955
+ if (native.randomUUID && !buf && !options) {
2956
+ return native.randomUUID();
2957
+ }
2958
+ options = options || {};
2959
+ const rnds = options.random || (options.rng || rng)();
2960
+ rnds[6] = rnds[6] & 15 | 64;
2961
+ rnds[8] = rnds[8] & 63 | 128;
2962
+ if (buf) {
2963
+ offset = offset || 0;
2964
+ for (let i = 0; i < 16; ++i) {
2965
+ buf[offset + i] = rnds[i];
2966
+ }
2967
+ return buf;
2968
+ }
2969
+ return unsafeStringify(rnds);
2970
+ }
2971
+ const COOKIE_MESSAGE = "cookie-message";
2972
+ const PRIVACY_MANAGER = "manage-cookies";
2973
+ const INITIAL_STATE = Object.freeze({
2974
+ activeComponent: COOKIE_MESSAGE
2975
+ });
2976
+ let privateState = INITIAL_STATE;
2977
+ function isPlainObject(obj) {
2978
+ return typeof obj === "object" && obj !== null && obj.constructor === Object && Object.prototype.toString.call(obj) === "[object Object]";
2979
+ }
2980
+ const getState = () => ({ ...privateState });
2981
+ const setState = (newState) => {
2982
+ if (!isPlainObject(newState)) {
2983
+ console.error("Invalid state changes");
2984
+ return;
2985
+ }
2986
+ privateState = { ...privateState, ...newState };
2987
+ };
2988
+ const ACCEPT_ALL_CHOICE = 11;
2989
+ const MANAGE_PREFS_CHOICE = 12;
2990
+ const REJECT_ALL_CHOICE = 13;
2991
+ const cookieToggleFlags = ["adsDisableInternalCMP", "pwm.cmp", "messageSlotBottom"];
2992
+ function initTracking(context) {
2993
+ const componentId = v4();
2994
+ const flags = extractRelevantFlags(context.flags);
2995
+ window._sp_queue = window._sp_queue ?? [];
2996
+ window._sp_queue.push(() => {
2997
+ var _a2, _b2;
2998
+ for (const [eventId, eventHandler] of Object.entries(trackingEventHandlers)) {
2999
+ (_b2 = (_a2 = window._sp_).addEventListener) == null ? void 0 : _b2.call(_a2, eventId, eventHandler({ ...context, flags, componentId }));
3000
+ }
3001
+ });
3002
+ }
3003
+ function extractRelevantFlags(flags) {
3004
+ const output = {};
3005
+ if (typeof flags === "object") {
3006
+ cookieToggleFlags.forEach((flagName) => {
3007
+ if (Object.prototype.hasOwnProperty.call(flags, flagName)) {
3008
+ output[flagName] = flags[flagName];
3009
+ }
3010
+ });
3011
+ }
3012
+ return output;
3013
+ }
3014
+ function track(payload) {
3015
+ if (!payload)
3016
+ return;
3017
+ const rootEl = document.body;
3018
+ const event = new CustomEvent("oTracking.event", {
3019
+ bubbles: true,
3020
+ cancelable: true,
3021
+ detail: payload.detail
3022
+ });
3023
+ rootEl.dispatchEvent(event);
3024
+ }
3025
+ function dispatchComponentEvent({
3026
+ trackingProps,
3027
+ action,
3028
+ triggerAction,
3029
+ messageType
3030
+ }) {
3031
+ const state = getState();
3032
+ const { componentId, product, app, flags } = trackingProps;
3033
+ const event = {
3034
+ detail: {
3035
+ component: {
3036
+ id: componentId,
3037
+ name: state.activeComponent,
3038
+ type: "overlay",
3039
+ subtype: "cmp",
3040
+ componentContentId: state[messageType]
3041
+ },
3042
+ category: "component",
3043
+ action,
3044
+ ...triggerAction && { trigger_action: triggerAction },
3045
+ ...product && { product },
3046
+ ...app && { app },
3047
+ custom: [
3048
+ {
3049
+ cookie_toggle_flag: flags
3050
+ }
3051
+ ]
3052
+ }
3053
+ };
3054
+ track(event);
3055
+ }
3056
+ const trackingEventHandlers = {
3057
+ onMessageChoiceSelect: (trackingProps) => (messageType, _choiceId, choiceTypeId) => {
3058
+ if (choiceTypeId === ACCEPT_ALL_CHOICE) {
3059
+ dispatchComponentEvent({
3060
+ trackingProps,
3061
+ action: "click",
3062
+ triggerAction: "accept_all",
3063
+ messageType
3064
+ });
3065
+ }
3066
+ if (choiceTypeId === MANAGE_PREFS_CHOICE) {
3067
+ dispatchComponentEvent({
3068
+ trackingProps,
3069
+ action: "click",
3070
+ triggerAction: "manage_cookies",
3071
+ messageType
3072
+ });
3073
+ setState({
3074
+ activeComponent: PRIVACY_MANAGER
3075
+ });
3076
+ }
3077
+ if (choiceTypeId === REJECT_ALL_CHOICE) {
3078
+ dispatchComponentEvent({
3079
+ trackingProps,
3080
+ action: "click",
3081
+ triggerAction: "reject_all",
3082
+ messageType
3083
+ });
3084
+ }
3085
+ },
3086
+ onMessageReady: (trackingProps) => (messageType) => {
3087
+ dispatchComponentEvent({
3088
+ trackingProps,
3089
+ action: "view",
3090
+ messageType
3091
+ });
3092
+ },
3093
+ onPrivacyManagerAction: (trackingProps) => (messageType, pmData) => {
3094
+ const { purposeConsent, vendorConsent } = pmData;
3095
+ const isAcceptAll = purposeConsent === "all" && vendorConsent === "all";
3096
+ const isRejectAll = purposeConsent === "none" && vendorConsent === "none";
3097
+ setState({
3098
+ activeComponent: PRIVACY_MANAGER
3099
+ });
3100
+ if (isAcceptAll) {
3101
+ dispatchComponentEvent({
3102
+ trackingProps,
3103
+ action: "click",
3104
+ triggerAction: "accept_all",
3105
+ messageType
3106
+ });
3107
+ } else if (isRejectAll) {
3108
+ dispatchComponentEvent({
3109
+ trackingProps,
3110
+ action: "click",
3111
+ triggerAction: "reject_all",
3112
+ messageType
3113
+ });
3114
+ } else {
3115
+ dispatchComponentEvent({
3116
+ trackingProps,
3117
+ action: "click",
3118
+ triggerAction: "save_and_close",
3119
+ messageType
3120
+ });
3121
+ }
3122
+ },
3123
+ onMessageReceiveData: () => (messageType, data) => {
3124
+ const { messageId } = data;
3125
+ setState({
3126
+ [messageType]: messageId
3127
+ });
3128
+ },
3129
+ onError: (trackingProps) => (messageType, errorCode) => {
3130
+ dispatchComponentEvent({
3131
+ trackingProps,
3132
+ action: "error",
3133
+ triggerAction: errorCode,
3134
+ messageType
3135
+ });
3136
+ }
3137
+ };
2938
3138
  async function initSourcepointCmp({
2939
3139
  propertyConfig = FT_DOTCOM_PROD,
2940
3140
  userId,
@@ -2942,9 +3142,9 @@ async function initSourcepointCmp({
2942
3142
  consentProxyHost = FT_CONSENT_PROXY_HOST,
2943
3143
  cookieDomain = FT_COOKIE_DOMAIN,
2944
3144
  formOfWordsId = SOURCEPOINT_FOW_ID,
2945
- useConsentStore = true
3145
+ useConsentStore = true,
3146
+ trackingContext = {}
2946
3147
  } = {}) {
2947
- var _a2;
2948
3148
  if (!userId && useFTSession) {
2949
3149
  try {
2950
3150
  const response = await getUuid();
@@ -2959,32 +3159,65 @@ async function initSourcepointCmp({
2959
3159
  if (userId) {
2960
3160
  propertyConfig.authId = userId;
2961
3161
  }
2962
- if ((_a2 = propertyConfig.events) == null ? void 0 : _a2.onConsentReady) {
2963
- console.warn("[cmp-client] The supplied 'onConsentReady' event handler will be overwritten.");
3162
+ if (propertyConfig.events) {
3163
+ console.warn(
3164
+ "[cmp-client] Passing an events map in the config is not supported and will be ignored. Please use window._sp_.addEventListener() to listen for events"
3165
+ );
3166
+ delete propertyConfig.events;
2964
3167
  }
2965
- const events2 = {
2966
- ...propertyConfig.events ?? {},
2967
- onConsentReady: consentReadyHandlerFn({
2968
- userId,
2969
- consentProxyHost,
2970
- cookieDomain,
2971
- formOfWordsId,
2972
- useConsentStore
2973
- })
2974
- };
2975
3168
  function getCookie(name) {
3169
+ var _a2, _b2;
2976
3170
  const value = `; ${document.cookie}`;
2977
3171
  const parts = value.split(`; ${name}=`);
2978
3172
  if (parts.length === 2)
2979
- return parts.pop().split(";").shift();
3173
+ return (_b2 = (_a2 = parts.pop()) == null ? void 0 : _a2.split(";")) == null ? void 0 : _b2.shift();
2980
3174
  }
2981
- propertyConfig.gdpr = {
3175
+ propertyConfig = {
3176
+ ...propertyConfig,
2982
3177
  targetingParams: {
2983
- // @ts-ignore
2984
- "cookiew": getCookie("cw")
3178
+ cookiew: getCookie("cw")
2985
3179
  }
2986
3180
  };
2987
- bootstrapCmp({ ...propertyConfig, events: events2 });
3181
+ bootstrapCmp(propertyConfig);
3182
+ window._sp_queue.push(() => {
3183
+ var _a2, _b2;
3184
+ (_b2 = (_a2 = window._sp_) == null ? void 0 : _a2.addEventListener) == null ? void 0 : _b2.call(
3185
+ _a2,
3186
+ "onConsentReady",
3187
+ consentReadyHandlerFn({
3188
+ userId,
3189
+ consentProxyHost,
3190
+ cookieDomain,
3191
+ formOfWordsId,
3192
+ useConsentStore
3193
+ })
3194
+ );
3195
+ });
3196
+ window._sp_queue.push(() => {
3197
+ var _a2, _b2;
3198
+ (_b2 = (_a2 = window._sp_) == null ? void 0 : _a2.addEventListener) == null ? void 0 : _b2.call(
3199
+ _a2,
3200
+ "onMessageChoiceSelect",
3201
+ (_messageType, _choiceId, choiceTypeId) => {
3202
+ if (choiceTypeId === 9) {
3203
+ document.cookie = "cw=dismissed; expires=Thu, 18 Dec 2023 12:00:00 UTC";
3204
+ }
3205
+ }
3206
+ );
3207
+ });
3208
+ window._sp_queue.push(() => {
3209
+ var _a2, _b2;
3210
+ (_b2 = (_a2 = window._sp_) == null ? void 0 : _a2.addEventListener) == null ? void 0 : _b2.call(
3211
+ _a2,
3212
+ "onPrivacyManagerAction",
3213
+ (_messageType, pmData) => {
3214
+ if (pmData.purposeConsent == "none" && pmData.vendorConsent == "none") {
3215
+ document.cookie = "cw=dismissed; expires=Thu, 18 Dec 2023 12:00:00 UTC";
3216
+ }
3217
+ }
3218
+ );
3219
+ });
3220
+ initTracking(trackingContext);
2988
3221
  }
2989
3222
  window.FT_CMP_CLIENT_VERSION = version;
2990
3223
  exports.debug = debug;
package/dist/index.js CHANGED
@@ -5,13 +5,10 @@ var __publicField = (obj, key, value) => {
5
5
  return value;
6
6
  };
7
7
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
8
- const version = "0.0.0-beta.1";
8
+ const version = "0.0.0-beta.2";
9
9
  const events = {
10
10
  onMessageChoiceSelect: (...args) => {
11
11
  console.log("[debug] onMessageChoiceSelect", args);
12
- if (choice_type_id == 9) {
13
- document.cookie = "cw=dismissed; expires=Thu, 18 Dec 2030 12:00:00 UTC";
14
- }
15
12
  },
16
13
  onMessageReady: (...args) => {
17
14
  console.log("[debug] onMessageReady", args);
@@ -21,9 +18,6 @@ const events = {
21
18
  },
22
19
  onPrivacyManagerAction: (...args) => {
23
20
  console.log("[debug] onPrivacyManagerAction", args);
24
- if (pmData.purposeConsent == "none" && pmData.vendorConsent == "none") {
25
- document.cookie = "cw=dismissed; expires=Thu, 18 Dec 2030 12:00:00 UTC";
26
- }
27
21
  },
28
22
  onPMCancel: (...args) => {
29
23
  console.log("[debug] onPMCancel", args);
@@ -2933,6 +2927,212 @@ function consentReadyHandlerFn(props) {
2933
2927
  document.dispatchEvent(new CustomEvent("oCookieMessage.act", { bubbles: true }));
2934
2928
  };
2935
2929
  }
2930
+ let getRandomValues;
2931
+ const rnds8 = new Uint8Array(16);
2932
+ function rng() {
2933
+ if (!getRandomValues) {
2934
+ getRandomValues = typeof crypto !== "undefined" && crypto.getRandomValues && crypto.getRandomValues.bind(crypto);
2935
+ if (!getRandomValues) {
2936
+ throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
2937
+ }
2938
+ }
2939
+ return getRandomValues(rnds8);
2940
+ }
2941
+ const byteToHex = [];
2942
+ for (let i = 0; i < 256; ++i) {
2943
+ byteToHex.push((i + 256).toString(16).slice(1));
2944
+ }
2945
+ function unsafeStringify(arr, offset = 0) {
2946
+ 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]];
2947
+ }
2948
+ const randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
2949
+ const native = {
2950
+ randomUUID
2951
+ };
2952
+ function v4(options, buf, offset) {
2953
+ if (native.randomUUID && !buf && !options) {
2954
+ return native.randomUUID();
2955
+ }
2956
+ options = options || {};
2957
+ const rnds = options.random || (options.rng || rng)();
2958
+ rnds[6] = rnds[6] & 15 | 64;
2959
+ rnds[8] = rnds[8] & 63 | 128;
2960
+ if (buf) {
2961
+ offset = offset || 0;
2962
+ for (let i = 0; i < 16; ++i) {
2963
+ buf[offset + i] = rnds[i];
2964
+ }
2965
+ return buf;
2966
+ }
2967
+ return unsafeStringify(rnds);
2968
+ }
2969
+ const COOKIE_MESSAGE = "cookie-message";
2970
+ const PRIVACY_MANAGER = "manage-cookies";
2971
+ const INITIAL_STATE = Object.freeze({
2972
+ activeComponent: COOKIE_MESSAGE
2973
+ });
2974
+ let privateState = INITIAL_STATE;
2975
+ function isPlainObject(obj) {
2976
+ return typeof obj === "object" && obj !== null && obj.constructor === Object && Object.prototype.toString.call(obj) === "[object Object]";
2977
+ }
2978
+ const getState = () => ({ ...privateState });
2979
+ const setState = (newState) => {
2980
+ if (!isPlainObject(newState)) {
2981
+ console.error("Invalid state changes");
2982
+ return;
2983
+ }
2984
+ privateState = { ...privateState, ...newState };
2985
+ };
2986
+ const ACCEPT_ALL_CHOICE = 11;
2987
+ const MANAGE_PREFS_CHOICE = 12;
2988
+ const REJECT_ALL_CHOICE = 13;
2989
+ const cookieToggleFlags = ["adsDisableInternalCMP", "pwm.cmp", "messageSlotBottom"];
2990
+ function initTracking(context) {
2991
+ const componentId = v4();
2992
+ const flags = extractRelevantFlags(context.flags);
2993
+ window._sp_queue = window._sp_queue ?? [];
2994
+ window._sp_queue.push(() => {
2995
+ var _a2, _b2;
2996
+ for (const [eventId, eventHandler] of Object.entries(trackingEventHandlers)) {
2997
+ (_b2 = (_a2 = window._sp_).addEventListener) == null ? void 0 : _b2.call(_a2, eventId, eventHandler({ ...context, flags, componentId }));
2998
+ }
2999
+ });
3000
+ }
3001
+ function extractRelevantFlags(flags) {
3002
+ const output = {};
3003
+ if (typeof flags === "object") {
3004
+ cookieToggleFlags.forEach((flagName) => {
3005
+ if (Object.prototype.hasOwnProperty.call(flags, flagName)) {
3006
+ output[flagName] = flags[flagName];
3007
+ }
3008
+ });
3009
+ }
3010
+ return output;
3011
+ }
3012
+ function track(payload) {
3013
+ if (!payload)
3014
+ return;
3015
+ const rootEl = document.body;
3016
+ const event = new CustomEvent("oTracking.event", {
3017
+ bubbles: true,
3018
+ cancelable: true,
3019
+ detail: payload.detail
3020
+ });
3021
+ rootEl.dispatchEvent(event);
3022
+ }
3023
+ function dispatchComponentEvent({
3024
+ trackingProps,
3025
+ action,
3026
+ triggerAction,
3027
+ messageType
3028
+ }) {
3029
+ const state = getState();
3030
+ const { componentId, product, app, flags } = trackingProps;
3031
+ const event = {
3032
+ detail: {
3033
+ component: {
3034
+ id: componentId,
3035
+ name: state.activeComponent,
3036
+ type: "overlay",
3037
+ subtype: "cmp",
3038
+ componentContentId: state[messageType]
3039
+ },
3040
+ category: "component",
3041
+ action,
3042
+ ...triggerAction && { trigger_action: triggerAction },
3043
+ ...product && { product },
3044
+ ...app && { app },
3045
+ custom: [
3046
+ {
3047
+ cookie_toggle_flag: flags
3048
+ }
3049
+ ]
3050
+ }
3051
+ };
3052
+ track(event);
3053
+ }
3054
+ const trackingEventHandlers = {
3055
+ onMessageChoiceSelect: (trackingProps) => (messageType, _choiceId, choiceTypeId) => {
3056
+ if (choiceTypeId === ACCEPT_ALL_CHOICE) {
3057
+ dispatchComponentEvent({
3058
+ trackingProps,
3059
+ action: "click",
3060
+ triggerAction: "accept_all",
3061
+ messageType
3062
+ });
3063
+ }
3064
+ if (choiceTypeId === MANAGE_PREFS_CHOICE) {
3065
+ dispatchComponentEvent({
3066
+ trackingProps,
3067
+ action: "click",
3068
+ triggerAction: "manage_cookies",
3069
+ messageType
3070
+ });
3071
+ setState({
3072
+ activeComponent: PRIVACY_MANAGER
3073
+ });
3074
+ }
3075
+ if (choiceTypeId === REJECT_ALL_CHOICE) {
3076
+ dispatchComponentEvent({
3077
+ trackingProps,
3078
+ action: "click",
3079
+ triggerAction: "reject_all",
3080
+ messageType
3081
+ });
3082
+ }
3083
+ },
3084
+ onMessageReady: (trackingProps) => (messageType) => {
3085
+ dispatchComponentEvent({
3086
+ trackingProps,
3087
+ action: "view",
3088
+ messageType
3089
+ });
3090
+ },
3091
+ onPrivacyManagerAction: (trackingProps) => (messageType, pmData) => {
3092
+ const { purposeConsent, vendorConsent } = pmData;
3093
+ const isAcceptAll = purposeConsent === "all" && vendorConsent === "all";
3094
+ const isRejectAll = purposeConsent === "none" && vendorConsent === "none";
3095
+ setState({
3096
+ activeComponent: PRIVACY_MANAGER
3097
+ });
3098
+ if (isAcceptAll) {
3099
+ dispatchComponentEvent({
3100
+ trackingProps,
3101
+ action: "click",
3102
+ triggerAction: "accept_all",
3103
+ messageType
3104
+ });
3105
+ } else if (isRejectAll) {
3106
+ dispatchComponentEvent({
3107
+ trackingProps,
3108
+ action: "click",
3109
+ triggerAction: "reject_all",
3110
+ messageType
3111
+ });
3112
+ } else {
3113
+ dispatchComponentEvent({
3114
+ trackingProps,
3115
+ action: "click",
3116
+ triggerAction: "save_and_close",
3117
+ messageType
3118
+ });
3119
+ }
3120
+ },
3121
+ onMessageReceiveData: () => (messageType, data) => {
3122
+ const { messageId } = data;
3123
+ setState({
3124
+ [messageType]: messageId
3125
+ });
3126
+ },
3127
+ onError: (trackingProps) => (messageType, errorCode) => {
3128
+ dispatchComponentEvent({
3129
+ trackingProps,
3130
+ action: "error",
3131
+ triggerAction: errorCode,
3132
+ messageType
3133
+ });
3134
+ }
3135
+ };
2936
3136
  async function initSourcepointCmp({
2937
3137
  propertyConfig = FT_DOTCOM_PROD,
2938
3138
  userId,
@@ -2940,9 +3140,9 @@ async function initSourcepointCmp({
2940
3140
  consentProxyHost = FT_CONSENT_PROXY_HOST,
2941
3141
  cookieDomain = FT_COOKIE_DOMAIN,
2942
3142
  formOfWordsId = SOURCEPOINT_FOW_ID,
2943
- useConsentStore = true
3143
+ useConsentStore = true,
3144
+ trackingContext = {}
2944
3145
  } = {}) {
2945
- var _a2;
2946
3146
  if (!userId && useFTSession) {
2947
3147
  try {
2948
3148
  const response = await getUuid();
@@ -2957,32 +3157,65 @@ async function initSourcepointCmp({
2957
3157
  if (userId) {
2958
3158
  propertyConfig.authId = userId;
2959
3159
  }
2960
- if ((_a2 = propertyConfig.events) == null ? void 0 : _a2.onConsentReady) {
2961
- console.warn("[cmp-client] The supplied 'onConsentReady' event handler will be overwritten.");
3160
+ if (propertyConfig.events) {
3161
+ console.warn(
3162
+ "[cmp-client] Passing an events map in the config is not supported and will be ignored. Please use window._sp_.addEventListener() to listen for events"
3163
+ );
3164
+ delete propertyConfig.events;
2962
3165
  }
2963
- const events2 = {
2964
- ...propertyConfig.events ?? {},
2965
- onConsentReady: consentReadyHandlerFn({
2966
- userId,
2967
- consentProxyHost,
2968
- cookieDomain,
2969
- formOfWordsId,
2970
- useConsentStore
2971
- })
2972
- };
2973
3166
  function getCookie(name) {
3167
+ var _a2, _b2;
2974
3168
  const value = `; ${document.cookie}`;
2975
3169
  const parts = value.split(`; ${name}=`);
2976
3170
  if (parts.length === 2)
2977
- return parts.pop().split(";").shift();
3171
+ return (_b2 = (_a2 = parts.pop()) == null ? void 0 : _a2.split(";")) == null ? void 0 : _b2.shift();
2978
3172
  }
2979
- propertyConfig.gdpr = {
3173
+ propertyConfig = {
3174
+ ...propertyConfig,
2980
3175
  targetingParams: {
2981
- // @ts-ignore
2982
- "cookiew": getCookie("cw")
3176
+ cookiew: getCookie("cw")
2983
3177
  }
2984
3178
  };
2985
- bootstrapCmp({ ...propertyConfig, events: events2 });
3179
+ bootstrapCmp(propertyConfig);
3180
+ window._sp_queue.push(() => {
3181
+ var _a2, _b2;
3182
+ (_b2 = (_a2 = window._sp_) == null ? void 0 : _a2.addEventListener) == null ? void 0 : _b2.call(
3183
+ _a2,
3184
+ "onConsentReady",
3185
+ consentReadyHandlerFn({
3186
+ userId,
3187
+ consentProxyHost,
3188
+ cookieDomain,
3189
+ formOfWordsId,
3190
+ useConsentStore
3191
+ })
3192
+ );
3193
+ });
3194
+ window._sp_queue.push(() => {
3195
+ var _a2, _b2;
3196
+ (_b2 = (_a2 = window._sp_) == null ? void 0 : _a2.addEventListener) == null ? void 0 : _b2.call(
3197
+ _a2,
3198
+ "onMessageChoiceSelect",
3199
+ (_messageType, _choiceId, choiceTypeId) => {
3200
+ if (choiceTypeId === 9) {
3201
+ document.cookie = "cw=dismissed; expires=Thu, 18 Dec 2023 12:00:00 UTC";
3202
+ }
3203
+ }
3204
+ );
3205
+ });
3206
+ window._sp_queue.push(() => {
3207
+ var _a2, _b2;
3208
+ (_b2 = (_a2 = window._sp_) == null ? void 0 : _a2.addEventListener) == null ? void 0 : _b2.call(
3209
+ _a2,
3210
+ "onPrivacyManagerAction",
3211
+ (_messageType, pmData) => {
3212
+ if (pmData.purposeConsent == "none" && pmData.vendorConsent == "none") {
3213
+ document.cookie = "cw=dismissed; expires=Thu, 18 Dec 2023 12:00:00 UTC";
3214
+ }
3215
+ }
3216
+ );
3217
+ });
3218
+ initTracking(trackingContext);
2986
3219
  }
2987
3220
  window.FT_CMP_CLIENT_VERSION = version;
2988
3221
  export {
@@ -1,3 +1,3 @@
1
1
  import type { CMPInitOptions } from "../typings/types.d.ts";
2
- export declare function initSourcepointCmp({ propertyConfig, userId, useFTSession, consentProxyHost, cookieDomain, formOfWordsId, useConsentStore, }?: CMPInitOptions): Promise<void>;
2
+ export declare function initSourcepointCmp({ propertyConfig, userId, useFTSession, consentProxyHost, cookieDomain, formOfWordsId, useConsentStore, trackingContext, }?: CMPInitOptions): Promise<void>;
3
3
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAS5D,wBAAsB,kBAAkB,CAAC,EACvC,cAA+B,EAC/B,MAAM,EACN,YAAmB,EACnB,gBAAwC,EACxC,YAA+B,EAC/B,aAAkC,EAClC,eAAsB,GACvB,GAAE,cAAmB,iBA+CrB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,uBAAuB,CAAC;AAUrF,wBAAsB,kBAAkB,CAAC,EACvC,cAA+B,EAC/B,MAAM,EACN,YAAmB,EACnB,gBAAwC,EACxC,YAA+B,EAC/B,aAAkC,EAClC,eAAsB,EACtB,eAAoB,GACrB,GAAE,cAAmB,iBA6ErB"}
@@ -1 +1 @@
1
- {"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../../src/lib/debug.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM;qCACgB,KAAK;8BAOZ,KAAK;oCAGC,KAAK;sCAGH,KAAK;0BAOjB,KAAK;oCAGK,KAAK;iCAGR,KAAK;;kBAQL,OAAO,GAAG,SAAS;;uBAM7B,KAAK;CAGzB,CAAC;AAEF,wBAAgB,YAAY,SAO3B"}
1
+ {"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../../src/lib/debug.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM;qCACgB,KAAK;8BAGZ,KAAK;oCAGC,KAAK;sCAGH,KAAK;0BAGjB,KAAK;oCAGK,KAAK;iCAGR,KAAK;;kBAQL,OAAO,GAAG,SAAS;;uBAM7B,KAAK;CAGzB,CAAC;AAEF,wBAAgB,YAAY,SAO3B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=state.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.test.d.ts","sourceRoot":"","sources":["../../../../src/tracking/__tests__/state.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export declare const COOKIE_MESSAGE = "cookie-message";
2
+ export declare const PRIVACY_MANAGER = "manage-cookies";
3
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/tracking/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAC/C,eAAO,MAAM,eAAe,mBAAmB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { TrackingContext } from "../../typings/types.d.ts";
2
+ export declare function initTracking(context: TrackingContext): void;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tracking/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAKV,eAAe,EAEhB,MAAM,0BAA0B,CAAC;AAUlC,wBAAgB,YAAY,CAAC,OAAO,EAAE,eAAe,QASpD"}
@@ -0,0 +1,9 @@
1
+ export declare const INITIAL_STATE: Readonly<{
2
+ activeComponent: "cookie-message";
3
+ }>;
4
+ export declare function isPlainObject(obj: unknown): obj is object;
5
+ export declare const getState: () => {
6
+ [x: string]: string | number | boolean | null | undefined;
7
+ };
8
+ export declare const setState: (newState: unknown) => void;
9
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/tracking/state.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,aAAa;;EAExB,CAAC;AAIH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,MAAM,CAOzD;AAGD,eAAO,MAAM,QAAQ;;CAA8B,CAAC;AAEpD,eAAO,MAAM,QAAQ,aAAc,OAAO,SAOzC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@financial-times/cmp-client",
3
- "version": "0.0.0-beta.1",
3
+ "version": "0.0.0-beta.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "files": [
@@ -17,9 +17,11 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@iabtechlabtcf/core": "^1.5.10",
20
- "next-session-client": "^5.0.0"
20
+ "next-session-client": "^5.0.0",
21
+ "uuid": "^9.0.1"
21
22
  },
22
23
  "devDependencies": {
24
+ "@types/uuid": "^9.0.7",
23
25
  "eslint": "^8.53.0",
24
26
  "npm-run-all": "^4.1.5",
25
27
  "typescript": "^5.2.2",
@@ -16,6 +16,7 @@ export interface SPConfig {
16
16
  joinHref?: boolean;
17
17
  events?: Partial<SPLifecycleEvents>;
18
18
  authId?: string;
19
+ targetingParams?: Record<string, unknown>;
19
20
  }
20
21
 
21
22
  export type SPEventCallback = (
@@ -33,7 +34,7 @@ export type CMPInitOptions = Partial<{
33
34
  cookieDomain: string;
34
35
  formOfWordsId: string;
35
36
  useConsentStore: boolean;
36
- spEventHandlers: [eventId: SPEventId, eventHandler: SPEventCallback][];
37
+ trackingContext?: TrackingContext;
37
38
  }>;
38
39
 
39
40
  export interface ConsentPayloadOptions {
@@ -96,3 +97,39 @@ export interface ConsentState {
96
97
  raw: RawConsentState;
97
98
  parsed: ParsedConsentState;
98
99
  }
100
+
101
+ export type TrackingProps = {
102
+ product?: string;
103
+ app?: string;
104
+ flags: FlagsObject;
105
+ componentId: string;
106
+ };
107
+
108
+ export type TrackingContext = {
109
+ product?: string;
110
+ app?: string;
111
+ flags?: FlagsObject;
112
+ };
113
+
114
+ export type TrackingEvent = {
115
+ detail: {
116
+ component: {
117
+ id: string;
118
+ name: string;
119
+ type: string;
120
+ subtype: string;
121
+ componentContentId: string | number;
122
+ };
123
+ category: string;
124
+ action: string;
125
+ custom?: Array<Record<string, unknown>>;
126
+ };
127
+ };
128
+ export type SPMessageType = "gdpr" | "ccpa" | "ios14" | "custom";
129
+
130
+ export type SPPMData = {
131
+ purposeConsent: "all" | "none" | "some";
132
+ vendorConsent: "all" | "none" | "some";
133
+ };
134
+
135
+ export type FlagsObject = Record<string, string | boolean>;