astro
Version:
Astro is a modern site builder with web best practices, performance, and DX front-of-mind.
134 lines (133 loc) • 5.68 kB
JavaScript
/**
* Public `astro/fetch` API.
*
* Every exported function here is a thin, byte-identical-signature wrapper
* that delegates to the handler modules. **Do not add logic here** — keep
* behaviour inside the handler modules so it stays unit-testable without
* the virtual-module wiring.
*/
import { handleAction } from "../../actions/handler.js";
import { FetchState as BaseFetchState } from "./fetch-state.js";
import { provideAndHandleCache } from "../cache/handler.js";
import { handleI18nWithErrorFallback } from "../i18n/error-fallback.js";
import { getI18n } from "../i18n/handler.js";
import { getAmbientManifest } from "../manifest/ambient.js";
import { handleNotFound } from "../errors/not-found.js";
import { handleMiddlewareWithErrorFallback } from "../middleware/astro-middleware.js";
import { handlePagesWithErrorFallback } from "../pages/handler.js";
import { handleRedirects } from "../redirects/render.js";
import { handleRequest } from "../routing/handler.js";
import { provideSession } from "../session/provider.js";
import { handleTrailingSlash } from "../routing/trailing-slash-handler.js";
/**
* The public per-request state, constructible from a bare `Request`.
* Static, build-time data comes from the ambient manifest — the manifest
* module bundled into every Astro-built server — so no app, pipeline, or
* request-attached handle is needed.
*/
export class FetchState extends BaseFetchState {
constructor(request) {
super(getAmbientManifest(), request);
}
}
export function astro(state) {
return handleRequest(state);
}
/**
* Checks if the request pathname needs trailing-slash normalization and
* returns a redirect `Response` if so. Returns `undefined` when no
* redirect is needed and the caller should continue processing.
*/
export function trailingSlash(state) {
return handleTrailingSlash(state);
}
/**
* Runs Astro's middleware chain for the given state, calling `next` at
* the bottom of the chain to produce the response. Lazily creates the
* render context if needed. Unmatched routes return a null-body 404 marked
* for `App.render` to replace with the 404 error page; pipelines that do
* not run inside `App.render` call `notFound()` first. Errors thrown by
* user middleware are logged and render the 500 error
* page; errors surfaced through `next` (the host framework's downstream
* chain) propagate to the host instead.
*/
export function middleware(state, next) {
return handleMiddlewareWithErrorFallback(state, (s, _ctx) => next(s));
}
/**
* Dispatches the request to the matched route (endpoint, page, redirect,
* or fallback). Lazily creates the render context if needed. Unmatched
* routes return a null-body 404 marked for `App.render` to replace with
* the 404 error page; pipelines that do not run inside `App.render` call
* `notFound()` first. Render-time errors are logged and render the 500
* error page.
*/
export function pages(state) {
return handlePagesWithErrorFallback(state);
}
/**
* Registers the session provider on the state. The session is created
* lazily when user code accesses `ctx.session`, and persisted when
* `state.finalizeAll()` is called. No-op if sessions are not configured.
*
* Call this early (before middleware runs). Call `state.finalizeAll()`
* in a `finally` block after the response is produced to persist
* any session mutations.
*/
export function sessions(state) {
return provideSession(state);
}
/**
* Checks if the matched route is a redirect and returns the redirect
* `Response` if so. Returns `undefined` when the route is not a
* redirect and the caller should continue processing. Returns an empty
* `400` when the request path is over-encoded.
* `state.routeData` must be set before calling this.
*/
export function redirects(state) {
return handleRedirects(state);
}
/**
* Renders the 404 error page when no route matched the request, including a
* prerendered `404.astro` (served through
* `renderOptions.prerenderedErrorPageFetch` in production). Returns
* `undefined` when a route matched and the caller should continue
* processing. Returns an empty `400` when the request path is
* over-encoded. Call this before `middleware()` and `pages()` in a
* pipeline that does not run inside `App.render`.
*/
export function notFound(state) {
return handleNotFound(state);
}
/**
* Handles Astro Action requests (RPC + form). Returns a `Response` for
* RPC actions, or `undefined` for form actions / non-action requests
* (the caller should continue to page rendering). Lazily creates
* the render context if needed. Returns an empty `400` when the request
* path is over-encoded, without running any action.
*/
export function actions(state) {
return handleAction(state.getAPIContext(), state);
}
/**
* Post-processes a response against the manifest's i18n configuration.
* Handles locale redirects, 404s for invalid locales, and fallback
* routing. A null-body 404 produced for an invalid locale path renders
* the 404 error page. Returns the response unmodified if i18n is not
* configured (or the routing strategy is `manual`).
*/
export function i18n(state, response) {
const compiled = getI18n(state.manifest);
if (!compiled) return Promise.resolve(response);
return handleI18nWithErrorFallback(compiled, state, response);
}
/**
* Wraps a render callback with cache provider logic. Handles runtime
* caching (onRequest), CDN-based providers (headers only), and the
* no-cache case transparently. Cache headers are applied and stripped
* internally. Registers the cache provider on the state before calling
* `next`, so `ctx.cache` / `Astro.cache` are available downstream.
*/
export function cache(state, next) {
return provideAndHandleCache(state, next);
}