cloudflare-next-intl 0.8.40 → 0.8.42
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 +22 -3
- package/dist/src/cookie_consent/gdpr_countries.d.ts +1 -1
- package/dist/src/cookie_consent/gdpr_countries.js +14 -4
- package/dist/src/server/components/server_provider.js +1 -1
- package/dist/src/server/components/server_provider_static.js +1 -1
- package/dist/src/server/functions/geo.d.ts +10 -4
- package/dist/src/server/functions/geo.js +44 -10
- package/dist/src/types/types.d.ts +24 -6
- package/dist/src/vite/build_id_asset.d.ts +2 -0
- package/dist/src/vite/build_id_asset.js +14 -0
- package/llms.txt +3 -2
- package/package.json +11 -2
package/README.md
CHANGED
|
@@ -217,6 +217,8 @@ export function customHandler(request: NextRequest) {
|
|
|
217
217
|
|
|
218
218
|
`intlMiddleware` automatically forwards `x-cf-country` and `x-cf-timezone` headers from `request.cf` so they are immediately available downstream via `next/headers`.
|
|
219
219
|
|
|
220
|
+
Header names default to `['x-cf-country', 'cf-ipcountry']` and `['x-cf-timezone', 'cf-timezone']`. You can customize them globally in `setIntlConfig({ generate: { countryHeaderNames: [...], timezoneHeaderNames: [...] } })` or per call via `getCountry(input, generate, headerNames)` / `getTimezone(input, fallback, generate, headerNames)`.
|
|
221
|
+
|
|
220
222
|
### Vinext Runtime Configuration
|
|
221
223
|
|
|
222
224
|
When deploying under [Vinext](https://github.com/cloudflare/vinext) with `cloudflare:workers`, you can pass your `env` and execution context (`ctx`) directly in `setIntlConfig`:
|
|
@@ -237,6 +239,22 @@ export default setIntlConfig({
|
|
|
237
239
|
});
|
|
238
240
|
```
|
|
239
241
|
|
|
242
|
+
#### Vite Build ID Asset Plugin (`cloudflare-next-intl/vite`)
|
|
243
|
+
|
|
244
|
+
When building client assets with Vite / Vinext for Cloudflare Workers, use `buildIdAsset` to emit the static `BUILD_ID` asset:
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
// vite.config.ts
|
|
248
|
+
import { defineConfig } from "vite";
|
|
249
|
+
import { buildIdAsset } from "cloudflare-next-intl/vite";
|
|
250
|
+
|
|
251
|
+
export default defineConfig({
|
|
252
|
+
plugins: [
|
|
253
|
+
buildIdAsset(), // reads __VINEXT_SHARED_BUILD_ID or __VINEXT_BUILD_ID
|
|
254
|
+
],
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
240
258
|
```tsx
|
|
241
259
|
// Client Components ("use client")
|
|
242
260
|
import { useLocale } from "cloudflare-next-intl/use";
|
|
@@ -389,9 +407,10 @@ export default setIntlConfig({
|
|
|
389
407
|
privacyPolicyDate: "2026-01-01",
|
|
390
408
|
// privacyPolicyPath: "/privacy-policy", // default; used by the
|
|
391
409
|
// dialogs' auto-rendered link. Set false to disable that link.
|
|
392
|
-
//
|
|
393
|
-
//
|
|
394
|
-
//
|
|
410
|
+
// country-based gating is enabled by default (reads Cloudflare geo
|
|
411
|
+
// headers; override via countryHeaderNames). Visitors outside GDPR
|
|
412
|
+
// regions skip the banner and get consent immediately.
|
|
413
|
+
// countryHeaderNames: ["x-cf-country", "cf-ipcountry"],
|
|
395
414
|
// gdprCountries: [...], // defaults to EU/EEA + UK + Switzerland
|
|
396
415
|
// enableAnalyticsInDevMode: true, // analytics stay off in dev otherwise
|
|
397
416
|
// autoWireDialogs: false, // opt out and render the dialogs yourself
|
|
@@ -5,4 +5,4 @@ import type { CookieConsentGetCloudflareContext, ErrorHandlingRoutingConfig } fr
|
|
|
5
5
|
* (nFADP). ISO 3166-1 alpha-2.
|
|
6
6
|
*/
|
|
7
7
|
export declare const defaultGdprCountries: readonly string[];
|
|
8
|
-
export default function resolveRequiresConsent(getCountryCode: (() => string | undefined | Promise<string | undefined>) | undefined, getCloudflareContext: CookieConsentGetCloudflareContext | undefined, gdprCountries: readonly string[] | undefined, errorHandlingConfig?: ErrorHandlingRoutingConfig): Promise<boolean>;
|
|
8
|
+
export default function resolveRequiresConsent(getCountryCode: (() => string | undefined | Promise<string | undefined>) | undefined, getCloudflareContext: CookieConsentGetCloudflareContext | undefined, gdprCountries: readonly string[] | undefined, errorHandlingConfig?: ErrorHandlingRoutingConfig, countryHeaderNames?: readonly string[]): Promise<boolean>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import reportError from '../error_handling/report_error';
|
|
2
|
+
import { getCountry } from '../server/functions/geo';
|
|
2
3
|
/**
|
|
3
4
|
* Default `cookieConsent.gdprCountries` — EU/EEA member states (GDPR),
|
|
4
5
|
* Iceland/Liechtenstein/Norway (EEA), the UK (UK-GDPR), and Switzerland
|
|
@@ -31,14 +32,12 @@ function getGdprCountriesSet(gdprCountries) {
|
|
|
31
32
|
}
|
|
32
33
|
return set;
|
|
33
34
|
}
|
|
34
|
-
export default async function resolveRequiresConsent(getCountryCode, getCloudflareContext, gdprCountries, errorHandlingConfig) {
|
|
35
|
-
if (!getCountryCode && !getCloudflareContext)
|
|
36
|
-
return true;
|
|
35
|
+
export default async function resolveRequiresConsent(getCountryCode, getCloudflareContext, gdprCountries, errorHandlingConfig, countryHeaderNames) {
|
|
37
36
|
let countryCode;
|
|
38
37
|
if (getCountryCode) {
|
|
39
38
|
countryCode = await getCountryCode();
|
|
40
39
|
}
|
|
41
|
-
else {
|
|
40
|
+
else if (getCloudflareContext) {
|
|
42
41
|
try {
|
|
43
42
|
countryCode = (await getCloudflareContext({ async: true }))?.cf?.country;
|
|
44
43
|
}
|
|
@@ -47,6 +46,17 @@ export default async function resolveRequiresConsent(getCountryCode, getCloudfla
|
|
|
47
46
|
return true;
|
|
48
47
|
}
|
|
49
48
|
}
|
|
49
|
+
// Neither getter supplied (or one resolved nothing): fall back to the
|
|
50
|
+
// package's own geo resolution, which reads the Cloudflare country
|
|
51
|
+
// headers off the current request.
|
|
52
|
+
if (typeof countryCode !== 'string' || !countryCode) {
|
|
53
|
+
try {
|
|
54
|
+
countryCode = await getCountry(undefined, undefined, countryHeaderNames);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
50
60
|
if (typeof countryCode !== 'string' || !countryCode)
|
|
51
61
|
return true;
|
|
52
62
|
return getGdprCountriesSet(gdprCountries).has(countryCode);
|
|
@@ -144,7 +144,7 @@ export default async function LocationzationProvider({ language, messages, stati
|
|
|
144
144
|
// `getCloudflareContext` path in dev; fail-safe to `true`
|
|
145
145
|
// (banner shown) same as an unresolved country would.
|
|
146
146
|
requiresConsent = !isDevEnvironment
|
|
147
|
-
? await resolveRequiresConsent(config.cookieConsent.getCountryCode, config.generate?.getCloudflareContext, config.cookieConsent.gdprCountries, config.errorHandling)
|
|
147
|
+
? await resolveRequiresConsent(config.cookieConsent.getCountryCode, config.generate?.getCloudflareContext, config.cookieConsent.gdprCountries, config.errorHandling, config.cookieConsent.countryHeaderNames)
|
|
148
148
|
: false;
|
|
149
149
|
const analyticsAllowedInEnv = config.cookieConsent.enableAnalyticsInDevMode === true || !isDevEnvironment;
|
|
150
150
|
if (config.cookieConsent.autoWireAnalytics !== false && analyticsAllowedInEnv) {
|
|
@@ -87,7 +87,7 @@ export default async function LocationzationProvider({ language, messages, child
|
|
|
87
87
|
// `getCloudflareContext` path in dev; fail-safe to `true`
|
|
88
88
|
// (banner shown) same as an unresolved country would.
|
|
89
89
|
requiresConsent = !isDevEnvironment
|
|
90
|
-
? await resolveRequiresConsent(config.cookieConsent.getCountryCode, config.generate?.getCloudflareContext, config.cookieConsent.gdprCountries, config.errorHandling)
|
|
90
|
+
? await resolveRequiresConsent(config.cookieConsent.getCountryCode, config.generate?.getCloudflareContext, config.cookieConsent.gdprCountries, config.errorHandling, config.cookieConsent.countryHeaderNames)
|
|
91
91
|
: false;
|
|
92
92
|
const analyticsAllowedInEnv = config.cookieConsent.enableAnalyticsInDevMode === true || !isDevEnvironment;
|
|
93
93
|
if (config.cookieConsent.autoWireAnalytics !== false && analyticsAllowedInEnv) {
|
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
import type { GenerateRoutingConfig, RequestOrHeaders } from '../../types/types';
|
|
2
|
+
/** Default request headers read to resolve the visitor's country, in order. */
|
|
3
|
+
export declare const defaultCountryHeaderNames: readonly string[];
|
|
4
|
+
/** Default request headers read to resolve the visitor's timezone, in order. */
|
|
5
|
+
export declare const defaultTimezoneHeaderNames: readonly string[];
|
|
2
6
|
/**
|
|
3
7
|
* Resolves the client's ISO 3166-1 alpha-2 country code (e.g. "US", "DE", "UA").
|
|
4
8
|
*
|
|
5
9
|
* Checks in order:
|
|
6
10
|
* 1. Explicit `input` (Request, NextRequest, or Headers) if provided
|
|
7
|
-
* 2. Next.js request headers via `headers()` (`
|
|
11
|
+
* 2. Next.js request headers via `headers()` (`headerNames`, default
|
|
12
|
+
* `x-cf-country`, `cf-ipcountry`)
|
|
8
13
|
* 3. `generate.getCloudflareContext` or `cf.country` if passed
|
|
9
14
|
* 4. `undefined` if outside request scope or unavailable
|
|
10
15
|
*/
|
|
11
|
-
export declare function getCountry(input?: RequestOrHeaders, generate?: GenerateRoutingConfig): Promise<string | undefined>;
|
|
16
|
+
export declare function getCountry(input?: RequestOrHeaders, generate?: GenerateRoutingConfig, headerNames?: readonly string[]): Promise<string | undefined>;
|
|
12
17
|
/**
|
|
13
18
|
* Resolves the client's IANA timezone string (e.g. "America/New_York", "Europe/Kyiv", "UTC").
|
|
14
19
|
*
|
|
15
20
|
* Checks in order:
|
|
16
21
|
* 1. Explicit `input` (Request, NextRequest, or Headers) if provided
|
|
17
|
-
* 2. Next.js request headers via `headers()` (`
|
|
22
|
+
* 2. Next.js request headers via `headers()` (`headerNames`, default
|
|
23
|
+
* `x-cf-timezone`, `cf-timezone`)
|
|
18
24
|
* 3. `generate.getCloudflareContext` or `cf.timezone` if passed
|
|
19
25
|
* 4. `fallback` (or `undefined`) if outside request scope or unavailable
|
|
20
26
|
*/
|
|
21
|
-
export declare function getTimezone(input?: RequestOrHeaders, fallback?: string, generate?: GenerateRoutingConfig): Promise<string | undefined>;
|
|
27
|
+
export declare function getTimezone(input?: RequestOrHeaders, fallback?: string, generate?: GenerateRoutingConfig, headerNames?: readonly string[]): Promise<string | undefined>;
|
|
22
28
|
/**
|
|
23
29
|
* Resolves the Cloudflare environment bindings object from `generate.env` or `generate.getCloudflareContext`.
|
|
24
30
|
*/
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/** Default request headers read to resolve the visitor's country, in order. */
|
|
2
|
+
export const defaultCountryHeaderNames = ['x-cf-country', 'cf-ipcountry'];
|
|
3
|
+
/** Default request headers read to resolve the visitor's timezone, in order. */
|
|
4
|
+
export const defaultTimezoneHeaderNames = ['x-cf-timezone', 'cf-timezone'];
|
|
1
5
|
function extractHeader(h, name) {
|
|
2
6
|
if (typeof h.get === 'function') {
|
|
3
7
|
const val = h.get(name);
|
|
@@ -7,24 +11,49 @@ function extractHeader(h, name) {
|
|
|
7
11
|
const val = rec[name] ?? rec[name.toLowerCase()];
|
|
8
12
|
return (typeof val === 'string' && val.length > 0) ? val : undefined;
|
|
9
13
|
}
|
|
14
|
+
// Read lazily (and tolerantly): `@intl-config` may not be set at all in
|
|
15
|
+
// standalone/unit usage of these helpers, and importing the config eagerly
|
|
16
|
+
// would risk a cycle with a config module that itself imports from here.
|
|
17
|
+
async function configuredHeaderNames(key) {
|
|
18
|
+
try {
|
|
19
|
+
const config = (await import('../../config/intl_config')).default;
|
|
20
|
+
return config?.generate?.[key];
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function extractFromHeaderNames(h, headerNames) {
|
|
27
|
+
for (const name of headerNames) {
|
|
28
|
+
const val = extractHeader(h, name);
|
|
29
|
+
if (val)
|
|
30
|
+
return val;
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
10
34
|
/**
|
|
11
35
|
* Resolves the client's ISO 3166-1 alpha-2 country code (e.g. "US", "DE", "UA").
|
|
12
36
|
*
|
|
13
37
|
* Checks in order:
|
|
14
38
|
* 1. Explicit `input` (Request, NextRequest, or Headers) if provided
|
|
15
|
-
* 2. Next.js request headers via `headers()` (`
|
|
39
|
+
* 2. Next.js request headers via `headers()` (`headerNames`, default
|
|
40
|
+
* `x-cf-country`, `cf-ipcountry`)
|
|
16
41
|
* 3. `generate.getCloudflareContext` or `cf.country` if passed
|
|
17
42
|
* 4. `undefined` if outside request scope or unavailable
|
|
18
43
|
*/
|
|
19
|
-
export async function getCountry(input, generate) {
|
|
44
|
+
export async function getCountry(input, generate, headerNames) {
|
|
45
|
+
const names = headerNames
|
|
46
|
+
?? generate?.countryHeaderNames
|
|
47
|
+
?? await configuredHeaderNames('countryHeaderNames')
|
|
48
|
+
?? defaultCountryHeaderNames;
|
|
20
49
|
if (input) {
|
|
21
50
|
if ('headers' in input && input.headers) {
|
|
22
|
-
const country =
|
|
51
|
+
const country = extractFromHeaderNames(input.headers, names);
|
|
23
52
|
if (country)
|
|
24
53
|
return country;
|
|
25
54
|
}
|
|
26
55
|
else if (typeof input.get === 'function') {
|
|
27
|
-
const country = input
|
|
56
|
+
const country = extractFromHeaderNames(input, names);
|
|
28
57
|
if (country)
|
|
29
58
|
return country;
|
|
30
59
|
}
|
|
@@ -36,7 +65,7 @@ export async function getCountry(input, generate) {
|
|
|
36
65
|
try {
|
|
37
66
|
const { headers } = await import('next/headers');
|
|
38
67
|
const h = await headers();
|
|
39
|
-
const country = h
|
|
68
|
+
const country = extractFromHeaderNames(h, names);
|
|
40
69
|
if (country)
|
|
41
70
|
return country;
|
|
42
71
|
}
|
|
@@ -61,19 +90,24 @@ export async function getCountry(input, generate) {
|
|
|
61
90
|
*
|
|
62
91
|
* Checks in order:
|
|
63
92
|
* 1. Explicit `input` (Request, NextRequest, or Headers) if provided
|
|
64
|
-
* 2. Next.js request headers via `headers()` (`
|
|
93
|
+
* 2. Next.js request headers via `headers()` (`headerNames`, default
|
|
94
|
+
* `x-cf-timezone`, `cf-timezone`)
|
|
65
95
|
* 3. `generate.getCloudflareContext` or `cf.timezone` if passed
|
|
66
96
|
* 4. `fallback` (or `undefined`) if outside request scope or unavailable
|
|
67
97
|
*/
|
|
68
|
-
export async function getTimezone(input, fallback, generate) {
|
|
98
|
+
export async function getTimezone(input, fallback, generate, headerNames) {
|
|
99
|
+
const names = headerNames
|
|
100
|
+
?? generate?.timezoneHeaderNames
|
|
101
|
+
?? await configuredHeaderNames('timezoneHeaderNames')
|
|
102
|
+
?? defaultTimezoneHeaderNames;
|
|
69
103
|
if (input) {
|
|
70
104
|
if ('headers' in input && input.headers) {
|
|
71
|
-
const tz =
|
|
105
|
+
const tz = extractFromHeaderNames(input.headers, names);
|
|
72
106
|
if (tz)
|
|
73
107
|
return tz;
|
|
74
108
|
}
|
|
75
109
|
else if (typeof input.get === 'function') {
|
|
76
|
-
const tz = input
|
|
110
|
+
const tz = extractFromHeaderNames(input, names);
|
|
77
111
|
if (tz)
|
|
78
112
|
return tz;
|
|
79
113
|
}
|
|
@@ -85,7 +119,7 @@ export async function getTimezone(input, fallback, generate) {
|
|
|
85
119
|
try {
|
|
86
120
|
const { headers } = await import('next/headers');
|
|
87
121
|
const h = await headers();
|
|
88
|
-
const tz = h
|
|
122
|
+
const tz = extractFromHeaderNames(h, names);
|
|
89
123
|
if (tz)
|
|
90
124
|
return tz;
|
|
91
125
|
}
|
|
@@ -144,6 +144,19 @@ export interface GenerateRoutingConfig {
|
|
|
144
144
|
* Set one of the two getters to scope the banner to GDPR regions only.
|
|
145
145
|
*/
|
|
146
146
|
getCloudflareContext?: CookieConsentGetCloudflareContext;
|
|
147
|
+
/**
|
|
148
|
+
* Request headers read (in order) by `getCountry()` to resolve the
|
|
149
|
+
* visitor's country. Defaults to `['x-cf-country', 'cf-ipcountry']` —
|
|
150
|
+
* override when your edge/proxy forwards it under a different name.
|
|
151
|
+
* `cookieConsent.countryHeaderNames` takes precedence for the
|
|
152
|
+
* cookie-consent banner's own resolution.
|
|
153
|
+
*/
|
|
154
|
+
countryHeaderNames?: readonly string[];
|
|
155
|
+
/**
|
|
156
|
+
* Request headers read (in order) by `getTimezone()` to resolve the
|
|
157
|
+
* visitor's IANA timezone. Defaults to `['x-cf-timezone', 'cf-timezone']`.
|
|
158
|
+
*/
|
|
159
|
+
timezoneHeaderNames?: readonly string[];
|
|
147
160
|
}
|
|
148
161
|
/**
|
|
149
162
|
* Flexible input accepted by `getCountry()` and `getTimezone()`:
|
|
@@ -359,14 +372,19 @@ export interface CookieConsentRoutingConfig {
|
|
|
359
372
|
* over `getCloudflareContext` when both are set.
|
|
360
373
|
*/
|
|
361
374
|
getCountryCode?: () => string | undefined | Promise<string | undefined>;
|
|
375
|
+
/**
|
|
376
|
+
* Request headers read (in order) to resolve the visitor's country when
|
|
377
|
+
* neither `getCountryCode` nor `generate.getCloudflareContext` produced
|
|
378
|
+
* one. Defaults to `['x-cf-country', 'cf-ipcountry']` — override when
|
|
379
|
+
* your edge/proxy forwards the country under a different name.
|
|
380
|
+
*/
|
|
381
|
+
countryHeaderNames?: readonly string[];
|
|
362
382
|
/**
|
|
363
383
|
* Country codes (ISO 3166-1 alpha-2) for which the cookie-consent banner
|
|
364
|
-
* is required.
|
|
365
|
-
*
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
* country that couldn't be resolved still requires it (fail-safe:
|
|
369
|
-
* unknown defaults to "ask").
|
|
384
|
+
* is required. Defaults to the EU/EEA + UK + Switzerland
|
|
385
|
+
* (GDPR/UK-GDPR/nFADP scope). A visitor whose resolved country isn't in
|
|
386
|
+
* this set is treated as NOT requiring consent; a country that couldn't
|
|
387
|
+
* be resolved still requires it (fail-safe: unknown defaults to "ask").
|
|
370
388
|
*/
|
|
371
389
|
gdprCountries?: readonly string[];
|
|
372
390
|
/**
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function buildIdAsset(fileName = "BUILD_ID") {
|
|
2
|
+
return {
|
|
3
|
+
name: "cfni:build-id-asset",
|
|
4
|
+
apply: "build",
|
|
5
|
+
generateBundle() {
|
|
6
|
+
if (this.environment?.name !== "client")
|
|
7
|
+
return;
|
|
8
|
+
const buildId = process.env.__VINEXT_SHARED_BUILD_ID ?? process.env.__VINEXT_BUILD_ID;
|
|
9
|
+
if (!buildId)
|
|
10
|
+
return;
|
|
11
|
+
this.emitFile({ type: "asset", fileName, source: buildId });
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
}
|
package/llms.txt
CHANGED
|
@@ -11,7 +11,7 @@ other subpath can be used.
|
|
|
11
11
|
- `.` — everything, re-exported (prefer the flat subpaths below for smaller bundles).
|
|
12
12
|
- `./client` — client-side barrel: `LocaleLink`, `usePathname`, `setCookieClient`, `getCookieClient`.
|
|
13
13
|
- `./server` — server-side barrel: `getMessage`, `getTranslations`, `getLocale`, `getCountry`, `getTimezone`, `resolveEnv`, `IntlProvider`, `Link`, `IntlHelperScript`, `getLocaleStaticParams`.
|
|
14
|
-
- `./geo` / `./getCountry` / `./getTimezone` — country & timezone resolver helpers (`getCountry(input?)`, `getTimezone(input?, fallback?)`, `resolveEnv(generate?)`) for Vinext, OpenNext, and Cloudflare Workers.
|
|
14
|
+
- `./geo` / `./getCountry` / `./getTimezone` — country & timezone resolver helpers (`getCountry(input?, generate?, headerNames?)`, `getTimezone(input?, fallback?, generate?, headerNames?)`, `resolveEnv(generate?)`) for Vinext, OpenNext, and Cloudflare Workers. Custom header names can be configured via `generate.countryHeaderNames`/`generate.timezoneHeaderNames` or passed per-call.
|
|
15
15
|
- `./middleware` — `intlMiddleware` for `middleware.ts`; locale detection/rewrite/redirect and automatic CF header forwarding.
|
|
16
16
|
- `./setIntlConfig` — identity function for typed `RoutingConfig` authoring; use in your `@intl-config` file.
|
|
17
17
|
- `./serverProvider` — `IntlProvider` server component (also under `./server`).
|
|
@@ -27,6 +27,7 @@ other subpath can be used.
|
|
|
27
27
|
- `./db` — `withPublicDb(fn)` / `withUserDb(fn, uid?)` server-side Postgres/Drizzle context helpers (require `db` set on your `RoutingConfig`; direct Postgres or Supabase Data API with automatic PostgREST REST translation and `cfni_exec` fallback, see below).
|
|
28
28
|
- `./dbEslint` — flat-config ESLint fragment banning direct `@supabase/supabase-js`, `pg`, `postgres`, and deep `dist/` imports in application code.
|
|
29
29
|
- `./dbHelpers` — generic Drizzle SQL helper functions (`excluded`, `onConflictSet`, `ago`, `currentDate`, `windowCount`, `unnestLateral`, `ascNullsLast`, `alwaysTrue`, `lateral`, `aliasColumn`, `minOf`, `maxOf`, `roundReal`, `multiply`, `scalarFromCte`) for use with `./db`.
|
|
30
|
+
- `./vite` — `buildIdAsset(fileName?)`: Vite plugin to emit the client `BUILD_ID` asset (from `__VINEXT_SHARED_BUILD_ID` or `__VINEXT_BUILD_ID`) during build in Vinext/Vite environments.
|
|
30
31
|
|
|
31
32
|
## `firebaseAuth*` subpaths (require `firebaseAuth` set on your `RoutingConfig`)
|
|
32
33
|
|
|
@@ -46,7 +47,7 @@ other subpath can be used.
|
|
|
46
47
|
- `./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.
|
|
47
48
|
- `./PrivacyPolicyUpdateDialog` — "privacy policy updated" banner; auto-enabled only when `cookieConsent.privacyPolicyDate` is set. Same default-link behavior as `CookieConsentDialog` (label default `"Learn more"`).
|
|
48
49
|
- `./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`.
|
|
49
|
-
- Country-based gating (`cookieConsent.getCountryCode` / `getCloudflareContext` + `gdprCountries`): resolved server-side by `IntlProvider` into a `requiresConsent` boolean passed to `CookieConsentProvider`.
|
|
50
|
+
- Country-based gating (`cookieConsent.countryHeaderNames` / `getCountryCode` / `getCloudflareContext` + `gdprCountries`): resolved server-side by `IntlProvider` into a `requiresConsent` boolean passed to `CookieConsentProvider`. Automatically falls back to request headers (`x-cf-country`, `cf-ipcountry` or custom `countryHeaderNames`) when neither getter is set or when they resolve empty. `getCountryCode` (direct country resolver) takes precedence over `getCloudflareContext` (reads `cf.country`) when both are set. Unresolved country (or a `null` context) always requires consent (fail-safe). `./cookieConsent` also exports `defaultGdprCountries` (EU/EEA + UK + Switzerland).
|
|
50
51
|
|
|
51
52
|
## `db*` subpaths (require `db` set on your `RoutingConfig`)
|
|
52
53
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cloudflare-next-intl",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.42",
|
|
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",
|
|
@@ -209,6 +209,10 @@
|
|
|
209
209
|
"./dbSchema": {
|
|
210
210
|
"types": "./dist/src/db/schema.d.ts",
|
|
211
211
|
"import": "./dist/src/db/schema.js"
|
|
212
|
+
},
|
|
213
|
+
"./vite": {
|
|
214
|
+
"types": "./dist/src/vite/build_id_asset.d.ts",
|
|
215
|
+
"import": "./dist/src/vite/build_id_asset.js"
|
|
212
216
|
}
|
|
213
217
|
},
|
|
214
218
|
"scripts": {
|
|
@@ -264,11 +268,15 @@
|
|
|
264
268
|
"peerDependencies": {
|
|
265
269
|
"next": ">=12.0.0",
|
|
266
270
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0",
|
|
267
|
-
"typescript": ">=5.0.0"
|
|
271
|
+
"typescript": ">=5.0.0",
|
|
272
|
+
"vite": ">=6"
|
|
268
273
|
},
|
|
269
274
|
"peerDependenciesMeta": {
|
|
270
275
|
"typescript": {
|
|
271
276
|
"optional": true
|
|
277
|
+
},
|
|
278
|
+
"vite": {
|
|
279
|
+
"optional": true
|
|
272
280
|
}
|
|
273
281
|
},
|
|
274
282
|
"devDependencies": {
|
|
@@ -292,6 +300,7 @@
|
|
|
292
300
|
"tsup": "^8.5.1",
|
|
293
301
|
"typescript": "^5.5.3",
|
|
294
302
|
"typescript-eslint": "^8.33.1",
|
|
303
|
+
"vite": "^7.0.0",
|
|
295
304
|
"vitest": "^3.0.8"
|
|
296
305
|
}
|
|
297
306
|
}
|