astro 7.2.2 → 7.2.3

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 (151) hide show
  1. package/dist/actions/handler.d.ts +6 -12
  2. package/dist/actions/handler.js +30 -40
  3. package/dist/actions/load.d.ts +12 -0
  4. package/dist/actions/load.js +55 -0
  5. package/dist/actions/runtime/entrypoints/server.js +5 -4
  6. package/dist/actions/runtime/server.js +8 -6
  7. package/dist/assets/fonts/providers/index.d.ts +1 -1
  8. package/dist/assets/fonts/providers/index.js +2 -12
  9. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  10. package/dist/container/environment.d.ts +20 -0
  11. package/dist/container/environment.js +106 -0
  12. package/dist/container/index.js +65 -32
  13. package/dist/content/content-layer.js +3 -3
  14. package/dist/content/data-store-writer.d.ts +7 -10
  15. package/dist/content/data-store-writer.js +62 -27
  16. package/dist/content/data-store.d.ts +20 -3
  17. package/dist/content/data-store.js +28 -7
  18. package/dist/content/mutable-data-store.js +15 -10
  19. package/dist/content/runtime.d.ts +3 -2
  20. package/dist/content/runtime.js +43 -26
  21. package/dist/core/app/app.d.ts +0 -2
  22. package/dist/core/app/app.js +0 -7
  23. package/dist/core/app/base.d.ts +32 -20
  24. package/dist/core/app/base.js +76 -66
  25. package/dist/core/app/dev-facade.d.ts +27 -0
  26. package/dist/core/app/dev-facade.js +51 -0
  27. package/dist/core/app/entrypoints/index.d.ts +0 -1
  28. package/dist/core/app/entrypoints/index.js +0 -2
  29. package/dist/core/app/entrypoints/virtual/dev.js +24 -19
  30. package/dist/core/app/node.js +13 -14
  31. package/dist/core/app/prepare-response.d.ts +1 -1
  32. package/dist/core/app/validate-headers.js +7 -3
  33. package/dist/core/build/app.d.ts +31 -6
  34. package/dist/core/build/app.js +31 -13
  35. package/dist/core/build/environment.d.ts +25 -0
  36. package/dist/core/build/environment.js +157 -0
  37. package/dist/core/cache/handler.d.ts +13 -7
  38. package/dist/core/cache/handler.js +55 -51
  39. package/dist/core/cache/provider.d.ts +4 -0
  40. package/dist/core/cache/provider.js +15 -0
  41. package/dist/core/constants.d.ts +0 -11
  42. package/dist/core/constants.js +1 -5
  43. package/dist/core/dev/dev.js +1 -1
  44. package/dist/core/environment/dev-nonrunnable.d.ts +6 -0
  45. package/dist/core/environment/dev-nonrunnable.js +170 -0
  46. package/dist/core/environment/index.d.ts +90 -0
  47. package/dist/core/environment/index.js +12 -0
  48. package/dist/core/environment/production.d.ts +6 -0
  49. package/dist/core/environment/production.js +117 -0
  50. package/dist/core/errors/build-handler.d.ts +5 -10
  51. package/dist/core/errors/build-handler.js +11 -17
  52. package/dist/core/errors/default-handler.d.ts +4 -9
  53. package/dist/core/errors/default-handler.js +92 -107
  54. package/dist/core/errors/dev-handler.d.ts +7 -11
  55. package/dist/core/errors/dev-handler.js +71 -69
  56. package/dist/core/errors/errors-data.d.ts +18 -0
  57. package/dist/core/errors/errors-data.js +7 -0
  58. package/dist/core/errors/handler.d.ts +22 -3
  59. package/dist/core/errors/handler.js +25 -0
  60. package/dist/core/fetch/default-handler.d.ts +15 -8
  61. package/dist/core/fetch/default-handler.js +12 -34
  62. package/dist/core/fetch/features.d.ts +23 -0
  63. package/dist/core/fetch/features.js +27 -0
  64. package/dist/core/fetch/fetch-state.d.ts +52 -7
  65. package/dist/core/fetch/fetch-state.js +92 -81
  66. package/dist/core/fetch/index.d.ts +9 -2
  67. package/dist/core/fetch/index.js +18 -79
  68. package/dist/core/fetch/vite-plugin.js +2 -1
  69. package/dist/core/i18n/handler.d.ts +28 -13
  70. package/dist/core/i18n/handler.js +100 -100
  71. package/dist/core/logger/manifest-logger.d.ts +31 -0
  72. package/dist/core/logger/manifest-logger.js +37 -0
  73. package/dist/core/manifest/ambient-source.d.ts +2 -0
  74. package/dist/core/manifest/ambient-source.js +4 -0
  75. package/dist/core/manifest/ambient.d.ts +16 -0
  76. package/dist/core/manifest/ambient.js +22 -0
  77. package/dist/core/manifest/derived.d.ts +3 -0
  78. package/dist/core/manifest/derived.js +10 -0
  79. package/dist/core/manifest/memo.d.ts +31 -0
  80. package/dist/core/manifest/memo.js +47 -0
  81. package/dist/core/messages/runtime.js +1 -1
  82. package/dist/core/middleware/astro-middleware.d.ts +25 -35
  83. package/dist/core/middleware/astro-middleware.js +61 -81
  84. package/dist/core/middleware/load.d.ts +19 -0
  85. package/dist/core/middleware/load.js +36 -0
  86. package/dist/core/middleware/sequence.js +15 -7
  87. package/dist/core/pages/handler.d.ts +18 -25
  88. package/dist/core/pages/handler.js +68 -84
  89. package/dist/core/redirects/render.js +3 -8
  90. package/dist/core/render/index.d.ts +0 -1
  91. package/dist/core/render/index.js +0 -2
  92. package/dist/core/render/route-cache.d.ts +6 -1
  93. package/dist/core/render/route-cache.js +11 -1
  94. package/dist/core/rewrites/handler.d.ts +4 -6
  95. package/dist/core/rewrites/handler.js +19 -20
  96. package/dist/core/routing/default.d.ts +2 -0
  97. package/dist/core/routing/default.js +7 -1
  98. package/dist/core/routing/dev.d.ts +1 -3
  99. package/dist/core/routing/dev.js +12 -5
  100. package/dist/core/routing/handler.d.ts +6 -16
  101. package/dist/core/routing/handler.js +126 -164
  102. package/dist/core/routing/helpers.d.ts +7 -1
  103. package/dist/core/routing/helpers.js +21 -0
  104. package/dist/core/routing/match-request.d.ts +10 -0
  105. package/dist/core/routing/match-request.js +57 -0
  106. package/dist/core/routing/route-table.d.ts +34 -0
  107. package/dist/core/routing/route-table.js +41 -0
  108. package/dist/core/routing/trailing-slash-handler.d.ts +4 -14
  109. package/dist/core/routing/trailing-slash-handler.js +39 -50
  110. package/dist/core/server-islands/mappings.d.ts +6 -0
  111. package/dist/core/server-islands/mappings.js +12 -0
  112. package/dist/core/session/driver.d.ts +4 -0
  113. package/dist/core/session/driver.js +14 -0
  114. package/dist/core/session/handler.d.ts +1 -1
  115. package/dist/core/session/handler.js +8 -8
  116. package/dist/core/session/provider-disabled.js +2 -2
  117. package/dist/entrypoints/prerender.js +5 -1
  118. package/dist/i18n/middleware.d.ts +4 -4
  119. package/dist/i18n/middleware.js +3 -3
  120. package/dist/manifest/serialized.d.ts +1 -0
  121. package/dist/manifest/serialized.js +9 -2
  122. package/dist/runtime/prerender/static-paths.d.ts +14 -2
  123. package/dist/runtime/prerender/static-paths.js +4 -3
  124. package/dist/types/public/config.d.ts +433 -241
  125. package/dist/vite-plugin-app/createAstroServerApp.js +22 -18
  126. package/dist/vite-plugin-app/environment.d.ts +18 -0
  127. package/dist/vite-plugin-app/environment.js +210 -0
  128. package/dist/vite-plugin-app/handle-request.d.ts +30 -0
  129. package/dist/vite-plugin-app/handle-request.js +129 -0
  130. package/dist/vite-plugin-app/index.d.ts +1 -1
  131. package/dist/vite-plugin-app/index.js +1 -1
  132. package/package.json +14 -7
  133. package/src/core/README.md +37 -0
  134. package/src/core/manifest/ambient-source.ts +9 -0
  135. package/src/types/README.md +5 -0
  136. package/dist/container/pipeline.d.ts +0 -14
  137. package/dist/container/pipeline.js +0 -78
  138. package/dist/core/app/dev/app.d.ts +0 -31
  139. package/dist/core/app/dev/app.js +0 -80
  140. package/dist/core/app/dev/pipeline.d.ts +0 -17
  141. package/dist/core/app/dev/pipeline.js +0 -133
  142. package/dist/core/app/pipeline.d.ts +0 -14
  143. package/dist/core/app/pipeline.js +0 -123
  144. package/dist/core/base-pipeline.d.ts +0 -183
  145. package/dist/core/base-pipeline.js +0 -293
  146. package/dist/core/build/pipeline.d.ts +0 -38
  147. package/dist/core/build/pipeline.js +0 -202
  148. package/dist/vite-plugin-app/app.d.ts +0 -62
  149. package/dist/vite-plugin-app/app.js +0 -237
  150. package/dist/vite-plugin-app/pipeline.d.ts +0 -25
  151. package/dist/vite-plugin-app/pipeline.js +0 -189
@@ -1,16 +1,16 @@
1
1
  import { AstroCookies } from "../cookies/index.js";
2
+ import { getEnvironment } from "../environment/index.js";
2
3
  import { ForbiddenRewrite } from "../errors/errors-data.js";
3
4
  import { AstroError } from "../errors/errors.js";
4
- import { AstroMiddleware } from "../middleware/astro-middleware.js";
5
- import { PagesHandler } from "../pages/handler.js";
6
- import { getParams } from "../render/index.js";
5
+ import { handleMiddleware } from "../middleware/astro-middleware.js";
6
+ import { handlePages } from "../pages/handler.js";
7
+ import { getParams } from "../render/params-and-props.js";
7
8
  import { copyRequest, setOriginPathname } from "../routing/rewrite.js";
8
9
  import { createNormalizedUrl } from "../util/normalized-url.js";
9
10
  function applyRewriteToState(state, payload, { routeData, componentInstance, newUrl, pathname }, { mergeCookies = false } = {}) {
10
- const pipeline = state.pipeline;
11
11
  const oldPathname = state.pathname;
12
12
  const isI18nFallback = routeData.fallbackRoutes && routeData.fallbackRoutes.length > 0;
13
- if (pipeline.manifest.serverLike && !state.routeData.prerender && routeData.prerender && !isI18nFallback) {
13
+ if (state.manifest.serverLike && !state.routeData.prerender && routeData.prerender && !isI18nFallback) {
14
14
  throw new AstroError({
15
15
  ...ForbiddenRewrite,
16
16
  message: ForbiddenRewrite.message(state.pathname, pathname, routeData.component),
@@ -26,7 +26,7 @@ function applyRewriteToState(state, payload, { routeData, componentInstance, new
26
26
  newUrl,
27
27
  state.request,
28
28
  routeData.prerender,
29
- pipeline.logger,
29
+ state.logger,
30
30
  state.routeData.route
31
31
  );
32
32
  }
@@ -45,23 +45,22 @@ function applyRewriteToState(state, payload, { routeData, componentInstance, new
45
45
  setOriginPathname(
46
46
  state.request,
47
47
  oldPathname,
48
- pipeline.manifest.trailingSlash,
49
- pipeline.manifest.buildFormat
48
+ state.manifest.trailingSlash,
49
+ state.manifest.buildFormat
50
50
  );
51
51
  state.invalidateContexts();
52
52
  }
53
- class Rewrites {
54
- async execute(state, payload) {
55
- const pipeline = state.pipeline;
56
- pipeline.logger.debug("router", "Calling rewrite: ", payload);
57
- const result = await pipeline.tryRewrite(payload, state.request);
58
- applyRewriteToState(state, payload, result, { mergeCookies: true });
59
- const middleware = new AstroMiddleware(pipeline);
60
- const pagesHandler = new PagesHandler(pipeline);
61
- return middleware.handle(state, pagesHandler.handle.bind(pagesHandler));
62
- }
53
+ async function executeRewrite(state, payload) {
54
+ state.logger.debug("router", "Calling rewrite: ", payload);
55
+ const result = await getEnvironment(state.manifest).tryRewrite(
56
+ state.manifest,
57
+ payload,
58
+ state.request
59
+ );
60
+ applyRewriteToState(state, payload, result, { mergeCookies: true });
61
+ return handleMiddleware(state, handlePages);
63
62
  }
64
63
  export {
65
- Rewrites,
66
- applyRewriteToState
64
+ applyRewriteToState,
65
+ executeRewrite
67
66
  };
@@ -8,3 +8,5 @@ export interface DefaultRouteParams {
8
8
  }
9
9
  export declare const DEFAULT_COMPONENTS: string[];
10
10
  export declare function createDefaultRoutes(manifest: SSRManifest): DefaultRouteParams[];
11
+ /** The built-in internal routes for a manifest, derived once per manifest. */
12
+ export declare function getDefaultRoutes(manifest: SSRManifest): DefaultRouteParams[];
@@ -1,4 +1,5 @@
1
1
  import { DEFAULT_404_COMPONENT } from "../constants.js";
2
+ import { createManifestMemo } from "../manifest/memo.js";
2
3
  import {
3
4
  createEndpoint as createServerIslandEndpoint,
4
5
  SERVER_ISLAND_COMPONENT,
@@ -23,7 +24,12 @@ function createDefaultRoutes(manifest) {
23
24
  }
24
25
  ];
25
26
  }
27
+ const defaultRoutesMemo = createManifestMemo(createDefaultRoutes);
28
+ function getDefaultRoutes(manifest) {
29
+ return defaultRoutesMemo.get(manifest);
30
+ }
26
31
  export {
27
32
  DEFAULT_COMPONENTS,
28
- createDefaultRoutes
33
+ createDefaultRoutes,
34
+ getDefaultRoutes
29
35
  };
@@ -1,16 +1,14 @@
1
1
  /**
2
2
  * Use this module only to have functions needed in development
3
3
  */
4
- import type { RoutesList } from '../../types/astro.js';
5
4
  import type { SSRManifest } from '../app/types.js';
6
5
  import type { RouteData } from '../../types/public/index.js';
7
- import type { RunnablePipeline } from '../../vite-plugin-app/pipeline.js';
8
6
  interface MatchedRoute {
9
7
  route: RouteData;
10
8
  filePath: URL;
11
9
  resolvedPathname: string;
12
10
  }
13
- export declare function matchRoute(pathname: string, routesList: RoutesList, pipeline: RunnablePipeline, manifest: SSRManifest, { prerenderOnly }?: {
11
+ export declare function matchRoute(manifest: SSRManifest, pathname: string, { prerenderOnly }?: {
14
12
  prerenderOnly?: boolean;
15
13
  }): Promise<MatchedRoute | undefined>;
16
14
  export {};
@@ -4,9 +4,16 @@ import { getProps } from "../render/index.js";
4
4
  import { getCustom404Route } from "./helpers.js";
5
5
  import { NoMatchingStaticPathFound } from "../errors/errors-data.js";
6
6
  import { isAstroError } from "../errors/errors.js";
7
+ import { getEnvironment } from "../environment/index.js";
8
+ import { getLogger } from "../logger/manifest-logger.js";
9
+ import { getRouteCache } from "../render/route-cache.js";
10
+ import { getRouteTable } from "./route-table.js";
7
11
  import { getErrorRoutePath } from "../../i18n/error-routes.js";
8
- async function matchRoute(pathname, routesList, pipeline, manifest, { prerenderOnly } = {}) {
9
- const { logger, routeCache } = pipeline;
12
+ async function matchRoute(manifest, pathname, { prerenderOnly } = {}) {
13
+ const logger = getLogger(manifest);
14
+ const routeCache = getRouteCache(manifest);
15
+ const env = getEnvironment(manifest);
16
+ const routesList = getRouteTable(manifest);
10
17
  const matches = matchAllRoutes(pathname, routesList);
11
18
  const preloadedMatches = getSortedPreloadedMatches({
12
19
  matches,
@@ -21,12 +28,12 @@ async function matchRoute(pathname, routesList, pipeline, manifest, { prerenderO
21
28
  }
22
29
  try {
23
30
  await getProps({
24
- mod: await pipeline.getComponentByRoute(maybeRoute),
31
+ mod: await env.getComponentByRoute(manifest, maybeRoute),
25
32
  routeData: maybeRoute,
26
33
  routeCache,
27
34
  pathname,
28
35
  logger,
29
- serverLike: pipeline.manifest.serverLike,
36
+ serverLike: manifest.serverLike,
30
37
  base: manifest.base,
31
38
  trailingSlash: manifest.trailingSlash
32
39
  });
@@ -48,7 +55,7 @@ async function matchRoute(pathname, routesList, pipeline, manifest, { prerenderO
48
55
  }
49
56
  const altPathname = pathname.replace(/\/index\.html$/, "/").replace(/\.html$/, "");
50
57
  if (altPathname !== pathname) {
51
- return await matchRoute(altPathname, routesList, pipeline, manifest, { prerenderOnly });
58
+ return await matchRoute(manifest, altPathname, { prerenderOnly });
52
59
  }
53
60
  if (skippedPrerenderOnly) {
54
61
  return void 0;
@@ -1,17 +1,7 @@
1
1
  import type { FetchState } from '../fetch/fetch-state.js';
2
- import type { BaseApp } from '../app/base.js';
3
- import { type Pipeline } from '../base-pipeline.js';
4
- export declare class AstroHandler {
5
- #private;
6
- constructor(app: BaseApp<Pipeline>);
7
- handle(state: FetchState): Promise<Response>;
8
- /**
9
- * Renders a response for the given `FetchState`. Assumes
10
- * trailing-slash redirects and routeData resolution have already run.
11
- *
12
- * User-triggered rewrites (`Astro.rewrite` / `ctx.rewrite`) go through
13
- * `Rewrites.execute` on the current `FetchState` — they mutate the
14
- * existing state in place and re-run middleware + page dispatch.
15
- */
16
- render(state: FetchState): Promise<Response>;
17
- }
2
+ /**
3
+ * The composite "batteries-included" handler that wires up every request
4
+ * feature internally; `astro(state)` (astro/fetch) delegates here, as does
5
+ * `BaseApp.render`'s default-handler fast path.
6
+ */
7
+ export declare function handleRequest(state: FetchState): Promise<Response>;
@@ -1,183 +1,145 @@
1
- import { ActionHandler } from "../../actions/handler.js";
1
+ import { handleAction } from "../../actions/handler.js";
2
2
  import { REROUTABLE_STATUS_CODES } from "../constants.js";
3
- import { TrailingSlashHandler } from "./trailing-slash-handler.js";
4
- import { CacheHandler, provideCache } from "../cache/handler.js";
5
- import { I18n } from "../i18n/handler.js";
6
- import { AstroMiddleware } from "../middleware/astro-middleware.js";
7
- import { PagesHandler } from "../pages/handler.js";
3
+ import { handleTrailingSlash } from "./trailing-slash-handler.js";
4
+ import { handleCache, provideCache } from "../cache/handler.js";
5
+ import { getEnvironment } from "../environment/index.js";
6
+ import { renderErrorFromState } from "../errors/handler.js";
7
+ import { ALL_FETCH_FEATURES, markFeatureUsed, FetchFeatures } from "../fetch/features.js";
8
+ import { finalizeI18n, getI18n } from "../i18n/handler.js";
9
+ import { getResolvedLogger } from "../logger/manifest-logger.js";
10
+ import { handleMiddleware } from "../middleware/astro-middleware.js";
11
+ import { handlePages } from "../pages/handler.js";
8
12
  import { renderRedirect } from "../redirects/render.js";
9
13
  import { provideSession } from "../session/provider.js";
10
14
  import { prepareResponse } from "../app/prepare-response.js";
11
- import { ALL_PIPELINE_FEATURES, PipelineFeatures } from "../base-pipeline.js";
12
- class AstroHandler {
13
- #app;
14
- #trailingSlashHandler;
15
- #actionHandler;
16
- #astroMiddleware;
17
- #pagesHandler;
18
- #cacheHandler;
19
- /** Bound callback for the middleware chain — created once, reused per request. */
20
- #renderRouteCallback;
21
- /**
22
- * i18n post-processor. Only set when the app has i18n configured and
23
- * the strategy is not `manual` — for the manual strategy users wire
24
- * `astro:i18n.middleware(...)` into their own `onRequest`.
25
- */
26
- #i18n;
27
- /** Whether sessions are configured on the manifest. */
28
- #hasSession;
29
- constructor(app) {
30
- this.#app = app;
31
- this.#trailingSlashHandler = new TrailingSlashHandler(app);
32
- this.#actionHandler = new ActionHandler();
33
- this.#astroMiddleware = new AstroMiddleware(app.pipeline);
34
- this.#pagesHandler = new PagesHandler(app.pipeline);
35
- this.#cacheHandler = new CacheHandler(app);
36
- this.#renderRouteCallback = this.#actionsAndPages.bind(this);
37
- this.#hasSession = !!app.manifest.sessionConfig;
38
- const i18n = app.manifest.i18n;
39
- if (i18n && i18n.strategy !== "manual") {
40
- this.#i18n = new I18n(
41
- i18n,
42
- app.manifest.base,
43
- app.manifest.trailingSlash,
44
- app.manifest.buildFormat
45
- );
46
- }
15
+ import { getDefaultStatusCode } from "./helpers.js";
16
+ function logRequestFromState(state, payload) {
17
+ if (state.logRequest) {
18
+ state.logRequest(payload);
19
+ } else {
20
+ getEnvironment(state.manifest).logRequest(state.manifest, payload);
47
21
  }
48
- /**
49
- * Runs actions then pages — the callback at the bottom of the
50
- * middleware chain. Bound once in the constructor to avoid
51
- * per-request closure allocation.
52
- */
53
- #actionsAndPages(state, ctx) {
54
- if (!state.skipMiddleware) {
55
- const actionResult = this.#actionHandler.handle(ctx, state);
56
- if (actionResult) {
57
- return actionResult.then((response) => response ?? this.#pagesHandler.handle(state, ctx));
58
- }
22
+ }
23
+ function actionsAndPages(state, ctx) {
24
+ if (!state.skipMiddleware) {
25
+ const actionResult = handleAction(ctx, state);
26
+ if (actionResult) {
27
+ return actionResult.then((response) => response ?? handlePages(state, ctx));
59
28
  }
60
- return this.#pagesHandler.handle(state, ctx);
61
29
  }
62
- async handle(state) {
63
- state.pipeline.usedFeatures |= ALL_PIPELINE_FEATURES;
64
- if (state.invalidEncoding) {
65
- return new Response(null, { status: 400, statusText: "Bad Request" });
66
- }
67
- const trailingSlashRedirect = this.#trailingSlashHandler.handle(state);
68
- if (trailingSlashRedirect) {
69
- return trailingSlashRedirect;
70
- }
71
- if (!state.routeData) {
72
- return this.#app.renderError(state.request, {
73
- ...state.renderOptions,
74
- status: 404,
75
- pathname: state.pathname
76
- });
77
- }
78
- return this.render(state);
30
+ return handlePages(state, ctx);
31
+ }
32
+ async function handleRequest(state) {
33
+ await getResolvedLogger(state.manifest);
34
+ markFeatureUsed(state.manifest, ALL_FETCH_FEATURES);
35
+ if (state.invalidEncoding) {
36
+ return new Response(null, { status: 400, statusText: "Bad Request" });
79
37
  }
80
- /**
81
- * Renders a response for the given `FetchState`. Assumes
82
- * trailing-slash redirects and routeData resolution have already run.
83
- *
84
- * User-triggered rewrites (`Astro.rewrite` / `ctx.rewrite`) go through
85
- * `Rewrites.execute` on the current `FetchState` — they mutate the
86
- * existing state in place and re-run middleware + page dispatch.
87
- */
88
- async render(state) {
89
- const routeData = state.routeData;
90
- const pathname = state.pathname;
91
- const request = state.request;
92
- const { addCookieHeader } = state.renderOptions;
93
- const defaultStatus = this.#app.getDefaultStatusCode(routeData, pathname);
94
- state.status = defaultStatus;
95
- let response;
96
- let finalizeError;
97
- try {
98
- const sessionP = this.#hasSession ? provideSession(state) : void 0;
99
- const cacheP = provideCache(state);
100
- if (sessionP || cacheP) await Promise.all([sessionP, cacheP]);
101
- state.pipeline.usedFeatures |= PipelineFeatures.sessions;
102
- if (routeData.type === "redirect") {
103
- const redirectResponse = await renderRedirect(state);
104
- this.#app.logThisRequest({
105
- pathname,
106
- method: request.method,
107
- statusCode: redirectResponse.status,
108
- isRewrite: false,
109
- timeStart: state.timeStart
110
- });
111
- prepareResponse(redirectResponse, { addCookieHeader });
112
- this.#app.pipeline.logger.flush();
113
- return redirectResponse;
114
- }
115
- if (!this.#app.pipeline.cacheProvider) {
116
- this.#app.pipeline.usedFeatures |= PipelineFeatures.cache;
117
- response = await this.#astroMiddleware.handle(state, this.#renderRouteCallback);
118
- if (this.#i18n) {
119
- response = await this.#i18n.finalize(state, response);
120
- }
121
- } else {
122
- const runPipeline = async () => {
123
- let res = await this.#astroMiddleware.handle(state, this.#renderRouteCallback);
124
- if (this.#i18n) {
125
- res = await this.#i18n.finalize(state, res);
126
- }
127
- return res;
128
- };
129
- response = await this.#cacheHandler.handle(state, runPipeline);
130
- }
131
- this.#app.logThisRequest({
38
+ const trailingSlashRedirect = handleTrailingSlash(state);
39
+ if (trailingSlashRedirect) {
40
+ return trailingSlashRedirect;
41
+ }
42
+ if (!state.routeData) {
43
+ return renderErrorFromState(state, state.request, {
44
+ ...state.renderOptions,
45
+ status: 404,
46
+ pathname: state.pathname
47
+ });
48
+ }
49
+ return render(state);
50
+ }
51
+ async function render(state) {
52
+ const routeData = state.routeData;
53
+ const pathname = state.pathname;
54
+ const request = state.request;
55
+ const { addCookieHeader } = state.renderOptions;
56
+ state.status = getDefaultStatusCode(state.manifest, routeData, pathname);
57
+ let response;
58
+ let finalizeError;
59
+ try {
60
+ const sessionP = state.manifest.sessionConfig ? provideSession(state) : void 0;
61
+ const cacheP = provideCache(state);
62
+ if (sessionP || cacheP) await Promise.all([sessionP, cacheP]);
63
+ markFeatureUsed(state.manifest, FetchFeatures.sessions);
64
+ if (routeData.type === "redirect") {
65
+ const redirectResponse = await renderRedirect(state);
66
+ logRequestFromState(state, {
132
67
  pathname,
133
68
  method: request.method,
134
- statusCode: response.status,
135
- isRewrite: state.isRewriting,
69
+ statusCode: redirectResponse.status,
70
+ isRewrite: false,
136
71
  timeStart: state.timeStart
137
72
  });
138
- } catch (err) {
139
- this.#app.logger.error(null, err.stack || err.message || String(err));
140
- return this.#app.renderError(request, {
141
- ...state.renderOptions,
142
- status: 500,
143
- error: err,
144
- pathname: state.pathname
145
- });
146
- } finally {
147
- try {
148
- const finalize = state.finalizeAll();
149
- if (finalize) await finalize;
150
- } catch (err) {
151
- finalizeError = err;
152
- this.#app.logger.error(null, err.stack || err.message || String(err));
153
- }
73
+ prepareResponse(redirectResponse, { addCookieHeader });
74
+ state.logger.flush();
75
+ return redirectResponse;
154
76
  }
155
- if (finalizeError) {
156
- return this.#app.renderError(request, {
157
- ...state.renderOptions,
158
- status: 500,
159
- error: finalizeError,
160
- pathname: state.pathname
161
- });
77
+ const i18n = getI18n(state.manifest);
78
+ if (!state.manifest.cacheProvider) {
79
+ markFeatureUsed(state.manifest, FetchFeatures.cache);
80
+ response = await handleMiddleware(state, actionsAndPages);
81
+ if (i18n) {
82
+ response = await finalizeI18n(i18n, state, response);
83
+ }
84
+ } else {
85
+ const runPipeline = async () => {
86
+ let res = await handleMiddleware(state, actionsAndPages);
87
+ if (i18n) {
88
+ res = await finalizeI18n(i18n, state, res);
89
+ }
90
+ return res;
91
+ };
92
+ response = await handleCache(state, runPipeline);
162
93
  }
163
- if (REROUTABLE_STATUS_CODES.includes(response.status) && // If the body isn't null, that means the user sets the 404 status
164
- // but uses the current route to handle the 404
165
- response.body === null && !state.skipErrorReroute) {
166
- return this.#app.renderError(request, {
167
- ...state.renderOptions,
168
- response,
169
- status: response.status,
170
- // We don't have an error to report here. Passing null means we pass nothing intentionally
171
- // while undefined means there's no error
172
- error: response.status === 500 ? null : void 0,
173
- pathname: state.pathname
174
- });
94
+ logRequestFromState(state, {
95
+ pathname,
96
+ method: request.method,
97
+ statusCode: response.status,
98
+ isRewrite: state.isRewriting,
99
+ timeStart: state.timeStart
100
+ });
101
+ } catch (err) {
102
+ state.logger.error(null, err.stack || err.message || String(err));
103
+ return renderErrorFromState(state, request, {
104
+ ...state.renderOptions,
105
+ status: 500,
106
+ error: err,
107
+ pathname: state.pathname
108
+ });
109
+ } finally {
110
+ try {
111
+ const finalize = state.finalizeAll();
112
+ if (finalize) await finalize;
113
+ } catch (err) {
114
+ finalizeError = err;
115
+ state.logger.error(null, err.stack || err.message || String(err));
175
116
  }
176
- prepareResponse(response, { addCookieHeader });
177
- this.#app.pipeline.logger.flush();
178
- return response;
179
117
  }
118
+ if (finalizeError) {
119
+ return renderErrorFromState(state, request, {
120
+ ...state.renderOptions,
121
+ status: 500,
122
+ error: finalizeError,
123
+ pathname: state.pathname
124
+ });
125
+ }
126
+ if (REROUTABLE_STATUS_CODES.includes(response.status) && // If the body isn't null, that means the user sets the 404 status
127
+ // but uses the current route to handle the 404
128
+ response.body === null && !state.skipErrorReroute) {
129
+ return renderErrorFromState(state, request, {
130
+ ...state.renderOptions,
131
+ response,
132
+ status: response.status,
133
+ // We don't have an error to report here. Passing null means we pass nothing intentionally
134
+ // while undefined means there's no error
135
+ error: response.status === 500 ? null : void 0,
136
+ pathname: state.pathname
137
+ });
138
+ }
139
+ prepareResponse(response, { addCookieHeader });
140
+ state.logger.flush();
141
+ return response;
180
142
  }
181
143
  export {
182
- AstroHandler
144
+ handleRequest
183
145
  };
@@ -1,6 +1,6 @@
1
1
  import type { RouteData } from '../../types/public/internal.js';
2
2
  import type { IntegrationResolvedRoute } from '../../types/public/integrations.js';
3
- import type { RouteInfo } from '../app/types.js';
3
+ import type { RouteInfo, SSRManifest } from '../app/types.js';
4
4
  import type { RoutesList } from '../../types/astro.js';
5
5
  type RedirectRouteData = RouteData & {
6
6
  redirect: string;
@@ -32,6 +32,12 @@ export declare function getCustom404Route(manifestData: RoutesList): RouteData |
32
32
  * Return a user-provided 500 route if one exists.
33
33
  */
34
34
  export declare function getCustom500Route(manifestData: RoutesList): RouteData | undefined;
35
+ /**
36
+ * Computes the default HTTP status code a route renders with:
37
+ * `302` for i18n fallback matches, `404`/`500` for (possibly localized)
38
+ * error routes, `200` otherwise.
39
+ */
40
+ export declare function getDefaultStatusCode(manifest: SSRManifest, routeData: RouteData, pathname: string): number;
35
41
  /**
36
42
  * Returns true if the route definition contains `.html` as a static segment part,
37
43
  * as is the case for routes like `[slug].html.astro`. Used to avoid stripping the
@@ -1,3 +1,5 @@
1
+ import { removeTrailingForwardSlash } from "@astrojs/internal-helpers/path";
2
+ import { isLocalizedErrorRoute } from "../../i18n/error-routes.js";
1
3
  import { isRoute404, isRoute500 } from "./internal/route-errors.js";
2
4
  function routeIsRedirect(route) {
3
5
  return route?.type === "redirect";
@@ -25,6 +27,24 @@ function getCustom404Route(manifestData) {
25
27
  function getCustom500Route(manifestData) {
26
28
  return manifestData.routes.find((r) => isRoute500(r.route));
27
29
  }
30
+ function getDefaultStatusCode(manifest, routeData, pathname) {
31
+ if (!routeData.pattern.test(pathname)) {
32
+ for (const fallbackRoute of routeData.fallbackRoutes) {
33
+ if (fallbackRoute.pattern.test(pathname)) {
34
+ return 302;
35
+ }
36
+ }
37
+ }
38
+ const route = removeTrailingForwardSlash(routeData.route);
39
+ const locales = manifest.i18n?.locales;
40
+ if (isRoute404(route) || isLocalizedErrorRoute(route, 404, locales)) {
41
+ return 404;
42
+ }
43
+ if (isRoute500(route) || isLocalizedErrorRoute(route, 500, locales)) {
44
+ return 500;
45
+ }
46
+ return 200;
47
+ }
28
48
  function routeHasHtmlExtension(route) {
29
49
  return route.segments.some(
30
50
  (segment) => segment.some((part) => !part.dynamic && part.content.includes(".html"))
@@ -43,6 +63,7 @@ function hasNonPrerenderedRoute(routes, options) {
43
63
  export {
44
64
  getCustom404Route,
45
65
  getCustom500Route,
66
+ getDefaultStatusCode,
46
67
  getFallbackRoute,
47
68
  hasNonPrerenderedRoute,
48
69
  routeHasHtmlExtension,
@@ -0,0 +1,10 @@
1
+ import type { RouteData } from '../../types/public/internal.js';
2
+ import type { SSRManifest } from '../app/types.js';
3
+ /**
4
+ * Given a `Request`, returns the `RouteData` that matches its pathname — the
5
+ * appless, purely functional body of `BaseApp.match()`. By default, prerendered
6
+ * routes aren't returned, even if they are matched; when
7
+ * `allowPrerenderedRoutes` is `true`, matched prerendered routes are returned
8
+ * too.
9
+ */
10
+ export declare function matchRequest(manifest: SSRManifest, request: Request, allowPrerenderedRoutes?: boolean): RouteData | undefined;
@@ -0,0 +1,57 @@
1
+ import {
2
+ collapseDuplicateLeadingSlashes,
3
+ prependForwardSlash,
4
+ removeTrailingForwardSlash
5
+ } from "@astrojs/internal-helpers/path";
6
+ import { computePathnameFromDomain } from "../i18n/domain.js";
7
+ import { AstroIntegrationLogger } from "../logger/core.js";
8
+ import { getLogger } from "../logger/manifest-logger.js";
9
+ import { matchAllRoutes, matchRoute } from "./route-table.js";
10
+ function removeBase(manifest, pathname) {
11
+ pathname = collapseDuplicateLeadingSlashes(pathname);
12
+ if (pathname.startsWith(manifest.base)) {
13
+ return pathname.slice(removeTrailingForwardSlash(manifest.base).length + 1);
14
+ }
15
+ return pathname;
16
+ }
17
+ function safeDecodeURI(manifest, pathname) {
18
+ try {
19
+ return decodeURI(pathname);
20
+ } catch (e) {
21
+ new AstroIntegrationLogger(getLogger(manifest).options, manifest.adapterName).debug(
22
+ e.toString()
23
+ );
24
+ return pathname;
25
+ }
26
+ }
27
+ function matchRequest(manifest, request, allowPrerenderedRoutes = false) {
28
+ const url = new URL(request.url);
29
+ if (manifest.assets.has(url.pathname)) return void 0;
30
+ let pathname = computePathnameFromDomain(
31
+ request,
32
+ url,
33
+ manifest.i18n,
34
+ manifest.base,
35
+ manifest.trailingSlash,
36
+ getLogger(manifest)
37
+ );
38
+ if (!pathname) {
39
+ pathname = prependForwardSlash(removeBase(manifest, url.pathname));
40
+ }
41
+ const routeData = matchRoute(manifest, safeDecodeURI(manifest, pathname));
42
+ if (!routeData) return void 0;
43
+ if (allowPrerenderedRoutes) {
44
+ return routeData;
45
+ }
46
+ if (routeData.prerender) {
47
+ if (routeData.params.length > 0) {
48
+ const allMatches = matchAllRoutes(manifest, safeDecodeURI(manifest, pathname));
49
+ return allMatches.find((r) => !r.prerender);
50
+ }
51
+ return void 0;
52
+ }
53
+ return routeData;
54
+ }
55
+ export {
56
+ matchRequest
57
+ };
@@ -0,0 +1,34 @@
1
+ import type { RouteData, SSRManifest } from '../../types/public/internal.js';
2
+ import { Router } from './router.js';
3
+ export interface RouteTable {
4
+ /** Route data derived from the manifest, used for route matching. */
5
+ routes: RouteData[];
6
+ /** Pattern-matching router compiled from `routes`. */
7
+ router: Router;
8
+ }
9
+ /**
10
+ * The route table for a manifest: the derived route list (with the default
11
+ * 404 ensured) and the compiled router. All route reads — matching, rewrites,
12
+ * custom-404 fallbacks, `manifestData` accessors — go through this single
13
+ * entry so dev HMR updates are visible to every consumer at once.
14
+ */
15
+ export declare function getRouteTable(manifest: SSRManifest): RouteTable;
16
+ /**
17
+ * Atomically replaces the route table for a manifest (dev `astro:routes-updated`).
18
+ * Runs `ensure404Route` on the new list, compiles a fresh `Router`, and swaps
19
+ * the memo entry in one step, so no consumer can observe a half-updated table.
20
+ */
21
+ export declare function updateRouteTable(manifest: SSRManifest, routes: RouteData[]): void;
22
+ /**
23
+ * Low-level route matching against the manifest routes. Returns the matched
24
+ * `RouteData` or `undefined`. Does not filter prerendered routes or check
25
+ * public assets — use the app-level match for that.
26
+ */
27
+ export declare function matchRoute(manifest: SSRManifest, pathname: string): RouteData | undefined;
28
+ /**
29
+ * Returns all routes matching the given pathname, in priority order. Used when
30
+ * the first match cannot serve the request (e.g. a prerendered dynamic route
31
+ * that doesn't cover this specific path) and the caller needs to try
32
+ * subsequent matches.
33
+ */
34
+ export declare function matchAllRoutes(manifest: SSRManifest, pathname: string): RouteData[];