@walkeros/web-source-cmp-cookiefirst 1.1.0-next-1771252576264

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,234 @@
1
+ import { Source, Elb, WalkerOS, Logger } from '@walkeros/core';
2
+
3
+ /**
4
+ * CookieFirst consent object structure
5
+ */
6
+ interface CookieFirstConsent {
7
+ necessary?: boolean;
8
+ functional?: boolean;
9
+ performance?: boolean;
10
+ advertising?: boolean;
11
+ [category: string]: boolean | undefined;
12
+ }
13
+ /**
14
+ * CookieFirst global API interface
15
+ */
16
+ interface CookieFirstAPI {
17
+ consent: CookieFirstConsent | null;
18
+ }
19
+ declare global {
20
+ interface Window {
21
+ CookieFirst?: CookieFirstAPI;
22
+ [key: string]: CookieFirstAPI | unknown;
23
+ }
24
+ interface WindowEventMap {
25
+ cf_init: Event;
26
+ cf_consent: CustomEvent<CookieFirstConsent>;
27
+ }
28
+ }
29
+ /**
30
+ * Settings for CookieFirst source
31
+ */
32
+ interface Settings {
33
+ /**
34
+ * Map CookieFirst categories to walkerOS consent groups.
35
+ * Keys: CookieFirst category names
36
+ * Values: walkerOS consent group names
37
+ *
38
+ * Default maps to standard walkerOS groups:
39
+ * - necessary → functional
40
+ * - functional → functional
41
+ * - performance → analytics
42
+ * - advertising → marketing
43
+ */
44
+ categoryMap?: Record<string, string>;
45
+ /**
46
+ * Only process explicit consent (user made a choice).
47
+ * When true: Ignores consent if CookieFirst.consent is null
48
+ * When false: Processes any consent state including defaults
49
+ *
50
+ * Default: true
51
+ */
52
+ explicitOnly?: boolean;
53
+ /**
54
+ * Custom name for window.CookieFirst object.
55
+ * Some implementations use a different global name.
56
+ *
57
+ * Default: 'CookieFirst'
58
+ */
59
+ globalName?: string;
60
+ }
61
+ /**
62
+ * User input settings (all optional)
63
+ */
64
+ type InitSettings = Partial<Settings>;
65
+ /**
66
+ * No mapping configuration for this source
67
+ */
68
+ interface Mapping {
69
+ }
70
+ /**
71
+ * Push function type - uses elb for consent commands
72
+ */
73
+ type Push = Elb.Fn;
74
+ /**
75
+ * Environment interface for CookieFirst source
76
+ */
77
+ interface Env extends Source.BaseEnv {
78
+ window?: Window & typeof globalThis;
79
+ }
80
+ /**
81
+ * Types bundle for CookieFirst source
82
+ */
83
+ type Types = Source.Types<Settings, Mapping, Push, Env, InitSettings>;
84
+ /**
85
+ * Config type alias
86
+ */
87
+ type Config = Source.Config<Types>;
88
+
89
+ type index_Config = Config;
90
+ type index_CookieFirstAPI = CookieFirstAPI;
91
+ type index_CookieFirstConsent = CookieFirstConsent;
92
+ type index_Env = Env;
93
+ type index_InitSettings = InitSettings;
94
+ type index_Mapping = Mapping;
95
+ type index_Push = Push;
96
+ type index_Settings = Settings;
97
+ type index_Types = Types;
98
+ declare namespace index {
99
+ export type { index_Config as Config, index_CookieFirstAPI as CookieFirstAPI, index_CookieFirstConsent as CookieFirstConsent, index_Env as Env, index_InitSettings as InitSettings, index_Mapping as Mapping, index_Push as Push, index_Settings as Settings, index_Types as Types };
100
+ }
101
+
102
+ /**
103
+ * Example CookieFirst consent inputs.
104
+ *
105
+ * These represent real consent states from CookieFirst CMP.
106
+ */
107
+ /**
108
+ * Full consent - user accepted all categories
109
+ */
110
+ declare const fullConsent: CookieFirstConsent;
111
+ /**
112
+ * Partial consent - user accepted only necessary and functional
113
+ */
114
+ declare const partialConsent: CookieFirstConsent;
115
+ /**
116
+ * Minimal consent - user accepted only necessary (required)
117
+ */
118
+ declare const minimalConsent: CookieFirstConsent;
119
+ /**
120
+ * No consent - user hasn't made a choice yet
121
+ * CookieFirst returns null when no explicit choice has been made
122
+ */
123
+ declare const noConsent: CookieFirstConsent | null;
124
+ /**
125
+ * Analytics only - user accepted performance tracking
126
+ */
127
+ declare const analyticsOnlyConsent: CookieFirstConsent;
128
+ /**
129
+ * Marketing only - user accepted advertising
130
+ */
131
+ declare const marketingOnlyConsent: CookieFirstConsent;
132
+
133
+ /**
134
+ * Expected walkerOS consent outputs.
135
+ *
136
+ * These represent the consent state after mapping CookieFirst categories
137
+ * to walkerOS consent groups using the default category map.
138
+ */
139
+ /**
140
+ * Full consent mapped to walkerOS groups
141
+ * (necessary + functional → functional, performance → analytics, advertising → marketing)
142
+ */
143
+ declare const fullConsentMapped: WalkerOS.Consent;
144
+ /**
145
+ * Partial consent mapped to walkerOS groups
146
+ */
147
+ declare const partialConsentMapped: WalkerOS.Consent;
148
+ /**
149
+ * Minimal consent mapped to walkerOS groups
150
+ */
151
+ declare const minimalConsentMapped: WalkerOS.Consent;
152
+ /**
153
+ * Analytics only consent mapped to walkerOS groups
154
+ * Note: functional is true because necessary=true maps to functional
155
+ * (OR logic: if ANY source category is true, target group is true)
156
+ */
157
+ declare const analyticsOnlyMapped: WalkerOS.Consent;
158
+ /**
159
+ * Marketing only consent mapped to walkerOS groups
160
+ * Note: functional is true because necessary=true maps to functional
161
+ * (OR logic: if ANY source category is true, target group is true)
162
+ */
163
+ declare const marketingOnlyMapped: WalkerOS.Consent;
164
+
165
+ /**
166
+ * Create a properly typed elb/push function mock that returns a promise with PushResult
167
+ */
168
+ declare const createMockElbFn: () => Elb.Fn;
169
+ /**
170
+ * Simple no-op logger for demo purposes
171
+ */
172
+ declare const noopLogger: Logger.Instance;
173
+ /**
174
+ * Environment interface for CookieFirst source
175
+ */
176
+ interface CookieFirstEnv extends Source.BaseEnv {
177
+ window?: typeof window;
178
+ }
179
+ /**
180
+ * Create a mock CookieFirst API object
181
+ */
182
+ declare const createMockCookieFirstAPI: (consent?: CookieFirstConsent | null) => CookieFirstAPI;
183
+ /**
184
+ * Create a mock window object with CookieFirst
185
+ */
186
+ declare const createMockWindow: (consent?: CookieFirstConsent | null) => Partial<Window> & {
187
+ CookieFirst: CookieFirstAPI;
188
+ };
189
+ /**
190
+ * Standard mock environment for testing CookieFirst source
191
+ *
192
+ * Use this for testing consent handling without requiring
193
+ * a real browser environment.
194
+ */
195
+ declare const mockEnv: CookieFirstEnv;
196
+
197
+ /**
198
+ * Default category mapping from CookieFirst to walkerOS consent groups.
199
+ *
200
+ * Maps CookieFirst's standard categories to walkerOS convention:
201
+ * - necessary/functional → functional (essential)
202
+ * - performance → analytics (measurement)
203
+ * - advertising → marketing (ads)
204
+ */
205
+ declare const DEFAULT_CATEGORY_MAP: Record<string, string>;
206
+ /**
207
+ * CookieFirst consent management source for walkerOS.
208
+ *
209
+ * This source listens to CookieFirst CMP events and translates
210
+ * consent states to walkerOS consent commands.
211
+ *
212
+ * @example
213
+ * ```typescript
214
+ * import { sourceCookieFirst } from '@walkeros/web-source-cmp-cookiefirst';
215
+ *
216
+ * await startFlow({
217
+ * sources: {
218
+ * consent: {
219
+ * code: sourceCookieFirst,
220
+ * config: {
221
+ * settings: {
222
+ * categoryMap: {
223
+ * performance: 'statistics', // Custom mapping
224
+ * },
225
+ * },
226
+ * },
227
+ * },
228
+ * },
229
+ * });
230
+ * ```
231
+ */
232
+ declare const sourceCookieFirst: Source.Init<Types>;
233
+
234
+ export { DEFAULT_CATEGORY_MAP, index as SourceCookieFirst, analyticsOnlyConsent, analyticsOnlyMapped, createMockCookieFirstAPI, createMockElbFn, createMockWindow, sourceCookieFirst as default, fullConsent, fullConsentMapped, marketingOnlyConsent, marketingOnlyMapped, minimalConsent, minimalConsentMapped, mockEnv, noConsent, noopLogger, partialConsent, partialConsentMapped, sourceCookieFirst };
@@ -0,0 +1 @@
1
+ "use strict";function _array_like_to_array(n,e){(null==e||e>n.length)&&(e=n.length);for(var t=0,r=new Array(e);t<e;t++)r[t]=n[t];return r}function _array_with_holes(n){if(Array.isArray(n))return n}function asyncGeneratorStep(n,e,t,r,o,i,a){try{var u=n[i](a),l=u.value}catch(n){return void t(n)}u.done?e(l):Promise.resolve(l).then(r,o)}function _async_to_generator(n){return function(){var e=this,t=arguments;return new Promise(function(r,o){var i=n.apply(e,t);function a(n){asyncGeneratorStep(i,r,o,a,u,"next",n)}function u(n){asyncGeneratorStep(i,r,o,a,u,"throw",n)}a(void 0)})}}function _define_property(n,e,t){return e in n?Object.defineProperty(n,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):n[e]=t,n}function _iterable_to_array_limit(n,e){var t=null==n?null:"undefined"!=typeof Symbol&&n[Symbol.iterator]||n["@@iterator"];if(null!=t){var r,o,i=[],a=!0,u=!1;try{for(t=t.call(n);!(a=(r=t.next()).done)&&(i.push(r.value),!e||i.length!==e);a=!0);}catch(n){u=!0,o=n}finally{try{a||null==t.return||t.return()}finally{if(u)throw o}}return i}}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 e=1;e<arguments.length;e++){var t=null!=arguments[e]?arguments[e]:{},r=Object.keys(t);"function"==typeof Object.getOwnPropertySymbols&&(r=r.concat(Object.getOwnPropertySymbols(t).filter(function(n){return Object.getOwnPropertyDescriptor(t,n).enumerable}))),r.forEach(function(e){_define_property(n,e,t[e])})}return n}function _sliced_to_array(n,e){return _array_with_holes(n)||_iterable_to_array_limit(n,e)||_unsupported_iterable_to_array(n,e)||_non_iterable_rest()}function _type_of(n){return n&&"undefined"!=typeof Symbol&&n.constructor===Symbol?"symbol":typeof n}function _unsupported_iterable_to_array(n,e){if(n){if("string"==typeof n)return _array_like_to_array(n,e);var t=Object.prototype.toString.call(n).slice(8,-1);return"Object"===t&&n.constructor&&(t=n.constructor.name),"Map"===t||"Set"===t?Array.from(t):"Arguments"===t||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)?_array_like_to_array(n,e):void 0}}function _ts_generator(n,e){var t,r,o,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]},a=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),u=Object.defineProperty;return u(a,"next",{value:l(0)}),u(a,"throw",{value:l(1)}),u(a,"return",{value:l(2)}),"function"==typeof Symbol&&u(a,Symbol.iterator,{value:function(){return this}}),a;function l(u){return function(l){return function(u){if(t)throw new TypeError("Generator is already executing.");for(;a&&(a=0,u[0]&&(i=0)),i;)try{if(t=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 i.label++,{value:u[1],done:!1};case 5:i.label++,r=u[1],u=[0];continue;case 7:u=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==u[0]&&2!==u[0])){i=0;continue}if(3===u[0]&&(!o||u[1]>o[0]&&u[1]<o[3])){i.label=u[1];break}if(6===u[0]&&i.label<o[1]){i.label=o[1],o=u;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(u);break}o[2]&&i.ops.pop(),i.trys.pop();continue}u=e.call(n,i)}catch(n){u=[6,n],r=0}finally{t=o=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}([u,l])}}}var SourceCookieFirst=function(){var n=Object.defineProperty,e=Object.getOwnPropertyDescriptor,t=Object.getOwnPropertyNames,r=Object.prototype.hasOwnProperty,o={};!function(e,t){for(var r in t)n(e,r,{get:t[r],enumerable:!0})}(o,{DEFAULT_CATEGORY_MAP:function(){return j},SourceCookieFirst:function(){return a},analyticsOnlyConsent:function(){return s},analyticsOnlyMapped:function(){return _},createMockCookieFirstAPI:function(){return w},createMockElbFn:function(){return m},createMockWindow:function(){return k},default:function(){return S},fullConsent:function(){return u},fullConsentMapped:function(){return p},marketingOnlyConsent:function(){return y},marketingOnlyMapped:function(){return b},minimalConsent:function(){return c},minimalConsentMapped:function(){return v},mockEnv:function(){return O},noConsent:function(){return f},noopLogger:function(){return h},partialConsent:function(){return l},partialConsentMapped:function(){return d},sourceCookieFirst:function(){return C}});var i,a={},u={necessary:!0,functional:!0,performance:!0,advertising:!0},l={necessary:!0,functional:!0,performance:!1,advertising:!1},c={necessary:!0,functional:!1,performance:!1,advertising:!1},f=null,s={necessary:!0,functional:!1,performance:!0,advertising:!1},y={necessary:!0,functional:!1,performance:!1,advertising:!0},p={functional:!0,analytics:!0,marketing:!0},d={functional:!0,analytics:!1,marketing:!1},v={functional:!0,analytics:!1,marketing:!1},_={functional:!0,analytics:!0,marketing:!1},b={functional:!0,analytics:!1,marketing:!0},g=function(){},m=function(){return function(){return Promise.resolve({ok:!0})}},h={error:g,info:g,debug:g,throw:function(n){throw"string"==typeof n?new Error(n):n},scope:function(){return h}},w=function(){return{consent:arguments.length>0&&void 0!==arguments[0]?arguments[0]:null}},k=function(){return{CookieFirst:w(arguments.length>0&&void 0!==arguments[0]?arguments[0]:null),addEventListener:g,removeEventListener:g}},O={get push(){return m()},get command(){return m()},get elb(){return m()},get window(){return k()},logger:h},j={necessary:"functional",functional:"functional",performance:"analytics",advertising:"marketing"},C=function(n){return _async_to_generator(function(){var e,t,r,o,i,a,u,l,c,f,s,y,p,d,v,_,b,g;return _ts_generator(this,function(m){return u=n.config,l=n.env,c=l.elb,f=null!==(e=l.window)&&void 0!==e?e:void 0!==globalThis.window?globalThis.window:void 0,s={categoryMap:_object_spread({},j,null==u||null===(o=u.settings)||void 0===o?void 0:o.categoryMap),explicitOnly:null===(t=null==u||null===(i=u.settings)||void 0===i?void 0:i.explicitOnly)||void 0===t||t,globalName:null!==(r=null==u||null===(a=u.settings)||void 0===a?void 0:a.globalName)&&void 0!==r?r:"CookieFirst"},y={settings:s},f&&(_=function(n){if((!s.explicitOnly||n)&&n){var e={};Object.entries(n).forEach(function(n){var t,r,o=_sliced_to_array(n,2),i=o[0],a=o[1];if("boolean"==typeof a){var u=null!==(t=null===(r=s.categoryMap)||void 0===r?void 0:r[i])&&void 0!==t?t:i;e[u]=e[u]||a}}),Object.keys(e).length>0&&c("walker consent",e)}},b=null!==(v=s.globalName)&&void 0!==v?v:"CookieFirst",(null==(g=f[b])?void 0:g.consent)&&_(g.consent),p=function(){var n,e=f[b];_(null!==(n=null==e?void 0:e.consent)&&void 0!==n?n:null)},f.addEventListener("cf_init",p),d=function(n){_(n.detail)},f.addEventListener("cf_consent",d)),[2,{type:"cookiefirst",config:y,push:c,destroy:function(){return _async_to_generator(function(){return _ts_generator(this,function(n){return f&&p&&f.removeEventListener("cf_init",p),f&&d&&f.removeEventListener("cf_consent",d),[2]})})()}}]})})()},S=C;return i=o,function(o,i,a,u){if(i&&"object"===(void 0===i?"undefined":_type_of(i))||"function"==typeof i){var l=!0,c=!1,f=void 0;try{for(var s,y=function(){var t=s.value;r.call(o,t)||t===a||n(o,t,{get:function(){return i[t]},enumerable:!(u=e(i,t))||u.enumerable})},p=t(i)[Symbol.iterator]();!(l=(s=p.next()).done);l=!0)y()}catch(n){c=!0,f=n}finally{try{l||null==p.return||p.return()}finally{if(c)throw f}}}return o}(n({},"__esModule",{value:!0}),i)}();
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,i={};((e,t)=>{for(var o in t)n(e,o,{get:t[o],enumerable:!0})})(i,{DEFAULT_CATEGORY_MAP:()=>E,SourceCookieFirst:()=>a,analyticsOnlyConsent:()=>f,analyticsOnlyMapped:()=>v,createMockCookieFirstAPI:()=>w,createMockElbFn:()=>b,createMockWindow:()=>C,default:()=>F,fullConsent:()=>l,fullConsentMapped:()=>d,marketingOnlyConsent:()=>g,marketingOnlyMapped:()=>m,minimalConsent:()=>c,minimalConsentMapped:()=>y,mockEnv:()=>M,noConsent:()=>u,noopLogger:()=>O,partialConsent:()=>s,partialConsentMapped:()=>p,sourceCookieFirst:()=>h}),module.exports=(e=i,((e,i,a,l)=>{if(i&&"object"==typeof i||"function"==typeof i)for(let s of o(i))r.call(e,s)||s===a||n(e,s,{get:()=>i[s],enumerable:!(l=t(i,s))||l.enumerable});return e})(n({},"__esModule",{value:!0}),e));var a={},l={necessary:!0,functional:!0,performance:!0,advertising:!0},s={necessary:!0,functional:!0,performance:!1,advertising:!1},c={necessary:!0,functional:!1,performance:!1,advertising:!1},u=null,f={necessary:!0,functional:!1,performance:!0,advertising:!1},g={necessary:!0,functional:!1,performance:!1,advertising:!0},d={functional:!0,analytics:!0,marketing:!0},p={functional:!0,analytics:!1,marketing:!1},y={functional:!0,analytics:!1,marketing:!1},v={functional:!0,analytics:!0,marketing:!1},m={functional:!0,analytics:!1,marketing:!0},k=()=>{},b=()=>()=>Promise.resolve({ok:!0}),O={error:k,info:k,debug:k,throw:e=>{throw"string"==typeof e?new Error(e):e},scope:()=>O},w=(e=null)=>({consent:e}),C=(e=null)=>({CookieFirst:w(e),addEventListener:k,removeEventListener:k}),M={get push(){return b()},get command(){return b()},get elb(){return b()},get window(){return C()},logger:O},E={necessary:"functional",functional:"functional",performance:"analytics",advertising:"marketing"},h=async e=>{var n,t,o,r,i,a,l;const{config:s,env:c}=e,{elb:u}=c,f=null!=(n=c.window)?n:void 0!==globalThis.window?globalThis.window:void 0,g={categoryMap:{...E,...null==(t=null==s?void 0:s.settings)?void 0:t.categoryMap},explicitOnly:null==(r=null==(o=null==s?void 0:s.settings)?void 0:o.explicitOnly)||r,globalName:null!=(a=null==(i=null==s?void 0:s.settings)?void 0:i.globalName)?a:"CookieFirst"},d={settings:g};let p,y;if(f){const e=e=>{if(g.explicitOnly&&!e)return;if(!e)return;const n={};Object.entries(e).forEach(([e,t])=>{var o,r;if("boolean"!=typeof t)return;const i=null!=(r=null==(o=g.categoryMap)?void 0:o[e])?r:e;n[i]=n[i]||t}),Object.keys(n).length>0&&u("walker consent",n)},n=null!=(l=g.globalName)?l:"CookieFirst",t=f[n];(null==t?void 0:t.consent)&&e(t.consent),p=()=>{var t;const o=f[n];e(null!=(t=null==o?void 0:o.consent)?t:null)},f.addEventListener("cf_init",p),y=n=>{e(n.detail)},f.addEventListener("cf_consent",y)}return{type:"cookiefirst",config:d,push:u,destroy:async()=>{f&&p&&f.removeEventListener("cf_init",p),f&&y&&f.removeEventListener("cf_consent",y)}}},F=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 {\n Types,\n Settings,\n CookieFirstConsent,\n CookieFirstAPI,\n} from './types';\n\n// Export types for external usage\nexport * as SourceCookieFirst from './types';\n\n// Export examples\nexport * from './examples';\n\n/**\n * Default category mapping from CookieFirst to walkerOS consent groups.\n *\n * Maps CookieFirst's standard categories to walkerOS convention:\n * - necessary/functional → functional (essential)\n * - performance → analytics (measurement)\n * - advertising → marketing (ads)\n */\nexport const DEFAULT_CATEGORY_MAP: Record<string, string> = {\n necessary: 'functional',\n functional: 'functional',\n performance: 'analytics',\n advertising: 'marketing',\n};\n\n/**\n * CookieFirst consent management source for walkerOS.\n *\n * This source listens to CookieFirst CMP events and translates\n * consent states to walkerOS consent commands.\n *\n * @example\n * ```typescript\n * import { sourceCookieFirst } from '@walkeros/web-source-cmp-cookiefirst';\n *\n * await startFlow({\n * sources: {\n * consent: {\n * code: sourceCookieFirst,\n * config: {\n * settings: {\n * categoryMap: {\n * performance: 'statistics', // Custom mapping\n * },\n * },\n * },\n * },\n * },\n * });\n * ```\n */\nexport const sourceCookieFirst: 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\n const settings: Settings = {\n categoryMap: { ...DEFAULT_CATEGORY_MAP, ...config?.settings?.categoryMap },\n explicitOnly: config?.settings?.explicitOnly ?? true,\n globalName: config?.settings?.globalName ?? 'CookieFirst',\n };\n\n const fullConfig: Source.Config<Types> = { settings };\n\n // Track listener references for cleanup\n let initListener: (() => void) | undefined;\n let consentListener: ((e: Event) => void) | undefined;\n\n // Only setup if in browser environment\n if (actualWindow) {\n /**\n * Handle consent state from CookieFirst.\n * Maps CookieFirst categories to walkerOS consent groups and calls elb.\n *\n * When multiple CookieFirst categories map to the same walkerOS group,\n * uses OR logic: if ANY category is true, the group is true.\n */\n const handleConsent = (consent: CookieFirstConsent | null) => {\n // Skip if explicitOnly and no explicit consent given\n if (settings.explicitOnly && !consent) return;\n if (!consent) return;\n\n // Map CookieFirst categories to walkerOS consent groups\n // Use OR logic: if ANY source category is true, the target group is true\n const state: WalkerOS.Consent = {};\n Object.entries(consent).forEach(([category, value]) => {\n if (typeof value !== 'boolean') return;\n const mapped = settings.categoryMap?.[category] ?? category;\n // OR logic: once true, stays true\n state[mapped] = state[mapped] || value;\n });\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 const globalName = settings.globalName ?? 'CookieFirst';\n const cmp = actualWindow[globalName] as CookieFirstAPI | undefined;\n\n // Process existing consent if CMP already loaded\n if (cmp?.consent) {\n handleConsent(cmp.consent);\n }\n\n // Listen for CMP initialization\n initListener = () => {\n const cmp = actualWindow[globalName] as CookieFirstAPI | undefined;\n handleConsent(cmp?.consent ?? null);\n };\n actualWindow.addEventListener('cf_init', initListener);\n\n // Listen for consent changes\n consentListener = (e: Event) => {\n const customEvent = e as CustomEvent<CookieFirstConsent>;\n handleConsent(customEvent.detail);\n };\n actualWindow.addEventListener('cf_consent', consentListener);\n }\n\n return {\n type: 'cookiefirst',\n config: fullConfig,\n push: elb,\n destroy: async () => {\n // Remove event listeners on cleanup\n if (actualWindow && initListener) {\n actualWindow.removeEventListener('cf_init', initListener);\n }\n if (actualWindow && consentListener) {\n actualWindow.removeEventListener('cf_consent', consentListener);\n }\n },\n };\n};\n\nexport default sourceCookieFirst;\n","import type { Source, Elb } from '@walkeros/core';\n\n/**\n * CookieFirst consent object structure\n */\nexport interface CookieFirstConsent {\n necessary?: boolean;\n functional?: boolean;\n performance?: boolean;\n advertising?: boolean;\n [category: string]: boolean | undefined;\n}\n\n/**\n * CookieFirst global API interface\n */\nexport interface CookieFirstAPI {\n consent: CookieFirstConsent | null;\n}\n\ndeclare global {\n interface Window {\n CookieFirst?: CookieFirstAPI;\n [key: string]: CookieFirstAPI | unknown;\n }\n\n interface WindowEventMap {\n cf_init: Event;\n cf_consent: CustomEvent<CookieFirstConsent>;\n }\n}\n\n/**\n * Settings for CookieFirst source\n */\nexport interface Settings {\n /**\n * Map CookieFirst categories to walkerOS consent groups.\n * Keys: CookieFirst category names\n * Values: walkerOS consent group names\n *\n * Default maps to standard walkerOS groups:\n * - necessary → functional\n * - functional → functional\n * - performance → analytics\n * - advertising → marketing\n */\n categoryMap?: Record<string, string>;\n\n /**\n * Only process explicit consent (user made a choice).\n * When true: Ignores consent if CookieFirst.consent is null\n * When false: Processes any consent state including defaults\n *\n * Default: true\n */\n explicitOnly?: boolean;\n\n /**\n * Custom name for window.CookieFirst object.\n * Some implementations use a different global name.\n *\n * Default: 'CookieFirst'\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 CookieFirst source\n */\nexport interface Env extends Source.BaseEnv {\n window?: Window & typeof globalThis;\n}\n\n/**\n * Types bundle for CookieFirst 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","import type { CookieFirstConsent } from '../types';\n\n/**\n * Example CookieFirst consent inputs.\n *\n * These represent real consent states from CookieFirst CMP.\n */\n\n/**\n * Full consent - user accepted all categories\n */\nexport const fullConsent: CookieFirstConsent = {\n necessary: true,\n functional: true,\n performance: true,\n advertising: true,\n};\n\n/**\n * Partial consent - user accepted only necessary and functional\n */\nexport const partialConsent: CookieFirstConsent = {\n necessary: true,\n functional: true,\n performance: false,\n advertising: false,\n};\n\n/**\n * Minimal consent - user accepted only necessary (required)\n */\nexport const minimalConsent: CookieFirstConsent = {\n necessary: true,\n functional: false,\n performance: false,\n advertising: false,\n};\n\n/**\n * No consent - user hasn't made a choice yet\n * CookieFirst returns null when no explicit choice has been made\n */\nexport const noConsent: CookieFirstConsent | null = null;\n\n/**\n * Analytics only - user accepted performance tracking\n */\nexport const analyticsOnlyConsent: CookieFirstConsent = {\n necessary: true,\n functional: false,\n performance: true,\n advertising: false,\n};\n\n/**\n * Marketing only - user accepted advertising\n */\nexport const marketingOnlyConsent: CookieFirstConsent = {\n necessary: true,\n functional: false,\n performance: false,\n advertising: true,\n};\n","import type { WalkerOS } from '@walkeros/core';\n\n/**\n * Expected walkerOS consent outputs.\n *\n * These represent the consent state after mapping CookieFirst categories\n * to walkerOS consent groups using the default category map.\n */\n\n/**\n * Full consent mapped to walkerOS groups\n * (necessary + functional → functional, performance → analytics, advertising → marketing)\n */\nexport const fullConsentMapped: WalkerOS.Consent = {\n functional: true,\n analytics: true,\n marketing: true,\n};\n\n/**\n * Partial consent mapped to walkerOS groups\n */\nexport const partialConsentMapped: WalkerOS.Consent = {\n functional: true,\n analytics: false,\n marketing: false,\n};\n\n/**\n * Minimal consent mapped to walkerOS groups\n */\nexport const minimalConsentMapped: WalkerOS.Consent = {\n functional: true,\n analytics: false,\n marketing: false,\n};\n\n/**\n * Analytics only consent mapped to walkerOS groups\n * Note: functional is true because necessary=true maps to functional\n * (OR logic: if ANY source category is true, target group is true)\n */\nexport const analyticsOnlyMapped: WalkerOS.Consent = {\n functional: true,\n analytics: true,\n marketing: false,\n};\n\n/**\n * Marketing only consent mapped to walkerOS groups\n * Note: functional is true because necessary=true maps to functional\n * (OR logic: if ANY source category is true, target group is true)\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 { CookieFirstAPI, CookieFirstConsent } from '../types';\n\n/**\n * Example environment configurations for CookieFirst source testing.\n *\n * These provide mock structures for testing consent handling\n * without requiring a real browser environment.\n */\n\n// Simple no-op function for mocking\nconst noop = () => {};\n\n/**\n * Create a properly typed elb/push function mock that returns a promise with PushResult\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 * Environment interface for CookieFirst source\n */\ninterface CookieFirstEnv extends Source.BaseEnv {\n window?: typeof window;\n}\n\n/**\n * Create a mock CookieFirst API object\n */\nexport const createMockCookieFirstAPI = (\n consent: CookieFirstConsent | null = null,\n): CookieFirstAPI => ({\n consent,\n});\n\n/**\n * Create a mock window object with CookieFirst\n */\nexport const createMockWindow = (\n consent: CookieFirstConsent | null = null,\n): Partial<Window> & { CookieFirst: CookieFirstAPI } => ({\n CookieFirst: createMockCookieFirstAPI(consent),\n addEventListener: noop,\n removeEventListener: noop,\n});\n\n/**\n * Standard mock environment for testing CookieFirst source\n *\n * Use this for testing consent handling without requiring\n * a real browser environment.\n */\nexport const mockEnv: CookieFirstEnv = {\n get push() {\n return createMockElbFn();\n },\n get command() {\n return createMockElbFn();\n },\n get elb() {\n return createMockElbFn();\n },\n get window() {\n return createMockWindow() as unknown as typeof window;\n },\n logger: noopLogger,\n};\n"],"mappings":"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","names":["_a","_b","cmp"]}
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ var n={},e={necessary:!0,functional:!0,performance:!0,advertising:!0},t={necessary:!0,functional:!0,performance:!1,advertising:!1},i={necessary:!0,functional:!1,performance:!1,advertising:!1},o=null,r={necessary:!0,functional:!1,performance:!0,advertising:!1},l={necessary:!0,functional:!1,performance:!1,advertising:!0},a={functional:!0,analytics:!0,marketing:!0},s={functional:!0,analytics:!1,marketing:!1},c={functional:!0,analytics:!1,marketing:!1},u={functional:!0,analytics:!0,marketing:!1},f={functional:!0,analytics:!1,marketing:!0},g=()=>{},d=()=>()=>Promise.resolve({ok:!0}),v={error:g,info:g,debug:g,throw:n=>{throw"string"==typeof n?new Error(n):n},scope:()=>v},y=(n=null)=>({consent:n}),m=(n=null)=>({CookieFirst:y(n),addEventListener:g,removeEventListener:g}),p={get push(){return d()},get command(){return d()},get elb(){return d()},get window(){return m()},logger:v},k={necessary:"functional",functional:"functional",performance:"analytics",advertising:"marketing"},w=async n=>{var e,t,i,o,r,l,a;const{config:s,env:c}=n,{elb:u}=c,f=null!=(e=c.window)?e:void 0!==globalThis.window?globalThis.window:void 0,g={categoryMap:{...k,...null==(t=null==s?void 0:s.settings)?void 0:t.categoryMap},explicitOnly:null==(o=null==(i=null==s?void 0:s.settings)?void 0:i.explicitOnly)||o,globalName:null!=(l=null==(r=null==s?void 0:s.settings)?void 0:r.globalName)?l:"CookieFirst"},d={settings:g};let v,y;if(f){const n=n=>{if(g.explicitOnly&&!n)return;if(!n)return;const e={};Object.entries(n).forEach(([n,t])=>{var i,o;if("boolean"!=typeof t)return;const r=null!=(o=null==(i=g.categoryMap)?void 0:i[n])?o:n;e[r]=e[r]||t}),Object.keys(e).length>0&&u("walker consent",e)},e=null!=(a=g.globalName)?a:"CookieFirst",t=f[e];(null==t?void 0:t.consent)&&n(t.consent),v=()=>{var t;const i=f[e];n(null!=(t=null==i?void 0:i.consent)?t:null)},f.addEventListener("cf_init",v),y=e=>{n(e.detail)},f.addEventListener("cf_consent",y)}return{type:"cookiefirst",config:d,push:u,destroy:async()=>{f&&v&&f.removeEventListener("cf_init",v),f&&y&&f.removeEventListener("cf_consent",y)}}},b=w;export{k as DEFAULT_CATEGORY_MAP,n as SourceCookieFirst,r as analyticsOnlyConsent,u as analyticsOnlyMapped,y as createMockCookieFirstAPI,d as createMockElbFn,m as createMockWindow,b as default,e as fullConsent,a as fullConsentMapped,l as marketingOnlyConsent,f as marketingOnlyMapped,i as minimalConsent,c as minimalConsentMapped,p as mockEnv,o as noConsent,v as noopLogger,t as partialConsent,s as partialConsentMapped,w as sourceCookieFirst};//# 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 * CookieFirst consent object structure\n */\nexport interface CookieFirstConsent {\n necessary?: boolean;\n functional?: boolean;\n performance?: boolean;\n advertising?: boolean;\n [category: string]: boolean | undefined;\n}\n\n/**\n * CookieFirst global API interface\n */\nexport interface CookieFirstAPI {\n consent: CookieFirstConsent | null;\n}\n\ndeclare global {\n interface Window {\n CookieFirst?: CookieFirstAPI;\n [key: string]: CookieFirstAPI | unknown;\n }\n\n interface WindowEventMap {\n cf_init: Event;\n cf_consent: CustomEvent<CookieFirstConsent>;\n }\n}\n\n/**\n * Settings for CookieFirst source\n */\nexport interface Settings {\n /**\n * Map CookieFirst categories to walkerOS consent groups.\n * Keys: CookieFirst category names\n * Values: walkerOS consent group names\n *\n * Default maps to standard walkerOS groups:\n * - necessary → functional\n * - functional → functional\n * - performance → analytics\n * - advertising → marketing\n */\n categoryMap?: Record<string, string>;\n\n /**\n * Only process explicit consent (user made a choice).\n * When true: Ignores consent if CookieFirst.consent is null\n * When false: Processes any consent state including defaults\n *\n * Default: true\n */\n explicitOnly?: boolean;\n\n /**\n * Custom name for window.CookieFirst object.\n * Some implementations use a different global name.\n *\n * Default: 'CookieFirst'\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 CookieFirst source\n */\nexport interface Env extends Source.BaseEnv {\n window?: Window & typeof globalThis;\n}\n\n/**\n * Types bundle for CookieFirst 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","import type { CookieFirstConsent } from '../types';\n\n/**\n * Example CookieFirst consent inputs.\n *\n * These represent real consent states from CookieFirst CMP.\n */\n\n/**\n * Full consent - user accepted all categories\n */\nexport const fullConsent: CookieFirstConsent = {\n necessary: true,\n functional: true,\n performance: true,\n advertising: true,\n};\n\n/**\n * Partial consent - user accepted only necessary and functional\n */\nexport const partialConsent: CookieFirstConsent = {\n necessary: true,\n functional: true,\n performance: false,\n advertising: false,\n};\n\n/**\n * Minimal consent - user accepted only necessary (required)\n */\nexport const minimalConsent: CookieFirstConsent = {\n necessary: true,\n functional: false,\n performance: false,\n advertising: false,\n};\n\n/**\n * No consent - user hasn't made a choice yet\n * CookieFirst returns null when no explicit choice has been made\n */\nexport const noConsent: CookieFirstConsent | null = null;\n\n/**\n * Analytics only - user accepted performance tracking\n */\nexport const analyticsOnlyConsent: CookieFirstConsent = {\n necessary: true,\n functional: false,\n performance: true,\n advertising: false,\n};\n\n/**\n * Marketing only - user accepted advertising\n */\nexport const marketingOnlyConsent: CookieFirstConsent = {\n necessary: true,\n functional: false,\n performance: false,\n advertising: true,\n};\n","import type { WalkerOS } from '@walkeros/core';\n\n/**\n * Expected walkerOS consent outputs.\n *\n * These represent the consent state after mapping CookieFirst categories\n * to walkerOS consent groups using the default category map.\n */\n\n/**\n * Full consent mapped to walkerOS groups\n * (necessary + functional → functional, performance → analytics, advertising → marketing)\n */\nexport const fullConsentMapped: WalkerOS.Consent = {\n functional: true,\n analytics: true,\n marketing: true,\n};\n\n/**\n * Partial consent mapped to walkerOS groups\n */\nexport const partialConsentMapped: WalkerOS.Consent = {\n functional: true,\n analytics: false,\n marketing: false,\n};\n\n/**\n * Minimal consent mapped to walkerOS groups\n */\nexport const minimalConsentMapped: WalkerOS.Consent = {\n functional: true,\n analytics: false,\n marketing: false,\n};\n\n/**\n * Analytics only consent mapped to walkerOS groups\n * Note: functional is true because necessary=true maps to functional\n * (OR logic: if ANY source category is true, target group is true)\n */\nexport const analyticsOnlyMapped: WalkerOS.Consent = {\n functional: true,\n analytics: true,\n marketing: false,\n};\n\n/**\n * Marketing only consent mapped to walkerOS groups\n * Note: functional is true because necessary=true maps to functional\n * (OR logic: if ANY source category is true, target group is true)\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 { CookieFirstAPI, CookieFirstConsent } from '../types';\n\n/**\n * Example environment configurations for CookieFirst source testing.\n *\n * These provide mock structures for testing consent handling\n * without requiring a real browser environment.\n */\n\n// Simple no-op function for mocking\nconst noop = () => {};\n\n/**\n * Create a properly typed elb/push function mock that returns a promise with PushResult\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 * Environment interface for CookieFirst source\n */\ninterface CookieFirstEnv extends Source.BaseEnv {\n window?: typeof window;\n}\n\n/**\n * Create a mock CookieFirst API object\n */\nexport const createMockCookieFirstAPI = (\n consent: CookieFirstConsent | null = null,\n): CookieFirstAPI => ({\n consent,\n});\n\n/**\n * Create a mock window object with CookieFirst\n */\nexport const createMockWindow = (\n consent: CookieFirstConsent | null = null,\n): Partial<Window> & { CookieFirst: CookieFirstAPI } => ({\n CookieFirst: createMockCookieFirstAPI(consent),\n addEventListener: noop,\n removeEventListener: noop,\n});\n\n/**\n * Standard mock environment for testing CookieFirst source\n *\n * Use this for testing consent handling without requiring\n * a real browser environment.\n */\nexport const mockEnv: CookieFirstEnv = {\n get push() {\n return createMockElbFn();\n },\n get command() {\n return createMockElbFn();\n },\n get elb() {\n return createMockElbFn();\n },\n get window() {\n return createMockWindow() as unknown as typeof window;\n },\n logger: noopLogger,\n};\n","import type { Source, WalkerOS } from '@walkeros/core';\nimport type {\n Types,\n Settings,\n CookieFirstConsent,\n CookieFirstAPI,\n} from './types';\n\n// Export types for external usage\nexport * as SourceCookieFirst from './types';\n\n// Export examples\nexport * from './examples';\n\n/**\n * Default category mapping from CookieFirst to walkerOS consent groups.\n *\n * Maps CookieFirst's standard categories to walkerOS convention:\n * - necessary/functional → functional (essential)\n * - performance → analytics (measurement)\n * - advertising → marketing (ads)\n */\nexport const DEFAULT_CATEGORY_MAP: Record<string, string> = {\n necessary: 'functional',\n functional: 'functional',\n performance: 'analytics',\n advertising: 'marketing',\n};\n\n/**\n * CookieFirst consent management source for walkerOS.\n *\n * This source listens to CookieFirst CMP events and translates\n * consent states to walkerOS consent commands.\n *\n * @example\n * ```typescript\n * import { sourceCookieFirst } from '@walkeros/web-source-cmp-cookiefirst';\n *\n * await startFlow({\n * sources: {\n * consent: {\n * code: sourceCookieFirst,\n * config: {\n * settings: {\n * categoryMap: {\n * performance: 'statistics', // Custom mapping\n * },\n * },\n * },\n * },\n * },\n * });\n * ```\n */\nexport const sourceCookieFirst: 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\n const settings: Settings = {\n categoryMap: { ...DEFAULT_CATEGORY_MAP, ...config?.settings?.categoryMap },\n explicitOnly: config?.settings?.explicitOnly ?? true,\n globalName: config?.settings?.globalName ?? 'CookieFirst',\n };\n\n const fullConfig: Source.Config<Types> = { settings };\n\n // Track listener references for cleanup\n let initListener: (() => void) | undefined;\n let consentListener: ((e: Event) => void) | undefined;\n\n // Only setup if in browser environment\n if (actualWindow) {\n /**\n * Handle consent state from CookieFirst.\n * Maps CookieFirst categories to walkerOS consent groups and calls elb.\n *\n * When multiple CookieFirst categories map to the same walkerOS group,\n * uses OR logic: if ANY category is true, the group is true.\n */\n const handleConsent = (consent: CookieFirstConsent | null) => {\n // Skip if explicitOnly and no explicit consent given\n if (settings.explicitOnly && !consent) return;\n if (!consent) return;\n\n // Map CookieFirst categories to walkerOS consent groups\n // Use OR logic: if ANY source category is true, the target group is true\n const state: WalkerOS.Consent = {};\n Object.entries(consent).forEach(([category, value]) => {\n if (typeof value !== 'boolean') return;\n const mapped = settings.categoryMap?.[category] ?? category;\n // OR logic: once true, stays true\n state[mapped] = state[mapped] || value;\n });\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 const globalName = settings.globalName ?? 'CookieFirst';\n const cmp = actualWindow[globalName] as CookieFirstAPI | undefined;\n\n // Process existing consent if CMP already loaded\n if (cmp?.consent) {\n handleConsent(cmp.consent);\n }\n\n // Listen for CMP initialization\n initListener = () => {\n const cmp = actualWindow[globalName] as CookieFirstAPI | undefined;\n handleConsent(cmp?.consent ?? null);\n };\n actualWindow.addEventListener('cf_init', initListener);\n\n // Listen for consent changes\n consentListener = (e: Event) => {\n const customEvent = e as CustomEvent<CookieFirstConsent>;\n handleConsent(customEvent.detail);\n };\n actualWindow.addEventListener('cf_consent', consentListener);\n }\n\n return {\n type: 'cookiefirst',\n config: fullConfig,\n push: elb,\n destroy: async () => {\n // Remove event listeners on cleanup\n if (actualWindow && initListener) {\n actualWindow.removeEventListener('cf_init', initListener);\n }\n if (actualWindow && consentListener) {\n actualWindow.removeEventListener('cf_consent', consentListener);\n }\n },\n };\n};\n\nexport default sourceCookieFirst;\n"],"mappings":"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","names":["_a","_b","cmp"]}
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@walkeros/web-source-cmp-cookiefirst",
3
+ "description": "CookieFirst consent management source for walkerOS",
4
+ "version": "1.1.0-next-1771252576264",
5
+ "license": "MIT",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.js"
14
+ },
15
+ "./examples": {
16
+ "types": "./dist/examples/index.d.ts",
17
+ "import": "./dist/examples/index.mjs",
18
+ "require": "./dist/examples/index.js"
19
+ },
20
+ "./dev": {
21
+ "types": "./dist/dev.d.ts",
22
+ "import": "./dist/dev.mjs",
23
+ "require": "./dist/dev.js"
24
+ }
25
+ },
26
+ "files": [
27
+ "dist/**"
28
+ ],
29
+ "scripts": {
30
+ "build": "tsup --silent",
31
+ "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
32
+ "dev": "jest --watchAll --colors",
33
+ "lint": "tsc && eslint \"**/*.ts*\"",
34
+ "test": "jest",
35
+ "update": "npx npm-check-updates -u && npm update"
36
+ },
37
+ "dependencies": {
38
+ "@walkeros/core": "1.4.0-next-1771252576264",
39
+ "@walkeros/collector": "1.3.0-next-1771252576264"
40
+ },
41
+ "devDependencies": {},
42
+ "repository": {
43
+ "url": "git+https://github.com/elbwalker/walkerOS.git",
44
+ "directory": "packages/web/sources/cmps/cookiefirst"
45
+ },
46
+ "author": "elbwalker <hello@elbwalker.com>",
47
+ "homepage": "https://github.com/elbwalker/walkerOS#readme",
48
+ "bugs": {
49
+ "url": "https://github.com/elbwalker/walkerOS/issues"
50
+ },
51
+ "keywords": [
52
+ "walker",
53
+ "walkerOS",
54
+ "source",
55
+ "web",
56
+ "cookiefirst",
57
+ "consent",
58
+ "cmp"
59
+ ],
60
+ "funding": [
61
+ {
62
+ "type": "GitHub Sponsors",
63
+ "url": "https://github.com/sponsors/elbwalker"
64
+ }
65
+ ]
66
+ }