astro 7.0.0-alpha.0 → 7.0.0-alpha.2

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 (251) hide show
  1. package/components/Code.astro +1 -1
  2. package/dist/actions/handler.d.ts +32 -0
  3. package/dist/actions/handler.js +45 -0
  4. package/dist/actions/runtime/server.js +1 -1
  5. package/dist/assets/build/generate.js +1 -1
  6. package/dist/assets/build/remote.d.ts +3 -2
  7. package/dist/assets/build/remote.js +16 -9
  8. package/dist/assets/endpoint/dev.js +1 -1
  9. package/dist/assets/endpoint/generic.js +8 -20
  10. package/dist/assets/endpoint/loadImage.d.ts +11 -0
  11. package/dist/assets/endpoint/loadImage.js +19 -0
  12. package/dist/assets/endpoint/shared.js +7 -2
  13. package/dist/assets/fonts/config.d.ts +4 -4
  14. package/dist/assets/fonts/core/optimize-fallbacks.js +38 -13
  15. package/dist/assets/fonts/definitions.d.ts +2 -2
  16. package/dist/assets/fonts/infra/system-fallbacks-provider.d.ts +2 -2
  17. package/dist/assets/fonts/infra/system-fallbacks-provider.js +46 -9
  18. package/dist/assets/fonts/types.d.ts +1 -0
  19. package/dist/assets/index.d.ts +1 -0
  20. package/dist/assets/index.js +2 -0
  21. package/dist/assets/internal.js +22 -3
  22. package/dist/assets/services/service.d.ts +1 -1
  23. package/dist/assets/services/service.js +9 -9
  24. package/dist/assets/services/sharp.js +53 -18
  25. package/dist/assets/utils/generateImageStylesCSS.js +26 -6
  26. package/dist/assets/utils/index.d.ts +1 -0
  27. package/dist/assets/utils/index.js +2 -0
  28. package/dist/assets/utils/inferSourceFormat.d.ts +8 -3
  29. package/dist/assets/utils/inferSourceFormat.js +15 -4
  30. package/dist/assets/utils/metadata.js +1 -1
  31. package/dist/assets/utils/redirectValidation.d.ts +48 -0
  32. package/dist/assets/utils/redirectValidation.js +48 -0
  33. package/dist/assets/utils/remoteProbe.js +25 -2
  34. package/dist/assets/utils/vendor/image-size/types/svg.js +1 -1
  35. package/dist/cli/add/index.js +7 -58
  36. package/dist/cli/dev/background.d.ts +16 -0
  37. package/dist/cli/dev/background.js +116 -0
  38. package/dist/cli/dev/index.js +82 -3
  39. package/dist/cli/dev/logs.d.ts +6 -0
  40. package/dist/cli/dev/logs.js +72 -0
  41. package/dist/cli/dev/status.d.ts +15 -0
  42. package/dist/cli/dev/status.js +27 -0
  43. package/dist/cli/dev/stop.d.ts +12 -0
  44. package/dist/cli/dev/stop.js +43 -0
  45. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  46. package/dist/container/index.js +18 -14
  47. package/dist/content/content-layer.js +16 -11
  48. package/dist/content/data-store.d.ts +1 -1
  49. package/dist/content/loaders/types.d.ts +1 -1
  50. package/dist/content/runtime-assets.d.ts +2 -2
  51. package/dist/content/runtime.d.ts +1 -1
  52. package/dist/content/runtime.js +9 -4
  53. package/dist/content/server-listeners.js +0 -4
  54. package/dist/content/types-generator.js +5 -1
  55. package/dist/content/utils.d.ts +1 -1
  56. package/dist/content/utils.js +1 -1
  57. package/dist/content/vite-plugin-content-assets.js +1 -0
  58. package/dist/content/vite-plugin-content-virtual-mod.js +9 -1
  59. package/dist/core/app/base.d.ts +42 -15
  60. package/dist/core/app/base.js +151 -375
  61. package/dist/core/app/dev/app.d.ts +3 -2
  62. package/dist/core/app/dev/app.js +4 -60
  63. package/dist/core/app/entrypoints/node.d.ts +1 -1
  64. package/dist/core/app/entrypoints/node.js +2 -0
  65. package/dist/core/app/entrypoints/virtual/dev.js +2 -0
  66. package/dist/core/app/entrypoints/virtual/prod.js +4 -1
  67. package/dist/core/app/node.d.ts +16 -0
  68. package/dist/core/app/node.js +59 -13
  69. package/dist/core/app/prepare-response.d.ts +11 -0
  70. package/dist/core/app/prepare-response.js +18 -0
  71. package/dist/core/app/render-options.d.ts +11 -0
  72. package/dist/core/app/render-options.js +11 -0
  73. package/dist/core/base-pipeline.d.ts +48 -1
  74. package/dist/core/base-pipeline.js +63 -8
  75. package/dist/core/build/app.d.ts +3 -4
  76. package/dist/core/build/app.js +3 -17
  77. package/dist/core/build/generate.js +8 -1
  78. package/dist/core/build/index.d.ts +0 -11
  79. package/dist/core/build/index.js +0 -3
  80. package/dist/core/build/internal.d.ts +7 -0
  81. package/dist/core/build/plugins/plugin-chunk-imports.d.ts +6 -0
  82. package/dist/core/build/plugins/plugin-chunk-imports.js +29 -17
  83. package/dist/core/build/plugins/plugin-css.js +40 -1
  84. package/dist/core/build/plugins/plugin-internals.js +1 -1
  85. package/dist/core/build/plugins/plugin-manifest.js +11 -1
  86. package/dist/core/build/static-build.js +22 -141
  87. package/dist/core/build/types.d.ts +0 -1
  88. package/dist/core/build/util.js +8 -1
  89. package/dist/core/build/vite-build-config.d.ts +28 -0
  90. package/dist/core/build/vite-build-config.js +165 -0
  91. package/dist/core/cache/handler.d.ts +29 -0
  92. package/dist/core/cache/handler.js +81 -0
  93. package/dist/core/compile/style.js +18 -1
  94. package/dist/core/config/index.d.ts +1 -1
  95. package/dist/core/config/index.js +4 -1
  96. package/dist/core/config/merge.js +4 -0
  97. package/dist/core/config/schemas/base.d.ts +25 -13
  98. package/dist/core/config/schemas/base.js +39 -10
  99. package/dist/core/config/schemas/relative.d.ts +76 -49
  100. package/dist/core/config/schemas/relative.js +2 -3
  101. package/dist/core/config/settings.js +2 -4
  102. package/dist/core/config/tsconfig.d.ts +24 -9
  103. package/dist/core/config/tsconfig.js +54 -45
  104. package/dist/core/config/validate.js +59 -0
  105. package/dist/core/constants.d.ts +27 -1
  106. package/dist/core/constants.js +14 -1
  107. package/dist/core/cookies/cookies.d.ts +7 -2
  108. package/dist/core/cookies/cookies.js +11 -4
  109. package/dist/core/cookies/response.d.ts +1 -1
  110. package/dist/core/cookies/response.js +1 -2
  111. package/dist/core/create-vite.js +18 -1
  112. package/dist/core/csp/config.js +17 -5
  113. package/dist/core/csp/runtime.js +6 -4
  114. package/dist/core/dev/dev.d.ts +1 -0
  115. package/dist/core/dev/dev.js +4 -13
  116. package/dist/core/dev/lockfile.d.ts +54 -0
  117. package/dist/core/dev/lockfile.js +93 -0
  118. package/dist/core/errors/build-handler.d.ts +17 -0
  119. package/dist/core/errors/build-handler.js +22 -0
  120. package/dist/core/errors/default-handler.d.ts +14 -0
  121. package/dist/core/errors/default-handler.js +144 -0
  122. package/dist/core/errors/dev-handler.d.ts +21 -0
  123. package/dist/core/errors/dev-handler.js +82 -0
  124. package/dist/core/errors/errors-data.d.ts +43 -38
  125. package/dist/core/errors/errors-data.js +79 -73
  126. package/dist/core/errors/handler.d.ts +9 -0
  127. package/dist/core/errors/handler.js +0 -0
  128. package/dist/core/errors/zod-error-map.js +30 -1
  129. package/dist/core/fetch/default-handler.d.ts +17 -0
  130. package/dist/core/fetch/default-handler.js +45 -0
  131. package/dist/core/fetch/fetch-state.d.ts +230 -0
  132. package/dist/core/fetch/fetch-state.js +896 -0
  133. package/dist/core/fetch/index.d.ts +61 -0
  134. package/dist/core/fetch/index.js +121 -0
  135. package/dist/core/fetch/types.d.ts +25 -0
  136. package/dist/core/fetch/types.js +0 -0
  137. package/dist/core/fetch/vite-plugin.d.ts +5 -0
  138. package/dist/core/fetch/vite-plugin.js +76 -0
  139. package/dist/core/hono/index.d.ts +21 -0
  140. package/dist/core/hono/index.js +101 -0
  141. package/dist/core/i18n/domain.d.ts +12 -0
  142. package/dist/core/i18n/domain.js +66 -0
  143. package/dist/core/i18n/handler.d.ts +18 -0
  144. package/dist/core/i18n/handler.js +122 -0
  145. package/dist/core/logger/core.d.ts +9 -1
  146. package/dist/core/logger/core.js +17 -1
  147. package/dist/core/messages/runtime.d.ts +0 -3
  148. package/dist/core/messages/runtime.js +1 -9
  149. package/dist/core/middleware/astro-middleware.d.ts +27 -0
  150. package/dist/core/middleware/astro-middleware.js +51 -0
  151. package/dist/core/module-loader/vite.js +1 -2
  152. package/dist/core/pages/handler.d.ts +20 -0
  153. package/dist/core/pages/handler.js +75 -0
  154. package/dist/core/preview/index.js +6 -5
  155. package/dist/core/preview/static-preview-server.js +5 -2
  156. package/dist/core/redirects/render.d.ts +2 -2
  157. package/dist/core/redirects/render.js +7 -8
  158. package/dist/core/render/params-and-props.js +2 -2
  159. package/dist/core/render/route-cache.d.ts +1 -0
  160. package/dist/core/render/route-cache.js +4 -4
  161. package/dist/core/render/slots.js +9 -2
  162. package/dist/core/rewrites/handler.d.ts +37 -0
  163. package/dist/core/rewrites/handler.js +67 -0
  164. package/dist/core/routing/3xx.js +8 -4
  165. package/dist/core/routing/create-manifest.js +11 -1
  166. package/dist/core/routing/handler.d.ts +17 -0
  167. package/dist/core/routing/handler.js +171 -0
  168. package/dist/core/routing/match.d.ts +0 -7
  169. package/dist/core/routing/match.js +0 -5
  170. package/dist/core/routing/parse-route.js +1 -1
  171. package/dist/core/routing/pattern.js +1 -1
  172. package/dist/core/routing/rewrite.js +2 -5
  173. package/dist/core/routing/router.d.ts +8 -0
  174. package/dist/core/routing/router.js +28 -0
  175. package/dist/core/routing/trailing-slash-handler.d.ts +18 -0
  176. package/dist/core/routing/trailing-slash-handler.js +67 -0
  177. package/dist/core/routing/validation.js +1 -1
  178. package/dist/core/server-islands/vite-plugin-server-islands.d.ts +6 -1
  179. package/dist/core/server-islands/vite-plugin-server-islands.js +13 -3
  180. package/dist/core/session/config.d.ts +1 -1
  181. package/dist/core/session/drivers.d.ts +1 -1
  182. package/dist/core/session/handler.d.ts +11 -0
  183. package/dist/core/session/handler.js +33 -0
  184. package/dist/core/session/runtime.js +7 -2
  185. package/dist/core/util/normalized-url.d.ts +10 -0
  186. package/dist/core/util/normalized-url.js +24 -0
  187. package/dist/core/util/pathname.d.ts +10 -1
  188. package/dist/core/util/pathname.js +13 -4
  189. package/dist/environments.js +1 -1
  190. package/dist/events/session.d.ts +8 -0
  191. package/dist/events/session.js +11 -0
  192. package/dist/i18n/middleware.d.ts +10 -0
  193. package/dist/i18n/middleware.js +4 -88
  194. package/dist/i18n/utils.js +2 -2
  195. package/dist/jsx/rehype.d.ts +1 -1
  196. package/dist/manifest/virtual-module.js +3 -1
  197. package/dist/markdown/index.d.ts +4 -0
  198. package/dist/markdown/index.js +14 -0
  199. package/dist/prefetch/index.js +12 -7
  200. package/dist/prerender/utils.js +5 -1
  201. package/dist/runtime/client/dev-toolbar/apps/audit/rules/a11y.js +9 -0
  202. package/dist/runtime/server/astro-island.js +57 -20
  203. package/dist/runtime/server/astro-island.prebuilt-dev.d.ts +1 -1
  204. package/dist/runtime/server/astro-island.prebuilt-dev.js +1 -1
  205. package/dist/runtime/server/astro-island.prebuilt.d.ts +1 -1
  206. package/dist/runtime/server/astro-island.prebuilt.js +1 -1
  207. package/dist/runtime/server/jsx.js +1 -1
  208. package/dist/runtime/server/render/common.js +10 -4
  209. package/dist/runtime/server/render/component.js +8 -6
  210. package/dist/runtime/server/render/head.js +1 -5
  211. package/dist/runtime/server/render/server-islands.js +2 -1
  212. package/dist/runtime/server/render/util.js +2 -2
  213. package/dist/runtime/server/scripts.js +6 -0
  214. package/dist/runtime/server/transition.d.ts +1 -6
  215. package/dist/runtime/server/transition.js +0 -8
  216. package/dist/transitions/events.d.ts +0 -14
  217. package/dist/transitions/events.js +0 -14
  218. package/dist/transitions/index.d.ts +0 -1
  219. package/dist/transitions/index.js +0 -2
  220. package/dist/transitions/vite-plugin-transitions.js +2 -4
  221. package/dist/types/public/config.d.ts +96 -14
  222. package/dist/types/public/content.d.ts +5 -5
  223. package/dist/types/public/index.d.ts +2 -1
  224. package/dist/types/public/integrations.d.ts +11 -3
  225. package/dist/types/public/internal.d.ts +1 -1
  226. package/dist/types/public/manifest.d.ts +1 -1
  227. package/dist/virtual-modules/i18n.d.ts +2 -2
  228. package/dist/virtual-modules/i18n.js +1 -1
  229. package/dist/vite-plugin-app/app.d.ts +13 -6
  230. package/dist/vite-plugin-app/app.js +51 -89
  231. package/dist/vite-plugin-app/createAstroServerApp.d.ts +3 -1
  232. package/dist/vite-plugin-app/createAstroServerApp.js +4 -3
  233. package/dist/vite-plugin-astro-server/plugin.js +11 -5
  234. package/dist/vite-plugin-astro-server/route-guard.d.ts +33 -0
  235. package/dist/vite-plugin-astro-server/route-guard.js +42 -23
  236. package/dist/vite-plugin-dev-status/index.d.ts +2 -0
  237. package/dist/vite-plugin-dev-status/index.js +15 -0
  238. package/dist/vite-plugin-head/index.js +36 -19
  239. package/dist/vite-plugin-hmr-reload/index.d.ts +1 -1
  240. package/dist/vite-plugin-hmr-reload/index.js +23 -1
  241. package/dist/vite-plugin-integrations-container/index.js +15 -6
  242. package/dist/vite-plugin-markdown/content-entry-type.js +7 -4
  243. package/dist/vite-plugin-markdown/images.js +9 -11
  244. package/dist/vite-plugin-markdown/index.js +12 -11
  245. package/dist/vite-plugin-utils/index.d.ts +1 -0
  246. package/dist/vite-plugin-utils/index.js +10 -1
  247. package/package.json +23 -16
  248. package/templates/content/types.d.ts +1 -0
  249. package/types/transitions.d.ts +0 -7
  250. package/dist/core/render-context.d.ts +0 -77
  251. package/dist/core/render-context.js +0 -826
@@ -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 +1 @@
1
- export { NodeApp, loadApp, loadManifest, createRequest, writeResponse, getAbortControllerCleanup, } from '../node.js';
1
+ export { NodeApp, loadApp, loadManifest, createRequest, createRequestFromNodeRequest, writeResponse, getAbortControllerCleanup, } from '../node.js';
@@ -3,12 +3,14 @@ import {
3
3
  loadApp,
4
4
  loadManifest,
5
5
  createRequest,
6
+ createRequestFromNodeRequest,
6
7
  writeResponse,
7
8
  getAbortControllerCleanup
8
9
  } from "../node.js";
9
10
  export {
10
11
  NodeApp,
11
12
  createRequest,
13
+ createRequestFromNodeRequest,
12
14
  getAbortControllerCleanup,
13
15
  loadApp,
14
16
  loadManifest,
@@ -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
@@ -25,6 +25,22 @@ interface NodeRequest extends IncomingMessage {
25
25
  * })
26
26
  * ```
27
27
  */
28
+ /**
29
+ * Internal version of `createRequest` that skips X-Forwarded-* header
30
+ * validation. Forwarded headers are resolved later inside `FetchState`,
31
+ * so doing it here too would duplicate work on every request.
32
+ *
33
+ * Use this for all internal call sites that go through `app.render()`
34
+ * (which creates a `FetchState`). The public `createRequest` keeps the
35
+ * forwarded header logic for external adapters that may not use
36
+ * `FetchState`.
37
+ */
38
+ export declare function createRequestFromNodeRequest(req: NodeRequest, { skipBody, allowedDomains, bodySizeLimit, port: serverPort, }?: {
39
+ skipBody?: boolean;
40
+ allowedDomains?: Partial<RemotePattern>[];
41
+ bodySizeLimit?: number;
42
+ port?: number;
43
+ }): Request;
28
44
  export declare function createRequest(req: NodeRequest, { skipBody, allowedDomains, bodySizeLimit, port: serverPort, }?: {
29
45
  skipBody?: boolean;
30
46
  allowedDomains?: Partial<RemotePattern>[];
@@ -9,6 +9,48 @@ import {
9
9
  validateForwardedHeaders,
10
10
  validateHost
11
11
  } from "./validate-headers.js";
12
+ function createRequestFromNodeRequest(req, {
13
+ skipBody = false,
14
+ allowedDomains = [],
15
+ bodySizeLimit,
16
+ port: serverPort
17
+ } = {}) {
18
+ const controller = new AbortController();
19
+ const isEncrypted = "encrypted" in req.socket && req.socket.encrypted;
20
+ const protocol = isEncrypted ? "https" : "http";
21
+ const hostname = typeof req.headers.host === "string" ? req.headers.host : typeof req.headers[":authority"] === "string" ? req.headers[":authority"] : serverPort ? `localhost:${serverPort}` : "localhost";
22
+ let url;
23
+ try {
24
+ url = new URL(`${protocol}://${hostname}${req.url}`);
25
+ } catch {
26
+ url = new URL(`${protocol}://${hostname}`);
27
+ }
28
+ const options = {
29
+ method: req.method || "GET",
30
+ headers: makeRequestHeaders(req),
31
+ signal: controller.signal
32
+ };
33
+ const bodyAllowed = options.method !== "HEAD" && options.method !== "GET" && skipBody === false;
34
+ if (bodyAllowed) {
35
+ Object.assign(options, makeRequestBody(req, bodySizeLimit));
36
+ }
37
+ const request = new Request(url, options);
38
+ wireAbortController(req, controller);
39
+ const untrustedHostname = req.headers.host ?? req.headers[":authority"];
40
+ const validatedHostname = validateHost(
41
+ typeof untrustedHostname === "string" ? untrustedHostname : void 0,
42
+ protocol,
43
+ allowedDomains
44
+ );
45
+ const forwardedHost = getFirstForwardedValue(req.headers["x-forwarded-host"]);
46
+ const hostValidated = validatedHostname !== void 0 || forwardedHost !== void 0 && allowedDomains.length > 0;
47
+ const forwardedClientIp = hostValidated ? getFirstForwardedValue(req.headers["x-forwarded-for"]) : void 0;
48
+ const clientIp = forwardedClientIp || req.socket?.remoteAddress;
49
+ if (clientIp) {
50
+ Reflect.set(request, clientAddressSymbol, clientIp);
51
+ }
52
+ return request;
53
+ }
12
54
  function createRequest(req, {
13
55
  skipBody = false,
14
56
  allowedDomains = [],
@@ -51,6 +93,16 @@ function createRequest(req, {
51
93
  Object.assign(options, makeRequestBody(req, bodySizeLimit));
52
94
  }
53
95
  const request = new Request(url, options);
96
+ wireAbortController(req, controller);
97
+ const hostValidated = validated.host !== void 0 || validatedHostname !== void 0;
98
+ const forwardedClientIp = hostValidated ? getFirstForwardedValue(req.headers["x-forwarded-for"]) : void 0;
99
+ const clientIp = forwardedClientIp || req.socket?.remoteAddress;
100
+ if (clientIp) {
101
+ Reflect.set(request, clientAddressSymbol, clientIp);
102
+ }
103
+ return request;
104
+ }
105
+ function wireAbortController(req, controller) {
54
106
  const socket = getRequestSocket(req);
55
107
  if (socket && typeof socket.on === "function") {
56
108
  const existingCleanup = getAbortControllerCleanup(req);
@@ -85,13 +137,6 @@ function createRequest(req, {
85
137
  onSocketClose();
86
138
  }
87
139
  }
88
- const hostValidated = validated.host !== void 0 || validatedHostname !== void 0;
89
- const forwardedClientIp = hostValidated ? getFirstForwardedValue(req.headers["x-forwarded-for"]) : void 0;
90
- const clientIp = forwardedClientIp || req.socket?.remoteAddress;
91
- if (clientIp) {
92
- Reflect.set(request, clientAddressSymbol, clientIp);
93
- }
94
- return request;
95
140
  }
96
141
  async function writeResponse(source, destination) {
97
142
  const { status, headers, body, statusText } = source;
@@ -147,18 +192,15 @@ class NodeApp extends App {
147
192
  }
148
193
  match(req, allowPrerenderedRoutes = false) {
149
194
  if (!(req instanceof Request)) {
150
- req = createRequest(req, {
151
- skipBody: true,
152
- allowedDomains: this.manifest.allowedDomains
195
+ req = createRequestFromNodeRequest(req, {
196
+ skipBody: true
153
197
  });
154
198
  }
155
199
  return super.match(req, allowPrerenderedRoutes);
156
200
  }
157
201
  render(request, options) {
158
202
  if (!(request instanceof Request)) {
159
- request = createRequest(request, {
160
- allowedDomains: this.manifest.allowedDomains
161
- });
203
+ request = createRequestFromNodeRequest(request);
162
204
  }
163
205
  return super.render(request, options);
164
206
  }
@@ -219,6 +261,9 @@ function makeRequestBody(req, bodySizeLimit) {
219
261
  if (typeof req.body === "string" && req.body.length > 0) {
220
262
  return { body: Buffer.from(req.body) };
221
263
  }
264
+ if (req.body instanceof ArrayBuffer || ArrayBuffer.isView(req.body)) {
265
+ return { body: req.body };
266
+ }
222
267
  if (typeof req.body === "object" && req.body !== null && Object.keys(req.body).length > 0) {
223
268
  return { body: Buffer.from(JSON.stringify(req.body)) };
224
269
  }
@@ -280,6 +325,7 @@ async function loadApp(rootFolder) {
280
325
  export {
281
326
  NodeApp,
282
327
  createRequest,
328
+ createRequestFromNodeRequest,
283
329
  getAbortControllerCleanup,
284
330
  loadApp,
285
331
  loadManifest,
@@ -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,32 @@ 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
+ };
32
+ /** All feature bits ORed together. Keep next to `PipelineFeatures` so
33
+ * new flags are hard to forget. */
34
+ export declare const ALL_PIPELINE_FEATURES: number;
17
35
  /**
18
36
  * The `Pipeline` represents the static parts of rendering that do not change between requests.
19
37
  * These are mostly known when the server first starts up and do not change.
20
38
  *
21
- * Thus, a `Pipeline` is created once at process start and then used by every `RenderContext`.
39
+ * Thus, a `Pipeline` is created once at process start and then used by every `FetchState`.
22
40
  */
23
41
  export declare abstract class Pipeline {
42
+ #private;
24
43
  readonly internalMiddleware: MiddlewareHandler[];
25
44
  resolvedMiddleware: MiddlewareHandler | undefined;
26
45
  resolvedLogger: boolean;
@@ -30,6 +49,12 @@ export declare abstract class Pipeline {
30
49
  compiledCacheRoutes: CompiledCacheRoute[] | undefined;
31
50
  nodePool: NodePool | undefined;
32
51
  htmlStringCache: HTMLStringCache | undefined;
52
+ /**
53
+ * Bit mask of pipeline features activated by handler classes.
54
+ * Each handler sets its bit via `|=`. Only meaningful when a
55
+ * custom `src/app.ts` fetch handler is in use.
56
+ */
57
+ usedFeatures: number;
33
58
  logger: AstroLogger;
34
59
  readonly manifest: SSRManifest;
35
60
  /**
@@ -63,6 +88,10 @@ export declare abstract class Pipeline {
63
88
  readonly cacheProvider: SSRManifest['cacheProvider'];
64
89
  readonly cacheConfig: SSRManifest['cacheConfig'];
65
90
  readonly serverIslands: SSRManifest['serverIslandMappings'];
91
+ /** Route data derived from the manifest, used for route matching. */
92
+ manifestData: {
93
+ routes: RouteData[];
94
+ };
66
95
  constructor(logger: AstroLogger, manifest: SSRManifest,
67
96
  /**
68
97
  * "development" or "production" only
@@ -85,6 +114,24 @@ export declare abstract class Pipeline {
85
114
  }>) | undefined, cacheProvider?: (() => Promise<{
86
115
  default: CacheProviderFactory | null;
87
116
  }>) | undefined, cacheConfig?: import("./cache/types.js").SSRManifestCache | undefined, serverIslands?: (() => Promise<ServerIslandMappings> | ServerIslandMappings) | undefined);
117
+ /**
118
+ * Low-level route matching against the manifest routes. Returns the
119
+ * matched `RouteData` or `undefined`. Does not filter prerendered
120
+ * routes or check public assets — use `BaseApp.match()` for that.
121
+ */
122
+ matchRoute(pathname: string): RouteData | undefined;
123
+ /**
124
+ * Returns all routes matching the given pathname, in priority order.
125
+ * Used when the first match cannot serve the request (e.g. a
126
+ * prerendered dynamic route that doesn't cover this specific path)
127
+ * and the caller needs to try subsequent matches.
128
+ */
129
+ matchAllRoutes(pathname: string): RouteData[];
130
+ /**
131
+ * Rebuilds the internal router after routes have been added or
132
+ * removed (e.g. by the dev server on HMR).
133
+ */
134
+ rebuildRouter(): void;
88
135
  abstract headElements(routeData: RouteData): Promise<HeadElements> | HeadElements;
89
136
  abstract componentMetadata(routeData: RouteData): Promise<SSRResult['componentMetadata']> | void;
90
137
  /**
@@ -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,21 @@ 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
+ };
24
+ const ALL_PIPELINE_FEATURES = PipelineFeatures.redirects | PipelineFeatures.sessions | PipelineFeatures.actions | PipelineFeatures.middleware | PipelineFeatures.i18n | PipelineFeatures.cache;
15
25
  class Pipeline {
16
26
  internalMiddleware;
17
27
  resolvedMiddleware = void 0;
@@ -22,6 +32,12 @@ class Pipeline {
22
32
  compiledCacheRoutes = void 0;
23
33
  nodePool;
24
34
  htmlStringCache;
35
+ /**
36
+ * Bit mask of pipeline features activated by handler classes.
37
+ * Each handler sets its bit via `|=`. Only meaningful when a
38
+ * custom `src/app.ts` fetch handler is in use.
39
+ */
40
+ usedFeatures = 0;
25
41
  logger;
26
42
  manifest;
27
43
  /**
@@ -55,6 +71,10 @@ class Pipeline {
55
71
  cacheProvider;
56
72
  cacheConfig;
57
73
  serverIslands;
74
+ /** Route data derived from the manifest, used for route matching. */
75
+ manifestData;
76
+ /** Pattern-matching router built from manifestData. */
77
+ #router;
58
78
  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
79
  this.logger = logger;
60
80
  this.manifest = manifest;
@@ -76,12 +96,14 @@ class Pipeline {
76
96
  this.cacheProvider = cacheProvider;
77
97
  this.cacheConfig = cacheConfig;
78
98
  this.serverIslands = serverIslands;
99
+ this.manifestData = { routes: (manifest.routes ?? []).map((route) => route.routeData) };
100
+ ensure404Route(this.manifestData);
101
+ this.#router = new Router(this.manifestData.routes, {
102
+ base: manifest.base,
103
+ trailingSlash: manifest.trailingSlash,
104
+ buildFormat: manifest.buildFormat
105
+ });
79
106
  this.internalMiddleware = [];
80
- if (i18n?.strategy !== "manual") {
81
- this.internalMiddleware.push(
82
- createI18nMiddleware(i18n, manifest.base, manifest.trailingSlash, manifest.buildFormat)
83
- );
84
- }
85
107
  if (manifest.experimentalQueuedRendering.enabled) {
86
108
  this.nodePool = this.createNodePool(
87
109
  manifest.experimentalQueuedRendering.poolSize ?? 1e3,
@@ -92,6 +114,36 @@ class Pipeline {
92
114
  }
93
115
  }
94
116
  }
117
+ /**
118
+ * Low-level route matching against the manifest routes. Returns the
119
+ * matched `RouteData` or `undefined`. Does not filter prerendered
120
+ * routes or check public assets — use `BaseApp.match()` for that.
121
+ */
122
+ matchRoute(pathname) {
123
+ const match = this.#router.match(pathname, { allowWithoutBase: true });
124
+ if (match.type !== "match") return void 0;
125
+ return match.route;
126
+ }
127
+ /**
128
+ * Returns all routes matching the given pathname, in priority order.
129
+ * Used when the first match cannot serve the request (e.g. a
130
+ * prerendered dynamic route that doesn't cover this specific path)
131
+ * and the caller needs to try subsequent matches.
132
+ */
133
+ matchAllRoutes(pathname) {
134
+ return this.#router.matchAll(pathname, { allowWithoutBase: true });
135
+ }
136
+ /**
137
+ * Rebuilds the internal router after routes have been added or
138
+ * removed (e.g. by the dev server on HMR).
139
+ */
140
+ rebuildRouter() {
141
+ this.#router = new Router(this.manifestData.routes, {
142
+ base: this.manifest.base,
143
+ trailingSlash: this.manifest.trailingSlash,
144
+ buildFormat: this.manifest.buildFormat
145
+ });
146
+ }
95
147
  /**
96
148
  * Resolves the middleware from the manifest, and returns the `onRequest` function. If `onRequest` isn't there,
97
149
  * it returns a no-op function
@@ -140,7 +192,8 @@ class Pipeline {
140
192
  if (this.resolvedActions) {
141
193
  return this.resolvedActions;
142
194
  } else if (this.actions) {
143
- return this.actions();
195
+ this.resolvedActions = await this.actions();
196
+ return this.resolvedActions;
144
197
  }
145
198
  return NOOP_ACTIONS_MOD;
146
199
  }
@@ -243,5 +296,7 @@ class Pipeline {
243
296
  }
244
297
  }
245
298
  export {
246
- Pipeline
299
+ ALL_PIPELINE_FEATURES,
300
+ Pipeline,
301
+ PipelineFeatures
247
302
  };
@@ -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) {
@@ -187,13 +187,20 @@ ${colors.bgGreen(colors.black(` ${verb} static routes `))}`);
187
187
  const cpuCount = os.cpus().length;
188
188
  const assetsCreationPipeline = await prepareAssetsGenerationEnv(options, totalCount);
189
189
  const queue = new PQueue({ concurrency: Math.max(cpuCount, 1) });
190
+ const errors = [];
190
191
  const assetsTimer = performance.now();
191
192
  for (const [originalPath, transforms] of staticImageList) {
192
193
  queue.add(() => generateImagesForPath(originalPath, transforms, assetsCreationPipeline)).catch((e) => {
193
- throw e;
194
+ logger.warn("build", `Unable to generate optimized image for ${originalPath}: ${e}`);
195
+ errors.push(new Error(`Error generating image for ${originalPath}: ${e}`, { cause: e }));
194
196
  });
195
197
  }
196
198
  await queue.onIdle();
199
+ if (errors.length === 1) {
200
+ throw errors[0];
201
+ } else if (errors.length > 1) {
202
+ throw new AggregateError(errors, `${errors.length} errors occurred during asset generation`);
203
+ }
197
204
  const assetsTimeEnd = performance.now();
198
205
  logger.info(null, colors.green(`\u2713 Completed in ${getTimeStat(assetsTimer, assetsTimeEnd)}.
199
206
  `));
@@ -9,16 +9,6 @@ interface BuildOptions {
9
9
  * @default false
10
10
  */
11
11
  devOutput?: boolean;
12
- /**
13
- * Teardown the compiler WASM instance after build. This can improve performance when
14
- * building once, but may cause a performance hit if building multiple times in a row.
15
- *
16
- * When building multiple projects in the same execution (e.g. during tests), disabling
17
- * this option can greatly improve performance at the cost of some extra memory usage.
18
- *
19
- * @default true
20
- */
21
- teardownCompiler?: boolean;
22
12
  }
23
13
  /**
24
14
  * Builds your site for deployment. By default, this will generate static files and place them in a dist/ directory.
@@ -50,7 +40,6 @@ export declare class AstroBuilder {
50
40
  private origin;
51
41
  private routesList;
52
42
  private timer;
53
- private teardownCompiler;
54
43
  private sync;
55
44
  constructor(settings: AstroSettings, options: AstroBuilderOptions);
56
45
  /** Setup Vite and run any async setup logic that couldn't run inside of the constructor. */
@@ -55,14 +55,12 @@ class AstroBuilder {
55
55
  origin;
56
56
  routesList;
57
57
  timer;
58
- teardownCompiler;
59
58
  sync;
60
59
  constructor(settings, options) {
61
60
  this.mode = options.mode;
62
61
  this.runtimeMode = options.runtimeMode;
63
62
  this.settings = settings;
64
63
  this.logger = options.logger;
65
- this.teardownCompiler = options.teardownCompiler ?? true;
66
64
  this.sync = options.sync ?? true;
67
65
  this.origin = settings.config.site ? new URL(settings.config.site).origin : `http://localhost:${settings.config.server.port}`;
68
66
  this.routesList = options.routesList ?? { routes: [] };
@@ -151,7 +149,6 @@ class AstroBuilder {
151
149
  runtimeMode: this.runtimeMode,
152
150
  origin: this.origin,
153
151
  pageNames,
154
- teardownCompiler: this.teardownCompiler,
155
152
  viteConfig,
156
153
  key: keyPromise
157
154
  };