feat(consent): CMP adapters for Cookiebot, OneTrust, and Complianz - #41
Conversation
Implements specs/003-cmp-adapters (#39). @vizuh/clicktrail-consent/cmp exports connectCookiebot, connectOneTrust, and connectComplianz. Each forwards the CMP's effective decision to a ConsentHub, deduplicates repeated events, stays subscribed so in-page withdrawals emit denied, and returns a disposer. No DOM access at import; a window-like target can be injected for tests. - Cookiebot: emits only once hasResponse is set; listens to OnConsentReady/OnAccept/OnDecline (it may wipe storage before them). - OneTrust: exact group matching; OneTrustGroupsUpdated plus a wrapped OptanonWrapper, so a later snippet reassignment cannot silence it. - Complianz: cmplz_has_consent() or event.detail.categories on cmplz_fire_categories / cmplz_status_change. - state follows marketing consent because storageAllowed() checks only state, matching the WordPress consent bridge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7de0f6284a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (typeof hasConsent === 'function') { | ||
| marketing = !!hasConsent('marketing'); | ||
| analytics = !!hasConsent('statistics'); | ||
| } else if (Array.isArray(categories)) { |
There was a problem hiding this comment.
Handle category-only Complianz status changes
When cmplz_has_consent is unavailable—the explicitly supported fallback case—Complianz's later cmplz_status_change events provide the changed detail.category and detail.value, rather than a detail.categories array. After an initial cmplz_fire_categories grant, a subsequent marketing withdrawal therefore skips this branch and returns without notifying the hub, leaving stored attribution uncleared. Preserve the fallback category state and apply these category/value updates.
Useful? React with 👍 / 👎.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(specs): CMP adapters for @vizuh/clicktrail-consent Spec-kit spec, plan and tasks for #39. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(specs): amend FR-004 to effective-decision semantics Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(specs): mark 003 status and tasks against #41 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Part of #39 (adapters; the
cmp-booking-handoffexample follows in clicktrail-examples). Implementsspecs/003-cmp-adapters(spec in #40).Acceptance criterion
@vizuh/clicktrail-consent/cmpconnects Cookiebot, OneTrust and Complianz to aConsentHub:denied;Design
target(window-like) seam, with no DOM access at import.sideEffects: falsestill holds.statefollows marketing consent, becausestorageAllowed()checks onlystate. This matches the WordPress bridge.once) and return disposers.hasResponseis set.C00040does not matchC0004). Listens toOneTrustGroupsUpdatedas well as theOptanonWrapperwrap.cmplz_has_consent(), falling back toevent.detail.categories, per the Complianz developer guide.Review notes
/code-reviewraised 4 findings. Fixed:OptanonWrappersilenced the adapter; it now also usesOneTrustGroupsUpdated;disposedflag fixes it.Documented rather than changed: OneTrust and Complianz report the CMP's effective state before an answer. With an opt-in banner that's
denied, which is harmless. In an opt-out region the CMP itself configures, it'sgranted, the same state the CMP uses for its own tags, and the same as the WordPress bridge. The README states this. The spec's FR-004 wording ("never emit while pending") holds strictly only for Cookiebot, and #40 should be amended to match.Validation
packages/consent: 19 tests (13 new) cover:cmplz_has_consentwithdrawal and banner-open;pnpm -r testgreen,pnpm typecheckclean, andverify:workspacepasses for 23 packages.cmpdist is 1,801 B gzip unminified, an upper bound against the 2 KB budget. The repo has no size tool, so none was added.dist/cmp/index.jsimports in Node without a window.🤖 Generated with Claude Code