blank project
This commit is contained in:
2
node_modules/astro/dist/core/app/common.d.ts
generated
vendored
Normal file
2
node_modules/astro/dist/core/app/common.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import type { SerializedSSRManifest, SSRManifest } from './types.js';
|
||||
export declare function deserializeManifest(serializedManifest: SerializedSSRManifest): SSRManifest;
|
||||
37
node_modules/astro/dist/core/app/common.js
generated
vendored
Normal file
37
node_modules/astro/dist/core/app/common.js
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
import { decodeKey } from "../encryption.js";
|
||||
import { NOOP_MIDDLEWARE_FN } from "../middleware/noop-middleware.js";
|
||||
import { deserializeRouteData } from "../routing/manifest/serialization.js";
|
||||
function deserializeManifest(serializedManifest) {
|
||||
const routes = [];
|
||||
for (const serializedRoute of serializedManifest.routes) {
|
||||
routes.push({
|
||||
...serializedRoute,
|
||||
routeData: deserializeRouteData(serializedRoute.routeData)
|
||||
});
|
||||
const route = serializedRoute;
|
||||
route.routeData = deserializeRouteData(serializedRoute.routeData);
|
||||
}
|
||||
const assets = new Set(serializedManifest.assets);
|
||||
const componentMetadata = new Map(serializedManifest.componentMetadata);
|
||||
const inlinedScripts = new Map(serializedManifest.inlinedScripts);
|
||||
const clientDirectives = new Map(serializedManifest.clientDirectives);
|
||||
const serverIslandNameMap = new Map(serializedManifest.serverIslandNameMap);
|
||||
const key = decodeKey(serializedManifest.key);
|
||||
return {
|
||||
// in case user middleware exists, this no-op middleware will be reassigned (see plugin-ssr.ts)
|
||||
middleware() {
|
||||
return { onRequest: NOOP_MIDDLEWARE_FN };
|
||||
},
|
||||
...serializedManifest,
|
||||
assets,
|
||||
componentMetadata,
|
||||
inlinedScripts,
|
||||
clientDirectives,
|
||||
routes,
|
||||
serverIslandNameMap,
|
||||
key
|
||||
};
|
||||
}
|
||||
export {
|
||||
deserializeManifest
|
||||
};
|
||||
9
node_modules/astro/dist/core/app/createOutgoingHttpHeaders.d.ts
generated
vendored
Normal file
9
node_modules/astro/dist/core/app/createOutgoingHttpHeaders.d.ts
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { OutgoingHttpHeaders } from 'node:http';
|
||||
/**
|
||||
* Takes in a nullable WebAPI Headers object and produces a NodeJS OutgoingHttpHeaders object suitable for usage
|
||||
* with ServerResponse.writeHead(..) or ServerResponse.setHeader(..)
|
||||
*
|
||||
* @param headers WebAPI Headers object
|
||||
* @returns {OutgoingHttpHeaders} NodeJS OutgoingHttpHeaders object with multiple set-cookie handled as an array of values
|
||||
*/
|
||||
export declare const createOutgoingHttpHeaders: (headers: Headers | undefined | null) => OutgoingHttpHeaders | undefined;
|
||||
19
node_modules/astro/dist/core/app/createOutgoingHttpHeaders.js
generated
vendored
Normal file
19
node_modules/astro/dist/core/app/createOutgoingHttpHeaders.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
const createOutgoingHttpHeaders = (headers) => {
|
||||
if (!headers) {
|
||||
return void 0;
|
||||
}
|
||||
const nodeHeaders = Object.fromEntries(headers.entries());
|
||||
if (Object.keys(nodeHeaders).length === 0) {
|
||||
return void 0;
|
||||
}
|
||||
if (headers.has("set-cookie")) {
|
||||
const cookieHeaders = headers.getSetCookie();
|
||||
if (cookieHeaders.length > 1) {
|
||||
nodeHeaders["set-cookie"] = cookieHeaders;
|
||||
}
|
||||
}
|
||||
return nodeHeaders;
|
||||
};
|
||||
export {
|
||||
createOutgoingHttpHeaders
|
||||
};
|
||||
99
node_modules/astro/dist/core/app/index.d.ts
generated
vendored
Normal file
99
node_modules/astro/dist/core/app/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
import { type RemotePattern } from '../../assets/utils/remotePattern.js';
|
||||
import type { RoutesList } from '../../types/astro.js';
|
||||
import type { RouteData, SSRManifest } from '../../types/public/internal.js';
|
||||
import { getSetCookiesFromResponse } from '../cookies/index.js';
|
||||
import { AstroIntegrationLogger } from '../logger/core.js';
|
||||
export { deserializeManifest } from './common.js';
|
||||
type ErrorPagePath = `${string}/404` | `${string}/500` | `${string}/404/` | `${string}/500/` | `${string}404.html` | `${string}500.html`;
|
||||
export interface RenderOptions {
|
||||
/**
|
||||
* Whether to automatically add all cookies written by `Astro.cookie.set()` to the response headers.
|
||||
*
|
||||
* When set to `true`, they will be added to the `Set-Cookie` header as comma-separated key=value pairs. You can use the standard `response.headers.getSetCookie()` API to read them individually.
|
||||
*
|
||||
* When set to `false`, the cookies will only be available from `App.getSetCookieFromResponse(response)`.
|
||||
*
|
||||
* @default {false}
|
||||
*/
|
||||
addCookieHeader?: boolean;
|
||||
/**
|
||||
* The client IP address that will be made available as `Astro.clientAddress` in pages, and as `ctx.clientAddress` in API routes and middleware.
|
||||
*
|
||||
* Default: `request[Symbol.for("astro.clientAddress")]`
|
||||
*/
|
||||
clientAddress?: string;
|
||||
/**
|
||||
* The mutable object that will be made available as `Astro.locals` in pages, and as `ctx.locals` in API routes and middleware.
|
||||
*/
|
||||
locals?: object;
|
||||
/**
|
||||
* A custom fetch function for retrieving prerendered pages - 404 or 500.
|
||||
*
|
||||
* If not provided, Astro will fallback to its default behavior for fetching error pages.
|
||||
*
|
||||
* When a dynamic route is matched but ultimately results in a 404, this function will be used
|
||||
* to fetch the prerendered 404 page if available. Similarly, it may be used to fetch a
|
||||
* prerendered 500 error page when necessary.
|
||||
*
|
||||
* @param {ErrorPagePath} url - The URL of the prerendered 404 or 500 error page to fetch.
|
||||
* @returns {Promise<Response>} A promise resolving to the prerendered response.
|
||||
*/
|
||||
prerenderedErrorPageFetch?: (url: ErrorPagePath) => Promise<Response>;
|
||||
/**
|
||||
* **Advanced API**: you probably do not need to use this.
|
||||
*
|
||||
* Default: `app.match(request)`
|
||||
*/
|
||||
routeData?: RouteData;
|
||||
}
|
||||
export interface RenderErrorOptions {
|
||||
locals?: App.Locals;
|
||||
routeData?: RouteData;
|
||||
response?: Response;
|
||||
status: 404 | 500;
|
||||
/**
|
||||
* Whether to skip middleware while rendering the error page. Defaults to false.
|
||||
*/
|
||||
skipMiddleware?: boolean;
|
||||
/**
|
||||
* Allows passing an error to 500.astro. It will be available through `Astro.props.error`.
|
||||
*/
|
||||
error?: unknown;
|
||||
clientAddress: string | undefined;
|
||||
prerenderedErrorPageFetch: (url: ErrorPagePath) => Promise<Response>;
|
||||
}
|
||||
export declare class App {
|
||||
#private;
|
||||
constructor(manifest: SSRManifest, streaming?: boolean);
|
||||
getAdapterLogger(): AstroIntegrationLogger;
|
||||
getAllowedDomains(): Partial<RemotePattern>[] | undefined;
|
||||
protected get manifest(): SSRManifest;
|
||||
protected set manifest(value: SSRManifest);
|
||||
protected matchesAllowedDomains(forwardedHost: string, protocol?: string): boolean;
|
||||
static validateForwardedHost(forwardedHost: string, allowedDomains?: Partial<RemotePattern>[], protocol?: string): boolean;
|
||||
set setManifestData(newManifestData: RoutesList);
|
||||
removeBase(pathname: string): string;
|
||||
/**
|
||||
* 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: Request, allowPrerenderedRoutes?: boolean): RouteData | undefined;
|
||||
render(request: Request, renderOptions?: RenderOptions): Promise<Response>;
|
||||
setCookieHeaders(response: Response): Generator<string, string[], any>;
|
||||
/**
|
||||
* 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: typeof getSetCookiesFromResponse;
|
||||
}
|
||||
494
node_modules/astro/dist/core/app/index.js
generated
vendored
Normal file
494
node_modules/astro/dist/core/app/index.js
generated
vendored
Normal file
@@ -0,0 +1,494 @@
|
||||
import {
|
||||
collapseDuplicateTrailingSlashes,
|
||||
hasFileExtension,
|
||||
isInternalPath
|
||||
} from "@astrojs/internal-helpers/path";
|
||||
import { matchPattern } from "../../assets/utils/remotePattern.js";
|
||||
import { normalizeTheLocale } from "../../i18n/index.js";
|
||||
import {
|
||||
clientAddressSymbol,
|
||||
DEFAULT_404_COMPONENT,
|
||||
REROUTABLE_STATUS_CODES,
|
||||
REROUTE_DIRECTIVE_HEADER,
|
||||
responseSentSymbol
|
||||
} from "../constants.js";
|
||||
import { getSetCookiesFromResponse } from "../cookies/index.js";
|
||||
import { AstroError, AstroErrorData } from "../errors/index.js";
|
||||
import { consoleLogDestination } from "../logger/console.js";
|
||||
import { AstroIntegrationLogger, Logger } from "../logger/core.js";
|
||||
import { NOOP_MIDDLEWARE_FN } from "../middleware/noop-middleware.js";
|
||||
import {
|
||||
appendForwardSlash,
|
||||
joinPaths,
|
||||
prependForwardSlash,
|
||||
removeTrailingForwardSlash
|
||||
} from "../path.js";
|
||||
import { createAssetLink } from "../render/ssr-element.js";
|
||||
import { RenderContext } from "../render-context.js";
|
||||
import { redirectTemplate } from "../routing/3xx.js";
|
||||
import { ensure404Route } from "../routing/astro-designed-error-pages.js";
|
||||
import { createDefaultRoutes } from "../routing/default.js";
|
||||
import { matchRoute } from "../routing/match.js";
|
||||
import { PERSIST_SYMBOL } from "../session.js";
|
||||
import { AppPipeline } from "./pipeline.js";
|
||||
import { deserializeManifest } from "./common.js";
|
||||
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(AstroErrorData.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;
|
||||
}
|
||||
}
|
||||
export {
|
||||
App,
|
||||
deserializeManifest
|
||||
};
|
||||
7
node_modules/astro/dist/core/app/middlewares.d.ts
generated
vendored
Normal file
7
node_modules/astro/dist/core/app/middlewares.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { MiddlewareHandler } from '../../types/public/common.js';
|
||||
/**
|
||||
* Returns a middleware function in charge to check the `origin` header.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
export declare function createOriginCheckMiddleware(): MiddlewareHandler;
|
||||
48
node_modules/astro/dist/core/app/middlewares.js
generated
vendored
Normal file
48
node_modules/astro/dist/core/app/middlewares.js
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
import { defineMiddleware } from "../middleware/index.js";
|
||||
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;
|
||||
}
|
||||
export {
|
||||
createOriginCheckMiddleware
|
||||
};
|
||||
60
node_modules/astro/dist/core/app/node.d.ts
generated
vendored
Normal file
60
node_modules/astro/dist/core/app/node.d.ts
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
import type { IncomingMessage, ServerResponse } from 'node:http';
|
||||
import type { RemotePattern } from '../../types/public/config.js';
|
||||
import type { RouteData } from '../../types/public/internal.js';
|
||||
import type { RenderOptions } from './index.js';
|
||||
import { App } from './index.js';
|
||||
import type { NodeAppHeadersJson, SSRManifest } from './types.js';
|
||||
export { apply as applyPolyfills } from '../polyfill.js';
|
||||
/**
|
||||
* Allow the request body to be explicitly overridden. For example, this
|
||||
* is used by the Express JSON middleware.
|
||||
*/
|
||||
interface NodeRequest extends IncomingMessage {
|
||||
body?: unknown;
|
||||
}
|
||||
export declare class NodeApp extends App {
|
||||
headersMap: NodeAppHeadersJson | undefined;
|
||||
setHeadersMap(headers: NodeAppHeadersJson): void;
|
||||
match(req: NodeRequest | Request, allowPrerenderedRoutes?: boolean): RouteData | undefined;
|
||||
render(request: NodeRequest | Request, options?: RenderOptions): Promise<Response>;
|
||||
/**
|
||||
* @deprecated Instead of passing `RouteData` and locals individually, pass an object with `routeData` and `locals` properties.
|
||||
* See https://github.com/withastro/astro/pull/9199 for more information.
|
||||
*/
|
||||
render(request: NodeRequest | Request, routeData?: RouteData, locals?: object): Promise<Response>;
|
||||
/**
|
||||
* Converts a NodeJS IncomingMessage into a web standard Request.
|
||||
* ```js
|
||||
* import { NodeApp } from 'astro/app/node';
|
||||
* import { createServer } from 'node:http';
|
||||
*
|
||||
* const server = createServer(async (req, res) => {
|
||||
* const request = NodeApp.createRequest(req);
|
||||
* const response = await app.render(request);
|
||||
* await NodeApp.writeResponse(response, res);
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
static createRequest(req: NodeRequest, { skipBody, allowedDomains, }?: {
|
||||
skipBody?: boolean;
|
||||
allowedDomains?: Partial<RemotePattern>[];
|
||||
}): Request;
|
||||
/**
|
||||
* Streams a web-standard Response into a NodeJS Server Response.
|
||||
* ```js
|
||||
* import { NodeApp } from 'astro/app/node';
|
||||
* import { createServer } from 'node:http';
|
||||
*
|
||||
* const server = createServer(async (req, res) => {
|
||||
* const request = NodeApp.createRequest(req);
|
||||
* const response = await app.render(request);
|
||||
* await NodeApp.writeResponse(response, res);
|
||||
* })
|
||||
* ```
|
||||
* @param source WhatWG Response
|
||||
* @param destination NodeJS ServerResponse
|
||||
*/
|
||||
static writeResponse(source: Response, destination: ServerResponse): Promise<ServerResponse<IncomingMessage> | undefined>;
|
||||
}
|
||||
export declare function loadManifest(rootFolder: URL): Promise<SSRManifest>;
|
||||
export declare function loadApp(rootFolder: URL): Promise<NodeApp>;
|
||||
264
node_modules/astro/dist/core/app/node.js
generated
vendored
Normal file
264
node_modules/astro/dist/core/app/node.js
generated
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
import fs from "node:fs";
|
||||
import { Http2ServerResponse } from "node:http2";
|
||||
import { clientAddressSymbol, nodeRequestAbortControllerCleanupSymbol } from "../constants.js";
|
||||
import { deserializeManifest } from "./common.js";
|
||||
import { createOutgoingHttpHeaders } from "./createOutgoingHttpHeaders.js";
|
||||
import { App } from "./index.js";
|
||||
import { apply } from "../polyfill.js";
|
||||
class NodeApp extends App {
|
||||
headersMap = void 0;
|
||||
setHeadersMap(headers) {
|
||||
this.headersMap = headers;
|
||||
}
|
||||
match(req, allowPrerenderedRoutes = false) {
|
||||
if (!(req instanceof Request)) {
|
||||
req = NodeApp.createRequest(req, {
|
||||
skipBody: true,
|
||||
allowedDomains: this.manifest.allowedDomains
|
||||
});
|
||||
}
|
||||
return super.match(req, allowPrerenderedRoutes);
|
||||
}
|
||||
render(req, routeDataOrOptions, maybeLocals) {
|
||||
if (!(req instanceof Request)) {
|
||||
req = NodeApp.createRequest(req, {
|
||||
allowedDomains: this.manifest.allowedDomains
|
||||
});
|
||||
}
|
||||
return super.render(req, routeDataOrOptions, maybeLocals);
|
||||
}
|
||||
/**
|
||||
* Converts a NodeJS IncomingMessage into a web standard Request.
|
||||
* ```js
|
||||
* import { NodeApp } from 'astro/app/node';
|
||||
* import { createServer } from 'node:http';
|
||||
*
|
||||
* const server = createServer(async (req, res) => {
|
||||
* const request = NodeApp.createRequest(req);
|
||||
* const response = await app.render(request);
|
||||
* await NodeApp.writeResponse(response, res);
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
static createRequest(req, {
|
||||
skipBody = false,
|
||||
allowedDomains = []
|
||||
} = {}) {
|
||||
const controller = new AbortController();
|
||||
const isEncrypted = "encrypted" in req.socket && req.socket.encrypted;
|
||||
const getFirstForwardedValue = (multiValueHeader) => {
|
||||
return multiValueHeader?.toString()?.split(",").map((e) => e.trim())?.[0];
|
||||
};
|
||||
const forwardedProtocol = getFirstForwardedValue(req.headers["x-forwarded-proto"]);
|
||||
const providedProtocol = isEncrypted ? "https" : "http";
|
||||
const protocol = forwardedProtocol ?? providedProtocol;
|
||||
let forwardedHostname = getFirstForwardedValue(req.headers["x-forwarded-host"]);
|
||||
const providedHostname = req.headers.host ?? req.headers[":authority"];
|
||||
if (forwardedHostname && !App.validateForwardedHost(
|
||||
forwardedHostname,
|
||||
allowedDomains,
|
||||
forwardedProtocol ?? providedProtocol
|
||||
)) {
|
||||
forwardedHostname = void 0;
|
||||
}
|
||||
const hostname = forwardedHostname ?? providedHostname;
|
||||
const port = getFirstForwardedValue(req.headers["x-forwarded-port"]);
|
||||
let url;
|
||||
try {
|
||||
const hostnamePort = getHostnamePort(hostname, port);
|
||||
url = new URL(`${protocol}://${hostnamePort}${req.url}`);
|
||||
} catch {
|
||||
const hostnamePort = getHostnamePort(providedHostname, port);
|
||||
url = new URL(`${providedProtocol}://${hostnamePort}`);
|
||||
}
|
||||
const options = {
|
||||
method: req.method || "GET",
|
||||
headers: makeRequestHeaders(req),
|
||||
signal: controller.signal
|
||||
};
|
||||
const bodyAllowed = options.method !== "HEAD" && options.method !== "GET" && skipBody === false;
|
||||
if (bodyAllowed) {
|
||||
Object.assign(options, makeRequestBody(req));
|
||||
}
|
||||
const request = new Request(url, options);
|
||||
const socket = getRequestSocket(req);
|
||||
if (socket && typeof socket.on === "function") {
|
||||
const existingCleanup = getAbortControllerCleanup(req);
|
||||
if (existingCleanup) {
|
||||
existingCleanup();
|
||||
}
|
||||
let cleanedUp = false;
|
||||
const removeSocketListener = () => {
|
||||
if (typeof socket.off === "function") {
|
||||
socket.off("close", onSocketClose);
|
||||
} else if (typeof socket.removeListener === "function") {
|
||||
socket.removeListener("close", onSocketClose);
|
||||
}
|
||||
};
|
||||
const cleanup = () => {
|
||||
if (cleanedUp) return;
|
||||
cleanedUp = true;
|
||||
removeSocketListener();
|
||||
controller.signal.removeEventListener("abort", cleanup);
|
||||
Reflect.deleteProperty(req, nodeRequestAbortControllerCleanupSymbol);
|
||||
};
|
||||
const onSocketClose = () => {
|
||||
cleanup();
|
||||
if (!controller.signal.aborted) {
|
||||
controller.abort();
|
||||
}
|
||||
};
|
||||
socket.on("close", onSocketClose);
|
||||
controller.signal.addEventListener("abort", cleanup, { once: true });
|
||||
Reflect.set(req, nodeRequestAbortControllerCleanupSymbol, cleanup);
|
||||
if (socket.destroyed) {
|
||||
onSocketClose();
|
||||
}
|
||||
}
|
||||
const forwardedClientIp = getFirstForwardedValue(req.headers["x-forwarded-for"]);
|
||||
const clientIp = forwardedClientIp || req.socket?.remoteAddress;
|
||||
if (clientIp) {
|
||||
Reflect.set(request, clientAddressSymbol, clientIp);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
/**
|
||||
* Streams a web-standard Response into a NodeJS Server Response.
|
||||
* ```js
|
||||
* import { NodeApp } from 'astro/app/node';
|
||||
* import { createServer } from 'node:http';
|
||||
*
|
||||
* const server = createServer(async (req, res) => {
|
||||
* const request = NodeApp.createRequest(req);
|
||||
* const response = await app.render(request);
|
||||
* await NodeApp.writeResponse(response, res);
|
||||
* })
|
||||
* ```
|
||||
* @param source WhatWG Response
|
||||
* @param destination NodeJS ServerResponse
|
||||
*/
|
||||
static async writeResponse(source, destination) {
|
||||
const { status, headers, body, statusText } = source;
|
||||
if (!(destination instanceof Http2ServerResponse)) {
|
||||
destination.statusMessage = statusText;
|
||||
}
|
||||
destination.writeHead(status, createOutgoingHttpHeaders(headers));
|
||||
const cleanupAbortFromDestination = getAbortControllerCleanup(
|
||||
destination.req ?? void 0
|
||||
);
|
||||
if (cleanupAbortFromDestination) {
|
||||
const runCleanup = () => {
|
||||
cleanupAbortFromDestination();
|
||||
if (typeof destination.off === "function") {
|
||||
destination.off("finish", runCleanup);
|
||||
destination.off("close", runCleanup);
|
||||
} else {
|
||||
destination.removeListener?.("finish", runCleanup);
|
||||
destination.removeListener?.("close", runCleanup);
|
||||
}
|
||||
};
|
||||
destination.on("finish", runCleanup);
|
||||
destination.on("close", runCleanup);
|
||||
}
|
||||
if (!body) return destination.end();
|
||||
try {
|
||||
const reader = body.getReader();
|
||||
destination.on("close", () => {
|
||||
reader.cancel().catch((err) => {
|
||||
console.error(
|
||||
`There was an uncaught error in the middle of the stream while rendering ${destination.req.url}.`,
|
||||
err
|
||||
);
|
||||
});
|
||||
});
|
||||
let result = await reader.read();
|
||||
while (!result.done) {
|
||||
destination.write(result.value);
|
||||
result = await reader.read();
|
||||
}
|
||||
destination.end();
|
||||
} catch (err) {
|
||||
destination.write("Internal server error", () => {
|
||||
err instanceof Error ? destination.destroy(err) : destination.destroy();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
function getHostnamePort(hostname, port) {
|
||||
const portInHostname = typeof hostname === "string" && /:\d+$/.test(hostname);
|
||||
const hostnamePort = portInHostname ? hostname : `${hostname}${port ? `:${port}` : ""}`;
|
||||
return hostnamePort;
|
||||
}
|
||||
function makeRequestHeaders(req) {
|
||||
const headers = new Headers();
|
||||
for (const [name, value] of Object.entries(req.headers)) {
|
||||
if (value === void 0) {
|
||||
continue;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
for (const item of value) {
|
||||
headers.append(name, item);
|
||||
}
|
||||
} else {
|
||||
headers.append(name, value);
|
||||
}
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
function makeRequestBody(req) {
|
||||
if (req.body !== void 0) {
|
||||
if (typeof req.body === "string" && req.body.length > 0) {
|
||||
return { body: Buffer.from(req.body) };
|
||||
}
|
||||
if (typeof req.body === "object" && req.body !== null && Object.keys(req.body).length > 0) {
|
||||
return { body: Buffer.from(JSON.stringify(req.body)) };
|
||||
}
|
||||
if (typeof req.body === "object" && req.body !== null && typeof req.body[Symbol.asyncIterator] !== "undefined") {
|
||||
return asyncIterableToBodyProps(req.body);
|
||||
}
|
||||
}
|
||||
return asyncIterableToBodyProps(req);
|
||||
}
|
||||
function asyncIterableToBodyProps(iterable) {
|
||||
return {
|
||||
// Node uses undici for the Request implementation. Undici accepts
|
||||
// a non-standard async iterable for the body.
|
||||
// @ts-expect-error
|
||||
body: iterable,
|
||||
// The duplex property is required when using a ReadableStream or async
|
||||
// iterable for the body. The type definitions do not include the duplex
|
||||
// property because they are not up-to-date.
|
||||
duplex: "half"
|
||||
};
|
||||
}
|
||||
function getAbortControllerCleanup(req) {
|
||||
if (!req) return void 0;
|
||||
const cleanup = Reflect.get(req, nodeRequestAbortControllerCleanupSymbol);
|
||||
return typeof cleanup === "function" ? cleanup : void 0;
|
||||
}
|
||||
function getRequestSocket(req) {
|
||||
if (req.socket && typeof req.socket.on === "function") {
|
||||
return req.socket;
|
||||
}
|
||||
const http2Socket = req.stream?.session?.socket;
|
||||
if (http2Socket && typeof http2Socket.on === "function") {
|
||||
return http2Socket;
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
async function loadManifest(rootFolder) {
|
||||
const manifestFile = new URL("./manifest.json", rootFolder);
|
||||
const rawManifest = await fs.promises.readFile(manifestFile, "utf-8");
|
||||
const serializedManifest = JSON.parse(rawManifest);
|
||||
return deserializeManifest(serializedManifest);
|
||||
}
|
||||
async function loadApp(rootFolder) {
|
||||
const manifest = await loadManifest(rootFolder);
|
||||
return new NodeApp(manifest);
|
||||
}
|
||||
export {
|
||||
NodeApp,
|
||||
apply as applyPolyfills,
|
||||
loadApp,
|
||||
loadManifest
|
||||
};
|
||||
13
node_modules/astro/dist/core/app/pipeline.d.ts
generated
vendored
Normal file
13
node_modules/astro/dist/core/app/pipeline.d.ts
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { ComponentInstance } from '../../types/astro.js';
|
||||
import type { RewritePayload } from '../../types/public/common.js';
|
||||
import type { RouteData, SSRResult } from '../../types/public/internal.js';
|
||||
import { Pipeline, type TryRewriteResult } from '../base-pipeline.js';
|
||||
import type { SinglePageBuiltModule } from '../build/types.js';
|
||||
export declare class AppPipeline extends Pipeline {
|
||||
static create({ logger, manifest, runtimeMode, renderers, resolve, serverLike, streaming, defaultRoutes, }: Pick<AppPipeline, 'logger' | 'manifest' | 'runtimeMode' | 'renderers' | 'resolve' | 'serverLike' | 'streaming' | 'defaultRoutes'>): AppPipeline;
|
||||
headElements(routeData: RouteData): Pick<SSRResult, 'scripts' | 'styles' | 'links'>;
|
||||
componentMetadata(): void;
|
||||
getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
|
||||
tryRewrite(payload: RewritePayload, request: Request): Promise<TryRewriteResult>;
|
||||
getModuleForRoute(route: RouteData): Promise<SinglePageBuiltModule>;
|
||||
}
|
||||
105
node_modules/astro/dist/core/app/pipeline.js
generated
vendored
Normal file
105
node_modules/astro/dist/core/app/pipeline.js
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
import { Pipeline } from "../base-pipeline.js";
|
||||
import { RedirectSinglePageBuiltModule } from "../redirects/component.js";
|
||||
import { createModuleScriptElement, createStylesheetElementSet } from "../render/ssr-element.js";
|
||||
import { findRouteToRewrite } from "../routing/rewrite.js";
|
||||
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."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
export {
|
||||
AppPipeline
|
||||
};
|
||||
121
node_modules/astro/dist/core/app/types.d.ts
generated
vendored
Normal file
121
node_modules/astro/dist/core/app/types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
import type { ZodType } from 'zod';
|
||||
import type { ActionAccept, ActionClient } from '../../actions/runtime/server.js';
|
||||
import type { RoutingStrategies } from '../../i18n/utils.js';
|
||||
import type { ComponentInstance, SerializedRouteData } from '../../types/astro.js';
|
||||
import type { AstroMiddlewareInstance } from '../../types/public/common.js';
|
||||
import type { AstroConfig, CspAlgorithm, Locales, RemotePattern, ResolvedSessionConfig } from '../../types/public/config.js';
|
||||
import type { RouteData, SSRComponentMetadata, SSRLoadedRenderer, SSRResult } from '../../types/public/internal.js';
|
||||
import type { SinglePageBuiltModule } from '../build/types.js';
|
||||
import type { CspDirective } from '../csp/config.js';
|
||||
type ComponentPath = string;
|
||||
export type StylesheetAsset = {
|
||||
type: 'inline';
|
||||
content: string;
|
||||
} | {
|
||||
type: 'external';
|
||||
src: string;
|
||||
};
|
||||
export interface RouteInfo {
|
||||
routeData: RouteData;
|
||||
file: string;
|
||||
links: string[];
|
||||
scripts: ({
|
||||
children: string;
|
||||
stage: string;
|
||||
} | {
|
||||
type: 'inline' | 'external';
|
||||
value: string;
|
||||
})[];
|
||||
styles: StylesheetAsset[];
|
||||
}
|
||||
export type SerializedRouteInfo = Omit<RouteInfo, 'routeData'> & {
|
||||
routeData: SerializedRouteData;
|
||||
};
|
||||
type ImportComponentInstance = () => Promise<SinglePageBuiltModule>;
|
||||
export type AssetsPrefix = string | ({
|
||||
fallback: string;
|
||||
} & Record<string, string>) | undefined;
|
||||
export type SSRManifest = {
|
||||
hrefRoot: string;
|
||||
adapterName: string;
|
||||
routes: RouteInfo[];
|
||||
site?: string;
|
||||
base: string;
|
||||
/**
|
||||
* The base of the assets generated **by the user**. For example, scripts created by the user falls under this category.
|
||||
*
|
||||
* The value of this field comes from `vite.base`. We aren't usually this tight to vite in our code base, so probably
|
||||
* this should be refactored somehow.
|
||||
*/
|
||||
userAssetsBase: string | undefined;
|
||||
trailingSlash: AstroConfig['trailingSlash'];
|
||||
buildFormat: NonNullable<AstroConfig['build']>['format'];
|
||||
compressHTML: boolean;
|
||||
assetsPrefix?: AssetsPrefix;
|
||||
renderers: SSRLoadedRenderer[];
|
||||
/**
|
||||
* Map of directive name (e.g. `load`) to the directive script code
|
||||
*/
|
||||
clientDirectives: Map<string, string>;
|
||||
entryModules: Record<string, string>;
|
||||
inlinedScripts: Map<string, string>;
|
||||
assets: Set<string>;
|
||||
componentMetadata: SSRResult['componentMetadata'];
|
||||
pageModule?: SinglePageBuiltModule;
|
||||
pageMap?: Map<ComponentPath, ImportComponentInstance>;
|
||||
serverIslandMap?: Map<string, () => Promise<ComponentInstance>>;
|
||||
serverIslandNameMap?: Map<string, string>;
|
||||
key: Promise<CryptoKey>;
|
||||
i18n: SSRManifestI18n | undefined;
|
||||
middleware?: () => Promise<AstroMiddlewareInstance> | AstroMiddlewareInstance;
|
||||
actions?: () => Promise<SSRActions> | SSRActions;
|
||||
checkOrigin: boolean;
|
||||
allowedDomains?: Partial<RemotePattern>[];
|
||||
sessionConfig?: ResolvedSessionConfig<any>;
|
||||
cacheDir: string | URL;
|
||||
srcDir: string | URL;
|
||||
outDir: string | URL;
|
||||
publicDir: string | URL;
|
||||
buildClientDir: string | URL;
|
||||
buildServerDir: string | URL;
|
||||
csp: SSRManifestCSP | undefined;
|
||||
};
|
||||
export type SSRActions = {
|
||||
server: Record<string, ActionClient<unknown, ActionAccept, ZodType>>;
|
||||
};
|
||||
export type SSRManifestI18n = {
|
||||
fallback: Record<string, string> | undefined;
|
||||
fallbackType: 'redirect' | 'rewrite';
|
||||
strategy: RoutingStrategies;
|
||||
locales: Locales;
|
||||
defaultLocale: string;
|
||||
domainLookupTable: Record<string, string>;
|
||||
};
|
||||
export type SSRManifestCSP = {
|
||||
cspDestination: 'adapter' | 'meta' | 'header' | undefined;
|
||||
algorithm: CspAlgorithm;
|
||||
scriptHashes: string[];
|
||||
scriptResources: string[];
|
||||
isStrictDynamic: boolean;
|
||||
styleHashes: string[];
|
||||
styleResources: string[];
|
||||
directives: CspDirective[];
|
||||
};
|
||||
/** Public type exposed through the `astro:build:ssr` integration hook */
|
||||
export type SerializedSSRManifest = Omit<SSRManifest, 'middleware' | 'routes' | 'assets' | 'componentMetadata' | 'inlinedScripts' | 'clientDirectives' | 'serverIslandNameMap' | 'key'> & {
|
||||
routes: SerializedRouteInfo[];
|
||||
assets: string[];
|
||||
componentMetadata: [string, SSRComponentMetadata][];
|
||||
inlinedScripts: [string, string][];
|
||||
clientDirectives: [string, string][];
|
||||
serverIslandNameMap: [string, string][];
|
||||
key: string;
|
||||
};
|
||||
export type NodeAppHeadersJson = {
|
||||
pathname: string;
|
||||
headers: {
|
||||
key: string;
|
||||
value: string;
|
||||
}[];
|
||||
}[];
|
||||
export {};
|
||||
0
node_modules/astro/dist/core/app/types.js
generated
vendored
Normal file
0
node_modules/astro/dist/core/app/types.js
generated
vendored
Normal file
Reference in New Issue
Block a user