@c15t/react 3.0.0-alpha.5 → 3.0.0-alpha.7
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 +6 -4
- package/SKILL.md +1 -1
- package/dist/component-hooks/use-headless-consent-ui.js +1 -1
- package/dist/components/iab-panel/atoms/vendor-list.js +1 -1
- package/dist/components/iab-panel/hooks/use-gvl-data.js +1 -1
- package/dist/components/iab-panel/index.js +1 -1
- package/dist/components/iab-prompt/atoms/overlay.js +1 -1
- package/dist/components/iab-prompt/atoms/root.js +1 -1
- package/dist/components/panel/index.js +1 -1
- package/dist/components/panel-trigger/atoms/toolbar.js +1 -1
- package/dist/components/panel-trigger/atoms/trigger-icons.js +1 -1
- package/dist/components/panel-trigger/panel-trigger.js +1 -1
- package/dist/components/preferences/index.js +1 -1
- package/dist/components/prompt/atoms/overlay.js +1 -1
- package/dist/components/prompt/atoms/root.js +1 -1
- package/dist/components/shared/ui/accordion/accordion.js +1 -1
- package/dist/components/shared/ui/collapsible/collapsible.js +1 -1
- package/dist/components/shared/ui/preference-item/preference-item.js +1 -1
- package/dist/components/shared/ui/switch/switch.js +1 -1
- package/dist/components/shared/ui/tabs/tabs.js +1 -1
- package/dist/devtools-launcher.js +2 -0
- package/dist/devtools.js +1 -1
- package/dist/hooks/use-headless-iab-consent-ui.js +1 -1
- package/dist/hooks/use-late-entry.js +2 -0
- package/dist/iab/styles.tw3.css +2 -2
- package/dist/index-parts/core.js +1 -1
- package/dist/provider.js +1 -1
- package/dist/styles.tw3.css +29 -5
- package/dist/version.js +1 -1
- package/dist-types/component-hooks/use-headless-consent-ui.d.ts +4 -4
- package/dist-types/components/iab-panel/index.d.ts +0 -1
- package/dist-types/components/panel/index.d.ts +0 -1
- package/dist-types/components/panel-trigger/atoms/trigger-icons.d.ts +5 -0
- package/dist-types/components/panel-trigger/panel-trigger.d.ts +0 -8
- package/dist-types/components/preferences/index.d.ts +0 -1
- package/dist-types/components/shared/ui/accordion/accordion.d.ts +0 -1
- package/dist-types/components/shared/ui/collapsible/collapsible.d.ts +0 -1
- package/dist-types/components/shared/ui/preference-item/preference-item.d.ts +0 -1
- package/dist-types/components/shared/ui/switch/switch.d.ts +0 -1
- package/dist-types/components/shared/ui/tabs/tabs.d.ts +0 -1
- package/dist-types/devtools-launcher.d.ts +29 -0
- package/dist-types/hooks/use-iab-manager.d.ts +4 -4
- package/dist-types/hooks/use-late-entry.d.ts +14 -0
- package/dist-types/hooks.d.ts +27 -5
- package/dist-types/index-parts/core.d.ts +1 -1
- package/dist-types/index.d.ts +1 -1
- package/dist-types/provider.d.ts +23 -4
- package/dist-types/version.d.ts +1 -1
- package/docs/README.md +6 -4
- package/docs/concepts/choose-your-setup.md +23 -6
- package/docs/concepts/consent-state.md +47 -0
- package/docs/concepts/data-fetching.md +68 -11
- package/docs/customization/motion.md +22 -13
- package/docs/customization/recipes.md +4 -5
- package/docs/customization/slots.md +3 -2
- package/docs/customization/stylesheets.md +29 -39
- package/docs/customization/tailwind.md +5 -5
- package/docs/customization/tokens.md +2 -1
- package/docs/customization/translations.md +32 -5
- package/docs/frameworks/react/components/consent-dialog-trigger.md +5 -0
- package/docs/frameworks/react/components/consent-dialog.md +2 -1
- package/docs/frameworks/react/components/consent-provider.md +29 -28
- package/docs/frameworks/react/components/dev-tools.md +23 -0
- package/docs/frameworks/react/headless.md +4 -4
- package/docs/frameworks/react/hooks.md +10 -5
- package/docs/frameworks/react/iab.md +24 -18
- package/docs/frameworks/react/quickstart.md +77 -16
- package/docs/frameworks/react/rendering.md +82 -11
- package/docs/frameworks/react/scripts.md +8 -3
- package/docs/frameworks/react/upgrade-v3.md +596 -0
- package/docs/frameworks/react/vendor-consent.md +6 -0
- package/docs/guides/banner-experiments.md +26 -5
- package/docs/guides/troubleshooting.md +3 -2
- package/docs/integrations/overview.md +28 -27
- package/docs/integrations/sentry.md +416 -0
- package/docs/upgrade-v3.md +205 -314
- package/package.json +8 -8
package/docs/upgrade-v3.md
CHANGED
|
@@ -1,11 +1,29 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Migrate to v3
|
|
3
|
-
description: Upgrade
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
description: Upgrade from c15t v2 to v3. Pick the guide for the v2 package you
|
|
4
|
+
use (@c15t/nextjs, @c15t/react or the c15t store), rename @c15t/scripts, keep
|
|
5
|
+
visitors' choices, and upgrade a self-hosted backend and the Node.js SDK.
|
|
6
6
|
group: reference
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## Hand the upgrade to a coding agent
|
|
10
|
+
|
|
11
|
+
**Upgrade this app to c15t v3**
|
|
12
|
+
|
|
13
|
+
Paste into Claude Code, Codex, Cursor or another coding agent at the root of your app.
|
|
14
|
+
|
|
15
|
+
```prompt
|
|
16
|
+
Upgrade this app from c15t v2 to c15t v3.
|
|
17
|
+
|
|
18
|
+
1. Check `package.json` for c15t packages. `@c15t/nextjs` means Next.js, `@c15t/react` without it means React, and `c15t` alone means the JavaScript store.
|
|
19
|
+
2. Read the matching guide before you change anything: <https://c15t.com/docs/frameworks/next/upgrade-v3.md>, <https://c15t.com/docs/frameworks/react/upgrade-v3.md> or <https://c15t.com/docs/frameworks/javascript/upgrade-v3.md>. Follow it in order and do not guess v3 APIs from memory.
|
|
20
|
+
3. If the app also runs its own c15t backend with `@c15t/backend`, read <https://c15t.com/docs/upgrade-v3.md> and upgrade the backend in the same change. Start with `npx @c15t/cli@alpha codemods backend-config-to-v3 node-sdk-to-v3 --dry-run --json`, then run it without `--dry-run`.
|
|
21
|
+
4. Keep the existing backend URL.
|
|
22
|
+
5. Run the typecheck and build when you finish.
|
|
23
|
+
|
|
24
|
+
List the files you changed, anything you could not migrate, and how you checked that vendor requests still wait for consent.
|
|
25
|
+
```
|
|
26
|
+
|
|
9
27
|
## What changes in v3
|
|
10
28
|
|
|
11
29
|
* One package, `c15t`, replaces `@c15t/nextjs`, `@c15t/react` and the v2
|
|
@@ -23,57 +41,38 @@ group: reference
|
|
|
23
41
|
rewrites most calls.
|
|
24
42
|
* Callbacks have new names, and each reports either a recorded choice or a
|
|
25
43
|
permission change.
|
|
44
|
+
* `theme` tokens no longer generate CSS on their own. Render `ConsentTheme` or
|
|
45
|
+
add `generateThemeCSS()` output to your stylesheet.
|
|
46
|
+
* IAB moves from the `iab` provider option to an `IABProvider` component in
|
|
47
|
+
React and Next.js.
|
|
48
|
+
* Every package ships ESM only. `require()` of a c15t package no longer
|
|
49
|
+
resolves.
|
|
26
50
|
* Visitors' existing choices keep working. v3 reads the v2 cookie.
|
|
27
51
|
* A self-hosted backend takes `database` instead of `adapter`, and needs a
|
|
28
52
|
schema migration.
|
|
29
53
|
* `@c15t/node-sdk` has a new client, `createC15tClient()`. Its methods return
|
|
30
54
|
results instead of throwing, and it reads no environment variables.
|
|
31
55
|
|
|
32
|
-
##
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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.
|
|
56
|
+
## Pick your guide
|
|
57
|
+
|
|
58
|
+
Each guide covers one v2 package from start to finish.
|
|
59
|
+
|
|
60
|
+
| You use in v2 | Follow |
|
|
61
|
+
| ----------------------------------------------------- | -------------------------------------------------------------------- |
|
|
62
|
+
| `@c15t/nextjs` | [Next.js](https://c15t.com/docs/frameworks/next/upgrade-v3) |
|
|
63
|
+
| `@c15t/react` | [React](./frameworks/react/upgrade-v3.md) |
|
|
64
|
+
| `c15t`, with `getOrCreateConsentRuntime` or the store | [JavaScript](https://c15t.com/docs/frameworks/javascript/upgrade-v3) |
|
|
65
|
+
|
|
66
|
+
v3 also adds TanStack Start, Nuxt, Vue, Astro, Svelte, SvelteKit and a script
|
|
67
|
+
tag. If you want to move to one of them, start with its quickstart from
|
|
68
|
+
[Choose your setup](./concepts/choose-your-setup.md).
|
|
69
|
+
|
|
70
|
+
If you run your own c15t backend, upgrade it in the same release as the
|
|
71
|
+
clients, following [Upgrade a self-hosted backend](#upgrade-a-self-hosted-backend).
|
|
72
|
+
Server code that calls the API with `@c15t/node-sdk` follows
|
|
73
|
+
[Update the Node.js SDK](#update-the-nodejs-sdk).
|
|
74
|
+
|
|
75
|
+
The sections below apply to every app.
|
|
77
76
|
|
|
78
77
|
## Rename the integrations dependency
|
|
79
78
|
|
|
@@ -91,21 +90,29 @@ dist-tag:
|
|
|
91
90
|
Replace the package name in each import. Vendor subpaths and helper names stay
|
|
92
91
|
the same.
|
|
93
92
|
|
|
94
|
-
Before, in v2
|
|
93
|
+
Before, in v2:
|
|
95
94
|
|
|
96
95
|
```ts
|
|
97
|
-
import {
|
|
96
|
+
import { googleTagManager } from '@c15t/scripts/google-tag-manager';
|
|
98
97
|
import { posthog } from '@c15t/scripts/posthog';
|
|
99
98
|
```
|
|
100
99
|
|
|
101
100
|
After:
|
|
102
101
|
|
|
103
102
|
```ts
|
|
104
|
-
import {
|
|
103
|
+
import { googleTagManager } from '@c15t/integrations/google-tag-manager';
|
|
105
104
|
import { posthog } from '@c15t/integrations/posthog';
|
|
106
105
|
```
|
|
107
106
|
|
|
108
107
|
The `scripts` configuration option and the `Script` type keep their names.
|
|
108
|
+
|
|
109
|
+
Two helper behaviors change. A helper that needs an ID, such as `metaPixel`,
|
|
110
|
+
`googleTagManager` or `posthog`, now throws when the ID is empty or only
|
|
111
|
+
whitespace, where v2 loaded a broken script. And if your code reads
|
|
112
|
+
`@c15t/integrations/registry`, an entry's `consentCategory` can now be a
|
|
113
|
+
compound condition such as `{ and: ['marketing', 'measurement'] }`, not only a
|
|
114
|
+
category name.
|
|
115
|
+
|
|
109
116
|
`@c15t/scripts` stays available as a deprecated compatibility package for all
|
|
110
117
|
of v3. It re-exports the implementation and types of `@c15t/integrations`, so
|
|
111
118
|
you can migrate imports separately from the rest of the upgrade. Compatibility
|
|
@@ -171,246 +178,86 @@ export function AcceptButton() {
|
|
|
171
178
|
The codemod keeps the entry you imported from. Change `@c15t/react` to
|
|
172
179
|
`c15t/react` afterwards if you moved to the umbrella package. Fields it cannot
|
|
173
180
|
rewrite stay on a `useConsentManager()` call under a `TODO(c15t v3)` comment,
|
|
174
|
-
which fails the build until you replace them. The table lists
|
|
181
|
+
which fails the build until you replace them. The table lists the v2 fields
|
|
182
|
+
components read. The other fields held provider configuration, such as
|
|
183
|
+
`legalLinks`, `scripts` and `storageConfig`, or store internals; set
|
|
184
|
+
configuration through `ConsentProvider` props.
|
|
175
185
|
Import hooks from `c15t/react`, `c15t/next` or `c15t/tanstack-start`, and
|
|
176
186
|
`useHeadlessConsentUI` from the matching `/headless` entry.
|
|
177
187
|
|
|
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()
|
|
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.
|
|
188
|
+
| v2 field | v3 replacement |
|
|
189
|
+
| ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
190
|
+
| `activeUI` | `useActiveUI()`. It returns `null` until c15t picks a surface, where v2 returned `'none'`. |
|
|
191
|
+
| `setActiveUI(ui)` | `useSetActiveUI()` |
|
|
192
|
+
| `has(category)` | `useConsent(category)`, one call per category at the top of the component |
|
|
193
|
+
| `consents` | `useConsents()` |
|
|
194
|
+
| `saveConsents('all')` | `useHeadlessConsentUI().saveCustomPreferences('all')` |
|
|
195
|
+
| `saveConsents('necessary')` | `useHeadlessConsentUI().saveCustomPreferences('none')` |
|
|
196
|
+
| `saveConsents('custom')` | `useConsentDraft().save()`, or `useHeadlessConsentUI().saveCustomPreferences()` inside a `ConsentDraftProvider` |
|
|
197
|
+
| `selectedConsents` | `useConsentDraft().values` |
|
|
198
|
+
| `setSelectedConsent(name, value)` | `useConsentDraft().set(name, value)` |
|
|
199
|
+
| `setConsent(name, value)` | `useSaveConsents()`, called with `{ [name]: value }` |
|
|
200
|
+
| `consentInfo` | `useExplicitChoice()` |
|
|
201
|
+
| `hasConsented()` | `useExplicitChoice() !== null` |
|
|
202
|
+
| `consentCategories`, `consentTypes`, `getDisplayedConsents()` | `useConsentDraft().displayedCategories`, with labels from `useTranslations().consentTypes` |
|
|
203
|
+
| `policyCategories` | `usePolicyCategories()`. The v2 list started with `'necessary'`; this one does not. |
|
|
204
|
+
| `policyScopeMode` | `usePolicyScopeMode()` |
|
|
205
|
+
| `policyBanner` | `usePromptPresentation()` |
|
|
206
|
+
| `policyDialog` | `usePreferencesPresentation()` |
|
|
207
|
+
| `model` | `useModel()`. It returns `null` while no policy matches, where v2 returned `'opt-in'`. |
|
|
208
|
+
| `branding` | `useBranding()`. It returns `null` when unset, where v2 returned `'c15t'`. |
|
|
209
|
+
| `iab` | `useIABSnapshot()` |
|
|
210
|
+
| `locationInfo` | `useLocation()` |
|
|
211
|
+
| `overrides`, `setOverrides()` | `useOverrides()`, `useSetOverrides()` |
|
|
212
|
+
| `setLanguage()` | `useSetLanguage()` |
|
|
213
|
+
| `user`, `identifyUser()` | `useUser()`, `useIdentify()` |
|
|
214
|
+
| `translationConfig` | `useTranslations()` for the active strings |
|
|
215
|
+
| `subscribeToConsentChanges(listener)` | `useSubscribeToConsentChanges()`, or the `onPermissionsChanged` callback |
|
|
216
|
+
| `updateConsentCategories(categories)` | `useRegisterConsentCategories()` |
|
|
217
|
+
| `manager` | Nothing. Use the hooks above. |
|
|
208
218
|
|
|
209
219
|
`saveCustomPreferences()` saves the way the stock buttons do. It closes the
|
|
210
220
|
banner or dialog after a successful save. `useSaveConsents()` calls the engine
|
|
211
221
|
directly and does not close anything.
|
|
212
222
|
|
|
213
223
|
In v2, `useConsentManager()` kept one draft per component. In v3,
|
|
214
|
-
`useConsentDraft()` and `useHeadlessConsentUI()` share
|
|
215
|
-
`ConsentDraftProvider`.
|
|
216
|
-
|
|
217
|
-
|
|
224
|
+
`useConsentDraft()` and `useHeadlessConsentUI()` share a draft only inside a
|
|
225
|
+
`ConsentDraftProvider`. Without one, `saveCustomPreferences()` saves a fresh
|
|
226
|
+
draft and ignores what `useConsentDraft().set()` staged, even in the same
|
|
227
|
+
component. Save with `useConsentDraft().save()`, or render the code that stages
|
|
228
|
+
and the code that saves inside one `ConsentDraftProvider`. `ConsentWidget`
|
|
229
|
+
already includes one. The codemod
|
|
218
230
|
adds a `TODO(c15t v3)` comment where this applies.
|
|
219
231
|
|
|
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';
|
|
226
|
-
|
|
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
|
-
}
|
|
244
|
-
```
|
|
245
|
-
|
|
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:
|
|
259
|
-
|
|
260
|
-
```tsx title="After (v3): components/consent-manager/provider.tsx, changed lines"
|
|
261
|
-
import { ConsentBanner, ConsentDialog, ConsentProvider, hosted } from 'c15t/next';
|
|
262
|
-
|
|
263
|
-
// In the component, replace ConsentManagerProvider:
|
|
264
|
-
<ConsentProvider
|
|
265
|
-
options={{ mode: hosted({ url: 'https://your-project.c15t.dev' }) }}
|
|
266
|
-
>
|
|
267
|
-
```
|
|
268
|
-
|
|
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](./frameworks/react/quickstart.md) 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
|
|
350
|
-
|
|
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
|
-
});
|
|
368
|
-
```
|
|
369
|
-
|
|
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
232
|
## Keep visitors' existing choices
|
|
404
233
|
|
|
405
234
|
v3 uses the same `c15t` cookie and storage key as v2 and reads v2 records. It
|
|
406
235
|
does not rewrite them on page load; the next accept, reject or save writes a
|
|
407
236
|
v3 record.
|
|
408
237
|
|
|
409
|
-
A v2 denial keeps restricting its category. A v2 grant keeps applying
|
|
410
|
-
|
|
411
|
-
|
|
238
|
+
A v2 denial keeps restricting its category. A v2 grant keeps applying until
|
|
239
|
+
the policy's validity period runs out, and then c15t asks again. If the rule
|
|
240
|
+
comes from a preset and the v2 record noted the policy it was made under, c15t
|
|
241
|
+
also asks again when that policy has changed. Under custom rules, a v2 grant
|
|
242
|
+
applies until it expires. Do not copy permissions into new
|
|
412
243
|
records yourself; c15t decides which v2 choices still count.
|
|
413
244
|
|
|
245
|
+
## Choose the HTML bundle
|
|
246
|
+
|
|
247
|
+
For HTML script tags, `c15t.js` is now the hosted bundle. Keep that filename
|
|
248
|
+
for Inth or a self-hosted backend and supply `data-backend-url`, a queued
|
|
249
|
+
`backendURL`, or a hosted factory. Loading it without a backend no longer
|
|
250
|
+
starts offline mode.
|
|
251
|
+
|
|
252
|
+
If an earlier v3 script tag used local policy rules, switch its URL to
|
|
253
|
+
`c15t.offline.js`. For manifest mode, custom transports or a page that selects
|
|
254
|
+
its mode at runtime, use the root ES module `@c15t/browser`, which still
|
|
255
|
+
accepts every mode. The headless script supports those modes with your own
|
|
256
|
+
UI, and the IAB script supports them for IAB policies. The self-hosted
|
|
257
|
+
backend's `/c15t.js` route now resolves policies through `/init`; its headless
|
|
258
|
+
and IAB routes still preload the manifest. See the
|
|
259
|
+
[script file reference](https://c15t.com/docs/frameworks/html/attributes-and-api#script-files).
|
|
260
|
+
|
|
414
261
|
## Upgrade a self-hosted backend
|
|
415
262
|
|
|
416
263
|
Deploy the v3 backend and the v3 clients in the same release. A v3 client
|
|
@@ -421,8 +268,9 @@ categories stay denied and no banner appears.
|
|
|
421
268
|
2. Replace `adapter` with `database` in your config. The Drizzle, Prisma,
|
|
422
269
|
TypeORM and Kysely adapters are gone; point `database` at the same SQL
|
|
423
270
|
database instead. MongoDB has no migration path.
|
|
424
|
-
3. Move `policyPacks`, `branding`, `
|
|
425
|
-
rename `policyPacks` to `policyRules`.
|
|
271
|
+
3. Move `policyPacks`, `branding`, `customTranslations`, `i18n` and `appName`
|
|
272
|
+
under `manifest`, and rename `policyPacks` to `policyRules`. Split `iab`
|
|
273
|
+
between `manifest.iab` and `gvl`, as the table below shows.
|
|
426
274
|
4. Back up the database, then plan and apply the schema migration:
|
|
427
275
|
|
|
428
276
|
```bash
|
|
@@ -437,9 +285,39 @@ nullable. [Database setup](https://c15t.com/docs/self-host/guides/database-setup
|
|
|
437
285
|
covers the details, and the [backend quickstart](https://c15t.com/docs/self-host/quickstart)
|
|
438
286
|
shows a complete v3 config and route.
|
|
439
287
|
|
|
288
|
+
The `backend-config-to-v3` codemod does step 3 for the keys that move as they
|
|
289
|
+
are, and leaves a `TODO(c15t v3)` comment on `adapter`, `iab`,
|
|
290
|
+
`disableGeoLocation` and the other options in the table below:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
npx @c15t/cli@alpha codemods backend-config-to-v3 policy-packs-to-policy-rules --dry-run --json
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Preset calls such as `policyRulePresets.europeOptIn()` need no other change.
|
|
297
|
+
A hand-written v2 pack uses `consent` and `ui` keys, which v3 rules replace
|
|
298
|
+
with flat keys such as `model` and `prompt`. See
|
|
299
|
+
[policy configuration](https://c15t.com/docs/self-host/guides/policy-packs).
|
|
300
|
+
|
|
301
|
+
The v3 backend stores timestamps in UTC. Convert rows that a v2 backend wrote
|
|
302
|
+
in another time zone before you deploy. Database setup lists the checks.
|
|
303
|
+
|
|
304
|
+
Other backend options and entries change too:
|
|
305
|
+
|
|
306
|
+
| v2 | v3 |
|
|
307
|
+
| ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
308
|
+
| `tablePrefix` | Removed. The migrator refuses a database with prefixed c15t tables, so rename them first. On PostgreSQL, `database.schema` keeps c15t's tables in their own schema. |
|
|
309
|
+
| `iab.vendorIds`, `iab.endpoint`, `cache.adapter` | `gvl: { vendorIds, endpoint, cache }` |
|
|
310
|
+
| `iab.enabled`, `iab.cmpId`, `iab.customVendors` | `manifest.iab` |
|
|
311
|
+
| `logger`, `telemetry` | `observability`, passed to `c15tInstance()` |
|
|
312
|
+
| `background`, `iab.bundled` | Removed |
|
|
313
|
+
| `openapi.docsPath`, `openapi.options`, `openapi.customUiTemplate` and the `/docs` page | Removed. The spec is still at `/spec.json`. |
|
|
314
|
+
| `policySnapshot.onValidationFailure` | Removed |
|
|
315
|
+
| `GET /` as an alias of `/status` | Removed. Call `/status`. |
|
|
316
|
+
| `@c15t/backend/define-config`, `/router`, `/types`, `/db/schema`, `/db/adapters/*`, `/db/migrator`, `/edge` | Removed. Import `defineConfig`, `createMigrator` and `policyRulePresets` from `@c15t/backend`. |
|
|
317
|
+
|
|
440
318
|
### Remove `disableGeoLocation`
|
|
441
319
|
|
|
442
|
-
v3 removes the `disableGeoLocation`
|
|
320
|
+
v3 removes the top-level `disableGeoLocation` option. Policy rules decide by
|
|
443
321
|
country and region. To show every visitor the same banner, configure one rule
|
|
444
322
|
with `match: { isDefault: true }`. It applies wherever the visitor is, so the
|
|
445
323
|
browser can resolve it without asking the backend for a location.
|
|
@@ -488,51 +366,64 @@ if (result.ok) {
|
|
|
488
366
|
}
|
|
489
367
|
```
|
|
490
368
|
|
|
491
|
-
| v2
|
|
492
|
-
|
|
|
493
|
-
| `c15tClient(options)`, `new C15TClient(options)`
|
|
494
|
-
| `C15T_API_URL`, `C15T_API_TOKEN` read from the environment
|
|
495
|
-
| `token`
|
|
496
|
-
| `prefix`
|
|
497
|
-
| `timeout`
|
|
498
|
-
| `retryConfig`
|
|
499
|
-
| `debug`, `C15T_DEBUG`
|
|
500
|
-
| `client.meta.status()`, `client.status()`
|
|
501
|
-
| `client.meta.init()`, `client.init()`
|
|
502
|
-
| `getSubject(id, { type: 'a,b' })`
|
|
503
|
-
| `createSubject(input)`
|
|
504
|
-
| `patchSubject(id, input)`, `subjects.patch(id, input)`
|
|
505
|
-
| `listSubjects({ externalId })`
|
|
506
|
-
| `checkConsent(query)`, `consent.check({ externalId, type: 'a,b' })`
|
|
507
|
-
| `
|
|
508
|
-
| `
|
|
509
|
-
| `
|
|
510
|
-
| `
|
|
511
|
-
| `
|
|
512
|
-
| `
|
|
513
|
-
| `
|
|
514
|
-
|
|
|
515
|
-
| `
|
|
369
|
+
| v2 | v3 |
|
|
370
|
+
| ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
371
|
+
| `c15tClient(options)`, `new C15TClient(options)` | `createC15tClient(options)` |
|
|
372
|
+
| `C15T_API_URL`, `C15T_API_TOKEN` read from the environment | Not read. Pass `baseUrl` and `apiKey`. |
|
|
373
|
+
| `token` | `apiKey` |
|
|
374
|
+
| `prefix` | Part of `baseUrl`. v2 replaced the base URL's path with `prefix`, so use the origin plus the prefix, such as `https://app.example.com/api/c15t`. |
|
|
375
|
+
| `timeout` | `timeoutMs`, per attempt. The default drops from 30 to 10 seconds. |
|
|
376
|
+
| `retryConfig` | `retry: { maxRetries, initialDelayMs, maxDelayMs }`, or `false`. `backoffFactor`, `retryableStatusCodes`, `nonRetryableStatusCodes` and `retryOnNetworkError` are gone. |
|
|
377
|
+
| `debug`, `C15T_DEBUG` | `onEvent` |
|
|
378
|
+
| `client.meta.status()`, `client.status()` | `c15t.status()` |
|
|
379
|
+
| `client.meta.init(options)`, `client.init(options)` | `c15t.init({ language, country, region, gpc }, options)`. Per-call options move to the second argument. |
|
|
380
|
+
| `getSubject(id, { type: 'a,b' })`, `subjects.get(id, { type: 'a,b' })` | `subjects.get(id, { types: ['a', 'b'] })` |
|
|
381
|
+
| `createSubject(input)` | `subjects.create(input)`. `givenAt` also takes a `Date`. |
|
|
382
|
+
| `patchSubject(id, input)`, `subjects.patch(id, input)` | `subjects.identify(id, { externalId, identityProvider })` |
|
|
383
|
+
| `listSubjects({ externalId })`, `subjects.list({ externalId })` | `subjects.list({ externalId })`, on a client with `apiKey` |
|
|
384
|
+
| `checkConsent(query)`, `consent.check({ externalId, type: 'a,b' })` | `consents.check({ externalId, types: ['a', 'b'] })`, on a client with `apiKey` |
|
|
385
|
+
| `ResponseContext` with `data: T \|null` | `{ ok: true, data } \|{ ok: false, error }`. Check `ok` first. |
|
|
386
|
+
| `unwrap()`, `expect()` on the response | `unwrap(result)`, imported from `@c15t/node-sdk` |
|
|
387
|
+
| `unwrapOr()`, `map()` on the response | Check `result.ok` |
|
|
388
|
+
| `throw: true` | `unwrap(result)` |
|
|
389
|
+
| `onSuccess`, `onError` | Check `result.ok` after the call |
|
|
390
|
+
| `C15TError`, `isC15TError()` | `C15tError`, `isC15tError(error, ...codes)` |
|
|
391
|
+
| `C15TClient`, `C15TClientOptions`, `RetryConfig`, `FetchOptions`, `ResponseContext` types | `C15tClient`, `C15tClientOptions`, `C15tRetryOptions`, `C15tCallOptions`, `C15tResult` |
|
|
392
|
+
| Per-call `timeout`, `retryConfig` | `timeoutMs`, `retry` |
|
|
393
|
+
| Per-call `body`, `query`, `method` | Removed. Pass the body and query as the method's arguments. |
|
|
394
|
+
| `$fetch`, `fetcher`, `resolveUrl`, `createResponseContext` | Removed. Pass a custom `fetch` to `createC15tClient` if you need one. |
|
|
395
|
+
| `createMockClient`, `createMockResponse`, `createMockErrorResponse` | `createMockC15tClient`, `ok`, `err` from `@c15t/node-sdk/testing` |
|
|
516
396
|
|
|
517
397
|
`patchSubject` returned `{ success, subject }`. `subjects.identify` returns
|
|
518
398
|
`{ subject }`, and `subject.identityProvider` is always set. Dates in
|
|
519
399
|
responses, such as `givenAt` and `createdAt`, are now `Date` objects rather
|
|
520
400
|
than strings.
|
|
521
401
|
|
|
522
|
-
|
|
523
|
-
|
|
402
|
+
`consents.check` and `subjects.list` count only verified links. Links made by
|
|
403
|
+
v2 don't count until you relink them with `subjects.identify` on a keyed
|
|
404
|
+
client, or [with an identity token](https://c15t.com/docs/self-host/api/node-sdk#verify-a-link-made-in-the-browser) on the user's next sign-in.
|
|
405
|
+
|
|
406
|
+
The `node-sdk-to-v3` codemod renames the factory, client options, methods,
|
|
407
|
+
types and errors in files that create a client. It turns `type` strings into
|
|
408
|
+
`types` arrays, and leaves a `TODO(c15t v3)` comment at each call, because
|
|
409
|
+
results are now `{ ok, data }` or `{ ok, error }`. It renames per-call
|
|
410
|
+
`timeout` and `retryConfig` too. It also marks `prefix`, `debug`, per-call
|
|
411
|
+
`throw`, `onSuccess`, `onError`, `body`, `query` and `method`, and a client
|
|
412
|
+
built from environment variables:
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
npx @c15t/cli@alpha codemods node-sdk-to-v3 --dry-run --json
|
|
416
|
+
```
|
|
524
417
|
|
|
525
|
-
|
|
418
|
+
The new client also adds `manifest()`, `legalDocuments.publish()` and
|
|
419
|
+
`experiments.summary()`. The last two need a client with `apiKey`. See the
|
|
420
|
+
[Node.js SDK reference](https://c15t.com/docs/self-host/api/node-sdk).
|
|
526
421
|
|
|
527
|
-
|
|
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.
|
|
422
|
+
## Update the CLI
|
|
536
423
|
|
|
537
|
-
|
|
538
|
-
|
|
424
|
+
* Run `c15t login` again. The CLI signs in through Inth now and no longer
|
|
425
|
+
reads sessions saved by v2.
|
|
426
|
+
* `c15t setup` no longer writes `.env.local` or `.env.example` and no longer
|
|
427
|
+
accepts `--env`. It writes the backend URL into the files it generates.
|
|
428
|
+
* `c15t setup` no longer detects Remix or Gatsby. Pick a guide from
|
|
429
|
+
[Choose your setup](./concepts/choose-your-setup.md) for those apps.
|