astro 4.10.3 → 4.11.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/components/Code.astro +9 -0
- package/dist/actions/runtime/virtual/server.d.ts +1 -1
- package/dist/assets/internal.d.ts +1 -1
- package/dist/assets/internal.js +6 -0
- package/dist/assets/types.d.ts +8 -2
- package/dist/assets/types.js +7 -0
- package/dist/container/pipeline.d.ts +0 -1
- package/dist/container/pipeline.js +13 -32
- package/dist/content/runtime-assets.d.ts +3 -3
- package/dist/content/types-generator.js +27 -6
- package/dist/core/app/index.d.ts +4 -0
- package/dist/core/app/index.js +17 -6
- package/dist/core/app/pipeline.d.ts +1 -2
- package/dist/core/app/pipeline.js +11 -39
- package/dist/core/base-pipeline.d.ts +0 -9
- package/dist/core/build/pipeline.d.ts +1 -2
- package/dist/core/build/pipeline.js +16 -42
- package/dist/core/constants.js +1 -1
- package/dist/core/cookies/cookies.d.ts +5 -0
- package/dist/core/cookies/cookies.js +12 -0
- package/dist/core/cookies/response.d.ts +1 -0
- package/dist/core/cookies/response.js +1 -0
- package/dist/core/create-vite.js +0 -4
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/errors/errors-data.d.ts +20 -11
- package/dist/core/errors/errors-data.js +7 -6
- package/dist/core/messages.js +2 -2
- package/dist/core/render-context.d.ts +1 -1
- package/dist/core/render-context.js +19 -6
- package/dist/core/request.js +7 -1
- package/dist/core/routing/rewrite.d.ts +10 -0
- package/dist/core/routing/rewrite.js +41 -0
- package/dist/vite-plugin-astro-server/pipeline.d.ts +1 -2
- package/dist/vite-plugin-astro-server/pipeline.js +15 -42
- package/dist/vite-plugin-astro-server/request.js +1 -1
- package/dist/vite-plugin-astro-server/route.js +39 -97
- package/package.json +4 -3
package/components/Code.astro
CHANGED
|
@@ -3,6 +3,7 @@ import type { ThemePresets } from '@astrojs/markdown-remark';
|
|
|
3
3
|
import type {
|
|
4
4
|
BuiltinLanguage,
|
|
5
5
|
LanguageRegistration,
|
|
6
|
+
ShikiTransformer,
|
|
6
7
|
SpecialLanguage,
|
|
7
8
|
ThemeRegistration,
|
|
8
9
|
ThemeRegistrationRaw,
|
|
@@ -50,6 +51,12 @@ interface Props extends Omit<HTMLAttributes<'pre'>, 'lang'> {
|
|
|
50
51
|
* @default false
|
|
51
52
|
*/
|
|
52
53
|
inline?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Shiki transformers to customize the generated HTML by manipulating the hast tree.
|
|
56
|
+
* Supports all transformers listed here: https://shiki.style/packages/transformers#transformers
|
|
57
|
+
* Instructions for custom transformers: https://shiki.style/guide/transformers
|
|
58
|
+
*/
|
|
59
|
+
transformers?: ShikiTransformer[];
|
|
53
60
|
}
|
|
54
61
|
|
|
55
62
|
const {
|
|
@@ -59,6 +66,7 @@ const {
|
|
|
59
66
|
themes = {},
|
|
60
67
|
wrap = false,
|
|
61
68
|
inline = false,
|
|
69
|
+
transformers = [],
|
|
62
70
|
...rest
|
|
63
71
|
} = Astro.props;
|
|
64
72
|
|
|
@@ -85,6 +93,7 @@ const highlighter = await getCachedHighlighter({
|
|
|
85
93
|
theme,
|
|
86
94
|
themes,
|
|
87
95
|
wrap,
|
|
96
|
+
transformers,
|
|
88
97
|
});
|
|
89
98
|
|
|
90
99
|
const html = await highlighter.highlight(code, typeof lang === 'string' ? lang : lang.name, {
|
|
@@ -14,7 +14,7 @@ export type ActionClient<TOutput, TAccept extends Accept, TInputSchema extends I
|
|
|
14
14
|
} : ((input?: any) => Promise<Awaited<TOutput>>) & {
|
|
15
15
|
safe: (input?: any) => Promise<SafeResult<never, Awaited<TOutput>>>;
|
|
16
16
|
};
|
|
17
|
-
export declare function defineAction<TOutput, TAccept extends Accept
|
|
17
|
+
export declare function defineAction<TOutput, TAccept extends Accept, TInputSchema extends InputSchema<Accept> | undefined = TAccept extends 'form' ? z.ZodType<FormData> : undefined>({ accept, input: inputSchema, handler, }: {
|
|
18
18
|
input?: TInputSchema;
|
|
19
19
|
accept?: TAccept;
|
|
20
20
|
handler: Handler<TInputSchema, TOutput>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AstroConfig } from '../@types/astro.js';
|
|
2
2
|
import { type ImageService } from './services/service.js';
|
|
3
|
-
import type
|
|
3
|
+
import { type GetImageResult, type UnresolvedImageTransform } from './types.js';
|
|
4
4
|
export declare function getConfiguredImageService(): Promise<ImageService>;
|
|
5
5
|
export declare function getImage(options: UnresolvedImageTransform, imageConfig: AstroConfig['image']): Promise<GetImageResult>;
|
package/dist/assets/internal.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { AstroError, AstroErrorData } from "../core/errors/index.js";
|
|
2
2
|
import { DEFAULT_HASH_PROPS } from "./consts.js";
|
|
3
3
|
import { isLocalService } from "./services/service.js";
|
|
4
|
+
import {
|
|
5
|
+
isImageMetadata
|
|
6
|
+
} from "./types.js";
|
|
4
7
|
import { isESMImportedImage, isRemoteImage, resolveSrc } from "./utils/imageKind.js";
|
|
5
8
|
import { probe } from "./utils/remoteProbe.js";
|
|
6
9
|
async function getConfiguredImageService() {
|
|
@@ -36,6 +39,9 @@ async function getImage(options, imageConfig) {
|
|
|
36
39
|
)
|
|
37
40
|
});
|
|
38
41
|
}
|
|
42
|
+
if (isImageMetadata(options)) {
|
|
43
|
+
throw new AstroError(AstroErrorData.ExpectedNotESMImage);
|
|
44
|
+
}
|
|
39
45
|
const service = await getConfiguredImageService();
|
|
40
46
|
const resolvedOptions = {
|
|
41
47
|
...options,
|
package/dist/assets/types.d.ts
CHANGED
|
@@ -20,16 +20,20 @@ declare global {
|
|
|
20
20
|
referencedImages?: Set<string>;
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
+
declare const isESMImport: unique symbol;
|
|
24
|
+
export type OmitBrand<T> = Omit<T, typeof isESMImport>;
|
|
23
25
|
/**
|
|
24
26
|
* Type returned by ESM imports of images
|
|
25
27
|
*/
|
|
26
|
-
export
|
|
28
|
+
export type ImageMetadata = {
|
|
27
29
|
src: string;
|
|
28
30
|
width: number;
|
|
29
31
|
height: number;
|
|
30
32
|
format: ImageInputFormat;
|
|
31
33
|
orientation?: number;
|
|
32
|
-
|
|
34
|
+
[isESMImport]?: true;
|
|
35
|
+
};
|
|
36
|
+
export declare function isImageMetadata(src: any): src is ImageMetadata;
|
|
33
37
|
/**
|
|
34
38
|
* A yet to be completed with an url `SrcSetValue`. Other hooks will only see a resolved value, where the URL of the image has been added.
|
|
35
39
|
*/
|
|
@@ -49,6 +53,8 @@ export type UnresolvedImageTransform = Omit<ImageTransform, 'src'> & {
|
|
|
49
53
|
default: ImageMetadata;
|
|
50
54
|
}>;
|
|
51
55
|
inferSize?: boolean;
|
|
56
|
+
} & {
|
|
57
|
+
[isESMImport]?: never;
|
|
52
58
|
};
|
|
53
59
|
/**
|
|
54
60
|
* Options accepted by the image transformation service.
|
package/dist/assets/types.js
CHANGED
|
@@ -8,5 +8,4 @@ export declare class ContainerPipeline extends Pipeline {
|
|
|
8
8
|
tryRewrite(payload: RewritePayload, request: Request): Promise<[RouteData, ComponentInstance, URL]>;
|
|
9
9
|
insertRoute(route: RouteData, componentInstance: ComponentInstance): void;
|
|
10
10
|
getComponentByRoute(_routeData: RouteData): Promise<ComponentInstance>;
|
|
11
|
-
rewriteKnownRoute(pathname: string, _sourceRoute: RouteData): ComponentInstance;
|
|
12
11
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Pipeline } from "../core/base-pipeline.js";
|
|
2
|
-
import {
|
|
2
|
+
import { RouteNotFound } from "../core/errors/errors-data.js";
|
|
3
3
|
import { AstroError } from "../core/errors/index.js";
|
|
4
4
|
import {
|
|
5
5
|
createModuleScriptElement,
|
|
6
6
|
createStylesheetElementSet
|
|
7
7
|
} from "../core/render/ssr-element.js";
|
|
8
|
-
import { DEFAULT_404_ROUTE
|
|
8
|
+
import { DEFAULT_404_ROUTE } from "../core/routing/astro-designed-error-pages.js";
|
|
9
|
+
import { findRouteToRewrite } from "../core/routing/rewrite.js";
|
|
9
10
|
class ContainerPipeline extends Pipeline {
|
|
10
11
|
/**
|
|
11
12
|
* Internal cache to store components instances by `RouteData`.
|
|
@@ -52,30 +53,16 @@ class ContainerPipeline extends Pipeline {
|
|
|
52
53
|
return { links, styles, scripts };
|
|
53
54
|
}
|
|
54
55
|
async tryRewrite(payload, request) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (route.routeData.pattern.test(decodeURI(finalUrl.pathname))) {
|
|
66
|
-
foundRoute = route.routeData;
|
|
67
|
-
break;
|
|
68
|
-
} else if (finalUrl.pathname === "/404") {
|
|
69
|
-
foundRoute = DEFAULT_404_ROUTE;
|
|
70
|
-
break;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
if (foundRoute && finalUrl) {
|
|
74
|
-
const componentInstance = await this.getComponentByRoute(foundRoute);
|
|
75
|
-
return [foundRoute, componentInstance, finalUrl];
|
|
76
|
-
} else {
|
|
77
|
-
throw new AstroError(RouteNotFound);
|
|
78
|
-
}
|
|
56
|
+
const [foundRoute, finalUrl] = findRouteToRewrite({
|
|
57
|
+
payload,
|
|
58
|
+
request,
|
|
59
|
+
routes: this.manifest?.routes.map((r) => r.routeData),
|
|
60
|
+
trailingSlash: this.manifest.trailingSlash,
|
|
61
|
+
buildFormat: this.manifest.buildFormat,
|
|
62
|
+
base: this.manifest.base
|
|
63
|
+
});
|
|
64
|
+
const componentInstance = await this.getComponentByRoute(foundRoute);
|
|
65
|
+
return [foundRoute, componentInstance, finalUrl];
|
|
79
66
|
}
|
|
80
67
|
insertRoute(route, componentInstance) {
|
|
81
68
|
this.#componentsInterner.set(route, {
|
|
@@ -90,12 +77,6 @@ class ContainerPipeline extends Pipeline {
|
|
|
90
77
|
// @ts-expect-error It needs to be implemented.
|
|
91
78
|
async getComponentByRoute(_routeData) {
|
|
92
79
|
}
|
|
93
|
-
rewriteKnownRoute(pathname, _sourceRoute) {
|
|
94
|
-
if (pathname === "/404") {
|
|
95
|
-
return { default: default404Page };
|
|
96
|
-
}
|
|
97
|
-
throw new AstroError(InvalidRewrite404);
|
|
98
|
-
}
|
|
99
80
|
}
|
|
100
81
|
export {
|
|
101
82
|
ContainerPipeline
|
|
@@ -2,10 +2,10 @@ import type { PluginContext } from 'rollup';
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export declare function createImage(pluginContext: PluginContext, shouldEmitFile: boolean, entryFilePath: string): () => z.ZodEffects<z.ZodString, z.ZodNever | {
|
|
4
4
|
ASTRO_ASSET: string;
|
|
5
|
-
|
|
5
|
+
format: "jpeg" | "jpg" | "png" | "tiff" | "webp" | "gif" | "svg" | "avif";
|
|
6
6
|
width: number;
|
|
7
7
|
height: number;
|
|
8
|
-
|
|
9
|
-
orientation?: number | undefined;
|
|
8
|
+
src: string;
|
|
10
9
|
fsPath: string;
|
|
10
|
+
orientation?: number | undefined;
|
|
11
11
|
}, string>;
|
|
@@ -318,13 +318,26 @@ async function writeContentFiles({
|
|
|
318
318
|
// This ensures `getCollection('empty-collection')` doesn't raise a type error
|
|
319
319
|
collectionConfig?.type ?? "data"
|
|
320
320
|
) : collection.type;
|
|
321
|
+
const collectionEntryKeys = Object.keys(collection.entries).sort();
|
|
322
|
+
const dataType = collectionConfig?.schema ? `InferEntrySchema<${collectionKey}>` : "any";
|
|
321
323
|
switch (resolvedType) {
|
|
322
324
|
case "content":
|
|
325
|
+
if (collectionEntryKeys.length === 0) {
|
|
326
|
+
contentTypesStr += `${collectionKey}: Record<string, {
|
|
327
|
+
id: string;
|
|
328
|
+
slug: string;
|
|
329
|
+
body: string;
|
|
330
|
+
collection: ${collectionKey};
|
|
331
|
+
data: ${dataType};
|
|
332
|
+
render(): Render[".md"];
|
|
333
|
+
}>;
|
|
334
|
+
`;
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
323
337
|
contentTypesStr += `${collectionKey}: {
|
|
324
338
|
`;
|
|
325
|
-
for (const entryKey of
|
|
339
|
+
for (const entryKey of collectionEntryKeys) {
|
|
326
340
|
const entryMetadata = collection.entries[entryKey];
|
|
327
|
-
const dataType = collectionConfig?.schema ? `InferEntrySchema<${collectionKey}>` : "any";
|
|
328
341
|
const renderType = `{ render(): Render[${JSON.stringify(
|
|
329
342
|
path.extname(JSON.parse(entryKey))
|
|
330
343
|
)}] }`;
|
|
@@ -342,16 +355,24 @@ async function writeContentFiles({
|
|
|
342
355
|
`;
|
|
343
356
|
break;
|
|
344
357
|
case "data":
|
|
345
|
-
|
|
358
|
+
if (collectionEntryKeys.length === 0) {
|
|
359
|
+
dataTypesStr += `${collectionKey}: Record<string, {
|
|
360
|
+
id: string;
|
|
361
|
+
collection: ${collectionKey};
|
|
362
|
+
data: ${dataType};
|
|
363
|
+
}>;
|
|
346
364
|
`;
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
365
|
+
} else {
|
|
366
|
+
dataTypesStr += `${collectionKey}: {
|
|
367
|
+
`;
|
|
368
|
+
for (const entryKey of collectionEntryKeys) {
|
|
369
|
+
dataTypesStr += `${entryKey}: {
|
|
350
370
|
id: ${entryKey};
|
|
351
371
|
collection: ${collectionKey};
|
|
352
372
|
data: ${dataType}
|
|
353
373
|
};
|
|
354
374
|
`;
|
|
375
|
+
}
|
|
355
376
|
dataTypesStr += `};
|
|
356
377
|
`;
|
|
357
378
|
}
|
package/dist/core/app/index.d.ts
CHANGED
|
@@ -39,6 +39,10 @@ export interface RenderErrorOptions {
|
|
|
39
39
|
* Whether to skip middleware while rendering the error page. Defaults to false.
|
|
40
40
|
*/
|
|
41
41
|
skipMiddleware?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Allows passing an error to 500.astro. It will be available through `Astro.props.error`.
|
|
44
|
+
*/
|
|
45
|
+
error?: unknown;
|
|
42
46
|
}
|
|
43
47
|
export declare class App {
|
|
44
48
|
#private;
|
package/dist/core/app/index.js
CHANGED
|
@@ -195,8 +195,9 @@ class App {
|
|
|
195
195
|
}
|
|
196
196
|
if (locals) {
|
|
197
197
|
if (typeof locals !== "object") {
|
|
198
|
-
|
|
199
|
-
|
|
198
|
+
const error = new AstroError(AstroErrorData.LocalsNotAnObject);
|
|
199
|
+
this.#logger.error(null, error.stack);
|
|
200
|
+
return this.#renderError(request, { status: 500, error });
|
|
200
201
|
}
|
|
201
202
|
Reflect.set(request, clientLocalsSymbol, locals);
|
|
202
203
|
}
|
|
@@ -229,13 +230,16 @@ class App {
|
|
|
229
230
|
response = await renderContext.render(await mod.page());
|
|
230
231
|
} catch (err) {
|
|
231
232
|
this.#logger.error(null, err.stack || err.message || String(err));
|
|
232
|
-
return this.#renderError(request, { locals, status: 500 });
|
|
233
|
+
return this.#renderError(request, { locals, status: 500, error: err });
|
|
233
234
|
}
|
|
234
235
|
if (REROUTABLE_STATUS_CODES.includes(response.status) && response.headers.get(REROUTE_DIRECTIVE_HEADER) !== "no") {
|
|
235
236
|
return this.#renderError(request, {
|
|
236
237
|
locals,
|
|
237
238
|
response,
|
|
238
|
-
status: response.status
|
|
239
|
+
status: response.status,
|
|
240
|
+
// We don't have an error to report here. Passing null means we pass nothing intentionally
|
|
241
|
+
// while undefined means there's no error
|
|
242
|
+
error: response.status === 500 ? null : void 0
|
|
239
243
|
});
|
|
240
244
|
}
|
|
241
245
|
if (response.headers.has(REROUTE_DIRECTIVE_HEADER)) {
|
|
@@ -276,7 +280,13 @@ class App {
|
|
|
276
280
|
* If it is a known error code, try sending the according page (e.g. 404.astro / 500.astro).
|
|
277
281
|
* This also handles pre-rendered /404 or /500 routes
|
|
278
282
|
*/
|
|
279
|
-
async #renderError(request, {
|
|
283
|
+
async #renderError(request, {
|
|
284
|
+
locals,
|
|
285
|
+
status,
|
|
286
|
+
response: originalResponse,
|
|
287
|
+
skipMiddleware = false,
|
|
288
|
+
error
|
|
289
|
+
}) {
|
|
280
290
|
const errorRoutePath = `/${status}${this.#manifest.trailingSlash === "always" ? "/" : ""}`;
|
|
281
291
|
const errorRouteData = matchRoute(errorRoutePath, this.#manifestData);
|
|
282
292
|
const url = new URL(request.url);
|
|
@@ -300,7 +310,8 @@ class App {
|
|
|
300
310
|
pathname: this.#getPathnameFromRequest(request),
|
|
301
311
|
request,
|
|
302
312
|
routeData: errorRouteData,
|
|
303
|
-
status
|
|
313
|
+
status,
|
|
314
|
+
props: { error }
|
|
304
315
|
});
|
|
305
316
|
const response2 = await renderContext.render(await mod.page());
|
|
306
317
|
return this.#mergeResponses(response2, originalResponse);
|
|
@@ -7,7 +7,6 @@ export declare class AppPipeline extends Pipeline {
|
|
|
7
7
|
headElements(routeData: RouteData): Pick<SSRResult, 'scripts' | 'styles' | 'links'>;
|
|
8
8
|
componentMetadata(): void;
|
|
9
9
|
getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
|
|
10
|
-
tryRewrite(payload: RewritePayload, request: Request,
|
|
10
|
+
tryRewrite(payload: RewritePayload, request: Request, _sourceRoute: RouteData): Promise<[RouteData, ComponentInstance, URL]>;
|
|
11
11
|
getModuleForRoute(route: RouteData): Promise<SinglePageBuiltModule>;
|
|
12
|
-
rewriteKnownRoute(pathname: string, _sourceRoute: RouteData): ComponentInstance;
|
|
13
12
|
}
|
|
@@ -5,6 +5,7 @@ import { AstroError } from "../errors/index.js";
|
|
|
5
5
|
import { RedirectSinglePageBuiltModule } from "../redirects/component.js";
|
|
6
6
|
import { createModuleScriptElement, createStylesheetElementSet } from "../render/ssr-element.js";
|
|
7
7
|
import { DEFAULT_404_ROUTE } from "../routing/astro-designed-error-pages.js";
|
|
8
|
+
import { findRouteToRewrite } from "../routing/rewrite.js";
|
|
8
9
|
class AppPipeline extends Pipeline {
|
|
9
10
|
#manifestData;
|
|
10
11
|
static create(manifestData, {
|
|
@@ -62,38 +63,17 @@ class AppPipeline extends Pipeline {
|
|
|
62
63
|
const module = await this.getModuleForRoute(routeData);
|
|
63
64
|
return module.page();
|
|
64
65
|
}
|
|
65
|
-
async tryRewrite(payload, request,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
} else {
|
|
74
|
-
finalUrl = new URL(payload, new URL(request.url).origin);
|
|
75
|
-
}
|
|
76
|
-
if (route.pattern.test(decodeURI(finalUrl.pathname))) {
|
|
77
|
-
foundRoute = route;
|
|
78
|
-
break;
|
|
79
|
-
} else if (finalUrl.pathname === "/404") {
|
|
80
|
-
foundRoute = DEFAULT_404_ROUTE;
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
if (foundRoute && finalUrl) {
|
|
85
|
-
if (foundRoute.pathname === "/404") {
|
|
86
|
-
const componentInstance = this.rewriteKnownRoute(foundRoute.pathname, sourceRoute);
|
|
87
|
-
return [foundRoute, componentInstance, finalUrl];
|
|
88
|
-
} else {
|
|
89
|
-
const componentInstance = await this.getComponentByRoute(foundRoute);
|
|
90
|
-
return [foundRoute, componentInstance, finalUrl];
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
throw new AstroError({
|
|
94
|
-
...RewriteEncounteredAnError,
|
|
95
|
-
message: RewriteEncounteredAnError.message(payload.toString())
|
|
66
|
+
async tryRewrite(payload, request, _sourceRoute) {
|
|
67
|
+
const [foundRoute, finalUrl] = findRouteToRewrite({
|
|
68
|
+
payload,
|
|
69
|
+
request,
|
|
70
|
+
routes: this.manifest?.routes.map((r) => r.routeData),
|
|
71
|
+
trailingSlash: this.manifest.trailingSlash,
|
|
72
|
+
buildFormat: this.manifest.buildFormat,
|
|
73
|
+
base: this.manifest.base
|
|
96
74
|
});
|
|
75
|
+
const componentInstance = await this.getComponentByRoute(foundRoute);
|
|
76
|
+
return [foundRoute, componentInstance, finalUrl];
|
|
97
77
|
}
|
|
98
78
|
async getModuleForRoute(route) {
|
|
99
79
|
if (route.component === DEFAULT_404_COMPONENT) {
|
|
@@ -121,14 +101,6 @@ class AppPipeline extends Pipeline {
|
|
|
121
101
|
);
|
|
122
102
|
}
|
|
123
103
|
}
|
|
124
|
-
// We don't need to check the source route, we already are in SSR
|
|
125
|
-
rewriteKnownRoute(pathname, _sourceRoute) {
|
|
126
|
-
if (pathname === "/404") {
|
|
127
|
-
return { default: () => new Response(null, { status: 404 }) };
|
|
128
|
-
} else {
|
|
129
|
-
return { default: () => new Response(null, { status: 500 }) };
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
104
|
}
|
|
133
105
|
export {
|
|
134
106
|
AppPipeline
|
|
@@ -73,15 +73,6 @@ export declare abstract class Pipeline {
|
|
|
73
73
|
* @param routeData
|
|
74
74
|
*/
|
|
75
75
|
abstract getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
|
|
76
|
-
/**
|
|
77
|
-
* Attempts to execute a rewrite of a known Astro route:
|
|
78
|
-
* - /404 -> src/pages/404.astro -> template
|
|
79
|
-
* - /500 -> src/pages/500.astro
|
|
80
|
-
*
|
|
81
|
-
* @param pathname The pathname where the user wants to rewrite e.g. "/404"
|
|
82
|
-
* @param sourceRoute The original route where the first request started. This is needed in case a pipeline wants to check if the current route is pre-rendered or not
|
|
83
|
-
*/
|
|
84
|
-
abstract rewriteKnownRoute(pathname: string, sourceRoute: RouteData): ComponentInstance;
|
|
85
76
|
}
|
|
86
77
|
export interface HeadElements extends Pick<SSRResult, 'scripts' | 'styles' | 'links'> {
|
|
87
78
|
}
|
|
@@ -38,7 +38,6 @@ export declare class BuildPipeline extends Pipeline {
|
|
|
38
38
|
*/
|
|
39
39
|
retrieveRoutesToGenerate(): Map<PageBuildData, string>;
|
|
40
40
|
getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
|
|
41
|
-
tryRewrite(payload: RewritePayload, request: Request,
|
|
41
|
+
tryRewrite(payload: RewritePayload, request: Request, _sourceRoute: RouteData): Promise<[RouteData, ComponentInstance, URL]>;
|
|
42
42
|
retrieveSsrEntry(route: RouteData, filePath: string): Promise<SinglePageBuiltModule>;
|
|
43
|
-
rewriteKnownRoute(_pathname: string, sourceRoute: RouteData): ComponentInstance;
|
|
44
43
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { getOutputDirectory } from "../../prerender/utils.js";
|
|
2
2
|
import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from "../../vite-plugin-scripts/index.js";
|
|
3
|
-
import {
|
|
4
|
-
import { AstroError } from "../errors/index.js";
|
|
3
|
+
import { DEFAULT_404_COMPONENT } from "../constants.js";
|
|
5
4
|
import { routeIsFallback, routeIsRedirect } from "../redirects/helpers.js";
|
|
6
5
|
import { RedirectSinglePageBuiltModule } from "../redirects/index.js";
|
|
7
6
|
import { Pipeline } from "../render/index.js";
|
|
@@ -10,7 +9,8 @@ import {
|
|
|
10
9
|
createModuleScriptsSet,
|
|
11
10
|
createStylesheetElementSet
|
|
12
11
|
} from "../render/ssr-element.js";
|
|
13
|
-
import {
|
|
12
|
+
import { default404Page } from "../routing/astro-designed-error-pages.js";
|
|
13
|
+
import { findRouteToRewrite } from "../routing/rewrite.js";
|
|
14
14
|
import { isServerLikeOutput } from "../util.js";
|
|
15
15
|
import { getOutDirWithinCwd } from "./common.js";
|
|
16
16
|
import { cssOrder, getPageData, mergeInlineCss } from "./internal.js";
|
|
@@ -201,45 +201,25 @@ class BuildPipeline extends Pipeline {
|
|
|
201
201
|
if (this.#componentsInterner.has(routeData)) {
|
|
202
202
|
const entry = this.#componentsInterner.get(routeData);
|
|
203
203
|
return await entry.page();
|
|
204
|
+
} else if (routeData.component === DEFAULT_404_COMPONENT) {
|
|
205
|
+
return { default: default404Page };
|
|
204
206
|
} else {
|
|
205
207
|
const filePath = this.#routesByFilePath.get(routeData);
|
|
206
208
|
const module = await this.retrieveSsrEntry(routeData, filePath);
|
|
207
209
|
return module.page();
|
|
208
210
|
}
|
|
209
211
|
}
|
|
210
|
-
async tryRewrite(payload, request,
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if (route.pattern.test(decodeURI(finalUrl.pathname))) {
|
|
222
|
-
foundRoute = route;
|
|
223
|
-
break;
|
|
224
|
-
} else if (finalUrl.pathname === "/404") {
|
|
225
|
-
foundRoute = DEFAULT_404_ROUTE;
|
|
226
|
-
break;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
if (foundRoute && finalUrl) {
|
|
230
|
-
if (foundRoute.pathname === "/404") {
|
|
231
|
-
const componentInstance = await this.rewriteKnownRoute(foundRoute.pathname, sourceRoute);
|
|
232
|
-
return [foundRoute, componentInstance, finalUrl];
|
|
233
|
-
} else {
|
|
234
|
-
const componentInstance = await this.getComponentByRoute(foundRoute);
|
|
235
|
-
return [foundRoute, componentInstance, finalUrl];
|
|
236
|
-
}
|
|
237
|
-
} else {
|
|
238
|
-
throw new AstroError({
|
|
239
|
-
...RewriteEncounteredAnError,
|
|
240
|
-
message: RewriteEncounteredAnError.message(payload.toString())
|
|
241
|
-
});
|
|
242
|
-
}
|
|
212
|
+
async tryRewrite(payload, request, _sourceRoute) {
|
|
213
|
+
const [foundRoute, finalUrl] = findRouteToRewrite({
|
|
214
|
+
payload,
|
|
215
|
+
request,
|
|
216
|
+
routes: this.options.manifest.routes,
|
|
217
|
+
trailingSlash: this.config.trailingSlash,
|
|
218
|
+
buildFormat: this.config.build.format,
|
|
219
|
+
base: this.config.base
|
|
220
|
+
});
|
|
221
|
+
const componentInstance = await this.getComponentByRoute(foundRoute);
|
|
222
|
+
return [foundRoute, componentInstance, finalUrl];
|
|
243
223
|
}
|
|
244
224
|
async retrieveSsrEntry(route, filePath) {
|
|
245
225
|
if (this.#componentsInterner.has(route)) {
|
|
@@ -285,12 +265,6 @@ class BuildPipeline extends Pipeline {
|
|
|
285
265
|
}
|
|
286
266
|
return RedirectSinglePageBuiltModule;
|
|
287
267
|
}
|
|
288
|
-
rewriteKnownRoute(_pathname, sourceRoute) {
|
|
289
|
-
if (!isServerLikeOutput(this.config) || sourceRoute.prerender) {
|
|
290
|
-
throw new AstroError(InvalidRewrite404);
|
|
291
|
-
}
|
|
292
|
-
throw new Error(`Unreachable, in SSG this route shouldn't be generated`);
|
|
293
|
-
}
|
|
294
268
|
}
|
|
295
269
|
function createEntryURL(filePath, outFolder) {
|
|
296
270
|
return new URL("./" + filePath + `?time=${Date.now()}`, outFolder);
|
package/dist/core/constants.js
CHANGED
|
@@ -58,6 +58,11 @@ declare class AstroCookies implements AstroCookiesInterface {
|
|
|
58
58
|
* @param options Options for the cookie, such as the path and security settings.
|
|
59
59
|
*/
|
|
60
60
|
set(key: string, value: string | Record<string, any>, options?: AstroCookieSetOptions): void;
|
|
61
|
+
/**
|
|
62
|
+
* Merges a new AstroCookies instance into the current instance. Any new cookies
|
|
63
|
+
* will be added to the current instance, overwriting any existing cookies with the same name.
|
|
64
|
+
*/
|
|
65
|
+
merge(cookies: AstroCookies): void;
|
|
61
66
|
/**
|
|
62
67
|
* Astro.cookies.header() returns an iterator for the cookies that have previously
|
|
63
68
|
* been set by either Astro.cookies.set() or Astro.cookies.delete().
|
|
@@ -136,6 +136,18 @@ class AstroCookies {
|
|
|
136
136
|
});
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Merges a new AstroCookies instance into the current instance. Any new cookies
|
|
141
|
+
* will be added to the current instance, overwriting any existing cookies with the same name.
|
|
142
|
+
*/
|
|
143
|
+
merge(cookies) {
|
|
144
|
+
const outgoing = cookies.#outgoing;
|
|
145
|
+
if (outgoing) {
|
|
146
|
+
for (const [key, value] of outgoing) {
|
|
147
|
+
this.#ensureOutgoingMap().set(key, value);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
139
151
|
/**
|
|
140
152
|
* Astro.cookies.header() returns an iterator for the cookies that have previously
|
|
141
153
|
* been set by either Astro.cookies.set() or Astro.cookies.delete().
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AstroCookies } from './cookies.js';
|
|
2
2
|
export declare function attachCookiesToResponse(response: Response, cookies: AstroCookies): void;
|
|
3
3
|
export declare function responseHasCookies(response: Response): boolean;
|
|
4
|
+
export declare function getFromResponse(response: Response): AstroCookies | undefined;
|
|
4
5
|
export declare function getSetCookiesFromResponse(response: Response): Generator<string, string[]>;
|
package/dist/core/create-vite.js
CHANGED
|
@@ -146,10 +146,6 @@ async function createVite(commandConfig, { settings, logger, mode, command, fs =
|
|
|
146
146
|
server: {
|
|
147
147
|
hmr: process.env.NODE_ENV === "test" || process.env.NODE_ENV === "production" ? false : void 0,
|
|
148
148
|
// disable HMR for test
|
|
149
|
-
// handle Vite URLs
|
|
150
|
-
proxy: {
|
|
151
|
-
// add proxies here
|
|
152
|
-
},
|
|
153
149
|
watch: {
|
|
154
150
|
// Prevent watching during the build to speed it up
|
|
155
151
|
ignored: mode === "build" ? ["**"] : void 0
|
package/dist/core/dev/dev.js
CHANGED
|
@@ -19,7 +19,7 @@ async function dev(inlineConfig) {
|
|
|
19
19
|
await telemetry.record([]);
|
|
20
20
|
const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
|
|
21
21
|
const logger = restart.container.logger;
|
|
22
|
-
const currentVersion = "4.
|
|
22
|
+
const currentVersion = "4.11.0";
|
|
23
23
|
const isPrerelease = currentVersion.includes("-");
|
|
24
24
|
if (!isPrerelease) {
|
|
25
25
|
try {
|
|
@@ -588,6 +588,26 @@ export declare const ExpectedImageOptions: {
|
|
|
588
588
|
title: string;
|
|
589
589
|
message: (options: string) => string;
|
|
590
590
|
};
|
|
591
|
+
/**
|
|
592
|
+
* @docs
|
|
593
|
+
* @see
|
|
594
|
+
* - [Images](https://docs.astro.build/en/guides/images/)
|
|
595
|
+
* @description
|
|
596
|
+
* An ESM-imported image cannot be passed directly to `getImage()`. Instead, pass an object with the image in the `src` property.
|
|
597
|
+
*
|
|
598
|
+
* ```diff
|
|
599
|
+
* import { getImage } from "astro:assets";
|
|
600
|
+
* import myImage from "../assets/my_image.png";
|
|
601
|
+
* - const optimizedImage = await getImage( myImage );
|
|
602
|
+
* + const optimizedImage = await getImage({ src: myImage });
|
|
603
|
+
* ```
|
|
604
|
+
*/
|
|
605
|
+
export declare const ExpectedNotESMImage: {
|
|
606
|
+
name: string;
|
|
607
|
+
title: string;
|
|
608
|
+
message: string;
|
|
609
|
+
hint: string;
|
|
610
|
+
};
|
|
591
611
|
/**
|
|
592
612
|
* @docs
|
|
593
613
|
* @see
|
|
@@ -1010,17 +1030,6 @@ export declare const RewriteEncounteredAnError: {
|
|
|
1010
1030
|
title: string;
|
|
1011
1031
|
message: (route: string, stack?: string) => string;
|
|
1012
1032
|
};
|
|
1013
|
-
/**
|
|
1014
|
-
* @docs
|
|
1015
|
-
* @description
|
|
1016
|
-
*
|
|
1017
|
-
* The user tried to rewrite a 404 page inside a static page.
|
|
1018
|
-
*/
|
|
1019
|
-
export declare const InvalidRewrite404: {
|
|
1020
|
-
name: string;
|
|
1021
|
-
title: string;
|
|
1022
|
-
message: string;
|
|
1023
|
-
};
|
|
1024
1033
|
/**
|
|
1025
1034
|
* @docs
|
|
1026
1035
|
* @description
|
|
@@ -209,6 +209,12 @@ const ExpectedImageOptions = {
|
|
|
209
209
|
title: "Expected image options.",
|
|
210
210
|
message: (options) => `Expected getImage() parameter to be an object. Received \`${options}\`.`
|
|
211
211
|
};
|
|
212
|
+
const ExpectedNotESMImage = {
|
|
213
|
+
name: "ExpectedNotESMImage",
|
|
214
|
+
title: "Expected image options, not an ESM-imported image.",
|
|
215
|
+
message: "An ESM-imported image cannot be passed directly to `getImage()`. Instead, pass an object with the image in the `src` property.",
|
|
216
|
+
hint: "Try changing `getImage(myImage)` to `getImage({ src: myImage })`"
|
|
217
|
+
};
|
|
212
218
|
const IncompatibleDescriptorOptions = {
|
|
213
219
|
name: "IncompatibleDescriptorOptions",
|
|
214
220
|
title: "Cannot set both `densities` and `widths`",
|
|
@@ -361,11 +367,6 @@ const RewriteEncounteredAnError = {
|
|
|
361
367
|
title: "Astro couldn't find the route to rewrite, or if was found but it emitted an error during the rendering phase.",
|
|
362
368
|
message: (route, stack) => `The route ${route} that you tried to render doesn't exist, or it emitted an error during the rendering phase. ${stack ? stack : ""}.`
|
|
363
369
|
};
|
|
364
|
-
const InvalidRewrite404 = {
|
|
365
|
-
name: "InvalidRewrite404",
|
|
366
|
-
title: "You attempted to rewrite a 404 inside a static page, and this isn't allowed.",
|
|
367
|
-
message: "Rewriting a 404 is only allowed inside on-demand pages."
|
|
368
|
-
};
|
|
369
370
|
const CantRenderPage = {
|
|
370
371
|
name: "CantRenderPage",
|
|
371
372
|
title: "Astro can't render the route.",
|
|
@@ -581,6 +582,7 @@ export {
|
|
|
581
582
|
EnvUnsupportedGetSecret,
|
|
582
583
|
ExpectedImage,
|
|
583
584
|
ExpectedImageOptions,
|
|
585
|
+
ExpectedNotESMImage,
|
|
584
586
|
FailedToFetchRemoteImageDimensions,
|
|
585
587
|
FailedToFindPageMapSSR,
|
|
586
588
|
FailedToLoadModuleSSR,
|
|
@@ -604,7 +606,6 @@ export {
|
|
|
604
606
|
InvalidGlob,
|
|
605
607
|
InvalidImageService,
|
|
606
608
|
InvalidPrerenderExport,
|
|
607
|
-
InvalidRewrite404,
|
|
608
609
|
LocalImageUsedWrongly,
|
|
609
610
|
LocalsNotAnObject,
|
|
610
611
|
MarkdownFrontmatterParseError,
|
package/dist/core/messages.js
CHANGED
|
@@ -37,7 +37,7 @@ function serverStart({
|
|
|
37
37
|
host,
|
|
38
38
|
base
|
|
39
39
|
}) {
|
|
40
|
-
const version = "4.
|
|
40
|
+
const version = "4.11.0";
|
|
41
41
|
const localPrefix = `${dim("\u2503")} Local `;
|
|
42
42
|
const networkPrefix = `${dim("\u2503")} Network `;
|
|
43
43
|
const emptyPrefix = " ".repeat(11);
|
|
@@ -269,7 +269,7 @@ function printHelp({
|
|
|
269
269
|
message.push(
|
|
270
270
|
linebreak(),
|
|
271
271
|
` ${bgGreen(black(` ${commandName} `))} ${green(
|
|
272
|
-
`v${"4.
|
|
272
|
+
`v${"4.11.0"}`
|
|
273
273
|
)} ${headline}`
|
|
274
274
|
);
|
|
275
275
|
}
|
|
@@ -29,7 +29,7 @@ export declare class RenderContext {
|
|
|
29
29
|
* A safety net in case of loops
|
|
30
30
|
*/
|
|
31
31
|
counter: number;
|
|
32
|
-
static create({ locals, middleware, pathname, pipeline, request, routeData, status, }: Pick<RenderContext, 'pathname' | 'pipeline' | 'request' | 'routeData'> & Partial<Pick<RenderContext, 'locals' | 'middleware' | 'status'>>): RenderContext;
|
|
32
|
+
static create({ locals, middleware, pathname, pipeline, request, routeData, status, props, }: Pick<RenderContext, 'pathname' | 'pipeline' | 'request' | 'routeData'> & Partial<Pick<RenderContext, 'locals' | 'middleware' | 'status' | 'props'>>): RenderContext;
|
|
33
33
|
/**
|
|
34
34
|
* The main function of the RenderContext.
|
|
35
35
|
*
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
responseSentSymbol
|
|
16
16
|
} from "./constants.js";
|
|
17
17
|
import { AstroCookies, attachCookiesToResponse } from "./cookies/index.js";
|
|
18
|
+
import { getFromResponse } from "./cookies/response.js";
|
|
18
19
|
import { AstroError, AstroErrorData } from "./errors/index.js";
|
|
19
20
|
import { callMiddleware } from "./middleware/callMiddleware.js";
|
|
20
21
|
import { sequence } from "./middleware/index.js";
|
|
@@ -52,7 +53,8 @@ class RenderContext {
|
|
|
52
53
|
pipeline,
|
|
53
54
|
request,
|
|
54
55
|
routeData,
|
|
55
|
-
status = 200
|
|
56
|
+
status = 200,
|
|
57
|
+
props
|
|
56
58
|
}) {
|
|
57
59
|
return new RenderContext(
|
|
58
60
|
pipeline,
|
|
@@ -61,7 +63,11 @@ class RenderContext {
|
|
|
61
63
|
pathname,
|
|
62
64
|
request,
|
|
63
65
|
routeData,
|
|
64
|
-
status
|
|
66
|
+
status,
|
|
67
|
+
void 0,
|
|
68
|
+
void 0,
|
|
69
|
+
void 0,
|
|
70
|
+
props
|
|
65
71
|
);
|
|
66
72
|
}
|
|
67
73
|
/**
|
|
@@ -113,14 +119,16 @@ class RenderContext {
|
|
|
113
119
|
);
|
|
114
120
|
}
|
|
115
121
|
}
|
|
122
|
+
let response2;
|
|
116
123
|
switch (this.routeData.type) {
|
|
117
|
-
case "endpoint":
|
|
118
|
-
|
|
124
|
+
case "endpoint": {
|
|
125
|
+
response2 = await renderEndpoint(componentInstance, ctx, serverLike, logger);
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
119
128
|
case "redirect":
|
|
120
129
|
return renderRedirect(this);
|
|
121
130
|
case "page": {
|
|
122
131
|
const result = await this.createResult(componentInstance);
|
|
123
|
-
let response2;
|
|
124
132
|
try {
|
|
125
133
|
response2 = await renderPage(
|
|
126
134
|
result,
|
|
@@ -138,12 +146,17 @@ class RenderContext {
|
|
|
138
146
|
if (this.routeData.route === "/404" || this.routeData.route === "/500" || this.isRewriting) {
|
|
139
147
|
response2.headers.set(REROUTE_DIRECTIVE_HEADER, "no");
|
|
140
148
|
}
|
|
141
|
-
|
|
149
|
+
break;
|
|
142
150
|
}
|
|
143
151
|
case "fallback": {
|
|
144
152
|
return new Response(null, { status: 500, headers: { [ROUTE_TYPE_HEADER]: "fallback" } });
|
|
145
153
|
}
|
|
146
154
|
}
|
|
155
|
+
const responseCookies = getFromResponse(response2);
|
|
156
|
+
if (responseCookies) {
|
|
157
|
+
cookies.merge(responseCookies);
|
|
158
|
+
}
|
|
159
|
+
return response2;
|
|
147
160
|
};
|
|
148
161
|
const response = await callMiddleware(
|
|
149
162
|
middleware,
|
package/dist/core/request.js
CHANGED
|
@@ -12,7 +12,13 @@ function createRequest({
|
|
|
12
12
|
locals,
|
|
13
13
|
staticLike = false
|
|
14
14
|
}) {
|
|
15
|
-
const headersObj = staticLike ? void 0 : headers instanceof Headers ? headers : new Headers(
|
|
15
|
+
const headersObj = staticLike ? void 0 : headers instanceof Headers ? headers : new Headers(
|
|
16
|
+
// Filter out HTTP/2 pseudo-headers. These are internally-generated headers added to all HTTP/2 requests with trusted metadata about the request.
|
|
17
|
+
// Examples include `:method`, `:scheme`, `:authority`, and `:path`.
|
|
18
|
+
// They are always prefixed with a colon to distinguish them from other headers, and it is an error to add the to a Headers object manually.
|
|
19
|
+
// See https://httpwg.org/specs/rfc7540.html#HttpRequest
|
|
20
|
+
Object.entries(headers).filter(([name]) => !name.startsWith(":"))
|
|
21
|
+
);
|
|
16
22
|
if (typeof url === "string") url = new URL(url);
|
|
17
23
|
const imageEndpoint = prependForwardSlash(appendForwardSlash(base)) + "_image";
|
|
18
24
|
if (staticLike && url.pathname !== imageEndpoint) {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AstroConfig, RewritePayload, RouteData } from '../../@types/astro.js';
|
|
2
|
+
export type FindRouteToRewrite = {
|
|
3
|
+
payload: RewritePayload;
|
|
4
|
+
routes: RouteData[];
|
|
5
|
+
request: Request;
|
|
6
|
+
trailingSlash: AstroConfig['trailingSlash'];
|
|
7
|
+
buildFormat: AstroConfig['build']['format'];
|
|
8
|
+
base: AstroConfig['base'];
|
|
9
|
+
};
|
|
10
|
+
export declare function findRouteToRewrite({ payload, routes, request, trailingSlash, buildFormat, base, }: FindRouteToRewrite): [RouteData, URL];
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { shouldAppendForwardSlash } from "../build/util.js";
|
|
2
|
+
import { appendForwardSlash, removeTrailingForwardSlash } from "../path.js";
|
|
3
|
+
import { DEFAULT_404_ROUTE } from "./astro-designed-error-pages.js";
|
|
4
|
+
function findRouteToRewrite({
|
|
5
|
+
payload,
|
|
6
|
+
routes,
|
|
7
|
+
request,
|
|
8
|
+
trailingSlash,
|
|
9
|
+
buildFormat,
|
|
10
|
+
base
|
|
11
|
+
}) {
|
|
12
|
+
let finalUrl = void 0;
|
|
13
|
+
if (payload instanceof URL) {
|
|
14
|
+
finalUrl = payload;
|
|
15
|
+
} else if (payload instanceof Request) {
|
|
16
|
+
finalUrl = new URL(payload.url);
|
|
17
|
+
} else {
|
|
18
|
+
finalUrl = new URL(payload, new URL(request.url).origin);
|
|
19
|
+
}
|
|
20
|
+
let foundRoute;
|
|
21
|
+
for (const route of routes) {
|
|
22
|
+
const pathname = shouldAppendForwardSlash(trailingSlash, buildFormat) ? appendForwardSlash(finalUrl.pathname) : base !== "/" ? removeTrailingForwardSlash(finalUrl.pathname) : finalUrl.pathname;
|
|
23
|
+
if (route.pattern.test(decodeURI(pathname))) {
|
|
24
|
+
foundRoute = route;
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (foundRoute) {
|
|
29
|
+
return [foundRoute, finalUrl];
|
|
30
|
+
} else {
|
|
31
|
+
const custom404 = routes.find((route) => route.route === "/404");
|
|
32
|
+
if (custom404) {
|
|
33
|
+
return [custom404, finalUrl];
|
|
34
|
+
} else {
|
|
35
|
+
return [DEFAULT_404_ROUTE, finalUrl];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
findRouteToRewrite
|
|
41
|
+
};
|
|
@@ -19,7 +19,6 @@ export declare class DevPipeline extends Pipeline {
|
|
|
19
19
|
preload(routeData: RouteData, filePath: URL): Promise<ComponentInstance>;
|
|
20
20
|
clearRouteCache(): void;
|
|
21
21
|
getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
|
|
22
|
-
tryRewrite(payload: RewritePayload, request: Request,
|
|
22
|
+
tryRewrite(payload: RewritePayload, request: Request, _sourceRoute: RouteData): Promise<[RouteData, ComponentInstance, URL]>;
|
|
23
23
|
setManifestData(manifestData: ManifestData): void;
|
|
24
|
-
rewriteKnownRoute(route: string, sourceRoute: RouteData): ComponentInstance;
|
|
25
24
|
}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { fileURLToPath } from "node:url";
|
|
2
2
|
import { getInfoOutput } from "../cli/info/index.js";
|
|
3
3
|
import {} from "../core/base-pipeline.js";
|
|
4
|
+
import { shouldAppendForwardSlash } from "../core/build/util.js";
|
|
4
5
|
import { ASTRO_VERSION, DEFAULT_404_COMPONENT } from "../core/constants.js";
|
|
5
6
|
import { enhanceViteSSRError } from "../core/errors/dev/index.js";
|
|
6
|
-
import {
|
|
7
|
+
import { RewriteEncounteredAnError } from "../core/errors/errors-data.js";
|
|
7
8
|
import { AggregateError, AstroError, CSSError, MarkdownError } from "../core/errors/index.js";
|
|
9
|
+
import { prependForwardSlash, removeTrailingForwardSlash } from "../core/path.js";
|
|
8
10
|
import { Pipeline, loadRenderer } from "../core/render/index.js";
|
|
9
11
|
import { DEFAULT_404_ROUTE, default404Page } from "../core/routing/astro-designed-error-pages.js";
|
|
12
|
+
import { findRouteToRewrite } from "../core/routing/rewrite.js";
|
|
10
13
|
import { isPage, isServerLikeOutput, resolveIdToUrl, viteID } from "../core/util.js";
|
|
11
14
|
import { PAGE_SCRIPT_ID } from "../vite-plugin-scripts/index.js";
|
|
12
15
|
import { getStylesForURL } from "./css.js";
|
|
@@ -133,54 +136,24 @@ class DevPipeline extends Pipeline {
|
|
|
133
136
|
return await this.preload(routeData, filePath);
|
|
134
137
|
}
|
|
135
138
|
}
|
|
136
|
-
async tryRewrite(payload, request,
|
|
137
|
-
let foundRoute;
|
|
139
|
+
async tryRewrite(payload, request, _sourceRoute) {
|
|
138
140
|
if (!this.manifestData) {
|
|
139
141
|
throw new Error("Missing manifest data. This is an internal error, please file an issue.");
|
|
140
142
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
foundRoute = route;
|
|
152
|
-
break;
|
|
153
|
-
} else if (finalUrl.pathname === "/404") {
|
|
154
|
-
foundRoute = DEFAULT_404_ROUTE;
|
|
155
|
-
break;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
if (foundRoute && finalUrl) {
|
|
159
|
-
if (foundRoute.pathname === "/404") {
|
|
160
|
-
const componentInstance = this.rewriteKnownRoute(foundRoute.pathname, sourceRoute);
|
|
161
|
-
return [foundRoute, componentInstance, finalUrl];
|
|
162
|
-
} else {
|
|
163
|
-
const componentInstance = await this.getComponentByRoute(foundRoute);
|
|
164
|
-
return [foundRoute, componentInstance, finalUrl];
|
|
165
|
-
}
|
|
166
|
-
} else {
|
|
167
|
-
throw new AstroError({
|
|
168
|
-
...RewriteEncounteredAnError,
|
|
169
|
-
message: RewriteEncounteredAnError.message(payload.toString())
|
|
170
|
-
});
|
|
171
|
-
}
|
|
143
|
+
const [foundRoute, finalUrl] = findRouteToRewrite({
|
|
144
|
+
payload,
|
|
145
|
+
request,
|
|
146
|
+
routes: this.manifestData?.routes,
|
|
147
|
+
trailingSlash: this.config.trailingSlash,
|
|
148
|
+
buildFormat: this.config.build.format,
|
|
149
|
+
base: this.config.base
|
|
150
|
+
});
|
|
151
|
+
const componentInstance = await this.getComponentByRoute(foundRoute);
|
|
152
|
+
return [foundRoute, componentInstance, finalUrl];
|
|
172
153
|
}
|
|
173
154
|
setManifestData(manifestData) {
|
|
174
155
|
this.manifestData = manifestData;
|
|
175
156
|
}
|
|
176
|
-
rewriteKnownRoute(route, sourceRoute) {
|
|
177
|
-
if (isServerLikeOutput(this.config) && sourceRoute.prerender) {
|
|
178
|
-
if (route === "/404") {
|
|
179
|
-
return { default: default404Page };
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
throw new AstroError(InvalidRewrite404);
|
|
183
|
-
}
|
|
184
157
|
}
|
|
185
158
|
export {
|
|
186
159
|
DevPipeline
|
|
@@ -11,7 +11,7 @@ async function handleRequest({
|
|
|
11
11
|
incomingResponse
|
|
12
12
|
}) {
|
|
13
13
|
const { config, loader } = pipeline;
|
|
14
|
-
const origin = `${loader.isHttps() ? "https" : "http"}://${incomingRequest.headers.host}`;
|
|
14
|
+
const origin = `${loader.isHttps() ? "https" : "http"}://${incomingRequest.headers[":authority"] ?? incomingRequest.headers.host}`;
|
|
15
15
|
const url = new URL(origin + incomingRequest.url);
|
|
16
16
|
let pathname;
|
|
17
17
|
if (config.trailingSlash === "never" && !incomingRequest.url) {
|
|
@@ -108,11 +108,8 @@ async function handleRoute({
|
|
|
108
108
|
}) {
|
|
109
109
|
const timeStart = performance.now();
|
|
110
110
|
const { config, loader, logger } = pipeline;
|
|
111
|
-
if (!matchedRoute
|
|
112
|
-
|
|
113
|
-
logger.info(null, req({ url: pathname, method: incomingRequest.method, statusCode: 404 }));
|
|
114
|
-
}
|
|
115
|
-
return handle404Response(origin, incomingRequest, incomingResponse);
|
|
111
|
+
if (!matchedRoute) {
|
|
112
|
+
throw new Error("No route matched, and default 404 route was not found.");
|
|
116
113
|
}
|
|
117
114
|
let request;
|
|
118
115
|
let renderContext;
|
|
@@ -121,96 +118,40 @@ async function handleRoute({
|
|
|
121
118
|
let route;
|
|
122
119
|
const middleware = (await loadMiddleware(loader)).onRequest;
|
|
123
120
|
const locals = Reflect.get(incomingRequest, clientLocalsSymbol);
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return found;
|
|
143
|
-
});
|
|
144
|
-
if (!pathNameHasLocale && pathname !== "/") {
|
|
145
|
-
return handle404Response(origin, incomingRequest, incomingResponse);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
request = createRequest({
|
|
149
|
-
base: config.base,
|
|
150
|
-
url,
|
|
151
|
-
headers: incomingRequest.headers,
|
|
152
|
-
logger,
|
|
153
|
-
// no route found, so we assume the default for rendering the 404 page
|
|
154
|
-
staticLike: config.output === "static" || config.output === "hybrid"
|
|
155
|
-
});
|
|
156
|
-
route = {
|
|
157
|
-
component: "",
|
|
158
|
-
generate(_data) {
|
|
159
|
-
return "";
|
|
160
|
-
},
|
|
161
|
-
params: [],
|
|
162
|
-
// Disable eslint as we only want to generate an empty RegExp
|
|
163
|
-
// eslint-disable-next-line prefer-regex-literals
|
|
164
|
-
pattern: new RegExp(""),
|
|
165
|
-
prerender: false,
|
|
166
|
-
segments: [],
|
|
167
|
-
type: "fallback",
|
|
168
|
-
route: "",
|
|
169
|
-
fallbackRoutes: [],
|
|
170
|
-
isIndex: false
|
|
171
|
-
};
|
|
172
|
-
renderContext = RenderContext.create({
|
|
173
|
-
pipeline,
|
|
174
|
-
pathname,
|
|
175
|
-
middleware,
|
|
176
|
-
request,
|
|
177
|
-
routeData: route
|
|
178
|
-
});
|
|
179
|
-
} else {
|
|
180
|
-
const filePath = matchedRoute.filePath;
|
|
181
|
-
const { preloadedComponent } = matchedRoute;
|
|
182
|
-
route = matchedRoute.route;
|
|
183
|
-
request = createRequest({
|
|
184
|
-
base: config.base,
|
|
185
|
-
url,
|
|
186
|
-
headers: incomingRequest.headers,
|
|
187
|
-
method: incomingRequest.method,
|
|
188
|
-
body,
|
|
189
|
-
logger,
|
|
190
|
-
clientAddress: incomingRequest.socket.remoteAddress,
|
|
191
|
-
staticLike: config.output === "static" || route.prerender
|
|
192
|
-
});
|
|
193
|
-
for (const [name, value] of Object.entries(config.server.headers ?? {})) {
|
|
194
|
-
if (value) incomingResponse.setHeader(name, value);
|
|
195
|
-
}
|
|
196
|
-
options = {
|
|
197
|
-
pipeline,
|
|
198
|
-
filePath,
|
|
199
|
-
preload: preloadedComponent,
|
|
200
|
-
pathname,
|
|
201
|
-
request,
|
|
202
|
-
route
|
|
203
|
-
};
|
|
204
|
-
mod = preloadedComponent;
|
|
205
|
-
renderContext = RenderContext.create({
|
|
206
|
-
locals,
|
|
207
|
-
pipeline,
|
|
208
|
-
pathname,
|
|
209
|
-
middleware,
|
|
210
|
-
request,
|
|
211
|
-
routeData: route
|
|
212
|
-
});
|
|
121
|
+
const filePath = matchedRoute.filePath;
|
|
122
|
+
const { preloadedComponent } = matchedRoute;
|
|
123
|
+
route = matchedRoute.route;
|
|
124
|
+
request = createRequest({
|
|
125
|
+
base: config.base,
|
|
126
|
+
url,
|
|
127
|
+
headers: incomingRequest.headers,
|
|
128
|
+
method: incomingRequest.method,
|
|
129
|
+
body,
|
|
130
|
+
logger,
|
|
131
|
+
clientAddress: incomingRequest.socket.remoteAddress,
|
|
132
|
+
staticLike: config.output === "static" || route.prerender
|
|
133
|
+
});
|
|
134
|
+
for (const [name, value] of Object.entries(config.server.headers ?? {})) {
|
|
135
|
+
if (value) incomingResponse.setHeader(name, value);
|
|
213
136
|
}
|
|
137
|
+
options = {
|
|
138
|
+
pipeline,
|
|
139
|
+
filePath,
|
|
140
|
+
preload: preloadedComponent,
|
|
141
|
+
pathname,
|
|
142
|
+
request,
|
|
143
|
+
route
|
|
144
|
+
};
|
|
145
|
+
mod = preloadedComponent;
|
|
146
|
+
const isPrerendered404 = matchedRoute.route.route === "/404" && matchedRoute.route.prerender;
|
|
147
|
+
renderContext = RenderContext.create({
|
|
148
|
+
locals,
|
|
149
|
+
pipeline,
|
|
150
|
+
pathname,
|
|
151
|
+
middleware: isPrerendered404 ? void 0 : middleware,
|
|
152
|
+
request,
|
|
153
|
+
routeData: route
|
|
154
|
+
});
|
|
214
155
|
let response;
|
|
215
156
|
try {
|
|
216
157
|
response = await renderContext.render(mod);
|
|
@@ -220,9 +161,10 @@ async function handleRoute({
|
|
|
220
161
|
throw err;
|
|
221
162
|
}
|
|
222
163
|
logger.error("router", err.stack || err.message);
|
|
223
|
-
const
|
|
224
|
-
const
|
|
225
|
-
|
|
164
|
+
const filePath500 = new URL(`./${custom500.component}`, config.root);
|
|
165
|
+
const preloaded500Component = await pipeline.preload(custom500, filePath500);
|
|
166
|
+
renderContext.props.error = err;
|
|
167
|
+
response = await renderContext.render(preloaded500Component);
|
|
226
168
|
status = 500;
|
|
227
169
|
}
|
|
228
170
|
if (isLoggedRequest(pathname)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.11.0",
|
|
4
4
|
"description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "withastro",
|
|
@@ -169,9 +169,9 @@
|
|
|
169
169
|
"yargs-parser": "^21.1.1",
|
|
170
170
|
"zod": "^3.23.8",
|
|
171
171
|
"zod-to-json-schema": "^3.23.0",
|
|
172
|
+
"@astrojs/markdown-remark": "5.1.0",
|
|
172
173
|
"@astrojs/internal-helpers": "0.4.0",
|
|
173
|
-
"@astrojs/telemetry": "3.1.0"
|
|
174
|
-
"@astrojs/markdown-remark": "5.1.0"
|
|
174
|
+
"@astrojs/telemetry": "3.1.0"
|
|
175
175
|
},
|
|
176
176
|
"optionalDependencies": {
|
|
177
177
|
"sharp": "^0.33.3"
|
|
@@ -214,6 +214,7 @@
|
|
|
214
214
|
"rollup": "^4.18.0",
|
|
215
215
|
"sass": "^1.77.5",
|
|
216
216
|
"srcset-parse": "^1.1.0",
|
|
217
|
+
"undici": "^6.19.2",
|
|
217
218
|
"unified": "^11.0.4",
|
|
218
219
|
"astro-scripts": "0.0.14"
|
|
219
220
|
},
|