import { NOOP_ACTIONS_MOD } from "../actions/noop-actions.js"; import { createI18nMiddleware } from "../i18n/middleware.js"; import { createOriginCheckMiddleware } from "./app/middlewares.js"; import { ActionNotFoundError } from "./errors/errors-data.js"; import { AstroError } from "./errors/index.js"; import { NOOP_MIDDLEWARE_FN } from "./middleware/noop-middleware.js"; import { sequence } from "./middleware/sequence.js"; import { RedirectSinglePageBuiltModule } from "./redirects/index.js"; import { RouteCache } from "./render/route-cache.js"; import { createDefaultRoutes } from "./routing/default.js"; import { NodePool } from "../runtime/server/render/queue/pool.js"; import { HTMLStringCache } from "../runtime/server/html-string-cache.js"; import { FORBIDDEN_PATH_KEYS } from "@astrojs/internal-helpers/object"; import { loadLogger } from "./logger/load.js"; class Pipeline { internalMiddleware; resolvedMiddleware = void 0; resolvedLogger = false; resolvedActions = void 0; resolvedSessionDriver = void 0; resolvedCacheProvider = void 0; compiledCacheRoutes = void 0; nodePool; htmlStringCache; logger; manifest; /** * "development" or "production" only */ runtimeMode; renderers; resolve; streaming; /** * Used to provide better error messages for `Astro.clientAddress` */ adapterName; clientDirectives; inlinedScripts; compressHTML; i18n; middleware; routeCache; /** * Used for `Astro.site`. */ site; /** * Array of built-in, internal, routes. * Used to find the route module */ defaultRoutes; actions; sessionDriver; cacheProvider; cacheConfig; serverIslands; constructor(logger, manifest, runtimeMode, renderers, resolve, streaming, adapterName = manifest.adapterName, clientDirectives = manifest.clientDirectives, inlinedScripts = manifest.inlinedScripts, compressHTML = manifest.compressHTML, i18n = manifest.i18n, middleware = manifest.middleware, routeCache = new RouteCache(logger, runtimeMode), site = manifest.site ? new URL(manifest.site) : void 0, defaultRoutes = createDefaultRoutes(manifest), actions = manifest.actions, sessionDriver = manifest.sessionDriver, cacheProvider = manifest.cacheProvider, cacheConfig = manifest.cacheConfig, serverIslands = manifest.serverIslandMappings) { this.logger = logger; this.manifest = manifest; this.runtimeMode = runtimeMode; this.renderers = renderers; this.resolve = resolve; this.streaming = streaming; this.adapterName = adapterName; this.clientDirectives = clientDirectives; this.inlinedScripts = inlinedScripts; this.compressHTML = compressHTML; this.i18n = i18n; this.middleware = middleware; this.routeCache = routeCache; this.site = site; this.defaultRoutes = defaultRoutes; this.actions = actions; this.sessionDriver = sessionDriver; this.cacheProvider = cacheProvider; this.cacheConfig = cacheConfig; this.serverIslands = serverIslands; this.internalMiddleware = []; if (i18n?.strategy !== "manual") { this.internalMiddleware.push( createI18nMiddleware(i18n, manifest.base, manifest.trailingSlash, manifest.buildFormat) ); } if (manifest.experimentalQueuedRendering.enabled) { this.nodePool = this.createNodePool( manifest.experimentalQueuedRendering.poolSize ?? 1e3, false ); if (manifest.experimentalQueuedRendering.contentCache) { this.htmlStringCache = this.createStringCache(); } } } /** * Resolves the middleware from the manifest, and returns the `onRequest` function. If `onRequest` isn't there, * it returns a no-op function */ async getMiddleware() { if (this.resolvedMiddleware) { return this.resolvedMiddleware; } if (this.middleware) { const middlewareInstance = await this.middleware(); const onRequest = middlewareInstance.onRequest ?? NOOP_MIDDLEWARE_FN; const internalMiddlewares = [onRequest]; if (this.manifest.checkOrigin) { internalMiddlewares.unshift(createOriginCheckMiddleware()); } this.resolvedMiddleware = sequence(...internalMiddlewares); return this.resolvedMiddleware; } else { this.resolvedMiddleware = NOOP_MIDDLEWARE_FN; return this.resolvedMiddleware; } } /** * Clears the cached middleware so it is re-resolved on the next request. * Called via HMR when middleware files change during development. */ clearMiddleware() { this.resolvedMiddleware = void 0; } /** * Resolves the logger destination from the manifest and updates the pipeline logger. * If the user configured `experimental.logger`, the bundled logger factory is loaded * and replaces the default console destination. This is lazy and only resolves once. */ async getLogger() { if (this.resolvedLogger) { return this.logger; } this.resolvedLogger = true; if (this.manifest.experimentalLogger) { this.logger = await loadLogger(this.manifest.experimentalLogger); } return this.logger; } async getActions() { if (this.resolvedActions) { return this.resolvedActions; } else if (this.actions) { return this.actions(); } return NOOP_ACTIONS_MOD; } async getSessionDriver() { if (this.resolvedSessionDriver !== void 0) { return this.resolvedSessionDriver; } if (this.sessionDriver) { const driverModule = await this.sessionDriver(); this.resolvedSessionDriver = driverModule?.default || null; return this.resolvedSessionDriver; } this.resolvedSessionDriver = null; return null; } async getCacheProvider() { if (this.resolvedCacheProvider !== void 0) { return this.resolvedCacheProvider; } if (this.cacheProvider) { const mod = await this.cacheProvider(); const factory = mod?.default || null; this.resolvedCacheProvider = factory ? factory(this.cacheConfig?.options) : null; return this.resolvedCacheProvider; } this.resolvedCacheProvider = null; return null; } async getServerIslands() { if (this.serverIslands) { return this.serverIslands(); } return { serverIslandMap: /* @__PURE__ */ new Map(), serverIslandNameMap: /* @__PURE__ */ new Map() }; } async getAction(path) { const pathKeys = path.split(".").map((key) => decodeURIComponent(key)); let { server } = await this.getActions(); if (!server || !(typeof server === "object")) { throw new TypeError( `Expected \`server\` export in actions file to be an object. Received ${typeof server}.` ); } for (const key of pathKeys) { if (FORBIDDEN_PATH_KEYS.has(key)) { throw new AstroError({ ...ActionNotFoundError, message: ActionNotFoundError.message(pathKeys.join(".")) }); } if (!Object.hasOwn(server, key)) { throw new AstroError({ ...ActionNotFoundError, message: ActionNotFoundError.message(pathKeys.join(".")) }); } server = server[key]; } if (typeof server !== "function") { throw new TypeError( `Expected handler for action ${pathKeys.join(".")} to be a function. Received ${typeof server}.` ); } return server; } async getModuleForRoute(route) { for (const defaultRoute of this.defaultRoutes) { if (route.component === defaultRoute.component) { return { page: () => Promise.resolve(defaultRoute.instance) }; } } if (route.type === "redirect") { return RedirectSinglePageBuiltModule; } else { if (this.manifest.pageMap) { const importComponentInstance = this.manifest.pageMap.get(route.component); if (!importComponentInstance) { throw new Error( `Unexpectedly unable to find a component instance for route ${route.route}` ); } return await importComponentInstance(); } else if (this.manifest.pageModule) { return this.manifest.pageModule; } throw new Error( "Astro couldn't find the correct page to render, probably because it wasn't correctly mapped for SSR usage. This is an internal error, please file an issue." ); } } createNodePool(poolSize, stats) { return new NodePool(poolSize, stats); } createStringCache() { return new HTMLStringCache(1e3); } } export { Pipeline };