@c15t/scripts 2.2.0 → 3.0.0-alpha.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 (197) hide show
  1. package/AGENTS.md +74 -48
  2. package/README.md +3 -3
  3. package/dist/e2e-test-utils.js +60 -24
  4. package/dist/engine/compile.js +45 -45
  5. package/dist/engine/runtime.js +119 -119
  6. package/dist/registry.js +186 -176
  7. package/dist/resolve.js +12 -12
  8. package/dist/vendors/_shared/attributes.js +5 -5
  9. package/dist/vendors/_shared/google-consent.js +10 -10
  10. package/dist/vendors/_shared/install-builders.js +9 -9
  11. package/dist/vendors/_shared/script-url.js +12 -12
  12. package/dist/vendors/ads-and-pixels/linkedin-insights.js +16 -16
  13. package/dist/vendors/ads-and-pixels/meta-pixel.js +82 -82
  14. package/dist/vendors/ads-and-pixels/microsoft-uet.js +57 -57
  15. package/dist/vendors/ads-and-pixels/openai-pixel.js +88 -0
  16. package/dist/vendors/ads-and-pixels/reddit-pixel.js +39 -39
  17. package/dist/vendors/ads-and-pixels/snapchat-pixel.js +25 -25
  18. package/dist/vendors/ads-and-pixels/tiktok-pixel.js +31 -31
  19. package/dist/vendors/ads-and-pixels/x-pixel.js +17 -17
  20. package/dist/vendors/analytics/adobe-analytics.js +17 -17
  21. package/dist/vendors/analytics/ahrefs-analytics.js +8 -8
  22. package/dist/vendors/analytics/amplitude.js +39 -39
  23. package/dist/vendors/analytics/clearbit.js +11 -11
  24. package/dist/vendors/analytics/cloudflare-web-analytics.js +13 -13
  25. package/dist/vendors/analytics/databuddy.js +45 -45
  26. package/dist/vendors/analytics/fathom-analytics.js +15 -15
  27. package/dist/vendors/analytics/google-tag.js +23 -23
  28. package/dist/vendors/analytics/heap.js +37 -37
  29. package/dist/vendors/analytics/hightouch.js +30 -30
  30. package/dist/vendors/analytics/hotjar.js +14 -14
  31. package/dist/vendors/analytics/logrocket.js +24 -24
  32. package/dist/vendors/analytics/matomo-analytics.js +51 -51
  33. package/dist/vendors/analytics/microsoft-clarity.js +31 -31
  34. package/dist/vendors/analytics/mixpanel-analytics.js +31 -31
  35. package/dist/vendors/analytics/pirsch.js +27 -27
  36. package/dist/vendors/analytics/plausible-analytics.js +24 -24
  37. package/dist/vendors/analytics/posthog.js +84 -79
  38. package/dist/vendors/analytics/promptwatch.js +8 -8
  39. package/dist/vendors/analytics/rudderstack.js +50 -50
  40. package/dist/vendors/analytics/rybbit-analytics.js +30 -30
  41. package/dist/vendors/analytics/segment.js +16 -16
  42. package/dist/vendors/analytics/umami-analytics.js +16 -16
  43. package/dist/vendors/analytics/vercel-analytics.js +22 -22
  44. package/dist/vendors/functional/crisp.js +49 -51
  45. package/dist/vendors/functional/intercom.js +18 -18
  46. package/dist/vendors/tag-managers/google-tag-manager.js +20 -20
  47. package/dist-types/__tests__/helpers.d.ts +10 -10
  48. package/dist-types/engine/compile.d.ts +2 -2
  49. package/dist-types/engine/runtime.d.ts +3 -3
  50. package/dist-types/registry.d.ts +182 -173
  51. package/dist-types/resolve.d.ts +2 -2
  52. package/dist-types/types.d.ts +2 -2
  53. package/dist-types/vendors/_shared/attributes.d.ts +2 -2
  54. package/dist-types/vendors/_shared/google-consent.d.ts +2 -2
  55. package/dist-types/vendors/_shared/install-builders.d.ts +1 -1
  56. package/dist-types/vendors/_shared/script-url.d.ts +6 -6
  57. package/dist-types/vendors/ads-and-pixels/linkedin-insights.d.ts +14 -14
  58. package/dist-types/vendors/ads-and-pixels/meta-pixel.d.ts +27 -27
  59. package/dist-types/vendors/ads-and-pixels/microsoft-uet.d.ts +40 -40
  60. package/dist-types/vendors/ads-and-pixels/openai-pixel.d.ts +211 -0
  61. package/dist-types/vendors/ads-and-pixels/reddit-pixel.d.ts +28 -29
  62. package/dist-types/vendors/ads-and-pixels/snapchat-pixel.d.ts +23 -23
  63. package/dist-types/vendors/ads-and-pixels/tiktok-pixel.d.ts +22 -22
  64. package/dist-types/vendors/ads-and-pixels/x-pixel.d.ts +15 -15
  65. package/dist-types/vendors/analytics/adobe-analytics.d.ts +3 -3
  66. package/dist-types/vendors/analytics/ahrefs-analytics.d.ts +5 -5
  67. package/dist-types/vendors/analytics/amplitude.d.ts +24 -24
  68. package/dist-types/vendors/analytics/clearbit.d.ts +5 -5
  69. package/dist-types/vendors/analytics/cloudflare-web-analytics.d.ts +6 -6
  70. package/dist-types/vendors/analytics/databuddy.d.ts +34 -31
  71. package/dist-types/vendors/analytics/fathom-analytics.d.ts +8 -8
  72. package/dist-types/vendors/analytics/google-tag.d.ts +17 -17
  73. package/dist-types/vendors/analytics/heap.d.ts +17 -17
  74. package/dist-types/vendors/analytics/hightouch.d.ts +15 -15
  75. package/dist-types/vendors/analytics/hotjar.d.ts +9 -9
  76. package/dist-types/vendors/analytics/logrocket.d.ts +11 -11
  77. package/dist-types/vendors/analytics/matomo-analytics.d.ts +3 -3
  78. package/dist-types/vendors/analytics/microsoft-clarity.d.ts +12 -13
  79. package/dist-types/vendors/analytics/mixpanel-analytics.d.ts +20 -20
  80. package/dist-types/vendors/analytics/pirsch.d.ts +10 -10
  81. package/dist-types/vendors/analytics/plausible-analytics.d.ts +13 -13
  82. package/dist-types/vendors/analytics/posthog.d.ts +35 -32
  83. package/dist-types/vendors/analytics/promptwatch.d.ts +5 -5
  84. package/dist-types/vendors/analytics/rudderstack.d.ts +16 -16
  85. package/dist-types/vendors/analytics/rybbit-analytics.d.ts +15 -15
  86. package/dist-types/vendors/analytics/segment.d.ts +11 -11
  87. package/dist-types/vendors/analytics/umami-analytics.d.ts +9 -9
  88. package/dist-types/vendors/analytics/vercel-analytics.d.ts +13 -13
  89. package/dist-types/vendors/functional/crisp.d.ts +9 -9
  90. package/dist-types/vendors/functional/intercom.d.ts +12 -12
  91. package/dist-types/vendors/tag-managers/google-tag-manager.d.ts +16 -16
  92. package/docs/README.md +74 -48
  93. package/docs/assets/v3/brand-bar.png +0 -0
  94. package/docs/assets/v3/brand-card.png +0 -0
  95. package/docs/assets/v3/choice-wall.png +0 -0
  96. package/docs/assets/v3/mobile-card.png +0 -0
  97. package/docs/assets/v3/preferences.png +0 -0
  98. package/docs/customization/overview.md +45 -0
  99. package/docs/customization/recipes.md +79 -0
  100. package/docs/customization/slots.md +55 -0
  101. package/docs/customization/tokens.md +76 -0
  102. package/docs/customization/translations.md +49 -0
  103. package/docs/frameworks/javascript/script-loader.md +30 -339
  104. package/docs/frameworks/next/script-loader.md +134 -467
  105. package/docs/frameworks/react/script-loader.md +35 -535
  106. package/docs/guides/consent-state.md +60 -0
  107. package/docs/guides/data-fetching.md +163 -0
  108. package/docs/guides/deployment-modes.md +63 -0
  109. package/docs/guides/troubleshooting.md +68 -0
  110. package/docs/guides/verify-consent.md +62 -0
  111. package/docs/integrations/adobe-analytics.md +239 -105
  112. package/docs/integrations/ahrefs-analytics.md +238 -104
  113. package/docs/integrations/amplitude.md +219 -157
  114. package/docs/integrations/building-integrations.md +32 -224
  115. package/docs/integrations/clearbit.md +247 -86
  116. package/docs/integrations/cloudflare-web-analytics.md +250 -84
  117. package/docs/integrations/crisp.md +251 -97
  118. package/docs/integrations/databuddy.md +259 -153
  119. package/docs/integrations/fathom-analytics.md +239 -96
  120. package/docs/integrations/google-maps.md +328 -207
  121. package/docs/integrations/google-tag-manager.md +248 -96
  122. package/docs/integrations/google-tag.md +261 -90
  123. package/docs/integrations/heap.md +222 -149
  124. package/docs/integrations/hightouch.md +225 -131
  125. package/docs/integrations/hotjar.md +239 -90
  126. package/docs/integrations/intercom.md +239 -98
  127. package/docs/integrations/linkedin-insights.md +243 -113
  128. package/docs/integrations/logrocket.md +241 -123
  129. package/docs/integrations/matomo-analytics.md +256 -111
  130. package/docs/integrations/meta-pixel.md +197 -324
  131. package/docs/integrations/microsoft-clarity.md +233 -114
  132. package/docs/integrations/microsoft-uet.md +245 -110
  133. package/docs/integrations/mixpanel-analytics.md +252 -87
  134. package/docs/integrations/openai-pixel.md +441 -0
  135. package/docs/integrations/overview.md +95 -133
  136. package/docs/integrations/pirsch.md +249 -96
  137. package/docs/integrations/plausible-analytics.md +241 -100
  138. package/docs/integrations/posthog.md +353 -214
  139. package/docs/integrations/promptwatch.md +251 -81
  140. package/docs/integrations/reddit-pixel.md +226 -173
  141. package/docs/integrations/rudderstack.md +244 -187
  142. package/docs/integrations/rybbit-analytics.md +244 -91
  143. package/docs/integrations/segment.md +238 -92
  144. package/docs/integrations/snapchat-pixel.md +240 -110
  145. package/docs/integrations/tiktok-pixel.md +249 -81
  146. package/docs/integrations/umami-analytics.md +242 -95
  147. package/docs/integrations/vercel-analytics.md +242 -90
  148. package/docs/integrations/x-pixel.md +238 -104
  149. package/docs/integrations/youtube.md +354 -142
  150. package/docs/upgrade-v3.md +334 -0
  151. package/package.json +85 -78
  152. package/readme.json +2 -2
  153. package/dist/e2e-test-utils.cjs +0 -166
  154. package/dist/engine/compile.cjs +0 -130
  155. package/dist/engine/runtime.cjs +0 -475
  156. package/dist/registry.cjs +0 -423
  157. package/dist/resolve.cjs +0 -71
  158. package/dist/types.cjs +0 -69
  159. package/dist/vendors/_shared/attributes.cjs +0 -55
  160. package/dist/vendors/_shared/google-consent.cjs +0 -69
  161. package/dist/vendors/_shared/install-builders.cjs +0 -59
  162. package/dist/vendors/_shared/script-url.cjs +0 -78
  163. package/dist/vendors/ads-and-pixels/linkedin-insights.cjs +0 -89
  164. package/dist/vendors/ads-and-pixels/meta-pixel.cjs +0 -206
  165. package/dist/vendors/ads-and-pixels/microsoft-uet.cjs +0 -151
  166. package/dist/vendors/ads-and-pixels/reddit-pixel.cjs +0 -151
  167. package/dist/vendors/ads-and-pixels/snapchat-pixel.cjs +0 -131
  168. package/dist/vendors/ads-and-pixels/tiktok-pixel.cjs +0 -130
  169. package/dist/vendors/ads-and-pixels/x-pixel.cjs +0 -92
  170. package/dist/vendors/analytics/adobe-analytics.cjs +0 -90
  171. package/dist/vendors/analytics/ahrefs-analytics.cjs +0 -68
  172. package/dist/vendors/analytics/amplitude.cjs +0 -193
  173. package/dist/vendors/analytics/clearbit.cjs +0 -69
  174. package/dist/vendors/analytics/cloudflare-web-analytics.cjs +0 -73
  175. package/dist/vendors/analytics/databuddy.cjs +0 -144
  176. package/dist/vendors/analytics/fathom-analytics.cjs +0 -76
  177. package/dist/vendors/analytics/google-tag.cjs +0 -107
  178. package/dist/vendors/analytics/heap.cjs +0 -181
  179. package/dist/vendors/analytics/hightouch.cjs +0 -153
  180. package/dist/vendors/analytics/hotjar.cjs +0 -85
  181. package/dist/vendors/analytics/logrocket.cjs +0 -99
  182. package/dist/vendors/analytics/matomo-analytics.cjs +0 -232
  183. package/dist/vendors/analytics/microsoft-clarity.cjs +0 -138
  184. package/dist/vendors/analytics/mixpanel-analytics.cjs +0 -134
  185. package/dist/vendors/analytics/pirsch.cjs +0 -108
  186. package/dist/vendors/analytics/plausible-analytics.cjs +0 -122
  187. package/dist/vendors/analytics/posthog.cjs +0 -236
  188. package/dist/vendors/analytics/promptwatch.cjs +0 -70
  189. package/dist/vendors/analytics/rudderstack.cjs +0 -227
  190. package/dist/vendors/analytics/rybbit-analytics.cjs +0 -104
  191. package/dist/vendors/analytics/segment.cjs +0 -97
  192. package/dist/vendors/analytics/umami-analytics.cjs +0 -80
  193. package/dist/vendors/analytics/vercel-analytics.cjs +0 -94
  194. package/dist/vendors/functional/crisp.cjs +0 -143
  195. package/dist/vendors/functional/intercom.cjs +0 -89
  196. package/dist/vendors/tag-managers/google-tag-manager.cjs +0 -100
  197. package/docs/shared/react/guides/script-loader.md +0 -311
@@ -0,0 +1,334 @@
1
+ ---
2
+ title: Upgrade to v3 policies
3
+ description: Migrate policy configuration, consent records, callbacks, and
4
+ custom transports to the v3 policy system.
5
+ group: reference
6
+ ---
7
+
8
+ ## Start with a policy rule
9
+
10
+ ```ts
11
+ import { policyRulePresets } from '@c15t/schema';
12
+ import { offline } from '@c15t/react';
13
+
14
+ const mode = offline({
15
+ policyRules: [policyRulePresets.europeOptIn()],
16
+ });
17
+ ```
18
+
19
+ Pass `mode` to `ConsentProvider`. For a backend integration, configure
20
+ `policyRules` on the backend and use `hosted({ url })` in the provider. Follow the
21
+ [React quickstart](https://c15t.com/docs/frameworks/react/quickstart),
22
+ [Next.js quickstart](https://c15t.com/docs/frameworks/next/quickstart), or
23
+ [JavaScript quickstart](https://c15t.com/docs/frameworks/javascript/quickstart) for a complete
24
+ integration.
25
+
26
+ The CLI no longer offers `offline-add-policy-packs`, which generated v2
27
+ configuration. For offline integrations, configure `offline({ policyRules })`
28
+ as shown above.
29
+
30
+ Replace legacy `policyPacks` and nested `consent` configuration with rules:
31
+
32
+ ```ts
33
+ import type { PolicyRule } from '@c15t/schema';
34
+
35
+ const policyRules = [
36
+ {
37
+ id: 'default-opt-in',
38
+ match: { fallback: true },
39
+ model: 'opt-in',
40
+ prompt: 'choice',
41
+ categories: ['measurement', 'marketing'],
42
+ scopeMode: 'strict',
43
+ },
44
+ ] satisfies PolicyRule[];
45
+ ```
46
+
47
+ `model` controls permission defaults. `prompt` controls whether the visitor must
48
+ make a choice, dismiss a notice, or see no prompt. Opt-in and IAB models require
49
+ `prompt: 'choice'`. Opt-out supports `choice`, `notice`, and `none`. The `none`
50
+ model permits optional categories in scope, allows only `prompt: 'none'`, owes
51
+ no rights, and renders no consent UI. v2's `none` model maps to it directly.
52
+
53
+ When `categories` selects only some optional categories, you must set
54
+ `scopeMode` explicitly. A strict scope blocks categories outside the rule. A permissive scope allows
55
+ those categories unless another restriction applies. An omitted scope, `['*']`,
56
+ or a list containing only `necessary` expands to the default optional categories.
57
+ `necessary` is always permitted.
58
+
59
+ `offline()` without `policyRules` resolves `recommendedPolicyRules()`, whose
60
+ Europe rule also matches a visitor with no country. A known US country with a
61
+ missing state uses US opt-out with GPC and persistent preferences; a missing
62
+ Canadian province stays strict opt-in. The last rule is `none` for other known
63
+ unmatched locations. Resolution exposes `matched`, `no-match`,
64
+ `unconfigured`, or `failed`; while nothing has matched, optional categories stay
65
+ denied and no consent surface renders. A missing or malformed policy never grants
66
+ optional permissions by itself.
67
+
68
+ ## Read the state you need
69
+
70
+ | Purpose | Snapshot field | React hook |
71
+ | ----------------------------------------------- | ---------------------- | --------------------------------------- |
72
+ | Gate scripts and optional features | `effectivePermissions` | `useConsent(category)`, `useConsents()` |
73
+ | Inspect recorded choices and confirmation times | `explicitChoice` | `useExplicitChoice()` |
74
+ | Decide whether to prompt | `promptRequirement` | `usePromptRequirement()` |
75
+ | Inspect the resolved rule | `policyRule` | `usePolicyRule()` |
76
+ | Inspect matching or failure | `resolution` | `usePolicyResolution()` |
77
+
78
+ An effective permission is not evidence of a grant. Under an opt-out rule it can
79
+ be true before a visitor acts. A notice dismissal updates `noticeDismissal` and
80
+ does not record consent. Global Privacy Control updates privacy signals and
81
+ configured opt-out directives without turning a browser signal into a choice.
82
+
83
+ ## Replace choice callbacks
84
+
85
+ ```tsx
86
+ <ConsentProvider
87
+ options={{
88
+ mode,
89
+ callbacks: {
90
+ onChoiceRecorded(event) {
91
+ console.log('Visitor recorded a choice', event);
92
+ },
93
+ onPermissionsChanged(event) {
94
+ console.log('Effective permissions changed', event);
95
+ },
96
+ },
97
+ }}
98
+ >
99
+ {children}
100
+ </ConsentProvider>
101
+ ```
102
+
103
+ Replace `onConsentSet` with `onChoiceRecorded` for explicit accept, reject, or
104
+ save actions. Use `onPermissionsChanged` for permission changes caused by a
105
+ choice, expiry, policy update, or privacy signal. Provider callbacks no longer
106
+ include `onBannerFetched`; use the resolved policy and pending state to render
107
+ loading UI.
108
+
109
+ Only `kernel.commands.save()` creates an explicit choice. `save('all')` accepts,
110
+ `save('none')` rejects, and `save({ marketing: false })` confirms only marketing.
111
+ A partial save keeps the other categories' confirmation times. Use
112
+ `commands.dismissNotice()` for the notice action and `kernel.hydrate()` to apply
113
+ validated records without recording an action.
114
+
115
+ ## Keep existing storage
116
+
117
+ The reader accepts valid v2 storage and translates it into per-category receipts.
118
+ It does not rewrite storage on startup. Existing denials continue to restrict
119
+ permissions; expired or incompatible positive receipts cannot restore grants.
120
+ The next explicit action writes the v3 record. Notice dismissal and privacy
121
+ opt-out directives have separate records.
122
+
123
+ Pass server-prepared `initialRecords`, `initialPolicyResolution`, and `now`
124
+ through the adapter's prefetch configuration. Do not rebuild consent from a
125
+ boolean `hasConsented` or copy effective permissions into explicit choice records.
126
+ Pending prefetch results cannot restore records after a clear or overwrite a
127
+ newer choice.
128
+
129
+ ## Update custom transports and backend clients
130
+
131
+ Use `KernelTransport` from `@c15t/core/transports`. Init returns a versioned
132
+ `policyResolution` with a matched rule and fingerprints, or an explicit
133
+ non-matched outcome. Use `mapInitOutputToInitResponse` for an HTTP init payload.
134
+ Do not return legacy `policy` or `policyDecision` fields.
135
+
136
+ Save requests contain the explicit choice and the categories confirmed by this
137
+ action. Return a `SaveResult` with `ok`; optional identity and record methods
138
+ must preserve the same receipt format. Forward the policy contract headers when
139
+ implementing an HTTP proxy. Keep client, schema, backend, and framework adapters
140
+ on compatible v3 versions.
141
+
142
+ Use the supplied hosted or manifest transports to capture policy evidence for
143
+ saves and retries. They preserve the action's policy, location, language, and
144
+ privacy signal inputs. A stale policy assertion is an error; it must not silently
145
+ save under a different rule. See the
146
+ [backend endpoint reference](https://c15t.com/docs/self-host/api/endpoints) for wire fields.
147
+
148
+ ## Shared runtime ownership
149
+
150
+ Astro and SvelteKit can create a runtime outside a component tree with
151
+ `createConsentRuntime` from `@c15t/core/runtime`. Pass that runtime to a
152
+ framework provider with its `runtime` prop. The owner calls `start()` after
153
+ mount and `dispose()` when the page no longer needs it. Borrowing providers
154
+ subscribe to the kernel and render UI without initializing or disposing it.
155
+
156
+ Runtime construction preserves the prepared server snapshot. Storage reads,
157
+ privacy-signal activation and script loading begin on `start()`. Pass server
158
+ records through `prefetch.initialRecords` with their evaluation time to keep
159
+ the first browser render consistent with the server. `runtime.clearRecords()`
160
+ clears both persisted and in-memory records.
161
+
162
+ Runtime callbacks use `onChoiceRecorded`, `onPermissionsChanged` and
163
+ `onError`. Hydrating records does not report a new visitor choice.
164
+
165
+ Astro's serializable offline descriptor accepts `policyRules`, just like the
166
+ other adapters' offline factories. Configure a preset or explicit rules;
167
+ omitting them keeps the conservative fallback.
168
+
169
+ ## Presentation corrections
170
+
171
+ Use `blocking` for backdrop, scroll locking and focus trapping together.
172
+ Choice banners default to non-blocking, choice walls always block, and notices
173
+ never block. A notice configured as a wall falls back to a floating card.
174
+ Preferences remain centered; `variant` and `position` apply only to prompts.
175
+
176
+ Replace reads of `uncoveredRights` with `preferenceControls`. The latter is a
177
+ list of additional preferences buttons recommended for the stock UI. It does
178
+ not verify disclosure or persistent access to policy rights.
179
+
180
+ Notice acknowledgement uses `common.acknowledge`, falling back to
181
+ `common.dismiss` for older translation bundles. It does not record a choice.
182
+
183
+ ## Astro notice acknowledgement
184
+
185
+ ```astro
186
+ ---
187
+ import ConsentBanner from '@c15t/astro/components/consent-banner.astro';
188
+ ---
189
+
190
+ <ConsentBanner dismissButtonText="Got it" />
191
+ ```
192
+
193
+ Astro's `ConsentBanner` accepts `dismissButtonText` as an optional string. It
194
+ labels the notice acknowledgement button, which defaults to
195
+ `common.acknowledge` and falls back to `common.dismiss` in older translation
196
+ bundles. Acknowledging a notice preserves the visitor's consent choices.
197
+
198
+ ## IAB blocking behavior
199
+
200
+ IAB banners and dialogs use the same `presentation.prompt.blocking` and
201
+ `presentation.preferences.blocking` settings as the other consent components.
202
+ A blocking surface shows a backdrop, traps focus and locks page scrolling.
203
+ Explicit `blocking` values take precedence over deprecated `scrollLock` and
204
+ `trapFocus` options. IAB components stay hidden without a matched policy,
205
+ including when a dialog receives `open={true}`.
206
+
207
+ The React consent dialog still blocks pointer interaction with the page when
208
+ `blocking` is true and you hide its backdrop with `overlay={false}`.
209
+
210
+ Legacy prompt options now control the whole blocking behavior. For example,
211
+ `scrollLock: true` alone enables a backdrop and focus trapping as well as
212
+ scroll locking. Set `blocking: false` explicitly for a non-modal banner.
213
+
214
+ Custom dialog backdrops follow the same rule. A dialog resolved as non-blocking
215
+ omits both the default backdrop and a supplied `overlay`. To retain a custom
216
+ backdrop when migrating from `trapFocus: false`, set
217
+ `presentation.preferences.blocking: true` and keep your `overlay` prop.
218
+
219
+ ## Next.js and TanStack Start renames
220
+
221
+ These names changed without deprecated aliases. `defineConsentConfig`,
222
+ `ConsentConfig` (the URL config) and `ConsentProvider` from `@c15t/react` are
223
+ unchanged.
224
+
225
+ Next.js (`c15t/next`, `c15t/next/server`, `c15t/next/pages`):
226
+
227
+ | v2 | v3 |
228
+ | --------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
229
+ | `ConsentBoundary` | `ConsentRoot` |
230
+ | `ConsentBoundaryProps` | `ConsentRootProps` |
231
+ | `config={initialConsent}` (the visitor's resolved state) | `state={...}` |
232
+ | `consent={consentConfig}` (the `defineConsentConfig` result) | `config={consentConfig}` |
233
+ | `prefetchInitialConsent(options)` | `resolveConsent(options)` with `config` or `backendURL` |
234
+ | `readInitialConsentConfig(options)` | `resolveConsent(options)` without `config` or `backendURL` |
235
+ | `InitialConsentConfig`, and `KernelConfig` where it named the returned value | `ConsentState` |
236
+ | `PrefetchInitialConsentOptions` | `ResolveConsentOptions` |
237
+ | `ReadInitialConsentConfigOptions` | `ConsentRequestOptions` |
238
+ | Pages Router `readInitialConsentConfig(req, opts)` and `prefetchInitialConsent({ req, ... })` | `resolveConsent({ req, ... })` |
239
+
240
+ TanStack Start (`c15t/tanstack-start`, `c15t/tanstack-start/server`):
241
+
242
+ | v2 | v3 |
243
+ | ------------------------------------- | ---------------------------------------------- |
244
+ | `ConsentBoundary` | `ConsentRoot` |
245
+ | `config={config}` | `state={state}` |
246
+ | `ConsentConfig` (the returned state) | `ConsentState` |
247
+ | `prefetchInitialConsent` | `resolveConsent(options)` with `backendURL` |
248
+ | `readInitialConsentConfig` | `resolveConsent(options)` without `backendURL` |
249
+ | `createConsentConfigHandler(options)` | `createConsentStateHandler(options)` |
250
+ | `mergeInitIntoConsentConfig` | `mergeInitIntoConsentState` |
251
+
252
+ `consentLoaderOptions`, `backendURL`, `initRoute` and `DEFAULT_INIT_ROUTE` are
253
+ unchanged.
254
+
255
+ ## Next.js RSC banner removal
256
+
257
+ The `@c15t/nextjs/rsc` entry (`c15t/next/rsc`) and its `RscConsentBanner`,
258
+ `RscBannerGate` and `RscBannerActions` exports are gone. Imports of that
259
+ entry now fail to resolve. Use the regular banner for server rendering.
260
+ The retained benchmark results showed slightly faster banner visibility and
261
+ interaction for the experimental shell, so this removal should not be read
262
+ as a performance improvement.
263
+
264
+ Replace `<RscConsentBanner config={config} />` with `<ConsentBanner />` inside
265
+ the same `ConsentRoot`, importing it from `c15t/next` when you use the
266
+ umbrella package or from `@c15t/nextjs` when you depend on the scoped package
267
+ directly. With an awaited `resolveConsent` result, the server renders
268
+ the banner into the response, which is what the RSC variant was for. Move
269
+ `presentation` to `options.presentation` on `ConsentRoot`.
270
+
271
+ Two defaults differ from the removed shell. It rendered no branding link, so
272
+ pass `hideBranding` to keep that. It also styled only its root and action row
273
+ (through the stock `ConsentBanner.Root` and `PolicyActions`) and left the
274
+ card, title, description, footer and buttons without base classes, whereas
275
+ `ConsentBanner` merges the stock styles into every part. If that changes a
276
+ custom layout, do not reach for `noStyle` on the whole banner, which also
277
+ drops the root positioning and action-row layout the old shell kept; compose
278
+ the compound parts instead and pass `noStyle` only to the parts you styled
279
+ yourself.
280
+
281
+ `ConsentBanner` has no `classNames` or `children` props. Move each legacy
282
+ `classNames` key to the `ConsentRoot` `options.components` slots, which take
283
+ `{ className }`:
284
+
285
+ | `classNames` key | Replacement |
286
+ | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
287
+ | `root`, `card`, `title`, `footer` | `components.banner.root`, `.card`, `.title`, `.footer` |
288
+ | `description` | `components.description.banner` |
289
+ | `rights`, `rightLink` | `components.banner.rights`, `components.banner.rightLink` |
290
+ | `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. |
291
+
292
+ Custom `children`, and any direct use of `RscBannerGate` or
293
+ `RscBannerActions`, map to the compound parts of `ConsentBanner` in a Client
294
+ Component. `RscBannerGate` becomes `ConsentBanner.Root`, which mounts only
295
+ while the policy owes a prompt and reopens on expiry. Remove the gate
296
+ `prompt` and `model` props; the root derives `data-prompt` and `data-model`
297
+ from the `ConsentRoot` policy. Rename `title` to `aria-label` to preserve its
298
+ accessible label. Keep `children`, `className`, `variant`, `position` and
299
+ `blocking` on the root. Add `disableAnimation` and `trapFocus={false}` to
300
+ retain the old gate defaults.
301
+
302
+ `RscBannerActions`
303
+ becomes `ConsentBanner.PolicyActions`, which renders the rights links and the
304
+ action row the policy requires; `ConsentBanner.Rights`, `RightLink`, `Footer`,
305
+ `FooterSubGroup` and the four buttons are available for finer control.
306
+ `PolicyActions` takes none of the old `acceptLabel`, `rejectLabel`,
307
+ `customizeLabel`, `dismissLabel`, `rightLabels` or `classNames` props: set
308
+ labels through the provider `i18n` translation overrides (`common.acceptAll`,
309
+ `common.rejectAll`, `common.customize`, `common.acknowledge`, `rights.*`), or
310
+ render `ConsentBanner.AcceptButton` and the other buttons with your own
311
+ children; `renderAction` on `PolicyActions` replaces one button; classes move
312
+ to the `components` slots listed in the table. Place the former `children`
313
+ inside `ConsentBanner.Card`:
314
+
315
+ ```tsx title="components/banner.tsx"
316
+ 'use client';
317
+
318
+ import { ConsentBanner } from 'c15t/next';
319
+
320
+ export function Banner() {
321
+ return (
322
+ <ConsentBanner.Root>
323
+ <ConsentBanner.Card>
324
+ <ConsentBanner.Header>
325
+ <ConsentBanner.Title />
326
+ <ConsentBanner.Description />
327
+ </ConsentBanner.Header>
328
+ <a href="/privacy">Privacy policy</a>
329
+ <ConsentBanner.PolicyActions />
330
+ </ConsentBanner.Card>
331
+ </ConsentBanner.Root>
332
+ );
333
+ }
334
+ ```