@c15t/scripts 3.0.0-alpha.2 → 3.0.0-alpha.4
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.
- package/AGENTS.md +129 -63
- package/README.md +8 -29
- package/SKILL.md +33 -0
- package/dist/adobe-analytics.js +2 -0
- package/dist/ahrefs-analytics.js +2 -0
- package/dist/amplitude.js +2 -0
- package/dist/clearbit.js +2 -0
- package/dist/cloudflare-web-analytics.js +2 -0
- package/dist/cloudflare-zaraz.js +2 -0
- package/dist/crisp.js +2 -0
- package/dist/databuddy.js +2 -0
- package/dist/e2e-test-utils.js +2 -139
- package/dist/engine/compile.js +2 -89
- package/dist/engine/runtime.js +2 -448
- package/dist/events.js +2 -218
- package/dist/fathom-analytics.js +2 -0
- package/dist/front-chat.js +2 -0
- package/dist/google-tag-manager.js +2 -0
- package/dist/google-tag.js +2 -0
- package/dist/heap.js +2 -0
- package/dist/hightouch.js +2 -0
- package/dist/hotjar.js +2 -0
- package/dist/intercom.js +2 -0
- package/dist/klaviyo.js +2 -0
- package/dist/linkedin-insights.js +2 -0
- package/dist/logrocket.js +2 -0
- package/dist/matomo-analytics.js +2 -0
- package/dist/meta-pixel.js +2 -0
- package/dist/microsoft-clarity.js +2 -0
- package/dist/microsoft-uet.js +2 -0
- package/dist/mixpanel-analytics.js +2 -0
- package/dist/one-dollar-stats.js +2 -0
- package/dist/openai-pixel.js +2 -0
- package/dist/pinterest-tag.js +2 -0
- package/dist/pirsch.js +2 -0
- package/dist/plausible-analytics.js +2 -0
- package/dist/posthog.js +2 -0
- package/dist/promptwatch.js +2 -0
- package/dist/reddit-pixel.js +2 -0
- package/dist/registry.js +2 -422
- package/dist/resolve.js +2 -33
- package/dist/rudderstack.js +2 -0
- package/dist/rybbit-analytics.js +2 -0
- package/dist/segment.js +2 -0
- package/dist/snapchat-pixel.js +2 -0
- package/dist/tiktok-pixel.js +2 -0
- package/dist/types.js +2 -16
- package/dist/umami-analytics.js +2 -0
- package/dist/vendors/_shared/attributes.js +2 -14
- package/dist/vendors/_shared/google-consent.js +2 -27
- package/dist/vendors/_shared/install-builders.js +2 -21
- package/dist/vendors/_shared/required-id.js +2 -0
- package/dist/vendors/_shared/script-url.js +2 -28
- package/dist/vendors/ads-and-pixels/linkedin-insights.js +2 -48
- package/dist/vendors/ads-and-pixels/meta-pixel.js +2 -153
- package/dist/vendors/ads-and-pixels/microsoft-uet.js +2 -110
- package/dist/vendors/ads-and-pixels/openai-pixel.js +2 -88
- package/dist/vendors/ads-and-pixels/pinterest-tag.js +2 -123
- package/dist/vendors/ads-and-pixels/reddit-pixel.js +2 -107
- package/dist/vendors/ads-and-pixels/snapchat-pixel.js +2 -87
- package/dist/vendors/ads-and-pixels/tiktok-pixel.js +2 -89
- package/dist/vendors/ads-and-pixels/x-pixel.js +2 -48
- package/dist/vendors/analytics/adobe-analytics.js +2 -49
- package/dist/vendors/analytics/ahrefs-analytics.js +2 -27
- package/dist/vendors/analytics/amplitude.js +2 -134
- package/dist/vendors/analytics/clearbit.js +2 -28
- package/dist/vendors/analytics/cloudflare-web-analytics.js +2 -32
- package/dist/vendors/analytics/databuddy.js +2 -103
- package/dist/vendors/analytics/fathom-analytics.js +2 -35
- package/dist/vendors/analytics/google-tag.js +2 -78
- package/dist/vendors/analytics/heap.js +2 -134
- package/dist/vendors/analytics/hightouch.js +2 -109
- package/dist/vendors/analytics/hotjar.js +2 -44
- package/dist/vendors/analytics/logrocket.js +2 -58
- package/dist/vendors/analytics/matomo-analytics.js +2 -191
- package/dist/vendors/analytics/microsoft-clarity.js +2 -100
- package/dist/vendors/analytics/mixpanel-analytics.js +2 -93
- package/dist/vendors/analytics/one-dollar-stats.js +2 -30
- package/dist/vendors/analytics/pirsch.js +2 -67
- package/dist/vendors/analytics/plausible-analytics.js +2 -81
- package/dist/vendors/analytics/posthog.js +2 -200
- package/dist/vendors/analytics/promptwatch.js +2 -29
- package/dist/vendors/analytics/rudderstack.js +2 -183
- package/dist/vendors/analytics/rybbit-analytics.js +2 -63
- package/dist/vendors/analytics/segment.js +2 -65
- package/dist/vendors/analytics/umami-analytics.js +2 -39
- package/dist/vendors/analytics/vercel-analytics.js +2 -53
- package/dist/vendors/email-and-sms/klaviyo.js +2 -0
- package/dist/vendors/functional/crisp.js +2 -100
- package/dist/vendors/functional/front-chat.js +2 -64
- package/dist/vendors/functional/intercom.js +2 -45
- package/dist/vendors/tag-managers/cloudflare-zaraz.js +2 -98
- package/dist/vendors/tag-managers/google-tag-manager.js +2 -73
- package/dist/vercel-analytics.js +2 -0
- package/dist/x-pixel.js +2 -0
- package/dist-types/adobe-analytics.d.ts +2 -0
- package/dist-types/ahrefs-analytics.d.ts +2 -0
- package/dist-types/amplitude.d.ts +2 -0
- package/dist-types/clearbit.d.ts +2 -0
- package/dist-types/cloudflare-web-analytics.d.ts +2 -0
- package/dist-types/cloudflare-zaraz.d.ts +2 -0
- package/dist-types/crisp.d.ts +2 -0
- package/dist-types/databuddy.d.ts +2 -0
- package/dist-types/e2e-test-utils.d.ts +2 -0
- package/dist-types/engine/compile.d.ts +2 -3
- package/dist-types/engine/runtime.d.ts +2 -3
- package/dist-types/events.d.ts +2 -46
- package/dist-types/fathom-analytics.d.ts +2 -0
- package/dist-types/front-chat.d.ts +2 -0
- package/dist-types/google-tag-manager.d.ts +2 -0
- package/dist-types/google-tag.d.ts +2 -0
- package/dist-types/heap.d.ts +2 -0
- package/dist-types/hightouch.d.ts +2 -0
- package/dist-types/hotjar.d.ts +2 -0
- package/dist-types/intercom.d.ts +2 -0
- package/dist-types/klaviyo.d.ts +2 -0
- package/dist-types/linkedin-insights.d.ts +2 -0
- package/dist-types/logrocket.d.ts +2 -0
- package/dist-types/matomo-analytics.d.ts +2 -0
- package/dist-types/meta-pixel.d.ts +2 -0
- package/dist-types/microsoft-clarity.d.ts +2 -0
- package/dist-types/microsoft-uet.d.ts +2 -0
- package/dist-types/mixpanel-analytics.d.ts +2 -0
- package/dist-types/one-dollar-stats.d.ts +2 -0
- package/dist-types/openai-pixel.d.ts +2 -0
- package/dist-types/pinterest-tag.d.ts +2 -0
- package/dist-types/pirsch.d.ts +2 -0
- package/dist-types/plausible-analytics.d.ts +2 -0
- package/dist-types/posthog.d.ts +2 -0
- package/dist-types/promptwatch.d.ts +2 -0
- package/dist-types/reddit-pixel.d.ts +2 -0
- package/dist-types/registry.d.ts +2 -485
- package/dist-types/resolve.d.ts +2 -9
- package/dist-types/rudderstack.d.ts +2 -0
- package/dist-types/rybbit-analytics.d.ts +2 -0
- package/dist-types/segment.d.ts +2 -0
- package/dist-types/snapchat-pixel.d.ts +2 -0
- package/dist-types/tiktok-pixel.d.ts +2 -0
- package/dist-types/types.d.ts +2 -314
- package/dist-types/umami-analytics.d.ts +2 -0
- package/dist-types/vendors/_shared/attributes.d.ts +2 -35
- package/dist-types/vendors/_shared/google-consent.d.ts +2 -47
- package/dist-types/vendors/_shared/install-builders.d.ts +2 -30
- package/dist-types/vendors/_shared/required-id.d.ts +2 -0
- package/dist-types/vendors/_shared/script-url.d.ts +2 -75
- package/dist-types/vendors/ads-and-pixels/linkedin-insights.d.ts +2 -92
- package/dist-types/vendors/ads-and-pixels/meta-pixel.d.ts +2 -289
- package/dist-types/vendors/ads-and-pixels/microsoft-uet.d.ts +2 -105
- package/dist-types/vendors/ads-and-pixels/openai-pixel.d.ts +2 -211
- package/dist-types/vendors/ads-and-pixels/pinterest-tag.d.ts +2 -295
- package/dist-types/vendors/ads-and-pixels/reddit-pixel.d.ts +2 -210
- package/dist-types/vendors/ads-and-pixels/snapchat-pixel.d.ts +2 -171
- package/dist-types/vendors/ads-and-pixels/tiktok-pixel.d.ts +2 -106
- package/dist-types/vendors/ads-and-pixels/x-pixel.d.ts +2 -183
- package/dist-types/vendors/analytics/adobe-analytics.d.ts +2 -75
- package/dist-types/vendors/analytics/ahrefs-analytics.d.ts +2 -62
- package/dist-types/vendors/analytics/amplitude.d.ts +2 -234
- package/dist-types/vendors/analytics/clearbit.d.ts +2 -60
- package/dist-types/vendors/analytics/cloudflare-web-analytics.d.ts +2 -67
- package/dist-types/vendors/analytics/databuddy.d.ts +2 -147
- package/dist-types/vendors/analytics/fathom-analytics.d.ts +2 -90
- package/dist-types/vendors/analytics/google-tag.d.ts +2 -95
- package/dist-types/vendors/analytics/heap.d.ts +2 -316
- package/dist-types/vendors/analytics/hightouch.d.ts +2 -285
- package/dist-types/vendors/analytics/hotjar.d.ts +2 -73
- package/dist-types/vendors/analytics/logrocket.d.ts +2 -101
- package/dist-types/vendors/analytics/matomo-analytics.d.ts +2 -41
- package/dist-types/vendors/analytics/microsoft-clarity.d.ts +2 -97
- package/dist-types/vendors/analytics/mixpanel-analytics.d.ts +2 -113
- package/dist-types/vendors/analytics/one-dollar-stats.d.ts +2 -39
- package/dist-types/vendors/analytics/pirsch.d.ts +2 -96
- package/dist-types/vendors/analytics/plausible-analytics.d.ts +2 -122
- package/dist-types/vendors/analytics/posthog.d.ts +2 -175
- package/dist-types/vendors/analytics/promptwatch.d.ts +2 -36
- package/dist-types/vendors/analytics/rudderstack.d.ts +2 -330
- package/dist-types/vendors/analytics/rybbit-analytics.d.ts +2 -82
- package/dist-types/vendors/analytics/segment.d.ts +2 -164
- package/dist-types/vendors/analytics/umami-analytics.d.ts +2 -93
- package/dist-types/vendors/analytics/vercel-analytics.d.ts +2 -66
- package/dist-types/vendors/email-and-sms/klaviyo.d.ts +2 -0
- package/dist-types/vendors/functional/crisp.d.ts +2 -78
- package/dist-types/vendors/functional/front-chat.d.ts +2 -62
- package/dist-types/vendors/functional/intercom.d.ts +2 -135
- package/dist-types/vendors/tag-managers/cloudflare-zaraz.d.ts +2 -39
- package/dist-types/vendors/tag-managers/google-tag-manager.d.ts +2 -96
- package/dist-types/vercel-analytics.d.ts +2 -0
- package/dist-types/x-pixel.d.ts +2 -0
- package/docs/README.md +129 -63
- package/docs/assets/v3/bottom-bar.png +0 -0
- package/docs/assets/v3/brand-card.png +0 -0
- package/docs/assets/v3/brand-preferences.png +0 -0
- package/docs/assets/v3/choice-wall.png +0 -0
- package/docs/assets/v3/headless-bar-html.png +0 -0
- package/docs/assets/v3/headless-bar-mobile.png +0 -0
- package/docs/assets/v3/headless-bar.png +0 -0
- package/docs/assets/v3/slim-bar.png +0 -0
- package/docs/concepts/choose-your-setup.md +87 -0
- package/docs/concepts/consent-categories.md +84 -0
- package/docs/{guides → concepts}/consent-state.md +89 -105
- package/docs/{guides → concepts}/data-fetching.md +31 -27
- package/docs/concepts/how-consent-works.md +123 -0
- package/docs/concepts/policies.md +71 -0
- package/docs/customization/class-names.md +202 -0
- package/docs/customization/dark-mode.md +157 -0
- package/docs/customization/motion.md +119 -0
- package/docs/customization/overview.md +67 -34
- package/docs/customization/recipes.md +839 -49
- package/docs/customization/slots.md +216 -35
- package/docs/customization/stylesheets.md +147 -0
- package/docs/customization/tailwind.md +842 -0
- package/docs/customization/tokens.md +163 -96
- package/docs/customization/translations.md +60 -3
- package/docs/frameworks/astro/embeds.md +160 -0
- package/docs/frameworks/astro/network-blocker.md +86 -0
- package/docs/frameworks/astro/scripts.md +155 -0
- package/docs/frameworks/html/embeds.md +142 -0
- package/docs/frameworks/html/network-blocker.md +105 -0
- package/docs/frameworks/html/scripts.md +164 -0
- package/docs/frameworks/javascript/scripts.md +137 -0
- package/docs/frameworks/next/embeds.md +90 -0
- package/docs/frameworks/next/network-blocker.md +153 -0
- package/docs/frameworks/next/scripts.md +196 -0
- package/docs/frameworks/nuxt/embeds.md +81 -0
- package/docs/frameworks/nuxt/network-blocker.md +97 -0
- package/docs/frameworks/nuxt/scripts.md +89 -0
- package/docs/frameworks/react/embeds.md +89 -0
- package/docs/frameworks/react/network-blocker.md +140 -0
- package/docs/frameworks/react/scripts.md +115 -0
- package/docs/frameworks/svelte/embeds.md +96 -0
- package/docs/frameworks/svelte/network-blocker.md +141 -0
- package/docs/frameworks/svelte/scripts.md +144 -0
- package/docs/frameworks/sveltekit/embeds.md +103 -0
- package/docs/frameworks/sveltekit/network-blocker.md +159 -0
- package/docs/frameworks/sveltekit/scripts.md +172 -0
- package/docs/frameworks/tanstack-start/embeds.md +96 -0
- package/docs/frameworks/tanstack-start/network-blocker.md +145 -0
- package/docs/frameworks/tanstack-start/scripts.md +103 -0
- package/docs/frameworks/vue/embeds.md +84 -0
- package/docs/frameworks/vue/network-blocker.md +99 -0
- package/docs/frameworks/vue/scripts.md +93 -0
- package/docs/guides/banner-experiments.md +654 -0
- package/docs/guides/troubleshooting.md +120 -47
- package/docs/guides/verify-consent.md +81 -49
- package/docs/integrations/adobe-analytics.md +167 -159
- package/docs/integrations/ahrefs-analytics.md +152 -154
- package/docs/integrations/amplitude.md +162 -156
- package/docs/integrations/building-integrations.md +136 -37
- package/docs/integrations/clearbit.md +154 -154
- package/docs/integrations/cloudflare-web-analytics.md +156 -156
- package/docs/integrations/cloudflare-zaraz.md +209 -261
- package/docs/integrations/crisp.md +164 -158
- package/docs/integrations/databuddy.md +157 -173
- package/docs/integrations/fathom-analytics.md +158 -156
- package/docs/integrations/front-chat.md +167 -167
- package/docs/integrations/google-maps.md +118 -83
- package/docs/integrations/google-tag-manager.md +178 -163
- package/docs/integrations/google-tag.md +163 -160
- package/docs/integrations/heap.md +163 -155
- package/docs/integrations/hightouch.md +161 -157
- package/docs/integrations/hotjar.md +159 -155
- package/docs/integrations/intercom.md +183 -153
- package/docs/integrations/klaviyo.md +486 -0
- package/docs/integrations/linkedin-insights.md +174 -150
- package/docs/integrations/logrocket.md +160 -156
- package/docs/integrations/matomo-analytics.md +188 -178
- package/docs/integrations/meta-pixel.md +188 -150
- package/docs/integrations/microsoft-clarity.md +163 -155
- package/docs/integrations/microsoft-uet.md +148 -154
- package/docs/integrations/mixpanel-analytics.md +155 -160
- package/docs/integrations/one-dollar-stats.md +166 -165
- package/docs/integrations/openai-pixel.md +204 -301
- package/docs/integrations/overview.md +137 -80
- package/docs/integrations/pinterest-tag.md +191 -183
- package/docs/integrations/pirsch.md +169 -159
- package/docs/integrations/plausible-analytics.md +172 -158
- package/docs/integrations/posthog.md +313 -240
- package/docs/integrations/promptwatch.md +154 -154
- package/docs/integrations/reddit-pixel.md +185 -157
- package/docs/integrations/rudderstack.md +201 -186
- package/docs/integrations/rybbit-analytics.md +171 -160
- package/docs/integrations/segment.md +182 -154
- package/docs/integrations/snapchat-pixel.md +186 -156
- package/docs/integrations/tiktok-pixel.md +171 -150
- package/docs/integrations/umami-analytics.md +163 -158
- package/docs/integrations/vercel-analytics.md +166 -157
- package/docs/integrations/x-pixel.md +176 -150
- package/docs/integrations/youtube.md +121 -86
- package/docs/upgrade-v3.md +496 -467
- package/package.json +10 -257
- package/dist-types/__tests__/helpers.d.ts +0 -141
- package/docs/assets/v3/brand-bar.png +0 -0
- package/docs/assets/v3/mobile-card.png +0 -0
- package/docs/assets/v3/preferences.png +0 -0
- package/docs/frameworks/javascript/script-loader.md +0 -100
- package/docs/frameworks/next/script-loader.md +0 -216
- package/docs/frameworks/react/script-loader.md +0 -69
- package/docs/guides/deployment-modes.md +0 -75
- package/docs/guides/shared-consent-controls.md +0 -158
- package/docs/integrations/clear-on-revocation.md +0 -167
- package/docs/integrations/granular-consent.md +0 -210
package/docs/upgrade-v3.md
CHANGED
|
@@ -1,509 +1,538 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
3
|
-
description:
|
|
4
|
-
|
|
2
|
+
title: Migrate to v3
|
|
3
|
+
description: Upgrade a c15t v2 app to v3. Covers packages, the Next.js and React
|
|
4
|
+
providers, the JavaScript runtime, custom UI built on useConsentManager,
|
|
5
|
+
callbacks, policies, stored consent and a self-hosted backend.
|
|
5
6
|
group: reference
|
|
6
7
|
---
|
|
7
8
|
|
|
8
|
-
##
|
|
9
|
+
## What changes in v3
|
|
10
|
+
|
|
11
|
+
* One package, `c15t`, replaces `@c15t/nextjs`, `@c15t/react` and the v2
|
|
12
|
+
`c15t` store. Import from its subpaths: `c15t/next`, `c15t/react`, and `c15t`
|
|
13
|
+
for the headless engine.
|
|
14
|
+
* The vendor helpers move from `@c15t/scripts` to `@c15t/integrations`, with
|
|
15
|
+
the same subpaths and helper names.
|
|
16
|
+
* `ConsentManagerProvider` becomes `ConsentProvider` in React. Next.js apps
|
|
17
|
+
that resolve consent on the server use `ConsentRoot`.
|
|
18
|
+
* `mode` and `backendURL` become one transport, `hosted({ url })` or
|
|
19
|
+
`offline()`.
|
|
20
|
+
* Policy packs become policy rules. You set them in your Inth project, in a
|
|
21
|
+
self-hosted backend's `manifest.policyRules`, or in `offline({ policyRules })`.
|
|
22
|
+
* `useConsentManager()` is gone. Each field has its own hook, and a codemod
|
|
23
|
+
rewrites most calls.
|
|
24
|
+
* Callbacks have new names, and each reports either a recorded choice or a
|
|
25
|
+
permission change.
|
|
26
|
+
* Visitors' existing choices keep working. v3 reads the v2 cookie.
|
|
27
|
+
* A self-hosted backend takes `database` instead of `adapter`, and needs a
|
|
28
|
+
schema migration.
|
|
29
|
+
* `@c15t/node-sdk` has a new client, `createC15tClient()`. Its methods return
|
|
30
|
+
results instead of throwing, and it reads no environment variables.
|
|
31
|
+
|
|
32
|
+
## Upgrade in this order
|
|
33
|
+
|
|
34
|
+
1. Upgrade React and React DOM to 18 or newer. The v3 React and Next.js
|
|
35
|
+
adapters require them, and `c15t/next` requires Next.js 15 or 16.
|
|
36
|
+
2. [Replace the packages](#replace-the-packages), including the
|
|
37
|
+
[integrations dependency](#rename-the-integrations-dependency).
|
|
38
|
+
3. Run the [`useConsentManager()` codemod](#replace-useconsentmanager) if your
|
|
39
|
+
code calls it.
|
|
40
|
+
4. Replace the provider for your framework: [Next.js](#nextjs-with-consentmanagerprovider),
|
|
41
|
+
[React](#react-with-consentmanagerprovider) or [JavaScript](#javascript-with-getorcreateconsentruntime).
|
|
42
|
+
5. Update [callbacks](#replace-callbacks), [policies](#move-policy-packs-to-policy-rules)
|
|
43
|
+
and [other options](#rename-options-and-components).
|
|
44
|
+
6. If you self-host, [upgrade the backend](#upgrade-a-self-hosted-backend) in the
|
|
45
|
+
same release as the clients.
|
|
46
|
+
7. If server code calls the API, [update the Node.js SDK](#update-the-nodejs-sdk).
|
|
47
|
+
8. [Check the result](#check-the-migration).
|
|
48
|
+
|
|
49
|
+
## Replace the packages
|
|
50
|
+
|
|
51
|
+
Remove `@c15t/nextjs` and `@c15t/react`, then install `c15t` from the `alpha`
|
|
52
|
+
dist-tag. npm's default tag still resolves v2.
|
|
53
|
+
|
|
54
|
+
| Package manager | Command |
|
|
55
|
+
| :-------------- | :------------------------------------------------ |
|
|
56
|
+
| npm | `npm install c15t@alpha @c15t/integrations@alpha` |
|
|
57
|
+
| pnpm | `pnpm add c15t@alpha @c15t/integrations@alpha` |
|
|
58
|
+
| yarn | `yarn add c15t@alpha @c15t/integrations@alpha` |
|
|
59
|
+
| bun | `bun add c15t@alpha @c15t/integrations@alpha` |
|
|
60
|
+
|
|
61
|
+
Drop `@c15t/integrations@alpha` if you do not use its vendor helpers.
|
|
62
|
+
|
|
63
|
+
| v2 import | v3 import |
|
|
64
|
+
| -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
65
|
+
| `@c15t/nextjs` | `c15t/next`. Server helpers are in `c15t/next/server`, `c15t/next/pages` and `c15t/next/api`. |
|
|
66
|
+
| `@c15t/react` | `c15t/react` |
|
|
67
|
+
| `@c15t/react/headless` | `c15t/react/headless` |
|
|
68
|
+
| `@c15t/nextjs/styles.css` | `c15t/next/styles.css` |
|
|
69
|
+
| `@c15t/react/styles.css` | `c15t/react/styles.css` |
|
|
70
|
+
| `c15t` (`getOrCreateConsentRuntime` and the store) | `c15t` for the engine and `c15t/runtime` for a managed runtime. The APIs are new; see [JavaScript](#javascript-with-getorcreateconsentruntime). |
|
|
71
|
+
| `DevTools` from `@c15t/dev-tools/react` | `DevTools` from `c15t/react/devtools` or `c15t/next/devtools` |
|
|
72
|
+
| `@c15t/scripts/*` | `@c15t/integrations/*`, with unchanged helper names. See [rename the integrations dependency](#rename-the-integrations-dependency). |
|
|
73
|
+
|
|
74
|
+
The scoped packages `@c15t/nextjs`, `@c15t/react` and `@c15t/core` still exist
|
|
75
|
+
at v3, so imports from them keep working if you pin them to `@alpha`. The docs
|
|
76
|
+
use the `c15t` subpaths.
|
|
77
|
+
|
|
78
|
+
## Rename the integrations dependency
|
|
79
|
+
|
|
80
|
+
v3 renames `@c15t/scripts` to `@c15t/integrations`. Remove `@c15t/scripts`
|
|
81
|
+
from your dependencies and install `@c15t/integrations` from the `alpha`
|
|
82
|
+
dist-tag:
|
|
83
|
+
|
|
84
|
+
| Package manager | Command |
|
|
85
|
+
| :-------------- | :------------------------------------- |
|
|
86
|
+
| npm | `npm install @c15t/integrations@alpha` |
|
|
87
|
+
| pnpm | `pnpm add @c15t/integrations@alpha` |
|
|
88
|
+
| yarn | `yarn add @c15t/integrations@alpha` |
|
|
89
|
+
| bun | `bun add @c15t/integrations@alpha` |
|
|
90
|
+
|
|
91
|
+
Replace the package name in each import. Vendor subpaths and helper names stay
|
|
92
|
+
the same.
|
|
9
93
|
|
|
10
|
-
|
|
11
|
-
Upgrade both packages together before installing v3. Earlier alpha peer ranges
|
|
12
|
-
incorrectly allowed React 16 and 17 even though v3 already uses `useId` and
|
|
13
|
-
`useSyncExternalStore`, which those versions do not provide.
|
|
14
|
-
|
|
15
|
-
## Start with a policy rule
|
|
94
|
+
Before, in v2 and earlier v3 alphas:
|
|
16
95
|
|
|
17
96
|
```ts
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
const mode = offline({
|
|
22
|
-
policyRules: [policyRulePresets.europeOptIn()],
|
|
23
|
-
});
|
|
97
|
+
import { createEventDispatcher } from '@c15t/scripts/events';
|
|
98
|
+
import { posthog } from '@c15t/scripts/posthog';
|
|
24
99
|
```
|
|
25
100
|
|
|
26
|
-
|
|
27
|
-
`policyRules` on the backend and use `hosted({ url })` in the provider. Follow the
|
|
28
|
-
[React quickstart](https://c15t.com/docs/frameworks/react/quickstart),
|
|
29
|
-
[Next.js quickstart](https://c15t.com/docs/frameworks/next/quickstart), or
|
|
30
|
-
[JavaScript quickstart](https://c15t.com/docs/frameworks/javascript/quickstart) for a complete
|
|
31
|
-
integration.
|
|
101
|
+
After:
|
|
32
102
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
103
|
+
```ts
|
|
104
|
+
import { createEventDispatcher } from '@c15t/integrations/events';
|
|
105
|
+
import { posthog } from '@c15t/integrations/posthog';
|
|
106
|
+
```
|
|
36
107
|
|
|
37
|
-
|
|
108
|
+
The `scripts` configuration option and the `Script` type keep their names.
|
|
109
|
+
`@c15t/scripts` stays available as a deprecated compatibility package for all
|
|
110
|
+
of v3. It re-exports the implementation and types of `@c15t/integrations`, so
|
|
111
|
+
you can migrate imports separately from the rest of the upgrade. Compatibility
|
|
112
|
+
ends in v4; versions already published stay on npm.
|
|
38
113
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
{
|
|
44
|
-
id: 'default-opt-in',
|
|
45
|
-
match: { fallback: true },
|
|
46
|
-
model: 'opt-in',
|
|
47
|
-
prompt: 'choice',
|
|
48
|
-
categories: ['measurement', 'marketing'],
|
|
49
|
-
scopeMode: 'strict',
|
|
50
|
-
},
|
|
51
|
-
] satisfies PolicyRule[];
|
|
114
|
+
To preview the import changes in JavaScript and TypeScript files:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npx @c15t/cli@alpha codemods scripts-to-integrations --dry-run --json
|
|
52
118
|
```
|
|
53
119
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
no rights, and renders no consent UI. v2's `none` model maps to it directly.
|
|
59
|
-
|
|
60
|
-
When `categories` selects only some optional categories, you must set
|
|
61
|
-
`scopeMode` explicitly. A strict scope blocks categories outside the rule. A permissive scope allows
|
|
62
|
-
those categories unless another restriction applies. An omitted scope, `['*']`,
|
|
63
|
-
or a list containing only `necessary` expands to the default optional categories.
|
|
64
|
-
`necessary` is always permitted.
|
|
65
|
-
|
|
66
|
-
`offline()` without `policyRules` resolves `recommendedPolicyRules()`, whose
|
|
67
|
-
Europe rule also matches a visitor with no country. A known US country with a
|
|
68
|
-
missing state uses US opt-out with GPC and persistent preferences; a missing
|
|
69
|
-
Canadian province stays strict opt-in. The last rule is `none` for other known
|
|
70
|
-
unmatched locations. Resolution exposes `matched`, `no-match`,
|
|
71
|
-
`unconfigured`, or `failed`; while nothing has matched, optional categories stay
|
|
72
|
-
denied and no consent surface renders. A missing or malformed policy never grants
|
|
73
|
-
optional permissions by itself.
|
|
74
|
-
|
|
75
|
-
## Read the state you need
|
|
76
|
-
|
|
77
|
-
| Purpose | Snapshot field | React hook |
|
|
78
|
-
| ----------------------------------------------- | ---------------------- | --------------------------------------- |
|
|
79
|
-
| Gate scripts and optional features | `effectivePermissions` | `useConsent(category)`, `useConsents()` |
|
|
80
|
-
| Inspect recorded choices and confirmation times | `explicitChoice` | `useExplicitChoice()` |
|
|
81
|
-
| Decide whether to prompt | `promptRequirement` | `usePromptRequirement()` |
|
|
82
|
-
| Inspect the resolved rule | `policyRule` | `usePolicyRule()` |
|
|
83
|
-
| Inspect matching or failure | `resolution` | `usePolicyResolution()` |
|
|
84
|
-
|
|
85
|
-
An effective permission is not evidence of a grant. Under an opt-out rule it can
|
|
86
|
-
be true before a visitor acts. A notice dismissal updates `noticeDismissal` and
|
|
87
|
-
does not record consent. Global Privacy Control updates privacy signals and
|
|
88
|
-
configured opt-out directives without turning a browser signal into a choice.
|
|
120
|
+
Review the output, then run it again without `--dry-run`. The codemod runs
|
|
121
|
+
only when you name it. It does not change `package.json`, lockfiles, or
|
|
122
|
+
imports inside `.vue`, `.svelte` or `.astro` files; update those by hand, then
|
|
123
|
+
reinstall dependencies and build the app.
|
|
89
124
|
|
|
90
125
|
## Replace `useConsentManager()`
|
|
91
126
|
|
|
92
|
-
`useConsentManager()`
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
change, including changes to categories it never read. Call one hook per field
|
|
96
|
-
instead; each re-renders only when its own value changes.
|
|
127
|
+
`useConsentManager()` returned the whole consent state, so every component
|
|
128
|
+
that called it re-rendered on every change. v3 has one hook per field. Run the
|
|
129
|
+
codemod first:
|
|
97
130
|
|
|
98
|
-
|
|
131
|
+
```bash
|
|
132
|
+
npx @c15t/cli@alpha codemods use-consent-manager-to-hooks --dry-run --json
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Review the proposed files, then run it again without `--dry-run`. For this v2
|
|
136
|
+
component:
|
|
99
137
|
|
|
100
|
-
```tsx title="components/
|
|
101
|
-
import { useConsentManager } from 'c15t/react';
|
|
138
|
+
```tsx title="Before (v2): components/accept-button.tsx"
|
|
139
|
+
import { useConsentManager } from '@c15t/react';
|
|
102
140
|
|
|
103
|
-
export function
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
141
|
+
export function AcceptButton() {
|
|
142
|
+
const { activeUI, has, saveConsents } = useConsentManager();
|
|
143
|
+
if (activeUI !== 'banner' || has('marketing')) return null;
|
|
144
|
+
return (
|
|
145
|
+
<button type="button" onClick={() => void saveConsents('all')}>
|
|
146
|
+
Accept
|
|
147
|
+
</button>
|
|
148
|
+
);
|
|
109
149
|
}
|
|
110
150
|
```
|
|
111
151
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
```tsx title="components/
|
|
115
|
-
import { useActiveUI, useConsent } from 'c15t/react';
|
|
116
|
-
import { useHeadlessConsentUI } from 'c15t/react/headless';
|
|
117
|
-
|
|
118
|
-
export function
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
152
|
+
the codemod writes:
|
|
153
|
+
|
|
154
|
+
```tsx title="After (v3): components/accept-button.tsx"
|
|
155
|
+
import { useActiveUI, useConsent } from '@c15t/react';
|
|
156
|
+
import { useHeadlessConsentUI } from '@c15t/react/headless';
|
|
157
|
+
|
|
158
|
+
export function AcceptButton() {
|
|
159
|
+
const activeUI = useActiveUI() ?? 'none';
|
|
160
|
+
const hasMarketing = useConsent('marketing');
|
|
161
|
+
const { saveCustomPreferences: saveConsents } = useHeadlessConsentUI();
|
|
162
|
+
if (activeUI !== 'banner' || hasMarketing) return null;
|
|
163
|
+
return (
|
|
164
|
+
<button type="button" onClick={() => void saveConsents('all')}>
|
|
165
|
+
Accept
|
|
166
|
+
</button>
|
|
167
|
+
);
|
|
126
168
|
}
|
|
127
169
|
```
|
|
128
170
|
|
|
129
|
-
|
|
130
|
-
`c15t/
|
|
131
|
-
`
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
|
137
|
-
|
|
|
138
|
-
| `
|
|
139
|
-
| `
|
|
140
|
-
| `
|
|
141
|
-
| `
|
|
142
|
-
| `
|
|
143
|
-
| `
|
|
144
|
-
| `
|
|
145
|
-
| `
|
|
146
|
-
| `
|
|
147
|
-
| `
|
|
148
|
-
| `
|
|
149
|
-
| `
|
|
150
|
-
| `
|
|
151
|
-
| `
|
|
152
|
-
| `
|
|
153
|
-
| `
|
|
154
|
-
| `
|
|
155
|
-
| `
|
|
156
|
-
| `
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
| `
|
|
160
|
-
| `
|
|
161
|
-
| `
|
|
162
|
-
| `
|
|
163
|
-
| `
|
|
164
|
-
| `
|
|
165
|
-
| `
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
`
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
The CLI rewrites the common destructuring forms for you:
|
|
171
|
+
The codemod keeps the entry you imported from. Change `@c15t/react` to
|
|
172
|
+
`c15t/react` afterwards if you moved to the umbrella package. Fields it cannot
|
|
173
|
+
rewrite stay on a `useConsentManager()` call under a `TODO(c15t v3)` comment,
|
|
174
|
+
which fails the build until you replace them. The table lists every v2 field.
|
|
175
|
+
Import hooks from `c15t/react`, `c15t/next` or `c15t/tanstack-start`, and
|
|
176
|
+
`useHeadlessConsentUI` from the matching `/headless` entry.
|
|
177
|
+
|
|
178
|
+
| v2 field | v3 replacement |
|
|
179
|
+
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
|
|
180
|
+
| `activeUI` | `useActiveUI()`. It returns `null` until c15t picks a surface, where v2 returned `'none'`. |
|
|
181
|
+
| `setActiveUI(ui)` | `useSetActiveUI()` |
|
|
182
|
+
| `has(category)` | `useConsent(category)`, one call per category at the top of the component |
|
|
183
|
+
| `consents` | `useConsents()` |
|
|
184
|
+
| `saveConsents('all')` | `useHeadlessConsentUI().saveCustomPreferences('all')` |
|
|
185
|
+
| `saveConsents('necessary')` | `useHeadlessConsentUI().saveCustomPreferences('none')` |
|
|
186
|
+
| `saveConsents('custom')` | `useHeadlessConsentUI().saveCustomPreferences()`, which saves the draft |
|
|
187
|
+
| `selectedConsents` | `useConsentDraft().values` |
|
|
188
|
+
| `setSelectedConsent(name, value)` | `useConsentDraft().set(name, value)` |
|
|
189
|
+
| `setConsent(name, value)` | `useSaveConsents()`, called with `{ [name]: value }` |
|
|
190
|
+
| `consentInfo` | `useExplicitChoice()` |
|
|
191
|
+
| `hasConsented()` | `useExplicitChoice() !== null` |
|
|
192
|
+
| `consentCategories`, `consentTypes`, `getDisplayedConsents()` | `useConsentDraft().displayedCategories`, with labels from `useTranslations().consentTypes` |
|
|
193
|
+
| `policyCategories` | `usePolicyCategories()`. The v2 list started with `'necessary'`; this one does not. |
|
|
194
|
+
| `policyScopeMode` | `usePolicyScopeMode()` |
|
|
195
|
+
| `policyBanner` | `usePromptPresentation()` |
|
|
196
|
+
| `policyDialog` | `usePreferencesPresentation()` |
|
|
197
|
+
| `model` | `useModel()`. It returns `null` while no policy matches, where v2 returned `'opt-in'`. |
|
|
198
|
+
| `branding` | `useBranding()`. It returns `null` when unset, where v2 returned `'c15t'`. |
|
|
199
|
+
| `iab` | `useIABSnapshot()` |
|
|
200
|
+
| `locationInfo` | `useLocation()` |
|
|
201
|
+
| `overrides`, `setOverrides()` | `useOverrides()`, `useSetOverrides()` |
|
|
202
|
+
| `setLanguage()` | `useSetLanguage()` |
|
|
203
|
+
| `user`, `identifyUser()` | `useUser()`, `useIdentify()` |
|
|
204
|
+
| `translationConfig` | `useTranslations()` for the active strings |
|
|
205
|
+
| `subscribeToConsentChanges(listener)` | `useSubscribeToConsentChanges()`, or the `onPermissionsChanged` callback |
|
|
206
|
+
| `updateConsentCategories(categories)` | `useRegisterConsentCategories()` |
|
|
207
|
+
| `manager` | Nothing. Use the hooks above. |
|
|
208
|
+
|
|
209
|
+
`saveCustomPreferences()` saves the way the stock buttons do. It closes the
|
|
210
|
+
banner or dialog after a successful save. `useSaveConsents()` calls the engine
|
|
211
|
+
directly and does not close anything.
|
|
212
|
+
|
|
213
|
+
In v2, `useConsentManager()` kept one draft per component. In v3,
|
|
214
|
+
`useConsentDraft()` and `useHeadlessConsentUI()` share the draft of the nearest
|
|
215
|
+
`ConsentDraftProvider`. When one component stages choices and another saves
|
|
216
|
+
them, render both inside the same `ConsentDraftProvider`; otherwise the save
|
|
217
|
+
commits nothing you staged. `ConsentWidget` already includes one. The codemod
|
|
218
|
+
adds a `TODO(c15t v3)` comment where this applies.
|
|
219
|
+
|
|
220
|
+
## Next.js with `ConsentManagerProvider`
|
|
221
|
+
|
|
222
|
+
A typical v2 App Router app wrapped the layout in a client component:
|
|
223
|
+
|
|
224
|
+
```tsx title="Before (v2): components/consent-manager/provider.tsx"
|
|
225
|
+
'use client';
|
|
185
226
|
|
|
186
|
-
|
|
187
|
-
|
|
227
|
+
import {
|
|
228
|
+
ConsentBanner,
|
|
229
|
+
ConsentDialog,
|
|
230
|
+
ConsentManagerProvider,
|
|
231
|
+
} from '@c15t/nextjs';
|
|
232
|
+
|
|
233
|
+
export default function ConsentManagerClient({ children }) {
|
|
234
|
+
return (
|
|
235
|
+
<ConsentManagerProvider
|
|
236
|
+
options={{ mode: 'hosted', backendURL: 'https://your-project.c15t.dev' }}
|
|
237
|
+
>
|
|
238
|
+
<ConsentBanner />
|
|
239
|
+
<ConsentDialog />
|
|
240
|
+
{children}
|
|
241
|
+
</ConsentManagerProvider>
|
|
242
|
+
);
|
|
243
|
+
}
|
|
188
244
|
```
|
|
189
245
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
246
|
+
v3 gives you two ways forward:
|
|
247
|
+
|
|
248
|
+
* **Resolve consent on the server** (recommended). The server reads the
|
|
249
|
+
visitor's policy and stored choice, so gated scripts can start right after
|
|
250
|
+
hydration and the banner can be in the first HTML. Replace the client
|
|
251
|
+
component with `ConsentRoot`, pass it `resolveConsent()` from
|
|
252
|
+
`c15t/next/server` as `state` and your `defineConsentConfig()` result as
|
|
253
|
+
`config`, and add the manifest route. Follow the
|
|
254
|
+
[App Router guide](https://c15t.com/docs/frameworks/next/app-router) or the
|
|
255
|
+
[Pages Router guide](https://c15t.com/docs/frameworks/next/pages-router). This replaces v2's
|
|
256
|
+
`fetchInitialData()`, `ssrData` and `C15tPrefetch`.
|
|
257
|
+
* **Keep browser initialization**, as v2 did without `fetchInitialData()`. Keep
|
|
258
|
+
your client component, import from `c15t/next`, and change the provider:
|
|
198
259
|
|
|
199
|
-
|
|
260
|
+
```tsx title="After (v3): components/consent-manager/provider.tsx, changed lines"
|
|
261
|
+
import { ConsentBanner, ConsentDialog, ConsentProvider, hosted } from 'c15t/next';
|
|
200
262
|
|
|
201
|
-
|
|
263
|
+
// In the component, replace ConsentManagerProvider:
|
|
202
264
|
<ConsentProvider
|
|
203
|
-
|
|
204
|
-
mode,
|
|
205
|
-
callbacks: {
|
|
206
|
-
onChoiceRecorded(event) {
|
|
207
|
-
console.log('Visitor recorded a choice', event);
|
|
208
|
-
},
|
|
209
|
-
onPermissionsChanged(event) {
|
|
210
|
-
console.log('Effective permissions changed', event);
|
|
211
|
-
},
|
|
212
|
-
},
|
|
213
|
-
}}
|
|
265
|
+
options={{ mode: hosted({ url: 'https://your-project.c15t.dev' }) }}
|
|
214
266
|
>
|
|
215
|
-
{children}
|
|
216
|
-
</ConsentProvider>
|
|
217
267
|
```
|
|
218
268
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
`
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
[
|
|
263
|
-
|
|
264
|
-
##
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
##
|
|
300
|
-
|
|
301
|
-
```astro
|
|
302
|
-
---
|
|
303
|
-
import ConsentBanner from 'c15t/astro/components/consent-banner.astro';
|
|
304
|
-
---
|
|
269
|
+
Static exports use browser initialization too. See
|
|
270
|
+
[static export](https://c15t.com/docs/frameworks/next/static-export) and
|
|
271
|
+
[client-side setup](https://c15t.com/docs/frameworks/next/client-side).
|
|
272
|
+
|
|
273
|
+
Either way, change the stylesheet import to `c15t/next/styles.css`, and keep
|
|
274
|
+
your backend URL. An existing hosted URL such as `https://your-project.c15t.dev`
|
|
275
|
+
keeps working with v3 clients. New Inth projects use URLs such as
|
|
276
|
+
`https://your-project.inth.app`. The
|
|
277
|
+
[CLI setup command](https://c15t.com/docs/cli/quickstart) can generate the browser-initialized
|
|
278
|
+
version for you.
|
|
279
|
+
|
|
280
|
+
## React with `ConsentManagerProvider`
|
|
281
|
+
|
|
282
|
+
Swap `ConsentManagerProvider` for `ConsentProvider` from `c15t/react`, and pass
|
|
283
|
+
a transport as `mode`:
|
|
284
|
+
|
|
285
|
+
| v2 option | v3 option |
|
|
286
|
+
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
287
|
+
| `mode: 'hosted'` with `backendURL` | `mode: hosted({ url })` |
|
|
288
|
+
| `mode: 'offline'` with `offlinePolicy` | `mode: offline({ policyRules })` |
|
|
289
|
+
| `mode: 'custom'` with `endpointHandlers` | `mode: custom(transport)`, where `transport` implements the v3 transport interface. `endpointHandlers` throws. |
|
|
290
|
+
|
|
291
|
+
`hosted` and `offline` are exported from `c15t/react`. The
|
|
292
|
+
[React quickstart](https://c15t.com/docs/frameworks/react/quickstart) shows the full provider.
|
|
293
|
+
[Data fetching](./concepts/data-fetching.md) covers custom transports.
|
|
294
|
+
|
|
295
|
+
Offline mode keeps choices in the browser and records nothing on a server. Not
|
|
296
|
+
recommended for production environments.
|
|
297
|
+
|
|
298
|
+
## JavaScript with `getOrCreateConsentRuntime`
|
|
299
|
+
|
|
300
|
+
v2's `getOrCreateConsentRuntime()`, `configureConsentManager()` and the
|
|
301
|
+
Zustand `consentStore` are gone. v3 has two replacements:
|
|
302
|
+
|
|
303
|
+
* `createConsentKernel()` from `c15t`, with `createHostedTransport()`. You read
|
|
304
|
+
`kernel.getSnapshot()`, listen with `kernel.subscribe()`, and save with
|
|
305
|
+
`kernel.commands.save('all' | 'none' | { marketing: false })`. See the
|
|
306
|
+
[JavaScript quickstart](https://c15t.com/docs/frameworks/javascript/quickstart).
|
|
307
|
+
* A script tag that includes the stock banner, for sites without a build
|
|
308
|
+
step. See [script tag](https://c15t.com/docs/frameworks/html/quickstart).
|
|
309
|
+
|
|
310
|
+
v3 also adds adapters for TanStack Start, Nuxt, Vue, Astro, Svelte and
|
|
311
|
+
SvelteKit. If you wired the v2 runtime into one of these frameworks, move to its
|
|
312
|
+
adapter from [Choose your setup](./concepts/choose-your-setup.md).
|
|
313
|
+
|
|
314
|
+
## Replace callbacks
|
|
315
|
+
|
|
316
|
+
Callbacks stay under `options.callbacks`, with new names:
|
|
317
|
+
|
|
318
|
+
| v2 callback | v3 callback |
|
|
319
|
+
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
320
|
+
| `onConsentSet` | `onPermissionsChanged` to react to what may run now. `onChoiceRecorded` to react to the visitor's accept, reject or save. |
|
|
321
|
+
| `onConsentChanged` | `onChoiceRecorded`. See the note below the table. |
|
|
322
|
+
| `onBannerFetched` | No provider callback. Read `usePolicyResolution()` to know when the policy has resolved. |
|
|
323
|
+
| `onError`, `onBeforeConsentRevocationReload` | Unchanged |
|
|
324
|
+
|
|
325
|
+
v2's `onConsentChanged` fired only when a save changed at least one category's
|
|
326
|
+
value, and passed `preferences` and `previousPreferences`. v3's
|
|
327
|
+
`onChoiceRecorded` fires for every accept, reject or save that confirms a
|
|
328
|
+
category, including one that saves the same values again, because each save
|
|
329
|
+
renews the choice's confirmation time. Its payload carries `snapshot`,
|
|
330
|
+
`confirmed` and `actionAt`. To act only on a real change, keep the last
|
|
331
|
+
`snapshot.explicitChoice` you saw and compare it.
|
|
332
|
+
|
|
333
|
+
v2's `onConsentSet` also fired on initialization and hydration. In v3,
|
|
334
|
+
`onChoiceRecorded` runs only when the visitor acts, and `onPermissionsChanged`
|
|
335
|
+
runs when effective permissions change for any reason, including expiry, a
|
|
336
|
+
policy update or a privacy signal.
|
|
337
|
+
|
|
338
|
+
```tsx title="After (v3): provider options"
|
|
339
|
+
callbacks: {
|
|
340
|
+
onChoiceRecorded(event) {
|
|
341
|
+
console.log('Visitor recorded a choice', event);
|
|
342
|
+
},
|
|
343
|
+
onPermissionsChanged(event) {
|
|
344
|
+
console.log('Effective permissions changed', event);
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## Move policy packs to policy rules
|
|
305
350
|
|
|
306
|
-
|
|
351
|
+
v2 policy packs become policy rules, and `policyPackPresets` becomes
|
|
352
|
+
`policyRulePresets`, exported from `c15t`. Where the rules live depends on your
|
|
353
|
+
backend:
|
|
354
|
+
|
|
355
|
+
* **Inth**: set the rules in your Inth project. Rules in client code do not
|
|
356
|
+
change a hosted policy.
|
|
357
|
+
* **Self-hosted**: move the backend's `policyPacks` to `manifest.policyRules`.
|
|
358
|
+
See [policy configuration](https://c15t.com/docs/self-host/guides/policy-packs).
|
|
359
|
+
* **Offline**: move `offlinePolicy.policyPacks` to `offline({ policyRules })`.
|
|
360
|
+
|
|
361
|
+
```tsx title="After (v3): offline policy rules"
|
|
362
|
+
import { policyRulePresets } from 'c15t';
|
|
363
|
+
import { offline } from 'c15t/react';
|
|
364
|
+
|
|
365
|
+
const mode = offline({
|
|
366
|
+
policyRules: [policyRulePresets.europeOptIn(), policyRulePresets.worldNone()],
|
|
367
|
+
});
|
|
307
368
|
```
|
|
308
369
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
`
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
`
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
`
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
`
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
translation keys, `--frame-*` CSS custom properties and
|
|
386
|
-
`data-testid="frame-placeholder"`, so custom copy, styles and tests continue
|
|
387
|
-
to apply.
|
|
388
|
-
|
|
389
|
-
## Split dialog and widget entries are deferred
|
|
390
|
-
|
|
391
|
-
`c15t/react/consent-dialog` and `c15t/react/consent-widget` (and their
|
|
392
|
-
`@c15t/react/*` equivalents) now export the same deferred `ConsentDialog` and
|
|
393
|
-
`ConsentWidget` as `c15t/react`. The dialog's code loads when it first opens
|
|
394
|
-
instead of with every page. `<ConsentDialog />`, `<ConsentWidget />` and the
|
|
395
|
-
`ConsentDialog.<Part>` properties need no change.
|
|
396
|
-
|
|
397
|
-
The two entries no longer export the individual parts. Import those from the
|
|
398
|
-
component entries, which keep the old, eagerly bundled exports:
|
|
399
|
-
|
|
400
|
-
| Before | After |
|
|
401
|
-
| --------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
402
|
-
| `import { Card, Header } from 'c15t/react/consent-dialog'` | `import { Card, Header } from 'c15t/react/components/consent-dialog'` |
|
|
403
|
-
| `import { Accordion, Switch } from 'c15t/react/consent-widget'` | `import { Accordion, Switch } from 'c15t/react/components/consent-widget'` |
|
|
404
|
-
|
|
405
|
-
To keep the dialog in the first load so its first open needs no download,
|
|
406
|
-
import `ConsentDialog` from `c15t/react/components/consent-dialog`.
|
|
407
|
-
|
|
408
|
-
## Next.js RSC banner removal
|
|
409
|
-
|
|
410
|
-
The `@c15t/nextjs/rsc` entry (`c15t/next/rsc`) and its `RscConsentBanner`,
|
|
411
|
-
`RscBannerGate` and `RscBannerActions` exports are gone. Imports of that
|
|
412
|
-
entry now fail to resolve. Use the regular banner for server rendering.
|
|
413
|
-
The retained benchmark results showed slightly faster banner visibility and
|
|
414
|
-
interaction for the experimental shell, so this removal should not be read
|
|
415
|
-
as a performance improvement.
|
|
416
|
-
|
|
417
|
-
Replace `<RscConsentBanner config={config} />` with `<ConsentBanner />` inside
|
|
418
|
-
the same `ConsentRoot`, importing it from `c15t/next` when you use the
|
|
419
|
-
umbrella package or from `@c15t/nextjs` when you depend on the scoped package
|
|
420
|
-
directly. With an awaited `resolveConsent` result, the server renders
|
|
421
|
-
the banner into the response, which is what the RSC variant was for. Move
|
|
422
|
-
`presentation` to `options.presentation` on `ConsentRoot`.
|
|
423
|
-
|
|
424
|
-
Two defaults differ from the removed shell. It rendered no branding link, so
|
|
425
|
-
pass `hideBranding` to keep that. It also styled only its root and action row
|
|
426
|
-
(through the stock `ConsentBanner.Root` and `PolicyActions`) and left the
|
|
427
|
-
card, title, description, footer and buttons without base classes, whereas
|
|
428
|
-
`ConsentBanner` merges the stock styles into every part. If that changes a
|
|
429
|
-
custom layout, do not reach for `noStyle` on the whole banner, which also
|
|
430
|
-
drops the root positioning and action-row layout the old shell kept; compose
|
|
431
|
-
the compound parts instead and pass `noStyle` only to the parts you styled
|
|
432
|
-
yourself.
|
|
433
|
-
|
|
434
|
-
`ConsentBanner` has no `classNames` or `children` props. Move each legacy
|
|
435
|
-
`classNames` key to the `ConsentRoot` `options.components` slots, which take
|
|
436
|
-
`{ className }`:
|
|
437
|
-
|
|
438
|
-
| `classNames` key | Replacement |
|
|
439
|
-
| ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
440
|
-
| `root`, `card`, `title`, `footer` | `components.banner.root`, `.card`, `.title`, `.footer` |
|
|
441
|
-
| `description` | `components.description.banner` |
|
|
442
|
-
| `rights`, `rightLink` | `components.banner.rights`, `components.banner.rightLink` |
|
|
443
|
-
| `acceptButton`, `rejectButton`, `customizeButton`, `dismissButton` | No per-button slot. Use `components.button.primary` / `.secondary` for shared styles, or target `[data-action="accept"]`, `[data-action="reject"]`, `[data-action="customize"]` and `[data-action="dismiss"]` in CSS. |
|
|
444
|
-
|
|
445
|
-
Custom `children`, and any direct use of `RscBannerGate` or
|
|
446
|
-
`RscBannerActions`, map to the compound parts of `ConsentBanner` in a Client
|
|
447
|
-
Component. `RscBannerGate` becomes `ConsentBanner.Root`, which mounts only
|
|
448
|
-
while the policy owes a prompt and reopens on expiry. Remove the gate
|
|
449
|
-
`prompt` and `model` props; the root derives `data-prompt` and `data-model`
|
|
450
|
-
from the `ConsentRoot` policy. Rename `title` to `aria-label` to preserve its
|
|
451
|
-
accessible label. Keep `children`, `className`, `variant`, `position` and
|
|
452
|
-
`blocking` on the root. Add `disableAnimation` and `trapFocus={false}` to
|
|
453
|
-
retain the old gate defaults.
|
|
454
|
-
|
|
455
|
-
`RscBannerActions`
|
|
456
|
-
becomes `ConsentBanner.PolicyActions`, which renders the rights links and the
|
|
457
|
-
action row the policy requires; `ConsentBanner.Rights`, `RightLink`, `Footer`,
|
|
458
|
-
`FooterSubGroup` and the four buttons are available for finer control.
|
|
459
|
-
`PolicyActions` takes none of the old `acceptLabel`, `rejectLabel`,
|
|
460
|
-
`customizeLabel`, `dismissLabel`, `rightLabels` or `classNames` props: set
|
|
461
|
-
labels through the provider `i18n` translation overrides (`common.acceptAll`,
|
|
462
|
-
`common.rejectAll`, `common.customize`, `common.acknowledge`, `rights.*`), or
|
|
463
|
-
render `ConsentBanner.AcceptButton` and the other buttons with your own
|
|
464
|
-
children; `renderAction` on `PolicyActions` replaces one button; classes move
|
|
465
|
-
to the `components` slots listed in the table. Place the former `children`
|
|
466
|
-
inside `ConsentBanner.Card`:
|
|
467
|
-
|
|
468
|
-
```tsx title="components/banner.tsx"
|
|
469
|
-
'use client';
|
|
370
|
+
| v2 preset | v3 preset |
|
|
371
|
+
| ----------------------------------------- | ------------- |
|
|
372
|
+
| `europeOptIn()`, `europeIab()` | Same names |
|
|
373
|
+
| `californiaOptIn()`, `californiaOptOut()` | Same names |
|
|
374
|
+
| `quebecOptIn()` | Same name |
|
|
375
|
+
| `worldNoBanner()` | `worldNone()` |
|
|
376
|
+
|
|
377
|
+
v3 adds presets for more regions. `offline()` without `policyRules` uses
|
|
378
|
+
`recommendedPolicyRules()`. Read [policies](./concepts/policies.md) before you
|
|
379
|
+
change a rule's model or prompt, and
|
|
380
|
+
[how consent works](./concepts/how-consent-works.md) for the difference
|
|
381
|
+
between a permission and a recorded choice.
|
|
382
|
+
|
|
383
|
+
## Rename options and components
|
|
384
|
+
|
|
385
|
+
| v2 | v3 |
|
|
386
|
+
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
|
387
|
+
| `translations` | `i18n` |
|
|
388
|
+
| `backendURL`, `mode: 'hosted'` | `mode: hosted({ url })` |
|
|
389
|
+
| `ssrData` (Next.js) | `ConsentRoot` with `state` from `resolveConsent()` |
|
|
390
|
+
| `iframeBlockerConfig` | `iframeBlocker`, or `false` to turn it off |
|
|
391
|
+
| `Frame` | `ConsentGate`. `Frame` still works as a deprecated alias. |
|
|
392
|
+
| `frame` translations, such as `frame.title` | `consentGate`, such as `consentGate.title`. Copy under `frame` still applies and logs a warning outside production. |
|
|
393
|
+
| `FrameTranslations` | `ConsentGateTranslations`. `FrameTranslations` still works as a deprecated alias. |
|
|
394
|
+
| `--frame-*` CSS variables | `--consent-gate-*`, with the same suffixes, such as `--consent-gate-placeholder-background-color`. The old names no longer apply. |
|
|
395
|
+
| `YouTubeEmbed`, `GoogleMap` | Removed. Wrap your own embed in `ConsentGate`. |
|
|
396
|
+
| `useConsentScript()` | Removed. Register the script in `scripts` with a `@c15t/integrations` helper. |
|
|
397
|
+
| `useSSRStatus()` | Removed |
|
|
398
|
+
|
|
399
|
+
`ConsentBanner`, `ConsentDialog`, `ConsentDialogLink`, `ConsentDialogTrigger`
|
|
400
|
+
and `ConsentWidget` keep their names. The `scripts`, `networkBlocker`,
|
|
401
|
+
`legalLinks`, `overrides`, `theme` and `colorScheme` options keep theirs too.
|
|
402
|
+
|
|
403
|
+
## Keep visitors' existing choices
|
|
404
|
+
|
|
405
|
+
v3 uses the same `c15t` cookie and storage key as v2 and reads v2 records. It
|
|
406
|
+
does not rewrite them on page load; the next accept, reject or save writes a
|
|
407
|
+
v3 record.
|
|
408
|
+
|
|
409
|
+
A v2 denial keeps restricting its category. A v2 grant keeps applying while it
|
|
410
|
+
is within the policy's validity period and the policy has not changed since the
|
|
411
|
+
visitor chose. Otherwise c15t asks again. Do not copy permissions into new
|
|
412
|
+
records yourself; c15t decides which v2 choices still count.
|
|
413
|
+
|
|
414
|
+
## Upgrade a self-hosted backend
|
|
415
|
+
|
|
416
|
+
Deploy the v3 backend and the v3 clients in the same release. A v3 client
|
|
417
|
+
cannot read a v2 backend's `/init` response. Policy resolution fails, optional
|
|
418
|
+
categories stay denied and no banner appears.
|
|
419
|
+
|
|
420
|
+
1. Install `@c15t/backend@alpha` and the SQL driver for your database.
|
|
421
|
+
2. Replace `adapter` with `database` in your config. The Drizzle, Prisma,
|
|
422
|
+
TypeORM and Kysely adapters are gone; point `database` at the same SQL
|
|
423
|
+
database instead. MongoDB has no migration path.
|
|
424
|
+
3. Move `policyPacks`, `branding`, `iab` and `appName` under `manifest`, and
|
|
425
|
+
rename `policyPacks` to `policyRules`.
|
|
426
|
+
4. Back up the database, then plan and apply the schema migration:
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
npx @c15t/cli@alpha self-host migrate --config ./c15t-backend.config.ts --plan
|
|
430
|
+
npx @c15t/cli@alpha self-host migrate --config ./c15t-backend.config.ts --apply
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
The migrator recognizes the v2 schema, adopts it, and adds the v3 tables and
|
|
434
|
+
columns. Apply it before the v3 backend serves traffic: v3 records policy
|
|
435
|
+
decisions without the v2 `jurisdiction` label, which the migration makes
|
|
436
|
+
nullable. [Database setup](https://c15t.com/docs/self-host/guides/database-setup#upgrade-a-v2-backend)
|
|
437
|
+
covers the details, and the [backend quickstart](https://c15t.com/docs/self-host/quickstart)
|
|
438
|
+
shows a complete v3 config and route.
|
|
439
|
+
|
|
440
|
+
### Remove `disableGeoLocation`
|
|
441
|
+
|
|
442
|
+
v3 removes the `disableGeoLocation` manifest option. Policy rules decide by
|
|
443
|
+
country and region. To show every visitor the same banner, configure one rule
|
|
444
|
+
with `match: { isDefault: true }`. It applies wherever the visitor is, so the
|
|
445
|
+
browser can resolve it without asking the backend for a location.
|
|
470
446
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
447
|
+
To test one region's rule from anywhere, set the country in the client's
|
|
448
|
+
`overrides`, for example `overrides: { country: 'US' }`. See
|
|
449
|
+
[runtime options](https://c15t.com/docs/frameworks/javascript/api/runtime).
|
|
450
|
+
|
|
451
|
+
### Stop reading `jurisdiction`
|
|
452
|
+
|
|
453
|
+
`/init` responses, session reports and `sessions.onReport` no longer carry a
|
|
454
|
+
`jurisdiction` label such as `GDPR`. Read the matched policy from
|
|
455
|
+
`policyResolution` instead, or the report's `policy`, `country` and `region`.
|
|
456
|
+
The backend still accepts `jurisdiction` in a v2 client's save request and
|
|
457
|
+
ignores it.
|
|
458
|
+
|
|
459
|
+
## Update the Node.js SDK
|
|
460
|
+
|
|
461
|
+
Install `@c15t/node-sdk@alpha`. The v2 client is gone: create one with
|
|
462
|
+
`createC15tClient()` and pass the backend URL and API key yourself.
|
|
463
|
+
|
|
464
|
+
| Package manager | Command |
|
|
465
|
+
| :-------------- | :--------------------------------- |
|
|
466
|
+
| npm | `npm install @c15t/node-sdk@alpha` |
|
|
467
|
+
| pnpm | `pnpm add @c15t/node-sdk@alpha` |
|
|
468
|
+
| yarn | `yarn add @c15t/node-sdk@alpha` |
|
|
469
|
+
| bun | `bun add @c15t/node-sdk@alpha` |
|
|
470
|
+
|
|
471
|
+
```ts
|
|
472
|
+
import { createC15tClient } from '@c15t/node-sdk';
|
|
473
|
+
|
|
474
|
+
const apiKey = process.env.C15T_API_KEY;
|
|
475
|
+
if (!apiKey) throw new Error('Set C15T_API_KEY');
|
|
476
|
+
|
|
477
|
+
const c15t = createC15tClient({
|
|
478
|
+
baseUrl: 'https://app.example.com/api/c15t',
|
|
479
|
+
apiKey,
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
const result = await c15t.consents.check({
|
|
483
|
+
externalId: 'user_123',
|
|
484
|
+
types: ['privacy_policy', 'marketing_communications'],
|
|
485
|
+
});
|
|
486
|
+
if (result.ok) {
|
|
487
|
+
console.log(result.data.results.privacy_policy.hasConsent);
|
|
486
488
|
}
|
|
487
489
|
```
|
|
488
490
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
`
|
|
507
|
-
|
|
508
|
-
`
|
|
509
|
-
|
|
491
|
+
| v2 | v3 |
|
|
492
|
+
| ------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
493
|
+
| `c15tClient(options)`, `new C15TClient(options)` | `createC15tClient(options)` |
|
|
494
|
+
| `C15T_API_URL`, `C15T_API_TOKEN` read from the environment | Not read. Pass `baseUrl` and `apiKey`. |
|
|
495
|
+
| `token` | `apiKey` |
|
|
496
|
+
| `prefix` | Part of `baseUrl`, such as `https://app.example.com/api/c15t` |
|
|
497
|
+
| `timeout` | `timeoutMs`, per attempt |
|
|
498
|
+
| `retryConfig` | `retry: { maxRetries, initialDelayMs, maxDelayMs }`, or `false` |
|
|
499
|
+
| `debug`, `C15T_DEBUG` | `onEvent` |
|
|
500
|
+
| `client.meta.status()`, `client.status()` | `c15t.status()` |
|
|
501
|
+
| `client.meta.init()`, `client.init()` | `c15t.init({ language, country, region, gpc })` |
|
|
502
|
+
| `getSubject(id, { type: 'a,b' })` | `subjects.get(id, { types: ['a', 'b'] })` |
|
|
503
|
+
| `createSubject(input)` | `subjects.create(input)`. `givenAt` also takes a `Date`. |
|
|
504
|
+
| `patchSubject(id, input)`, `subjects.patch(id, input)` | `subjects.identify(id, { externalId, identityProvider })` |
|
|
505
|
+
| `listSubjects({ externalId })` | `subjects.list({ externalId })`, on a client with `apiKey` |
|
|
506
|
+
| `checkConsent(query)`, `consent.check({ externalId, type: 'a,b' })` | `consents.check({ externalId, types: ['a', 'b'] })` |
|
|
507
|
+
| `summarizeExperiment(id, query)`, `experiments.summary(id, query)` | `experiments.summary(id, { from, to, domain })`, on a client with `apiKey` |
|
|
508
|
+
| `ResponseContext` with `data: T \|null` | `{ ok: true, data } \|{ ok: false, error }`. Check `ok` first. |
|
|
509
|
+
| `unwrap()`, `expect()` on the response | `unwrap(result)`, imported from `@c15t/node-sdk` |
|
|
510
|
+
| `unwrapOr()`, `map()` on the response | Check `result.ok` |
|
|
511
|
+
| `throw: true` | `unwrap(result)` |
|
|
512
|
+
| `onSuccess`, `onError` | Check `result.ok` after the call |
|
|
513
|
+
| `C15TError`, `isC15TError()` | `C15tError`, `isC15tError(error, ...codes)` |
|
|
514
|
+
| `$fetch`, `fetcher`, `resolveUrl`, `createResponseContext` | Removed. Pass a custom `fetch` to `createC15tClient` if you need one. |
|
|
515
|
+
| `createMockClient`, `createMockResponse`, `createMockErrorResponse` | `createMockC15tClient`, `ok`, `err` from `@c15t/node-sdk/testing` |
|
|
516
|
+
|
|
517
|
+
`patchSubject` returned `{ success, subject }`. `subjects.identify` returns
|
|
518
|
+
`{ subject }`, and `subject.identityProvider` is always set. Dates in
|
|
519
|
+
responses, such as `givenAt` and `createdAt`, are now `Date` objects rather
|
|
520
|
+
than strings.
|
|
521
|
+
|
|
522
|
+
The new client also adds `manifest()` and `legalDocuments.publish()`. See the
|
|
523
|
+
[Node.js SDK reference](https://c15t.com/docs/self-host/api/node-sdk).
|
|
524
|
+
|
|
525
|
+
## Check the migration
|
|
526
|
+
|
|
527
|
+
1. Run your typecheck and build. Remaining `TODO(c15t v3)` comments from the
|
|
528
|
+
codemod fail the build until you resolve them.
|
|
529
|
+
2. Load the app with a v2 consent cookie from before the upgrade. The banner
|
|
530
|
+
stays closed if that choice still applies, and a rejected category stays
|
|
531
|
+
blocked.
|
|
532
|
+
3. In a private window, check in DevTools Network that vendor requests wait for
|
|
533
|
+
consent, start after you accept, and stay absent after you reject and
|
|
534
|
+
reload.
|
|
535
|
+
4. Reopen preferences from your privacy settings link and change a category.
|
|
536
|
+
|
|
537
|
+
The [verification guide](./guides/verify-consent.md) has the full release
|
|
538
|
+
checklist.
|