astro 7.0.0-beta.4 → 7.0.0-beta.6
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/cli/infra/build-time-astro-version-provider.js +1 -1
- package/dist/content/content-layer.js +3 -3
- package/dist/core/app/prepare-response.d.ts +2 -3
- package/dist/core/app/prepare-response.js +1 -6
- package/dist/core/build/generate.js +1 -1
- package/dist/core/build/plugins/plugin-manifest.js +1 -4
- package/dist/core/build/vite-build-config.js +6 -0
- package/dist/core/cache/config.d.ts +7 -6
- package/dist/core/cache/runtime/noop.js +1 -1
- package/dist/core/cache/utils.d.ts +3 -3
- package/dist/core/cache/vite-plugin.js +1 -1
- package/dist/core/config/schemas/base.d.ts +13 -13
- package/dist/core/config/schemas/base.js +4 -4
- package/dist/core/config/schemas/relative.d.ts +36 -36
- package/dist/core/constants.d.ts +0 -41
- package/dist/core/constants.js +1 -18
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/errors/default-handler.js +1 -0
- package/dist/core/errors/errors-data.js +2 -2
- package/dist/core/fetch/fetch-state.d.ts +11 -0
- package/dist/core/fetch/fetch-state.js +19 -1
- package/dist/core/fetch/index.d.ts +8 -3
- package/dist/core/fetch/index.js +2 -2
- package/dist/core/i18n/handler.js +7 -13
- package/dist/core/messages/runtime.js +1 -1
- package/dist/core/middleware/astro-middleware.d.ts +19 -0
- package/dist/core/middleware/astro-middleware.js +43 -0
- package/dist/core/middleware/noop-middleware.js +0 -2
- package/dist/core/pages/handler.d.ts +13 -0
- package/dist/core/pages/handler.js +35 -14
- package/dist/core/routing/handler.js +6 -8
- package/dist/core/routing/rewrite.js +2 -1
- package/dist/core/util/pathname.d.ts +17 -16
- package/dist/core/util/pathname.js +6 -2
- package/dist/i18n/index.js +5 -7
- package/dist/manifest/serialized.js +2 -5
- package/dist/runtime/server/endpoint.d.ts +2 -1
- package/dist/runtime/server/endpoint.js +4 -13
- package/dist/types/public/config.d.ts +85 -83
- package/dist/virtual-modules/container.d.ts +1 -1
- package/dist/vite-plugin-config-alias/index.d.ts +2 -2
- package/dist/vite-plugin-config-alias/index.js +66 -61
- package/dist/vite-plugin-head/index.js +5 -11
- package/package.json +6 -6
- package/templates/content/module.mjs +0 -1
- package/dist/core/head-propagation/hint.d.ts +0 -4
- package/dist/core/head-propagation/hint.js +0 -7
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { FetchState } from '../fetch/fetch-state.js';
|
|
2
2
|
import type { APIContext } from '../../types/public/context.js';
|
|
3
|
+
import type { BaseApp } from '../app/base.js';
|
|
3
4
|
import { type Pipeline } from '../base-pipeline.js';
|
|
4
5
|
/**
|
|
5
6
|
* Callback invoked at the bottom of the middleware chain to dispatch the
|
|
@@ -24,4 +25,22 @@ export declare class AstroMiddleware {
|
|
|
24
25
|
#private;
|
|
25
26
|
constructor(pipeline: Pipeline);
|
|
26
27
|
handle(state: FetchState, renderRouteCallback: RenderRouteCallback): Promise<Response>;
|
|
28
|
+
/**
|
|
29
|
+
* Like `handle`, but mirrors the app-level error handling that
|
|
30
|
+
* `AstroHandler` provides on the standard path, the same way
|
|
31
|
+
* `PagesHandler.handleWithErrorFallback` does for `pages()`. When no
|
|
32
|
+
* route matched it returns a 404 marked with `X-Astro-Error` for the
|
|
33
|
+
* app's post-check; when Astro's own middleware chain throws it logs the
|
|
34
|
+
* error and renders the custom `500.astro`.
|
|
35
|
+
*
|
|
36
|
+
* Errors surfaced through `renderRouteCallback` (the host framework's
|
|
37
|
+
* `next`, e.g. host middleware mounted below `middleware()`) are
|
|
38
|
+
* re-thrown instead, so the host's own error handling still runs rather
|
|
39
|
+
* than being swallowed into Astro's 500 page. A sentinel tells the two
|
|
40
|
+
* apart.
|
|
41
|
+
*
|
|
42
|
+
* Used by the composable `astro/fetch` `middleware()` entry point, where
|
|
43
|
+
* there is no surrounding `AstroHandler` to supply this fallback.
|
|
44
|
+
*/
|
|
45
|
+
handleWithErrorFallback(app: BaseApp<Pipeline>, state: FetchState, renderRouteCallback: RenderRouteCallback): Promise<Response>;
|
|
27
46
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PipelineFeatures } from "../base-pipeline.js";
|
|
2
|
+
import { ASTRO_ERROR_HEADER } from "../constants.js";
|
|
2
3
|
import { attachCookiesToResponse } from "../cookies/index.js";
|
|
3
4
|
import { applyRewriteToState } from "../rewrites/handler.js";
|
|
4
5
|
import { callMiddleware } from "./callMiddleware.js";
|
|
@@ -41,6 +42,48 @@ class AstroMiddleware {
|
|
|
41
42
|
state.response = response;
|
|
42
43
|
return response;
|
|
43
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Like `handle`, but mirrors the app-level error handling that
|
|
47
|
+
* `AstroHandler` provides on the standard path, the same way
|
|
48
|
+
* `PagesHandler.handleWithErrorFallback` does for `pages()`. When no
|
|
49
|
+
* route matched it returns a 404 marked with `X-Astro-Error` for the
|
|
50
|
+
* app's post-check; when Astro's own middleware chain throws it logs the
|
|
51
|
+
* error and renders the custom `500.astro`.
|
|
52
|
+
*
|
|
53
|
+
* Errors surfaced through `renderRouteCallback` (the host framework's
|
|
54
|
+
* `next`, e.g. host middleware mounted below `middleware()`) are
|
|
55
|
+
* re-thrown instead, so the host's own error handling still runs rather
|
|
56
|
+
* than being swallowed into Astro's 500 page. A sentinel tells the two
|
|
57
|
+
* apart.
|
|
58
|
+
*
|
|
59
|
+
* Used by the composable `astro/fetch` `middleware()` entry point, where
|
|
60
|
+
* there is no surrounding `AstroHandler` to supply this fallback.
|
|
61
|
+
*/
|
|
62
|
+
async handleWithErrorFallback(app, state, renderRouteCallback) {
|
|
63
|
+
if (!state.routeData) {
|
|
64
|
+
return new Response(null, { status: 404, headers: { [ASTRO_ERROR_HEADER]: "true" } });
|
|
65
|
+
}
|
|
66
|
+
let nextError;
|
|
67
|
+
try {
|
|
68
|
+
return await this.handle(state, async (s, ctx) => {
|
|
69
|
+
try {
|
|
70
|
+
return await renderRouteCallback(s, ctx);
|
|
71
|
+
} catch (err) {
|
|
72
|
+
nextError = err;
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
} catch (err) {
|
|
77
|
+
if (err === nextError) throw err;
|
|
78
|
+
app.logger.error(null, err.stack || err.message || String(err));
|
|
79
|
+
return app.renderError(state.request, {
|
|
80
|
+
...state.renderOptions,
|
|
81
|
+
status: 500,
|
|
82
|
+
error: err,
|
|
83
|
+
pathname: state.pathname
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
44
87
|
#finalize(state, response) {
|
|
45
88
|
attachCookiesToResponse(response, state.cookies);
|
|
46
89
|
return response;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { APIContext } from '../../types/public/context.js';
|
|
2
|
+
import type { BaseApp } from '../app/base.js';
|
|
2
3
|
import type { FetchState } from '../fetch/fetch-state.js';
|
|
3
4
|
import type { Pipeline } from '../base-pipeline.js';
|
|
4
5
|
/**
|
|
@@ -17,4 +18,16 @@ export declare class PagesHandler {
|
|
|
17
18
|
#private;
|
|
18
19
|
constructor(pipeline: Pipeline);
|
|
19
20
|
handle(state: FetchState, ctx: APIContext): Promise<Response>;
|
|
21
|
+
/**
|
|
22
|
+
* Like `handle`, but mirrors the app-level error handling that
|
|
23
|
+
* `AstroHandler` provides on the standard path: unmatched routes
|
|
24
|
+
* return a 404 marked with `X-Astro-Error` for the app's post-check
|
|
25
|
+
* to render the 404 error page, and render-time errors are logged
|
|
26
|
+
* and render the 500 error page instead of propagating to the host
|
|
27
|
+
* framework.
|
|
28
|
+
*
|
|
29
|
+
* Used by the composable `astro/fetch` `pages()` entry point, where
|
|
30
|
+
* there is no surrounding `AstroHandler` to supply this fallback.
|
|
31
|
+
*/
|
|
32
|
+
handleWithErrorFallback(app: BaseApp<Pipeline>, state: FetchState): Promise<Response>;
|
|
20
33
|
}
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import { renderEndpoint } from "../../runtime/server/endpoint.js";
|
|
2
2
|
import { renderPage } from "../../runtime/server/index.js";
|
|
3
|
-
import {
|
|
4
|
-
ASTRO_ERROR_HEADER,
|
|
5
|
-
REROUTE_DIRECTIVE_HEADER,
|
|
6
|
-
REWRITE_DIRECTIVE_HEADER_KEY,
|
|
7
|
-
REWRITE_DIRECTIVE_HEADER_VALUE,
|
|
8
|
-
ROUTE_TYPE_HEADER
|
|
9
|
-
} from "../constants.js";
|
|
3
|
+
import { ASTRO_ERROR_HEADER } from "../constants.js";
|
|
10
4
|
import { getCookiesFromResponse } from "../cookies/response.js";
|
|
11
5
|
const EMPTY_SLOTS = Object.freeze({});
|
|
12
6
|
class PagesHandler {
|
|
@@ -17,6 +11,7 @@ class PagesHandler {
|
|
|
17
11
|
async handle(state, ctx) {
|
|
18
12
|
const pipeline = this.#pipeline;
|
|
19
13
|
const { logger, streaming } = pipeline;
|
|
14
|
+
state.resetResponseMetadata();
|
|
20
15
|
let response;
|
|
21
16
|
const componentInstance = await state.loadComponentInstance();
|
|
22
17
|
switch (state.routeData.type) {
|
|
@@ -25,7 +20,8 @@ class PagesHandler {
|
|
|
25
20
|
componentInstance,
|
|
26
21
|
ctx,
|
|
27
22
|
state.routeData.prerender,
|
|
28
|
-
logger
|
|
23
|
+
logger,
|
|
24
|
+
state
|
|
29
25
|
);
|
|
30
26
|
break;
|
|
31
27
|
}
|
|
@@ -46,12 +42,9 @@ class PagesHandler {
|
|
|
46
42
|
result.cancelled = true;
|
|
47
43
|
throw e;
|
|
48
44
|
}
|
|
49
|
-
|
|
45
|
+
state.responseRouteType = "page";
|
|
50
46
|
if (state.routeData.route === "/404" || state.routeData.route === "/500") {
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
if (state.isRewriting) {
|
|
54
|
-
response.headers.set(REWRITE_DIRECTIVE_HEADER_KEY, REWRITE_DIRECTIVE_HEADER_VALUE);
|
|
47
|
+
state.skipErrorReroute = true;
|
|
55
48
|
}
|
|
56
49
|
break;
|
|
57
50
|
}
|
|
@@ -59,7 +52,8 @@ class PagesHandler {
|
|
|
59
52
|
return new Response(null, { status: 404, headers: { [ASTRO_ERROR_HEADER]: "true" } });
|
|
60
53
|
}
|
|
61
54
|
case "fallback": {
|
|
62
|
-
|
|
55
|
+
state.responseRouteType = "fallback";
|
|
56
|
+
return new Response(null, { status: 500 });
|
|
63
57
|
}
|
|
64
58
|
}
|
|
65
59
|
const responseCookies = getCookiesFromResponse(response);
|
|
@@ -69,6 +63,33 @@ class PagesHandler {
|
|
|
69
63
|
state.response = response;
|
|
70
64
|
return response;
|
|
71
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Like `handle`, but mirrors the app-level error handling that
|
|
68
|
+
* `AstroHandler` provides on the standard path: unmatched routes
|
|
69
|
+
* return a 404 marked with `X-Astro-Error` for the app's post-check
|
|
70
|
+
* to render the 404 error page, and render-time errors are logged
|
|
71
|
+
* and render the 500 error page instead of propagating to the host
|
|
72
|
+
* framework.
|
|
73
|
+
*
|
|
74
|
+
* Used by the composable `astro/fetch` `pages()` entry point, where
|
|
75
|
+
* there is no surrounding `AstroHandler` to supply this fallback.
|
|
76
|
+
*/
|
|
77
|
+
async handleWithErrorFallback(app, state) {
|
|
78
|
+
if (!state.routeData) {
|
|
79
|
+
return new Response(null, { status: 404, headers: { [ASTRO_ERROR_HEADER]: "true" } });
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
return await this.handle(state, state.getAPIContext());
|
|
83
|
+
} catch (err) {
|
|
84
|
+
app.logger.error(null, err.stack || err.message || String(err));
|
|
85
|
+
return app.renderError(state.request, {
|
|
86
|
+
...state.renderOptions,
|
|
87
|
+
status: 500,
|
|
88
|
+
error: err,
|
|
89
|
+
pathname: state.pathname
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
72
93
|
}
|
|
73
94
|
export {
|
|
74
95
|
PagesHandler
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { ActionHandler } from "../../actions/handler.js";
|
|
2
|
-
import {
|
|
3
|
-
REROUTABLE_STATUS_CODES,
|
|
4
|
-
REROUTE_DIRECTIVE_HEADER,
|
|
5
|
-
REWRITE_DIRECTIVE_HEADER_KEY
|
|
6
|
-
} from "../constants.js";
|
|
2
|
+
import { REROUTABLE_STATUS_CODES } from "../constants.js";
|
|
7
3
|
import { TrailingSlashHandler } from "./trailing-slash-handler.js";
|
|
8
4
|
import { CacheHandler, provideCache } from "../cache/handler.js";
|
|
9
5
|
import { I18n } from "../i18n/handler.js";
|
|
@@ -65,6 +61,9 @@ class AstroHandler {
|
|
|
65
61
|
}
|
|
66
62
|
async handle(state) {
|
|
67
63
|
state.pipeline.usedFeatures |= ALL_PIPELINE_FEATURES;
|
|
64
|
+
if (state.invalidEncoding) {
|
|
65
|
+
return new Response(null, { status: 400, statusText: "Bad Request" });
|
|
66
|
+
}
|
|
68
67
|
const trailingSlashRedirect = this.#trailingSlashHandler.handle(state);
|
|
69
68
|
if (trailingSlashRedirect) {
|
|
70
69
|
return trailingSlashRedirect;
|
|
@@ -128,12 +127,11 @@ class AstroHandler {
|
|
|
128
127
|
};
|
|
129
128
|
response = await this.#cacheHandler.handle(state, runPipeline);
|
|
130
129
|
}
|
|
131
|
-
const isRewrite = response.headers.has(REWRITE_DIRECTIVE_HEADER_KEY);
|
|
132
130
|
this.#app.logThisRequest({
|
|
133
131
|
pathname,
|
|
134
132
|
method: request.method,
|
|
135
133
|
statusCode: response.status,
|
|
136
|
-
isRewrite,
|
|
134
|
+
isRewrite: state.isRewriting,
|
|
137
135
|
timeStart: state.timeStart
|
|
138
136
|
});
|
|
139
137
|
} catch (err) {
|
|
@@ -150,7 +148,7 @@ class AstroHandler {
|
|
|
150
148
|
}
|
|
151
149
|
if (REROUTABLE_STATUS_CODES.includes(response.status) && // If the body isn't null, that means the user sets the 404 status
|
|
152
150
|
// but uses the current route to handle the 404
|
|
153
|
-
response.body === null &&
|
|
151
|
+
response.body === null && !state.skipErrorReroute) {
|
|
154
152
|
return this.#app.renderError(request, {
|
|
155
153
|
...state.renderOptions,
|
|
156
154
|
response,
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
trimSlashes
|
|
11
11
|
} from "../path.js";
|
|
12
12
|
import { createRequest } from "../request.js";
|
|
13
|
+
import { validateAndDecodePathname } from "../util/pathname.js";
|
|
13
14
|
import { DEFAULT_404_ROUTE } from "./internal/astro-designed-error-pages.js";
|
|
14
15
|
import { isRoute404, isRoute500 } from "./internal/route-errors.js";
|
|
15
16
|
function findRouteToRewrite({
|
|
@@ -36,7 +37,7 @@ function findRouteToRewrite({
|
|
|
36
37
|
buildFormat
|
|
37
38
|
);
|
|
38
39
|
newUrl.pathname = resolvedUrlPathname;
|
|
39
|
-
const decodedPathname =
|
|
40
|
+
const decodedPathname = validateAndDecodePathname(pathname);
|
|
40
41
|
if (isRoute404(decodedPathname)) {
|
|
41
42
|
const errorRoute = routes.find((route) => route.route === "/404");
|
|
42
43
|
if (errorRoute) {
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* decoded iteratively instead of rejected. Kept for backwards compatibility
|
|
8
|
-
* in case third-party code references the class.
|
|
2
|
+
* Thrown when a URL path is encoded so many times that we give up decoding it
|
|
3
|
+
* (see {@link validateAndDecodePathname}). When this happens we reject the
|
|
4
|
+
* request with a `400` instead of guessing the path. If we let a half-decoded
|
|
5
|
+
* path through, your middleware might check one path while Astro routes to a
|
|
6
|
+
* different one.
|
|
9
7
|
*/
|
|
10
8
|
export declare class MultiLevelEncodingError extends Error {
|
|
11
9
|
constructor();
|
|
12
10
|
}
|
|
13
11
|
/**
|
|
14
|
-
* Decodes a
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* fully resolve it so middleware always sees the true decoded path.
|
|
12
|
+
* Decodes a URL path over and over until it stops changing, so a path that was
|
|
13
|
+
* encoded several times ends up as a single, final path. This stops someone
|
|
14
|
+
* from sneaking a path like `/admin` past middleware by encoding it multiple
|
|
15
|
+
* times — middleware always sees the real, decoded path.
|
|
19
16
|
*
|
|
20
|
-
* @param pathname - The
|
|
21
|
-
* @returns The fully decoded
|
|
22
|
-
* @throws Error if the
|
|
23
|
-
*
|
|
17
|
+
* @param pathname - The path to decode
|
|
18
|
+
* @returns The final, fully decoded path
|
|
19
|
+
* @throws Error if the path has broken encoding that can't be decoded at all
|
|
20
|
+
* (for example a lone `%` that isn't followed by two hex digits)
|
|
21
|
+
* @throws MultiLevelEncodingError if the path is still changing after
|
|
22
|
+
* {@link MAX_DECODE_ITERATIONS} tries (it was encoded too many times).
|
|
23
|
+
* Handing back a half-decoded path here would bring back the security hole
|
|
24
|
+
* this function exists to close.
|
|
24
25
|
*/
|
|
25
26
|
export declare function validateAndDecodePathname(pathname: string): string;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
class MultiLevelEncodingError extends Error {
|
|
2
2
|
constructor() {
|
|
3
|
-
super("
|
|
3
|
+
super("URL encoding depth exceeded the maximum number of decode iterations");
|
|
4
4
|
this.name = "MultiLevelEncodingError";
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
|
+
const MAX_DECODE_ITERATIONS = 10;
|
|
7
8
|
function validateAndDecodePathname(pathname) {
|
|
8
9
|
let decoded;
|
|
9
10
|
try {
|
|
@@ -12,7 +13,10 @@ function validateAndDecodePathname(pathname) {
|
|
|
12
13
|
throw new Error("Invalid URL encoding");
|
|
13
14
|
}
|
|
14
15
|
let iterations = 0;
|
|
15
|
-
while (decoded !== pathname
|
|
16
|
+
while (decoded !== pathname) {
|
|
17
|
+
if (iterations >= MAX_DECODE_ITERATIONS) {
|
|
18
|
+
throw new MultiLevelEncodingError();
|
|
19
|
+
}
|
|
16
20
|
pathname = decoded;
|
|
17
21
|
try {
|
|
18
22
|
decoded = decodeURI(pathname);
|
package/dist/i18n/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
removeTrailingForwardSlash
|
|
5
5
|
} from "@astrojs/internal-helpers/path";
|
|
6
6
|
import { shouldAppendForwardSlash } from "../core/build/util.js";
|
|
7
|
-
import {
|
|
7
|
+
import { getFetchStateFromAPIContext } from "../core/fetch/fetch-state.js";
|
|
8
8
|
import { i18nNoLocaleFoundInPath, MissingLocale } from "../core/errors/errors-data.js";
|
|
9
9
|
import { AstroError } from "../core/errors/index.js";
|
|
10
10
|
import { createI18nMiddleware } from "./middleware.js";
|
|
@@ -200,24 +200,22 @@ function redirectToDefaultLocale({
|
|
|
200
200
|
}
|
|
201
201
|
function notFound({ base, locales, fallback }) {
|
|
202
202
|
return function(context, response) {
|
|
203
|
-
|
|
203
|
+
const fetchState = getFetchStateFromAPIContext(context);
|
|
204
|
+
if (fetchState.skipErrorReroute && typeof fallback === "undefined") {
|
|
204
205
|
return response;
|
|
205
206
|
}
|
|
206
207
|
const url = context.url;
|
|
207
208
|
const isRoot = url.pathname === base + "/" || url.pathname === base;
|
|
208
209
|
if (!(isRoot || pathHasLocale(url.pathname, locales))) {
|
|
210
|
+
fetchState.skipErrorReroute = true;
|
|
209
211
|
if (response) {
|
|
210
|
-
response.headers.set(REROUTE_DIRECTIVE_HEADER, "no");
|
|
211
212
|
return new Response(response.body, {
|
|
212
213
|
status: 404,
|
|
213
214
|
headers: response.headers
|
|
214
215
|
});
|
|
215
216
|
} else {
|
|
216
217
|
return new Response(null, {
|
|
217
|
-
status: 404
|
|
218
|
-
headers: {
|
|
219
|
-
[REROUTE_DIRECTIVE_HEADER]: "no"
|
|
220
|
-
}
|
|
218
|
+
status: 404
|
|
221
219
|
});
|
|
222
220
|
}
|
|
223
221
|
}
|
|
@@ -83,7 +83,7 @@ function serializedManifestPlugin({
|
|
|
83
83
|
const serialized = await createSerializedManifest(settings, await getEncodedKey());
|
|
84
84
|
manifestData = JSON.stringify(serialized);
|
|
85
85
|
}
|
|
86
|
-
const hasCacheConfig = !!settings.config.
|
|
86
|
+
const hasCacheConfig = !!settings.config.cache?.provider;
|
|
87
87
|
const cacheProviderLine = hasCacheConfig ? `cacheProvider: () => import('${VIRTUAL_CACHE_PROVIDER_ID}'),` : "";
|
|
88
88
|
const code = `
|
|
89
89
|
import { deserializeManifest as _deserializeManifest } from 'astro/app';
|
|
@@ -181,10 +181,7 @@ async function createSerializedManifest(settings, encodedKey) {
|
|
|
181
181
|
// 1mb default
|
|
182
182
|
key: encodedKey ?? await encodeKey(hasEnvironmentKey() ? await getEnvironmentKey() : await createKey()),
|
|
183
183
|
sessionConfig: sessionConfigToManifest(settings.config.session),
|
|
184
|
-
cacheConfig: cacheConfigToManifest(
|
|
185
|
-
settings.config.experimental?.cache,
|
|
186
|
-
settings.config.experimental?.routeRules
|
|
187
|
-
),
|
|
184
|
+
cacheConfig: cacheConfigToManifest(settings.config.cache, settings.config.routeRules),
|
|
188
185
|
csp,
|
|
189
186
|
image: {
|
|
190
187
|
objectFit: settings.config.image.objectFit,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type { FetchState } from '../../core/fetch/fetch-state.js';
|
|
1
2
|
import type { AstroLogger } from '../../core/logger/core.js';
|
|
2
3
|
import type { APIRoute } from '../../types/public/common.js';
|
|
3
4
|
import type { APIContext } from '../../types/public/context.js';
|
|
4
5
|
/** Renders an endpoint request to completion, returning the body. */
|
|
5
6
|
export declare function renderEndpoint(mod: {
|
|
6
7
|
[method: string]: APIRoute;
|
|
7
|
-
}, context: APIContext, isPrerendered: boolean, logger: AstroLogger): Promise<Response>;
|
|
8
|
+
}, context: APIContext, isPrerendered: boolean, logger: AstroLogger, state?: FetchState): Promise<Response>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import colors from "piccolore";
|
|
2
|
-
import { REROUTABLE_STATUS_CODES
|
|
2
|
+
import { REROUTABLE_STATUS_CODES } from "../../core/constants.js";
|
|
3
3
|
import { AstroError } from "../../core/errors/errors.js";
|
|
4
4
|
import { EndpointDidNotReturnAResponse } from "../../core/errors/errors-data.js";
|
|
5
|
-
async function renderEndpoint(mod, context, isPrerendered, logger) {
|
|
5
|
+
async function renderEndpoint(mod, context, isPrerendered, logger, state) {
|
|
6
6
|
const { request, url } = context;
|
|
7
7
|
const method = request.method.toUpperCase();
|
|
8
8
|
let handler = mod[method] ?? mod["ALL"];
|
|
@@ -38,17 +38,8 @@ Found handlers: ${Object.keys(mod).map((exp) => JSON.stringify(exp)).join(", ")}
|
|
|
38
38
|
if (!response || response instanceof Response === false) {
|
|
39
39
|
throw new AstroError(EndpointDidNotReturnAResponse);
|
|
40
40
|
}
|
|
41
|
-
if (REROUTABLE_STATUS_CODES.includes(response.status)) {
|
|
42
|
-
|
|
43
|
-
response.headers.set(REROUTE_DIRECTIVE_HEADER, "no");
|
|
44
|
-
} catch (err) {
|
|
45
|
-
if (err.message?.includes("immutable")) {
|
|
46
|
-
response = new Response(response.body, response);
|
|
47
|
-
response.headers.set(REROUTE_DIRECTIVE_HEADER, "no");
|
|
48
|
-
} else {
|
|
49
|
-
throw err;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
41
|
+
if (state && REROUTABLE_STATUS_CODES.includes(response.status)) {
|
|
42
|
+
state.skipErrorReroute = true;
|
|
52
43
|
}
|
|
53
44
|
if (method === "HEAD") {
|
|
54
45
|
return new Response(null, response);
|
|
@@ -420,22 +420,22 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
|
|
|
420
420
|
* @docs
|
|
421
421
|
* @name compressHTML
|
|
422
422
|
* @type {boolean | "jsx"}
|
|
423
|
-
* @default `
|
|
423
|
+
* @default `'jsx'`
|
|
424
424
|
* @description
|
|
425
425
|
*
|
|
426
426
|
* Controls how Astro handles whitespace in your HTML. This affects both development mode and the final build output.
|
|
427
427
|
*
|
|
428
|
-
*
|
|
428
|
+
* Since v7.0, Astro applies by default the JSX whitespace rules used by frameworks like React. This removes whitespace and line breaks around elements, collapses multi-line text onto a single line, and preserves whitespace within a single line (e.g. a space between two inline elements). To keep a space that would otherwise be removed, include it explicitly in the source through constructs such as `{" "}`.
|
|
429
429
|
*
|
|
430
|
-
*
|
|
430
|
+
* Setting this option to `true` instead removes whitespace, including line breaks, in a lossless manner from `.astro` components. Some whitespace may be preserved as needed to maintain the visual rendering of your HTML.
|
|
431
431
|
*
|
|
432
|
-
* Setting this option to false disables HTML compression and preserves all whitespace.
|
|
432
|
+
* Setting this option to `false` disables HTML compression and preserves all whitespace.
|
|
433
433
|
*
|
|
434
434
|
* ```js
|
|
435
435
|
* {
|
|
436
|
-
* compressHTML:
|
|
436
|
+
* compressHTML: true
|
|
437
437
|
* // or:
|
|
438
|
-
* // compressHTML:
|
|
438
|
+
* // compressHTML: false
|
|
439
439
|
* }
|
|
440
440
|
* ```
|
|
441
441
|
*/
|
|
@@ -2752,6 +2752,85 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
|
|
|
2752
2752
|
fonts?: [TFontProviders] extends [never] ? Array<FontFamily> : {
|
|
2753
2753
|
[K in keyof TFontProviders]: FontFamily<TFontProviders[K]>;
|
|
2754
2754
|
};
|
|
2755
|
+
/**
|
|
2756
|
+
* @docs
|
|
2757
|
+
* @kind heading
|
|
2758
|
+
* @name cache
|
|
2759
|
+
* @type {object}
|
|
2760
|
+
* @default `undefined`
|
|
2761
|
+
* @version 7.0.0
|
|
2762
|
+
* @description
|
|
2763
|
+
*
|
|
2764
|
+
* Enables route caching for SSR responses. Provides a platform-agnostic API
|
|
2765
|
+
* for caching rendered pages and API responses, with pluggable providers
|
|
2766
|
+
* that adapters can configure automatically.
|
|
2767
|
+
*
|
|
2768
|
+
* ```js
|
|
2769
|
+
* // astro.config.mjs
|
|
2770
|
+
* import { memoryCache } from 'astro/config';
|
|
2771
|
+
*
|
|
2772
|
+
* {
|
|
2773
|
+
* cache: {
|
|
2774
|
+
* provider: memoryCache(),
|
|
2775
|
+
* },
|
|
2776
|
+
* routeRules: {
|
|
2777
|
+
* '/blog/[...path]': { maxAge: 300, swr: 60 },
|
|
2778
|
+
* },
|
|
2779
|
+
* }
|
|
2780
|
+
* ```
|
|
2781
|
+
*
|
|
2782
|
+
* Use `Astro.cache.set()` in routes and `context.cache.set()` in middleware
|
|
2783
|
+
* or API routes to control caching per-request.
|
|
2784
|
+
*/
|
|
2785
|
+
cache?: {
|
|
2786
|
+
/**
|
|
2787
|
+
* @docs
|
|
2788
|
+
* @name cache.provider
|
|
2789
|
+
* @type {CacheProviderConfig}
|
|
2790
|
+
* @version 7.0.0
|
|
2791
|
+
* @description
|
|
2792
|
+
*
|
|
2793
|
+
* A provider that controls how responses are cached.
|
|
2794
|
+
*
|
|
2795
|
+
* Use the provider's config function to get type-safe configuration:
|
|
2796
|
+
*
|
|
2797
|
+
* ```js
|
|
2798
|
+
* import { defineConfig, memoryCache } from 'astro/config';
|
|
2799
|
+
*
|
|
2800
|
+
* export default defineConfig({
|
|
2801
|
+
* cache: { provider: memoryCache() },
|
|
2802
|
+
* });
|
|
2803
|
+
* ```
|
|
2804
|
+
*/
|
|
2805
|
+
provider?: CacheProviderConfig;
|
|
2806
|
+
};
|
|
2807
|
+
/**
|
|
2808
|
+
* @docs
|
|
2809
|
+
* @kind heading
|
|
2810
|
+
* @name routeRules
|
|
2811
|
+
* @type {Record<string, RouteRule>}
|
|
2812
|
+
* @default `undefined`
|
|
2813
|
+
* @version 7.0.0
|
|
2814
|
+
* @description
|
|
2815
|
+
*
|
|
2816
|
+
* Route patterns mapped to cache rules.
|
|
2817
|
+
* Uses the same `[param]` and `[...rest]` syntax as [file-based routing](/en/guides/routing/#route-priority-order).
|
|
2818
|
+
* Use a `[...rest]` parameter to match a group of routes:
|
|
2819
|
+
*
|
|
2820
|
+
* ```js
|
|
2821
|
+
* // astro.config.mjs
|
|
2822
|
+
* import { memoryCache } from 'astro/config';
|
|
2823
|
+
*
|
|
2824
|
+
* {
|
|
2825
|
+
* cache: { provider: memoryCache() },
|
|
2826
|
+
* routeRules: {
|
|
2827
|
+
* '/api/[...path]': { swr: 600 },
|
|
2828
|
+
* '/products/[...slug]': { maxAge: 3600, tags: ['products'] },
|
|
2829
|
+
* },
|
|
2830
|
+
* }
|
|
2831
|
+
* ```
|
|
2832
|
+
*/
|
|
2833
|
+
routeRules?: RouteRules;
|
|
2755
2834
|
/**
|
|
2756
2835
|
*
|
|
2757
2836
|
* @kind heading
|
|
@@ -2895,83 +2974,6 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
|
|
|
2895
2974
|
* See the [experimental SVG optimization docs](https://docs.astro.build/en/reference/experimental-flags/svg-optimization/) for more information.
|
|
2896
2975
|
*/
|
|
2897
2976
|
svgOptimizer?: SvgOptimizer;
|
|
2898
|
-
/**
|
|
2899
|
-
* @name experimental.cache
|
|
2900
|
-
* @type {object}
|
|
2901
|
-
* @default `undefined`
|
|
2902
|
-
* @description
|
|
2903
|
-
*
|
|
2904
|
-
* Enables route caching for SSR responses. Provides a platform-agnostic API
|
|
2905
|
-
* for caching rendered pages and API responses, with pluggable providers
|
|
2906
|
-
* that adapters can configure automatically.
|
|
2907
|
-
*
|
|
2908
|
-
* ```js
|
|
2909
|
-
* // astro.config.mjs
|
|
2910
|
-
* import { memoryCache } from 'astro/config';
|
|
2911
|
-
*
|
|
2912
|
-
* {
|
|
2913
|
-
* experimental: {
|
|
2914
|
-
* cache: {
|
|
2915
|
-
* provider: memoryCache(),
|
|
2916
|
-
* },
|
|
2917
|
-
* routeRules: {
|
|
2918
|
-
* '/blog/[...path]': { maxAge: 300, swr: 60 },
|
|
2919
|
-
* },
|
|
2920
|
-
* },
|
|
2921
|
-
* }
|
|
2922
|
-
* ```
|
|
2923
|
-
*
|
|
2924
|
-
* Use `Astro.cache.set()` in routes and `context.cache.set()` in middleware
|
|
2925
|
-
* or API routes to control caching per-request.
|
|
2926
|
-
*/
|
|
2927
|
-
cache?: {
|
|
2928
|
-
/**
|
|
2929
|
-
* @name experimental.cache.provider
|
|
2930
|
-
* @type {import('../../core/cache/types.js').CacheProviderConfig}
|
|
2931
|
-
* @description
|
|
2932
|
-
*
|
|
2933
|
-
* The cache provider. Adapters typically set a default, but you can
|
|
2934
|
-
* override it with your own.
|
|
2935
|
-
*
|
|
2936
|
-
* Use the provider's config function to get type-safe configuration:
|
|
2937
|
-
*
|
|
2938
|
-
* ```js
|
|
2939
|
-
* import { memoryCache } from 'astro/config';
|
|
2940
|
-
*
|
|
2941
|
-
* export default defineConfig({
|
|
2942
|
-
* experimental: {
|
|
2943
|
-
* cache: { provider: memoryCache() },
|
|
2944
|
-
* },
|
|
2945
|
-
* });
|
|
2946
|
-
* ```
|
|
2947
|
-
*/
|
|
2948
|
-
provider?: CacheProviderConfig;
|
|
2949
|
-
};
|
|
2950
|
-
/**
|
|
2951
|
-
* @name experimental.routeRules
|
|
2952
|
-
* @type {Record<string, RouteRule>}
|
|
2953
|
-
* @default `undefined`
|
|
2954
|
-
* @description
|
|
2955
|
-
*
|
|
2956
|
-
* Route patterns mapped to cache rules.
|
|
2957
|
-
* Uses the same `[param]` and `[...rest]` syntax as file-based routing.
|
|
2958
|
-
*
|
|
2959
|
-
* ```js
|
|
2960
|
-
* // astro.config.mjs
|
|
2961
|
-
* import { memoryCache } from 'astro/config';
|
|
2962
|
-
*
|
|
2963
|
-
* {
|
|
2964
|
-
* experimental: {
|
|
2965
|
-
* cache: { provider: memoryCache() },
|
|
2966
|
-
* routeRules: {
|
|
2967
|
-
* '/api/*': { swr: 600 },
|
|
2968
|
-
* '/products/*': { maxAge: 3600, tags: ['products'] },
|
|
2969
|
-
* },
|
|
2970
|
-
* },
|
|
2971
|
-
* }
|
|
2972
|
-
* ```
|
|
2973
|
-
*/
|
|
2974
|
-
routeRules?: RouteRules;
|
|
2975
2977
|
};
|
|
2976
2978
|
}
|
|
2977
2979
|
/**
|
|
@@ -4,7 +4,7 @@ import type { SSRLoadedRenderer } from '../types/public/internal.js';
|
|
|
4
4
|
* Use this function to provide renderers to the `AstroContainer`:
|
|
5
5
|
*
|
|
6
6
|
* ```js
|
|
7
|
-
* import { getContainerRenderer } from "@astrojs/react";
|
|
7
|
+
* import { getContainerRenderer } from "@astrojs/react/container-renderer";
|
|
8
8
|
* import { experimental_AstroContainer as AstroContainer } from "astro/container";
|
|
9
9
|
* import { loadRenderers } from "astro:container"; // use this only when using vite/vitest
|
|
10
10
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Plugin as VitePlugin } from 'vite';
|
|
2
2
|
import type { AstroSettings } from '../types/astro.js';
|
|
3
|
-
/** Returns
|
|
3
|
+
/** Returns Vite plugins used to alias paths from tsconfig.json and jsconfig.json. */
|
|
4
4
|
export default function configAliasVitePlugin({ settings, }: {
|
|
5
5
|
settings: AstroSettings;
|
|
6
|
-
}): VitePlugin | null;
|
|
6
|
+
}): VitePlugin[] | null;
|