cloudflare-next-intl 0.4.1 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -1
- package/dist/src/cookie_consent/client/components/cookie_consent_dialog.d.ts +9 -2
- package/dist/src/cookie_consent/client/components/cookie_consent_dialog.js +7 -3
- package/dist/src/cookie_consent/client/components/default_privacy_policy_link.d.ts +14 -0
- package/dist/src/cookie_consent/client/components/default_privacy_policy_link.js +21 -0
- package/dist/src/cookie_consent/client/components/privacy_policy_update_dialog.d.ts +9 -2
- package/dist/src/cookie_consent/client/components/privacy_policy_update_dialog.js +7 -3
- package/dist/src/cookie_consent/client/cookie_consent_provider.js +3 -2
- package/dist/src/cookie_consent/gdpr_countries.bench.js +5 -1
- package/dist/src/cookie_consent/gdpr_countries.d.ts +2 -2
- package/dist/src/cookie_consent/gdpr_countries.js +2 -2
- package/dist/src/cookie_consent/index.d.ts +1 -1
- package/dist/src/cookie_consent/types.d.ts +7 -0
- package/dist/src/types/index.d.ts +1 -1
- package/dist/src/types/types.d.ts +38 -11
- package/llms.txt +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -193,14 +193,21 @@ auto-wires `CookieConsentProvider` (and `CookieConsentAnalytics`, if
|
|
|
193
193
|
|
|
194
194
|
```typescript
|
|
195
195
|
// intl-config.ts
|
|
196
|
+
import { getCloudflareContext } from "@opennextjs/cloudflare";
|
|
197
|
+
|
|
196
198
|
export default setIntlConfig({
|
|
197
199
|
locales: ["en", "de"],
|
|
198
200
|
defaultLocale: "en",
|
|
199
201
|
cookieConsent: {
|
|
200
202
|
privacyPolicyDate: "2026-01-01",
|
|
203
|
+
// privacyPolicyPath: "/privacy-policy", // default; used by the
|
|
204
|
+
// dialogs' auto-rendered link. Set false to disable that link.
|
|
201
205
|
// Optional: gate the banner to GDPR-region visitors only. Omit both
|
|
202
206
|
// getters to disable country-based gating (consent always implicit).
|
|
203
|
-
getCloudflareContext
|
|
207
|
+
// Pass @opennextjs/cloudflare's getCloudflareContext directly — its
|
|
208
|
+
// exact overloaded signature is accepted as-is, called internally
|
|
209
|
+
// with { async: true }.
|
|
210
|
+
getCloudflareContext,
|
|
204
211
|
// gdprCountries: [...], // defaults to EU/EEA + UK + Switzerland
|
|
205
212
|
// enableAnalyticsInDevMode: true, // analytics stay off in dev otherwise
|
|
206
213
|
},
|
|
@@ -2,8 +2,15 @@ import type { CookieDialogClassNames, CookieDialogStyles } from '../../types';
|
|
|
2
2
|
export interface CookieConsentDialogProps {
|
|
3
3
|
/** Banner message text. */
|
|
4
4
|
message?: React.ReactNode;
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Link element rendered right after `message`. Defaults to a link to
|
|
7
|
+
* `cookieConsent.privacyPolicyPath` (`'/privacy-policy'` unless
|
|
8
|
+
* configured otherwise) with `privacyPolicyLinkText` as its label. Pass
|
|
9
|
+
* `null` to render no link, or your own element to override it.
|
|
10
|
+
*/
|
|
6
11
|
link?: React.ReactNode;
|
|
12
|
+
/** Label for the default privacy-policy link. Ignored when `link` is set. */
|
|
13
|
+
privacyPolicyLinkText?: string;
|
|
7
14
|
acceptText?: string;
|
|
8
15
|
declineText?: string;
|
|
9
16
|
/** Hides the decline ("necessary only") button, leaving only accept. */
|
|
@@ -25,4 +32,4 @@ export interface CookieConsentDialogProps {
|
|
|
25
32
|
* `render` (full custom markup) — none of it is hardcoded to Tailwind or any
|
|
26
33
|
* particular design system.
|
|
27
34
|
*/
|
|
28
|
-
export default function CookieConsentDialog({ message, link, acceptText, declineText, hideDecline, id, classNames, styles, render, }: CookieConsentDialogProps): React.ReactElement | null;
|
|
35
|
+
export default function CookieConsentDialog({ message, link, privacyPolicyLinkText, acceptText, declineText, hideDecline, id, classNames, styles, render, }: CookieConsentDialogProps): React.ReactElement | null;
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import useCookieConsent from '../use_cookie_consent';
|
|
4
|
+
import DefaultPrivacyPolicyLink from './default_privacy_policy_link';
|
|
4
5
|
/**
|
|
5
6
|
* Cookie-consent banner. Renders `null` once `consent` is already decided.
|
|
6
7
|
* Every visual aspect is overridable via `classNames`/`styles` (per-slot) or
|
|
7
8
|
* `render` (full custom markup) — none of it is hardcoded to Tailwind or any
|
|
8
9
|
* particular design system.
|
|
9
10
|
*/
|
|
10
|
-
export default function CookieConsentDialog({ message = 'We use cookies to improve your experience.', link, acceptText = 'Accept', declineText = 'Necessary only', hideDecline = false, id = 'cookie-consent-dialog', classNames, styles, render, }) {
|
|
11
|
-
const { consent, setConsent } = useCookieConsent();
|
|
11
|
+
export default function CookieConsentDialog({ message = 'We use cookies to improve your experience.', link, privacyPolicyLinkText = 'Privacy Policy', acceptText = 'Accept', declineText = 'Necessary only', hideDecline = false, id = 'cookie-consent-dialog', classNames, styles, render, }) {
|
|
12
|
+
const { consent, setConsent, privacyPolicyPath } = useCookieConsent();
|
|
12
13
|
if (consent !== null)
|
|
13
14
|
return null;
|
|
14
15
|
if (render)
|
|
15
16
|
return _jsx(_Fragment, { children: render({ setConsent }) });
|
|
16
|
-
|
|
17
|
+
const resolvedLink = link !== undefined
|
|
18
|
+
? link
|
|
19
|
+
: _jsx(DefaultPrivacyPolicyLink, { privacyPolicyPath: privacyPolicyPath, text: privacyPolicyLinkText });
|
|
20
|
+
return (_jsxs("div", { id: id, role: "dialog", "aria-modal": "false", "aria-labelledby": `${id}-title`, className: classNames?.root, style: styles?.root, children: [_jsxs("p", { id: `${id}-title`, className: classNames?.message, style: styles?.message, children: [message, resolvedLink ? _jsxs("span", { className: classNames?.link, style: styles?.link, children: [" ", resolvedLink] }) : null] }), _jsxs("div", { className: classNames?.actions, style: styles?.actions, children: [!hideDecline && (_jsx("button", { type: "button", onClick: () => setConsent(false), className: classNames?.declineButton, style: styles?.declineButton, children: declineText })), _jsx("button", { type: "button", onClick: () => setConsent(true), className: classNames?.acceptButton, style: styles?.acceptButton, children: acceptText })] })] }));
|
|
17
21
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders the default privacy-policy link used by `CookieConsentDialog`/
|
|
3
|
+
* `PrivacyPolicyUpdateDialog` when their `link` prop is omitted. Returns
|
|
4
|
+
* `null` when `privacyPolicyPath` is `false` (disabled via
|
|
5
|
+
* `cookieConsent.privacyPolicyPath`). Locale-prefixes `privacyPolicyPath`
|
|
6
|
+
* the same way the server `Link` component does — reads the locale set by
|
|
7
|
+
* `LocationzationClientProvider` on the current render.
|
|
8
|
+
*/
|
|
9
|
+
export default function DefaultPrivacyPolicyLink({ privacyPolicyPath, text, className, style }: {
|
|
10
|
+
privacyPolicyPath: string | false;
|
|
11
|
+
text: string;
|
|
12
|
+
className?: string;
|
|
13
|
+
style?: React.CSSProperties;
|
|
14
|
+
}): React.ReactElement | null;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import NextLink from 'next/link';
|
|
4
|
+
import config from '../../../config/intl_config';
|
|
5
|
+
import { getLocaleCache } from '../../../general/cache_variables';
|
|
6
|
+
/**
|
|
7
|
+
* Renders the default privacy-policy link used by `CookieConsentDialog`/
|
|
8
|
+
* `PrivacyPolicyUpdateDialog` when their `link` prop is omitted. Returns
|
|
9
|
+
* `null` when `privacyPolicyPath` is `false` (disabled via
|
|
10
|
+
* `cookieConsent.privacyPolicyPath`). Locale-prefixes `privacyPolicyPath`
|
|
11
|
+
* the same way the server `Link` component does — reads the locale set by
|
|
12
|
+
* `LocationzationClientProvider` on the current render.
|
|
13
|
+
*/
|
|
14
|
+
export default function DefaultPrivacyPolicyLink({ privacyPolicyPath, text, className, style }) {
|
|
15
|
+
if (privacyPolicyPath === false)
|
|
16
|
+
return null;
|
|
17
|
+
const localeValue = getLocaleCache();
|
|
18
|
+
const needsLangPath = localeValue !== config.defaultLocale || !localeValue;
|
|
19
|
+
const href = needsLangPath ? `/${localeValue}${privacyPolicyPath}` : privacyPolicyPath;
|
|
20
|
+
return (_jsx(NextLink, { href: href, className: className, style: style, children: text }));
|
|
21
|
+
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import type { CookieDialogClassNames, CookieDialogStyles } from '../../types';
|
|
2
2
|
export interface PrivacyPolicyUpdateDialogProps {
|
|
3
3
|
message?: React.ReactNode;
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Link element rendered right after `message`. Defaults to a link to
|
|
6
|
+
* `cookieConsent.privacyPolicyPath` (`'/privacy-policy'` unless
|
|
7
|
+
* configured otherwise) with `privacyPolicyLinkText` as its label. Pass
|
|
8
|
+
* `null` to render no link, or your own element to override it.
|
|
9
|
+
*/
|
|
5
10
|
link?: React.ReactNode;
|
|
11
|
+
/** Label for the default privacy-policy link. Ignored when `link` is set. */
|
|
12
|
+
privacyPolicyLinkText?: string;
|
|
6
13
|
closeText?: string;
|
|
7
14
|
id?: string;
|
|
8
15
|
classNames?: CookieDialogClassNames;
|
|
@@ -21,4 +28,4 @@ export interface PrivacyPolicyUpdateDialogProps {
|
|
|
21
28
|
* `null` otherwise, or once acknowledged. Every visual aspect is overridable
|
|
22
29
|
* via `classNames`/`styles` (per-slot) or `render` (full custom markup).
|
|
23
30
|
*/
|
|
24
|
-
export default function PrivacyPolicyUpdateDialog({ message, link, closeText, id, classNames, styles, render, }: PrivacyPolicyUpdateDialogProps): React.ReactElement | null;
|
|
31
|
+
export default function PrivacyPolicyUpdateDialog({ message, link, privacyPolicyLinkText, closeText, id, classNames, styles, render, }: PrivacyPolicyUpdateDialogProps): React.ReactElement | null;
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import useCookieConsent from '../use_cookie_consent';
|
|
4
|
+
import DefaultPrivacyPolicyLink from './default_privacy_policy_link';
|
|
4
5
|
/**
|
|
5
6
|
* "Privacy policy updated" banner. Auto-enabled only when
|
|
6
7
|
* `cookieConsent.privacyPolicyDate` is set on the `RoutingConfig` — renders
|
|
7
8
|
* `null` otherwise, or once acknowledged. Every visual aspect is overridable
|
|
8
9
|
* via `classNames`/`styles` (per-slot) or `render` (full custom markup).
|
|
9
10
|
*/
|
|
10
|
-
export default function PrivacyPolicyUpdateDialog({ message = 'Our privacy policy has been updated.', link, closeText = 'Got it', id = 'privacy-policy-update-dialog', classNames, styles, render, }) {
|
|
11
|
-
const { privacyPolicyUpdated, acknowledgePrivacyPolicyUpdate } = useCookieConsent();
|
|
11
|
+
export default function PrivacyPolicyUpdateDialog({ message = 'Our privacy policy has been updated.', link, privacyPolicyLinkText = 'Learn more', closeText = 'Got it', id = 'privacy-policy-update-dialog', classNames, styles, render, }) {
|
|
12
|
+
const { privacyPolicyUpdated, acknowledgePrivacyPolicyUpdate, privacyPolicyPath } = useCookieConsent();
|
|
12
13
|
if (!privacyPolicyUpdated)
|
|
13
14
|
return null;
|
|
14
15
|
if (render)
|
|
15
16
|
return _jsx(_Fragment, { children: render({ acknowledge: acknowledgePrivacyPolicyUpdate }) });
|
|
16
|
-
|
|
17
|
+
const resolvedLink = link !== undefined
|
|
18
|
+
? link
|
|
19
|
+
: _jsx(DefaultPrivacyPolicyLink, { privacyPolicyPath: privacyPolicyPath, text: privacyPolicyLinkText });
|
|
20
|
+
return (_jsxs("div", { id: id, role: "dialog", "aria-modal": "false", "aria-labelledby": `${id}-title`, className: classNames?.root, style: styles?.root, children: [_jsxs("p", { id: `${id}-title`, className: classNames?.message, style: styles?.message, children: [message, resolvedLink ? _jsxs("span", { className: classNames?.link, style: styles?.link, children: [" ", resolvedLink] }) : null] }), _jsx("button", { type: "button", onClick: acknowledgePrivacyPolicyUpdate, "aria-label": closeText, className: classNames?.closeButton, style: styles?.closeButton, children: closeText })] }));
|
|
17
21
|
}
|
|
@@ -45,13 +45,14 @@ function parseConsent(raw) {
|
|
|
45
45
|
* ```
|
|
46
46
|
*/
|
|
47
47
|
export default function CookieConsentProvider({ requiresConsent = true, children }) {
|
|
48
|
-
const { consentCookieName, dateCookieName, maxAge, policyDate } = useMemo(() => {
|
|
48
|
+
const { consentCookieName, dateCookieName, maxAge, policyDate, privacyPolicyPath } = useMemo(() => {
|
|
49
49
|
const cc = requireCookieConsentConfig(config.cookieConsent);
|
|
50
50
|
return {
|
|
51
51
|
consentCookieName: cc.consentCookieName ?? cookieConsentCookieKey,
|
|
52
52
|
dateCookieName: cc.privacyPolicyDateCookieName ?? privacyPolicyDateCookieKey,
|
|
53
53
|
maxAge: cc.cookieMaxAge ?? 31536000,
|
|
54
54
|
policyDate: cc.privacyPolicyDate ? new Date(cc.privacyPolicyDate) : null,
|
|
55
|
+
privacyPolicyPath: cc.privacyPolicyPath ?? '/privacy-policy',
|
|
55
56
|
};
|
|
56
57
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
57
58
|
}, []);
|
|
@@ -89,6 +90,6 @@ export default function CookieConsentProvider({ requiresConsent = true, children
|
|
|
89
90
|
setPrivacyPolicyUpdated(false);
|
|
90
91
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
91
92
|
}, []);
|
|
92
|
-
const contextValue = useMemo(() => ({ consent, privacyPolicyUpdated, setConsent, acknowledgePrivacyPolicyUpdate }), [consent, privacyPolicyUpdated, setConsent, acknowledgePrivacyPolicyUpdate]);
|
|
93
|
+
const contextValue = useMemo(() => ({ consent, privacyPolicyUpdated, setConsent, acknowledgePrivacyPolicyUpdate, privacyPolicyPath }), [consent, privacyPolicyUpdated, setConsent, acknowledgePrivacyPolicyUpdate, privacyPolicyPath]);
|
|
93
94
|
return (_jsx(CookieConsentContext.Provider, { value: contextValue, children: children }));
|
|
94
95
|
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { bench, describe } from 'vitest';
|
|
2
2
|
import resolveRequiresConsent, { defaultGdprCountries } from './gdpr_countries';
|
|
3
|
+
const fakeGetCloudflareContext = ((options) => {
|
|
4
|
+
const context = { cf: { country: 'DE' } };
|
|
5
|
+
return options?.async === false ? context : Promise.resolve(context);
|
|
6
|
+
});
|
|
3
7
|
const customList = ['US', 'CA', 'MX'];
|
|
4
8
|
describe('resolveRequiresConsent: default GDPR list lookup', () => {
|
|
5
9
|
bench('country inside the list (worst case for Array.includes: near the end)', async () => {
|
|
@@ -21,7 +25,7 @@ describe('resolveRequiresConsent: gating disabled', () => {
|
|
|
21
25
|
});
|
|
22
26
|
describe('resolveRequiresConsent: getCloudflareContext path', () => {
|
|
23
27
|
bench('resolves cf.country from an async context getter', async () => {
|
|
24
|
-
await resolveRequiresConsent(undefined,
|
|
28
|
+
await resolveRequiresConsent(undefined, fakeGetCloudflareContext, undefined);
|
|
25
29
|
});
|
|
26
30
|
});
|
|
27
31
|
// Sanity check the list itself isn't accidentally growing unbounded — a
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CookieConsentGetCloudflareContext } from '../types/types';
|
|
2
2
|
/**
|
|
3
3
|
* Default `cookieConsent.gdprCountries` — EU/EEA member states (GDPR),
|
|
4
4
|
* Iceland/Liechtenstein/Norway (EEA), the UK (UK-GDPR), and Switzerland
|
|
@@ -15,4 +15,4 @@ export declare const defaultGdprCountries: readonly string[];
|
|
|
15
15
|
* `gdprCountries` skips the banner. `getCountryCode` takes precedence
|
|
16
16
|
* over `getCloudflareContext` when both are set.
|
|
17
17
|
*/
|
|
18
|
-
export default function resolveRequiresConsent(getCountryCode: (() => string | undefined | Promise<string | undefined>) | undefined, getCloudflareContext:
|
|
18
|
+
export default function resolveRequiresConsent(getCountryCode: (() => string | undefined | Promise<string | undefined>) | undefined, getCloudflareContext: CookieConsentGetCloudflareContext | undefined, gdprCountries: readonly string[] | undefined): Promise<boolean>;
|
|
@@ -45,8 +45,8 @@ export default async function resolveRequiresConsent(getCountryCode, getCloudfla
|
|
|
45
45
|
return false;
|
|
46
46
|
const countryCode = getCountryCode
|
|
47
47
|
? await getCountryCode()
|
|
48
|
-
: (await getCloudflareContext())
|
|
49
|
-
if (!countryCode)
|
|
48
|
+
: (await getCloudflareContext({ async: true }))?.cf?.country;
|
|
49
|
+
if (typeof countryCode !== 'string' || !countryCode)
|
|
50
50
|
return true;
|
|
51
51
|
return getGdprCountriesSet(gdprCountries).has(countryCode);
|
|
52
52
|
}
|
|
@@ -5,4 +5,4 @@ export { default as PrivacyPolicyUpdateDialog } from './client/components/privac
|
|
|
5
5
|
export { default as CookieConsentAnalytics } from './client/components/cookie_consent_analytics';
|
|
6
6
|
export { defaultGdprCountries } from './gdpr_countries';
|
|
7
7
|
export type { CookieConsentContextType, ConsentValue, CookieDialogClassNames, CookieDialogStyles } from './types';
|
|
8
|
-
export type { CookieConsentRoutingConfig, CookieConsentAnalyticsSecrets } from '../types/types';
|
|
8
|
+
export type { CookieConsentRoutingConfig, CookieConsentAnalyticsSecrets, CookieConsentCloudflareContext, CookieConsentGetCloudflareContext, } from '../types/types';
|
|
@@ -14,6 +14,13 @@ export interface CookieConsentContextType {
|
|
|
14
14
|
setConsent: (value: boolean) => void;
|
|
15
15
|
/** Acknowledges the privacy-policy update banner and persists the new date. */
|
|
16
16
|
acknowledgePrivacyPolicyUpdate: () => void;
|
|
17
|
+
/**
|
|
18
|
+
* Resolved from `cookieConsent.privacyPolicyPath` (defaults to
|
|
19
|
+
* `'/privacy-policy'`; `false` disables it). Used by the default
|
|
20
|
+
* dialog components to render a privacy-policy link automatically
|
|
21
|
+
* when their `link` prop is omitted.
|
|
22
|
+
*/
|
|
23
|
+
privacyPolicyPath: string | false;
|
|
17
24
|
}
|
|
18
25
|
/** Slot-level style/class overrides accepted by the default dialog components. */
|
|
19
26
|
export interface CookieDialogClassNames {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export type { CookieAttributes, LocalePrefixMode, Locales, ReturnType, RoutingConfig, TranslationEntry, TranslationObject, TranslatorReturnType, Alternates, changeFrequency, IntlSitemap, CookieConsentRoutingConfig, CookieConsentAnalyticsSecrets, CookieConsentCloudflareContext, } from './types';
|
|
1
|
+
export type { CookieAttributes, LocalePrefixMode, Locales, ReturnType, RoutingConfig, TranslationEntry, TranslationObject, TranslatorReturnType, Alternates, changeFrequency, IntlSitemap, CookieConsentRoutingConfig, CookieConsentAnalyticsSecrets, CookieConsentCloudflareContext, CookieConsentGetCloudflareContext, } from './types';
|
|
@@ -98,6 +98,14 @@ export interface CookieConsentRoutingConfig {
|
|
|
98
98
|
* cookie-consent banner still works independently).
|
|
99
99
|
*/
|
|
100
100
|
privacyPolicyDate?: string | Date;
|
|
101
|
+
/**
|
|
102
|
+
* Path to your privacy-policy page, e.g. `"/privacy-policy"`. Used by
|
|
103
|
+
* `CookieConsentDialog`/`PrivacyPolicyUpdateDialog` to render a default
|
|
104
|
+
* link automatically when their `link` prop is omitted. Defaults to
|
|
105
|
+
* `'/privacy-policy'`. Set `false` to render no link by default (still
|
|
106
|
+
* overridable per-dialog via the `link` prop).
|
|
107
|
+
*/
|
|
108
|
+
privacyPolicyPath?: string | false;
|
|
101
109
|
/** Cookie-consent cookie name. Defaults to `'__cookie_consent_key__'`. */
|
|
102
110
|
consentCookieName?: string;
|
|
103
111
|
/** Privacy-policy-date cookie name. Defaults to `'__privacy_policy_date_key__'`. */
|
|
@@ -136,11 +144,12 @@ export interface CookieConsentRoutingConfig {
|
|
|
136
144
|
*/
|
|
137
145
|
getCountryCode?: () => string | undefined | Promise<string | undefined>;
|
|
138
146
|
/**
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
147
|
+
* Pass `getCloudflareContext` from `@opennextjs/cloudflare` directly
|
|
148
|
+
* (not a dependency of this package, so bring your own import) — its
|
|
149
|
+
* exact overloaded signature is accepted as-is; called internally with
|
|
150
|
+
* `{ async: true }`, so you never need to wrap it yourself. Only
|
|
151
|
+
* `cf.country` is read from the resolved context. Ignored when
|
|
152
|
+
* `getCountryCode` is also set.
|
|
144
153
|
*
|
|
145
154
|
* Country-based gating (via either `getCountryCode` or
|
|
146
155
|
* `getCloudflareContext`) decides whether the cookie-consent banner is
|
|
@@ -151,7 +160,7 @@ export interface CookieConsentRoutingConfig {
|
|
|
151
160
|
* is the simplest opt-in-by-default setup; set one of the two getters
|
|
152
161
|
* once you need real GDPR-region gating.
|
|
153
162
|
*/
|
|
154
|
-
getCloudflareContext?:
|
|
163
|
+
getCloudflareContext?: CookieConsentGetCloudflareContext;
|
|
155
164
|
/**
|
|
156
165
|
* Country codes (ISO 3166-1 alpha-2) for which the cookie-consent banner
|
|
157
166
|
* is required. Only consulted when `getCountryCode` or
|
|
@@ -174,14 +183,32 @@ export interface CookieConsentRoutingConfig {
|
|
|
174
183
|
}
|
|
175
184
|
/**
|
|
176
185
|
* Minimal shape read from your `getCloudflareContext()` return value — only
|
|
177
|
-
* `cf.country` is consulted
|
|
178
|
-
*
|
|
186
|
+
* `cf.country` is consulted (read defensively at the call site, since `cf`'s
|
|
187
|
+
* real type — `@opennextjs/cloudflare`'s `CfProperties`, a union of the
|
|
188
|
+
* incoming-request and request-init variants — only has `country` on one
|
|
189
|
+
* branch). `cf` is typed loosely here so the real (generic) function is
|
|
190
|
+
* assignable to `CookieConsentGetCloudflareContext` without a hard
|
|
179
191
|
* dependency on that package.
|
|
180
192
|
*/
|
|
181
193
|
export interface CookieConsentCloudflareContext {
|
|
182
|
-
cf?:
|
|
183
|
-
|
|
184
|
-
|
|
194
|
+
cf?: Record<string, unknown>;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Matches `@opennextjs/cloudflare`'s `getCloudflareContext` overloaded
|
|
198
|
+
* signature exactly, so that function can be passed as
|
|
199
|
+
* `cookieConsent.getCloudflareContext` directly — this package always
|
|
200
|
+
* calls it with `{ async: true }` internally (the first overload), which is
|
|
201
|
+
* why that overload's return type drives `resolveRequiresConsent`'s
|
|
202
|
+
* awaited result; the sync overload is accepted structurally only so the
|
|
203
|
+
* real function's type (which has both) is assignable as-is.
|
|
204
|
+
*/
|
|
205
|
+
export interface CookieConsentGetCloudflareContext {
|
|
206
|
+
(options: {
|
|
207
|
+
async: true;
|
|
208
|
+
}): Promise<CookieConsentCloudflareContext | null>;
|
|
209
|
+
(options?: {
|
|
210
|
+
async: false;
|
|
211
|
+
}): CookieConsentCloudflareContext | null;
|
|
185
212
|
}
|
|
186
213
|
export interface CookieConsentAnalyticsSecrets {
|
|
187
214
|
/** Cloudflare Web Analytics beacon token, e.g. `'{"token": "..."}'` (the raw `data-cf-beacon` attribute value). */
|
package/llms.txt
CHANGED
|
@@ -39,10 +39,10 @@ other subpath can be used.
|
|
|
39
39
|
- `./cookieConsent` — barrel: `CookieConsentProvider`, `useCookieConsent`, `CookieConsentDialog`, `PrivacyPolicyUpdateDialog`, `CookieConsentAnalytics`.
|
|
40
40
|
- `./CookieConsentProvider` — context provider; reads/writes consent + privacy-policy-date cookies. Auto-wired by `IntlProvider` when `cookieConsent` is configured — manual nesting is optional.
|
|
41
41
|
- `./useCookieConsent` — context hook; throws `"useCookieConsent must be used within a CookieConsentProvider"` if called outside one.
|
|
42
|
-
- `./CookieConsentDialog` — default cookie-consent banner; accepts per-slot `classNames`/`styles` or a `render` prop for fully custom markup.
|
|
43
|
-
- `./PrivacyPolicyUpdateDialog` — "privacy policy updated" banner; auto-enabled only when `cookieConsent.privacyPolicyDate` is set.
|
|
42
|
+
- `./CookieConsentDialog` — default cookie-consent banner; accepts per-slot `classNames`/`styles` or a `render` prop for fully custom markup. When `link` is omitted, renders a default link to `cookieConsent.privacyPolicyPath` (defaults to `'/privacy-policy'`; label via `privacyPolicyLinkText`, default `"Privacy Policy"`) — pass `link={null}` for no link, or set `privacyPolicyPath: false` to disable it everywhere.
|
|
43
|
+
- `./PrivacyPolicyUpdateDialog` — "privacy policy updated" banner; auto-enabled only when `cookieConsent.privacyPolicyDate` is set. Same default-link behavior as `CookieConsentDialog` (label default `"Learn more"`).
|
|
44
44
|
- `./cookieConsentAnalytics` — `CookieConsentAnalytics`: gates Cloudflare Web Analytics / Google Ads / Google Analytics / AdSense / Microsoft Clarity behind consent; rendered automatically by `IntlProvider` when `cookieConsent.secrets` or `getSecrets` is set (and `autoWireAnalytics !== false`). Never renders in local dev (`NODE_ENV === 'development'`) unless `cookieConsent.enableAnalyticsInDevMode` is `true`.
|
|
45
|
-
- Country-based gating (`cookieConsent.getCountryCode` / `getCloudflareContext` + `gdprCountries`): resolved server-side by `IntlProvider` into a `requiresConsent` boolean passed to `CookieConsentProvider`. Neither getter set → gating off, consent always implicitly granted. `getCountryCode` (direct country resolver) takes precedence over `getCloudflareContext` (reads `cf.country`) when both are set. Unresolved country always requires consent (fail-safe). `./cookieConsent` also exports `defaultGdprCountries` (EU/EEA + UK + Switzerland).
|
|
45
|
+
- Country-based gating (`cookieConsent.getCountryCode` / `getCloudflareContext` + `gdprCountries`): resolved server-side by `IntlProvider` into a `requiresConsent` boolean passed to `CookieConsentProvider`. Neither getter set → gating off, consent always implicitly granted. `getCountryCode` (direct country resolver) takes precedence over `getCloudflareContext` (reads `cf.country`) when both are set. `getCloudflareContext` accepts `@opennextjs/cloudflare`'s `getCloudflareContext` function directly (its exact overloaded signature — `CookieConsentGetCloudflareContext`), called internally with `{ async: true }`. Unresolved country (or a `null` context) always requires consent (fail-safe). `./cookieConsent` also exports `defaultGdprCountries` (EU/EEA + UK + Switzerland).
|
|
46
46
|
|
|
47
47
|
## Conventions
|
|
48
48
|
|