cloudflare-next-intl 0.5.4 → 0.5.6

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 CHANGED
@@ -189,7 +189,7 @@ import ThemeSwitcher from "cloudflare-next-intl/ThemeSwitcher";
189
189
 
190
190
  Set `cookieConsent` on your `RoutingConfig` to enable — `IntlProvider` then
191
191
  auto-wires `CookieConsentProvider`, `CookieConsentAnalytics` (if
192
- `cookieConsent.secrets`/`getSecrets` is set), and both `CookieConsentDialog`/
192
+ `cookieConsent.analytics`/`getAnalytics` is set), and both `CookieConsentDialog`/
193
193
  `PrivacyPolicyUpdateDialog` (with their built-in default styling and
194
194
  English/Ukrainian copy) with no manual nesting needed.
195
195
 
@@ -1,6 +1,6 @@
1
1
  import type { TranslationObject } from "../../types/types";
2
2
  import type { SerializedAuthUser } from "../../firebase_auth/types";
3
- import type { CookieConsentAnalyticsSecrets } from "../../types/types";
3
+ import type { CookieConsentAnalyticsConfig } from "../../types/types";
4
4
  import type { CookieConsentDialogProps } from "../../cookie_consent/client/components/cookie_consent_dialog";
5
5
  import type { PrivacyPolicyUpdateDialogProps } from "../../cookie_consent/client/components/privacy_policy_update_dialog";
6
6
  interface LocaleContextType {
@@ -8,14 +8,14 @@ interface LocaleContextType {
8
8
  messages: TranslationObject;
9
9
  }
10
10
  export declare const LocaleContext: import("react").Context<LocaleContextType | undefined>;
11
- export default function LocationzationClientProvider({ language, messages, initialAuthUser, skipAuthProvider, analyticsSecrets, requiresConsent, autoWireDialogs, dialogProps, updateDialogProps, children }: {
11
+ export default function LocationzationClientProvider({ language, messages, initialAuthUser, skipAuthProvider, analyticsConfig, requiresConsent, autoWireDialogs, dialogProps, updateDialogProps, children }: {
12
12
  language: string;
13
13
  messages: TranslationObject;
14
14
  initialAuthUser?: SerializedAuthUser | null;
15
15
  /** Set when `firebaseAuth.autoWireClientProvider` is `false` — skips wrapping `children` in the client `AuthUserProvider` entirely. */
16
16
  skipAuthProvider?: boolean;
17
- /** Resolved server-side from `cookieConsent.secrets`/`getSecrets` when `autoWireAnalytics` isn't `false`. */
18
- analyticsSecrets?: CookieConsentAnalyticsSecrets;
17
+ /** Resolved server-side from `cookieConsent.analytics`/`getAnalytics` when `autoWireAnalytics` isn't `false`. */
18
+ analyticsConfig?: CookieConsentAnalyticsConfig;
19
19
  /**
20
20
  * Resolved server-side from `cookieConsent.getCountryCode`/`gdprCountries`.
21
21
  * `false` means the visitor's country doesn't require the consent
@@ -17,7 +17,7 @@ const CookieConsentProvider = dynamic(() => import("../../cookie_consent/client/
17
17
  const CookieConsentAnalytics = dynamic(() => import("../../cookie_consent/client/components/cookie_consent_analytics"));
18
18
  const CookieConsentDialog = dynamic(() => import("../../cookie_consent/client/components/cookie_consent_dialog"));
19
19
  const PrivacyPolicyUpdateDialog = dynamic(() => import("../../cookie_consent/client/components/privacy_policy_update_dialog"));
20
- export default function LocationzationClientProvider({ language, messages, initialAuthUser = null, skipAuthProvider = false, analyticsSecrets, requiresConsent = true, autoWireDialogs = true, dialogProps, updateDialogProps, children }) {
20
+ export default function LocationzationClientProvider({ language, messages, initialAuthUser = null, skipAuthProvider = false, analyticsConfig, requiresConsent = true, autoWireDialogs = true, dialogProps, updateDialogProps, children }) {
21
21
  setLocaleCache(language);
22
22
  setMessageForLocaleCache(language, messages);
23
23
  // `LocaleContext.Provider` stays the outermost element here — the
@@ -30,7 +30,7 @@ export default function LocationzationClientProvider({ language, messages, initi
30
30
  providedChildren = _jsx(AuthUserProvider, { initialUser: initialAuthUser, children: children });
31
31
  }
32
32
  if (config.cookieConsent) {
33
- providedChildren = _jsxs(CookieConsentProvider, { requiresConsent: requiresConsent, children: [providedChildren, analyticsSecrets && _jsx(CookieConsentAnalytics, { secrets: analyticsSecrets }), autoWireDialogs && _jsx(CookieConsentDialog, { ...dialogProps }), autoWireDialogs && _jsx(PrivacyPolicyUpdateDialog, { ...updateDialogProps })] });
33
+ providedChildren = _jsxs(CookieConsentProvider, { requiresConsent: requiresConsent, children: [providedChildren, analyticsConfig && _jsx(CookieConsentAnalytics, { config: analyticsConfig }), autoWireDialogs && _jsx(CookieConsentDialog, { ...dialogProps }), autoWireDialogs && _jsx(PrivacyPolicyUpdateDialog, { ...updateDialogProps })] });
34
34
  }
35
35
  const contextValue = useMemo(() => ({ language, messages }), [language, messages]);
36
36
  return _jsx(LocaleContext.Provider, { value: contextValue, children: providedChildren });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { bench, describe } from 'vitest';
3
+ import { renderHook } from '@testing-library/react';
4
+ import { useLocale, useTranslations } from './client_hooks';
5
+ import { LocaleContext } from '../components/client_provider';
6
+ const messages = { Common: { title: 'Hello' } };
7
+ function wrapper({ children }) {
8
+ return (_jsx(LocaleContext.Provider, { value: { language: 'en', messages }, children: children }));
9
+ }
10
+ describe('useLocale (client)', () => {
11
+ bench('reads the language from context', () => {
12
+ renderHook(() => useLocale(), { wrapper });
13
+ });
14
+ });
15
+ describe('useTranslations (client)', () => {
16
+ bench('builds a namespace-scoped translation function', () => {
17
+ renderHook(() => useTranslations('Common'), { wrapper });
18
+ });
19
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { bench, describe, vi } from 'vitest';
3
+ import { renderHook } from '@testing-library/react';
4
+ import usePathname from './use_path_name';
5
+ import { LocaleContext } from '../components/client_provider';
6
+ vi.mock('next/navigation', () => ({
7
+ usePathname: vi.fn(() => '/en/about'),
8
+ }));
9
+ function wrapper({ children }) {
10
+ return (_jsx(LocaleContext.Provider, { value: { language: 'en', messages: {} }, children: children }));
11
+ }
12
+ describe('usePathname (locale-stripped)', () => {
13
+ bench('strips the locale prefix from the current pathname', () => {
14
+ renderHook(() => usePathname(), { wrapper });
15
+ });
16
+ });
@@ -2,7 +2,7 @@
2
2
  * Loads and initializes Microsoft Clarity. Split into its own module and
3
3
  * loaded via `next/dynamic` from `cookie_consent_analytics.tsx` so it's
4
4
  * only fetched as a separate chunk once actually rendered (consent granted
5
- * and `secrets.clarityProjectId` set) — `@microsoft/clarity` is a real
5
+ * and `analytics.clarityProjectId` set) — `@microsoft/clarity` is a real
6
6
  * dependency of this package, so it's always installed regardless.
7
7
  */
8
8
  export default function ClarityScript({ projectId }: {
@@ -11,7 +11,7 @@ function getClarityModule() {
11
11
  * Loads and initializes Microsoft Clarity. Split into its own module and
12
12
  * loaded via `next/dynamic` from `cookie_consent_analytics.tsx` so it's
13
13
  * only fetched as a separate chunk once actually rendered (consent granted
14
- * and `secrets.clarityProjectId` set) — `@microsoft/clarity` is a real
14
+ * and `analytics.clarityProjectId` set) — `@microsoft/clarity` is a real
15
15
  * dependency of this package, so it's always installed regardless.
16
16
  */
17
17
  export default function ClarityScript({ projectId }) {
@@ -1,19 +1,19 @@
1
- import type { CookieConsentAnalyticsSecrets } from '../../../types/types';
1
+ import type { CookieConsentAnalyticsConfig } from '../../../types/types';
2
2
  /**
3
3
  * Renders whichever analytics/ads scripts have a resolved secret, gated on
4
4
  * consent: Google Consent Mode bootstrap always loads (defaults to
5
5
  * `denied`, only sends `update` once `consent` is decided); Cloudflare Web
6
6
  * Analytics beacon and Microsoft Clarity only load once `consent === true`.
7
- * Rendered automatically by `IntlProvider` when `cookieConsent.secrets`/
8
- * `getSecrets` resolves at least one field and `autoWireAnalytics` isn't
7
+ * Rendered automatically by `IntlProvider` when `cookieConsent.analytics`/
8
+ * `getAnalytics` resolves at least one field and `autoWireAnalytics` isn't
9
9
  * `false` — render manually instead if you set `autoWireAnalytics: false`.
10
10
  */
11
- export default function CookieConsentAnalytics({ secrets }: {
12
- secrets: CookieConsentAnalyticsSecrets;
11
+ export default function CookieConsentAnalytics({ config }: {
12
+ config: CookieConsentAnalyticsConfig;
13
13
  }): React.ReactElement | null;
14
14
  /**
15
15
  * Denies storage by default and loads the configured Google tags; the
16
16
  * effect above sends the `update` once consent is known. Only IDs present
17
- * in `secrets` are included.
17
+ * in `config` are included.
18
18
  */
19
- export declare function googleConsentModeBootstrapScript(secrets: CookieConsentAnalyticsSecrets): string;
19
+ export declare function googleConsentModeBootstrapScript(config: CookieConsentAnalyticsConfig): string;
@@ -13,11 +13,11 @@ const ClarityScript = dynamic(() => import('./clarity_script'));
13
13
  * consent: Google Consent Mode bootstrap always loads (defaults to
14
14
  * `denied`, only sends `update` once `consent` is decided); Cloudflare Web
15
15
  * Analytics beacon and Microsoft Clarity only load once `consent === true`.
16
- * Rendered automatically by `IntlProvider` when `cookieConsent.secrets`/
17
- * `getSecrets` resolves at least one field and `autoWireAnalytics` isn't
16
+ * Rendered automatically by `IntlProvider` when `cookieConsent.analytics`/
17
+ * `getAnalytics` resolves at least one field and `autoWireAnalytics` isn't
18
18
  * `false` — render manually instead if you set `autoWireAnalytics: false`.
19
19
  */
20
- export default function CookieConsentAnalytics({ secrets }) {
20
+ export default function CookieConsentAnalytics({ config }) {
21
21
  const { consent } = useCookieConsent();
22
22
  useEffect(() => {
23
23
  if (consent === null)
@@ -33,33 +33,33 @@ export default function CookieConsentAnalytics({ secrets }) {
33
33
  analytics_storage: state,
34
34
  });
35
35
  }, [consent]);
36
- const hasGoogle = Boolean(secrets.googleAnalyticsId || secrets.googleAdsId || secrets.googleAdSenseId);
37
- return (_jsxs(_Fragment, { children: [hasGoogle && (_jsx("script", { id: "cookie-consent-google-consent-mode", dangerouslySetInnerHTML: { __html: googleConsentModeBootstrapScript(secrets) } })), consent === true && secrets.cloudflareBeaconToken && (_jsx("script", { defer: true, src: "https://static.cloudflareinsights.com/beacon.min.js", "data-cf-beacon": secrets.cloudflareBeaconToken })), consent === true && secrets.clarityProjectId && _jsx(ClarityScript, { projectId: secrets.clarityProjectId })] }));
36
+ const hasGoogle = Boolean(config.googleAnalyticsId || config.googleAdsId || config.googleAdSenseId);
37
+ return (_jsxs(_Fragment, { children: [hasGoogle && (_jsx("script", { id: "cookie-consent-google-consent-mode", dangerouslySetInnerHTML: { __html: googleConsentModeBootstrapScript(config) } })), consent === true && config.cloudflareBeaconToken && (_jsx("script", { defer: true, src: "https://static.cloudflareinsights.com/beacon.min.js", "data-cf-beacon": config.cloudflareBeaconToken })), consent === true && config.clarityProjectId && _jsx(ClarityScript, { projectId: config.clarityProjectId })] }));
38
38
  }
39
39
  /**
40
40
  * Denies storage by default and loads the configured Google tags; the
41
41
  * effect above sends the `update` once consent is known. Only IDs present
42
- * in `secrets` are included.
42
+ * in `config` are included.
43
43
  */
44
- export function googleConsentModeBootstrapScript(secrets) {
45
- const configCalls = [secrets.googleAnalyticsId, secrets.googleAdsId]
44
+ export function googleConsentModeBootstrapScript(config) {
45
+ const configCalls = [config.googleAnalyticsId, config.googleAdsId]
46
46
  .filter(Boolean)
47
47
  .map((id) => `gtag('config', '${id}');`)
48
48
  .join('\n');
49
- const gtagLoader = secrets.googleAnalyticsId || secrets.googleAdsId
49
+ const gtagLoader = config.googleAnalyticsId || config.googleAdsId
50
50
  ? `(function(){
51
51
  var s = document.createElement('script');
52
52
  s.async = true;
53
- s.src = 'https://www.googletagmanager.com/gtag/js?id=${secrets.googleAnalyticsId ?? secrets.googleAdsId}';
53
+ s.src = 'https://www.googletagmanager.com/gtag/js?id=${config.googleAnalyticsId ?? config.googleAdsId}';
54
54
  document.head.appendChild(s);
55
55
  })();`
56
56
  : '';
57
- const adSenseLoader = secrets.googleAdSenseId
57
+ const adSenseLoader = config.googleAdSenseId
58
58
  ? `(function(){
59
59
  var a = document.createElement('script');
60
60
  a.async = true;
61
61
  a.crossOrigin = 'anonymous';
62
- a.src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${secrets.googleAdSenseId}';
62
+ a.src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${config.googleAdSenseId}';
63
63
  document.head.appendChild(a);
64
64
  })();`
65
65
  : '';
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { bench, describe, vi } from 'vitest';
3
+ import { render, act } from '@testing-library/react';
4
+ vi.mock('../../config/intl_config', () => ({
5
+ default: { cookieConsent: { privacyPolicyDate: '2026-07-20' } },
6
+ }));
7
+ const cookies = new Map();
8
+ vi.mock('../../client/functions/get_cookie', () => ({
9
+ default: (name) => cookies.get(name) ?? null,
10
+ }));
11
+ vi.mock('../../client/functions/set_cookie', () => ({
12
+ default: ({ name, value }) => {
13
+ cookies.set(name, String(value));
14
+ },
15
+ }));
16
+ const { default: CookieConsentProvider } = await import('./cookie_consent_provider');
17
+ describe('CookieConsentProvider mount cost', () => {
18
+ bench('cold mount: no stored consent', async () => {
19
+ cookies.clear();
20
+ await act(async () => {
21
+ render(_jsx(CookieConsentProvider, { children: null }));
22
+ });
23
+ });
24
+ bench('warm mount: consent already granted and privacy-policy date current', async () => {
25
+ cookies.set('__cookie_consent_key__', 'true');
26
+ cookies.set('__privacy_policy_date_key__', new Date('2027-01-01').toISOString());
27
+ await act(async () => {
28
+ render(_jsx(CookieConsentProvider, { children: null }));
29
+ });
30
+ });
31
+ });
@@ -11,7 +11,10 @@ export declare const CookieConsentContext: import("react").Context<CookieConsent
11
11
  * `cookieConsent.privacyPolicyDate` is configured: once a visitor has
12
12
  * consented, if their stored consent date predates `privacyPolicyDate`,
13
13
  * `privacyPolicyUpdated` becomes `true` until they call
14
- * `acknowledgePrivacyPolicyUpdate()`.
14
+ * `acknowledgePrivacyPolicyUpdate()` — or until they navigate to
15
+ * `cookieConsent.privacyPolicyPath`, which auto-acknowledges it (visiting
16
+ * the page counts as having seen the update; skipped entirely when
17
+ * `privacyPolicyPath` is `false`).
15
18
  *
16
19
  * @param requiresConsent Resolved server-side from
17
20
  * `cookieConsent.getCountryCode`/`gdprCountries` — `false` means the
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { createContext, useCallback, useEffect, useMemo, useState } from 'react';
4
+ import { usePathname } from 'next/navigation';
4
5
  import config from '../../config/intl_config';
5
6
  import requireCookieConsentConfig from '../require_config';
6
7
  import getCookie from '../../client/functions/get_cookie';
@@ -25,7 +26,10 @@ function parseConsent(raw) {
25
26
  * `cookieConsent.privacyPolicyDate` is configured: once a visitor has
26
27
  * consented, if their stored consent date predates `privacyPolicyDate`,
27
28
  * `privacyPolicyUpdated` becomes `true` until they call
28
- * `acknowledgePrivacyPolicyUpdate()`.
29
+ * `acknowledgePrivacyPolicyUpdate()` — or until they navigate to
30
+ * `cookieConsent.privacyPolicyPath`, which auto-acknowledges it (visiting
31
+ * the page counts as having seen the update; skipped entirely when
32
+ * `privacyPolicyPath` is `false`).
29
33
  *
30
34
  * @param requiresConsent Resolved server-side from
31
35
  * `cookieConsent.getCountryCode`/`gdprCountries` — `false` means the
@@ -59,6 +63,7 @@ export default function CookieConsentProvider({ requiresConsent = true, children
59
63
  const [consent, setConsentState] = useState(null);
60
64
  const [privacyPolicyUpdated, setPrivacyPolicyUpdated] = useState(false);
61
65
  const [isMounted, setIsMounted] = useState(false);
66
+ const pathname = usePathname();
62
67
  useEffect(() => {
63
68
  const storedConsent = parseConsent(getCookie(consentCookieName));
64
69
  const autoAccepted = storedConsent === null && !requiresConsent;
@@ -90,6 +95,15 @@ export default function CookieConsentProvider({ requiresConsent = true, children
90
95
  setPrivacyPolicyUpdated(false);
91
96
  // eslint-disable-next-line react-hooks/exhaustive-deps
92
97
  }, []);
98
+ // Visiting the privacy-policy page itself counts as having seen the
99
+ // update — auto-acknowledge instead of also showing the banner there.
100
+ // `pathname` still carries the locale prefix (e.g. `/de/privacy-policy`),
101
+ // so match on a trailing segment rather than strict equality.
102
+ useEffect(() => {
103
+ if (privacyPolicyUpdated && privacyPolicyPath !== false && pathname.endsWith(privacyPolicyPath)) {
104
+ acknowledgePrivacyPolicyUpdate();
105
+ }
106
+ }, [pathname, privacyPolicyUpdated, privacyPolicyPath, acknowledgePrivacyPolicyUpdate]);
93
107
  const contextValue = useMemo(() => ({ consent, privacyPolicyUpdated, isMounted, setConsent, acknowledgePrivacyPolicyUpdate, privacyPolicyPath }), [consent, privacyPolicyUpdated, isMounted, setConsent, acknowledgePrivacyPolicyUpdate, privacyPolicyPath]);
94
108
  return (_jsx(CookieConsentContext.Provider, { value: contextValue, children: children }));
95
109
  }
@@ -7,4 +7,4 @@ export { defaultGdprCountries } from './gdpr_countries';
7
7
  export type { CookieConsentContextType, ConsentValue, CookieDialogClassNames, CookieDialogStyles } from './types';
8
8
  export type { CookieConsentDialogProps } from './client/components/cookie_consent_dialog';
9
9
  export type { PrivacyPolicyUpdateDialogProps } from './client/components/privacy_policy_update_dialog';
10
- export type { CookieConsentRoutingConfig, CookieConsentAnalyticsSecrets, CookieConsentCloudflareContext, CookieConsentGetCloudflareContext, } from '../types/types';
10
+ export type { CookieConsentRoutingConfig, CookieConsentAnalyticsConfig, CookieConsentCloudflareContext, CookieConsentGetCloudflareContext, } from '../types/types';
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { bench, describe } from 'vitest';
3
+ import { renderHook } from '@testing-library/react';
4
+ import useAuthUser from './use_auth_user';
5
+ import { AuthUserContext } from './auth_user_provider';
6
+ describe('useAuthUser (client)', () => {
7
+ bench('reads a provided context value', () => {
8
+ renderHook(() => useAuthUser(), {
9
+ wrapper: ({ children }) => (_jsx(AuthUserContext.Provider, { value: {
10
+ user: { uid: 'bench-user' },
11
+ loading: false,
12
+ reloadUser: async () => { },
13
+ sendVerificationEmail: async () => { },
14
+ logout: async () => { },
15
+ }, children: children })),
16
+ });
17
+ });
18
+ });
@@ -56,7 +56,7 @@ export default async function LocationzationProvider({ language, messages, child
56
56
  }
57
57
  initialAuthUser = await authUserServerProviderModule.resolveAuthUserAndRedirect();
58
58
  }
59
- let analyticsSecrets;
59
+ let analyticsConfig;
60
60
  let requiresConsent = true;
61
61
  if (config.cookieConsent) {
62
62
  const isDevEnvironment = process.env.NODE_ENV === 'development';
@@ -72,10 +72,10 @@ export default async function LocationzationProvider({ language, messages, child
72
72
  : false;
73
73
  const analyticsAllowedInEnv = config.cookieConsent.enableAnalyticsInDevMode === true || !isDevEnvironment;
74
74
  if (config.cookieConsent.autoWireAnalytics !== false && analyticsAllowedInEnv) {
75
- analyticsSecrets = config.cookieConsent.getSecrets
76
- ? await config.cookieConsent.getSecrets()
77
- : config.cookieConsent.secrets;
75
+ analyticsConfig = config.cookieConsent.getAnalytics
76
+ ? await config.cookieConsent.getAnalytics()
77
+ : config.cookieConsent.analytics;
78
78
  }
79
79
  }
80
- return _jsx(LocationzationClientProvider, { language: language, messages: messagesValue, initialAuthUser: initialAuthUser, skipAuthProvider: !autoWireClientProvider, analyticsSecrets: analyticsSecrets, requiresConsent: requiresConsent, autoWireDialogs: config.cookieConsent?.autoWireDialogs !== false, dialogProps: config.cookieConsent?.dialogProps, updateDialogProps: config.cookieConsent?.updateDialogProps, children: children });
80
+ return _jsx(LocationzationClientProvider, { language: language, messages: messagesValue, initialAuthUser: initialAuthUser, skipAuthProvider: !autoWireClientProvider, analyticsConfig: analyticsConfig, requiresConsent: requiresConsent, autoWireDialogs: config.cookieConsent?.autoWireDialogs !== false, dialogProps: config.cookieConsent?.dialogProps, updateDialogProps: config.cookieConsent?.updateDialogProps, children: children });
81
81
  }
@@ -1 +1 @@
1
- export type { CookieAttributes, LocalePrefixMode, Locales, ReturnType, RoutingConfig, TranslationEntry, TranslationObject, TranslatorReturnType, Alternates, changeFrequency, IntlSitemap, CookieConsentRoutingConfig, CookieConsentAnalyticsSecrets, CookieConsentCloudflareContext, CookieConsentGetCloudflareContext, } from './types';
1
+ export type { CookieAttributes, LocalePrefixMode, Locales, ReturnType, RoutingConfig, TranslationEntry, TranslationObject, TranslatorReturnType, Alternates, changeFrequency, IntlSitemap, CookieConsentRoutingConfig, CookieConsentAnalyticsConfig, CookieConsentCloudflareContext, CookieConsentGetCloudflareContext, } from './types';
@@ -117,27 +117,27 @@ export interface CookieConsentRoutingConfig {
117
117
  /**
118
118
  * Whether `IntlProvider` should automatically render the analytics/ads
119
119
  * scripts (Cloudflare Web Analytics beacon, Google Consent Mode + gtag,
120
- * Microsoft Clarity — whichever secrets resolve below) once consent is
120
+ * Microsoft Clarity — whichever config resolves below) once consent is
121
121
  * granted, and gate them behind the cookie-consent banner otherwise.
122
- * Defaults to `true` when `secrets`/`getSecrets` is set; set `false` to
123
- * keep `cookieConsent` configured for the dialogs/hook only and wire
122
+ * Defaults to `true` when `analytics`/`getAnalytics` is set; set `false`
123
+ * to keep `cookieConsent` configured for the dialogs/hook only and wire
124
124
  * analytics yourself.
125
125
  */
126
126
  autoWireAnalytics?: boolean;
127
127
  /**
128
- * Static secrets/IDs for the analytics providers below. Use this OR
129
- * `getSecrets`, not both — `getSecrets` takes precedence when both are
130
- * set (e.g. secrets only available at request time from a Cloudflare
128
+ * Static IDs/tokens for the analytics providers below. Use this OR
129
+ * `getAnalytics`, not both — `getAnalytics` takes precedence when both are
130
+ * set (e.g. values only available at request time from a Cloudflare
131
131
  * `env` binding).
132
132
  */
133
- secrets?: CookieConsentAnalyticsSecrets;
133
+ analytics?: CookieConsentAnalyticsConfig;
134
134
  /**
135
- * Resolves the same secrets at request time — e.g. from Cloudflare's
135
+ * Resolves the same config at request time — e.g. from Cloudflare's
136
136
  * `getCloudflareContext().env` (via `@opennextjs/cloudflare`, not a
137
137
  * dependency of this package — pass your own getter). Any field left
138
138
  * `undefined` in the returned object disables that provider's script.
139
139
  */
140
- getSecrets?: () => CookieConsentAnalyticsSecrets | Promise<CookieConsentAnalyticsSecrets>;
140
+ getAnalytics?: () => CookieConsentAnalyticsConfig | Promise<CookieConsentAnalyticsConfig>;
141
141
  /**
142
142
  * Resolves the visitor's country code directly (ISO 3166-1 alpha-2,
143
143
  * e.g. `"DE"`) — the simplest option when you already have it from
@@ -231,7 +231,7 @@ export interface CookieConsentGetCloudflareContext {
231
231
  async: false;
232
232
  }): CookieConsentCloudflareContext | null;
233
233
  }
234
- export interface CookieConsentAnalyticsSecrets {
234
+ export interface CookieConsentAnalyticsConfig {
235
235
  /** Cloudflare Web Analytics beacon token, e.g. `'{"token": "..."}'` (the raw `data-cf-beacon` attribute value). */
236
236
  cloudflareBeaconToken?: string;
237
237
  /** Google Analytics measurement ID, e.g. `"G-XXXXXXX"`. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudflare-next-intl",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "description": "Optimized Next Intl Package Special for App Router and Cloudflare",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -182,10 +182,10 @@
182
182
  },
183
183
  "homepage": "https://github.com/demian-ilnytskyi/cloudflare-next-intl#readme",
184
184
  "dependencies": {
185
- "@microsoft/clarity": "^1.0.2"
185
+ "@microsoft/clarity": "^1.0.2",
186
+ "firebase": "^12.17.0"
186
187
  },
187
188
  "peerDependencies": {
188
- "firebase": ">=10.0.0",
189
189
  "next": ">=12.0.0",
190
190
  "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0",
191
191
  "typescript": ">=5.0.0"
@@ -193,9 +193,6 @@
193
193
  "peerDependenciesMeta": {
194
194
  "typescript": {
195
195
  "optional": true
196
- },
197
- "firebase": {
198
- "optional": true
199
196
  }
200
197
  },
201
198
  "devDependencies": {
@@ -211,7 +208,6 @@
211
208
  "eslint": "^9.28.0",
212
209
  "eslint-config-next": "15.3.3",
213
210
  "eslint-config-prettier": "^10.1.2",
214
- "firebase": "^12.17.0",
215
211
  "jsdom": "^29.1.1",
216
212
  "next": "^15.3.0",
217
213
  "react": "^19.0.0",