globalThis.process ??= {}; globalThis.process.env ??= {}; import { f as fileExtension, j as joinPaths, s as slash, p as prependForwardSlash, r as removeTrailingForwardSlash, a as appendForwardSlash, b as isInternalPath, c as collapseDuplicateTrailingSlashes, h as hasFileExtension } from './path_CH3auf61.mjs'; import { m as matchPattern } from './remote_BC1y8RCW.mjs'; import { r as requestIs404Or500, i as isRequestServerIsland, n as notFound, a as redirectToFallback, b as redirectToDefaultLocale, c as requestHasLocale, d as normalizeTheLocale, e as defineMiddleware, S as SERVER_ISLAND_COMPONENT, f as SERVER_ISLAND_ROUTE, g as createEndpoint, R as RouteCache, s as sequence, h as findRouteToRewrite, m as matchRoute, j as RenderContext, P as PERSIST_SYMBOL, k as getSetCookiesFromResponse } from './index_BfW_FHpJ.mjs'; import { R as ROUTE_TYPE_HEADER, q as REROUTE_DIRECTIVE_HEADER, D as DEFAULT_404_COMPONENT, A as AstroError, v as ActionNotFoundError, w as bold, x as red, y as yellow, z as dim, B as blue, C as clientAddressSymbol, G as LocalsNotAnObject, H as REROUTABLE_STATUS_CODES, J as responseSentSymbol } from './astro/server_WO3f6Mge.mjs'; import { D as DEFAULT_404_ROUTE, d as default404Instance, e as ensure404Route } from './astro-designed-error-pages_CuMapJD2.mjs'; import { N as NOOP_MIDDLEWARE_FN } from './noop-middleware_C9xlyid3.mjs'; import 'cloudflare:workers'; function createI18nMiddleware(i18n, base, trailingSlash, format) { if (!i18n) return (_, next) => next(); const payload = { ...i18n, trailingSlash, base, format}; const _redirectToDefaultLocale = redirectToDefaultLocale(payload); const _noFoundForNonLocaleRoute = notFound(payload); const _requestHasLocale = requestHasLocale(payload.locales); const _redirectToFallback = redirectToFallback(payload); const prefixAlways = (context, response) => { const url = context.url; if (url.pathname === base + "/" || url.pathname === base) { return _redirectToDefaultLocale(context); } else if (!_requestHasLocale(context)) { return _noFoundForNonLocaleRoute(context, response); } return void 0; }; const prefixOtherLocales = (context, response) => { let pathnameContainsDefaultLocale = false; const url = context.url; for (const segment of url.pathname.split("/")) { if (normalizeTheLocale(segment) === normalizeTheLocale(i18n.defaultLocale)) { pathnameContainsDefaultLocale = true; break; } } if (pathnameContainsDefaultLocale) { const newLocation = url.pathname.replace(`/${i18n.defaultLocale}`, ""); response.headers.set("Location", newLocation); return _noFoundForNonLocaleRoute(context); } return void 0; }; return async (context, next) => { const response = await next(); const type = response.headers.get(ROUTE_TYPE_HEADER); const isReroute = response.headers.get(REROUTE_DIRECTIVE_HEADER); if (isReroute === "no" && typeof i18n.fallback === "undefined") { return response; } if (type !== "page" && type !== "fallback") { return response; } if (requestIs404Or500(context.request, base)) { return response; } if (isRequestServerIsland(context.request, base)) { return response; } const { currentLocale } = context; switch (i18n.strategy) { // NOTE: theoretically, we should never hit this code path case "manual": { return response; } case "domains-prefix-other-locales": { if (localeHasntDomain(i18n, currentLocale)) { const result = prefixOtherLocales(context, response); if (result) { return result; } } break; } case "pathname-prefix-other-locales": { const result = prefixOtherLocales(context, response); if (result) { return result; } break; } case "domains-prefix-always-no-redirect": { if (localeHasntDomain(i18n, currentLocale)) { const result = _noFoundForNonLocaleRoute(context, response); if (result) { return result; } } break; } case "pathname-prefix-always-no-redirect": { const result = _noFoundForNonLocaleRoute(context, response); if (result) { return result; } break; } case "pathname-prefix-always": { const result = prefixAlways(context, response); if (result) { return result; } break; } case "domains-prefix-always": { if (localeHasntDomain(i18n, currentLocale)) { const result = prefixAlways(context, response); if (result) { return result; } } break; } } return _redirectToFallback(context, response); }; } function localeHasntDomain(i18n, currentLocale) { for (const domainLocale of Object.values(i18n.domainLookupTable)) { if (domainLocale === currentLocale) { return false; } } return true; } const NOOP_ACTIONS_MOD = { server: {} }; const FORM_CONTENT_TYPES = [ "application/x-www-form-urlencoded", "multipart/form-data", "text/plain" ]; const SAFE_METHODS = ["GET", "HEAD", "OPTIONS"]; function createOriginCheckMiddleware() { return defineMiddleware((context, next) => { const { request, url, isPrerendered } = context; if (isPrerendered) { return next(); } if (SAFE_METHODS.includes(request.method)) { return next(); } const isSameOrigin = request.headers.get("origin") === url.origin; const hasContentType = request.headers.has("content-type"); if (hasContentType) { const formLikeHeader = hasFormLikeHeader(request.headers.get("content-type")); if (formLikeHeader && !isSameOrigin) { return new Response(`Cross-site ${request.method} form submissions are forbidden`, { status: 403 }); } } else { if (!isSameOrigin) { return new Response(`Cross-site ${request.method} form submissions are forbidden`, { status: 403 }); } } return next(); }); } function hasFormLikeHeader(contentType) { if (contentType) { for (const FORM_CONTENT_TYPE of FORM_CONTENT_TYPES) { if (contentType.toLowerCase().includes(FORM_CONTENT_TYPE)) { return true; } } } return false; } function createDefaultRoutes(manifest) { const root = new URL(manifest.hrefRoot); return [ { instance: default404Instance, matchesComponent: (filePath) => filePath.href === new URL(DEFAULT_404_COMPONENT, root).href, route: DEFAULT_404_ROUTE.route, component: DEFAULT_404_COMPONENT }, { instance: createEndpoint(manifest), matchesComponent: (filePath) => filePath.href === new URL(SERVER_ISLAND_COMPONENT, root).href, route: SERVER_ISLAND_ROUTE, component: SERVER_ISLAND_COMPONENT } ]; } class Pipeline { constructor(logger, manifest, runtimeMode, renderers, resolve, serverLike, 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) { this.logger = logger; this.manifest = manifest; this.runtimeMode = runtimeMode; this.renderers = renderers; this.resolve = resolve; this.serverLike = serverLike; this.streaming = streaming; this.adapterName = adapterName; this.clientDirectives = clientDirectives; this.inlinedScripts = inlinedScripts; this.compressHTML = compressHTML; this.i18n = i18n; this.middleware = middleware; this.routeCache = routeCache; this.site = site; this.defaultRoutes = defaultRoutes; this.actions = actions; this.internalMiddleware = []; if (i18n?.strategy !== "manual") { this.internalMiddleware.push( createI18nMiddleware(i18n, manifest.base, manifest.trailingSlash, manifest.buildFormat) ); } } internalMiddleware; resolvedMiddleware = void 0; resolvedActions = void 0; /** * Resolves the middleware from the manifest, and returns the `onRequest` function. If `onRequest` isn't there, * it returns a no-op function */ async getMiddleware() { if (this.resolvedMiddleware) { return this.resolvedMiddleware; } else if (this.middleware) { const middlewareInstance = await this.middleware(); const onRequest = middlewareInstance.onRequest ?? NOOP_MIDDLEWARE_FN; const internalMiddlewares = [onRequest]; if (this.manifest.checkOrigin) { internalMiddlewares.unshift(createOriginCheckMiddleware()); } this.resolvedMiddleware = sequence(...internalMiddlewares); return this.resolvedMiddleware; } else { this.resolvedMiddleware = NOOP_MIDDLEWARE_FN; return this.resolvedMiddleware; } } setActions(actions) { this.resolvedActions = actions; } async getActions() { if (this.resolvedActions) { return this.resolvedActions; } else if (this.actions) { return await this.actions(); } return NOOP_ACTIONS_MOD; } async getAction(path) { const pathKeys = path.split(".").map((key) => decodeURIComponent(key)); let { server } = await this.getActions(); if (!server || !(typeof server === "object")) { throw new TypeError( `Expected \`server\` export in actions file to be an object. Received ${typeof server}.` ); } for (const key of pathKeys) { if (!(key in server)) { throw new AstroError({ ...ActionNotFoundError, message: ActionNotFoundError.message(pathKeys.join(".")) }); } server = server[key]; } if (typeof server !== "function") { throw new TypeError( `Expected handler for action ${pathKeys.join(".")} to be a function. Received ${typeof server}.` ); } return server; } } const RedirectComponentInstance = { default() { return new Response(null, { status: 301 }); } }; const RedirectSinglePageBuiltModule = { page: () => Promise.resolve(RedirectComponentInstance), onRequest: (_, next) => next(), renderers: [] }; const dateTimeFormat = new Intl.DateTimeFormat([], { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false }); const levels = { debug: 20, info: 30, warn: 40, error: 50, silent: 90 }; function log(opts, level, label, message, newLine = true) { const logLevel = opts.level; const dest = opts.dest; const event = { label, level, message, newLine }; if (!isLogLevelEnabled(logLevel, level)) { return; } dest.write(event); } function isLogLevelEnabled(configuredLogLevel, level) { return levels[configuredLogLevel] <= levels[level]; } function info(opts, label, message, newLine = true) { return log(opts, "info", label, message, newLine); } function warn(opts, label, message, newLine = true) { return log(opts, "warn", label, message, newLine); } function error(opts, label, message, newLine = true) { return log(opts, "error", label, message, newLine); } function debug(...args) { if ("_astroGlobalDebug" in globalThis) { globalThis._astroGlobalDebug(...args); } } function getEventPrefix({ level, label }) { const timestamp = `${dateTimeFormat.format(/* @__PURE__ */ new Date())}`; const prefix = []; if (level === "error" || level === "warn") { prefix.push(bold(timestamp)); prefix.push(`[${level.toUpperCase()}]`); } else { prefix.push(timestamp); } if (label) { prefix.push(`[${label}]`); } if (level === "error") { return red(prefix.join(" ")); } if (level === "warn") { return yellow(prefix.join(" ")); } if (prefix.length === 1) { return dim(prefix[0]); } return dim(prefix[0]) + " " + blue(prefix.splice(1).join(" ")); } class Logger { options; constructor(options) { this.options = options; } info(label, message, newLine = true) { info(this.options, label, message, newLine); } warn(label, message, newLine = true) { warn(this.options, label, message, newLine); } error(label, message, newLine = true) { error(this.options, label, message, newLine); } debug(label, ...messages) { debug(label, ...messages); } level() { return this.options.level; } forkIntegrationLogger(label) { return new AstroIntegrationLogger(this.options, label); } } class AstroIntegrationLogger { options; label; constructor(logging, label) { this.options = logging; this.label = label; } /** * Creates a new logger instance with a new label, but the same log options. */ fork(label) { return new AstroIntegrationLogger(this.options, label); } info(message) { info(this.options, this.label, message); } warn(message) { warn(this.options, this.label, message); } error(message) { error(this.options, this.label, message); } debug(message) { debug(this.label, message); } } const consoleLogDestination = { write(event) { let dest = console.error; if (levels[event.level] < levels["error"]) { dest = console.info; } if (event.label === "SKIP_FORMAT") { dest(event.message); } else { dest(getEventPrefix(event) + " " + event.message); } return true; } }; function getAssetsPrefix(fileExtension, assetsPrefix) { if (!assetsPrefix) return ""; if (typeof assetsPrefix === "string") return assetsPrefix; const dotLessFileExtension = fileExtension.slice(1); if (assetsPrefix[dotLessFileExtension]) { return assetsPrefix[dotLessFileExtension]; } return assetsPrefix.fallback; } function createAssetLink(href, base, assetsPrefix) { if (assetsPrefix) { const pf = getAssetsPrefix(fileExtension(href), assetsPrefix); return joinPaths(pf, slash(href)); } else if (base) { return prependForwardSlash(joinPaths(base, slash(href))); } else { return href; } } function createStylesheetElement(stylesheet, base, assetsPrefix) { if (stylesheet.type === "inline") { return { props: {}, children: stylesheet.content }; } else { return { props: { rel: "stylesheet", href: createAssetLink(stylesheet.src, base, assetsPrefix) }, children: "" }; } } function createStylesheetElementSet(stylesheets, base, assetsPrefix) { return new Set(stylesheets.map((s) => createStylesheetElement(s, base, assetsPrefix))); } function createModuleScriptElement(script, base, assetsPrefix) { if (script.type === "external") { return createModuleScriptElementWithSrc(script.value, base, assetsPrefix); } else { return { props: { type: "module" }, children: script.value }; } } function createModuleScriptElementWithSrc(src, base, assetsPrefix) { return { props: { type: "module", src: createAssetLink(src, base, assetsPrefix) }, children: "" }; } function redirectTemplate({ status, absoluteLocation, relativeLocation, from }) { const delay = status === 302 ? 2 : 0; return ` Redirecting to: ${relativeLocation} Redirecting ${from ? `from ${from} ` : ""}to ${relativeLocation} `; } class AppPipeline extends Pipeline { static create({ logger, manifest, runtimeMode, renderers, resolve, serverLike, streaming, defaultRoutes }) { const pipeline = new AppPipeline( logger, manifest, runtimeMode, renderers, resolve, serverLike, streaming, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, defaultRoutes ); return pipeline; } headElements(routeData) { const routeInfo = this.manifest.routes.find((route) => route.routeData === routeData); const links = /* @__PURE__ */ new Set(); const scripts = /* @__PURE__ */ new Set(); const styles = createStylesheetElementSet(routeInfo?.styles ?? []); for (const script of routeInfo?.scripts ?? []) { if ("stage" in script) { if (script.stage === "head-inline") { scripts.add({ props: {}, children: script.children }); } } else { scripts.add(createModuleScriptElement(script)); } } return { links, styles, scripts }; } componentMetadata() { } async getComponentByRoute(routeData) { const module = await this.getModuleForRoute(routeData); return module.page(); } async tryRewrite(payload, request) { const { newUrl, pathname, routeData } = findRouteToRewrite({ payload, request, routes: this.manifest?.routes.map((r) => r.routeData), trailingSlash: this.manifest.trailingSlash, buildFormat: this.manifest.buildFormat, base: this.manifest.base, outDir: this.serverLike ? this.manifest.buildClientDir : this.manifest.outDir }); const componentInstance = await this.getComponentByRoute(routeData); return { newUrl, pathname, componentInstance, routeData }; } async getModuleForRoute(route) { for (const defaultRoute of this.defaultRoutes) { if (route.component === defaultRoute.component) { return { page: () => Promise.resolve(defaultRoute.instance), renderers: [] }; } } if (route.type === "redirect") { return RedirectSinglePageBuiltModule; } else { if (this.manifest.pageMap) { const importComponentInstance = this.manifest.pageMap.get(route.component); if (!importComponentInstance) { throw new Error( `Unexpectedly unable to find a component instance for route ${route.route}` ); } return await importComponentInstance(); } else if (this.manifest.pageModule) { return this.manifest.pageModule; } throw new Error( "Astro couldn't find the correct page to render, probably because it wasn't correctly mapped for SSR usage. This is an internal error, please file an issue." ); } } } class App { #manifest; #manifestData; #logger = new Logger({ dest: consoleLogDestination, level: "info" }); #baseWithoutTrailingSlash; #pipeline; #adapterLogger; constructor(manifest, streaming = true) { this.#manifest = manifest; this.#manifestData = { routes: manifest.routes.map((route) => route.routeData) }; ensure404Route(this.#manifestData); this.#baseWithoutTrailingSlash = removeTrailingForwardSlash(this.#manifest.base); this.#pipeline = this.#createPipeline(streaming); this.#adapterLogger = new AstroIntegrationLogger( this.#logger.options, this.#manifest.adapterName ); } getAdapterLogger() { return this.#adapterLogger; } getAllowedDomains() { return this.#manifest.allowedDomains; } get manifest() { return this.#manifest; } set manifest(value) { this.#manifest = value; } matchesAllowedDomains(forwardedHost, protocol) { return App.validateForwardedHost(forwardedHost, this.#manifest.allowedDomains, protocol); } static validateForwardedHost(forwardedHost, allowedDomains, protocol) { if (!allowedDomains || allowedDomains.length === 0) { return false; } try { const testUrl = new URL(`${protocol || "https"}://${forwardedHost}`); return allowedDomains.some((pattern) => { return matchPattern(testUrl, pattern); }); } catch { return false; } } /** * Creates a pipeline by reading the stored manifest * * @param streaming * @private */ #createPipeline(streaming = false) { return AppPipeline.create({ logger: this.#logger, manifest: this.#manifest, runtimeMode: "production", renderers: this.#manifest.renderers, defaultRoutes: createDefaultRoutes(this.#manifest), resolve: async (specifier) => { if (!(specifier in this.#manifest.entryModules)) { throw new Error(`Unable to resolve [${specifier}]`); } const bundlePath = this.#manifest.entryModules[specifier]; if (bundlePath.startsWith("data:") || bundlePath.length === 0) { return bundlePath; } else { return createAssetLink(bundlePath, this.#manifest.base, this.#manifest.assetsPrefix); } }, serverLike: true, streaming }); } set setManifestData(newManifestData) { this.#manifestData = newManifestData; } removeBase(pathname) { if (pathname.startsWith(this.#manifest.base)) { return pathname.slice(this.#baseWithoutTrailingSlash.length + 1); } return pathname; } /** * It removes the base from the request URL, prepends it with a forward slash and attempts to decoded it. * * If the decoding fails, it logs the error and return the pathname as is. * @param request * @private */ #getPathnameFromRequest(request) { const url = new URL(request.url); const pathname = prependForwardSlash(this.removeBase(url.pathname)); try { return decodeURI(pathname); } catch (e) { this.getAdapterLogger().error(e.toString()); return pathname; } } /** * Given a `Request`, it returns the `RouteData` that matches its `pathname`. By default, prerendered * routes aren't returned, even if they are matched. * * When `allowPrerenderedRoutes` is `true`, the function returns matched prerendered routes too. * @param request * @param allowPrerenderedRoutes */ match(request, allowPrerenderedRoutes = false) { const url = new URL(request.url); if (this.#manifest.assets.has(url.pathname)) return void 0; let pathname = this.#computePathnameFromDomain(request); if (!pathname) { pathname = prependForwardSlash(this.removeBase(url.pathname)); } let routeData = matchRoute(decodeURI(pathname), this.#manifestData); if (!routeData) return void 0; if (allowPrerenderedRoutes) { return routeData; } else if (routeData.prerender) { return void 0; } return routeData; } #computePathnameFromDomain(request) { let pathname = void 0; const url = new URL(request.url); if (this.#manifest.i18n && (this.#manifest.i18n.strategy === "domains-prefix-always" || this.#manifest.i18n.strategy === "domains-prefix-other-locales" || this.#manifest.i18n.strategy === "domains-prefix-always-no-redirect")) { let forwardedHost = request.headers.get("X-Forwarded-Host"); let protocol = request.headers.get("X-Forwarded-Proto"); if (protocol) { protocol = protocol + ":"; } else { protocol = url.protocol; } if (forwardedHost && !this.matchesAllowedDomains(forwardedHost, protocol?.replace(":", ""))) { forwardedHost = null; } let host = forwardedHost; if (!host) { host = request.headers.get("Host"); } if (host && protocol) { host = host.split(":")[0]; try { let locale; const hostAsUrl = new URL(`${protocol}//${host}`); for (const [domainKey, localeValue] of Object.entries( this.#manifest.i18n.domainLookupTable )) { const domainKeyAsUrl = new URL(domainKey); if (hostAsUrl.host === domainKeyAsUrl.host && hostAsUrl.protocol === domainKeyAsUrl.protocol) { locale = localeValue; break; } } if (locale) { pathname = prependForwardSlash( joinPaths(normalizeTheLocale(locale), this.removeBase(url.pathname)) ); if (url.pathname.endsWith("/")) { pathname = appendForwardSlash(pathname); } } } catch (e) { this.#logger.error( "router", `Astro tried to parse ${protocol}//${host} as an URL, but it threw a parsing error. Check the X-Forwarded-Host and X-Forwarded-Proto headers.` ); this.#logger.error("router", `Error: ${e}`); } } } return pathname; } #redirectTrailingSlash(pathname) { const { trailingSlash } = this.#manifest; if (pathname === "/" || isInternalPath(pathname)) { return pathname; } const path = collapseDuplicateTrailingSlashes(pathname, trailingSlash !== "never"); if (path !== pathname) { return path; } if (trailingSlash === "ignore") { return pathname; } if (trailingSlash === "always" && !hasFileExtension(pathname)) { return appendForwardSlash(pathname); } if (trailingSlash === "never") { return removeTrailingForwardSlash(pathname); } return pathname; } async render(request, renderOptions) { let routeData; let locals; let clientAddress; let addCookieHeader; const url = new URL(request.url); const redirect = this.#redirectTrailingSlash(url.pathname); const prerenderedErrorPageFetch = renderOptions?.prerenderedErrorPageFetch ?? fetch; if (redirect !== url.pathname) { const status = request.method === "GET" ? 301 : 308; return new Response( redirectTemplate({ status, relativeLocation: url.pathname, absoluteLocation: redirect, from: request.url }), { status, headers: { location: redirect + url.search } } ); } addCookieHeader = renderOptions?.addCookieHeader; clientAddress = renderOptions?.clientAddress ?? Reflect.get(request, clientAddressSymbol); routeData = renderOptions?.routeData; locals = renderOptions?.locals; if (routeData) { this.#logger.debug( "router", "The adapter " + this.#manifest.adapterName + " provided a custom RouteData for ", request.url ); this.#logger.debug("router", "RouteData:\n" + routeData); } if (locals) { if (typeof locals !== "object") { const error = new AstroError(LocalsNotAnObject); this.#logger.error(null, error.stack); return this.#renderError(request, { status: 500, error, clientAddress, prerenderedErrorPageFetch }); } } if (!routeData) { routeData = this.match(request); this.#logger.debug("router", "Astro matched the following route for " + request.url); this.#logger.debug("router", "RouteData:\n" + routeData); } if (!routeData) { routeData = this.#manifestData.routes.find( (route) => route.component === "404.astro" || route.component === DEFAULT_404_COMPONENT ); } if (!routeData) { this.#logger.debug("router", "Astro hasn't found routes that match " + request.url); this.#logger.debug("router", "Here's the available routes:\n", this.#manifestData); return this.#renderError(request, { locals, status: 404, clientAddress, prerenderedErrorPageFetch }); } const pathname = this.#getPathnameFromRequest(request); const defaultStatus = this.#getDefaultStatusCode(routeData, pathname); let response; let session; try { const mod = await this.#pipeline.getModuleForRoute(routeData); const renderContext = await RenderContext.create({ pipeline: this.#pipeline, locals, pathname, request, routeData, status: defaultStatus, clientAddress }); session = renderContext.session; response = await renderContext.render(await mod.page()); } catch (err) { this.#logger.error(null, err.stack || err.message || String(err)); return this.#renderError(request, { locals, status: 500, error: err, clientAddress, prerenderedErrorPageFetch }); } finally { await session?.[PERSIST_SYMBOL](); } if (REROUTABLE_STATUS_CODES.includes(response.status) && response.headers.get(REROUTE_DIRECTIVE_HEADER) !== "no") { return this.#renderError(request, { locals, response, status: response.status, // We don't have an error to report here. Passing null means we pass nothing intentionally // while undefined means there's no error error: response.status === 500 ? null : void 0, clientAddress, prerenderedErrorPageFetch }); } if (response.headers.has(REROUTE_DIRECTIVE_HEADER)) { response.headers.delete(REROUTE_DIRECTIVE_HEADER); } if (addCookieHeader) { for (const setCookieHeaderValue of App.getSetCookieFromResponse(response)) { response.headers.append("set-cookie", setCookieHeaderValue); } } Reflect.set(response, responseSentSymbol, true); return response; } setCookieHeaders(response) { return getSetCookiesFromResponse(response); } /** * Reads all the cookies written by `Astro.cookie.set()` onto the passed response. * For example, * ```ts * for (const cookie_ of App.getSetCookieFromResponse(response)) { * const cookie: string = cookie_ * } * ``` * @param response The response to read cookies from. * @returns An iterator that yields key-value pairs as equal-sign-separated strings. */ static getSetCookieFromResponse = getSetCookiesFromResponse; /** * If it is a known error code, try sending the according page (e.g. 404.astro / 500.astro). * This also handles pre-rendered /404 or /500 routes */ async #renderError(request, { locals, status, response: originalResponse, skipMiddleware = false, error, clientAddress, prerenderedErrorPageFetch }) { const errorRoutePath = `/${status}${this.#manifest.trailingSlash === "always" ? "/" : ""}`; const errorRouteData = matchRoute(errorRoutePath, this.#manifestData); const url = new URL(request.url); if (errorRouteData) { if (errorRouteData.prerender) { const maybeDotHtml = errorRouteData.route.endsWith(`/${status}`) ? ".html" : ""; const statusURL = new URL( `${this.#baseWithoutTrailingSlash}/${status}${maybeDotHtml}`, url ); if (statusURL.toString() !== request.url) { const response2 = await prerenderedErrorPageFetch(statusURL.toString()); const override = { status, removeContentEncodingHeaders: true }; return this.#mergeResponses(response2, originalResponse, override); } } const mod = await this.#pipeline.getModuleForRoute(errorRouteData); let session; try { const renderContext = await RenderContext.create({ locals, pipeline: this.#pipeline, middleware: skipMiddleware ? NOOP_MIDDLEWARE_FN : void 0, pathname: this.#getPathnameFromRequest(request), request, routeData: errorRouteData, status, props: { error }, clientAddress }); session = renderContext.session; const response2 = await renderContext.render(await mod.page()); return this.#mergeResponses(response2, originalResponse); } catch { if (skipMiddleware === false) { return this.#renderError(request, { locals, status, response: originalResponse, skipMiddleware: true, clientAddress, prerenderedErrorPageFetch }); } } finally { await session?.[PERSIST_SYMBOL](); } } const response = this.#mergeResponses(new Response(null, { status }), originalResponse); Reflect.set(response, responseSentSymbol, true); return response; } #mergeResponses(newResponse, originalResponse, override) { let newResponseHeaders = newResponse.headers; if (override?.removeContentEncodingHeaders) { newResponseHeaders = new Headers(newResponseHeaders); newResponseHeaders.delete("Content-Encoding"); newResponseHeaders.delete("Content-Length"); } if (!originalResponse) { if (override !== void 0) { return new Response(newResponse.body, { status: override.status, statusText: newResponse.statusText, headers: newResponseHeaders }); } return newResponse; } const status = override?.status ? override.status : originalResponse.status === 200 ? newResponse.status : originalResponse.status; try { originalResponse.headers.delete("Content-type"); } catch { } const mergedHeaders = new Map([ ...Array.from(newResponseHeaders), ...Array.from(originalResponse.headers) ]); const newHeaders = new Headers(); for (const [name, value] of mergedHeaders) { newHeaders.set(name, value); } return new Response(newResponse.body, { status, statusText: status === 200 ? newResponse.statusText : originalResponse.statusText, // If you're looking at here for possible bugs, it means that it's not a bug. // With the middleware, users can meddle with headers, and we should pass to the 404/500. // If users see something weird, it's because they are setting some headers they should not. // // Although, we don't want it to replace the content-type, because the error page must return `text/html` headers: newHeaders }); } #getDefaultStatusCode(routeData, pathname) { if (!routeData.pattern.test(pathname)) { for (const fallbackRoute of routeData.fallbackRoutes) { if (fallbackRoute.pattern.test(pathname)) { return 302; } } } const route = removeTrailingForwardSlash(routeData.route); if (route.endsWith("/404")) return 404; if (route.endsWith("/500")) return 500; return 200; } } async function handle(manifest, app, request, env, context) { const { pathname } = new URL(request.url); const bindingName = "SESSION"; globalThis.__env__ ??= {}; globalThis.__env__[bindingName] = env[bindingName]; if (manifest.assets.has(pathname)) { return env.ASSETS.fetch(request.url.replace(/\.html$/, "")); } const routeData = app.match(request); if (!routeData) { const asset = await env.ASSETS.fetch( request.url.replace(/index.html$/, "").replace(/\.html$/, "") ); if (asset.status !== 404) { return asset; } } Reflect.set(request, Symbol.for("astro.clientAddress"), request.headers.get("cf-connecting-ip")); const locals = { runtime: { env, cf: request.cf, caches, ctx: { waitUntil: (promise) => context.waitUntil(promise), // Currently not available: https://developers.cloudflare.com/pages/platform/known-issues/#pages-functions passThroughOnException: () => { throw new Error( "`passThroughOnException` is currently not available in Cloudflare Pages. See https://developers.cloudflare.com/pages/platform/known-issues/#pages-functions." ); }, props: {} } } }; const response = await app.render( request, { routeData, locals, prerenderedErrorPageFetch: async (url) => { return env.ASSETS.fetch(url.replace(/\.html$/, "")); } } ); if (app.setCookieHeaders) { for (const setCookieHeader of app.setCookieHeaders(response)) { response.headers.append("Set-Cookie", setCookieHeader); } } return response; } function createExports(manifest) { const app = new App(manifest); const fetch = async (request, env, context) => { return await handle(manifest, app, request, env, context); }; return { default: { fetch } }; } const serverEntrypointModule = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({ __proto__: null, createExports }, Symbol.toStringTag, { value: 'Module' })); export { createExports as c, serverEntrypointModule as s };