cloudflare-next-intl 0.4.1 → 0.4.2

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
@@ -193,6 +193,8 @@ 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",
@@ -200,7 +202,10 @@ export default setIntlConfig({
200
202
  privacyPolicyDate: "2026-01-01",
201
203
  // Optional: gate the banner to GDPR-region visitors only. Omit both
202
204
  // getters to disable country-based gating (consent always implicit).
203
- getCloudflareContext: () => getCloudflareContext(),
205
+ // Pass @opennextjs/cloudflare's getCloudflareContext directly its
206
+ // exact overloaded signature is accepted as-is, called internally
207
+ // with { async: true }.
208
+ getCloudflareContext,
204
209
  // gdprCountries: [...], // defaults to EU/EEA + UK + Switzerland
205
210
  // enableAnalyticsInDevMode: true, // analytics stay off in dev otherwise
206
211
  },
@@ -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, async () => ({ cf: { country: 'DE' } }), 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 { CookieConsentCloudflareContext } from '../types/types';
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: (() => CookieConsentCloudflareContext | Promise<CookieConsentCloudflareContext>) | undefined, gdprCountries: readonly string[] | undefined): Promise<boolean>;
18
+ export default function resolveRequiresConsent(getCountryCode: (() => string | undefined | Promise<string | undefined>) | undefined, getCloudflareContext: CookieConsentGetCloudflareContext | undefined, gdprCountries: readonly string[] | undefined): Promise<boolean>;
@@ -45,7 +45,7 @@ export default async function resolveRequiresConsent(getCountryCode, getCloudfla
45
45
  return false;
46
46
  const countryCode = getCountryCode
47
47
  ? await getCountryCode()
48
- : (await getCloudflareContext()).cf?.country;
48
+ : (await getCloudflareContext({ async: true }))?.cf?.country;
49
49
  if (!countryCode)
50
50
  return true;
51
51
  return getGdprCountriesSet(gdprCountries).has(countryCode);
@@ -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';
@@ -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';
@@ -136,11 +136,12 @@ export interface CookieConsentRoutingConfig {
136
136
  */
137
137
  getCountryCode?: () => string | undefined | Promise<string | undefined>;
138
138
  /**
139
- * Returns the Cloudflare request context — e.g. your own
140
- * `getCloudflareContext()` call from `@opennextjs/cloudflare` (not a
141
- * dependency of this package, so bring your own). Only `cf.country`
142
- * is read from the resolved context. Ignored when `getCountryCode` is
143
- * also set.
139
+ * Pass `getCloudflareContext` from `@opennextjs/cloudflare` directly
140
+ * (not a dependency of this package, so bring your own import) — its
141
+ * exact overloaded signature is accepted as-is; called internally with
142
+ * `{ async: true }`, so you never need to wrap it yourself. Only
143
+ * `cf.country` is read from the resolved context. Ignored when
144
+ * `getCountryCode` is also set.
144
145
  *
145
146
  * Country-based gating (via either `getCountryCode` or
146
147
  * `getCloudflareContext`) decides whether the cookie-consent banner is
@@ -151,7 +152,7 @@ export interface CookieConsentRoutingConfig {
151
152
  * is the simplest opt-in-by-default setup; set one of the two getters
152
153
  * once you need real GDPR-region gating.
153
154
  */
154
- getCloudflareContext?: () => CookieConsentCloudflareContext | Promise<CookieConsentCloudflareContext>;
155
+ getCloudflareContext?: CookieConsentGetCloudflareContext;
155
156
  /**
156
157
  * Country codes (ISO 3166-1 alpha-2) for which the cookie-consent banner
157
158
  * is required. Only consulted when `getCountryCode` or
@@ -183,6 +184,23 @@ export interface CookieConsentCloudflareContext {
183
184
  country?: string;
184
185
  };
185
186
  }
187
+ /**
188
+ * Matches `@opennextjs/cloudflare`'s `getCloudflareContext` overloaded
189
+ * signature exactly, so that function can be passed as
190
+ * `cookieConsent.getCloudflareContext` directly — this package always
191
+ * calls it with `{ async: true }` internally (the first overload), which is
192
+ * why that overload's return type drives `resolveRequiresConsent`'s
193
+ * awaited result; the sync overload is accepted structurally only so the
194
+ * real function's type (which has both) is assignable as-is.
195
+ */
196
+ export interface CookieConsentGetCloudflareContext {
197
+ (options: {
198
+ async: true;
199
+ }): Promise<CookieConsentCloudflareContext | null>;
200
+ (options?: {
201
+ async: false;
202
+ }): CookieConsentCloudflareContext | null;
203
+ }
186
204
  export interface CookieConsentAnalyticsSecrets {
187
205
  /** Cloudflare Web Analytics beacon token, e.g. `'{"token": "..."}'` (the raw `data-cf-beacon` attribute value). */
188
206
  cloudflareBeaconToken?: string;
package/llms.txt CHANGED
@@ -42,7 +42,7 @@ other subpath can be used.
42
42
  - `./CookieConsentDialog` — default cookie-consent banner; accepts per-slot `classNames`/`styles` or a `render` prop for fully custom markup.
43
43
  - `./PrivacyPolicyUpdateDialog` — "privacy policy updated" banner; auto-enabled only when `cookieConsent.privacyPolicyDate` is set.
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudflare-next-intl",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
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",