astro 6.2.2 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/dist/actions/handler.d.ts +32 -0
  2. package/dist/actions/handler.js +45 -0
  3. package/dist/actions/runtime/server.js +1 -1
  4. package/dist/assets/build/generate.js +1 -1
  5. package/dist/assets/build/remote.d.ts +3 -2
  6. package/dist/assets/build/remote.js +16 -9
  7. package/dist/assets/endpoint/generic.js +4 -7
  8. package/dist/assets/endpoint/shared.js +7 -2
  9. package/dist/assets/index.d.ts +1 -0
  10. package/dist/assets/index.js +2 -0
  11. package/dist/assets/services/sharp.js +7 -0
  12. package/dist/assets/utils/index.d.ts +1 -0
  13. package/dist/assets/utils/index.js +2 -0
  14. package/dist/assets/utils/redirectValidation.d.ts +48 -0
  15. package/dist/assets/utils/redirectValidation.js +48 -0
  16. package/dist/assets/utils/remoteProbe.js +25 -2
  17. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  18. package/dist/container/index.js +18 -14
  19. package/dist/content/content-layer.js +3 -4
  20. package/dist/content/server-listeners.js +0 -4
  21. package/dist/content/vite-plugin-content-virtual-mod.js +9 -1
  22. package/dist/core/app/base.d.ts +33 -15
  23. package/dist/core/app/base.js +120 -324
  24. package/dist/core/app/dev/app.d.ts +3 -2
  25. package/dist/core/app/dev/app.js +4 -60
  26. package/dist/core/app/entrypoints/virtual/dev.js +2 -0
  27. package/dist/core/app/entrypoints/virtual/prod.js +4 -1
  28. package/dist/core/app/prepare-response.d.ts +11 -0
  29. package/dist/core/app/prepare-response.js +18 -0
  30. package/dist/core/app/render-options.d.ts +11 -0
  31. package/dist/core/app/render-options.js +11 -0
  32. package/dist/core/base-pipeline.d.ts +38 -1
  33. package/dist/core/base-pipeline.js +50 -7
  34. package/dist/core/build/app.d.ts +3 -4
  35. package/dist/core/build/app.js +3 -17
  36. package/dist/core/cache/handler.d.ts +29 -0
  37. package/dist/core/cache/handler.js +81 -0
  38. package/dist/core/config/schemas/base.d.ts +4 -0
  39. package/dist/core/config/schemas/base.js +4 -0
  40. package/dist/core/config/schemas/relative.d.ts +6 -0
  41. package/dist/core/constants.d.ts +27 -1
  42. package/dist/core/constants.js +14 -1
  43. package/dist/core/cookies/cookies.d.ts +7 -2
  44. package/dist/core/cookies/cookies.js +11 -4
  45. package/dist/core/cookies/response.d.ts +1 -1
  46. package/dist/core/cookies/response.js +1 -2
  47. package/dist/core/create-vite.js +15 -0
  48. package/dist/core/csp/runtime.js +6 -4
  49. package/dist/core/dev/dev.js +1 -1
  50. package/dist/core/errors/build-handler.d.ts +17 -0
  51. package/dist/core/errors/build-handler.js +22 -0
  52. package/dist/core/errors/default-handler.d.ts +14 -0
  53. package/dist/core/errors/default-handler.js +144 -0
  54. package/dist/core/errors/dev-handler.d.ts +21 -0
  55. package/dist/core/errors/dev-handler.js +82 -0
  56. package/dist/core/errors/handler.d.ts +9 -0
  57. package/dist/core/errors/handler.js +0 -0
  58. package/dist/core/fetch/default-handler.d.ts +17 -0
  59. package/dist/core/fetch/default-handler.js +45 -0
  60. package/dist/core/fetch/fetch-state.d.ts +244 -0
  61. package/dist/core/fetch/fetch-state.js +779 -0
  62. package/dist/core/fetch/index.d.ts +61 -0
  63. package/dist/core/fetch/index.js +121 -0
  64. package/dist/core/fetch/types.d.ts +6 -0
  65. package/dist/core/fetch/types.js +0 -0
  66. package/dist/core/fetch/vite-plugin.d.ts +5 -0
  67. package/dist/core/fetch/vite-plugin.js +69 -0
  68. package/dist/core/hono/index.d.ts +21 -0
  69. package/dist/core/hono/index.js +98 -0
  70. package/dist/core/i18n/handler.d.ts +18 -0
  71. package/dist/core/i18n/handler.js +119 -0
  72. package/dist/core/logger/core.d.ts +8 -0
  73. package/dist/core/logger/core.js +16 -0
  74. package/dist/core/messages/runtime.js +1 -1
  75. package/dist/core/middleware/astro-middleware.d.ts +27 -0
  76. package/dist/core/middleware/astro-middleware.js +53 -0
  77. package/dist/core/pages/handler.d.ts +20 -0
  78. package/dist/core/pages/handler.js +74 -0
  79. package/dist/core/redirects/render.d.ts +2 -2
  80. package/dist/core/redirects/render.js +7 -8
  81. package/dist/core/rewrites/handler.d.ts +37 -0
  82. package/dist/core/rewrites/handler.js +67 -0
  83. package/dist/core/routing/3xx.js +8 -4
  84. package/dist/core/routing/handler.d.ts +17 -0
  85. package/dist/core/routing/handler.js +172 -0
  86. package/dist/core/routing/match.d.ts +0 -7
  87. package/dist/core/routing/match.js +0 -5
  88. package/dist/core/routing/trailing-slash-handler.d.ts +18 -0
  89. package/dist/core/routing/trailing-slash-handler.js +67 -0
  90. package/dist/core/session/drivers.d.ts +1 -1
  91. package/dist/core/session/handler.d.ts +11 -0
  92. package/dist/core/session/handler.js +33 -0
  93. package/dist/core/util/normalized-url.d.ts +10 -0
  94. package/dist/core/util/normalized-url.js +21 -0
  95. package/dist/i18n/middleware.d.ts +10 -0
  96. package/dist/i18n/middleware.js +4 -88
  97. package/dist/i18n/utils.js +2 -2
  98. package/dist/runtime/server/astro-island.js +57 -20
  99. package/dist/runtime/server/astro-island.prebuilt-dev.d.ts +1 -1
  100. package/dist/runtime/server/astro-island.prebuilt-dev.js +1 -1
  101. package/dist/runtime/server/astro-island.prebuilt.d.ts +1 -1
  102. package/dist/runtime/server/astro-island.prebuilt.js +1 -1
  103. package/dist/runtime/server/render/server-islands.js +2 -1
  104. package/dist/types/public/config.d.ts +46 -12
  105. package/dist/types/public/internal.d.ts +1 -1
  106. package/dist/vite-plugin-app/app.d.ts +4 -5
  107. package/dist/vite-plugin-app/app.js +20 -65
  108. package/package.json +11 -5
  109. package/dist/core/render-context.d.ts +0 -77
  110. package/dist/core/render-context.js +0 -826
@@ -1,6 +1,7 @@
1
1
  import type { RouteData } from '../../../types/public/index.js';
2
+ import type { ErrorHandler } from '../../errors/handler.js';
2
3
  import type { AstroLogger } from '../../logger/core.js';
3
- import { BaseApp, type DevMatch, type LogRequestPayload, type RenderErrorOptions } from '../base.js';
4
+ import { BaseApp, type DevMatch, type LogRequestPayload } from '../base.js';
4
5
  import type { SSRManifest } from '../types.js';
5
6
  import { NonRunnablePipeline } from './pipeline.js';
6
7
  import type { RoutesList } from '../../../types/astro.js';
@@ -20,6 +21,6 @@ export declare class DevApp extends BaseApp<NonRunnablePipeline> {
20
21
  updateRoutes(newRoutesList: RoutesList): void;
21
22
  match(request: Request): RouteData | undefined;
22
23
  devMatch(pathname: string): Promise<DevMatch | undefined>;
23
- renderError(request: Request, { skipMiddleware, error, status, response: _response, ...resolvedRenderOptions }: RenderErrorOptions): Promise<Response>;
24
+ protected createErrorHandler(): ErrorHandler;
24
25
  logRequest({ pathname, method, statusCode, isRewrite, reqTime }: LogRequestPayload): void;
25
26
  }
@@ -1,10 +1,6 @@
1
- import { MiddlewareNoDataOrNextCalled, MiddlewareNotAResponse } from "../../errors/errors-data.js";
2
- import { isAstroError } from "../../errors/index.js";
3
- import {
4
- BaseApp
5
- } from "../base.js";
1
+ import { DevErrorHandler } from "../../errors/dev-handler.js";
2
+ import { BaseApp } from "../base.js";
6
3
  import { NonRunnablePipeline } from "./pipeline.js";
7
- import { getCustom404Route, getCustom500Route } from "../../routing/helpers.js";
8
4
  import { ensure404Route } from "../../routing/astro-designed-error-pages.js";
9
5
  import { matchRoute } from "../../routing/dev.js";
10
6
  import { req } from "../../messages/runtime.js";
@@ -53,60 +49,8 @@ class DevApp extends BaseApp {
53
49
  resolvedPathname: matchedRoute.resolvedPathname
54
50
  };
55
51
  }
56
- async renderError(request, {
57
- skipMiddleware = false,
58
- error,
59
- status,
60
- response: _response,
61
- ...resolvedRenderOptions
62
- }) {
63
- if (isAstroError(error) && [MiddlewareNoDataOrNextCalled.name, MiddlewareNotAResponse.name].includes(error.name)) {
64
- throw error;
65
- }
66
- const renderRoute = async (routeData) => {
67
- try {
68
- const preloadedComponent = await this.pipeline.getComponentByRoute(routeData);
69
- const renderContext = await this.createRenderContext({
70
- locals: resolvedRenderOptions.locals,
71
- pipeline: this.pipeline,
72
- pathname: this.getPathnameFromRequest(request),
73
- skipMiddleware,
74
- request,
75
- routeData,
76
- clientAddress: resolvedRenderOptions.clientAddress,
77
- status,
78
- shouldInjectCspMetaTags: false
79
- });
80
- renderContext.props.error = error;
81
- const response = await renderContext.render(preloadedComponent);
82
- if (error) {
83
- this.logger.error("router", error.stack || error.message);
84
- }
85
- return response;
86
- } catch (_err) {
87
- if (skipMiddleware === false) {
88
- return this.renderError(request, {
89
- ...resolvedRenderOptions,
90
- status: 500,
91
- skipMiddleware: true,
92
- error: _err
93
- });
94
- }
95
- throw _err;
96
- }
97
- };
98
- if (status === 404) {
99
- const custom404 = getCustom404Route(this.manifestData);
100
- if (custom404) {
101
- return renderRoute(custom404);
102
- }
103
- }
104
- const custom500 = getCustom500Route(this.manifestData);
105
- if (!custom500) {
106
- throw error;
107
- } else {
108
- return renderRoute(custom500);
109
- }
52
+ createErrorHandler() {
53
+ return new DevErrorHandler(this, { shouldInjectCspMetaTags: false });
110
54
  }
111
55
  logRequest({ pathname, method, statusCode, isRewrite, reqTime }) {
112
56
  if (pathname === "/favicon.ico") {
@@ -1,3 +1,4 @@
1
+ import fetchable from "virtual:astro:fetchable";
1
2
  import { manifest } from "virtual:astro:manifest";
2
3
  import { DevApp } from "../../dev/app.js";
3
4
  import { createConsoleLogger } from "../../../logger/impls/console.js";
@@ -5,6 +6,7 @@ let currentDevApp = null;
5
6
  const createApp = ({ streaming } = {}) => {
6
7
  const logger = createConsoleLogger(manifest.logLevel);
7
8
  currentDevApp = new DevApp(manifest, streaming, logger);
9
+ currentDevApp.setFetchHandler(fetchable);
8
10
  if (import.meta.hot) {
9
11
  import.meta.hot.on("astro:routes-updated", async () => {
10
12
  if (!currentDevApp) return;
@@ -1,7 +1,10 @@
1
+ import fetchable from "virtual:astro:fetchable";
1
2
  import { manifest } from "virtual:astro:manifest";
2
3
  import { App } from "../../app.js";
3
4
  const createApp = ({ streaming } = {}) => {
4
- return new App(manifest, streaming);
5
+ const app = new App(manifest, streaming);
6
+ app.setFetchHandler(fetchable);
7
+ return app;
5
8
  };
6
9
  export {
7
10
  createApp
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Strips internal-only headers from the response before sending it to the
3
+ * user agent, and optionally appends cookies written via `Astro.cookie.set()`
4
+ * to the `Set-Cookie` header.
5
+ *
6
+ * This is a pure function with no dependencies on the app; it is shared by
7
+ * `AstroHandler` and the various error handlers.
8
+ */
9
+ export declare function prepareResponse(response: Response, { addCookieHeader }: {
10
+ addCookieHeader: boolean;
11
+ }): void;
@@ -0,0 +1,18 @@
1
+ import { INTERNAL_RESPONSE_HEADERS, responseSentSymbol } from "../constants.js";
2
+ import { getSetCookiesFromResponse } from "../cookies/index.js";
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
+ if (addCookieHeader) {
10
+ for (const setCookieHeaderValue of getSetCookiesFromResponse(response)) {
11
+ response.headers.append("set-cookie", setCookieHeaderValue);
12
+ }
13
+ }
14
+ Reflect.set(response, responseSentSymbol, true);
15
+ }
16
+ export {
17
+ prepareResponse
18
+ };
@@ -0,0 +1,11 @@
1
+ import type { ResolvedRenderOptions } from './base.js';
2
+ /**
3
+ * Reads `ResolvedRenderOptions` that were attached to a request via
4
+ * `renderOptionsSymbol`. Returns `undefined` if no options are attached.
5
+ */
6
+ export declare function getRenderOptions(request: Request): ResolvedRenderOptions | undefined;
7
+ /**
8
+ * Attaches `ResolvedRenderOptions` to a request via `renderOptionsSymbol` so
9
+ * that downstream handlers can read them.
10
+ */
11
+ export declare function setRenderOptions(request: Request, options: ResolvedRenderOptions): void;
@@ -0,0 +1,11 @@
1
+ const renderOptionsSymbol = /* @__PURE__ */ Symbol.for("astro.renderOptions");
2
+ function getRenderOptions(request) {
3
+ return Reflect.get(request, renderOptionsSymbol);
4
+ }
5
+ function setRenderOptions(request, options) {
6
+ Reflect.set(request, renderOptionsSymbol, options);
7
+ }
8
+ export {
9
+ getRenderOptions,
10
+ setRenderOptions
11
+ };
@@ -14,13 +14,29 @@ import type { CompiledCacheRoute } from './cache/runtime/route-matching.js';
14
14
  import type { SessionDriverFactory } from './session/types.js';
15
15
  import { NodePool } from '../runtime/server/render/queue/pool.js';
16
16
  import { HTMLStringCache } from '../runtime/server/html-string-cache.js';
17
+ /**
18
+ * Bit flags for pipeline features that handler classes register as
19
+ * "used" when a custom `src/app.ts` fetch handler is in play. After the
20
+ * first request (dev) or at runtime (prod SSR), we compare against the
21
+ * manifest to warn about features the user configured but forgot to
22
+ * include in their custom pipeline.
23
+ */
24
+ export declare const PipelineFeatures: {
25
+ readonly redirects: number;
26
+ readonly sessions: number;
27
+ readonly actions: number;
28
+ readonly middleware: number;
29
+ readonly i18n: number;
30
+ readonly cache: number;
31
+ };
17
32
  /**
18
33
  * The `Pipeline` represents the static parts of rendering that do not change between requests.
19
34
  * These are mostly known when the server first starts up and do not change.
20
35
  *
21
- * Thus, a `Pipeline` is created once at process start and then used by every `RenderContext`.
36
+ * Thus, a `Pipeline` is created once at process start and then used by every `FetchState`.
22
37
  */
23
38
  export declare abstract class Pipeline {
39
+ #private;
24
40
  readonly internalMiddleware: MiddlewareHandler[];
25
41
  resolvedMiddleware: MiddlewareHandler | undefined;
26
42
  resolvedLogger: boolean;
@@ -30,6 +46,12 @@ export declare abstract class Pipeline {
30
46
  compiledCacheRoutes: CompiledCacheRoute[] | undefined;
31
47
  nodePool: NodePool | undefined;
32
48
  htmlStringCache: HTMLStringCache | undefined;
49
+ /**
50
+ * Bit mask of pipeline features activated by handler classes.
51
+ * Each handler sets its bit via `|=`. Only meaningful when a
52
+ * custom `src/app.ts` fetch handler is in use.
53
+ */
54
+ usedFeatures: number;
33
55
  logger: AstroLogger;
34
56
  readonly manifest: SSRManifest;
35
57
  /**
@@ -63,6 +85,10 @@ export declare abstract class Pipeline {
63
85
  readonly cacheProvider: SSRManifest['cacheProvider'];
64
86
  readonly cacheConfig: SSRManifest['cacheConfig'];
65
87
  readonly serverIslands: SSRManifest['serverIslandMappings'];
88
+ /** Route data derived from the manifest, used for route matching. */
89
+ manifestData: {
90
+ routes: RouteData[];
91
+ };
66
92
  constructor(logger: AstroLogger, manifest: SSRManifest,
67
93
  /**
68
94
  * "development" or "production" only
@@ -85,6 +111,17 @@ export declare abstract class Pipeline {
85
111
  }>) | undefined, cacheProvider?: (() => Promise<{
86
112
  default: CacheProviderFactory | null;
87
113
  }>) | undefined, cacheConfig?: import("./cache/types.js").SSRManifestCache | undefined, serverIslands?: (() => Promise<ServerIslandMappings> | ServerIslandMappings) | undefined);
114
+ /**
115
+ * Low-level route matching against the manifest routes. Returns the
116
+ * matched `RouteData` or `undefined`. Does not filter prerendered
117
+ * routes or check public assets — use `BaseApp.match()` for that.
118
+ */
119
+ matchRoute(pathname: string): RouteData | undefined;
120
+ /**
121
+ * Rebuilds the internal router after routes have been added or
122
+ * removed (e.g. by the dev server on HMR).
123
+ */
124
+ rebuildRouter(): void;
88
125
  abstract headElements(routeData: RouteData): Promise<HeadElements> | HeadElements;
89
126
  abstract componentMetadata(routeData: RouteData): Promise<SSRResult['componentMetadata']> | void;
90
127
  /**
@@ -1,5 +1,4 @@
1
1
  import { NOOP_ACTIONS_MOD } from "../actions/noop-actions.js";
2
- import { createI18nMiddleware } from "../i18n/middleware.js";
3
2
  import { createOriginCheckMiddleware } from "./app/middlewares.js";
4
3
  import { ActionNotFoundError } from "./errors/errors-data.js";
5
4
  import { AstroError } from "./errors/index.js";
@@ -8,10 +7,20 @@ import { sequence } from "./middleware/sequence.js";
8
7
  import { RedirectSinglePageBuiltModule } from "./redirects/index.js";
9
8
  import { RouteCache } from "./render/route-cache.js";
10
9
  import { createDefaultRoutes } from "./routing/default.js";
10
+ import { ensure404Route } from "./routing/astro-designed-error-pages.js";
11
+ import { Router } from "./routing/router.js";
11
12
  import { NodePool } from "../runtime/server/render/queue/pool.js";
12
13
  import { HTMLStringCache } from "../runtime/server/html-string-cache.js";
13
14
  import { FORBIDDEN_PATH_KEYS } from "@astrojs/internal-helpers/object";
14
15
  import { loadLogger } from "./logger/load.js";
16
+ const PipelineFeatures = {
17
+ redirects: 1 << 0,
18
+ sessions: 1 << 1,
19
+ actions: 1 << 2,
20
+ middleware: 1 << 3,
21
+ i18n: 1 << 4,
22
+ cache: 1 << 5
23
+ };
15
24
  class Pipeline {
16
25
  internalMiddleware;
17
26
  resolvedMiddleware = void 0;
@@ -22,6 +31,12 @@ class Pipeline {
22
31
  compiledCacheRoutes = void 0;
23
32
  nodePool;
24
33
  htmlStringCache;
34
+ /**
35
+ * Bit mask of pipeline features activated by handler classes.
36
+ * Each handler sets its bit via `|=`. Only meaningful when a
37
+ * custom `src/app.ts` fetch handler is in use.
38
+ */
39
+ usedFeatures = 0;
25
40
  logger;
26
41
  manifest;
27
42
  /**
@@ -55,6 +70,10 @@ class Pipeline {
55
70
  cacheProvider;
56
71
  cacheConfig;
57
72
  serverIslands;
73
+ /** Route data derived from the manifest, used for route matching. */
74
+ manifestData;
75
+ /** Pattern-matching router built from manifestData. */
76
+ #router;
58
77
  constructor(logger, manifest, runtimeMode, renderers, resolve, streaming, adapterName = manifest.adapterName, clientDirectives = manifest.clientDirectives, inlinedScripts = manifest.inlinedScripts, compressHTML = manifest.compressHTML, i18n = manifest.i18n, middleware = manifest.middleware, routeCache = new RouteCache(logger, runtimeMode), site = manifest.site ? new URL(manifest.site) : void 0, defaultRoutes = createDefaultRoutes(manifest), actions = manifest.actions, sessionDriver = manifest.sessionDriver, cacheProvider = manifest.cacheProvider, cacheConfig = manifest.cacheConfig, serverIslands = manifest.serverIslandMappings) {
59
78
  this.logger = logger;
60
79
  this.manifest = manifest;
@@ -76,12 +95,14 @@ class Pipeline {
76
95
  this.cacheProvider = cacheProvider;
77
96
  this.cacheConfig = cacheConfig;
78
97
  this.serverIslands = serverIslands;
98
+ this.manifestData = { routes: (manifest.routes ?? []).map((route) => route.routeData) };
99
+ ensure404Route(this.manifestData);
100
+ this.#router = new Router(this.manifestData.routes, {
101
+ base: manifest.base,
102
+ trailingSlash: manifest.trailingSlash,
103
+ buildFormat: manifest.buildFormat
104
+ });
79
105
  this.internalMiddleware = [];
80
- if (i18n?.strategy !== "manual") {
81
- this.internalMiddleware.push(
82
- createI18nMiddleware(i18n, manifest.base, manifest.trailingSlash, manifest.buildFormat)
83
- );
84
- }
85
106
  if (manifest.experimentalQueuedRendering.enabled) {
86
107
  this.nodePool = this.createNodePool(
87
108
  manifest.experimentalQueuedRendering.poolSize ?? 1e3,
@@ -92,6 +113,27 @@ class Pipeline {
92
113
  }
93
114
  }
94
115
  }
116
+ /**
117
+ * Low-level route matching against the manifest routes. Returns the
118
+ * matched `RouteData` or `undefined`. Does not filter prerendered
119
+ * routes or check public assets — use `BaseApp.match()` for that.
120
+ */
121
+ matchRoute(pathname) {
122
+ const match = this.#router.match(pathname, { allowWithoutBase: true });
123
+ if (match.type !== "match") return void 0;
124
+ return match.route;
125
+ }
126
+ /**
127
+ * Rebuilds the internal router after routes have been added or
128
+ * removed (e.g. by the dev server on HMR).
129
+ */
130
+ rebuildRouter() {
131
+ this.#router = new Router(this.manifestData.routes, {
132
+ base: this.manifest.base,
133
+ trailingSlash: this.manifest.trailingSlash,
134
+ buildFormat: this.manifest.buildFormat
135
+ });
136
+ }
95
137
  /**
96
138
  * Resolves the middleware from the manifest, and returns the `onRequest` function. If `onRequest` isn't there,
97
139
  * it returns a no-op function
@@ -243,5 +285,6 @@ class Pipeline {
243
285
  }
244
286
  }
245
287
  export {
246
- Pipeline
288
+ Pipeline,
289
+ PipelineFeatures
247
290
  };
@@ -1,20 +1,19 @@
1
- import { BaseApp, type RenderErrorOptions } from '../app/entrypoints/index.js';
1
+ import { BaseApp } from '../app/entrypoints/index.js';
2
2
  import type { SSRManifest } from '../app/types.js';
3
3
  import type { BuildInternals } from './internal.js';
4
4
  import { BuildPipeline } from './pipeline.js';
5
5
  import type { StaticBuildOptions } from './types.js';
6
- import type { CreateRenderContext, RenderContext } from '../render-context.js';
7
6
  import type { LogRequestPayload } from '../app/base.js';
7
+ import type { ErrorHandler } from '../errors/handler.js';
8
8
  import type { PoolStatsReport } from '../../runtime/server/render/queue/pool.js';
9
9
  export declare class BuildApp extends BaseApp<BuildPipeline> {
10
10
  createPipeline(_streaming: boolean, manifest: SSRManifest, ..._args: any[]): BuildPipeline;
11
- createRenderContext(payload: CreateRenderContext): Promise<RenderContext>;
12
11
  isDev(): boolean;
13
12
  setInternals(internals: BuildInternals): void;
14
13
  setOptions(options: StaticBuildOptions): void;
15
14
  getOptions(): StaticBuildOptions;
16
15
  getSettings(): import("../../types/astro.js").AstroSettings;
17
- renderError(request: Request, options: RenderErrorOptions): Promise<Response>;
16
+ protected createErrorHandler(): ErrorHandler;
18
17
  getQueueStats(): PoolStatsReport | undefined;
19
18
  logRequest(_options: LogRequestPayload): void;
20
19
  }
@@ -1,16 +1,12 @@
1
1
  import { BaseApp } from "../app/entrypoints/index.js";
2
2
  import { BuildPipeline } from "./pipeline.js";
3
+ import { BuildErrorHandler } from "../errors/build-handler.js";
3
4
  class BuildApp extends BaseApp {
4
5
  createPipeline(_streaming, manifest, ..._args) {
5
6
  return BuildPipeline.create({
6
7
  manifest
7
8
  });
8
9
  }
9
- async createRenderContext(payload) {
10
- return await super.createRenderContext({
11
- ...payload
12
- });
13
- }
14
10
  isDev() {
15
11
  return true;
16
12
  }
@@ -28,18 +24,8 @@ class BuildApp extends BaseApp {
28
24
  getSettings() {
29
25
  return this.pipeline.getSettings();
30
26
  }
31
- async renderError(request, options) {
32
- if (options.status === 500) {
33
- if (options.response) {
34
- return options.response;
35
- }
36
- throw options.error;
37
- } else {
38
- return super.renderError(request, {
39
- ...options,
40
- prerenderedErrorPageFetch: void 0
41
- });
42
- }
27
+ createErrorHandler() {
28
+ return new BuildErrorHandler(this);
43
29
  }
44
30
  getQueueStats() {
45
31
  if (this.pipeline.nodePool) {
@@ -0,0 +1,29 @@
1
+ import type { BaseApp } from '../app/base.js';
2
+ import type { FetchState } from '../fetch/fetch-state.js';
3
+ import type { Pipeline } from '../base-pipeline.js';
4
+ /**
5
+ * Registers a cache provider on the given `FetchState`. When
6
+ * `state.resolve('cache')` is first called, the appropriate cache
7
+ * implementation is created (disabled, noop for dev, or real).
8
+ *
9
+ * Returns synchronously when cache is not configured or in dev mode.
10
+ */
11
+ export declare function provideCache(state: FetchState): Promise<void> | void;
12
+ /**
13
+ * Wraps a render callback with cache provider logic. Handles both
14
+ * runtime caching (onRequest) and CDN-based providers (headers only).
15
+ *
16
+ * - When a cache provider with `onRequest` is configured, the callback
17
+ * is wrapped so the provider can serve from cache or fall through.
18
+ * - When only CDN headers are needed, the callback runs directly and
19
+ * cache headers are applied to the response.
20
+ * - When no cache provider is configured, the callback runs as-is.
21
+ *
22
+ * Cache headers (`CDN-Cache-Control`, `Cache-Tag`) are stripped from
23
+ * the final response after the runtime provider has read them.
24
+ */
25
+ export declare class CacheHandler {
26
+ #private;
27
+ constructor(app: BaseApp<Pipeline>);
28
+ handle(state: FetchState, next: () => Promise<Response>): Promise<Response>;
29
+ }
@@ -0,0 +1,81 @@
1
+ import { PipelineFeatures } from "../base-pipeline.js";
2
+ import { AstroCache, applyCacheHeaders } from "./runtime/cache.js";
3
+ import { NoopAstroCache, DisabledAstroCache } from "./runtime/noop.js";
4
+ import { compileCacheRoutes, matchCacheRoute } from "./runtime/route-matching.js";
5
+ const CACHE_KEY = "cache";
6
+ function provideCache(state) {
7
+ const pipeline = state.pipeline;
8
+ if (!pipeline.cacheConfig) {
9
+ state.provide(CACHE_KEY, {
10
+ create: () => new DisabledAstroCache(pipeline.logger)
11
+ });
12
+ return;
13
+ }
14
+ if (pipeline.runtimeMode === "development") {
15
+ state.provide(CACHE_KEY, {
16
+ create: () => new NoopAstroCache()
17
+ });
18
+ return;
19
+ }
20
+ return provideCacheAsync(state, pipeline);
21
+ }
22
+ async function provideCacheAsync(state, pipeline) {
23
+ const cacheProvider = await pipeline.getCacheProvider();
24
+ state.provide(CACHE_KEY, {
25
+ create() {
26
+ const cache = new AstroCache(cacheProvider);
27
+ if (pipeline.cacheConfig?.routes) {
28
+ if (!pipeline.compiledCacheRoutes) {
29
+ pipeline.compiledCacheRoutes = compileCacheRoutes(
30
+ pipeline.cacheConfig.routes,
31
+ pipeline.manifest.base,
32
+ pipeline.manifest.trailingSlash
33
+ );
34
+ }
35
+ const matched = matchCacheRoute(state.pathname, pipeline.compiledCacheRoutes);
36
+ if (matched) {
37
+ cache.set(matched);
38
+ }
39
+ }
40
+ return cache;
41
+ }
42
+ });
43
+ }
44
+ class CacheHandler {
45
+ #app;
46
+ constructor(app) {
47
+ this.#app = app;
48
+ }
49
+ async handle(state, next) {
50
+ this.#app.pipeline.usedFeatures |= PipelineFeatures.cache;
51
+ if (!this.#app.pipeline.cacheProvider) {
52
+ return next();
53
+ }
54
+ const cache = state.resolve(CACHE_KEY);
55
+ const cacheProvider = await this.#app.pipeline.getCacheProvider();
56
+ if (cacheProvider?.onRequest) {
57
+ const response2 = await cacheProvider.onRequest(
58
+ {
59
+ request: state.request,
60
+ url: new URL(state.request.url),
61
+ waitUntil: state.renderOptions.waitUntil
62
+ },
63
+ async () => {
64
+ const res = await next();
65
+ applyCacheHeaders(cache, res);
66
+ return res;
67
+ }
68
+ );
69
+ response2.headers.delete("CDN-Cache-Control");
70
+ response2.headers.delete("Cache-Tag");
71
+ return response2;
72
+ }
73
+ const response = await next();
74
+ applyCacheHeaders(cache, response);
75
+ return response;
76
+ }
77
+ }
78
+ export {
79
+ CacheHandler,
80
+ provideCache
81
+ };
@@ -43,6 +43,7 @@ export declare const ASTRO_CONFIG_DEFAULTS: {
43
43
  entrypoint: "astro/assets/services/sharp";
44
44
  config: {};
45
45
  };
46
+ dangerouslyProcessSVG: false;
46
47
  responsiveStyles: false;
47
48
  };
48
49
  devToolbar: {
@@ -75,6 +76,7 @@ export declare const ASTRO_CONFIG_DEFAULTS: {
75
76
  };
76
77
  prerenderConflictBehavior: "warn";
77
78
  experimental: {
79
+ advancedRouting: false;
78
80
  clientPrerender: false;
79
81
  contentIntellisense: false;
80
82
  chromeDevtoolsWorkspace: false;
@@ -153,6 +155,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
153
155
  entrypoint: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<"astro/assets/services/sharp">, z.ZodString]>>;
154
156
  config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodAny>>;
155
157
  }, z.core.$strip>>;
158
+ dangerouslyProcessSVG: z.ZodDefault<z.ZodBoolean>;
156
159
  domains: z.ZodDefault<z.ZodArray<z.ZodString>>;
157
160
  remotePatterns: z.ZodDefault<z.ZodArray<z.ZodObject<{
158
161
  protocol: z.ZodOptional<z.ZodString>;
@@ -498,6 +501,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
498
501
  options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
499
502
  }, z.core.$strict>>>;
500
503
  experimental: z.ZodPrefault<z.ZodObject<{
504
+ advancedRouting: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
501
505
  clientPrerender: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
502
506
  contentIntellisense: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
503
507
  chromeDevtoolsWorkspace: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -28,6 +28,7 @@ const ASTRO_CONFIG_DEFAULTS = {
28
28
  image: {
29
29
  endpoint: { entrypoint: void 0, route: "/_image" },
30
30
  service: { entrypoint: "astro/assets/services/sharp", config: {} },
31
+ dangerouslyProcessSVG: false,
31
32
  responsiveStyles: false
32
33
  },
33
34
  devToolbar: {
@@ -60,6 +61,7 @@ const ASTRO_CONFIG_DEFAULTS = {
60
61
  },
61
62
  prerenderConflictBehavior: "warn",
62
63
  experimental: {
64
+ advancedRouting: false,
63
65
  clientPrerender: false,
64
66
  contentIntellisense: false,
65
67
  chromeDevtoolsWorkspace: false,
@@ -171,6 +173,7 @@ const AstroConfigSchema = z.object({
171
173
  entrypoint: z.union([z.literal("astro/assets/services/sharp"), z.string()]).default(ASTRO_CONFIG_DEFAULTS.image.service.entrypoint),
172
174
  config: z.record(z.string(), z.any()).default({})
173
175
  }).default(ASTRO_CONFIG_DEFAULTS.image.service),
176
+ dangerouslyProcessSVG: z.boolean().default(ASTRO_CONFIG_DEFAULTS.image.dangerouslyProcessSVG),
174
177
  domains: z.array(z.string()).default([]),
175
178
  remotePatterns: z.array(
176
179
  z.object({
@@ -307,6 +310,7 @@ const AstroConfigSchema = z.object({
307
310
  prerenderConflictBehavior: z.enum(["error", "warn", "ignore"]).optional().default(ASTRO_CONFIG_DEFAULTS.prerenderConflictBehavior),
308
311
  fonts: z.array(FontFamilySchema).optional(),
309
312
  experimental: z.strictObject({
313
+ advancedRouting: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.advancedRouting),
310
314
  clientPrerender: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.clientPrerender),
311
315
  contentIntellisense: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.contentIntellisense),
312
316
  chromeDevtoolsWorkspace: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.chromeDevtoolsWorkspace),
@@ -36,6 +36,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
36
36
  entrypoint: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<"astro/assets/services/sharp">, z.ZodString]>>;
37
37
  config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodAny>>;
38
38
  }, z.core.$strip>>;
39
+ dangerouslyProcessSVG: z.ZodDefault<z.ZodBoolean>;
39
40
  domains: z.ZodDefault<z.ZodArray<z.ZodString>>;
40
41
  remotePatterns: z.ZodDefault<z.ZodArray<z.ZodObject<{
41
42
  protocol: z.ZodOptional<z.ZodString>;
@@ -381,6 +382,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
381
382
  options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
382
383
  }, z.core.$strict>>>;
383
384
  experimental: z.ZodPrefault<z.ZodObject<{
385
+ advancedRouting: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
384
386
  clientPrerender: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
385
387
  contentIntellisense: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
386
388
  chromeDevtoolsWorkspace: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -468,6 +470,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
468
470
  entrypoint: string;
469
471
  config: Record<string, any>;
470
472
  };
473
+ dangerouslyProcessSVG: boolean;
471
474
  domains: string[];
472
475
  remotePatterns: {
473
476
  protocol?: string | undefined;
@@ -573,6 +576,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
573
576
  };
574
577
  prerenderConflictBehavior: "error" | "ignore" | "warn";
575
578
  experimental: {
579
+ advancedRouting: boolean;
576
580
  clientPrerender: boolean;
577
581
  contentIntellisense: boolean;
578
582
  chromeDevtoolsWorkspace: boolean;
@@ -716,6 +720,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
716
720
  entrypoint: string;
717
721
  config: Record<string, any>;
718
722
  };
723
+ dangerouslyProcessSVG: boolean;
719
724
  domains: string[];
720
725
  remotePatterns: {
721
726
  protocol?: string | undefined;
@@ -821,6 +826,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
821
826
  };
822
827
  prerenderConflictBehavior: "error" | "ignore" | "warn";
823
828
  experimental: {
829
+ advancedRouting: boolean;
824
830
  clientPrerender: boolean;
825
831
  contentIntellisense: boolean;
826
832
  chromeDevtoolsWorkspace: boolean;