astro 6.0.0-beta.17 → 6.0.0-beta.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/runtime/types.d.ts +1 -1
- package/dist/assets/utils/proxy.js +1 -1
- package/dist/assets/utils/svg.js +11 -1
- package/dist/assets/vite-plugin-assets.js +15 -1
- package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
- package/dist/config/entrypoint.d.ts +7 -0
- package/dist/config/entrypoint.js +8 -0
- package/dist/content/content-layer.js +3 -3
- package/dist/content/runtime.js +7 -1
- package/dist/content/vite-plugin-content-assets.js +7 -4
- package/dist/core/app/base.d.ts +11 -7
- package/dist/core/app/base.js +118 -54
- package/dist/core/app/dev/app.d.ts +1 -1
- package/dist/core/app/dev/app.js +11 -6
- package/dist/core/app/node.js +2 -1
- package/dist/core/app/types.d.ts +5 -0
- package/dist/core/base-pipeline.d.ts +12 -1
- package/dist/core/base-pipeline.js +19 -2
- package/dist/core/build/common.js +2 -1
- package/dist/core/build/generate.js +1 -1
- package/dist/core/build/plugins/plugin-manifest.js +5 -0
- package/dist/core/build/static-build.js +2 -1
- package/dist/core/cache/config.d.ts +29 -0
- package/dist/core/cache/config.js +20 -0
- package/dist/core/cache/memory-provider.d.ts +56 -0
- package/dist/core/cache/memory-provider.js +305 -0
- package/dist/core/cache/runtime/cache.d.ts +36 -0
- package/dist/core/cache/runtime/cache.js +98 -0
- package/dist/core/cache/runtime/noop.d.ts +19 -0
- package/dist/core/cache/runtime/noop.js +33 -0
- package/dist/core/cache/runtime/route-matching.d.ts +20 -0
- package/dist/core/cache/runtime/route-matching.js +28 -0
- package/dist/core/cache/runtime/utils.d.ts +8 -0
- package/dist/core/cache/runtime/utils.js +34 -0
- package/dist/core/cache/types.d.ts +64 -0
- package/dist/core/cache/types.js +0 -0
- package/dist/core/cache/utils.d.ts +16 -0
- package/dist/core/cache/utils.js +47 -0
- package/dist/core/cache/vite-plugin.d.ts +6 -0
- package/dist/core/cache/vite-plugin.js +56 -0
- package/dist/core/config/schemas/base.d.ts +14 -0
- package/dist/core/config/schemas/base.js +3 -0
- package/dist/core/config/schemas/relative.d.ts +42 -4
- package/dist/core/constants.js +1 -1
- package/dist/core/create-vite.js +2 -0
- package/dist/core/dev/container.js +3 -3
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/errors/errors-data.d.ts +46 -3
- package/dist/core/errors/errors-data.js +26 -5
- package/dist/core/logger/core.d.ts +1 -1
- package/dist/core/messages/runtime.js +1 -1
- package/dist/core/middleware/index.js +2 -0
- package/dist/core/redirects/render.js +5 -2
- package/dist/core/render-context.d.ts +2 -0
- package/dist/core/render-context.js +36 -1
- package/dist/core/routing/generator.js +2 -1
- package/dist/core/server-islands/endpoint.d.ts +6 -0
- package/dist/core/server-islands/endpoint.js +1 -0
- package/dist/core/session/runtime.js +20 -1
- package/dist/i18n/fallback.js +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/integrations/hooks.js +2 -1
- package/dist/manifest/serialized.js +9 -0
- package/dist/prerender/utils.js +5 -1
- package/dist/runtime/server/astro-global.js +3 -0
- package/dist/runtime/server/render/util.js +0 -12
- package/dist/types/public/config.d.ts +70 -14
- package/dist/types/public/context.d.ts +10 -0
- package/dist/types/public/index.d.ts +1 -0
- package/dist/types/public/integrations.d.ts +8 -0
- package/dist/vite-plugin-app/app.d.ts +1 -1
- package/dist/vite-plugin-app/app.js +11 -6
- package/package.json +6 -5
- package/tsconfigs/base.json +3 -1
|
@@ -49,7 +49,7 @@ export interface ActionsLocals {
|
|
|
49
49
|
actionName: string;
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
|
-
export type ActionAPIContext = Pick<APIContext, 'request' | 'url' | 'isPrerendered' | 'locals' | 'clientAddress' | 'cookies' | 'currentLocale' | 'generator' | 'routePattern' | 'site' | 'params' | 'preferredLocale' | 'preferredLocaleList' | 'originPathname' | 'session' | 'csp'>;
|
|
52
|
+
export type ActionAPIContext = Pick<APIContext, 'request' | 'url' | 'isPrerendered' | 'locals' | 'clientAddress' | 'cookies' | 'currentLocale' | 'generator' | 'routePattern' | 'site' | 'params' | 'preferredLocale' | 'preferredLocaleList' | 'originPathname' | 'session' | 'cache' | 'csp'>;
|
|
53
53
|
export type MaybePromise<T> = T | Promise<T>;
|
|
54
54
|
/**
|
|
55
55
|
* Used to preserve the input schema type in the error object.
|
|
@@ -9,7 +9,7 @@ function getProxyCode(options, isSSR) {
|
|
|
9
9
|
if (name === 'fsPath') {
|
|
10
10
|
return ${stringifiedFSPath};
|
|
11
11
|
}
|
|
12
|
-
${!isSSR ? `if (target[name] !== undefined && globalThis.astroAsset) globalThis.astroAsset?.referencedImages
|
|
12
|
+
${!isSSR ? `if (target[name] !== undefined && globalThis.astroAsset) globalThis.astroAsset?.referencedImages?.add(${stringifiedFSPath});` : ""}
|
|
13
13
|
return target[name];
|
|
14
14
|
}
|
|
15
15
|
})
|
package/dist/assets/utils/svg.js
CHANGED
|
@@ -49,6 +49,16 @@ function makeSvgComponent(meta, contents, svgoConfig) {
|
|
|
49
49
|
return `import { createSvgComponent } from 'astro/assets/runtime';
|
|
50
50
|
export default createSvgComponent(${JSON.stringify(props)})`;
|
|
51
51
|
}
|
|
52
|
+
function parseSvgComponentData(meta, contents, svgoConfig) {
|
|
53
|
+
const file = typeof contents === "string" ? contents : contents.toString("utf-8");
|
|
54
|
+
const { attributes, body: children } = parseSvg({
|
|
55
|
+
path: meta.fsPath,
|
|
56
|
+
contents: file,
|
|
57
|
+
svgoConfig
|
|
58
|
+
});
|
|
59
|
+
return { attributes: dropAttributes(attributes), children };
|
|
60
|
+
}
|
|
52
61
|
export {
|
|
53
|
-
makeSvgComponent
|
|
62
|
+
makeSvgComponent,
|
|
63
|
+
parseSvgComponentData
|
|
54
64
|
};
|
|
@@ -29,7 +29,7 @@ import { hashTransform, propsToFilename } from "./utils/hash.js";
|
|
|
29
29
|
import { emitImageMetadata } from "./utils/node.js";
|
|
30
30
|
import { CONTENT_IMAGE_FLAG } from "../content/consts.js";
|
|
31
31
|
import { getProxyCode } from "./utils/proxy.js";
|
|
32
|
-
import { makeSvgComponent } from "./utils/svg.js";
|
|
32
|
+
import { makeSvgComponent, parseSvgComponentData } from "./utils/svg.js";
|
|
33
33
|
import { createPlaceholderURL, stringifyPlaceholderURL } from "./utils/url.js";
|
|
34
34
|
const assetRegex = new RegExp(`\\.(${VALID_INPUT_FORMATS.join("|")})`, "i");
|
|
35
35
|
const assetRegexEnds = new RegExp(`\\.(${VALID_INPUT_FORMATS.join("|")})$`, "i");
|
|
@@ -252,6 +252,20 @@ function assets({ fs, settings, sync, logger }) {
|
|
|
252
252
|
if (isSSROnlyEnvironment) {
|
|
253
253
|
globalThis.astroAsset.referencedImages.add(imageMetadata.fsPath);
|
|
254
254
|
}
|
|
255
|
+
if (id.endsWith(".svg") && isContentImage) {
|
|
256
|
+
const contents = await fs.promises.readFile(imageMetadata.fsPath, {
|
|
257
|
+
encoding: "utf8"
|
|
258
|
+
});
|
|
259
|
+
const svgData = parseSvgComponentData(
|
|
260
|
+
imageMetadata,
|
|
261
|
+
contents,
|
|
262
|
+
settings.config.experimental.svgo
|
|
263
|
+
);
|
|
264
|
+
const metadataWithSvg = { ...imageMetadata, __svgData: svgData };
|
|
265
|
+
return {
|
|
266
|
+
code: `export default ${getProxyCode(metadataWithSvg, isSSROnlyEnvironment)}`
|
|
267
|
+
};
|
|
268
|
+
}
|
|
255
269
|
return {
|
|
256
270
|
code: `export default ${getProxyCode(imageMetadata, isSSROnlyEnvironment)}`
|
|
257
271
|
};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { SharpImageServiceConfig } from '../assets/services/sharp.js';
|
|
2
|
+
import type { MemoryCacheProviderOptions } from '../core/cache/memory-provider.js';
|
|
3
|
+
import type { CacheProviderConfig } from '../core/cache/types.js';
|
|
2
4
|
import type { ImageServiceConfig } from '../types/public/index.js';
|
|
3
5
|
export { fontProviders } from '../assets/fonts/providers/index.js';
|
|
4
6
|
export { mergeConfig } from '../core/config/merge.js';
|
|
@@ -17,3 +19,8 @@ export declare function sharpImageService(config?: SharpImageServiceConfig): Ima
|
|
|
17
19
|
* See: https://docs.astro.build/en/guides/images/#configure-no-op-passthrough-service
|
|
18
20
|
*/
|
|
19
21
|
export declare function passthroughImageService(): ImageServiceConfig;
|
|
22
|
+
/**
|
|
23
|
+
* Return the configuration needed to use the built-in in-memory LRU cache provider.
|
|
24
|
+
* This is a runtime-agnostic provider suitable for single-instance deployments.
|
|
25
|
+
*/
|
|
26
|
+
export declare function memoryCache(config?: MemoryCacheProviderOptions): CacheProviderConfig<MemoryCacheProviderOptions>;
|
|
@@ -16,11 +16,19 @@ function passthroughImageService() {
|
|
|
16
16
|
config: {}
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
|
+
function memoryCache(config = {}) {
|
|
20
|
+
return {
|
|
21
|
+
name: "memory",
|
|
22
|
+
entrypoint: "astro/cache/memory",
|
|
23
|
+
config
|
|
24
|
+
};
|
|
25
|
+
}
|
|
19
26
|
export {
|
|
20
27
|
defineConfig,
|
|
21
28
|
envField,
|
|
22
29
|
fontProviders,
|
|
23
30
|
getViteConfig,
|
|
31
|
+
memoryCache,
|
|
24
32
|
mergeConfig,
|
|
25
33
|
passthroughImageService,
|
|
26
34
|
sessionDrivers,
|
|
@@ -189,7 +189,7 @@ ${contentConfig.error.message}`
|
|
|
189
189
|
logger.info("Content config changed");
|
|
190
190
|
shouldClear = true;
|
|
191
191
|
}
|
|
192
|
-
if (previousAstroVersion && previousAstroVersion !== "6.0.0-beta.
|
|
192
|
+
if (previousAstroVersion && previousAstroVersion !== "6.0.0-beta.18") {
|
|
193
193
|
logger.info("Astro version changed");
|
|
194
194
|
shouldClear = true;
|
|
195
195
|
}
|
|
@@ -197,8 +197,8 @@ ${contentConfig.error.message}`
|
|
|
197
197
|
logger.info("Clearing content store");
|
|
198
198
|
this.#store.clearAll();
|
|
199
199
|
}
|
|
200
|
-
if ("6.0.0-beta.
|
|
201
|
-
this.#store.metaStore().set("astro-version", "6.0.0-beta.
|
|
200
|
+
if ("6.0.0-beta.18") {
|
|
201
|
+
this.#store.metaStore().set("astro-version", "6.0.0-beta.18");
|
|
202
202
|
}
|
|
203
203
|
if (currentConfigDigest) {
|
|
204
204
|
this.#store.metaStore().set("content-config-digest", currentConfigDigest);
|
package/dist/content/runtime.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { escape } from "html-escaper";
|
|
2
2
|
import { Traverse } from "neotraverse/modern";
|
|
3
3
|
import * as z from "zod/v4";
|
|
4
|
+
import { createSvgComponent } from "../assets/runtime.js";
|
|
4
5
|
import { imageSrcToImportId } from "../assets/utils/resolveImports.js";
|
|
5
6
|
import { AstroError, AstroErrorData } from "../core/errors/index.js";
|
|
6
7
|
import { isRemotePath, prependForwardSlash } from "../core/path.js";
|
|
@@ -363,7 +364,12 @@ function updateImageReferencesInData(data, fileName, imageAssetMap) {
|
|
|
363
364
|
}
|
|
364
365
|
const imported = imageAssetMap?.get(id);
|
|
365
366
|
if (imported) {
|
|
366
|
-
|
|
367
|
+
if (imported.__svgData) {
|
|
368
|
+
const { __svgData: svgData, ...meta } = imported;
|
|
369
|
+
ctx.update(createSvgComponent({ meta, ...svgData }));
|
|
370
|
+
} else {
|
|
371
|
+
ctx.update(imported);
|
|
372
|
+
}
|
|
367
373
|
} else {
|
|
368
374
|
ctx.update(src);
|
|
369
375
|
}
|
|
@@ -60,10 +60,12 @@ function astroContentAssetPropagationPlugin({
|
|
|
60
60
|
}
|
|
61
61
|
},
|
|
62
62
|
configureServer(server) {
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
const ssrEnv = server.environments[ASTRO_VITE_ENVIRONMENT_NAMES.ssr];
|
|
64
|
+
if (isRunnableDevEnvironment(ssrEnv)) {
|
|
65
|
+
environment = ssrEnv;
|
|
66
|
+
} else if (isRunnableDevEnvironment(server.environments[ASTRO_VITE_ENVIRONMENT_NAMES.astro])) {
|
|
67
|
+
environment = server.environments[ASTRO_VITE_ENVIRONMENT_NAMES.astro];
|
|
65
68
|
}
|
|
66
|
-
environment = server.environments[ASTRO_VITE_ENVIRONMENT_NAMES.ssr];
|
|
67
69
|
},
|
|
68
70
|
transform: {
|
|
69
71
|
filter: {
|
|
@@ -75,7 +77,8 @@ function astroContentAssetPropagationPlugin({
|
|
|
75
77
|
let stringifiedLinks, stringifiedStyles;
|
|
76
78
|
if (isAstroServerEnvironment(this.environment) && environment) {
|
|
77
79
|
if (!environment.moduleGraph.getModuleById(basePath)?.ssrModule) {
|
|
78
|
-
await environment.runner.import(basePath)
|
|
80
|
+
await environment.runner.import(basePath).catch(() => {
|
|
81
|
+
});
|
|
79
82
|
}
|
|
80
83
|
const {
|
|
81
84
|
styles,
|
package/dist/core/app/base.d.ts
CHANGED
|
@@ -51,9 +51,15 @@ export interface RenderOptions {
|
|
|
51
51
|
*/
|
|
52
52
|
routeData?: RouteData;
|
|
53
53
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
type RequiredRenderOptions = Required<RenderOptions>;
|
|
55
|
+
interface ResolvedRenderOptions {
|
|
56
|
+
addCookieHeader: RequiredRenderOptions['addCookieHeader'];
|
|
57
|
+
clientAddress: RequiredRenderOptions['clientAddress'] | undefined;
|
|
58
|
+
prerenderedErrorPageFetch: RequiredRenderOptions['prerenderedErrorPageFetch'] | undefined;
|
|
59
|
+
locals: RequiredRenderOptions['locals'] | undefined;
|
|
60
|
+
routeData: RequiredRenderOptions['routeData'] | undefined;
|
|
61
|
+
}
|
|
62
|
+
export interface RenderErrorOptions extends ResolvedRenderOptions {
|
|
57
63
|
response?: Response;
|
|
58
64
|
status: 404 | 500;
|
|
59
65
|
/**
|
|
@@ -64,8 +70,6 @@ export interface RenderErrorOptions {
|
|
|
64
70
|
* Allows passing an error to 500.astro. It will be available through `Astro.props.error`.
|
|
65
71
|
*/
|
|
66
72
|
error?: unknown;
|
|
67
|
-
clientAddress: string | undefined;
|
|
68
|
-
prerenderedErrorPageFetch: ((url: ErrorPagePath) => Promise<Response>) | undefined;
|
|
69
73
|
}
|
|
70
74
|
type ErrorPagePath = `${string}/404` | `${string}/500` | `${string}/404/` | `${string}/500/` | `${string}404.html` | `${string}500.html`;
|
|
71
75
|
export declare abstract class BaseApp<P extends Pipeline = AppPipeline> {
|
|
@@ -120,7 +124,7 @@ export declare abstract class BaseApp<P extends Pipeline = AppPipeline> {
|
|
|
120
124
|
devMatch(pathname?: string): Promise<DevMatch | undefined> | undefined;
|
|
121
125
|
private computePathnameFromDomain;
|
|
122
126
|
private redirectTrailingSlash;
|
|
123
|
-
render(request: Request,
|
|
127
|
+
render(request: Request, { addCookieHeader, clientAddress, locals, prerenderedErrorPageFetch, routeData, }?: RenderOptions): Promise<Response>;
|
|
124
128
|
setCookieHeaders(response: Response): Generator<string, string[], any>;
|
|
125
129
|
/**
|
|
126
130
|
* Reads all the cookies written by `Astro.cookie.set()` onto the passed response.
|
|
@@ -138,7 +142,7 @@ export declare abstract class BaseApp<P extends Pipeline = AppPipeline> {
|
|
|
138
142
|
* If it is a known error code, try sending the according page (e.g. 404.astro / 500.astro).
|
|
139
143
|
* This also handles pre-rendered /404 or /500 routes
|
|
140
144
|
*/
|
|
141
|
-
renderError(request: Request, {
|
|
145
|
+
renderError(request: Request, { status, response: originalResponse, skipMiddleware, error, ...resolvedRenderOptions }: RenderErrorOptions): Promise<Response>;
|
|
142
146
|
private mergeResponses;
|
|
143
147
|
getDefaultStatusCode(routeData: RouteData, pathname: string): number;
|
|
144
148
|
getManifest(): SSRManifest;
|
package/dist/core/app/base.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
appendForwardSlash,
|
|
3
|
+
collapseDuplicateLeadingSlashes,
|
|
3
4
|
collapseDuplicateTrailingSlashes,
|
|
4
5
|
hasFileExtension,
|
|
5
6
|
isInternalPath,
|
|
@@ -12,12 +13,19 @@ import { normalizeTheLocale } from "../../i18n/index.js";
|
|
|
12
13
|
import {
|
|
13
14
|
clientAddressSymbol,
|
|
14
15
|
DEFAULT_404_COMPONENT,
|
|
16
|
+
NOOP_MIDDLEWARE_HEADER,
|
|
15
17
|
REROUTABLE_STATUS_CODES,
|
|
16
18
|
REROUTE_DIRECTIVE_HEADER,
|
|
17
19
|
responseSentSymbol,
|
|
18
|
-
REWRITE_DIRECTIVE_HEADER_KEY
|
|
20
|
+
REWRITE_DIRECTIVE_HEADER_KEY,
|
|
21
|
+
ROUTE_TYPE_HEADER
|
|
19
22
|
} from "../constants.js";
|
|
20
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
AstroCookies,
|
|
25
|
+
attachCookiesToResponse,
|
|
26
|
+
getSetCookiesFromResponse
|
|
27
|
+
} from "../cookies/index.js";
|
|
28
|
+
import { getCookiesFromResponse } from "../cookies/response.js";
|
|
21
29
|
import { AstroError, AstroErrorData } from "../errors/index.js";
|
|
22
30
|
import { consoleLogDestination } from "../logger/console.js";
|
|
23
31
|
import { AstroIntegrationLogger, Logger } from "../logger/core.js";
|
|
@@ -25,6 +33,7 @@ import { RenderContext } from "../render-context.js";
|
|
|
25
33
|
import { redirectTemplate } from "../routing/3xx.js";
|
|
26
34
|
import { ensure404Route } from "../routing/astro-designed-error-pages.js";
|
|
27
35
|
import { matchRoute } from "../routing/match.js";
|
|
36
|
+
import { applyCacheHeaders } from "../cache/runtime/cache.js";
|
|
28
37
|
import { Router } from "../routing/router.js";
|
|
29
38
|
import { PERSIST_SYMBOL } from "../session/runtime.js";
|
|
30
39
|
class BaseApp {
|
|
@@ -78,6 +87,7 @@ class BaseApp {
|
|
|
78
87
|
this.#router = this.createRouter(this.manifestData);
|
|
79
88
|
}
|
|
80
89
|
removeBase(pathname) {
|
|
90
|
+
pathname = collapseDuplicateLeadingSlashes(pathname);
|
|
81
91
|
if (pathname.startsWith(this.manifest.base)) {
|
|
82
92
|
return pathname.slice(this.baseWithoutTrailingSlash.length + 1);
|
|
83
93
|
}
|
|
@@ -208,18 +218,19 @@ class BaseApp {
|
|
|
208
218
|
}
|
|
209
219
|
return pathname;
|
|
210
220
|
}
|
|
211
|
-
async render(request,
|
|
221
|
+
async render(request, {
|
|
222
|
+
addCookieHeader = false,
|
|
223
|
+
clientAddress = Reflect.get(request, clientAddressSymbol),
|
|
224
|
+
locals,
|
|
225
|
+
prerenderedErrorPageFetch = fetch,
|
|
226
|
+
routeData
|
|
227
|
+
} = {}) {
|
|
212
228
|
const timeStart = performance.now();
|
|
213
|
-
let routeData = renderOptions?.routeData;
|
|
214
|
-
let locals;
|
|
215
|
-
let clientAddress;
|
|
216
|
-
let addCookieHeader;
|
|
217
229
|
const url = new URL(request.url);
|
|
218
230
|
const redirect = this.redirectTrailingSlash(url.pathname);
|
|
219
|
-
const prerenderedErrorPageFetch = renderOptions?.prerenderedErrorPageFetch ?? fetch;
|
|
220
231
|
if (redirect !== url.pathname) {
|
|
221
232
|
const status = request.method === "GET" ? 301 : 308;
|
|
222
|
-
|
|
233
|
+
const response2 = new Response(
|
|
223
234
|
redirectTemplate({
|
|
224
235
|
status,
|
|
225
236
|
relativeLocation: url.pathname,
|
|
@@ -233,11 +244,9 @@ class BaseApp {
|
|
|
233
244
|
}
|
|
234
245
|
}
|
|
235
246
|
);
|
|
247
|
+
this.#prepareResponse(response2, { addCookieHeader });
|
|
248
|
+
return response2;
|
|
236
249
|
}
|
|
237
|
-
addCookieHeader = renderOptions?.addCookieHeader;
|
|
238
|
-
clientAddress = renderOptions?.clientAddress ?? Reflect.get(request, clientAddressSymbol);
|
|
239
|
-
routeData = renderOptions?.routeData;
|
|
240
|
-
locals = renderOptions?.locals;
|
|
241
250
|
if (routeData) {
|
|
242
251
|
this.logger.debug(
|
|
243
252
|
"router",
|
|
@@ -247,15 +256,24 @@ class BaseApp {
|
|
|
247
256
|
this.logger.debug("router", "RouteData");
|
|
248
257
|
this.logger.debug("router", routeData);
|
|
249
258
|
}
|
|
259
|
+
const resolvedRenderOptions = {
|
|
260
|
+
addCookieHeader,
|
|
261
|
+
clientAddress,
|
|
262
|
+
prerenderedErrorPageFetch,
|
|
263
|
+
locals,
|
|
264
|
+
routeData
|
|
265
|
+
};
|
|
250
266
|
if (locals) {
|
|
251
267
|
if (typeof locals !== "object") {
|
|
252
268
|
const error = new AstroError(AstroErrorData.LocalsNotAnObject);
|
|
253
269
|
this.logger.error(null, error.stack);
|
|
254
270
|
return this.renderError(request, {
|
|
271
|
+
...resolvedRenderOptions,
|
|
272
|
+
// If locals are invalid, we don't want to include them when
|
|
273
|
+
// rendering the error page
|
|
274
|
+
locals: void 0,
|
|
255
275
|
status: 500,
|
|
256
|
-
error
|
|
257
|
-
clientAddress,
|
|
258
|
-
prerenderedErrorPageFetch
|
|
276
|
+
error
|
|
259
277
|
});
|
|
260
278
|
}
|
|
261
279
|
}
|
|
@@ -280,16 +298,15 @@ class BaseApp {
|
|
|
280
298
|
this.logger.debug("router", "Astro hasn't found routes that match " + request.url);
|
|
281
299
|
this.logger.debug("router", "Here's the available routes:\n", this.manifestData);
|
|
282
300
|
return this.renderError(request, {
|
|
283
|
-
|
|
284
|
-
status: 404
|
|
285
|
-
clientAddress,
|
|
286
|
-
prerenderedErrorPageFetch
|
|
301
|
+
...resolvedRenderOptions,
|
|
302
|
+
status: 404
|
|
287
303
|
});
|
|
288
304
|
}
|
|
289
305
|
const pathname = this.getPathnameFromRequest(request);
|
|
290
306
|
const defaultStatus = this.getDefaultStatusCode(routeData, pathname);
|
|
291
307
|
let response;
|
|
292
308
|
let session;
|
|
309
|
+
let cache;
|
|
293
310
|
try {
|
|
294
311
|
const componentInstance = await this.pipeline.getComponentByRoute(routeData);
|
|
295
312
|
const renderContext = await this.createRenderContext({
|
|
@@ -302,7 +319,30 @@ class BaseApp {
|
|
|
302
319
|
clientAddress
|
|
303
320
|
});
|
|
304
321
|
session = renderContext.session;
|
|
305
|
-
|
|
322
|
+
cache = renderContext.cache;
|
|
323
|
+
if (this.pipeline.cacheProvider) {
|
|
324
|
+
const cacheProvider = await this.pipeline.getCacheProvider();
|
|
325
|
+
if (cacheProvider?.onRequest) {
|
|
326
|
+
response = await cacheProvider.onRequest(
|
|
327
|
+
{
|
|
328
|
+
request,
|
|
329
|
+
url: new URL(request.url)
|
|
330
|
+
},
|
|
331
|
+
async () => {
|
|
332
|
+
const res = await renderContext.render(componentInstance);
|
|
333
|
+
applyCacheHeaders(cache, res);
|
|
334
|
+
return res;
|
|
335
|
+
}
|
|
336
|
+
);
|
|
337
|
+
response.headers.delete("CDN-Cache-Control");
|
|
338
|
+
response.headers.delete("Cache-Tag");
|
|
339
|
+
} else {
|
|
340
|
+
response = await renderContext.render(componentInstance);
|
|
341
|
+
applyCacheHeaders(cache, response);
|
|
342
|
+
}
|
|
343
|
+
} else {
|
|
344
|
+
response = await renderContext.render(componentInstance);
|
|
345
|
+
}
|
|
306
346
|
const isRewrite = response.headers.has(REWRITE_DIRECTIVE_HEADER_KEY);
|
|
307
347
|
this.logThisRequest({
|
|
308
348
|
pathname,
|
|
@@ -314,11 +354,9 @@ class BaseApp {
|
|
|
314
354
|
} catch (err) {
|
|
315
355
|
this.logger.error(null, err.stack || err.message || String(err));
|
|
316
356
|
return this.renderError(request, {
|
|
317
|
-
|
|
357
|
+
...resolvedRenderOptions,
|
|
318
358
|
status: 500,
|
|
319
|
-
error: err
|
|
320
|
-
clientAddress,
|
|
321
|
-
prerenderedErrorPageFetch
|
|
359
|
+
error: err
|
|
322
360
|
});
|
|
323
361
|
} finally {
|
|
324
362
|
await session?.[PERSIST_SYMBOL]();
|
|
@@ -327,26 +365,34 @@ class BaseApp {
|
|
|
327
365
|
// but uses the current route to handle the 404
|
|
328
366
|
response.body === null && response.headers.get(REROUTE_DIRECTIVE_HEADER) !== "no") {
|
|
329
367
|
return this.renderError(request, {
|
|
330
|
-
|
|
368
|
+
...resolvedRenderOptions,
|
|
331
369
|
response,
|
|
332
370
|
status: response.status,
|
|
333
371
|
// We don't have an error to report here. Passing null means we pass nothing intentionally
|
|
334
372
|
// while undefined means there's no error
|
|
335
|
-
error: response.status === 500 ? null : void 0
|
|
336
|
-
clientAddress,
|
|
337
|
-
prerenderedErrorPageFetch
|
|
373
|
+
error: response.status === 500 ? null : void 0
|
|
338
374
|
});
|
|
339
375
|
}
|
|
340
|
-
|
|
341
|
-
|
|
376
|
+
this.#prepareResponse(response, { addCookieHeader });
|
|
377
|
+
return response;
|
|
378
|
+
}
|
|
379
|
+
#prepareResponse(response, { addCookieHeader }) {
|
|
380
|
+
for (const headerName of [
|
|
381
|
+
REROUTE_DIRECTIVE_HEADER,
|
|
382
|
+
REWRITE_DIRECTIVE_HEADER_KEY,
|
|
383
|
+
NOOP_MIDDLEWARE_HEADER,
|
|
384
|
+
ROUTE_TYPE_HEADER
|
|
385
|
+
]) {
|
|
386
|
+
if (response.headers.has(headerName)) {
|
|
387
|
+
response.headers.delete(headerName);
|
|
388
|
+
}
|
|
342
389
|
}
|
|
343
390
|
if (addCookieHeader) {
|
|
344
|
-
for (const setCookieHeaderValue of
|
|
391
|
+
for (const setCookieHeaderValue of getSetCookiesFromResponse(response)) {
|
|
345
392
|
response.headers.append("set-cookie", setCookieHeaderValue);
|
|
346
393
|
}
|
|
347
394
|
}
|
|
348
395
|
Reflect.set(response, responseSentSymbol, true);
|
|
349
|
-
return response;
|
|
350
396
|
}
|
|
351
397
|
setCookieHeaders(response) {
|
|
352
398
|
return getSetCookiesFromResponse(response);
|
|
@@ -368,13 +414,11 @@ class BaseApp {
|
|
|
368
414
|
* This also handles pre-rendered /404 or /500 routes
|
|
369
415
|
*/
|
|
370
416
|
async renderError(request, {
|
|
371
|
-
locals,
|
|
372
417
|
status,
|
|
373
418
|
response: originalResponse,
|
|
374
419
|
skipMiddleware = false,
|
|
375
420
|
error,
|
|
376
|
-
|
|
377
|
-
prerenderedErrorPageFetch
|
|
421
|
+
...resolvedRenderOptions
|
|
378
422
|
}) {
|
|
379
423
|
const errorRoutePath = `/${status}${this.manifest.trailingSlash === "always" ? "/" : ""}`;
|
|
380
424
|
const errorRouteData = matchRoute(errorRoutePath, this.manifestData);
|
|
@@ -383,17 +427,21 @@ class BaseApp {
|
|
|
383
427
|
if (errorRouteData.prerender) {
|
|
384
428
|
const maybeDotHtml = errorRouteData.route.endsWith(`/${status}`) ? ".html" : "";
|
|
385
429
|
const statusURL = new URL(`${this.baseWithoutTrailingSlash}/${status}${maybeDotHtml}`, url);
|
|
386
|
-
if (statusURL.toString() !== request.url && prerenderedErrorPageFetch) {
|
|
387
|
-
const response2 = await prerenderedErrorPageFetch(
|
|
430
|
+
if (statusURL.toString() !== request.url && resolvedRenderOptions.prerenderedErrorPageFetch) {
|
|
431
|
+
const response2 = await resolvedRenderOptions.prerenderedErrorPageFetch(
|
|
432
|
+
statusURL.toString()
|
|
433
|
+
);
|
|
388
434
|
const override = { status, removeContentEncodingHeaders: true };
|
|
389
|
-
|
|
435
|
+
const newResponse = this.mergeResponses(response2, originalResponse, override);
|
|
436
|
+
this.#prepareResponse(newResponse, resolvedRenderOptions);
|
|
437
|
+
return newResponse;
|
|
390
438
|
}
|
|
391
439
|
}
|
|
392
440
|
const mod = await this.pipeline.getComponentByRoute(errorRouteData);
|
|
393
441
|
let session;
|
|
394
442
|
try {
|
|
395
443
|
const renderContext = await this.createRenderContext({
|
|
396
|
-
locals,
|
|
444
|
+
locals: resolvedRenderOptions.locals,
|
|
397
445
|
pipeline: this.pipeline,
|
|
398
446
|
skipMiddleware,
|
|
399
447
|
pathname: this.getPathnameFromRequest(request),
|
|
@@ -401,20 +449,20 @@ class BaseApp {
|
|
|
401
449
|
routeData: errorRouteData,
|
|
402
450
|
status,
|
|
403
451
|
props: { error },
|
|
404
|
-
clientAddress
|
|
452
|
+
clientAddress: resolvedRenderOptions.clientAddress
|
|
405
453
|
});
|
|
406
454
|
session = renderContext.session;
|
|
407
455
|
const response2 = await renderContext.render(mod);
|
|
408
|
-
|
|
456
|
+
const newResponse = this.mergeResponses(response2, originalResponse);
|
|
457
|
+
this.#prepareResponse(newResponse, resolvedRenderOptions);
|
|
458
|
+
return newResponse;
|
|
409
459
|
} catch {
|
|
410
460
|
if (skipMiddleware === false) {
|
|
411
461
|
return this.renderError(request, {
|
|
412
|
-
|
|
462
|
+
...resolvedRenderOptions,
|
|
413
463
|
status,
|
|
414
464
|
response: originalResponse,
|
|
415
|
-
skipMiddleware: true
|
|
416
|
-
clientAddress,
|
|
417
|
-
prerenderedErrorPageFetch
|
|
465
|
+
skipMiddleware: true
|
|
418
466
|
});
|
|
419
467
|
}
|
|
420
468
|
} finally {
|
|
@@ -422,7 +470,7 @@ class BaseApp {
|
|
|
422
470
|
}
|
|
423
471
|
}
|
|
424
472
|
const response = this.mergeResponses(new Response(null, { status }), originalResponse);
|
|
425
|
-
|
|
473
|
+
this.#prepareResponse(response, resolvedRenderOptions);
|
|
426
474
|
return response;
|
|
427
475
|
}
|
|
428
476
|
mergeResponses(newResponse, originalResponse, override) {
|
|
@@ -447,15 +495,18 @@ class BaseApp {
|
|
|
447
495
|
originalResponse.headers.delete("Content-type");
|
|
448
496
|
} catch {
|
|
449
497
|
}
|
|
450
|
-
const mergedHeaders = new Map([
|
|
451
|
-
...Array.from(newResponseHeaders),
|
|
452
|
-
...Array.from(originalResponse.headers)
|
|
453
|
-
]);
|
|
454
498
|
const newHeaders = new Headers();
|
|
455
|
-
|
|
456
|
-
|
|
499
|
+
const seen = /* @__PURE__ */ new Set();
|
|
500
|
+
for (const [name, value] of originalResponse.headers) {
|
|
501
|
+
newHeaders.append(name, value);
|
|
502
|
+
seen.add(name.toLowerCase());
|
|
457
503
|
}
|
|
458
|
-
|
|
504
|
+
for (const [name, value] of newResponseHeaders) {
|
|
505
|
+
if (!seen.has(name.toLowerCase())) {
|
|
506
|
+
newHeaders.append(name, value);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
const mergedResponse = new Response(newResponse.body, {
|
|
459
510
|
status,
|
|
460
511
|
statusText: status === 200 ? newResponse.statusText : originalResponse.statusText,
|
|
461
512
|
// If you're looking at here for possible bugs, it means that it's not a bug.
|
|
@@ -465,6 +516,19 @@ class BaseApp {
|
|
|
465
516
|
// Although, we don't want it to replace the content-type, because the error page must return `text/html`
|
|
466
517
|
headers: newHeaders
|
|
467
518
|
});
|
|
519
|
+
const originalCookies = getCookiesFromResponse(originalResponse);
|
|
520
|
+
const newCookies = getCookiesFromResponse(newResponse);
|
|
521
|
+
if (originalCookies) {
|
|
522
|
+
if (newCookies) {
|
|
523
|
+
for (const cookieValue of AstroCookies.consume(newCookies)) {
|
|
524
|
+
originalResponse.headers.append("set-cookie", cookieValue);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
attachCookiesToResponse(mergedResponse, originalCookies);
|
|
528
|
+
} else if (newCookies) {
|
|
529
|
+
attachCookiesToResponse(mergedResponse, newCookies);
|
|
530
|
+
}
|
|
531
|
+
return mergedResponse;
|
|
468
532
|
}
|
|
469
533
|
getDefaultStatusCode(routeData, pathname) {
|
|
470
534
|
if (!routeData.pattern.test(pathname)) {
|
|
@@ -19,6 +19,6 @@ export declare class DevApp extends BaseApp<NonRunnablePipeline> {
|
|
|
19
19
|
match(request: Request): RouteData | undefined;
|
|
20
20
|
devMatch(pathname: string): Promise<DevMatch | undefined>;
|
|
21
21
|
createRenderContext(payload: CreateRenderContext): Promise<RenderContext>;
|
|
22
|
-
renderError(request: Request, {
|
|
22
|
+
renderError(request: Request, { skipMiddleware, error, status, response: _response, ...resolvedRenderOptions }: RenderErrorOptions): Promise<Response>;
|
|
23
23
|
logRequest({ pathname, method, statusCode, isRewrite, reqTime }: LogRequestPayload): void;
|
|
24
24
|
}
|
package/dist/core/app/dev/app.js
CHANGED
|
@@ -56,7 +56,13 @@ class DevApp extends BaseApp {
|
|
|
56
56
|
pathname: this.resolvedPathname ?? payload.pathname
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
|
-
async renderError(request, {
|
|
59
|
+
async renderError(request, {
|
|
60
|
+
skipMiddleware = false,
|
|
61
|
+
error,
|
|
62
|
+
status,
|
|
63
|
+
response: _response,
|
|
64
|
+
...resolvedRenderOptions
|
|
65
|
+
}) {
|
|
60
66
|
if (isAstroError(error) && [MiddlewareNoDataOrNextCalled.name, MiddlewareNotAResponse.name].includes(error.name)) {
|
|
61
67
|
throw error;
|
|
62
68
|
}
|
|
@@ -64,13 +70,13 @@ class DevApp extends BaseApp {
|
|
|
64
70
|
try {
|
|
65
71
|
const preloadedComponent = await this.pipeline.getComponentByRoute(routeData);
|
|
66
72
|
const renderContext = await this.createRenderContext({
|
|
67
|
-
locals,
|
|
73
|
+
locals: resolvedRenderOptions.locals,
|
|
68
74
|
pipeline: this.pipeline,
|
|
69
|
-
pathname:
|
|
75
|
+
pathname: this.getPathnameFromRequest(request),
|
|
70
76
|
skipMiddleware,
|
|
71
77
|
request,
|
|
72
78
|
routeData,
|
|
73
|
-
clientAddress,
|
|
79
|
+
clientAddress: resolvedRenderOptions.clientAddress,
|
|
74
80
|
status,
|
|
75
81
|
shouldInjectCspMetaTags: false
|
|
76
82
|
});
|
|
@@ -83,8 +89,7 @@ class DevApp extends BaseApp {
|
|
|
83
89
|
} catch (_err) {
|
|
84
90
|
if (skipMiddleware === false) {
|
|
85
91
|
return this.renderError(request, {
|
|
86
|
-
|
|
87
|
-
prerenderedErrorPageFetch: fetch,
|
|
92
|
+
...resolvedRenderOptions,
|
|
88
93
|
status: 500,
|
|
89
94
|
skipMiddleware: true,
|
|
90
95
|
error: _err
|
package/dist/core/app/node.js
CHANGED
|
@@ -82,7 +82,8 @@ function createRequest(req, {
|
|
|
82
82
|
onSocketClose();
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
-
const
|
|
85
|
+
const hostValidated = validated.host !== void 0 || validatedHostname !== void 0;
|
|
86
|
+
const forwardedClientIp = hostValidated ? getFirstForwardedValue(req.headers["x-forwarded-for"]) : void 0;
|
|
86
87
|
const clientIp = forwardedClientIp || req.socket?.remoteAddress;
|
|
87
88
|
if (clientIp) {
|
|
88
89
|
Reflect.set(request, clientAddressSymbol, clientIp);
|
package/dist/core/app/types.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { SinglePageBuiltModule } from '../build/types.js';
|
|
|
7
7
|
import type { CspDirective } from '../csp/config.js';
|
|
8
8
|
import type { LoggerLevel } from '../logger/core.js';
|
|
9
9
|
import type { RoutingStrategies } from './common.js';
|
|
10
|
+
import type { CacheProviderFactory, SSRManifestCache } from '../cache/types.js';
|
|
10
11
|
import type { BaseSessionConfig, SessionDriverFactory } from '../session/types.js';
|
|
11
12
|
import type { DevToolbarPlacement } from '../../types/public/toolbar.js';
|
|
12
13
|
import type { MiddlewareMode } from '../../types/public/integrations.js';
|
|
@@ -99,10 +100,14 @@ export type SSRManifest = {
|
|
|
99
100
|
sessionDriver?: () => Promise<{
|
|
100
101
|
default: SessionDriverFactory | null;
|
|
101
102
|
}>;
|
|
103
|
+
cacheProvider?: () => Promise<{
|
|
104
|
+
default: CacheProviderFactory | null;
|
|
105
|
+
}>;
|
|
102
106
|
checkOrigin: boolean;
|
|
103
107
|
allowedDomains?: Partial<RemotePattern>[];
|
|
104
108
|
actionBodySizeLimit: number;
|
|
105
109
|
sessionConfig?: SSRManifestSession;
|
|
110
|
+
cacheConfig?: SSRManifestCache;
|
|
106
111
|
cacheDir: URL;
|
|
107
112
|
srcDir: URL;
|
|
108
113
|
outDir: URL;
|