cloudflare-next-intl 0.9.14 → 0.9.16

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
@@ -260,7 +260,7 @@ export default defineConfig({
260
260
 
261
261
  The scan (`checkDynamicPages`, also usable standalone from `cloudflare-next-intl/checkDynamicPages`) is a text heuristic, not a real parser, so it's deliberately conservative and follows a page's own local (relative/`@/`-alias) imports transitively — cycle-safe, capped at 300 files — so a signal several files away (a component's repository calling `cookies()`) still marks the page dynamic, not just literal text in the page file itself. Recognized signals: `cookies()`, `headers()`, `searchParams`, `unstable_noStore()`, `connection()`, `cache: "no-store"`, `next: { revalidate: 0 }`, and this package's own `getAuthUser()`/`useAuthUser()`/`withUserDb()` (each of which reads `cookies()` internally). Set `resolveImports: false` on `checkDynamicPages` to restore the original single-file-only scan, or pass `aliases` to override the default `@/` → `<appDir>/..` mapping.
262
262
 
263
- Being text-only and transitive, it can over-flag: any local file the page reaches — however many imports away — that merely *calls* a recognized signal counts, even along a branch that never runs in production (a `Config.isDev`-gated `fetch(..., { cache: "no-store" })`) or one that's optional/best-effort (a `try`/`catch`-wrapped `getAuthUser()` used only to tag a log line). It cannot see that a call is conditional or swallowed. For a page whose only reason for being flagged is that kind of optional read — attaching "whoever's signed in, if anyone" to an error report, analytics event, or log line — switch that read to `resolveOptionalAuthUser()` (`cloudflare-next-intl/resolveOptionalAuthUser`, see Firebase Auth below): it wraps `getAuthUser()` the same way but, being an npm-package import, is a boundary the scan doesn't open, so it contributes no signal.
263
+ Being text-only and transitive, it can over-flag: any local file the page reaches — however many imports away — that merely *calls* a recognized signal counts, even along a branch that never runs in production (a `Config.isDev`-gated `fetch(..., { cache: "no-store" })`) or one that's optional/best-effort (a `try`/`catch`-wrapped `getAuthUser()` used only to tag a log line). It cannot see that a call is conditional or swallowed. For a page whose only reason for being flagged is that kind of optional read — attaching "whoever's signed in, if anyone" to an error report, analytics event, or log line — switch that read to `resolveOptionalAuthUser()` (`cloudflare-next-intl/resolveOptionalAuthUser`, see Firebase Auth below): it wraps `getAuthUser()` the same way but, being an npm-package import, is a boundary the scan doesn't open, so it contributes no signal. If that read lives in a shared `onError` sink used by many pages at once, `resolveErrorReportingUser(useAuthUser?)` (same subpath) is the more precise fix: it's off (`{ user: null }`, no `getAuthUser()` call) by default, and only a `reportError({ ..., useAuthUser: true })` call site that actually wants the user on that report opts in per-call — instead of every page reaching that sink getting flagged.
264
264
  2. **Build-Time & Dev Image Optimizer (`imageOptimizer`)**: Automatically scans your image directories (`public/images`, `public/icons`), downscales oversized assets, produces sibling formats (`webp` by default; also supports `avif`, `png`, `jpeg`, `gif`, `tiff`, `heif`, `jp2`, `jxl`), generates 8px `.blur.webp` thumbnails with Next.js-matching SVG Gaussian blur placeholders, and provides transparent `<Image placeholder="blur" />` shimming via virtual modules. When more than one format is generated for an image, the shim renders a `<picture>` with one `<source>` per format — ordered exactly as configured — so the browser picks the best format it supports, with the original untouched file as an `onError` fallback if a generated asset fails to load. When the same image is used at different widths across the codebase, each size gets its own generated variant, and each `<Image>` usage automatically resolves to the closest matching size.
265
265
  3. **Locale File Bundling & Resolution (`localeFiles`)**: Resolves `@locale-file/*` to your `./messages` directory and transforms dynamic imports into `import.meta.glob('/messages/*.json', { eager: true })` for lightning-fast locale loading on Cloudflare Workers.
266
266
  4. **User-Agent Stub (`userAgentStub`)**: Prevents Next.js `user-agent` from importing `node:fs` during workerd runtime execution (which otherwise causes runtime 404 / 500 crashes in Workers proxy/middleware).
@@ -480,6 +480,23 @@ Features include:
480
480
  - `followSameOriginContinueUrl`: Automatically forwards emailed action links with `continueUrl` to the specified path (or external URL) directly from `intlMiddleware` (default `true`; set `false` on `firebaseAuth` config to disable). If `continueUrl` points to home root (`/`), it resolves to `actionLinkPath` (if set) or the mode target path (e.g. `/reset-password`).
481
481
  - `appCheck`: Firebase App Check integration supporting reCAPTCHA Enterprise (`recaptchaEnterpriseSiteKey`) and reCAPTCHA v3 (`recaptchaV3SiteKey`). For reCAPTCHA v3, defaults to a `CustomProvider` using `IntlHelperScript`'s explicit script tag to avoid iframe/webworker CDN integrity issues in private windows (`useExplicitRecaptchaScript: false` to opt out). Supports server-side token minting via service accounts.
482
482
  - `resolveOptionalAuthUser()` (`cloudflare-next-intl/resolveOptionalAuthUser`): best-effort variant of `getAuthUser()` for callers that want to *attach* the current user when one happens to be known — error/telemetry reporting, analytics, logging — without failing or changing behavior when no request/session context is available. Swallows every failure and resolves `{ user: null }` instead of throwing. Use `getAuthUser()` (not this) whenever your own output actually depends on who's signed in — `checkDynamicPages` (below) treats `getAuthUser()`/`useAuthUser()`/`withUserDb()` as page-blocking dynamic-API signals but does not follow into this helper, so it's also the way to read "whoever's signed in, if anyone" from a page or a module it imports without forcing that page dynamic.
483
+ - `resolveErrorReportingUser(useAuthUser?)` (same subpath): gated form of `resolveOptionalAuthUser()` for an `onError` sink — pass `ErrorHandlingParams.useAuthUser` straight through. Defaults to `false`: when not `true`, resolves `{ user: null }` immediately without calling `getAuthUser()` at all, so a page reached only through your `onError` sink's default path stays static-eligible. A specific `reportError({ ..., useAuthUser: true })` call site opts in per-call when it actually wants the user on that report.
484
+
485
+ ```ts
486
+ // your onError sink
487
+ import { resolveErrorReportingUser } from "cloudflare-next-intl/resolveOptionalAuthUser";
488
+
489
+ export default async function onError(params: ErrorHandlingParams) {
490
+ const { user } = await resolveErrorReportingUser(params.useAuthUser);
491
+ // ...write params + user?.email to your error store
492
+ }
493
+ ```
494
+
495
+ A specific call site rarely needs to set `useAuthUser: true` by hand: `syncErrorReportingAuthUser` (`cloudflare-next-intl/checkDynamicPages`, also `checkDynamicPages`'s and the Vite plugin's `syncErrorReportingAuthUser` option, default `false`) does it for you — it finds every `reportError()` call reached *only* from pages already confirmed `force-dynamic` and inserts `useAuthUser: true` there automatically, leaving alone any call reachable from even one static/unknown-status page. Opt in explicitly (it mutates call-site arguments across your app, a bigger change than the top-of-file `export const dynamic` insertion `checkDynamicPages` does by default):
496
+
497
+ ```ts
498
+ await checkDynamicPages({ appDir, mode: "fix", syncErrorReportingAuthUser: true });
499
+ ```
483
500
 
484
501
  ```tsx
485
502
  import ThemeSwitcher from "cloudflare-next-intl/ThemeSwitcher";
@@ -1,3 +1,4 @@
1
+ import { type SyncErrorReportingAuthUserReport } from './sync_error_reporting_auth_user.js';
1
2
  import type { AliasConfig } from './resolve_local_imports.js';
2
3
  export type DynamicPagesCheckMode = 'off' | 'report' | 'fix';
3
4
  export interface CheckDynamicPagesOptions {
@@ -7,6 +8,7 @@ export interface CheckDynamicPagesOptions {
7
8
  skip?: readonly string[];
8
9
  resolveImports?: boolean;
9
10
  aliases?: readonly AliasConfig[];
11
+ syncErrorReportingAuthUser?: boolean;
10
12
  }
11
13
  export interface CheckDynamicPagesReport {
12
14
  file: string;
@@ -18,4 +20,4 @@ export interface CheckDynamicPagesIo {
18
20
  writeFile?: (file: string, contents: string) => void;
19
21
  isFile?: (file: string) => boolean;
20
22
  }
21
- export declare function checkDynamicPages(options: CheckDynamicPagesOptions, io?: CheckDynamicPagesIo): Promise<CheckDynamicPagesReport[]>;
23
+ export declare function checkDynamicPages(options: CheckDynamicPagesOptions, io?: CheckDynamicPagesIo): Promise<(CheckDynamicPagesReport | SyncErrorReportingAuthUserReport)[]>;
@@ -4,6 +4,7 @@ import { findPageFiles as findPageFilesImpl } from './find_page_files.js';
4
4
  import { detectDynamicUsage } from './detect_dynamic_usage.js';
5
5
  import { traceDynamicUsage } from './trace_dynamic_usage.js';
6
6
  import { insertDynamicExport } from './insert_dynamic_export.js';
7
+ import { syncErrorReportingAuthUser } from './sync_error_reporting_auth_user.js';
7
8
  function defaultIsFile(path) {
8
9
  try {
9
10
  return statSync(path).isFile();
@@ -62,5 +63,9 @@ export async function checkDynamicPages(options, io = {}) {
62
63
  reports.push({ file, action: 'would-add-force-dynamic' });
63
64
  }
64
65
  }
66
+ if (options.syncErrorReportingAuthUser === true) {
67
+ const syncReports = await syncErrorReportingAuthUser({ appDir: options.appDir, mode: options.mode, target: options.target, skip: options.skip, aliases: options.aliases }, { findPageFiles, readFile, writeFile, isFile });
68
+ reports.push(...syncReports);
69
+ }
65
70
  return reports;
66
71
  }
@@ -0,0 +1,7 @@
1
+ import { type AliasConfig } from './resolve_local_imports.js';
2
+ export interface CollectReachableFilesIo {
3
+ readFile: (file: string) => string;
4
+ isFile?: (file: string) => boolean;
5
+ }
6
+ export declare const MAX_FILES_VISITED = 300;
7
+ export declare function collectReachableFiles(entryFile: string, entrySource: string, aliases: readonly AliasConfig[], io: CollectReachableFilesIo): Map<string, string>;
@@ -0,0 +1,30 @@
1
+ import { extractImportSpecifiers, resolveLocalImport } from './resolve_local_imports.js';
2
+ export const MAX_FILES_VISITED = 300;
3
+ export function collectReachableFiles(entryFile, entrySource, aliases, io) {
4
+ const isFile = io.isFile ?? (() => false);
5
+ const files = new Map([[entryFile, entrySource]]);
6
+ const queue = [entryFile];
7
+ while (queue.length > 0) {
8
+ const current = queue.shift();
9
+ if (files.size >= MAX_FILES_VISITED)
10
+ continue;
11
+ const source = files.get(current);
12
+ for (const specifier of extractImportSpecifiers(source)) {
13
+ if (files.size >= MAX_FILES_VISITED)
14
+ break;
15
+ const resolved = resolveLocalImport(specifier, current, aliases, isFile);
16
+ if (resolved === null || files.has(resolved))
17
+ continue;
18
+ let importedSource;
19
+ try {
20
+ importedSource = io.readFile(resolved);
21
+ }
22
+ catch {
23
+ continue;
24
+ }
25
+ files.set(resolved, importedSource);
26
+ queue.push(resolved);
27
+ }
28
+ }
29
+ return files;
30
+ }
@@ -3,3 +3,4 @@ export interface DynamicDetectionResult {
3
3
  detectedDynamicApis: string[];
4
4
  }
5
5
  export declare function detectDynamicUsage(sourceText: string): DynamicDetectionResult;
6
+ export declare function readExplicitDynamicValue(sourceText: string): 'force-static' | 'force-dynamic' | 'auto' | 'error' | null;
@@ -17,3 +17,13 @@ export function detectDynamicUsage(sourceText) {
17
17
  detectedDynamicApis: DYNAMIC_API_CHECKS.filter(({ pattern }) => pattern.test(sourceText)).map(({ name }) => name),
18
18
  };
19
19
  }
20
+ const EXPLICIT_DYNAMIC_EXPORT_VALUE = /export\s+const\s+dynamic\s*=\s*['"]([^'"]+)['"]/;
21
+ export function readExplicitDynamicValue(sourceText) {
22
+ const match = EXPLICIT_DYNAMIC_EXPORT_VALUE.exec(sourceText);
23
+ if (match === null)
24
+ return null;
25
+ const value = match[1];
26
+ if (value === 'force-static' || value === 'force-dynamic' || value === 'auto' || value === 'error')
27
+ return value;
28
+ return null;
29
+ }
@@ -0,0 +1,5 @@
1
+ export interface ReportErrorCall {
2
+ insertPos: number | null;
3
+ hasExplicitUseAuthUser: boolean;
4
+ }
5
+ export declare function findReportErrorCalls(sourceText: string): ReportErrorCall[];
@@ -0,0 +1,71 @@
1
+ const REPORT_ERROR_CALL = /\breportError\s*\(/g;
2
+ export function findReportErrorCalls(sourceText) {
3
+ const calls = [];
4
+ REPORT_ERROR_CALL.lastIndex = 0;
5
+ let match;
6
+ while ((match = REPORT_ERROR_CALL.exec(sourceText)) !== null) {
7
+ calls.push(parseCallArgs(sourceText, match.index + match[0].length));
8
+ }
9
+ return calls;
10
+ }
11
+ function parseCallArgs(sourceText, start) {
12
+ let depth = 1;
13
+ let i = start;
14
+ let firstArgEnd = -1;
15
+ let callEnd = -1;
16
+ while (i < sourceText.length && callEnd === -1) {
17
+ const ch = sourceText[i];
18
+ if (ch === '"' || ch === "'" || ch === '`') {
19
+ i = skipStringLiteral(sourceText, i, ch);
20
+ continue;
21
+ }
22
+ if (ch === '/' && sourceText[i + 1] === '/') {
23
+ const nextNewline = sourceText.indexOf('\n', i);
24
+ i = nextNewline === -1 ? sourceText.length : nextNewline;
25
+ continue;
26
+ }
27
+ if (ch === '/' && sourceText[i + 1] === '*') {
28
+ const end = sourceText.indexOf('*/', i + 2);
29
+ i = end === -1 ? sourceText.length : end + 2;
30
+ continue;
31
+ }
32
+ if (ch === '(' || ch === '{' || ch === '[') {
33
+ depth += 1;
34
+ }
35
+ else if (ch === ')' || ch === '}' || ch === ']') {
36
+ depth -= 1;
37
+ if (depth === 0) {
38
+ callEnd = i;
39
+ break;
40
+ }
41
+ }
42
+ else if (ch === ',' && depth === 1 && firstArgEnd === -1) {
43
+ firstArgEnd = i;
44
+ }
45
+ i += 1;
46
+ }
47
+ if (firstArgEnd === -1 || callEnd === -1) {
48
+ return { insertPos: null, hasExplicitUseAuthUser: false };
49
+ }
50
+ const paramsText = sourceText.slice(firstArgEnd + 1, callEnd);
51
+ const hasExplicitUseAuthUser = /\buseAuthUser\b/.test(paramsText);
52
+ const leadingWhitespace = paramsText.length - paramsText.trimStart().length;
53
+ const paramsStart = firstArgEnd + 1 + leadingWhitespace;
54
+ if (sourceText[paramsStart] !== '{') {
55
+ return { insertPos: null, hasExplicitUseAuthUser };
56
+ }
57
+ return { insertPos: paramsStart + 1, hasExplicitUseAuthUser };
58
+ }
59
+ function skipStringLiteral(sourceText, start, quote) {
60
+ let i = start + 1;
61
+ while (i < sourceText.length) {
62
+ if (sourceText[i] === '\\') {
63
+ i += 2;
64
+ continue;
65
+ }
66
+ if (sourceText[i] === quote)
67
+ return i + 1;
68
+ i += 1;
69
+ }
70
+ return sourceText.length;
71
+ }
@@ -0,0 +1,21 @@
1
+ import type { AliasConfig } from './resolve_local_imports.js';
2
+ import type { DynamicPagesCheckMode } from './check_dynamic_pages.js';
3
+ export interface SyncErrorReportingAuthUserOptions {
4
+ appDir: string;
5
+ mode?: DynamicPagesCheckMode;
6
+ target?: 'next' | 'vinext';
7
+ skip?: readonly string[];
8
+ aliases?: readonly AliasConfig[];
9
+ }
10
+ export interface SyncErrorReportingAuthUserReport {
11
+ file: string;
12
+ action: 'added-use-auth-user' | 'would-add-use-auth-user';
13
+ callCount: number;
14
+ }
15
+ export interface SyncErrorReportingAuthUserIo {
16
+ findPageFiles?: (appDir: string) => string[];
17
+ readFile?: (file: string) => string;
18
+ writeFile?: (file: string, contents: string) => void;
19
+ isFile?: (file: string) => boolean;
20
+ }
21
+ export declare function syncErrorReportingAuthUser(options: SyncErrorReportingAuthUserOptions, io?: SyncErrorReportingAuthUserIo): Promise<SyncErrorReportingAuthUserReport[]>;
@@ -0,0 +1,73 @@
1
+ import { readFileSync, statSync, writeFileSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { findPageFiles as findPageFilesImpl } from './find_page_files.js';
4
+ import { detectDynamicUsage, readExplicitDynamicValue } from './detect_dynamic_usage.js';
5
+ import { collectReachableFiles } from './collect_reachable_files.js';
6
+ import { findReportErrorCalls } from './find_report_error_calls.js';
7
+ function defaultIsFile(path) {
8
+ try {
9
+ return statSync(path).isFile();
10
+ }
11
+ catch {
12
+ return false;
13
+ }
14
+ }
15
+ function isConfirmedDynamic(source, reachableApis, target) {
16
+ const explicit = readExplicitDynamicValue(source);
17
+ if (explicit !== null)
18
+ return explicit === 'force-dynamic';
19
+ if (target === 'vinext')
20
+ return reachableApis.length > 0;
21
+ return false;
22
+ }
23
+ export async function syncErrorReportingAuthUser(options, io = {}) {
24
+ const mode = options.mode ?? 'report';
25
+ if (mode === 'off')
26
+ return [];
27
+ const target = options.target ?? 'next';
28
+ const findPageFiles = io.findPageFiles ?? findPageFilesImpl;
29
+ const readFile = io.readFile ?? ((file) => readFileSync(file, 'utf8'));
30
+ const writeFile = io.writeFile ?? ((file, contents) => writeFileSync(file, contents, 'utf8'));
31
+ const isFile = io.isFile ?? defaultIsFile;
32
+ const skipSet = new Set(options.skip ?? []);
33
+ const aliases = options.aliases ?? [
34
+ { prefix: '@/', replacement: resolve(options.appDir, '..') },
35
+ ];
36
+ const dynamicReachable = new Set();
37
+ const notConfirmedReachable = new Set();
38
+ const fileSources = new Map();
39
+ for (const page of findPageFiles(options.appDir)) {
40
+ if (skipSet.has(page))
41
+ continue;
42
+ const source = readFile(page);
43
+ const files = collectReachableFiles(page, source, aliases, { readFile, isFile });
44
+ const apis = new Set();
45
+ for (const [file, fileSource] of files) {
46
+ fileSources.set(file, fileSource);
47
+ detectDynamicUsage(fileSource).detectedDynamicApis.forEach((api) => apis.add(api));
48
+ }
49
+ const bucket = isConfirmedDynamic(source, [...apis], target) ? dynamicReachable : notConfirmedReachable;
50
+ for (const file of files.keys())
51
+ bucket.add(file);
52
+ }
53
+ const safeFiles = [...dynamicReachable].filter((file) => !notConfirmedReachable.has(file));
54
+ const reports = [];
55
+ for (const file of safeFiles) {
56
+ const source = fileSources.get(file);
57
+ const calls = findReportErrorCalls(source).filter((call) => call.insertPos !== null && !call.hasExplicitUseAuthUser);
58
+ if (calls.length === 0)
59
+ continue;
60
+ if (mode === 'fix') {
61
+ let rewritten = source;
62
+ for (const call of [...calls].sort((a, b) => b.insertPos - a.insertPos)) {
63
+ rewritten = `${rewritten.slice(0, call.insertPos)}useAuthUser: true, ${rewritten.slice(call.insertPos)}`;
64
+ }
65
+ writeFile(file, rewritten);
66
+ reports.push({ file, action: 'added-use-auth-user', callCount: calls.length });
67
+ }
68
+ else {
69
+ reports.push({ file, action: 'would-add-use-auth-user', callCount: calls.length });
70
+ }
71
+ }
72
+ return reports;
73
+ }
@@ -1,7 +1,5 @@
1
1
  import { type DynamicDetectionResult } from './detect_dynamic_usage.js';
2
- import { type AliasConfig } from './resolve_local_imports.js';
3
- export interface TraceDynamicUsageIo {
4
- readFile: (file: string) => string;
5
- isFile?: (file: string) => boolean;
6
- }
2
+ import { type CollectReachableFilesIo } from './collect_reachable_files.js';
3
+ import type { AliasConfig } from './resolve_local_imports.js';
4
+ export type TraceDynamicUsageIo = CollectReachableFilesIo;
7
5
  export declare function traceDynamicUsage(entryFile: string, entrySource: string, aliases: readonly AliasConfig[], io: TraceDynamicUsageIo): DynamicDetectionResult;
@@ -1,39 +1,17 @@
1
1
  import { detectDynamicUsage } from './detect_dynamic_usage.js';
2
- import { extractImportSpecifiers, resolveLocalImport } from './resolve_local_imports.js';
3
- const MAX_FILES_VISITED = 300;
2
+ import { collectReachableFiles } from './collect_reachable_files.js';
4
3
  export function traceDynamicUsage(entryFile, entrySource, aliases, io) {
5
- const isFile = io.isFile ?? (() => false);
6
- const visited = new Set([entryFile]);
7
- const queue = [{ file: entryFile, source: entrySource }];
4
+ const files = collectReachableFiles(entryFile, entrySource, aliases, io);
8
5
  let hasExplicitDynamicExport = false;
9
6
  const detectedApis = new Set();
10
7
  let first = true;
11
- while (queue.length > 0) {
12
- const current = queue.shift();
13
- const detection = detectDynamicUsage(current.source);
8
+ for (const source of files.values()) {
9
+ const detection = detectDynamicUsage(source);
14
10
  if (first) {
15
11
  hasExplicitDynamicExport = detection.hasExplicitDynamicExport;
16
12
  first = false;
17
13
  }
18
14
  detection.detectedDynamicApis.forEach((api) => detectedApis.add(api));
19
- if (visited.size >= MAX_FILES_VISITED)
20
- continue;
21
- for (const specifier of extractImportSpecifiers(current.source)) {
22
- if (visited.size >= MAX_FILES_VISITED)
23
- break;
24
- const resolved = resolveLocalImport(specifier, current.file, aliases, isFile);
25
- if (resolved === null || visited.has(resolved))
26
- continue;
27
- visited.add(resolved);
28
- let importedSource;
29
- try {
30
- importedSource = io.readFile(resolved);
31
- }
32
- catch {
33
- continue;
34
- }
35
- queue.push({ file: resolved, source: importedSource });
36
- }
37
15
  }
38
16
  return { hasExplicitDynamicExport, detectedDynamicApis: [...detectedApis] };
39
17
  }
@@ -2,3 +2,6 @@ import type { User } from '@firebase/auth';
2
2
  export default function resolveOptionalAuthUser(): Promise<{
3
3
  user: User | null;
4
4
  }>;
5
+ export declare function resolveErrorReportingUser(useAuthUser?: boolean): Promise<{
6
+ user: User | null;
7
+ }>;
@@ -8,3 +8,8 @@ export default async function resolveOptionalAuthUser() {
8
8
  return { user: null };
9
9
  }
10
10
  }
11
+ export async function resolveErrorReportingUser(useAuthUser) {
12
+ if (useAuthUser !== true)
13
+ return { user: null };
14
+ return resolveOptionalAuthUser();
15
+ }
@@ -54,6 +54,7 @@ export interface ErrorHandlingParams {
54
54
  consent?: ConsentValue;
55
55
  formattedMessage?: string;
56
56
  dedupKey?: string;
57
+ useAuthUser?: boolean;
57
58
  }
58
59
  export interface ErrorHandlingRoutingConfig {
59
60
  enable?: boolean;
@@ -4,5 +4,6 @@ export interface AutoDynamicPagesPluginOptions {
4
4
  appDir?: string;
5
5
  mode?: DynamicPagesCheckMode;
6
6
  target?: 'next' | 'vinext';
7
+ syncErrorReportingAuthUser?: boolean;
7
8
  }
8
9
  export declare function autoDynamicPagesPlugin(options?: AutoDynamicPagesPluginOptions): Plugin;
@@ -28,6 +28,7 @@ export function autoDynamicPagesPlugin(options = {}) {
28
28
  appDir,
29
29
  mode: options.mode ?? "fix",
30
30
  target: options.target ?? "vinext",
31
+ syncErrorReportingAuthUser: options.syncErrorReportingAuthUser ?? false,
31
32
  });
32
33
  }
33
34
  catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudflare-next-intl",
3
- "version": "0.9.14",
3
+ "version": "0.9.16",
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",