@c15t/react 3.0.0-alpha.9 → 3.0.0

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.
Files changed (147) hide show
  1. package/AGENTS.md +7 -9
  2. package/README.md +41 -70
  3. package/SKILL.md +1 -1
  4. package/dist/aggregate-components.js +1 -1
  5. package/dist/components/consent-gate/atoms.js +1 -1
  6. package/dist/components/consent-gate/frame.js +2 -0
  7. package/dist/components/consent-gate/index.js +1 -1
  8. package/dist/components/iab-panel/atoms/root.js +1 -1
  9. package/dist/components/iab-panel/iab-panel.js +1 -1
  10. package/dist/components/iab-prompt/atoms/root.js +1 -1
  11. package/dist/components/iab-prompt/iab-prompt.js +1 -1
  12. package/dist/components/panel/atoms/root.js +1 -1
  13. package/dist/components/panel-trigger/atoms/root.js +1 -1
  14. package/dist/components/panel-trigger/panel-trigger.js +1 -1
  15. package/dist/components/panel-trigger/toolbar-loader.js +2 -0
  16. package/dist/components/preferences/atoms/root.js +1 -1
  17. package/dist/components/prompt/atoms/early-tap-script.js +2 -0
  18. package/dist/components/prompt/atoms/root.js +1 -1
  19. package/dist/components/shared/primitives/button.js +1 -1
  20. package/dist/components/shared/surface-styles.js +1 -1
  21. package/dist/consent-gate.js +1 -1
  22. package/dist/context/index.js +1 -1
  23. package/dist/devtools.js +1 -1
  24. package/dist/iab/styles.tw3.css +2 -2
  25. package/dist/iab-dialog-deferred.js +2 -0
  26. package/dist/iab.js +1 -1
  27. package/dist/index-parts/consent-gate.js +1 -1
  28. package/dist/index-parts/core.js +1 -1
  29. package/dist/index-parts/frame.js +1 -0
  30. package/dist/index-parts/hosted.js +1 -0
  31. package/dist/index-parts/offline.js +1 -0
  32. package/dist/index-parts/presets.js +1 -0
  33. package/dist/index.js +1 -1
  34. package/dist/modes.js +1 -0
  35. package/dist/panel-link.js +1 -1
  36. package/dist/panel-trigger.js +1 -1
  37. package/dist/provider.js +1 -1
  38. package/dist/styles.tw3.css +2 -2
  39. package/dist/transports/hosted.js +1 -0
  40. package/dist/transports/manifest.js +1 -0
  41. package/dist/utils/deferred-module.js +1 -1
  42. package/dist/version.js +1 -1
  43. package/dist-types/chunk-warming.d.ts +7 -6
  44. package/dist-types/components/consent-gate/frame.d.ts +19 -0
  45. package/dist-types/components/consent-gate/index.d.ts +3 -19
  46. package/dist-types/components/iab-prompt/iab-prompt.d.ts +1 -1
  47. package/dist-types/components/panel/index.d.ts +1 -1
  48. package/dist-types/components/panel-trigger/toolbar-loader.d.ts +34 -0
  49. package/dist-types/components/preferences/index.d.ts +1 -1
  50. package/dist-types/components/prompt/atoms/early-tap-script.d.ts +17 -0
  51. package/dist-types/components/prompt/index.d.ts +1 -1
  52. package/dist-types/components/shared/surface-styles.d.ts +26 -2
  53. package/dist-types/consent-gate.d.ts +1 -1
  54. package/dist-types/context/index.d.ts +3 -3
  55. package/dist-types/context.d.ts +2 -0
  56. package/dist-types/gpp.d.ts +1 -1
  57. package/dist-types/iab-dialog-deferred.d.ts +36 -0
  58. package/dist-types/iab.d.ts +3 -2
  59. package/dist-types/index-parts/consent-gate.d.ts +1 -1
  60. package/dist-types/index-parts/core.d.ts +1 -2
  61. package/dist-types/index-parts/frame.d.ts +7 -0
  62. package/dist-types/index-parts/hosted.d.ts +7 -0
  63. package/dist-types/index-parts/offline.d.ts +7 -0
  64. package/dist-types/index-parts/presets.d.ts +7 -0
  65. package/dist-types/index.d.ts +5 -1
  66. package/dist-types/modes.d.ts +26 -0
  67. package/dist-types/panel-link.d.ts +1 -1
  68. package/dist-types/panel-trigger.d.ts +1 -1
  69. package/dist-types/provider.d.ts +3 -3
  70. package/dist-types/transports/hosted.d.ts +36 -0
  71. package/dist-types/transports/manifest.d.ts +48 -0
  72. package/dist-types/version.d.ts +1 -1
  73. package/docs/README.md +7 -9
  74. package/docs/concepts/choose-your-setup.md +45 -10
  75. package/docs/concepts/consent-categories.md +1 -1
  76. package/docs/concepts/consent-state.md +5 -2
  77. package/docs/concepts/data-fetching.md +100 -42
  78. package/docs/concepts/modes.md +281 -0
  79. package/docs/customization/dark-mode.md +1 -1
  80. package/docs/customization/motion.md +2 -2
  81. package/docs/customization/recipes.md +4 -4
  82. package/docs/customization/slots.md +25 -25
  83. package/docs/customization/stylesheets.md +12 -14
  84. package/docs/customization/tailwind.md +17 -11
  85. package/docs/customization/tokens.md +36 -7
  86. package/docs/frameworks/react/components/consent-banner.md +14 -10
  87. package/docs/frameworks/react/components/consent-dialog.md +14 -10
  88. package/docs/frameworks/react/components/consent-provider.md +51 -44
  89. package/docs/frameworks/react/components.md +14 -10
  90. package/docs/frameworks/react/content-security-policy.md +21 -12
  91. package/docs/frameworks/react/hooks.md +2 -2
  92. package/docs/frameworks/react/iab.md +20 -2
  93. package/docs/frameworks/react/quickstart.md +63 -97
  94. package/docs/frameworks/react/rendering.md +168 -94
  95. package/docs/frameworks/react/scripts.md +19 -28
  96. package/docs/frameworks/react/troubleshooting.md +57 -25
  97. package/docs/frameworks/react/upgrade-v3.md +110 -62
  98. package/docs/guides/banner-experiments.md +21 -6
  99. package/docs/guides/troubleshooting.md +89 -25
  100. package/docs/guides/verify-consent.md +23 -8
  101. package/docs/integrations/adobe-analytics.md +60 -64
  102. package/docs/integrations/ahrefs-analytics.md +58 -63
  103. package/docs/integrations/amplitude.md +60 -64
  104. package/docs/integrations/clearbit.md +59 -63
  105. package/docs/integrations/cloudflare-web-analytics.md +56 -60
  106. package/docs/integrations/cloudflare-zaraz.md +55 -57
  107. package/docs/integrations/crisp.md +64 -69
  108. package/docs/integrations/databuddy.md +62 -64
  109. package/docs/integrations/fathom-analytics.md +56 -60
  110. package/docs/integrations/front-chat.md +56 -60
  111. package/docs/integrations/google-maps.md +25 -13
  112. package/docs/integrations/google-tag-manager.md +153 -77
  113. package/docs/integrations/google-tag.md +134 -78
  114. package/docs/integrations/heap.md +56 -60
  115. package/docs/integrations/hightouch.md +55 -60
  116. package/docs/integrations/hotjar.md +60 -64
  117. package/docs/integrations/intercom.md +55 -60
  118. package/docs/integrations/klaviyo.md +65 -66
  119. package/docs/integrations/linkedin-insights.md +58 -63
  120. package/docs/integrations/logrocket.md +55 -60
  121. package/docs/integrations/matomo-analytics.md +58 -60
  122. package/docs/integrations/meta-pixel.md +56 -60
  123. package/docs/integrations/microsoft-clarity.md +57 -60
  124. package/docs/integrations/microsoft-uet.md +58 -61
  125. package/docs/integrations/mixpanel-analytics.md +73 -75
  126. package/docs/integrations/one-dollar-stats.md +53 -59
  127. package/docs/integrations/openai-pixel.md +58 -60
  128. package/docs/integrations/overview.md +59 -42
  129. package/docs/integrations/pinterest-tag.md +56 -60
  130. package/docs/integrations/pirsch.md +54 -60
  131. package/docs/integrations/plausible-analytics.md +55 -60
  132. package/docs/integrations/posthog.md +56 -60
  133. package/docs/integrations/promptwatch.md +57 -63
  134. package/docs/integrations/reddit-pixel.md +57 -60
  135. package/docs/integrations/rudderstack.md +65 -67
  136. package/docs/integrations/rybbit-analytics.md +70 -75
  137. package/docs/integrations/segment.md +56 -60
  138. package/docs/integrations/sentry.md +65 -60
  139. package/docs/integrations/snapchat-pixel.md +54 -60
  140. package/docs/integrations/tiktok-pixel.md +59 -63
  141. package/docs/integrations/umami-analytics.md +54 -60
  142. package/docs/integrations/vercel-analytics.md +53 -59
  143. package/docs/integrations/vercel-speed-insights.md +317 -0
  144. package/docs/integrations/x-pixel.md +57 -63
  145. package/docs/integrations/youtube.md +25 -13
  146. package/package.json +18 -8
  147. package/docs/upgrade-v3.md +0 -429
@@ -5,34 +5,12 @@ description: Fix a missing banner, early vendor requests, unstyled components
5
5
  group: frameworks
6
6
  ---
7
7
 
8
- ## Why does the build fail to download the manifest?
9
-
10
- **Check.** `vite build` or `vite dev` stops before compiling, with an error
11
- from `consentManifest` that starts with `@c15t/core/build:`.
12
-
13
- | Error | Cause | Fix |
14
- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
15
- | `build-time manifests require an absolute upstream URL.` | `backendURL` is empty or relative, such as `/api/c15t` | Pass the absolute backend URL from your Inth project |
16
- | `build-time manifests require an http(s) upstream URL.` | `backendURL` uses another protocol | Use the `https://` URL Inth shows |
17
- | `/manifest responded 404` | The URL is not your project's backend, such as the `https://your-project.inth.app` placeholder or a URL missing its path prefix | Copy the backend URL exactly as Inth shows it, or set `VITE_C15T_BACKEND_URL` |
18
- | `/manifest returned an invalid consent manifest.` | The URL answered with something other than a consent manifest, such as an HTML page | Point `backendURL` at the backend itself, not your site or a dashboard page |
19
- | `fetch failed` | The build cannot reach the backend | Build where the backend is reachable. A failed download never reuses an old snapshot |
20
-
21
- ## Why can't TypeScript find ./c15t-manifest?
22
-
23
- **Check.** `tsc`, `vue-tsc` or your editor reports that it cannot find the
24
- module `./c15t-manifest`, on a fresh checkout or in CI.
25
-
26
- **Fix.** `consentManifest` writes `src/c15t-manifest.ts` when `vite build` or
27
- `vite dev` starts, and the file is not in Git. Run one of them before the type
28
- check. In CI, run the build first, or cache the generated file with the build
29
- output.
30
-
31
8
  ## There is no banner
32
9
 
33
10
  **Check.** In DevTools Network, find the `GET` request to `/init` on your
34
- backend URL. With the bundled manifest, the browser makes no request before
35
- the banner unless the policy depends on a country or region it does not know.
11
+ backend URL. With `hosted()`, the browser sends it while the provider first
12
+ renders. With a bundled `manifest()`, the browser makes no request before the
13
+ banner unless the policy depends on a country or region it does not know.
36
14
 
37
15
  | What you see | Cause | Fix |
38
16
  | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -44,6 +22,60 @@ A policy with `prompt: 'none'` shows no banner by design, and so does a
44
22
  returning visitor with a valid stored choice. [Policies](../../concepts/policies.md)
45
23
  explains why a region may not show one.
46
24
 
25
+ ## Why does the build fail to download the manifest?
26
+
27
+ **Check.** `vite build` stops with an error from `consentManifest` that
28
+ starts with the plugin's name, such as
29
+ `@c15t/core/build: could not fetch the consent manifest from <url> during the
30
+ build`. The name is `@c15t/core/build` for `c15t/build` and `@c15t/vue/vite`
31
+ for `c15t/vue/vite`. `vite dev` logs the same message as a warning and keeps
32
+ going. The part in parentheses names the cause:
33
+
34
+ | Message | Cause | Fix |
35
+ | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
36
+ | `fetch failed`, with `ENOTFOUND`, `ECONNREFUSED` or another network error | The build cannot reach the backend | Build where the backend is reachable |
37
+ | `no response within 10 seconds` | The backend did not answer in time | Check the backend, or build where it is reachable |
38
+ | `/manifest responded 404` | The URL is not your project's backend, such as the `https://your-project.inth.app` placeholder or a URL missing its path prefix | Copy the backend URL exactly as Inth shows it, or set `VITE_C15T_BACKEND_URL` |
39
+ | `/manifest returned an invalid consent manifest.` | The URL answered with something other than a consent manifest, such as an HTML page | Point `backendURL` at the backend itself, not your site or a dashboard page |
40
+
41
+ A failed download never reuses an old snapshot. To deploy while the backend
42
+ is down, run the build with `C15T_ON_BUILD_ERROR=runtime`. `snapshot` is then
43
+ `undefined`, and the browser fetches the policy from the backend at runtime.
44
+
45
+ Only a build that uses `manifest()` downloads the manifest. The plugin
46
+ fetches after Vite has dropped the code the app does not use, so a `hosted()`
47
+ or `offline()` build never contacts the backend and never fails this way.
48
+
49
+ An error or warning that says `no backend URL is set` means the plugin found
50
+ no `backendURL` option and no variable. Set `VITE_C15T_BACKEND_URL` (or
51
+ `VITE_INTH_PROJECT_URL`) in `.env` or the build environment, or pass the absolute backend URL from your Inth
52
+ project. The [troubleshooting guide](../../guides/troubleshooting.md#why-does-the-build-fail-to-download-the-manifest)
53
+ lists every message.
54
+
55
+ A notice that the build `skipped the consent manifest fetch` means the backend
56
+ URL is relative, such as `/api/c15t`. Pass the absolute backend URL instead.
57
+ With `onBuildError: 'fail'`, this stops the build with `build-time manifests
58
+ require an absolute upstream URL`.
59
+
60
+ ## Why is snapshot undefined?
61
+
62
+ **Check.** `snapshot` from `c15t/generated` is `undefined`, and the browser
63
+ requests `${backendURL}/manifest` on page load.
64
+
65
+ **Fix.** `snapshot` is `undefined` when Vite has no policy to serve:
66
+
67
+ * `consentManifest` is missing from `plugins` in `vite.config.ts`. Without the
68
+ plugin, `c15t/generated` still resolves, but exports `undefined`.
69
+ * The fetch failed in `vite dev`, or in a build with
70
+ `C15T_ON_BUILD_ERROR=runtime`. The terminal shows a `could not fetch the
71
+ consent manifest` warning.
72
+ * The backend URL is relative, so the plugin skipped the fetch.
73
+ * `consentManifest({ source: 'runtime' })` is set, so the plugin never
74
+ fetches.
75
+
76
+ Fix the cause, then restart `vite dev` or rebuild. The plugin fetches once
77
+ when Vite starts.
78
+
47
79
  ## The page throws that no IABProvider is mounted
48
80
 
49
81
  The visitor's policy uses the `iab` model and the backend sent its vendor
@@ -6,8 +6,6 @@ description: Upgrade a React app from c15t v2 (@c15t/react) to v3. Covers
6
6
  group: frameworks
7
7
  ---
8
8
 
9
- ## Hand the upgrade to a coding agent
10
-
11
9
  **Upgrade this React app to c15t v3**
12
10
 
13
11
  Paste into Claude Code, Codex, Cursor or another coding agent at the root of your app.
@@ -15,15 +13,15 @@ Paste into Claude Code, Codex, Cursor or another coding agent at the root of you
15
13
  ```prompt
16
14
  Upgrade this React app from c15t v2 to c15t v3.
17
15
 
18
- Read <https://c15t.com/docs/frameworks/react/upgrade-v3.md> first and follow it in order. Do not guess v3 APIs from memory.
16
+ Read ./upgrade-v3.md first and follow it in order. Do not guess v3 APIs from memory.
19
17
 
20
18
  1. List every c15t dependency and import: `@c15t/react`, `@c15t/scripts`, `@c15t/dev-tools` and `c15t`.
21
19
  2. Check that React is 18 or later. Stop and tell me if it needs a major upgrade.
22
- 3. Replace the packages with `c15t@alpha`, plus `@c15t/integrations@alpha` if the app uses vendor helpers.
23
- 4. Run `npx @c15t/cli@alpha codemods consent-provider-options root-exports-to-subpaths use-consent-manager-to-hooks scripts-to-integrations dev-tools-to-c15t policy-packs-to-policy-rules callbacks-to-v3 theme-to-consent-theme iab-option-to-iab-provider css-variables-to-v3 postcss-tailwind3 --dry-run --json`. Review the output, then run the same command without `--dry-run`. The codemods leave a `TODO(c15t v3)` comment wherever they need you to finish a change.
20
+ 3. Replace the packages with `c15t`, plus `@c15t/integrations` if the app uses vendor helpers.
21
+ 4. Run `npx @c15t/cli codemods packages-to-c15t consent-provider-options root-exports-to-subpaths use-consent-manager-to-hooks scripts-to-integrations dev-tools-to-c15t policy-packs-to-policy-rules callbacks-to-v3 theme-to-consent-theme iab-option-to-iab-provider css-variables-to-v3 postcss-tailwind3 --dry-run --json`. Review the output, then run the same command without `--dry-run`. The codemods leave a `TODO(c15t v3)` comment wherever they need you to finish a change.
24
22
  5. Check that `ConsentManagerProvider` is now `ConsentProvider` from `c15t/react`, with a transport such as `hosted()` as `mode`. Finish any custom mode the codemod marked.
25
23
  6. Update callbacks, policy presets, renamed options and components, theme CSS, CSS variables and IAB setup as the guide describes.
26
- 7. Keep the existing backend URL. If the app runs its own c15t backend, stop and tell me, because it has to be upgraded in the same release.
24
+ 7. Keep the existing backend URL. If the app runs its own c15t backend, stop and tell me, because it has to be upgraded in the same release with <https://v3.c15t.com/docs/self-host/upgrade-v3.md>.
27
25
  8. Run the typecheck and build, and resolve every `TODO(c15t v3)` comment.
28
26
 
29
27
  When you finish, list the files you changed, anything you could not migrate, and how you checked that vendor requests still wait for consent.
@@ -34,22 +32,21 @@ When you finish, list the files you changed, anything you could not migrate, and
34
32
  * Upgrade React and React DOM to 18 or later.
35
33
  * If you run your own c15t backend, upgrade it in the same release. A v3
36
34
  client can't read a v2 backend. See
37
- [Upgrade a self-hosted backend](../../upgrade-v3.md#upgrade-a-self-hosted-backend).
35
+ [Upgrade a self-hosted backend](https://c15t.com/docs/self-host/upgrade-v3).
38
36
  Inth-hosted backends need no change.
39
37
 
40
38
  ## Replace the packages
41
39
 
42
- Remove `@c15t/react` and `@c15t/scripts`, then install `c15t` from the
43
- `alpha` dist-tag. npm's default tag still resolves v2.
40
+ Remove `@c15t/react` and `@c15t/scripts`, then install `c15t`.
44
41
 
45
- | Package manager | Command |
46
- | :-------------- | :------------------------------------------------ |
47
- | npm | `npm install c15t@alpha @c15t/integrations@alpha` |
48
- | pnpm | `pnpm add c15t@alpha @c15t/integrations@alpha` |
49
- | yarn | `yarn add c15t@alpha @c15t/integrations@alpha` |
50
- | bun | `bun add c15t@alpha @c15t/integrations@alpha` |
42
+ | Package manager | Command |
43
+ | :-------------- | :------------------------------------ |
44
+ | npm | `npm install c15t @c15t/integrations` |
45
+ | pnpm | `pnpm add c15t @c15t/integrations` |
46
+ | yarn | `yarn add c15t @c15t/integrations` |
47
+ | bun | `bun add c15t @c15t/integrations` |
51
48
 
52
- Drop `@c15t/integrations@alpha` if you don't use its vendor helpers.
49
+ Drop `@c15t/integrations` if you don't use its vendor helpers.
53
50
 
54
51
  | v2 import | v3 import |
55
52
  | --------------------------------------- | ---------------------------------------------------------------------------------- |
@@ -59,8 +56,11 @@ Drop `@c15t/integrations@alpha` if you don't use its vendor helpers.
59
56
  | `DevTools` from `@c15t/dev-tools/react` | `DevTools` from `c15t/react/devtools` |
60
57
  | `@c15t/scripts/*` | `@c15t/integrations/*` |
61
58
 
62
- `@c15t/react` is still published at v3, so its imports keep working if you pin
63
- it to `@alpha`. These docs use `c15t/react`.
59
+ The `packages-to-c15t` codemod rewrites the `@c15t/react` imports and removes
60
+ the stylesheet import. It doesn't edit `package.json`.
61
+
62
+ `@c15t/react` is still published at v3, so its imports keep working after you
63
+ upgrade it. These docs use `c15t/react`.
64
64
 
65
65
  Every v3 package ships ESM only. If a CommonJS file in your app calls
66
66
  `require()` on a c15t package, convert it to ESM.
@@ -68,15 +68,14 @@ Every v3 package ships ESM only. If a CommonJS file in your app calls
68
68
  ## Rename the integrations dependency
69
69
 
70
70
  v3 renames `@c15t/scripts` to `@c15t/integrations`. Remove `@c15t/scripts`
71
- from your dependencies and install `@c15t/integrations` from the `alpha`
72
- dist-tag:
71
+ from your dependencies and install `@c15t/integrations`:
73
72
 
74
- | Package manager | Command |
75
- | :-------------- | :------------------------------------- |
76
- | npm | `npm install @c15t/integrations@alpha` |
77
- | pnpm | `pnpm add @c15t/integrations@alpha` |
78
- | yarn | `yarn add @c15t/integrations@alpha` |
79
- | bun | `bun add @c15t/integrations@alpha` |
73
+ | Package manager | Command |
74
+ | :-------------- | :------------------------------- |
75
+ | npm | `npm install @c15t/integrations` |
76
+ | pnpm | `pnpm add @c15t/integrations` |
77
+ | yarn | `yarn add @c15t/integrations` |
78
+ | bun | `bun add @c15t/integrations` |
80
79
 
81
80
  Replace the package name in each import. Vendor subpaths and helper names stay
82
81
  the same.
@@ -98,11 +97,11 @@ import { posthog } from '@c15t/integrations/posthog';
98
97
  The `scripts` configuration option and the `Script` type keep their names.
99
98
 
100
99
  Two helper behaviors change. A helper that needs an ID, such as `metaPixel`,
101
- `googleTagManager` or `posthog`, now throws when the ID is empty or only
102
- whitespace, where v2 loaded a broken script. And if your code reads
103
- `@c15t/integrations/registry`, an entry's `consentCategory` can now be a
104
- compound condition such as `{ and: ['marketing', 'measurement'] }`, not only a
105
- category name.
100
+ `googleTagManager` or `posthog`, now logs an error and skips its script when
101
+ the ID is empty or only whitespace, where v2 loaded a broken script. And if
102
+ your code reads `@c15t/integrations/registry`, an entry's `consentCategory` can
103
+ now be a compound condition such as `{ and: ['marketing', 'measurement'] }`,
104
+ not only a category name.
106
105
 
107
106
  `@c15t/scripts` stays available as a deprecated compatibility package for all
108
107
  of v3. It re-exports the implementation and types of `@c15t/integrations`, so
@@ -112,7 +111,7 @@ ends in v4; versions already published stay on npm.
112
111
  To preview the import changes in JavaScript and TypeScript files:
113
112
 
114
113
  ```bash
115
- npx @c15t/cli@alpha codemods scripts-to-integrations --dry-run --json
114
+ npx @c15t/cli codemods scripts-to-integrations --dry-run --json
116
115
  ```
117
116
 
118
117
  Review the output, then run it again without `--dry-run`. The codemod runs
@@ -127,7 +126,7 @@ that called it re-rendered on every change. v3 has one hook per field. Run the
127
126
  codemod first:
128
127
 
129
128
  ```bash
130
- npx @c15t/cli@alpha codemods use-consent-manager-to-hooks --dry-run --json
129
+ npx @c15t/cli codemods use-consent-manager-to-hooks --dry-run --json
131
130
  ```
132
131
 
133
132
  Review the proposed files, then run it again without `--dry-run`. For this v2
@@ -227,7 +226,7 @@ a transport as `mode`:
227
226
 
228
227
  | v2 option | v3 option |
229
228
  | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
230
- | `mode: 'hosted'` with `backendURL` | `mode: hosted({ url })` |
229
+ | `mode: 'hosted'` with `backendURL` | `mode: hosted({ backendURL })` |
231
230
  | `mode: 'offline'` with `offlinePolicy` | `mode: offline({ policyRules })` |
232
231
  | `mode: 'custom'` with `endpointHandlers` | `mode: custom(transport)`, where `transport` implements the v3 transport interface. `endpointHandlers` throws. |
233
232
 
@@ -236,7 +235,7 @@ import { ConsentBanner, ConsentDialog, ConsentProvider, hosted } from 'c15t/reac
236
235
 
237
236
  // Replace ConsentManagerProvider:
238
237
  <ConsentProvider
239
- options={{ mode: hosted({ url: 'https://your-project.c15t.dev' }) }}
238
+ options={{ mode: hosted({ backendURL: 'https://your-project.c15t.dev' }) }}
240
239
  >
241
240
  ```
242
241
 
@@ -245,7 +244,7 @@ and adds the transport import. It can't translate `endpointHandlers`, so it
245
244
  leaves a `TODO(c15t v3)` comment on a custom mode:
246
245
 
247
246
  ```bash
248
- npx @c15t/cli@alpha codemods consent-provider-options --dry-run --json
247
+ npx @c15t/cli codemods consent-provider-options --dry-run --json
249
248
  ```
250
249
 
251
250
  Keep your backend URL. An existing hosted URL such as
@@ -254,6 +253,13 @@ projects use URLs such as `https://your-project.inth.app`. The
254
253
  [React quickstart](./quickstart.md) shows the full provider,
255
254
  and [data fetching](../../concepts/data-fetching.md) covers custom transports.
256
255
 
256
+ The quickstart keeps `hosted()` and adds `consentManifest()` from
257
+ `c15t/build` to `vite.config.ts`. `hosted()` then reads the backend URL from
258
+ `VITE_C15T_BACKEND_URL`, so it needs no arguments. v3 also adds `manifest()`,
259
+ which bundles the policy when Vite builds. It skips `/init` only when the
260
+ policy has no location rules or the page knows the visitor's location. See
261
+ [consent modes](../../concepts/modes.md).
262
+
257
263
  Offline mode keeps choices in the browser and records nothing on a server. Not
258
264
  recommended for production environments.
259
265
 
@@ -279,7 +285,7 @@ payload, and on `onConsentSet` and `onBannerFetched`, which it can't choose a
279
285
  replacement for:
280
286
 
281
287
  ```bash
282
- npx @c15t/cli@alpha codemods callbacks-to-v3 --dry-run --json
288
+ npx @c15t/cli codemods callbacks-to-v3 --dry-run --json
283
289
  ```
284
290
 
285
291
  v2's `onConsentChanged` fired only when a save changed at least one category's
@@ -336,6 +342,9 @@ const mode = offline({
336
342
  });
337
343
  ```
338
344
 
345
+ In Next.js, import `offline` from `c15t/next` instead and set the result as
346
+ `mode` in `c15t.config.ts`. Both take the same `policyRules`.
347
+
339
348
  | v2 preset | v3 preset |
340
349
  | ----------------------------------------- | ----------------------- |
341
350
  | `europeOptIn()`, `europeIab()` | Same names |
@@ -362,25 +371,25 @@ between a permission and a recorded choice.
362
371
 
363
372
  ## Rename options and components
364
373
 
365
- | v2 | v3 |
366
- | -------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
367
- | `translations` | `i18n` |
368
- | `backendURL`, `mode: 'hosted'` | `mode: hosted({ url })` |
369
- | `ssrData` (Next.js) | `ConsentRoot` with `state` from `resolveConsent()` |
370
- | `iframeBlockerConfig` | `iframeBlocker`, or `false` to turn it off |
371
- | `Frame` | `ConsentGate`. `Frame` still works as a deprecated alias. |
372
- | `frame` translations, such as `frame.title` | `consentGate`, such as `consentGate.title`. Copy under `frame` still applies and logs a warning outside production. |
373
- | `FrameTranslations` | `ConsentGateTranslations`. `FrameTranslations` still works as a deprecated alias. |
374
- | `--frame-*` CSS variables | `--consent-gate-*`, with the same suffixes, such as `--consent-gate-placeholder-background-color`. The old names no longer apply. |
375
- | `YouTubeEmbed`, `GoogleMap` | Removed. Wrap your own embed in `ConsentGate`. |
376
- | `useConsentScript()` | Removed. Register the script in `scripts` with a `@c15t/integrations` helper. |
377
- | `useSSRStatus()` | Removed |
378
- | `ConsentButton` | Removed. Use the `ConsentBanner` and `ConsentWidget` buttons, or call `useHeadlessConsentUI()` from your own button. |
379
- | `@c15t/react/cookie-banner` | `c15t/react/consent-banner` |
380
- | `retryConfig` | Removed |
381
- | `store`, including `namespace`, `debug`, `initialConsentCategories` and `initialTranslationConfig` | Removed. Use the top-level `consentCategories` and `i18n` options. Debug information is on `window.c15t`. |
382
- | `window.c15tStore` | `window.c15t` |
383
- | `iab: iab({ ... })` | `IABProvider`. See [Move IAB setup](#move-iab-setup-to-iabprovider). |
374
+ | v2 | v3 |
375
+ | -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
376
+ | `translations` | `i18n` |
377
+ | `backendURL`, `mode: 'hosted'` | `mode: hosted({ backendURL })` from `c15t/react` on `ConsentProvider`. Next.js `ConsentRoot`: `NEXT_PUBLIC_C15T_BACKEND_URL` and `c15t.config.ts`. |
378
+ | `ssrData` (Next.js) | `ConsentRoot` with `state` from `resolveConsent()` |
379
+ | `iframeBlockerConfig` | `iframeBlocker`, or `false` to turn it off |
380
+ | `Frame`, `FrameRoot`, `FrameTitle`, `FrameButton`, `FrameProps` | `ConsentGate` and its parts. The `Frame` names still work as deprecated aliases and log a one-time warning outside production. |
381
+ | `frame` translations, such as `frame.title` | `consentGate`, such as `consentGate.title`. Copy under `frame` still applies and logs a warning outside production. |
382
+ | `FrameTranslations` | `ConsentGateTranslations`. `FrameTranslations` still works as a deprecated alias. |
383
+ | `--frame-*` CSS variables | `--consent-gate-*`, with the same suffixes, such as `--consent-gate-placeholder-background-color`. The old names no longer apply. |
384
+ | `YouTubeEmbed`, `GoogleMap` | Removed. Wrap your own embed in `ConsentGate`. |
385
+ | `useConsentScript()` | Removed. Register the script in `scripts` with a `@c15t/integrations` helper. |
386
+ | `useSSRStatus()` | Removed |
387
+ | `ConsentButton` | Removed. Use the `ConsentBanner` and `ConsentWidget` buttons, or call `useHeadlessConsentUI()` from your own button. |
388
+ | `@c15t/react/cookie-banner` | `c15t/react/consent-banner` |
389
+ | `retryConfig` | Removed |
390
+ | `store`, including `namespace`, `debug`, `initialConsentCategories` and `initialTranslationConfig` | Removed. Use the top-level `consentCategories` and `i18n` options. Debug information is on `window.c15t`. |
391
+ | `window.c15tStore` | `window.c15t` |
392
+ | `iab: iab({ ... })` | `IABProvider`. See [Move IAB setup](#move-iab-setup-to-iabprovider). |
384
393
 
385
394
  The `consent-provider-options` codemod renames `ConsentManagerProvider` and
386
395
  its option and prop types, turns `mode` and `backendURL` into `hosted()` or
@@ -389,7 +398,7 @@ deprecated `translations` option; the `translations-to-i18n` codemod moves it
389
398
  to `i18n`.
390
399
 
391
400
  ```bash
392
- npx @c15t/cli@alpha codemods consent-provider-options translations-to-i18n --dry-run --json
401
+ npx @c15t/cli codemods consent-provider-options translations-to-i18n --dry-run --json
393
402
  ```
394
403
 
395
404
  `ConsentBanner`, `ConsentDialog`, `ConsentDialogLink`, `ConsentDialogTrigger`
@@ -417,7 +426,7 @@ The `root-exports-to-subpaths` codemod moves these imports to their new
417
426
  entries and marks removed names with a `TODO(c15t v3)` comment:
418
427
 
419
428
  ```bash
420
- npx @c15t/cli@alpha codemods root-exports-to-subpaths --dry-run --json
429
+ npx @c15t/cli codemods root-exports-to-subpaths --dry-run --json
421
430
  ```
422
431
 
423
432
  `ConsentGate` changes one behavior from `Frame`. When its category is granted,
@@ -459,6 +468,9 @@ A generated theme uses `:root:root`, so your own `--c15t-*` values on plain
459
468
  `styles: false` in the provider options so the components add no second
460
469
  copy. See
461
470
  [stylesheets and CSS layers](../../customization/stylesheets.md#import-the-stylesheet-yourself).
471
+ The `packages-to-c15t` codemod removes `@c15t/react` and `@c15t/nextjs`
472
+ stylesheet imports. With Tailwind CSS 3 or a cascade layer it keeps them,
473
+ pointed at `c15t`, with a `TODO(c15t v3)` comment.
462
474
  * With manual styles, `iab/styles.css` no longer repeats the default tokens.
463
475
  Import it after `styles.css`. Automatic IAB styling needs neither import.
464
476
  * Tailwind CSS 3 needs a PostCSS plugin for c15t's `styles.css`. Add
@@ -486,7 +498,7 @@ The `css-variables-to-v3` codemod renames `--consent-widget-*` and
486
498
  `theme.slots.consentDialogFooter` and marks `theme.slots.frame`.
487
499
 
488
500
  ```bash
489
- npx @c15t/cli@alpha codemods theme-to-consent-theme css-variables-to-v3 postcss-tailwind3 --dry-run --json
501
+ npx @c15t/cli codemods theme-to-consent-theme css-variables-to-v3 postcss-tailwind3 --dry-run --json
490
502
  ```
491
503
 
492
504
  `theme.slots` now applies in React. v2 accepted it in types and ignored it, so
@@ -509,8 +521,8 @@ the CMP doesn't mount, so there is no `__tcfapi` and no TC string.
509
521
  `@c15t/iab` no longer exports `createIABManager`, `decodeTCString`,
510
522
  `generateTCString` or `c15tToIabPurposes`. Use `createIAB({ kernel, cmpId })`,
511
523
  which returns a handle with `generateTCString()`, `acceptAll()`, `rejectAll()`
512
- and `save()`. If your app depends on `@c15t/iab` directly, upgrade it to
513
- `@c15t/iab@alpha` too, or your import resolves to the v2 package. Remove it if
524
+ and `save()`. If your app depends on `@c15t/iab` directly, upgrade it to v3
525
+ too, on the same release as `c15t`. Remove it if
514
526
  `IABProvider` now covers everything you used it for.
515
527
 
516
528
  Server integrations now send a reference to the Global Vendor List instead of
@@ -574,9 +586,45 @@ The `dev-tools-to-c15t` codemod points the imports at `c15t/react/devtools` and
574
586
  removes the `namespace` prop:
575
587
 
576
588
  ```bash
577
- npx @c15t/cli@alpha codemods dev-tools-to-c15t --dry-run --json
589
+ npx @c15t/cli codemods dev-tools-to-c15t --dry-run --json
578
590
  ```
579
591
 
592
+ ## Upgrade from an earlier v3 alpha
593
+
594
+ The v3 alphas renamed and removed APIs that never shipped in a stable release.
595
+ Names that were in stable v2 keep a deprecated alias. Every other renamed name
596
+ is removed with no alias, so a build that still uses one fails to type-check
597
+ or throws at runtime.
598
+
599
+ ### Deprecated, still working
600
+
601
+ Only React's v2 `Frame` names remain. They render `ConsentGate` and, outside
602
+ production, log a one-time warning such as
603
+ ``c15t: `Frame` is deprecated and will be removed in a future major release. Use `ConsentGate` instead.``
604
+
605
+ | Package | Deprecated | Use instead |
606
+ | ------------------------------------------------ | ---------------------------------------------------------------------------- | --------------------------------------------------- |
607
+ | `c15t/react`, `c15t/next`, `c15t/tanstack-start` | `Frame`, `FrameRoot`, `FrameTitle`, `FrameButton`, and the `FrameProps` type | `ConsentGate` and its parts, and `ConsentGateProps` |
608
+
609
+ v2's `ConsentManagerProvider` and string modes such as `mode: 'hosted'` are
610
+ handled by the `consent-provider-options` codemod, not by aliases.
611
+
612
+ ### Removed
613
+
614
+ | Removed | Use instead |
615
+ | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
616
+ | `hosted({ url })` | `hosted({ backendURL })`, or the framework's backend URL variable |
617
+ | `createManifestTransport({ manifest })` | `createManifestTransport({ snapshot })` |
618
+ | `assertDecisionInputs` defaulting to `false` on `hosted()` | It now defaults to `true` whenever `initURL` is set. Pass `false` to turn it off. |
619
+ | `hostedModes` from `c15t/runtime/provider` | `readHostedMode(mode)` |
620
+ | `buildManifest: true` in Astro and Nuxt | `onBuildError: 'fail'`, the default for production builds. `buildManifest: false` is `manifest({ source: 'runtime' })`. |
621
+ | A generated `c15t-manifest.ts` and its `.gitignore` entry | `import { snapshot } from 'c15t/generated'`. Most apps no longer import it at all. |
622
+ | The build options `outputFile`, `exportName`, `importSource` and `rootDir` | Removed. The snapshot is a virtual module, or a file under `node_modules/.cache/c15t/` in Next.js. |
623
+
624
+ React removes nothing besides the modes above. Import `manifest()` from
625
+ `c15t/react`, next to `hosted()` and `offline()`, instead of from
626
+ `@c15t/browser/headless`; React apps need nothing from `@c15t/browser`.
627
+
580
628
  ## Update the CLI
581
629
 
582
630
  * Run `c15t login` again. The CLI signs in through Inth now and no longer
@@ -32,7 +32,7 @@ import type { ReactNode } from 'react';
32
32
 
33
33
  import { scripts } from './scripts';
34
34
 
35
- const mode = hosted({ url: 'https://your-project.inth.app' });
35
+ const mode = hosted({ backendURL: 'https://your-project.inth.app' });
36
36
 
37
37
  // `control` is the stock banner. `wall` blocks the page until the visitor
38
38
  // chooses.
@@ -256,7 +256,6 @@ import { resolveConsent } from 'c15t/next/server';
256
256
  import { Suspense } from 'react';
257
257
  import type { ReactNode } from 'react';
258
258
 
259
- import { consentOptions } from '@/c15t.server';
260
259
  import { ExperimentConsent } from '@/components/experiment-consent';
261
260
  import { bannerExperiment } from '@/lib/experiment';
262
261
  import { bannerExperimentFlag } from '@/lib/flags';
@@ -266,7 +265,6 @@ import '@/styles/globals.css';
266
265
  const ResolvedConsent = async ({ children }: { children: ReactNode }) => {
267
266
  const arm = await bannerExperimentFlag();
268
267
  const state = await resolveConsent({
269
- ...consentOptions,
270
268
  // `off` keeps this visitor out of the experiment.
271
269
  experiment: arm === 'off' ? undefined : { ...bannerExperiment, arm },
272
270
  });
@@ -399,6 +397,22 @@ arm re-assigns only the visitors who were in it. For a clean analysis, change
399
397
  Built-in assignment is not available in Astro; see
400
398
  [Astro](#astro).
401
399
 
400
+ A Vite app's early `/init` script, from `consentManifest()`, picks the arm
401
+ the same way when you pass it the experiment, and the app then runs that
402
+ arm. Import the same object into `vite.config.ts`:
403
+
404
+ ```ts title="vite.config.ts"
405
+ consentManifest({ initPrefetch: { experiment: bannerExperiment } });
406
+ ```
407
+
408
+ Without it, the app sends its own `/init` for visitors who have not chosen
409
+ yet. The same goes for `consentPrefetchHead` in TanStack Start and
410
+ `buildPrefetchScript` elsewhere, which take the same `experiment` option.
411
+
412
+ When a feature flag picks the arm, leave `experiment` out of
413
+ `initPrefetch`. The script would pick its own arm and send it to the
414
+ backend, and the app would then send a second `/init` with the flag's arm.
415
+
402
416
  ## Acknowledge presentation diagnostics
403
417
 
404
418
  Each arm is resolved under the visitor's policy the same way `presentation`
@@ -492,11 +506,12 @@ owed to, and how many of them accepted. c15t sends both to the backend on
492
506
  its own; you do not wire anything up.
493
507
 
494
508
  * **Visitors owed the banner.** While a visitor has no stored choice, every
495
- `/init` carries their arm in an `x-c15t-experiment: <id>=<arm>` header,
496
- and the backend puts it on that request's session report as
509
+ `/init` carries their arm as `<id>=<arm>` in the `experiment` query
510
+ parameter, and the backend puts it on that request's session report as
497
511
  `experiment: { id, arm }`. In manifest mode, the server render or the
498
512
  init route puts it on the report it sends to `POST /sessions`. A visitor
499
- who already chose is not shown the banner, so is not counted.
513
+ who already chose is not shown the banner, so is not counted. A
514
+ server-to-server caller can send the `x-c15t-experiment` header instead.
500
515
  * **Choices.** Every choice saved through `POST /subjects` carries the arm
501
516
  in `metadata.experiment`, as above.
502
517