feat: scaffold Astro + Tailwind project
This commit is contained in:
7
node_modules/astro/dist/core/app/app.d.ts
generated
vendored
Normal file
7
node_modules/astro/dist/core/app/app.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import { BaseApp, type LogRequestPayload } from './base.js';
|
||||
import { AppPipeline } from './pipeline.js';
|
||||
export declare class App extends BaseApp {
|
||||
createPipeline(streaming: boolean): AppPipeline;
|
||||
isDev(): boolean;
|
||||
logRequest(_options: LogRequestPayload): void;
|
||||
}
|
||||
19
node_modules/astro/dist/core/app/app.js
generated
vendored
Normal file
19
node_modules/astro/dist/core/app/app.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import { BaseApp } from "./base.js";
|
||||
import { AppPipeline } from "./pipeline.js";
|
||||
class App extends BaseApp {
|
||||
createPipeline(streaming) {
|
||||
return AppPipeline.create({
|
||||
manifest: this.manifest,
|
||||
streaming
|
||||
});
|
||||
}
|
||||
isDev() {
|
||||
return false;
|
||||
}
|
||||
// Should we log something for our users?
|
||||
logRequest(_options) {
|
||||
}
|
||||
}
|
||||
export {
|
||||
App
|
||||
};
|
||||
212
node_modules/astro/dist/core/app/base.d.ts
generated
vendored
Normal file
212
node_modules/astro/dist/core/app/base.d.ts
generated
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
import type { RoutesList } from '../../types/astro.js';
|
||||
import type { RemotePattern, RouteData } from '../../types/public/index.js';
|
||||
import { type Pipeline } from '../base-pipeline.js';
|
||||
import { getSetCookiesFromResponse } from '../cookies/index.js';
|
||||
import { AstroIntegrationLogger, type AstroLogger } from '../logger/core.js';
|
||||
import type { FetchHandler } from '../fetch/types.js';
|
||||
import type { ErrorHandler } from '../errors/handler.js';
|
||||
import type { WaitUntilHook } from '../wait-until.js';
|
||||
import type { AppPipeline } from './pipeline.js';
|
||||
import type { SSRManifest } from './types.js';
|
||||
export interface DevMatch {
|
||||
routeData: RouteData;
|
||||
resolvedPathname: string;
|
||||
}
|
||||
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 fall back 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>;
|
||||
/**
|
||||
* Optional platform hook to keep background work alive after the response is sent.
|
||||
*
|
||||
* Adapters can pass this through so runtime cache providers can schedule cache writes
|
||||
* without blocking the response path.
|
||||
*/
|
||||
waitUntil?: WaitUntilHook;
|
||||
/**
|
||||
* **Advanced API**: you probably do not need to use this.
|
||||
*
|
||||
* Default: `app.match(request)`
|
||||
*/
|
||||
routeData?: RouteData;
|
||||
}
|
||||
type RequiredRenderOptions = Required<RenderOptions>;
|
||||
export interface ResolvedRenderOptions {
|
||||
addCookieHeader: RequiredRenderOptions['addCookieHeader'];
|
||||
clientAddress: RequiredRenderOptions['clientAddress'] | undefined;
|
||||
prerenderedErrorPageFetch: RequiredRenderOptions['prerenderedErrorPageFetch'] | undefined;
|
||||
locals: RequiredRenderOptions['locals'] | undefined;
|
||||
routeData: RequiredRenderOptions['routeData'] | undefined;
|
||||
waitUntil: RequiredRenderOptions['waitUntil'] | undefined;
|
||||
}
|
||||
export interface RenderErrorOptions extends ResolvedRenderOptions {
|
||||
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;
|
||||
/**
|
||||
* The pathname to use for the error page render context. If omitted, the
|
||||
* error handler computes it from `request` via a short-lived `FetchState`.
|
||||
*/
|
||||
pathname?: string;
|
||||
}
|
||||
type ErrorPagePath = `${string}/404` | `${string}/500` | `${string}/404/` | `${string}/500/` | `${string}404.html` | `${string}500.html`;
|
||||
export declare abstract class BaseApp<P extends Pipeline = AppPipeline> {
|
||||
#private;
|
||||
manifest: SSRManifest;
|
||||
manifestData: {
|
||||
routes: RouteData[];
|
||||
};
|
||||
pipeline: P;
|
||||
baseWithoutTrailingSlash: string;
|
||||
get logger(): AstroLogger;
|
||||
get adapterLogger(): AstroIntegrationLogger;
|
||||
constructor(manifest: SSRManifest, streaming?: boolean, ...args: any[]);
|
||||
/**
|
||||
* Override the fetch handler used to dispatch requests. Entrypoints
|
||||
* call this with the default export of `virtual:astro:fetchable` to
|
||||
* plug in a user-authored handler from `src/app.ts`.
|
||||
*/
|
||||
setFetchHandler(handler: {
|
||||
fetch: FetchHandler;
|
||||
}): void;
|
||||
/**
|
||||
* Returns the error handler strategy used by this app. Override to
|
||||
* provide environment-specific behavior (dev overlay, build-time throws, etc.).
|
||||
*/
|
||||
protected createErrorHandler(): ErrorHandler;
|
||||
abstract isDev(): boolean;
|
||||
/**
|
||||
* Resets the cached adapter logger so it picks up a new logger instance.
|
||||
* Used by BuildApp when the logger is replaced via setOptions().
|
||||
*/
|
||||
protected resetAdapterLogger(): void;
|
||||
getAllowedDomains(): Partial<RemotePattern>[] | undefined;
|
||||
protected matchesAllowedDomains(forwardedHost: string, protocol?: string): boolean;
|
||||
static validateForwardedHost(forwardedHost: string, allowedDomains?: Partial<RemotePattern>[], protocol?: string): boolean;
|
||||
/**
|
||||
* Creates a pipeline by reading the stored manifest
|
||||
*
|
||||
* @param streaming
|
||||
* @param manifest
|
||||
* @param args
|
||||
* @private
|
||||
*/
|
||||
abstract createPipeline(streaming: boolean, manifest: SSRManifest, ...args: any[]): P;
|
||||
set setManifestData(newManifestData: RoutesList);
|
||||
removeBase(pathname: string): string;
|
||||
/**
|
||||
* Extracts the base-stripped, decoded pathname from a request.
|
||||
* Used by adapters to compute the pathname for dev-mode route matching.
|
||||
*/
|
||||
getPathnameFromRequest(request: Request): 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;
|
||||
/**
|
||||
* A matching route function to use in the development server.
|
||||
* Contrary to the `.match` function, this function resolves props and params, returning the correct
|
||||
* route based on the priority, segments. It also returns the correct, resolved pathname.
|
||||
* @param pathname
|
||||
*/
|
||||
devMatch(pathname?: string): Promise<DevMatch | undefined> | undefined;
|
||||
private computePathnameFromDomain;
|
||||
render(request: Request, { addCookieHeader, clientAddress, locals, prerenderedErrorPageFetch, routeData, waitUntil, }?: 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;
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* Delegates to the app's configured `ErrorHandler`. To customize behavior
|
||||
* for a specific environment, override `createErrorHandler()` rather than
|
||||
* this method.
|
||||
*/
|
||||
renderError(request: Request, options: RenderErrorOptions): Promise<Response>;
|
||||
getDefaultStatusCode(routeData: RouteData, pathname: string): number;
|
||||
getManifest(): SSRManifest;
|
||||
logThisRequest({ pathname, method, statusCode, isRewrite, timeStart, }: {
|
||||
pathname: string;
|
||||
method: string;
|
||||
statusCode: number;
|
||||
isRewrite: boolean;
|
||||
timeStart: number;
|
||||
}): void;
|
||||
abstract logRequest(_options: LogRequestPayload): void;
|
||||
}
|
||||
export type LogRequestPayload = {
|
||||
/**
|
||||
* The current path being rendered
|
||||
*/
|
||||
pathname: string;
|
||||
/**
|
||||
* The method of the request
|
||||
*/
|
||||
method: string;
|
||||
/**
|
||||
* The status code of the request
|
||||
*/
|
||||
statusCode: number;
|
||||
/**
|
||||
* If the current request is a rewrite
|
||||
*/
|
||||
isRewrite: boolean;
|
||||
/**
|
||||
* How long it took to render the request
|
||||
*/
|
||||
reqTime: number;
|
||||
};
|
||||
export {};
|
||||
391
node_modules/astro/dist/core/app/base.js
generated
vendored
Normal file
391
node_modules/astro/dist/core/app/base.js
generated
vendored
Normal file
@@ -0,0 +1,391 @@
|
||||
import {
|
||||
appendForwardSlash,
|
||||
collapseDuplicateLeadingSlashes,
|
||||
joinPaths,
|
||||
prependForwardSlash,
|
||||
removeTrailingForwardSlash
|
||||
} from "@astrojs/internal-helpers/path";
|
||||
import { matchPattern } from "@astrojs/internal-helpers/remote";
|
||||
import { normalizeTheLocale } from "../../i18n/index.js";
|
||||
import { PipelineFeatures } from "../base-pipeline.js";
|
||||
import { ASTRO_ERROR_HEADER, clientAddressSymbol } from "../constants.js";
|
||||
import { getSetCookiesFromResponse } from "../cookies/index.js";
|
||||
import { AstroError, AstroErrorData } from "../errors/index.js";
|
||||
import { AstroIntegrationLogger } from "../logger/core.js";
|
||||
import { DefaultFetchHandler } from "../fetch/default-handler.js";
|
||||
import { appSymbol } from "../constants.js";
|
||||
import { DefaultErrorHandler } from "../errors/default-handler.js";
|
||||
import { setRenderOptions } from "./render-options.js";
|
||||
class BaseApp {
|
||||
manifest;
|
||||
manifestData;
|
||||
pipeline;
|
||||
#adapterLogger;
|
||||
baseWithoutTrailingSlash;
|
||||
/**
|
||||
* The handler that turns incoming `Request` objects into `Response`s.
|
||||
* Defaults to a `DefaultFetchHandler` pinned to this app and can be
|
||||
* overridden via `setFetchHandler` — typically by the bundled
|
||||
* entrypoint after importing `virtual:astro:fetchable`.
|
||||
*/
|
||||
#fetchHandler;
|
||||
#errorHandler;
|
||||
/**
|
||||
* Whether a custom fetch handler (from `src/app.ts`) has been set
|
||||
* via `setFetchHandler`. When false, the `DefaultFetchHandler` is
|
||||
* in use and all features are implicitly active.
|
||||
*/
|
||||
#hasCustomFetchHandler = false;
|
||||
/**
|
||||
* Whether the missing-feature check has already run. We only want
|
||||
* to warn once — after the first request in dev, or at build end.
|
||||
*/
|
||||
#featureCheckDone = false;
|
||||
get logger() {
|
||||
return this.pipeline.logger;
|
||||
}
|
||||
get adapterLogger() {
|
||||
if (!this.#adapterLogger) {
|
||||
this.#adapterLogger = new AstroIntegrationLogger(
|
||||
this.logger.options,
|
||||
this.manifest.adapterName
|
||||
);
|
||||
}
|
||||
return this.#adapterLogger;
|
||||
}
|
||||
constructor(manifest, streaming = true, ...args) {
|
||||
this.manifest = manifest;
|
||||
this.baseWithoutTrailingSlash = removeTrailingForwardSlash(manifest.base);
|
||||
this.pipeline = this.createPipeline(streaming, manifest, ...args);
|
||||
this.manifestData = this.pipeline.manifestData;
|
||||
this.#fetchHandler = new DefaultFetchHandler(this);
|
||||
this.#errorHandler = this.createErrorHandler();
|
||||
}
|
||||
/**
|
||||
* Override the fetch handler used to dispatch requests. Entrypoints
|
||||
* call this with the default export of `virtual:astro:fetchable` to
|
||||
* plug in a user-authored handler from `src/app.ts`.
|
||||
*/
|
||||
setFetchHandler(handler) {
|
||||
this.#fetchHandler = handler;
|
||||
this.#hasCustomFetchHandler = !(handler instanceof DefaultFetchHandler);
|
||||
}
|
||||
/**
|
||||
* Returns the error handler strategy used by this app. Override to
|
||||
* provide environment-specific behavior (dev overlay, build-time throws, etc.).
|
||||
*/
|
||||
createErrorHandler() {
|
||||
return new DefaultErrorHandler(this);
|
||||
}
|
||||
/**
|
||||
* Resets the cached adapter logger so it picks up a new logger instance.
|
||||
* Used by BuildApp when the logger is replaced via setOptions().
|
||||
*/
|
||||
resetAdapterLogger() {
|
||||
this.#adapterLogger = void 0;
|
||||
}
|
||||
getAllowedDomains() {
|
||||
return this.manifest.allowedDomains;
|
||||
}
|
||||
matchesAllowedDomains(forwardedHost, protocol) {
|
||||
return BaseApp.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;
|
||||
}
|
||||
}
|
||||
set setManifestData(newManifestData) {
|
||||
this.manifestData = newManifestData;
|
||||
this.pipeline.manifestData = newManifestData;
|
||||
this.pipeline.rebuildRouter();
|
||||
}
|
||||
removeBase(pathname) {
|
||||
pathname = collapseDuplicateLeadingSlashes(pathname);
|
||||
if (pathname.startsWith(this.manifest.base)) {
|
||||
return pathname.slice(this.baseWithoutTrailingSlash.length + 1);
|
||||
}
|
||||
return pathname;
|
||||
}
|
||||
/**
|
||||
* Extracts the base-stripped, decoded pathname from a request.
|
||||
* Used by adapters to compute the pathname for dev-mode route matching.
|
||||
*/
|
||||
getPathnameFromRequest(request) {
|
||||
const url = new URL(request.url);
|
||||
const pathname = prependForwardSlash(this.removeBase(url.pathname));
|
||||
try {
|
||||
return decodeURI(pathname);
|
||||
} catch (e) {
|
||||
this.adapterLogger.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));
|
||||
}
|
||||
const routeData = this.pipeline.matchRoute(decodeURI(pathname));
|
||||
if (!routeData) return void 0;
|
||||
if (allowPrerenderedRoutes) {
|
||||
return routeData;
|
||||
}
|
||||
if (routeData.prerender) {
|
||||
return void 0;
|
||||
}
|
||||
return routeData;
|
||||
}
|
||||
/**
|
||||
* A matching route function to use in the development server.
|
||||
* Contrary to the `.match` function, this function resolves props and params, returning the correct
|
||||
* route based on the priority, segments. It also returns the correct, resolved pathname.
|
||||
* @param pathname
|
||||
*/
|
||||
devMatch(pathname) {
|
||||
pathname;
|
||||
return void 0;
|
||||
}
|
||||
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 host = request.headers.get("X-Forwarded-Host");
|
||||
let protocol = request.headers.get("X-Forwarded-Proto");
|
||||
if (protocol) {
|
||||
protocol = protocol + ":";
|
||||
} else {
|
||||
protocol = url.protocol;
|
||||
}
|
||||
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 (this.manifest.trailingSlash === "always") {
|
||||
pathname = appendForwardSlash(pathname);
|
||||
} else if (this.manifest.trailingSlash === "never") {
|
||||
pathname = removeTrailingForwardSlash(pathname);
|
||||
} else 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;
|
||||
}
|
||||
async render(request, {
|
||||
addCookieHeader = false,
|
||||
clientAddress = Reflect.get(request, clientAddressSymbol),
|
||||
locals,
|
||||
prerenderedErrorPageFetch = fetch,
|
||||
routeData,
|
||||
waitUntil
|
||||
} = {}) {
|
||||
await this.pipeline.getLogger();
|
||||
if (routeData) {
|
||||
this.logger.debug(
|
||||
"router",
|
||||
"The adapter " + this.manifest.adapterName + " provided a custom RouteData for ",
|
||||
request.url
|
||||
);
|
||||
this.logger.debug("router", "RouteData");
|
||||
this.logger.debug("router", routeData);
|
||||
}
|
||||
if (locals) {
|
||||
if (typeof locals !== "object") {
|
||||
const error = new AstroError(AstroErrorData.LocalsNotAnObject);
|
||||
this.logger.error(null, error.stack);
|
||||
return this.renderError(request, {
|
||||
addCookieHeader,
|
||||
clientAddress,
|
||||
prerenderedErrorPageFetch,
|
||||
// If locals are invalid, we don't want to include them when
|
||||
// rendering the error page
|
||||
locals: void 0,
|
||||
routeData,
|
||||
waitUntil,
|
||||
status: 500,
|
||||
error
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!routeData) {
|
||||
const domainPathname = this.computePathnameFromDomain(request);
|
||||
if (domainPathname) {
|
||||
routeData = this.pipeline.matchRoute(decodeURI(domainPathname));
|
||||
}
|
||||
}
|
||||
const resolvedOptions = {
|
||||
addCookieHeader,
|
||||
clientAddress,
|
||||
prerenderedErrorPageFetch,
|
||||
locals,
|
||||
routeData,
|
||||
waitUntil
|
||||
};
|
||||
let response;
|
||||
if (this.#fetchHandler instanceof DefaultFetchHandler) {
|
||||
Reflect.set(request, appSymbol, this);
|
||||
response = await this.#fetchHandler.renderWithOptions(request, resolvedOptions);
|
||||
} else {
|
||||
setRenderOptions(request, resolvedOptions);
|
||||
Reflect.set(request, appSymbol, this);
|
||||
response = await this.#fetchHandler.fetch(request);
|
||||
}
|
||||
this.#warnMissingFeatures();
|
||||
if (response.headers.get(ASTRO_ERROR_HEADER)) {
|
||||
response.headers.delete(ASTRO_ERROR_HEADER);
|
||||
return this.renderError(request, {
|
||||
addCookieHeader,
|
||||
clientAddress,
|
||||
prerenderedErrorPageFetch,
|
||||
locals,
|
||||
routeData,
|
||||
waitUntil,
|
||||
response,
|
||||
status: response.status,
|
||||
error: response.status === 500 ? null : void 0
|
||||
});
|
||||
}
|
||||
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.
|
||||
*
|
||||
* Delegates to the app's configured `ErrorHandler`. To customize behavior
|
||||
* for a specific environment, override `createErrorHandler()` rather than
|
||||
* this method.
|
||||
*/
|
||||
async renderError(request, options) {
|
||||
return this.#errorHandler.renderError(request, options);
|
||||
}
|
||||
/**
|
||||
* One-shot check: after the first request with a custom `src/app.ts`,
|
||||
* compare `usedFeatures` against the manifest and warn about any
|
||||
* configured features the user's pipeline doesn't call.
|
||||
*/
|
||||
#warnMissingFeatures() {
|
||||
if (this.#featureCheckDone || !this.#hasCustomFetchHandler) return;
|
||||
this.#featureCheckDone = true;
|
||||
const manifest = this.manifest;
|
||||
const missing = [];
|
||||
const used = this.pipeline.usedFeatures;
|
||||
if (manifest.routes.some((r) => r.routeData.type === "redirect") && !(used & PipelineFeatures.redirects)) {
|
||||
missing.push("redirects");
|
||||
}
|
||||
if (manifest.sessionConfig && !(used & PipelineFeatures.sessions)) {
|
||||
missing.push("sessions");
|
||||
}
|
||||
if (manifest.actions && !(used & PipelineFeatures.actions)) {
|
||||
missing.push("actions");
|
||||
}
|
||||
if (manifest.middleware && !(used & PipelineFeatures.middleware)) {
|
||||
missing.push("middleware");
|
||||
}
|
||||
if (manifest.i18n && manifest.i18n.strategy !== "manual" && !(used & PipelineFeatures.i18n)) {
|
||||
missing.push("i18n");
|
||||
}
|
||||
if (manifest.cacheConfig && !(used & PipelineFeatures.cache)) {
|
||||
missing.push("cache");
|
||||
}
|
||||
for (const feature of missing) {
|
||||
this.logger.warn(
|
||||
"router",
|
||||
`Your project uses ${feature}, but your custom src/app.ts does not call the ${feature}() handler. This feature will not work unless you add it to your app.ts pipeline.`
|
||||
);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
getManifest() {
|
||||
return this.pipeline.manifest;
|
||||
}
|
||||
logThisRequest({
|
||||
pathname,
|
||||
method,
|
||||
statusCode,
|
||||
isRewrite,
|
||||
timeStart
|
||||
}) {
|
||||
const timeEnd = performance.now();
|
||||
this.logRequest({
|
||||
pathname,
|
||||
method,
|
||||
statusCode,
|
||||
isRewrite,
|
||||
reqTime: timeEnd - timeStart
|
||||
});
|
||||
}
|
||||
}
|
||||
export {
|
||||
BaseApp
|
||||
};
|
||||
6
node_modules/astro/dist/core/app/common.d.ts
generated
vendored
Normal file
6
node_modules/astro/dist/core/app/common.d.ts
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import type { AstroConfig } from '../../types/public/index.js';
|
||||
import type { SSRManifest } from './types.js';
|
||||
export type RoutingStrategies = 'manual' | 'pathname-prefix-always' | 'pathname-prefix-other-locales' | 'pathname-prefix-always-no-redirect' | 'domains-prefix-always' | 'domains-prefix-other-locales' | 'domains-prefix-always-no-redirect';
|
||||
export declare function toRoutingStrategy(routing: NonNullable<AstroConfig['i18n']>['routing'], domains: NonNullable<AstroConfig['i18n']>['domains']): RoutingStrategies;
|
||||
export declare function toFallbackType(routing: NonNullable<AstroConfig['i18n']>['routing']): 'redirect' | 'rewrite';
|
||||
export declare function fromRoutingStrategy(strategy: RoutingStrategies, fallbackType: NonNullable<SSRManifest['i18n']>['fallbackType']): NonNullable<AstroConfig['i18n']>['routing'];
|
||||
64
node_modules/astro/dist/core/app/common.js
generated
vendored
Normal file
64
node_modules/astro/dist/core/app/common.js
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
function toRoutingStrategy(routing, domains) {
|
||||
let strategy;
|
||||
const hasDomains = domains ? Object.keys(domains).length > 0 : false;
|
||||
if (routing === "manual") {
|
||||
strategy = "manual";
|
||||
} else {
|
||||
if (!hasDomains) {
|
||||
if (routing?.prefixDefaultLocale === true) {
|
||||
if (routing.redirectToDefaultLocale) {
|
||||
strategy = "pathname-prefix-always";
|
||||
} else {
|
||||
strategy = "pathname-prefix-always-no-redirect";
|
||||
}
|
||||
} else {
|
||||
strategy = "pathname-prefix-other-locales";
|
||||
}
|
||||
} else {
|
||||
if (routing?.prefixDefaultLocale === true) {
|
||||
if (routing.redirectToDefaultLocale) {
|
||||
strategy = "domains-prefix-always";
|
||||
} else {
|
||||
strategy = "domains-prefix-always-no-redirect";
|
||||
}
|
||||
} else {
|
||||
strategy = "domains-prefix-other-locales";
|
||||
}
|
||||
}
|
||||
}
|
||||
return strategy;
|
||||
}
|
||||
function toFallbackType(routing) {
|
||||
if (routing === "manual") {
|
||||
return "rewrite";
|
||||
}
|
||||
return routing.fallbackType;
|
||||
}
|
||||
const PREFIX_DEFAULT_LOCALE = /* @__PURE__ */ new Set([
|
||||
"pathname-prefix-always",
|
||||
"domains-prefix-always",
|
||||
"pathname-prefix-always-no-redirect",
|
||||
"domains-prefix-always-no-redirect"
|
||||
]);
|
||||
const REDIRECT_TO_DEFAULT_LOCALE = /* @__PURE__ */ new Set([
|
||||
"pathname-prefix-always-no-redirect",
|
||||
"domains-prefix-always-no-redirect"
|
||||
]);
|
||||
function fromRoutingStrategy(strategy, fallbackType) {
|
||||
let routing;
|
||||
if (strategy === "manual") {
|
||||
routing = "manual";
|
||||
} else {
|
||||
routing = {
|
||||
prefixDefaultLocale: PREFIX_DEFAULT_LOCALE.has(strategy),
|
||||
redirectToDefaultLocale: !REDIRECT_TO_DEFAULT_LOCALE.has(strategy),
|
||||
fallbackType
|
||||
};
|
||||
}
|
||||
return routing;
|
||||
}
|
||||
export {
|
||||
fromRoutingStrategy,
|
||||
toFallbackType,
|
||||
toRoutingStrategy
|
||||
};
|
||||
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
|
||||
};
|
||||
26
node_modules/astro/dist/core/app/dev/app.d.ts
generated
vendored
Normal file
26
node_modules/astro/dist/core/app/dev/app.d.ts
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
import type { RouteData } from '../../../types/public/index.js';
|
||||
import type { ErrorHandler } from '../../errors/handler.js';
|
||||
import type { AstroLogger } from '../../logger/core.js';
|
||||
import { BaseApp, type DevMatch, type LogRequestPayload } from '../base.js';
|
||||
import type { SSRManifest } from '../types.js';
|
||||
import { NonRunnablePipeline } from './pipeline.js';
|
||||
import type { RoutesList } from '../../../types/astro.js';
|
||||
export declare class DevApp extends BaseApp<NonRunnablePipeline> {
|
||||
constructor(manifest: SSRManifest, streaming: boolean | undefined, logger: AstroLogger);
|
||||
createPipeline(streaming: boolean, manifest: SSRManifest, logger: AstroLogger): NonRunnablePipeline;
|
||||
isDev(): boolean;
|
||||
/**
|
||||
* Clears the cached middleware so it is re-resolved on the next request.
|
||||
* Called via HMR when middleware files change.
|
||||
*/
|
||||
clearMiddleware(): void;
|
||||
/**
|
||||
* Updates the routes list when files change during development.
|
||||
* Called via HMR when new pages are added/removed.
|
||||
*/
|
||||
updateRoutes(newRoutesList: RoutesList): void;
|
||||
match(request: Request): RouteData | undefined;
|
||||
devMatch(pathname: string): Promise<DevMatch | undefined>;
|
||||
protected createErrorHandler(): ErrorHandler;
|
||||
logRequest({ pathname, method, statusCode, isRewrite, reqTime }: LogRequestPayload): void;
|
||||
}
|
||||
73
node_modules/astro/dist/core/app/dev/app.js
generated
vendored
Normal file
73
node_modules/astro/dist/core/app/dev/app.js
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
import { DevErrorHandler } from "../../errors/dev-handler.js";
|
||||
import { BaseApp } from "../base.js";
|
||||
import { NonRunnablePipeline } from "./pipeline.js";
|
||||
import { ensure404Route } from "../../routing/astro-designed-error-pages.js";
|
||||
import { matchRoute } from "../../routing/dev.js";
|
||||
import { req } from "../../messages/runtime.js";
|
||||
class DevApp extends BaseApp {
|
||||
constructor(manifest, streaming = true, logger) {
|
||||
super(manifest, streaming, logger);
|
||||
}
|
||||
createPipeline(streaming, manifest, logger) {
|
||||
return NonRunnablePipeline.create({
|
||||
logger,
|
||||
manifest,
|
||||
streaming
|
||||
});
|
||||
}
|
||||
isDev() {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Clears the cached middleware so it is re-resolved on the next request.
|
||||
* Called via HMR when middleware files change.
|
||||
*/
|
||||
clearMiddleware() {
|
||||
this.pipeline.clearMiddleware();
|
||||
}
|
||||
/**
|
||||
* Updates the routes list when files change during development.
|
||||
* Called via HMR when new pages are added/removed.
|
||||
*/
|
||||
updateRoutes(newRoutesList) {
|
||||
this.manifestData = newRoutesList;
|
||||
ensure404Route(this.manifestData);
|
||||
}
|
||||
match(request) {
|
||||
return super.match(request, true);
|
||||
}
|
||||
async devMatch(pathname) {
|
||||
const matchedRoute = await matchRoute(
|
||||
pathname,
|
||||
this.manifestData,
|
||||
this.pipeline,
|
||||
this.manifest
|
||||
);
|
||||
if (!matchedRoute) return void 0;
|
||||
return {
|
||||
routeData: matchedRoute.route,
|
||||
resolvedPathname: matchedRoute.resolvedPathname
|
||||
};
|
||||
}
|
||||
createErrorHandler() {
|
||||
return new DevErrorHandler(this, { shouldInjectCspMetaTags: false });
|
||||
}
|
||||
logRequest({ pathname, method, statusCode, isRewrite, reqTime }) {
|
||||
if (pathname === "/favicon.ico") {
|
||||
return;
|
||||
}
|
||||
this.logger.info(
|
||||
null,
|
||||
req({
|
||||
url: pathname,
|
||||
method,
|
||||
statusCode,
|
||||
isRewrite,
|
||||
reqTime
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
export {
|
||||
DevApp
|
||||
};
|
||||
16
node_modules/astro/dist/core/app/dev/pipeline.d.ts
generated
vendored
Normal file
16
node_modules/astro/dist/core/app/dev/pipeline.d.ts
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import type { ComponentInstance } from '../../../types/astro.js';
|
||||
import type { RewritePayload, RouteData } from '../../../types/public/index.js';
|
||||
import { type HeadElements, Pipeline, type TryRewriteResult } from '../../base-pipeline.js';
|
||||
type DevPipelineCreate = Pick<NonRunnablePipeline, 'logger' | 'manifest' | 'streaming'>;
|
||||
/**
|
||||
* A pipeline that can't load modules at runtime using the vite environment APIs
|
||||
*/
|
||||
export declare class NonRunnablePipeline extends Pipeline {
|
||||
getName(): string;
|
||||
static create({ logger, manifest, streaming }: DevPipelineCreate): NonRunnablePipeline;
|
||||
headElements(routeData: RouteData): Promise<HeadElements>;
|
||||
componentMetadata(): void;
|
||||
getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
|
||||
tryRewrite(payload: RewritePayload, request: Request): Promise<TryRewriteResult>;
|
||||
}
|
||||
export {};
|
||||
137
node_modules/astro/dist/core/app/dev/pipeline.js
generated
vendored
Normal file
137
node_modules/astro/dist/core/app/dev/pipeline.js
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
import { Pipeline } from "../../base-pipeline.js";
|
||||
import { ASTRO_VERSION } from "../../constants.js";
|
||||
import { createModuleScriptElement, createStylesheetElementSet } from "../../render/ssr-element.js";
|
||||
import { findRouteToRewrite } from "../../routing/rewrite.js";
|
||||
import { newNodePool } from "../../../runtime/server/render/queue/pool.js";
|
||||
import { HTMLStringCache } from "../../../runtime/server/html-string-cache.js";
|
||||
import { queueRenderingEnabled } from "../manifest.js";
|
||||
class NonRunnablePipeline extends Pipeline {
|
||||
getName() {
|
||||
return "NonRunnablePipeline";
|
||||
}
|
||||
static create({ logger, manifest, streaming }) {
|
||||
async function resolve(specifier) {
|
||||
if (specifier.startsWith("/")) {
|
||||
return specifier;
|
||||
} else {
|
||||
return "/@id/" + specifier;
|
||||
}
|
||||
}
|
||||
const pipeline = new NonRunnablePipeline(
|
||||
logger,
|
||||
manifest,
|
||||
"development",
|
||||
manifest.renderers,
|
||||
resolve,
|
||||
streaming,
|
||||
void 0,
|
||||
void 0,
|
||||
void 0,
|
||||
void 0,
|
||||
void 0,
|
||||
void 0,
|
||||
void 0,
|
||||
void 0
|
||||
);
|
||||
if (queueRenderingEnabled(manifest.experimentalQueuedRendering)) {
|
||||
pipeline.nodePool = newNodePool(manifest.experimentalQueuedRendering);
|
||||
if (manifest.experimentalQueuedRendering.contentCache) {
|
||||
pipeline.htmlStringCache = new HTMLStringCache(1e3);
|
||||
}
|
||||
}
|
||||
return pipeline;
|
||||
}
|
||||
async headElements(routeData) {
|
||||
const { componentMetadataEntries } = await import("virtual:astro:component-metadata");
|
||||
for (const [id, entry] of componentMetadataEntries) {
|
||||
this.manifest.componentMetadata.set(id, entry);
|
||||
}
|
||||
const { assetsPrefix, base } = this.manifest;
|
||||
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 ?? [], base, assetsPrefix);
|
||||
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));
|
||||
}
|
||||
}
|
||||
scripts.add({
|
||||
props: { type: "module", src: "/@vite/client" },
|
||||
children: ""
|
||||
});
|
||||
if (this.manifest.devToolbar.enabled) {
|
||||
scripts.add({
|
||||
props: {
|
||||
type: "module",
|
||||
src: "/@id/astro/runtime/client/dev-toolbar/entrypoint.js"
|
||||
},
|
||||
children: ""
|
||||
});
|
||||
const additionalMetadata = {
|
||||
root: this.manifest.rootDir.toString(),
|
||||
version: ASTRO_VERSION,
|
||||
latestAstroVersion: this.manifest.devToolbar.latestAstroVersion,
|
||||
debugInfo: this.manifest.devToolbar.debugInfoOutput ?? "",
|
||||
placement: this.manifest.devToolbar.placement
|
||||
};
|
||||
const children = `window.__astro_dev_toolbar__ = ${JSON.stringify(additionalMetadata)}`;
|
||||
scripts.add({ props: {}, children });
|
||||
}
|
||||
const { devCSSMap } = await import("virtual:astro:dev-css-all");
|
||||
const importer = devCSSMap.get(routeData.component);
|
||||
let css = /* @__PURE__ */ new Set();
|
||||
if (importer) {
|
||||
const cssModule = await importer();
|
||||
css = cssModule.css;
|
||||
} else {
|
||||
this.logger.warn(
|
||||
"assets",
|
||||
`Unable to find CSS for ${routeData.component}. This is likely a bug in Astro.`
|
||||
);
|
||||
}
|
||||
for (const { id, url: src, content } of css) {
|
||||
scripts.add({ props: { type: "module", src }, children: "" });
|
||||
styles.add({ props: { "data-vite-dev-id": id }, children: content });
|
||||
}
|
||||
return { scripts, styles, links };
|
||||
}
|
||||
componentMetadata() {
|
||||
}
|
||||
async getComponentByRoute(routeData) {
|
||||
try {
|
||||
const module2 = await this.getModuleForRoute(routeData);
|
||||
return module2.page();
|
||||
} catch {
|
||||
}
|
||||
const url = new URL(routeData.component, this.manifest.rootDir);
|
||||
const module = await import(
|
||||
/* @vite-ignore */
|
||||
url.toString()
|
||||
);
|
||||
return module;
|
||||
}
|
||||
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.manifest?.serverLike ? this.manifest.buildClientDir : this.manifest.outDir
|
||||
});
|
||||
const componentInstance = await this.getComponentByRoute(routeData);
|
||||
return { newUrl, pathname, componentInstance, routeData };
|
||||
}
|
||||
}
|
||||
export {
|
||||
NonRunnablePipeline
|
||||
};
|
||||
7
node_modules/astro/dist/core/app/entrypoints/index.d.ts
generated
vendored
Normal file
7
node_modules/astro/dist/core/app/entrypoints/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export type { RoutesList } from '../../../types/astro.js';
|
||||
export { App } from '../app.js';
|
||||
export { BaseApp, type RenderErrorOptions, type RenderOptions, type LogRequestPayload, } from '../base.js';
|
||||
export { fromRoutingStrategy, toRoutingStrategy } from '../common.js';
|
||||
export { createConsoleLogger } from '../../logger/impls/console.js';
|
||||
export { deserializeManifest, deserializeRouteData, deserializeRouteInfo, serializeRouteData, serializeRouteInfo, } from '../manifest.js';
|
||||
export { AppPipeline } from '../pipeline.js';
|
||||
27
node_modules/astro/dist/core/app/entrypoints/index.js
generated
vendored
Normal file
27
node_modules/astro/dist/core/app/entrypoints/index.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
import { App } from "../app.js";
|
||||
import {
|
||||
BaseApp
|
||||
} from "../base.js";
|
||||
import { fromRoutingStrategy, toRoutingStrategy } from "../common.js";
|
||||
import { createConsoleLogger } from "../../logger/impls/console.js";
|
||||
import {
|
||||
deserializeManifest,
|
||||
deserializeRouteData,
|
||||
deserializeRouteInfo,
|
||||
serializeRouteData,
|
||||
serializeRouteInfo
|
||||
} from "../manifest.js";
|
||||
import { AppPipeline } from "../pipeline.js";
|
||||
export {
|
||||
App,
|
||||
AppPipeline,
|
||||
BaseApp,
|
||||
createConsoleLogger,
|
||||
deserializeManifest,
|
||||
deserializeRouteData,
|
||||
deserializeRouteInfo,
|
||||
fromRoutingStrategy,
|
||||
serializeRouteData,
|
||||
serializeRouteInfo,
|
||||
toRoutingStrategy
|
||||
};
|
||||
1
node_modules/astro/dist/core/app/entrypoints/manifest.d.ts
generated
vendored
Normal file
1
node_modules/astro/dist/core/app/entrypoints/manifest.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export { type SerializedRouteData, deserializeManifest, deserializeRouteData, deserializeRouteInfo, serializeRouteData, serializeRouteInfo, } from '../manifest.js';
|
||||
14
node_modules/astro/dist/core/app/entrypoints/manifest.js
generated
vendored
Normal file
14
node_modules/astro/dist/core/app/entrypoints/manifest.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import {
|
||||
deserializeManifest,
|
||||
deserializeRouteData,
|
||||
deserializeRouteInfo,
|
||||
serializeRouteData,
|
||||
serializeRouteInfo
|
||||
} from "../manifest.js";
|
||||
export {
|
||||
deserializeManifest,
|
||||
deserializeRouteData,
|
||||
deserializeRouteInfo,
|
||||
serializeRouteData,
|
||||
serializeRouteInfo
|
||||
};
|
||||
1
node_modules/astro/dist/core/app/entrypoints/node.d.ts
generated
vendored
Normal file
1
node_modules/astro/dist/core/app/entrypoints/node.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export { NodeApp, loadApp, loadManifest, createRequest, writeResponse, getAbortControllerCleanup, } from '../node.js';
|
||||
16
node_modules/astro/dist/core/app/entrypoints/node.js
generated
vendored
Normal file
16
node_modules/astro/dist/core/app/entrypoints/node.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import {
|
||||
NodeApp,
|
||||
loadApp,
|
||||
loadManifest,
|
||||
createRequest,
|
||||
writeResponse,
|
||||
getAbortControllerCleanup
|
||||
} from "../node.js";
|
||||
export {
|
||||
NodeApp,
|
||||
createRequest,
|
||||
getAbortControllerCleanup,
|
||||
loadApp,
|
||||
loadManifest,
|
||||
writeResponse
|
||||
};
|
||||
2
node_modules/astro/dist/core/app/entrypoints/virtual/dev.d.ts
generated
vendored
Normal file
2
node_modules/astro/dist/core/app/entrypoints/virtual/dev.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import type { CreateApp } from '../../types.js';
|
||||
export declare const createApp: CreateApp;
|
||||
37
node_modules/astro/dist/core/app/entrypoints/virtual/dev.js
generated
vendored
Normal file
37
node_modules/astro/dist/core/app/entrypoints/virtual/dev.js
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
import fetchable from "virtual:astro:fetchable";
|
||||
import { manifest } from "virtual:astro:manifest";
|
||||
import { DevApp } from "../../dev/app.js";
|
||||
import { createConsoleLogger } from "../../../logger/impls/console.js";
|
||||
let currentDevApp = null;
|
||||
const createApp = ({ streaming } = {}) => {
|
||||
const logger = createConsoleLogger(manifest.logLevel);
|
||||
currentDevApp = new DevApp(manifest, streaming, logger);
|
||||
currentDevApp.setFetchHandler(fetchable);
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot.on("astro:routes-updated", async () => {
|
||||
if (!currentDevApp) return;
|
||||
try {
|
||||
const { routes: newRoutes } = await import("virtual:astro:routes");
|
||||
const newRoutesList = {
|
||||
routes: newRoutes.map((r) => r.routeData)
|
||||
};
|
||||
currentDevApp.updateRoutes(newRoutesList);
|
||||
} catch (e) {
|
||||
logger.error("router", `Failed to update routes via HMR:
|
||||
${e}`);
|
||||
}
|
||||
});
|
||||
import.meta.hot.on("astro:content-changed", () => {
|
||||
if (!currentDevApp) return;
|
||||
currentDevApp.pipeline.routeCache.clearAll();
|
||||
});
|
||||
import.meta.hot.on("astro:middleware-updated", () => {
|
||||
if (!currentDevApp) return;
|
||||
currentDevApp.clearMiddleware();
|
||||
});
|
||||
}
|
||||
return currentDevApp;
|
||||
};
|
||||
export {
|
||||
createApp
|
||||
};
|
||||
2
node_modules/astro/dist/core/app/entrypoints/virtual/index.d.ts
generated
vendored
Normal file
2
node_modules/astro/dist/core/app/entrypoints/virtual/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import type { CreateApp } from '../../types.js';
|
||||
export declare const createApp: CreateApp;
|
||||
5
node_modules/astro/dist/core/app/entrypoints/virtual/index.js
generated
vendored
Normal file
5
node_modules/astro/dist/core/app/entrypoints/virtual/index.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import { createApp as _createApp } from "virtual:astro:app";
|
||||
const createApp = _createApp;
|
||||
export {
|
||||
createApp
|
||||
};
|
||||
2
node_modules/astro/dist/core/app/entrypoints/virtual/prod.d.ts
generated
vendored
Normal file
2
node_modules/astro/dist/core/app/entrypoints/virtual/prod.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import type { CreateApp } from '../../types.js';
|
||||
export declare const createApp: CreateApp;
|
||||
11
node_modules/astro/dist/core/app/entrypoints/virtual/prod.js
generated
vendored
Normal file
11
node_modules/astro/dist/core/app/entrypoints/virtual/prod.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import fetchable from "virtual:astro:fetchable";
|
||||
import { manifest } from "virtual:astro:manifest";
|
||||
import { App } from "../../app.js";
|
||||
const createApp = ({ streaming } = {}) => {
|
||||
const app = new App(manifest, streaming);
|
||||
app.setFetchHandler(fetchable);
|
||||
return app;
|
||||
};
|
||||
export {
|
||||
createApp
|
||||
};
|
||||
12
node_modules/astro/dist/core/app/manifest.d.ts
generated
vendored
Normal file
12
node_modules/astro/dist/core/app/manifest.d.ts
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import type { SerializedRouteData } from '../../types/astro.js';
|
||||
import type { AstroConfig, RouteData } from '../../types/public/index.js';
|
||||
import type { RoutesList } from '../../types/astro.js';
|
||||
import type { RouteInfo, SerializedSSRManifest, SSRManifest, SerializedRouteInfo } from './types.js';
|
||||
export type { SerializedRouteData } from '../../types/astro.js';
|
||||
export declare function deserializeManifest(serializedManifest: SerializedSSRManifest, routesList?: RoutesList): SSRManifest;
|
||||
export declare function serializeRouteData(routeData: RouteData, trailingSlash: AstroConfig['trailingSlash']): SerializedRouteData;
|
||||
export declare function deserializeRouteData(rawRouteData: SerializedRouteData): RouteData;
|
||||
export declare function serializeRouteInfo(routeInfo: RouteInfo, trailingSlash: AstroConfig['trailingSlash']): SerializedRouteInfo;
|
||||
export declare function deserializeRouteInfo(rawRouteInfo: SerializedRouteInfo): RouteInfo;
|
||||
export declare function queuePoolSize(config: NonNullable<SSRManifest['experimentalQueuedRendering']>): number;
|
||||
export declare function queueRenderingEnabled(config: SSRManifest['experimentalQueuedRendering']): boolean;
|
||||
117
node_modules/astro/dist/core/app/manifest.js
generated
vendored
Normal file
117
node_modules/astro/dist/core/app/manifest.js
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
import { decodeKey } from "../encryption.js";
|
||||
import { NOOP_MIDDLEWARE_FN } from "../middleware/noop-middleware.js";
|
||||
function deserializeManifest(serializedManifest, routesList) {
|
||||
const routes = [];
|
||||
if (serializedManifest.routes) {
|
||||
for (const serializedRoute of serializedManifest.routes) {
|
||||
routes.push({
|
||||
...serializedRoute,
|
||||
routeData: deserializeRouteData(serializedRoute.routeData)
|
||||
});
|
||||
const route = serializedRoute;
|
||||
route.routeData = deserializeRouteData(serializedRoute.routeData);
|
||||
}
|
||||
}
|
||||
if (routesList) {
|
||||
for (const route of routesList?.routes) {
|
||||
routes.push({
|
||||
file: "",
|
||||
links: [],
|
||||
scripts: [],
|
||||
styles: [],
|
||||
routeData: route
|
||||
});
|
||||
}
|
||||
}
|
||||
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 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,
|
||||
rootDir: new URL(serializedManifest.rootDir),
|
||||
srcDir: new URL(serializedManifest.srcDir),
|
||||
publicDir: new URL(serializedManifest.publicDir),
|
||||
outDir: new URL(serializedManifest.outDir),
|
||||
cacheDir: new URL(serializedManifest.cacheDir),
|
||||
buildClientDir: new URL(serializedManifest.buildClientDir),
|
||||
buildServerDir: new URL(serializedManifest.buildServerDir),
|
||||
assets,
|
||||
componentMetadata,
|
||||
inlinedScripts,
|
||||
clientDirectives,
|
||||
routes,
|
||||
key
|
||||
};
|
||||
}
|
||||
function serializeRouteData(routeData, trailingSlash) {
|
||||
return {
|
||||
...routeData,
|
||||
pattern: routeData.pattern.source,
|
||||
redirectRoute: routeData.redirectRoute ? serializeRouteData(routeData.redirectRoute, trailingSlash) : void 0,
|
||||
fallbackRoutes: routeData.fallbackRoutes.map((fallbackRoute) => {
|
||||
return serializeRouteData(fallbackRoute, trailingSlash);
|
||||
}),
|
||||
_meta: { trailingSlash }
|
||||
};
|
||||
}
|
||||
function deserializeRouteData(rawRouteData) {
|
||||
return {
|
||||
route: rawRouteData.route,
|
||||
type: rawRouteData.type,
|
||||
// nosemgrep: javascript.lang.security.audit.detect-non-literal-regexp.detect-non-literal-regexp
|
||||
// This pattern is serialized from Astro's own route manifest.
|
||||
pattern: new RegExp(rawRouteData.pattern),
|
||||
params: rawRouteData.params,
|
||||
component: rawRouteData.component,
|
||||
pathname: rawRouteData.pathname || void 0,
|
||||
segments: rawRouteData.segments,
|
||||
prerender: rawRouteData.prerender,
|
||||
redirect: rawRouteData.redirect,
|
||||
redirectRoute: rawRouteData.redirectRoute ? deserializeRouteData(rawRouteData.redirectRoute) : void 0,
|
||||
fallbackRoutes: rawRouteData.fallbackRoutes.map((fallback) => {
|
||||
return deserializeRouteData(fallback);
|
||||
}),
|
||||
isIndex: rawRouteData.isIndex,
|
||||
origin: rawRouteData.origin,
|
||||
distURL: rawRouteData.distURL
|
||||
};
|
||||
}
|
||||
function serializeRouteInfo(routeInfo, trailingSlash) {
|
||||
return {
|
||||
styles: routeInfo.styles,
|
||||
file: routeInfo.file,
|
||||
links: routeInfo.links,
|
||||
scripts: routeInfo.scripts,
|
||||
routeData: serializeRouteData(routeInfo.routeData, trailingSlash)
|
||||
};
|
||||
}
|
||||
function deserializeRouteInfo(rawRouteInfo) {
|
||||
return {
|
||||
styles: rawRouteInfo.styles,
|
||||
file: rawRouteInfo.file,
|
||||
links: rawRouteInfo.links,
|
||||
scripts: rawRouteInfo.scripts,
|
||||
routeData: deserializeRouteData(rawRouteInfo.routeData)
|
||||
};
|
||||
}
|
||||
function queuePoolSize(config) {
|
||||
return config?.poolSize ?? 1e3;
|
||||
}
|
||||
function queueRenderingEnabled(config) {
|
||||
return config?.enabled ?? false;
|
||||
}
|
||||
export {
|
||||
deserializeManifest,
|
||||
deserializeRouteData,
|
||||
deserializeRouteInfo,
|
||||
queuePoolSize,
|
||||
queueRenderingEnabled,
|
||||
serializeRouteData,
|
||||
serializeRouteInfo
|
||||
};
|
||||
8
node_modules/astro/dist/core/app/middlewares.d.ts
generated
vendored
Normal file
8
node_modules/astro/dist/core/app/middlewares.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
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;
|
||||
export declare function hasFormLikeHeader(contentType: string | null): boolean;
|
||||
49
node_modules/astro/dist/core/app/middlewares.js
generated
vendored
Normal file
49
node_modules/astro/dist/core/app/middlewares.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
import { defineMiddleware } from "../middleware/defineMiddleware.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,
|
||||
hasFormLikeHeader
|
||||
};
|
||||
114
node_modules/astro/dist/core/app/node.d.ts
generated
vendored
Normal file
114
node_modules/astro/dist/core/app/node.d.ts
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
import type { IncomingMessage, ServerResponse } from 'node:http';
|
||||
import type { RemotePattern } from '../../types/public/config.js';
|
||||
import type { RenderOptions } from './base.js';
|
||||
import { App } from './app.js';
|
||||
import type { NodeAppHeadersJson, SSRManifest } from './types.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;
|
||||
}
|
||||
/**
|
||||
* Converts a NodeJS IncomingMessage into a web standard Request.
|
||||
* ```js
|
||||
* import { createApp } from 'astro/app/entrypoint';
|
||||
* import { createRequest } from 'astro/app/node';
|
||||
* import { createServer } from 'node:http';
|
||||
*
|
||||
* const app = createApp();
|
||||
*
|
||||
* const server = createServer(async (req, res) => {
|
||||
* const request = createRequest(req);
|
||||
* const response = await app.render(request);
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export declare function createRequest(req: NodeRequest, { skipBody, allowedDomains, bodySizeLimit, port: serverPort, }?: {
|
||||
skipBody?: boolean;
|
||||
allowedDomains?: Partial<RemotePattern>[];
|
||||
bodySizeLimit?: number;
|
||||
port?: number;
|
||||
}): Request;
|
||||
/**
|
||||
* Streams a web-standard Response into a NodeJS Server Response.
|
||||
* ```js
|
||||
* import { createApp } from 'astro/app/entrypoint';
|
||||
* import { createRequest, writeResponse } from 'astro/app/node';
|
||||
* import { createServer } from 'node:http';
|
||||
*
|
||||
* const app = createApp();
|
||||
*
|
||||
* const server = createServer(async (req, res) => {
|
||||
* const request = createRequest(req);
|
||||
* const response = await app.render(request);
|
||||
* await writeResponse(response, res);
|
||||
* })
|
||||
* ```
|
||||
* @param source WhatWG Response
|
||||
* @param destination NodeJS ServerResponse
|
||||
*/
|
||||
export declare function writeResponse(source: Response, destination: ServerResponse): Promise<ServerResponse<IncomingMessage> | undefined>;
|
||||
/**
|
||||
* @deprecated Use `App` or `createApp()` instead, and use in conjunction with `convertRequest()`
|
||||
* and `writeResponse()` helpers. This will be removed in a future major version.
|
||||
*/
|
||||
export declare class NodeApp extends App {
|
||||
headersMap: NodeAppHeadersJson | undefined;
|
||||
setHeadersMap(headers: NodeAppHeadersJson): void;
|
||||
match(req: NodeRequest | Request, allowPrerenderedRoutes?: boolean): import("../../index.js").RouteData | undefined;
|
||||
render(request: NodeRequest | Request, options?: RenderOptions): 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: typeof createRequest;
|
||||
/**
|
||||
* 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: typeof writeResponse;
|
||||
}
|
||||
/**
|
||||
* Returns the cleanup function for the AbortController and socket listeners created by `createRequest()`
|
||||
* for the NodeJS IncomingMessage. This should only be called directly if the request is not
|
||||
* being handled by Astro, i.e. if not calling `writeResponse()` after `createRequest()`.
|
||||
* ```js
|
||||
* import { createRequest, getAbortControllerCleanup } from 'astro/app/node';
|
||||
* import { createServer } from 'node:http';
|
||||
*
|
||||
* const server = createServer(async (req, res) => {
|
||||
* const request = createRequest(req);
|
||||
* const cleanup = getAbortControllerCleanup(req);
|
||||
* if (cleanup) cleanup();
|
||||
* // can now safely call another handler
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export declare function getAbortControllerCleanup(req?: NodeRequest): (() => void) | undefined;
|
||||
/** @deprecated This will be removed in a future major version. */
|
||||
export declare function loadManifest(rootFolder: URL): Promise<SSRManifest>;
|
||||
/** @deprecated This will be removed in a future major version. */
|
||||
export declare function loadApp(rootFolder: URL): Promise<NodeApp>;
|
||||
export {};
|
||||
287
node_modules/astro/dist/core/app/node.js
generated
vendored
Normal file
287
node_modules/astro/dist/core/app/node.js
generated
vendored
Normal file
@@ -0,0 +1,287 @@
|
||||
import fs from "node:fs";
|
||||
import { Http2ServerResponse } from "node:http2";
|
||||
import { clientAddressSymbol, nodeRequestAbortControllerCleanupSymbol } from "../constants.js";
|
||||
import { deserializeManifest } from "./manifest.js";
|
||||
import { createOutgoingHttpHeaders } from "./createOutgoingHttpHeaders.js";
|
||||
import { App } from "./app.js";
|
||||
import {
|
||||
getFirstForwardedValue,
|
||||
validateForwardedHeaders,
|
||||
validateHost
|
||||
} from "./validate-headers.js";
|
||||
function createRequest(req, {
|
||||
skipBody = false,
|
||||
allowedDomains = [],
|
||||
bodySizeLimit,
|
||||
port: serverPort
|
||||
} = {}) {
|
||||
const controller = new AbortController();
|
||||
const isEncrypted = "encrypted" in req.socket && req.socket.encrypted;
|
||||
const providedProtocol = isEncrypted ? "https" : "http";
|
||||
const untrustedHostname = req.headers.host ?? req.headers[":authority"];
|
||||
const validated = validateForwardedHeaders(
|
||||
getFirstForwardedValue(req.headers["x-forwarded-proto"]),
|
||||
getFirstForwardedValue(req.headers["x-forwarded-host"]),
|
||||
getFirstForwardedValue(req.headers["x-forwarded-port"]),
|
||||
allowedDomains
|
||||
);
|
||||
const protocol = validated.protocol ?? providedProtocol;
|
||||
const validatedHostname = validateHost(
|
||||
typeof untrustedHostname === "string" ? untrustedHostname : void 0,
|
||||
protocol,
|
||||
allowedDomains
|
||||
);
|
||||
const hostname = validated.host ?? validatedHostname ?? "localhost";
|
||||
const port = validated.port ?? (!validated.host && !validatedHostname && serverPort ? String(serverPort) : void 0);
|
||||
let url;
|
||||
try {
|
||||
const hostnamePort = getHostnamePort(hostname, port);
|
||||
url = new URL(`${protocol}://${hostnamePort}${req.url}`);
|
||||
} catch {
|
||||
const hostnamePort = getHostnamePort(hostname, port);
|
||||
url = new URL(`${protocol}://${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, bodySizeLimit));
|
||||
}
|
||||
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 hostValidated = validated.host !== void 0 || validatedHostname !== void 0;
|
||||
const forwardedClientIp = hostValidated ? getFirstForwardedValue(req.headers["x-forwarded-for"]) : void 0;
|
||||
const clientIp = forwardedClientIp || req.socket?.remoteAddress;
|
||||
if (clientIp) {
|
||||
Reflect.set(request, clientAddressSymbol, clientIp);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
async function 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 %s.",
|
||||
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();
|
||||
});
|
||||
}
|
||||
}
|
||||
class NodeApp extends App {
|
||||
headersMap = void 0;
|
||||
setHeadersMap(headers) {
|
||||
this.headersMap = headers;
|
||||
}
|
||||
match(req, allowPrerenderedRoutes = false) {
|
||||
if (!(req instanceof Request)) {
|
||||
req = createRequest(req, {
|
||||
skipBody: true,
|
||||
allowedDomains: this.manifest.allowedDomains
|
||||
});
|
||||
}
|
||||
return super.match(req, allowPrerenderedRoutes);
|
||||
}
|
||||
render(request, options) {
|
||||
if (!(request instanceof Request)) {
|
||||
request = createRequest(request, {
|
||||
allowedDomains: this.manifest.allowedDomains
|
||||
});
|
||||
}
|
||||
return super.render(request, options);
|
||||
}
|
||||
/**
|
||||
* 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 = createRequest;
|
||||
/**
|
||||
* 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 = writeResponse;
|
||||
}
|
||||
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, bodySizeLimit) {
|
||||
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, bodySizeLimit);
|
||||
}
|
||||
}
|
||||
return asyncIterableToBodyProps(req, bodySizeLimit);
|
||||
}
|
||||
function asyncIterableToBodyProps(iterable, bodySizeLimit) {
|
||||
const source = bodySizeLimit != null ? limitAsyncIterable(iterable, bodySizeLimit) : iterable;
|
||||
return {
|
||||
// Node uses undici for the Request implementation. Undici accepts
|
||||
// a non-standard async iterable for the body.
|
||||
// @ts-expect-error
|
||||
body: source,
|
||||
// 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"
|
||||
};
|
||||
}
|
||||
async function* limitAsyncIterable(iterable, limit) {
|
||||
let received = 0;
|
||||
for await (const chunk of iterable) {
|
||||
const byteLength = chunk instanceof Uint8Array ? chunk.byteLength : typeof chunk === "string" ? Buffer.byteLength(chunk) : 0;
|
||||
received += byteLength;
|
||||
if (received > limit) {
|
||||
throw new Error(`Body size limit exceeded: received more than ${limit} bytes`);
|
||||
}
|
||||
yield chunk;
|
||||
}
|
||||
}
|
||||
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,
|
||||
createRequest,
|
||||
getAbortControllerCleanup,
|
||||
loadApp,
|
||||
loadManifest,
|
||||
writeResponse
|
||||
};
|
||||
14
node_modules/astro/dist/core/app/pipeline.d.ts
generated
vendored
Normal file
14
node_modules/astro/dist/core/app/pipeline.d.ts
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { ComponentInstance } from '../../types/astro.js';
|
||||
import type { RewritePayload } from '../../types/public/common.js';
|
||||
import type { RouteData } from '../../types/public/internal.js';
|
||||
import { type HeadElements, Pipeline, type TryRewriteResult } from '../base-pipeline.js';
|
||||
import type { SinglePageBuiltModule } from '../build/types.js';
|
||||
export declare class AppPipeline extends Pipeline {
|
||||
getName(): string;
|
||||
static create({ manifest, streaming }: Pick<AppPipeline, 'manifest' | 'streaming'>): AppPipeline;
|
||||
headElements(routeData: RouteData): Promise<HeadElements>;
|
||||
componentMetadata(): void;
|
||||
getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
|
||||
getModuleForRoute(route: RouteData): Promise<SinglePageBuiltModule>;
|
||||
tryRewrite(payload: RewritePayload, request: Request): Promise<TryRewriteResult>;
|
||||
}
|
||||
123
node_modules/astro/dist/core/app/pipeline.js
generated
vendored
Normal file
123
node_modules/astro/dist/core/app/pipeline.js
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
import { Pipeline } from "../base-pipeline.js";
|
||||
import { RedirectSinglePageBuiltModule } from "../redirects/index.js";
|
||||
import {
|
||||
createAssetLink,
|
||||
createModuleScriptElement,
|
||||
createStylesheetElementSet
|
||||
} from "../render/ssr-element.js";
|
||||
import { getFallbackRoute, routeIsFallback, routeIsRedirect } from "../routing/helpers.js";
|
||||
import { findRouteToRewrite } from "../routing/rewrite.js";
|
||||
import { createConsoleLogger } from "../logger/impls/console.js";
|
||||
class AppPipeline extends Pipeline {
|
||||
getName() {
|
||||
return "AppPipeline";
|
||||
}
|
||||
static create({ manifest, streaming }) {
|
||||
const resolve = async function resolve2(specifier) {
|
||||
if (!(specifier in manifest.entryModules)) {
|
||||
throw new Error(`Unable to resolve [${specifier}]`);
|
||||
}
|
||||
const bundlePath = manifest.entryModules[specifier];
|
||||
if (bundlePath.startsWith("data:") || bundlePath.length === 0) {
|
||||
return bundlePath;
|
||||
} else {
|
||||
return createAssetLink(bundlePath, manifest.base, manifest.assetsPrefix);
|
||||
}
|
||||
};
|
||||
const logger = createConsoleLogger({ level: manifest.logLevel });
|
||||
const pipeline = new AppPipeline(
|
||||
logger,
|
||||
manifest,
|
||||
"production",
|
||||
manifest.renderers,
|
||||
resolve,
|
||||
streaming,
|
||||
void 0,
|
||||
void 0,
|
||||
void 0,
|
||||
void 0,
|
||||
void 0,
|
||||
void 0,
|
||||
void 0,
|
||||
void 0
|
||||
);
|
||||
return pipeline;
|
||||
}
|
||||
async headElements(routeData) {
|
||||
const { assetsPrefix, base } = this.manifest;
|
||||
const routeInfo = this.manifest.routes.find(
|
||||
(route) => route.routeData.route === routeData.route
|
||||
);
|
||||
const links = /* @__PURE__ */ new Set();
|
||||
const scripts = /* @__PURE__ */ new Set();
|
||||
const styles = createStylesheetElementSet(routeInfo?.styles ?? [], base, assetsPrefix);
|
||||
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, base, assetsPrefix));
|
||||
}
|
||||
}
|
||||
return { links, styles, scripts };
|
||||
}
|
||||
componentMetadata() {
|
||||
}
|
||||
async getComponentByRoute(routeData) {
|
||||
const module = await this.getModuleForRoute(routeData);
|
||||
return module.page();
|
||||
}
|
||||
async getModuleForRoute(route) {
|
||||
for (const defaultRoute of this.defaultRoutes) {
|
||||
if (route.component === defaultRoute.component) {
|
||||
return {
|
||||
page: () => Promise.resolve(defaultRoute.instance)
|
||||
};
|
||||
}
|
||||
}
|
||||
let routeToProcess = route;
|
||||
if (routeIsRedirect(route)) {
|
||||
if (route.redirectRoute) {
|
||||
routeToProcess = route.redirectRoute;
|
||||
} else {
|
||||
return RedirectSinglePageBuiltModule;
|
||||
}
|
||||
} else if (routeIsFallback(route)) {
|
||||
routeToProcess = getFallbackRoute(route, this.manifest.routes);
|
||||
}
|
||||
if (this.manifest.pageMap) {
|
||||
const importComponentInstance = this.manifest.pageMap.get(routeToProcess.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."
|
||||
);
|
||||
}
|
||||
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.manifest?.serverLike ? this.manifest.buildClientDir : this.manifest.outDir
|
||||
});
|
||||
const componentInstance = await this.getComponentByRoute(routeData);
|
||||
return { newUrl, pathname, componentInstance, routeData };
|
||||
}
|
||||
}
|
||||
export {
|
||||
AppPipeline
|
||||
};
|
||||
11
node_modules/astro/dist/core/app/prepare-response.d.ts
generated
vendored
Normal file
11
node_modules/astro/dist/core/app/prepare-response.d.ts
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Strips internal-only headers from the response before sending it to the
|
||||
* user agent, and optionally appends cookies written via `Astro.cookie.set()`
|
||||
* to the `Set-Cookie` header.
|
||||
*
|
||||
* This is a pure function with no dependencies on the app; it is shared by
|
||||
* `AstroHandler` and the various error handlers.
|
||||
*/
|
||||
export declare function prepareResponse(response: Response, { addCookieHeader }: {
|
||||
addCookieHeader: boolean;
|
||||
}): void;
|
||||
18
node_modules/astro/dist/core/app/prepare-response.js
generated
vendored
Normal file
18
node_modules/astro/dist/core/app/prepare-response.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import { INTERNAL_RESPONSE_HEADERS, responseSentSymbol } from "../constants.js";
|
||||
import { getSetCookiesFromResponse } from "../cookies/index.js";
|
||||
function prepareResponse(response, { addCookieHeader }) {
|
||||
for (const headerName of INTERNAL_RESPONSE_HEADERS) {
|
||||
if (response.headers.has(headerName)) {
|
||||
response.headers.delete(headerName);
|
||||
}
|
||||
}
|
||||
if (addCookieHeader) {
|
||||
for (const setCookieHeaderValue of getSetCookiesFromResponse(response)) {
|
||||
response.headers.append("set-cookie", setCookieHeaderValue);
|
||||
}
|
||||
}
|
||||
Reflect.set(response, responseSentSymbol, true);
|
||||
}
|
||||
export {
|
||||
prepareResponse
|
||||
};
|
||||
11
node_modules/astro/dist/core/app/render-options.d.ts
generated
vendored
Normal file
11
node_modules/astro/dist/core/app/render-options.d.ts
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { ResolvedRenderOptions } from './base.js';
|
||||
/**
|
||||
* Reads `ResolvedRenderOptions` that were attached to a request via
|
||||
* `renderOptionsSymbol`. Returns `undefined` if no options are attached.
|
||||
*/
|
||||
export declare function getRenderOptions(request: Request): ResolvedRenderOptions | undefined;
|
||||
/**
|
||||
* Attaches `ResolvedRenderOptions` to a request via `renderOptionsSymbol` so
|
||||
* that downstream handlers can read them.
|
||||
*/
|
||||
export declare function setRenderOptions(request: Request, options: ResolvedRenderOptions): void;
|
||||
11
node_modules/astro/dist/core/app/render-options.js
generated
vendored
Normal file
11
node_modules/astro/dist/core/app/render-options.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
const renderOptionsSymbol = /* @__PURE__ */ Symbol.for("astro.renderOptions");
|
||||
function getRenderOptions(request) {
|
||||
return Reflect.get(request, renderOptionsSymbol);
|
||||
}
|
||||
function setRenderOptions(request, options) {
|
||||
Reflect.set(request, renderOptionsSymbol, options);
|
||||
}
|
||||
export {
|
||||
getRenderOptions,
|
||||
setRenderOptions
|
||||
};
|
||||
203
node_modules/astro/dist/core/app/types.d.ts
generated
vendored
Normal file
203
node_modules/astro/dist/core/app/types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
import type { ActionClient } from '../../actions/runtime/types.js';
|
||||
import type { ComponentInstance, SerializedRouteData } from '../../types/astro.js';
|
||||
import type { AstroMiddlewareInstance } from '../../types/public/common.js';
|
||||
import type { AstroConfig, CspAlgorithm, Locales, RemotePattern } 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';
|
||||
import type { AstroLoggerDestination, AstroLoggerLevel, AstroLoggerMessage } from '../logger/core.js';
|
||||
import type { RoutingStrategies } from './common.js';
|
||||
import type { CacheProviderFactory, SSRManifestCache } from '../cache/types.js';
|
||||
import type { BaseSessionConfig, SessionDriverFactory } from '../session/types.js';
|
||||
import type { DevToolbarPlacement } from '../../types/public/toolbar.js';
|
||||
import type { MiddlewareMode } from '../../types/public/integrations.js';
|
||||
import type { BaseApp } from './base.js';
|
||||
import type { LoggerHandlerConfig } from '../logger/config.js';
|
||||
type ComponentPath = string;
|
||||
export type StylesheetAsset = {
|
||||
type: 'inline';
|
||||
content: string;
|
||||
} | {
|
||||
type: 'external';
|
||||
src: string;
|
||||
};
|
||||
type ScriptAsset = {
|
||||
children: string;
|
||||
stage: string;
|
||||
} | {
|
||||
type: 'inline' | 'external';
|
||||
value: string;
|
||||
};
|
||||
export interface RouteInfo {
|
||||
routeData: RouteData;
|
||||
file: string;
|
||||
links: string[];
|
||||
scripts: ScriptAsset[];
|
||||
styles: StylesheetAsset[];
|
||||
}
|
||||
export type SerializedRouteInfo = Omit<RouteInfo, 'routeData'> & {
|
||||
routeData: SerializedRouteData;
|
||||
};
|
||||
type ImportComponentInstance = () => Promise<SinglePageBuiltModule>;
|
||||
export type ServerIslandMappings = {
|
||||
serverIslandMap?: Map<string, () => Promise<ComponentInstance>>;
|
||||
serverIslandNameMap?: Map<string, string>;
|
||||
};
|
||||
export type AssetsPrefix = string | ({
|
||||
fallback: string;
|
||||
} & Record<string, string>) | undefined;
|
||||
export type SSRManifest = {
|
||||
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 | 'jsx';
|
||||
experimentalQueuedRendering: {
|
||||
enabled: boolean;
|
||||
/** Node pool size for memory reuse (default: 1000, set to 0 to disable pooling) */
|
||||
poolSize?: number;
|
||||
/** Whether to enable HTMLString caching for deduplicating repeated HTML fragments (default: true) */
|
||||
contentCache?: boolean;
|
||||
};
|
||||
assetsPrefix?: AssetsPrefix;
|
||||
renderers: SSRLoadedRenderer[];
|
||||
/**
|
||||
* Based on Astro config's `output` option, `true` if "server" or "hybrid".
|
||||
*
|
||||
* Whether this application is SSR-like. If so, this has some implications, such as
|
||||
* the creation of `dist/client` and `dist/server` folders.
|
||||
*/
|
||||
serverLike: boolean;
|
||||
/**
|
||||
* The middleware mode determines when and how middleware executes.
|
||||
* - 'classic' (default): Build-time for prerendered pages, request-time for SSR pages
|
||||
* - 'edge': Middleware deployed as separate edge function
|
||||
*/
|
||||
middlewareMode: MiddlewareMode;
|
||||
/**
|
||||
* 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>;
|
||||
serverIslandMappings?: () => Promise<ServerIslandMappings> | ServerIslandMappings;
|
||||
key: Promise<CryptoKey>;
|
||||
i18n: SSRManifestI18n | undefined;
|
||||
middleware?: () => Promise<AstroMiddlewareInstance> | AstroMiddlewareInstance;
|
||||
logger?: () => Promise<{
|
||||
default: AstroLoggerDestination<AstroLoggerMessage>;
|
||||
}> | {
|
||||
default: AstroLoggerDestination<AstroLoggerMessage>;
|
||||
};
|
||||
actions?: () => Promise<SSRActions> | SSRActions;
|
||||
sessionDriver?: () => Promise<{
|
||||
default: SessionDriverFactory | null;
|
||||
}>;
|
||||
cacheProvider?: () => Promise<{
|
||||
default: CacheProviderFactory | null;
|
||||
}>;
|
||||
checkOrigin: boolean;
|
||||
allowedDomains?: Partial<RemotePattern>[];
|
||||
actionBodySizeLimit: number;
|
||||
serverIslandBodySizeLimit: number;
|
||||
sessionConfig?: SSRManifestSession;
|
||||
cacheConfig?: SSRManifestCache;
|
||||
cacheDir: URL;
|
||||
srcDir: URL;
|
||||
outDir: URL;
|
||||
rootDir: URL;
|
||||
publicDir: URL;
|
||||
assetsDir: string;
|
||||
buildClientDir: URL;
|
||||
buildServerDir: URL;
|
||||
csp: SSRManifestCSP | undefined;
|
||||
image: {
|
||||
objectFit?: string;
|
||||
objectPosition?: string;
|
||||
layout?: string;
|
||||
};
|
||||
shouldInjectCspMetaTags: boolean;
|
||||
devToolbar: {
|
||||
enabled: boolean;
|
||||
/**
|
||||
* Latest version of Astro, will be undefined if:
|
||||
* - unable to check
|
||||
* - the user has disabled the check
|
||||
* - the check has not completed yet
|
||||
* - the user is on the latest version already
|
||||
*/
|
||||
latestAstroVersion: string | undefined;
|
||||
debugInfoOutput: string | undefined;
|
||||
placement: DevToolbarPlacement | undefined;
|
||||
};
|
||||
internalFetchHeaders?: Record<string, string>;
|
||||
logLevel: AstroLoggerLevel;
|
||||
experimentalLogger: LoggerHandlerConfig | undefined;
|
||||
};
|
||||
export type SSRActions = {
|
||||
server: Record<string, ActionClient<any, any, any>>;
|
||||
};
|
||||
export type SSRManifestI18n = {
|
||||
fallback: Record<string, string> | undefined;
|
||||
fallbackType: 'redirect' | 'rewrite';
|
||||
strategy: RoutingStrategies;
|
||||
locales: Locales;
|
||||
defaultLocale: string;
|
||||
domainLookupTable: Record<string, string>;
|
||||
domains: Record<string, string> | undefined;
|
||||
};
|
||||
export type SSRManifestCSP = {
|
||||
cspDestination: 'adapter' | 'meta' | 'header' | undefined;
|
||||
algorithm: CspAlgorithm;
|
||||
scriptHashes: string[];
|
||||
scriptResources: string[];
|
||||
isStrictDynamic: boolean;
|
||||
styleHashes: string[];
|
||||
styleResources: string[];
|
||||
directives: CspDirective[];
|
||||
};
|
||||
export interface SSRManifestSession extends BaseSessionConfig {
|
||||
driver: string;
|
||||
options?: Record<string, any> | undefined;
|
||||
}
|
||||
/** Public type exposed through the `astro:build:ssr` integration hook */
|
||||
export type SerializedSSRManifest = Omit<SSRManifest, 'middleware' | 'logger' | 'routes' | 'assets' | 'componentMetadata' | 'inlinedScripts' | 'clientDirectives' | 'serverIslandNameMap' | 'key' | 'rootDir' | 'srcDir' | 'cacheDir' | 'outDir' | 'publicDir' | 'buildClientDir' | 'buildServerDir'> & {
|
||||
rootDir: string;
|
||||
srcDir: string;
|
||||
cacheDir: string;
|
||||
outDir: string;
|
||||
publicDir: string;
|
||||
buildClientDir: string;
|
||||
buildServerDir: string;
|
||||
routes: SerializedRouteInfo[];
|
||||
assets: string[];
|
||||
componentMetadata: [string, SSRComponentMetadata][];
|
||||
inlinedScripts: [string, string][];
|
||||
clientDirectives: [string, string][];
|
||||
key: string;
|
||||
};
|
||||
/** @deprecated This will be removed in a future major version. */
|
||||
export type NodeAppHeadersJson = {
|
||||
pathname: string;
|
||||
headers: {
|
||||
key: string;
|
||||
value: string;
|
||||
}[];
|
||||
}[];
|
||||
export type CreateApp = (options?: {
|
||||
streaming?: boolean;
|
||||
}) => BaseApp;
|
||||
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
23
node_modules/astro/dist/core/app/validate-headers.d.ts
generated
vendored
Normal file
23
node_modules/astro/dist/core/app/validate-headers.d.ts
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import { type RemotePattern } from '@astrojs/internal-helpers/remote';
|
||||
/**
|
||||
* Parses a potentially comma-separated multi-value header (as produced by
|
||||
* proxy chains) and returns the first value, trimmed of whitespace.
|
||||
* Returns `undefined` when the header is absent or empty.
|
||||
*/
|
||||
export declare function getFirstForwardedValue(multiValueHeader: string | string[] | undefined): string | undefined;
|
||||
/**
|
||||
* Validate a host against allowedDomains.
|
||||
* Returns the host only if it matches an allowed pattern; otherwise, undefined.
|
||||
* This prevents SSRF attacks by ensuring the Host header is trusted.
|
||||
*/
|
||||
export declare function validateHost(host: string | undefined, protocol: string, allowedDomains?: Partial<RemotePattern>[]): string | undefined;
|
||||
/**
|
||||
* Validate forwarded headers (proto, host, port) against allowedDomains.
|
||||
* Returns validated values or undefined for rejected headers.
|
||||
* Uses strict defaults: http/https only for proto, rejects port if not in allowedDomains.
|
||||
*/
|
||||
export declare function validateForwardedHeaders(forwardedProtocol?: string, forwardedHost?: string, forwardedPort?: string, allowedDomains?: Partial<RemotePattern>[]): {
|
||||
protocol?: string;
|
||||
host?: string;
|
||||
port?: string;
|
||||
};
|
||||
84
node_modules/astro/dist/core/app/validate-headers.js
generated
vendored
Normal file
84
node_modules/astro/dist/core/app/validate-headers.js
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
import { matchPattern } from "@astrojs/internal-helpers/remote";
|
||||
function getFirstForwardedValue(multiValueHeader) {
|
||||
return multiValueHeader?.toString().split(",").map((e) => e.trim())[0];
|
||||
}
|
||||
function sanitizeHost(hostname) {
|
||||
if (!hostname) return void 0;
|
||||
if (/[/\\]/.test(hostname)) return void 0;
|
||||
return hostname;
|
||||
}
|
||||
function parseHost(host) {
|
||||
const parts = host.split(":");
|
||||
return {
|
||||
hostname: parts[0],
|
||||
port: parts[1]
|
||||
};
|
||||
}
|
||||
function matchesAllowedDomains(hostname, protocol, port, allowedDomains) {
|
||||
const hostWithPort = port ? `${hostname}:${port}` : hostname;
|
||||
const urlString = `${protocol}://${hostWithPort}`;
|
||||
if (!URL.canParse(urlString)) {
|
||||
return false;
|
||||
}
|
||||
const testUrl = new URL(urlString);
|
||||
return allowedDomains.some((pattern) => matchPattern(testUrl, pattern));
|
||||
}
|
||||
function validateHost(host, protocol, allowedDomains) {
|
||||
if (!host || host.length === 0) return void 0;
|
||||
if (!allowedDomains || allowedDomains.length === 0) return void 0;
|
||||
const sanitized = sanitizeHost(host);
|
||||
if (!sanitized) return void 0;
|
||||
const { hostname, port } = parseHost(sanitized);
|
||||
if (matchesAllowedDomains(hostname, protocol, port, allowedDomains)) {
|
||||
return sanitized;
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
function validateForwardedHeaders(forwardedProtocol, forwardedHost, forwardedPort, allowedDomains) {
|
||||
const result = {};
|
||||
if (forwardedProtocol) {
|
||||
if (allowedDomains && allowedDomains.length > 0) {
|
||||
const hasProtocolPatterns = allowedDomains.some((pattern) => pattern.protocol !== void 0);
|
||||
if (hasProtocolPatterns) {
|
||||
try {
|
||||
const testUrl = new URL(`${forwardedProtocol}://example.com`);
|
||||
const isAllowed = allowedDomains.some(
|
||||
(pattern) => matchPattern(testUrl, { protocol: pattern.protocol })
|
||||
);
|
||||
if (isAllowed) {
|
||||
result.protocol = forwardedProtocol;
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
} else if (/^https?$/.test(forwardedProtocol)) {
|
||||
result.protocol = forwardedProtocol;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (forwardedPort && allowedDomains && allowedDomains.length > 0) {
|
||||
const hasPortPatterns = allowedDomains.some((pattern) => pattern.port !== void 0);
|
||||
if (hasPortPatterns) {
|
||||
const isAllowed = allowedDomains.some((pattern) => pattern.port === forwardedPort);
|
||||
if (isAllowed) {
|
||||
result.port = forwardedPort;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (forwardedHost && forwardedHost.length > 0 && allowedDomains && allowedDomains.length > 0) {
|
||||
const protoForValidation = result.protocol || "https";
|
||||
const sanitized = sanitizeHost(forwardedHost);
|
||||
if (sanitized) {
|
||||
const { hostname, port: portFromHost } = parseHost(sanitized);
|
||||
const portForValidation = result.port || portFromHost;
|
||||
if (matchesAllowedDomains(hostname, protoForValidation, portForValidation, allowedDomains)) {
|
||||
result.host = sanitized;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
export {
|
||||
getFirstForwardedValue,
|
||||
validateForwardedHeaders,
|
||||
validateHost
|
||||
};
|
||||
Reference in New Issue
Block a user