vinext 0.1.8 → 0.2.1
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 +51 -30
- package/dist/build/css-url-assets.d.ts +3 -1
- package/dist/build/css-url-assets.js +18 -1
- package/dist/build/inject-pregenerated-paths.d.ts +7 -0
- package/dist/build/inject-pregenerated-paths.js +21 -0
- package/dist/build/layout-classification.js +1 -1
- package/dist/build/nitro-route-rules.js +1 -1
- package/dist/build/pages-client-assets-module.d.ts +11 -0
- package/dist/build/pages-client-assets-module.js +27 -0
- package/dist/build/prerender-server-entry.d.ts +1 -0
- package/dist/build/prerender-server-entry.js +49 -0
- package/dist/build/prerender-server-pool.d.ts +44 -0
- package/dist/build/prerender-server-pool.js +194 -0
- package/dist/build/prerender.d.ts +2 -1
- package/dist/build/prerender.js +98 -27
- package/dist/build/report.d.ts +13 -2
- package/dist/build/report.js +99 -2
- package/dist/build/run-prerender.d.ts +7 -0
- package/dist/build/run-prerender.js +12 -2
- package/dist/build/standalone.js +2 -0
- package/dist/cache/cache-adapters-virtual.js +3 -3
- package/dist/check.d.ts +4 -6
- package/dist/check.js +48 -11
- package/dist/cli-args.d.ts +1 -2
- package/dist/cli-args.js +1 -1
- package/dist/cli-dev-config.d.ts +12 -0
- package/dist/cli-dev-config.js +23 -0
- package/dist/cli.js +112 -96
- package/dist/{server → client}/dev-error-overlay-store.d.ts +1 -1
- package/dist/{server → client}/dev-error-overlay-store.js +1 -1
- package/dist/{server → client}/dev-error-overlay.d.ts +1 -1
- package/dist/{server → client}/dev-error-overlay.js +2 -2
- package/dist/client/navigation-runtime.d.ts +2 -0
- package/dist/client/navigation-runtime.js +3 -1
- package/dist/client/vinext-next-data.d.ts +4 -1
- package/dist/client/window-next.d.ts +2 -1
- package/dist/cloudflare/index.d.ts +2 -2
- package/dist/cloudflare/index.js +2 -2
- package/dist/config/config-matchers.js +45 -19
- package/dist/config/next-config.d.ts +41 -9
- package/dist/config/next-config.js +60 -3
- package/dist/config/prerender.d.ts +34 -0
- package/dist/config/prerender.js +55 -0
- package/dist/entries/app-browser-entry.js +5 -1
- package/dist/entries/app-rsc-entry.d.ts +5 -3
- package/dist/entries/app-rsc-entry.js +44 -10
- package/dist/entries/app-rsc-manifest.js +2 -0
- package/dist/entries/pages-client-entry.d.ts +3 -0
- package/dist/entries/pages-client-entry.js +28 -3
- package/dist/entries/pages-server-entry.js +23 -6
- package/dist/image/image-adapters-virtual.d.ts +59 -0
- package/dist/image/image-adapters-virtual.js +59 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +482 -120
- package/dist/init-cloudflare.d.ts +43 -0
- package/dist/init-cloudflare.js +839 -0
- package/dist/init-platform.d.ts +40 -0
- package/dist/init-platform.js +195 -0
- package/dist/init.d.ts +16 -38
- package/dist/init.js +209 -99
- package/dist/node_modules/.pnpm/am-i-vibing@0.5.0/node_modules/am-i-vibing/dist/detector-1yx2Hoe0.js +294 -0
- package/dist/node_modules/.pnpm/process-ancestry@0.1.0/node_modules/process-ancestry/dist/index.js +94 -0
- package/dist/{cloudflare → packages/cloudflare}/src/cache/cdn-adapter.runtime.js +1 -1
- package/dist/{cloudflare → packages/cloudflare}/src/cache/kv-data-adapter.runtime.d.ts +2 -2
- package/dist/{cloudflare → packages/cloudflare}/src/cache/kv-data-adapter.runtime.js +9 -2
- package/dist/packages/cloudflare/src/deploy-config.js +150 -0
- package/dist/packages/cloudflare/src/deploy-help.js +55 -0
- package/dist/packages/cloudflare/src/deploy.js +272 -0
- package/dist/{cloudflare → packages/cloudflare/src}/tpr.d.ts +4 -41
- package/dist/{cloudflare → packages/cloudflare/src}/tpr.js +44 -20
- package/dist/plugins/ast-scope.d.ts +16 -0
- package/dist/plugins/ast-scope.js +62 -0
- package/dist/plugins/ast-utils.d.ts +27 -1
- package/dist/plugins/ast-utils.js +32 -1
- package/dist/plugins/css-module-imports.d.ts +14 -0
- package/dist/plugins/css-module-imports.js +59 -0
- package/dist/plugins/extensionless-dynamic-import.js +2 -2
- package/dist/plugins/fonts.js +1 -1
- package/dist/plugins/ignore-dynamic-requests.d.ts +11 -0
- package/dist/plugins/ignore-dynamic-requests.js +530 -0
- package/dist/plugins/og-assets.js +2 -1
- package/dist/plugins/optimize-imports.js +1 -1
- package/dist/plugins/rsc-reference-validation-normalizer.d.ts +12 -0
- package/dist/plugins/rsc-reference-validation-normalizer.js +48 -0
- package/dist/plugins/sass.d.ts +17 -1
- package/dist/plugins/sass.js +74 -1
- package/dist/plugins/styled-jsx.d.ts +16 -0
- package/dist/plugins/styled-jsx.js +149 -0
- package/dist/plugins/typeof-window.d.ts +1 -1
- package/dist/plugins/typeof-window.js +28 -56
- package/dist/routing/app-route-graph.d.ts +23 -2
- package/dist/routing/app-route-graph.js +138 -38
- package/dist/routing/file-matcher.d.ts +11 -1
- package/dist/routing/file-matcher.js +18 -3
- package/dist/routing/pages-router.js +2 -2
- package/dist/server/api-handler.js +9 -14
- package/dist/server/app-browser-action-result.d.ts +4 -1
- package/dist/server/app-browser-action-result.js +8 -1
- package/dist/server/app-browser-entry.js +198 -57
- package/dist/server/app-browser-interception-context.d.ts +1 -0
- package/dist/server/app-browser-interception-context.js +4 -2
- package/dist/server/app-browser-navigation-controller.d.ts +2 -0
- package/dist/server/app-browser-navigation-controller.js +60 -31
- package/dist/server/app-browser-server-action-client.d.ts +1 -1
- package/dist/server/app-browser-server-action-client.js +8 -7
- package/dist/server/app-browser-state.d.ts +12 -1
- package/dist/server/app-browser-state.js +25 -8
- package/dist/server/app-browser-visible-commit.d.ts +6 -1
- package/dist/server/app-browser-visible-commit.js +42 -24
- package/dist/server/app-elements-wire.d.ts +9 -2
- package/dist/server/app-elements-wire.js +8 -1
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +4 -3
- package/dist/server/app-fallback-renderer.d.ts +2 -1
- package/dist/server/app-fallback-renderer.js +10 -6
- package/dist/server/app-hydration-cache-publication.d.ts +11 -0
- package/dist/server/app-hydration-cache-publication.js +43 -0
- package/dist/server/app-middleware.d.ts +4 -3
- package/dist/server/app-middleware.js +8 -3
- package/dist/server/app-optimistic-routing.js +11 -4
- package/dist/server/app-page-boundary.js +2 -1
- package/dist/server/app-page-cache-finalizer.d.ts +1 -0
- package/dist/server/app-page-cache-finalizer.js +5 -4
- package/dist/server/app-page-cache-render.d.ts +1 -0
- package/dist/server/app-page-cache-render.js +8 -4
- package/dist/server/app-page-cache.d.ts +1 -0
- package/dist/server/app-page-cache.js +27 -7
- package/dist/server/app-page-dispatch.d.ts +1 -0
- package/dist/server/app-page-dispatch.js +26 -8
- package/dist/server/app-page-element-builder.d.ts +2 -1
- package/dist/server/app-page-element-builder.js +59 -4
- package/dist/server/app-page-execution.js +2 -1
- package/dist/server/app-page-probe.js +5 -0
- package/dist/server/app-page-render-identity.d.ts +2 -0
- package/dist/server/app-page-render-identity.js +3 -2
- package/dist/server/app-page-render.d.ts +2 -0
- package/dist/server/app-page-render.js +85 -16
- package/dist/server/app-page-request.d.ts +14 -0
- package/dist/server/app-page-request.js +69 -4
- package/dist/server/app-page-response.d.ts +7 -0
- package/dist/server/app-page-response.js +16 -4
- package/dist/server/app-page-route-wiring.d.ts +8 -1
- package/dist/server/app-page-route-wiring.js +32 -18
- package/dist/server/app-page-segment-state.d.ts +2 -1
- package/dist/server/app-page-segment-state.js +3 -1
- package/dist/server/app-page-stream.d.ts +7 -1
- package/dist/server/app-page-stream.js +3 -1
- package/dist/server/app-route-handler-execution.js +5 -1
- package/dist/server/app-route-handler-response.js +1 -0
- package/dist/server/app-route-handler-runtime.js +1 -1
- package/dist/server/app-route-tree-prefetch.d.ts +43 -0
- package/dist/server/app-route-tree-prefetch.js +187 -0
- package/dist/server/app-router-entry.js +9 -2
- package/dist/server/app-rsc-cache-busting.d.ts +2 -1
- package/dist/server/app-rsc-cache-busting.js +9 -4
- package/dist/server/app-rsc-handler.d.ts +7 -0
- package/dist/server/app-rsc-handler.js +148 -39
- package/dist/server/app-rsc-render-mode.d.ts +3 -2
- package/dist/server/app-rsc-render-mode.js +4 -1
- package/dist/server/app-rsc-request-normalization.d.ts +6 -6
- package/dist/server/app-rsc-request-normalization.js +10 -8
- package/dist/server/app-segment-config.d.ts +11 -0
- package/dist/server/app-segment-config.js +62 -6
- package/dist/server/app-server-action-execution.d.ts +1 -0
- package/dist/server/app-server-action-execution.js +61 -30
- package/dist/server/app-ssr-entry.d.ts +3 -0
- package/dist/server/app-ssr-entry.js +13 -5
- package/dist/server/app-ssr-stream.d.ts +7 -3
- package/dist/server/app-ssr-stream.js +10 -6
- package/dist/server/app-visited-response-cache.d.ts +6 -0
- package/dist/server/app-visited-response-cache.js +3 -1
- package/dist/server/cache-control.d.ts +3 -1
- package/dist/server/cache-control.js +13 -1
- package/dist/server/client-trace-metadata.js +26 -0
- package/dist/server/default-global-not-found-module.d.ts +14 -0
- package/dist/server/default-global-not-found-module.js +14 -0
- package/dist/server/dev-route-files.js +4 -0
- package/dist/server/dev-server.d.ts +11 -1
- package/dist/server/dev-server.js +94 -35
- package/dist/server/dev-stack-sourcemap.d.ts +1 -1
- package/dist/server/dev-stack-sourcemap.js +1 -1
- package/dist/server/fetch-handler.d.ts +2 -0
- package/dist/server/fetch-handler.js +18 -0
- package/dist/server/headers.d.ts +7 -15
- package/dist/server/headers.js +11 -18
- package/dist/server/image-optimization.d.ts +51 -1
- package/dist/server/image-optimization.js +52 -2
- package/dist/server/implicit-tags.js +1 -1
- package/dist/server/isr-cache.d.ts +3 -2
- package/dist/server/isr-cache.js +9 -5
- package/dist/server/metadata-routes.d.ts +3 -1
- package/dist/server/metadata-routes.js +12 -2
- package/dist/server/middleware-runtime.js +6 -1
- package/dist/server/navigation-planner.d.ts +1 -0
- package/dist/server/navigation-planner.js +14 -3
- package/dist/server/pages-api-route.js +2 -2
- package/dist/server/pages-asset-tags.d.ts +4 -6
- package/dist/server/pages-asset-tags.js +12 -12
- package/dist/server/pages-client-assets.d.ts +12 -0
- package/dist/server/pages-client-assets.js +10 -0
- package/dist/server/pages-data-route.d.ts +4 -2
- package/dist/server/pages-data-route.js +18 -4
- package/dist/server/pages-dev-module-url.d.ts +2 -1
- package/dist/server/pages-dev-module-url.js +6 -3
- package/dist/server/pages-node-compat.d.ts +19 -1
- package/dist/server/pages-node-compat.js +81 -4
- package/dist/server/pages-page-data.d.ts +33 -1
- package/dist/server/pages-page-data.js +62 -33
- package/dist/server/pages-page-handler.d.ts +2 -1
- package/dist/server/pages-page-handler.js +38 -19
- package/dist/server/pages-page-response.d.ts +8 -0
- package/dist/server/pages-page-response.js +7 -3
- package/dist/server/pages-request-pipeline.d.ts +9 -5
- package/dist/server/pages-request-pipeline.js +55 -7
- package/dist/server/pages-router-entry.d.ts +30 -0
- package/dist/server/pages-router-entry.js +108 -0
- package/dist/server/prerender-manifest.d.ts +3 -1
- package/dist/server/prerender-route-params.js +1 -1
- package/dist/server/prod-server.d.ts +5 -3
- package/dist/server/prod-server.js +68 -39
- package/dist/server/request-pipeline.js +2 -1
- package/dist/server/seed-cache.js +4 -4
- package/dist/shims/app-router-scroll-state.d.ts +1 -0
- package/dist/shims/app-router-scroll-state.js +1 -0
- package/dist/shims/app-router-scroll.js +2 -1
- package/dist/shims/cache-handler.js +8 -1
- package/dist/shims/cache.js +22 -15
- package/dist/shims/cdn-cache.js +1 -1
- package/dist/shims/dynamic-preload-chunks.js +2 -1
- package/dist/shims/fetch-cache.d.ts +3 -1
- package/dist/shims/fetch-cache.js +77 -52
- package/dist/shims/form.d.ts +4 -2
- package/dist/shims/form.js +37 -43
- package/dist/shims/headers.d.ts +7 -1
- package/dist/shims/headers.js +17 -3
- package/dist/shims/image.js +75 -14
- package/dist/shims/internal/app-prefetch-fetch-queue.d.ts +10 -0
- package/dist/shims/internal/app-prefetch-fetch-queue.js +61 -0
- package/dist/shims/internal/app-route-detection.d.ts +2 -17
- package/dist/shims/internal/app-route-detection.js +4 -17
- package/dist/shims/internal/hybrid-client-route-owner-direct.d.ts +23 -0
- package/dist/shims/internal/hybrid-client-route-owner-direct.js +51 -0
- package/dist/shims/internal/hybrid-client-route-owner.d.ts +3 -15
- package/dist/shims/internal/hybrid-client-route-owner.js +40 -58
- package/dist/shims/internal/pages-data-fetch-dedup.d.ts +10 -5
- package/dist/shims/internal/pages-data-fetch-dedup.js +84 -14
- package/dist/shims/internal/pages-data-target.d.ts +18 -12
- package/dist/shims/internal/pages-data-target.js +97 -13
- package/dist/shims/internal/pages-router-components.d.ts +7 -0
- package/dist/shims/internal/pages-router-components.js +13 -0
- package/dist/shims/layout-segment-context.d.ts +4 -1
- package/dist/shims/layout-segment-context.js +18 -4
- package/dist/shims/link.d.ts +1 -1
- package/dist/shims/link.js +224 -58
- package/dist/shims/navigation.d.ts +19 -3
- package/dist/shims/navigation.js +245 -47
- package/dist/shims/request-context.js +18 -0
- package/dist/shims/root-params.d.ts +15 -1
- package/dist/shims/root-params.js +21 -1
- package/dist/shims/router.d.ts +5 -7
- package/dist/shims/router.js +387 -102
- package/dist/shims/server.js +3 -2
- package/dist/shims/slot.js +3 -6
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/typegen.js +1 -1
- package/dist/utils/client-runtime-metadata.d.ts +2 -18
- package/dist/utils/client-runtime-metadata.js +31 -22
- package/dist/utils/dev-stack-sourcemap-endpoint.d.ts +4 -0
- package/dist/{server → utils}/dev-stack-sourcemap-endpoint.js +1 -1
- package/dist/utils/domain-locale.d.ts +6 -3
- package/dist/{server → utils}/middleware-request-headers.d.ts +1 -1
- package/dist/{server → utils}/middleware-request-headers.js +3 -3
- package/dist/utils/project.d.ts +48 -2
- package/dist/utils/project.js +225 -4
- package/dist/utils/protocol-headers.d.ts +23 -0
- package/dist/utils/protocol-headers.js +23 -0
- package/dist/utils/react-version.d.ts +4 -0
- package/dist/utils/react-version.js +44 -0
- package/dist/utils/vite-version.d.ts +2 -0
- package/dist/utils/vite-version.js +11 -1
- package/package.json +47 -2
- package/dist/deploy.d.ts +0 -197
- package/dist/deploy.js +0 -1040
- package/dist/server/dev-stack-sourcemap-endpoint.d.ts +0 -4
- /package/dist/{cloudflare → packages/cloudflare}/src/utils/cache-control-metadata.js +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { decodeRouteSegment, isInvisibleSegment, sortRoutes } from "./utils.js";
|
|
2
1
|
import { normalizePathSeparators } from "../utils/path.js";
|
|
2
|
+
import { decodeRouteSegment, isInvisibleSegment, sortRoutes } from "./utils.js";
|
|
3
3
|
import { findFileWithExts, scanWithExtensions } from "./file-matcher.js";
|
|
4
4
|
import { validateRoutePatterns } from "./route-validation.js";
|
|
5
5
|
import { compareStrings } from "../utils/compare.js";
|
|
@@ -83,6 +83,19 @@ function createStaticSegmentGraph(routes) {
|
|
|
83
83
|
templateIds: [...route.ids.templates],
|
|
84
84
|
slotIds: route.parallelSlots.map((slot) => slot.id).sort(compareStableStrings)
|
|
85
85
|
});
|
|
86
|
+
if (route.childrenSlot) {
|
|
87
|
+
const ownerLayoutId = findRouteManifestOwnerLayoutIdByTreePath(route, route.childrenSlot.ownerTreePath);
|
|
88
|
+
routeEntries.get(route.ids.route).slotIds = [...routeEntries.get(route.ids.route).slotIds, route.childrenSlot.id].sort(compareStableStrings);
|
|
89
|
+
slotBindings.set(`${route.ids.route}::${route.childrenSlot.id}`, {
|
|
90
|
+
id: `${route.ids.route}::${route.childrenSlot.id}`,
|
|
91
|
+
routeId: route.ids.route,
|
|
92
|
+
slotId: route.childrenSlot.id,
|
|
93
|
+
ownerLayoutId,
|
|
94
|
+
state: route.childrenSlot.state,
|
|
95
|
+
defaultId: null,
|
|
96
|
+
routeSegments: null
|
|
97
|
+
});
|
|
98
|
+
}
|
|
86
99
|
if (route.ids.page) pages.set(route.ids.page, {
|
|
87
100
|
id: route.ids.page,
|
|
88
101
|
routeId: route.ids.route,
|
|
@@ -225,6 +238,10 @@ function findRouteManifestOwnerLayoutId(route, treePosition) {
|
|
|
225
238
|
const layoutIndex = route.layoutTreePositions.indexOf(treePosition);
|
|
226
239
|
return route.ids.layouts[layoutIndex] ?? null;
|
|
227
240
|
}
|
|
241
|
+
function findRouteManifestOwnerLayoutIdByTreePath(route, treePath) {
|
|
242
|
+
const layoutIndex = route.layoutTreePositions.findIndex((treePosition) => createAppRouteGraphTreePath(route.routeSegments, treePosition) === treePath);
|
|
243
|
+
return route.ids.layouts[layoutIndex] ?? null;
|
|
244
|
+
}
|
|
228
245
|
function findSlotOwnerLayoutId(route, slot) {
|
|
229
246
|
if (slot.layoutIndex < 0) return null;
|
|
230
247
|
return route.ids.layouts[slot.layoutIndex] ?? null;
|
|
@@ -344,6 +361,13 @@ function createRouteManifestGraphVersion(segmentGraph) {
|
|
|
344
361
|
};
|
|
345
362
|
return `graph:${createHash("sha256").update(JSON.stringify(stableShape)).digest("hex")}`;
|
|
346
363
|
}
|
|
364
|
+
/**
|
|
365
|
+
* Build the App Router route graph by scanning `appDir`.
|
|
366
|
+
*
|
|
367
|
+
* `appDir` must be forward-slash. Every path in the graph is derived from it
|
|
368
|
+
* with `path.posix.*` and `findFile`, so a native appDir would produce mixed
|
|
369
|
+
* separators on Windows. Production callers normalize it at their entry.
|
|
370
|
+
*/
|
|
347
371
|
async function buildAppRouteGraph(appDir, matcher) {
|
|
348
372
|
const routes = [];
|
|
349
373
|
const scanMatcher = { ...matcher };
|
|
@@ -363,9 +387,13 @@ async function buildAppRouteGraph(appDir, matcher) {
|
|
|
363
387
|
const dir = path.posix.dirname(file);
|
|
364
388
|
const routeDir = dir === "." ? appDir : path.posix.join(appDir, dir);
|
|
365
389
|
if (!hasParallelSlotDirectory(routeDir)) continue;
|
|
366
|
-
if (discoverParallelSlots(routeDir, appDir, scanMatcher).length === 0) continue;
|
|
367
|
-
const route = directoryToAppRoute(dir, appDir, scanMatcher, null, null);
|
|
390
|
+
if (discoverParallelSlots(routeDir, appDir, scanMatcher, true).length === 0) continue;
|
|
391
|
+
const route = directoryToAppRoute(dir, appDir, scanMatcher, null, null, true);
|
|
368
392
|
if (!route) continue;
|
|
393
|
+
if (routes.some((candidate) => candidate.patternParts.length === route.patternParts.length + 1 && candidate.patternParts.at(-1)?.endsWith("*") && patternsStructurallyEquivalent(candidate.patternParts.slice(0, -1), route.patternParts))) {
|
|
394
|
+
ghostParentRoutes.push(route);
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
369
397
|
if (routePatterns.has(route.pattern)) {
|
|
370
398
|
ghostParentRoutes.push(route);
|
|
371
399
|
continue;
|
|
@@ -412,9 +440,9 @@ function validatePageRouteConflicts(routes, appDir) {
|
|
|
412
440
|
}
|
|
413
441
|
}
|
|
414
442
|
function formatAppFilePath(filePath, appDir) {
|
|
415
|
-
const relativePath = path.relative(appDir, filePath)
|
|
443
|
+
const relativePath = normalizePathSeparators(path.relative(appDir, filePath));
|
|
416
444
|
const parsedPath = path.parse(relativePath);
|
|
417
|
-
const withoutExtension = path.join(parsedPath.dir, parsedPath.name)
|
|
445
|
+
const withoutExtension = normalizePathSeparators(path.join(parsedPath.dir, parsedPath.name));
|
|
418
446
|
return withoutExtension.startsWith("/") ? withoutExtension : `/${withoutExtension}`;
|
|
419
447
|
}
|
|
420
448
|
/**
|
|
@@ -482,8 +510,29 @@ function discoverSlotSubRoutes(routes, matcher, ghostParents = []) {
|
|
|
482
510
|
}
|
|
483
511
|
}
|
|
484
512
|
if (subPathMap.size === 0) continue;
|
|
513
|
+
const childrenOwnerTreePath = parentRoute.parallelSlots.find((slot) => path.dirname(slot.ownerDir) === parentPageDir)?.ownerTreePath;
|
|
514
|
+
if (!childrenOwnerTreePath) throw new Error(`[vinext] App route graph invariant violated: missing children slot owner for ${parentRoute.pattern}`);
|
|
485
515
|
const childrenDefault = findFile(parentPageDir, "default", matcher);
|
|
486
516
|
if (parentRoute.pagePath && !childrenDefault) continue;
|
|
517
|
+
const childrenSlotId = createAppRouteGraphSlotId("children", childrenOwnerTreePath);
|
|
518
|
+
if (parentRoute.pagePath) parentRoute.childrenSlot = {
|
|
519
|
+
id: childrenSlotId,
|
|
520
|
+
ownerTreePath: childrenOwnerTreePath,
|
|
521
|
+
state: "active"
|
|
522
|
+
};
|
|
523
|
+
for (const route of routes) {
|
|
524
|
+
if (!route.pagePath || route === parentRoute) continue;
|
|
525
|
+
const relativePageDir = path.relative(parentPageDir, path.dirname(route.pagePath));
|
|
526
|
+
if (relativePageDir === "" || relativePageDir === ".." || relativePageDir.startsWith(`..${path.sep}`) || path.isAbsolute(relativePageDir)) continue;
|
|
527
|
+
const existingOwnerDepth = route.childrenSlot?.ownerTreePath.split("/").filter(Boolean).length;
|
|
528
|
+
const candidateOwnerDepth = childrenOwnerTreePath.split("/").filter(Boolean).length;
|
|
529
|
+
if (existingOwnerDepth !== void 0 && existingOwnerDepth >= candidateOwnerDepth) continue;
|
|
530
|
+
route.childrenSlot = {
|
|
531
|
+
id: childrenSlotId,
|
|
532
|
+
ownerTreePath: childrenOwnerTreePath,
|
|
533
|
+
state: "active"
|
|
534
|
+
};
|
|
535
|
+
}
|
|
487
536
|
const childrenCatchAll = childrenDefault ? null : findCatchAllPage(parentPageDir, matcher);
|
|
488
537
|
const childrenFallback = childrenDefault ?? childrenCatchAll;
|
|
489
538
|
for (const { rawSegments, converted: convertedSubRoute, slotPages } of subPathMap.values()) {
|
|
@@ -525,6 +574,11 @@ function discoverSlotSubRoutes(routes, matcher, ghostParents = []) {
|
|
|
525
574
|
layouts: parentRoute.layouts,
|
|
526
575
|
templates: parentRoute.templates,
|
|
527
576
|
parallelSlots: subSlots,
|
|
577
|
+
childrenSlot: {
|
|
578
|
+
id: childrenSlotId,
|
|
579
|
+
ownerTreePath: childrenOwnerTreePath,
|
|
580
|
+
state: childrenDefault ? "default" : childrenCatchAll ? "active" : "unmatched"
|
|
581
|
+
},
|
|
528
582
|
loadingPath: parentRoute.loadingPath,
|
|
529
583
|
errorPath: parentRoute.errorPath,
|
|
530
584
|
layoutErrorPaths: parentRoute.layoutErrorPaths,
|
|
@@ -535,6 +589,7 @@ function discoverSlotSubRoutes(routes, matcher, ghostParents = []) {
|
|
|
535
589
|
unauthorizedPath: parentRoute.unauthorizedPath,
|
|
536
590
|
unauthorizedPaths: parentRoute.unauthorizedPaths,
|
|
537
591
|
routeSegments: [...parentRoute.routeSegments, ...rawSegments],
|
|
592
|
+
childrenRouteSegments: childrenDefault ? parentRoute.routeSegments : void 0,
|
|
538
593
|
templateTreePositions: parentRoute.templateTreePositions,
|
|
539
594
|
layoutTreePositions: parentRoute.layoutTreePositions,
|
|
540
595
|
isDynamic: parentRoute.isDynamic || subIsDynamic,
|
|
@@ -549,6 +604,26 @@ function discoverSlotSubRoutes(routes, matcher, ghostParents = []) {
|
|
|
549
604
|
}
|
|
550
605
|
return syntheticRoutes;
|
|
551
606
|
}
|
|
607
|
+
const dirEntriesCache = /* @__PURE__ */ new WeakMap();
|
|
608
|
+
function readDirEntriesCached(dir, matcher) {
|
|
609
|
+
let perMatcher = dirEntriesCache.get(matcher);
|
|
610
|
+
if (!perMatcher) {
|
|
611
|
+
perMatcher = /* @__PURE__ */ new Map();
|
|
612
|
+
dirEntriesCache.set(matcher, perMatcher);
|
|
613
|
+
}
|
|
614
|
+
let entries = perMatcher.get(dir);
|
|
615
|
+
if (entries === void 0) {
|
|
616
|
+
try {
|
|
617
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
618
|
+
} catch (error) {
|
|
619
|
+
const code = error.code;
|
|
620
|
+
if (code !== "ENOENT" && code !== "ENOTDIR") throw error;
|
|
621
|
+
entries = [];
|
|
622
|
+
}
|
|
623
|
+
perMatcher.set(dir, entries);
|
|
624
|
+
}
|
|
625
|
+
return entries;
|
|
626
|
+
}
|
|
552
627
|
const findSlotSubPagesCache = /* @__PURE__ */ new WeakMap();
|
|
553
628
|
function findSlotSubPages(slotDir, matcher) {
|
|
554
629
|
let perMatcher = findSlotSubPagesCache.get(matcher);
|
|
@@ -629,23 +704,29 @@ function findCatchAllPage(dir, matcher) {
|
|
|
629
704
|
}
|
|
630
705
|
/**
|
|
631
706
|
* Convert a file path relative to app/ into an AppRoute.
|
|
707
|
+
*
|
|
708
|
+
* `file` and `appDir` must be forward-slash. `file` comes from
|
|
709
|
+
* `scanWithExtensions` (already forward-slash) and is joined onto `appDir` with
|
|
710
|
+
* `path.posix.join` to form the page/route path, so a native input would
|
|
711
|
+
* produce a mixed separator on Windows.
|
|
632
712
|
*/
|
|
633
713
|
function fileToAppRoute(file, appDir, type, matcher) {
|
|
634
|
-
let dir = path.dirname(file);
|
|
635
|
-
if (type === "page" && dir !== "." && path.basename(dir) === "@children") {
|
|
636
|
-
const parent = path.dirname(dir);
|
|
714
|
+
let dir = path.posix.dirname(file);
|
|
715
|
+
if (type === "page" && dir !== "." && path.posix.basename(dir) === "@children") {
|
|
716
|
+
const parent = path.posix.dirname(dir);
|
|
637
717
|
dir = parent === "" || parent === "." ? "." : parent;
|
|
638
718
|
}
|
|
639
|
-
return directoryToAppRoute(dir, appDir, matcher, type === "page" ? path.join(appDir, file) : null, type === "route" ? path.join(appDir, file) : null);
|
|
719
|
+
return directoryToAppRoute(dir, appDir, matcher, type === "page" ? path.posix.join(appDir, file) : null, type === "route" ? path.posix.join(appDir, file) : null);
|
|
640
720
|
}
|
|
641
721
|
/**
|
|
642
|
-
* `dir` and `
|
|
643
|
-
* `path.posix.sep` and joined onto `appDir` with `path.posix.join
|
|
644
|
-
* is threaded to the layout/slot/boundary discovery below, which
|
|
645
|
-
* same way.
|
|
722
|
+
* `dir`, `appDir`, `pagePath`, and `routePath` must all be forward-slash. `dir`
|
|
723
|
+
* is split on `path.posix.sep` and joined onto `appDir` with `path.posix.join`.
|
|
724
|
+
* `appDir` is threaded to the layout/slot/boundary discovery below, which builds
|
|
725
|
+
* paths the same way. `pagePath` and `routePath` are stored on the route node as
|
|
726
|
+
* canonical ids that get compared and re-joined downstream.
|
|
646
727
|
*/
|
|
647
|
-
function directoryToAppRoute(dir, appDir, matcher, pagePath, routePath) {
|
|
648
|
-
const segments = dir === "." ? [] : dir.split(
|
|
728
|
+
function directoryToAppRoute(dir, appDir, matcher, pagePath, routePath, includeNestedOnlySlots = false) {
|
|
729
|
+
const segments = dir === "." ? [] : dir.split("/");
|
|
649
730
|
const params = [];
|
|
650
731
|
let isDynamic = false;
|
|
651
732
|
const convertedRoute = convertSegmentsToRouteParts(segments);
|
|
@@ -663,6 +744,7 @@ function directoryToAppRoute(dir, appDir, matcher, pagePath, routePath) {
|
|
|
663
744
|
const errorPaths = errorEntries.map((entry) => entry.path);
|
|
664
745
|
const errorTreePositions = errorEntries.map((entry) => entry.treePosition);
|
|
665
746
|
const routeDir = dir === "." ? appDir : path.posix.join(appDir, dir);
|
|
747
|
+
const effectivePagePath = pagePath ?? (routePath ? null : findFile(routeDir, "default", matcher));
|
|
666
748
|
const loadingPath = findFile(routeDir, "loading", matcher);
|
|
667
749
|
const errorPath = findFile(routeDir, "error", matcher);
|
|
668
750
|
const notFoundPath = discoverBoundaryFile(segments, appDir, "not-found", matcher);
|
|
@@ -671,11 +753,11 @@ function directoryToAppRoute(dir, appDir, matcher, pagePath, routePath) {
|
|
|
671
753
|
const notFoundPaths = discoverBoundaryFilePerLayout(layouts, "not-found", matcher);
|
|
672
754
|
const forbiddenPaths = discoverBoundaryFilePerLayout(layouts, "forbidden", matcher);
|
|
673
755
|
const unauthorizedPaths = discoverBoundaryFilePerLayout(layouts, "unauthorized", matcher);
|
|
674
|
-
const parallelSlots = discoverInheritedParallelSlots(segments, appDir, routeDir, matcher);
|
|
756
|
+
const parallelSlots = discoverInheritedParallelSlots(segments, appDir, routeDir, matcher, includeNestedOnlySlots);
|
|
675
757
|
return {
|
|
676
758
|
ids: createAppRouteSemanticIds({
|
|
677
759
|
pattern: pattern === "/" ? "/" : pattern,
|
|
678
|
-
pagePath,
|
|
760
|
+
pagePath: effectivePagePath,
|
|
679
761
|
routePath,
|
|
680
762
|
routeSegments: segments,
|
|
681
763
|
layoutTreePositions,
|
|
@@ -683,7 +765,7 @@ function directoryToAppRoute(dir, appDir, matcher, pagePath, routePath) {
|
|
|
683
765
|
slots: parallelSlots
|
|
684
766
|
}),
|
|
685
767
|
pattern: pattern === "/" ? "/" : pattern,
|
|
686
|
-
pagePath,
|
|
768
|
+
pagePath: effectivePagePath,
|
|
687
769
|
routePath,
|
|
688
770
|
layouts,
|
|
689
771
|
templates,
|
|
@@ -899,7 +981,7 @@ function discoverBoundaryFilePerLayout(layouts, fileName, matcher) {
|
|
|
899
981
|
* `appDir` via `path.posix.join`, and the `dir === routeDir` active-level test
|
|
900
982
|
* below only matches when both share the canonical separator.
|
|
901
983
|
*/
|
|
902
|
-
function discoverInheritedParallelSlots(segments, appDir, routeDir, matcher) {
|
|
984
|
+
function discoverInheritedParallelSlots(segments, appDir, routeDir, matcher, includeNestedOnlySlots = false) {
|
|
903
985
|
const slotMap = /* @__PURE__ */ new Map();
|
|
904
986
|
let currentDir = appDir;
|
|
905
987
|
const dirsToCheck = [];
|
|
@@ -922,9 +1004,9 @@ function discoverInheritedParallelSlots(segments, appDir, routeDir, matcher) {
|
|
|
922
1004
|
for (const { dir, layoutIdx: lvlLayoutIdx, segmentIndex } of dirsToCheck) {
|
|
923
1005
|
if (lvlLayoutIdx < 0 && routeHasLayout) continue;
|
|
924
1006
|
const slotLayoutIdx = Math.max(lvlLayoutIdx, 0);
|
|
925
|
-
const slotsAtLevel = discoverParallelSlots(dir, appDir, matcher);
|
|
926
1007
|
const segmentsBelow = segments.slice(segmentIndex);
|
|
927
1008
|
const isActiveUrlLevel = dir === routeDir || segmentsBelow.every(isInvisibleSegment);
|
|
1009
|
+
const slotsAtLevel = discoverParallelSlots(dir, appDir, matcher, includeNestedOnlySlots && isActiveUrlLevel);
|
|
928
1010
|
for (const slot of slotsAtLevel) if (isActiveUrlLevel) {
|
|
929
1011
|
slot.layoutIndex = slotLayoutIdx;
|
|
930
1012
|
slotMap.set(slot.key, slot);
|
|
@@ -1083,12 +1165,7 @@ function patternsStructurallyEquivalent(a, b) {
|
|
|
1083
1165
|
function findSlotRootPage(slotDir, matcher) {
|
|
1084
1166
|
const directPage = findFile(slotDir, "page", matcher);
|
|
1085
1167
|
if (directPage) return directPage;
|
|
1086
|
-
|
|
1087
|
-
try {
|
|
1088
|
-
entries = fs.readdirSync(slotDir, { withFileTypes: true });
|
|
1089
|
-
} catch {
|
|
1090
|
-
return null;
|
|
1091
|
-
}
|
|
1168
|
+
const entries = readDirEntriesCached(slotDir, matcher);
|
|
1092
1169
|
for (const entry of entries) {
|
|
1093
1170
|
if (!entry.isDirectory()) continue;
|
|
1094
1171
|
if (!entry.name.startsWith("(") || !entry.name.endsWith(")")) continue;
|
|
@@ -1099,11 +1176,14 @@ function findSlotRootPage(slotDir, matcher) {
|
|
|
1099
1176
|
}
|
|
1100
1177
|
/**
|
|
1101
1178
|
* Discover parallel route slots (@team, @analytics, etc.) in a directory.
|
|
1102
|
-
* Returns a ParallelSlot for each @-prefixed subdirectory that has a page
|
|
1179
|
+
* Returns a ParallelSlot for each @-prefixed subdirectory that has a page,
|
|
1180
|
+
* default component, intercepting route, or nested page-backed sub-route.
|
|
1181
|
+
*
|
|
1182
|
+
* `dir` and `appDir` must be forward-slash. The slot directory is built from
|
|
1183
|
+
* `dir` with `path.posix.join`.
|
|
1103
1184
|
*/
|
|
1104
|
-
function discoverParallelSlots(dir, appDir, matcher) {
|
|
1105
|
-
|
|
1106
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1185
|
+
function discoverParallelSlots(dir, appDir, matcher, includeNestedOnlySlots = false) {
|
|
1186
|
+
const entries = readDirEntriesCached(dir, matcher);
|
|
1107
1187
|
const slots = [];
|
|
1108
1188
|
for (const entry of entries) {
|
|
1109
1189
|
if (!entry.isDirectory() || !entry.name.startsWith("@")) continue;
|
|
@@ -1113,13 +1193,14 @@ function discoverParallelSlots(dir, appDir, matcher) {
|
|
|
1113
1193
|
const pagePath = findSlotRootPage(slotDir, matcher);
|
|
1114
1194
|
const defaultPath = findFile(slotDir, "default", matcher);
|
|
1115
1195
|
const interceptingRoutes = discoverInterceptingRoutes(slotDir, dir, appDir, matcher);
|
|
1116
|
-
|
|
1196
|
+
const hasNestedPages = includeNestedOnlySlots && findSlotSubPages(slotDir, matcher).length > 0;
|
|
1197
|
+
if (!pagePath && !defaultPath && interceptingRoutes.length === 0 && !hasNestedPages) continue;
|
|
1117
1198
|
const ownerSegments = path.relative(appDir, dir).split(path.sep).filter((segment) => segment.length > 0);
|
|
1118
1199
|
const ownerTreePath = createAppRouteGraphTreePath(ownerSegments, ownerSegments.length);
|
|
1119
1200
|
const configLayoutPaths = findSlotConfigLayoutPaths(slotDir, pagePath, matcher);
|
|
1120
1201
|
slots.push({
|
|
1121
1202
|
id: createAppRouteGraphSlotId(slotName, ownerTreePath),
|
|
1122
|
-
key: `${slotName}@${path.relative(appDir, slotDir)
|
|
1203
|
+
key: `${slotName}@${normalizePathSeparators(path.relative(appDir, slotDir))}`,
|
|
1123
1204
|
name: slotName,
|
|
1124
1205
|
ownerDir: slotDir,
|
|
1125
1206
|
ownerTreePath,
|
|
@@ -1178,6 +1259,9 @@ function isInterceptionMarkerDir(name) {
|
|
|
1178
1259
|
* Intercepting routes use conventions like (.)photo, (..)feed, (...), etc.
|
|
1179
1260
|
* They intercept navigation to another route and render within the slot instead.
|
|
1180
1261
|
*
|
|
1262
|
+
* `slotDir`, `routeDir`, and `appDir` must be forward-slash. They are passed
|
|
1263
|
+
* down to `path.posix.join` when building the intercept page paths.
|
|
1264
|
+
*
|
|
1181
1265
|
* @param slotDir - The parallel slot directory (e.g. app/feed/@modal)
|
|
1182
1266
|
* @param routeDir - The directory of the route that owns this slot (e.g. app/feed)
|
|
1183
1267
|
* @param appDir - The root app directory
|
|
@@ -1196,13 +1280,17 @@ function discoverInterceptingRoutes(slotDir, routeDir, appDir, matcher) {
|
|
|
1196
1280
|
* Sibling intercepts use the same conventions and target-computation logic as
|
|
1197
1281
|
* slot intercepts, but their intercepting page replaces the full page response
|
|
1198
1282
|
* (not a slot) during soft navigation.
|
|
1283
|
+
*
|
|
1284
|
+
* `appDir` and each route's `pagePath` / `routePath` must be forward-slash. The
|
|
1285
|
+
* owner directories are derived from `pagePath` / `routePath` and matched
|
|
1286
|
+
* against `appDir`-relative paths built with `path.posix.*`.
|
|
1199
1287
|
*/
|
|
1200
1288
|
function discoverSiblingInterceptingRoutes(routes, appDir, matcher) {
|
|
1201
1289
|
const routesByDir = /* @__PURE__ */ new Map();
|
|
1202
1290
|
for (const route of routes) {
|
|
1203
1291
|
const filePath = route.pagePath ?? route.routePath;
|
|
1204
1292
|
if (!filePath) continue;
|
|
1205
|
-
const routeDir =
|
|
1293
|
+
const routeDir = path.posix.dirname(filePath);
|
|
1206
1294
|
if (!routesByDir.has(routeDir)) routesByDir.set(routeDir, route);
|
|
1207
1295
|
}
|
|
1208
1296
|
function walk(dir) {
|
|
@@ -1216,7 +1304,7 @@ function discoverSiblingInterceptingRoutes(routes, appDir, matcher) {
|
|
|
1216
1304
|
if (!entry.isDirectory()) continue;
|
|
1217
1305
|
if (entry.name.startsWith("_")) continue;
|
|
1218
1306
|
if (entry.name.startsWith("@")) continue;
|
|
1219
|
-
const childDir = path.join(dir, entry.name);
|
|
1307
|
+
const childDir = path.posix.join(dir, entry.name);
|
|
1220
1308
|
const marker = matchInterceptConvention(entry.name);
|
|
1221
1309
|
if (marker) {
|
|
1222
1310
|
const restOfName = entry.name.slice(marker.prefix.length);
|
|
@@ -1281,6 +1369,9 @@ function findOwnerRouteForDir(dir, appDir, routes, routesByDir) {
|
|
|
1281
1369
|
/**
|
|
1282
1370
|
* Recursively scan a directory tree for page.tsx files that are inside
|
|
1283
1371
|
* intercepting route directories.
|
|
1372
|
+
*
|
|
1373
|
+
* `currentDir`, `routeDir`, and `appDir` must be forward-slash. `currentDir`
|
|
1374
|
+
* descends with `path.posix.join` when building the intercept page paths.
|
|
1284
1375
|
*/
|
|
1285
1376
|
function scanForInterceptingPages(currentDir, routeDir, appDir, results, matcher) {
|
|
1286
1377
|
if (!fs.existsSync(currentDir)) return;
|
|
@@ -1289,11 +1380,11 @@ function scanForInterceptingPages(currentDir, routeDir, appDir, results, matcher
|
|
|
1289
1380
|
if (!entry.isDirectory()) continue;
|
|
1290
1381
|
if (entry.name.startsWith("_")) continue;
|
|
1291
1382
|
const interceptMatch = matchInterceptConvention(entry.name);
|
|
1383
|
+
const interceptDir = path.posix.join(currentDir, entry.name);
|
|
1292
1384
|
if (interceptMatch) {
|
|
1293
1385
|
const restOfName = entry.name.slice(interceptMatch.prefix.length);
|
|
1294
|
-
const interceptDir = path.join(currentDir, entry.name);
|
|
1295
1386
|
collectInterceptingPages(interceptDir, interceptDir, interceptMatch.convention, restOfName, routeDir, appDir, currentDir, results, matcher);
|
|
1296
|
-
} else scanForInterceptingPages(
|
|
1387
|
+
} else scanForInterceptingPages(interceptDir, routeDir, appDir, results, matcher);
|
|
1297
1388
|
}
|
|
1298
1389
|
}
|
|
1299
1390
|
/**
|
|
@@ -1306,6 +1397,12 @@ function matchInterceptConvention(name) {
|
|
|
1306
1397
|
/**
|
|
1307
1398
|
* Collect page.tsx files inside an intercepting route directory tree
|
|
1308
1399
|
* and compute their target URL patterns.
|
|
1400
|
+
*
|
|
1401
|
+
* `currentDir`, `interceptRoot`, `routeDir`, `appDir`, and `interceptParentDir`
|
|
1402
|
+
* must all be forward-slash. `currentDir` descends with `path.posix.join` and
|
|
1403
|
+
* its `findFile` results become the stored layout/page paths. The others are
|
|
1404
|
+
* relativized against `appDir` (and each other) to derive the intercept page
|
|
1405
|
+
* segments and URL patterns.
|
|
1309
1406
|
*/
|
|
1310
1407
|
function collectInterceptingPages(currentDir, interceptRoot, convention, interceptSegment, routeDir, appDir, interceptParentDir, results, matcher, parentLayoutPaths = []) {
|
|
1311
1408
|
const currentLayoutPath = findFile(currentDir, "layout", matcher);
|
|
@@ -1316,7 +1413,7 @@ function collectInterceptingPages(currentDir, interceptRoot, convention, interce
|
|
|
1316
1413
|
if (targetPattern) {
|
|
1317
1414
|
const sourceMatchPattern = computeInterceptSourceMatchPattern(interceptParentDir, appDir);
|
|
1318
1415
|
results.push({
|
|
1319
|
-
branchSegments: [interceptSegment, ...
|
|
1416
|
+
branchSegments: [interceptSegment, ...path.relative(interceptRoot, path.dirname(page)).split(path.sep).filter(Boolean)],
|
|
1320
1417
|
convention,
|
|
1321
1418
|
layoutPaths: [...layoutPaths],
|
|
1322
1419
|
layoutSegments: layoutPaths.map((layoutPath) => {
|
|
@@ -1335,7 +1432,7 @@ function collectInterceptingPages(currentDir, interceptRoot, convention, interce
|
|
|
1335
1432
|
for (const entry of entries) {
|
|
1336
1433
|
if (!entry.isDirectory()) continue;
|
|
1337
1434
|
if (entry.name.startsWith("_")) continue;
|
|
1338
|
-
collectInterceptingPages(path.join(currentDir, entry.name), interceptRoot, convention, interceptSegment, routeDir, appDir, interceptParentDir, results, matcher, layoutPaths);
|
|
1435
|
+
collectInterceptingPages(path.posix.join(currentDir, entry.name), interceptRoot, convention, interceptSegment, routeDir, appDir, interceptParentDir, results, matcher, layoutPaths);
|
|
1339
1436
|
}
|
|
1340
1437
|
}
|
|
1341
1438
|
/**
|
|
@@ -1455,6 +1552,9 @@ const findFileProbeCache = /* @__PURE__ */ new WeakMap();
|
|
|
1455
1552
|
* registered per-scan cache; otherwise falls back to a direct probe (identical
|
|
1456
1553
|
* result). The `null` "not found" outcome is cached too, so repeated misses on
|
|
1457
1554
|
* shared ancestors cost a single set of `existsSync` calls per scan.
|
|
1555
|
+
*
|
|
1556
|
+
* `dir` must be forward-slash. The returned path comes from `findFileWithExts`,
|
|
1557
|
+
* so it is forward-slash too.
|
|
1458
1558
|
*/
|
|
1459
1559
|
function findFile(dir, name, matcher) {
|
|
1460
1560
|
const cache = findFileProbeCache.get(matcher);
|
|
@@ -21,6 +21,9 @@ declare function findFileWithExtensions(basePath: string, matcher: ValidFileMatc
|
|
|
21
21
|
/**
|
|
22
22
|
* Find a file by basename and configured page extension in a directory.
|
|
23
23
|
* Returns the first matching absolute path, or null if not found.
|
|
24
|
+
*
|
|
25
|
+
* `dir` must be forward-slash. The returned path is built with `path.posix.join`,
|
|
26
|
+
* so it is forward-slash too.
|
|
24
27
|
*/
|
|
25
28
|
declare function findFileWithExts(dir: string, name: string, matcher: ValidFileMatcher): string | null;
|
|
26
29
|
/**
|
|
@@ -36,11 +39,18 @@ declare function findFileWithExts(dir: string, name: string, matcher: ValidFileM
|
|
|
36
39
|
* 1. User-configured pageExtensions go first (each prefixed with `.`) so
|
|
37
40
|
* the user's priority wins. e.g. `.platform.tsx` resolves before `.tsx`.
|
|
38
41
|
* 2. Vite's defaults follow, with duplicates removed.
|
|
42
|
+
* 3. `.cjs`/`.cts` go last (lowest priority). Neither Vite's defaults nor the
|
|
43
|
+
* user's pageExtensions include them, but `vinext init` renames CJS config
|
|
44
|
+
* files (e.g. `tailwind.config.js` → `tailwind.config.cjs`) when it adds
|
|
45
|
+
* `"type": "module"`, and app code imports those extensionlessly
|
|
46
|
+
* (`import cfg from "../tailwind.config"`). Without these, the bundle fails
|
|
47
|
+
* with "[UNRESOLVED_IMPORT] Could not resolve '../tailwind.config'".
|
|
39
48
|
*
|
|
40
49
|
* The user's pageExtensions retain their relative order, which is what
|
|
41
50
|
* Next.js / Turbopack do via the `resolveExtensions` config option.
|
|
42
51
|
*
|
|
43
|
-
* See: cloudflare/vinext#1502
|
|
52
|
+
* See: cloudflare/vinext#1502 for page-extension ordering, and
|
|
53
|
+
* cloudflare/vinext#2435 for extensionless `.cjs` config imports.
|
|
44
54
|
*/
|
|
45
55
|
declare function buildViteResolveExtensions(pageExtensions?: readonly string[] | null, viteDefaults?: readonly string[]): string[];
|
|
46
56
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { escapeRegExp } from "../utils/regex.js";
|
|
2
1
|
import { normalizePathSeparators } from "../utils/path.js";
|
|
2
|
+
import { escapeRegExp } from "../utils/regex.js";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { glob } from "node:fs/promises";
|
|
@@ -67,6 +67,9 @@ function findFileWithExtensions(basePath, matcher) {
|
|
|
67
67
|
/**
|
|
68
68
|
* Find a file by basename and configured page extension in a directory.
|
|
69
69
|
* Returns the first matching absolute path, or null if not found.
|
|
70
|
+
*
|
|
71
|
+
* `dir` must be forward-slash. The returned path is built with `path.posix.join`,
|
|
72
|
+
* so it is forward-slash too.
|
|
70
73
|
*/
|
|
71
74
|
function findFileWithExts(dir, name, matcher) {
|
|
72
75
|
for (const ext of matcher.dottedExtensions) {
|
|
@@ -88,11 +91,18 @@ function findFileWithExts(dir, name, matcher) {
|
|
|
88
91
|
* 1. User-configured pageExtensions go first (each prefixed with `.`) so
|
|
89
92
|
* the user's priority wins. e.g. `.platform.tsx` resolves before `.tsx`.
|
|
90
93
|
* 2. Vite's defaults follow, with duplicates removed.
|
|
94
|
+
* 3. `.cjs`/`.cts` go last (lowest priority). Neither Vite's defaults nor the
|
|
95
|
+
* user's pageExtensions include them, but `vinext init` renames CJS config
|
|
96
|
+
* files (e.g. `tailwind.config.js` → `tailwind.config.cjs`) when it adds
|
|
97
|
+
* `"type": "module"`, and app code imports those extensionlessly
|
|
98
|
+
* (`import cfg from "../tailwind.config"`). Without these, the bundle fails
|
|
99
|
+
* with "[UNRESOLVED_IMPORT] Could not resolve '../tailwind.config'".
|
|
91
100
|
*
|
|
92
101
|
* The user's pageExtensions retain their relative order, which is what
|
|
93
102
|
* Next.js / Turbopack do via the `resolveExtensions` config option.
|
|
94
103
|
*
|
|
95
|
-
* See: cloudflare/vinext#1502
|
|
104
|
+
* See: cloudflare/vinext#1502 for page-extension ordering, and
|
|
105
|
+
* cloudflare/vinext#2435 for extensionless `.cjs` config imports.
|
|
96
106
|
*/
|
|
97
107
|
function buildViteResolveExtensions(pageExtensions, viteDefaults = [
|
|
98
108
|
".mjs",
|
|
@@ -106,7 +116,12 @@ function buildViteResolveExtensions(pageExtensions, viteDefaults = [
|
|
|
106
116
|
const dotted = normalizePageExtensions(pageExtensions).map((ext) => `.${ext}`);
|
|
107
117
|
const seen = /* @__PURE__ */ new Set();
|
|
108
118
|
const result = [];
|
|
109
|
-
for (const ext of [
|
|
119
|
+
for (const ext of [
|
|
120
|
+
...dotted,
|
|
121
|
+
...viteDefaults,
|
|
122
|
+
".cjs",
|
|
123
|
+
".cts"
|
|
124
|
+
]) {
|
|
110
125
|
if (seen.has(ext)) continue;
|
|
111
126
|
seen.add(ext);
|
|
112
127
|
result.push(ext);
|
|
@@ -63,7 +63,7 @@ async function scanPageRoutes(pagesDir, matcher) {
|
|
|
63
63
|
function fileToRoute(file, pagesDir, matcher) {
|
|
64
64
|
const withoutExt = matcher.stripExtension(file);
|
|
65
65
|
if (withoutExt === file) return null;
|
|
66
|
-
const segments = withoutExt.split(
|
|
66
|
+
const segments = withoutExt.split("/");
|
|
67
67
|
if (segments[segments.length - 1] === "index") segments.pop();
|
|
68
68
|
const params = [];
|
|
69
69
|
let isDynamic = false;
|
|
@@ -152,7 +152,7 @@ async function scanApiRoutes(pagesDir, matcher) {
|
|
|
152
152
|
}
|
|
153
153
|
const routes = [];
|
|
154
154
|
for (const file of files) {
|
|
155
|
-
const route = fileToRoute(path.join("api", file), pagesDir, matcher);
|
|
155
|
+
const route = fileToRoute(path.posix.join("api", file), pagesDir, matcher);
|
|
156
156
|
if (route) routes.push(route);
|
|
157
157
|
}
|
|
158
158
|
validateRoutePatterns(routes.map((route) => route.pattern));
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { hasBasePath } from "../utils/base-path.js";
|
|
2
2
|
import { matchRoute } from "../routing/pages-router.js";
|
|
3
3
|
import "./server-globals.js";
|
|
4
|
-
import { parseCookieHeader } from "../utils/parse-cookie.js";
|
|
5
4
|
import { NextRequest } from "../shims/server.js";
|
|
6
5
|
import { importModule, reportRequestError } from "./instrumentation.js";
|
|
7
6
|
import { mergeRouteParamsIntoQuery, parseQueryString, urlQueryToSearchParams } from "../utils/query.js";
|
|
8
|
-
import { PagesBodyParseError, getMediaType, isJsonMediaType } from "./pages-media-type.js";
|
|
9
|
-
import { isEdgeApiRuntime } from "./edge-api-runtime.js";
|
|
10
7
|
import { DEFAULT_PAGES_API_BODY_SIZE_LIMIT, resolveBodyParserConfig } from "./pages-body-parser-config.js";
|
|
8
|
+
import { PagesBodyParseError, getMediaType, isJsonMediaType } from "./pages-media-type.js";
|
|
11
9
|
import { resolveRequestHost, resolveRequestProtocol } from "./proxy-trust.js";
|
|
12
10
|
import { performOnDemandRevalidate } from "./pages-revalidate.js";
|
|
11
|
+
import { attachPagesRequestCookies } from "./pages-node-compat.js";
|
|
12
|
+
import { isEdgeApiRuntime } from "./edge-api-runtime.js";
|
|
13
13
|
import { decode } from "node:querystring";
|
|
14
14
|
import { Buffer } from "node:buffer";
|
|
15
15
|
//#region src/server/api-handler.ts
|
|
@@ -69,12 +69,6 @@ async function parseBody(req, sizeLimit = MAX_BODY_SIZE) {
|
|
|
69
69
|
});
|
|
70
70
|
});
|
|
71
71
|
}
|
|
72
|
-
/**
|
|
73
|
-
* Parse cookies from the Cookie header.
|
|
74
|
-
*/
|
|
75
|
-
function parseCookies(req) {
|
|
76
|
-
return parseCookieHeader(req.headers.cookie);
|
|
77
|
-
}
|
|
78
72
|
function isEdgeApiRouteModule(module) {
|
|
79
73
|
if (typeof module.default !== "function") return false;
|
|
80
74
|
const bare = module.runtime;
|
|
@@ -167,12 +161,13 @@ async function writeEdgeApiResponseBody(res, body) {
|
|
|
167
161
|
* Enhance a Node.js req/res pair with Next.js API route helpers.
|
|
168
162
|
*/
|
|
169
163
|
function enhanceApiObjects(req, res, query, body) {
|
|
164
|
+
const apiReq = Object.assign(req, {
|
|
165
|
+
body,
|
|
166
|
+
query
|
|
167
|
+
});
|
|
168
|
+
attachPagesRequestCookies(apiReq);
|
|
170
169
|
return {
|
|
171
|
-
apiReq
|
|
172
|
-
body,
|
|
173
|
-
cookies: parseCookies(req),
|
|
174
|
-
query
|
|
175
|
-
}),
|
|
170
|
+
apiReq,
|
|
176
171
|
apiRes: Object.assign(res, {
|
|
177
172
|
status(code) {
|
|
178
173
|
this.statusCode = code;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { OperationLane } from "./operation-token.js";
|
|
1
2
|
import { ServerActionResultFacts } from "./navigation-planner.js";
|
|
2
3
|
|
|
3
4
|
//#region src/server/app-browser-action-result.d.ts
|
|
@@ -24,7 +25,9 @@ type ServerActionInitiationSnapshot<TRouterState> = {
|
|
|
24
25
|
declare function isServerActionResult<TRoot>(value: unknown): value is AppBrowserServerActionResult<TRoot>;
|
|
25
26
|
declare function shouldClearClientNavigationCachesForServerActionResult<TRoot>(result: AppBrowserServerActionResult<TRoot> | TRoot, revalidation?: ServerActionRevalidationKind): boolean;
|
|
26
27
|
declare function parseServerActionRevalidationHeader(headers: Pick<Headers, "get">): ServerActionRevalidationKind;
|
|
28
|
+
declare function resolveServerActionOperationLane(revalidation: ServerActionRevalidationKind): Extract<OperationLane, "refresh" | "server-action">;
|
|
27
29
|
declare function normalizeServerActionThrownValue(data: unknown, responseStatus: number): unknown;
|
|
30
|
+
declare function shouldSyncServerActionHttpFallbackHead<TRoot>(result: AppBrowserServerActionResult<TRoot> | TRoot): boolean;
|
|
28
31
|
declare function readInvalidServerActionResponseError(response: Pick<Response, "headers" | "status" | "text">, hasRedirectLocation: boolean): Promise<Error | null>;
|
|
29
32
|
type ServerActionResultResponseFactsInput = {
|
|
30
33
|
actionRedirectHref: string | null;
|
|
@@ -61,4 +64,4 @@ type DiscardedServerActionRefreshSchedulerOptions = {
|
|
|
61
64
|
};
|
|
62
65
|
declare function createDiscardedServerActionRefreshScheduler(options: DiscardedServerActionRefreshSchedulerOptions): DiscardedServerActionRefreshScheduler;
|
|
63
66
|
//#endregion
|
|
64
|
-
export { AppBrowserServerActionResult, ServerActionResultResponseFactsInput, ServerActionRevalidationKind, createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, shouldClearClientNavigationCachesForServerActionResult, shouldScheduleRefreshForDiscardedServerAction };
|
|
67
|
+
export { AppBrowserServerActionResult, ServerActionResultResponseFactsInput, ServerActionRevalidationKind, createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, resolveServerActionOperationLane, shouldClearClientNavigationCachesForServerActionResult, shouldScheduleRefreshForDiscardedServerAction, shouldSyncServerActionHttpFallbackHead };
|
|
@@ -32,6 +32,9 @@ function parseServerActionRevalidationHeader(headers) {
|
|
|
32
32
|
default: return "none";
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
+
function resolveServerActionOperationLane(revalidation) {
|
|
36
|
+
return revalidation === "none" ? "server-action" : "refresh";
|
|
37
|
+
}
|
|
35
38
|
function createServerActionHttpFallbackError(status) {
|
|
36
39
|
if (status !== 401 && status !== 403 && status !== 404) return null;
|
|
37
40
|
const digest = status === 404 ? "NEXT_HTTP_ERROR_FALLBACK;404" : `NEXT_HTTP_ERROR_FALLBACK;${status}`;
|
|
@@ -41,6 +44,10 @@ function createServerActionHttpFallbackError(status) {
|
|
|
41
44
|
function normalizeServerActionThrownValue(data, responseStatus) {
|
|
42
45
|
return createServerActionHttpFallbackError(responseStatus) ?? data;
|
|
43
46
|
}
|
|
47
|
+
function shouldSyncServerActionHttpFallbackHead(result) {
|
|
48
|
+
if (!isServerActionResult(result) || result.root !== void 0) return false;
|
|
49
|
+
return result.returnValue?.ok !== false;
|
|
50
|
+
}
|
|
44
51
|
async function readInvalidServerActionResponseError(response, hasRedirectLocation) {
|
|
45
52
|
const contentType = response.headers.get("content-type") ?? "";
|
|
46
53
|
if (contentType.startsWith("text/x-component") || hasRedirectLocation) return null;
|
|
@@ -108,4 +115,4 @@ function createDiscardedServerActionRefreshScheduler(options) {
|
|
|
108
115
|
};
|
|
109
116
|
}
|
|
110
117
|
//#endregion
|
|
111
|
-
export { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, shouldClearClientNavigationCachesForServerActionResult, shouldScheduleRefreshForDiscardedServerAction };
|
|
118
|
+
export { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, resolveServerActionOperationLane, shouldClearClientNavigationCachesForServerActionResult, shouldScheduleRefreshForDiscardedServerAction, shouldSyncServerActionHttpFallbackHead };
|