@walkeros/web-source-cmp-cookiepro 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,251 @@
1
+ import { Source, Elb, WalkerOS, Logger } from '@walkeros/core';
2
+
3
+ /**
4
+ * OneTrust global API interface.
5
+ *
6
+ * Represents the subset of the OneTrust SDK we interact with.
7
+ * The full SDK is much larger, but we only need consent-related methods.
8
+ */
9
+ interface OneTrustAPI {
10
+ /** Returns true if user has made an explicit consent choice */
11
+ IsAlertBoxClosed: () => boolean;
12
+ /** Register a callback for consent changes (callback receives event with detail: string[]) */
13
+ OnConsentChanged?: (fn: (event: {
14
+ detail: string[];
15
+ }) => void) => void;
16
+ }
17
+ declare global {
18
+ interface Window {
19
+ /** OneTrust SDK global object */
20
+ OneTrust?: OneTrustAPI;
21
+ /** Comma-separated string of active consent category IDs (e.g. ",C0001,C0003,") */
22
+ OptanonActiveGroups?: string;
23
+ /** OneTrust callback function, called on SDK load and consent changes */
24
+ OptanonWrapper?: () => void;
25
+ /** CookiePro legacy alias for OneTrust */
26
+ Optanon?: unknown;
27
+ [key: string]: OneTrustAPI | unknown;
28
+ }
29
+ interface WindowEventMap {
30
+ /** event.detail is an array of active group ID strings (e.g. ["C0001", "C0002"]) */
31
+ OneTrustGroupsUpdated: CustomEvent<string[]>;
32
+ }
33
+ }
34
+ /**
35
+ * Settings for CookiePro/OneTrust source
36
+ */
37
+ interface Settings {
38
+ /**
39
+ * Map CookiePro category IDs to walkerOS consent groups.
40
+ * Keys: CookiePro category IDs (e.g. 'C0001', 'C0002')
41
+ * Values: walkerOS consent group names
42
+ *
43
+ * Comparison is case-insensitive (keys are normalized to lowercase during init).
44
+ *
45
+ * Default provides sensible mapping for standard OneTrust categories:
46
+ * - C0001 (Strictly Necessary) -> functional
47
+ * - C0002 (Performance) -> analytics
48
+ * - C0003 (Functional) -> functional
49
+ * - C0004 (Targeting) -> marketing
50
+ * - C0005 (Social Media) -> marketing
51
+ */
52
+ categoryMap?: Record<string, string>;
53
+ /**
54
+ * Only process explicit consent (user made a choice).
55
+ * When true: Checks OneTrust.IsAlertBoxClosed() -- only processes
56
+ * consent if user has actively interacted with the banner.
57
+ * When false: Processes any consent state including defaults.
58
+ *
59
+ * Default: true
60
+ */
61
+ explicitOnly?: boolean;
62
+ /**
63
+ * Custom name for window.OneTrust object.
64
+ * Some implementations use a different global name.
65
+ *
66
+ * Default: 'OneTrust'
67
+ */
68
+ globalName?: string;
69
+ }
70
+ /**
71
+ * User input settings (all optional)
72
+ */
73
+ type InitSettings = Partial<Settings>;
74
+ /**
75
+ * No mapping configuration for this source
76
+ */
77
+ interface Mapping {
78
+ }
79
+ /**
80
+ * Push function type - uses elb for consent commands
81
+ */
82
+ type Push = Elb.Fn;
83
+ /**
84
+ * Environment interface for CookiePro source
85
+ */
86
+ interface Env extends Source.BaseEnv {
87
+ window?: Window & typeof globalThis;
88
+ }
89
+ /**
90
+ * Types bundle for CookiePro source
91
+ */
92
+ type Types = Source.Types<Settings, Mapping, Push, Env, InitSettings>;
93
+ /**
94
+ * Config type alias
95
+ */
96
+ type Config = Source.Config<Types>;
97
+
98
+ type index_Config = Config;
99
+ type index_Env = Env;
100
+ type index_InitSettings = InitSettings;
101
+ type index_Mapping = Mapping;
102
+ type index_OneTrustAPI = OneTrustAPI;
103
+ type index_Push = Push;
104
+ type index_Settings = Settings;
105
+ type index_Types = Types;
106
+ declare namespace index {
107
+ export type { index_Config as Config, index_Env as Env, index_InitSettings as InitSettings, index_Mapping as Mapping, index_OneTrustAPI as OneTrustAPI, index_Push as Push, index_Settings as Settings, index_Types as Types };
108
+ }
109
+
110
+ /**
111
+ * Example CookiePro OptanonActiveGroups strings.
112
+ *
113
+ * These represent real consent states from CookiePro/OneTrust CMP.
114
+ * Format: comma-separated active category IDs with leading/trailing commas.
115
+ * Only active groups are listed. Absence means denied.
116
+ */
117
+ /**
118
+ * Full consent - user accepted all categories
119
+ */
120
+ declare const fullConsent = ",C0001,C0002,C0003,C0004,C0005,";
121
+ /**
122
+ * Partial consent - necessary + functional only
123
+ */
124
+ declare const partialConsent = ",C0001,C0003,";
125
+ /**
126
+ * Minimal consent - only strictly necessary (always active)
127
+ */
128
+ declare const minimalConsent = ",C0001,";
129
+ /**
130
+ * Analytics only - necessary + performance
131
+ */
132
+ declare const analyticsOnlyConsent = ",C0001,C0002,";
133
+ /**
134
+ * Marketing only - necessary + targeting
135
+ */
136
+ declare const marketingOnlyConsent = ",C0001,C0004,";
137
+ /**
138
+ * Empty string - no consent yet or cleared
139
+ */
140
+ declare const emptyConsent = "";
141
+ /**
142
+ * Custom category IDs - some installations use custom IDs
143
+ */
144
+ declare const customCategoryConsent = ",C0001,CUSTOM01,CUSTOM02,";
145
+
146
+ /**
147
+ * Expected walkerOS consent outputs.
148
+ *
149
+ * These represent the consent state after parsing OptanonActiveGroups
150
+ * and mapping through the default categoryMap.
151
+ *
152
+ * Default map:
153
+ * - C0001 -> functional
154
+ * - C0002 -> analytics
155
+ * - C0003 -> functional
156
+ * - C0004 -> marketing
157
+ * - C0005 -> marketing
158
+ *
159
+ * All mapped walkerOS groups get explicit true/false values.
160
+ * Active groups -> true, absent groups -> false.
161
+ */
162
+ /**
163
+ * Full consent mapped to walkerOS groups
164
+ */
165
+ declare const fullConsentMapped: WalkerOS.Consent;
166
+ /**
167
+ * Partial consent - necessary + functional mapped
168
+ * C0001 -> functional (true), C0003 -> functional (true)
169
+ * analytics and marketing absent -> false
170
+ */
171
+ declare const partialConsentMapped: WalkerOS.Consent;
172
+ /**
173
+ * Minimal consent - only strictly necessary
174
+ * C0001 -> functional (true)
175
+ * analytics and marketing absent -> false
176
+ */
177
+ declare const minimalConsentMapped: WalkerOS.Consent;
178
+ /**
179
+ * Analytics only - necessary + performance
180
+ * C0001 -> functional (true), C0002 -> analytics (true)
181
+ * marketing absent -> false
182
+ */
183
+ declare const analyticsOnlyMapped: WalkerOS.Consent;
184
+ /**
185
+ * Marketing only - necessary + targeting
186
+ * C0001 -> functional (true), C0004 -> marketing (true)
187
+ * analytics absent -> false
188
+ */
189
+ declare const marketingOnlyMapped: WalkerOS.Consent;
190
+
191
+ /**
192
+ * Create a properly typed elb/push function mock
193
+ */
194
+ declare const createMockElbFn: () => Elb.Fn;
195
+ /**
196
+ * Simple no-op logger for demo purposes
197
+ */
198
+ declare const noopLogger: Logger.Instance;
199
+ /**
200
+ * Create a mock OneTrust API object
201
+ */
202
+ declare const createMockOneTrustAPI: (isAlertBoxClosed?: boolean) => OneTrustAPI;
203
+
204
+ /**
205
+ * Default category mapping from CookiePro/OneTrust to walkerOS consent groups.
206
+ *
207
+ * Keys use OneTrust's standard uppercase IDs (as shown in CookiePro dashboard).
208
+ * Lookups are case-insensitive (normalized during init).
209
+ *
210
+ * Maps OneTrust's standard category IDs to walkerOS convention:
211
+ * - C0001 (Strictly Necessary) -> functional
212
+ * - C0002 (Performance) -> analytics
213
+ * - C0003 (Functional) -> functional
214
+ * - C0004 (Targeting) -> marketing
215
+ * - C0005 (Social Media) -> marketing
216
+ */
217
+ declare const DEFAULT_CATEGORY_MAP: Record<string, string>;
218
+ /**
219
+ * CookiePro/OneTrust consent management source for walkerOS.
220
+ *
221
+ * This source listens to CookiePro/OneTrust CMP events and translates
222
+ * consent states to walkerOS consent commands.
223
+ *
224
+ * Three detection paths:
225
+ * 1. Already loaded: window.OneTrust + window.OptanonActiveGroups
226
+ * 2. Init: Wraps OptanonWrapper (preserves existing)
227
+ * 3. Change: OneTrustGroupsUpdated window event
228
+ *
229
+ * @example
230
+ * ```typescript
231
+ * import { sourceCookiePro } from '@walkeros/web-source-cmp-cookiepro';
232
+ *
233
+ * await startFlow({
234
+ * sources: {
235
+ * consent: {
236
+ * code: sourceCookiePro,
237
+ * config: {
238
+ * settings: {
239
+ * categoryMap: {
240
+ * C0002: 'statistics', // Custom mapping
241
+ * },
242
+ * },
243
+ * },
244
+ * },
245
+ * },
246
+ * });
247
+ * ```
248
+ */
249
+ declare const sourceCookiePro: Source.Init<Types>;
250
+
251
+ export { DEFAULT_CATEGORY_MAP, index as SourceCookiePro, analyticsOnlyConsent, analyticsOnlyMapped, createMockElbFn, createMockOneTrustAPI, customCategoryConsent, sourceCookiePro as default, emptyConsent, fullConsent, fullConsentMapped, marketingOnlyConsent, marketingOnlyMapped, minimalConsent, minimalConsentMapped, noopLogger, partialConsent, partialConsentMapped, sourceCookiePro };
@@ -0,0 +1 @@
1
+ "use strict";function _array_like_to_array(n,t){(null==t||t>n.length)&&(t=n.length);for(var e=0,r=new Array(t);e<t;e++)r[e]=n[e];return r}function _array_with_holes(n){if(Array.isArray(n))return n}function asyncGeneratorStep(n,t,e,r,o,a,i){try{var u=n[a](i),l=u.value}catch(n){return void e(n)}u.done?t(l):Promise.resolve(l).then(r,o)}function _async_to_generator(n){return function(){var t=this,e=arguments;return new Promise(function(r,o){var a=n.apply(t,e);function i(n){asyncGeneratorStep(a,r,o,i,u,"next",n)}function u(n){asyncGeneratorStep(a,r,o,i,u,"throw",n)}i(void 0)})}}function _define_property(n,t,e){return t in n?Object.defineProperty(n,t,{value:e,enumerable:!0,configurable:!0,writable:!0}):n[t]=e,n}function _iterable_to_array_limit(n,t){var e=null==n?null:"undefined"!=typeof Symbol&&n[Symbol.iterator]||n["@@iterator"];if(null!=e){var r,o,a=[],i=!0,u=!1;try{for(e=e.call(n);!(i=(r=e.next()).done)&&(a.push(r.value),!t||a.length!==t);i=!0);}catch(n){u=!0,o=n}finally{try{i||null==e.return||e.return()}finally{if(u)throw o}}return a}}function _non_iterable_rest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _object_spread(n){for(var t=1;t<arguments.length;t++){var e=null!=arguments[t]?arguments[t]:{},r=Object.keys(e);"function"==typeof Object.getOwnPropertySymbols&&(r=r.concat(Object.getOwnPropertySymbols(e).filter(function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),r.forEach(function(t){_define_property(n,t,e[t])})}return n}function _sliced_to_array(n,t){return _array_with_holes(n)||_iterable_to_array_limit(n,t)||_unsupported_iterable_to_array(n,t)||_non_iterable_rest()}function _type_of(n){return n&&"undefined"!=typeof Symbol&&n.constructor===Symbol?"symbol":typeof n}function _unsupported_iterable_to_array(n,t){if(n){if("string"==typeof n)return _array_like_to_array(n,t);var e=Object.prototype.toString.call(n).slice(8,-1);return"Object"===e&&n.constructor&&(e=n.constructor.name),"Map"===e||"Set"===e?Array.from(e):"Arguments"===e||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e)?_array_like_to_array(n,t):void 0}}function _ts_generator(n,t){var e,r,o,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]},i=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),u=Object.defineProperty;return u(i,"next",{value:l(0)}),u(i,"throw",{value:l(1)}),u(i,"return",{value:l(2)}),"function"==typeof Symbol&&u(i,Symbol.iterator,{value:function(){return this}}),i;function l(u){return function(l){return function(u){if(e)throw new TypeError("Generator is already executing.");for(;i&&(i=0,u[0]&&(a=0)),a;)try{if(e=1,r&&(o=2&u[0]?r.return:u[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,u[1])).done)return o;switch(r=0,o&&(u=[2&u[0],o.value]),u[0]){case 0:case 1:o=u;break;case 4:return a.label++,{value:u[1],done:!1};case 5:a.label++,r=u[1],u=[0];continue;case 7:u=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==u[0]&&2!==u[0])){a=0;continue}if(3===u[0]&&(!o||u[1]>o[0]&&u[1]<o[3])){a.label=u[1];break}if(6===u[0]&&a.label<o[1]){a.label=o[1],o=u;break}if(o&&a.label<o[2]){a.label=o[2],a.ops.push(u);break}o[2]&&a.ops.pop(),a.trys.pop();continue}u=t.call(n,a)}catch(n){u=[6,n],r=0}finally{e=o=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}([u,l])}}}var SourceCookiePro=function(){var n=Object.defineProperty,t=Object.getOwnPropertyDescriptor,e=Object.getOwnPropertyNames,r=Object.prototype.hasOwnProperty,o={};!function(t,e){for(var r in e)n(t,r,{get:e[r],enumerable:!0})}(o,{DEFAULT_CATEGORY_MAP:function(){return w},SourceCookiePro:function(){return i},analyticsOnlyConsent:function(){return f},analyticsOnlyMapped:function(){return b},createMockElbFn:function(){return h},createMockOneTrustAPI:function(){return C},customCategoryConsent:function(){return y},default:function(){return j},emptyConsent:function(){return p},fullConsent:function(){return u},fullConsentMapped:function(){return _},marketingOnlyConsent:function(){return s},marketingOnlyMapped:function(){return g},minimalConsent:function(){return c},minimalConsentMapped:function(){return v},noopLogger:function(){return O},partialConsent:function(){return l},partialConsentMapped:function(){return d},sourceCookiePro:function(){return k}});var a,i={},u=",C0001,C0002,C0003,C0004,C0005,",l=",C0001,C0003,",c=",C0001,",f=",C0001,C0002,",s=",C0001,C0004,",p="",y=",C0001,CUSTOM01,CUSTOM02,",_={functional:!0,analytics:!0,marketing:!0},d={functional:!0,analytics:!1,marketing:!1},v={functional:!0,analytics:!1,marketing:!1},b={functional:!0,analytics:!0,marketing:!1},g={functional:!0,analytics:!1,marketing:!0},m=function(){},h=function(){return function(){return Promise.resolve({ok:!0})}},O={error:m,info:m,debug:m,throw:function(n){throw"string"==typeof n?new Error(n):n},scope:function(){return O}},C=function(){var n=arguments.length>0&&void 0!==arguments[0]&&arguments[0];return{IsAlertBoxClosed:function(){return n}}},w={C0001:"functional",C0002:"analytics",C0003:"functional",C0004:"marketing",C0005:"marketing"},k=function(n){return _async_to_generator(function(){var t,e,r,o,a,i,u,l,c,f,s,p,y,_,d,v,b,g,m,h,O,C,k,j;return _ts_generator(this,function(S){return l=n.config,c=n.env,f=c.elb,s=null!==(t=c.window)&&void 0!==t?t:void 0!==globalThis.window?globalThis.window:void 0,p=_object_spread({},w,null!==(e=null==l||null===(a=l.settings)||void 0===a?void 0:a.categoryMap)&&void 0!==e?e:{}),y={},Object.entries(p).forEach(function(n){var t=_sliced_to_array(n,2),e=t[0],r=t[1];y[e.toLowerCase()]=r}),_={categoryMap:p,explicitOnly:null===(r=null==l||null===(i=l.settings)||void 0===i?void 0:i.explicitOnly)||void 0===r||r,globalName:null!==(o=null==l||null===(u=l.settings)||void 0===u?void 0:u.globalName)&&void 0!==o?o:"OneTrust"},d={settings:_},g=!1,s&&(h=null!==(m=_.globalName)&&void 0!==m?m:"OneTrust",O=new Set(Object.values(y)),C=function(n){var t={};return O.forEach(function(n){t[n]=!1}),n.split(",").filter(function(n){return n.length>0}).forEach(function(n){var e=y[n.toLowerCase()];e&&(t[e]=!0)}),t},k=function(){var n=s.OptanonActiveGroups;if(null!=n){if(_.explicitOnly){var t=s[h];if((null==t?void 0:t.IsAlertBoxClosed)&&!t.IsAlertBoxClosed())return}var e=C(n);Object.keys(e).length>0&&f("walker consent",e)}},(j=s[h])&&void 0!==s.OptanonActiveGroups&&k(),j||(b=s.OptanonWrapper,g=!0,s.OptanonWrapper=function(){b&&b(),k(),s.OptanonWrapper=b,g=!1}),v=function(){k()},s.addEventListener("OneTrustGroupsUpdated",v)),[2,{type:"cookiepro",config:d,push:f,destroy:function(){return _async_to_generator(function(){return _ts_generator(this,function(n){return s&&v&&s.removeEventListener("OneTrustGroupsUpdated",v),s&&g&&(s.OptanonWrapper=b),[2]})})()}}]})})()},j=k;return a=o,function(o,a,i,u){if(a&&"object"===(void 0===a?"undefined":_type_of(a))||"function"==typeof a){var l=!0,c=!1,f=void 0;try{for(var s,p=function(){var e=s.value;r.call(o,e)||e===i||n(o,e,{get:function(){return a[e]},enumerable:!(u=t(a,e))||u.enumerable})},y=e(a)[Symbol.iterator]();!(l=(s=y.next()).done);l=!0)p()}catch(n){c=!0,f=n}finally{try{l||null==y.return||y.return()}finally{if(c)throw f}}}return o}(n({},"__esModule",{value:!0}),a)}();
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";var e,n=Object.defineProperty,t=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,r=Object.prototype.hasOwnProperty,l={};((e,t)=>{for(var o in t)n(e,o,{get:t[o],enumerable:!0})})(l,{DEFAULT_CATEGORY_MAP:()=>M,SourceCookiePro:()=>a,analyticsOnlyConsent:()=>p,analyticsOnlyMapped:()=>f,createMockElbFn:()=>b,createMockOneTrustAPI:()=>w,customCategoryConsent:()=>d,default:()=>T,emptyConsent:()=>C,fullConsent:()=>i,fullConsentMapped:()=>g,marketingOnlyConsent:()=>u,marketingOnlyMapped:()=>m,minimalConsent:()=>c,minimalConsentMapped:()=>O,noopLogger:()=>k,partialConsent:()=>s,partialConsentMapped:()=>y,sourceCookiePro:()=>h}),module.exports=(e=l,((e,l,a,i)=>{if(l&&"object"==typeof l||"function"==typeof l)for(let s of o(l))r.call(e,s)||s===a||n(e,s,{get:()=>l[s],enumerable:!(i=t(l,s))||i.enumerable});return e})(n({},"__esModule",{value:!0}),e));var a={},i=",C0001,C0002,C0003,C0004,C0005,",s=",C0001,C0003,",c=",C0001,",p=",C0001,C0002,",u=",C0001,C0004,",C="",d=",C0001,CUSTOM01,CUSTOM02,",g={functional:!0,analytics:!0,marketing:!0},y={functional:!0,analytics:!1,marketing:!1},O={functional:!0,analytics:!1,marketing:!1},f={functional:!0,analytics:!0,marketing:!1},m={functional:!0,analytics:!1,marketing:!0},v=()=>{},b=()=>()=>Promise.resolve({ok:!0}),k={error:v,info:v,debug:v,throw:e=>{throw"string"==typeof e?new Error(e):e},scope:()=>k},w=(e=!1)=>({IsAlertBoxClosed:()=>e}),M={C0001:"functional",C0002:"analytics",C0003:"functional",C0004:"marketing",C0005:"marketing"},h=async e=>{var n,t,o,r,l,a,i,s;const{config:c,env:p}=e,{elb:u}=p,C=null!=(n=p.window)?n:void 0!==globalThis.window?globalThis.window:void 0,d={...M,...null!=(o=null==(t=null==c?void 0:c.settings)?void 0:t.categoryMap)?o:{}},g={};Object.entries(d).forEach(([e,n])=>{g[e.toLowerCase()]=n});const y={categoryMap:d,explicitOnly:null==(l=null==(r=null==c?void 0:c.settings)?void 0:r.explicitOnly)||l,globalName:null!=(i=null==(a=null==c?void 0:c.settings)?void 0:a.globalName)?i:"OneTrust"},O={settings:y};let f,m,v=!1;if(C){const e=null!=(s=y.globalName)?s:"OneTrust",n=new Set(Object.values(g)),t=e=>{const t={};return n.forEach(e=>{t[e]=!1}),e.split(",").filter(e=>e.length>0).forEach(e=>{const n=g[e.toLowerCase()];n&&(t[n]=!0)}),t},o=()=>{const n=C.OptanonActiveGroups;if(null==n)return;if(y.explicitOnly){const n=C[e];if((null==n?void 0:n.IsAlertBoxClosed)&&!n.IsAlertBoxClosed())return}const o=t(n);Object.keys(o).length>0&&u("walker consent",o)},r=C[e];r&&void 0!==C.OptanonActiveGroups&&o(),r||(m=C.OptanonWrapper,v=!0,C.OptanonWrapper=()=>{m&&m(),o(),C.OptanonWrapper=m,v=!1}),f=()=>{o()},C.addEventListener("OneTrustGroupsUpdated",f)}return{type:"cookiepro",config:O,push:u,destroy:async()=>{C&&f&&C.removeEventListener("OneTrustGroupsUpdated",f),C&&v&&(C.OptanonWrapper=m)}}},T=h;//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/types/index.ts","../src/examples/inputs.ts","../src/examples/outputs.ts","../src/examples/env.ts"],"sourcesContent":["import type { Source, WalkerOS } from '@walkeros/core';\nimport type { Types, Settings, OneTrustAPI } from './types';\n\n// Export types for external usage\nexport * as SourceCookiePro from './types';\n\n// Export examples\nexport * from './examples';\n\n/**\n * Default category mapping from CookiePro/OneTrust to walkerOS consent groups.\n *\n * Keys use OneTrust's standard uppercase IDs (as shown in CookiePro dashboard).\n * Lookups are case-insensitive (normalized during init).\n *\n * Maps OneTrust's standard category IDs to walkerOS convention:\n * - C0001 (Strictly Necessary) -> functional\n * - C0002 (Performance) -> analytics\n * - C0003 (Functional) -> functional\n * - C0004 (Targeting) -> marketing\n * - C0005 (Social Media) -> marketing\n */\nexport const DEFAULT_CATEGORY_MAP: Record<string, string> = {\n C0001: 'functional',\n C0002: 'analytics',\n C0003: 'functional',\n C0004: 'marketing',\n C0005: 'marketing',\n};\n\n/**\n * CookiePro/OneTrust consent management source for walkerOS.\n *\n * This source listens to CookiePro/OneTrust CMP events and translates\n * consent states to walkerOS consent commands.\n *\n * Three detection paths:\n * 1. Already loaded: window.OneTrust + window.OptanonActiveGroups\n * 2. Init: Wraps OptanonWrapper (preserves existing)\n * 3. Change: OneTrustGroupsUpdated window event\n *\n * @example\n * ```typescript\n * import { sourceCookiePro } from '@walkeros/web-source-cmp-cookiepro';\n *\n * await startFlow({\n * sources: {\n * consent: {\n * code: sourceCookiePro,\n * config: {\n * settings: {\n * categoryMap: {\n * C0002: 'statistics', // Custom mapping\n * },\n * },\n * },\n * },\n * },\n * });\n * ```\n */\nexport const sourceCookiePro: Source.Init<Types> = async (context) => {\n const { config, env } = context;\n const { elb } = env;\n\n // Resolve window with fallback to globalThis\n const actualWindow =\n env.window ??\n (typeof globalThis.window !== 'undefined' ? globalThis.window : undefined);\n\n // Merge user settings with defaults (user overrides win)\n const mergedCategoryMap = {\n ...DEFAULT_CATEGORY_MAP,\n ...(config?.settings?.categoryMap ?? {}),\n };\n\n // Build normalized (lowercase) lookup map for case-insensitive matching\n const normalizedMap: Record<string, string> = {};\n Object.entries(mergedCategoryMap).forEach(([key, value]) => {\n normalizedMap[key.toLowerCase()] = value;\n });\n\n const settings: Settings = {\n categoryMap: mergedCategoryMap, // Preserves original casing for config\n explicitOnly: config?.settings?.explicitOnly ?? true,\n globalName: config?.settings?.globalName ?? 'OneTrust',\n };\n\n const fullConfig: Source.Config<Types> = { settings };\n\n // Track references for cleanup\n let eventListener: (() => void) | undefined;\n let originalOptanonWrapper: (() => void) | undefined;\n let wrappedOptanonWrapper = false;\n\n if (actualWindow) {\n const globalName = settings.globalName ?? 'OneTrust';\n\n /**\n * Collect all unique walkerOS group names from the normalizedMap.\n * Used to set explicit false for absent groups.\n */\n const allMappedGroups = new Set(Object.values(normalizedMap));\n\n /**\n * Parse OptanonActiveGroups string into walkerOS consent state.\n *\n * OptanonActiveGroups format: \",C0001,C0003,\" (comma-separated, leading/trailing commas)\n * Only active groups are listed. Absence means denied.\n * Uses case-insensitive comparison for category IDs via normalizedMap.\n * Only mapped categories produce consent entries (unmapped IDs are ignored).\n * Sets explicit false for all mapped groups not in the active list.\n */\n const parseActiveGroups = (activeGroups: string): WalkerOS.Consent => {\n const state: WalkerOS.Consent = {};\n\n // Initialize all mapped groups to false\n allMappedGroups.forEach((group) => {\n state[group] = false;\n });\n\n // Set active groups to true (case-insensitive via normalizedMap)\n activeGroups\n .split(',')\n .filter((id) => id.length > 0)\n .forEach((id) => {\n const mapped = normalizedMap[id.toLowerCase()];\n if (mapped) {\n state[mapped] = true;\n }\n });\n\n return state;\n };\n\n /**\n * Handle consent by reading current OptanonActiveGroups from window.\n * Checks explicitOnly against IsAlertBoxClosed when available.\n */\n const handleConsent = () => {\n const activeGroups = actualWindow.OptanonActiveGroups;\n if (activeGroups === undefined || activeGroups === null) return;\n\n // Check explicit consent if required\n if (settings.explicitOnly) {\n const cmp = actualWindow[globalName] as OneTrustAPI | undefined;\n if (cmp?.IsAlertBoxClosed && !cmp.IsAlertBoxClosed()) return;\n }\n\n const state = parseActiveGroups(activeGroups);\n\n // Only call if we have consent state to report\n if (Object.keys(state).length > 0) {\n elb('walker consent', state);\n }\n };\n\n // --- Detection path 1: Already loaded ---\n const cmp = actualWindow[globalName] as OneTrustAPI | undefined;\n if (cmp && actualWindow.OptanonActiveGroups !== undefined) {\n handleConsent();\n }\n\n // --- Detection path 2: OptanonWrapper ---\n // Only wrap if SDK is not yet loaded (no already-loaded path).\n // Self-unwraps after first call -- the event listener handles all\n // subsequent changes, avoiding double-firing.\n if (!cmp) {\n originalOptanonWrapper = actualWindow.OptanonWrapper;\n wrappedOptanonWrapper = true;\n\n actualWindow.OptanonWrapper = () => {\n // Call original wrapper if it existed\n if (originalOptanonWrapper) originalOptanonWrapper();\n handleConsent();\n // Self-unwrap: restore original after first call (SDK init).\n // The OneTrustGroupsUpdated listener handles all future changes.\n actualWindow.OptanonWrapper = originalOptanonWrapper;\n wrappedOptanonWrapper = false;\n };\n }\n\n // --- Detection path 3: OneTrustGroupsUpdated event ---\n eventListener = () => {\n handleConsent();\n };\n actualWindow.addEventListener('OneTrustGroupsUpdated', eventListener);\n }\n\n return {\n type: 'cookiepro',\n config: fullConfig,\n push: elb,\n destroy: async () => {\n // Remove event listener\n if (actualWindow && eventListener) {\n actualWindow.removeEventListener(\n 'OneTrustGroupsUpdated',\n eventListener,\n );\n }\n // Restore original OptanonWrapper\n if (actualWindow && wrappedOptanonWrapper) {\n actualWindow.OptanonWrapper = originalOptanonWrapper;\n }\n },\n };\n};\n\nexport default sourceCookiePro;\n","import type { Source, Elb } from '@walkeros/core';\n\n/**\n * OneTrust global API interface.\n *\n * Represents the subset of the OneTrust SDK we interact with.\n * The full SDK is much larger, but we only need consent-related methods.\n */\nexport interface OneTrustAPI {\n /** Returns true if user has made an explicit consent choice */\n IsAlertBoxClosed: () => boolean;\n /** Register a callback for consent changes (callback receives event with detail: string[]) */\n OnConsentChanged?: (fn: (event: { detail: string[] }) => void) => void;\n}\n\ndeclare global {\n interface Window {\n /** OneTrust SDK global object */\n OneTrust?: OneTrustAPI;\n /** Comma-separated string of active consent category IDs (e.g. \",C0001,C0003,\") */\n OptanonActiveGroups?: string;\n /** OneTrust callback function, called on SDK load and consent changes */\n OptanonWrapper?: () => void;\n /** CookiePro legacy alias for OneTrust */\n Optanon?: unknown;\n [key: string]: OneTrustAPI | unknown;\n }\n\n interface WindowEventMap {\n /** event.detail is an array of active group ID strings (e.g. [\"C0001\", \"C0002\"]) */\n OneTrustGroupsUpdated: CustomEvent<string[]>;\n }\n}\n\n/**\n * Settings for CookiePro/OneTrust source\n */\nexport interface Settings {\n /**\n * Map CookiePro category IDs to walkerOS consent groups.\n * Keys: CookiePro category IDs (e.g. 'C0001', 'C0002')\n * Values: walkerOS consent group names\n *\n * Comparison is case-insensitive (keys are normalized to lowercase during init).\n *\n * Default provides sensible mapping for standard OneTrust categories:\n * - C0001 (Strictly Necessary) -> functional\n * - C0002 (Performance) -> analytics\n * - C0003 (Functional) -> functional\n * - C0004 (Targeting) -> marketing\n * - C0005 (Social Media) -> marketing\n */\n categoryMap?: Record<string, string>;\n\n /**\n * Only process explicit consent (user made a choice).\n * When true: Checks OneTrust.IsAlertBoxClosed() -- only processes\n * consent if user has actively interacted with the banner.\n * When false: Processes any consent state including defaults.\n *\n * Default: true\n */\n explicitOnly?: boolean;\n\n /**\n * Custom name for window.OneTrust object.\n * Some implementations use a different global name.\n *\n * Default: 'OneTrust'\n */\n globalName?: string;\n}\n\n/**\n * User input settings (all optional)\n */\nexport type InitSettings = Partial<Settings>;\n\n/**\n * No mapping configuration for this source\n */\nexport interface Mapping {}\n\n/**\n * Push function type - uses elb for consent commands\n */\nexport type Push = Elb.Fn;\n\n/**\n * Environment interface for CookiePro source\n */\nexport interface Env extends Source.BaseEnv {\n window?: Window & typeof globalThis;\n}\n\n/**\n * Types bundle for CookiePro source\n */\nexport type Types = Source.Types<Settings, Mapping, Push, Env, InitSettings>;\n\n/**\n * Config type alias\n */\nexport type Config = Source.Config<Types>;\n","/**\n * Example CookiePro OptanonActiveGroups strings.\n *\n * These represent real consent states from CookiePro/OneTrust CMP.\n * Format: comma-separated active category IDs with leading/trailing commas.\n * Only active groups are listed. Absence means denied.\n */\n\n/**\n * Full consent - user accepted all categories\n */\nexport const fullConsent = ',C0001,C0002,C0003,C0004,C0005,';\n\n/**\n * Partial consent - necessary + functional only\n */\nexport const partialConsent = ',C0001,C0003,';\n\n/**\n * Minimal consent - only strictly necessary (always active)\n */\nexport const minimalConsent = ',C0001,';\n\n/**\n * Analytics only - necessary + performance\n */\nexport const analyticsOnlyConsent = ',C0001,C0002,';\n\n/**\n * Marketing only - necessary + targeting\n */\nexport const marketingOnlyConsent = ',C0001,C0004,';\n\n/**\n * Empty string - no consent yet or cleared\n */\nexport const emptyConsent = '';\n\n/**\n * Custom category IDs - some installations use custom IDs\n */\nexport const customCategoryConsent = ',C0001,CUSTOM01,CUSTOM02,';\n","import type { WalkerOS } from '@walkeros/core';\n\n/**\n * Expected walkerOS consent outputs.\n *\n * These represent the consent state after parsing OptanonActiveGroups\n * and mapping through the default categoryMap.\n *\n * Default map:\n * - C0001 -> functional\n * - C0002 -> analytics\n * - C0003 -> functional\n * - C0004 -> marketing\n * - C0005 -> marketing\n *\n * All mapped walkerOS groups get explicit true/false values.\n * Active groups -> true, absent groups -> false.\n */\n\n/**\n * Full consent mapped to walkerOS groups\n */\nexport const fullConsentMapped: WalkerOS.Consent = {\n functional: true,\n analytics: true,\n marketing: true,\n};\n\n/**\n * Partial consent - necessary + functional mapped\n * C0001 -> functional (true), C0003 -> functional (true)\n * analytics and marketing absent -> false\n */\nexport const partialConsentMapped: WalkerOS.Consent = {\n functional: true,\n analytics: false,\n marketing: false,\n};\n\n/**\n * Minimal consent - only strictly necessary\n * C0001 -> functional (true)\n * analytics and marketing absent -> false\n */\nexport const minimalConsentMapped: WalkerOS.Consent = {\n functional: true,\n analytics: false,\n marketing: false,\n};\n\n/**\n * Analytics only - necessary + performance\n * C0001 -> functional (true), C0002 -> analytics (true)\n * marketing absent -> false\n */\nexport const analyticsOnlyMapped: WalkerOS.Consent = {\n functional: true,\n analytics: true,\n marketing: false,\n};\n\n/**\n * Marketing only - necessary + targeting\n * C0001 -> functional (true), C0004 -> marketing (true)\n * analytics absent -> false\n */\nexport const marketingOnlyMapped: WalkerOS.Consent = {\n functional: true,\n analytics: false,\n marketing: true,\n};\n","import type { Source, Elb, Logger } from '@walkeros/core';\nimport type { OneTrustAPI } from '../types';\n\n/**\n * Example environment configurations for CookiePro source testing.\n */\n\nconst noop = () => {};\n\n/**\n * Create a properly typed elb/push function mock\n */\nexport const createMockElbFn = (): Elb.Fn => {\n const fn = (() =>\n Promise.resolve({\n ok: true,\n })) as Elb.Fn;\n return fn;\n};\n\n/**\n * Simple no-op logger for demo purposes\n */\nexport const noopLogger: Logger.Instance = {\n error: noop,\n info: noop,\n debug: noop,\n throw: (message: string | Error) => {\n throw typeof message === 'string' ? new Error(message) : message;\n },\n scope: () => noopLogger,\n};\n\n/**\n * Create a mock OneTrust API object\n */\nexport const createMockOneTrustAPI = (\n isAlertBoxClosed = false,\n): OneTrustAPI => ({\n IsAlertBoxClosed: () => isAlertBoxClosed,\n});\n"],"mappings":"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","names":["cmp"]}
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ var n={},t=",C0001,C0002,C0003,C0004,C0005,",e=",C0001,C0003,",o=",C0001,",l=",C0001,C0002,",a=",C0001,C0004,",r="",i=",C0001,CUSTOM01,CUSTOM02,",s={functional:!0,analytics:!0,marketing:!0},c={functional:!0,analytics:!1,marketing:!1},u={functional:!0,analytics:!1,marketing:!1},p={functional:!0,analytics:!0,marketing:!1},C={functional:!0,analytics:!1,marketing:!0},d=()=>{},g=()=>()=>Promise.resolve({ok:!0}),f={error:d,info:d,debug:d,throw:n=>{throw"string"==typeof n?new Error(n):n},scope:()=>f},v=(n=!1)=>({IsAlertBoxClosed:()=>n}),O={C0001:"functional",C0002:"analytics",C0003:"functional",C0004:"marketing",C0005:"marketing"},y=async n=>{var t,e,o,l,a,r,i,s;const{config:c,env:u}=n,{elb:p}=u,C=null!=(t=u.window)?t:void 0!==globalThis.window?globalThis.window:void 0,d={...O,...null!=(o=null==(e=null==c?void 0:c.settings)?void 0:e.categoryMap)?o:{}},g={};Object.entries(d).forEach(([n,t])=>{g[n.toLowerCase()]=t});const f={categoryMap:d,explicitOnly:null==(a=null==(l=null==c?void 0:c.settings)?void 0:l.explicitOnly)||a,globalName:null!=(i=null==(r=null==c?void 0:c.settings)?void 0:r.globalName)?i:"OneTrust"},v={settings:f};let y,w,k=!1;if(C){const n=null!=(s=f.globalName)?s:"OneTrust",t=new Set(Object.values(g)),e=n=>{const e={};return t.forEach(n=>{e[n]=!1}),n.split(",").filter(n=>n.length>0).forEach(n=>{const t=g[n.toLowerCase()];t&&(e[t]=!0)}),e},o=()=>{const t=C.OptanonActiveGroups;if(null==t)return;if(f.explicitOnly){const t=C[n];if((null==t?void 0:t.IsAlertBoxClosed)&&!t.IsAlertBoxClosed())return}const o=e(t);Object.keys(o).length>0&&p("walker consent",o)},l=C[n];l&&void 0!==C.OptanonActiveGroups&&o(),l||(w=C.OptanonWrapper,k=!0,C.OptanonWrapper=()=>{w&&w(),o(),C.OptanonWrapper=w,k=!1}),y=()=>{o()},C.addEventListener("OneTrustGroupsUpdated",y)}return{type:"cookiepro",config:v,push:p,destroy:async()=>{C&&y&&C.removeEventListener("OneTrustGroupsUpdated",y),C&&k&&(C.OptanonWrapper=w)}}},w=y;export{O as DEFAULT_CATEGORY_MAP,n as SourceCookiePro,l as analyticsOnlyConsent,p as analyticsOnlyMapped,g as createMockElbFn,v as createMockOneTrustAPI,i as customCategoryConsent,w as default,r as emptyConsent,t as fullConsent,s as fullConsentMapped,a as marketingOnlyConsent,C as marketingOnlyMapped,o as minimalConsent,u as minimalConsentMapped,f as noopLogger,e as partialConsent,c as partialConsentMapped,y as sourceCookiePro};//# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types/index.ts","../src/examples/inputs.ts","../src/examples/outputs.ts","../src/examples/env.ts","../src/index.ts"],"sourcesContent":["import type { Source, Elb } from '@walkeros/core';\n\n/**\n * OneTrust global API interface.\n *\n * Represents the subset of the OneTrust SDK we interact with.\n * The full SDK is much larger, but we only need consent-related methods.\n */\nexport interface OneTrustAPI {\n /** Returns true if user has made an explicit consent choice */\n IsAlertBoxClosed: () => boolean;\n /** Register a callback for consent changes (callback receives event with detail: string[]) */\n OnConsentChanged?: (fn: (event: { detail: string[] }) => void) => void;\n}\n\ndeclare global {\n interface Window {\n /** OneTrust SDK global object */\n OneTrust?: OneTrustAPI;\n /** Comma-separated string of active consent category IDs (e.g. \",C0001,C0003,\") */\n OptanonActiveGroups?: string;\n /** OneTrust callback function, called on SDK load and consent changes */\n OptanonWrapper?: () => void;\n /** CookiePro legacy alias for OneTrust */\n Optanon?: unknown;\n [key: string]: OneTrustAPI | unknown;\n }\n\n interface WindowEventMap {\n /** event.detail is an array of active group ID strings (e.g. [\"C0001\", \"C0002\"]) */\n OneTrustGroupsUpdated: CustomEvent<string[]>;\n }\n}\n\n/**\n * Settings for CookiePro/OneTrust source\n */\nexport interface Settings {\n /**\n * Map CookiePro category IDs to walkerOS consent groups.\n * Keys: CookiePro category IDs (e.g. 'C0001', 'C0002')\n * Values: walkerOS consent group names\n *\n * Comparison is case-insensitive (keys are normalized to lowercase during init).\n *\n * Default provides sensible mapping for standard OneTrust categories:\n * - C0001 (Strictly Necessary) -> functional\n * - C0002 (Performance) -> analytics\n * - C0003 (Functional) -> functional\n * - C0004 (Targeting) -> marketing\n * - C0005 (Social Media) -> marketing\n */\n categoryMap?: Record<string, string>;\n\n /**\n * Only process explicit consent (user made a choice).\n * When true: Checks OneTrust.IsAlertBoxClosed() -- only processes\n * consent if user has actively interacted with the banner.\n * When false: Processes any consent state including defaults.\n *\n * Default: true\n */\n explicitOnly?: boolean;\n\n /**\n * Custom name for window.OneTrust object.\n * Some implementations use a different global name.\n *\n * Default: 'OneTrust'\n */\n globalName?: string;\n}\n\n/**\n * User input settings (all optional)\n */\nexport type InitSettings = Partial<Settings>;\n\n/**\n * No mapping configuration for this source\n */\nexport interface Mapping {}\n\n/**\n * Push function type - uses elb for consent commands\n */\nexport type Push = Elb.Fn;\n\n/**\n * Environment interface for CookiePro source\n */\nexport interface Env extends Source.BaseEnv {\n window?: Window & typeof globalThis;\n}\n\n/**\n * Types bundle for CookiePro source\n */\nexport type Types = Source.Types<Settings, Mapping, Push, Env, InitSettings>;\n\n/**\n * Config type alias\n */\nexport type Config = Source.Config<Types>;\n","/**\n * Example CookiePro OptanonActiveGroups strings.\n *\n * These represent real consent states from CookiePro/OneTrust CMP.\n * Format: comma-separated active category IDs with leading/trailing commas.\n * Only active groups are listed. Absence means denied.\n */\n\n/**\n * Full consent - user accepted all categories\n */\nexport const fullConsent = ',C0001,C0002,C0003,C0004,C0005,';\n\n/**\n * Partial consent - necessary + functional only\n */\nexport const partialConsent = ',C0001,C0003,';\n\n/**\n * Minimal consent - only strictly necessary (always active)\n */\nexport const minimalConsent = ',C0001,';\n\n/**\n * Analytics only - necessary + performance\n */\nexport const analyticsOnlyConsent = ',C0001,C0002,';\n\n/**\n * Marketing only - necessary + targeting\n */\nexport const marketingOnlyConsent = ',C0001,C0004,';\n\n/**\n * Empty string - no consent yet or cleared\n */\nexport const emptyConsent = '';\n\n/**\n * Custom category IDs - some installations use custom IDs\n */\nexport const customCategoryConsent = ',C0001,CUSTOM01,CUSTOM02,';\n","import type { WalkerOS } from '@walkeros/core';\n\n/**\n * Expected walkerOS consent outputs.\n *\n * These represent the consent state after parsing OptanonActiveGroups\n * and mapping through the default categoryMap.\n *\n * Default map:\n * - C0001 -> functional\n * - C0002 -> analytics\n * - C0003 -> functional\n * - C0004 -> marketing\n * - C0005 -> marketing\n *\n * All mapped walkerOS groups get explicit true/false values.\n * Active groups -> true, absent groups -> false.\n */\n\n/**\n * Full consent mapped to walkerOS groups\n */\nexport const fullConsentMapped: WalkerOS.Consent = {\n functional: true,\n analytics: true,\n marketing: true,\n};\n\n/**\n * Partial consent - necessary + functional mapped\n * C0001 -> functional (true), C0003 -> functional (true)\n * analytics and marketing absent -> false\n */\nexport const partialConsentMapped: WalkerOS.Consent = {\n functional: true,\n analytics: false,\n marketing: false,\n};\n\n/**\n * Minimal consent - only strictly necessary\n * C0001 -> functional (true)\n * analytics and marketing absent -> false\n */\nexport const minimalConsentMapped: WalkerOS.Consent = {\n functional: true,\n analytics: false,\n marketing: false,\n};\n\n/**\n * Analytics only - necessary + performance\n * C0001 -> functional (true), C0002 -> analytics (true)\n * marketing absent -> false\n */\nexport const analyticsOnlyMapped: WalkerOS.Consent = {\n functional: true,\n analytics: true,\n marketing: false,\n};\n\n/**\n * Marketing only - necessary + targeting\n * C0001 -> functional (true), C0004 -> marketing (true)\n * analytics absent -> false\n */\nexport const marketingOnlyMapped: WalkerOS.Consent = {\n functional: true,\n analytics: false,\n marketing: true,\n};\n","import type { Source, Elb, Logger } from '@walkeros/core';\nimport type { OneTrustAPI } from '../types';\n\n/**\n * Example environment configurations for CookiePro source testing.\n */\n\nconst noop = () => {};\n\n/**\n * Create a properly typed elb/push function mock\n */\nexport const createMockElbFn = (): Elb.Fn => {\n const fn = (() =>\n Promise.resolve({\n ok: true,\n })) as Elb.Fn;\n return fn;\n};\n\n/**\n * Simple no-op logger for demo purposes\n */\nexport const noopLogger: Logger.Instance = {\n error: noop,\n info: noop,\n debug: noop,\n throw: (message: string | Error) => {\n throw typeof message === 'string' ? new Error(message) : message;\n },\n scope: () => noopLogger,\n};\n\n/**\n * Create a mock OneTrust API object\n */\nexport const createMockOneTrustAPI = (\n isAlertBoxClosed = false,\n): OneTrustAPI => ({\n IsAlertBoxClosed: () => isAlertBoxClosed,\n});\n","import type { Source, WalkerOS } from '@walkeros/core';\nimport type { Types, Settings, OneTrustAPI } from './types';\n\n// Export types for external usage\nexport * as SourceCookiePro from './types';\n\n// Export examples\nexport * from './examples';\n\n/**\n * Default category mapping from CookiePro/OneTrust to walkerOS consent groups.\n *\n * Keys use OneTrust's standard uppercase IDs (as shown in CookiePro dashboard).\n * Lookups are case-insensitive (normalized during init).\n *\n * Maps OneTrust's standard category IDs to walkerOS convention:\n * - C0001 (Strictly Necessary) -> functional\n * - C0002 (Performance) -> analytics\n * - C0003 (Functional) -> functional\n * - C0004 (Targeting) -> marketing\n * - C0005 (Social Media) -> marketing\n */\nexport const DEFAULT_CATEGORY_MAP: Record<string, string> = {\n C0001: 'functional',\n C0002: 'analytics',\n C0003: 'functional',\n C0004: 'marketing',\n C0005: 'marketing',\n};\n\n/**\n * CookiePro/OneTrust consent management source for walkerOS.\n *\n * This source listens to CookiePro/OneTrust CMP events and translates\n * consent states to walkerOS consent commands.\n *\n * Three detection paths:\n * 1. Already loaded: window.OneTrust + window.OptanonActiveGroups\n * 2. Init: Wraps OptanonWrapper (preserves existing)\n * 3. Change: OneTrustGroupsUpdated window event\n *\n * @example\n * ```typescript\n * import { sourceCookiePro } from '@walkeros/web-source-cmp-cookiepro';\n *\n * await startFlow({\n * sources: {\n * consent: {\n * code: sourceCookiePro,\n * config: {\n * settings: {\n * categoryMap: {\n * C0002: 'statistics', // Custom mapping\n * },\n * },\n * },\n * },\n * },\n * });\n * ```\n */\nexport const sourceCookiePro: Source.Init<Types> = async (context) => {\n const { config, env } = context;\n const { elb } = env;\n\n // Resolve window with fallback to globalThis\n const actualWindow =\n env.window ??\n (typeof globalThis.window !== 'undefined' ? globalThis.window : undefined);\n\n // Merge user settings with defaults (user overrides win)\n const mergedCategoryMap = {\n ...DEFAULT_CATEGORY_MAP,\n ...(config?.settings?.categoryMap ?? {}),\n };\n\n // Build normalized (lowercase) lookup map for case-insensitive matching\n const normalizedMap: Record<string, string> = {};\n Object.entries(mergedCategoryMap).forEach(([key, value]) => {\n normalizedMap[key.toLowerCase()] = value;\n });\n\n const settings: Settings = {\n categoryMap: mergedCategoryMap, // Preserves original casing for config\n explicitOnly: config?.settings?.explicitOnly ?? true,\n globalName: config?.settings?.globalName ?? 'OneTrust',\n };\n\n const fullConfig: Source.Config<Types> = { settings };\n\n // Track references for cleanup\n let eventListener: (() => void) | undefined;\n let originalOptanonWrapper: (() => void) | undefined;\n let wrappedOptanonWrapper = false;\n\n if (actualWindow) {\n const globalName = settings.globalName ?? 'OneTrust';\n\n /**\n * Collect all unique walkerOS group names from the normalizedMap.\n * Used to set explicit false for absent groups.\n */\n const allMappedGroups = new Set(Object.values(normalizedMap));\n\n /**\n * Parse OptanonActiveGroups string into walkerOS consent state.\n *\n * OptanonActiveGroups format: \",C0001,C0003,\" (comma-separated, leading/trailing commas)\n * Only active groups are listed. Absence means denied.\n * Uses case-insensitive comparison for category IDs via normalizedMap.\n * Only mapped categories produce consent entries (unmapped IDs are ignored).\n * Sets explicit false for all mapped groups not in the active list.\n */\n const parseActiveGroups = (activeGroups: string): WalkerOS.Consent => {\n const state: WalkerOS.Consent = {};\n\n // Initialize all mapped groups to false\n allMappedGroups.forEach((group) => {\n state[group] = false;\n });\n\n // Set active groups to true (case-insensitive via normalizedMap)\n activeGroups\n .split(',')\n .filter((id) => id.length > 0)\n .forEach((id) => {\n const mapped = normalizedMap[id.toLowerCase()];\n if (mapped) {\n state[mapped] = true;\n }\n });\n\n return state;\n };\n\n /**\n * Handle consent by reading current OptanonActiveGroups from window.\n * Checks explicitOnly against IsAlertBoxClosed when available.\n */\n const handleConsent = () => {\n const activeGroups = actualWindow.OptanonActiveGroups;\n if (activeGroups === undefined || activeGroups === null) return;\n\n // Check explicit consent if required\n if (settings.explicitOnly) {\n const cmp = actualWindow[globalName] as OneTrustAPI | undefined;\n if (cmp?.IsAlertBoxClosed && !cmp.IsAlertBoxClosed()) return;\n }\n\n const state = parseActiveGroups(activeGroups);\n\n // Only call if we have consent state to report\n if (Object.keys(state).length > 0) {\n elb('walker consent', state);\n }\n };\n\n // --- Detection path 1: Already loaded ---\n const cmp = actualWindow[globalName] as OneTrustAPI | undefined;\n if (cmp && actualWindow.OptanonActiveGroups !== undefined) {\n handleConsent();\n }\n\n // --- Detection path 2: OptanonWrapper ---\n // Only wrap if SDK is not yet loaded (no already-loaded path).\n // Self-unwraps after first call -- the event listener handles all\n // subsequent changes, avoiding double-firing.\n if (!cmp) {\n originalOptanonWrapper = actualWindow.OptanonWrapper;\n wrappedOptanonWrapper = true;\n\n actualWindow.OptanonWrapper = () => {\n // Call original wrapper if it existed\n if (originalOptanonWrapper) originalOptanonWrapper();\n handleConsent();\n // Self-unwrap: restore original after first call (SDK init).\n // The OneTrustGroupsUpdated listener handles all future changes.\n actualWindow.OptanonWrapper = originalOptanonWrapper;\n wrappedOptanonWrapper = false;\n };\n }\n\n // --- Detection path 3: OneTrustGroupsUpdated event ---\n eventListener = () => {\n handleConsent();\n };\n actualWindow.addEventListener('OneTrustGroupsUpdated', eventListener);\n }\n\n return {\n type: 'cookiepro',\n config: fullConfig,\n push: elb,\n destroy: async () => {\n // Remove event listener\n if (actualWindow && eventListener) {\n actualWindow.removeEventListener(\n 'OneTrustGroupsUpdated',\n eventListener,\n );\n }\n // Restore original OptanonWrapper\n if (actualWindow && wrappedOptanonWrapper) {\n actualWindow.OptanonWrapper = originalOptanonWrapper;\n }\n },\n };\n};\n\nexport default sourceCookiePro;\n"],"mappings":"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","names":["cmp"]}
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@walkeros/web-source-cmp-cookiepro",
3
+ "description": "CookiePro/OneTrust consent management source for walkerOS",
4
+ "version": "0.1.0",
5
+ "license": "MIT",
6
+ "walkerOS": {
7
+ "type": "source",
8
+ "platform": "web"
9
+ },
10
+ "main": "./dist/index.js",
11
+ "module": "./dist/index.mjs",
12
+ "types": "./dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.mjs",
17
+ "require": "./dist/index.js"
18
+ },
19
+ "./examples": {
20
+ "types": "./dist/examples/index.d.ts",
21
+ "import": "./dist/examples/index.mjs",
22
+ "require": "./dist/examples/index.js"
23
+ },
24
+ "./dev": {
25
+ "types": "./dist/dev.d.ts",
26
+ "import": "./dist/dev.mjs",
27
+ "require": "./dist/dev.js"
28
+ }
29
+ },
30
+ "files": [
31
+ "dist/**"
32
+ ],
33
+ "scripts": {
34
+ "build": "tsup --silent",
35
+ "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
36
+ "dev": "jest --watchAll --colors",
37
+ "lint": "tsc && eslint \"**/*.ts*\"",
38
+ "test": "jest",
39
+ "update": "npx npm-check-updates -u && npm update"
40
+ },
41
+ "dependencies": {
42
+ "@walkeros/core": "1.0.0",
43
+ "@walkeros/collector": "1.0.0"
44
+ },
45
+ "devDependencies": {},
46
+ "repository": {
47
+ "url": "git+https://github.com/elbwalker/walkerOS.git",
48
+ "directory": "packages/web/sources/cmps/cookiepro"
49
+ },
50
+ "author": "elbwalker <hello@elbwalker.com>",
51
+ "homepage": "https://github.com/elbwalker/walkerOS#readme",
52
+ "bugs": {
53
+ "url": "https://github.com/elbwalker/walkerOS/issues"
54
+ },
55
+ "keywords": [
56
+ "walker",
57
+ "walkerOS",
58
+ "walkerOS-source",
59
+ "source",
60
+ "web",
61
+ "cookiepro",
62
+ "onetrust",
63
+ "consent",
64
+ "cmp"
65
+ ],
66
+ "funding": [
67
+ {
68
+ "type": "GitHub Sponsors",
69
+ "url": "https://github.com/sponsors/elbwalker"
70
+ }
71
+ ]
72
+ }