Skip to content

AstroEco is Contributing…

Display your GitHub pull requests using astro-loader-github-prs

withastro/astro

Changes

The markdown.processor part of withastro/roadmap#1364, please see the RFC for details.

Testing

Updated tests that relied on specific remark plugins and what not. Added tests using a custom processor to make sure it works from e2e

Docs

withastro/docs#13919

withastro/astro

Changes

Added a minimal reproduction for the transport invoke timed out after 60000ms error that occurs when running Astro dev server inside Docker with WSL2 backend on Windows, and also on macOS.

Reproduction is located at reproductions/docker-wsl-timeout/ and includes:

  • Dockerfile
  • docker-compose.yml
  • package.json
  • README.md with steps to reproduce

Testing

This was tested by following the Docker/WSL2 setup described in the README. The error appears in container logs after starting the dev server and hitting http://localhost:4321.

No code changes were made to the core Astro package, so no changeset is needed.

Docs

No docs changes needed. This only adds a reproduction case for an existing open issue.

withastro/astro

Changes

  • Upgrades @flue/sdk@0.3.10@flue/runtime@0.7.0 and @flue/cli@0.3.10@flue/cli@0.7.0. The SDK package was renamed to @flue/runtime in 0.6.0.
  • Migrates all agents and workflows from the removed defineCommand/commands API to the new local() sandbox factory from @flue/runtime/node. The local() sandbox runs commands directly on the host via child_process.exec, so shell pipes work natively — fixing a bug where piped commands (e.g. gh ... | node -e "...") hung indefinitely under the old in-memory bash emulator.
  • Updates structured output calls to destructure { data } from prompt()/skill() results, matching the new return shape.

The pipe bug caused a triage job timeout when the verify agent ran gh issue view | node -e "..." — the old defineCommand executor used execFile which cannot pipe stdin between commands.

Testing

  • Created a temporary test-node-pipe agent that exercises plain node -e, echo | node -e, and gh | node -e — all three pass with the new local() sandbox. The test agent is not included in this PR.

Docs

  • No docs update needed — these are internal CI agent infrastructure changes with no user-facing impact.
withastro/astro

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to 5-legacy, this PR will be updated.

Releases

astro@5.18.2

Patch Changes

  • #16813 8f7d8c4 Thanks @matthewp! - Populates styles in the SSR manifest for prerendered routes. Previously, prerendered routes had styles: [] in the manifest, making it impossible for workers or middleware to discover which CSS files a prerendered page uses.
withastro/astro

Fixes #16838.

Changes

The problem (#16838): @astrojs/sitemap writes per-URL <lastmod> into the child sitemaps but never into the <sitemap> entries of sitemap-index.xml. The index gets a <lastmod> only if you set the global lastmod option, and then every entry carries the same date. So the index cannot tell a crawler which child sitemap actually changed — even though the freshness data is already computed and sitting in the child sitemaps.

This PR derives each index entry's <lastmod> from the child sitemap it points to:

  • Each <sitemap> entry is stamped with the most recent <lastmod> among the URLs that land in that file. URLs are written in source order, limit per file, so the date is computed from items.slice(i * limit, (i + 1) * limit).
  • Works for both chunked (chunks) and non-chunked output, and stays accurate when a sitemap overflows into multiple numbered files.
  • When a child sitemap has no per-URL lastmod, the entry falls back to the configured lastmod option — existing behaviour preserved.
  • customSitemaps entries keep using the global lastmod (there are no items to derive a date from).

Before / after, for the reproduction in #16838:

<!-- before -->
<sitemap><loc>https://example.com/sitemap-0.xml</loc></sitemap>

<!-- after -->
<sitemap><loc>https://example.com/sitemap-0.xml</loc><lastmod>2024-09-15T00:00:00.000Z</lastmod></sitemap>

The changeset is patch. It is a behaviour change for anyone setting per-URL lastmod via serialize (their index now carries accurate per-file dates), so happy to bump to minor if preferred.

Testing

New test/index-lastmod.test.ts:

  • Chunked — distinct lastmod values across blog/glossary chunks; asserts each index entry surfaces the newest date in its child sitemap, and that a chunk with no per-URL lastmod falls back to the configured lastmod.
  • Non-chunked, multiple filesentryLimit: 1 so each URL gets its own file; asserts every index entry's lastmod equals the date in the child sitemap it points to (exercises the per-file slicing for i > 0).

Full @astrojs/sitemap suite passes (40/40). biome, eslint, knip, and tsc -b are clean.

Docs

No docs change needed — this refines the existing lastmod behaviour with no new or changed API surface. The lastmod option keeps working as a fallback for child sitemaps without per-URL dates.

withastro/astro

Changes

Document on config reference page that compressHTML: "jsx" is only available starting Astro 6.2.0.

Without this reference, it looks like the option has always been available but users of older versions (e.g. 6.1.9) will see the following message that contradicts current documentation:

[config] Astro found issue(s) with your configuration:

! compressHTML: Expected type "boolean", received "string"

I tried to follow the writing style from i18n.routing which also introduced a new option, by starting the sentence similarly.

From some past PRs I checked, doesn't seem like minor doc text change requires changeset, please correct me otherwise.

Testing

Not tested since it's a doc text change.

Docs

This is a doc change itself, which I previously mistakenly tried to do on the generated doc: withastro/docs#13920

withastro/starlight

Description

This PR disables the minimum release age check of 3 days recently added for withastro/automation updates.

While reviewing #3903, and even after retrying the PR, I was confused why the renovate/stability-days check was still pending, even though all the updates were released around 10 days ago (last change for withastro/automation - last release for pnpm/action-setup).

I'm not a Renovate expert, but I think I finally understand the reason:

  • The withastro/automation is a digest update as we're using the latest commit SHA on the main branch in workflow files without a version tag (@<sha> # main).
  • As documented here, for digest updates, having a release timestamp that can have minimumReleaseAge enforced is "Generally not supported".
  • In Renovate 42, the absence of a release timestamp will be treated as if the release is not yet past the timestamp, which provides a safer default.

I'm not 100% sure, but I think this is the reason why the renovate/stability-days check is still pending, and will probably be always pending, preventing us from merging other updates.

A few extra points:

  • If merging this PR and retrying #3903 does not resolve the issue, we can revert this PR and investigate further.
  • If this works, it could still be a short-term solution and maybe a more long term solution would be to add proper releases with tags to withastro/automation.
  • No matter what we end up doing, we will probably need to do the same to the Docs repo as I think withastro/docs#13873 may have the same issue.
withastro/starlight

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

@astrojs/starlight@0.39.3

Patch Changes

withastro/astro

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

astro@6.3.8

Patch Changes

  • #16830 f2bf3cb Thanks @matthewp! - Fixes 404s for dynamically imported JS chunks when using an adapter with assetQueryParams (e.g. Vercel skew protection)

  • #16831 ace96ba Thanks @astrobot-houston! - Fixes a misleading GetStaticPathsRequired error when a redirect is configured from a dynamic route to a static (or less-dynamic) destination. For example, '/project/[slug]': '/' previously produced a confusing error pointing at index.astro. Astro now detects the parameter mismatch at config validation time and throws a clear InvalidRedirectDestination error naming the missing parameters.

  • #16702 b7d1758 Thanks @matthewp! - Fixes scoped styles from .astro components being dropped when rendered inside MDX content (<Content /> from render(entry)) passed through a named slot using <Fragment slot="X">. The Fragment component now eagerly evaluates its slot contents to ensure propagating components register their styles before head content is flushed.

  • #16836 3d7adfa Thanks @LongYC! - Document compressHTML: "jsx" config is only available since Astro v6.2.0

@astrojs/cloudflare@13.5.5

Patch Changes

  • #16607 98297af Thanks @alexanderflodin! - Fixes incorrect assets.directory in the generated wrangler.json when a base path is configured

  • Updated dependencies []:

    • @astrojs/underscore-redirects@1.0.3
withastro/astro

Changes

  • Fixes misleading GetStaticPathsRequired error when redirects from dynamic routes to static destinations are configured (e.g., '/project/[slug]': '/')
  • Adds parameter validation in createRedirectRoutes() to check that destination routes have all required parameters from source routes
  • Extends InvalidRedirectDestination error message to clearly identify missing parameters, preventing confusion about which file is causing the issue

Testing

  • Added unit test for dynamic origin redirecting to static destination (/project/[slug]/)
  • Added unit test for dynamic origin with more params than destination (/old/[id]/[page]/posts/[id])
  • Both tests verify the error is InvalidRedirectDestination with clear parameter information, not the misleading GetStaticPathsRequired

Docs

  • No docs update needed, as this fixes an existing error case to be clearer rather than introducing new functionality.

Closes #16482

withastro/astro

Changes

  • Moves plugin-chunk-imports from renderChunk to generateBundle so it runs after Vite's CSS plugin cleans up pure CSS wrapper chunks. Previously, appending ?dpl=... query params during renderChunk broke Vite's regex-based /* empty css */ replacement, leaving dangling imports to deleted chunks that 404 at runtime.

Fixes #16520

Testing

  • New css-pure-chunk-query-params.test.ts with a Vue fixture where two async components share the same CSS import, forcing Rollup to create a shared pure CSS chunk. Verifies no JS imports reference deleted files, and that query params are still appended to surviving imports.

Docs

  • No docs needed — internal build pipeline fix with no user-facing API change.
withastro/astro

Changes

  • Adds GH_TOKEN to the "Remove Preview Label" step in the preview release workflow. PR #16810 replaced the actions-ecosystem/action-remove-labels action with a gh CLI call but did not set the token — gh requires GH_TOKEN explicitly, unlike GitHub Actions which inject auth automatically for actions.

Testing

  • No test changes. This is a CI-only fix — the step was failing with exit code 4 on every preview release since #16810 merged.

Docs

  • No docs needed — internal CI fix.
withastro/astro

Fixes #16817

When a tsconfig uses project references that include .vue or .svelte files, TypeScript's getOutputDeclarationFileName returns the input path unchanged (since changeExtension doesn't recognize these extensions). This creates self-referencing entries in the redirect maps (Hello.vueHello.vue), causing infinite recursion in findSourceFile.

The fix provides getParsedCommandLine on the language service host, which is TypeScript's official hook for customizing how referenced tsconfigs are parsed. Our implementation parses them normally but filters .vue/.svelte/.astro files from the file list, preventing the self-referencing redirect entries. Project references remain fully functional for all standard TS/JS files.

withastro/astro

Changes

  • Builds now properly fail when components throw errors during workerd prerendering, instead of silently producing truncated HTML with exit code 0
  • Dev mode now displays Astro's error overlay when rendering errors occur, matching the behavior of regular Astro dev servers
  • Creates separate non-streaming app instance for prerender requests so errors propagate synchronously as 500 responses instead of being deferred
  • Adds missing !response.ok check in prerenderer's render() method to detect and throw on error responses
  • Wraps response body streams in dev mode to catch mid-stream errors and inject error overlay scripts

Testing

  • Added prerenderer-render-errors.test.ts that verifies builds fail with clear error messages when components have missing imports
  • Test fixture includes intentionally broken component to trigger ReferenceError during rendering
  • Verified fix works for both build and dev modes with the issue reporter's test case

Docs

  • No docs update needed, this fixes broken behavior to match expected Astro error handling.

Closes #16809

withastro/astro

This PR targets astro-bot’s branch for #16783 and applies the requested CI/test clean up + a small dev-server regression test for the actual stale inline CSS behaviour. It does not change the fix implementation.

Changes

  • Adds idToModuleMap: new Map() to the existing hmr-reload.test.ts mock so it matches the new module graph iteration added in #16783.
  • Replaces the unsafe Function cast in hmr-css-invalidation.test.ts with a local typed hot update handler helper.
  • Adds a minimal dev-server fixture test that requests a getStaticPaths() route, edits global CSS, then verifies the next SSR response contains updated inline CSS.
  • Keeps the main CSS HMR invalidation implementation unchanged.

Testing

  • Fixes the current Test (astro) failure caused by the mocked environment.moduleGraph missing idToModuleMap.
  • Fixes the lint/type failure from @typescript-eslint/no-unsafe-function-type.
  • Keeps unit coverage for virtual:astro:dev-css:* module graph invalidation.
  • Adds integration-style coverage for the actual stale SSR inline CSS behavior using Astro’s dev server, fixture.fetch(), and fixture.editFile().

Docs

No docs changes needed. This only fixes internal dev-server HMR cache invalidation behavior and test coverage.

withastro/astro

Changes

  • Fixes CSS for conditionally rendered Svelte components being missing from production builds when the condition is false during SSR
  • During the SSR build, tracks which component exports were actually rendered (ssrRenderedExports on BuildInternals)
  • Saves CSS assets before deletion during client build deduplication and restores them only when the cssScopeTo target component was not rendered in SSR — meaning the styles were genuinely tree-shaken and missing from the page. CSS for components that were rendered in SSR (and already on the page) stays deleted to avoid duplicate stylesheets.
  • Updates test fixture to use deterministic condition ($state(false) with $effect()) instead of random condition that was passing by coincidence

Testing

  • Updated packages/integrations/svelte/test/fixtures/conditional-rendering/src/components/Parent.svelte to use $state(false) instead of Math.random() > 0.5 for deterministic reproduction
  • Existing conditional-rendering.test.ts now consistently verifies that conditionally rendered component CSS is included in production builds
  • Verified that the existing 0-css.test.ts "remove unused styles from client:load components" test continues to pass (CSS for normally rendered client:load components is still correctly deduplicated)

Docs

  • No docs update needed — this fixes existing documented behavior rather than introducing new functionality

Closes #16251

withastro/astro

Changes

Adds styleDirective.unsafeInline opt-in flag to Astro's CSP configuration (fixes #14798).

Per the CSP spec, browsers silently ignore unsafe-inline when hashes or nonces are present in the same directive. This meant users who needed unsafe-inline for styles (e.g. third-party libraries, inline style attributes) were forced to abandon Astro's CSP feature entirely — losing script hashing in the process.

When styleDirective.unsafeInline: true is set:

  • Astro emits unsafe-inline in style-src instead of style hashes
  • Script hashing is unaffected

Testing

Unit tests added in test/units/csp/rendering.test.ts covering:

  • unsafe-inline is emitted and style hashes are omitted when the flag is set
  • Script hashes are unaffected when the flag is set
  • Default behavior (hashes emitted, no unsafe-inline) is unchanged

Docs

The unsafeInline property is documented inline in config.ts alongside the existing hashes and resources properties. The CspStyleDirective exported type is also updated.

/cc @withastro/maintainers-docs for feedback!

withastro/astro

Changes

  • Fixes Node adapter in middleware mode incorrectly JSON-stringifying Buffer bodies from serverless-http
  • Adds binary data check (ArrayBuffer.isView() and instanceof ArrayBuffer) before generic object branch in makeRequestBody
  • Buffer, Uint8Array, and other typed arrays now pass through directly as valid BodyInit values

Testing

  • Added 5 new test cases in test/units/app/node.test.ts covering Buffer, Uint8Array, ArrayBuffer, plain objects, and strings
  • Verifies binary data passes through unchanged while preserving existing string/object handling
  • All existing tests pass with no regressions

Docs

  • No docs update needed, this restores expected behavior for a specific integration pattern

Closes #16820

withastro/astro

Changes

  • Custom elements (tags with hyphens like <my-element>) in MDX files now go through the renderer pipeline, matching .astro file behavior
  • Adds hyphen check in JSX runtime so custom elements fall through to renderComponentToString() instead of renderElement()
  • Preserves backward compatibility — custom elements with no registered renderer still render as raw HTML

Testing

  • Added unit tests in packages/astro/test/units/render/jsx-custom-elements.test.ts covering renderer pipeline integration and fallback behavior
  • Verified standard HTML elements continue using renderElement() path
  • Confirmed no regressions in existing MDX and render test suites

Docs

  • No docs update needed — this fixes existing documented behavior rather than introducing new functionality

Closes #16273

withastro/astro

Changes

  • normalizes the name field of wrangler.jsonc files that astro add cloudflare creates, ensuring that even if a project has a name incompatible with Cloudflare Worker's name constraint the command still produces a working project

Testing

  • manually I created a new astro project via npm create astro called "astro.app", I run npx astro add cloudflare on it and it generated a wrangler.jsonc file with the invalid name "astro.app", then I locally build astro and retried again with my version and the name in the wrangler.jsonc is now a correct "astro-app"
  • The astro add cloudflare command doesn't seem to be test covered

Docs

This is a self explanatory/minimal fix

withastro/astro

This change is so that users can look at manifest.routes[].styles and add Preload link headers. Previously we didn't include this information for prerendered routes because we didn't think it was necessary.

Changes

  • Populates external stylesheet URLs in the SSR manifest for prerendered routes. Previously these had styles: [], making it impossible for workers to discover which CSS files belong to a prerendered page. Inline styles are still omitted (already in the HTML).

Testing

  • No test changes — this is a data-only change to the serialized manifest.

Docs

  • No docs needed.
withastro/astro

Changes

This PR pin the exact version used by the merge-main-to-next workflow to match the same version we use in the repository. I should fix the failures.

Testing

Merge and wait once it's triggered again

Docs

N/A

withastro/astro

Changes

This PR adds:

  • zizmor to our CI to check for incorrect usage of our workflows. As for now, I tuned the tool to target high confidence and high severity
  • I run the tool in our actions, and applied the suggestions
    • removed an action from our preview release
    • removed a possible template injection

There's still a warning

warning[secrets-inherit]: secrets unconditionally inherited by called workflow
  --> .github/workflows/format.yml:12:11
   |
12 |     uses: withastro/automation/.github/workflows/format.yml@497c9268ad4267c842a8f6c4d830ad0182d6f6b3 # main
   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this reusable workflow
...
15 |     secrets: inherit
   |     ---------------- inherits all parent secrets
   |
   = note: audit confidence → High

However it's not easy fixable at the moment

Note

I plan to address even warnings, but for now I'll focus on high profile errors.

Testing

Green CI

Docs

withastro/astro

Changes

Closes #16781

It hardens and fixes the double encoding algorithm.

Testing

Added a bunch of unit tests, and an integration test.

Docs

N/A

withastro/astro

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

astro@6.3.7

Patch Changes

  • #16821 9c76b12 Thanks @astrobot-houston! - Fixes request body handling in the Node adapter when req.body is a Buffer, Uint8Array, or ArrayBuffer. Previously, binary body data was incorrectly JSON-stringified (producing {"type":"Buffer","data":[...]}) instead of being passed through directly. This affected libraries like serverless-http that set req.body to a Buffer.

  • #16785 de96360 Thanks @astrobot-houston! - Fixes vite.build.minify, vite.build.sourcemap, and vite.build.rollupOptions.output (e.g. compact) being ignored for client-side builds. These top-level Vite build options are now properly forwarded to the client environment, with environment-specific overrides (vite.environments.client.build.*) taking priority when set.

  • #16819 b5dd8f1 Thanks @astrobot-houston! - Fixes custom elements in MDX files bypassing the renderer pipeline. Custom elements (tags containing hyphens like <my-element>) in .mdx files are now routed through registered renderers for SSR, matching the behavior of .astro files. If no renderer claims the element, it falls back to rendering as raw HTML.

  • #16808 765896c Thanks @ematipico! - Fixes dynamic routes returning 400 Bad Request when the URL contains a literal % character, such as paths built with encodeURIComponent('%?.pdf')

  • #16804 90d2aca Thanks @jp-knj! - Fixes a v6 regression where astro:i18n could not be imported from client <script> blocks.

@astrojs/cloudflare@13.5.4

Patch Changes

  • #16769 428cb1b Thanks @astrobot-houston! - Forwards user-provided optimizeDeps settings (exclude, include, esbuildOptions.loader) to SSR/prerender environments. Previously, top-level vite.optimizeDeps in the Astro config was silently ignored for server environments because Vite 6 scopes it to client-only and the adapter's configEnvironment hook did not forward it. This caused packages with non-standard file types (e.g. .data files) to fail during dev-mode dependency optimization with errors like "No loader is configured for '.data' files".

  • Updated dependencies []:

    • @astrojs/underscore-redirects@1.0.3
withastro/astro

Adds guardrails to the triage skill so the agent bails out after 2 failed server starts instead of looping until timeout.

Prompted by this run where the agent confirmed the bug early but wasted ~10 minutes fighting a stale server process and ran out of time before writing its report.

Changes:

  • SKILL.md: General "don't get stuck" rule at the top level
  • reproduce.md: Server Management Rules subsection (bail after 2 failures, stop before restart, one repro run is enough, prefer build over dev/preview)
  • diagnose.md: Brief server management reminder in the instrumentation step
withastro/astro

Changes

It seems that emdash-cms/emdash#1116 was caused by #16708

This PR reverts it

Testing

Preview release

Docs

withastro/astro

Changes

  • Adds 5-legacy to the branches filter on the preview release workflow so PRs targeting 5-legacy can get preview releases via the pr preview label.

Testing

  • No test changes.

Docs

  • No docs needed.
withastro/astro

Changes

  • Re-enables all Svelte e2e tests that were disabled when the monorepo upgraded to Vite 8. @sveltejs/vite-plugin-svelte@6.2.4 now has experimental Vite 8 support, and all previously-skipped tests pass.
  • Uncomments @astrojs/svelte integration setup and Svelte component usage across 25 e2e fixture files (configs + pages), and removes .skip from 11 e2e test files.
  • The Cloudflare svelte-rune-deps test still fails (500 in dev mode) so it remains skipped with an updated reason. The async-rendering test is a separate Svelte upstream issue and was not touched.

Testing

  • No new tests added — this PR re-enables ~20 existing test cases across svelte-component, nested-in-svelte, nested-in-react, nested-in-vue, nested-in-preact, nested-in-solid, nested-recursive, client-only, csp-client-only, errors, and view-transitions e2e suites.

Docs

  • No docs needed — test-only change.

Closes AST-87

withastro/astro

Changes

This PR fixes this failure: https://github.com/withastro/astro/actions/runs/25864427348/job/76002567202#step:7:13

It's caused by conflicts=true, which leaves possible conflict markers in package.json. Then the pnpm action comes, and tries to use the version from the manifest, which is broken.

This PR pins the pnpm version to use in the GH action

Testing

Green CI. We will see if it works after the next release.

Docs

withastro/astro

Changes

  • Before creating a PR, the fix-verification agent now checks if one already exists for the flue/fix-{issueNumber} branch. If a PR exists, it posts a comment linking to it instead of failing with a 422 from the GitHub API.
  • Adds a findPullRequest helper to .flue/lib/github.ts that queries open PRs by head branch.

Testing

  • No automated tests; this is CI workflow glue code. Verified the logic matches the GitHub Pulls API behavior.

Docs

  • No docs needed — internal CI change only.
withastro/astro

Changes

Update esbuild and tsx to the latest versions. This reduces the vite instances installed under node_modules/ and resolves the test failure in Examples astro check / astro check CI job.

Before:

We have 3 vite instances installed. astro and @example/with-vitest use different vite.

$ git status
On branch chore/merge-main-into-next

$ pnpm -r why vite | egrep ' astro@|vite@8|@example|Found'
vite@8.0.13 peer#4033 (3 variations)
│   └── astro@7.0.0-alpha.1 (devDependencies)
├── astro@7.0.0-alpha.1 (dependencies)
│ └── astro@7.0.0-alpha.1 (dependencies)
vite@8.0.13 peer#5d0f (3 variations)
vite@8.0.13 peer#96d1 (3 variations)
│ ├── @example/with-tailwindcss@0.0.1 (dependencies)
│   ├── @example/container-with-vitest@0.0.1 (dependencies)
│   └── @example/with-vitest@0.0.1 (dependencies)

Found 1 version, 3 instances of vite

After:

We have 2 vite instances installed. astro and @example/with-vitest share the same vite.

$ git status
On branch ocavue/chore/merge-main-into-next

$ pnpm -r why vite | egrep ' astro@|vite@8|@example|Found'
vite@8.0.13 peer#1781 (2 variations)
│ ├── @example/with-tailwindcss@0.0.1 (dependencies)
│   ├── @example/container-with-vitest@0.0.1 (dependencies)
│   ├── astro@7.0.0-alpha.1 (devDependencies)
│   └── @example/with-vitest@0.0.1 (dependencies)
├── astro@7.0.0-alpha.1 (dependencies)
│ ├── astro@7.0.0-alpha.1 (dependencies)
vite@8.0.13 peer#ade4 (2 variations)

Found 1 version, 2 instances of vite

Testing

Docs

withastro/astro

Changes

  • Fixes vite.build.minify, vite.build.sourcemap, and rollup output options being ignored when configured through the top-level vite.build in astro.config.ts
  • Adds proper fallback chains so client environment config inherits from top-level Vite config, with environment-specific overrides taking highest priority
  • Resolves regression from Vite Environment API migration (PR #14306) where these options were hardcoded instead of respecting user configuration

Testing

  • Added 8 new unit tests in packages/astro/test/units/build/vite-build-config.test.ts covering minify, sourcemap, and rollup output inheritance scenarios
  • Tests verify environment-specific config takes priority over top-level config, which takes priority over defaults
  • Existing sourcemap integration tests continue to pass

Docs

  • No docs update needed, as this restores documented behavior that was broken by the Environment API migration

Closes #16268

withastro/astro

Changes

This PR improves the printed time stamp of the build

Testing

Added unit tests

Docs

N/A

withastro/astro

Changes

  • Fixes stale inline <style> tags in server-rendered HTML after CSS file edits during dev. CSS changes now properly update both client-side HMR and server-side inline styles, eliminating the flash of old CSS (FOUC) on fresh page loads.
  • Adds invalidation of virtual:astro:dev-css:* modules in both the SSR module graph and module runner evaluation cache when style files change during HMR. This ensures the next SSR render picks up fresh CSS while preserving the performance benefit of skipping full page reloads for CSS-only changes.

Testing

  • Added packages/astro/test/units/dev/hmr-css-invalidation.test.ts with 5 test cases covering CSS/SCSS invalidation, module graph behavior, non-style change passthrough, and edge cases.
  • Tests verify that dev-css virtual modules are properly invalidated when style files change and that non-style changes are unaffected.

Docs

  • No docs update needed, this fixes dev-only behavior to match user expectations.

Closes #16780

withastro/starlight

Description

Fixes #2697.

When the mobile menu is open on narrow viewports, Tab navigation currently escapes the menu after the last focusable element (the theme switcher) and lands on the underlying page content.

This PR extends the existing StarlightMenuButton custom element with a keydown handler that wraps Tab / Shift+Tab focus between the first and last visible focusable elements inside the surrounding <nav> while the menu is expanded (body[data-mobile-menu-expanded]).

The trap is scoped to the same <nav> already used for the Escape listener and is gated on the existing data attribute, so there is no behavioural change while the menu is closed.

Test plan

  • Added Playwright e2e coverage in packages/starlight/__e2e__/mobile-menu.test.ts:
    • Tab from the last focusable wraps to the first.
    • Shift+Tab from the first wraps to the last.
    • Trap does not engage while the menu is closed.
    • Escape still closes the menu and restores focus to the toggle (regression check).
  • All existing unit tests (519) and e2e tests pass locally.

Changeset

Patch bump for @astrojs/starlight included.

withastro/astro

Changes

  • Adds npm and npx as allowed commands in the triage agent's flue sandbox. The agent uses npx stackblitz-clone to clone issue reproductions, but npx wasn't a permitted command, causing the agent to waste time hunting for tools and ultimately fail (run).

Testing

  • No test changes. This is a configuration-only change to the flue agent definition.

Docs

  • No docs needed — internal CI tooling change.
withastro/astro

Changes

  • The HMR reload plugin now invalidates all recursively-invalidated modules in the SSR module runner's evaluatedModules cache, not just the directly changed file. moduleGraph.invalidateModule() already walks importers and populates an invalidatedModules set, but the runner cache only cleared the leaf module. Barrel files (e.g. index.ts re-exporting components) stayed cached, so await import("../components") returned stale exports even after a full page reload.

Fixes #16000

Testing

  • New unit test in hmr-reload.test.ts: "invalidates importers in the module graph for dynamic import chains" -- sets up a component with a barrel file importer and verifies the invalidation propagates through the mock module graph.
  • Updated mock invalidateModule to simulate Vite's recursive importer walk by adding importers to the seen set.

Docs

  • No docs changes needed. This is a bug fix restoring behavior from Astro 5.
withastro/astro

Changes

  • The route cache (callGetStaticPaths) now stores the module reference alongside cached static paths and compares identity on lookup. After HMR, mod is a new object from a fresh import(), so the cache treats the old entry as stale and re-calls getStaticPaths() with updated component references. This fixes the case where components passed as props via getStaticPaths() served stale content in dev — even on manual refresh.

Fixes #16522

Testing

  • New unit test in getstaticpaths-cache.test.ts: "re-calls getStaticPaths when module identity changes (HMR)" — calls callGetStaticPaths with one module, confirms cache hit on same module, then passes a different module object and asserts the cache is bypassed and fresh props are returned.

Docs

  • No docs changes needed. This is a bug fix restoring existing behavior from Astro 5.
withastro/astro

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

astro@6.3.6

Patch Changes

  • #16774 8f77583 Thanks @astrobot-houston! - Fixes markdown images with empty alt text (![](image.jpg)) in content collections dropping the alt attribute entirely. The alt="" attribute is now correctly preserved in the rendered HTML output, which is important for accessibility (indicating decorative images).

  • #16776 3d10b5e Thanks @matthewp! - Fixes HMR serving stale content when components are passed as props via getStaticPaths()

  • #16784 7453860 Thanks @ematipico! - Improved the printing of the build time if it goes over the 60 seconds.

  • #16665 3dbbcee Thanks @Princesseuh! - Fixes remote SVG sources erroring with dangerouslyProcessSVG after the v6.3 SVG-processing gate. The default Sharp service now resolves the output format from the source up-front when it can (URL extension, data: MIME, ESM metadata), and from the actual buffer at request time when it can't, so SVG sources pass through untouched without needing to set image.dangerouslyProcessSVG: true or an explicit format="svg".

    The error message has also been updated to point at format="svg" as the simpler workaround when an SVG source is encountered without dangerouslyProcessSVG enabled.

  • #16777 1754b91 Thanks @matthewp! - Fixes HMR serving stale content for dynamically imported components through barrel files

  • #16730 068d924 Thanks @harshagarwalnyu! - Fixes an issue where the file() content loader did not generate a valid JSON Schema for collections whose JSON or YAML data is a top-level array instead of an object.

@astrojs/cloudflare@13.5.3

Patch Changes

  • #16801 d619277 Thanks @ematipico! - Reverts a change to the esbuild dep-scan plugin that caused astro check and astro build to fail by making esbuild incorrectly bundle virtual: modules (e.g. from expressive-code)

  • Updated dependencies []:

    • @astrojs/underscore-redirects@1.0.3
withastro/astro

Changes

  • Fixes markdown images with empty alt text (![](image.jpg)) in content collections to render alt="" instead of dropping the attribute entirely
  • Replaces JavaScript truthiness check with explicit value != null filtering to preserve empty string attributes
  • Only affects content collections markdown path — pages-based markdown already handled this correctly

Testing

  • Added test 'content collection images with empty alt preserve the alt attribute' in packages/astro/test/core-image.test.ts to verify empty alt attributes are preserved
  • Verified all existing image, markdown, and content collection tests still pass

Docs

  • No docs update needed, this fixes a regression to match existing expected behavior

Closes #16621

withastro/astro

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

astro@6.3.5

Patch Changes

  • #16771 07c8805 Thanks @ematipico! - Fixes position prop on <Image> and <Picture> components breaking Content Security Policy (CSP).

  • #16593 50924ce Thanks @yanthomasdev! - Improves error messages with more consistent and correct writing.

  • #16757 5d661cd Thanks @astrobot-houston! - Fixes dev server serving stale content when SSR-only modules change (e.g. .astro files outside the project root in a monorepo, or dynamically imported components).

    Previously, the astro:hmr-reload plugin returned an empty array after detecting SSR-only module changes, which prevented Vite's updateModules from propagating the invalidation to the SSR module runner. The runner's evaluated module cache stayed stale, so subsequent requests continued returning old content.

    Now the plugin returns the SSR-only modules so Vite can process them through updateModules, which properly invalidates the module runner's cache and ensures fresh content on the next request.

withastro/starlight

Summary

  • fix a typo in the Romanian previous page label
  • translate remaining English strings in packages/starlight/translations/ro.json
  • add a changeset for the user-facing translation fix
withastro/astro

Changes

Closes #16656

The solution of #16236 doesn't work with CSP.

In this PR we extend the solution we already have by taking position into account too.

Testing

Added a bunch of unit tests and a couple of integration tests.

Docs

N/A

withastro/astro

Changes

  • Uses the server to do injectScript entrypoint discover to prevent a race condition with the dep optimizer.

Closes #16766. Related: #16387.

Testing

  • User confirmed the fix
  • Reproduced locally against npm-installed astro using the reporter's reproduction. Before fix: _metadata.json contained 1 entry. After fix: 10 entries including all React deps.
  • No new test — the race condition requires packages installed from npm (not workspace links) and timing-dependent optimizer behavior.

Docs

  • No docs changes needed.
withastro/astro

Changes

  • Forwards user-provided optimizeDeps.exclude, optimizeDeps.include, and optimizeDeps.esbuildOptions.loader from the Astro config to SSR/prerender environments in the Cloudflare adapter
  • Fixes packages with non-standard file extensions (like .data) failing during dev-mode dependency optimization
  • Resolves issue where top-level vite.optimizeDeps configuration was silently ignored for server environments due to Vite 6's client-scoped design

Testing

  • Added packages/integrations/cloudflare/test/user-optimize-deps.test.ts with a test that imports a package with .data files to verify the exclude configuration works
  • Test uses a fake-data-pkg fixture that would fail without the fix but succeeds when optimizeDeps.exclude is properly forwarded

Docs

  • No docs update needed, this fix restores expected behavior where user Vite config applies to all environments.

Closes #16491

withastro/astro

Root cause

The suggestion of Astro bot is included in #16124 . This fixing is clear the cache of disc. But it didn't solve the issue.
It seems the root cause is remaining cache of vite runner eveluatedModules cache.

Changes

Close #13149

Implemented invalidation for file paths and cache clearing in /packages/astro/src/content/vite-plugin-content-virtual-mod.ts.

Testing

Before Implementation

スクリーンショット 2026-05-17 0 00 19

After Implementation

スクリーンショット 2026-05-17 20 55 52
withastro/starlight

Description

This pull request, adds a simple new page template called blank that allows the end-user to fully customize what's rendered in the ContentPanel without having to worry about CSS hacks to hide things like the PageTitle which are present in the splash template. For more information see #3906

Additionally, it refactors a small section in the Page.astro that handles conditional rendering for pages with a hero image. Hopefully it improves visibility and maintainability in comparison to the previous version.

This pull request does not impact the default Starlight look.

withastro/astro

Summary

Fixes #14013.

On case-insensitive filesystems (Windows, macOS), starting astro dev from a working directory whose case differs from the actual filesystem case (e.g. d:\dev\app vs D:\dev\app) causes styles to be stripped from Astro components.

Root Cause

normalizeFilename in vite-plugin-utils/index.ts uses commonAncestorPath to decide whether an absolute path lives inside the project root. commonAncestorPath performs a case-sensitive string comparison. When the CWD (root) and the Vite-resolved module path (filename) disagree on case, the check fails and the path is incorrectly rewritten — producing a path that misses the compile-metadata cache and causes the virtual style module to be generated with no styles.

Fix

A small helper isPathInRoot is introduced. It first attempts an exact (fast) match via commonAncestorPath. If that fails, it retries with both paths lower-cased, matching the semantics of case-insensitive filesystems. The change is limited to this one fallback; it does not alter any other behaviour and has no performance impact on correct (same-case) paths.

function isPathInRoot(filename: string, rootPath: string) {
  return (
    commonAncestorPath(filename, rootPath) ||
    commonAncestorPath(filename.toLowerCase(), rootPath.toLowerCase())
  );
}

Tests

Added a unit test in test/units/vite-plugin-utils/normalize-filename.test.ts that directly reproduces the issue: normalizeFilename is called with a filename whose case differs from the root URL, and the function should return the original filename unchanged (i.e. not rewrite it onto the root).


This fix was contributed with AI assistance by SwarmFix (sulphur-swarm).

withastro/astro

Summary

Fix syntax highlighting for <style> and <script> tags when the lang or type attribute is on a different line from the opening tag.

Root Cause

The TextMate grammar regex used [^>]*? to scan for lang/type attributes within style/script tags. In Oniguruma (VS Code's regex engine), [^>] does not reliably match across newlines in all configurations, causing the language detection to fail when attributes span multiple lines. The content then falls back to default CSS highlighting.

Changes

  • astro.tmLanguage.src.yaml: Changed [^>]*?[\s\S]*? in all three language-detection patterns (JSON-LD, module/JS, and generic language)
  • astro.tmLanguage.json: Same change in compiled grammar
  • Test fixture: Added sass-multiline.astro covering SCSS, LESS, SASS, and CSS with both single-line and multi-line attribute layouts

Testing

  • Manually verified the regex matches using Node.js and Python
  • Added test fixture covering all style language types with both single-line and multi-line <style> tag layouts
  • Existing grammar snapshot tests should continue to pass (pnpm test:grammar)

Related

Fixes #14657
Closes draft PR #15066 (supersedes with proper YAML source + JSON update)

withastro/astro

Changes

There is a json schema file included in the wrangler npm package used to specify the structure of the cloudflare wrangler configurations.

This changes the astro add cloudflare command to include the schema reference when generating the wrangler.jsonc file.

  • I included a changeset

Testing

Doesn't look like there are any existing tests for the astro add command.

Tested it locally instead.

Screenshot 2026-05-16 at 1 31 44 PM

Docs

Sufficient documentation exists for the add command and the CLI walks the user through it.

withastro/astro

Changes

Assigns VS Code's registered dotenv language to .dev.vars env file used in the Cloudflare adapter.

Astro recommends using this file to store development-only environment variables when using the Cloudflare adapter, but VS Code displays it as plaintext rather than a dotenv file. This is the fix.

  • I included a changeset with this change

Before / After

Screenshot 2026-05-16 at 8 47 08 AM Screenshot 2026-05-16 at 8 46 33 AM

Testing

Tested using VS Code extension test runner.

Docs

Documentation exists for this file. Syntax highlighting will reassure new developers using Astro & Cloudflare workers that they are following documentation correctly.

withastro/astro

Summary

  • Adds a warning when a page partial's rendered component tree includes Astro component scripts or scoped styles that get stripped from the partial HTML output.
  • Warning fires once per route component per PagesHandler lifetime (deduped), so dev users see it on first request and prerender users see it once during build.
  • Detects via result._metadata.propagators.size > 0 after renderPage, which is exactly the runtime set populated by components the compiler marked as propagating (i.e. components with scoped <style> or hoisted <script> blocks).
  • Adds 4 regression unit tests using the existing SpyLogger + createBasicPipeline helpers.

Fixes #11885

Tests run

  • astro-scripts test "test/units/**/*.test.ts" --strip-types --teardown ./test/units/teardown.ts — 2622 passing, 0 failing
  • astro-scripts test "test/units/render/**/*.test.ts" --strip-types --teardown ./test/units/teardown.ts — 273 passing
  • astro-scripts test "test/partials*.test.ts" --strip-types --parallel — 3 passing (existing fixtures)
  • New test/units/render/partials-warnings.test.ts — 4 passing, covering:
    • warns when the tree includes propagating components
    • does not warn when the partial has no stripped assets
    • does not warn when the page is not a partial
    • warns exactly once across repeated renders
  • biome check and prettier -c clean on touched files.

Docs

No docs change strictly needed — the existing partials docs already describe the stripping behavior, and the warning links back to that section. Happy to add a note there if maintainers prefer.

withastro/astro

Changes

  • Handles CSS @property rules inside Astro <style> blocks before delegating to VS Code's generic CSS grammar.
  • Prevents the tokenizer from staying in CSS context after </style>, so following <style> and <script> blocks keep correct highlighting.

Testing

  • Adds a grammar fixture covering @property descriptors followed by additional style and script blocks.
  • Adds a snapshot assertion that the closing style tags and following script block keep Astro scopes.

Docs

  • No docs update needed because this fixes editor syntax highlighting behavior only.
withastro/astro

Changes

  • Fixes HMR for SSR-only modules in monorepo setups where shared components live outside the Astro project root
  • Changes astro:hmr-reload plugin to return SSR-only modules from hotUpdate instead of an empty array, allowing Vite's updateModules() to properly invalidate the SSR module runner cache
  • Resolves regression from Astro 4/5 where external file changes required dev server restart to be visible

Testing

  • Added comprehensive unit tests in packages/astro/test/units/vite-plugin-hmr-reload/hmr-reload.test.ts covering the key scenarios:
    • SSR-only modules are returned (not []) — the critical test that fails without the fix
    • Non-SSR environments are skipped correctly
    • Style-only modules continue to return [] as expected
    • Modules that exist in both client and SSR environments are excluded

Docs

  • No docs update needed, this fixes existing functionality to work as documented

Closes #16754

withastro/astro

Changes

  • Fixes getSSREnvironment() in module loader to return the passed ssrEnvironment parameter instead of hardcoded viteServer.environments['ssr']
  • Resolves missing styles from Markdoc/MDX custom components in <head> when using Cloudflare adapter with prerenderEnvironment: 'node' and wrapper components
  • The bug occurred because component metadata crawling used the wrong environment's module graph (empty workerd vs populated prerender)

Testing

  • Added packages/astro/test/units/dev/module-loader.test.ts with 2 unit tests confirming getSSREnvironment() returns the correct environment
  • Verified the fix resolves the issue in the reporter's reproduction case

Docs

  • No docs update needed, this fixes a bug with no API changes

Closes #16013

withastro/astro

Changes

Reverts the two-job build/publish split from #16710 back to a single job. The split caused artifact upload timeouts and workspace config mismatches after the pnpm v11 upgrade. Skipping the pnpm cache instead eliminates the cache poisoning vector without needing to shuttle artifacts between jobs.

Testing

CI-only workflow change, validated by triggering a preview release.

Docs

No docs needed — internal CI change.

withastro/astro

Changes

The hardened preview-release workflow (#16710) combined with the pnpm v11 upgrade broke preview releases. This generates a synthetic minimal workspace for the publish artifact and uses pnpm dlx to run pkg-pr-new without triggering workspace resolution. Also excludes test/src/e2e directories from the artifact to prevent upload timeouts.

Testing

  • Added smoke tests for the staging script (scripts/stage-preview-publish.test.ts).

Docs

No docs needed — internal CI change.

withastro/astro

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to next, this PR will be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

next is currently in pre mode so this branch has prereleases rather than normal releases. If you want to exit prereleases, run changeset pre exit on next.

⚠️⚠️⚠️⚠️⚠️⚠️

Releases

astro@7.0.0-alpha.2

Major Changes

  • #16725 10229f7 Thanks @ArmandPhilippot! - Removes deprecated APIs exported from astro:transitions.

    In Astro 6.x, some helpers available in astro:transitions and astro:transitions/client were deprecated.

    In Astro 7.0, the following APIs can no longer be used in your project:

    • TRANSITION_BEFORE_PREPARATION
    • TRANSITION_AFTER_PREPARATION
    • TRANSITION_BEFORE_SWAP
    • TRANSITION_AFTER_SWAP
    • TRANSITION_PAGE_LOAD
    • isTransitionBeforePreparationEvent()
    • isTransitionBeforeSwapEvent()
    • createAnimationScope()

    What should I do?

    Remove any occurrence of createAnimationScope():

    -import { createAnimationScope } from 'astro:transitions';

    Replace any occurrence of the other APIs using the lifecycle event names directly:

    -import {
    -	TRANSITION_AFTER_SWAP,
    -	isTransitionBeforePreparationEvent,
    -} from 'astro:transitions/client';
    
    -console.log(isTransitionBeforePreparationEvent(event));
    +console.log(event.type === 'astro:before-preparation');
    
    -console.log(TRANSITION_AFTER_SWAP);
    +console.log('astro:after-swap');

    Learn more about all utilities available in the View Transitions Router API Reference.

Patch Changes

  • #16774 8f77583 Thanks @astrobot-houston! - Fixes markdown images with empty alt text (![](image.jpg)) in content collections dropping the alt attribute entirely. The alt="" attribute is now correctly preserved in the rendered HTML output, which is important for accessibility (indicating decorative images).

  • #16730 068d924 Thanks @harshagarwalnyu! - Fixes an issue where the file() content loader did not generate a valid JSON Schema for collections whose JSON or YAML data is a top-level array instead of an object.

@astrojs/svelte@9.0.0-alpha.2

Minor Changes

  • #16549 9d9d516 Thanks @ocavue! - Updates @sveltejs/vite-plugin-svelte to v7. No user action is necessary.

@astrojs/cloudflare@14.0.0-alpha.1

Patch Changes

withastro/astro

Changes

The hardening split (#16710) combined with the pnpm v11 upgrade broke preview releases — the publish job's minimal artifact was missing patches/ and had unresolvable workspace:* deps. This generates synthetic workspace configs in the staging step and uses pnpm dlx instead of pnpm exec to skip workspace resolution entirely.

Testing

Note, this is me, the human. Preview releases are currently broken after we split up the job for security reasons (so installing code not have access to the id token).

I ran the script in this change and verified it does pack all of the things it's supposed to. I can't run a preview release to verify that works.

Also added some unit tests to the script itself.

Docs

No docs needed — internal CI change.

withastro/astro

Changes

  • Fixes the dev prerender/SSR handoff for Cloudflare prerenderEnvironment: 'node' by delaying request body reads until AstroServerApp.handleRequest() finishes route resolution in prerenderOnly mode. If the resolved route falls through to SSR, the POST body is still intact when the SSR handler receives it.
  • Adds a comment next to the prerender middleware gate explaining why the matchAllRoutes() check is intentional: the final dev routing decision still needs the deeper route resolution in handleRequest(), so future changes do not replace that gate with matchRoute() again.

Testing

  • Added a Cloudflare regression test in packages/integrations/cloudflare/test/prerender-node-env.test.ts that exercises POST /_actions/hello with a prerendered catch-all route.
  • The same fixture continues to cover the surrounding prerenderEnvironment: 'node' behavior for prerendered pages, SSR pages, and server islands.

Docs

  • No docs update needed, because this fixes broken dev behavior rather than changing the supported API.

Closes #16746

withastro/astro

Changes

Closes AST-44

This PR stabilise the logger feature

Testing

Green CI.

Docs

withastro/docs#13907

withastro/astro

Changes

  • Adds a sparse checkout step to the publish job in the preview release workflow so pnpm/action-setup can read the packageManager field from package.json. The publish job previously had no checkout, so pnpm setup failed with "No pnpm version is specified."

Testing

  • No test changes. This is a CI workflow fix — validation is the next preview release run succeeding.

Docs

  • No docs needed — internal CI change only.
withastro/astro

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

astro@6.3.4

Patch Changes

  • #16723 0f10bfe Thanks @matthewp! - Adds fetchFile option to experimental.advancedRouting to customize or disable the entrypoint file

    export default defineConfig({
      experimental: {
        advancedRouting: {
          fetchFile: 'fetch.ts',
        },
      },
    });
  • #16723 0f10bfe Thanks @matthewp! - Fixes Hono cache() middleware to follow the standard wrapper pattern

  • #16723 0f10bfe Thanks @matthewp! - Adds App.Providers interface for typing custom context providers on Astro and ctx

    declare namespace App {
      interface Providers {
        oauth: import('./lib/oauth').OAuthSession;
      }
    }
  • #16723 0f10bfe Thanks @matthewp! - Adds FetchState.response property, set automatically after pages() or middleware() completes

    const response = await middleware(state, (s) => pages(s));
    console.log(state.response === response); // true
  • #16723 0f10bfe Thanks @matthewp! - Adds Fetchable type export for typing the advanced routing entrypoint

    import type { Fetchable } from 'astro';
    
    export default {
      async fetch(request) {
        return new Response('ok');
      },
    } satisfies Fetchable;
  • #16572 4a5a077 Thanks @DORI2001! - Suppresses [WARN] Vite warning: unused imports from "@astrojs/internal-helpers/remote" during prerender builds. The package is now bundled alongside astro in the prerender environment, matching how it is handled in the SSR environment.

  • #16756 b6ee23d Thanks @astrobot-houston! - Fixes styles from Markdoc/MDX custom components not being extracted to <head> in the dev server when using the Cloudflare adapter with prerenderEnvironment: 'node' and rendering content through a wrapper component.

  • #16747 904d19a Thanks @astrobot-houston! - Fixes Astro action requests failing in astro dev when using the Cloudflare adapter with prerenderEnvironment: 'node' alongside a prerendered catch-all route such as [...page].astro.

    Actions and other SSR POST endpoints now continue to work in dev instead of returning an HTTP 500 error.

  • #16701 3495ce4 Thanks @demaisj! - Fix Map and Set instances saved in a content collection being broken when retrieving entries.

  • #16614 fca1c32 Thanks @Eptagone! - Fixes entry.data type inference when a live collection is configured without a schema.

  • #16661 03b8f7f Thanks @ocavue! - Updates typescript to v6. No changes are needed from users.

  • #16681 c22770a Thanks @dotnetCarpenter! - Fixes an issue where SVG images with width="0" or height="0" incorrectly threw a NoImageMetadata error instead of being treated as valid dimensions.

@astrojs/db@0.21.2

Patch Changes

@astrojs/cloudflare@13.5.2

Patch Changes

  • #16708 bb709ff Thanks @fkatsuhiro! - Fixed a bug where a cascade of reloads would cause the page to crash during the first visit when building or developing with Cloudflare SSR in Astro v6 due to dependency loading issues.

  • Updated dependencies []:

    • @astrojs/underscore-redirects@1.0.3

@astrojs/netlify@7.0.10

Patch Changes

  • #16661 03b8f7f Thanks @ocavue! - Updates typescript to v6. No changes are needed from users.

  • Updated dependencies []:

    • @astrojs/underscore-redirects@1.0.3

@astrojs/language-server@2.16.9

Patch Changes

  • #16661 03b8f7f Thanks @ocavue! - Updates typescript to v6. No changes are needed from users.

  • Updated dependencies [03b8f7f]:

    • @astrojs/yaml2ts@0.2.4

@astrojs/ts-plugin@1.10.9

Patch Changes

  • #16661 03b8f7f Thanks @ocavue! - Updates typescript to v6. No changes are needed from users.

  • Updated dependencies [03b8f7f]:

    • @astrojs/yaml2ts@0.2.4

astro-vscode@2.16.16

Patch Changes

@astrojs/yaml2ts@0.2.4

Patch Changes

withastro/astro

Changes

  • Extracts the Vite InlineConfig assembly from buildEnvironments() into a new createViteBuildConfig() function in vite-build-config.ts. The function takes settings, viteConfig, routes, plugins, builder, and isRollupInput, and returns the config object without executing any build.
  • The buildApp callback (which depends on internals) is passed in as a parameter, keeping the function free of build-time state.

Testing

  • New test/units/build/vite-build-config.test.ts with 12 unit tests covering: user rollup output overrides (assetFileNames, chunkFileNames, entryFileNames) preserved in top-level, client, and prerender environments; Astro defaults applied when no override; build.assets prefix flowing into rollup templates; base, envPrefix, and cssMinify behavior.
  • Removed 5 integration tests + 3 fixtures replaced by unit tests:
    • custom-assets-name.test.ts + fixture (user assetFileNames function override)
    • entry-file-names.test.ts + fixture (client entryFileNames override)
    • astro-assets-dir.test.ts + fixture (build.assets prefix)
    • config-vite.test.ts first describe block (prerender rollup output override)
    • astro-css-bundling.test.ts custom assetFileNames section (prerender assetFileNames override)

Docs

  • No docs needed — internal refactor with no user-facing behavior change.
withastro/astro

Changes

  • Replaces the astro-global integration test suite with unit tests using createTestApp. Covers Astro.site, Astro.url, Astro.routePattern, Astro.isPrerendered, and middleware locals propagation.
  • Removes the integration test file, fixture directory, and all associated fixture files (21 files including a 7MB penguin image).

Testing

  • New unit test file at test/units/render/astro-global.test.ts with 10 tests covering the same Astro globals behavior. Runs in ~330ms vs seconds for the integration tests.
  • Dropped 4 tests that provided no meaningful coverage: 3 tested import.meta.glob() (Vite behavior, not Astro globals) and 1 was accidentally asserting a 404 response.

Docs

  • No docs needed — test-only change.
withastro/astro

Changes

Replaces the flaky integration test added in d2e25c6, which fetched a remote image from kaleidoscopic-biscotti-6fe98c.netlify.app.

The replacement is a set of offline unit tests for propsToFilename that cover the same filename-sanitization logic without any network calls.

Testing

See changed tests

Docs

N/A

withastro/astro

Changes

  • Fixes a reflected XSS where slot names on hydrated (client:*) components were interpolated raw into data-astro-template and astro-slot name HTML attributes during SSR. An attacker could break out of the attribute context and inject arbitrary HTML when a slot name is derived from user input. Applies escapeHTML() to the slot name key at both interpolation points in component.ts.

Testing

  • Added slot-name-escape.astro fixture page that uses a slot name containing "><img src=x onerror=alert(1)> on a client:load component
  • Added test case in astro-children.test.ts verifying no injected <img> element exists and the attribute value contains properly escaped entities

Docs

  • No docs update needed — this is an internal security fix with no user-facing API change.
withastro/astro

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

astro@6.3.3

Patch Changes

  • #16737 bd84f33 Thanks @matthewp! - Fixes a reflected XSS vulnerability where slot names on hydrated components were not HTML-escaped in SSR output

@astrojs/mdx@5.0.6

Patch Changes

withastro/astro

Changes

This PR addresses a flaky test shown in this run: https://github.com/withastro/astro/actions/runs/25853010563/job/75964157111?pr=16734

    Retry #2 ───────────────────────────────────────────────────────────────────────────────────────

    Error: There should be 3 page loads (for page one & three), and an additional loads for the back navigation

    expect(received).toEqual(expected) // deep equality

    Expected: 3
    Received: 2

      206 | 			loads.length,
      207 | 			'There should be 3 page loads (for page one & three), and an additional loads for the back navigation',
    > 208 | 		).toEqual(3);
          | 		  ^
      209 | 	});
      210 |
      211 | 	test('Declarative Shadow DOM elements are attached after transitions', async ({
        at D:\a\astro\astro\packages\astro\e2e\view-transitions.test.ts:208:5

    Error Context: test-results\e2e-view-transitions-View--20f1e--ClientRouter-w-back-button-Firefox-Stable-retry2\error-context.md

Particularly, I used expect.poll and expect.toPass to refactor some tests with a magic timeout.

// Bad pattern
doSomething()
await page.waitForTimeout(500);  // <-- A magic timeout number whether is too big (too slow) on a fast machine or too small (too fast) on a slow machine
expect(getResult()).toBe(expectedResult)

// Good pattern
doSomething()
await page.poll(getResult).toBe(expectedResult)

// Good pattern
doSomething()
await expect(() => { expect(getResult()).toBe(expectedResult) }).toPass()

Testing

CI should pass

Docs

N/A

withastro/astro

Changes

Previous, if generateImagesForPath() fails, an uncaught error will be thrown. This is an issue because it doesn't break the build() function itself, causing flaky tests.

For example, in this job run, the await fixture.build() returns a resolved promise, but the build is not actually successful.

astro:test: ✖ astro:image (37126.090234ms)
astro:test: ℹ Error: Test hook "before" at test/core-image.test.ts:992:3 generated asynchronous activity after the test ended. This activity created the error "TypeError: fetch failed" and would have caused the test to fail, but instead triggered an unhandledRejection event.

Later, when we want to check out the built result, we hit errors:

astro:test: ✖ failing tests:
astro:test: 
astro:test: test at test/core-image.test.ts:1020:3
astro:test: ✖ writes out allowed remote images (1.309057ms)
astro:test:   Error: ENOENT: no such file or directory, open '/home/runner/work/astro/astro/packages/astro/test/fixtures/core-image-ssg/dist/core-image-build-ssg/_astro/sponsors_1Wl70z.webp'
astro:test:       at async open (node:internal/fs/promises:640:25)
astro:test:       at async Object.readFile (node:internal/fs/promises:1283:14)
astro:test:       at async TestContext.<anonymous> (file:///home/runner/work/astro/astro/packages/astro/test/core-image.test.ts:1025:17)
astro:test:       at async Test.run (node:internal/test_runner/test:1125:7)
astro:test:       at async Suite.processPendingSubtests (node:internal/test_runner/test:787:7) {
astro:test:     errno: -2,
astro:test:     code: 'ENOENT',
astro:test:     syscall: 'open',
astro:test:     path: '/home/runner/work/astro/astro/packages/astro/test/fixtures/core-image-ssg/dist/core-image-build-ssg/_astro/sponsors_1Wl70z.webp'
astro:test:   }
astro:test: 

Testing

CI should pass

Docs

This change doesn't affect users, so no changeset is needed. The error message is silently improved.

If I have a 404 image in the repo, here is what I get before and after when running astro build:

Before:

$ ./node_modules/.bin/astro build
21:21:59 [content] Syncing content
21:21:59 [content] Synced content
21:21:59 [types] Generated 253ms
21:21:59 [build] output: "static"
21:21:59 [build] mode: "static"
21:21:59 [build] directory: /Users/ocavue/code/github/astro/packages/astro/test/fixtures/core-image-ssg/dist/
21:21:59 [build] Collecting build info...
21:21:59 [build] ✓ Completed in 259ms.
21:21:59 [build] Building static entrypoints...
21:21:59 [vite] ✓ built in 350ms
21:21:59 [vite] ✓ built in 6ms
21:21:59 [build] Rearranging server assets...

 generating static routes
21:21:59   ├─ /remote/index.html (+8ms)
21:21:59   ├─ /srcset/index.html (+1ms)
21:21:59 ✓ Completed in 16ms.

 generating optimized images
21:21:59   ▶ /_astro/image 1.ZqYaJ2Hs_Zkuiyp.webp (reused cache entry) (+9ms) (1/3)
21:21:59   ▶ /_astro/image 1.ZqYaJ2Hs_2gIxxN.webp (reused cache entry) (+0ms) (2/3)
21:22:00 ✓ Completed in 1.21s.  <-- ⚠️⚠️⚠️ Notice this "Completed in 1.21s" message

file:///Users/ocavue/code/github/astro/packages/astro/dist/assets/build/remote.js:10
    throw new Error(
          ^

Error: Failed to load remote image https://astro.build/this_img_does_not_exist.png. The request did not return a 200 OK response. (received 404))
    at loadRemoteImage (file:///Users/ocavue/code/github/astro/packages/astro/dist/assets/build/remote.js:10:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:103:5)
    at async loadImage (file:///Users/ocavue/code/github/astro/packages/astro/dist/assets/build/generate.js:237:12)
    at async generateImageInternal (file:///Users/ocavue/code/github/astro/packages/astro/dist/assets/build/generate.js:154:23)
    at async generateImage (file:///Users/ocavue/code/github/astro/packages/astro/dist/assets/build/generate.js:69:28)
    at async generateImagesForPath (file:///Users/ocavue/code/github/astro/packages/astro/dist/assets/build/generate.js:53:5)
    at async file:///Users/ocavue/code/github/astro/node_modules/.pnpm/p-queue@9.1.0/node_modules/p-queue/dist/index.js:394:36

Node.js v24.11.1
$ echo $?
1 <-- ⚠️⚠️⚠️ `astro build` exits with code 1

After:

$  ./node_modules/.bin/astro build
21:27:17 [content] Syncing content
21:27:17 [content] Synced content
21:27:17 [types] Generated 258ms
21:27:17 [build] output: "static"
21:27:17 [build] mode: "static"
21:27:17 [build] directory: /Users/ocavue/code/github/astro/packages/astro/test/fixtures/core-image-ssg/dist/
21:27:17 [build] Collecting build info...
21:27:17 [build] ✓ Completed in 263ms.
21:27:17 [build] Building static entrypoints...
21:27:17 [vite] ✓ built in 377ms
21:27:17 [vite] ✓ built in 5ms
21:27:17 [build] Rearranging server assets...

 generating static routes
21:27:17   ├─ /remote/index.html (+8ms)
21:27:17   ├─ /srcset/index.html (+1ms)
21:27:17 ✓ Completed in 16ms.

 generating optimized images
21:27:17   ▶ /_astro/image 1.ZqYaJ2Hs_Zkuiyp.webp (reused cache entry) (+10ms) (1/3)
21:27:17   ▶ /_astro/image 1.ZqYaJ2Hs_2gIxxN.webp (reused cache entry) (+0ms) (2/3)
21:27:18 [WARN] [build] Unable to generate optimized image for https://astro.build/this_image_does_not_exist.png: Error: Failed to load remote image https://astro.build/this_image_does_not_exist.png. The request did not return a 200 OK response. (received 404))
Error generating image for https://astro.build/this_image_does_not_exist.png: Error: Failed to load remote image https://astro.build/this_image_does_not_exist.png. The request did not return a 200 OK response. (received 404))
  Stack trace:
    at file:///Users/ocavue/code/github/astro/packages/astro/dist/core/build/generate.js:195:21
  Caused by:
  Failed to load remote image https://astro.build/this_image_does_not_exist.png. The request did not return a 200 OK response. (received 404))
    at loadRemoteImage (file:///Users/ocavue/code/github/astro/packages/astro/dist/assets/build/remote.js:10:11)
    at async loadImage (file:///Users/ocavue/code/github/astro/packages/astro/dist/assets/build/generate.js:237:12)
    at async generateImage (file:///Users/ocavue/code/github/astro/packages/astro/dist/assets/build/generate.js:69:28)
    at async file:///Users/ocavue/code/github/astro/node_modules/.pnpm/p-queue@9.1.0/node_modules/p-queue/dist/index.js:394:36
$ echo $?
1 <-- ⚠️⚠️⚠️ `astro build` still exits with code 1

Notice that after this PR, you no longer see the Completed in 1.21s message in the shell because the build() function itself throws the error and never finishes. This should be a minor improvement for users.

withastro/astro

Changes

  • file() loader JSON Schema generation now emits an anyOf schema instead of a plain record-only schema
  • Branch 1: { type: 'array', items: <itemSchema> } — validates top-level array JSON/YAML files (e.g. [{ name: 'red', color: '#f00' }])
  • Branch 2: { type: 'object', additionalProperties: <itemSchema>, properties: { $schema: string } } — validates record-style files and preserves the $schema property
  • Before: VS Code flagged top-level array files as invalid against the generated schema
  • After: Both array and record shapes pass validation
  • Fixes #16602
  • Changeset included (.changeset/tangy-chairs-smile.md)

Testing

Updated packages/astro/test/content-intellisense.test.ts — renamed and expanded the existing test to assert:

  1. schema.anyOf exists with exactly 2 branches
  2. Array branch: type: 'array' with items.properties matching the collection item schema
  3. Object branch: type: 'object' with additionalProperties.properties matching the item schema and a $schema property present

Run with:

pnpm test packages/astro/test/content-intellisense.test.ts

Docs

No docs change needed — this is an internal schema generation improvement. The file() loader public API is unchanged; users who already use file() get correct IntelliSense automatically.

withastro/astro

@astrojs/cloudflare/fetch

import { astro, FetchState } from 'astro/fetch';
import { cf } from '@astrojs/cloudflare/fetch';

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext) {
    const state = new FetchState(request);
    const asset = await cf(state, env, ctx);
    if (asset) return asset;
    return astro(state);
  }
}

@astrojs/cloudflare/hono

import { Hono } from 'hono';
import { actions, middleware, pages, i18n } from 'astro/hono';
import { cf } from '@astrojs/cloudflare/hono';

const app = new Hono<{ Bindings: Env }>();

app.use(cf());
app.use(actions());
app.use(middleware());
app.use(pages());
app.use(i18n());

export default app;

Changes

  • Adds @astrojs/cloudflare/fetch exporting a cf(state, env, ctx) function that applies Cloudflare-specific setup to a FetchState — session KV binding injection, static asset serving via ASSETS, locals.cfContext, client address from cf-connecting-ip, waitUntil, and prerendered error page fetch. Returns a Response for asset hits, undefined otherwise.
  • Adds @astrojs/cloudflare/hono exporting a cf() Hono middleware that does the same setup, reading env and executionCtx from the Hono context automatically (no arguments needed).
  • Extracts shared helpers from the existing handler.ts into cf-helpers.ts and cf.ts, then refactors handler.ts to use them. Zero duplication between the handle() entrypoint and the new exports.

Testing

  • Adds cf-helpers.test.ts with 18 unit tests covering createLocals, getClientAddress, matchStaticAsset, fallbackToAssets, and createErrorPageFetch. Tests use mock Env and ExecutionContext objects — no fixtures or build required.
  • All 207 existing Cloudflare adapter tests continue to pass after the handler.ts refactor.

Docs

withastro/astro

Changes

  • Reverts npm ci back to npm i in the VSCode extension publish step of the release workflow. npm ci requires a package-lock.json which does not exist in packages/language-tools/vscode/ (and is globally gitignored). This was broken by #16711.

Testing

  • No test changes. This is a CI workflow fix — validated by the next release that publishes the VSCode extension.

Docs

  • No docs needed — internal CI change only.
withastro/astro

Astro v7 PR

Changes

Removes the astro:transitions APIs deprecated in #14989 and scheduled to be removed in Astro v7.

Testing

Green CI.

Docs

Changeset added.
Docs PR: withastro/docs#13886

/cc @withastro/maintainers-docs for feedback!

withastro/astro

Changes

  • When the triage bot publishes a preview release, the issue now gets a fix pending verification label and the comment asks the reporter to confirm the fix works
  • A new fix-verification workflow listens for comments on issues with that label. A flue agent (Sonnet) classifies whether the comment is a positive confirmation
  • If verified: removes the label, generates a PR title/body via the astro-pr-writer skill, creates the PR from the existing flue/fix-{N} branch, and adds a fix verified label to the PR

This closes the loop on the triage bot fix pipeline: reproduce → diagnose → fix → test → preview release → reporter verification → PR creation.

Testing

  • No automated tests — this is CI/agent infrastructure. Will be validated by the next triage bot run that produces a fix with a preview release.

Docs

  • No docs needed — internal CI automation, not user-facing.
withastro/astro

Changes

  • Fetchable type: Exported from astro so users can type src/app.ts with satisfies Fetchable.
  • FetchState.response: Set by PagesHandler and AstroMiddleware after rendering so callers can read state.response.
  • App.Providers: New extendable interface for typing custom context providers on ctx and Astro.
  • fetchFile config: Lets users rename the entrypoint away from src/app.ts, or set null to disable.
  • Hono cache() wrapper: Now follows the standard middleware pattern like the other Hono wrappers.

Testing

Added 6 unit tests in test/units/fetch/index.test.ts:

  • state.response is set after pages() and middleware()
  • Context provider provide/resolve lazy creation and caching
  • finalizeAll runs finalize for resolved providers, skips unresolved ones

Docs

Added here: withastro/docs#13890

withastro/astro

Changes

Fixes dynamic routes returning the string [object Object] under the following conditions:

  1. when used with Cloudflare Workers with the nodejs_compat flag. The affected projects all use compatibility dates of 2025-04-01 or newer, not sure if older dates are affected.
  2. only for large, complex projects where Rollup splits code in a way that triggers it. The exact level of complexity/size required is unknown. The fix should work for projects of all sizes though.

This was a very difficult issue to track down. Static routes were fine, and in the Worker logs I could see that the dynamic routes were being processed correctly (I see things like logs indicating success for loading external content and other expected internal logging from the build process) but the returned response was just the string [object Object] regardless of which page or what content was expected -- no error messages of any kind.

I did not open an issue for this because by the time I had enough detail to do so, Claude Code had provided a fix, so I'm just going straight to a PR.

See included Claude Code analysis below for full details.

Testing

I did not add tests because I'm not sure how to provide a sufficiently complicated test project -- this problem only surfaces in larger projects. I'm happy to assist adding tests if I can get some help.

I do have this fix running in 3 separate projects ranging in size and complexity from a stripped down copy of the Astro blog starter template for Workers (where the problem never exhibited but this fix does not cause any issues), up to a 1000-page hybrid site with upwards of 100 Astro components and a mix of dynamic and static routes (where the problem surfaced and the fix works).

Claude Code's explanation of the issue and proposed fix were arrived at after several rounds of analysis and refinements, and its explanation makes sense and matches what I've been experiencing. I specifically asked it to check that the changes do not affect anything for Deno or Node prerendering environments, only workerd.

Docs

I don't believe docs updates are needed because this fixes an issue with expected functionality with no changes needed by the user.

Claude's analysis, RCA, and proposed fix, which I've implemented in this PR

If you're interested, here's what my AI agent found This analysis was done with Astro 6.2.x and Cloudflare 13.3.x, but I've confirmed the problem still exists in the current versions. I'm barred by work policy from installing packages newer than 7 days so I cannot test the latest versions directly, but the problem code still exists in the latest version, unchanged.

This analysis was done by comparing two projects:

  • astro-blog-starter-template which is a copy of the Astro starter for Workers, stripped of all but one dynamic and one static test page
  • web-dev-collibra-astro which is our largest, most complicated project where the problem surfaced

This is its final summary, verbatim:

Fix Summary — Astro isNode false-positive in workerd

Symptom

In an Astro 6.2.x project deployed to Cloudflare Workers via @astrojs/cloudflare 13.3.x with nodejs_compat, any route with prerender: false returns an HTTP 200, content-type: text/html response whose body is the 15-byte string [object Object]. Static / prerendered routes are unaffected. Reproducible locally with astro build && astro preview.

Root cause

astro/dist/runtime/server/render/util.js defines:

const isNode = typeof process !== "undefined"
  && Object.prototype.toString.call(process) === "[object process]";

astro/dist/runtime/server/render/page.js then chooses the response body shape:

if (isNode && !isDeno) {
  body = await renderToAsyncIterable(...);   // Node-only async iterable
} else {
  body = await renderToReadableStream(...);  // standard ReadableStream
}

With nodejs_compat, workerd's process reports Object.prototype.toString.call(process) === "[object process]" until the @cloudflare/unenv-preset polyfill replaces it with a plain object. The output of renderToAsyncIterable is an object exposing Symbol.asyncIterator. Node's undici accepts async iterables as a Response body; workerd's Response does not, and falls back to String(body)"[object Object]".

Why the bug surfaces in some projects but not others

The bug is a module-initialization-order race that only manifests once Rollup decides to code-split Astro's shared runtime.

Both the failing project and the working starter contain the same two pieces of code in the worker bundle:

// A — unenv polyfill assignment (replaces workerd's raw process)
globalThis.process = _process;

// B — Astro's isNode evaluation (reads process)
const isNode = typeof process !== "undefined"
  && Object.prototype.toString.call(process) === "[object process]";

The order in which A and B run depends on whether Rollup keeps them in one chunk or splits them across two:

astro-blog-starter-template (2 pages, almost no Astro internals reused) — Rollup keeps everything in one chunk, worker-entry_DEEjL72T.mjs:

line  558:  globalThis.process = _process;       ← A runs first
line 5864:  const isNode = ...                   ← B sees the unenv polyfill

Single module body, top-down execution → process is the plain-object unenv polyfill by the time isNode runs → isNode = falserenderToReadableStream → works.

web-dev-collibra-astro (many pages and components importing from astro/runtime/server/*) — Rollup factors Astro's shared runtime into its own chunk:

transition_DTdhAtUt.mjs:814    const isNode = ...                ← B
worker-entry_2ArJYird.mjs:1282 globalThis.process = _process;    ← A

worker-entry imports transition. ES Module spec executes imported module bodies before the importer's body, so B runs before A. isNode is evaluated against workerd's raw nodejs_compat process, latches to true, and renderToAsyncIterable is selected → broken response.

The threshold is whatever pushes Rollup over its code-splitting heuristic for shared dependencies. Any project with enough reuse of astro/runtime/server/* across pages or components will eventually trip it — it's not specific to Vue, custom integrations, or middleware.

I confirmed module init order is the differentiator by logging Object.prototype.toString.call(process) at module init vs. request time in the failing project: "[object process]" at init, "[object Object]" at request time — proving the polyfill assignment happens between the two, after isNode has already been frozen.

The fix

One line in packages/astro/src/runtime/server/render/util.ts:

const isNode = typeof process !== "undefined"
  && Object.prototype.toString.call(process) === "[object process]"
  && !(typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers");

Workerd's navigator.userAgent === "Cloudflare-Workers" is documented, stable, and present from t=0 — so the check is immune to the module-init-order race that broke the original process-only detection.

Behavior matrix

Environment process toString navigator.userAgent isNode before isNode after Behavior change
Node.js "[object process]" undefined / Node ua true true None
Deno "[object process]" (Node compat shim) "Deno/x.y.z" true true None — also gated by !isDeno in renderPage
Browser undefined various, never "Cloudflare-Workers" false false None
Cloudflare Workers (workerd) without nodejs_compat undefined "Cloudflare-Workers" false false None
Cloudflare Workers (workerd) with nodejs_compat, polyfill already installed before isNode eval "[object Object]" "Cloudflare-Workers" false false None (incidentally-correct case — the starter)
Cloudflare Workers (workerd) with nodejs_compat, polyfill not yet installed "[object process]" "Cloudflare-Workers" true (wrong) false (correct) Bug fixed

The change only flips behavior in the row where the original heuristic is wrong.

Cross-checks against the prerender flow

@astrojs/cloudflare exposes prerenderEnvironment: "node" | "workerd" (default "workerd").

  • prerenderEnvironment: "node": prerender runs in real Node. No navigator global, original isNode = true preserved. Same as before. ✓
  • prerenderEnvironment: "workerd" (default): prerender runs in workerd. New check correctly returns false. The renderToReadableStream path produces a ReadableStream body, which Astro's prerender pipeline consumes the same way it consumes an async iterable. ✓

Verification performed

  1. Reproduced locally on web-dev-collibra-astro with astro build + astro previewcurl /dev/dynamic returns [object Object] (15 bytes).
  2. Confirmed the path by logging isNode, streaming, and body.constructor.name inside the bundled renderPageisNode=true, body constructor is Object (the async iterable), not ReadableStream.
  3. Confirmed module-init-order theory by logging Object.prototype.toString.call(process) both at module init ("[object process]") and at request time ("[object Object]") — proves the polyfill assignment happens between the two.
  4. Confirmed astro-blog-starter-template evaluates isNode = false because the unenv polyfill assignment (line 558) precedes the isNode evaluation (line 5864) in the same chunk.
  5. Applied the patch via build-scripts/patch-astro-renderer.mjs; re-ran preview; dynamic route returns <!DOCTYPE html>...<div>TEST</div>, static route unchanged.
Details
withastro/astro

Changes

Bug reported: #16667
FIXES #16667

The Astro extension was causing MDX highlighting errors, but only when the code snippets were indented:

BEFORE FIX:

Image

AFTER FIX:

Screenshot 2026-05-12 at 16 09 35

Testing

  1. pnpm install
  2. pnpm -C packages/language-tools/vscode build
  3. In Cursor: Run and Debug → Launch Client
  4. Opened an MDX file and tested an indented astro codeblock

Docs

No docs necessary

withastro/astro

Changes

  • Updates pnpm to v11
  • Removes minimum release age exceptions that are no longer required
  • Cleans up deps in a couple of fixtures that were accidentally using npm versions of monorepo packages
  • Explicitly disallows postinstall scripts for all dependencies that have them
  • Enables pnpm’s trustPolicy which prevents installing versions of packages that have reduced their publishing provenance. This required applying some limited exceptions to continue installing our currently installed packages.

Some semi-user-facing changes:

  • Updated deps in the Netlify adapter
  • Dropped support for older versions of VS Code so we can test with Node ≥22 which is pnpm 11’s minimum required version

Testing

Existing tests should pass

Docs

n/a — monorepo hardening only

withastro/starlight

Description

  • Companion to #3902
  • Tells Renovate to wait for 3 days before applying updates to match our pnpm policy
  • In practice not super important as we mainly use Renovate for GitHub Actions, which don’t involve pnpm, but still good to keep these in sync
withastro/starlight

This PR contains the following updates:

Package Type Update Change
pnpm/action-setup action patch v6.0.7v6.0.8
pnpm/action-setup action patch v6.0.5v6.0.8
withastro/automation action digest 3754a7453c85fa

Release Notes

pnpm/action-setup (pnpm/action-setup)

v6.0.8

Compare Source


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

👻 Immortal: This PR will be recreated if closed unmerged. Get config help if that's undesired.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

withastro/starlight

Description

This PR updates to pnpm 11 and configures a 3-day minimum release age for dependencies to mirror the main astro monorepo: https://github.com/withastro/astro/blob/3abcc86c092ca2a3455fc0ffc72b6b7ca300f1a2/pnpm-workspace.yaml#L32

This helps defend a little against supply chain attacks, but also avoids us installing deps that then cause issues in the astro monorepo CI because they’re newer than their config allows.

withastro/astro

Summary

  • Adds permissions: {} at the top level of every workflow that was missing it
  • Adds explicit job-level permissions to jobs that previously inherited the default token permissions
  • This ensures no workflow accidentally gets broad GITHUB_TOKEN access

Affected workflows: ci.yml, scripts.yml, check.yml, semgrep.yml, congrats.yml, continuous_benchmark.yml, issue-triage.yml, merge-fix.yml, merge-main-to-next.yml.

Part of supply chain hardening in response to the TanStack/Mini Shai-Hulud compromise.

withastro/astro

What''s wrong?

When a developer adds a script-src or style-src entry to security.csp.directives, Astro rejects it with a generic Zod "Did not match" error that gives no actionable guidance.

Closes #16663

What changed?

Replaced the bare z.custom() validator in packages/astro/src/core/csp/config.ts with a z.string().superRefine() that emits two distinct, actionable errors:

  1. Managed directive (script-src, style-src): tells the user which directive is managed by Astro and points them to the correct config key (security.csp.scriptDirective or security.csp.styleDirective).
  2. Unknown directive: lists all allowed directives so the user knows exactly what is valid.

Before / After

Before

[ConfigError] Did not match union

After (script-src example)

[ConfigError] The `script-src` directive is managed by Astro and cannot be set in `security.csp.directives`. Use `security.csp.scriptDirective` instead.

Checklist

  • Added changeset (patch for astro)
  • No behaviour change for valid configs — only the error path is affected
  • Follows existing superRefine + z.ZodIssueCode.custom pattern used in the codebase
withastro/astro

Summary

  • Removes pnpm store cache (cache: "pnpm") from the release workflow
  • Removes Turbo remote cache (TURBO_TOKEN/TURBO_TEAM)
  • Adds --force to the build step to skip any local Turbo cache
  • Adds --frozen-lockfile to ensure the lockfile is the source of truth

The release workflow now does a fully clean install and build from scratch every time. This eliminates cache poisoning as an attack vector for the publish pipeline.

Part of supply chain hardening in response to the TanStack/Mini Shai-Hulud compromise.

withastro/astro

Summary

Hardens the preview-release workflow against the attack vector used in the TanStack/Mini Shai-Hulud compromise.

Two changes:

  • Block fork PRs from preview releases. Adds a head.repo.full_name == github.repository check so only branches within withastro/astro can trigger preview builds. This prevents a malicious fork from running code in a privileged context.
  • Split into two jobs to isolate OIDC token. The build job runs pnpm install and pnpm build but has no id-token: write. The publish job has id-token: write but only downloads build artifacts and runs pkg-pr-new — it never executes user code. This ensures the OIDC token is never available during code execution, even for non-fork PRs.

The build job uploads only the minimal files needed for publishing (root workspace files + affected package directories), not the entire workspace.

withastro/starlight

Description

This PR contains various improvements to the E2E tests mostly focusing on CI performance.

Here is a table summarizing some of the most impactful changes comparing the before, before average, and after times on my personal machine and CI:

Task Host Before1 Before average After
E2E tests Personal Mac 43.6s N/A 28.9s
E2E tests CI - Linux 2m 27s 2m 34s 1m 29s
E2E tests CI - Windows 5m 9s 5m 11s 3m 11s
A11y tests Personal Mac 1m 1s N/A 41s
A11y tests CI - Linux 2m 39s 2m 43s 1m 47s

You can find below a review were I try to comment on the reasoning behind most of the changes.

Footnotes

  1. For CI times, the "before" times are from merging to main the recent autogenerated sidebar groups refactor.

withastro/astro

Summary

  • Pins actions/labeler from mutable @v4 tag to commit SHA ac9175f8a1f3625fd0d4fb234536d26811351594 (v4.3.0)
  • This was the only action in the repo not pinned to SHA
  • This workflow runs on pull_request_target with write permissions, so a tag hijack would affect every PR including forks

Part of supply chain hardening in response to the TanStack/Mini Shai-Hulud compromise.

withastro/astro

Changes

Close #16248

Root cause

Dependencies imported within .astro file frontmatter are not detected during Vite's initial Dependency Optimization phase. This leads to several issues.

Solution

I have added an onResolve handler to the astro-frontmatter-scan plugin to ensure proper dependency discovery

Testing

Before Implemented

スクリーンショット 2026-05-11 8 11 09

After Implemented

スクリーンショット 2026-05-12 21 44 31

Docs

withastro/astro

Summary

Fixes #16705

Fixes remoteBindings: false being ignored during astro build. The Cloudflare prerenderer's internal Vite preview server now receives the user's adapter options, so remote-flagged bindings (e.g. a D1 database with remote: true in wrangler.toml) are emulated locally during build, matching the existing astro dev behavior.

Changes

The fix is accomplished by forwarding cloudflareOptions (which include remoteBindings setting) to createCloudflarePrerenderer()

withastro/starlight

Description

Fixes the theme select dropdown having illegible colors in dark mode on Windows Firefox.

On Windows, Firefox renders native <select> dropdown options with white backgrounds in dark mode, making the text nearly invisible. The hovered/checked option text color is also white-on-white.

Before

The theme select in dark mode on Windows Firefox shows white option backgrounds with poor contrast, making it hard to read available options.

After

Explicit dark-theme color rules are applied to the select and option elements, using the existing Starlight design tokens (--sl-color-gray-6, --sl-color-text, --sl-color-accent-high, --sl-color-text-invert).

Changes

  • Added dark-mode-specific styles for select, option, and option:checked in Select.astro
  • Added hover state styles for options in dark mode
  • Uses existing CSS custom properties for consistency with the rest of the theme

Fixes #3426

withastro/astro

Fixes #14013.

On case-insensitive filesystems (Windows, macOS), starting astro dev from a cwd whose case differs from the actual filesystem case (e.g. d:\dev\app vs. D:\dev\app) made the project root and Vite-resolved module ids disagree on case. normalizeFilename then failed its commonAncestorPath check on the absolute id, treated it as a server-relative URL, and concatenated it onto the root — producing a bogus path that missed the compile metadata cache and stripped scoped styles.

The lookup now falls back to a case-insensitive ancestor check, so absolute paths inside the project are recognized regardless of case and the cache hit succeeds.

withastro/astro

Changes

  • Content entry styles (?astroPropagatedAssets) are now collected at render time instead of being baked into the module at transform time. The old approach captured a snapshot of the Vite module graph during the transform hook — if the graph was incomplete at that moment, styles were permanently missing. A new dev-style-collector.ts registry (shared via globalThis Symbol.for to bridge the Vite plugin and SSR runner module caches) lets the Content component in runtime.ts call getStylesForURL fresh on each render.
  • Adds templateDepth guards to head/maybe-head instructions in common.ts so that maybeRenderHead() never fires inside an inert <template> element in layouts (e.g. theme-provider icon sprites).

Closes #16181

Testing

  • test/content-collections-dev-css.test.ts — dev server integration test verifying scoped styles from .astro components in MDX content entries are present across multiple collections and with component indirection.
  • test/units/render/inert-head-guard.test.ts — verifies templateDepth guard suppresses head rendering inside templates.
  • test/units/render/head-in-template.test.ts — simulates Layout → ThemeProvider → <template> → Icon pipeline, verifying styles land in <head>.

Docs

  • No docs update needed — bug fix restoring expected behavior.
withastro/astro

The updateImageReferencesInData function uses Traverse.map which uses a custom cloning algorithm and as such does not copy correctly instances of native objects such as Map and Set rendering them unusable.

Instead Travserse.forEach can be used after cloning the data object beforehand with the native structuredClone function.

Closes #16682

Changes

  • Use Travserse.forEach instead of Traverse.map in updateImageReferencesInData
  • Clone data before updating image references
  • Update getEntry to not mutate data in store when updating image references

Testing

  • 2 new tests added to cover Map/Set regressions

Docs

  • no docs changes, this is a bug fix
withastro/astro

fixes: #16688

Changes

There was an issue where passing the entry property, returned by the getLiveEntry function imported from astro:content, to the render function caused a type error.
This pull request adds tests and a changeset to the fix originally authored by Houston bot.

Houston bot comment:

The render() function type in packages/astro/templates/content/types.d.ts only has an overload for regular content collection entries (DataEntryMap[C][string]), but no overload for LiveDataEntry. When a project uses only live.config.ts, DataEntryMap is empty, so render() accepts never. The live collections RFC and the existing test fixture both show render(entry) being used with live entries — the type overload was simply missed when live collections were added in PR #13685.

I found a potential fix for this issue. The fix adds a render() overload for LiveDataEntry<LiveLoaderDataType<C>> to the type template. It's a 4-line change that brings the type declarations in line with the runtime behavior. All existing tests (live loaders, content collections, type inference, render) continue to pass.

Testing

Added a test using the astro check command to verify that no type errors occur.
No changes were made to the test fixtures themselves. The error was originally occurring at the following location.

import { getLiveEntry, render } from "astro:content";
const { entry } = await getLiveEntry("liveStuff", "123");
if (!entry) {
return new Response(null, { status: 404 });
}
const { Content } = await render(entry);

src/pages/index.astro:10:34 - error ts(2345): Argument of type 'LiveDataEntry<{ ... }>' is not assignable to parameter of type 'never'.

10 const { Content } = await render(entry);
                                    ~~~~~

Docs

N/A, bug fix

withastro/astro

Changes

  • When the triage bot produces a high-confidence fix (fix verified + unit test created), it now publishes a preview release via pkg.pr.new so reporters can immediately test the fix with npm i https://pkg.pr.new/astro@<sha>.
  • The fix skill now generates a changeset file (.changeset/<slug>.md) for every successful fix, making the branch PR-ready with proper changelog entries.
  • Preview URLs are included in the triage bot issue comment under a "Try this fix" section, giving reporters a one-liner install command.

Testing

  • No test changes — this modifies CI agent infrastructure (skill instructions, Flue orchestrator, GHA workflow).

Docs

  • No docs needed — this is internal CI tooling, not user-facing.
withastro/starlight

This PR contains the following updates:

Package Type Update Change
pnpm/action-setup action patch v6.0.6v6.0.7

Release Notes

pnpm/action-setup (pnpm/action-setup)

v6.0.7

Compare Source


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

withastro/astro

Changes

Testing

Docs

withastro/astro

Changes

This PR removes a bunch of tests and assertions that are already checked against unit tests, so there's so reason to use a dev server for that.

The few that were still needed, they are checked against the build because it's the same behaviour

Testing

Green CI

Docs

withastro/astro

Changes

  • Adds ASTRO_VITE_ENVIRONMENT_NAMES.astro to isAstroServerEnvironment() in packages/astro/src/environments.ts. The internal 'astro' environment is a Node.js fallback used when the 'ssr' environment is not runnable (e.g. Cloudflare adapter with workerd). Without this, Vite plugins like the script loader served actual client-side script content in this environment, causing HTMLElement is not defined crashes on HMR reload.

Closes #16626

Testing

  • New unit test packages/astro/test/units/environments.test.ts covering isAstroServerEnvironment and isAstroClientEnvironment for all four environment names (ssr, prerender, astro, client).

Docs

  • No docs update needed — this is an internal bug fix with no API change.
withastro/astro

Changes

This PR targets the integration tests that user the dev server. The vast majority of the logic is already tested in a unit test environment, so they were removed.

some functions that were used in the dev server as middleware, they are extracted as a unit test function and tested.

Testing

Removed some fixtures. Green CI.

Docs

withastro/astro

Changes

I encountered the following flaky test:

https://github.com/withastro/astro/actions/runs/25663263442/job/75329416110#step:8:7300

Error: EPERM: operation not permitted, rename 'D:\a\astro\astro\packages\astro\test\fixtures\astro-assets-prefix\node_modules\.astro\data-store.json.tmp' -> 'D:\a\astro\astro\packages\astro\test\fixtures\astro-assets-prefix\node_modules\.astro\data-store.json'

I investigated this error. Two test files test/asset-query-params.test.ts and test/astro-assets-prefix.test.ts are using the same fixture ./fixtures/astro-assets-prefix/. Although these two tests have different outDir as added in #16382, they still share the same cache directory ./fixtures/astro-assets-prefix/node_module/.astro/. This seems to be the reason for the flaky test above.

In this PR, I provide a unique cacheDir for every fixture that is used in multiple test files.

15 fixtures are affected:

Fixture (test/fixtures/…) Test files
astro pages test/astro-pages.test.ts
test/static-build-page-dist-url.test.ts
test/static-build-vite-plugins.test.ts
astro-assets test/asset-query-params.test.ts
test/astro-assets.test.ts
astro-assets-prefix test/asset-query-params.test.ts
test/astro-assets-prefix.test.ts
astro-basic test/astro-basic.test.ts
test/astro-sync.test.ts
test/config-mode.test.ts
astro-dev-headers test/astro-dev-headers.test.ts
test/chrome-devtools-workspace.test.ts
css-order-layout test/css-order-layout.test.ts
test/css-order.test.ts
dev-render test/config-format.test.ts
test/dev-base.test.ts
test/dev-render-chunk.test.ts
test/dev-render-components.test.ts
test/integration-route-setup-hook.test.ts
endpoint-routing test/endpoint-response.test.ts
test/endpoint-routing.test.ts
test/endpoint-runtime.test.ts
fonts test/asset-query-params.test.ts
test/fonts.test.ts
middleware space test/featuresSupport.test.ts
test/middleware.test.ts
multiple-jsx-renderers test/asset-query-params.test.ts
test/multiple-jsx-renderers.test.ts
server-islands/hybrid test/csp-server-islands.test.ts
test/server-islands.test.ts
server-islands/ssr test/csp-server-islands.test.ts
test/server-islands.test.ts
ssr-assets test/ssr-assets.test.ts
test/units/app/logger.test.ts
ssr-request test/ssr-adapter-build-config.test.ts
test/ssr-request.test.ts

Testing

CI should pass.

Docs

N/A

withastro/astro

Changes

  • Applied @typescript-eslint/no-floating-promises rule to all tests;
  • Fixed all issues to pass ESLint. Check my code comments / PR comments for details.
  • This PR is the first step. I eventually want to apply the rule to all code, including package sources.

Testing

CI should pass

Docs

N/A

withastro/astro

Awesome work by @OfirHaf and @fkatsuhiro! Fixing bug #16633 🎉

This PR is a curated combination of #16674 and #16676.

What does this fix?

Closes #16633

SVG elements with explicit width="0" or height="0" attributes threw NoImageMetadata: Could not process image metadata instead of being imported normally. This is a valid and common pattern for SVG filter containers hidden from screen readers:

<svg width="0" height="0" aria-hidden="true">
  <defs>...</defs>
</svg>

Changes

issus: #16633

Root cause

Two falsy-zero checks along the metadata extraction path:

vendor/image-size/types/svg.ts — the calculate() function:

// Before: 0 is falsy, so an SVG with width="0" height="0" fell through
if (attrs.width && attrs.height) { ... }

// After: explicit null check allows 0 as a valid dimension
if (attrs.width != null && attrs.height != null) { ... }

assets/utils/metadata.ts — post-probe validation:

// Before: !0 === true, triggering the error for zero dimensions
if (!result.height || !result.width || !result.type) { ... }

// After: only null/undefined signals a missing value
if (result.height == null || result.width == null || !result.type) { ... }

Changes

  • packages/astro/src/assets/utils/vendor/image-size/types/svg.ts: replace truthiness check with null check in calculate()
  • packages/astro/src/assets/utils/metadata.ts: replace truthiness check with null check in imageMetadata()

Both changes are minimal and surgical — they only affect the specific falsy-zero edge case while leaving all other behavior unchanged. SVGs with missing dimensions (null/undefined) still throw the appropriate error.

Testing

Befor implement testing

スクリーンショット 2026-05-10 21 18 10

After implement testing

スクリーンショット 2026-05-10 21 13 38
withastro/astro

Changes

Added instructions for linking the correct folder when using pnpm link for installing your local copy of astro. It took me a while to figure out which folder actually needed to be linked. It is not enough to link to the root folder using pnpm 11.0.9.

Testing

No code changed.

Docs

This is only for contributors.

withastro/astro

Changes

Fixes a regression introduced in #16366, where Astro.cache was undefined when experimental.cache was not configured.

The previous documented behaviour is for Astro.cache to always be defined as a no-op shim: cache.set() warns once, cache.invalidate() throws and cache.enabled can be used to gate. This allows library and user code can call cache methods without conditional checks. The cache provider registration was being gated at the call site on experimental.cache being configured, which meant the disabled shim branch inside the provider was unreachable and the Astro.cache getter was never attached to the context.

Testing

Added a regression test

Docs

Bug fix

withastro/astro

Summary

createStaticHandler in @astrojs/node looks up per-route static headers (e.g. Content-Security-Policy) using header.pathname.includes(baselessPathname). The headers map is keyed by exact prerendered route pathnames written by core/build/generate.ts (routeToHeaders.set(pathname, ...)), and the comment immediately above the lookup states that headers are "keyed by base-less route paths" — so the intent is keyed lookup, not substring matching.

Substring matching causes the wrong headers to be applied whenever one prerendered route's path is a substring of another's:

  • Two prerendered routes /users and /users/profile, each with a different CSP.
  • /users/profile is inserted into routeToHeaders first → it ends up first in the JSON array.
  • A request for /users matches the route correctly via app.match, but headersMap.find(h => h.pathname.includes("/users")) returns the /users/profile entry.
  • The wrong CSP is sent on the /users response.

The fix is a one-line change to use === instead of .includes().

Changes

  • packages/integrations/node/src/serve-static.ts: match header.pathname by equality.
  • Changeset: @astrojs/node patch.

Test plan

  • pnpm -C packages/integrations/node test passes.
  • Manual: build a project with two prerendered routes where one path is a prefix of the other, both emitting different CSPs via the static-headers feature; confirm each route receives its own CSP under @astrojs/node standalone.
withastro/astro

Changes

This PR adjusts the reference zod support to allow numbers that are transformed to strings.

This has been an issue with collection-A markdown content that references collection-B entries with 1234 in the frontmatter as the yaml is parsed to numbers.

Testing

Added a small unit test that tests the case.

Docs

/cc @withastro/maintainers-docs I am not if documentation for this is needed.

withastro/starlight

Description

Opposite of:

but the goal is the same: to silence the Postinstall Scripts Unapproved notification when pnpm install.

References:

Package URL Quote
esbuild evanw/esbuild#4085 (comment) The install script still optimizes the command by replacing the JavaScript shim by the actual binary executable, so that running the esbuild command directly doesn't have to run node first just to shell out to the executable. So it's not necessary for correctness (and you're welcome to disable the install script if you'd like to and if it still works for you) but it might result in esbuild being slower than it would have been otherwise.
sharp https://sharp.pixelplumbing.com/install/ When using pnpm, add sharp to ignoredBuiltDependencies1 to silence warnings.

Changesets are NOT required.

Footnotes

  1. equivalent to allowBuilds = false in pnpm v10.26+.

withastro/astro

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to next, this PR will be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

next is currently in pre mode so this branch has prereleases rather than normal releases. If you want to exit prereleases, run changeset pre exit on next.

⚠️⚠️⚠️⚠️⚠️⚠️

Releases

astro@7.0.0-alpha.1

Patch Changes

withastro/starlight

Description

Tweak a comment: "non-Firefox" → "Chromium-based"

Safari has already supported the syntax :lang(zh, ja).

image

The position of Opera is the culprit.

This change is so trivial that we should ship it with other changes.

withastro/starlight

This PR contains the following updates:

Package Type Update Change
pnpm/action-setup action patch v6.0.5v6.0.6
withastro/automation action digest c8a2e8b3754a74

Release Notes

pnpm/action-setup (pnpm/action-setup)

v6.0.6

Compare Source

What's Changed
  • fix: bin_dest output points to self-updated pnpm, not bootstrap by @​zkochan in #​249

Full Changelog: pnpm/action-setup@v6.0.5...v6.0.6


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

👻 Immortal: This PR will be recreated if closed unmerged. Get config help if that's undesired.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

withastro/astro

Changes

  • Adds a new "Write a Unit Test" step to the triage bot's fix skill, so it produces a regression test alongside every fix attempt.
  • Creates reference/unit-testing.md documenting unit test conventions, file placement, and the shared test utilities/mocks available in the repo. Referenced from AGENTS.md so any agent (not just triage) can use it.
  • Adds a Unit Test line to the triage bot's GitHub comment template.

Testing

  • No test changes — this PR only modifies agent instructions and reference docs.

Docs

  • No user-facing docs needed. reference/unit-testing.md is agent-facing only.
withastro/starlight

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

@astrojs/starlight@0.39.2

Patch Changes

  • #3890 2d05e18 Thanks @tats-u! - Fixes CSS selector for text-autospace styles in Chromium browsers
withastro/starlight

Description

:lang(zh, ja) used in #3872 shamefully has not been supported Chromium and Safari. As a result, text-autospace has been enabled only in Firefox. Replaced it with the combination of :lang(zh) and :lang(ja).

Screenshot in Chrome (Pay attention to the slight presence of whitespace around "Astro" and "Starlight"):

Before (https://starlight.astro.build/ja/getting-started/):

image

After:

image
withastro/astro

Changes

Since the creation of astro:assets, there has been many lingering issues regarding default output formats. The way the pipeline has to work for SSG / SSR, perf reasons etc, means that we typically don't know the format of the image for real if its remote, which is mostly fine except for one case: SVGs. Since we don't want to convert SVGs to WebP by default, and also the reverse, we often need to know what we're working with to set the default format.

Previously, this wasn't that much of an issue, because imo, it's kinda edge casey and being remote images meant that anyway it's up to the user to authorize. However, now in 6.3 with dangerouslyProcessSVG, it's actually problematic to not really know what we're dealing it, because it could mean a SVG go through when it shouldn't, but also the reverse!

This PR tries to fix this through a few methods:

  • Do a best effort guess at the format early on, allowing ourselves to fail sometimes
  • ... If we failed and we're not converting, and we're in SSG, use the service's way of inferring formats to craft the proper file type, or let the service handle it (as it should, since images could anyway come from a random request!)
  • Harden the service against these problems in various ways

Testing

Updated and added tests for certain of the newly covered cases

Docs

N/A

withastro/astro

Changes

Updates the attribute escaping logic to use named entities (&amp; and &quot;) instead of numeric entities (&#38; and &#34;).

Currently, <title> tags render named entities, while other meta tags render numeric entities. Although both formats are semantically equivalent, this results in inconsistent raw HTML output.

This change aligns the escaping behavior across all head and meta tags so they consistently render named entities.

Closes #16657

Testing

Updates the test cases that rendered &#38; and &#34; to instead render &amp; and &quot;.

Docs

N/A

withastro/astro

Changes

  • Fixes #16201 — the Cloudflare adapter silently replaced a user-defined image.service with @astrojs/cloudflare/image-service-workerd whenever imageService was unset (default 'cloudflare-binding') or set to 'compile'/'cloudflare-binding'/'cloudflare'/'passthrough'. Custom services (e.g., a third-party CDN service) are now preserved across all modes.
  • Added a guard at the top of setImageConfig that detects a non-default image.service (entrypoint ≠ astro/assets/services/sharp) and returns the config untouched, mirroring the precedent in the existing fallback default: branch and the explicit 'custom' mode.
  • Emits a single logger.info line when this preservation kicks in, telling the user the override was skipped and pointing them at imageService: 'custom' to silence the notice.
  • Added a .changeset (@astrojs/cloudflare patch).

Testing

  • New unit test: packages/integrations/cloudflare/test/image-config.test.ts (10 cases) covering preservation across undefined, 'passthrough', 'cloudflare', 'cloudflare-binding', 'compile', and the compound { build: 'compile' } / { build: 'compile', runtime: 'cloudflare-binding' } configs. Also asserts the existing override of default sharp in 'cloudflare-binding' and 'compile' is preserved (no regression) and that explicit 'custom' continues to work.
  • Existing image-related fixture tests run clean: external-image-service.test.ts (2/2), binding-image-service.test.ts (7/7), compile-image-service.test.ts (5/5).
  • pnpm run build succeeds; tsc -b clean.

Docs

No user-facing docs changes needed. Behavior aligns with what the existing docs already imply (a custom image.service should be respected); this PR brings the Cloudflare adapter into line. Worth a brief note in the Cloudflare adapter README that custom services are preserved alongside imageService modes — happy to follow up in withastro/docs if maintainers prefer.

Closes #16201

withastro/astro

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

astro@6.3.2

Patch Changes

  • #16675 11d4592 Thanks @ascorbic! - Fixes a regression where Astro.cache was undefined when experimental.cache was not configured.

    The previous documented behavior is for Astro.cache to always be defined as a no-op shim: cache.set() warns once, cache.invalidate() throws and cache.enabled can be used to gate. This allows library and user code can call cache methods without conditional checks. The cache provider registration was being gated at the call site on experimental.cache being configured, which meant the disabled shim branch inside the provider was unreachable and the Astro.cache getter was never attached to the context.

  • #16691 0f0a4ce Thanks @matthewp! - Fixes HTMLElement is not defined error during HMR when using components with client-side scripts (e.g. Starlight <Tabs>) and the Cloudflare adapter

  • #16562 07529ec Thanks @matthewp! - Fixes non-prerendered routes failing when a dynamic prerendered route exists in the same project with prerenderEnvironment: 'node'

  • #16638 272185b Thanks @ematipico! - Fixes a bug where the Astro compiler wasn't freed at the end of the build. After the fix, the memory used by the compiler is now correctly freed at the end of the build.

  • #16544 d365c97 Thanks @matthewp! - Tightens isRemotePath() to reject control characters after a leading slash and fixes the dev image endpoint origin check

  • #16685 889e748 Thanks @farrosfr! - Improve validation messages for security.csp.directives when script-src or style-src are incorrectly placed in the directives array.

  • #16605 772f13a Thanks @rururux! - Fixes assetsPrefix not being available on build from astro:config/server.

  • #16556 f38dec7 Thanks @matthewp! - Rejects double-encoded URL paths with a 400 response instead of silently falling back to partial decoding

  • #16659 38bcb25 Thanks @jsparkdev! - Fixes & characters appearing as raw entity strings (e.g. &#38;) in <meta> tags when viewed in link previews or raw HTML.

  • Updated dependencies [d365c97, 9256345]:

    • @astrojs/internal-helpers@0.9.1
    • @astrojs/markdown-remark@7.1.2

@astrojs/prism@4.0.2

Patch Changes

  • #15723 9256345 Thanks @rururux! - Fixes an issue where the <Prism /> component failed to work in Cloudflare Workers.

@astrojs/cloudflare@13.5.1

Patch Changes

  • #16707 2ff3f8f Thanks @helio-cf! - Fixes remoteBindings: false being ignored during astro build. The Cloudflare prerenderer's internal Vite preview server now receives the user's adapter options, so remote-flagged bindings (e.g. a D1 database with remote: true in wrangler.toml) are emulated locally during build, matching the existing astro dev behavior.

  • #16652 98c32cc Thanks @greatjourney589! - Fixes user-declared KV namespace bindings being duplicated in the generated dist/server/wrangler.json, which caused wrangler validation to fail with " assigned to multiple KV Namespace bindings." The Astro Cloudflare config customizer now returns only the auto-injected SESSION binding and lets @cloudflare/vite-plugin merge it with the user's wrangler config, instead of pre-merging the user's bindings into the output.

  • #16272 4f9521e Thanks @barry3406! - Fixes .astro files failing with No matching export in "html:..." for import "default" when default-imported from a .ts file

  • #15723 9256345 Thanks @rururux! - Fixes an issue where the <Prism /> component failed to work in Cloudflare Workers.

  • Updated dependencies [d365c97]:

    • @astrojs/internal-helpers@0.9.1
    • @astrojs/underscore-redirects@1.0.3

@astrojs/markdoc@1.0.5

Patch Changes

  • #15723 9256345 Thanks @rururux! - Updates internal type usage from @astrojs/prism.

  • Updated dependencies [d365c97, 9256345, 9256345]:

    • @astrojs/internal-helpers@0.9.1
    • @astrojs/markdown-remark@7.1.2
    • @astrojs/prism@4.0.2

@astrojs/mdx@5.0.5

Patch Changes

  • Updated dependencies [9256345]:
    • @astrojs/markdown-remark@7.1.2

@astrojs/netlify@7.0.9

Patch Changes

  • #16716 04fdbb2 Thanks @delucis! - Updates internal dependencies

  • Updated dependencies [d365c97]:

    • @astrojs/internal-helpers@0.9.1
    • @astrojs/underscore-redirects@1.0.3

@astrojs/node@10.1.1

Patch Changes

  • Updated dependencies [d365c97]:
    • @astrojs/internal-helpers@0.9.1

@astrojs/preact@5.1.3

Patch Changes

  • Updated dependencies [d365c97]:
    • @astrojs/internal-helpers@0.9.1

@astrojs/react@5.0.5

Patch Changes

  • Updated dependencies [d365c97]:
    • @astrojs/internal-helpers@0.9.1

@astrojs/svelte@8.1.1

Patch Changes

@astrojs/vercel@10.0.7

Patch Changes

  • Updated dependencies [d365c97]:
    • @astrojs/internal-helpers@0.9.1

@astrojs/internal-helpers@0.9.1

Patch Changes

  • #16544 d365c97 Thanks @matthewp! - Tightens isRemotePath() to reject control characters after a leading slash and fixes the dev image endpoint origin check

@astrojs/ts-plugin@1.10.8

Patch Changes

astro-vscode@2.16.15

Patch Changes

@astrojs/markdown-remark@7.1.2

Patch Changes

  • #15723 9256345 Thanks @rururux! - Updates internal type usage from @astrojs/prism.

  • Updated dependencies [d365c97, 9256345]:

    • @astrojs/internal-helpers@0.9.1
    • @astrojs/prism@4.0.2
withastro/astro

Closes #16590

Changes

  • Fixes a regression introduced in #16555 where user-declared KV namespace bindings (e.g. RATE_LIMIT, CACHE) appear twice in the generated dist/server/wrangler.json, causing wrangler to fail with "<binding> assigned to multiple KV Namespace bindings.".
  • The Astro Cloudflare config customizer now returns only the auto-injected SESSION binding from kv_namespaces, instead of pre-merging the user's existing bindings into the output.
  • @cloudflare/vite-plugin already merges the customizer's output with the user's wrangler config, so echoing the user's bindings caused the duplication.
  • Removed the now-unused withSessionKVBinding() helper.
  • Added a changeset (@astrojs/cloudflare patch).

Affected versions reported in the issue: @astrojs/cloudflare@13.3.0–13.3.1 + astro@6.2.x. Last working combination was astro@6.1.9 + @astrojs/cloudflare@13.2.1, which matches the pre-#16555 behavior this PR restores.

Testing

  • Updated two existing assertions in packages/integrations/cloudflare/test/wrangler.test.ts that locked in the buggy merged-output shape.
  • Added a dedicated regression test does not include user-declared KV bindings in the output (regression #16590) covering the multi-binding scenario from the issue (RATE_LIMIT + CACHE declared by the user) and asserting the customizer returns only [{ binding: 'SESSION' }].
  • All 25 tests in wrangler.test.ts pass locally.

Docs

No documentation changes needed. The fix restores documented and previously-shipped behavior — the public API and configuration surface (sessionKVBindingName, automatic SESSION binding provisioning) are unchanged.

withastro/astro

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

astro@6.3.1

Patch Changes

  • #16646 15fbc41 Thanks @matthewp! - Fixes local images returning 404 on non-prerendered pages when using the generic image endpoint
withastro/astro

Changes

  • Restores the FREDKBOT_GITHUB_TOKEN env var mapping that was accidentally dropped in the flue 0.3 upgrade (#16441). Without it, postGitHubComment fails at the end of every triage run.

Testing

  • No test changes. Verified by inspecting the failing run.

Docs

  • No docs needed — CI-only change.
withastro/starlight

Description

Adds generic clock, desktop, mobile phone, app window, database, server, git branch, notes, question mark, analytics, and padlock icons. Also adds a new logo icon for SolidJS. The mobile icon has a bit of a funny name — mobile-android — but I kept it to match the source library’s name.

Closes #3881
Closes #3863

Which icons to include built-in is always a bit subjective, but I went through our icon library and tried to add a handful that might meet some more common needs on docs sites given I was already adding a couple based on user requests.

For the SolidJS logo, I asked on their Discord server to confirm which style they preferred for a monochrome icon (as it deviates from their more common blue gradient style).

withastro/astro

Changes

After #16402 migrated every test under packages/astro/test to TypeScript, two scripts in packages/astro/package.json were left pointing at non-existent .test.js globs:

"test:match": "astro-scripts test \"test/**/*.test.js\" --match",
"test:cli":   "astro-scripts test \"test/**/cli.test.js\"",

Because astro-scripts test wraps the matched files in a temp module before invoking node:test (see scripts/cmd/test.js:90-102), an empty match still produces a passing run — node:test counts the empty wrapper as a single passing "test" — so the breakage was silent. pnpm test:cli reports tests 1, pass 1, suites 0 and exits in ~100ms without ever executing the real CLI tests in test/cli.test.ts.

This PR:

  • Updates the globs to .test.ts so they match real files (test/cli.test.ts, test/units/**/*.test.ts, test/*.test.ts).
  • Adds --strip-types so node:test can load the TypeScript files, matching the existing test:unit and test:integration scripts on the surrounding lines.
  • Restores test:match as the documented "run a subset of tests by name pattern" command referenced in CONTRIBUTING.md lines 130-132.

Testing

Verified locally before/after the change:

Beforepnpm test:cli (phantom pass, no real tests run):

> astro-scripts test "test/**/cli.test.js"
✔ /workspaces/astro/packages/astro/node_modules/.astro/test.mjs (90ms)
ℹ tests 1   ℹ suites 0   ℹ pass 1

Afterpnpm test:cli --match "astro --version" (real cli.test.ts test):

> astro-scripts test "test/**/cli.test.ts" --strip-types --match 'astro --version'
▶ astro cli
  ✔ astro --version (338ms)
✔ astro cli (339ms)
ℹ tests 1   ℹ suites 1   ℹ pass 1

Note the suite count flips from 0 → 1, confirming cli.test.ts is actually loaded and the describe('astro cli') suite runs.

Docs

No docs changes needed — CONTRIBUTING.md:130-132 already documents pnpm test:match "<pattern>"; this PR makes that documented behaviour work again.

No changeset added — internal-only package.json script change, no published-package surface affected.

withastro/astro

Changes

  • Renames packages/astro/e2e/astro-island-hydration-error.test.js to .test.ts and adds minimal type annotations to align with the e2e test convention established in #16402.
  • This file was introduced in #16412 (after #16402 had already migrated every other e2e test to TypeScript), so it landed using the prior .js convention. It is the only remaining .test.js file in packages/astro/e2e/.
  • As a side effect, the file is now matched by playwright.config.js (which uses testMatch: 'e2e/*.test.ts'), so its two regression tests for astro:hydration-error recovery (added in #16412) now actually execute in CI. They were silently skipped before this rename.

Testing

  • pnpm exec tsc --noEmit -p tsconfig.test.json passes against the converted file.
  • The diff is a near-mechanical port of the existing test (12 insertions / 6 deletions), preserving identical test semantics. git recognises the change as a rename (83% similarity).
  • The Window.__hydrationErrorEvents typing follows the same declare global { interface Window {...} } pattern already used by e2e/view-transitions.test.ts.

Docs

No docs changes required — internal test refactor with no public-API surface.

No changeset added — internal-only test file rename, no published-package behaviour changes.

withastro/astro

Changes

  • The generic image endpoint (assets/endpoint/generic.ts) self-fetches local images from the same origin. #16519 added an isRemoteAllowed check on the response URL, but that check rejects local URLs (e.g. http://host/_astro/image.png) since they aren't in image.domains or image.remotePatterns. This caused local images on non-prerendered pages to 404.
  • Extracted the fetch logic into loadImage.ts with an isRemote flag that gates the isRemoteAllowed check. Local images skip it — they're already protected by the same-origin guard in the caller.

Fixes #16644

Testing

  • Added test/units/assets/endpoint-load-image.test.ts with 4 cases: local image succeeds, unauthorized remote rejected, allowed remote succeeds, fetch failure handled. The local image test fails without the fix.

Docs

  • No docs needed — this is a regression fix restoring prior behavior.
withastro/astro

Changes

A flaky test was detected in astro-assets-prefix.test.ts in CI.
https://github.com/withastro/astro/actions/runs/25502409719/job/74839082587

The root cause is likely that tests are now running in parallel, and both astro-assets-prefix.test.ts and astro-assets-prefix-multi-cdn.test.ts share the same fixture while also calling fixture.clean() in their after() hooks, which deletes the cache folder.
When the test fails, the log shows "The collection "blog" does not exist or is empty. Please check your content config file for errors." and as shown here, the getDataStoreFile function references the .astro folder, which is exactly what clean() removes.

export function getDataStoreFile(settings: AstroSettings, isDev: boolean) {
return new URL(DATA_STORE_FILE, isDev ? settings.dotAstroDir : settings.config.cacheDir);
}

clean: async () => {
await fs.promises.rm(config.outDir, {
maxRetries: 10,
recursive: true,
force: true,
});
const astroCache = new URL('./node_modules/.astro', config.root);
if (fs.existsSync(astroCache)) {
await fs.promises.rm(astroCache, {
maxRetries: 10,
recursive: true,
force: true,
});
}
},

To fix this, I merged the two test files into one.
An alternative would have been to give each test its own dedicated fixture, but since the two test cases are similar in nature, I went with the merge approach instead.

Testing

Green CI

Docs

N/A

withastro/starlight

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

@astrojs/starlight@0.39.1

Patch Changes

  • #3885 010eed1 Thanks @ArmandPhilippot! - Fixes the version mentioned in an error message related to autogenerated sidebar groups support.

  • #3887 b3c6990 Thanks @delucis! - Adds 13 new icons: clock, desktop, mobile-android, window, database, server, code-branch, notes, question, question-circle, analytics, padlock, and solidjs.

withastro/starlight

Description

The Starlight version mentioned in the error related to autogenerated sidebar groups support is wrong:

Support for autogenerated sidebar groups was removed in Starlight v0.38.0.

#3618 has been released earlier in 0.39.0, not 0.38.0.

I added a changeset because we need a new version for such a small change. 😅

withastro/astro

Changes

Migrate a js test file to ts.

Testing

CI should pass.

Docs

N/A

withastro/starlight

This PR contains the following updates:

Package Type Update Change
changesets/action action minor v1.7.0v1.8.0

Release Notes

changesets/action (changesets/action)

v1.8.0

Compare Source

Minor Changes
  • #​258 f5dbf72 Thanks @​tom-sherman! - Support draft version PR modes with a new prDraft input. Use create to create new version PRs as drafts, or always to also convert existing version PRs back to draft when updating them.
Patch Changes

Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

withastro/astro

Changes

A follow-up to #16471 and #16472

svelte2tsx@0.7.55 supports typescript v6, so we can also update the typescript peer dependency range in @astrojs/svelte.

Testing

CI should pass

Docs

A changeset file is added because we need to release a new version for @astrojs/svelte.

withastro/astro

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

@astrojs/cloudflare@13.5.0

Minor Changes

@astrojs/node@10.1.0

Minor Changes

withastro/astro

Changes

Thank you @TheOtterlord for catching this

Testing

Green CI

Docs

withastro/astro

Changes

The compiler was never torn down at the end of the build. This PR fixes it.

Testing

Manually tested.

Docs

N/A

withastro/starlight

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

@astrojs/starlight@0.39.0

Minor Changes

  • #3618 dcf6d09 Thanks @HiDeoo! - ⚠️ BREAKING CHANGE: This release changes how autogenerated links work in Starlight’s sidebar configuration.

    If you have sidebar groups using the autogenerate key, you must now wrap that configuration in an items array:

    {
        label: 'My group',
    -   autogenerate: { directory: 'some-dir' },
    +   items: [{ autogenerate: { directory: 'some-dir' } }],
    }

    This change unlocks the possibility to mix autogenerated links and other links in a single group, for example:

    {
      label: 'Mixed group',
      items: [
        'example-page',
        { autogenerate: { directory: 'examples' } },
        { label: 'More examples', link: 'https://example.com' },
      ],
    }

    This release also updates the shape of autogenerated sidebar entries in route data. Autogenerated links and groups in Astro.locals.starlightRoute.sidebar now include an autogenerate object with the configured directory value:

    {
      type: 'link',
      label: 'Example',
      href: '/examples/example/',
      isCurrent: false,
      autogenerate: { directory: 'examples' }
    }
  • #3618 dcf6d09 Thanks @HiDeoo! - ⚠️ BREAKING CHANGE: This release changes the default collapsed state of autogenerated sidebar subgroups.

    Autogenerated subgroups no longer inherit the collapsed value from their parent group. They are now expanded by default unless explicitly configured with autogenerate.collapsed.

    If your sidebar configuration relies on a collapsed parent group to also collapse its autogenerated subgroups, update your configuration to set autogenerate.collapsed to true:

    {
      label: 'Reference',
      collapsed: true,
      items: [
    -   { autogenerate: { directory: 'reference' } },
    +   { autogenerate: { directory: 'reference', collapsed: true } },
      ],
    }
  • #3845 4d755f5 Thanks @delucis! - Adds a <link rel="alternate" hreflang="x-default" href="..."> tag pointing to the default locale in multilingual sites. The x-default alternate is used as a signal of which language to fall back to if no other is available. Learn more in Google’s SEO localization docs.

  • #3862 ec70630 Thanks @itrew! - Makes spacing of items in nested lists more consistent

  • #3872 417a66c Thanks @tats-u! - Enables the CSS property text-autospace in Chinese and Japanese documents.

    If you would prefer to disable autospacing in Chinese and Japanese pages, you can add the following custom CSS to your site:

    [lang]:where(:lang(zh, ja)) {
      text-autospace: initial;
    }
  • #3797 9764ebd Thanks @delucis! - Avoids the risk of layout shift when users expand and collapse sidebar groups

    This release can introduce additional padding to the site sidebar on certain devices to reserve space for scrollbars. You may wish to inspect your site sidebar visually when upgrading.

    If you would prefer to keep the previous styling, you can add the following custom CSS to your site:

    .sidebar-pane {
      scrollbar-gutter: auto;
    }
  • #3858 6672c35 Thanks @delucis! - Updates i18next, used for Starlight’s localization APIs, from v23 to v26

    There should not be any user-facing changes from this update

withastro/astro

Description

Adds flush() and close() methods to AstroIntegrationLogger, mirroring AstroLogger. Both delegate to the underlying destination's optional flush / close hooks.

AstroLogger already exposes flush() and close() (added in #16404). AstroIntegrationLogger did not, so any code path that placed an AstroIntegrationLogger where an AstroLogger was expected — e.g. App.#prepareResponse calling this.logger.flush() — would crash with TypeError: this.logger.flush is not a function. The two logger classes now have a symmetric public surface.

Closes #16622.

Changes

  • packages/astro/src/core/logger/core.ts: add flush() and close() to AstroIntegrationLogger, identical shape to the methods on AstroLogger.
  • packages/astro/test/units/logger/logger.test.ts: cover AstroIntegrationLogger.flush() / .close() (delegation, no-throw, fork inheritance).
  • changeset: patch.

Testing

pnpm --filter astro build:ci
pnpm --filter astro exec astro-scripts test test/units/logger/logger.test.ts --strip-types --teardown ./test/units/teardown.ts
# 10 pass, 0 fail

Docs

No public API docs change required — AstroIntegrationLogger.flush() / .close() mirror the existing AstroLogger methods (no behaviour change for destinations that don't define flush/close).

withastro/astro

Changes

Fixes #16612

Testing

Should pass! We unfortunately cannot test this in the monorepo because TypeScript is of course always available

Docs

N/A

withastro/astro

Changes

This PR improves integration tests:

  • remove large-array, as we already use that in our benchmarks
  • moves some fixtures at higher level so that they aren't built multiple times
  • removes the custom rollup thing because it's already tested elsewhere

Testing

Green CI

Docs

N/A

withastro/astro

Changes

Some tests in core-image.test.ts have been flaky in Astro's CI.
https://github.com/withastro/astro/actions/runs/25425893932/job/74579340641?pr=16579
https://github.com/withastro/astro/actions/runs/25407064617/job/74520525804?pr=16614

After investigating, I found that the removeDir function, which is used to clean up the cache directory before tests, was not being awaited despite returning a Promise.

This PR adds the missing await to address the potential race condition.

Testing

Green CI

Docs

N/A

withastro/astro

Changes

One of TypeScript's biggest strengths is static analysis. In practice, we rely on it in three places:

  1. In editors (e.g. vscode / TypeScript language service)
  2. During local and CI builds via tsc
  3. During local and CI linting via eslint with type-aware linting

All three ultimately depend on TypeScript project configuration through tsconfig.

Before #16241, Astro used three different tsconfig setups for these workflows:

  1. Editors used an effectively empty root tsconfig.json, so the language service fell back to its default behavior.
  2. tsc used per-package configs that only included src/, excluding files like bin/ and test/.
  3. eslint used a separate tsconfig.eslint.json.

This inconsistency created a poor developer experience. For example, vscode could report type errors while CI remained green, making editor diagnostics unreliable.

This PR completes the TypeScript project references work introduced in previous PRs. After this PR, all three workflows share the same source of truth: the root tsconfig.json.

The root tsconfig.json now includes all src/, test/, scripts, and configuration files (e.g. prettier.config.mjs). It doesn't include SFC files (.astro, .svelte, etc.) and test fixtures, though.

Also, note that if a JS/TS file is included in eslint but not in the root tsconfig.json, eslint will show the following errors. This is beneficial because it ensures that we have all files added to tsconfig.json, thus these files are covered by tsc.

/astro/packages/astro/e2e/astro-island-hydration-error.test.js
  0:0  error  Parsing error: /astro/packages/astro/e2e/astro-island-hydration-error.test.js was not found by the project service. Consider either including it in the tsconfig.json or including it in allowDefaultProject

Testing

CI should pass

Docs

N/A

withastro/astro

Changes

Migrate some tests from JS to TS.

These tests come from an old pull request, which was merged into main after the TypeScript migration was completed.

Testing

N/A

Docs

N/A

withastro/starlight

This PR contains the following updates:

Package Type Update Change
actions/labeler action minor v6.0.1v6.1.0

Release Notes

actions/labeler (actions/labeler)

v6.1.0

Compare Source

Enhancements

  • Add changed-files-labels-limit and max-files-changed configuration options to cap the number of labels added by @​bluca in #​923

Bug Fixes

Dependency Updates

New Contributors

Full Changelog: actions/labeler@v6...v6.1.0


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

withastro/astro

Changes

  • Fixes ModuleLoader.getSSREnvironment() to return the ssrEnvironment parameter the loader was constructed with, instead of always looking up viteServer.environments.ssr.
  • With adapters that register a separate prerender Vite dev environment (notably @astrojs/cloudflare with prerenderEnvironment: 'node'), createViteLoader builds a dedicated loader per environment. Every other method already uses the constructor parameter - only getSSREnvironment() ignored it, so the prerender handler's loader returned the unrelated ssr environment and getComponentMetadata() walked the wrong module graph in dev. With Cloudflare's default workerd ssr, that env is also non-runnable, making the as RunnableDevEnvironment cast unsafe.
  • Removes the now-unused ASTRO_VITE_ENVIRONMENT_NAMES import.
  • Changeset: astro: patch (.changeset/fix-module-loader-prerender-env.md).
  • Closes #16436. Follow-up to #16292, which fixed the visible style-into-<template> symptom in astro:head-metadata but did not touch this separate correctness bug in the per-environment module loader.

Testing

  • tsc --noEmit on packages/astro passes cleanly.
  • Existing regression test packages/astro/test/head-propagation-prerender-env.test.js still passes (1/1) - confirms no regression on the astro:head-metadata path that #16292 fixed.
  • No new test added: loader.getSSREnvironment() has a single caller (getComponentMetadata), and when only the ssr env exists ssrEnvironment === viteServer.environments.ssr, so the new behaviour is a strict superset of the old correct behaviour. Happy to extend the head-propagation-prerender-env fixture with a prerendered route to exercise the prerender handler's loader directly if maintainers prefer.

Docs

No docs change needed - this is a dev-server-internal correctness fix with no user-facing API or behaviour change. Users on adapters with a separate prerender env (e.g. @astrojs/cloudflare with prerenderEnvironment: 'node') will simply see correct head metadata for prerendered routes in dev.

withastro/astro

Changes

The Houston bot for the triage workflow is currently not working.
https://github.com/withastro/astro/actions/runs/25424727887/job/74575139340

The log shows the following:

pnpm exec flue run issue-triage \
    --target node \
    --session-id "issue-triage-$ISSUE_NUMBER" \
    --payload "{\"issueNumber\": $ISSUE_NUMBER}"

Unknown argument: --session-id

Looking into the flue repository, I couldn't find the --session-id argument anywhere.
Instead, I found that --id is defined as the correct argument.
https://github.com/withastro/flue/blob/808b34ee154b94025d5cb2b45288d88b7766ae0f/packages/cli/bin/flue.ts#L95-L108

I also confirmed that commit 8388ed1 in the flue repository changed --session-id to --id.
Based on this, I concluded that --id should be used instead of --session-id, and updated it accordingly.

Testing

I don't know how to do it 😔

Docs

N/A

withastro/astro

Changes

Right now, types for entry.data field returned by getLiveEntry() are not working.

---
import { getLiveEntry } from "astro:content";

const { entry } = await getLiveEntry("example", "hello-world");
const data = entry?.data; // type `any` instead of defined type from loader.
---

The cause is that the utility type ExtractDataType used here is missing, so entry.data is always of type any.

This pr adds the missing utility type to the file.

Testing

Tested by manually adding the missing utility type to the generated .astro/content.d.ts in my projects and verifing the expected types to work.

Docs

It adds missing typing.

withastro/astro

Fixes the smoke test failure caused by astro-expressive-code@0.42.0 being too recently published to pass the 3-day minimumReleaseAge gate. Since this is a Starlight dependency used by our docs smoke test, it should always be installable regardless of release age.

withastro/starlight

Another PR updating depedencies. Expressive Code is the main motivator as the latest release updates to Shiki v4 (thanks again @ocavue!) so Starlight will share this with Astro instead of having v3 and v4 in the tree.

Prod dependencies

  • Updates astro-expressive-code in Starlight (0.41.7 => 0.42.0)

Dev depdendencies

  • Updates astro across monorepo (6.1.9 => 6.2.2)
  • Updates @astrojs/check (0.9.8 => 0.9.9)
  • Updates pnpm (10.33.2 => 10.33.3)
  • Updates linters
    • eslint (10.2.1 => 10.3.0)
    • globals (17.5.0 => 17.6.0)
    • typescript-eslint (8.59.0 => 8.59.2)

Haven’t bothered with a changeset as we already have an unreleased “update deps” patch changeset in the pipeline. Should see no user-facing change in any case.

withastro/astro

Changes

This PR adds the missing * line from a code sample in JSDoc, which basically removed the whitespace between the imports and the code.

This doesn't need a changeset, AFAIK

Testing

Docs

That's all it is.

withastro/astro

Changes

Fixes a regression from #16277 where the generated wrangler.json sets
assets.directory to include the base prefix (e.g. "../client/blog"
instead of "../client").

Cloudflare's asset binding resolves the full request URL path (including
the base) against the directory. With the prefixed path, requests would
resolve to a double-nested location (e.g. client/blog/blog/file.js),
causing 404s for all static assets.

Related: #16276

Testing

Added a test to with-base.test.ts verifying the assets directory in
the generated wrangler.json points to the un-prefixed client root.

Docs

withastro/astro

fixes: #16604

Changes

As reported in the issue, the migration guide and deprecation comments recommended using build.assetsPrefix from astro:config/server as a replacement for the deprecated import.meta.env.ASSETS_PREFIX, but astro:config/server was not actually exporting build.assetsPrefix.

/**
* The prefix for Astro-generated asset links if the build.assetsPrefix config option is set. This can be used to create asset links not handled by Astro.
* @deprecated This will be removed in a future major version of Astro. Use `build.assetsPrefix` from `astro:config/server` instead.
*/
readonly ASSETS_PREFIX: string | Record<string, string>;

This PR fixes the implementation so that build.assetsPrefix is correctly exported from astro:config/server.

Testing

Added tests to verify that build.assetsPrefix is properly exported and that its value can be read correctly.

Docs

The "Upgrade to Astro v6" page documents this under "Deprecated: import.meta.env.ASSETS_PREFIX" and recommends using build.assetsPrefix instead, but the "Imports from astro:config/server" reference page does not yet list build.assetsPrefix.

A follow-up PR to update the docs will be submitted separately.

withastro/astro

Fixes #16491

Context: In Vite 6, top-level vite.optimizeDeps only applies to the client environment. The Cloudflare adapter owns SSR/prerender dep optimization via its configEnvironment hook, so user-configured optimizeDeps.exclude and optimizeDeps.esbuildOptions.loader were silently ignored for server environments.

Changes

  • Fix: capture the user's config.vite.optimizeDeps in astro:config:setup and merge it into the adapter's configEnvironment return value for server environments.
  • Added integration test: (test/custom-loader.test.ts) with a fixture containing a fake package that imports a .data file, reproduces the esbuild "No loader is configured for .data files" error when the fix is absent.
  • Extended test/ssr-deps.test.ts with a dynamically-created fake-data-pkg that imports a .data file, reproduces the esbuild "No loader is configured for .data files" error when the fix is absent.

Testing

  1. Run NODE_OPTIONS="--experimental-strip-types --no-warnings" pnpm test in packages/integrations/cloudflare.
  2. If the new test fails locally with a miniflare compatibility date error, that is a pre-existing local env issue (same as ssr-deps.test.ts) CI is the source of truth

Docs

Fix doesn't introduce any new config options or change any public API. No docs update needed.

withastro/astro

Changes

  • Moves conflict resolution and changeset cleanup into the merge-main-to-next action so the branch is clean and buildable before CI runs. AI only runs when there are actual conflicts; clean merges skip it entirely.
  • Strips the merge-fix action down to just test fixing — no more conflict stripping, no --no-frozen-lockfile. Uses --frozen-lockfile since the lockfile is already correct.
  • Adds critical rules to the fix-tests skill based on analysis of a 1-hour timeout: never run pnpm install, time-box investigation to 5 min, diff before deep-reading source, batch bash commands.

Testing

  • No test changes — these are CI workflow and skill instruction changes.

Docs

  • No docs needed — internal CI automation only.
withastro/astro

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

astro@6.3.0

Minor Changes

  • #16366 d69f858 Thanks @matthewp! - Adds a new experimental.advancedRouting option that lets you take full control of Astro's request handling pipeline by creating a src/app.ts file in your project.

    Today, Astro handles every incoming request through a fixed internal pipeline: trailing slash normalization, redirects, actions, middleware, page rendering, i18n, and so on. That pipeline works great for most sites, but as projects grow you often want to run your own logic between those steps — an auth check before rendering, a rate limiter before actions, custom logging around the whole stack. Advanced routing gives you that control.

    When enabled, Astro looks for a src/app.ts file in your project. If it finds one, that file becomes the entrypoint for all server-rendered requests. You compose the pipeline yourself using the handlers Astro provides, and you can slot your own logic anywhere in the chain.

    Enabling advanced routing

    // astro.config.mjs
    import { defineConfig } from 'astro/config';
    
    export default defineConfig({
      experimental: {
        advancedRouting: true,
      },
    });

    Two ways to build your pipeline

    Astro ships two entrypoints for advanced routing: astro/fetch and astro/hono.

    astro/fetch is a low-level, framework-free API built on the Web Fetch standard. You create a FetchState from the incoming request, then call handler functions in sequence. Each handler takes the state, does its work, and returns a Response (or undefined to pass through). This is the core primitive that everything else is built on:

    // src/app.ts
    import {
      FetchState,
      trailingSlash,
      redirects,
      actions,
      middleware,
      pages,
      i18n,
    } from 'astro/fetch';
    
    export default {
      async fetch(request: Request) {
        const state = new FetchState(request);
    
        // Early exits — these return a Response only when they apply.
        const slash = trailingSlash(state);
        if (slash) return slash;
    
        const redirect = redirects(state);
        if (redirect) return redirect;
    
        const action = await actions(state);
        if (action) return action;
    
        // Middleware wraps page rendering; i18n post-processes the response.
        const response = await middleware(state, () => pages(state));
        return i18n(state, response);
      },
    };

    astro/hono wraps the same handlers as Hono middleware, so you can mix Astro's pipeline with Hono's ecosystem of middleware (logger, CORS, JWT, rate limiting, etc.) using the app.use() pattern you already know:

    // src/app.ts
    import { Hono } from 'hono';
    import { getCookie } from 'hono/cookie';
    import { logger } from 'hono/logger';
    import { actions, middleware, pages, i18n } from 'astro/hono';
    
    const app = new Hono();
    
    app.use(logger());
    
    // Auth gate — only runs for /dashboard routes.
    app.use('/dashboard/*', async (c, next) => {
      const session = getCookie(c, 'session');
      if (!session) return c.redirect('/login');
      return next();
    });
    
    app.use(actions());
    app.use(middleware());
    app.use(pages());
    app.use(i18n());
    
    export default app;

    Both approaches give you the same power — pick whichever fits your project. If you don't need a framework, astro/fetch keeps things minimal. If you want a rich middleware ecosystem, astro/hono gets you there with one import.

    For more information on enabling and using this feature in your project, see the experimental advanced routing docs. To give feedback, or to keep up with its development, see the advanced routing RFC for more information and discussion.

  • #16366 d69f858 Thanks @matthewp! - Adds a consume() instance method to AstroCookies. This method marks the cookies as consumed and returns the Set-Cookie header values. After consumption, any subsequent set() calls will log a warning, since the headers have already been sent.

    Previously this was only available as a static method AstroCookies.consume(cookies). The static method is now deprecated but kept for backward compatibility with existing adapters.

  • #16412 ba2d2e3 Thanks @0xbejaxer! - Add retry and error event handling for astro-island hydration import failures to reduce unrecoverable hydration errors on transient network failures.

  • #16582 885cd31 Thanks @Princesseuh! - Adds a new image.dangerouslyProcessSVG flag to optionally enable processing SVG inputs. For security reasons, Astro will no longer rasterizes SVG image sources by default in its default image service and endpoint.

    Set image.dangerouslyProcessSVG: true to opt back into processing SVG inputs.

    // astro.config.mjs
    import { defineConfig } from 'astro/config';
    
    export default defineConfig({
      // ...
      image: {
        dangerouslyProcessSVG: true,
      },
    });

    Note that this is a breaking change for users who were previously relying on Astro's default image service to rasterize SVG inputs, but it is a necessary change to improve security and prevent potential vulnerabilities.

  • #16519 1b1c218 Thanks @louisescher! - Adds support for redirecting URLs in remote image optimization.

    Previously, when a remote image URL meant to be optimized by Astro led to a redirect, Astro would fail silently and ignore the redirect. Now, Astro tracks up to 10 redirects for these images. If any of the redirects are not covered by a pattern in image.remotePatterns or a domain in image.domains, Astro will fail with a helpful error message.

    In the following example, the first image would be loaded successfully, while the second would lead to Astro throwing an error:

    export default defineConfig({
      image: {
        domains: ['example.com', 'cdn.example.com'],
      },
    });
    {
      /* Redirects to https://cdn.example.com/assets/image.png: */
    }
    <Image
      src="https://example.com/assets/image.png"
      width="1920"
      height="1080"
      alt="An example image."
    />;
    
    {
      /* Redirects to https://malicious.com/image.png: */
    }
    <Image
      src="https://example.com/bad-image.png"
      width="1920"
      height="1080"
      alt="An example image."
    />;

    In cases where all redirects to HTTPS hosts should be trusted, the following configuration for image.remotePatterns can be used:

    export default defineConfig({
      image: {
        remotePatterns: [
          {
            protocol: 'https',
          },
        ],
      },
    });

Patch Changes

  • #16592 9c6efc5 Thanks @matthewp! - Escapes interpolated values in the dev server redirect HTML template, consistent with how the 404 template already handles them

  • #16585 78f305e Thanks @web-dev0521! - Fixes z.array(z.boolean()) in form actions incorrectly coercing the string "false" to true. Boolean array elements now use the same 'true'/'false' string comparison as single z.boolean() fields, so submitting ["false", "true", "false"] correctly parses as [false, true, false].

  • #16567 12a03f2 Thanks @matthewp! - Fixes deleted content collection entries persisting in getCollection() results during dev

  • #16595 ce9b25c Thanks @web-dev0521! - Fixes pushDirective in the CSP runtime duplicating the new directive once per existing non-matching directive. Calling insertDirective() (or otherwise pushing a directive whose name is not yet in the list) now appends it exactly once, and a directive that merges with a later existing entry no longer leaves an unmerged copy behind.

  • #16600 94e4b7c Thanks @web-dev0521! - Fixes Astro.preferredLocale returning the wrong value when i18n.locales mixes object-form entries ({ path, codes }) with string entries that normalize to the same locale. The first matching code in the configured locales order is now selected, matching the documented behavior.

  • #16591 cce20f7 Thanks @matthewp! - Uses a consistent generic error message in the image endpoint across all adapters

  • #16629 f54be80 Thanks @g-taki! - Fixes a bug where SSR responses in astro dev could crash with TypeError: this.logger.flush is not a function.

  • #16589 3740b24 Thanks @ArmandPhilippot! - Fixes an outdated code snippet in the documentation for session storage configuration.

  • Updated dependencies [354e231]:

    • @astrojs/telemetry@3.3.2

@astrojs/cloudflare@13.4.0

Minor Changes

  • #16519 1b1c218 Thanks @louisescher! - Adds support for redirecting URLs in remote image optimization.

    Previously, when a remote image URL meant to be optimized by Astro led to a redirect, Astro would fail silently and ignore the redirect. Now, Astro tracks up to 10 redirects for these images. If any of the redirects are not covered by a pattern in image.remotePatterns or a domain in image.domains, Astro will fail with a helpful error message.

    In the following example, the first image would be loaded successfully, while the second would lead to Astro throwing an error:

    export default defineConfig({
      image: {
        domains: ['example.com', 'cdn.example.com'],
      },
    });
    {
      /* Redirects to https://cdn.example.com/assets/image.png: */
    }
    <Image
      src="https://example.com/assets/image.png"
      width="1920"
      height="1080"
      alt="An example image."
    />;
    
    {
      /* Redirects to https://malicious.com/image.png: */
    }
    <Image
      src="https://example.com/bad-image.png"
      width="1920"
      height="1080"
      alt="An example image."
    />;

    In cases where all redirects to HTTPS hosts should be trusted, the following configuration for image.remotePatterns can be used:

    export default defineConfig({
      image: {
        remotePatterns: [
          {
            protocol: 'https',
          },
        ],
      },
    });

Patch Changes

  • Updated dependencies []:
    • @astrojs/underscore-redirects@1.0.3

@astrojs/language-server@2.16.8

Patch Changes

  • #16627 5778cb7 Thanks @Princesseuh! - Fixes unintended dependency on the typescript package being available to the language server

@astrojs/telemetry@3.3.2

Patch Changes

  • #16260 354e231 Thanks @gameroman! - Refactors internal config logic to remove the dlv dependency in favor of native logic
withastro/astro

Changes

  • Fix pushDirective in the CSP runtime duplicating the new directive once per existing non-matching directive.
  • Root cause: the else branch inside the loop pushed newDirective on every non-match instead of once after the loop. Replaced the deduplicated flag with a matched flag and moved the newDirective push outside the loop, guarded by !matched.
  • Closes #16594.

Before: pushDirective(["img-src 'self'", "style-src 'self'"], "script-src 'self'")["img-src 'self'", "script-src 'self'", "style-src 'self'", "script-src 'self'"] (duplicated + interleaved)
After:["img-src 'self'", "style-src 'self'", "script-src 'self'"]

Also fixes Mode 2: a directive that merges with a later existing entry no longer leaves an unmerged copy in front of the merged result.

Don't forget a changeset! Run pnpm changeset. — Added: .changeset/fix-csp-push-directive-duplicate.md

Testing

  • Added a regression: issue #16594 suite in packages/astro/test/units/csp/runtime.test.ts covering:
    • Mode 1 — non-matching new directive appended exactly once.
    • Mode 2 — merge with a later match, no unmerged copy left behind.
    • Empty input list edge case.
    • Many non-matches: directive-name uniqueness asserted via a Map count.
    • Table-driven sweep across "non-match", "match in middle", "match at end" shapes, asserting both length and Set-based name uniqueness.
  • All 11 tests in csp/runtime.test.ts pass locally (node --test test/units/csp/runtime.test.ts).

Docs

No docs change required — pushDirective is internal CSP runtime; public insertDirective() semantics are unchanged (this restores them to the documented behavior).

withastro/astro

Changes

This PR does an overhaul of all error messages to make them more consistent with each other, namely:

  • fixing missing full stop at the end of messages.
  • adding missing backticks to code excerpts.
  • adding () to differentiate functions from simple properties/objects.
  • improving error titles/messages with more context.

Testing

I am not sure if adding backticks in a few places could break rendering, we'll be sure once we get the automated PR on docs.

Docs

That's all it is.

withastro/astro

Changes

  • The redirect template in 3xx.ts interpolated URL values directly into HTML without escaping. The sibling 4xx.ts template already escapes its values using html-escaper. This applies the same pattern to the redirect template for consistency.

Testing

  • No new tests. The change adds escape() calls around existing interpolations — the same approach 4xx.ts already uses.

Docs

  • No docs update needed.
withastro/astro

Changes

  • The Node image endpoint (node.ts) returns a generic 'Internal Server Error' string on failure, but the generic adapter endpoint (generic.ts) was interpolating the error object into the response. This aligns generic.ts with node.ts so all adapters use the same consistent error response.

Testing

  • No new tests. Single-line string replacement in an error path — existing image endpoint tests cover the surrounding behavior.

Docs

  • No docs update needed.
withastro/starlight

This PR contains the following updates:

Package Type Update Change
withastro/automation action digest e27ec6dc8a2e8b

Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

withastro/starlight

Description

Especially in Chinese and Japanese, the CSS property text-autospace: normal is preferred for better looking like books by automatically inserting spaces with the moderate width.

Without this, some users and AIs try to insert such spaces manually as workarounds but they are too wide and prevent keywords from searched.

Japanese:

Before:

image

After:

image

Note: the current Chinese content of Starlight translation is not affected because it took the workarounds like manually inserting spaces.

The other languages are not affected.

withastro/astro

Changes

  • During astro build, createTempViteServer (in packages/astro/src/core/sync/index.ts) creates a Vite dev server purely to resolve virtual modules for type generation. The server never handles HTTP requests, but every plugin's configureServer hook still fires — including adapter plugins that start heavy runtimes (notably @astrojs/cloudflare@cloudflare/vite-plugin → miniflare/workerd, ~1–3.5 s of overhead).
  • Additionally, top-level optimizeDeps: { noDiscovery: true } only applies to the client environment under Vite 7's Environment API, so adapters' configEnvironment hooks re-injected their optimizeDeps.include lists into ssr / astro / prerender and forced unnecessary pre-bundling.
  • Two changes in createTempViteServer:
    • Per-environment optimizeDeps: { noDiscovery: true, include: [] } for all four environments.
    • Inline astro:sync:strip-server-hooks plugin that removes configureServer from non-astro: plugins in configResolved.
  • Net effect on a representative project: Types Generated drops from ~3.6 s to ~125 ms; total build from ~13 s to ~9.2 s.
  • Closes #16332.
  • Changeset added (patch for astro).

This is the fix astrobot-houston suggested on the issue, applied verbatim.

Testing

  • pnpm exec astro-scripts test test/astro-sync.test.ts --strip-types — all 9 existing sync tests pass.
  • Verified end-to-end against the MRE from #16332 (https://github.com/adamchal/astro-sync-perf): with @astrojs/cloudflare on the adapter, Types Generated drops from ~2.3 s to ~100 ms and miniflare no longer starts during sync.
  • I have been running this same patch (applied as a postinstall monkey-patch) on a production Astro/Cloudflare site for the past few weeks with no regressions in dev or build.

Docs

No user-facing API changes — this is a build-time perf fix. Adapter authors who relied on configureServer firing during sync would notice, but that path was unintentional and has no documented contract.

withastro/astro

Changes

  • Fix z.array(z.boolean()) in form actions incorrectly coercing the string "false" to true.
  • handleFormDataGetAll was using entries.map(Boolean), but FormData values are always strings and Boolean("false") === true. Replaced with the same 'true' / 'false' comparison already used for single z.boolean() fields in handleFormDataGet.
  • Closes #16584.

Before: ["false", "true", "false"][true, true, true]
After: ["false", "true", "false"][false, true, false]

Testing

  • Added a new boolean arrays suite in packages/astro/test/units/actions/form-data-to-object.test.ts:
    • should preserve "false" string values in boolean arrays — direct regression test for the reported case.
    • should coerce mixed boolean array values correctly — table-driven coverage across all-true / all-false / mixed inputs.
  • All 25 tests in formDataToObject pass locally (node --test test/units/actions/form-data-to-object.test.ts).

Docs

No docs change required — this is a behavior fix bringing array-element parsing in line with the already-documented single-boolean coercion behavior.

withastro/astro

fixes #13297

Changes

In the current implementation, enabling prefetch settings causes links to be collected via document.getElementsByTagName('a') on the initial page load.
While this approach works for most cases, it fails to cover certain scenarios, such as the one reported in issue #13297.

The root cause of issue #13297 is that when a component with the server:defer attribute uses top-level await, its links are rendered after the Promise resolves, meaning they are not captured by the initial document.getElementsByTagName('a') call.
More broadly, the same issue occurs whenever links are dynamically added to the DOM after the initial page load.

To address this, this pull request adds the observeDynamicLinks option, which uses a MutationObserver to watch for dynamically added link elements.
This ensures that links added after the initial render are properly captured.

This feature is opt-in.

Why MutationObserver?

Investigation process
  • First, I checked the code around server:defer to see if it used any event notifications.
  • It did not, but I found that the prefetch code [uses the astro:page-load event].
    document.addEventListener('astro:page-load', () => {
  • When I looked into whether astro:page-load could be used here, I found that the constant defining this event name is marked as @deprecated, so I decided to look for a different approach.
    /** @deprecated This will be removed in Astro 7 */
    export const TRANSITION_PAGE_LOAD = 'astro:page-load';
  • I also considered that the root cause of issue #13297 is not specific to server:defer, the same problem can occur in other situations where links are added to the DOM dynamically. For this reason, I wanted an approach that resolves the issue within the prefetch code itself, rather than adding prefetch-dependent logic to the server:defer side.
  • As a result, I concluded that MutationObserver is the best approach, as it is well-suited for observing DOM changes and allows the fix to be fully self-contained within the prefetch implementation.

Testing

Added tests to verify that the observeDynamicLinks option works correctly in the following scenarios:

  • Links dynamically added via server:defer, as reported in issue #13297
  • Links dynamically added by a toggle component (ToggleButton.jsx)

Docs

/cc @withastro/maintainers-docs for feedback!

withastro/astro

Changes

SVGs are always troublesome in the end and wanting to actually process them is so uncommon that it's best to leave it to the user.

I decided to put it on a global image option so that other services could also use it, but I'd be okay with it being a service config as well, it's ok

Testing

Added a test

Docs

WIP

withastro/astro

This PR contains the following updates:

Package Change Age Confidence
@markdoc/markdoc (source) ^0.5.4^0.5.7 age confidence
devalue ^5.6.3^5.8.0 age confidence
preact (source) ^10.28.4^10.29.1 age confidence
vite (source) ^7.3.2^7.3.3 age confidence

Release Notes

markdoc/markdoc (@​markdoc/markdoc)

v0.5.7

Compare Source

What's Changed
  • Make table-syntax validation error location more precise by @​yue-stripe in #​605
    • the validate() method now returns more location/line info than before
    • Build output now includes ES2022 syntax. The esbuild version used to build markdoc was upgraded from 0.13 to 0.25, which raises the effective output target from ~ES2020 to ES2022+. If your build pipeline transpiles @​markdoc/markdoc, you may need to ensure your toolchain supports ES2022 features such as static class blocks.

Full Changelog: markdoc/markdoc@0.5.6...0.5.7

v0.5.6

Compare Source

What's Changed

  • Add validation for invalid Markdoc table syntax by @​yue-stripe in #​603
    • Markdoc.validate will now raise errors for invalid syntax within {% table %} tags.

Full Changelog: markdoc/markdoc@0.5.5...0.5.6

v0.5.5

Compare Source

Added support for providing a list of conditional tags in addition to if. (['if'] is set by default). No breaking changes.

#​600

sveltejs/devalue (devalue)

v5.8.0

Compare Source

Minor Changes
  • c5115b0: feat: add stringifyAsync for async serialization

v5.7.1

Compare Source

Patch Changes
  • 8becc7c: fix: handle regexes consistently in uneval's value and reference formats

v5.7.0

Compare Source

Minor Changes
  • df2e284: feat: use native alternatives to encode/decode base64
  • 498656e: feat: add DataView support
  • a210130: feat: whitelist Float16Array
  • df2e284: feat: simplify TypedArray slices
Patch Changes
  • 5590634: fix: get uneval type handling up to parity with stringify
  • 57f73fc: fix: correctly support boxed bigints and sentinel values
preactjs/preact (preact)

v10.29.1

Compare Source

Fixes

Maintenance

vitejs/vite (vite)

v7.3.3

Compare Source

Please refer to CHANGELOG.md for details.


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • Between 12:00 AM and 03:59 AM, only on Monday (* 0-3 * * 1)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

👻 Immortal: This PR will be recreated if closed unmerged. Get config help if that's undesired.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

withastro/astro

Changes

Minor adjustment to @astrojs/mdx so smartypants object options are passed to remark-smartypants, matching Astro's markdown behavior since v6.1.

Testing

Added a regression test that verifies smartypants object options (e.g. dashes: "oldschool") are applied in MDX. The test fails without this change (e.g., for dashes: "oldschool" an em-dash is expected while the default configuration produces an en-dash) and passes with it.

withastro/astro

Changes

Close #16273

Fixed issue where custome elements in MDX bypass the renderer pipline. By detecting hyphens in tag names within the JSX runtime, custom elements are now correctly routed to the renderer for SSR, ensuring parity with .astro files.

Testing

Before fixing bug

Test result after implement all test.

スクリーンショット 2026-05-05 23 33 57

After fixing bug

スクリーンショット 2026-05-05 23 24 59

Docs

withastro/starlight

This PR contains the following updates:

Package Type Update Change
pnpm/action-setup action patch v6.0.4v6.0.5

Release Notes

pnpm/action-setup (pnpm/action-setup)

v6.0.5

Compare Source

What's Changed
  • fix: append (not prepend) action node dir to PATH for npm bootstrap by @​zkochan in #​241

Full Changelog: pnpm/action-setup@v6.0.4...v6.0.5


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

lin-stephanie/astro-antfustyle-theme

Description

withastro/astro

Changes

Fixes prerendered pages returning 404 when build.format: 'file' is set in the Node standalone adapter.

When build.format is 'file', pages are emitted as flat .html files (about.html) instead of about/index.html. The send library's extensions option tells it to try appending .html before giving up, so a request to /about resolves correctly on disk instead of falling through to the SSR handler as a 404.

One-line change in serve-static.tsapp.manifest.buildFormat is already available in scope (same as app.manifest.trailingSlash used just above).

Testing

Added two cases to the existing prerender.test.ts under a new "build.format: 'file'" describe block:

  • prerendered page is served correctly via its clean URL
  • SSR route still works alongside it

Docs

No user-facing behavior change beyond bug fix — no docs update needed.

Fixes #16570.

withastro/astro

Changes

Fixes the Vite build warning reported in #15957:

[WARN] Plugin vite:reporter: Unused imports from "@astrojs/internal-helpers/remote":
 – "matchHostname", "matchPathname", "matchPort", "matchProtocol"

plugin-internals.ts sets noExternal: ['astro'] for the prerender environment, which bundles astro but leaves @astrojs/internal-helpers as an external. Rollup then sees that those four helpers are imported by the bundled astro code but not consumed inside the bundle boundary, which triggers the unused-import warning.

Adding @astrojs/internal-helpers to noExternal alongside astro co-bundles it in the prerender environment, eliminating the warning. This is a first-party workspace package and the same pattern is already used elsewhere.

Testing

The warning is emitted by Vite/Rollup during the build phase and is not directly observable in the integration test suite without capturing stderr. Verified manually by running a project build with output: 'hybrid' before and after the change — the warning disappears with the fix applied.

Docs

No user-facing behavior change — no docs update needed.

Fixes #15957.

withastro/astro

Fixes #16692

Changes

  • Automatically injects Cache-Control: public, max-age=31536000, immutable for hashed Astro assets (/_astro/*) into Cloudflare's _headers file at build time, so browsers cache assets across deploys without extra user configuration.
  • Skips injection when build.assetsPrefix is set (assets are served from a different origin).
  • Skips injection when the user's existing _headers already has a Cache-Control rule whose URL pattern matches the assets path — Cloudflare merges duplicate matching rules' headers with a comma, which would produce contradictory cache directives.
  • Respects base config: the injected pattern is prefixed accordingly (e.g. /blog/_astro/*).
  • Injection block is prepended before any existing user-defined headers so rule ordering in the file is predictable.
  • Atomic _headers write (write to .tmp, then rename) to avoid leaving the file truncated on a mid-write crash.

Testing

  • Added unit tests for the new headersFileHasCacheControlForPath utility in packages/integrations/cloudflare/test/headers.test.ts, covering: empty files, exact patterns, global splat (/*), ! Cache-Control detach, non-matching rules, placeholder patterns (:name), host-prefixed patterns, comments/blank lines, base-prefixed paths, and case-insensitivity.
  • Extended the existing with-base integration test to assert the injected block is present with the correct base prefix, that user-defined headers are preserved, and that the injected block is placed before user headers.

Docs

No documentation changes needed — this is an internal build-time improvement for Cloudflare deployments. The behavior is automatic and the skip conditions (logged via logger.info) are observable in build output. No new configuration options were added.

Other Info

Live preview of the fix: https://with-fix-astro-assets-cf-repro.ma2153.workers.dev/

withastro/astro

Changes

  • Invalidates the astro:data-layer-content virtual module in the SSR module runner's evaluatedModules cache when the data store changes, not just in the server-side module graph. The existing invalidateModule call only clears the server's transformResult, but a subsequent transformRequest (triggered during module resolution) re-populates it before the runner's fetchModule check, causing a false cache hit that returns stale data.

Closes #16561

Testing

  • No new tests added. Manually verified with a content collection setup: deleting entries correctly updates getCollection() results on the next page load in dev.

Docs

  • No docs update needed; this is a bug fix with no API change.
withastro/astro

Changes

  • Fixes #16564data-astro-prefetch="tap" silently failing when the user clicks a nested child element (e.g. <span>, <img>, <svg>, Astro <Image />) inside an anchor
  • e.target on touchstart/mousedown is the deepest element under the pointer, not necessarily the <a> — use closest('a') to walk up to the anchor before checking the strategy
  • Particularly impactful on slow connections / data-saver mode, where all strategies collapse to tap — meaning zero prefetching was happening for any link with nested content for the users who would benefit most

Testing

  • Added e2e fixture link <a data-astro-prefetch="tap"><span>tap nested</span></a> and a corresponding page
  • Added e2e test in prefetch.test.ts that clicks the inner <span> and asserts the prefetch request fires

Docs

No docs change needed — this is a bug fix restoring already-documented behavior, not a new feature or API change.

withastro/astro

Closes #16563

Summary

Calling session.delete(key) as the first mutation in a request (no prior get, set, has, keys, etc.) did not write back to session storage. The session stayed dirty in memory, but [PERSIST_SYMBOL]() skipped the save path because #data was still undefined, so the backing store kept the old value and the next request could still read the “deleted” key.

Root cause

  • set() initializes the in-memory map with this.#data ??= new Map(); delete() only did this.#data?.delete(key), so #data could remain undefined.
  • Persistence gated saves on if (this.#dirty && this.#data), so delete-only flows never called setItem and #toDelete was never applied to storage.

Fix

  • Initialize the map in delete() the same way as in set(): this.#data ??= new Map() before removing the key, so the persist path runs and #ensureData() can merge, apply deletions, and serialize to the driver.

Testing

  • Added a unit test that pre-seeds backing storage, calls only delete() then persist, and asserts a new AstroSession with the same storage/session id no longer returns the deleted key.
  • Adjusted an existing persistence test so the follow-up session’s storage get returns parsed JSON (matching real unstorage behavior) after setItem writes a devalue JSON string.

Docs

No documentation change required; behavior now matches what the session API already promises.

Contributor checklist (see CONTRIBUTING.md)

  • pnpm exec changeset for the astro package (user-facing bugfix)
  • Tests: pnpm -C packages/astro exec astro-scripts test "test/units/sessions/astro-session.test.ts"
withastro/astro

Fixes #16553

Changes

  • Fixes non-prerendered routes (e.g. SSR endpoints using cloudflare:workers) failing when a dynamic prerendered route like [page].astro exists in the same project with prerenderEnvironment: 'node'.
  • The dev prerender middleware was using matchAllRoutes(), which returns every route matching a pathname. A request to /ssr would match both ssr.astro (non-prerendered) and [page].astro (prerendered), and since one match was prerendered, the request was incorrectly routed to the Node handler. Replaced with matchRoute(), which returns only the highest-priority match.

Testing

  • Added a dynamic prerendered route ([page].astro with getStaticPaths) to the existing prerender-node-env fixture. The existing "renders SSR page through workerd" test now exercises this scenario.

Docs

  • No docs needed.
withastro/starlight

This PR contains the following updates:

Package Type Update Change
withastro/automation action digest 497c926e27ec6d

Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

withastro/astro

Changes

  • Updates ./test-utils.js imports to ./test-utils.ts in three .test.js files that were missed when #16492 renamed test-utils.jstest-utils.ts.

Testing

  • No new tests. This fixes the existing test:integration:js suite which fails immediately with ERR_MODULE_NOT_FOUND.

Docs

  • No docs needed — test-only change.
withastro/astro

Changes

Simplify db's tsconfig by removing tsconfig.virtual.json.

Its only purpose is to prevent incorrect auto-imports from editor hints and doesn’t affect the runtime output, so it should be relatively safe to remove it.

This file makes it tricky for the TypeScript project references refactor.

Testing

Green CI

Docs

N/A

withastro/astro

Changes

  • Double-encoded URL paths like /api/%2561dmin/users could bypass middleware auth checks because the normalization fallback left ctx.url.pathname half-decoded.
  • Adds MultiLevelEncodingError as a distinct error type so callers can distinguish it from generic decode failures.
  • #createNormalizedUrl now re-throws MultiLevelEncodingError instead of falling back. Other decode errors (truly malformed URLs) still fall back gracefully.
  • BaseApp.render() catches MultiLevelEncodingError and returns 400 Bad Request.

Testing

  • Added test/units/app/double-encoding-bypass.test.ts — 7 tests using a catch-all /api/[...path] endpoint behind auth middleware. Covers the direct path (401), single-encoded (401), double-encoded (400), multiple encoded segments (400), public routes (200), and non-protected API routes (200).

Docs

  • No docs update needed — no user-facing API changes.
withastro/astro

Changes

  • Fixes a bug in @astrojs/cloudflare where custom KV namespace bindings (e.g. MY_KV, CACHE) were silently removed when Astro's session functionality was enabled.
  • The root cause was in packages/integrations/cloudflare/src/wrangler.ts: when injecting the SESSION KV binding, the code returned a fresh single-item array instead of merging with the user's existing kv_namespaces.
  • Extracted a withSessionKVBinding helper that copies existing namespaces and appends the SESSION binding, preserving all user-defined bindings.
  • Fix applies to both the top-level config and the previews config (same code path).
  • Updated the existing test that was asserting the broken behavior, and added a new test covering the previews case.

Closes #16554

Testing

  • Updated packages/integrations/cloudflare/test/wrangler.test.ts: fixed the assertion in "adds SESSION binding when other KV bindings exist but not the session one" to verify OTHER_KV is preserved alongside SESSION.
  • Added a new test "preserves existing previews KV bindings when adding SESSION binding" covering the same scenario in the previews config.
  • No integration test needed: the bug and fix are fully exercised by the unit test suite for cloudflareConfigCustomizer.

Docs

No docs change needed. This is a bug fix restoring behavior that users already rely on — their existing kv_namespaces entries in wrangler.toml now survive when sessions are enabled.

withastro/astro

Changes

  • Fixes a regex bug where return was incorrectly rewritten inside string literals, template literals, and comments during esbuild's dep-scan / frontmatter error-check phase
  • Replaces the two-pass \breturn\b regex with a single-pass state-machine regex that skips over all string/comment tokens before rewriting bare return statements
  • Fixes the primary report case: gen.return(value) → was producing gen.throw (value) (syntax error); now preserved correctly
  • Extracts a shared replaceTopLevelReturns() helper into utils.ts to deduplicate logic between the cloudflare esbuild plugin and compile.ts

Affected files:

  • packages/integrations/cloudflare/src/esbuild-plugin-astro-frontmatter.ts
  • packages/astro/src/vite-plugin-astro/utils.ts
  • packages/astro/src/vite-plugin-astro/compile.ts

Closes #16551

Testing

The fix is a pure regex change with no new dependencies. Verified manually against the cases from the issue:

Input Before After
gen.return(val) gen.throw (val) ← syntax error unchanged ✓
"return value" "throw value" unchanged ✓
// return foo // throw foo unchanged ✓
`return ${x}` `throw ${x}` unchanged ✓
return foo return foo throw foo
return; return; throw 0;

No new tests added — the two affected code paths are internal-only (esbuild dep scan and compile-error enhancement), exercised by the existing integration test suite.

Docs

No user-facing behavior change — this only affects internal dep scanning and error reporting during compilation. No docs update needed.

withastro/astro

Changes

fixes #16524.

with vite.css.transformer: 'lightningcss', scoped styles using a nested & selector inside :where(...) silently produce css where the scope attribute lands on the matched child instead of the intended parent. tailwind v4's space-x-*, space-y-*, and divide-* all expand to this shape and tailwind v4 ships with lightningcss in the loop, so any astro 6 + tailwind v4 project using these utilities in scoped <style> blocks targeting children from another component gets broken spacing in production while the css rule still looks present in the bundle.

what's happening: lightningcss runs inside vite's preprocessCSS() and lowers nesting before @astrojs/compiler injects scope attributes. by the time the compiler sees the css, .parent is buried inside :where(...) and isn't a top-level compound anymore, so the injector prepends [data-astro-cid-X] as a new leading compound — which constrains the wrong element.

fix in packages/astro/src/core/compile/style.ts: when the user has css.transformer: 'lightningcss', call preprocessCSS() with a shallow-cloned vite config whose css.lightningcss.exclude ORs in Features.Nesting, so lightningcss skips its nesting-lowering pass for this preprocess call. vite's final pipeline still lowers nesting for the bundle so output stays compatible with the user's targets. clone is non-mutating per call so it's safe under parallel .astro compiles. lightningcss is resolved from the user's project root via createRequire — same instance vite uses, no new dep added to packages/astro. falls back to the original config if lightningcss can't be resolved.

i think a better fix would live in @astrojs/compiler itself, teach the scope injector to recognize :where(<simple-compound>, ...) as a leading-compound wrapper and attach the cid to the inner compound instead of prepending a new one. similar in spirit to withastro/compiler#1153 but extended to cover the :where(...) case, and it'd cover any future css transform that produces a similarly shaped selector not just lightningcss.

Testing

added a regression fixture under packages/astro/test/:

  • lightningcss-scoped-nesting.test.ts — compiles the reporter's exact shape with vite.css.transformer: 'lightningcss' and asserts the scope id binds to .parent, not as a leading compound on the matched child.
  • fixture under packages/astro/test/fixtures/lightningcss-scoped-nesting/ — single page using the reporter's :where(& > :not(:last-child)) selector inside a scoped <style> block.

reporter's reproduction repo: https://github.com/rklos/astro-css-bug-repro

Docs

no docs changes. silent regression in css output; behavior after the fix matches what the docs already describe for scoped styles + nested selectors.

withastro/astro

Changes

upgrade/package.json has "build": "astro-scripts build \"src/index.ts\" --bundle && tsc". The output dist/index.js should be emitted by astro-scripts, while tsc should only emit .d.ts files.

In #16493, tsc emits both .js and .d.ts files, which overrides the bundled dist/index.js file that was just emitted by astro-scripts.

This PR updates upgrade/tsconfig.json to ensure that tsc won't emit any .js files.

Testing

Before this PR:

$ pnpm -w build
$ tree ./packages/upgrade/dist/
./packages/upgrade/dist/
├── actions
│   ├── context.d.ts
│   ├── context.js
│   ├── help.d.ts
│   ├── help.js
│   ├── install.d.ts
│   ├── install.js
│   ├── verify.d.ts
│   └── verify.js
├── index.d.ts
├── index.js
├── messages.d.ts
├── messages.js
├── shell.d.ts
└── shell.js

2 directories, 14 files

After this PR:

$ pnpm -w build
$ tree ./packages/upgrade/dist/
./packages/upgrade/dist/
├── actions
│   ├── context.d.ts
│   ├── help.d.ts
│   ├── install.d.ts
│   └── verify.d.ts
├── index.d.ts
├── index.js
├── messages.d.ts
└── shell.d.ts

2 directories, 8 files

After this PR, only one bundled dist/index.js file is emitted in dist/.

Docs

The previous and afterward outputs can both work, so there is no behavior change. No docs are needed.


Last fetched:  |  Scheduled refresh: Every Saturday

See Customizing GitHub Activity Pages to configure your own

Inspired by prs.atinux.com