@walkeros/web-source-cmp-usercentrics 3.4.2 → 4.0.0-next-1777463920154

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/parseConsent.ts","../src/lib/v2.ts","../src/lib/v3.ts","../src/types/index.ts","../src/examples/inputs.ts","../src/examples/outputs.ts","../src/examples/env.ts","../src/examples/step.ts","../src/examples/trigger.ts","../src/index.ts"],"sourcesContent":["import type { WalkerOS } from '@walkeros/core';\nimport type { UsercentricsEventDetail, Settings } from '../types';\n\n/** Reserved keys in event.detail that are not service names */\nexport const RESERVED_KEYS = ['action', 'event', 'type', 'ucCategory'];\n\n/**\n * Determine if ucCategory represents group-level consent.\n * Group-level: all values are booleans.\n * Service-level: some values are non-boolean (e.g., 'partial').\n */\nexport function isGroupLevel(\n ucCategory: Record<string, boolean | unknown>,\n): boolean {\n return Object.values(ucCategory).every((val) => typeof val === 'boolean');\n}\n\n/**\n * Merge an incoming consent signal into the accumulating state using strict\n * AND semantics: absent key initialises from the incoming value; present key\n * becomes `true` only if both existing and incoming are `true`. Any single\n * `false` anywhere in the merge chain revokes consent for that key.\n *\n * This matches the consent rule of thumb: any deny signal denies. Permissive\n * (OR) and \"last-wins\" semantics are both unsafe for a privacy primitive.\n */\nfunction mergeConsent(\n state: WalkerOS.Consent,\n key: string,\n value: boolean,\n): void {\n state[key] = state[key] === undefined ? value : Boolean(state[key]) && value;\n}\n\n/**\n * Parse consent from Usercentrics event detail.\n *\n * Group-level: ucCategory values are all booleans → use them directly.\n * Service-level: ucCategory has non-booleans → mix boolean ucCategory entries\n * with top-level service keys from event.detail.\n *\n * categoryMap is applied in both modes to ucCategory boolean entries.\n * Strict AND: if multiple source categories map to the same target group,\n * the target is `true` only when ALL contributing sources are `true`.\n */\nexport function parseConsent(\n detail: UsercentricsEventDetail,\n settings: Settings,\n): WalkerOS.Consent {\n const state: WalkerOS.Consent = {};\n\n if (detail.ucCategory && isGroupLevel(detail.ucCategory)) {\n Object.entries(detail.ucCategory).forEach(([category, value]) => {\n if (typeof value !== 'boolean') return;\n const mapped = settings.categoryMap?.[category] ?? category;\n mergeConsent(state, mapped, value);\n });\n } else {\n if (detail.ucCategory) {\n Object.entries(detail.ucCategory).forEach(([key, value]) => {\n if (typeof value === 'boolean') {\n const mapped = settings.categoryMap?.[key] ?? key;\n mergeConsent(state, mapped, value);\n }\n });\n }\n\n Object.entries(detail).forEach(([key, value]) => {\n if (RESERVED_KEYS.includes(key)) return;\n if (typeof value !== 'boolean') return;\n const normalized = key.toLowerCase().replace(/ /g, '_');\n mergeConsent(state, normalized, value);\n });\n }\n\n return state;\n}\n","import type { Elb, Logger } from '@walkeros/core';\nimport type {\n Settings,\n UsercentricsEventDetail,\n UsercentricsV2Service,\n} from '../types';\nimport { parseConsent } from './parseConsent';\n\nexport interface V2AdapterContext {\n window: Window & typeof globalThis;\n elb: Elb.Fn;\n settings: Settings;\n logger: Logger.Instance;\n}\n\n/**\n * Aggregate V2 service array into a group-level ucCategory object using strict\n * AND logic. A category is `true` only if EVERY service in that category is\n * accepted. Any single denied service denies the whole category — this\n * matches the consent rule of thumb: any deny signal denies.\n */\nfunction aggregateByCategory(\n services: UsercentricsV2Service[],\n): Record<string, boolean> {\n const categories: Record<string, boolean> = {};\n services.forEach((service) => {\n const category = service.categorySlug;\n const status = service.consent?.status ?? false;\n categories[category] =\n categories[category] === undefined\n ? status\n : categories[category] && status;\n });\n return categories;\n}\n\n/**\n * Build a synthetic UsercentricsEventDetail from the V2 static API.\n * Marked as 'implicit' because UC_UI.isInitialized() === true does NOT prove\n * the read was user-initiated — it only proves the SDK has finished loading.\n * With settings.explicitOnly = true (the default), consumers correctly drop\n * this detail. Set explicitOnly = false to surface the static snapshot.\n */\nfunction buildDetailFromStatic(\n services: UsercentricsV2Service[],\n): UsercentricsEventDetail {\n return {\n event: 'consent_status',\n type: 'implicit',\n ucCategory: aggregateByCategory(services),\n };\n}\n\n/**\n * Set up the V2 adapter: listens on the configured event AND performs a\n * static read if UC_UI is already initialized.\n *\n * Returns a cleanup function that removes the event listener.\n */\nexport function setupV2Adapter(ctx: V2AdapterContext): () => void {\n const { window: win, elb, settings, logger } = ctx;\n const eventName = settings.eventName ?? 'ucEvent';\n\n const handleDetail = (detail: UsercentricsEventDetail) => {\n logger.debug('event received', detail);\n\n if (detail.event !== 'consent_status') return;\n if (settings.explicitOnly && detail.type?.toLowerCase() !== 'explicit')\n return;\n\n const state = parseConsent(detail, settings);\n if (Object.keys(state).length > 0) {\n elb('walker consent', state);\n }\n };\n\n const listener = (e: Event) => {\n const custom = e as CustomEvent<UsercentricsEventDetail>;\n if (custom.detail) handleDetail(custom.detail);\n };\n win.addEventListener(eventName, listener);\n\n // Static check: if UC_UI is already initialized, read current consent now.\n const api = win.UC_UI;\n if (api?.isInitialized?.() && api.getServicesBaseInfo) {\n const services = api.getServicesBaseInfo();\n if (services.length > 0) {\n handleDetail(buildDetailFromStatic(services));\n }\n }\n\n return () => {\n win.removeEventListener(eventName, listener);\n };\n}\n","import type { Elb, Logger } from '@walkeros/core';\nimport type {\n Settings,\n UsercentricsEventDetail,\n UsercentricsV3Api,\n UsercentricsV3CategoryState,\n UsercentricsV3CmpEventDetail,\n UsercentricsV3ConsentDetails,\n} from '../types';\nimport { parseConsent } from './parseConsent';\n\nexport interface V3AdapterContext {\n window: Window & typeof globalThis;\n elb: Elb.Fn;\n settings: Settings;\n logger: Logger.Instance;\n}\n\nconst V3_DEFAULT_EVENT_NAME = 'UC_UI_CMP_EVENT';\n\n/**\n * V3 CMP event types that represent a user consent decision. Presentation\n * events like `CMP_SHOWN` or `UI_INITIALIZED` must NOT trigger a consent\n * publish — they carry no user decision.\n */\nconst V3_DECISION_TYPES: ReadonlySet<string> = new Set([\n 'ACCEPT_ALL',\n 'DENY_ALL',\n 'SAVE',\n]);\n\n/**\n * Map a V3 CategoryData.state value to a walkerOS boolean using strict\n * semantics: only fully-accepted categories are `true`. Any partial or\n * denied state (including future/unknown states) resolves to `false`.\n *\n * This matches the consent rule of thumb: any deny signal denies.\n */\nfunction categoryStateToBoolean(state: UsercentricsV3CategoryState): boolean {\n return state === 'ALL_ACCEPTED';\n}\n\n/**\n * Build a synthetic UsercentricsEventDetail from V3 ConsentDetails.\n * Translates V3's structured consent state into the shape parseConsent expects.\n */\nfunction buildDetailFromV3(\n details: UsercentricsV3ConsentDetails,\n): UsercentricsEventDetail {\n const ucCategory: Record<string, boolean> = {};\n Object.entries(details.categories).forEach(([slug, category]) => {\n ucCategory[slug] = categoryStateToBoolean(category.state);\n });\n\n return {\n event: 'consent_status',\n type: details.consent.type === 'EXPLICIT' ? 'explicit' : 'implicit',\n ucCategory,\n };\n}\n\n/**\n * Set up the V3 adapter: registers a listener on the V3 consent event AND\n * (if __ucCmp is already initialized) performs a static read.\n *\n * Both paths re-fetch getConsentDetails() because the event payload does\n * not include consent state.\n *\n * Returns a cleanup function that removes the event listener.\n */\nexport async function setupV3Adapter(\n ctx: V3AdapterContext,\n): Promise<() => void> {\n const { window: win, elb, settings, logger } = ctx;\n const eventName = settings.v3EventName ?? V3_DEFAULT_EVENT_NAME;\n\n const publishConsent = async (cmp: UsercentricsV3Api): Promise<void> => {\n const details = await cmp.getConsentDetails();\n const detail = buildDetailFromV3(details);\n logger.debug('event received', detail);\n\n if (settings.explicitOnly && detail.type !== 'explicit') return;\n\n const state = parseConsent(detail, settings);\n if (Object.keys(state).length > 0) {\n elb('walker consent', state);\n }\n };\n\n const listener = (event: Event): void => {\n const cmp = win.__ucCmp;\n if (!cmp) return;\n const custom = event as CustomEvent<UsercentricsV3CmpEventDetail>;\n const detail = custom.detail;\n // Filter to decision events only: the CMP emits a broad set of events\n // (CMP_SHOWN, UI_INITIALIZED, VIEW_CHANGED, …) on this bus. Without\n // filtering, every view toggle would re-publish consent.\n if (!detail || detail.source !== 'CMP') return;\n if (!detail.type || !V3_DECISION_TYPES.has(detail.type)) return;\n publishConsent(cmp).catch(() => {\n // Swallow — a failed V3 fetch should not break the page.\n });\n };\n win.addEventListener(eventName, listener);\n\n // Static check: if __ucCmp is already initialized, fetch now.\n // Wrapped in try/catch so transient API failures during setup don't\n // reject setupV3Adapter() and tear down the whole flow — the listener\n // stays registered and will pick up the next real event.\n const cmp = win.__ucCmp;\n if (cmp) {\n try {\n const initialized = await cmp.isInitialized();\n if (initialized) {\n await publishConsent(cmp);\n }\n } catch (err) {\n logger.warn('v3 static consent read failed', err);\n }\n }\n\n return () => {\n win.removeEventListener(eventName, listener);\n };\n}\n","import type { Source, Elb } from '@walkeros/core';\n\n/**\n * Usercentrics consent event detail structure.\n *\n * Fired as event.detail on the configured window event (e.g. 'ucEvent').\n * Contains both category-level (ucCategory) and service-level consent.\n */\nexport interface UsercentricsEventDetail {\n /** Always 'consent_status' for consent events */\n event: string;\n /** 'explicit' when user actively chose, 'implicit' for page-load defaults (casing may vary) */\n type: string;\n /** Action taken: 'onAcceptAllServices', 'onDenyAllServices', 'onUpdateServices' */\n action?: string;\n /** Category-level consent booleans (e.g. { marketing: true, functional: false }) */\n ucCategory?: Record<string, boolean | unknown>;\n /** Service-level consent as top-level keys (e.g. 'Google Analytics': true) */\n [service: string]: unknown;\n}\n\ndeclare global {\n interface WindowEventMap {\n ucEvent: CustomEvent<UsercentricsEventDetail>;\n UC_UI_CMP_EVENT: CustomEvent<UsercentricsV3CmpEventDetail>;\n }\n}\n\n/**\n * Usercentrics V2 service info shape returned by `UC_UI.getServicesBaseInfo()`.\n * Only the fields we use are typed — minimal surface, not a full V2 API mirror.\n */\nexport interface UsercentricsV2Service {\n /** Category slug: 'essential' | 'functional' | 'marketing' | custom */\n categorySlug: string;\n /** Consent state for this service */\n consent: {\n status: boolean;\n };\n}\n\n/**\n * Usercentrics V2 window API (`window.UC_UI`).\n *\n * Methods are synchronous (unlike V3). All methods are optional because\n * Usercentrics does not guarantee every deployment exposes every method.\n */\nexport interface UsercentricsV2Api {\n isInitialized?: () => boolean;\n getServicesBaseInfo?: () => UsercentricsV2Service[];\n areAllConsentsAccepted?: () => boolean;\n}\n\n/**\n * Usercentrics V3 category state. The SDK may add future states; we handle\n * unknowns conservatively as non-accepting.\n */\nexport type UsercentricsV3CategoryState =\n | 'ALL_ACCEPTED'\n | 'ALL_DENIED'\n | 'SOME_ACCEPTED'\n | 'NO_STATE'\n | string;\n\n/**\n * Minimal V3 CategoryData — only fields the adapter reads.\n */\nexport interface UsercentricsV3CategoryData {\n state: UsercentricsV3CategoryState;\n name: string;\n}\n\n/**\n * Minimal V3 ConsentData — only the `type` field is used to distinguish\n * explicit vs implicit consent. Other fields (status, version, etc.) exist on\n * the real SDK but are not read by this adapter.\n */\nexport interface UsercentricsV3ConsentData {\n type: 'EXPLICIT' | 'IMPLICIT' | string;\n}\n\n/**\n * Minimal V3 ConsentDetails — only the fields the adapter reads.\n * The real SDK also exposes `services`, but the adapter currently operates\n * at category level only.\n */\nexport interface UsercentricsV3ConsentDetails {\n consent: UsercentricsV3ConsentData;\n categories: Record<string, UsercentricsV3CategoryData>;\n}\n\n/**\n * Usercentrics V3 window API (`window.__ucCmp`).\n *\n * Only the methods this adapter calls are typed — the real SDK surface is\n * much wider but we intentionally keep this narrow.\n */\nexport interface UsercentricsV3Api {\n isInitialized: () => Promise<boolean>;\n getConsentDetails: () => Promise<UsercentricsV3ConsentDetails>;\n}\n\n/**\n * V3 CMP event detail. Fired on `UC_UI_CMP_EVENT` (or custom name).\n * `source: 'CMP'` + a decision `type` tells us a user action has been taken.\n */\nexport interface UsercentricsV3CmpEventDetail {\n source?: string;\n type?: string;\n}\n\ndeclare global {\n interface Window {\n /**\n * Usercentrics V2 CMP API. Attached once the V2 Browser SDK is\n * initialized. Optional because the SDK loads asynchronously — guard\n * with a truthiness check before access.\n */\n UC_UI?: UsercentricsV2Api;\n /**\n * Usercentrics V3 CMP API. Attached once the V3 Browser SDK is\n * initialized. Optional because the SDK loads asynchronously — guard\n * with a truthiness check before access.\n */\n __ucCmp?: UsercentricsV3Api;\n }\n}\n\n/**\n * Settings for Usercentrics source\n */\nexport interface Settings {\n /**\n * Window event name to listen for.\n * Configured in Usercentrics admin under Implementation > Data Layer & Events.\n * Can also be set to 'UC_SDK_EVENT' for the built-in Browser SDK event.\n *\n * Default: 'ucEvent'\n */\n eventName?: string;\n\n /**\n * Map Usercentrics categories to walkerOS consent groups.\n * Keys: Usercentrics category names (from ucCategory)\n * Values: walkerOS consent group names\n *\n * Applied in both group-level and service-level consent modes.\n * When multiple source categories map to the same group, strict AND logic\n * applies: ALL contributing source categories must be true for the target\n * group to be true. Any single false denies consent.\n *\n * Default: {} (pass through category names as-is)\n */\n categoryMap?: Record<string, string>;\n\n /**\n * Only process explicit consent (user made a choice).\n * When true: Ignores events where type !== 'explicit'\n * When false: Processes any consent_status event including implicit/defaults\n *\n * Default: true\n */\n explicitOnly?: boolean;\n\n /**\n * Which Usercentrics API to target.\n * - 'auto' (default): detect at init. If `window.__ucCmp` is present, use V3.\n * If only `window.UC_UI` is present, use V2. If neither is present yet,\n * register listeners for both so late-loading CMPs are still caught.\n * - 'v2': force legacy `window.UC_UI` path.\n * - 'v3': force current `window.__ucCmp` path.\n */\n apiVersion?: 'auto' | 'v2' | 'v3';\n\n /**\n * V3 window event name to listen for consent changes.\n *\n * Usercentrics V3 hardcodes its built-in event names (`UC_UI_CMP_EVENT`,\n * `UC_UI_INITIALIZED`, `UC_UI_VIEW_CHANGED`, `UC_CONSENT`) — they cannot be\n * renamed. However, the Usercentrics admin dashboard (Implementation >\n * Data Layer & Events) lets admins configure an ADDITIONAL custom window\n * event. Use this setting to point at that custom event name if\n * configured; otherwise leave as default.\n *\n * Default: 'UC_UI_CMP_EVENT'\n */\n v3EventName?: 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 Usercentrics source\n */\nexport interface Env extends Source.BaseEnv {\n window?: Window & typeof globalThis;\n}\n\n/**\n * Types bundle for Usercentrics 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 { UsercentricsEventDetail } from '../types';\n\n/**\n * Example Usercentrics consent event detail inputs.\n *\n * These represent real event.detail payloads from Usercentrics CMP.\n */\n\n/**\n * Full consent - user accepted all categories (explicit)\n */\nexport const fullConsent: UsercentricsEventDetail = {\n event: 'consent_status',\n type: 'explicit',\n action: 'onAcceptAllServices',\n ucCategory: {\n essential: true,\n functional: true,\n marketing: true,\n },\n 'Google Analytics': true,\n 'Google Ads Remarketing': true,\n};\n\n/**\n * Partial consent - user accepted only essential and functional (explicit)\n */\nexport const partialConsent: UsercentricsEventDetail = {\n event: 'consent_status',\n type: 'explicit',\n action: 'onUpdateServices',\n ucCategory: {\n essential: true,\n functional: true,\n marketing: false,\n },\n 'Google Analytics': true,\n 'Google Ads Remarketing': false,\n};\n\n/**\n * Minimal consent - user denied everything except essential (explicit)\n */\nexport const minimalConsent: UsercentricsEventDetail = {\n event: 'consent_status',\n type: 'explicit',\n action: 'onDenyAllServices',\n ucCategory: {\n essential: true,\n functional: false,\n marketing: false,\n },\n 'Google Analytics': false,\n 'Google Ads Remarketing': false,\n};\n\n/**\n * Implicit consent - page load with default consent state\n * (not an explicit user choice)\n */\nexport const implicitConsent: UsercentricsEventDetail = {\n event: 'consent_status',\n type: 'implicit',\n ucCategory: {\n essential: true,\n functional: false,\n marketing: false,\n },\n 'Google Analytics': false,\n 'Google Ads Remarketing': false,\n};\n\n/**\n * Explicit consent with uppercase type field (Usercentrics docs are\n * inconsistent about casing - some show 'EXPLICIT', others 'explicit')\n */\nexport const fullConsentUpperCase: UsercentricsEventDetail = {\n event: 'consent_status',\n type: 'EXPLICIT',\n action: 'onAcceptAllServices',\n ucCategory: {\n essential: true,\n functional: true,\n marketing: true,\n },\n};\n\n/**\n * Service-level consent - ucCategory has mixed types (non-boolean values\n * indicate individual service-level choice rather than group-level)\n */\nexport const serviceLevelConsent: UsercentricsEventDetail = {\n event: 'consent_status',\n type: 'explicit',\n action: 'onUpdateServices',\n ucCategory: {\n essential: true,\n functional: 'partial', // Non-boolean indicates mixed service choices\n marketing: 'partial',\n },\n 'Google Analytics': true,\n 'Google Ads Remarketing': false,\n Hotjar: true,\n};\n\n/**\n * Non-consent event (should be ignored)\n */\nexport const nonConsentEvent: UsercentricsEventDetail = {\n event: 'other_event',\n type: 'explicit',\n};\n","import type { WalkerOS } from '@walkeros/core';\n\n/**\n * Expected walkerOS consent outputs.\n *\n * These represent the consent state after parsing Usercentrics event details\n * with no category mapping configured (pass-through).\n */\n\n/**\n * Full consent - all categories true (group-level)\n */\nexport const fullConsentMapped: WalkerOS.Consent = {\n essential: true,\n functional: true,\n marketing: true,\n};\n\n/**\n * Partial consent - essential and functional true, marketing false\n */\nexport const partialConsentMapped: WalkerOS.Consent = {\n essential: true,\n functional: true,\n marketing: false,\n};\n\n/**\n * Minimal consent - only essential true\n */\nexport const minimalConsentMapped: WalkerOS.Consent = {\n essential: true,\n functional: false,\n marketing: false,\n};\n\n/**\n * Full consent with custom category mapping applied\n * (essential->functional, functional->functional, marketing->marketing)\n */\nexport const fullConsentCustomMapped: WalkerOS.Consent = {\n functional: true,\n marketing: true,\n};\n\n/**\n * Service-level consent - individual service booleans + boolean ucCategory entries\n * (services normalized: lowercase, spaces to underscores)\n * (ucCategory boolean entries mapped through categoryMap)\n */\nexport const serviceLevelMapped: WalkerOS.Consent = {\n essential: true,\n google_analytics: true,\n google_ads_remarketing: false,\n hotjar: true,\n};\n","import type { Elb, Logger } from '@walkeros/core';\n\n/**\n * Example environment configurations for Usercentrics 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 warn: noop,\n info: noop,\n debug: noop,\n throw: (message: string | Error) => {\n throw typeof message === 'string' ? new Error(message) : message;\n },\n json: noop,\n scope: () => noopLogger,\n};\n","import type { Flow } from '@walkeros/core';\n\nexport const fullConsent: Flow.StepExample = {\n title: 'Full consent',\n description:\n 'A Usercentrics onAcceptAllServices event emits a walker consent command with essential, functional, and marketing granted.',\n trigger: { type: 'consent' },\n in: {\n event: 'consent_status',\n type: 'explicit',\n action: 'onAcceptAllServices',\n ucCategory: {\n essential: true,\n functional: true,\n marketing: true,\n },\n },\n out: [\n [\n 'elb',\n 'walker consent',\n {\n essential: true,\n functional: true,\n marketing: true,\n },\n ],\n ],\n};\n\nexport const minimalConsent: Flow.StepExample = {\n title: 'Minimal consent',\n description:\n 'A Usercentrics onDenyAllServices event emits a walker consent command with only essential granted.',\n trigger: { type: 'consent' },\n in: {\n event: 'consent_status',\n type: 'explicit',\n action: 'onDenyAllServices',\n ucCategory: {\n essential: true,\n functional: false,\n marketing: false,\n },\n },\n out: [\n [\n 'elb',\n 'walker consent',\n {\n essential: true,\n functional: false,\n marketing: false,\n },\n ],\n ],\n};\n\nexport const categoryMapOverride: Flow.StepExample = {\n title: 'Category map override',\n description:\n 'Custom categoryMap remaps essential to functional and functional to analytics',\n trigger: { type: 'consent' },\n in: {\n event: 'consent_status',\n type: 'explicit',\n ucCategory: {\n essential: true,\n functional: true,\n marketing: false,\n },\n },\n mapping: {\n categoryMap: { essential: 'functional', functional: 'analytics' },\n },\n out: [\n [\n 'elb',\n 'walker consent',\n {\n functional: true,\n analytics: true,\n marketing: false,\n },\n ],\n ],\n};\n\nexport const customEventName: Flow.StepExample = {\n title: 'Custom event name',\n description: 'Using UC_SDK_EVENT instead of ucEvent for Usercentrics SDK v2',\n trigger: { type: 'consent', options: { eventName: 'UC_SDK_EVENT' } },\n in: {\n event: 'consent_status',\n type: 'explicit',\n ucCategory: {\n essential: true,\n functional: true,\n marketing: true,\n },\n },\n mapping: { eventName: 'UC_SDK_EVENT' },\n out: [\n [\n 'elb',\n 'walker consent',\n {\n essential: true,\n functional: true,\n marketing: true,\n },\n ],\n ],\n};\n","import type { Trigger, Collector } from '@walkeros/core';\nimport { startFlow } from '@walkeros/collector';\n\ninterface UsercentricsContent {\n event: string;\n type: string;\n action?: string;\n ucCategory?: Record<string, boolean | unknown>;\n [service: string]: unknown;\n}\n\nconst createTrigger: Trigger.CreateFn<UsercentricsContent, void> = async (\n config: Collector.InitConfig,\n) => {\n let flow: Trigger.FlowHandle | undefined;\n\n const trigger: Trigger.Fn<UsercentricsContent, void> =\n (type?: string, opts?: unknown) => async (content: UsercentricsContent) => {\n // Lazy startFlow — source registers ucEvent listener during init\n if (!flow) {\n const result = await startFlow({ ...config, run: config.run ?? true });\n flow = { collector: result.collector, elb: result.elb };\n }\n\n // Dispatch the CMP event — source's listener catches it\n const eventName =\n (opts as { eventName?: string })?.eventName || 'ucEvent';\n window.dispatchEvent(new CustomEvent(eventName, { detail: content }));\n };\n\n return {\n get flow() {\n return flow;\n },\n trigger,\n };\n};\n\n/** Dispatches ucEvent CustomEvent after source init (post-init trigger). */\nconst trigger = (\n input: unknown,\n env: Record<string, unknown>,\n): void | (() => void) => {\n if (!input || typeof input !== 'object') return;\n return () => {\n (env.window as Window).dispatchEvent(\n new CustomEvent('ucEvent', { detail: input }),\n );\n };\n};\n\nexport { createTrigger, trigger };\n","import type { Source } from '@walkeros/core';\nimport type { Types, Settings } from './types';\nimport { setupV2Adapter } from './lib/v2';\nimport { setupV3Adapter } from './lib/v3';\n\n// Export types for external usage\nexport * as SourceUsercentrics from './types';\n\n// Export examples\nexport * from './examples';\n\n/**\n * Usercentrics consent management source for walkerOS.\n *\n * Listens to Usercentrics CMP events and translates consent states to\n * walkerOS consent commands. Supports both the legacy V2 API\n * (`window.UC_UI` + `ucEvent`) and the current V3 API\n * (`window.__ucCmp` + `UC_UI_CMP_EVENT`).\n *\n * @example\n * ```typescript\n * import { sourceUsercentrics } from '@walkeros/web-source-cmp-usercentrics';\n *\n * await startFlow({\n * sources: {\n * consent: {\n * code: sourceUsercentrics,\n * config: {\n * settings: {\n * eventName: 'ucEvent',\n * categoryMap: {\n * essential: 'functional',\n * functional: 'functional',\n * marketing: 'marketing',\n * },\n * },\n * },\n * },\n * },\n * });\n * ```\n */\nexport const sourceUsercentrics: Source.Init<Types> = async (context) => {\n const { config, env } = context;\n const { elb, logger } = 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 so adapters always see a fully-resolved Settings\n const settings: Settings = {\n eventName: config?.settings?.eventName ?? 'ucEvent',\n categoryMap: config?.settings?.categoryMap ?? {},\n explicitOnly: config?.settings?.explicitOnly ?? true,\n apiVersion: config?.settings?.apiVersion ?? 'auto',\n v3EventName: config?.settings?.v3EventName ?? 'UC_UI_CMP_EVENT',\n };\n\n const fullConfig: Source.Config<Types> = { settings };\n const cleanups: Array<() => void> = [];\n\n if (actualWindow) {\n const adapterCtx = { window: actualWindow, elb, settings, logger };\n const apiVersion = settings.apiVersion ?? 'auto';\n\n if (apiVersion === 'v2') {\n cleanups.push(setupV2Adapter(adapterCtx));\n } else if (apiVersion === 'v3') {\n cleanups.push(await setupV3Adapter(adapterCtx));\n } else {\n // auto: detect which API is present\n if (actualWindow.__ucCmp) {\n cleanups.push(await setupV3Adapter(adapterCtx));\n } else if (actualWindow.UC_UI) {\n cleanups.push(setupV2Adapter(adapterCtx));\n } else {\n // Neither loaded yet — attach both listeners so whichever loads later is caught.\n cleanups.push(setupV2Adapter(adapterCtx));\n cleanups.push(await setupV3Adapter(adapterCtx));\n }\n }\n }\n\n return {\n type: 'usercentrics',\n config: fullConfig,\n push: elb,\n destroy: async () => {\n cleanups.forEach((fn) => fn());\n },\n };\n};\n\nexport default sourceUsercentrics;\n"],"mappings":"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","names":["_a","cmp","fullConsent","minimalConsent","trigger"]}
1
+ {"version":3,"sources":["../src/lib/parseConsent.ts","../src/lib/v2.ts","../src/lib/v3.ts","../src/types/index.ts","../src/examples/inputs.ts","../src/examples/outputs.ts","../src/examples/env.ts","../src/examples/step.ts","../src/examples/trigger.ts","../src/index.ts"],"sourcesContent":["import type { WalkerOS } from '@walkeros/core';\nimport type { UsercentricsEventDetail, Settings } from '../types';\n\n/** Reserved keys in event.detail that are not service names */\nexport const RESERVED_KEYS = ['action', 'event', 'type', 'ucCategory'];\n\n/**\n * Determine if ucCategory represents group-level consent.\n * Group-level: all values are booleans.\n * Service-level: some values are non-boolean (e.g., 'partial').\n */\nexport function isGroupLevel(\n ucCategory: Record<string, boolean | unknown>,\n): boolean {\n return Object.values(ucCategory).every((val) => typeof val === 'boolean');\n}\n\n/**\n * Merge an incoming consent signal into the accumulating state using strict\n * AND semantics: absent key initialises from the incoming value; present key\n * becomes `true` only if both existing and incoming are `true`. Any single\n * `false` anywhere in the merge chain revokes consent for that key.\n *\n * This matches the consent rule of thumb: any deny signal denies. Permissive\n * (OR) and \"last-wins\" semantics are both unsafe for a privacy primitive.\n */\nfunction mergeConsent(\n state: WalkerOS.Consent,\n key: string,\n value: boolean,\n): void {\n state[key] = state[key] === undefined ? value : Boolean(state[key]) && value;\n}\n\n/**\n * Parse consent from Usercentrics event detail.\n *\n * Group-level: ucCategory values are all booleans → use them directly.\n * Service-level: ucCategory has non-booleans → mix boolean ucCategory entries\n * with top-level service keys from event.detail.\n *\n * categoryMap is applied in both modes to ucCategory boolean entries.\n * Strict AND: if multiple source categories map to the same target group,\n * the target is `true` only when ALL contributing sources are `true`.\n */\nexport function parseConsent(\n detail: UsercentricsEventDetail,\n settings: Settings,\n): WalkerOS.Consent {\n const state: WalkerOS.Consent = {};\n\n if (detail.ucCategory && isGroupLevel(detail.ucCategory)) {\n Object.entries(detail.ucCategory).forEach(([category, value]) => {\n if (typeof value !== 'boolean') return;\n const mapped = settings.categoryMap?.[category] ?? category;\n mergeConsent(state, mapped, value);\n });\n } else {\n if (detail.ucCategory) {\n Object.entries(detail.ucCategory).forEach(([key, value]) => {\n if (typeof value === 'boolean') {\n const mapped = settings.categoryMap?.[key] ?? key;\n mergeConsent(state, mapped, value);\n }\n });\n }\n\n Object.entries(detail).forEach(([key, value]) => {\n if (RESERVED_KEYS.includes(key)) return;\n if (typeof value !== 'boolean') return;\n const normalized = key.toLowerCase().replace(/ /g, '_');\n mergeConsent(state, normalized, value);\n });\n }\n\n return state;\n}\n","import type { Elb, Logger } from '@walkeros/core';\nimport type {\n Settings,\n UsercentricsEventDetail,\n UsercentricsV2Service,\n} from '../types';\nimport { parseConsent } from './parseConsent';\n\nexport interface V2AdapterContext {\n window: Window & typeof globalThis;\n elb: Elb.Fn;\n settings: Settings;\n logger: Logger.Instance;\n}\n\n/**\n * Aggregate V2 service array into a group-level ucCategory object using strict\n * AND logic. A category is `true` only if EVERY service in that category is\n * accepted. Any single denied service denies the whole category — this\n * matches the consent rule of thumb: any deny signal denies.\n */\nfunction aggregateByCategory(\n services: UsercentricsV2Service[],\n): Record<string, boolean> {\n const categories: Record<string, boolean> = {};\n services.forEach((service) => {\n const category = service.categorySlug;\n const status = service.consent?.status ?? false;\n categories[category] =\n categories[category] === undefined\n ? status\n : categories[category] && status;\n });\n return categories;\n}\n\n/**\n * Build a synthetic UsercentricsEventDetail from the V2 static API.\n * Marked as 'implicit' because UC_UI.isInitialized() === true does NOT prove\n * the read was user-initiated — it only proves the SDK has finished loading.\n * With settings.explicitOnly = true (the default), consumers correctly drop\n * this detail. Set explicitOnly = false to surface the static snapshot.\n */\nfunction buildDetailFromStatic(\n services: UsercentricsV2Service[],\n): UsercentricsEventDetail {\n return {\n event: 'consent_status',\n type: 'implicit',\n ucCategory: aggregateByCategory(services),\n };\n}\n\n/**\n * Set up the V2 adapter: listens on the configured event AND performs a\n * static read if UC_UI is already initialized.\n *\n * Returns a cleanup function that removes the event listener.\n */\nexport function setupV2Adapter(ctx: V2AdapterContext): () => void {\n const { window: win, elb, settings, logger } = ctx;\n const eventName = settings.eventName ?? 'ucEvent';\n\n const handleDetail = (detail: UsercentricsEventDetail) => {\n logger.debug('event received', detail);\n\n if (detail.event !== 'consent_status') return;\n if (settings.explicitOnly && detail.type?.toLowerCase() !== 'explicit')\n return;\n\n const state = parseConsent(detail, settings);\n if (Object.keys(state).length > 0) {\n elb('walker consent', state);\n }\n };\n\n const listener = (e: Event) => {\n const custom = e as CustomEvent<UsercentricsEventDetail>;\n if (custom.detail) handleDetail(custom.detail);\n };\n win.addEventListener(eventName, listener);\n\n // Static check: if UC_UI is already initialized, read current consent now.\n const api = win.UC_UI;\n if (api?.isInitialized?.() && api.getServicesBaseInfo) {\n const services = api.getServicesBaseInfo();\n if (services.length > 0) {\n handleDetail(buildDetailFromStatic(services));\n }\n }\n\n return () => {\n win.removeEventListener(eventName, listener);\n };\n}\n","import type { Elb, Logger } from '@walkeros/core';\nimport type {\n Settings,\n UsercentricsEventDetail,\n UsercentricsV3Api,\n UsercentricsV3CategoryState,\n UsercentricsV3CmpEventDetail,\n UsercentricsV3ConsentDetails,\n} from '../types';\nimport { parseConsent } from './parseConsent';\n\nexport interface V3AdapterContext {\n window: Window & typeof globalThis;\n elb: Elb.Fn;\n settings: Settings;\n logger: Logger.Instance;\n}\n\nconst V3_DEFAULT_EVENT_NAME = 'UC_UI_CMP_EVENT';\n\n/**\n * V3 CMP event types that represent a user consent decision. Presentation\n * events like `CMP_SHOWN` or `UI_INITIALIZED` must NOT trigger a consent\n * publish — they carry no user decision.\n */\nconst V3_DECISION_TYPES: ReadonlySet<string> = new Set([\n 'ACCEPT_ALL',\n 'DENY_ALL',\n 'SAVE',\n]);\n\n/**\n * Map a V3 CategoryData.state value to a walkerOS boolean using strict\n * semantics: only fully-accepted categories are `true`. Any partial or\n * denied state (including future/unknown states) resolves to `false`.\n *\n * This matches the consent rule of thumb: any deny signal denies.\n */\nfunction categoryStateToBoolean(state: UsercentricsV3CategoryState): boolean {\n return state === 'ALL_ACCEPTED';\n}\n\n/**\n * Build a synthetic UsercentricsEventDetail from V3 ConsentDetails.\n * Translates V3's structured consent state into the shape parseConsent expects.\n */\nfunction buildDetailFromV3(\n details: UsercentricsV3ConsentDetails,\n): UsercentricsEventDetail {\n const ucCategory: Record<string, boolean> = {};\n Object.entries(details.categories).forEach(([slug, category]) => {\n ucCategory[slug] = categoryStateToBoolean(category.state);\n });\n\n return {\n event: 'consent_status',\n type: details.consent.type === 'EXPLICIT' ? 'explicit' : 'implicit',\n ucCategory,\n };\n}\n\n/**\n * Set up the V3 adapter: registers a listener on the V3 consent event AND\n * (if __ucCmp is already initialized) performs a static read.\n *\n * Both paths re-fetch getConsentDetails() because the event payload does\n * not include consent state.\n *\n * Returns a cleanup function that removes the event listener.\n */\nexport async function setupV3Adapter(\n ctx: V3AdapterContext,\n): Promise<() => void> {\n const { window: win, elb, settings, logger } = ctx;\n const eventName = settings.v3EventName ?? V3_DEFAULT_EVENT_NAME;\n\n const publishConsent = async (cmp: UsercentricsV3Api): Promise<void> => {\n const details = await cmp.getConsentDetails();\n const detail = buildDetailFromV3(details);\n logger.debug('event received', detail);\n\n if (settings.explicitOnly && detail.type !== 'explicit') return;\n\n const state = parseConsent(detail, settings);\n if (Object.keys(state).length > 0) {\n elb('walker consent', state);\n }\n };\n\n const listener = (event: Event): void => {\n const cmp = win.__ucCmp;\n if (!cmp) return;\n const custom = event as CustomEvent<UsercentricsV3CmpEventDetail>;\n const detail = custom.detail;\n // Filter to decision events only: the CMP emits a broad set of events\n // (CMP_SHOWN, UI_INITIALIZED, VIEW_CHANGED, …) on this bus. Without\n // filtering, every view toggle would re-publish consent.\n if (!detail || detail.source !== 'CMP') return;\n if (!detail.type || !V3_DECISION_TYPES.has(detail.type)) return;\n publishConsent(cmp).catch(() => {\n // Swallow — a failed V3 fetch should not break the page.\n });\n };\n win.addEventListener(eventName, listener);\n\n // Static check: if __ucCmp is already initialized, fetch now.\n // Wrapped in try/catch so transient API failures during setup don't\n // reject setupV3Adapter() and tear down the whole flow — the listener\n // stays registered and will pick up the next real event.\n const cmp = win.__ucCmp;\n if (cmp) {\n try {\n const initialized = await cmp.isInitialized();\n if (initialized) {\n await publishConsent(cmp);\n }\n } catch (err) {\n logger.warn('v3 static consent read failed', err);\n }\n }\n\n return () => {\n win.removeEventListener(eventName, listener);\n };\n}\n","import type { Source, Elb } from '@walkeros/core';\n\ndeclare module '@walkeros/core' {\n interface SourceMap {\n usercentrics: { type: 'usercentrics'; platform?: 'web' };\n }\n}\n\n/**\n * Usercentrics consent event detail structure.\n *\n * Fired as event.detail on the configured window event (e.g. 'ucEvent').\n * Contains both category-level (ucCategory) and service-level consent.\n */\nexport interface UsercentricsEventDetail {\n /** Always 'consent_status' for consent events */\n event: string;\n /** 'explicit' when user actively chose, 'implicit' for page-load defaults (casing may vary) */\n type: string;\n /** Action taken: 'onAcceptAllServices', 'onDenyAllServices', 'onUpdateServices' */\n action?: string;\n /** Category-level consent booleans (e.g. { marketing: true, functional: false }) */\n ucCategory?: Record<string, boolean | unknown>;\n /** Service-level consent as top-level keys (e.g. 'Google Analytics': true) */\n [service: string]: unknown;\n}\n\ndeclare global {\n interface WindowEventMap {\n ucEvent: CustomEvent<UsercentricsEventDetail>;\n UC_UI_CMP_EVENT: CustomEvent<UsercentricsV3CmpEventDetail>;\n }\n}\n\n/**\n * Usercentrics V2 service info shape returned by `UC_UI.getServicesBaseInfo()`.\n * Only the fields we use are typed - minimal surface, not a full V2 API mirror.\n */\nexport interface UsercentricsV2Service {\n /** Category slug: 'essential' | 'functional' | 'marketing' | custom */\n categorySlug: string;\n /** Consent state for this service */\n consent: {\n status: boolean;\n };\n}\n\n/**\n * Usercentrics V2 window API (`window.UC_UI`).\n *\n * Methods are synchronous (unlike V3). All methods are optional because\n * Usercentrics does not guarantee every deployment exposes every method.\n */\nexport interface UsercentricsV2Api {\n isInitialized?: () => boolean;\n getServicesBaseInfo?: () => UsercentricsV2Service[];\n areAllConsentsAccepted?: () => boolean;\n}\n\n/**\n * Usercentrics V3 category state. The SDK may add future states; we handle\n * unknowns conservatively as non-accepting.\n */\nexport type UsercentricsV3CategoryState =\n | 'ALL_ACCEPTED'\n | 'ALL_DENIED'\n | 'SOME_ACCEPTED'\n | 'NO_STATE'\n | string;\n\n/**\n * Minimal V3 CategoryData - only fields the adapter reads.\n */\nexport interface UsercentricsV3CategoryData {\n state: UsercentricsV3CategoryState;\n name: string;\n}\n\n/**\n * Minimal V3 ConsentData - only the `type` field is used to distinguish\n * explicit vs implicit consent. Other fields (status, version, etc.) exist on\n * the real SDK but are not read by this adapter.\n */\nexport interface UsercentricsV3ConsentData {\n type: 'EXPLICIT' | 'IMPLICIT' | string;\n}\n\n/**\n * Minimal V3 ConsentDetails - only the fields the adapter reads.\n * The real SDK also exposes `services`, but the adapter currently operates\n * at category level only.\n */\nexport interface UsercentricsV3ConsentDetails {\n consent: UsercentricsV3ConsentData;\n categories: Record<string, UsercentricsV3CategoryData>;\n}\n\n/**\n * Usercentrics V3 window API (`window.__ucCmp`).\n *\n * Only the methods this adapter calls are typed - the real SDK surface is\n * much wider but we intentionally keep this narrow.\n */\nexport interface UsercentricsV3Api {\n isInitialized: () => Promise<boolean>;\n getConsentDetails: () => Promise<UsercentricsV3ConsentDetails>;\n}\n\n/**\n * V3 CMP event detail. Fired on `UC_UI_CMP_EVENT` (or custom name).\n * `source: 'CMP'` + a decision `type` tells us a user action has been taken.\n */\nexport interface UsercentricsV3CmpEventDetail {\n source?: string;\n type?: string;\n}\n\ndeclare global {\n interface Window {\n /**\n * Usercentrics V2 CMP API. Attached once the V2 Browser SDK is\n * initialized. Optional because the SDK loads asynchronously - guard\n * with a truthiness check before access.\n */\n UC_UI?: UsercentricsV2Api;\n /**\n * Usercentrics V3 CMP API. Attached once the V3 Browser SDK is\n * initialized. Optional because the SDK loads asynchronously - guard\n * with a truthiness check before access.\n */\n __ucCmp?: UsercentricsV3Api;\n }\n}\n\n/**\n * Settings for Usercentrics source\n */\nexport interface Settings {\n /**\n * Window event name to listen for.\n * Configured in Usercentrics admin under Implementation > Data Layer & Events.\n * Can also be set to 'UC_SDK_EVENT' for the built-in Browser SDK event.\n *\n * Default: 'ucEvent'\n */\n eventName?: string;\n\n /**\n * Map Usercentrics categories to walkerOS consent groups.\n * Keys: Usercentrics category names (from ucCategory)\n * Values: walkerOS consent group names\n *\n * Applied in both group-level and service-level consent modes.\n * When multiple source categories map to the same group, strict AND logic\n * applies: ALL contributing source categories must be true for the target\n * group to be true. Any single false denies consent.\n *\n * Default: {} (pass through category names as-is)\n */\n categoryMap?: Record<string, string>;\n\n /**\n * Only process explicit consent (user made a choice).\n * When true: Ignores events where type !== 'explicit'\n * When false: Processes any consent_status event including implicit/defaults\n *\n * Default: true\n */\n explicitOnly?: boolean;\n\n /**\n * Which Usercentrics API to target.\n * - 'auto' (default): detect at init. If `window.__ucCmp` is present, use V3.\n * If only `window.UC_UI` is present, use V2. If neither is present yet,\n * register listeners for both so late-loading CMPs are still caught.\n * - 'v2': force legacy `window.UC_UI` path.\n * - 'v3': force current `window.__ucCmp` path.\n */\n apiVersion?: 'auto' | 'v2' | 'v3';\n\n /**\n * V3 window event name to listen for consent changes.\n *\n * Usercentrics V3 hardcodes its built-in event names (`UC_UI_CMP_EVENT`,\n * `UC_UI_INITIALIZED`, `UC_UI_VIEW_CHANGED`, `UC_CONSENT`) - they cannot be\n * renamed. However, the Usercentrics admin dashboard (Implementation >\n * Data Layer & Events) lets admins configure an ADDITIONAL custom window\n * event. Use this setting to point at that custom event name if\n * configured; otherwise leave as default.\n *\n * Default: 'UC_UI_CMP_EVENT'\n */\n v3EventName?: 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 Usercentrics source\n */\nexport interface Env extends Source.BaseEnv {\n window?: Window & typeof globalThis;\n}\n\n/**\n * Types bundle for Usercentrics 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 { UsercentricsEventDetail } from '../types';\n\n/**\n * Example Usercentrics consent event detail inputs.\n *\n * These represent real event.detail payloads from Usercentrics CMP.\n */\n\n/**\n * Full consent - user accepted all categories (explicit)\n */\nexport const fullConsent: UsercentricsEventDetail = {\n event: 'consent_status',\n type: 'explicit',\n action: 'onAcceptAllServices',\n ucCategory: {\n essential: true,\n functional: true,\n marketing: true,\n },\n 'Google Analytics': true,\n 'Google Ads Remarketing': true,\n};\n\n/**\n * Partial consent - user accepted only essential and functional (explicit)\n */\nexport const partialConsent: UsercentricsEventDetail = {\n event: 'consent_status',\n type: 'explicit',\n action: 'onUpdateServices',\n ucCategory: {\n essential: true,\n functional: true,\n marketing: false,\n },\n 'Google Analytics': true,\n 'Google Ads Remarketing': false,\n};\n\n/**\n * Minimal consent - user denied everything except essential (explicit)\n */\nexport const minimalConsent: UsercentricsEventDetail = {\n event: 'consent_status',\n type: 'explicit',\n action: 'onDenyAllServices',\n ucCategory: {\n essential: true,\n functional: false,\n marketing: false,\n },\n 'Google Analytics': false,\n 'Google Ads Remarketing': false,\n};\n\n/**\n * Implicit consent - page load with default consent state\n * (not an explicit user choice)\n */\nexport const implicitConsent: UsercentricsEventDetail = {\n event: 'consent_status',\n type: 'implicit',\n ucCategory: {\n essential: true,\n functional: false,\n marketing: false,\n },\n 'Google Analytics': false,\n 'Google Ads Remarketing': false,\n};\n\n/**\n * Explicit consent with uppercase type field (Usercentrics docs are\n * inconsistent about casing - some show 'EXPLICIT', others 'explicit')\n */\nexport const fullConsentUpperCase: UsercentricsEventDetail = {\n event: 'consent_status',\n type: 'EXPLICIT',\n action: 'onAcceptAllServices',\n ucCategory: {\n essential: true,\n functional: true,\n marketing: true,\n },\n};\n\n/**\n * Service-level consent - ucCategory has mixed types (non-boolean values\n * indicate individual service-level choice rather than group-level)\n */\nexport const serviceLevelConsent: UsercentricsEventDetail = {\n event: 'consent_status',\n type: 'explicit',\n action: 'onUpdateServices',\n ucCategory: {\n essential: true,\n functional: 'partial', // Non-boolean indicates mixed service choices\n marketing: 'partial',\n },\n 'Google Analytics': true,\n 'Google Ads Remarketing': false,\n Hotjar: true,\n};\n\n/**\n * Non-consent event (should be ignored)\n */\nexport const nonConsentEvent: UsercentricsEventDetail = {\n event: 'other_event',\n type: 'explicit',\n};\n","import type { WalkerOS } from '@walkeros/core';\n\n/**\n * Expected walkerOS consent outputs.\n *\n * These represent the consent state after parsing Usercentrics event details\n * with no category mapping configured (pass-through).\n */\n\n/**\n * Full consent - all categories true (group-level)\n */\nexport const fullConsentMapped: WalkerOS.Consent = {\n essential: true,\n functional: true,\n marketing: true,\n};\n\n/**\n * Partial consent - essential and functional true, marketing false\n */\nexport const partialConsentMapped: WalkerOS.Consent = {\n essential: true,\n functional: true,\n marketing: false,\n};\n\n/**\n * Minimal consent - only essential true\n */\nexport const minimalConsentMapped: WalkerOS.Consent = {\n essential: true,\n functional: false,\n marketing: false,\n};\n\n/**\n * Full consent with custom category mapping applied\n * (essential->functional, functional->functional, marketing->marketing)\n */\nexport const fullConsentCustomMapped: WalkerOS.Consent = {\n functional: true,\n marketing: true,\n};\n\n/**\n * Service-level consent - individual service booleans + boolean ucCategory entries\n * (services normalized: lowercase, spaces to underscores)\n * (ucCategory boolean entries mapped through categoryMap)\n */\nexport const serviceLevelMapped: WalkerOS.Consent = {\n essential: true,\n google_analytics: true,\n google_ads_remarketing: false,\n hotjar: true,\n};\n","import type { Elb, Logger } from '@walkeros/core';\n\n/**\n * Example environment configurations for Usercentrics 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 warn: noop,\n info: noop,\n debug: noop,\n throw: (message: string | Error) => {\n throw typeof message === 'string' ? new Error(message) : message;\n },\n json: noop,\n scope: () => noopLogger,\n};\n","import type { Flow } from '@walkeros/core';\n\nexport const fullConsent: Flow.StepExample = {\n title: 'Full consent',\n description:\n 'A Usercentrics onAcceptAllServices event emits a walker consent command with essential, functional, and marketing granted.',\n trigger: { type: 'consent' },\n in: {\n event: 'consent_status',\n type: 'explicit',\n action: 'onAcceptAllServices',\n ucCategory: {\n essential: true,\n functional: true,\n marketing: true,\n },\n },\n out: [\n [\n 'elb',\n 'walker consent',\n {\n essential: true,\n functional: true,\n marketing: true,\n },\n ],\n ],\n};\n\nexport const minimalConsent: Flow.StepExample = {\n title: 'Minimal consent',\n description:\n 'A Usercentrics onDenyAllServices event emits a walker consent command with only essential granted.',\n trigger: { type: 'consent' },\n in: {\n event: 'consent_status',\n type: 'explicit',\n action: 'onDenyAllServices',\n ucCategory: {\n essential: true,\n functional: false,\n marketing: false,\n },\n },\n out: [\n [\n 'elb',\n 'walker consent',\n {\n essential: true,\n functional: false,\n marketing: false,\n },\n ],\n ],\n};\n\nexport const categoryMapOverride: Flow.StepExample = {\n title: 'Category map override',\n description:\n 'Custom categoryMap remaps essential to functional and functional to analytics',\n trigger: { type: 'consent' },\n in: {\n event: 'consent_status',\n type: 'explicit',\n ucCategory: {\n essential: true,\n functional: true,\n marketing: false,\n },\n },\n mapping: {\n categoryMap: { essential: 'functional', functional: 'analytics' },\n },\n out: [\n [\n 'elb',\n 'walker consent',\n {\n functional: true,\n analytics: true,\n marketing: false,\n },\n ],\n ],\n};\n\nexport const customEventName: Flow.StepExample = {\n title: 'Custom event name',\n description: 'Using UC_SDK_EVENT instead of ucEvent for Usercentrics SDK v2',\n trigger: { type: 'consent', options: { eventName: 'UC_SDK_EVENT' } },\n in: {\n event: 'consent_status',\n type: 'explicit',\n ucCategory: {\n essential: true,\n functional: true,\n marketing: true,\n },\n },\n mapping: { eventName: 'UC_SDK_EVENT' },\n out: [\n [\n 'elb',\n 'walker consent',\n {\n essential: true,\n functional: true,\n marketing: true,\n },\n ],\n ],\n};\n","import type { Trigger, Collector } from '@walkeros/core';\nimport { startFlow } from '@walkeros/collector';\n\ninterface UsercentricsContent {\n event: string;\n type: string;\n action?: string;\n ucCategory?: Record<string, boolean | unknown>;\n [service: string]: unknown;\n}\n\nconst createTrigger: Trigger.CreateFn<UsercentricsContent, void> = async (\n config: Collector.InitConfig,\n) => {\n let flow: Trigger.FlowHandle | undefined;\n\n const trigger: Trigger.Fn<UsercentricsContent, void> =\n (type?: string, opts?: unknown) => async (content: UsercentricsContent) => {\n // Lazy startFlow — source registers ucEvent listener during init\n if (!flow) {\n const result = await startFlow({ ...config, run: config.run ?? true });\n flow = { collector: result.collector, elb: result.elb };\n }\n\n // Dispatch the CMP event — source's listener catches it\n const eventName =\n (opts as { eventName?: string })?.eventName || 'ucEvent';\n window.dispatchEvent(new CustomEvent(eventName, { detail: content }));\n };\n\n return {\n get flow() {\n return flow;\n },\n trigger,\n };\n};\n\n/** Dispatches ucEvent CustomEvent after source init (post-init trigger). */\nconst trigger = (\n input: unknown,\n env: Record<string, unknown>,\n): void | (() => void) => {\n if (!input || typeof input !== 'object') return;\n return () => {\n (env.window as Window).dispatchEvent(\n new CustomEvent('ucEvent', { detail: input }),\n );\n };\n};\n\nexport { createTrigger, trigger };\n","import type { Source } from '@walkeros/core';\nimport type { Types, Settings } from './types';\nimport { setupV2Adapter } from './lib/v2';\nimport { setupV3Adapter } from './lib/v3';\n\n// Export types for external usage\nexport * as SourceUsercentrics from './types';\n\n// Export examples\nexport * from './examples';\n\n/**\n * Usercentrics consent management source for walkerOS.\n *\n * Listens to Usercentrics CMP events and translates consent states to\n * walkerOS consent commands. Supports both the legacy V2 API\n * (`window.UC_UI` + `ucEvent`) and the current V3 API\n * (`window.__ucCmp` + `UC_UI_CMP_EVENT`).\n *\n * @example\n * ```typescript\n * import { sourceUsercentrics } from '@walkeros/web-source-cmp-usercentrics';\n *\n * await startFlow({\n * sources: {\n * consent: {\n * code: sourceUsercentrics,\n * config: {\n * settings: {\n * eventName: 'ucEvent',\n * categoryMap: {\n * essential: 'functional',\n * functional: 'functional',\n * marketing: 'marketing',\n * },\n * },\n * },\n * },\n * },\n * });\n * ```\n */\nexport const sourceUsercentrics: Source.Init<Types> = async (context) => {\n const { config, env } = context;\n const { elb, logger } = 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 so adapters always see a fully-resolved Settings\n const settings: Settings = {\n eventName: config?.settings?.eventName ?? 'ucEvent',\n categoryMap: config?.settings?.categoryMap ?? {},\n explicitOnly: config?.settings?.explicitOnly ?? true,\n apiVersion: config?.settings?.apiVersion ?? 'auto',\n v3EventName: config?.settings?.v3EventName ?? 'UC_UI_CMP_EVENT',\n };\n\n const fullConfig: Source.Config<Types> = { settings };\n const cleanups: Array<() => void> = [];\n\n if (actualWindow) {\n const adapterCtx = { window: actualWindow, elb, settings, logger };\n const apiVersion = settings.apiVersion ?? 'auto';\n\n if (apiVersion === 'v2') {\n cleanups.push(setupV2Adapter(adapterCtx));\n } else if (apiVersion === 'v3') {\n cleanups.push(await setupV3Adapter(adapterCtx));\n } else {\n // auto: detect which API is present\n if (actualWindow.__ucCmp) {\n cleanups.push(await setupV3Adapter(adapterCtx));\n } else if (actualWindow.UC_UI) {\n cleanups.push(setupV2Adapter(adapterCtx));\n } else {\n // Neither loaded yet — attach both listeners so whichever loads later is caught.\n cleanups.push(setupV2Adapter(adapterCtx));\n cleanups.push(await setupV3Adapter(adapterCtx));\n }\n }\n }\n\n return {\n type: 'usercentrics',\n config: fullConfig,\n push: elb,\n destroy: async () => {\n cleanups.forEach((fn) => fn());\n },\n };\n};\n\nexport default sourceUsercentrics;\n"],"mappings":"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","names":["_a","cmp","fullConsent","minimalConsent","trigger"]}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$meta": {
3
3
  "package": "@walkeros/web-source-cmp-usercentrics",
4
- "version": "3.4.2",
4
+ "version": "4.0.0-next-1777463920154",
5
5
  "type": "source",
6
6
  "platform": [
7
7
  "web"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@walkeros/web-source-cmp-usercentrics",
3
3
  "description": "Usercentrics consent management source for walkerOS",
4
- "version": "3.4.2",
4
+ "version": "4.0.0-next-1777463920154",
5
5
  "license": "MIT",
6
6
  "walkerOS": {
7
7
  "type": "source",
@@ -45,8 +45,8 @@
45
45
  "update": "npx npm-check-updates -u && npm update"
46
46
  },
47
47
  "dependencies": {
48
- "@walkeros/collector": "3.4.2",
49
- "@walkeros/core": "3.4.2"
48
+ "@walkeros/collector": "4.0.0-next-1777463920154",
49
+ "@walkeros/core": "4.0.0-next-1777463920154"
50
50
  },
51
51
  "repository": {
52
52
  "url": "git+https://github.com/elbwalker/walkerOS.git",