astro 6.2.2 → 6.3.0
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/dist/actions/handler.d.ts +32 -0
- package/dist/actions/handler.js +45 -0
- package/dist/actions/runtime/server.js +1 -1
- package/dist/assets/build/generate.js +1 -1
- package/dist/assets/build/remote.d.ts +3 -2
- package/dist/assets/build/remote.js +16 -9
- package/dist/assets/endpoint/generic.js +4 -7
- package/dist/assets/endpoint/shared.js +7 -2
- package/dist/assets/index.d.ts +1 -0
- package/dist/assets/index.js +2 -0
- package/dist/assets/services/sharp.js +7 -0
- package/dist/assets/utils/index.d.ts +1 -0
- package/dist/assets/utils/index.js +2 -0
- package/dist/assets/utils/redirectValidation.d.ts +48 -0
- package/dist/assets/utils/redirectValidation.js +48 -0
- package/dist/assets/utils/remoteProbe.js +25 -2
- package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
- package/dist/container/index.js +18 -14
- package/dist/content/content-layer.js +3 -4
- package/dist/content/server-listeners.js +0 -4
- package/dist/content/vite-plugin-content-virtual-mod.js +9 -1
- package/dist/core/app/base.d.ts +33 -15
- package/dist/core/app/base.js +120 -324
- package/dist/core/app/dev/app.d.ts +3 -2
- package/dist/core/app/dev/app.js +4 -60
- package/dist/core/app/entrypoints/virtual/dev.js +2 -0
- package/dist/core/app/entrypoints/virtual/prod.js +4 -1
- package/dist/core/app/prepare-response.d.ts +11 -0
- package/dist/core/app/prepare-response.js +18 -0
- package/dist/core/app/render-options.d.ts +11 -0
- package/dist/core/app/render-options.js +11 -0
- package/dist/core/base-pipeline.d.ts +38 -1
- package/dist/core/base-pipeline.js +50 -7
- package/dist/core/build/app.d.ts +3 -4
- package/dist/core/build/app.js +3 -17
- package/dist/core/cache/handler.d.ts +29 -0
- package/dist/core/cache/handler.js +81 -0
- package/dist/core/config/schemas/base.d.ts +4 -0
- package/dist/core/config/schemas/base.js +4 -0
- package/dist/core/config/schemas/relative.d.ts +6 -0
- package/dist/core/constants.d.ts +27 -1
- package/dist/core/constants.js +14 -1
- package/dist/core/cookies/cookies.d.ts +7 -2
- package/dist/core/cookies/cookies.js +11 -4
- package/dist/core/cookies/response.d.ts +1 -1
- package/dist/core/cookies/response.js +1 -2
- package/dist/core/create-vite.js +15 -0
- package/dist/core/csp/runtime.js +6 -4
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/errors/build-handler.d.ts +17 -0
- package/dist/core/errors/build-handler.js +22 -0
- package/dist/core/errors/default-handler.d.ts +14 -0
- package/dist/core/errors/default-handler.js +144 -0
- package/dist/core/errors/dev-handler.d.ts +21 -0
- package/dist/core/errors/dev-handler.js +82 -0
- package/dist/core/errors/handler.d.ts +9 -0
- package/dist/core/errors/handler.js +0 -0
- package/dist/core/fetch/default-handler.d.ts +17 -0
- package/dist/core/fetch/default-handler.js +45 -0
- package/dist/core/fetch/fetch-state.d.ts +244 -0
- package/dist/core/fetch/fetch-state.js +779 -0
- package/dist/core/fetch/index.d.ts +61 -0
- package/dist/core/fetch/index.js +121 -0
- package/dist/core/fetch/types.d.ts +6 -0
- package/dist/core/fetch/types.js +0 -0
- package/dist/core/fetch/vite-plugin.d.ts +5 -0
- package/dist/core/fetch/vite-plugin.js +69 -0
- package/dist/core/hono/index.d.ts +21 -0
- package/dist/core/hono/index.js +98 -0
- package/dist/core/i18n/handler.d.ts +18 -0
- package/dist/core/i18n/handler.js +119 -0
- package/dist/core/logger/core.d.ts +8 -0
- package/dist/core/logger/core.js +16 -0
- package/dist/core/messages/runtime.js +1 -1
- package/dist/core/middleware/astro-middleware.d.ts +27 -0
- package/dist/core/middleware/astro-middleware.js +53 -0
- package/dist/core/pages/handler.d.ts +20 -0
- package/dist/core/pages/handler.js +74 -0
- package/dist/core/redirects/render.d.ts +2 -2
- package/dist/core/redirects/render.js +7 -8
- package/dist/core/rewrites/handler.d.ts +37 -0
- package/dist/core/rewrites/handler.js +67 -0
- package/dist/core/routing/3xx.js +8 -4
- package/dist/core/routing/handler.d.ts +17 -0
- package/dist/core/routing/handler.js +172 -0
- package/dist/core/routing/match.d.ts +0 -7
- package/dist/core/routing/match.js +0 -5
- package/dist/core/routing/trailing-slash-handler.d.ts +18 -0
- package/dist/core/routing/trailing-slash-handler.js +67 -0
- package/dist/core/session/drivers.d.ts +1 -1
- package/dist/core/session/handler.d.ts +11 -0
- package/dist/core/session/handler.js +33 -0
- package/dist/core/util/normalized-url.d.ts +10 -0
- package/dist/core/util/normalized-url.js +21 -0
- package/dist/i18n/middleware.d.ts +10 -0
- package/dist/i18n/middleware.js +4 -88
- package/dist/i18n/utils.js +2 -2
- package/dist/runtime/server/astro-island.js +57 -20
- package/dist/runtime/server/astro-island.prebuilt-dev.d.ts +1 -1
- package/dist/runtime/server/astro-island.prebuilt-dev.js +1 -1
- package/dist/runtime/server/astro-island.prebuilt.d.ts +1 -1
- package/dist/runtime/server/astro-island.prebuilt.js +1 -1
- package/dist/runtime/server/render/server-islands.js +2 -1
- package/dist/types/public/config.d.ts +46 -12
- package/dist/types/public/internal.d.ts +1 -1
- package/dist/vite-plugin-app/app.d.ts +4 -5
- package/dist/vite-plugin-app/app.js +20 -65
- package/package.json +11 -5
- package/dist/core/render-context.d.ts +0 -77
- package/dist/core/render-context.js +0 -826
package/dist/core/app/base.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { RoutesList } from '../../types/astro.js';
|
|
2
2
|
import type { RemotePattern, RouteData } from '../../types/public/index.js';
|
|
3
|
-
import type
|
|
3
|
+
import { type Pipeline } from '../base-pipeline.js';
|
|
4
4
|
import { getSetCookiesFromResponse } from '../cookies/index.js';
|
|
5
5
|
import { AstroIntegrationLogger, type AstroLogger } from '../logger/core.js';
|
|
6
|
-
import
|
|
6
|
+
import type { FetchHandler } from '../fetch/types.js';
|
|
7
|
+
import type { ErrorHandler } from '../errors/handler.js';
|
|
7
8
|
import type { WaitUntilHook } from '../wait-until.js';
|
|
8
9
|
import type { AppPipeline } from './pipeline.js';
|
|
9
10
|
import type { SSRManifest } from './types.js';
|
|
@@ -60,7 +61,7 @@ export interface RenderOptions {
|
|
|
60
61
|
routeData?: RouteData;
|
|
61
62
|
}
|
|
62
63
|
type RequiredRenderOptions = Required<RenderOptions>;
|
|
63
|
-
interface ResolvedRenderOptions {
|
|
64
|
+
export interface ResolvedRenderOptions {
|
|
64
65
|
addCookieHeader: RequiredRenderOptions['addCookieHeader'];
|
|
65
66
|
clientAddress: RequiredRenderOptions['clientAddress'] | undefined;
|
|
66
67
|
prerenderedErrorPageFetch: RequiredRenderOptions['prerenderedErrorPageFetch'] | undefined;
|
|
@@ -79,20 +80,38 @@ export interface RenderErrorOptions extends ResolvedRenderOptions {
|
|
|
79
80
|
* Allows passing an error to 500.astro. It will be available through `Astro.props.error`.
|
|
80
81
|
*/
|
|
81
82
|
error?: unknown;
|
|
83
|
+
/**
|
|
84
|
+
* The pathname to use for the error page render context. If omitted, the
|
|
85
|
+
* error handler computes it from `request` via a short-lived `FetchState`.
|
|
86
|
+
*/
|
|
87
|
+
pathname?: string;
|
|
82
88
|
}
|
|
83
89
|
type ErrorPagePath = `${string}/404` | `${string}/500` | `${string}/404/` | `${string}/500/` | `${string}404.html` | `${string}500.html`;
|
|
84
90
|
export declare abstract class BaseApp<P extends Pipeline = AppPipeline> {
|
|
85
91
|
#private;
|
|
86
92
|
manifest: SSRManifest;
|
|
87
|
-
manifestData:
|
|
93
|
+
manifestData: {
|
|
94
|
+
routes: RouteData[];
|
|
95
|
+
};
|
|
88
96
|
pipeline: P;
|
|
89
97
|
baseWithoutTrailingSlash: string;
|
|
90
98
|
get logger(): AstroLogger;
|
|
91
99
|
get adapterLogger(): AstroIntegrationLogger;
|
|
92
100
|
constructor(manifest: SSRManifest, streaming?: boolean, ...args: any[]);
|
|
101
|
+
/**
|
|
102
|
+
* Override the fetch handler used to dispatch requests. Entrypoints
|
|
103
|
+
* call this with the default export of `virtual:astro:fetchable` to
|
|
104
|
+
* plug in a user-authored handler from `src/app.ts`.
|
|
105
|
+
*/
|
|
106
|
+
setFetchHandler(handler: {
|
|
107
|
+
fetch: FetchHandler;
|
|
108
|
+
}): void;
|
|
109
|
+
/**
|
|
110
|
+
* Returns the error handler strategy used by this app. Override to
|
|
111
|
+
* provide environment-specific behavior (dev overlay, build-time throws, etc.).
|
|
112
|
+
*/
|
|
113
|
+
protected createErrorHandler(): ErrorHandler;
|
|
93
114
|
abstract isDev(): boolean;
|
|
94
|
-
createRenderContext(payload: CreateRenderContext): Promise<RenderContext>;
|
|
95
|
-
getAdapterLogger(): AstroIntegrationLogger;
|
|
96
115
|
/**
|
|
97
116
|
* Resets the cached adapter logger so it picks up a new logger instance.
|
|
98
117
|
* Used by BuildApp when the logger is replaced via setOptions().
|
|
@@ -113,10 +132,8 @@ export declare abstract class BaseApp<P extends Pipeline = AppPipeline> {
|
|
|
113
132
|
set setManifestData(newManifestData: RoutesList);
|
|
114
133
|
removeBase(pathname: string): string;
|
|
115
134
|
/**
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* If the decoding fails, it logs the error and return the pathname as is.
|
|
119
|
-
* @param request
|
|
135
|
+
* Extracts the base-stripped, decoded pathname from a request.
|
|
136
|
+
* Used by adapters to compute the pathname for dev-mode route matching.
|
|
120
137
|
*/
|
|
121
138
|
getPathnameFromRequest(request: Request): string;
|
|
122
139
|
/**
|
|
@@ -128,7 +145,6 @@ export declare abstract class BaseApp<P extends Pipeline = AppPipeline> {
|
|
|
128
145
|
* @param allowPrerenderedRoutes
|
|
129
146
|
*/
|
|
130
147
|
match(request: Request, allowPrerenderedRoutes?: boolean): RouteData | undefined;
|
|
131
|
-
private createRouter;
|
|
132
148
|
/**
|
|
133
149
|
* A matching route function to use in the development server.
|
|
134
150
|
* Contrary to the `.match` function, this function resolves props and params, returning the correct
|
|
@@ -137,7 +153,6 @@ export declare abstract class BaseApp<P extends Pipeline = AppPipeline> {
|
|
|
137
153
|
*/
|
|
138
154
|
devMatch(pathname?: string): Promise<DevMatch | undefined> | undefined;
|
|
139
155
|
private computePathnameFromDomain;
|
|
140
|
-
private redirectTrailingSlash;
|
|
141
156
|
render(request: Request, { addCookieHeader, clientAddress, locals, prerenderedErrorPageFetch, routeData, waitUntil, }?: RenderOptions): Promise<Response>;
|
|
142
157
|
setCookieHeaders(response: Response): Generator<string, string[], any>;
|
|
143
158
|
/**
|
|
@@ -154,10 +169,13 @@ export declare abstract class BaseApp<P extends Pipeline = AppPipeline> {
|
|
|
154
169
|
static getSetCookieFromResponse: typeof getSetCookiesFromResponse;
|
|
155
170
|
/**
|
|
156
171
|
* If it is a known error code, try sending the according page (e.g. 404.astro / 500.astro).
|
|
157
|
-
* This also handles pre-rendered /404 or /500 routes
|
|
172
|
+
* This also handles pre-rendered /404 or /500 routes.
|
|
173
|
+
*
|
|
174
|
+
* Delegates to the app's configured `ErrorHandler`. To customize behavior
|
|
175
|
+
* for a specific environment, override `createErrorHandler()` rather than
|
|
176
|
+
* this method.
|
|
158
177
|
*/
|
|
159
|
-
renderError(request: Request,
|
|
160
|
-
private mergeResponses;
|
|
178
|
+
renderError(request: Request, options: RenderErrorOptions): Promise<Response>;
|
|
161
179
|
getDefaultStatusCode(routeData: RouteData, pathname: string): number;
|
|
162
180
|
getManifest(): SSRManifest;
|
|
163
181
|
logThisRequest({ pathname, method, statusCode, isRewrite, timeStart, }: {
|
package/dist/core/app/base.js
CHANGED
|
@@ -1,48 +1,46 @@
|
|
|
1
1
|
import {
|
|
2
2
|
appendForwardSlash,
|
|
3
3
|
collapseDuplicateLeadingSlashes,
|
|
4
|
-
collapseDuplicateTrailingSlashes,
|
|
5
|
-
hasFileExtension,
|
|
6
|
-
isInternalPath,
|
|
7
4
|
joinPaths,
|
|
8
5
|
prependForwardSlash,
|
|
9
6
|
removeTrailingForwardSlash
|
|
10
7
|
} from "@astrojs/internal-helpers/path";
|
|
11
8
|
import { matchPattern } from "@astrojs/internal-helpers/remote";
|
|
12
9
|
import { normalizeTheLocale } from "../../i18n/index.js";
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
NOOP_MIDDLEWARE_HEADER,
|
|
17
|
-
REROUTABLE_STATUS_CODES,
|
|
18
|
-
REROUTE_DIRECTIVE_HEADER,
|
|
19
|
-
responseSentSymbol,
|
|
20
|
-
REWRITE_DIRECTIVE_HEADER_KEY,
|
|
21
|
-
ROUTE_TYPE_HEADER
|
|
22
|
-
} from "../constants.js";
|
|
23
|
-
import {
|
|
24
|
-
AstroCookies,
|
|
25
|
-
attachCookiesToResponse,
|
|
26
|
-
getSetCookiesFromResponse
|
|
27
|
-
} from "../cookies/index.js";
|
|
28
|
-
import { getCookiesFromResponse } from "../cookies/response.js";
|
|
10
|
+
import { PipelineFeatures } from "../base-pipeline.js";
|
|
11
|
+
import { ASTRO_ERROR_HEADER, clientAddressSymbol } from "../constants.js";
|
|
12
|
+
import { getSetCookiesFromResponse } from "../cookies/index.js";
|
|
29
13
|
import { AstroError, AstroErrorData } from "../errors/index.js";
|
|
30
14
|
import { AstroIntegrationLogger } from "../logger/core.js";
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import { matchRoute } from "../routing/match.js";
|
|
36
|
-
import { applyCacheHeaders } from "../cache/runtime/cache.js";
|
|
37
|
-
import { Router } from "../routing/router.js";
|
|
38
|
-
import { PERSIST_SYMBOL } from "../session/runtime.js";
|
|
15
|
+
import { DefaultFetchHandler } from "../fetch/default-handler.js";
|
|
16
|
+
import { appSymbol } from "../constants.js";
|
|
17
|
+
import { DefaultErrorHandler } from "../errors/default-handler.js";
|
|
18
|
+
import { setRenderOptions } from "./render-options.js";
|
|
39
19
|
class BaseApp {
|
|
40
20
|
manifest;
|
|
41
21
|
manifestData;
|
|
42
22
|
pipeline;
|
|
43
23
|
#adapterLogger;
|
|
44
24
|
baseWithoutTrailingSlash;
|
|
45
|
-
|
|
25
|
+
/**
|
|
26
|
+
* The handler that turns incoming `Request` objects into `Response`s.
|
|
27
|
+
* Defaults to a `DefaultFetchHandler` pinned to this app and can be
|
|
28
|
+
* overridden via `setFetchHandler` — typically by the bundled
|
|
29
|
+
* entrypoint after importing `virtual:astro:fetchable`.
|
|
30
|
+
*/
|
|
31
|
+
#fetchHandler;
|
|
32
|
+
#errorHandler;
|
|
33
|
+
/**
|
|
34
|
+
* Whether a custom fetch handler (from `src/app.ts`) has been set
|
|
35
|
+
* via `setFetchHandler`. When false, the `DefaultFetchHandler` is
|
|
36
|
+
* in use and all features are implicitly active.
|
|
37
|
+
*/
|
|
38
|
+
#hasCustomFetchHandler = false;
|
|
39
|
+
/**
|
|
40
|
+
* Whether the missing-feature check has already run. We only want
|
|
41
|
+
* to warn once — after the first request in dev, or at build end.
|
|
42
|
+
*/
|
|
43
|
+
#featureCheckDone = false;
|
|
46
44
|
get logger() {
|
|
47
45
|
return this.pipeline.logger;
|
|
48
46
|
}
|
|
@@ -57,17 +55,27 @@ class BaseApp {
|
|
|
57
55
|
}
|
|
58
56
|
constructor(manifest, streaming = true, ...args) {
|
|
59
57
|
this.manifest = manifest;
|
|
60
|
-
this.manifestData = { routes: manifest.routes.map((route) => route.routeData) };
|
|
61
58
|
this.baseWithoutTrailingSlash = removeTrailingForwardSlash(manifest.base);
|
|
62
59
|
this.pipeline = this.createPipeline(streaming, manifest, ...args);
|
|
63
|
-
|
|
64
|
-
this.#
|
|
60
|
+
this.manifestData = this.pipeline.manifestData;
|
|
61
|
+
this.#fetchHandler = new DefaultFetchHandler(this);
|
|
62
|
+
this.#errorHandler = this.createErrorHandler();
|
|
65
63
|
}
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Override the fetch handler used to dispatch requests. Entrypoints
|
|
66
|
+
* call this with the default export of `virtual:astro:fetchable` to
|
|
67
|
+
* plug in a user-authored handler from `src/app.ts`.
|
|
68
|
+
*/
|
|
69
|
+
setFetchHandler(handler) {
|
|
70
|
+
this.#fetchHandler = handler;
|
|
71
|
+
this.#hasCustomFetchHandler = !(handler instanceof DefaultFetchHandler);
|
|
68
72
|
}
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Returns the error handler strategy used by this app. Override to
|
|
75
|
+
* provide environment-specific behavior (dev overlay, build-time throws, etc.).
|
|
76
|
+
*/
|
|
77
|
+
createErrorHandler() {
|
|
78
|
+
return new DefaultErrorHandler(this);
|
|
71
79
|
}
|
|
72
80
|
/**
|
|
73
81
|
* Resets the cached adapter logger so it picks up a new logger instance.
|
|
@@ -97,7 +105,8 @@ class BaseApp {
|
|
|
97
105
|
}
|
|
98
106
|
set setManifestData(newManifestData) {
|
|
99
107
|
this.manifestData = newManifestData;
|
|
100
|
-
this
|
|
108
|
+
this.pipeline.manifestData = newManifestData;
|
|
109
|
+
this.pipeline.rebuildRouter();
|
|
101
110
|
}
|
|
102
111
|
removeBase(pathname) {
|
|
103
112
|
pathname = collapseDuplicateLeadingSlashes(pathname);
|
|
@@ -107,10 +116,8 @@ class BaseApp {
|
|
|
107
116
|
return pathname;
|
|
108
117
|
}
|
|
109
118
|
/**
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* If the decoding fails, it logs the error and return the pathname as is.
|
|
113
|
-
* @param request
|
|
119
|
+
* Extracts the base-stripped, decoded pathname from a request.
|
|
120
|
+
* Used by adapters to compute the pathname for dev-mode route matching.
|
|
114
121
|
*/
|
|
115
122
|
getPathnameFromRequest(request) {
|
|
116
123
|
const url = new URL(request.url);
|
|
@@ -118,7 +125,7 @@ class BaseApp {
|
|
|
118
125
|
try {
|
|
119
126
|
return decodeURI(pathname);
|
|
120
127
|
} catch (e) {
|
|
121
|
-
this.
|
|
128
|
+
this.adapterLogger.error(e.toString());
|
|
122
129
|
return pathname;
|
|
123
130
|
}
|
|
124
131
|
}
|
|
@@ -137,23 +144,16 @@ class BaseApp {
|
|
|
137
144
|
if (!pathname) {
|
|
138
145
|
pathname = prependForwardSlash(this.removeBase(url.pathname));
|
|
139
146
|
}
|
|
140
|
-
const
|
|
141
|
-
if (
|
|
142
|
-
const routeData = match.route;
|
|
147
|
+
const routeData = this.pipeline.matchRoute(decodeURI(pathname));
|
|
148
|
+
if (!routeData) return void 0;
|
|
143
149
|
if (allowPrerenderedRoutes) {
|
|
144
150
|
return routeData;
|
|
145
|
-
}
|
|
151
|
+
}
|
|
152
|
+
if (routeData.prerender) {
|
|
146
153
|
return void 0;
|
|
147
154
|
}
|
|
148
155
|
return routeData;
|
|
149
156
|
}
|
|
150
|
-
createRouter(manifestData) {
|
|
151
|
-
return new Router(manifestData.routes, {
|
|
152
|
-
base: this.manifest.base,
|
|
153
|
-
trailingSlash: this.manifest.trailingSlash,
|
|
154
|
-
buildFormat: this.manifest.buildFormat
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
157
|
/**
|
|
158
158
|
* A matching route function to use in the development server.
|
|
159
159
|
* Contrary to the `.match` function, this function resolves props and params, returning the correct
|
|
@@ -215,26 +215,6 @@ class BaseApp {
|
|
|
215
215
|
}
|
|
216
216
|
return pathname;
|
|
217
217
|
}
|
|
218
|
-
redirectTrailingSlash(pathname) {
|
|
219
|
-
const { trailingSlash } = this.manifest;
|
|
220
|
-
if (pathname === "/" || isInternalPath(pathname)) {
|
|
221
|
-
return pathname;
|
|
222
|
-
}
|
|
223
|
-
const path = collapseDuplicateTrailingSlashes(pathname, trailingSlash !== "never");
|
|
224
|
-
if (path !== pathname) {
|
|
225
|
-
return path;
|
|
226
|
-
}
|
|
227
|
-
if (trailingSlash === "ignore") {
|
|
228
|
-
return pathname;
|
|
229
|
-
}
|
|
230
|
-
if (trailingSlash === "always" && !hasFileExtension(pathname)) {
|
|
231
|
-
return appendForwardSlash(pathname);
|
|
232
|
-
}
|
|
233
|
-
if (trailingSlash === "never") {
|
|
234
|
-
return removeTrailingForwardSlash(pathname);
|
|
235
|
-
}
|
|
236
|
-
return pathname;
|
|
237
|
-
}
|
|
238
218
|
async render(request, {
|
|
239
219
|
addCookieHeader = false,
|
|
240
220
|
clientAddress = Reflect.get(request, clientAddressSymbol),
|
|
@@ -244,28 +224,6 @@ class BaseApp {
|
|
|
244
224
|
waitUntil
|
|
245
225
|
} = {}) {
|
|
246
226
|
await this.pipeline.getLogger();
|
|
247
|
-
const timeStart = performance.now();
|
|
248
|
-
const url = new URL(request.url);
|
|
249
|
-
const redirect = this.redirectTrailingSlash(url.pathname);
|
|
250
|
-
if (redirect !== url.pathname) {
|
|
251
|
-
const status = request.method === "GET" ? 301 : 308;
|
|
252
|
-
const response2 = new Response(
|
|
253
|
-
redirectTemplate({
|
|
254
|
-
status,
|
|
255
|
-
relativeLocation: url.pathname,
|
|
256
|
-
absoluteLocation: redirect,
|
|
257
|
-
from: request.url
|
|
258
|
-
}),
|
|
259
|
-
{
|
|
260
|
-
status,
|
|
261
|
-
headers: {
|
|
262
|
-
location: redirect + url.search
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
);
|
|
266
|
-
this.#prepareResponse(response2, { addCookieHeader });
|
|
267
|
-
return response2;
|
|
268
|
-
}
|
|
269
227
|
if (routeData) {
|
|
270
228
|
this.logger.debug(
|
|
271
229
|
"router",
|
|
@@ -275,150 +233,64 @@ class BaseApp {
|
|
|
275
233
|
this.logger.debug("router", "RouteData");
|
|
276
234
|
this.logger.debug("router", routeData);
|
|
277
235
|
}
|
|
278
|
-
const resolvedRenderOptions = {
|
|
279
|
-
addCookieHeader,
|
|
280
|
-
clientAddress,
|
|
281
|
-
prerenderedErrorPageFetch,
|
|
282
|
-
locals,
|
|
283
|
-
routeData,
|
|
284
|
-
waitUntil
|
|
285
|
-
};
|
|
286
236
|
if (locals) {
|
|
287
237
|
if (typeof locals !== "object") {
|
|
288
238
|
const error = new AstroError(AstroErrorData.LocalsNotAnObject);
|
|
289
239
|
this.logger.error(null, error.stack);
|
|
290
240
|
return this.renderError(request, {
|
|
291
|
-
|
|
241
|
+
addCookieHeader,
|
|
242
|
+
clientAddress,
|
|
243
|
+
prerenderedErrorPageFetch,
|
|
292
244
|
// If locals are invalid, we don't want to include them when
|
|
293
245
|
// rendering the error page
|
|
294
246
|
locals: void 0,
|
|
247
|
+
routeData,
|
|
248
|
+
waitUntil,
|
|
295
249
|
status: 500,
|
|
296
250
|
error
|
|
297
251
|
});
|
|
298
252
|
}
|
|
299
253
|
}
|
|
300
254
|
if (!routeData) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
routeData = result.routeData;
|
|
305
|
-
}
|
|
306
|
-
} else {
|
|
307
|
-
routeData = this.match(request);
|
|
255
|
+
const domainPathname = this.computePathnameFromDomain(request);
|
|
256
|
+
if (domainPathname) {
|
|
257
|
+
routeData = this.pipeline.matchRoute(decodeURI(domainPathname));
|
|
308
258
|
}
|
|
309
|
-
this.logger.debug("router", "Astro matched the following route for " + request.url);
|
|
310
|
-
this.logger.debug("router", "RouteData:\n" + routeData);
|
|
311
|
-
}
|
|
312
|
-
if (!routeData) {
|
|
313
|
-
routeData = this.manifestData.routes.find(
|
|
314
|
-
(route) => route.component === "404.astro" || route.component === DEFAULT_404_COMPONENT
|
|
315
|
-
);
|
|
316
259
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
}
|
|
325
|
-
let pathname = this.getPathnameFromRequest(request);
|
|
326
|
-
if (this.isDev() && !routeHasHtmlExtension(routeData)) {
|
|
327
|
-
pathname = pathname.replace(/\/index\.html$/, "/").replace(/\.html$/, "");
|
|
328
|
-
}
|
|
329
|
-
const defaultStatus = this.getDefaultStatusCode(routeData, pathname);
|
|
260
|
+
const resolvedOptions = {
|
|
261
|
+
addCookieHeader,
|
|
262
|
+
clientAddress,
|
|
263
|
+
prerenderedErrorPageFetch,
|
|
264
|
+
locals,
|
|
265
|
+
routeData,
|
|
266
|
+
waitUntil
|
|
267
|
+
};
|
|
330
268
|
let response;
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
269
|
+
if (this.#fetchHandler instanceof DefaultFetchHandler) {
|
|
270
|
+
Reflect.set(request, appSymbol, this);
|
|
271
|
+
response = await this.#fetchHandler.renderWithOptions(request, resolvedOptions);
|
|
272
|
+
} else {
|
|
273
|
+
setRenderOptions(request, resolvedOptions);
|
|
274
|
+
Reflect.set(request, appSymbol, this);
|
|
275
|
+
response = await this.#fetchHandler.fetch(request);
|
|
276
|
+
}
|
|
277
|
+
this.#warnMissingFeatures();
|
|
278
|
+
if (response.headers.get(ASTRO_ERROR_HEADER)) {
|
|
279
|
+
response.headers.delete(ASTRO_ERROR_HEADER);
|
|
280
|
+
return this.renderError(request, {
|
|
281
|
+
addCookieHeader,
|
|
282
|
+
clientAddress,
|
|
283
|
+
prerenderedErrorPageFetch,
|
|
337
284
|
locals,
|
|
338
|
-
pathname,
|
|
339
|
-
request,
|
|
340
285
|
routeData,
|
|
341
|
-
|
|
342
|
-
clientAddress
|
|
343
|
-
});
|
|
344
|
-
session = renderContext.session;
|
|
345
|
-
cache = renderContext.cache;
|
|
346
|
-
if (this.pipeline.cacheProvider) {
|
|
347
|
-
const cacheProvider = await this.pipeline.getCacheProvider();
|
|
348
|
-
if (cacheProvider?.onRequest) {
|
|
349
|
-
response = await cacheProvider.onRequest(
|
|
350
|
-
{
|
|
351
|
-
request,
|
|
352
|
-
url: new URL(request.url),
|
|
353
|
-
waitUntil: resolvedRenderOptions.waitUntil
|
|
354
|
-
},
|
|
355
|
-
async () => {
|
|
356
|
-
const res = await renderContext.render(componentInstance);
|
|
357
|
-
applyCacheHeaders(cache, res);
|
|
358
|
-
return res;
|
|
359
|
-
}
|
|
360
|
-
);
|
|
361
|
-
response.headers.delete("CDN-Cache-Control");
|
|
362
|
-
response.headers.delete("Cache-Tag");
|
|
363
|
-
} else {
|
|
364
|
-
response = await renderContext.render(componentInstance);
|
|
365
|
-
applyCacheHeaders(cache, response);
|
|
366
|
-
}
|
|
367
|
-
} else {
|
|
368
|
-
response = await renderContext.render(componentInstance);
|
|
369
|
-
}
|
|
370
|
-
const isRewrite = response.headers.has(REWRITE_DIRECTIVE_HEADER_KEY);
|
|
371
|
-
this.logThisRequest({
|
|
372
|
-
pathname,
|
|
373
|
-
method: request.method,
|
|
374
|
-
statusCode: response.status,
|
|
375
|
-
isRewrite,
|
|
376
|
-
timeStart
|
|
377
|
-
});
|
|
378
|
-
} catch (err) {
|
|
379
|
-
this.logger.error(null, err.stack || err.message || String(err));
|
|
380
|
-
return this.renderError(request, {
|
|
381
|
-
...resolvedRenderOptions,
|
|
382
|
-
status: 500,
|
|
383
|
-
error: err
|
|
384
|
-
});
|
|
385
|
-
} finally {
|
|
386
|
-
await session?.[PERSIST_SYMBOL]();
|
|
387
|
-
}
|
|
388
|
-
if (REROUTABLE_STATUS_CODES.includes(response.status) && // If the body isn't null, that means the user sets the 404 status
|
|
389
|
-
// but uses the current route to handle the 404
|
|
390
|
-
response.body === null && response.headers.get(REROUTE_DIRECTIVE_HEADER) !== "no") {
|
|
391
|
-
return this.renderError(request, {
|
|
392
|
-
...resolvedRenderOptions,
|
|
286
|
+
waitUntil,
|
|
393
287
|
response,
|
|
394
288
|
status: response.status,
|
|
395
|
-
// We don't have an error to report here. Passing null means we pass nothing intentionally
|
|
396
|
-
// while undefined means there's no error
|
|
397
289
|
error: response.status === 500 ? null : void 0
|
|
398
290
|
});
|
|
399
291
|
}
|
|
400
|
-
this.#prepareResponse(response, { addCookieHeader });
|
|
401
292
|
return response;
|
|
402
293
|
}
|
|
403
|
-
#prepareResponse(response, { addCookieHeader }) {
|
|
404
|
-
for (const headerName of [
|
|
405
|
-
REROUTE_DIRECTIVE_HEADER,
|
|
406
|
-
REWRITE_DIRECTIVE_HEADER_KEY,
|
|
407
|
-
NOOP_MIDDLEWARE_HEADER,
|
|
408
|
-
ROUTE_TYPE_HEADER
|
|
409
|
-
]) {
|
|
410
|
-
if (response.headers.has(headerName)) {
|
|
411
|
-
response.headers.delete(headerName);
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
if (addCookieHeader) {
|
|
415
|
-
for (const setCookieHeaderValue of getSetCookiesFromResponse(response)) {
|
|
416
|
-
response.headers.append("set-cookie", setCookieHeaderValue);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
this.logger.flush();
|
|
420
|
-
Reflect.set(response, responseSentSymbol, true);
|
|
421
|
-
}
|
|
422
294
|
setCookieHeaders(response) {
|
|
423
295
|
return getSetCookiesFromResponse(response);
|
|
424
296
|
}
|
|
@@ -436,126 +308,50 @@ class BaseApp {
|
|
|
436
308
|
static getSetCookieFromResponse = getSetCookiesFromResponse;
|
|
437
309
|
/**
|
|
438
310
|
* If it is a known error code, try sending the according page (e.g. 404.astro / 500.astro).
|
|
439
|
-
* This also handles pre-rendered /404 or /500 routes
|
|
311
|
+
* This also handles pre-rendered /404 or /500 routes.
|
|
312
|
+
*
|
|
313
|
+
* Delegates to the app's configured `ErrorHandler`. To customize behavior
|
|
314
|
+
* for a specific environment, override `createErrorHandler()` rather than
|
|
315
|
+
* this method.
|
|
440
316
|
*/
|
|
441
|
-
async renderError(request, {
|
|
442
|
-
|
|
443
|
-
response: originalResponse,
|
|
444
|
-
skipMiddleware = false,
|
|
445
|
-
error,
|
|
446
|
-
...resolvedRenderOptions
|
|
447
|
-
}) {
|
|
448
|
-
const errorRoutePath = `/${status}${this.manifest.trailingSlash === "always" ? "/" : ""}`;
|
|
449
|
-
const errorRouteData = matchRoute(errorRoutePath, this.manifestData);
|
|
450
|
-
const url = new URL(request.url);
|
|
451
|
-
if (errorRouteData) {
|
|
452
|
-
if (errorRouteData.prerender) {
|
|
453
|
-
const maybeDotHtml = errorRouteData.route.endsWith(`/${status}`) ? ".html" : "";
|
|
454
|
-
const statusURL = new URL(`${this.baseWithoutTrailingSlash}/${status}${maybeDotHtml}`, url);
|
|
455
|
-
if (statusURL.toString() !== request.url && resolvedRenderOptions.prerenderedErrorPageFetch) {
|
|
456
|
-
const response2 = await resolvedRenderOptions.prerenderedErrorPageFetch(
|
|
457
|
-
statusURL.toString()
|
|
458
|
-
);
|
|
459
|
-
const override = { status, removeContentEncodingHeaders: true };
|
|
460
|
-
const newResponse = this.mergeResponses(response2, originalResponse, override);
|
|
461
|
-
this.#prepareResponse(newResponse, resolvedRenderOptions);
|
|
462
|
-
return newResponse;
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
const mod = await this.pipeline.getComponentByRoute(errorRouteData);
|
|
466
|
-
let session;
|
|
467
|
-
try {
|
|
468
|
-
const renderContext = await this.createRenderContext({
|
|
469
|
-
locals: resolvedRenderOptions.locals,
|
|
470
|
-
pipeline: this.pipeline,
|
|
471
|
-
skipMiddleware,
|
|
472
|
-
pathname: this.getPathnameFromRequest(request),
|
|
473
|
-
request,
|
|
474
|
-
routeData: errorRouteData,
|
|
475
|
-
status,
|
|
476
|
-
props: { error },
|
|
477
|
-
clientAddress: resolvedRenderOptions.clientAddress
|
|
478
|
-
});
|
|
479
|
-
session = renderContext.session;
|
|
480
|
-
const response2 = await renderContext.render(mod);
|
|
481
|
-
const newResponse = this.mergeResponses(response2, originalResponse);
|
|
482
|
-
this.#prepareResponse(newResponse, resolvedRenderOptions);
|
|
483
|
-
return newResponse;
|
|
484
|
-
} catch {
|
|
485
|
-
if (skipMiddleware === false) {
|
|
486
|
-
return this.renderError(request, {
|
|
487
|
-
...resolvedRenderOptions,
|
|
488
|
-
status,
|
|
489
|
-
response: originalResponse,
|
|
490
|
-
skipMiddleware: true
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
|
-
} finally {
|
|
494
|
-
await session?.[PERSIST_SYMBOL]();
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
const response = this.mergeResponses(new Response(null, { status }), originalResponse);
|
|
498
|
-
this.#prepareResponse(response, resolvedRenderOptions);
|
|
499
|
-
return response;
|
|
317
|
+
async renderError(request, options) {
|
|
318
|
+
return this.#errorHandler.renderError(request, options);
|
|
500
319
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
320
|
+
/**
|
|
321
|
+
* One-shot check: after the first request with a custom `src/app.ts`,
|
|
322
|
+
* compare `usedFeatures` against the manifest and warn about any
|
|
323
|
+
* configured features the user's pipeline doesn't call.
|
|
324
|
+
*/
|
|
325
|
+
#warnMissingFeatures() {
|
|
326
|
+
if (this.#featureCheckDone || !this.#hasCustomFetchHandler) return;
|
|
327
|
+
this.#featureCheckDone = true;
|
|
328
|
+
const manifest = this.manifest;
|
|
329
|
+
const missing = [];
|
|
330
|
+
const used = this.pipeline.usedFeatures;
|
|
331
|
+
if (manifest.routes.some((r) => r.routeData.type === "redirect") && !(used & PipelineFeatures.redirects)) {
|
|
332
|
+
missing.push("redirects");
|
|
507
333
|
}
|
|
508
|
-
if (!
|
|
509
|
-
|
|
510
|
-
return new Response(newResponse.body, {
|
|
511
|
-
status: override.status,
|
|
512
|
-
statusText: newResponse.statusText,
|
|
513
|
-
headers: newResponseHeaders
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
return newResponse;
|
|
334
|
+
if (manifest.sessionConfig && !(used & PipelineFeatures.sessions)) {
|
|
335
|
+
missing.push("sessions");
|
|
517
336
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
originalResponse.headers.delete("Content-type");
|
|
521
|
-
originalResponse.headers.delete("Content-Length");
|
|
522
|
-
originalResponse.headers.delete("Transfer-Encoding");
|
|
523
|
-
} catch {
|
|
337
|
+
if (manifest.actions && !(used & PipelineFeatures.actions)) {
|
|
338
|
+
missing.push("actions");
|
|
524
339
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
for (const [name, value] of originalResponse.headers) {
|
|
528
|
-
newHeaders.append(name, value);
|
|
529
|
-
seen.add(name.toLowerCase());
|
|
340
|
+
if (manifest.middleware && !(used & PipelineFeatures.middleware)) {
|
|
341
|
+
missing.push("middleware");
|
|
530
342
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
newHeaders.append(name, value);
|
|
534
|
-
}
|
|
343
|
+
if (manifest.i18n && manifest.i18n.strategy !== "manual" && !(used & PipelineFeatures.i18n)) {
|
|
344
|
+
missing.push("i18n");
|
|
535
345
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
headers: newHeaders
|
|
545
|
-
});
|
|
546
|
-
const originalCookies = getCookiesFromResponse(originalResponse);
|
|
547
|
-
const newCookies = getCookiesFromResponse(newResponse);
|
|
548
|
-
if (originalCookies) {
|
|
549
|
-
if (newCookies) {
|
|
550
|
-
for (const cookieValue of AstroCookies.consume(newCookies)) {
|
|
551
|
-
originalResponse.headers.append("set-cookie", cookieValue);
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
attachCookiesToResponse(mergedResponse, originalCookies);
|
|
555
|
-
} else if (newCookies) {
|
|
556
|
-
attachCookiesToResponse(mergedResponse, newCookies);
|
|
346
|
+
if (manifest.cacheConfig && !(used & PipelineFeatures.cache)) {
|
|
347
|
+
missing.push("cache");
|
|
348
|
+
}
|
|
349
|
+
for (const feature of missing) {
|
|
350
|
+
this.logger.warn(
|
|
351
|
+
"router",
|
|
352
|
+
`Your project uses ${feature}, but your custom src/app.ts does not call the ${feature}() handler. This feature will not work unless you add it to your app.ts pipeline.`
|
|
353
|
+
);
|
|
557
354
|
}
|
|
558
|
-
return mergedResponse;
|
|
559
355
|
}
|
|
560
356
|
getDefaultStatusCode(routeData, pathname) {
|
|
561
357
|
if (!routeData.pattern.test(pathname)) {
|