vinext 1.4.2 → 1.4.4
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 +4 -1
- package/dist/build/prerender-paths.d.ts +11 -1
- package/dist/build/prerender-paths.js +41 -11
- package/dist/cli.js +1 -1
- package/dist/client/dev-error-overlay.d.ts +2 -1
- package/dist/client/dev-error-overlay.js +8 -3
- package/dist/config/config-matchers.js +6 -2
- package/dist/config/next-config.d.ts +9 -0
- package/dist/entries/app-rsc-entry.js +24 -12
- package/dist/entries/pages-server-entry.js +17 -4
- package/dist/index.js +48 -39
- package/dist/init-platform.js +2 -2
- package/dist/init.js +42 -5
- package/dist/server/api-handler.js +8 -5
- package/dist/server/app-browser-entry.js +26 -47
- package/dist/server/app-browser-error.d.ts +1 -1
- package/dist/server/app-browser-error.js +13 -4
- package/dist/server/app-browser-navigation-controller.js +2 -2
- package/dist/server/app-browser-server-action-client.js +2 -2
- package/dist/server/app-browser-state.js +2 -2
- package/dist/server/app-browser-supplemental-refresh.d.ts +13 -0
- package/dist/server/app-browser-supplemental-refresh.js +36 -4
- package/dist/server/app-browser-visible-commit.js +1 -1
- package/dist/server/app-history-state.js +1 -1
- package/dist/server/app-middleware.d.ts +2 -0
- package/dist/server/app-middleware.js +1 -0
- package/dist/server/app-page-boundary-render.js +4 -2
- package/dist/server/app-page-dispatch.d.ts +1 -0
- package/dist/server/app-page-dispatch.js +5 -1
- package/dist/server/app-page-element-builder.d.ts +2 -0
- package/dist/server/app-page-element-builder.js +6 -5
- package/dist/server/app-page-render.js +1 -1
- package/dist/server/app-page-route-wiring.d.ts +7 -5
- package/dist/server/app-page-route-wiring.js +11 -9
- package/dist/server/app-pages-bridge.d.ts +6 -0
- package/dist/server/app-pages-bridge.js +8 -3
- package/dist/server/app-request-context.js +1 -1
- package/dist/server/app-request-stage-independent-entry.js +2 -3
- package/dist/server/app-route-handler-dispatch.js +1 -1
- package/dist/server/app-route-handler-execution.js +1 -1
- package/dist/server/app-route-handler-response.d.ts +1 -0
- package/dist/server/app-route-handler-response.js +27 -2
- package/dist/server/app-router-entry.js +2 -3
- package/dist/server/app-rsc-cache-busting.d.ts +8 -0
- package/dist/server/app-rsc-cache-busting.js +13 -1
- package/dist/server/app-rsc-combined-handler.js +2 -1
- package/dist/server/app-rsc-handler.d.ts +4 -0
- package/dist/server/app-rsc-handler.js +41 -24
- package/dist/server/app-rsc-response-finalizer.d.ts +15 -3
- package/dist/server/app-rsc-response-finalizer.js +51 -7
- package/dist/server/app-rsc-response-stage.js +1 -1
- package/dist/server/app-server-action-execution.js +1 -1
- package/dist/server/app-ssr-entry.js +18 -10
- package/dist/server/config-headers.d.ts +7 -0
- package/dist/server/config-headers.js +20 -1
- package/dist/server/edge-api-runtime.d.ts +6 -2
- package/dist/server/edge-api-runtime.js +21 -4
- package/dist/server/image-animation.d.ts +9 -0
- package/dist/server/image-animation.js +118 -0
- package/dist/server/image-optimization.d.ts +25 -5
- package/dist/server/image-optimization.js +305 -21
- package/dist/server/image-source-reader.d.ts +34 -0
- package/dist/server/image-source-reader.js +126 -0
- package/dist/server/metadata-route-response.d.ts +6 -1
- package/dist/server/metadata-route-response.js +24 -6
- package/dist/server/middleware-matcher.d.ts +1 -0
- package/dist/server/middleware-matcher.js +1 -1
- package/dist/server/middleware-runtime.d.ts +5 -0
- package/dist/server/middleware-runtime.js +48 -15
- package/dist/server/middleware.d.ts +1 -1
- package/dist/server/middleware.js +2 -1
- package/dist/server/navigation-planner.js +14 -6
- package/dist/server/nitro-request-target-plugin.d.ts +17 -0
- package/dist/server/nitro-request-target-plugin.js +22 -0
- package/dist/server/open-redirect.d.ts +2 -1
- package/dist/server/open-redirect.js +2 -1
- package/dist/server/pages-client-assets.d.ts +1 -0
- package/dist/server/pages-i18n.d.ts +7 -0
- package/dist/server/pages-i18n.js +14 -1
- package/dist/server/pages-node-compat.js +7 -3
- package/dist/server/pages-page-handler.js +4 -4
- package/dist/server/pages-request-pipeline.d.ts +9 -0
- package/dist/server/pages-request-pipeline.js +29 -10
- package/dist/server/pages-request-stage-entry.js +7 -2
- package/dist/server/pages-router-entry.js +3 -0
- package/dist/server/prod-server.d.ts +1 -1
- package/dist/server/prod-server.js +48 -54
- package/dist/server/remove-request-headers.d.ts +16 -0
- package/dist/server/remove-request-headers.js +23 -0
- package/dist/server/srvx-middleware-origin.d.ts +13 -0
- package/dist/server/srvx-middleware-origin.js +19 -0
- package/dist/server/srvx-request-target.d.ts +12 -0
- package/dist/server/srvx-request-target.js +20 -0
- package/dist/server/static-file-cache.js +10 -22
- package/dist/server/worker-image-optimization.d.ts +8 -1
- package/dist/server/worker-image-optimization.js +25 -6
- package/dist/server/worker-revalidation-context.js +1 -0
- package/dist/shims/cache-runtime.js +1 -1
- package/dist/shims/cache.js +6 -3
- package/dist/shims/client-page-root.js +2 -2
- package/dist/shims/error-boundary.d.ts +6 -2
- package/dist/shims/error-boundary.js +6 -4
- package/dist/shims/internal/navigation-untracked.js +1 -1
- package/dist/shims/metadata.js +1 -1
- package/dist/shims/navigation-server.js +1 -1
- package/dist/shims/navigation.js +4 -4
- package/dist/shims/navigation.react-server.js +3 -3
- package/dist/shims/request-context.d.ts +3 -1
- package/dist/shims/root-params.js +16 -2
- package/dist/shims/slot.js +3 -3
- package/dist/shims/url-utils.js +6 -1
- package/dist/utils/client-entry-manifest.d.ts +5 -0
- package/dist/utils/client-entry-manifest.js +1 -0
- package/dist/utils/client-runtime-metadata.d.ts +5 -0
- package/dist/utils/client-runtime-metadata.js +33 -7
- package/package.json +1 -1
|
@@ -19,6 +19,7 @@ import { setFrameworkRequestRoute } from "./request-tracing.js";
|
|
|
19
19
|
import { withExternalRewriteResponseHeaders } from "./middleware-response-headers.js";
|
|
20
20
|
import { applyConfigHeadersToHeaderRecord } from "./config-headers.js";
|
|
21
21
|
import { finalizeMissingStaticAssetResponse, mergeHeaders, mergeStaticFileHeaders } from "./worker-utils.js";
|
|
22
|
+
import { publicFileRouteKey } from "../utils/public-file-path.js";
|
|
22
23
|
//#region src/server/pages-request-pipeline.ts
|
|
23
24
|
function ruleUsesUnkeyedRequestCondition(rule) {
|
|
24
25
|
return [...rule.has ?? [], ...rule.missing ?? []].some((condition) => condition.type === "header" || condition.type === "cookie" || condition.type === "host");
|
|
@@ -35,24 +36,41 @@ function headersFromRecord(record) {
|
|
|
35
36
|
else headers.set(name, value);
|
|
36
37
|
return headers;
|
|
37
38
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Whether a filesystem route may serve `requestPathname` from the client
|
|
41
|
+
* build directory. Like Next.js, only a public file or a build asset resolves
|
|
42
|
+
* there: the directory also holds build metadata and private artifacts. A
|
|
43
|
+
* direct GET/HEAD reaches this route only for a public file, since servers
|
|
44
|
+
* answer existing build assets before middleware.
|
|
45
|
+
*/
|
|
46
|
+
function isServableFilesystemRoute(requestPathname, phase, method, publicFiles, basePath = "", assetPathPrefix = "", pathnameHasBasePath = true) {
|
|
47
|
+
const assetUrl = new URL("http://localhost");
|
|
41
48
|
assetUrl.pathname = requestPathname;
|
|
42
|
-
assetUrl.search = "";
|
|
43
49
|
const decodedAssetUrl = new URL(assetUrl);
|
|
44
50
|
let publicFileKey;
|
|
51
|
+
let servedPathname;
|
|
52
|
+
let servedFileKey;
|
|
45
53
|
try {
|
|
46
54
|
decodedAssetUrl.pathname = decodeURIComponent(assetUrl.pathname);
|
|
47
55
|
publicFileKey = normalizePathnameForRouteMatchStrict(assetUrl.pathname);
|
|
56
|
+
servedPathname = decodeURIComponent(requestPathname);
|
|
57
|
+
servedFileKey = publicFileRouteKey(servedPathname);
|
|
48
58
|
} catch {
|
|
49
59
|
return false;
|
|
50
60
|
}
|
|
51
|
-
|
|
52
|
-
|
|
61
|
+
const decodedPathname = decodedAssetUrl.pathname;
|
|
62
|
+
if (!pathnameHasBasePath && !isAssetPrefixBuildAsset(decodedPathname, assetPathPrefix)) return false;
|
|
63
|
+
const isPublicFile = pathnameHasBasePath && publicFiles.has(publicFileKey) && publicFiles.has(servedFileKey);
|
|
53
64
|
if (!isPublicFile && (requestPathname === "/api" || requestPathname.startsWith("/api/"))) return false;
|
|
54
|
-
if (phase === "direct" &&
|
|
55
|
-
|
|
65
|
+
if (phase === "direct" && (method === "GET" || method === "HEAD") && !isPublicFile) return false;
|
|
66
|
+
return isPublicFile || isNextStaticPath(decodedPathname, basePath, assetPathPrefix) && isNextStaticPath(servedPathname, basePath, assetPathPrefix);
|
|
67
|
+
}
|
|
68
|
+
async function fetchWorkerFilesystemRoute(request, requestPathname, phase, fetchAsset, publicFiles, basePath = "", assetPathPrefix = "", pathnameHasBasePath = true) {
|
|
69
|
+
const isRetrievalMethod = request.method === "GET" || request.method === "HEAD";
|
|
70
|
+
const assetUrl = new URL(request.url);
|
|
71
|
+
assetUrl.pathname = requestPathname;
|
|
72
|
+
assetUrl.search = "";
|
|
73
|
+
if (!isServableFilesystemRoute(requestPathname, phase, request.method, publicFiles, basePath, assetPathPrefix, pathnameHasBasePath)) return false;
|
|
56
74
|
const response = await fetchAsset(isRetrievalMethod ? new Request(assetUrl, request) : new Request(assetUrl, {
|
|
57
75
|
method: "HEAD",
|
|
58
76
|
headers: request.headers
|
|
@@ -179,7 +197,8 @@ async function runPagesRequest(request, deps) {
|
|
|
179
197
|
if (!isOnDemandRevalidate && typeof deps.runMiddleware === "function") {
|
|
180
198
|
const result = await deps.runMiddleware(deps.middlewareRequest ?? request, deps.ctx ?? null, {
|
|
181
199
|
isDataRequest,
|
|
182
|
-
isStaleDataRequest: isDataRequest && !!deps.dataNotFoundResponse
|
|
200
|
+
isStaleDataRequest: isDataRequest && !!deps.dataNotFoundResponse,
|
|
201
|
+
restoreLocaleRootTrailingSlash: deps.restoreLocaleRootTrailingSlash
|
|
183
202
|
});
|
|
184
203
|
if (deps.recordCacheability !== false && result.pathnameEligible) markRouteCacheabilityDynamic("middleware can match this pathname");
|
|
185
204
|
if (result.waitUntilPromises && result.waitUntilPromises.length > 0) {
|
|
@@ -465,4 +484,4 @@ async function runPagesRequest(request, deps) {
|
|
|
465
484
|
};
|
|
466
485
|
}
|
|
467
486
|
//#endregion
|
|
468
|
-
export { fetchWorkerFilesystemRoute, runPagesRequest, wrapMiddlewareWithBasePath };
|
|
487
|
+
export { fetchWorkerFilesystemRoute, isServableFilesystemRoute, runPagesRequest, wrapMiddlewareWithBasePath };
|
|
@@ -73,7 +73,9 @@ const imageConfig = vinextConfig?.images ? {
|
|
|
73
73
|
dangerouslyAllowSVG: vinextConfig.images.dangerouslyAllowSVG,
|
|
74
74
|
dangerouslyAllowLocalIP: vinextConfig.images.dangerouslyAllowLocalIP,
|
|
75
75
|
contentDispositionType: vinextConfig.images.contentDispositionType,
|
|
76
|
-
contentSecurityPolicy: vinextConfig.images.contentSecurityPolicy
|
|
76
|
+
contentSecurityPolicy: vinextConfig.images.contentSecurityPolicy,
|
|
77
|
+
minimumCacheTTL: vinextConfig.images.minimumCacheTTL,
|
|
78
|
+
maximumResponseBody: vinextConfig.images.maximumResponseBody
|
|
77
79
|
} : void 0;
|
|
78
80
|
/**
|
|
79
81
|
* Whether the request stage serves this request as a client build file
|
|
@@ -384,7 +386,10 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
|
|
|
384
386
|
});
|
|
385
387
|
if (sourceResult.type !== "response") return null;
|
|
386
388
|
await sourceResult.response.body?.cancel().catch(() => {});
|
|
387
|
-
if (isImageSourceBodyStatus(sourceResult.response.status)
|
|
389
|
+
if (isImageSourceBodyStatus(sourceResult.response.status) && sourceAsset !== null) {
|
|
390
|
+
const { withStagedCacheControl } = await import("./worker-image-optimization.js");
|
|
391
|
+
return withStagedCacheControl(sourceAsset, sourceResult.response.headers.get("Cache-Control"));
|
|
392
|
+
}
|
|
388
393
|
await sourceAsset?.body?.cancel().catch(() => {});
|
|
389
394
|
return null;
|
|
390
395
|
};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { VINEXT_CACHEABILITY_PROBE_HEADER, VINEXT_CACHEABILITY_PROBE_QUERY_PARAM } from "./headers.js";
|
|
2
|
+
import { notFoundResponse } from "./http-error-responses.js";
|
|
2
3
|
import { cloneRequestWithHeaders, cloneRequestWithUrl, stripRequestUrlFragment } from "./request-pipeline.js";
|
|
3
4
|
import { runWithExecutionContext } from "../shims/request-context.js";
|
|
4
5
|
import { getCdnCacheAdapter } from "../shims/cdn-cache.js";
|
|
5
6
|
import { validateCdnRequest } from "./cache-control.js";
|
|
6
7
|
import { createWorkerRevalidationContext } from "./worker-revalidation-context.js";
|
|
7
8
|
import { createWorkerPrerenderDiscoveryContext, createWorkerPrerenderReadinessResponse } from "./worker-prerender-discovery.js";
|
|
9
|
+
import { isSrvxAbsoluteFormTarget } from "./srvx-request-target.js";
|
|
8
10
|
import { handleRequestStageLocally, isPagesClientBuildFileRequest, pagesRequestStageBuildId, pagesRequestStagePrerenderSecret } from "./pages-request-stage-entry.js";
|
|
9
11
|
import { renderPagesResponse } from "./pages-response-stage-entry.js";
|
|
10
12
|
import { registerConfiguredCacheAdapters } from "virtual:vinext-cache-adapters";
|
|
@@ -52,6 +54,7 @@ async function handleSingleStageRequest(request, env, platformCtx) {
|
|
|
52
54
|
return finalize ? finalize(response, ctx) : response;
|
|
53
55
|
}
|
|
54
56
|
var pages_router_entry_default = { fetch(request, env, ctx) {
|
|
57
|
+
if (isSrvxAbsoluteFormTarget(request)) return Promise.resolve(notFoundResponse());
|
|
55
58
|
const strippedRequest = stripRequestUrlFragment(request);
|
|
56
59
|
const handle = () => handleSingleStageRequest(strippedRequest, env, ctx);
|
|
57
60
|
return ctx && typeof ctx.waitUntil === "function" ? runWithExecutionContext(ctx, handle) : handle();
|
|
@@ -90,7 +90,7 @@ declare function mergeWebResponse(middlewareHeaders: Record<string, string | str
|
|
|
90
90
|
* Send a compressed response if the content type is compressible and the
|
|
91
91
|
* client supports compression. Otherwise send uncompressed.
|
|
92
92
|
*/
|
|
93
|
-
declare function sendCompressed(req: IncomingMessage, res: ServerResponse, body: string | Buffer, contentType: string, statusCode: number, extraHeaders?: Record<string, string | string[]>, compress?: boolean, statusText?: string): void;
|
|
93
|
+
declare function sendCompressed(req: IncomingMessage, res: ServerResponse, body: string | Buffer, contentType: string | undefined, statusCode: number, extraHeaders?: Record<string, string | string[]>, compress?: boolean, statusText?: string): void;
|
|
94
94
|
/**
|
|
95
95
|
* Try to serve a static file from the client build directory.
|
|
96
96
|
*
|
|
@@ -7,7 +7,7 @@ import { notFoundResponse } from "./http-error-responses.js";
|
|
|
7
7
|
import { getRepeatedSlashRedirect, isOpenRedirectShaped, sendRepeatedSlashRedirect } from "./open-redirect.js";
|
|
8
8
|
import { readStaticFileSignal } from "./static-file-signal.js";
|
|
9
9
|
import { canonicalizeRequestPathname, filterInternalHeaders } from "./request-pipeline.js";
|
|
10
|
-
import { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix
|
|
10
|
+
import { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix } from "../utils/asset-prefix.js";
|
|
11
11
|
import { StaticFileCache, contentTypeForPath, etagFromFilenameHash, staticFileCacheControl } from "./static-file-cache.js";
|
|
12
12
|
import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
|
|
13
13
|
import { resolveRequestHost, resolveRequestProtocol, resolveTrustedForwardedHost, trustProxy, trustedHosts } from "./proxy-trust.js";
|
|
@@ -19,13 +19,13 @@ import { parseHttpDate } from "./http-date.js";
|
|
|
19
19
|
import { evaluateStaticPreconditions } from "./http-conditional.js";
|
|
20
20
|
import { setPagesClientAssets } from "./pages-client-assets.js";
|
|
21
21
|
import { signalFromNodeResponse } from "./node-response-signal.js";
|
|
22
|
-
import { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, IMAGE_RESPONSE_CACHE_STATE,
|
|
22
|
+
import { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, IMAGE_RESPONSE_CACHE_STATE, IMAGE_TYPE_NOT_ALLOWED_MESSAGE, INVALID_IMAGE_SOURCE_MESSAGE, isImageOptimizationPath, isImageSourceBodyStatus, isSafeImageContentType, parseImageParams, readImageOptimizationSignal, sourceImageCacheControl } from "./image-optimization.js";
|
|
23
23
|
import { installSocketErrorBackstop } from "./socket-error-backstop.js";
|
|
24
24
|
import { collectInlineCssManifest } from "../build/inline-css.js";
|
|
25
25
|
import { readTrustedRevalidationHostname } from "./revalidation-host.js";
|
|
26
26
|
import { traceFrameworkRequest } from "./request-tracing.js";
|
|
27
27
|
import { mergeHeaders } from "./worker-utils.js";
|
|
28
|
-
import { runPagesRequest, wrapMiddlewareWithBasePath } from "./pages-request-pipeline.js";
|
|
28
|
+
import { isServableFilesystemRoute, runPagesRequest, wrapMiddlewareWithBasePath } from "./pages-request-pipeline.js";
|
|
29
29
|
import { computeClientRuntimeMetadata } from "../utils/client-runtime-metadata.js";
|
|
30
30
|
import { readPrerenderSecret, readServerCompress } from "../build/server-manifest.js";
|
|
31
31
|
import { readTrustedPrerenderRouteParamsFromHeaders, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
|
|
@@ -339,6 +339,7 @@ function installClientBuildManifestGlobals(clientDir, assetBase, assetPrefix, cr
|
|
|
339
339
|
});
|
|
340
340
|
setPagesClientAssets({
|
|
341
341
|
appBootstrapPreinitModules: metadata.appBootstrapPreinitModules,
|
|
342
|
+
appBootstrapPreloadModules: metadata.appBootstrapPreloadModules,
|
|
342
343
|
appRouteManifestModule: metadata.appRouteManifestModule,
|
|
343
344
|
lazyChunks: metadata.lazyChunks,
|
|
344
345
|
dynamicPreloads: metadata.dynamicPreloads,
|
|
@@ -444,7 +445,7 @@ function sendCompressed(req, res, body, contentType, statusCode, extraHeaders =
|
|
|
444
445
|
if (encoding !== "identity") {
|
|
445
446
|
writeHead(mergeVaryHeader({
|
|
446
447
|
...headersWithoutBodyHeaders,
|
|
447
|
-
"Content-Type": contentType,
|
|
448
|
+
...contentType !== void 0 && { "Content-Type": contentType },
|
|
448
449
|
"Content-Encoding": encoding
|
|
449
450
|
}, "Accept-Encoding"));
|
|
450
451
|
const compressor = createCompressor(encoding);
|
|
@@ -453,7 +454,7 @@ function sendCompressed(req, res, body, contentType, statusCode, extraHeaders =
|
|
|
453
454
|
} else {
|
|
454
455
|
const identityHeaders = {
|
|
455
456
|
...headersWithoutBodyHeaders,
|
|
456
|
-
"Content-Type": contentType,
|
|
457
|
+
...contentType !== void 0 && { "Content-Type": contentType },
|
|
457
458
|
"Content-Length": String(buf.length)
|
|
458
459
|
};
|
|
459
460
|
writeHead(varyByEncoding ? mergeVaryHeader(identityHeaders, "Accept-Encoding") : identityHeaders);
|
|
@@ -477,20 +478,18 @@ function staticCacheLookupPath(pathname) {
|
|
|
477
478
|
}
|
|
478
479
|
/**
|
|
479
480
|
* Give a Node image passthrough Next.js's image Cache-Control instead of the
|
|
480
|
-
* public-file default: a
|
|
481
|
-
*
|
|
481
|
+
* public-file default: a build asset keeps its immutable default, and a public
|
|
482
|
+
* file, whatever its path, is revalidated after `images.minimumCacheTTL`, or
|
|
483
|
+
* after the max-age a direct request for it gets (from middleware or
|
|
484
|
+
* `headers()`, else the public-file default) when that is longer.
|
|
482
485
|
*/
|
|
483
|
-
function withImageSourceCacheControl(headers,
|
|
484
|
-
if (
|
|
486
|
+
function withImageSourceCacheControl(headers, publicFileCacheControl, config) {
|
|
487
|
+
if (publicFileCacheControl === void 0) return headers;
|
|
485
488
|
return {
|
|
486
489
|
...headers,
|
|
487
|
-
"Cache-Control":
|
|
490
|
+
"Cache-Control": sourceImageCacheControl(false, publicFileCacheControl ?? staticFileCacheControl(false), config)
|
|
488
491
|
};
|
|
489
492
|
}
|
|
490
|
-
/** Pathnames the Pages Router serves from routes rather than the client directory. */
|
|
491
|
-
function isPagesFilesystemExcludedPath(pathname, phase) {
|
|
492
|
-
return pathname === "/" || pathname === "/api" || pathname.startsWith("/api/") || phase === "direct" && pathname.startsWith(`/_next/static/`);
|
|
493
|
-
}
|
|
494
493
|
/**
|
|
495
494
|
* Try to serve a static file from the client build directory.
|
|
496
495
|
*
|
|
@@ -783,32 +782,14 @@ function pipeStaticFileRange(filePath, range, res) {
|
|
|
783
782
|
}
|
|
784
783
|
});
|
|
785
784
|
}
|
|
786
|
-
/**
|
|
787
|
-
* Resolve the actual file to serve, trying extension-less HTML fallbacks.
|
|
788
|
-
* Returns the resolved path + size + mtime, or null if not found.
|
|
789
|
-
*/
|
|
785
|
+
/** Returns the file's path + size + mtime, or null if it is not a regular file. */
|
|
790
786
|
async function resolveStaticFile(staticFile) {
|
|
791
787
|
const stat = await statIfFile(staticFile);
|
|
792
|
-
|
|
788
|
+
return stat ? {
|
|
793
789
|
path: staticFile,
|
|
794
790
|
size: stat.size,
|
|
795
791
|
mtimeMs: stat.mtimeMs
|
|
796
|
-
};
|
|
797
|
-
const htmlFallback = staticFile + ".html";
|
|
798
|
-
const htmlStat = await statIfFile(htmlFallback);
|
|
799
|
-
if (htmlStat) return {
|
|
800
|
-
path: htmlFallback,
|
|
801
|
-
size: htmlStat.size,
|
|
802
|
-
mtimeMs: htmlStat.mtimeMs
|
|
803
|
-
};
|
|
804
|
-
const indexFallback = path.join(staticFile, "index.html");
|
|
805
|
-
const indexStat = await statIfFile(indexFallback);
|
|
806
|
-
if (indexStat) return {
|
|
807
|
-
path: indexFallback,
|
|
808
|
-
size: indexStat.size,
|
|
809
|
-
mtimeMs: indexStat.mtimeMs
|
|
810
|
-
};
|
|
811
|
-
return null;
|
|
792
|
+
} : null;
|
|
812
793
|
}
|
|
813
794
|
async function statIfFile(filePath) {
|
|
814
795
|
try {
|
|
@@ -1129,6 +1110,7 @@ function installPagesClientAssets(options) {
|
|
|
1129
1110
|
setPagesClientAssets({
|
|
1130
1111
|
clientEntry: metadata.clientEntryFile,
|
|
1131
1112
|
appBootstrapPreinitModules: metadata.appBootstrapPreinitModules,
|
|
1113
|
+
appBootstrapPreloadModules: metadata.appBootstrapPreloadModules,
|
|
1132
1114
|
appRouteManifestModule: metadata.appRouteManifestModule,
|
|
1133
1115
|
ssrManifest: Object.keys(ssrManifest).length > 0 ? ssrManifest : void 0,
|
|
1134
1116
|
sharedChunks: metadata.sharedChunks,
|
|
@@ -1214,7 +1196,7 @@ async function startAppRouterServer(options) {
|
|
|
1214
1196
|
return;
|
|
1215
1197
|
}
|
|
1216
1198
|
const sendUnsafeContentType = () => {
|
|
1217
|
-
sendBadRequest(
|
|
1199
|
+
sendBadRequest(IMAGE_TYPE_NOT_ALLOWED_MESSAGE);
|
|
1218
1200
|
};
|
|
1219
1201
|
const isSafeSourcePath = (sourcePath) => isSafeImageContentType(contentTypeForPath(sourcePath), imageConfig?.dangerouslyAllowSVG);
|
|
1220
1202
|
const imageSecurityHeaders = {
|
|
@@ -1222,7 +1204,7 @@ async function startAppRouterServer(options) {
|
|
|
1222
1204
|
"X-Content-Type-Options": "nosniff",
|
|
1223
1205
|
"Content-Disposition": imageConfig?.contentDispositionType === "attachment" ? "attachment" : "inline"
|
|
1224
1206
|
};
|
|
1225
|
-
const serveSource = (sourcePath) => tryServeStatic(req, res, clientDir, sourcePath, false, staticCache, withImageSourceCacheControl(imageSecurityHeaders,
|
|
1207
|
+
const serveSource = (sourcePath, publicFileCacheControl) => tryServeStatic(req, res, clientDir, sourcePath, false, staticCache, withImageSourceCacheControl(imageSecurityHeaders, publicFileCacheControl, imageConfig), void 0, IMAGE_REPRESENTATION_HEADERS);
|
|
1226
1208
|
const sourceUrl = new URL(params.imageUrl, request.url);
|
|
1227
1209
|
let sourcePathname = null;
|
|
1228
1210
|
try {
|
|
@@ -1248,7 +1230,7 @@ async function startAppRouterServer(options) {
|
|
|
1248
1230
|
sendUnsafeContentType();
|
|
1249
1231
|
return;
|
|
1250
1232
|
}
|
|
1251
|
-
if (await serveSource(sourcePath)) return;
|
|
1233
|
+
if (await serveSource(sourcePath, sourceResponse.headers.get("Cache-Control"))) return;
|
|
1252
1234
|
}
|
|
1253
1235
|
}
|
|
1254
1236
|
sendBadRequest(INVALID_IMAGE_SOURCE_MESSAGE);
|
|
@@ -1440,6 +1422,8 @@ async function createPagesRouterRequestHandler(options) {
|
|
|
1440
1422
|
const ensureInstrumentation = typeof serverEntry.__ensureInstrumentation === "function" ? () => serverEntry.__ensureInstrumentation() : () => void 0;
|
|
1441
1423
|
const hasMiddleware = serverEntry.hasMiddleware === true;
|
|
1442
1424
|
const pageRoutes = readPagesServerEntryPageRoutes(serverEntry.pageRoutes);
|
|
1425
|
+
const publicFiles = serverEntry.publicFiles instanceof Set ? serverEntry.publicFiles : /* @__PURE__ */ new Set();
|
|
1426
|
+
const clientBuildFiles = serverEntry.clientBuildFiles instanceof Set ? serverEntry.clientBuildFiles : /* @__PURE__ */ new Set();
|
|
1443
1427
|
const prerenderSecret = readPrerenderSecret(path.dirname(serverEntryPath));
|
|
1444
1428
|
const compress = compressOption && readServerCompress(serverDir);
|
|
1445
1429
|
const basePath = vinextConfig?.basePath ?? "";
|
|
@@ -1464,7 +1448,9 @@ async function createPagesRouterRequestHandler(options) {
|
|
|
1464
1448
|
qualities: vinextConfig.images.qualities,
|
|
1465
1449
|
localPatterns: vinextConfig.images.localPatterns,
|
|
1466
1450
|
contentDispositionType: vinextConfig.images.contentDispositionType,
|
|
1467
|
-
contentSecurityPolicy: vinextConfig.images.contentSecurityPolicy
|
|
1451
|
+
contentSecurityPolicy: vinextConfig.images.contentSecurityPolicy,
|
|
1452
|
+
minimumCacheTTL: vinextConfig.images.minimumCacheTTL,
|
|
1453
|
+
maximumResponseBody: vinextConfig.images.maximumResponseBody
|
|
1468
1454
|
} : void 0;
|
|
1469
1455
|
const ssrManifest = installPagesClientAssets({
|
|
1470
1456
|
clientDir,
|
|
@@ -1554,6 +1540,10 @@ async function createPagesRouterRequestHandler(options) {
|
|
|
1554
1540
|
if (pagesAssetLookup) {
|
|
1555
1541
|
if (await tryServeStatic(req, res, clientDir, pagesAssetLookup, compress, staticCache)) return;
|
|
1556
1542
|
}
|
|
1543
|
+
if (req.method === "GET" || req.method === "HEAD") {
|
|
1544
|
+
const clientBuildFile = resolveClientBuildFile(rawPagesPathname, basePath, clientBuildFiles);
|
|
1545
|
+
if (clientBuildFile && await tryServeStatic(req, res, clientDir, clientBuildFile, compress, staticCache)) return;
|
|
1546
|
+
}
|
|
1557
1547
|
try {
|
|
1558
1548
|
const hadBasePath = !basePath || hasBasePath(requestPathname, basePath);
|
|
1559
1549
|
const restoreLocaleRootTrailingSlash = shouldRestoreLocaleRootTrailingSlash(requestPathname, {
|
|
@@ -1624,6 +1614,7 @@ async function createPagesRouterRequestHandler(options) {
|
|
|
1624
1614
|
const middlewareRequest = isDataReq && skipProxyUrlNormalize ? new Request(new URL(originalRenderUrl, webRequest.url), webRequest) : void 0;
|
|
1625
1615
|
const middlewareCtx = createNodeExecutionContext(void 0, { middlewareOrigin: resolveNodeMiddlewareOrigin(req, webRequest.url, host, port) });
|
|
1626
1616
|
const runNodeMiddleware = typeof runMiddleware === "function" ? (request, _ctx, opts) => runMiddleware(request, middlewareCtx, opts) : null;
|
|
1617
|
+
/** The public file a source resolves to, with the Cache-Control staged for it. */
|
|
1627
1618
|
const resolvePublicImageSource = async (sourceUrl) => {
|
|
1628
1619
|
const rawSourcePathname = sourceUrl.pathname;
|
|
1629
1620
|
if (getRepeatedSlashRedirect(rawSourcePathname) || isOpenRedirectShaped(rawSourcePathname)) return null;
|
|
@@ -1631,7 +1622,7 @@ async function createPagesRouterRequestHandler(options) {
|
|
|
1631
1622
|
const sourceHadBasePath = !basePath || hasBasePath(sourceRequestPathname, basePath);
|
|
1632
1623
|
const strippedSourcePathname = stripBasePath(sourceRequestPathname, basePath);
|
|
1633
1624
|
if (isNextDataPathname(strippedSourcePathname)) return null;
|
|
1634
|
-
let
|
|
1625
|
+
let source = null;
|
|
1635
1626
|
const result = await runPagesRequest(new Request(new URL(strippedSourcePathname + sourceUrl.search, sourceUrl), { signal: webRequest.signal }), {
|
|
1636
1627
|
...deps,
|
|
1637
1628
|
hadBasePath: sourceHadBasePath,
|
|
@@ -1649,17 +1640,20 @@ async function createPagesRouterRequestHandler(options) {
|
|
|
1649
1640
|
runMiddleware: runNodeMiddleware ? wrapMiddlewareWithBasePath(runNodeMiddleware, basePath, sourceHadBasePath) : null,
|
|
1650
1641
|
renderPage: null,
|
|
1651
1642
|
handleApi: null,
|
|
1652
|
-
serveFilesystemRoute: async (candidate,
|
|
1653
|
-
if (
|
|
1643
|
+
serveFilesystemRoute: async (candidate, stagedHeaders, phase, _resolvedUrl, sourceRequest, candidateHasBasePath) => {
|
|
1644
|
+
if (isImageOptimizationPath(candidate) || !isServableFilesystemRoute(candidate, phase, sourceRequest.method, publicFiles, basePath, pagesAssetPathPrefix, candidateHasBasePath)) return false;
|
|
1654
1645
|
const lookupPath = staticCacheLookupPath(candidate);
|
|
1655
1646
|
if (lookupPath === null || lookupPath === "/" || !staticCache.lookup(lookupPath)) return false;
|
|
1656
|
-
|
|
1647
|
+
source = {
|
|
1648
|
+
path: candidate,
|
|
1649
|
+
cacheControl: readHeaderCaseInsensitive(stagedHeaders, "cache-control") ?? null
|
|
1650
|
+
};
|
|
1657
1651
|
return new Response(null);
|
|
1658
1652
|
}
|
|
1659
1653
|
});
|
|
1660
1654
|
if (result.type !== "response") return null;
|
|
1661
1655
|
cancelResponseBody(result.response);
|
|
1662
|
-
return isImageSourceBodyStatus(result.response.status) ?
|
|
1656
|
+
return isImageSourceBodyStatus(result.response.status) ? source : null;
|
|
1663
1657
|
};
|
|
1664
1658
|
const deps = {
|
|
1665
1659
|
assetPrefix,
|
|
@@ -1693,7 +1687,7 @@ async function createPagesRouterRequestHandler(options) {
|
|
|
1693
1687
|
return handleApi(request, apiUrl, createNodeExecutionContext(), resolveTrustedNodeRevalidateOrigin(req, host, port), "node", stagedHeaders);
|
|
1694
1688
|
} : null,
|
|
1695
1689
|
handleApiAppliesStagedHeaders: true,
|
|
1696
|
-
serveFilesystemRoute: async (requestPathname, stagedHeaders, phase, resolvedUrl,
|
|
1690
|
+
serveFilesystemRoute: async (requestPathname, stagedHeaders, phase, resolvedUrl, filesystemRequest, resolvedPathnameHasBasePath) => {
|
|
1697
1691
|
if (resolvedPathnameHasBasePath && isImageOptimizationPath(requestPathname)) {
|
|
1698
1692
|
for (const [name, value] of Object.entries(stagedHeaders)) res.setHeader(name, value);
|
|
1699
1693
|
const parsedUrl = new URL(resolvedUrl, "http://localhost");
|
|
@@ -1705,7 +1699,7 @@ async function createPagesRouterRequestHandler(options) {
|
|
|
1705
1699
|
}
|
|
1706
1700
|
const sendUnsafeContentType = () => {
|
|
1707
1701
|
res.writeHead(400);
|
|
1708
|
-
res.end(
|
|
1702
|
+
res.end(IMAGE_TYPE_NOT_ALLOWED_MESSAGE);
|
|
1709
1703
|
};
|
|
1710
1704
|
const isSafeSourcePath = (sourcePath) => isSafeImageContentType(contentTypeForPath(sourcePath), pagesImageConfig?.dangerouslyAllowSVG);
|
|
1711
1705
|
const imageSecurityHeaders = {
|
|
@@ -1713,7 +1707,7 @@ async function createPagesRouterRequestHandler(options) {
|
|
|
1713
1707
|
"X-Content-Type-Options": "nosniff",
|
|
1714
1708
|
"Content-Disposition": pagesImageConfig?.contentDispositionType === "attachment" ? "attachment" : "inline"
|
|
1715
1709
|
};
|
|
1716
|
-
const serveSource = (sourcePath) => tryServeStatic(req, res, clientDir, sourcePath, false, staticCache, withImageSourceCacheControl(imageSecurityHeaders,
|
|
1710
|
+
const serveSource = (sourcePath, publicFileCacheControl) => tryServeStatic(req, res, clientDir, sourcePath, false, staticCache, withImageSourceCacheControl(imageSecurityHeaders, publicFileCacheControl, pagesImageConfig), void 0, IMAGE_REPRESENTATION_HEADERS);
|
|
1717
1711
|
const sourceUrl = new URL(params.imageUrl, webRequest.url);
|
|
1718
1712
|
let sourcePathname = null;
|
|
1719
1713
|
try {
|
|
@@ -1723,22 +1717,22 @@ async function createPagesRouterRequestHandler(options) {
|
|
|
1723
1717
|
sendUnsafeContentType();
|
|
1724
1718
|
return true;
|
|
1725
1719
|
}
|
|
1726
|
-
const assetLookupPath = sourcePathname !== null ? resolveAppRouterAssetPath(sourcePathname, pagesAssetPathPrefix, assetPrefix) : null;
|
|
1720
|
+
const assetLookupPath = sourcePathname !== null ? resolveAppRouterAssetPath(sourcePathname, pagesAssetPathPrefix, assetPrefix) ?? resolveClientBuildFile(sourceUrl.pathname, basePath, clientBuildFiles) : null;
|
|
1727
1721
|
if (assetLookupPath && await serveSource(assetLookupPath)) return true;
|
|
1728
|
-
const
|
|
1722
|
+
const source = sourcePathname !== null ? await resolvePublicImageSource(sourceUrl) : null;
|
|
1729
1723
|
if (webRequest.signal.aborted) return true;
|
|
1730
|
-
if (
|
|
1731
|
-
if (!isSafeSourcePath(staticCacheLookupPath(
|
|
1724
|
+
if (source !== null) {
|
|
1725
|
+
if (!isSafeSourcePath(staticCacheLookupPath(source.path) ?? source.path)) {
|
|
1732
1726
|
sendUnsafeContentType();
|
|
1733
1727
|
return true;
|
|
1734
1728
|
}
|
|
1735
|
-
if (await serveSource(
|
|
1729
|
+
if (await serveSource(source.path, source.cacheControl)) return true;
|
|
1736
1730
|
}
|
|
1737
1731
|
res.writeHead(400);
|
|
1738
1732
|
res.end(INVALID_IMAGE_SOURCE_MESSAGE);
|
|
1739
1733
|
return true;
|
|
1740
1734
|
}
|
|
1741
|
-
if (!
|
|
1735
|
+
if (!isServableFilesystemRoute(requestPathname, phase, filesystemRequest.method, publicFiles, basePath, pagesAssetPathPrefix, resolvedPathnameHasBasePath)) return false;
|
|
1742
1736
|
return tryServeStatic(req, res, clientDir, requestPathname, compress, staticCache, stagedHeaders);
|
|
1743
1737
|
}
|
|
1744
1738
|
};
|
|
@@ -1758,7 +1752,7 @@ async function createPagesRouterRequestHandler(options) {
|
|
|
1758
1752
|
}
|
|
1759
1753
|
const responseBody = await bufferResponseBodyUntilAborted(response, webRequest.signal);
|
|
1760
1754
|
if (!responseBody) return;
|
|
1761
|
-
const ct = response.headers.get("content-type") ?? result.defaultContentType;
|
|
1755
|
+
const ct = response.headers.get("content-type") ?? (responseBody.length > 0 ? result.defaultContentType : void 0);
|
|
1762
1756
|
const responseHeaders = {};
|
|
1763
1757
|
response.headers.forEach((v, k) => {
|
|
1764
1758
|
if (k === "set-cookie") return;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { IncomingMessage } from "node:http";
|
|
2
|
+
import { Http2ServerRequest } from "node:http2";
|
|
3
|
+
//#region src/server/remove-request-headers.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Remove headers from every view of a Node request.
|
|
6
|
+
*
|
|
7
|
+
* Node keeps each client header in req.rawHeaders as well as req.headers, and
|
|
8
|
+
* srvx (plugin-rsc's dev request adapter) answers Headers reads from rawHeaders
|
|
9
|
+
* once anything iterates them, so later handlers must not find a removed
|
|
10
|
+
* header in either. On HTTP/1, Node builds req.headers and req.headersDistinct
|
|
11
|
+
* lazily from rawHeaders and the header count it parsed, so both must exist
|
|
12
|
+
* before rawHeaders gets shorter. HTTP/2 compatibility requests (Vite with
|
|
13
|
+
* `server.https`) have no headersDistinct.
|
|
14
|
+
*/
|
|
15
|
+
export declare function removeRequestHeaders(req: IncomingMessage | Http2ServerRequest, names: ReadonlySet<string>): void;
|
|
16
|
+
//#endregion
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/server/remove-request-headers.ts
|
|
2
|
+
/**
|
|
3
|
+
* Remove headers from every view of a Node request.
|
|
4
|
+
*
|
|
5
|
+
* Node keeps each client header in req.rawHeaders as well as req.headers, and
|
|
6
|
+
* srvx (plugin-rsc's dev request adapter) answers Headers reads from rawHeaders
|
|
7
|
+
* once anything iterates them, so later handlers must not find a removed
|
|
8
|
+
* header in either. On HTTP/1, Node builds req.headers and req.headersDistinct
|
|
9
|
+
* lazily from rawHeaders and the header count it parsed, so both must exist
|
|
10
|
+
* before rawHeaders gets shorter. HTTP/2 compatibility requests (Vite with
|
|
11
|
+
* `server.https`) have no headersDistinct.
|
|
12
|
+
*/
|
|
13
|
+
function removeRequestHeaders(req, names) {
|
|
14
|
+
const headersDistinct = "headersDistinct" in req ? req.headersDistinct : void 0;
|
|
15
|
+
for (const name of names) {
|
|
16
|
+
delete req.headers[name];
|
|
17
|
+
if (headersDistinct) delete headersDistinct[name];
|
|
18
|
+
}
|
|
19
|
+
const rawHeaders = req.rawHeaders;
|
|
20
|
+
for (let i = rawHeaders.length - 2; i >= 0; i -= 2) if (names.has(rawHeaders[i].toLowerCase())) rawHeaders.splice(i, 2);
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { removeRequestHeaders };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/server/srvx-middleware-origin.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The server-owned origin middleware runs against when srvx serves the
|
|
4
|
+
* request on Node. srvx builds `request.url` from the client's Host and
|
|
5
|
+
* `X-Forwarded-Proto` headers, which must not decide whether a rewrite to
|
|
6
|
+
* another host is external, so like the Node production server (and Next.js,
|
|
7
|
+
* which uses its hostname and port) this uses the socket's TLS state and
|
|
8
|
+
* local port, or a trusted `X-Forwarded-Proto` and `X-Forwarded-Host`.
|
|
9
|
+
* Undefined on other hosts, and on Vercel, which routes by hostname like
|
|
10
|
+
* Workers; they keep the request URL's origin.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveSrvxMiddlewareOrigin(request: Request): string | undefined;
|
|
13
|
+
//#endregion
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { resolveRequestProtocol, resolveTrustedForwardedHost } from "./proxy-trust.js";
|
|
2
|
+
//#region src/server/srvx-middleware-origin.ts
|
|
3
|
+
/**
|
|
4
|
+
* The server-owned origin middleware runs against when srvx serves the
|
|
5
|
+
* request on Node. srvx builds `request.url` from the client's Host and
|
|
6
|
+
* `X-Forwarded-Proto` headers, which must not decide whether a rewrite to
|
|
7
|
+
* another host is external, so like the Node production server (and Next.js,
|
|
8
|
+
* which uses its hostname and port) this uses the socket's TLS state and
|
|
9
|
+
* local port, or a trusted `X-Forwarded-Proto` and `X-Forwarded-Host`.
|
|
10
|
+
* Undefined on other hosts, and on Vercel, which routes by hostname like
|
|
11
|
+
* Workers; they keep the request URL's origin.
|
|
12
|
+
*/
|
|
13
|
+
function resolveSrvxMiddlewareOrigin(request) {
|
|
14
|
+
const socket = request.runtime?.node?.req?.socket;
|
|
15
|
+
if (!socket || process.env.VERCEL) return void 0;
|
|
16
|
+
return `${socket.encrypted === true || resolveRequestProtocol(request.headers) === "https" ? "https:" : "http:"}//${resolveTrustedForwardedHost(request.headers) ?? (socket.localPort === void 0 ? "localhost" : `localhost:${socket.localPort}`)}`;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { resolveSrvxMiddlewareOrigin };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/server/srvx-request-target.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Whether srvx, serving the request on Node, got a request target that is not
|
|
4
|
+
* origin-form (`GET https://other.example/x`). srvx then takes the origin of
|
|
5
|
+
* `request.url` from the target, as RFC 9112 §3.2.2 asks of an origin server.
|
|
6
|
+
* `vinext start` 404s every such target (see `getRepeatedSlashRedirect`) and
|
|
7
|
+
* Next.js never routes one, so the request-based entries Nitro calls refuse
|
|
8
|
+
* them too. The raw target is the one `nitroRequestTargetPlugin` saved before
|
|
9
|
+
* h3 could rewrite `req.url`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function isSrvxAbsoluteFormTarget(request: Request): boolean;
|
|
12
|
+
//#endregion
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { NITRO_REQUEST_TARGET_KEY } from "./nitro-request-target-plugin.js";
|
|
2
|
+
//#region src/server/srvx-request-target.ts
|
|
3
|
+
/**
|
|
4
|
+
* Whether srvx, serving the request on Node, got a request target that is not
|
|
5
|
+
* origin-form (`GET https://other.example/x`). srvx then takes the origin of
|
|
6
|
+
* `request.url` from the target, as RFC 9112 §3.2.2 asks of an origin server.
|
|
7
|
+
* `vinext start` 404s every such target (see `getRepeatedSlashRedirect`) and
|
|
8
|
+
* Next.js never routes one, so the request-based entries Nitro calls refuse
|
|
9
|
+
* them too. The raw target is the one `nitroRequestTargetPlugin` saved before
|
|
10
|
+
* h3 could rewrite `req.url`.
|
|
11
|
+
*/
|
|
12
|
+
function isSrvxAbsoluteFormTarget(request) {
|
|
13
|
+
const req = request.runtime?.node?.req;
|
|
14
|
+
if (!req) return false;
|
|
15
|
+
const saved = Reflect.get(req, Symbol.for(NITRO_REQUEST_TARGET_KEY));
|
|
16
|
+
const target = typeof saved === "string" ? saved : req.url;
|
|
17
|
+
return !!target && !target.startsWith("/");
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { isSrvxAbsoluteFormTarget };
|
|
@@ -29,9 +29,11 @@ const CONTENT_TYPES = {
|
|
|
29
29
|
".css": "text/css; charset=utf-8",
|
|
30
30
|
".html": "text/html; charset=utf-8",
|
|
31
31
|
".ico": "image/x-icon",
|
|
32
|
+
".icns": "image/x-icns",
|
|
32
33
|
".jpeg": "image/jpeg",
|
|
33
34
|
".jpg": "image/jpeg",
|
|
34
35
|
".json": "application/json; charset=utf-8",
|
|
36
|
+
".jxl": "image/jxl",
|
|
35
37
|
".map": "application/json; charset=utf-8",
|
|
36
38
|
".mp3": "audio/mpeg",
|
|
37
39
|
".mp4": "video/mp4",
|
|
@@ -148,30 +150,16 @@ var StaticFileCache = class StaticFileCache {
|
|
|
148
150
|
}
|
|
149
151
|
const pathname = "/" + relativePath;
|
|
150
152
|
entries.set(pathname, entry);
|
|
151
|
-
if (ext === ".html") {
|
|
152
|
-
if (relativePath.endsWith("/index.html")) {
|
|
153
|
-
const dirPath = "/" + relativePath.slice(0, -11);
|
|
154
|
-
if (dirPath !== "/") entries.set(dirPath, entry);
|
|
155
|
-
} else {
|
|
156
|
-
const withoutExt = "/" + relativePath.slice(0, -ext.length);
|
|
157
|
-
entries.set(withoutExt, entry);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
153
|
}
|
|
161
154
|
const toBuffer = [];
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
entry.zst
|
|
171
|
-
]) {
|
|
172
|
-
if (!variant || variant.size > BUFFER_THRESHOLD) continue;
|
|
173
|
-
toBuffer.push(variant);
|
|
174
|
-
}
|
|
155
|
+
for (const entry of entries.values()) for (const variant of [
|
|
156
|
+
entry.original,
|
|
157
|
+
entry.br,
|
|
158
|
+
entry.gz,
|
|
159
|
+
entry.zst
|
|
160
|
+
]) {
|
|
161
|
+
if (!variant || variant.size > BUFFER_THRESHOLD) continue;
|
|
162
|
+
toBuffer.push(variant);
|
|
175
163
|
}
|
|
176
164
|
for (let i = 0; i < toBuffer.length; i += 64) await Promise.all(toBuffer.slice(i, i + 64).map(async (v) => {
|
|
177
165
|
v.buffer = await fsp.readFile(v.path);
|
|
@@ -19,10 +19,17 @@ export type WorkerImageSourceOptions = {
|
|
|
19
19
|
* served only when the application pipeline selects a public file for it.
|
|
20
20
|
*/
|
|
21
21
|
export declare function fetchWorkerImageSource(imageUrl: string, request: Request, options: WorkerImageSourceOptions): Promise<Response>;
|
|
22
|
+
/**
|
|
23
|
+
* Give a public-file source the Cache-Control middleware or `headers()` staged
|
|
24
|
+
* for it, which a direct request receives in place of the asset default and
|
|
25
|
+
* Next.js' internal source fetch reads.
|
|
26
|
+
*/
|
|
27
|
+
export declare function withStagedCacheControl(asset: Response, cacheControl: string | null): Response;
|
|
22
28
|
/**
|
|
23
29
|
* Return the public file a framework static-file signal selects, provided the
|
|
24
30
|
* pipeline answered with a body-bearing 2xx outcome. The file is fetched with middleware's
|
|
25
|
-
* request header overrides, as resolveStaticAssetSignal fetches it
|
|
31
|
+
* request header overrides, as resolveStaticAssetSignal fetches it, and keeps
|
|
32
|
+
* the Cache-Control the pipeline staged.
|
|
26
33
|
*/
|
|
27
34
|
export declare function fetchSignalledPublicFile(response: Response, sourceRequest: Request, assets: VinextAssetFetcher): Promise<Response> | null;
|
|
28
35
|
/**
|