astro 7.0.0-beta.3 → 7.0.0-beta.5
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/assets/build/generate.js +4 -3
- package/dist/cli/add/index.js +1 -0
- package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
- package/dist/container/index.d.ts +3 -3
- package/dist/content/content-layer.js +3 -3
- package/dist/content/runtime.d.ts +1 -1
- package/dist/content/runtime.js +1 -0
- package/dist/content/vite-plugin-content-virtual-mod.js +27 -0
- package/dist/core/app/base.js +7 -15
- 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-css.js +1 -0
- package/dist/core/config/schemas/base.d.ts +4 -4
- package/dist/core/config/schemas/base.js +4 -4
- package/dist/core/config/validate.js +10 -2
- 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 +22 -8
- package/dist/core/fetch/fetch-state.d.ts +11 -0
- package/dist/core/fetch/fetch-state.js +21 -2
- 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/middleware/vite-plugin.d.ts +1 -0
- package/dist/core/middleware/vite-plugin.js +5 -1
- 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/normalized-url.js +2 -5
- package/dist/core/util/pathname.d.ts +17 -10
- package/dist/core/util/pathname.js +14 -7
- package/dist/i18n/index.js +11 -9
- package/dist/runtime/server/endpoint.d.ts +2 -1
- package/dist/runtime/server/endpoint.js +4 -13
- package/dist/runtime/server/jsx.js +2 -1
- package/dist/runtime/server/render/head.js +2 -1
- package/dist/runtime/server/render/util.js +4 -0
- package/dist/types/public/config.d.ts +68 -13
- package/dist/virtual-modules/container.d.ts +1 -1
- package/dist/vite-plugin-head/index.js +5 -11
- package/dist/vite-plugin-hmr-reload/index.js +19 -6
- package/dist/vite-plugin-html/transform/slots.js +4 -1
- package/dist/vite-plugin-pages/pages.d.ts +11 -0
- package/dist/vite-plugin-pages/pages.js +1 -3
- package/package.json +12 -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
- package/dist/jsx/rehype.d.ts +0 -5
- package/dist/jsx/rehype.js +0 -241
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import fs, { readFileSync } from "node:fs";
|
|
2
2
|
import { basename } from "node:path/posix";
|
|
3
3
|
import colors from "piccolore";
|
|
4
|
-
import { getOutDirWithinCwd } from "../../core/build/common.js";
|
|
5
4
|
import { getTimeStat } from "../../core/build/util.js";
|
|
6
5
|
import { AstroError } from "../../core/errors/errors.js";
|
|
7
6
|
import { AstroErrorData } from "../../core/errors/index.js";
|
|
8
7
|
import { isRemotePath, removeLeadingForwardSlash } from "../../core/path.js";
|
|
8
|
+
import { getClientOutputDirectory } from "../../prerender/utils.js";
|
|
9
9
|
import { getConfiguredImageService } from "../internal.js";
|
|
10
10
|
import { isESMImportedImage } from "../utils/imageKind.js";
|
|
11
11
|
import { loadRemoteImage, revalidateRemoteImage } from "./remote.js";
|
|
@@ -29,8 +29,9 @@ async function prepareAssetsGenerationEnv(options, totalCount) {
|
|
|
29
29
|
serverRoot = new URL(".prerender/", settings.config.build.server);
|
|
30
30
|
clientRoot = settings.config.build.client;
|
|
31
31
|
} else {
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
const clientOutputDir = getClientOutputDirectory(settings);
|
|
33
|
+
serverRoot = clientOutputDir;
|
|
34
|
+
clientRoot = clientOutputDir;
|
|
34
35
|
}
|
|
35
36
|
return {
|
|
36
37
|
logger,
|
package/dist/cli/add/index.js
CHANGED
|
@@ -48,6 +48,7 @@ export default {
|
|
|
48
48
|
public-hoist-pattern[]=*lit*
|
|
49
49
|
`,
|
|
50
50
|
CLOUDFLARE_WRANGLER_CONFIG: (name, compatibilityDate) => `{
|
|
51
|
+
"$schema": "./node_modules/wrangler/config-schema.json",
|
|
51
52
|
"compatibility_date": ${JSON.stringify(compatibilityDate)},
|
|
52
53
|
"compatibility_flags": ["global_fetch_strictly_public"],
|
|
53
54
|
"name": ${JSON.stringify(name)},
|
|
@@ -67,7 +67,7 @@ export type ContainerRenderOptions = {
|
|
|
67
67
|
*/
|
|
68
68
|
routeType?: RouteType;
|
|
69
69
|
/**
|
|
70
|
-
* Allows
|
|
70
|
+
* Allows passing `Astro.props` to an Astro component:
|
|
71
71
|
*
|
|
72
72
|
* ```js
|
|
73
73
|
* container.renderToString(Endpoint, { props: { "lorem": "ipsum" } });
|
|
@@ -75,9 +75,9 @@ export type ContainerRenderOptions = {
|
|
|
75
75
|
*/
|
|
76
76
|
props?: Props;
|
|
77
77
|
/**
|
|
78
|
-
* When `false`, it forces to render
|
|
78
|
+
* When `false`, it forces the component to render as if it were a full-fledged page.
|
|
79
79
|
*
|
|
80
|
-
* By default, the container API
|
|
80
|
+
* By default, the container API renders components as [partials](https://docs.astro.build/en/basics/astro-pages/#page-partials).
|
|
81
81
|
*
|
|
82
82
|
*/
|
|
83
83
|
partial?: boolean;
|
|
@@ -197,7 +197,7 @@ ${contentConfig.error.message}`
|
|
|
197
197
|
logger.info("Content config changed");
|
|
198
198
|
shouldClear = true;
|
|
199
199
|
}
|
|
200
|
-
if (previousAstroVersion && previousAstroVersion !== "7.0.0-beta.
|
|
200
|
+
if (previousAstroVersion && previousAstroVersion !== "7.0.0-beta.5") {
|
|
201
201
|
logger.info("Astro version changed");
|
|
202
202
|
shouldClear = true;
|
|
203
203
|
}
|
|
@@ -205,8 +205,8 @@ ${contentConfig.error.message}`
|
|
|
205
205
|
logger.info("Clearing content store");
|
|
206
206
|
this.#store.clearAll();
|
|
207
207
|
}
|
|
208
|
-
if ("7.0.0-beta.
|
|
209
|
-
this.#store.metaStore().set("astro-version", "7.0.0-beta.
|
|
208
|
+
if ("7.0.0-beta.5") {
|
|
209
|
+
this.#store.metaStore().set("astro-version", "7.0.0-beta.5");
|
|
210
210
|
}
|
|
211
211
|
if (currentConfigDigest) {
|
|
212
212
|
this.#store.metaStore().set("content-config-digest", currentConfigDigest);
|
|
@@ -70,7 +70,7 @@ type RenderResult = {
|
|
|
70
70
|
};
|
|
71
71
|
export declare function updateImageReferencesInData<T extends Record<string, unknown>>(data: T, fileName?: string, imageAssetMap?: Map<string, ImageMetadata>): T;
|
|
72
72
|
export declare function renderEntry(entry: DataEntry): Promise<RenderResult>;
|
|
73
|
-
export declare function createReference(): (collection: string) => z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
73
|
+
export declare function createReference(): (collection: string) => z.ZodPipe<z.ZodUnion<readonly [z.ZodPipe<z.ZodNumber, z.ZodTransform<string, number>>, z.ZodString, z.ZodObject<{
|
|
74
74
|
id: z.ZodString;
|
|
75
75
|
collection: z.ZodString;
|
|
76
76
|
}, z.core.$strip>, z.ZodObject<{
|
package/dist/content/runtime.js
CHANGED
|
@@ -23,6 +23,25 @@ import {
|
|
|
23
23
|
} from "./consts.js";
|
|
24
24
|
import { getDataStoreFile } from "./content-layer.js";
|
|
25
25
|
import { getContentPaths, isDeferredModule } from "./utils.js";
|
|
26
|
+
function invalidateAssetImports(viteServer, filePath) {
|
|
27
|
+
const timestamp = Date.now();
|
|
28
|
+
for (const environment of Object.values(viteServer.environments)) {
|
|
29
|
+
const modules = environment.moduleGraph.getModulesByFile(filePath);
|
|
30
|
+
if (modules) {
|
|
31
|
+
for (const module of modules) {
|
|
32
|
+
environment.moduleGraph.invalidateModule(module, void 0, timestamp, true);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (isRunnableDevEnvironment(environment)) {
|
|
36
|
+
const runnerModules = environment.runner.evaluatedModules.getModulesByFile(filePath);
|
|
37
|
+
if (runnerModules) {
|
|
38
|
+
for (const runnerModule of runnerModules) {
|
|
39
|
+
environment.runner.evaluatedModules.invalidateModule(runnerModule);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
26
45
|
function invalidateDataStore(viteServer) {
|
|
27
46
|
const environment = viteServer.environments[ASTRO_VITE_ENVIRONMENT_NAMES.ssr];
|
|
28
47
|
const module = environment.moduleGraph.getModuleById(RESOLVED_DATA_STORE_VIRTUAL_ID);
|
|
@@ -67,8 +86,11 @@ function astroContentVirtualModPlugin({
|
|
|
67
86
|
},
|
|
68
87
|
buildStart() {
|
|
69
88
|
if (devServer) {
|
|
89
|
+
const assetImportsPath = fileURLToPath(new URL(ASSET_IMPORTS_FILE, settings.dotAstroDir));
|
|
70
90
|
devServer.watcher.add(fileURLToPath(dataStoreFile));
|
|
91
|
+
devServer.watcher.add(assetImportsPath);
|
|
71
92
|
invalidateDataStore(devServer);
|
|
93
|
+
invalidateAssetImports(devServer, assetImportsPath);
|
|
72
94
|
}
|
|
73
95
|
},
|
|
74
96
|
resolveId: {
|
|
@@ -175,14 +197,19 @@ function astroContentVirtualModPlugin({
|
|
|
175
197
|
configureServer(server) {
|
|
176
198
|
devServer = server;
|
|
177
199
|
const dataStorePath = fileURLToPath(dataStoreFile);
|
|
200
|
+
const assetImportsPath = fileURLToPath(new URL(ASSET_IMPORTS_FILE, settings.dotAstroDir));
|
|
178
201
|
server.watcher.on("add", (addedPath) => {
|
|
179
202
|
if (addedPath === dataStorePath) {
|
|
180
203
|
invalidateDataStore(server);
|
|
204
|
+
invalidateAssetImports(server, assetImportsPath);
|
|
181
205
|
}
|
|
182
206
|
});
|
|
183
207
|
server.watcher.on("change", (changedPath) => {
|
|
184
208
|
if (changedPath === dataStorePath) {
|
|
185
209
|
invalidateDataStore(server);
|
|
210
|
+
invalidateAssetImports(server, assetImportsPath);
|
|
211
|
+
} else if (changedPath === assetImportsPath) {
|
|
212
|
+
invalidateAssetImports(server, assetImportsPath);
|
|
186
213
|
}
|
|
187
214
|
});
|
|
188
215
|
}
|
package/dist/core/app/base.js
CHANGED
|
@@ -14,7 +14,6 @@ import { DefaultFetchHandler } from "../fetch/default-handler.js";
|
|
|
14
14
|
import { appSymbol } from "../constants.js";
|
|
15
15
|
import { DefaultErrorHandler } from "../errors/default-handler.js";
|
|
16
16
|
import { setRenderOptions } from "./render-options.js";
|
|
17
|
-
import { MultiLevelEncodingError } from "../util/pathname.js";
|
|
18
17
|
class BaseApp {
|
|
19
18
|
manifest;
|
|
20
19
|
manifestData;
|
|
@@ -237,20 +236,13 @@ class BaseApp {
|
|
|
237
236
|
waitUntil
|
|
238
237
|
};
|
|
239
238
|
let response;
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
response = await this.#fetchHandler.fetch(request);
|
|
248
|
-
}
|
|
249
|
-
} catch (err) {
|
|
250
|
-
if (err instanceof MultiLevelEncodingError) {
|
|
251
|
-
return new Response("Bad Request", { status: 400 });
|
|
252
|
-
}
|
|
253
|
-
throw err;
|
|
239
|
+
if (this.#fetchHandler instanceof DefaultFetchHandler) {
|
|
240
|
+
Reflect.set(request, appSymbol, this);
|
|
241
|
+
response = await this.#fetchHandler.renderWithOptions(request, resolvedOptions);
|
|
242
|
+
} else {
|
|
243
|
+
setRenderOptions(request, resolvedOptions);
|
|
244
|
+
Reflect.set(request, appSymbol, this);
|
|
245
|
+
response = await this.#fetchHandler.fetch(request);
|
|
254
246
|
}
|
|
255
247
|
this.#warnMissingFeatures();
|
|
256
248
|
if (response.headers.get(ASTRO_ERROR_HEADER)) {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* to the `Set-Cookie` header.
|
|
2
|
+
* Appends cookies written via `Astro.cookie.set()` to the `Set-Cookie` header
|
|
3
|
+
* and marks the response as sent.
|
|
5
4
|
*
|
|
6
5
|
* This is a pure function with no dependencies on the app; it is shared by
|
|
7
6
|
* `AstroHandler` and the various error handlers.
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { responseSentSymbol } from "../constants.js";
|
|
2
2
|
import { getSetCookiesFromResponse } from "../cookies/index.js";
|
|
3
3
|
function prepareResponse(response, { addCookieHeader }) {
|
|
4
|
-
for (const headerName of INTERNAL_RESPONSE_HEADERS) {
|
|
5
|
-
if (response.headers.has(headerName)) {
|
|
6
|
-
response.headers.delete(headerName);
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
4
|
if (addCookieHeader) {
|
|
10
5
|
for (const setCookieHeaderValue of getSetCookiesFromResponse(response)) {
|
|
11
6
|
response.headers.append("set-cookie", setCookieHeaderValue);
|
|
@@ -107,6 +107,7 @@ function rollupPluginAstroBuildCSS(options) {
|
|
|
107
107
|
if (meta.importedCss.size < 1) continue;
|
|
108
108
|
if (this.environment?.name === ASTRO_VITE_ENVIRONMENT_NAMES.client) {
|
|
109
109
|
for (const id of Object.keys(chunk.modules)) {
|
|
110
|
+
if (!isCSSRequest(id)) continue;
|
|
110
111
|
for (const pageData of getParentClientOnlys(id, this, internals)) {
|
|
111
112
|
for (const importedCssImport of meta.importedCss) {
|
|
112
113
|
const cssToInfoRecord = pagesToCss[pageData.moduleSpecifier] ??= {};
|
|
@@ -49,7 +49,7 @@ export declare const ASTRO_CONFIG_DEFAULTS: {
|
|
|
49
49
|
devToolbar: {
|
|
50
50
|
enabled: true;
|
|
51
51
|
};
|
|
52
|
-
compressHTML:
|
|
52
|
+
compressHTML: "jsx";
|
|
53
53
|
server: {
|
|
54
54
|
host: false;
|
|
55
55
|
port: number;
|
|
@@ -57,7 +57,7 @@ export declare const ASTRO_CONFIG_DEFAULTS: {
|
|
|
57
57
|
allowedHosts: never[];
|
|
58
58
|
};
|
|
59
59
|
integrations: never[];
|
|
60
|
-
markdown: Required<Omit<import("@astrojs/markdown
|
|
60
|
+
markdown: Required<Omit<import("@astrojs/internal-helpers/markdown").AstroMarkdownOptions, "image">>;
|
|
61
61
|
vite: {};
|
|
62
62
|
legacy: {
|
|
63
63
|
collectionsBackwardsCompat: false;
|
|
@@ -329,8 +329,8 @@ export declare const AstroConfigSchema: z.ZodObject<{
|
|
|
329
329
|
processor: z.ZodDefault<z.ZodObject<{
|
|
330
330
|
name: z.ZodString;
|
|
331
331
|
options: z.ZodDefault<z.ZodCustom<object, object>>;
|
|
332
|
-
createRenderer: z.ZodCustom<(shared: import("@astrojs/markdown
|
|
333
|
-
createMdxRenderer: z.ZodOptional<z.ZodCustom<((shared: import("@astrojs/markdown
|
|
332
|
+
createRenderer: z.ZodCustom<(shared: import("@astrojs/internal-helpers/markdown").AstroMarkdownOptions) => Promise<import("@astrojs/internal-helpers/markdown").MarkdownRenderer>, (shared: import("@astrojs/internal-helpers/markdown").AstroMarkdownOptions) => Promise<import("@astrojs/internal-helpers/markdown").MarkdownRenderer>>;
|
|
333
|
+
createMdxRenderer: z.ZodOptional<z.ZodCustom<((shared: import("@astrojs/internal-helpers/markdown").AstroMarkdownOptions, mdx: import("@astrojs/internal-helpers/markdown").MdxRendererOptions) => Promise<import("@astrojs/internal-helpers/markdown").MdxRenderer>) | undefined, ((shared: import("@astrojs/internal-helpers/markdown").AstroMarkdownOptions, mdx: import("@astrojs/internal-helpers/markdown").MdxRendererOptions) => Promise<import("@astrojs/internal-helpers/markdown").MdxRenderer>) | undefined>>;
|
|
334
334
|
}, z.core.$strip>>;
|
|
335
335
|
}, z.core.$strip>>;
|
|
336
336
|
vite: z.ZodDefault<z.ZodCustom<ViteUserConfig, ViteUserConfig>>;
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
markdownConfigDefaults,
|
|
3
3
|
syntaxHighlightDefaults
|
|
4
4
|
} from "@astrojs/internal-helpers/markdown";
|
|
5
|
-
import {
|
|
5
|
+
import { satteri } from "@astrojs/markdown-satteri";
|
|
6
6
|
import { bundledThemes } from "shiki";
|
|
7
7
|
import * as z from "zod/v4";
|
|
8
8
|
import { FontFamilySchema } from "../../../assets/fonts/config.js";
|
|
@@ -38,7 +38,7 @@ const ASTRO_CONFIG_DEFAULTS = {
|
|
|
38
38
|
devToolbar: {
|
|
39
39
|
enabled: true
|
|
40
40
|
},
|
|
41
|
-
compressHTML:
|
|
41
|
+
compressHTML: "jsx",
|
|
42
42
|
server: {
|
|
43
43
|
host: false,
|
|
44
44
|
port: 4321,
|
|
@@ -238,7 +238,7 @@ const AstroConfigSchema = z.object({
|
|
|
238
238
|
remarkRehype: z.custom((data) => data instanceof Object && !Array.isArray(data)).default(ASTRO_CONFIG_DEFAULTS.markdown.remarkRehype),
|
|
239
239
|
// Deprecated: left undefined unless the user explicitly sets them, so the
|
|
240
240
|
// deprecation warning only fires when actually used. The active processor
|
|
241
|
-
// (`
|
|
241
|
+
// (`satteri()`) supplies the real default (`gfm`/smart punctuation on) when
|
|
242
242
|
// these are absent.
|
|
243
243
|
gfm: z.boolean().optional(),
|
|
244
244
|
smartypants: z.union([z.boolean(), smartypantsOptionsSchema]).transform((val) => {
|
|
@@ -256,7 +256,7 @@ const AstroConfigSchema = z.object({
|
|
|
256
256
|
createMdxRenderer: z.custom(
|
|
257
257
|
(v) => v === void 0 || typeof v === "function"
|
|
258
258
|
).optional()
|
|
259
|
-
}).default(() =>
|
|
259
|
+
}).default(() => satteri())
|
|
260
260
|
}).prefault({}),
|
|
261
261
|
vite: z.custom((data) => data instanceof Object && !Array.isArray(data)).default(ASTRO_CONFIG_DEFAULTS.vite),
|
|
262
262
|
i18n: z.optional(
|
|
@@ -30,7 +30,7 @@ function warnDeprecatedMarkdownOptions(config) {
|
|
|
30
30
|
const names = deprecated.map((key) => `\`markdown.${key}\``).join(" and ");
|
|
31
31
|
const isPlural = deprecated.length > 1;
|
|
32
32
|
console.warn(
|
|
33
|
-
`[astro] ${names} ${isPlural ? "are" : "is"} deprecated. Move ${isPlural ? "them" : "it"} onto your processor instead (e.g. \`unified({ gfm: false, smartypants: false })\`). Will be removed in a future major.`
|
|
33
|
+
`[astro] ${names} ${isPlural ? "are" : "is"} deprecated. Move ${isPlural ? "them" : "it"} onto your processor instead (e.g. \`satteri({ features: { gfm: false, smartPunctuation: false } })\`, or \`unified({ gfm: false, smartypants: false })\` from \`@astrojs/markdown-remark\`). Will be removed in a future major.`
|
|
34
34
|
);
|
|
35
35
|
}
|
|
36
36
|
let didWarnAboutLegacyMarkdownPlugins = false;
|
|
@@ -45,7 +45,15 @@ async function coerceLegacyMarkdownPlugins(config) {
|
|
|
45
45
|
if (remarkPlugins.length === 0 && rehypePlugins.length === 0 && Object.keys(remarkRehype).length === 0) {
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
|
-
|
|
48
|
+
let unified;
|
|
49
|
+
let isUnifiedProcessor;
|
|
50
|
+
try {
|
|
51
|
+
({ unified, isUnifiedProcessor } = await import("@astrojs/markdown-remark"));
|
|
52
|
+
} catch {
|
|
53
|
+
throw new Error(
|
|
54
|
+
"`markdown.remarkPlugins`, `markdown.rehypePlugins`, and `markdown.remarkRehype` run on the `unified` processor from `@astrojs/markdown-remark`, which is no longer installed by default now that S\xE4tteri is the default Markdown processor. Install it with:\n npm install @astrojs/markdown-remark"
|
|
55
|
+
);
|
|
56
|
+
}
|
|
49
57
|
const current = md.processor;
|
|
50
58
|
if (!current || isUnifiedProcessor(current)) {
|
|
51
59
|
const target = current ?? (md.processor = unified());
|
package/dist/core/constants.d.ts
CHANGED
|
@@ -1,46 +1,5 @@
|
|
|
1
1
|
export declare const ASTRO_VERSION: string;
|
|
2
2
|
export declare const ASTRO_GENERATOR: string;
|
|
3
|
-
/**
|
|
4
|
-
* The name for the header used to help rerouting behavior.
|
|
5
|
-
* When set to "no", astro will NOT try to reroute an error response to the corresponding error page, which is the default behavior that can sometimes lead to loops.
|
|
6
|
-
*
|
|
7
|
-
* ```ts
|
|
8
|
-
* const response = new Response("keep this content as-is", {
|
|
9
|
-
* status: 404,
|
|
10
|
-
* headers: {
|
|
11
|
-
* // note that using a variable name as the key of an object needs to be wrapped in square brackets in javascript
|
|
12
|
-
* // without them, the header name will be interpreted as "REROUTE_DIRECTIVE_HEADER" instead of "X-Astro-Reroute"
|
|
13
|
-
* [REROUTE_DIRECTIVE_HEADER]: 'no',
|
|
14
|
-
* }
|
|
15
|
-
* })
|
|
16
|
-
* ```
|
|
17
|
-
* Alternatively...
|
|
18
|
-
* ```ts
|
|
19
|
-
* response.headers.set(REROUTE_DIRECTIVE_HEADER, 'no');
|
|
20
|
-
* ```
|
|
21
|
-
*/
|
|
22
|
-
export declare const REROUTE_DIRECTIVE_HEADER = "X-Astro-Reroute";
|
|
23
|
-
/**
|
|
24
|
-
* Header and value that are attached to a Response object when a **user rewrite** occurs.
|
|
25
|
-
*
|
|
26
|
-
* This metadata is used to determine the origin of a Response. If a rewrite has occurred, it should be prioritised over other logic.
|
|
27
|
-
*/
|
|
28
|
-
export declare const REWRITE_DIRECTIVE_HEADER_KEY = "X-Astro-Rewrite";
|
|
29
|
-
export declare const REWRITE_DIRECTIVE_HEADER_VALUE = "yes";
|
|
30
|
-
/**
|
|
31
|
-
* This header is set by the no-op Astro middleware.
|
|
32
|
-
*/
|
|
33
|
-
export declare const NOOP_MIDDLEWARE_HEADER = "X-Astro-Noop";
|
|
34
|
-
/**
|
|
35
|
-
* The name for the header used to help i18n middleware, which only needs to act on "page" and "fallback" route types.
|
|
36
|
-
*/
|
|
37
|
-
export declare const ROUTE_TYPE_HEADER = "X-Astro-Route-Type";
|
|
38
|
-
/**
|
|
39
|
-
* Internal headers that should be stripped from the response before
|
|
40
|
-
* sending it to the user agent. Add new internal headers here so
|
|
41
|
-
* `prepareResponse` removes them automatically.
|
|
42
|
-
*/
|
|
43
|
-
export declare const INTERNAL_RESPONSE_HEADERS: readonly ["X-Astro-Reroute", "X-Astro-Rewrite", "X-Astro-Noop", "X-Astro-Route-Type"];
|
|
44
3
|
/**
|
|
45
4
|
* Set by internal handlers (e.g. PagesHandler) to signal that a
|
|
46
5
|
* response should be replaced with the corresponding error page.
|
package/dist/core/constants.js
CHANGED
|
@@ -1,16 +1,5 @@
|
|
|
1
|
-
const ASTRO_VERSION = "7.0.0-beta.
|
|
1
|
+
const ASTRO_VERSION = "7.0.0-beta.5";
|
|
2
2
|
const ASTRO_GENERATOR = `Astro v${ASTRO_VERSION}`;
|
|
3
|
-
const REROUTE_DIRECTIVE_HEADER = "X-Astro-Reroute";
|
|
4
|
-
const REWRITE_DIRECTIVE_HEADER_KEY = "X-Astro-Rewrite";
|
|
5
|
-
const REWRITE_DIRECTIVE_HEADER_VALUE = "yes";
|
|
6
|
-
const NOOP_MIDDLEWARE_HEADER = "X-Astro-Noop";
|
|
7
|
-
const ROUTE_TYPE_HEADER = "X-Astro-Route-Type";
|
|
8
|
-
const INTERNAL_RESPONSE_HEADERS = [
|
|
9
|
-
REROUTE_DIRECTIVE_HEADER,
|
|
10
|
-
REWRITE_DIRECTIVE_HEADER_KEY,
|
|
11
|
-
NOOP_MIDDLEWARE_HEADER,
|
|
12
|
-
ROUTE_TYPE_HEADER
|
|
13
|
-
];
|
|
14
3
|
const ASTRO_ERROR_HEADER = "X-Astro-Error";
|
|
15
4
|
const DEFAULT_404_COMPONENT = "astro-default-404.astro";
|
|
16
5
|
const REDIRECT_STATUS_CODES = [301, 302, 303, 307, 308, 300, 304];
|
|
@@ -57,15 +46,9 @@ export {
|
|
|
57
46
|
ASTRO_VERSION,
|
|
58
47
|
ASTRO_VITE_ENVIRONMENT_NAMES,
|
|
59
48
|
DEFAULT_404_COMPONENT,
|
|
60
|
-
INTERNAL_RESPONSE_HEADERS,
|
|
61
49
|
MIDDLEWARE_PATH_SEGMENT_NAME,
|
|
62
|
-
NOOP_MIDDLEWARE_HEADER,
|
|
63
50
|
REDIRECT_STATUS_CODES,
|
|
64
51
|
REROUTABLE_STATUS_CODES,
|
|
65
|
-
REROUTE_DIRECTIVE_HEADER,
|
|
66
|
-
REWRITE_DIRECTIVE_HEADER_KEY,
|
|
67
|
-
REWRITE_DIRECTIVE_HEADER_VALUE,
|
|
68
|
-
ROUTE_TYPE_HEADER,
|
|
69
52
|
SUPPORTED_MARKDOWN_FILE_EXTENSIONS,
|
|
70
53
|
appSymbol,
|
|
71
54
|
clientAddressSymbol,
|
package/dist/core/dev/dev.js
CHANGED
|
@@ -26,7 +26,7 @@ async function dev(inlineConfig) {
|
|
|
26
26
|
await telemetry.record([]);
|
|
27
27
|
const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
|
|
28
28
|
const logger = restart.container.logger;
|
|
29
|
-
const currentVersion = "7.0.0-beta.
|
|
29
|
+
const currentVersion = "7.0.0-beta.5";
|
|
30
30
|
const isPrerelease = currentVersion.includes("-");
|
|
31
31
|
if (!isPrerelease) {
|
|
32
32
|
try {
|
|
@@ -6,6 +6,7 @@ import { AstroMiddleware } from "../middleware/astro-middleware.js";
|
|
|
6
6
|
import { PagesHandler } from "../pages/handler.js";
|
|
7
7
|
import { matchRoute } from "../routing/match.js";
|
|
8
8
|
import { provideSession } from "../session/handler.js";
|
|
9
|
+
import { validateHost } from "../app/validate-headers.js";
|
|
9
10
|
class DefaultErrorHandler {
|
|
10
11
|
#app;
|
|
11
12
|
#astroMiddleware;
|
|
@@ -31,15 +32,27 @@ class DefaultErrorHandler {
|
|
|
31
32
|
if (errorRouteData) {
|
|
32
33
|
if (errorRouteData.prerender) {
|
|
33
34
|
const maybeDotHtml = errorRouteData.route.endsWith(`/${status}`) ? ".html" : "";
|
|
34
|
-
const
|
|
35
|
+
const allowedDomains = app.manifest.allowedDomains;
|
|
36
|
+
const validatedHost = validateHost(url.host, url.protocol.replace(":", ""), allowedDomains);
|
|
37
|
+
const safeOrigin = validatedHost ? url.origin : `${url.protocol}//localhost`;
|
|
38
|
+
const statusURL = new URL(
|
|
39
|
+
`${app.baseWithoutTrailingSlash}/${status}${maybeDotHtml}`,
|
|
40
|
+
safeOrigin
|
|
41
|
+
);
|
|
35
42
|
if (statusURL.toString() !== request.url && resolvedRenderOptions.prerenderedErrorPageFetch) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
try {
|
|
44
|
+
const response2 = await resolvedRenderOptions.prerenderedErrorPageFetch(
|
|
45
|
+
statusURL.toString()
|
|
46
|
+
);
|
|
47
|
+
const override = { status, removeContentEncodingHeaders: true };
|
|
48
|
+
const newResponse = mergeResponses(response2, originalResponse, override);
|
|
49
|
+
prepareResponse(newResponse, resolvedRenderOptions);
|
|
50
|
+
return newResponse;
|
|
51
|
+
} catch {
|
|
52
|
+
const response2 = mergeResponses(new Response(null, { status }), originalResponse);
|
|
53
|
+
prepareResponse(response2, resolvedRenderOptions);
|
|
54
|
+
return response2;
|
|
55
|
+
}
|
|
43
56
|
}
|
|
44
57
|
}
|
|
45
58
|
const mod = await app.pipeline.getComponentByRoute(errorRouteData);
|
|
@@ -66,6 +79,7 @@ class DefaultErrorHandler {
|
|
|
66
79
|
return this.renderError(request, {
|
|
67
80
|
...resolvedRenderOptions,
|
|
68
81
|
status,
|
|
82
|
+
error,
|
|
69
83
|
response: originalResponse,
|
|
70
84
|
skipMiddleware: true,
|
|
71
85
|
pathname: resolvedPathname
|
|
@@ -108,6 +108,12 @@ export declare class FetchState implements AstroFetchState {
|
|
|
108
108
|
status: number;
|
|
109
109
|
/** Whether user middleware should be skipped for this request. */
|
|
110
110
|
skipMiddleware: boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Set to `true` when the request path was encoded too many times to fully
|
|
113
|
+
* decode (see {@link validateAndDecodePathname}). These requests are
|
|
114
|
+
* rejected with a `400` before middleware or routing run.
|
|
115
|
+
*/
|
|
116
|
+
invalidEncoding: boolean;
|
|
111
117
|
/** A flag that tells the render content if the rewriting was triggered. */
|
|
112
118
|
isRewriting: boolean;
|
|
113
119
|
/** A safety net in case of loops (rewrite counter). */
|
|
@@ -122,6 +128,10 @@ export declare class FetchState implements AstroFetchState {
|
|
|
122
128
|
clientAddress: string | undefined;
|
|
123
129
|
/** Whether this is a partial render (container API). */
|
|
124
130
|
partial: boolean | undefined;
|
|
131
|
+
/** Internal metadata about the current response route type. */
|
|
132
|
+
responseRouteType: 'page' | 'fallback' | undefined;
|
|
133
|
+
/** Internal flag to prevent rerouting this response to an error page. */
|
|
134
|
+
skipErrorReroute: boolean;
|
|
125
135
|
/** Whether to inject CSP meta tags. */
|
|
126
136
|
shouldInjectCspMetaTags: boolean | undefined;
|
|
127
137
|
/** Request-scoped locals object, shared with user middleware. */
|
|
@@ -227,4 +237,5 @@ export declare class FetchState implements AstroFetchState {
|
|
|
227
237
|
* after an in-flight rewrite swaps the route / request / params.
|
|
228
238
|
*/
|
|
229
239
|
invalidateContexts(): void;
|
|
240
|
+
resetResponseMetadata(): void;
|
|
230
241
|
}
|
|
@@ -29,6 +29,7 @@ import { getParams, getProps } from "../render/index.js";
|
|
|
29
29
|
import { Rewrites } from "../rewrites/handler.js";
|
|
30
30
|
import { isRoute404or500, isRouteServerIsland } from "../routing/match.js";
|
|
31
31
|
import { normalizeUrl } from "../util/normalized-url.js";
|
|
32
|
+
import { MultiLevelEncodingError, validateAndDecodePathname } from "../util/pathname.js";
|
|
32
33
|
import { getOriginPathname, setOriginPathname } from "../routing/rewrite.js";
|
|
33
34
|
import { computePathnameFromDomain } from "../i18n/domain.js";
|
|
34
35
|
import { getCustom404Route, routeHasHtmlExtension } from "../routing/helpers.js";
|
|
@@ -87,6 +88,12 @@ class FetchState {
|
|
|
87
88
|
status = 200;
|
|
88
89
|
/** Whether user middleware should be skipped for this request. */
|
|
89
90
|
skipMiddleware = false;
|
|
91
|
+
/**
|
|
92
|
+
* Set to `true` when the request path was encoded too many times to fully
|
|
93
|
+
* decode (see {@link validateAndDecodePathname}). These requests are
|
|
94
|
+
* rejected with a `400` before middleware or routing run.
|
|
95
|
+
*/
|
|
96
|
+
invalidEncoding = false;
|
|
90
97
|
/** A flag that tells the render content if the rewriting was triggered. */
|
|
91
98
|
isRewriting = false;
|
|
92
99
|
/** A safety net in case of loops (rewrite counter). */
|
|
@@ -110,6 +117,10 @@ class FetchState {
|
|
|
110
117
|
clientAddress;
|
|
111
118
|
/** Whether this is a partial render (container API). */
|
|
112
119
|
partial;
|
|
120
|
+
/** Internal metadata about the current response route type. */
|
|
121
|
+
responseRouteType;
|
|
122
|
+
/** Internal flag to prevent rerouting this response to an error page. */
|
|
123
|
+
skipErrorReroute = false;
|
|
113
124
|
/** Whether to inject CSP meta tags. */
|
|
114
125
|
shouldInjectCspMetaTags;
|
|
115
126
|
/** Request-scoped locals object, shared with user middleware. */
|
|
@@ -190,7 +201,7 @@ class FetchState {
|
|
|
190
201
|
this.locals = options?.locals ?? {};
|
|
191
202
|
this.url = normalizeUrl(url);
|
|
192
203
|
this.cookies = new AstroCookies(request);
|
|
193
|
-
if (pipeline.manifest.allowedDomains && pipeline.manifest.allowedDomains.length > 0) {
|
|
204
|
+
if (pipeline.manifest.allowedDomains && pipeline.manifest.allowedDomains.length > 0 && !this.routeData?.prerender) {
|
|
194
205
|
this.#applyForwardedHeaders();
|
|
195
206
|
}
|
|
196
207
|
if (!Reflect.get(this.request, originPathnameSymbol)) {
|
|
@@ -694,8 +705,12 @@ class FetchState {
|
|
|
694
705
|
}
|
|
695
706
|
pathname = prependForwardSlash(pathname);
|
|
696
707
|
try {
|
|
697
|
-
return
|
|
708
|
+
return validateAndDecodePathname(pathname);
|
|
698
709
|
} catch (e) {
|
|
710
|
+
if (e instanceof MultiLevelEncodingError) {
|
|
711
|
+
this.invalidEncoding = true;
|
|
712
|
+
return pathname;
|
|
713
|
+
}
|
|
699
714
|
this.pipeline.logger.error(null, e.toString());
|
|
700
715
|
return pathname;
|
|
701
716
|
}
|
|
@@ -875,6 +890,10 @@ class FetchState {
|
|
|
875
890
|
this.actionApiContext = null;
|
|
876
891
|
this.apiContext = null;
|
|
877
892
|
}
|
|
893
|
+
resetResponseMetadata() {
|
|
894
|
+
this.responseRouteType = void 0;
|
|
895
|
+
this.skipErrorReroute = false;
|
|
896
|
+
}
|
|
878
897
|
}
|
|
879
898
|
export {
|
|
880
899
|
FetchState,
|
|
@@ -13,13 +13,18 @@ export declare function astro(state: FetchState): Promise<Response>;
|
|
|
13
13
|
export declare function trailingSlash(state: FetchState): Response | undefined;
|
|
14
14
|
/**
|
|
15
15
|
* Runs Astro's middleware chain for the given state, calling `next` at
|
|
16
|
-
* the bottom of the chain to produce the response. Lazily creates
|
|
17
|
-
*
|
|
16
|
+
* the bottom of the chain to produce the response. Lazily creates the
|
|
17
|
+
* render context if needed. Unmatched routes render the 404 error page;
|
|
18
|
+
* errors thrown by user middleware are logged and render the 500 error
|
|
19
|
+
* page; errors surfaced through `next` (the host framework's downstream
|
|
20
|
+
* chain) propagate to the host instead.
|
|
18
21
|
*/
|
|
19
22
|
export declare function middleware(state: FetchState, next: (state: FetchState) => Promise<Response>): Promise<Response>;
|
|
20
23
|
/**
|
|
21
24
|
* Dispatches the request to the matched route (endpoint, page, redirect,
|
|
22
|
-
* or fallback). Lazily creates the render context if needed.
|
|
25
|
+
* or fallback). Lazily creates the render context if needed. Unmatched
|
|
26
|
+
* routes render the 404 error page; render-time errors are logged and
|
|
27
|
+
* render the 500 error page.
|
|
23
28
|
*/
|
|
24
29
|
export declare function pages(state: FetchState): Promise<Response>;
|
|
25
30
|
/**
|
package/dist/core/fetch/index.js
CHANGED
|
@@ -51,7 +51,7 @@ function middleware(state, next) {
|
|
|
51
51
|
mw = new AstroMiddleware(app.pipeline);
|
|
52
52
|
middlewareInstances.set(app, mw);
|
|
53
53
|
}
|
|
54
|
-
return mw.
|
|
54
|
+
return mw.handleWithErrorFallback(app, state, (s, _ctx) => next(s));
|
|
55
55
|
}
|
|
56
56
|
const pagesHandlers = /* @__PURE__ */ new WeakMap();
|
|
57
57
|
function pages(state) {
|
|
@@ -61,7 +61,7 @@ function pages(state) {
|
|
|
61
61
|
handler = new PagesHandler(app.pipeline);
|
|
62
62
|
pagesHandlers.set(app, handler);
|
|
63
63
|
}
|
|
64
|
-
return handler.
|
|
64
|
+
return handler.handleWithErrorFallback(app, state);
|
|
65
65
|
}
|
|
66
66
|
function sessions(state) {
|
|
67
67
|
return provideSession(state);
|