Skip to content

feat: Usercentrics CMP#749

Merged
harlan-zw merged 7 commits intomainfrom
feat/usercentrics-cmp
May 8, 2026
Merged

feat: Usercentrics CMP#749
harlan-zw merged 7 commits intomainfrom
feat/usercentrics-cmp

Conversation

@harlan-zw
Copy link
Copy Markdown
Collaborator

@harlan-zw harlan-zw commented May 7, 2026

🔗 Linked issue

Related to #177

❓ Type of change

  • 📖 Documentation
  • 🐞 Bug fix
  • 👌 Enhancement
  • ✨ New feature
  • 🧹 Chore
  • ⚠️ Breaking change

📚 Description

Adds Usercentrics CMP v3 ("Web CMP") to the registry as useScriptUsercentrics. Loads the unbundled, unproxied v3 loader from web.cmp.usercentrics.eu/ui/loader.js (the consent surface itself must hit origin) and is exempt from consent gating. The composable surfaces the integration win: consent.onConsentChange(cb) over UC_UI_CMP_EVENT and whenReady() over UC_CMP_API_READY so users can drive useScript consent triggers from Usercentrics events, plus typed showFirstLayer / showSecondLayer / acceptAll / denyAll helpers backed by the v3 window.__ucCmp programmatic API. Schema covers rulesetId (the v3 attribute), optional autoblocker (injects autoblocker.js ahead of the loader for Auto Blocking rulesets), and optional language.

🧪 Usage

<script setup lang="ts">
const { proxy, consent } = useScriptUsercentrics({
  rulesetId: 'your-ruleset-id',
  autoblocker: true,
})

consent.onConsentChange(async (detail) => {
  if (detail.type === 'ACCEPT_ALL' || detail.type === 'SAVE') {
    const details = await proxy.ucCmp.getConsentDetails()
    console.log(details)
  }
})
</script>

<template>
  <button @click="consent.showSecondLayer()">
    Privacy settings
  </button>
</template>

Add usercentrics: { rulesetId: 'your-ruleset-id' } under scripts.registry in nuxt.config.ts to register the script.

🛠 v3 pivot

The original revision of this PR targeted the legacy CMP v2 surface (app.usercentrics.eu/browser-ui/<ver>/loader.js + data-settings-id + UC_UI). After live-verifying against a real v3 ruleset, the registration was unreachable for any modern Usercentrics customer (new signups only get v3). Pivoted to v3 only:

was (v2) now (v3)
app.usercentrics.eu/browser-ui/${version}/loader.js web.cmp.usercentrics.eu/ui/loader.js
data-settings-id data-ruleset-id
settingsId + version + tcfEnabled + embeddingType rulesetId + autoblocker + language (TCF / embedding type are now configured server-side in the ruleset)
window.UC_UI (not bound on v3 rulesets we tested) window.__ucCmp (typed UsercentricsCmp)
UC_CONSENT listener UC_UI_CMP_EVENT (carries detail.type)
UC_UI_INITIALIZED for whenReady UC_CMP_API_READY

Live verification: confirmed __ucCmp global + UC_CMP_API_READY event + the proto methods (acceptAllConsents, denyAllConsents, showFirstLayer, showSecondLayer, getConsentDetails, isInitialized, …) on a registered v3 ruleset.

✅ What's covered

  • Wiring contract: script tag carries the v3 URL + data-ruleset-id; autoblocker: true injects web.cmp.usercentrics.eu/modules/autoblocker.js ahead of the loader.
  • Behavioural contract: stubbed __ucCmp shim dispatches UC_CMP_API_READY + UC_UI_CMP_EVENT (ACCEPT_ALL / DENY_ALL); the composable surfaces the events through consent.onConsentChange.
  • Live-loader contract: a separate test fetches the live web.cmp.usercentrics.eu/ui/loader.js and asserts the body still references __ucCmp + UC_CMP_API_READY, so a vendor-side rename breaks the test instead of silently breaking the integration.
  • Schema validation rejects empty rulesetId so misconfig fails dev validation.
  • Typed UsercentricsApi / UsercentricsCmp / UsercentricsConsent / UsercentricsCmpEventDetail are exported.
  • Docs, devtools listing, and playground pages aligned with the v3 surface.
  • Partytown intentionally unsupported (method-heavy API, needs main-thread DOM for overlays).

harlan-zw added 2 commits May 7, 2026 15:10
Adds the Usercentrics consent management platform to the registry as
useScriptUsercentrics with typed UC_UI access plus a consent helper
exposing onConsentChange(), letting users wire other registry scripts'
consent triggers directly to UC_CONSENT events. Bundle and proxy are
intentionally off and the script is exempt from consent gating since
it is the consent surface itself.
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
scripts-playground Ready Ready Preview, Comment May 8, 2026 5:11am

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 7, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@nuxt/scripts@749

commit: de1c989

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds comprehensive Usercentrics CMP integration: a new useScriptUsercentrics() composable that registers the Usercentrics loader, typed UC_UI interfaces and consent helper (whenReady, onConsentChange, show/accept/deny), valibot schema and registry types, registry metadata and logo, documentation page, playground example pages, E2E tests with fixtures, and a types assertion for the module registry.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: Usercentrics CMP' is concise and clearly describes the main change—adding Usercentrics CMP v3 integration as a new feature.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the Usercentrics CMP v3 integration, schema, usage examples, and test coverage.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/usercentrics-cmp

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
playground/pages/third-parties/usercentrics/nuxt-scripts.vue (1)

20-24: ⚡ Quick win

Guard nested consent access in service mapping.

Line 23 dereferences s.consent.status directly. If a service payload is partial, this can throw and break UI updates; use optional chaining.

Proposed defensive tweak
-      granted: !!s.consent.status,
+      granted: !!s.consent?.status,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@playground/pages/third-parties/usercentrics/nuxt-scripts.vue` around lines 20
- 24, The mapping that sets services.value uses s.consent.status directly which
can throw if the service payload is partial; update the mapping (where
services.value is assigned from window.UC_UI?.getServicesBaseInfo?.()) to guard
nested access by using optional chaining for consent (e.g., replace the use of
s.consent.status with s?.consent?.status) so missing consent objects won't break
the UI when getServicesBaseInfo returns partial entries.
packages/script/src/runtime/registry/usercentrics.ts (1)

103-111: ⚡ Quick win

whenReady() hangs indefinitely if UC_UI_INITIALIZED never fires.

If the Usercentrics script is blocked (adblocker, network failure, CSP) the UC_UI_INITIALIZED event never arrives. The returned Promise never settles, the window listener is never cleaned up, and any await consent.whenReady() call in user code stalls permanently. Consider adding an AbortSignal/timeout path or a rejection fallback.

♻️ Proposed fix: add optional timeout / abort support
-    const whenReady = (): Promise<UsercentricsUI> => new Promise((resolve) => {
+    const whenReady = (signal?: AbortSignal): Promise<UsercentricsUI> => new Promise((resolve, reject) => {
       if (window.UC_UI?.isInitialized?.())
         return resolve(window.UC_UI)
       const onInit = () => {
         window.removeEventListener('UC_UI_INITIALIZED', onInit)
+        signal?.removeEventListener('abort', onAbort)
         resolve(window.UC_UI as UsercentricsUI)
       }
+      const onAbort = () => {
+        window.removeEventListener('UC_UI_INITIALIZED', onInit)
+        reject(signal!.reason ?? new DOMException('whenReady aborted', 'AbortError'))
+      }
       window.addEventListener('UC_UI_INITIALIZED', onInit)
+      signal?.addEventListener('abort', onAbort)
     })

Callers can then pass AbortSignal.timeout(10_000) for a bounded wait.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/script/src/runtime/registry/usercentrics.ts` around lines 103 - 111,
whenReady currently returns a Promise that never settles if the
UC_UI_INITIALIZED event never fires; update whenReady to accept an optional
AbortSignal or timeout parameter and use it to reject the Promise and remove the
UC_UI_INITIALIZED listener when aborted or timed out. Specifically, modify the
whenReady function to: check window.UC_UI as before, attach the onInit listener
via window.addEventListener('UC_UI_INITIALIZED', onInit), and also attach an
abort/timeout handler (or use AbortSignal.timeout) that calls
window.removeEventListener('UC_UI_INITIALIZED', onInit) and rejects the Promise
with a clear error; ensure both paths clean up listeners and return/throw
consistent errors for callers awaiting whenReady or passing an AbortSignal.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/script/src/runtime/registry/usercentrics.ts`:
- Line 87: The current code sets 'data-settings-id' to options.settingsId || ''
which produces a silent empty attribute in production; update the logic that
builds the attribute (the object entry with key 'data-settings-id' referencing
options.settingsId) to perform an explicit runtime guard: if options.settingsId
is missing or empty, throw a clear error (or at minimum omit the
'data-settings-id' attribute) instead of falling back to ''. Implement this
check where the attributes for the Usercentrics script are composed (look for
the object literal containing 'data-settings-id') and use options.settingsId
directly after validating it, e.g. validate typeof and length then either throw
new Error("missing settingsId") or skip adding the 'data-settings-id' key.

---

Nitpick comments:
In `@packages/script/src/runtime/registry/usercentrics.ts`:
- Around line 103-111: whenReady currently returns a Promise that never settles
if the UC_UI_INITIALIZED event never fires; update whenReady to accept an
optional AbortSignal or timeout parameter and use it to reject the Promise and
remove the UC_UI_INITIALIZED listener when aborted or timed out. Specifically,
modify the whenReady function to: check window.UC_UI as before, attach the
onInit listener via window.addEventListener('UC_UI_INITIALIZED', onInit), and
also attach an abort/timeout handler (or use AbortSignal.timeout) that calls
window.removeEventListener('UC_UI_INITIALIZED', onInit) and rejects the Promise
with a clear error; ensure both paths clean up listeners and return/throw
consistent errors for callers awaiting whenReady or passing an AbortSignal.

In `@playground/pages/third-parties/usercentrics/nuxt-scripts.vue`:
- Around line 20-24: The mapping that sets services.value uses s.consent.status
directly which can throw if the service payload is partial; update the mapping
(where services.value is assigned from window.UC_UI?.getServicesBaseInfo?.()) to
guard nested access by using optional chaining for consent (e.g., replace the
use of s.consent.status with s?.consent?.status) so missing consent objects
won't break the UI when getServicesBaseInfo returns partial entries.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cb609490-22c7-4522-a215-d11d31868b5f

📥 Commits

Reviewing files that changed from the base of the PR and between 6ddc9f6 and dfe028e.

📒 Files selected for processing (19)
  • docs/content/scripts/usercentrics.md
  • packages/script/src/registry-logos.ts
  • packages/script/src/registry-types.json
  • packages/script/src/registry.ts
  • packages/script/src/runtime/registry/schemas.ts
  • packages/script/src/runtime/registry/usercentrics.ts
  • packages/script/src/runtime/types.ts
  • packages/script/src/script-meta.ts
  • playground/pages/index.vue
  • playground/pages/third-parties/usercentrics/default.vue
  • playground/pages/third-parties/usercentrics/nuxt-scripts.vue
  • test/e2e/_usercentrics-suite.ts
  • test/e2e/usercentrics.test.ts
  • test/fixtures/usercentrics/app.vue
  • test/fixtures/usercentrics/nuxt.config.ts
  • test/fixtures/usercentrics/package.json
  • test/fixtures/usercentrics/pages/index.vue
  • test/fixtures/usercentrics/tsconfig.json
  • test/types/types.test-d.ts

Comment thread packages/script/src/runtime/registry/usercentrics.ts Outdated
Remove the `|| ''` fallback so the type contract is the single source of
truth, and add optional chaining when reading `s.consent?.status` from
`getServicesBaseInfo()` results.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
playground/pages/third-parties/usercentrics/nuxt-scripts.vue (1)

17-27: ⚡ Quick win

Hydrate services once on ready, not only on consent events.

At Line 18–25, the list updates only after UC_CONSENT. If CMP is already initialized, UI remains empty until user action. Consider a one-time refresh via consent.whenReady() plus reuse in the event handler.

Suggested refactor
 if (import.meta.client) {
-  const off = consent.onConsentChange(() => {
+  const refreshServices = () => {
     lastEventAt.value = new Date().toISOString()
     services.value = (window.UC_UI?.getServicesBaseInfo?.() || []).map(s => ({
       id: s.id,
       name: s.name,
       granted: !!s.consent?.status,
     }))
-  })
+  }
+
+  consent.whenReady().then(refreshServices)
+  const off = consent.onConsentChange(refreshServices)
   onScopeDispose(off)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@playground/pages/third-parties/usercentrics/nuxt-scripts.vue` around lines 17
- 27, The services list is only populated in the consent.onConsentChange
callback so the UI stays empty if the CMP is already ready; extract the update
logic into a small function (e.g., updateServices) that sets lastEventAt.value
and services.value using window.UC_UI?.getServicesBaseInfo?.(), then inside the
import.meta.client block call consent.whenReady().then(updateServices) for a
one-time hydration and also register const off = consent.onConsentChange(() =>
updateServices()) and onScopeDispose(off) to keep the existing event teardown
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/script/src/runtime/registry/usercentrics.ts`:
- Line 12: The UsercentricsService type currently declares consent as required
but code uses s.consent?.status, so change the type for
UsercentricsService.consent to be optional (make consent optional on the
interface/type, e.g., consent?: { status: boolean }) so callers who use
s.consent?.status match the type; update any related type aliases or usages that
reference UsercentricsService.consent to accept the optional shape to prevent
unsafe access.

---

Nitpick comments:
In `@playground/pages/third-parties/usercentrics/nuxt-scripts.vue`:
- Around line 17-27: The services list is only populated in the
consent.onConsentChange callback so the UI stays empty if the CMP is already
ready; extract the update logic into a small function (e.g., updateServices)
that sets lastEventAt.value and services.value using
window.UC_UI?.getServicesBaseInfo?.(), then inside the import.meta.client block
call consent.whenReady().then(updateServices) for a one-time hydration and also
register const off = consent.onConsentChange(() => updateServices()) and
onScopeDispose(off) to keep the existing event teardown behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9081cae1-52e9-4caa-be66-5165cc7cbda1

📥 Commits

Reviewing files that changed from the base of the PR and between da24ce2 and f403674.

📒 Files selected for processing (2)
  • packages/script/src/runtime/registry/usercentrics.ts
  • playground/pages/third-parties/usercentrics/nuxt-scripts.vue

Comment thread packages/script/src/runtime/registry/usercentrics.ts Outdated
Replace env-var skip gating with a Playwright network stub. The real
loader validates settings IDs against the registered origin and refuses
to bootstrap on localhost:<random>, so CI previously skipped the
behavioural test. Stubbing app.usercentrics.eu and injecting a minimal
UC_UI shim via addInitScript lets the UC_CONSENT round-trip assertion
run unconditionally.
…eset-id, __ucCmp)

The original PR targeted the legacy CMP v2 surface (app.usercentrics.eu/browser-ui/<ver>/loader.js
+ data-settings-id + UC_UI). New Usercentrics signups only get v3, so the
integration was unreachable for any modern customer. Verified live against a
real v3 ruleset:

- Loader URL is web.cmp.usercentrics.eu/ui/loader.js (no version segment).
- Required attribute is data-ruleset-id (not data-settings-id).
- Programmatic API is window.__ucCmp (UC_UI is not bound for v3 rulesets we
  observed); methods isInitialized / isConsentRequired / showFirstLayer /
  showSecondLayer / acceptAllConsents / denyAllConsents / getConsentDetails /
  refreshScripts live on its prototype.
- Init event is UC_CMP_API_READY; consent change event is UC_UI_CMP_EVENT
  (with detail.type ∈ ACCEPT_ALL | DENY_ALL | SAVE | …).
- v2-only fields removed: settingsId, version, tcfEnabled, embeddingType
  (TCF / embedding mode now configured server-side in the ruleset).

Schema is now { rulesetId, autoblocker?, language? }. autoblocker injects
web.cmp.usercentrics.eu/modules/autoblocker.js ahead of the loader for
rulesets configured with Auto Blocking. The composable surface exposes
{ ucCmp } in the script result and a typed `consent` helper for
onConsentChange / whenReady / showFirstLayer / showSecondLayer / acceptAll /
denyAll backed by __ucCmp.

Suite stubs the loader and dispatches UC_CMP_API_READY + UC_UI_CMP_EVENT to
keep behavioural tests deterministic on CI; an additional contract test
fetches the live loader and asserts it still references __ucCmp +
UC_CMP_API_READY so a vendor change breaks tests instead of silently
breaking the integration.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/script/src/registry-types.json (1)

980-984: 💤 Low value

Consider narrowing UsercentricsCmpEventDetail.type to a documented union.

The field is currently string, but the JSDoc on UsercentricsConsent.onConsentChange already documents the concrete values callers branch on: 'ACCEPT_ALL' | 'DENY_ALL' | 'SAVE'. Using plain string leaves consumers without autocomplete or exhaustiveness checking on the most important field of the event detail.

♻️ Proposed refinement
-"code": "export interface UsercentricsCmpEventDetail {\n  type: string\n  source?: string\n  [key: string]: any\n}"
+"code": "export interface UsercentricsCmpEventDetail {\n  type: 'ACCEPT_ALL' | 'DENY_ALL' | 'SAVE' | (string & {})\n  source?: string\n  [key: string]: any\n}"

The (string & {}) tail preserves forward compatibility if Usercentrics v3 emits additional event types.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/script/src/registry-types.json` around lines 980 - 984, Update the
UsercentricsCmpEventDetail interface's type property from plain string to a
narrowed union of the documented event literals to enable autocomplete and
exhaustiveness checking; change the signature on the UsercentricsCmpEventDetail
interface (the type field) to "'ACCEPT_ALL' | 'DENY_ALL' | 'SAVE' | (string &
{})" so existing code handles known values but remains forward-compatible with
future event types.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/content/scripts/usercentrics.md`:
- Line 11: Summary: Fix hyphenation of the compound adjective "end-user" in the
docs copy. Replace the phrase "end user consent" with "end-user consent" in the
sentence that currently reads "used to collect, store, and signal end user
consent..." so the text becomes "used to collect, store, and signal end-user
consent..."; ensure only the hyphen is added and no other wording is altered.

---

Nitpick comments:
In `@packages/script/src/registry-types.json`:
- Around line 980-984: Update the UsercentricsCmpEventDetail interface's type
property from plain string to a narrowed union of the documented event literals
to enable autocomplete and exhaustiveness checking; change the signature on the
UsercentricsCmpEventDetail interface (the type field) to "'ACCEPT_ALL' |
'DENY_ALL' | 'SAVE' | (string & {})" so existing code handles known values but
remains forward-compatible with future event types.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0ffef7b9-ce7b-4714-8064-21e62b4aed5a

📥 Commits

Reviewing files that changed from the base of the PR and between 591cb4a and 8d25ad6.

📒 Files selected for processing (11)
  • docs/content/scripts/usercentrics.md
  • packages/script/src/registry-types.json
  • packages/script/src/registry.ts
  • packages/script/src/runtime/registry/schemas.ts
  • packages/script/src/runtime/registry/usercentrics.ts
  • packages/script/src/script-meta.ts
  • playground/pages/third-parties/usercentrics/default.vue
  • playground/pages/third-parties/usercentrics/nuxt-scripts.vue
  • test/e2e/_usercentrics-suite.ts
  • test/e2e/usercentrics.test.ts
  • test/fixtures/usercentrics/nuxt.config.ts
🚧 Files skipped from review as they are similar to previous changes (8)
  • packages/script/src/script-meta.ts
  • packages/script/src/runtime/registry/schemas.ts
  • test/e2e/usercentrics.test.ts
  • playground/pages/third-parties/usercentrics/default.vue
  • packages/script/src/registry.ts
  • test/e2e/_usercentrics-suite.ts
  • test/fixtures/usercentrics/nuxt.config.ts
  • packages/script/src/runtime/registry/usercentrics.ts

Comment thread docs/content/scripts/usercentrics.md Outdated
# Conflicts:
#	package.json
#	playground/pages/index.vue
@harlan-zw harlan-zw merged commit d2114c5 into main May 8, 2026
19 checks passed
@harlan-zw harlan-zw deleted the feat/usercentrics-cmp branch May 8, 2026 05:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant