| import fs, { readFileSync } from "node:fs"; | ||
| import { basename } from "node:path/posix"; | ||
| import colors from "piccolore"; | ||
| import { getOutDirWithinCwd } from "../../core/build/common.js"; | ||
| import { getTimeStat } from "../../core/build/util.js"; | ||
@@ -9,2 +8,3 @@ import { AstroError } from "../../core/errors/errors.js"; | ||
| import { isRemotePath, removeLeadingForwardSlash } from "../../core/path.js"; | ||
| import { getClientOutputDirectory } from "../../prerender/utils.js"; | ||
| import { getConfiguredImageService } from "../internal.js"; | ||
@@ -33,4 +33,5 @@ import { isESMImportedImage } from "../utils/imageKind.js"; | ||
| } else { | ||
| serverRoot = getOutDirWithinCwd(settings.config.outDir); | ||
| clientRoot = settings.config.outDir; | ||
| const clientOutputDir = getClientOutputDirectory(settings); | ||
| serverRoot = clientOutputDir; | ||
| clientRoot = clientOutputDir; | ||
| } | ||
@@ -37,0 +38,0 @@ return { |
@@ -65,2 +65,3 @@ import fsMod, { existsSync, promises as fs } from "node:fs"; | ||
| CLOUDFLARE_WRANGLER_CONFIG: (name, compatibilityDate) => `{ | ||
| "$schema": "./node_modules/wrangler/config-schema.json", | ||
| "compatibility_date": ${JSON.stringify(compatibilityDate)}, | ||
@@ -67,0 +68,0 @@ "compatibility_flags": ["global_fetch_strictly_public"], |
| class BuildTimeAstroVersionProvider { | ||
| // Injected during the build through esbuild define | ||
| version = "6.4.6"; | ||
| version = "6.4.7"; | ||
| } | ||
@@ -5,0 +5,0 @@ export { |
@@ -70,3 +70,3 @@ import type { AstroComponentFactory } from '../runtime/server/index.js'; | ||
| /** | ||
| * Allows to pass `Astro.props` to an Astro component: | ||
| * Allows passing `Astro.props` to an Astro component: | ||
| * | ||
@@ -79,5 +79,5 @@ * ```js | ||
| /** | ||
| * When `false`, it forces to render the component as it was a full-fledged page. | ||
| * When `false`, it forces the component to render as if it were a full-fledged page. | ||
| * | ||
| * By default, the container API render components as [partials](https://docs.astro.build/en/basics/astro-pages/#page-partials). | ||
| * By default, the container API renders components as [partials](https://docs.astro.build/en/basics/astro-pages/#page-partials). | ||
| * | ||
@@ -84,0 +84,0 @@ */ |
@@ -200,3 +200,3 @@ import { existsSync, promises as fs } from "node:fs"; | ||
| } | ||
| if (previousAstroVersion && previousAstroVersion !== "6.4.6") { | ||
| if (previousAstroVersion && previousAstroVersion !== "6.4.7") { | ||
| logger.info("Astro version changed"); | ||
@@ -209,4 +209,4 @@ shouldClear = true; | ||
| } | ||
| if ("6.4.6") { | ||
| this.#store.metaStore().set("astro-version", "6.4.6"); | ||
| if ("6.4.7") { | ||
| this.#store.metaStore().set("astro-version", "6.4.7"); | ||
| } | ||
@@ -213,0 +213,0 @@ if (currentConfigDigest) { |
@@ -73,3 +73,3 @@ import type { MarkdownHeading } from '@astrojs/internal-helpers/markdown'; | ||
| export declare function renderEntry(entry: DataEntry): Promise<RenderResult>; | ||
| export declare function createReference(): (collection: string) => z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{ | ||
| export declare function createReference(): (collection: string) => z.ZodPipe<z.ZodUnion<readonly [z.ZodPipe<z.ZodNumber, z.ZodTransform<string, number>>, z.ZodString, z.ZodObject<{ | ||
| id: z.ZodString; | ||
@@ -76,0 +76,0 @@ collection: z.ZodString; |
@@ -487,2 +487,3 @@ import { escape } from "html-escaper"; | ||
| return z.union([ | ||
| z.number().transform((num) => num.toString(10)), | ||
| z.string(), | ||
@@ -489,0 +490,0 @@ z.object({ |
@@ -17,3 +17,2 @@ import { | ||
| import { setRenderOptions } from "./render-options.js"; | ||
| import { MultiLevelEncodingError } from "../util/pathname.js"; | ||
| class BaseApp { | ||
@@ -241,16 +240,9 @@ manifest; | ||
| let response; | ||
| try { | ||
| 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); | ||
| } | ||
| } catch (err) { | ||
| if (err instanceof MultiLevelEncodingError) { | ||
| return new Response("Bad Request", { status: 400 }); | ||
| } | ||
| throw err; | ||
| 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); | ||
| } | ||
@@ -257,0 +249,0 @@ this.#warnMissingFeatures(); |
@@ -110,2 +110,3 @@ import { isCSSRequest } from "vite"; | ||
| for (const id of Object.keys(chunk.modules)) { | ||
| if (!isCSSRequest(id)) continue; | ||
| for (const pageData of getParentClientOnlys(id, this, internals)) { | ||
@@ -112,0 +113,0 @@ for (const importedCssImport of meta.importedCss) { |
@@ -1,2 +0,2 @@ | ||
| const ASTRO_VERSION = "6.4.6"; | ||
| const ASTRO_VERSION = "6.4.7"; | ||
| const ASTRO_GENERATOR = `Astro v${ASTRO_VERSION}`; | ||
@@ -3,0 +3,0 @@ const REROUTE_DIRECTIVE_HEADER = "X-Astro-Reroute"; |
@@ -40,3 +40,3 @@ import fs from "node:fs"; | ||
| const logger = restart.container.logger; | ||
| const currentVersion = "6.4.6"; | ||
| const currentVersion = "6.4.7"; | ||
| const isPrerelease = currentVersion.includes("-"); | ||
@@ -43,0 +43,0 @@ if (!isPrerelease) { |
@@ -32,2 +32,3 @@ import colors from "piccolore"; | ||
| import { normalizeUrl } from "../util/normalized-url.js"; | ||
| import { validateAndDecodePathname } from "../util/pathname.js"; | ||
| import { getOriginPathname, setOriginPathname } from "../routing/rewrite.js"; | ||
@@ -682,3 +683,3 @@ import { computePathnameFromDomain } from "../i18n/domain.js"; | ||
| try { | ||
| return decodeURI(pathname); | ||
| return validateAndDecodePathname(pathname); | ||
| } catch (e) { | ||
@@ -685,0 +686,0 @@ this.pipeline.logger.error(null, e.toString()); |
@@ -279,3 +279,3 @@ import colors from "piccolore"; | ||
| ` ${bgGreen(black(` ${commandName} `))} ${green( | ||
| `v${"6.4.6"}` | ||
| `v${"6.4.7"}` | ||
| )} ${headline}` | ||
@@ -282,0 +282,0 @@ ); |
@@ -6,2 +6,3 @@ import { type Plugin as VitePlugin } from 'vite'; | ||
| export declare const MIDDLEWARE_MODULE_ID = "virtual:astro:middleware"; | ||
| export declare function isMiddlewarePath(relativePath: string): boolean; | ||
| export declare function vitePluginMiddleware({ settings }: { | ||
@@ -8,0 +9,0 @@ settings: AstroSettings; |
@@ -14,2 +14,5 @@ import { fileURLToPath } from "node:url"; | ||
| const NOOP_MIDDLEWARE = "\0noop-middleware"; | ||
| function isMiddlewarePath(relativePath) { | ||
| return relativePath.startsWith(`${MIDDLEWARE_PATH_SEGMENT_NAME}.`) || relativePath.startsWith(`${MIDDLEWARE_PATH_SEGMENT_NAME}/`); | ||
| } | ||
| function vitePluginMiddleware({ settings }) { | ||
@@ -30,3 +33,3 @@ let resolvedMiddlewareId = void 0; | ||
| const relativePath = normalizedPath.slice(normalizedSrcDir.length); | ||
| if (!relativePath.startsWith(`${MIDDLEWARE_PATH_SEGMENT_NAME}.`)) return; | ||
| if (!isMiddlewarePath(relativePath)) return; | ||
| for (const name of [ | ||
@@ -140,4 +143,5 @@ ASTRO_VITE_ENVIRONMENT_NAMES.ssr, | ||
| MIDDLEWARE_MODULE_ID, | ||
| isMiddlewarePath, | ||
| vitePluginMiddleware, | ||
| vitePluginMiddlewareBuild | ||
| }; |
| import { collapseDuplicateSlashes } from "@astrojs/internal-helpers/path"; | ||
| import { MultiLevelEncodingError, validateAndDecodePathname } from "./pathname.js"; | ||
| import { validateAndDecodePathname } from "./pathname.js"; | ||
| function createNormalizedUrl(requestUrl) { | ||
@@ -9,6 +9,3 @@ return normalizeUrl(new URL(requestUrl)); | ||
| url.pathname = validateAndDecodePathname(url.pathname); | ||
| } catch (e) { | ||
| if (e instanceof MultiLevelEncodingError) { | ||
| throw e; | ||
| } | ||
| } catch { | ||
| try { | ||
@@ -15,0 +12,0 @@ url.pathname = decodeURI(url.pathname); |
@@ -5,2 +5,6 @@ /** | ||
| * (e.g., returning a 400 response) rather than falling back to partial decoding. | ||
| * | ||
| * @deprecated No longer thrown internally — multi-level encoding is now | ||
| * decoded iteratively instead of rejected. Kept for backwards compatibility | ||
| * in case third-party code references the class. | ||
| */ | ||
@@ -11,11 +15,13 @@ export declare class MultiLevelEncodingError extends Error { | ||
| /** | ||
| * Validates that a pathname is not multi-level encoded. | ||
| * Detects if a pathname contains encoding that was encoded again (e.g., %2561dmin where %25 decodes to %). | ||
| * This prevents double/triple encoding bypasses of security checks. | ||
| * Decodes a pathname iteratively until stable, collapsing all levels of | ||
| * percent-encoding into a single canonical form. This prevents | ||
| * double/triple encoding from bypassing middleware authorization checks | ||
| * (CVE-2025-66202) — instead of rejecting multi-level encoding, we | ||
| * fully resolve it so middleware always sees the true decoded path. | ||
| * | ||
| * @param pathname - The pathname to validate | ||
| * @returns The decoded pathname if valid | ||
| * @throws MultiLevelEncodingError if multi-level encoding is detected | ||
| * @throws Error if the pathname contains invalid URL encoding | ||
| * @param pathname - The pathname to decode | ||
| * @returns The fully decoded pathname | ||
| * @throws Error if the pathname contains invalid URL encoding that | ||
| * cannot be decoded at all (e.g., a bare `%` not followed by hex digits) | ||
| */ | ||
| export declare function validateAndDecodePathname(pathname: string): string; |
@@ -7,7 +7,3 @@ class MultiLevelEncodingError extends Error { | ||
| } | ||
| const ENCODING_REGEX = /%25[0-9a-fA-F]{2}/; | ||
| function validateAndDecodePathname(pathname) { | ||
| if (ENCODING_REGEX.test(pathname)) { | ||
| throw new MultiLevelEncodingError(); | ||
| } | ||
| let decoded; | ||
@@ -19,4 +15,11 @@ try { | ||
| } | ||
| if (ENCODING_REGEX.test(decoded)) { | ||
| throw new MultiLevelEncodingError(); | ||
| let iterations = 0; | ||
| while (decoded !== pathname && iterations < 10) { | ||
| pathname = decoded; | ||
| try { | ||
| decoded = decodeURI(pathname); | ||
| } catch { | ||
| break; | ||
| } | ||
| iterations++; | ||
| } | ||
@@ -23,0 +26,0 @@ return decoded; |
@@ -1,2 +0,6 @@ | ||
| import { appendForwardSlash, joinPaths } from "@astrojs/internal-helpers/path"; | ||
| import { | ||
| appendForwardSlash, | ||
| joinPaths, | ||
| removeTrailingForwardSlash | ||
| } from "@astrojs/internal-helpers/path"; | ||
| import { shouldAppendForwardSlash } from "../core/build/util.js"; | ||
@@ -58,3 +62,3 @@ import { REROUTE_DIRECTIVE_HEADER } from "../core/constants.js"; | ||
| } else { | ||
| relativePath = joinPaths(...pathsToJoin); | ||
| relativePath = removeTrailingForwardSlash(joinPaths(...pathsToJoin)); | ||
| } | ||
@@ -61,0 +65,0 @@ if (relativePath === "") { |
@@ -90,3 +90,3 @@ import { AstroJSX, isVNode } from "../../jsx-runtime/index.js"; | ||
| } | ||
| if ("slot" in child.props) { | ||
| if ("slot" in child.props && !isCustomElement) { | ||
| _slots[child.props.slot] = [..._slots[child.props.slot] ?? [], child]; | ||
@@ -120,2 +120,3 @@ delete child.props.slot; | ||
| }; | ||
| const isCustomElement = typeof vnode.type === "string" && vnode.type.includes("-"); | ||
| extractSlots2(children); | ||
@@ -122,0 +123,0 @@ for (const [key, value] of Object.entries(props)) { |
@@ -54,3 +54,4 @@ import { markHTMLString } from "../escape.js"; | ||
| ); | ||
| content += styles.join("\n") + links.join("\n") + scripts.join("\n"); | ||
| const sep = result.compressHTML === true || result.compressHTML === "jsx" ? "" : "\n"; | ||
| content += styles.join(sep) + links.join(sep) + scripts.join(sep); | ||
| content += result._metadata.extraHead.join(""); | ||
@@ -57,0 +58,0 @@ return markHTMLString(content); |
| import { isRunnableDevEnvironment } from "vite"; | ||
| import { VIRTUAL_PAGE_RESOLVED_MODULE_ID } from "../vite-plugin-pages/const.js"; | ||
| import { RESOLVED_MODULE_DEV_CSS_PREFIX } from "../vite-plugin-css/const.js"; | ||
| import { getDevCssModuleNameFromPageVirtualModuleName } from "../vite-plugin-css/util.js"; | ||
| import { isAstroServerEnvironment } from "../environments.js"; | ||
| const STYLE_EXT_REGEX = /\.(?:css|scss|sass|less|styl|pcss)$/i; | ||
| const RAW_QUERY_REGEX = /(?:\?|&)raw(?:&|$)/; | ||
| function hasStyleExtension(id) { | ||
| return STYLE_EXT_REGEX.test(id.split("?")[0]); | ||
| } | ||
| function isStyleModule(mod) { | ||
| if (mod.file && STYLE_EXT_REGEX.test(mod.file)) return true; | ||
| if (mod.id) { | ||
| const idPath = mod.id.split("?")[0]; | ||
| if (STYLE_EXT_REGEX.test(idPath)) return true; | ||
| } | ||
| return false; | ||
| if (mod.id && RAW_QUERY_REGEX.test(mod.id) && hasStyleExtension(mod.id)) return false; | ||
| if (mod.file && hasStyleExtension(mod.file)) return true; | ||
| return mod.id ? hasStyleExtension(mod.id) : false; | ||
| } | ||
@@ -68,2 +70,13 @@ function hmrReload() { | ||
| if (hasSkippedStyleModules) { | ||
| for (const [id, mod] of this.environment.moduleGraph.idToModuleMap) { | ||
| if (id.startsWith(RESOLVED_MODULE_DEV_CSS_PREFIX)) { | ||
| this.environment.moduleGraph.invalidateModule(mod, void 0, timestamp, true); | ||
| if (isRunnableDevEnvironment(this.environment)) { | ||
| const runnerMod = this.environment.runner.evaluatedModules.getModuleById(id); | ||
| if (runnerMod) { | ||
| this.environment.runner.evaluatedModules.invalidateModule(runnerMod); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return []; | ||
@@ -70,0 +83,0 @@ } |
| import type { Plugin as VitePlugin } from 'vite'; | ||
| import type { RoutesList } from '../types/astro.js'; | ||
| import type { RouteData } from '../types/public/internal.js'; | ||
| export declare const VIRTUAL_PAGES_MODULE_ID = "virtual:astro:pages"; | ||
@@ -7,3 +8,13 @@ interface PagesPluginOptions { | ||
| } | ||
| /** | ||
| * Filters routes for a specific build environment. | ||
| * | ||
| * Redirect target routes do not need special handling here: they already | ||
| * appear in the routes list with their own `prerender` flag and are | ||
| * included when it matches `isPrerender`. At SSR runtime, redirect | ||
| * responses are generated from route metadata alone (no component is | ||
| * loaded), so the target's component is never needed in the SSR page map. | ||
| */ | ||
| export declare function getRoutesForEnvironment(routes: RouteData[], isPrerender: boolean): Set<RouteData>; | ||
| export declare function pluginPages({ routesList }: PagesPluginOptions): VitePlugin; | ||
| export {}; |
@@ -14,5 +14,2 @@ import { DEFAULT_COMPONENTS } from "../core/routing/default.js"; | ||
| } | ||
| if (route.redirectRoute) { | ||
| result.add(route.redirectRoute); | ||
| } | ||
| } | ||
@@ -79,3 +76,4 @@ return result; | ||
| VIRTUAL_PAGES_MODULE_ID, | ||
| getRoutesForEnvironment, | ||
| pluginPages | ||
| }; |
+4
-4
| { | ||
| "name": "astro", | ||
| "version": "6.4.6", | ||
| "version": "6.4.7", | ||
| "description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.", | ||
@@ -169,4 +169,4 @@ "type": "module", | ||
| "@astrojs/internal-helpers": "0.10.0", | ||
| "@astrojs/telemetry": "3.3.2", | ||
| "@astrojs/markdown-remark": "7.2.0" | ||
| "@astrojs/markdown-remark": "7.2.0", | ||
| "@astrojs/telemetry": "3.3.2" | ||
| }, | ||
@@ -177,3 +177,3 @@ "optionalDependencies": { | ||
| "devDependencies": { | ||
| "@astrojs/compiler-rs": "^0.1.6", | ||
| "@astrojs/compiler-rs": "^0.2.2", | ||
| "@playwright/test": "1.58.2", | ||
@@ -180,0 +180,0 @@ "@types/aria-query": "^5.0.4", |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
2832965
0.08%74681
0.05%