cloudflare-next-intl 0.9.46 → 0.9.47

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
@@ -266,6 +266,7 @@ export default defineConfig({
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).
267
267
  5. **Cloudflare Workers Client Stub (`cfWorkersClientStub`)**: Stubs `cloudflare:workers` in client builds so shared modules can be referenced without client bundling errors.
268
268
  6. **Build ID Asset Emission (`buildIdAsset`)**: Emits `BUILD_ID` static asset in the client build directory from `process.env.__VINEXT_SHARED_BUILD_ID` or `process.env.__VINEXT_BUILD_ID`.
269
+ 7. **Vinext Route Wiring & Optimistic Prefetch Fix (`vinextRouteWiringFix`)**: Patches Vinext runtime route wiring, route matching, optimistic route template resolution, and prefetch learning so pending prefetches with already cached templates don't block navigation, and leading `:locale` segments route correctly.
269
270
 
270
271
  ##### Plugin Options
271
272
  All features are enabled by default, and can be individually configured or toggled off:
@@ -297,13 +298,14 @@ export default defineConfig({
297
298
  localeFiles: true, // Enable @locale-file & glob bundling (default: true)
298
299
  userAgentStub: true, // Enable regex-based user-agent stub (default: true)
299
300
  cfWorkersClientStub: true, // Enable client cloudflare:workers stub (default: true)
301
+ vinextRouteWiringFix: true, // Enable vinext route wiring, matching, and prefetch fixes (default: true, or options object)
300
302
  }),
301
303
  ],
302
304
  });
303
305
  ```
304
306
 
305
307
  Individual standalone plugins are also exported if you only need a specific feature:
306
- `imageOptimizerPlugin` (or `imageOptimizer`), `buildIdAsset`, `localeFilePlugin`, `userAgentStubPlugin`, `cfWorkersClientStubPlugin`.
308
+ `imageOptimizerPlugin` (or `imageOptimizer`), `buildIdAsset`, `localeFilePlugin`, `userAgentStubPlugin`, `cfWorkersClientStubPlugin`, `vinextRouteWiringFixPlugin`.
307
309
 
308
310
  ##### Per-Image Optimizer Settings
309
311
 
@@ -163,13 +163,31 @@ export function isPrefetchLearningFile(id) {
163
163
  return cleanId.endsWith("/app-browser-entry.js") || cleanId.endsWith("/app-browser-entry.ts");
164
164
  }
165
165
  export function isPrefetchLearningAlreadyFixed(code) {
166
- const hasFixedFunction = code.includes("isPendingNavigationTarget");
167
- const hasFixedCallSite = code.includes("targetRscUrl: rscUrl,");
166
+ const hasFixedFunction = code.includes("stripRsc(parsePrefetchCacheKey(cacheKey).rscUrl)") && code.includes("hasOptimisticTemplate");
167
+ const hasFixedCallSite = code.includes("targetHref: currentHref,") && code.includes("targetRscUrl: rscUrl,") && !LEARN_TEMPLATES_CALL_RE.test(code);
168
168
  return hasFixedFunction && hasFixedCallSite;
169
169
  }
170
170
  const LEARN_TEMPLATES_FN_RE = /async\s+function\s+learnOptimisticRouteTemplatesFromPrefetchCache\s*\(\s*options\s*\)\s*\{[\s\S]*?await\s+Promise\.allSettled\(\s*learning\s*\);\s*\}/;
171
171
  const FIXED_LEARN_TEMPLATES_FN = `async function learnOptimisticRouteTemplatesFromPrefetchCache(options) {
172
172
  if (options.routeManifest === null) return;
173
+ const hasOptimisticTemplate = options.targetHref !== void 0 && resolveOptimisticNavigationPayload({
174
+ basePath: __basePath,
175
+ href: options.targetHref,
176
+ interceptionContext: options.interceptionContext,
177
+ mountedSlotsHeader: options.mountedSlotsHeader,
178
+ routeManifest: options.routeManifest,
179
+ templates: optimisticRouteTemplates
180
+ }) !== null;
181
+ const stripRsc = (u) => {
182
+ if (!u) return "";
183
+ const q = u.indexOf("?");
184
+ if (q === -1) return u;
185
+ const sp = new URLSearchParams(u.slice(q + 1));
186
+ sp.delete("_rsc");
187
+ sp.delete("%5Frsc");
188
+ const s = sp.toString();
189
+ return s ? \`\${u.slice(0, q)}?\${s}\` : u.slice(0, q);
190
+ };
173
191
  const learning = [...optimisticRouteTemplateLearning.values()];
174
192
  for (const [cacheKey, entry] of getPrefetchCache()) {
175
193
  const sourceKey = getOptimisticPrefetchSourceKey({
@@ -180,7 +198,7 @@ const FIXED_LEARN_TEMPLATES_FN = `async function learnOptimisticRouteTemplatesFr
180
198
  if (optimisticRouteTemplateSources.has(sourceKey)) continue;
181
199
  if (optimisticRouteTemplateLearning.has(sourceKey)) continue;
182
200
  if (entry.prefetchKind === "route-tree") continue;
183
- const isPendingNavigationTarget = !isSettledPrefetchCacheEntry(entry) && entry.pending !== void 0 && options.targetRscUrl !== void 0 && parsePrefetchCacheKey(cacheKey).rscUrl === options.targetRscUrl;
201
+ const isPendingNavigationTarget = !hasOptimisticTemplate && !isSettledPrefetchCacheEntry(entry) && entry.pending !== void 0 && options.targetRscUrl !== void 0 && stripRsc(parsePrefetchCacheKey(cacheKey).rscUrl) === stripRsc(options.targetRscUrl);
184
202
  if (!isSettledPrefetchCacheEntry(entry) && !isPendingNavigationTarget) continue;
185
203
  const promise = (async () => {
186
204
  let settledEntry = entry;
@@ -210,17 +228,23 @@ const FIXED_LEARN_TEMPLATES_FN = `async function learnOptimisticRouteTemplatesFr
210
228
  if (learning.length === 0) return;
211
229
  await Promise.allSettled(learning);
212
230
  }`;
213
- const LEARN_TEMPLATES_CALL_RE = /(await\s+learnOptimisticRouteTemplatesFromPrefetchCache\(\s*\{\s*)interceptionContext:\s*requestInterceptionContext,/;
214
- const FIXED_LEARN_TEMPLATES_CALL = "$1interceptionContext: requestInterceptionContext,\n\t\t\t\t\t\t\ttargetRscUrl: rscUrl,";
231
+ const LEARN_TEMPLATES_CALL_RE = /await\s+learnOptimisticRouteTemplatesFromPrefetchCache\(\s*\{\s*interceptionContext:\s*requestInterceptionContext,\s*(targetRscUrl:\s*rscUrl,\s*)?mountedSlotsHeader,[\s\S]*?routeManifest\s*\n\s*\}\);/;
232
+ const FIXED_LEARN_TEMPLATES_CALL = `await learnOptimisticRouteTemplatesFromPrefetchCache({
233
+ interceptionContext: requestInterceptionContext,
234
+ targetHref: currentHref,
235
+ targetRscUrl: rscUrl,
236
+ mountedSlotsHeader,
237
+ routeManifest
238
+ });`;
215
239
  export function patchPrefetchLearning(code) {
216
240
  if (isPrefetchLearningAlreadyFixed(code)) {
217
241
  return code;
218
242
  }
219
243
  let result = code;
220
- if (!result.includes("isPendingNavigationTarget") && LEARN_TEMPLATES_FN_RE.test(result)) {
244
+ if (!result.includes("hasOptimisticTemplate") && LEARN_TEMPLATES_FN_RE.test(result)) {
221
245
  result = result.replace(LEARN_TEMPLATES_FN_RE, FIXED_LEARN_TEMPLATES_FN);
222
246
  }
223
- if (!result.includes("targetRscUrl: rscUrl,") && LEARN_TEMPLATES_CALL_RE.test(result)) {
247
+ if (LEARN_TEMPLATES_CALL_RE.test(result)) {
224
248
  result = result.replace(LEARN_TEMPLATES_CALL_RE, FIXED_LEARN_TEMPLATES_CALL);
225
249
  }
226
250
  return result;
package/llms.txt CHANGED
@@ -27,7 +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` — `cloudflareNextIntl(options?)` / `cloudflareNextIntlPlugin`, `imageOptimizerPlugin(options?)` / `imageOptimizer`, `buildIdAsset(fileName?)`, `localeFilePlugin(options?)`, `userAgentStubPlugin()`, `cfWorkersClientStubPlugin()`: All-in-one Vite plugin required for Vinext/Cloudflare Workers environments (bundles `@locale-file/*` via eager glob, resolves `@intl-config`, stubs Node.js `user-agent` to prevent runtime `node:fs` errors, stubs `cloudflare:workers` for client builds, emits client `BUILD_ID`, and runs build-time/dev Image Optimizer with Next.js blur placeholder shimming).
30
+ - `./vite` — `cloudflareNextIntl(options?)` / `cloudflareNextIntlPlugin`, `imageOptimizerPlugin(options?)` / `imageOptimizer`, `buildIdAsset(fileName?)`, `localeFilePlugin(options?)`, `userAgentStubPlugin()`, `cfWorkersClientStubPlugin()`, `vinextRouteWiringFixPlugin(options?)`: All-in-one Vite plugin required for Vinext/Cloudflare Workers environments (bundles `@locale-file/*` via eager glob, resolves `@intl-config`, stubs Node.js `user-agent` to prevent runtime `node:fs` errors, stubs `cloudflare:workers` for client builds, emits client `BUILD_ID`, runs build-time/dev Image Optimizer with Next.js blur placeholder shimming, and fixes vinext route wiring, matching, and non-blocking optimistic prefetch learning).
31
31
  - `./image-optimizer` / `./imageOptimizer` — image optimization suite: `imageOptimizerPlugin`, `imageOptimizer`, `resolveOptions`, `resolveImageConfig`, `resolveBlurOptions`, `processImage`, `makeBlurDataURL`, `getImageBlurSvg`, `renderManifest`, `writeManifest`, `isFresh`, `loadCache`, `saveCache`, `collectImages`, `run`.
32
32
  - `./errorHandling` — error reporting & stale deploy recovery barrel: `reportError`, `withErrorHandling`, `installConsoleErrorOverride`, `installGlobalErrorOverride`, `stringifyUnknown`, `formatErrorMessage`, `defaultIgnoredConsoleErrors`, `createServerErrorAction`, `isStaleDeployError`, `defaultStaleDeployPatterns`, `setStaleDeployPatterns`, `getStaleDeployPatterns`, `clearClientCache`, `useStaleDeployRecovery`, `shouldRecoverFromStaleDeploy`, `isRecentBuild`.
33
33
  - `./isStaleDeployError` — `isStaleDeployError(error, patterns?)`, `setStaleDeployPatterns(patterns)`, `getStaleDeployPatterns()`: detector returning `true` for version skew / chunk load / dynamic import / server action 404 / hydration errors (ChunkLoadError, UnrecognizedActionError, server action not found, failed to fetch, dynamically imported module failure, loading CSS chunk, connection closed, RSC payload failure, minified error #412, or missing stream error `undefined`) with fast pre-lowercased pattern cache and intl-config integration (`errorHandling.staleDeployPatterns`).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudflare-next-intl",
3
- "version": "0.9.46",
3
+ "version": "0.9.47",
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",