cloudflare-next-intl 0.9.45 → 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
|
|
|
@@ -22,8 +22,6 @@ function bindingsFromClause(clause) {
|
|
|
22
22
|
const namespaceMatch = /^\*\s*as\s+(\w+)$/.exec(clause.trim());
|
|
23
23
|
if (namespaceMatch)
|
|
24
24
|
return [namespaceMatch[1]];
|
|
25
|
-
if (clause.trim() === '*')
|
|
26
|
-
return [];
|
|
27
25
|
const braceMatch = /\{([^}]*)\}/.exec(clause);
|
|
28
26
|
if (braceMatch) {
|
|
29
27
|
for (const rawItem of braceMatch[1].split(',')) {
|
|
@@ -7,6 +7,10 @@ export declare function patchRouteMatching(code: string): string;
|
|
|
7
7
|
export declare function isOptimisticRoutingFile(id: string): boolean;
|
|
8
8
|
export declare function isOptimisticRoutingAlreadyFixed(code: string): boolean;
|
|
9
9
|
export declare function patchOptimisticRouting(code: string): string;
|
|
10
|
+
export declare function isPrefetchLearningFile(id: string): boolean;
|
|
11
|
+
export declare function isPrefetchLearningAlreadyFixed(code: string): boolean;
|
|
12
|
+
export declare function patchPrefetchLearning(code: string): string;
|
|
13
|
+
export declare function resolveVinextBrowserEntryPath(root?: string): string | null;
|
|
10
14
|
export declare function isAppPageRouteWiringFile(id: string): boolean;
|
|
11
15
|
export declare function resolveVinextAppPageRouteWiringPath(root?: string): string | null;
|
|
12
16
|
export declare function resolveVinextRouteMatchingPath(root?: string): string | null;
|
|
@@ -15,11 +19,14 @@ export interface SyncPatchVinextOnDiskOptions {
|
|
|
15
19
|
routeWiring?: boolean;
|
|
16
20
|
routeMatching?: boolean;
|
|
17
21
|
optimisticRouting?: boolean;
|
|
22
|
+
prefetchLearning?: boolean;
|
|
18
23
|
}
|
|
19
24
|
export declare function syncPatchVinextOnDisk(root?: string, options?: SyncPatchVinextOnDiskOptions): boolean;
|
|
25
|
+
export declare function bustVinextOptimizeDepsCache(cacheDir: string): boolean;
|
|
20
26
|
export interface VinextRouteWiringFixPluginOptions {
|
|
21
27
|
routeWiring?: boolean;
|
|
22
28
|
routeMatching?: boolean;
|
|
23
29
|
optimisticRouting?: boolean;
|
|
30
|
+
prefetchLearning?: boolean;
|
|
24
31
|
}
|
|
25
32
|
export declare function vinextRouteWiringFixPlugin(options?: VinextRouteWiringFixPluginOptions): Plugin;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, rmSync } from "node:fs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
const PREFETCH_LOADING_FN_RE = /function\s+getPrefetchLoadingEntry\s*\(\s*route\s*\)\s*\{[\s\S]*?return\s+getDefaultExport\s*\(\s*route\.loading\s*\)\s*\?[\s\S]*?:\s*null\s*;\s*\}/;
|
|
4
4
|
const FIXED_PREFETCH_LOADING_FN = `function getPrefetchLoadingEntry(route) {
|
|
@@ -113,14 +113,17 @@ export function isOptimisticRoutingAlreadyFixed(code) {
|
|
|
113
113
|
const hasRawPartsFix = code.includes("options.rawUrlParts[0] !== options.match.params.locale");
|
|
114
114
|
return hasLocalePrefixFirst && hasRawPartsFix;
|
|
115
115
|
}
|
|
116
|
-
const MATCH_OPTIMISTIC_ROUTE_RE = /function\s+matchOptimisticRouteManifestRoute\s*\(\s*options\s*\)\s*\{[\s\S]*?
|
|
117
|
-
const FIXED_MATCH_OPTIMISTIC_ROUTE = `function
|
|
116
|
+
const MATCH_OPTIMISTIC_ROUTE_RE = /function\s+matchOptimisticRouteManifestRoute\s*\(\s*options\s*\)\s*\{[\s\S]*?getRouteTrie\([\s\S]*?\)[\s\S]*?\n\}/;
|
|
117
|
+
const FIXED_MATCH_OPTIMISTIC_ROUTE = `function getActiveRouteLocale() {
|
|
118
|
+
return (typeof document !== "undefined" && (document.documentElement?.lang || document.cookie.match(/__user_locale_key__=([^;]+)/)?.[1])) || (typeof window !== "undefined" && window.__VINEXT_LOCALE__) || "en";
|
|
119
|
+
}
|
|
120
|
+
function matchOptimisticRouteManifestRoute(options) {
|
|
118
121
|
const urlParts = hrefToRouteParts(options.href, options.basePath);
|
|
119
122
|
if (urlParts === null) return null;
|
|
120
123
|
const trie = getRouteTrie(options.routeManifest);
|
|
121
124
|
const hasLeadingLocaleParam = Array.from(options.routeManifest?.segmentGraph?.routes?.values() ?? []).some((r) => r.patternParts?.[0] === ":locale");
|
|
122
125
|
if (hasLeadingLocaleParam) {
|
|
123
|
-
const activeLocale = (
|
|
126
|
+
const activeLocale = getActiveRouteLocale();
|
|
124
127
|
if (urlParts.normalized[0] !== activeLocale) {
|
|
125
128
|
const localeMatch = matchNode(trie, [activeLocale, ...urlParts.normalized], 0, []);
|
|
126
129
|
if (localeMatch !== null) {
|
|
@@ -147,14 +150,109 @@ export function patchOptimisticRouting(code) {
|
|
|
147
150
|
return code;
|
|
148
151
|
}
|
|
149
152
|
let result = code;
|
|
150
|
-
if (MATCH_OPTIMISTIC_ROUTE_RE.test(result)) {
|
|
153
|
+
if (!result.includes("hasLeadingLocaleParam") && MATCH_OPTIMISTIC_ROUTE_RE.test(result)) {
|
|
151
154
|
result = result.replace(MATCH_OPTIMISTIC_ROUTE_RE, FIXED_MATCH_OPTIMISTIC_ROUTE);
|
|
152
155
|
}
|
|
153
|
-
if (RESOLVE_OPTIMISTIC_NAV_PARAMS_RE.test(result)) {
|
|
156
|
+
if (!result.includes("options.rawUrlParts[0] !== options.match.params.locale") && RESOLVE_OPTIMISTIC_NAV_PARAMS_RE.test(result)) {
|
|
154
157
|
result = result.replace(RESOLVE_OPTIMISTIC_NAV_PARAMS_RE, FIXED_RESOLVE_OPTIMISTIC_NAV_PARAMS);
|
|
155
158
|
}
|
|
156
159
|
return result;
|
|
157
160
|
}
|
|
161
|
+
export function isPrefetchLearningFile(id) {
|
|
162
|
+
const cleanId = id.split("?")[0].replace(/\\/g, "/");
|
|
163
|
+
return cleanId.endsWith("/app-browser-entry.js") || cleanId.endsWith("/app-browser-entry.ts");
|
|
164
|
+
}
|
|
165
|
+
export function isPrefetchLearningAlreadyFixed(code) {
|
|
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
|
+
return hasFixedFunction && hasFixedCallSite;
|
|
169
|
+
}
|
|
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
|
+
const FIXED_LEARN_TEMPLATES_FN = `async function learnOptimisticRouteTemplatesFromPrefetchCache(options) {
|
|
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
|
+
};
|
|
191
|
+
const learning = [...optimisticRouteTemplateLearning.values()];
|
|
192
|
+
for (const [cacheKey, entry] of getPrefetchCache()) {
|
|
193
|
+
const sourceKey = getOptimisticPrefetchSourceKey({
|
|
194
|
+
cacheKey,
|
|
195
|
+
interceptionContext: options.interceptionContext,
|
|
196
|
+
mountedSlotsHeader: options.mountedSlotsHeader
|
|
197
|
+
});
|
|
198
|
+
if (optimisticRouteTemplateSources.has(sourceKey)) continue;
|
|
199
|
+
if (optimisticRouteTemplateLearning.has(sourceKey)) continue;
|
|
200
|
+
if (entry.prefetchKind === "route-tree") continue;
|
|
201
|
+
const isPendingNavigationTarget = !hasOptimisticTemplate && !isSettledPrefetchCacheEntry(entry) && entry.pending !== void 0 && options.targetRscUrl !== void 0 && stripRsc(parsePrefetchCacheKey(cacheKey).rscUrl) === stripRsc(options.targetRscUrl);
|
|
202
|
+
if (!isSettledPrefetchCacheEntry(entry) && !isPendingNavigationTarget) continue;
|
|
203
|
+
const promise = (async () => {
|
|
204
|
+
let settledEntry = entry;
|
|
205
|
+
if (!isSettledPrefetchCacheEntry(settledEntry)) {
|
|
206
|
+
await Promise.race([
|
|
207
|
+
settledEntry.pending?.catch(() => {}),
|
|
208
|
+
new Promise((resolve) => setTimeout(resolve, 3000))
|
|
209
|
+
]);
|
|
210
|
+
settledEntry = getPrefetchCache().get(cacheKey) ?? settledEntry;
|
|
211
|
+
if (!isSettledPrefetchCacheEntry(settledEntry)) return;
|
|
212
|
+
}
|
|
213
|
+
return learnOptimisticRouteTemplateFromPrefetch({
|
|
214
|
+
cacheKey,
|
|
215
|
+
entry: settledEntry,
|
|
216
|
+
interceptionContext: options.interceptionContext,
|
|
217
|
+
mountedSlotsHeader: options.mountedSlotsHeader,
|
|
218
|
+
routeManifest: options.routeManifest
|
|
219
|
+
});
|
|
220
|
+
})().then((learned) => {
|
|
221
|
+
if (learned) optimisticRouteTemplateSources.add(sourceKey);
|
|
222
|
+
}).finally(() => {
|
|
223
|
+
optimisticRouteTemplateLearning.delete(sourceKey);
|
|
224
|
+
});
|
|
225
|
+
optimisticRouteTemplateLearning.set(sourceKey, promise);
|
|
226
|
+
learning.push(promise);
|
|
227
|
+
}
|
|
228
|
+
if (learning.length === 0) return;
|
|
229
|
+
await Promise.allSettled(learning);
|
|
230
|
+
}`;
|
|
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
|
+
});`;
|
|
239
|
+
export function patchPrefetchLearning(code) {
|
|
240
|
+
if (isPrefetchLearningAlreadyFixed(code)) {
|
|
241
|
+
return code;
|
|
242
|
+
}
|
|
243
|
+
let result = code;
|
|
244
|
+
if (!result.includes("hasOptimisticTemplate") && LEARN_TEMPLATES_FN_RE.test(result)) {
|
|
245
|
+
result = result.replace(LEARN_TEMPLATES_FN_RE, FIXED_LEARN_TEMPLATES_FN);
|
|
246
|
+
}
|
|
247
|
+
if (LEARN_TEMPLATES_CALL_RE.test(result)) {
|
|
248
|
+
result = result.replace(LEARN_TEMPLATES_CALL_RE, FIXED_LEARN_TEMPLATES_CALL);
|
|
249
|
+
}
|
|
250
|
+
return result;
|
|
251
|
+
}
|
|
252
|
+
export function resolveVinextBrowserEntryPath(root = process.cwd()) {
|
|
253
|
+
const directPath = resolve(root, "node_modules/vinext/dist/server/app-browser-entry.js");
|
|
254
|
+
return existsSync(directPath) ? directPath : null;
|
|
255
|
+
}
|
|
158
256
|
export function isAppPageRouteWiringFile(id) {
|
|
159
257
|
const cleanId = id.split("?")[0].replace(/\\/g, "/");
|
|
160
258
|
return cleanId.endsWith("/app-page-route-wiring.js") || cleanId.endsWith("/app-page-route-wiring.tsx") || cleanId.endsWith("/app-page-route-wiring.ts");
|
|
@@ -172,7 +270,7 @@ export function resolveVinextOptimisticRoutingPath(root = process.cwd()) {
|
|
|
172
270
|
return existsSync(directPath) ? directPath : null;
|
|
173
271
|
}
|
|
174
272
|
export function syncPatchVinextOnDisk(root = process.cwd(), options = {}) {
|
|
175
|
-
const { routeWiring = true, routeMatching = true, optimisticRouting = true } = options;
|
|
273
|
+
const { routeWiring = true, routeMatching = true, optimisticRouting = true, prefetchLearning = true } = options;
|
|
176
274
|
let changed = false;
|
|
177
275
|
const wiringPath = routeWiring ? resolveVinextAppPageRouteWiringPath(root) : null;
|
|
178
276
|
if (wiringPath) {
|
|
@@ -184,6 +282,9 @@ export function syncPatchVinextOnDisk(root = process.cwd(), options = {}) {
|
|
|
184
282
|
writeFileSync(wiringPath, patched, "utf8");
|
|
185
283
|
changed = true;
|
|
186
284
|
}
|
|
285
|
+
else {
|
|
286
|
+
console.warn(`[cfni:vinext-route-wiring-fix] ${wiringPath} does not match the expected shape for patchAppPageRouteWiring — this vinext version may have changed; the route-wiring fix was NOT applied.`);
|
|
287
|
+
}
|
|
187
288
|
}
|
|
188
289
|
}
|
|
189
290
|
catch {
|
|
@@ -199,6 +300,9 @@ export function syncPatchVinextOnDisk(root = process.cwd(), options = {}) {
|
|
|
199
300
|
writeFileSync(matchingPath, patched, "utf8");
|
|
200
301
|
changed = true;
|
|
201
302
|
}
|
|
303
|
+
else {
|
|
304
|
+
console.warn(`[cfni:vinext-route-wiring-fix] ${matchingPath} does not match the expected shape for patchRouteMatching — this vinext version may have changed; the route-matching fix was NOT applied.`);
|
|
305
|
+
}
|
|
202
306
|
}
|
|
203
307
|
}
|
|
204
308
|
catch {
|
|
@@ -214,6 +318,27 @@ export function syncPatchVinextOnDisk(root = process.cwd(), options = {}) {
|
|
|
214
318
|
writeFileSync(optimisticPath, patched, "utf8");
|
|
215
319
|
changed = true;
|
|
216
320
|
}
|
|
321
|
+
else {
|
|
322
|
+
console.warn(`[cfni:vinext-route-wiring-fix] ${optimisticPath} does not match the expected shape for patchOptimisticRouting — this vinext version may have changed; the optimistic-routing fix was NOT applied.`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const browserEntryPath = prefetchLearning ? resolveVinextBrowserEntryPath(root) : null;
|
|
330
|
+
if (browserEntryPath) {
|
|
331
|
+
try {
|
|
332
|
+
const content = readFileSync(browserEntryPath, "utf8");
|
|
333
|
+
if (!isPrefetchLearningAlreadyFixed(content)) {
|
|
334
|
+
const patched = patchPrefetchLearning(content);
|
|
335
|
+
if (patched !== content) {
|
|
336
|
+
writeFileSync(browserEntryPath, patched, "utf8");
|
|
337
|
+
changed = true;
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
console.warn(`[cfni:vinext-route-wiring-fix] ${browserEntryPath} does not match the expected shape for patchPrefetchLearning — this vinext version may have changed; the prefetch-learning fix was NOT applied.`);
|
|
341
|
+
}
|
|
217
342
|
}
|
|
218
343
|
}
|
|
219
344
|
catch {
|
|
@@ -221,16 +346,39 @@ export function syncPatchVinextOnDisk(root = process.cwd(), options = {}) {
|
|
|
221
346
|
}
|
|
222
347
|
return changed;
|
|
223
348
|
}
|
|
349
|
+
export function bustVinextOptimizeDepsCache(cacheDir) {
|
|
350
|
+
let removed = false;
|
|
351
|
+
for (const sub of ["deps", "deps_ssr", "deps_rsc"]) {
|
|
352
|
+
const dir = resolve(cacheDir, sub);
|
|
353
|
+
if (!existsSync(dir))
|
|
354
|
+
continue;
|
|
355
|
+
try {
|
|
356
|
+
rmSync(dir, { recursive: true, force: true });
|
|
357
|
+
removed = true;
|
|
358
|
+
}
|
|
359
|
+
catch {
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return removed;
|
|
363
|
+
}
|
|
224
364
|
export function vinextRouteWiringFixPlugin(options = {}) {
|
|
225
365
|
const routeWiring = options.routeWiring !== false;
|
|
226
366
|
const routeMatching = options.routeMatching !== false;
|
|
227
367
|
const optimisticRouting = options.optimisticRouting !== false;
|
|
368
|
+
const prefetchLearning = options.prefetchLearning !== false;
|
|
228
369
|
return {
|
|
229
370
|
name: "cfni:vinext-route-wiring-fix",
|
|
230
371
|
enforce: "pre",
|
|
231
372
|
configResolved(config) {
|
|
232
373
|
const root = config.root || process.cwd();
|
|
233
|
-
syncPatchVinextOnDisk(root, { routeWiring, routeMatching, optimisticRouting });
|
|
374
|
+
const changed = syncPatchVinextOnDisk(root, { routeWiring, routeMatching, optimisticRouting, prefetchLearning });
|
|
375
|
+
if (changed) {
|
|
376
|
+
const cacheDir = config.cacheDir || resolve(root, "node_modules/.vite");
|
|
377
|
+
const busted = bustVinextOptimizeDepsCache(cacheDir);
|
|
378
|
+
if (busted) {
|
|
379
|
+
console.log("[cfni:vinext-route-wiring-fix] patched vinext on disk and cleared its stale Vite optimizeDeps cache — dependencies will re-bundle on next request.");
|
|
380
|
+
}
|
|
381
|
+
}
|
|
234
382
|
},
|
|
235
383
|
transform(code, id) {
|
|
236
384
|
if (routeWiring && isAppPageRouteWiringFile(id)) {
|
|
@@ -253,6 +401,16 @@ export function vinextRouteWiringFixPlugin(options = {}) {
|
|
|
253
401
|
map: null,
|
|
254
402
|
};
|
|
255
403
|
}
|
|
404
|
+
if (prefetchLearning && isPrefetchLearningFile(id)) {
|
|
405
|
+
if (isPrefetchLearningAlreadyFixed(code)) {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
const patched = patchPrefetchLearning(code);
|
|
409
|
+
return {
|
|
410
|
+
code: patched,
|
|
411
|
+
map: null,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
256
414
|
if (optimisticRouting && isOptimisticRoutingFile(id)) {
|
|
257
415
|
if (isOptimisticRoutingAlreadyFixed(code)) {
|
|
258
416
|
return;
|
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`,
|
|
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`).
|