Skip to content
Sibiswhisper - 思比的纸条

AstroEco is Contributing…

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

withastro/astro

Changes

Deno's latest patch dropped a flag on deno eval, seemingly by accident, that Netlify uses. Deno's CLI throws when it sees an unexpected flag (ugh), so this was breaking everything. This PR pins to the last working version.

Testing

Tests should pass!

Docs

N/A

withastro/astro

Changes

Found this bug on a site that uses prims, and the adapter would attempt to optimise only when the page was navigated.

Testing

N/A

Docs

N/A

withastro/astro

Changes

Fixes #17823.

createConsoleLogger takes an options object ({ level }), but the non-runnable dev entrypoint was calling it with the bare level string:

setLogger(manifest, createConsoleLogger(manifest.logLevel));

Destructuring { level } out of a string yields undefined, so the logger was constructed with no level. Every call then goes through isLogLevelEnabled(undefined, level), which evaluates levels[undefined] <= levels[level]undefined <= 30 is false — so every message is dropped before it ever reaches the destination. That is why Astro.logger / context.logger are completely silent while console.log still shows up.

This only affects adapters whose dev server runs in a non-runnable environment (workerd, i.e. @astrojs/cloudflare), because that path loads astro/app/entrypoint/dev (core/app/entrypoints/virtual/dev.ts). The Node adapter's dev server goes through vite-plugin-app/createAstroServerApp.ts, which injects an already-constructed logger, so it was never affected — matching the report.

The fix is to pass the options object the function actually expects.

Testing

Added packages/astro/test/units/logger/dev-entrypoint.test.ts, which stubs the virtual:astro:manifest / virtual:astro:fetchable modules via registerHooks, calls createApp() from the dev entrypoint, and asserts the manifest's logger reports the configured level and actually emits both error and info records.

  • The new test fails against the old code (logger.level() is undefined and nothing is written) and passes with the fix.
  • packages/astro logger unit tests: 88 passing, 0 failing.
  • Full pnpm --filter astro test:unit: 3360 tests, 3359 passing, 0 failing.
  • tsc -b on packages/astro is clean.

Docs

No docs change needed — this restores documented Astro.logger behaviour rather than changing it.

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.41.10

Patch Changes

withastro/starlight

Description

Follow-up on withastro/docs#14460 (comment)

Expressive Code only has English and German translations built-in. Astro Docs has more translations: we should take advantage of this to upstream the missing translations to Starlight.

I only included the missing ones: ar, de, hi, it, ja, ko, pt, zh-CN, and zh-TW.

The following are not included:

And, I haven't checked if the translation are correct... I trust Astro Docs translators. 😅

withastro/starlight

Description

Although I can already feel custom icons tingling in my fingertips, I would like to add one of my favorite icons of 2026: npmx.

withastro/astro

Changes

  • Fixes the sitemap emitting the homepage as <loc>https://example.com</loc> instead of <loc>https://example.com/</loc> when trailingSlash: 'never' or build.format: 'file' is set.
  • Removes the stream-replacement workaround in write-sitemap.ts and write-sitemap-chunk.ts (added in #10772 for an old sitemap.js bug). SitemapStream v9 no longer appends trailing slashes, so the workaround now only ever stripped the root URL's slash. Also drops the now-unused stream-replace-string dependency and the AstroConfig argument those functions no longer need.

Testing

  • Updated trailing-slash.test.ts to assert the root URL keeps its / across the trailingSlash: 'never', build.format: 'file', and base cases, locking in the fix as a regression test.

Docs

  • No docs update needed; this is a bug fix with no user-facing API or config change.

Closes #17848

withastro/astro

Changes

  • Prebundles astro/logger/json in Cloudflare server environments only when JSON logging is active, avoiding a mid-request optimizer reload that can break first-request React SSR. Fixes #17834.

Testing

  • Extends Cloudflare config tests to cover default, console, and JSON logger optimization.

Docs

  • No docs update needed because this corrects internal dev-server dependency optimization.
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@7.2.10

Patch Changes

  • #17833 413a6e7 Thanks @astro-factory! - Fixes prerender conflict warnings to correctly identify the route that first rendered a duplicate pathname, instead of misattributing the conflict to an unrelated route that merely matches the URL pattern

  • #17755 157c500 Thanks @matthewp! - Fixes a bug where editing a content collection entry during astro dev on Windows kept serving stale content until the dev server was restarted. The data store now notifies the dev server directly after each write instead of relying only on the file watcher, which can miss the atomic rename that commits the write on some platforms.

@astrojs/cloudflare@14.2.6

Patch Changes

  • #17854 07b919f Thanks @ematipico! - Added @astrojs/prism to the list of dependencies to optimise. The dev server is now faster for sites that use Prism as code highlighter.

  • #17850 1301c37 Thanks @matthewp! - Fixes React SSR failures on the first Cloudflare dev request when JSON logging is enabled

  • Updated dependencies []:

    • @astrojs/underscore-redirects@1.0.4

@astrojs/sitemap@3.7.4

Patch Changes

  • #17851 52d3f56 Thanks @astro-factory! - Fixes the sitemap outputting a URL with an empty path for the homepage (e.g. https://example.com instead of https://example.com/) when trailingSlash is set to "never" or build.format is set to "file"

@astrojs/language-server@2.16.16

Patch Changes

  • #17715 a51c533 Thanks @wakqasahmed! - Fixes astro check silently skipping .astro files that are only reachable through a TypeScript project reference (a tsconfig referenced via references in another tsconfig). These files are now checked and reported like any other .astro file.
withastro/astro

Changes

  • Escapes string values passed to set:text before Astro JSX rendering
  • Preserves intentional raw script and style children

Testing

  • Adds MDX build and dev coverage for set:text in script and style elements

Docs

  • No docs update needed; this aligns with the documented set:text behavior
withastro/astro

Changes

You can in theory import HTML files inside .ts files, re-export them, use them inside Astro files etc. Found while messing around with content mappers.

Testing

Tested manually

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@7.2.9

Patch Changes

withastro/astro

Fixes #17843

What's wrong

plugin-manifest.ts substitutes @@ASTRO_MANIFEST_REPLACE@@ with a regex that runs in a build post hook — i.e. on already-generated chunk code, after the minifier has run. The character class was ['"], quotes only.

Rolldown/oxc's minifier normalises string literals to template literals, so a minified server build emits the placeholder as `@@ASTRO_MANIFEST_REPLACE@@` and the regex does not match. The placeholder ships verbatim, deserializeManifest reads rootDir/srcDir/outDir/… off a plain string, and the first new URL(undefined) throws:

service core:user:<worker>: Uncaught TypeError: Invalid URL string.
  at entry.mjs:13:29846 in wi

The build exits 0, so nothing surfaces until runtime. On @astrojs/cloudflare the Worker cannot boot at all.

Setting build.minify at the top level rather than on the ssr environment produces the same error at build time instead, because the prerender environment inherits it and its renderer hits the same unsubstituted manifest.

The fix

Accept a backtick in the character class, in both places the pattern appears:

  • plugin-manifest.ts — the manifest placeholder (the one I reproduced).
  • vite-plugin-server-islands.ts — the two server-islands placeholders. I did not reproduce a failure there (that code is tree-shaken out of my app), but the mechanism is identical, so they are fixed alongside rather than left as a latent copy of the same bug.

Verification

Astro 7.1.2, Vite 8.1.5 (rolldown-native), @astrojs/cloudflare 14.1.3, minification enabled on the ssr environment via astro:build:setup:

before after
grep -c '@@ASTRO_MANIFEST_REPLACE@@' dist/server/entry.mjs 1 0
grep -c 'file:///' dist/server/entry.mjs (manifest injected) 0 1
Worker boots under wrangler dev Invalid URL string
prerendered route / 200
server-rendered route /status 200

With the fix the minified bundle also came out 27% smaller gzipped than the unminified one (874.5 kB → 633.8 kB), which is what prompted the investigation.

Possible follow-up

The failure mode here is silent — nothing warned that an expected substitution had not happened, and the broken artifact passed every build check. Asserting that the substitution occurred (and failing the build otherwise) would stop a future quoting change from reintroducing a server bundle that cannot boot. Happy to add that here or separately if you'd like it.

withastro/astro

Summary

When a hybrid build includes lazily imported modules used exclusively by prerendered pages, the shared BuildInternals.entrySpecifierToBundleMap retains those specifiers after the prerender output is deleted. This causes the SSR manifest to reference chunk files that don't exist in the final dist/server/ or dist/client/ output, resulting in missing resolver URLs at runtime.

Fix

Following the established pattern from stripPrerenderedRouteStyles() (PR #16517), this fix:

  1. Adds a prerenderOnlyEntrySpecifiers set to BuildInternals to track specifiers written exclusively by the prerender build environment.
  2. Updates plugin-internals.ts to populate that set during the prerender generateBundle phase.
  3. Strips those prerender-only entries from entryModules during SSR manifest injection in plugin-manifest.ts.

This ensures every entry specifier in the SSR manifest resolves to a file that actually exists in the final server output.

Validation

Reporter @yumam0815 confirmed the fix eliminates all stale manifest references in their downstream validation:

  • Stale/missing manifest references: 12 → 0
  • Missing resolver URLs: 12 → 0
  • Tested on macOS arm64 and Ubuntu 24.04 with Node 22 and Node 24
  • workerd HTTP suite: 54/54 passing

Closes #17838

withastro/astro

Changes

  • Updates Astro’s optional Sharp dependency to 0.35.4.
  • Refreshes the lockfile and package-age exceptions.

Testing

  • No test changes; this is a dependency-only update.

Docs

  • No docs update needed because there are no API changes.
withastro/astro

Changes

  • Prerender conflict warnings now name the route that actually first rendered a duplicate pathname. Previously the warning called matchRoute(), which returns the first route whose URL pattern matches the path rather than the route that emitted it, so the "winning" route in the message could be unrelated.
  • Changes builtPaths from Set<string> to Map<string, RouteData> in packages/astro/src/core/build/generate.ts. The map records which route first claimed each normalized pathname, and duplicate detection reads the winning route from the map instead of guessing via pattern matching.
  • Also handles same-route duplicates: a single route emitting the same pathname more than once now produces a correct conflict warning (or error, under prerenderConflictBehavior: 'error') instead of passing through silently.

Testing

  • Adds prerender-conflict-same-route fixture and two cases in packages/astro/test/prerender-conflict.test.ts covering the same-route duplicate scenario: one asserts the warning names the correct winning route, one asserts the build throws with the correct message under prerenderConflictBehavior: 'error'.

Docs

  • No docs update needed; this corrects the accuracy of an existing build warning with no user-facing API or behavior change.

Closes #17832

withastro/astro

Changes

  • Prevents /index.html requests from crashing when an on-demand dynamic page such as [slug].astro matches the raw pathname. This affects the default build.format: 'directory', where HTML-suffixed paths are not normalized before route matching.
  • Restores the original pathname when stripping .html would invalidate the route Astro already selected, keeping parameter extraction consistent with that match.

Testing

  • Adds unit coverage for root and nested dynamic page routes where stripping /index.html breaks the selected route pattern.
  • Covers the existing /foo.html behavior, where stripping remains valid because the normalized pathname still matches the dynamic route.

Docs

No docs update needed because this prevents an internal routing crash without changing a public API.

Closes #17827

withastro/astro

Changes

We have disabled duplicate-threshold in e18e/action-dependency-diff (by setting it to a large number 100, instead of the default value 1). This PR re-enabled it.

Why we disabled it?

If we enable duplicate-threshold, the previous version of e18e/action-dependency-diff will emit all duplicated packages in the pull request comments. In the astro repo, that’s 200+ packages in total. An example bot comment is shown below:

link:

ocavue-forks#36 (comment)

screenshot:

This information in the comment is too verbose and not useful at all. I guess that's why we disabled it.

Why enable it now?

In the latest e18e/action-dependency-diff v1.7.x, I've contributed a feature that changes duplicate-threshold to only scan the changed dependency in a pull request.

For example, PR #17450 introduced some duplicated package. Now the CI would comment the following content:

link:

ocavue-forks#38 (comment)

screenshot:

The bot comment is much more useful now.

Testing

Green CI

Docs

N/A

withastro/astro

What?

Adds a new with-aws-fargate example demonstrating how to deploy an Astro static site to AWS ECS Fargate via an unprivileged Nginx container using Terraform and GitHub Actions.

Why?

Deploying containerized Astro builds directly to AWS ECS/Fargate behind an Application Load Balancer and CloudFront is a common cloud hosting architecture. Providing a standardized IaC baseline simplifies infrastructure setup for teams managing their own AWS environments.

How?

The infrastructure configuration and deployment workflow were generated using deploy-stack to establish standard Terraform and keyless OIDC GitHub Actions patterns.

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@7.2.8

Patch Changes

withastro/starlight

Description

Adds 1 new icon: hypothesis, for Hypothesis (hypothes.is), the open-source web annotation service.

This follows on from the Goodreads icon in #4145. I raised it on Discord first:

By the way, as I look at my site now, I am missing one more social icon for hypothes.is. Maybe I will also open a PR if you are fine. What do you think, since it is a more niche website for annotating text, and so far, I conquered it with the following (as on the screenshot below) using icon: 'document'

2026-08-25 at 21 42 45

I'm opening this so the mark is concrete to look at rather than hypothetical - very happy to close it if you'd rather not take this one. It's a more niche service than Goodreads or WhatsApp, and I don't want to spam the icon set on account of my own site.

The case for it, for what it's worth: Hypothesis is an annotation layer for documentation and long-form web reading, so it's arguably closer to Starlight's audience than some social platforms. And the icon set already includes comparably specialised entries like forgejo, sourcehut, nostr, jsr and pkl.

About the icon: monochrome 24x24 mark from the official brand page, via Simple Icons (CC0-1.0), optimised with SVGOMG at precision 2 per your note on #4145 - it comes out at 390 bytes. The h. and the dot are knockouts, so it inverts correctly in dark mode like the existing facebook and linkedin marks. I checked it renders cleanly from 16px up.

Placed after goodreads, following where recent social icons have been added.

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.41.9

Patch Changes

withastro/starlight

Description

The sidebar now finds all groups containing the current page in one traversal. Previously, each group repeatedly flattened its subtree, causing unnecessary work for deeply nested sidebars.

Should save some memory and a bit of milliseconds.

withastro/starlight

Description

Replaced repeated route and sidebar scans with maps, sets, and small caches. This reduces build work on documentation sites with many pages and avoids attaching unused route data to static paths.

This PR doesn't affect anything visual

withastro/astro

Changes

  • Prevents TypeScript code actions from inserting generated component exports into .astro source.
  • Tracks the generated export range so user-authored exports and script edits remain unchanged. Fixes #17811.

Testing

  • Adds organize-import coverage for generated exports, matching user exports, and script tags.

Before

vscode-before-organize-imports

After

vscode-after-organize-imports

Docs

  • No docs update needed; this restores expected language-server behavior.
withastro/astro

Changes

  • Derive generated and default Cloudflare compatibility dates from the installed workerd version. Fixes #17796.
  • Expose the date through @astrojs/cloudflare/info and align Cloudflare dependencies.

Testing

  • Cover project-local adapter resolution, derived defaults, and user-provided dates.

Docs

  • No docs update needed; this corrects internal default behavior.
withastro/astro

Changes

  • Where possible, update console calls with the logger instead
  • In some cases, this affects public APIs in non breaking ways so it needs to be a minor
  • I'd like to know if what I've done looks okay, or if some changes need to be reverted in some places
  • Made partially with Claude

Testing

Added

Docs

withastro/starlight

Description

  • This PR adds a new feature which has been discussed and approved here.

Adds 1 new icon: goodreads.

The path is the monochrome Goodreads g mark on a 24x24 viewBox, taken from Simple Icons (CC0-1.0) and optimised with SVGOMG, per the guidance in #4135. It's the same path that was reviewed in the discussion.

Placed after tiktok, following where the recently added social icons have been landing.

withastro/astro

Changes

  • The experimental svgOptimizer did not forward the SVG's file path to SVGO's optimize(). Plugins like prefixIds that derive per-file values from the path fell back to the same generic prefix for every file, so inlining multiple SVGs on one page produced colliding IDs.
  • SvgOptimizer.optimize now takes the file path as a second parameter, and svgoOptimizer() forwards it into SVGO's config, so prefixIds (and similar plugins) generate distinct prefixes per file.
  • This changes the SvgOptimizer interface by adding a required path parameter. Since svgOptimizer is experimental, this is acceptable, but custom SvgOptimizer implementations will need to pass through the new parameter.

Testing

  • Added a fixture with two SVGs sharing an element ID and a page inlining both, then asserted via prefixIds that the resulting IDs differ across files.

Docs

  • No docs update needed; SvgOptimizer is an experimental interface and its usage docs don't specify the optimize signature.

Fixes #17728

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@7.2.7

Patch Changes

  • #17415 55d38c8 Thanks @iseraph-dev! - Deserializes each route once when loading the SSR manifest

  • #17772 023b48b Thanks @matthewp! - Fixes route selection for normalized request paths in adapter and development request handling

  • #17819 633855b Thanks @matthewp! - Updates generated and default Cloudflare compatibility_date values to match the installed runtime and requires Wrangler ^4.125.0

  • #17813 ae26d18 Thanks @matthewp! - Fixes rewrite() and next(payload) for GET and HEAD requests with host-provided bodies

  • #17816 a0d2fe3 Thanks @astro-factory! - Fixes the experimental svgOptimizer not generating unique per-file ID prefixes when using SVGO's prefixIds plugin

@astrojs/cloudflare@14.2.5

Patch Changes

  • #17819 633855b Thanks @matthewp! - Updates generated and default Cloudflare compatibility_date values to match the installed runtime and requires Wrangler ^4.125.0

  • #17675 44d384c Thanks @danielmlr! - Adds the Worker version to the cache metadata of cached responses when the CF_VERSION_METADATA binding is configured. Responses carry an astro-version:<id> cache tag for version-specific purging, and responses that already send Last-Modified get a weak ETag that folds the version in. Conditional revalidation then returns fresh content after a deploy that changes rendered output but not content — most commonly the hashed asset URLs in server-rendered HTML. Without the binding, nothing changes.

  • Updated dependencies []:

    • @astrojs/underscore-redirects@1.0.4

@astrojs/language-server@2.16.15

Patch Changes

  • #17820 89e5349 Thanks @matthewp! - Fixes source.organizeImports leaking generated Astro component exports into .astro files

astro-vscode@2.16.20

Patch Changes

  • #17792 6a46994 Thanks @matthewp! - Fixes syntax highlighting for multiline <script> and <style> tags with a lang or type attribute
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@7.2.6

Patch Changes

  • #17812 29af6da Thanks @matthewp! - Fixes a bug where new FetchState(request) could fail in development when server dependencies were optimized
withastro/astro

Changes

  • Prevents rewrite() and sequenced next(payload) calls from returning 500 when an incoming GET or HEAD request contains a body.
  • Omits bodies when constructing rewritten GET and HEAD requests, while preserving body forwarding for methods such as POST.

Testing

  • Adds rewrite and middleware sequence coverage for incoming GET and HEAD requests with bodies and POST body preservation.

Docs

  • No docs update needed because this corrects an internal request-handling edge case.

Fixes #17801

withastro/astro

Changes

  • The ambient manifest was getting resolved to the fallback. This fixes it by externalizing that import so that Vite resolves it like it normally does, not during the optimization phase.

Testing

  • I added Cloudflare dev coverage for a custom worker using FetchState. Was missing a dev test here.

Fixes astro.build dev

Screenshot 2026-08-24 at 10 28 50 AM

Docs

  • No docs update needed because this restores expected behavior.
withastro/astro

Changes

  • Fixes a regression from 7.2.3, introduced in cf29bec
  • It was happening in a complex private project so I got Claude to reproduce and fix it

Testing

New tests

Docs

Changeset

withastro/astro

Changes

This PR getSafeErrorMessage by removing the redundant String.raw wrapper around the return value of extractStringFromFunction.

withastro/starlight

Description

  • This PR adds a new feature which has been discussed and approved [here](link to GitHub or Discord discussion).

Addresses #4135

Adds a WhatsApp icon to the set.

Before (no WhatsApp icon):

image

After (WhatsApp icon next to Telegram's):

image
withastro/astro

This PR contains the following updates:

Package Change Age Confidence
devalue ^5.9.0^5.9.1 age confidence
fastify (source) ^5.12.0^5.12.1 age confidence

Release Notes

sveltejs/devalue (devalue)

v5.9.1

Compare Source

Patch Changes
  • 39457ce: fix: uneval emits valid JS for graphs with more than 65534 repeated references
  • 686e379: fix: emit valid JS for Node Buffer in uneval
  • 376b65c: fix: preserve -0 in float typed arrays in uneval
fastify/fastify (fastify)

v5.12.1

Compare Source

⚠️ Security release

What's Changed

Full Changelog: fastify/fastify@v5.12.0...v5.12.1


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

This PR contains the following updates:

Package Change Age Confidence
@netlify/blobs (source) ^10.7.4^10.7.13 age confidence
@netlify/functions (source) ^5.2.0^5.3.0 age confidence
@netlify/vite-plugin (source) ^2.12.3^2.12.9 age confidence
@vercel/nft ^1.3.2^1.11.0 age confidence
devalue ^5.8.1^5.9.1 age confidence
tinyglobby (source) ^0.2.15^0.2.17 age confidence
vite (source) ^8.0.13^8.2.2 age confidence

Release Notes

netlify/primitives (@​netlify/blobs)

v10.7.13

Compare Source

Bug Fixes
  • blobs: better error message when using site stores during prebuild (#​737) (80fe1f0)
  • deps: use extracted @netlify/test-utils (5f9c2f9)
Dependencies

v10.7.12

Compare Source

Bug Fixes
  • blobs: send conditional write headers in setJSON (#​731) (a8d9044)

v10.7.11

Compare Source

Dependencies
  • The following workspace dependencies were updated

v10.7.10

Compare Source

Dependencies

v10.7.9

Compare Source

Dependencies

v10.7.8

Compare Source

Dependencies

v10.7.7

Compare Source

Dependencies

v10.7.6

Compare Source

Bug Fixes
netlify/primitives (@​netlify/functions)

v5.3.0

Compare Source

Features
Dependencies
  • The following workspace dependencies were updated

v5.2.2

Compare Source

Dependencies
  • The following workspace dependencies were updated

v5.2.1

Compare Source

Bug Fixes
netlify/framework-adapters (@​netlify/vite-plugin)

v2.12.9

Compare Source

Bug Fixes

v2.12.8

Compare Source

Bug Fixes
  • trigger new releases with Trusted Publishing (#​7) (3052ecb)

v2.12.7

Compare Source

Dependencies

v2.12.6

Compare Source

Dependencies

v2.12.5

Compare Source

Dependencies

v2.12.4

Compare Source

Dependencies
  • The following workspace dependencies were updated
vercel/nft (@​vercel/nft)

v1.11.0

Compare Source

Features

v1.10.2

Compare Source

Bug Fixes

v1.10.0

Compare Source

Features

v1.9.0

Compare Source

Features

v1.5.0

Compare Source

Features
  • trace pino transports in constructor and fastify patterns (#​573) (a044730)

v1.4.0

Compare Source

Features
vitejs/vite (vite)

v8.2.2

Compare Source

Features
Bug Fixes
Documentation
Miscellaneous Chores
Code Refactoring
Tests
Build System
  • use JSON import attributes instead of readFIleSync in rolldown configs (#​23251) (d615bcd)

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

  • Fixes an issue where @astrojs/cloudflare with imageService: "compile" assigned @astrojs/cloudflare/image-transform-endpoint in development mode (astro dev).
  • When paired with passthroughImageService(), format conversion is disabled (delete options.format), omitting f= from the /_image query string. This caused the Cloudflare transform endpoint to crash with 400 Bad Request (Unsupported format: null).
  • Updates case "compile": in packages/integrations/cloudflare/src/utils/image-config.ts to use GENERIC_ENDPOINT (astro/assets/endpoint/generic) when command === "dev", matching the behavior of custom.
  • Added changeset for @astrojs/cloudflare.

Testing

  • Added unit tests in packages/integrations/cloudflare/test/image-config.test.ts verifying that imageService: "compile" resolves to astro/assets/endpoint/generic in dev mode and CLOUDFLARE_PASSTHROUGH_ENDPOINT in build mode.
  • Verified that tests fail on the unpatched code (AssertionError: Expected 'astro/assets/endpoint/generic', got '@astrojs/cloudflare/image-transform-endpoint') and pass with 0 errors when the fix is applied.
  • Tested locally in an Astro project with imageService: "compile" and passthroughImageService() to verify <Image /> components load with HTTP 200 in dev.

Docs

No documentation changes needed.

withastro/astro

Changes

  • Fixes a TypeError: Cannot assign to read only property crash in the Content Layer when a content collection schema applies Zod .readonly() (which freezes parsed data at runtime) to objects containing image() fields.
  • Root cause: MutableDataStore.scopedStore().set() stripped the IMAGE_IMPORT_PREFIX from image values in place using neotraverse's forEach + ctx.update(), which performs direct property assignment (safe_set). On runtime-frozen objects this throws.
  • This is a regression from #17631, which moved prefix-stripping from read-time (structuredClone) to store-time (in-place mutation).
  • Fix: traverse immutably with neotraverse's map instead of mutating via forEach. Replacements are written into copies, so frozen data is handled without reverting to structuredClone (avoiding the class-instance serialization problems #17631 fixed). When no image references are found, the original object is stored unchanged, preserving the previous zero-copy behavior for entries without images.

Closes #17793

Testing

  • Added a regression test in packages/astro/test/units/content-collections/mutable-data-store.test.ts: strips image prefixes from frozen data without mutating it (Zod .readonly() schemas, issue #17793). It asserts that prefixed image values are stripped in the stored entry, that the caller's frozen object is left untouched, and that imageImports/assetImports are recorded correctly.
  • Verified red/green locally:
    • Without the fix, the new test fails with exactly the reported error: TypeError: Cannot assign to read only property 'hero' of object '#<Object>' at safe_setctx.update.
    • With the fix, all 42 tests in test/units/content-collections/ pass (pnpm exec astro-scripts test "test/units/content-collections/**/*.test.ts" --strip-types --teardown ./test/units/teardown.tstests 42, pass 42, fail 0).
  • Changeset added (.changeset/frozen-readonly-content-schemas.md, astro: patch).

Docs

No docs changes needed — this makes an already-valid Zod schema pattern (.readonly() + image()) work as users would expect; no behavior or API surface changed otherwise.

withastro/astro

Changes

  • The incremental build cache now works with build.concurrency > 1; previously Astro disabled the cache with a warning.
  • When collecting incremental metadata, each prerendered path runs with an isolated store. Content entries and image transforms used by that render are recorded in its store, allowing concurrent pages to be cached independently.
  • Custom prerenderers can return this metadata alongside their response. The Cloudflare adapter implements this for workerd prerendering.

Testing

  • Added unit coverage for metadata isolation across concurrent renders and separately bundled Astro modules.
  • Added end-to-end coverage for concurrent incremental builds in Astro and Cloudflare, including content dependencies, optimized images, and cache restoration.

Docs

  • No docs update needed because the concurrency limitation was only exposed through a build-time warning, and the changeset documents the experimental adapter API change.
withastro/astro

Changes

  • Sets the Vercel NFT trace base to the common ancestor of the project root and server entry so builds support outDir outside root.
  • Uses platform-aware ancestry checks with filesystem-root termination, preventing build hangs on Windows and root-boundary layouts.

Testing

  • Adds an integration fixture that verifies an external outDir produces a function containing all traced chunks.
  • Adds unit coverage for entries inside the project root, sibling output directories, and filesystem-root boundaries.

Docs

  • No docs update needed because this fixes internal dependency tracing for existing root and outDir options.

Closes #17761

withastro/astro

Changes

  • When lang or type appeared on a later line of a <style> or <script> opening tag, VS Code ignored it and highlighted the embedded content as default CSS or JavaScript. Multiline tags now use the requested Sass, TypeScript, JSON-LD, or other language grammar just like single-line tags. Fixes #14657.
  • The TextMate grammar now prescans ordinary opening-tag attributes and applies the language scope when it reaches a complete literal lang or type value. This preserves attribute highlighting without treating dynamic values, unrelated attribute names, or prefixes such as modulex as language selectors.
sass-multiline-fixed

Testing

  • Added multiline Sass and TypeScript grammar fixtures and snapshots covering preceding attributes, default-language fallbacks, JSON-LD and module scripts, quoted and unquoted values, dynamic values, and lookalike attribute names and values.

Docs

  • No docs update needed because this corrects syntax highlighting for already-valid <style> and <script> formatting.
withastro/astro

Changes

  • Astro's Volar proxy caches getCompletionsAtPosition the first time it is accessed. Vue later replaces that method, but the stale wrapper prevents Vue's auto-import logic from running.
  • Invalidates the cached method on assignment so the next request rebuilds the wrapper around Vue's decorated method, restoring auto-imports when Astro loads first. Fixes #15962.
vue-auto-import-fixed

Testing

  • Adds a regression test proving methods assigned by a later TypeScript plugin replace cached wrappers.

Docs

  • No docs update needed; this restores existing editor behavior.
withastro/astro

Changes

  • Fixes #17697 by wrapping Astro frontmatter in an async function during Cloudflare dependency scans, so top-level return statements are valid without fragile token rewriting.
  • Hoists static imports outside the wrapper so Rolldown still discovers dependencies, and removes the unused esbuild scanner left behind by the Vite 8 migration.

Testing

  • Adds unit coverage for import forms, top-level and bare returns, import.meta, frontmatter without imports, and regex literals containing quote characters.
  • Updates the Cloudflare top-level-return fixture to reproduce the regex-literal dependency scan failure.

Docs

  • No docs update needed because this fixes internal dependency-scanning behavior without changing user-facing APIs or configuration.
withastro/starlight

Description

  • When adding support for the Sätteri Markdown processor, we missed that because Sätteri provides a URL in its file object, we were treating it with the same logic we used for the <Code> component when trying to detect the locale (which passes Astro.url). Because the assumptions are quite different this broke localisation of Expressive Code code blocks when using with the Sätteri processor.
  • This PR fixes that by detecting Sätteri’s file:// URLs and ignoring them.
  • I’ve added some new unit tests for getBlockLocale() although I’m a bit conflicted because these test don’t actually check the interface between real world inputs and the getBlockLocale() method, so I suppose a future change to the file object passed by a Markdown processor could still cause a similar regression, but at least this is better than nothing.
  • Doing this also brought these files newly into view for Vitest, so dropped our coverage down. I’ve added some additional tests for other parts of the Expressive Code config processing logic to keep coverage high.

(It might be best to hide whitespace changes while reviewing the tests because I wrapped some existing tests in this file in a describe() block but otherwise they are unchanged.)

withastro/astro

Changes

  • Adds apng to the format union returned by image(). #17774 added apng to VALID_INPUT_FORMATS but not to the matching ImageFunction type, so images from a collection schema no longer type-check against ImageMetadata — this breaks astro check on examples/blog, and main has been red since it merged.

Testing

  • Adds a type test asserting the image() schema's format matches ImageInputFormat; it fails without the fix. This runs in test:types, which is why the drift is caught here rather than by widening the astro check path filter.

Docs

  • Not needed, this restores the intended type for an existing API.
withastro/astro

Changes

Enables the Node module compile cache. Vite and some other projects started doing this a few years back to great result. I tried it in local and it's a pretty good boost in local for little cost (a few mb, at worse).

I got gains ranging from 50 to 200ms on the various commands of the CLI trying it in local, with most notably some of our examples astro build being 100-200ms faster, pretty neat.

Testing

Tested manually

Docs

N/A

withastro/astro

Changes

  • Prevents memoryCache() from storing responses with cookies queued by Astro.cookies or Astro.session. Fixes #17775.
  • Detects attached outgoing cookies without consuming them, preserving final Set-Cookie handling.

Testing

  • Adds App pipeline coverage for uncached Astro cookie and session responses, including subsequent session updates.

Docs

  • No docs update needed because this restores the existing Set-Cookie cache exclusion behavior.
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.41.8

Patch Changes

  • #4142 cacbc9f Thanks @alebelcor! - Adds 1 new icon: whatsApp

  • #4133 3944311 Thanks @delucis! - Internal refactor: numbered id attributes in the <Tabs> component are now page-specific instead of using a global counter

  • #4138 cd4b665 Thanks @delucis! - Fixes localisation of code block UI elements when using the Sätteri Markdown processor

withastro/astro

Changes

  • glob() now loads content files whose names contain a colon (e.g. Guide: Architecture.md). Previously these failed with The URL must be of scheme file and the entry was dropped from the collection.
  • encodeURI() preserves colons, so new URL('Guide:%20Architecture.md', base) parsed Guide: as a URL scheme rather than a path segment. Prefixing ./ forces the constructor to resolve it as a relative-path reference. Applied at the three call sites that build a URL from a glob result; isConfigFile() also now encodes the path so config-file matching works for these names.

Testing

  • Adds loads files whose names contain a colon to glob-loader.test.ts, covering that the entry is loaded and its body is readable.
  • The test writes its fixture to a temp directory at runtime instead of committing one, because colons are reserved in Windows filenames and a committed fixture makes git checkout fail on Windows CI. The case is skipped on Windows.

Docs

  • No docs update needed; this restores the documented behavior of glob() for filenames it was already expected to handle.

Closes #17762

withastro/astro

Changes

  • Fixes #17709 by allowing .apng imports to resolve as ImageMetadata with their source, dimensions, and APNG format for use with standard <img> elements.
  • Keeps APNG out of the supported optimization formats so getImage(), <Image>, and <Picture> report an unsupported format instead of stripping animation.

Testing

  • Adds a real two-frame APNG fixture and verifies its 2x3 dimensions and apng metadata format.
  • Covers plain <img> rendering and rejection through getImage(), <Image>, and <Picture>.

Docs

  • No docs update needed because APNG uses the existing image metadata API and the existing unsupported-format error directs users to a standard <img> element.
withastro/starlight

Description

This PR refactors some of the code to use the new Sätteri 0.10 APIs now available in Astro 7.2.4 (but technically 7.2.5 for a fix).

One of the most meaningful change is our components that were previously using rehype and creating processors to parse the default slot content are now using the new Sätteri htmlToHast() API.

Regarding the changeset, not quite sure yet the level of details we should use, e.g. should we just say we updated some deps or go as far as mentioning that we can now only check paths to transform once per plugin type thanks to Sätteri conditional plugin bundles.

Note that GitHub displays some renamed files as deletions + additions because they changed significantly (mostly indentations tho). The rename-only commit may be easier to review separately.

Remaining tasks

withastro/astro

Changes

  • Repeatedly encoded characters can make a request select a catch-all route instead of the exact page users expect. For example, /docs/%2567uide can be matched differently from its normalized /docs/guide path, including between development and deployed apps.
  • Fully normalizes pathnames before adapter and development route matching, so route selection and rendering use the same pathname while preserving adapter-provided route data.

Testing

  • Adds app-level coverage confirming a multi-encoded request selects the exact route before adapter rendering.

Docs

  • No docs update needed because this corrects internal route selection without changing public APIs.
withastro/astro

Changes

Added GitHub discussions link for support options.

Testing

N/A

Docs

N/A

withastro/astro

Summary

buildBackgroundArgs() in packages/astro/src/cli/server.ts reconstructed the child process argv from a hardcoded allowlist that only forwarded 6 flags (--port, --host, --config, --root, --allowed-hosts, --json). Seven additional flags recognized by flagsToAstroInlineConfig()--mode, --site, --base, --out-dir, --verbose, --silent, --open — were silently dropped when running in background mode.

This was especially impactful for --mode, which controls which .env.[mode] file Vite loads. Users running astro dev --background --mode staging would get the default .env with no warning. The problem was further amplified by AI agent auto-detection silently routing users into background mode without any opt-in.

Fix

Added the 7 missing flag forwarding entries to buildBackgroundArgs(), following the same patterns already used for existing flags. Also adds unit tests covering the new flags.


Reporter @aheckerling confirmed the fix resolves their issue.

Closes #17768

withastro/astro

Changes

  • Fixes an SSR build failure that occurs when a user defines vite.environments.ssr in their Astro config: the server entry was emitted as index.mjs instead of entry.mjs, breaking adapters (e.g. @astrojs/vercel) that expect entry.mjs in the astro:build:done hook.
  • In createViteBuildConfig() (packages/astro/src/core/build/vite-build-config.ts), user-provided environments were spread before Astro's managed prerender/client/ssr environments. Because object key order follows insertion order, a user-supplied environments.ssr key ended up earlier in the object than expected, and the astro:resolve-input plugin (which relies on ssr being resolved last) saved the wrong rolldown input.
  • Destructures the Astro-managed environment keys (ssr, prerender, client) out of the user-provided environments before spreading, so they're always re-inserted last and in a fixed order.
  • Also fixes a bug where user-provided non-build environment config (e.g. resolve.external) was silently dropped instead of merged into the managed environment config.
  • Adds a changeset.

Closes #17760

Testing

Added 5 unit tests in packages/astro/test/units/build/vite-build-config.test.ts (environment key ordering block) covering:

  • ssr staying last in the environments object even when the user defines environments.ssr.
  • User non-build properties (resolve.external) being preserved on the ssr, prerender, and client environments.
  • Managed keys appearing exactly once, in the expected order, when the user defines all three.

Also confirmed fixed manually by @matthewp.

Docs

No docs changes needed — this is a bugfix restoring existing documented behavior, not a change to public API or user-facing config.

withastro/astro

Summary

When Astro 7.2 introduced the lock file mechanism for astro preview (PR #17174), it did not include a way to bypass the lock check. When --ignore-lock was subsequently added for astro dev (PR #17331), it was not extended to astro preview. This meant that users running multiple simultaneous preview servers (e.g., in Playwright E2E test setups) would always hit the "Another astro preview server is already running" error, with no workaround.

What Changed

  • Extends --ignore-lock support to packages/astro/src/cli/preview/index.ts, reusing the existing isIgnoreLock() helper from the dev module.
  • Adds conflict detection: --ignore-lock is rejected when combined with --force or --background, mirroring the dev server behavior.
  • When --ignore-lock is set, the lock file check and write are skipped, allowing multiple preview servers to run simultaneously on different ports.
  • Adds --ignore-lock to the preview --help output.
  • Includes a unit test (packages/astro/test/units/preview/ignore-lock-flag.test.ts) and a patch changeset.

Confirmation

@ematipico confirmed the fix: "The preview seems to be working".

Closes #17720

Docs

Needs a docs PR for the new flag

withastro/starlight

Description

  • Closes #4132
  • Uses a per-page counter so that the HTML output by <Tabs> does not change on one page as a side effect of adding/removing tabs in other pages.
  • Before, tab HTML would include markup like id="tab-panel-37" indicating the 37th panel rendered during a build/dev session. These IDs now contain two indexes: one for the instance on the page, another for the panel within that instance, e.g. id="tab-panel-1-3" for the fourth panel in the second <Tabs> on a page (the counts are zero-indexed).
  • Initially when reading #4132 I considered closing it as “working as intended” because tab IDs are an internal API detail and don’t matter too much. However, I think it’s valuable to fix as build systems that diff page content and upload changed files may benefit from this by not needing to reupload multiple files just because of a <Tabs> change on another page earlier in the build.
  • Made this a patch as I don’t think there are any reasonable ways people could be using the current id format but happy to reconsider if someone knows of one.
withastro/astro

Changes

This PR fixes the Sätteri processor option types to accept all plugin entries supported by Sätteri v0.10.3 released yesterday.

Testing

I added a test using a conditional plugin factory which is a new supported type of plugin entry.

Docs

This is a type-only change.

withastro/astro

Summary

Fixes #17748

When building an Astro site with output: "static" and the Cloudflare adapter configured with imageService: "compile" (or "cloudflare-binding"), original image files referenced directly in pages (e.g. <a href={image.src}>, og:image, etc.) were missing from dist/client/_astro/ while resized variants were emitted.

Cause

  1. During prerendering in the Cloudflare preview/workerd worker, raw src accesses add image paths to globalThis.astroAsset.referencedImages inside the workerd isolate.
  2. The /__astro_static_images endpoint returned only staticImages transforms and did not serialize globalThis.astroAsset.referencedImages.
  3. Consequently, the Node-side build (generate.ts) had an empty referencedImages set and deleted the original unoptimized images because it assumed they were only used as intermediate transform sources.

Fix

  • Extended handleStaticImagesRequest in packages/integrations/cloudflare/src/utils/prerender.ts to serialize referencedImages alongside entries.
  • Updated collectStaticImages in packages/integrations/cloudflare/src/prerenderer.ts to deserialize and merge referencedImages into Node's globalThis.astroAsset.referencedImages.
  • generate.ts now sees the referenced source paths and leaves the original image assets in dist/client/_astro/.
withastro/astro

Summary

When using the Cloudflare adapter, Vite's dep optimizer triggers the load hook for astro/assets/fonts/runtime.js eagerly during startup — before the HTTP server has started listening. This caused RemoteRuntimeFontFileUrlResolver.resolve() to throw a "Server address unavailable" error (surfaced as the misleading "URL is invalid" error) because the server address was baked in as null at module load time.

Fix

Updates RemoteRuntimeFontFileUrlResolver.resolve() to use the requestUrl parameter (already part of the RuntimeFontFileUrlResolver interface but previously ignored) as a fallback when the server address is null. When the address is unavailable, requestUrl.origin is used to construct the font file URL instead. This works across runtime boundaries (Node.js and workerd) without requiring shared state or deadlock-prone awaits.

Two new unit tests were added to packages/astro/test/units/assets/fonts/infra.test.ts covering the fallback behavior.

Confirmation

@matthewp confirmed this fixes the problem.

Closes #17722

withastro/astro

Summary

Fixes two bugs in astro build error reporting that caused incorrect or missing file locations and misleading hints when MDX (or other plugins) throw transform errors.

Bug 1: Variable scoping in collectErrorMetadata() (packages/astro/src/core/errors/dev/utils.ts)

Inside the err.forEach((error) => { ... }) loop, three references used e (the outer/parent Vite/rolldown error) instead of error (the current sub-error). This caused the sub-error's correct loc, plugin, and stack to be overwritten with data from the parent error — resulting in wrong file locations and spurious "Browser APIs are not available" hints.

  • if (e.stack)if (error.stack)
  • collectInfoFromStacktrace(e)collectInfoFromStacktrace(error)
  • generateHint(e)generateHint(error)

Bug 2: Missing line:col in MDX plugin (packages/integrations/mdx/src/vite-plugin-mdx.ts)

The MDX plugin's catch block set err.loc = { file: id, line: e.line, column: e.column }, but oxc parser errors don't expose .line/.column as properties — the position info is only available as a "10:5: ..." prefix in the error message. This caused location to render as file:0:0. A fallback that parses line:col from the message string was added.

Tests

Added 3 unit tests in packages/astro/test/units/errors/dev-utils.test.ts covering the aggregate error path for collectErrorMetadata().

Confirmed by @matthewp.

Closes #17735

withastro/astro

Summary

Adds "allowScripts": { "esbuild": true } to all 24 example package.json files and introduces ensureNpmScriptsAllowed() in packages/create-astro/src/actions/dependencies.ts to handle third-party templates as well.

Why

npm v11 introduced allowScripts — a security feature requiring explicit approval of packages with install scripts. esbuild (a direct dependency of astro) runs a postinstall script to download platform-specific binaries. Without this approval, npm v11 emits a warning on every npm install, and npm v12 (expected July 2026) will make it a hard failure.

This is the npm counterpart to the pnpm v11 strictDepBuilds fix from PR #17205, which added ensurePnpmBuildsAllowed(). The new ensureNpmScriptsAllowed() follows the same pattern.

Confirmation

@matthewp confirmed this fix resolves the issue.

Closes #17745

withastro/astro

Changes

  • Fixes #17335. Astro updates the content store after a collection changes, but Windows sometimes misses the file-change event needed to clear Vite's cached content.
  • The content store now tells Vite directly when Astro finishes writing the update, so invalidation no longer depends on that unreliable event.
  • Vite clears its cached content and route data before reloading the page, allowing the updated content to appear.

Testing

  • store-write-notifications.test.ts: write notifications fire for the store file (single-file and chunked), asset imports file, not for identical data, and stop after unsubscribe.
  • content-virtual-mod.test.ts: simulates the Windows failure mode. A store write with no watcher event still invalidates and reloads once, the watcher echo is skipped, and a later external watcher event still invalidates.

Docs

  • No docs update needed; this is a bug fix with no API or behavior change beyond dev HMR working as documented.
withastro/astro

Summary

Fixes a bug where astro dev would incorrectly treat a stale lock file as valid when the new process inherited the same PID as the old one — a common occurrence in Docker containers, where PID namespaces reset on restart.

Root Cause

In packages/astro/src/core/dev/lockfile.ts, isLockFileProcessAlive() checks whether the PID in the lock file belongs to a running Astro process. When a container restarts, the new astro dev process often gets the same PID as the previous one. The function would find itself running, correctly identify it as an Astro command, and conclude the lock file was still valid — blocking startup.

Fix

Added a self-PID guard at the top of isLockFileProcessAlive():

if (data.pid === process.pid) {
  return false;
}

The current process cannot be the server recorded in the lock file (it hasn't started one yet), so a matching PID always means the lock file is stale.

A unit test covering this case was also added in packages/astro/test/units/dev/lockfile.test.ts.

Confirmed by

@RashiqAzhan confirmed the fix resolves the issue: "I can confirm this is working for me. No more --force is required."

Closes #17744

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@7.2.5

Patch Changes

  • #17758 5f419e2 Thanks @astro-factory! - Fixes a bug where experimental_getFontFileURL() rejected valid font URLs when using the Cloudflare adapter

  • #17416 493796b Thanks @iseraph-dev! - Skips no-op pathname writes when normalizing SSR request URLs

  • #17712 bd374b7 Thanks @fkatsuhiro! - Updates deprecation messages target from Astro 7 to 8

  • #17719 dac1768 Thanks @astrobot-houston! - Fixes session ID validation to reject non-UUID cookie values before using them as storage keys

  • #17770 84eb7e7 Thanks @astro-factory! - Fixes --mode, --site, --base, --out-dir, --verbose, --silent, and --open flags being silently dropped when using astro dev --background or astro preview --background

  • #17713 d035290 Thanks @wakqasahmed! - Fixes content-modules.mjs not removing entries for deleted or renamed content files, which could cause Vite to attempt to resolve non-existent modules

    As part of this fix, #moduleImports is now fully rebuilt from deferredRender entries before every write, so a module import added only through the public addModuleImport() API without a corresponding deferredRender entry in the store will no longer be preserved across writes.

  • #17743 adc750f Thanks @contactjawad! - Fixes Astro.preferredLocale and Astro.preferredLocaleList ignoring Accept-Language quality values when they are absent or 0. An entry without an explicit q= now correctly counts as quality 1.0 (per RFC 7231) and an entry with q=0 is treated as not acceptable, so the highest-quality locale is selected regardless of header order.

  • #17757 660991c Thanks @astro-factory! - Fixes build errors showing wrong file location, missing line:col, and misleading hints when a plugin error (e.g. from MDX) is wrapped by Vite's build error

  • #17783 60b14ff Thanks @matthewp! - Fixes a type error when passing an image from a content collection image() schema to a component or <Image />. The schema returned by image() was missing the apng format, so it no longer matched the type of an imported image.

  • #17664 d483125 Thanks @astrobot-houston! - Fixes an issue where Astro CSP support didn't correctly handle cases "unsafe-inline" resource. Now when "unsafe-inline", Astro won't emit hashes for the directive specified.

  • #17810 0fc5f65 Thanks @florian-lefebvre! - Fixes a regression in the content collections that could cause images to not be resolved

  • #17781 aa33b44 Thanks @matthewp! - Fixes memoryCache() storing responses that set cookies through Astro.cookies or Astro.session

  • #17787 6661fbe Thanks @astro-factory! - Fixes server:defer crashing the dev server with "undefined is not a function" when a deferred component imports from astro:i18n

  • #17750 dd0e3ac Thanks @dobrodob! - Fixes a regression where transition:persist stopped working for <audio> and <video> elements.

  • #17774 fe1d16d Thanks @astro-factory! - Adds support for importing .apng files as image metadata for use with standard <img> elements. Astro's image components reject APNG files to avoid removing their animation

  • #17799 8797754 Thanks @astro-factory! - Fixes i18n fallbackType: "rewrite" returning 500 instead of 404 when the fallback locale also has no matching static path for a prerendered dynamic route

  • #17741 99d3d3d Thanks @ericswpark! - Bumps the Astro compiler to the latest version. Changelog.

  • #17782 3578d45 Thanks @Princesseuh! - Improves the performance of the Astro CLI in local by enabling Node's module compilation cache.

  • #17705 2043e4f Thanks @astrobot-houston! - Fixes incremental builds serving cached HTML that references stale CSS filenames after a stylesheet-only edit

  • #17754 3d50dfd Thanks @astro-factory! - Fixes the dev server refusing to start in Docker containers after a restart due to PID reuse in the lock file check

  • #17769 bbda94d Thanks @astro-factory! - Fixes a build failure when defining vite.environments.ssr in the Astro config. User-provided environment config for ssr, prerender, or client is now properly deep-merged with Astro's internal environment settings instead of silently breaking the server entry naming.

  • #17776 0874da8 Thanks @astro-factory! - Fixes the glob() content loader failing to load files with colons in their names (e.g., Guide: Architecture.md)

  • Updated dependencies [0762a83, 0c99615]:

    • @astrojs/markdown-satteri@0.3.8

create-astro@5.2.4

Patch Changes

  • #17756 f88c875 Thanks @astro-factory! - Fixes npm install warnings on npm v11+ about esbuild's install scripts not being covered by allowScripts. Adds ensureNpmScriptsAllowed() to pre-approve esbuild in package.json before running npm install, matching the existing pnpm v11 compatibility fix.

@astrojs/cloudflare@14.2.4

Patch Changes

  • #17789 7c541a7 Thanks @astro-factory! - Fixes dep scanning failure when .astro frontmatter contains regex literals with quote characters (e.g. /"/g)

  • Updated dependencies []:

    • @astrojs/underscore-redirects@1.0.4

@astrojs/mdx@7.0.8

Patch Changes

  • #17757 660991c Thanks @astro-factory! - Fixes build errors showing wrong file location, missing line:col, and misleading hints when a plugin error (e.g. from MDX) is wrapped by Vite's build error

  • #17766 0762a83 Thanks @HiDeoo! - Fixes Sätteri processor option types to accept all plugin entries supported by Sätteri v0.10.3.

@astrojs/netlify@8.2.4

Patch Changes

  • #17752 e362d4c Thanks @matthewp! - Fixes generated Netlify Image CDN allowlists to reject remote URLs that contain an allowed image origin only within their path or query string

  • Updated dependencies []:

    • @astrojs/underscore-redirects@1.0.4

@astrojs/vercel@11.0.8

Patch Changes

  • #17794 dd29ce8 Thanks @astro-factory! - Fixes a bug where @vercel/nft file tracing silently dropped all dependency files when outDir was configured outside root, causing deployed functions to crash with ERR_MODULE_NOT_FOUND

astro-vscode@2.16.19

Patch Changes

  • #17791 426eaa1 Thanks @matthewp! - Fixes missing Vue template auto-import completions when the Astro extension loads first

@astrojs/markdown-satteri@0.3.8

Patch Changes

  • #17766 0762a83 Thanks @HiDeoo! - Fixes Sätteri processor option types to accept all plugin entries supported by Sätteri v0.10.3.

  • #17314 0c99615 Thanks @barry166! - Fixes the editor tooltip for smartPunctuation claiming it defaults to false when Astro enables it by default.

withastro/astro

Changes

  • For config.domains we should be using ^ so that the URL matches at the front of the URL.
  • This prevents query params from matching.

Testing

  • Tests explain what this fixes best.

Docs

N/A, bug fix

withastro/astro

Changes

  • reifyMediaElements() (added in #17603, shipped in 7.2.1) runs after the transition:persist elements from the old document have been moved into the new body, so it also replaced the live <audio>/<video> nodes carried over from the previous page. Those nodes were never parsed by DOMParser and are not inert; re-creating them resets currentTime/paused and drops listeners and framework refs, which breaks persistent players on every <ClientRouter /> navigation.
  • Collect the media nodes of the old body before the swap (new Set(oldElement.querySelectorAll('video, audio'))) and skip exactly those in reifyMediaElements(). A node that was live and is still in the new body got there through transition:persist — at any nesting depth (including a persist container nested inside a persisted one that has no counterpart on the new page) or with the attribute on the media element itself — so the check is precise by construction. Media parsed from the new document are never in the set and still get reified, so #17601 stays fixed for them.

Closes #17749

Testing

  • Two new e2e tests in packages/astro/e2e/view-transitions.test.ts (fixtures nested-persist-one/two.astro): an expando set on the persisted <video> before navigation must still be there afterwards — (1) transition:persist on the media element itself (existing video-one/two fixture), (2) media inside an inner persist container that has no counterpart on the next page and travels with its matched outer container. Run locally in Chrome Stable: both fail on main (2 failed) and pass with this branch (2 passed). The existing <video> can persist test only asserts that currentTime grows, which a freshly re-created autoplaying element also satisfies — that is why the regression was not caught.
  • Also reproduced in a real app (discours/publy, persistent audio player): with stock 7.2.2 the persisted <audio> loses its identity after a link navigation; with this change applied to dist/transitions/swap-functions.js and the app rebuilt, the app's e2e passes. Details: discours/publy#1410 (comment)

Docs

  • No docs update needed; this restores the behaviour transition:persist always had before 7.2.1.
withastro/astro

Changes

Make sure image-size doesn't hang infinitely on some malformed images. This code has been ported from a community fork called image-size-next

Testing

Added new tests

Docs

N/A

withastro/astro

Changes

Updated the issue template configuration to rename 'Chat' to 'Chat & support' and added a new support option for GitHub discussions.

Testing

N/A

Docs

N/A

withastro/astro

Changes

Fixes #17726.

With build.format: 'preserve' the build asks for pages as /welcome.html, and #stripHtmlExtension() removes that framework-injected suffix so the pipeline sees the canonical path:

this.pathname = this.pathname.replace(/\/index\.html$/, '/').replace(/\.html$/, '');

The first replacement keeps the trailing slash; the second one drops it. Route patterns are compiled with the configured trailing slash, so under trailingSlash: 'always' the route no longer matches its own path. getParams() returns nothing and stringifyParams() then throws TypeError: Missing parameter for any dynamic route — the build fails with no way out other than changing config.

The trailing slash is now restored after stripping when trailingSlash is 'always', so the pathname matches the pattern it came from. Nothing changes for 'ignore' or 'never', and /index.html was already handled by the first replacement.

This needs both settings together, which is why it looked unreproducible at first — build.format: 'preserve' alone is fine, and trailingSlash: 'always' alone is fine.

Testing

Two cases in packages/astro/test/units/fetch/index.test.ts, next to the existing .html stripping test:

  • trailingSlash: 'always'/welcome.html resolves to /welcome/
  • trailingSlash: 'ignore'/welcome.html resolves to /welcome, unchanged

Reverting the source change fails the first with trailing slash should survive .html stripping. Worth noting these tests import from dist/, so the package has to be rebuilt for that check to mean anything — reverting only src leaves them passing.

test/units/fetch (80) and test/units/routing (56) both pass.

Docs

No docs change — this restores the documented behaviour of a supported config combination.

withastro/astro

Changes

  • Updates compiler-rs to 0.4.0

Testing

Tested with pnpm build and pnpm test

Docs

No behavior change AFAIK other than the bugfix for the define:vars issue

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@7.2.4

Patch Changes

  • #17747 a90ff66 Thanks @Princesseuh! - Fixes builds hanging when an image file is malformed

  • #17701 05763a0 Thanks @matthewp! - Fixes base path stripping to respect path-segment boundaries. With a configured base such as /docs, a request like /docs-archive/page is no longer treated as being under the base, so routing and context.url.pathname now agree on the same pathname.

  • #17742 70b449d Thanks @Kjubikstronk! - Fixes astro build throwing TypeError: Missing parameter for dynamic routes when build.format: 'preserve' and trailingSlash: 'always' are used together. Stripping the framework-injected .html suffix dropped the trailing slash that the compiled route pattern requires, so the route no longer matched itself and its params resolved as empty.

  • #17703 771b0a9 Thanks @astrobot-houston! - Fixes Astro.site always being undefined when rendering components via the Container API, even when site is set in astroConfig

  • Updated dependencies [05763a0, bc171af]:

    • @astrojs/internal-helpers@0.10.4
    • @astrojs/markdown-satteri@0.3.7
    • @astrojs/markdown-remark@7.2.4

@astrojs/cloudflare@14.2.3

Patch Changes

  • Updated dependencies [05763a0]:
    • @astrojs/internal-helpers@0.10.4
    • @astrojs/underscore-redirects@1.0.4

@astrojs/markdoc@2.0.8

Patch Changes

  • Updated dependencies [05763a0]:
    • @astrojs/internal-helpers@0.10.4

@astrojs/mdx@7.0.7

Patch Changes

  • #17731 bc171af Thanks @Princesseuh! - Updates Sätteri processor to v0.10.3. See its changelog for details on bugs fixed and features added.

  • Updated dependencies [05763a0]:

    • @astrojs/internal-helpers@0.10.4
    • @astrojs/markdown-remark@7.2.4

@astrojs/netlify@8.2.3

Patch Changes

  • Updated dependencies [05763a0]:
    • @astrojs/internal-helpers@0.10.4
    • @astrojs/underscore-redirects@1.0.4

@astrojs/node@11.1.4

Patch Changes

  • Updated dependencies [05763a0]:
    • @astrojs/internal-helpers@0.10.4

@astrojs/preact@6.0.4

Patch Changes

  • Updated dependencies [05763a0]:
    • @astrojs/internal-helpers@0.10.4

@astrojs/react@6.0.4

Patch Changes

  • Updated dependencies [05763a0]:
    • @astrojs/internal-helpers@0.10.4

@astrojs/vercel@11.0.7

Patch Changes

  • #17687 0a22ff5 Thanks @asmyshlyaev177! - Fixes middlewareMode: 'edge' not running your middleware when isr is also enabled

    Previously, enabling both options deployed the edge middleware but never reached it: requests went straight to the ISR function, which skips rendering entirely on a cache hit. Middleware now runs at the edge for ISR-backed routes before the cached response is served, and query strings are preserved when it forwards the request.

  • Updated dependencies [05763a0]:

    • @astrojs/internal-helpers@0.10.4

@astrojs/internal-helpers@0.10.4

Patch Changes

  • #17701 05763a0 Thanks @matthewp! - Fixes base path stripping to respect path-segment boundaries. With a configured base such as /docs, a request like /docs-archive/page is no longer treated as being under the base, so routing and context.url.pathname now agree on the same pathname.

@astrojs/markdown-remark@7.2.4

Patch Changes

  • Updated dependencies [05763a0]:
    • @astrojs/internal-helpers@0.10.4

@astrojs/markdown-satteri@0.3.7

Patch Changes

withastro/astro

Changes

Adds renderComponent() to the Astro container APIs. The added feature to this function is that it renders the scripts and styles that are declared in the component. It uses the compiler the runtime to dynamically attach and swap them.

import Component from "./components/Footer.astro"

const container = await experimental_AstroContainer.create();

export const GET: APIRoute = async () => {

	return new Response(
		await container.renderComponent(Component, {
			props: { message: 'Hello ' },
			slots: { default: 'World' },
		}),
	);
};

What do you think?

Testing

Added new tests

Docs

Will create one

withastro/astro

Changes

  • Removes the issue-triage github action. We have a separate GitHub app now that includes issue triage (same code) and review.
  • Adds factory-preview.yml. Since triage is being driven by a GitHub app now, it cannot do preview releases since we need OIDC. The solution is to have an action the bot can call to do the releases. That's what this is for.

Testing

N/A

Docs

N/A

withastro/astro

Changes

Updated to the latest version of Sätteri. This update brings on a bunch of features people have been asking for (root visitors, rehype-raw equivalent, bug fixes. etc)

Testing

Tests should pass!

Docs

N/A, we don't document the current version of Sätteri used

withastro/starlight

Description

Adds new LinkCard entries for two new plugins to the starlight community plugins section:

Convention seemed to be to link the GitHub source repositories, so that's what I did. If you prefer, I can link the docs websites instead:

Thank you for Astro and Starlight! 🌟

withastro/astro

Changes

  • Switches from astro-review.yml -> factory.yml, a general purpose agent bot that includes review and other things.
  • Only review enabled right now. It works exactly the same as astro-review.yml.

Testing

Not testable

  • Needs to be installed in the repo after this is merged.

Docs

N/A

withastro/astro

Changes

Fixes a bug I found while using the chunked collection storage. This fix splits the writing, so it should avoid the OOM I experienced

Testing

Added new tests.

I will create a preview release and test it

Docs

N/A

withastro/starlight

Description

This PR updating Vite to version 8.2.0 included a change to warn for features incompatible with the native loader when using the bundle loader (default).

Vite is planning to switch to the native loader by default so this change is just preparing for that future change.

In our case, this means that every Vitest workspace emit such warnings so it ends up being a lot of noise, e.g. here is one example for 1 workspace:

(!) Your Vite config uses features that are unsupported by `configLoader: 'native'`, which is planned to become the default in a future major version of Vite:
  - import "../test-config" without a file extension (vitest.config.ts:1:36). Add the file extension
  - import "../integrations/vite-virtual-modules" without a file extension (../test-config.ts:5:51). Add the file extension
  - import "../utils/plugins" without a file extension (../test-config.ts:6:65). Add the file extension
  - import "./test-plugin-utils" without a file extension (../test-config.ts:7:41). Add the file extension
  - import "../integrations/vite-layer-order" without a file extension (../test-config.ts:8:50). Add the file extension
  - import "../utils/plugins" without a file extension (../test-plugin-utils.ts:2:45). Add the file extension
  - import "../utils/error-map" without a file extension (../../utils/plugins.ts:4:41). Add the file extension
  - import "../utils/collection-fs" without a file extension (../../integrations/vite-virtual-modules.ts:5:39). Add the file extension
  - import "../utils/user-config" without a file extension (../../utils/plugins.ts:9:8). Add the file extension
  - import "../utils/user-config" without a file extension (../../integrations/vite-virtual-modules.ts:6:38). Add the file extension
  - import "./translations" without a file extension (../../utils/plugins.ts:10:37). Add the file extension
  - import "../utils/git" without a file extension (../../integrations/vite-virtual-modules.ts:7:40). Add the file extension
  - import "./translations-fs" without a file extension (../../utils/plugins.ts:11:47). Add the file extension
  - import "../utils/plugins" without a file extension (../../integrations/vite-virtual-modules.ts:8:41). Add the file extension
  - import "../integrations/shared/absolutePathToLang" without a file extension (../../utils/plugins.ts:12:63). Add the file extension
  - import "./collection-fs" without a file extension (../../utils/plugins.ts:13:40). Add the file extension
  - import "./collection" without a file extension (../../utils/collection-fs.ts:3:60). Add the file extension
  - import "../../types" without a file extension (../../integrations/shared/absolutePathToLang.ts:1:38). Add the file extension
  - import "../schemas/i18n" without a file extension (../../utils/translations-fs.ts:5:39). Add the file extension
  - import "../schemas/components" without a file extension (../../utils/user-config.ts:3:39). Add the file extension
  - import "./localeToLang" without a file extension (../../integrations/shared/absolutePathToLang.ts:2:30). Add the file extension
  - import "./createTranslationSystem" without a file extension (../../utils/translations-fs.ts:6:41). Add the file extension
  - import "../schemas/expressiveCode" without a file extension (../../utils/user-config.ts:4:38). Add the file extension
  - import "./slugToLocale" without a file extension (../../integrations/shared/absolutePathToLang.ts:3:30). Add the file extension
  - import "./user-config" without a file extension (../../utils/translations-fs.ts:7:38). Add the file extension
  - import "../schemas/favicon" without a file extension (../../utils/user-config.ts:5:31). Add the file extension
  - import "../schemas/head" without a file extension (../../utils/user-config.ts:6:34). Add the file extension
  - import "../../types" without a file extension (../../integrations/shared/slugToLocale.ts:1:38). Add the file extension
  - import "../../types" without a file extension (../../integrations/shared/localeToLang.ts:1:38). Add the file extension
  - import "../schemas/logo" without a file extension (../../utils/user-config.ts:7:34). Add the file extension
  - import "../schemas/i18n" without a file extension (../../utils/createTranslationSystem.ts:2:39). Add the file extension
  - import "../../utils/i18n" without a file extension (../../integrations/shared/localeToLang.ts:2:38). Add the file extension
  - import "../schemas/pagefind" without a file extension (../../utils/user-config.ts:8:62). Add the file extension
  - import "../translations/index" without a file extension (../../utils/createTranslationSystem.ts:3:33). Add the file extension
  - import "../schemas/sidebar" without a file extension (../../utils/user-config.ts:9:35). Add the file extension
  - import "./user-config" without a file extension (../../utils/i18n.ts:3:38). Add the file extension
  - import "./i18n" without a file extension (../../utils/createTranslationSystem.ts:4:38). Add the file extension
  - import "../schemas/site-title" without a file extension (../../utils/user-config.ts:10:63). Add the file extension
  - import "./user-config" without a file extension (../../utils/createTranslationSystem.ts:5:38). Add the file extension
  - import "../schemas/social" without a file extension (../../utils/user-config.ts:11:35). Add the file extension
  - import "./translations" without a file extension (../../utils/createTranslationSystem.ts:6:51). Add the file extension
  - import "../schemas/tableOfContents" without a file extension (../../utils/user-config.ts:12:49). Add the file extension
  - import "./i18n" without a file extension (../../utils/user-config.ts:13:38). Add the file extension
  - import "../schemas/i18n" without a file extension (../../translations/index.ts:1:35). Add the file extension
  - JSON import "./cs.json" without import attributes (../../translations/index.ts:2:16). Add `with { type: 'json' }`
  - JSON import "./en.json" without import attributes (../../translations/index.ts:3:16). Add `with { type: 'json' }`
  - JSON import "./es.json" without import attributes (../../translations/index.ts:4:16). Add `with { type: 'json' }`
  - JSON import "./ca.json" without import attributes (../../translations/index.ts:5:16). Add `with { type: 'json' }`
  - JSON import "./de.json" without import attributes (../../translations/index.ts:6:16). Add `with { type: 'json' }`
  - JSON import "./ja.json" without import attributes (../../translations/index.ts:7:16). Add `with { type: 'json' }`
  - JSON import "./pt.json" without import attributes (../../translations/index.ts:8:16). Add `with { type: 'json' }`
  - JSON import "./fa.json" without import attributes (../../translations/index.ts:9:16). Add `with { type: 'json' }`
  - JSON import "./fi.json" without import attributes (../../translations/index.ts:10:16). Add `with { type: 'json' }`
  - JSON import "./fr.json" without import attributes (../../translations/index.ts:11:16). Add `with { type: 'json' }`
  - JSON import "./gl.json" without import attributes (../../translations/index.ts:12:16). Add `with { type: 'json' }`
  - JSON import "./he.json" without import attributes (../../translations/index.ts:13:16). Add `with { type: 'json' }`
  - JSON import "./id.json" without import attributes (../../translations/index.ts:14:16). Add `with { type: 'json' }`
  - JSON import "./it.json" without import attributes (../../translations/index.ts:15:16). Add `with { type: 'json' }`
  - JSON import "./nl.json" without import attributes (../../translations/index.ts:16:16). Add `with { type: 'json' }`
  - JSON import "./da.json" without import attributes (../../translations/index.ts:17:16). Add `with { type: 'json' }`
  - JSON import "./th.json" without import attributes (../../translations/index.ts:18:16). Add `with { type: 'json' }`
  - JSON import "./tr.json" without import attributes (../../translations/index.ts:19:16). Add `with { type: 'json' }`
  - JSON import "./ar.json" without import attributes (../../translations/index.ts:20:16). Add `with { type: 'json' }`
  - JSON import "./nb.json" without import attributes (../../translations/index.ts:21:16). Add `with { type: 'json' }`
  - JSON import "./zh-CN.json" without import attributes (../../translations/index.ts:22:16). Add `with { type: 'json' }`
  - JSON import "./ko.json" without import attributes (../../translations/index.ts:23:16). Add `with { type: 'json' }`
  - JSON import "./sv.json" without import attributes (../../translations/index.ts:24:16). Add `with { type: 'json' }`
  - JSON import "./ro.json" without import attributes (../../translations/index.ts:25:16). Add `with { type: 'json' }`
  - JSON import "./ru.json" without import attributes (../../translations/index.ts:26:16). Add `with { type: 'json' }`
  - JSON import "./vi.json" without import attributes (../../translations/index.ts:27:16). Add `with { type: 'json' }`
  - JSON import "./uk.json" without import attributes (../../translations/index.ts:28:16). Add `with { type: 'json' }`
  - JSON import "./hi.json" without import attributes (../../translations/index.ts:29:16). Add `with { type: 'json' }`
  - JSON import "./zh-TW.json" without import attributes (../../translations/index.ts:30:18). Add `with { type: 'json' }`
  - JSON import "./pl.json" without import attributes (../../translations/index.ts:31:16). Add `with { type: 'json' }`
  - JSON import "./sk.json" without import attributes (../../translations/index.ts:32:16). Add `with { type: 'json' }`
  - JSON import "./lv.json" without import attributes (../../translations/index.ts:33:16). Add `with { type: 'json' }`
  - JSON import "./hu.json" without import attributes (../../translations/index.ts:34:16). Add `with { type: 'json' }`
  - JSON import "./el.json" without import attributes (../../translations/index.ts:35:16). Add `with { type: 'json' }`
  - import "../integrations/expressive-code" resolves to a directory index (../../schemas/expressiveCode.ts:2:53). Import the index file directly
  - import "./badge" without a file extension (../../schemas/sidebar.ts:4:39). Add the file extension
  - import "./icon" without a file extension (../../schemas/social.ts:2:28). Add the file extension
  - import "../utils/path" without a file extension (../../schemas/sidebar.ts:5:48). Add the file extension
  - import "../components-internals/Icons" without a file extension (../../schemas/icon.ts:2:43). Add the file extension
  - import "../user-components/file-tree-icons" without a file extension (../../components-internals/Icons.ts:1:27). Add the file extension
Set `VITE_CONFIG_NATIVE_IGNORE_WARNING=true` to suppress this warning.

Multiplied by the number of workspaces, this makes the output very noisy and hard to read while working on tests.

This PR removes such warnings by using the VITE_CONFIG_NATIVE_IGNORE_WARNING=true environment variable. This means that it only suppresses the warnings and does not really fix them:

  • An environment variable is the only way to suppress the warnings, as there is no equivalent configuration option.
  • Such default loader change would probably have quite the impact on the Astro ecosystem, and we don't know yet how we will handle it.
  • Fixing the project to be compatible with the native loader is entirely possible right now, but with #3572 around the corner:
    • It will be a lot of changes probably touching every file in the project (extension-less imports) so having 2 PRs touching so many files in parallel will just be annoying.
    • Doing it in #3572 does not make a lot of sense and will only make the review more difficult

Considering all this, this PR just suppresses the warnings for now, making running tests locally readable again, and we can deal with the real fix later, at least once #3572 is merged.

withastro/astro

Changes

  • #ensureSessionID() now validates the client-supplied session cookie value against a UUID v4 format before accepting it as the session ID. Non-UUID values are silently rejected and a fresh UUID is generated instead.
  • Closes #17718. Only affects setups where the session driver shares a storage backend with other data and no key prefix is used — all default adapter configurations are unaffected.

Testing

  • Adds a test case that sends a crafted non-UUID cookie value (not-a-uuid-at-all) and asserts that the resulting session ID is a valid UUID distinct from the crafted value.

Docs

  • No docs update needed; this is an internal validation fix with no API surface changes.
withastro/astro

Fixes #17478

Problem

When a project uses TypeScript project references (references in tsconfig.json), astro check (and the editor language server) silently drops .astro files that live inside a referenced tsconfig's project. Only the root tsconfig's files were checked with Astro's extraFileExtensions; files pulled in through a reference were not.

Root cause

In @volar/kit's createChecker.js, the root tsconfig is parsed with ts.parseJsonSourceFileConfigFileContent(...), explicitly passing the language plugins' extraFileExtensions (so .astro is included). The project-reference walker (visit()) instead reuses TypeScript's own internally-resolved ref.commandLine for each referenced project, which was resolved without knowledge of extraFileExtensions. As a result, .astro files inside a referenced project were never added to the referenced project's file list.

Revised approach (see review discussion)

The first version of this PR patched @volar/kit@2.4.28 directly via pnpm's patchedDependencies. A cold-start review caught a blocking problem with that approach: @astrojs/language-server and @astrojs/check both build with tsc -b (no bundling) and declare @volar/kit as a normal runtime dependency. pnpm's patchedDependencies only rewrites node_modules inside this monorepo for local dev/CI — it is never encoded into the published npm tarballs. Anyone running npm install @astrojs/check (or @astrojs/language-server) would still get the real, unpatched @volar/kit, so the original bug would remain for every CLI/CI user — the exact scenario in #17478. The only place that actually got the fix was the VS Code extension, because it bundles with esbuild and inlines the patched code at build time.

This PR now implements the fix directly in @astrojs/language-server's own source instead, so it ships in the real published packages:

  • createTypeScriptChecker's setup callback runs once per project — the root project and each project reference — and receives that project's configFileName and a mutable languageServiceHost.
  • For each project, we re-parse its own tsconfig with the language plugins' extraFileExtensions (the same call shape @volar/kit already uses for the root tsconfig) and merge any newly-found files into languageServiceHost.getScriptFileNames(). This affects the actual TypeScript Program used for diagnostics.
  • getRootFileNames() (used by AstroCheck.lint() to enumerate the whole project when no explicit file list is given) reads project-reference file lists from a separate internal host that isn't reachable from setup, so it gets its own equivalent patch on this.linter.getRootFileNames.
  • No changes to the @volar/kit dependency at all — patches/@volar__kit@2.4.28.patch and the patchedDependencies entries in pnpm-workspace.yaml/pnpm-lock.yaml have been removed.

There is still an open upstream fix for the same root cause in volar.js itself (volarjs/volar.js#315). If/when that lands and this repo's @volar/kit pin is bumped past it, our in-source workaround in check.ts becomes redundant (harmless, since it re-derives the same file list) and can be removed.

Test plan

  • Regression test in packages/language-tools/language-server/test/check/check.test.ts: a .astro file with a type error added to the project-references fixture, asserting via checker.linter.getRootFileNames() (per review feedback, independent of the diagnostics-count assertion) that the referenced project's file list includes it, plus asserting the error count and file-checked count.
  • Verified the assertions fail without the fix and pass with it, using the real, unpatched @volar/kit@2.4.28 from npm (not a pnpm patch) — confirms the fix is present in code that will actually reach published packages.
  • node --test test/check/check.test.ts in packages/language-tools/language-server: 10/10 passing, including a clean rebuild of astro, @astrojs/markdown-satteri, @astrojs/svelte, and @astrojs/vue to confirm the two previously-"pre-existing" failures were an artifact of an unbuilt local environment, not a real repo-level issue.
  • Updated changeset for @astrojs/language-server describing the in-source fix.
withastro/astro

Fixes #17707

Changes

  • content-modules.mjs was only ever appended to via #moduleImports, so deleting or renaming a content file with deferredRender left a stale entry pointing at a non-existent file. This caused Vite to attempt to resolve the missing module (e.g. in dev, after removing an MDX/Markdown page).
  • Added #rebuildModuleImports(), mirroring the existing #rebuildAssetImports() pattern used for the asset-imports stale-entry fix (#16097). It clears #moduleImports and rebuilds it from the current _collections state.
  • writeModuleImports() now calls #rebuildModuleImports() before writing, and delete(), clear(), and clearAll() now also trigger a debounced module-imports rewrite (previously they only rewrote asset imports).

Testing

Added two unit tests to packages/astro/test/units/content-collections/mutable-data-store.test.ts:

  • removes stale module imports when an entry is deleted
  • removes stale module imports when a collection is cleared

Ran the full mutable-data-store.test.ts suite locally (8 tests, all passing):

✔ removes stale image asset import after entry image path is updated (issue #16097)
✔ removes asset imports when an entry is deleted
✔ removes asset imports when a collection is cleared
✔ removes stale module imports when an entry is deleted
✔ removes stale module imports when a collection is cleared
✔ reproduces race condition: concurrent writeToDisk() calls lose data
✔ strips image prefixes and records their paths as out-of-band imageImports
✔ does not set imageImports when the entry has no images

Docs

No user-facing API changes; no docs needed.

withastro/astro

Changes

Please refar this comment from @florian-lefebvre san.

IIRC all comments/deprecations that talk about Astro 7 are wrong because v7 was a small focused major. Instead they should mention v8

In this PR, deprecation warnings and inline comments from Astro 7.0 to 8.0.

withastro/astro

Changes

  • Adds FetchState response finalizers and original-route detection for composable fetch handlers.
  • Restores cookies, sessions, CDN cache defaults, asset fallback, and prerendering for Cloudflare custom entrypoints. Fixes #17600.

Testing

  • Expands custom-entrypoint coverage for cookies, sessions, cache headers, assets, Hono, and prerendering.
  • Adds FetchState and mutable/immutable response finalization tests.

Docs

withastro/astro

Changes

  • CSS modules in the prerender build have empty code — Vite extracts their content into separate assets, leaving the module's code as "". Because hashModules() was skipping modules with no code, CSS edits never changed the dependency hash and canSkip() incorrectly returned true, restoring cached HTML that referenced the old, now-missing _astro/*.css filename.
  • When a module's code is empty and its ID matches CSS_LANGS_RE, hashModules() now reads the source file from disk and includes its contents in the hash. CSS edits now produce a different dependency hash, causing affected pages to re-render with the correct stylesheet reference.

Closes #17704

Testing

  • Added two unit tests in plugin-incremental.test.ts under CSS modules (#17704): one that asserts the hash changes when the CSS file is modified on disk, and one that asserts the hash is stable when the file is unchanged.

Docs

  • No docs update needed — this fixes a bug in experimental.incrementalBuild, which is not yet documented beyond the config reference.
withastro/astro

Closes #17682

Changes

  • Astro.site is now correctly set when rendering components via the Container API. Previously, astroConfig.site passed to AstroContainer.create() was accepted in the type signature but never read — the value was never forwarded to the internal createManifest() call or written onto the SSRManifest, so Astro.site was always undefined.
  • Wires astroConfig.site through AstroContainer.create() → constructor → createManifest(), and adds 'site' to the AstroContainerManifest Pick type so a pre-built manifest can also carry the value.

Testing

  • Added 'Astro.site reflects astroConfig.site' — verifies that Astro.site matches the URL set in astroConfig.site.
  • Added 'Astro.site is undefined when astroConfig.site is not set' — verifies the default behavior remains unchanged.

Docs

No docs update needed — AstroContainer.create() already documents the astroConfig.site option; this fix makes it work as documented.

withastro/astro

Changes

  • Base stripping now only removes a configured base when the pathname is the base itself or continues at a path-segment boundary. With base: '/docs', a request like /docs-archive/page is treated as outside the base instead of being rewritten to /page. This keeps route matching and context.url.pathname in agreement.
  • Consolidates the three duplicated base-stripping implementations (BaseApp.removeBase, FetchState.#computePathname, and the i18n domain helper) into a single shared stripRequestBase helper in @astrojs/internal-helpers, matching the boundary logic the router already uses in stripBase.

Testing

  • Adds base-prefix-boundary.test.ts covering single-character extensions of the base prefix (/docsX/..., /docs2/..., /docs-/...), asserting they do not resolve to a route under the base.

Docs

  • No docs update needed; this corrects internal pathname handling with no public API change.
withastro/astro

Changes

  • computePreferredLocaleList compared object-form locale codes exactly, while every other locale comparison in i18n/utils.ts normalizes both sides first. That one raw comparison is now normalized like the rest.
  • The result is a self-contradiction on a single request: sortAndFilterLocales filters on normalized codes, so a locale configured as { path: 'english', codes: ['en-us'] } passes the filter when a browser sends Accept-Language: en-US, and is then silently dropped by the exact comparison. Astro.preferredLocale returns 'en-us' while Astro.preferredLocaleList returns [].
  • The two branches of the same loop disagreed: the string-locale branch already normalized (so locales: ['en-us'] works today), the object-form branch did not. Underscore codes such as en_US were affected the same way, since normalizeTheLocale maps _ to -.
  • The configured casing is still what gets returned — the comparison is normalized, but the original code is what's pushed, matching how getLocaleByPath compares normalized and returns the configured value.

Production change is one line:

-  if (code === browserLocale.locale) {
+  if (normalizeTheLocale(code) === normalizeTheLocale(browserLocale.locale)) {

One thing I deliberately left out: computePreferredLocale breaks out of its codes loop on first match (#16600), and this list function doesn't. That's a visible behaviour difference between the pair, but it's a separate change with its own semantics, so I'd rather ask than bundle it — happy to follow up if you want them aligned.

Testing

Added to the existing packages/astro/test/units/i18n/i18n-utils.test.ts, in the style of the surrounding cases:

  • object-form codes matched case-insensitively (codes: ['en-us'] vs en-US) — failed before this change, returning []
  • object-form codes with an underscore separator (codes: ['en_US']) — failed before, returning []
  • object-form matches sorted by quality value — failed before
  • the configured casing is returned for an exact-case object-form code
  • string locales still match case-insensitively
  • a code is returned rather than the path for a multi-code entry

The last three pass both before and after, so they guard against a regression rather than describing the fix.

Locally: 32/32 in that file, and the full i18n unit suite (396 tests), tsc -b, format:ci, biome and eslint all pass. One caveat — astro-scripts test fails on my machine with ERR_UNKNOWN_FILE_EXTENSION for .ts on Node 22.17.1 (the repo's .nvmrc is 24.14.0); it fails identically on files I didn't touch, so I ran the units via the equivalent node --experimental-strip-types --test. CI on Node 24 will run them through the wrapper.

Docs

No docs change needed. Astro.preferredLocaleList is already documented as returning the list of matching locales; this makes the object-form config shape behave as documented, rather than changing any documented behaviour.

withastro/astro

Changes

  • Shallow-clones langAlias before passing it to Shiki's createHighlighter() in packages/internal-helpers/src/shiki.ts. Shiki's Registry.loadLanguage() writes built-in language aliases (e.g. js, cjs, mjs for JavaScript) directly into the langAlias object it receives. Because Astro passed the same object reference from the resolved config, those aliases leaked back into config.markdown.shikiConfig.langAlias. Since computeConfigHash() runs after the Vite build, the hash then reflected which languages appeared in code blocks rather than the user's actual config, causing the incremental build cache to be invalidated on every content change.

Closes #17693

Testing

  • Adds packages/internal-helpers/test/shiki.test.ts with a test that highlights a JavaScript code block and asserts the original langAlias object passed to createShikiHighlighter is not mutated.

Docs

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

Changes

  • Require a directory boundary when deciding whether an MDX file is under src/pages.
  • Prevent sibling directories such as src/pages-old and src/pages2 from receiving page-only automatic charset injection in both the unified and Sätteri processors.

Testing

  • Added focused coverage for real pages and similarly prefixed sibling directories across both processor paths.
  • Ran: pnpm -C packages/integrations/mdx test
  • Ran: pnpm -C packages/integrations/mdx build
  • Ran: pnpm lint:ai

Docs

No docs changes. This corrects internal page classification without changing the public API.

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@7.2.3

Patch Changes

  • #17724 97140b2 Thanks @ematipico! - Fixes an issue where Astro could run out of memory when experimental.collectionStorage is set to chunked and there are multiple concurrent updates to the same collection.

  • #17636 51723b1 Thanks @matthewp! - Fixes the dev server sometimes matching against stale routes after pages were added, removed, or renamed, requiring a dev server restart to pick up the change

  • #17636 51723b1 Thanks @matthewp! - Fixes the composable request helpers (astro/fetch) throwing an error when used on a request that had been rewritten with Astro.rewrite() or next()

  • #17636 51723b1 Thanks @matthewp! - Refactors Astro's internal server-side request handling. This is an internal change: all documented public APIs, including App and NodeApp, keep their existing signatures and behavior.

    The undocumented internal app.pipeline property and the AppPipeline export from astro/app have been removed. Adapters that used app.pipeline.getLogger() to wait for the configured log destination can call the new app.getLogger() instead.

    As a result of this refactor, new FetchState(request) from astro/fetch now works anywhere inside a built Astro server — including custom src/fetch.ts entrypoints — without the request needing to first pass through app.render(). Previously this threw an error, breaking patterns like the Cloudflare adapter's advanced custom-worker setup.

  • #17723 c3b9aed Thanks @florian-lefebvre! - Fixes a link in font providers JSDoc annotations

  • #17699 e28d227 Thanks @ArmandPhilippot! - Fixes several documentation issues related to the JSDoc for configuration options.

    • When hovering over the server and fonts options, the JSDoc for the nested options was displayed instead of the JSDoc for the top-level property.
    • Two i18n configuration options were being used incorrectly in the examples.
    • The indentation of some code blocks was broken on hover.
  • #17572 2066f39 Thanks @matthewp! - Fixes a crash when a request arrives with a malformed port in the Host header (for example example.com:65536 or example.com:8080:8080). Such a host made the constructed request URL invalid, and the fallback that was meant to recover reused the same invalid host and threw again. The request URL now degrades to a host the server controls when the incoming host cannot be parsed, so the request is handled instead of erroring.

  • #17685 9f15609 Thanks @astrobot-houston! - Fixes a dev server error where an SSR full reload triggered by a third-party Vite plugin (such as @tailwindcss/vite) could fail with Failed to load url astro:server-app.js

  • #17636 51723b1 Thanks @matthewp! - Improves error handling for custom log destinations. When the configured logger fails to load, Astro now reports the error and continues with the default console logger instead of failing the first request.

  • #17631 cf29bec Thanks @matthewp! - Fixes getCollection() and getEntry() throwing DataCloneError when a collection schema transform returns a Temporal.PlainDate or other class instance.

  • Updated dependencies [8c193f6]:

    • @astrojs/internal-helpers@0.10.3
    • @astrojs/markdown-remark@7.2.3
    • @astrojs/markdown-satteri@0.3.6

@astrojs/cloudflare@14.2.2

Patch Changes

  • Updated dependencies [8c193f6]:
    • @astrojs/internal-helpers@0.10.3
    • @astrojs/underscore-redirects@1.0.4

@astrojs/markdoc@2.0.7

Patch Changes

  • Updated dependencies [8c193f6]:
    • @astrojs/internal-helpers@0.10.3

@astrojs/mdx@7.0.6

Patch Changes

  • Updated dependencies [8c193f6]:
    • @astrojs/internal-helpers@0.10.3
    • @astrojs/markdown-remark@7.2.3

@astrojs/netlify@8.2.2

Patch Changes

  • Updated dependencies [8c193f6]:
    • @astrojs/internal-helpers@0.10.3
    • @astrojs/underscore-redirects@1.0.4

@astrojs/node@11.1.3

Patch Changes

  • #17636 51723b1 Thanks @matthewp! - Updates the adapter to wait for the configured log destination through Astro's new app.getLogger() API. This release requires Astro 7.2.1 or later.

  • Updated dependencies [8c193f6]:

    • @astrojs/internal-helpers@0.10.3

@astrojs/preact@6.0.3

Patch Changes

  • Updated dependencies [8c193f6]:
    • @astrojs/internal-helpers@0.10.3

@astrojs/react@6.0.3

Patch Changes

  • Updated dependencies [8c193f6]:
    • @astrojs/internal-helpers@0.10.3

@astrojs/vercel@11.0.6

Patch Changes

  • #17680 ce9f1da Thanks @astrobot-houston! - Fixes server islands returning 404 responses in Vercel deployments using output: "static"

  • Updated dependencies [8c193f6]:

    • @astrojs/internal-helpers@0.10.3

@astrojs/internal-helpers@0.10.3

Patch Changes

  • #17696 8c193f6 Thanks @astrobot-houston! - Fixes incremental build cache invalidation caused by Shiki mutating the langAlias config object when loading languages

@astrojs/ts-plugin@1.10.11

Patch Changes

  • #17668 bef9db5 Thanks @lazerg! - Fixes Astro's ambient types leaking into unrelated TypeScript projects. In a monorepo with hoisted node_modules, the plugin found the shared astro install from any project and injected env.d.ts and astro-jsx.d.ts into it, which pulled @types/node into projects that never asked for it. The plugin now only injects those types when the project actually depends on astro or has an astro.config.* file.

@astrojs/markdown-remark@7.2.3

Patch Changes

  • Updated dependencies [8c193f6]:
    • @astrojs/internal-helpers@0.10.3

@astrojs/markdown-satteri@0.3.6

Patch Changes

  • Updated dependencies [8c193f6]:
    • @astrojs/internal-helpers@0.10.3
withastro/astro

Changes

  • Require a directory boundary when checking whether a file is inside src/pages.
  • Prevent sibling directories such as src/pages-old and src/pages2 from receiving page-only handling.
  • Add regression coverage for pages, nested pages, endpoints, and sibling-directory false positives.

Testing

  • pnpm --filter astro exec astro-scripts test "test/units/util/*.test.ts" --strip-types (41 passed)
  • pnpm --filter astro build
  • pnpm lint:ai

Docs

No docs changes. This fixes internal path classification without changing the public API.

withastro/starlight

Description

We noticed while working on #4121 that our current size limit checks won’t reflect changes to the page sidebars because we test against the start template’s landing page.

This PR adds one of the example guide pages in the starter template to our size limit checks so we also track changes in size to the more standard documentation page layouts as suggested by @trueberryless.

While there I’ve also slightly reduced the size limit for the HTML pages to be a bit closer to the current output sizes and trigger a failure earlier if those increase.

withastro/astro

Changes

  • Updates the dependency diffing action to 1.7.1. Primarily to fix a bug for PRs from branches that were behind main where they would report changes that were inaccurate as you can see in #17688 (comment) for example. The issue should be fixed by e18e/action-dependency-diff#177 which is included in the 1.7.1 release.
  • Versions 1.6 and 1.7 updated internal dependencies, improved trusted publishing checks, and fixed duplicate scanning (a feature we don’t use) so otherwise should be a safe update.

Testing

Tested upstream, 🤞

Docs

n/a

withastro/starlight

Description

This PR refactors Starlight’s mobile menu toggle to use the Popover API instead of the current JS-powered <button> with aria-expanded pattern.

  • A small amount of JS remains but it’s now only a progressive enhancement for focus trapping. The core functionality of opening/closing the mobile menu and locking body scroll works even if JS breaks for whatever reason.

  • The JS is now in the PageFrame component as a custom element that attaches to the popover body instead of the menu button. It reacts to global events (matchMedia()) and the popover’s "toggle" event so it makes more sense to live alongside the element it attaches to. This also means the menu button component is now easier to override as any button with the correct popovertarget attribute will work.

  • CSS switches from hooking into [aria-expanded] to using the :popover-open pseudo class.

  • We no longer add a data-mobile-menu-expanded attribute to <body> when the menu is open and use body:has(#starlight__sidebar:popover-open) in CSS instead, which works without the JS-managed attribute.

  • While I was updating the button, I switched from aria-label to a visually hidden span of text, which is generally the recommended pattern for labels where possible.

Browser compatibility

Use of the Popover API requires slightly bumping our minimum supported browsers:

  • Firefox 121 (December 2023) => 125 (April 2024)
  • Chromium 111 (March 2023) => 116 (August 2023)
  • Safari 16.4 (March 2023) => 17.0 (September 2023) (for both macOS and iOS)

According to browsersl.ist, comparing before and after shows a drop in global coverage of 1 percentage point. The newest minimum supported browser will be Firefox 125, released 29 months ago.

N.B. that umbrella compatibility measures such as wf-popover show support only arriving later in some browsers. However, IIUC this is due to subfeatures that we are not relying on not being ready yet and the features we require are safe even in these older browser versions:

Safari on iOS had a long-standing bug in versions 17.0–18.2 which prevented tap-away clicks closing popovers as is expected. However, we do not require that behaviour in Starlight mobile menus as there is nowhere a user expects to click away to and the main control is the button.

Accessibility

The button with popovertarget and popover combo has built-in accessible roles equivalent to our previous aria-expanded pattern. I tested with VoiceOver in Firefox, Chrome, and Safari on macOS 26.5.1 and found the behaviour to be a very slight improvement in my opinion compared to the current announcements although both are basically equivalent. Would be great to test in more scenarios!

Demo

Here’s a small screen capture of the live Starlight docs and compared to this branch, showing the menu working without JavaScript after these changes:

popover.mp4
withastro/astro

Changes

  • No code changes, just tests

Testing

  • Uses a local mock rather than going to GitHub, to prevent flakiness caused by GitHub not responding in time.

Docs

N/A, test fix

withastro/astro

Changes

With isr enabled, middlewareMode: 'edge' is silently inert.

The adapter builds and deploys _middleware.func, but every on-demand route's
dest is set to the ISR function, so nothing ever routes to it. Middleware
still runs — but only inside the ISR function, which Vercel skips entirely on a
cache hit. The observable result is middleware that works on a cold entry and
then stops running once the entry is warm, with no error and no log.

This is the ordering problem: middleware has to run before the cache is
consulted, not behind it.

  • Route on-demand pages at _middleware rather than _isr when a middleware
    entry point exists, so the edge function is actually reached.
  • Collect those route patterns and inline them into the generated middleware,
    so next() forwards to /_isr?x_astro_path=… for a route the ISR function
    backs, and /_render for one it doesn't. Cached responses are still served
    from cache; only the entry point moves.
  • _image and _server-islands keep going straight to _render, unchanged.
  • Routes matched by isr.exclude still resolve to _render through next().
  • Prerendered pages are untouched: no route entry, served as static files.

x_astro_path carries the original pathname, so the ISR cache key stays the
request path rather than collapsing to /_isr; x_astro_path_token is the
build token added in #17370. Without isr, or without a middleware file,
nothing about the output changes.

Testing

New: packages/integrations/vercel/test/isr-edge-middleware.test.ts — 16 tests
over two fixtures.

isr-with-edge-middleware asserts against the real build output, since the bug
is entirely a property of the emitted config.json:

  • pages, dynamic routes, endpoints and the 404 resolve to _middleware
  • _image and _server-islands still resolve to _render
  • prerendered pages get no route entry and ship as static HTML
  • configured redirects still resolve ahead of the middleware
  • the ISR prerender config and its expiration survive

and then imports the generated middleware.mjs with fetch stubbed, to check
where next() actually forwards:

  • a cached route → /_isr, with x_astro_path and a token
  • a dynamic route → /_isr?x_astro_path=/cached/42, the real path, because that
    path is the cache key
  • an isr.exclude route → /_render
  • a query string does not leak into x_astro_path
  • the response still reaches the middleware, headers intact

isr-edge-no-middleware covers middlewareMode: 'edge' with no middleware file
present: routes go straight to _isr as before and no middleware function is
built.

Verified as a regression guard by reverting src/ and re-running: 4 of the 16
fail, all of them on dest.

Also ran the full suite — core unit (3307), core integration (1240), all 18
integration packages including @astrojs/vercel (58), language-tools (98), and
e2e in chrome and firefox. No new failures; the pre-existing ones
(test/fonts.test.ts cancellations, a handful of e2e) don't touch the adapter.

Reproduction

Repo with reproduction (2 branches) https://github.com/asmyshlyaev177/astro-isr-middleware-repro
And deployed versions:
https://astro-isr-middleware-repro.vercel.app/
https://astro-isr-mw-patched.vercel.app/

withastro/astro

Changes

  • Removed the .flue folder from the repository. We don't use it anymore.
  • Adds evals.json files and an harness that we can test when want. The harness isn't wired to our testing infra because it spends tokens.

Testing

Tested locally and all assertions pass

Docs

withastro/astro

Closes #17684

Changes

  • Prefixes ASTRO_DEV_SERVER_APP_ID with virtual: (changing it from astro:server-app to virtual:astro:server-app), matching the convention already used by the sibling virtual:astro:app module in the same file. Vite's ModuleGraph._resolveUrl() skips URL normalization for IDs that start with virtual: — without this prefix, Vite appended .js to the stored URL, so full-reload attempts via runner.import("astro:server-app.js") failed to match Astro's resolveId filter.
  • Fixes the error Failed to load url astro:server-app.js that appeared when a third-party Vite plugin (e.g. @tailwindcss/vite) triggered an SSR full reload on a non-page file.

Testing

  • No automated test added — reproducing this requires a live dev server with @tailwindcss/vite triggering an SSR full reload, which is outside the current unit/integration test infrastructure.
  • Fix was manually verified against the minimal reproduction from the issue; editing src/content/test.md now produces [vite] program reload without the astro:server-app.js error, and the server continues serving successfully. Confirmed by the issue reporter (@mavam).

Docs

No docs update needed — this is an internal virtual module ID fix with no user-facing API change.

withastro/astro

Closes #17679

Changes

  • The glob() and file() content loaders now respect prerenderConflictBehavior when a duplicate entry ID is detected. Previously, both loaders always emitted a hardcoded logger.warn() regardless of the config setting.
  • "error" throws DuplicateContentEntrySlugError during content sync; "ignore" suppresses the warning entirely; "warn" (the default) preserves the existing behavior.

Testing

  • Added tests to file-loader.test.ts covering "error" (throws), "warn" (logs), and "ignore" (silent) modes for duplicate IDs in the file() loader.
  • Added tests to glob-loader.test.ts covering the same three modes for duplicate IDs in the glob() loader.

Docs

No docs update needed — prerenderConflictBehavior is already documented; this extends its existing behavior to a new context without changing its API or semantics.

withastro/astro

Changes

  • Fixes server:defer components returning 404 responses on Vercel when using output: "static".
  • Preserves a dedicated server build directory and packages it through the existing Vercel serverless and middleware path only when Astro runs the SSR build for discovered server islands. Fully static sites continue to emit no serverless function, and server build files are not published as static assets.

Closes #17678

Testing

  • Adds a static server-islands fixture that verifies _render.func, its route configuration, and rendering through the packaged function.
  • Verifies the server entry is excluded from static assets and a fully static fixture does not create a serverless function.

Docs

  • No docs update needed because this restores the documented server:defer behavior for static output.
withastro/starlight

Description

  • Replace "Markdown plugins" links

We have recently updated the Markdown guide in Astro Docs (withastro/docs#14297) and the section was renamed "Markdown processor plugins". There was two occurrences in Starlight docs.

  • Replace an example using Astro DB

Astro DB has been removed in Astro 7 (withastro/docs#13985) and the Astro DB guide now redirects to the integration page with an aside saying "Removed". I think it is better to use an example that is still relevant.

withastro/astro

Changes

Remote images whose URL has no file extension fail with 400 Unsupported format: null under the cloudflare-binding image service (the adapter default).

Astro's baseService.validateOptions only sets options.format when it can infer a source format from the URL, and since #16665 deliberately leaves it undefined otherwise so the image service resolves the format from the source bytes instead — which is what the Sharp service does at sharp.ts#L155-L156. With format undefined, no f parameter is emitted onto the /_image URL, and transformStream treated a missing f as a client error.

Extensionless remote images are the common case here — GitHub avatars like https://avatars.githubusercontent.com/u/192622539?s=200&v=4 have no extension to infer from, which is why every theme author avatar on astro.build is currently broken:

$ curl -sD - -o /dev/null 'https://astro.build/_image?href=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F192622539%3Fs%3D200%26v%3D4&w=300&h=300'
HTTP/1.1 400 Bad Request
Unsupported format: null

# ...the same URL with an explicit format works
$ curl -so /dev/null -w '%{http_code} %{content_type}\n' '...&w=300&h=300&f=webp'
200 image/webp
  • transformStream now takes the source's media type and uses it when f is absent: SVG sources pass through unchanged, everything else is encoded as WebP. This mirrors core's resolveDefaultOutputFormat, which webp-encodes every non-SVG source.
  • Requests that explicitly ask for a format the IMAGES binding cannot produce (e.g. f=tiff) still return 400.
  • This also fixes SVG images, which core requests as f=svg and which previously failed the same way — the IMAGES binding cannot emit SVG, so those bytes are served as-is.

Fixes withastro/astro.build#2610

Testing

Added four cases to test/binding-image-service.test.ts (build + preview, exercising the IMAGES binding for real) covering remote/local sources with no f, and SVG passthrough. A local HTTP server serves images from extensionless paths to reproduce the GitHub avatar shape. Also added the no-f case to test/dev-image-endpoint.test.ts.

All four new binding tests fail on main with 400 and pass with this change; the seven pre-existing tests in that file are unaffected.

Note

Two things worth flagging for maintainers, both pre-existing and left untouched here:

  • caches.default is persisted under test/fixtures/binding-image-service/.wrangler/state/v3/cache, so a previously-cached 200 can mask a genuine failure for any stable /_image URL. I had to clear that directory to see the new tests fail on main.
  • createPreviewServer returns the requested port rather than the bound one (preview.ts#L97), so the whole suite 404s if port 4321 is already taken.

Docs

No docs changes needed. This restores the documented behavior of image.remotePatterns/image.domains for remote images; there's no API or configuration surface change.

withastro/astro

Changes

  • A deploy that changes rendered output without changing content leaves a cached page's validator untouched. Revalidation answers 304, so clients keep HTML that points at /_astro/<hash>.css from the previous build. Every validator the Cloudflare provider can send today comes from the caller and describes the content, never the build.
  • With the CF_VERSION_METADATA binding configured, the provider reads the Worker version id, adds an astro-version:<id> cache tag for version-specific purging, and folds the id into a weak ETag (W/"<id>:<lastModified-ms>") on responses that already send Last-Modified and no etag of their own. Without the binding, every header is exactly what it was before.
  • Picks up #17038, which targeted feat/cdn-cache-providers and was closed when that branch was deleted. The version tag it built on never reached main, so this adds it.

Testing

  • test/cache-provider.test.ts gains four cases against the preview server: the version tag on a cacheable response, the weak ETag carrying the same id and the lastModified timestamp, an explicit etag surviving untouched, and a cacheable response without a validator still getting none. Two fixture pages (/lastmod, /explicit-etag) and the version_metadata binding support them.
  • No automated case for the prerenderEnvironment: 'node' build path, since it would need a second fixture build per run. Checked by hand against a fixture build with a prerendered route and the provider enabled.

Docs

  • The adapter README does not cover route caching, so there is nothing to update there. The behavior is worth a paragraph in the Cloudflare adapter guide on docs.astro.build, and I will open that PR once this lands.
withastro/astro

Changes

  • Moves satteri from devDependencies to dependencies in @astrojs/mdx. The package has unconditional static from 'satteri' imports across four files under src/satteri/, making it a runtime requirement. Listing it only as a devDependency meant pnpm never linked it into @astrojs/mdx's isolated node_modules, so astro build failed with ERR_MODULE_NOT_FOUND in strict pnpm setups (e.g. hoist: false, Vercel monorepo deploys). The import resolved accidentally in non-strict layouts only because pnpm hoisted satteri as a transitive dep of astro → @astrojs/markdown-satteri.

Testing

  • No new tests added. The bug is a packaging/manifest issue that cannot be covered by unit tests run inside the monorepo (which hoists all deps). The fix was confirmed in an isolated hoist: false pnpm project by @danielmlr, and by the packageExtensions counter-check in their report.

Docs

  • No docs update needed; this is an internal dependency declaration fix with no user-visible API change.

Closes #17371

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@7.2.2

Patch Changes

  • #17611 9bc3207 Thanks @thelazylamaGit! - Fixes component styles rendered from content entries remaining stale until a second save when an adapter uses Astro's fallback development environment

  • #17634 2267eee Thanks @astrobot-houston! - Fixes incremental builds dropping optimized images for cached pages when using a collectStaticImages prerenderer (e.g. @astrojs/cloudflare with compile-time image optimization)

  • #17650 4cdf128 Thanks @astrobot-houston! - Fixes intermittent ImageNotFound errors during build on projects with many images. The build now limits concurrent image file reads to avoid exhausting OS file descriptors (EMFILE) and retries transient I/O errors with backoff. Non-transient errors are no longer silently swallowed.

  • #17683 2378221 Thanks @astrobot-houston! - Fixes prerenderConflictBehavior not applying to content collection duplicate ID warnings in the glob() and file() loaders. Setting it to 'error' now throws during content sync, and 'ignore' suppresses the warning.

  • #17659 90c6ea4 Thanks @astrobot-houston! - Fixes the Fonts API breaking experimental.incrementalBuild caching by embedding a build-local, randomly-assigned server port in generated code used for the dependency hash

  • #17630 fd1d9ee Thanks @ericclemmons! - Fixes incremental builds becoming prohibitively slow for sites with many pages or content entries that share a large dependency graph.

  • #17690 93beecc Thanks @NgoQuocViet2001! - Prevents files in directories whose names start with pages from being treated as page routes

  • #17671 09f0dc7 Thanks @tarikermis! - Fixes astro dev refusing to start after a Docker container restart when an unrelated process reuses the PID from a persisted lock file. Astro now checks the process command across platforms, so stale lock files are cleaned up and --force does not signal the unrelated process.

@astrojs/node@11.1.2

Patch Changes

  • #17400 c1cf110 Thanks @tianrking! - Return a 404 instead of a 500 for unknown parameters that match a prerendered dynamic endpoint.
withastro/astro

Closes #17656

Changes

  • Checks the command for the PID stored in the dev or preview lock file instead of assuming that any live process with the same PID is Astro.
  • Uses an exact PID lookup on Linux, macOS, and Windows. This cleans up stale locks after container restarts and prevents --force from signalling an unrelated process when the command can be verified.

Testing

  • Added Unix and Windows command matching cases, including the Windows .cmd shim and unrelated commands.
  • Added coverage for matching processes, reused PIDs, unavailable process lookups, and stale lock cleanup through the real process lookup.

Docs

No docs update needed because the CLI workflow and user-facing messages stay the same.

withastro/astro

Changes

Testing

Docs

withastro/astro

Changes

This PR adds a configuration file that adds some configuration for the upcoming automated reviews.

Testing

Tested in a different repository

Docs

N/A

withastro/astro

Changes

  • The TS plugin is registered globally, so it runs for every project in a workspace. Since #17269 it calls addAstroTypes() unconditionally, and findAstroPackageDirectory() just walks up the tree looking for node_modules/astro/. With a hoisted node_modules (pnpm nodeLinker: hoisted, npm, classic Yarn) that lookup succeeds from any sibling project, so env.d.ts and astro-jsx.d.ts were injected into projects that have nothing to do with Astro. Those files transitively pull in @types/node, and its global shims then win over lib.dom.d.ts, so "Go to Definition" on Blob, fetch or URL in a browser-only app lands in @types/node.
  • Adds an isAstroProject() guard in front of the injection: the nearest package.json has to list astro, or there has to be an astro.config.* next to it. The language server already does this through getAstroInstall(), the plugin was the one place missing it.

Closes #17667

Testing

  • Three cases in packages/language-tools/ts-plugin/test/units/astro-types.test.mts over a fixture monorepo with a hoisted node_modules: a React project that only reaches astro through the shared root is skipped, a project that depends on astro is detected, and so is one with an astro.config.mjs but no dependency.

Docs

  • No docs change, this only narrows when the plugin injects its own ambient types.
withastro/astro

Changes

Error stack traces printed to the terminal lose every other frame.

formatErrorStackTrace filters the stack with a module-level global regex:

const STACK_LINE_REGEXP = /^\s+at /g;
...
const stackLines = (err.stack || '').split('\n').filter((line) => STACK_LINE_REGEXP.test(line));

RegExp.prototype.test on a /g regex advances lastIndex on every match. The next call starts searching mid-string, where ^ cannot match, so it returns false — and then resets lastIndex to 0, which lets the frame after that match again. The result is that exactly half the frames are dropped:

const STACK_LINE_REGEXP = /^\s+at /g;
const stack = [
  'Error: boom',
  '    at first (/app/src/pages/index.astro:3:1)',
  '    at second (/app/src/lib/a.ts:10:5)',
  '    at third (/app/src/lib/b.ts:2:2)',
  '    at fourth (/app/src/lib/c.ts:4:4)',
];
stack.filter((l) => STACK_LINE_REGEXP.test(l));
// → [ 'at first …', 'at third …' ]     // second and fourth are gone
stack.filter((l) => /^\s+at /.test(l));
// → [ 'at first …', 'at second …', 'at third …', 'at fourth …' ]

IRRELEVANT_STACK_REGEXP on the next line has the same shape — it is also only ever asked whether one line matches, and it feeds findIndex, which decides where the stack gets truncated.

Neither regex needs the g flag, so this drops it from both. Nothing else changes: both are still single-line predicates.

Testing

Added packages/astro/test/units/errors/format-error-message.test.js:

  • every frame of a four-frame stack survives formatErrorMessage()
  • formatting the same error twice produces the same string (the leaked lastIndex is per-regex module state, so repeated calls were order-dependent)

The first test fails on main with missing stack frame: at second (/app/src/lib/a.ts:10:5) and passes with this change.

Docs

Not applicable — no API or behaviour that is documented changes; printed stacks just stop losing lines.

withastro/astro

Changes

  • When 'unsafe-inline' is present in script-src, style-src, script-src-elem, or style-src-elem, Astro no longer emits auto-generated hashes on that directive. Per the CSP spec, browsers silently ignore 'unsafe-inline' when a hash is present in the same directive — so users who need 'unsafe-inline' (e.g. to allow third-party scripts that inject dynamic inline styles) were getting a broken policy with no workaround.
  • Adds a hasUnsafeInline() helper in csp.ts checked at three points: the script-src baseline, the style-src baseline, and inside renderSpecificDirective() for -elem variants. The previous fix (#14798) had only addressed style-src-attr, which happened to never emit hashes anyway.
  • Updates the security.csp config docs to describe this suppression behavior.

Testing

  • 7 new unit tests in packages/astro/test/units/csp/render-csp.test.ts covering: hash suppression on style-src, script-src, style-src-elem, script-src-elem, render-time extra hashes with unsafe-inline, and a guard confirming hashes are not suppressed when 'unsafe-inline' is scoped only to -attr (which doesn't affect the baseline directive).

Docs

  • Inline JSDoc in packages/astro/src/types/public/config.ts updated to document the hash-suppression behavior when 'unsafe-inline' is used.

Closes #17663

withastro/astro

Changes

  • The virtual:astro:assets/fonts/runtime/font-file-url-resolver virtual module was embedding the font HTTP server's AddressInfo (including an OS-assigned ephemeral port) as a JSON literal directly in its compiled source text. Because the port changes on every build, any route that transitively imports <Font /> got a different dependencyHash on every run, silently defeating experimental.incrementalBuild for any project using the Fonts API from a shared layout.
  • Fixes this by assigning the server address to a named variable (__ASTRO_FONTS_SERVER_ADDRESS__) in the generated module, then stripping that variable declaration in resolveAssetPlaceholders() (in plugin-incremental.ts) before the module code is hashed. The stable variable reference remains in the hashed code; only the volatile declaration (with the changing port) is removed. This follows the same pattern already used to normalize asset emit handles before hashing.

Closes #17626

Testing

  • Added packages/astro/test/incremental-build-fonts.test.ts: runs two consecutive builds of a fixture that uses the Fonts API with experimental.incrementalBuild: true and asserts the route's dependencyHash is identical across both builds.
  • Added the corresponding fixture (packages/astro/test/fixtures/incremental-build-fonts/) with a dynamic route using <Font /> and a stable cacheKey from getStaticPaths().

Docs

No docs update needed — this is a bug fix for two experimental features; no user-facing API or behavior contract changed.

withastro/astro

Changes

  • Fixes a MaxListenersExceededWarning that fires after ~11 keep-alive requests when staticHeaders: true and security.csp are both active on the Node adapter. serve-static.ts calls createRequestFromNodeRequest() solely for route matching via app.match(), but that function wires an AbortController close listener on the socket that was never cleaned up. On keep-alive connections the listener count grows by one per request. The fix adds getAbortControllerCleanup(req)?.() immediately after app.match(), using the same cleanup pattern already applied to serve-app.ts in #15735.

Testing

  • Added a 'Static headers listener cleanup' test suite to packages/integrations/node/test/static-headers.test.ts that sends 30 keep-alive requests and asserts no MaxListenersExceededWarning is emitted.

Docs

  • No docs update needed; this is an internal resource-management fix with no user-facing API change.

Closes #17657

withastro/astro

Overview

Adds graceful shutdown support to the Node.js standalone adapter. When the process receives SIGTERM or SIGINT, the server stops accepting new connections and waits for all in-flight requests to complete before exiting.

What's new

  • SIGTERM / SIGINT handling — the server closes gracefully on either signal
  • Force-destroy timeout — if connections don't drain within the timeout, remaining connections are force-destroyed. Default is 10s, configurable via ASTRO_NODE_GRACEFUL_SHUTDOWN_TIMEOUT (milliseconds)
  • Opt-out — set ASTRO_NODE_GRACEFUL_SHUTDOWN=disabled to skip signal handler registration entirely

Testing

Adds an integration test suite (graceful-shutdown.test.ts) covering:

  • No new connections accepted after server.close()
  • SIGTERM and SIGINT each independently stop the server (SIGINT tested on a fresh server)
  • Multiple concurrent in-flight requests all complete before closed() resolves
  • Force-destroy fires after timeout when a connection is permanently stalled

Docs

Docs have not been updated yet.

withastro/astro

Changes

Context #17521

  • Replaces semver with the smaller ESM-native verkit package for Astro's Node.js version gate, update checks, integration resolution, and the upgrade CLI.
  • Removes unused semver dependencies from @astrojs/ts-plugin while preserving existing version-handling behavior.

Testing

  • No test changes; the migration preserves the behavior covered by the existing Astro CLI and upgrade tests.

Docs

  • No docs update needed because this refactor does not change public APIs or user-facing behavior.
withastro/astro

Changes

  • emitImageMetadata now uses a concurrency-limited file reader (max 200 simultaneous fs.readFile calls) to prevent exhausting OS file descriptors on projects with tens of thousands of images. Previously, all image imports were read concurrently with no limit, causing EMFILE: too many open files errors — especially after astro check or astro dev already consumed file descriptors.
  • Transient I/O errors (EMFILE, ENFILE, EAGAIN, EBUSY) are retried with exponential backoff instead of failing immediately.
  • The bare catch that silently swallowed all errors (including EMFILE) is replaced: only ENOENT returns undefined; other errors are re-thrown with the real OS error message. This makes ImageNotFound accurate — it now only fires when the file genuinely doesn't exist.

Closes #17649

Testing

  • Added packages/astro/test/units/assets/emit-image-metadata.test.ts covering: undefined id returns undefined, a missing file (ENOENT) returns undefined, and a real JPEG file returns correct width/height/format metadata.

Docs

No docs update needed — this is a build reliability fix with no user-facing API change.

withastro/astro

Changes

  • The adapter injects a SESSION KV binding with no id, which Wrangler treats as a
    request to auto-provision a namespace on deploy. That needs an API token with
    Workers KV Storage: Edit, so deploys without it fail with a generic
    Authentication error [code: 10000] against /storage/kv/namespacesafter the
    build already succeeded
    , and with nothing in the message pointing back at sessions.

  • astro build now warns when that binding is about to be provisioned, naming the
    permission and both escape hatches:

    [@astrojs/cloudflare] The "SESSION" KV binding has no `id`, so `wrangler deploy` will
    provision a new KV namespace. This requires an API token with the "Workers KV Storage:
    Edit" permission.
      To use an existing namespace, add `kv_namespaces: [{ binding: "SESSION", id: "<id>" }]`
      to your Wrangler config.
      To skip sessions entirely, set `session: false` in your Astro config.
    
  • Silent when the user already declared the binding, when session: false, and during
    dev (which never provisions anything). Deduplicated to one warning per build, since
    the customizer runs once per worker (entry, prerender, previews).

  • No change to the emitted Wrangler config. The existing
    !needsSessionKVBinding || hasSessionBinding ternary is extracted into a named
    injectsSessionBinding so the warning condition and the emission condition can't
    drift apart, but the output is identical.

  • The warning lives in cloudflareConfigCustomizer rather than the astro:config:setup
    hook because that's the only place that knows whether an id-less binding is actually
    being emitted — warning from index.ts would also fire for users who correctly
    declared SESSION with an id.

Closes #17640

Testing

Five cases added to the existing test/session-false.test.ts, which already covers the
sibling session: false behavior: warns with both key phrases, dedupes across workers,
silent when user-declared, silent when sessions disabled, and doesn't throw without a
logger.

Being upfront about verification: the suite imports from dist/, so it needs a full
monorepo install and build, which I did not run locally. I verified the logic by
compiling wrangler.ts standalone and running the same assertions plus three
regressions asserting binding emission is unchanged (8/8 passing). The committed test
file itself has therefore not been executed, and tsc -b is unconfirmed — I'd
appreciate CI confirming both.

Docs

No docs change needed: this adds no API or config surface, and the new logger option
is internal to the customizer.

That said, the underlying gotcha — that a default-on adapter feature makes deploy
require Workers KV Storage: Edit — isn't currently called out on the Cloudflare
sessions docs page, and arguably should be.

/cc @withastro/maintainers-docs for feedback!

withastro/astro

The remote image fetch in redirectValidation.ts passes no signal or timeout to fetchFn. A slow or unresponsive image origin server will stall the fetch indefinitely - blocking SSR responses in production and the dev server during development. Added AbortSignal.timeout(10_000) to the fetch options so the call aborts after 10 seconds rather than hanging forever.

withastro/astro

Changes

  • What does this change?

  • Add UT restore issue.

  • Improve cache key handling with a hashing function

  • This doc must be updated if you accept my PR.

Testing

Run node test command:

node ./packages/astro/test/get-static-paths-incremental.test.ts 

Closed issue: #17635

withastro/astro

Changes

  • Primary purpose of this pull-request is to refactor internal requests to get rid of the Pipeline and App classes as used internally. These were essentially "god objects" that held state related to the server-side app.
  • The problem with these objects were that there was no way to pass them into FetchState when access from outside of the App class. For example in Cloudflare you can create a custom worker which is the entrypoint to the application.
  • I realized that the manifest is the one true god-object in SSR, and we could simply derive all state from that. So this new architecture is much more functional. Derived state is created as createManifestMemo and createAsyncManifestMemo which are keyed on the manifest. Anything that needs this state can simply import it now.
  • Everything else in this PR is just conforming to the above.
  • App remains as its the external API for adapters, but mostly just defers to the functional approach now.

Fixes #17591

Testing

  • Mostly refactored existing tests which relied in the Pipeline.

Docs

  • N/A, just a refactor
withastro/astro

Changes

  • Fixes experimental.incrementalBuild dropping optimized images for cached pages when an adapter uses collectStaticImages (e.g. @astrojs/cloudflare with compile-time image optimization). When a cached page and a re-rendered page share the same source image with different transforms, the merge loop in generatePages was replacing the entire entry with .set(path, entry), discarding transforms that restoreStaticImages() had already replayed into the global static image list. The fix merges adapter transforms into existing entries instead of overwriting them, matching the deduplication pattern already used by restoreStaticImages(). Closes #17633.

Testing

  • Added packages/astro/test/units/build/incremental-images.test.ts with two unit tests: one verifying that restored transforms are preserved when adapter images share the same source path, and one verifying that new source paths from adapter images are still added when no restored entry exists.

Docs

  • No docs update needed — this is a bug fix for experimental.incrementalBuild, and no user-facing API or behavior contract changed.
withastro/astro

Changes

  • A collection schema transform returning a Temporal.PlainDate or other class instance no longer throws DataCloneError from getCollection()/getEntry().
  • Gets rid of structuredClone usage, so any types supported by devalue() should work.

Testing

  • image-references.test.ts: reworked, removed old tests
  • mutable-data-store.test.ts: asserts image prefixes are stripped to plain srcs and their paths recorded as imageImports, and that entries without images record nothing.

Docs

  • N/A, bug fix

Alternative to #17596.
Closes #17589

withastro/astro

Changes

Optimizes experimental cache from O(R × G) to O(G × R) using a Merkle-style hashing algorithm to content roots that heavily share dependencies.

  • R = # of roots. (e.g. 8,000 content pages)
  • G = graph size.
flowchart LR
    subgraph Before["Before: O(R × G)"]
        P1["Entry 1"] --> G1["Walk graph"]
        P2["Entry 2"] --> G2["Walk graph"]
        P3["Entry 3"] --> G3["Walk graph"]
    end

    subgraph After["After: O(G + R)"]
        G["Analyze graph once"] --> H["Hash cache"]
        H --> R1["Entry 1: O(1) lookup"]
        H --> R2["Entry 2: O(1) lookup"]
        H --> R3["Entry 3: O(1) lookup"]
    end
Loading

Testing

The performance degradation was discovered on my fork of cloudflare-docs where I enabled incrementalBuild. ~10m builds now timed out at 30 minutes.

  • TODO: Can this be published on pkg.pr.new to validate?
13:01:47.975
> astro build
13:01:47.976
13:01:58.504
18:01:58 [astro-skills] Setting up Agent Skills Discovery routes
13:01:58.504
18:01:58 [astro-skills] Agent Skills Discovery routes configured
13:02:01.502
18:02:01 [build] Waiting for integration "@cloudflare/nimbus-docs", hook "astro:config:setup"...
13:02:14.225
18:02:14 [WARN] [@cloudflare/nimbus-docs] [nimbus-docs] (nimbus/duplicate-slug, warning) 3 routes are served by an explicit src/pages file that shadows a content entry at the same URL:
13:02:14.225
  /ai/models  ←  src/content/docs/ai/models/index.mdx, src/pages/ai/models/index.astro
13:02:14.225
  /ruleset-engine/rules-language/fields/reference  ←  src/content/docs/ruleset-engine/rules-language/fields/reference/index.mdx, src/pages/ruleset-engine/rules-language/fields/reference/index.astro
13:02:14.225
  /workers-ai/models  ←  src/content/docs/workers-ai/models/index.mdx, src/pages/workers-ai/models/index.astro
13:02:14.225
13:02:14.226
Astro serves the page and drops the content route (deterministic). Intended when a content page wraps a custom page component; verify each shadow is intentional.
13:02:18.146
18:02:18 [content] Syncing content
13:02:18.149
18:02:18 [content] Astro config changed
13:02:18.150
18:02:18 [content] Clearing content store
13:02:28.869
18:02:28 [skills-loader] Loaded 11 skill(s) from "skills"
13:02:41.475
18:02:41 [content] Synced content
13:02:41.488
18:02:41 [types] Generated 27.00s
13:02:41.489
18:02:41 [build] output: "static"
13:02:41.490
18:02:41 [build] mode: "static"
13:02:41.490
18:02:41 [build] directory: /opt/buildhome/repo/dist/
13:02:41.490
18:02:41 [build] Collecting build info...
13:02:41.495
18:02:41 [build] ✓ Completed in 43.00s.
13:02:41.498
18:02:41 [build] Building static entrypoints...
13:04:25.008
18:04:25 [astro-icon] Loaded icons from src/icons, ph, simple-icons, vscode-icons
13:31:14.749
Build took too long and was timed out

Docs

withastro/astro

Changes

  • When both security.csp and experimental.clientPrerender are enabled, Astro now injects a single static <script type="speculationrules"> at render time using "source": "document" with a CSS selector (a[data-astro-prefetch] or a when prefetchAll is enabled). This produces a deterministic payload whose hash can be computed at build time and added to the CSP script-src directive.
  • The client-side prefetch code detects existing document-source speculation rules in the DOM and skips dynamic per-URL injection, which would generate unwhitelistable hashes.

Closes #17599

Testing

  • New unit test file packages/astro/test/units/csp/speculation-rules.test.ts covering generateSpeculationRulesContent() output shape and hash determinism.

Docs

  • No docs update needed; this fixes a bug in the interaction between two existing features without changing any user-facing API or configuration.
withastro/astro

Changes

  • Bumps the astro peer dependency in @astrojs/cloudflare from ^7.0.0 to ^7.2.0. The adapter imports beginContentEntryCollection, beginImageCollection, endContentEntryCollection, and endImageCollection from astro/app, which were added in 7.2.0. The wider range allowed npm to silently resolve astro@7.1.x, causing a cryptic MISSING_EXPORT build failure with no install-time warning.

Closes #17622

Testing

  • No new tests added — the fix is a manifest correction; existing adapter tests cover the affected code paths.

Docs

  • No docs update needed; this corrects a peer dependency declaration, not a user-facing API.
withastro/astro

Closes #17624

Changes

  • Entries whose frontmatter slug is an unquoted YAML number (e.g. slug: 20260624) now survive repeated syncs. YAML parses an unquoted number as a JS number, but the untouchedEntries Set holds string keys from the store. The Set.delete call used strict equality, so delete(20260624) was a no-op against "20260624", leaving the entry marked "untouched" and deleted in the cleanup pass on every sync after the first.
  • generateIdDefault() now calls String(data.slug) instead of relying on the as string type assertion, which was compile-time-only and did nothing at runtime.
  • The generateId wrapper also coerces the return value with String() so custom generateId callbacks returning non-string values are handled defensively as well.

Testing

  • Added a unit test in packages/astro/test/units/content-layer/glob-loader.test.ts that calls contentLayer.sync() twice and asserts the numeric-slug entry (id === '20260624') is present after both syncs and that the entry count is stable.
  • Added a fixture file src/content/space/numeric-slug.md with slug: 20260624 to back the new test case.

Docs

No docs update needed — this is a bug fix for an internal ID coercion issue with no API surface change.

withastro/astro

Changes

Update example template to refer to Astro 7.0

Testing

No test changed since this is a simple text update in example template.

Docs

No document changed since this is a simple text update in example template.

withastro/astro

Changes

  • Dynamic redirect routes in createRedirectsFromAstroRoutes now honour the user-configured status code. Previously, the dynamic branch hardcoded 301 (route.type === 'redirect' ? 301 : 200), so a redirect configured as { destination: '/new', status: 302 } would be written as 301 in the _redirects file. The static branch already called getRedirectStatus(route) correctly; this applies the same call to the dynamic branch.
  • Since 301 is cached essentially permanently by browsers, an incorrect status is very difficult to reverse in production.

Closes #17619

Testing

  • Two new test cases in packages/underscore-redirects/test/astro.test.ts: one verifies that a dynamic redirect with { destination, status: 302 } emits 302, the other verifies that a string-form redirect still defaults to 301.

Docs

  • No docs update needed — this restores already-documented behavior (configured status is respected).
withastro/astro

Changes

  • Since #15908 the generated TSX exports a component as BlogPostAstroComponent, so TypeScript never matches <BlogPost /> to it and stops offering "Add all missing imports" or "Add import from …". Completions still worked because they strip the suffix afterwards, while code actions need TypeScript to find the export first.
  • patchTSX now also re-exports the component under its clean name, which keeps the suffixed function name that avoids conflicts with same-name imports inside the file.
  • rewriteAstroImportText turns the resulting import { BlogPost } from './BlogPost.astro' back into a default import. Other named imports from .astro files, such as Props, are left alone.
  • Astro components are now offered once in the auto-import completion list instead of twice.

Fixes #17617

Testing

  • New packages/language-tools/language-server/test/typescript/code-actions.test.ts asks the server for quick fixes on an unimported component and checks the import edit. It fails on main.
  • New patchTSX and rewriteAstroImportText unit tests, plus a count assertion on the existing component auto-import completion test.
  • The @astrojs/language-server and @astrojs/check suites pass.

Docs

None, this is a bug fix with no API change.

withastro/astro

Changes

  • closes #17615
  • With experimental.incrementalBuild, a route that imports more than one asset was sometimes re-rendered even though nothing about it changed. An imported image's module code carries an __ASTRO_ASSET_IMAGE__<handle>__ placeholder, other assets carry Vite's __VITE_ASSET__<handle>__, and the handle comes from emitFile in the order the modules finish transforming, so two builds of the same sources can swap the handles around. The route hash then changes while the output stays byte-for-byte identical.
  • Before hashing a module, the placeholders are replaced with the file name each handle resolves to. Those names are content-hashed, so the hash stays stable across builds and still changes when an asset's contents change. Replacing the placeholder with a fixed token would also stop the churn, but then an image edited without a dimension change would leave the hash untouched and the restored HTML would point at a file name the build no longer emits.

Testing

New unit tests in test/units/build/plugin-incremental.test.ts drive the plugin with swapped emit handles, for images and for other assets, and assert the hash is unchanged, plus the reverse case where a different resolved file name does change it. Also confirmed against the reproduction in the issue, where 50 builds now produce the same hash, and against a variant of it importing a video and a PDF rather than images.

Docs

No user-facing behavior change, so nothing to document.

withastro/astro

Fixes: #17621

When navigating away from a route with ClientRouter and then returning to it, later CSS edits can trigger an HMR update without changing the visible page. A manual reload temporarily restores HMR until another navigation causes the problem again.

Vite keeps references to the <style data-vite-dev-id> elements it creates and updates those same elements during CSS HMR. ClientRouter head swaps can remove a Vite-managed style element and replace it with a new element containing the same CSS. Vite still holds the original element reference, so subsequent updates are applied to a detached element instead of the stylesheet currently in the document.

This can affect any route-specific style managed by Vite, including Svelte and other framework component styles, imported CSS, and Astro component styles. Svelte components make the problem particularly visible because their styles can be inserted asynchronously after hydration. Vue already has special handling for browser-transformed scoped styles, which this change preserves.

Changes

  • Tracks Vite-managed style elements by their data-vite-dev-id and reuses the existing element during ClientRouter head swaps. This preserves the element reference used by Vite’s CSS HMR runtime.
  • Observes styles inserted asynchronously by client framework runtimes so they can also be retained across later navigations.
  • Refreshes the contents of server-generated styles when the same Vite ID represents different CSS on the next route, while preserving Vue scoped styles that have been transformed in the browser.

Testing

  • Adds coverage for navigating away from and back to a route before updating a nested Svelte component style and an imported stylesheet.
  • Verifies that both updates use native CSS HMR without causing a full page reload.
  • Adds coverage using a real Vite-created style node to verify that ClientRouter preserves its identity while applying changed CSS from the incoming document.
  • Existing Vue scoped-style tests continue to cover preservation of browser-transformed CSS.

Docs

No docs changes. This fixes development-only ClientRouter and Vite HMR coordination without changing public APIs or production output.

withastro/astro

Fixes: #17672

When editing a style block in an Astro component rendered from an MDX content entry, the first save triggers a reload but the page can still render the previous CSS. Saving the file again triggers another reload and finally displays the change.

This happens when Astro cannot run the adapter’s SSR environment directly and uses its internal astro environment to collect styles from content entries. In my case this was because I was using the Cloudflare workerd environment.

Astro’s dev CSS plugin does not currently run in the fallback environment, so the first update reloads the page before that environment has collected the latest transformed CSS.

This change enables the existing dev CSS plugin in the fallback astro environment. The updated CSS is then collected during the first file change, allowing the first reload to render the new styles instead of requiring a second save.

Changes

  • Applies the dev CSS collection plugin to Astro’s fallback runnable environment, used when an adapter’s SSR environment cannot be run directly, such as with Cloudflare workerd.
  • Ensures content-rendered styles are refreshed before an SSR reload, instead of requiring a second save for the latest CSS to appear.

Testing

  • Adds coverage verifying that the dev CSS plugin applies to the fallback astro environment.

Docs

No docs changes. This fixes internal development-server CSS collection behavior.

withastro/astro

Changes

Add a test case missed in #17605

Testing

This change is only the addition of a test case

Docs

No docs needed for the addition of a test case

withastro/astro

PR #17383 fixed stale server-rendered CSS during HMR, but its client-module detection included a broad same-file fallback intended to support speculative query variants such as ?used and ?direct.

Those variants are not part of the verified Astro/Vite update path, and another style module associated with the same source file is not necessarily capable of applying the update. It could represent a different component style index or a non-injected CSS import.

This follow-up removes hasClientStyleModuleByFile() and retains only the module matching behavior supported by observed requests and Astro’s CSS collection code.

Changes

  • Removes the same-file fallback previously used to decide whether a client style module could handle an update.
  • Uses exact client module IDs when selecting native Vite CSS HMR. The only normalized difference is the bare inline parameter that Astro adds when loading component CSS text server-side.
  • Keeps .css?raw and .css?inline imports on the SSR invalidation path because they export strings rather than injecting client styles.

Testing

  • Updates coverage to verify that a different style index from the same component does not count as a matching client module.
  • Adds coverage for Astro’s server-side inline component requests mapping to their exact client equivalent.
  • Covers CSS string imports, reordered component-style queries, and incomplete or non-style requests.

Docs

No docs changes. This tightens internal HMR module matching without changing public APIs.

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@7.2.1

Patch Changes

  • #17612 7133730 Thanks @thelazylamaGit! - Fixes CSS hot module replacement after navigating between pages with ClientRouter

  • #17628 4ada248 Thanks @astrobot-houston! - Fixes a CSP violation when using both security.csp and experimental.clientPrerender with data-astro-prefetch links. The dynamically injected <script type="speculationrules"> now uses a static "source": "document" approach with a CSS selector, producing a deterministic payload that is hashed and included in the CSP script-src directive at build time.

  • #17605 89e4647 Thanks @ashleigh-yeoman! - Fixes middleware HMR not responding to changes in imported modules. Previously, only direct edits to the middleware file would trigger a reload.

  • #17582 bd2c1a5 Thanks @astrobot-houston! - Fixes a regression where content collection reference() fields silently accepted entry IDs that don't exist, such as an ID that doesn't match a loader's slugified version of it. Astro now logs an error for references that point to a missing entry after all loaders finish syncing.

  • #17661 97b0cc7 Thanks @ArmandPhilippot! - Improves Markdown options documentation with links to the Markdown guide and official processors.

  • #17349 4328c73 Thanks @astrobot-houston! - Fixes an issue where requests handled by the dev prerender environment (e.g. /_image with @astrojs/cloudflare's prerenderEnvironment: 'node') returned a 500 when a prerendered catch-all route existed, because non-prerendered route modules were imported in an environment where their runtime-specific APIs are unavailable

  • #17603 722eed6 Thanks @astrobot-houston! - Fixes <video> and <audio> elements being non-functional after navigating via view transitions (<ClientRouter />)

  • #17616 3a890d2 Thanks @lazerg! - Fixes experimental.incrementalBuild re-rendering unchanged routes that import more than one asset. The route's dependency hash depended on the order the assets finished building, so two builds of identical sources could produce different hashes. The hash is now based on the file name each asset resolves to.

  • #17547 fba468c Thanks @dmgawel! - Improves getCollection() and getEntry() performance for entries without local image references

  • #17602 16e0d9d Thanks @astrobot-houston! - Fixes a build error caused by hash collisions in generated content collection image import identifiers

@astrojs/cloudflare@14.2.1

Patch Changes

  • #17627 ba6a9f6 Thanks @astrobot-houston! - Fixes the astro peer dependency range from ^7.0.0 to ^7.2.0. The adapter imports symbols (beginContentEntryCollection, beginImageCollection, endContentEntryCollection, endImageCollection) from astro/app that were added in Astro 7.2.0, so earlier versions fail at build time with a MISSING_EXPORT error.

  • Updated dependencies [0891ac9]:

    • @astrojs/underscore-redirects@1.0.4

@astrojs/netlify@8.2.1

Patch Changes

  • Updated dependencies [0891ac9]:
    • @astrojs/underscore-redirects@1.0.4

@astrojs/node@11.1.1

Patch Changes

  • #17658 8b211a5 Thanks @astrobot-houston! - Fixes an EventEmitter memory leak when serving static pages over keep-alive connections with staticHeaders enabled and CSP (security.csp) active

@astrojs/language-server@2.16.14

Patch Changes

  • #17618 2630631 Thanks @lazerg! - Fixes the missing "Add all missing imports" and "Add import from" quick fixes for Astro components

@astrojs/underscore-redirects@1.0.4

Patch Changes

  • #17620 0891ac9 Thanks @astrobot-houston! - Fixes dynamic redirect routes to honour user-configured status codes instead of hardcoding 301. Previously, a redirect configured with { destination: '/new', status: 302 } would be emitted as 301 in the _redirects file when the route was dynamic.
withastro/astro

Changes

Fixes the three @astrojs/cloudflare session-false tests failing on main and blocking #17558.

The adapter's astro:config:setup gained an unguarded read of config.experimental.collectionStorage in #17543 (src/index.ts:289). session-false.test.ts calls that hook with a mock config that has no experimental key, so it threw TypeError: Cannot read properties of undefined (reading 'collectionStorage'). This PR adds the missing key to the mock:

experimental: { collectionStorage: 'single-file' },

A resolved AstroConfig always has it, since the schema defaults it to 'single-file', so the mock was incomplete rather than the adapter.

Testing

  • Fixed the failing Cloudflare tests.
  • Node and Netlify are unaffected since their mocks don't read experimental.

Docs

None needed, test-only change. No changeset for the same reason.

withastro/astro

Changes

Fixes the previous attempt to get HMR working for middleware. Now any imports (and transitive imports) in middleware.ts can trigger HMR for middleware.ts, instead of just itself.

This is meant to be a cleaner and better-tested version of #17597

Closes #17590

Testing

3 tests added to packages/astro/test/middleware.test.ts, covering the 3 main HMR cases

  1. middleware.ts is modified
  2. A module imported by middleware.ts is modified
  3. A transitive dependency (a module imported by a module imported by middleware.ts) is modified

Docs

No docs update needed. This PR fixes a bug in HMR behavior, with no API changes.

withastro/astro

Changes

  • <video> and <audio> elements are now fully functional after navigating to a page via <ClientRouter />. Previously, media controls were permanently disabled and playback was impossible after any client-side navigation.
  • The root cause is DOMParser.parseFromString(), which parses incoming page HTML into an inert document where the browser never initializes the media stack. Moving those elements into the live DOM does not retroactively initialize it. The fix adds a reifyMediaElements() post-swap step (following the existing attachShadowRoots() pattern) that replaces each <video>/<audio> element with a fresh copy created via document.createElement(), forcing the browser to properly initialize the media stack.

Testing

  • No automated test added — the fix is client-side browser code that exercises the browser's media stack initialization, which cannot be meaningfully tested in Node.js.

Docs

  • No docs update needed; this is a bug fix restoring behavior that was always expected to work.

Closes #17601

withastro/astro

Changes

  • Content collection image imports in .astro/content-assets.mjs now use sequential identifiers (__ASTRO_IMAGE_IMPORT_0, __ASTRO_IMAGE_IMPORT_1, …) instead of hash-based names. The previous shorthash()-derived names used a 32-bit hash that could collide for different image paths, causing a PARSE_ERROR at build time. Sequential indices are collision-free by construction.
  • Removes the now-unused importIdToSymbolName export and shorthash import from resolveImports.ts.

Closes #17595

Testing

  • Adds packages/astro/test/units/content-layer/asset-imports.test.ts: verifies that two image paths whose filenames produce identical shorthash() values (imgAa.jpg / imgBB.jpg) are assigned distinct import identifiers.

Docs

  • No docs update needed — this is an internal codegen detail with no user-facing API change.
withastro/starlight

Adds https://lilypond.ky.fyi to the Starlight Showcase following the contribution guidelines.

withastro/astro

Changes

  • app.use(cf()) from @astrojs/cloudflare/hono now type-checks correctly in projects that use wrangler types. Previously, HonoCloudflareContextLike declared executionCtx: ExecutionContext, binding it to the global ExecutionContext type. When wrangler types generates worker-configuration.d.ts, that global gains required members (tracing, exports) that Hono's own ExecutionContext doesn't have, making the handler contravariant-incompatible with MiddlewareHandler.
  • Replaces executionCtx: ExecutionContext with an inline structural type listing only the three members actually consumed downstream (waitUntil, passThroughOnException, props). This matches the approach astro/hono already uses for its duck-typed context, and the narrowed type remains assignable to internal callers (cfFetch, createLocals) without any casts.

Testing

  • No new automated test — the mismatch only surfaces when the user's wrangler types-generated ExecutionContext global is in scope, which the package's own test compilation doesn't exercise (it compiles against @cloudflare/workers-types, whose ExecutionContext has fewer/optional members). The fix was verified against the reporter's repro at https://github.com/iseraph-dev/repro-astro-cf-hono-types, where astro check goes from 1 error to 0.

Docs

  • No docs change needed — this is a type-only fix with no behavior or API surface change.

Closes #17593

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.41.7

Patch Changes

  • #4114 3e486fb Thanks @delucis! - Fixes processing of code examples in RTL languages when using Astro’s Sätteri Markdown processor
withastro/starlight

Description

  • Fixes our Sätteri plugin for supporting code in RTL documents in newer versions of Astro
  • Fixes the failing test in #4113
  • Sätteri now has a ctx.parent() we can use to get parents so we can remove the more convoluted code for working this out. Strictly speaking these do not work 1:1 — before, we’d skip applying attributes to a <code> element even if it was deeply nested in a <pre> whereas now we only skip if the <code> is a direct child of the <pre>. However, in practice, I think this covers all the scenarios we were intending?
  • Existing tests here should pass, showing that the changes work for people on older versions of Astro. And I ran the changes against #4113 too to ensure it fixes the failing test there.
withastro/starlight

Description

  • Updates monorepo versions of astro to latest, fixes #3991 in our own docs
  • Also updates other @astrojs/* packages
  • Updates sharp to latest in examples and docs
withastro/starlight

Description

While reviewing another PR, I noticed we use pnpm dlx to run pkg-pr-new for preview releases.

This is not recommended because pnpm dlx would always resolves to the latest version which could have unexpected behavior due to some upstream breaking changes but also increases supply-chain risks.

Caution

In CI environments, avoid npx, pnpm dlx, yarn dlx, and bunx for this step. Install pkg-pr-new as a dependency and execute it from the lockfile (npm exec, pnpm exec, yarn, or bun run).

This PR fixes that by installing pkg-pr-new as a dev dependency and running it using pnpm exec.

withastro/astro

Changes

I hit this while following up on #17481. The same header mutation that crashed the Cloudflare adapter on cached image responses also lives in core: applyCacheHeaders() calls response.headers.set() directly on the response a route returns, and CacheHandler deletes CDN-Cache-Control and Cache-Tag from the response a provider returns. Both throw TypeError: immutable when the response headers can't be modified, which is the case for any response returned straight from fetch(). A route that proxies an upstream (return fetch(...) plus cache.set({ maxAge })) gets a 500 on every request. A user already reported this error class when combining cache.set() with a Vary header on Cloudflare (comment on #17408). I haven't verified that path, it needs the Cloudflare dev runtime, but the repro here is adapter free and fails on plain Node.

The fix mirrors what #17481 did in the adapter: try the mutation, and when it throws, rebuild the response with new Response(response.body, response) and apply the headers to the copy. The first .set() throws before changing anything, so applying them again can't duplicate headers. Header stripping now also checks has() first, so provider responses without CDN headers aren't rebuilt for nothing.

One heads up: pnpm install with the pinned pnpm also dropped a stale triage/gh-17583 importer from the lockfile that #17584 left behind. I can split that out if you'd rather keep it.

Testing

Two new fixtures. Without the fix all four new tests fail with a 500 instead of a 200: a memoryCache() route returning a fetch() proxied response, and a provider whose onRequest serves responses with immutable headers, where the CDN header stripping used to crash even when those headers weren't present. With the fix they pass and the second request is served as a cache HIT. The cache unit suite (162 tests) and the neighbouring integration tests still pass. I also reproduced the crash end to end against published astro 7.1.6 with @astrojs/node before writing the fix.

Docs

No docs changes. The changeset describes the fix.

withastro/astro

Changes

Skip the failing type check tests in ecosystem-ci. This will make ecosystem-ci pass.

I think it is better to make the tests pass so we can easily catch regressions. If we want to catch regressions for types, we can enable these tests later when it passes.

I didn't add a changeset as this is completely an internal change.

Testing

I ran ecosystem-ci against my fork by running node ecosystem-ci.ts astro in the local modified ecosystem-ci repo.

Docs

No docs change as this is an internal change.

withastro/astro

Changes

Astro's config schema imported @astrojs/markdown-satteri at the top level, so Sätteri and its optional platform-specific native binaries landed in the module graph on every astro dev/build, even for projects with no Markdown files. When npm skips the unavailable optional binary for the host platform (for example Windows without @bruits/satteri-wasm32-wasi), the bundler then can't resolve it and the build crashes.

This puts the default processor behind a dynamic import, so @astrojs/markdown-satteri is only resolved when Markdown actually gets rendered. A project with no Markdown never pulls it into the graph.

Testing

I added a unit test checking that the default markdown.processor still resolves to the Sätteri processor. The existing markdown.processor integration test already covers rendering with the default, and it plus the full unit suite pass. The Windows build crash from the report needs the missing optional binary, so it can't be reproduced on Linux CI.

Docs

No user-facing behavior change, so no docs needed.

Fixes #17585

withastro/astro

Changes

  • Solid component libraries that ship pre-compiled browser artifacts via the exports.solid condition (e.g. @kobalte/core) were left external during prerendering. Node resolved them via the default condition instead, which picks up browser-only code that calls template() and other APIs stubbed with notSup() in solid-js/web/dist/server.js — crashing astro build with "Client-only API called on the server side".
  • Uses crawlFrameworkPkgs from vitefu to discover all packages that declare solid-js as a peer dependency, then adds them to resolve.noExternal for non-client environments (e.g. prerender). This forces Vite to bundle those packages so it can apply the solid export condition correctly, matching the established pattern from @astrojs/svelte (PR #16210).
  • Adds vitefu to @astrojs/solid-js's dependencies (previously it was only available as a transitive dep via other packages).

Testing

No automated test added — configEnvironmentPlugin is internal and the solid integration has no existing test infrastructure for this; the svelte integration's equivalent fix also lacks a unit test. Fix was confirmed working by the reporter against both a minimal reproduction and a production project (12 pages).

Docs

No docs update needed — this restores expected build behavior with no API changes.

Closes #17583

withastro/astro

Changes

  • reference() fields in content collections no longer silently accept entry IDs that don't exist in the store. After all loaders finish syncing, ContentLayer now walks every entry's data to find reference objects ({ id, collection }) and logs an error for any that point to a missing entry. This catches cases like author: "John-Doe" where the glob() loader slugified the actual entry ID to john-doe.
  • This is a regression from the Zod 4 upgrade (PR #14956), which removed the inline Zod validation that previously caught invalid references. Inline validation can't be restored because loaders run in parallel and the referenced collection may not be populated yet, so validation runs post-sync instead.

Closes #17322

Testing

  • Two new unit tests in packages/astro/test/units/content-layer/data-transforms.test.ts: one verifying that an invalid reference (John-Doe where only john-doe exists) produces an error log, and one verifying that a valid reference produces no error.

Docs

  • No docs update needed; this restores previously documented behavior that was accidentally removed.
withastro/astro

See #2587

withastro/astro

Changes

package-manager-detector recently supported the devEngines field, but for our custom strategies option passing, we redefine the list and didn't include the devEngines-field option, so this PR includes it.

Its default value had devEngines-field.

Testing

Didn't test as should be a simple change

Docs

Added a changeset.

withastro/astro

This PR contains the following updates:

Package Change Age Confidence
@types/semver (source) ^7.7.1^7.8.0 age confidence
@vscode/test-cli ^0.0.12^0.0.15 age confidence
js-yaml ^4.3.0^4.3.1 age confidence
mocha (source) ^11.7.5^11.8.0 age confidence
ovsx (source) ^0.10.10^0.10.12 age confidence
prettier (source) ^3.9.0^3.9.6 age confidence
semver ^7.7.4^7.8.5 age confidence
svelte (source) ^5.55.3^5.56.10 age confidence
tinyglobby (source) ^0.2.16^0.2.17 age confidence
tsx (source) ^4.22.0^4.23.12 age confidence
vscode-languageserver-protocol (source) ^3.17.5^3.18.2 age confidence
vscode-languageserver-textdocument (source) ^1.0.12^1.0.14 age confidence
vscode-uri ^3.1.0^3.2.0 age confidence
yaml (source) ^2.8.3^2.9.0 age confidence
yargs (source) ^18.0.0^18.1.0 age confidence

Release Notes

nodeca/js-yaml (js-yaml)

v4.3.1

Compare Source

mochajs/mocha (mocha)

v11.8.0

Compare Source

v11.7.6

Compare Source

🩹 Fixes
  • make describe().timeout() work (aafe6fd)
  • test: replace wmic usage with native Windows API (#​5694) (73ebdfa)
🧹 Chores
eclipse-openvsx/openvsx (ovsx)

v0.10.12

Compare Source

Dependencies
  • Bump follow-redirects from 1.15.6 to 1.16.0 (#​1759)
  • Bump ip-address from 10.1.0 to 10.2.0 (#​1820)

v0.10.11

Compare Source

Dependencies
  • Bump picomatch from 2.3.1 to 2.3.2 (#​1719)
  • Bump picomatch from 4.0.3 to 4.0.4
  • Bump brace-expansion from 1.1.12 to 1.1.13 (#​1725)
  • Bump brace-expansion from 2.0.2 to 2.0.3
  • Bump brace-expansion from 5.0.4 to 5.0.5
  • Bump lodash from 4.17.23 to 4.18.1 (#​1745)
prettier/prettier (prettier)

v3.9.6

Compare Source

v3.9.5

Compare Source

diff

Markdown: Cap ordered list mark at 999,999,999 (#​19351 by @​tats-u)

CommonMark parsers only support ordered list item numbers up to 999,999,999.

With this change, Prettier now caps the ordered list item number at 999,999,999 to ensure that the output is correctly parsed as an ordered list by CommonMark parsers. Numbers larger than 999,999,999 are not parsed as list item numbers and are left unchanged in the output:

<!-- Input -->
999999998. text
999999998. text
999999998. text
999999998. text

1234567890123456789012) text

<!-- Prettier 3.9.4 -->
999999998. text
999999999. text
1000000000. text
1000000001. text

1234567890123456789012) text

<!-- Prettier 3.9.5 -->
999999998. text
999999999. text
999999999. text
999999999. text

1234567890123456789012) text
Markdown: Avoid corrupting empty link with title (#​19487 by @​andersk)

Do not remove <> from an inline link or image with an empty URL and a title, as this removal would change its interpretation.

<!-- Input -->
[link](<> "title")

<!-- Prettier 3.9.4 -->
[link]( "title")

<!-- Prettier 3.9.5 -->
[link](<> "title")
Less: Remove extra spaces after [ in map lookups (#​19503 by @​kovsu)
// Input
.foo {
  color: #theme[ primary];
  color: #theme[@name];
  color: #theme[@@name];
}

// Prettier 3.9.4
.foo {
  color: #theme[ primary];
  color: #theme[ @name];
  color: #theme[ @@name];
}

// Prettier 3.9.5
.foo {
  color: #theme[primary];
  color: #theme[@name];
  color: #theme[@@name];
}
CSS: Prevent addition space in type() with + (#​19516 by @​bigandy)

This fixes the addition space before + in CSS type() declaration. For example type(<number>+) was being converted into type(<number> +) which is invalid CSS and does not work.

/* Input */
div {
  border-radius: attr(br type(<length>+));
}

/* Prettier 3.9.4 */
div {
  border-radius: attr(br type(<length> +));
}

/* Prettier 3.9.5 */
div {
  border-radius: attr(br type(<length>+));
}
Less: Remove spaces between merge markers and colons (#​19517 by @​kovsu)
// Input
a {
  box-shadow  +  : 0 0 1px #&#8203;000;
}

// Prettier 3.9.4
a {
  box-shadow+  : 0 0 1px #&#8203;000;
}

// Prettier 3.9.5
a {
  box-shadow+: 0 0 1px #&#8203;000;
}
Markdown: Preserve wiki links with aliases (#​19527 by @​kovsu)
<!-- Input -->
[[Foo:Bar]]

<!-- Prettier 3.9.4 -->
[[Foo]]

<!-- Prettier 3.9.5 -->
[[Foo:Bar]]
TypeScript: Fix comments being dropped on shorthand type import/export specifiers (#​19565 by @​kirkwaiblinger)
// Input
export { type /* comment */ T } from "foo";
import { type /* comment */ T } from "foo";

// Prettier 3.9.4
Error: Comment "comment" was not printed. Please report this error!

// Prettier 3.9.5
export { type /* comment */ T } from "foo";
import { type /* comment */ T } from "foo";
Miscellaneous: Preserving comments' placement property (#​19567 by @​Janther)

Prettier@​3.9.0 deleted an undocumented property on comments, which was already used by plugins, comment.placement is now available again after comment attach.

Flow: Stop enforcing empty module declaration to break (#​19568 by @​fisker)
// Input
declare module "foo" {}

// Prettier 3.9.4
declare module "foo" {
}

// Prettier 3.9.5
declare module "foo" {}
Angular: Support expression for exhaustive typechecking (#​19571 by @​fisker)
<!-- Input -->
@switch (state.mode) {
  @default never(state);
}

<!-- Prettier 3.9.4 -->
@switch (state.mode) {
  @default never;
}

<!-- Prettier 3.9.5 -->
@switch (state.mode) {
  @default never(state);
}
TypeScript: Ignore comments inside mapped type when checking type parameter comments (#​19572 by @​fisker)
// Input
foo<{
  // comment
  [key in keyof Foo]: number
}>();

// Prettier 3.9.4
foo<
  {
    // comment
    [key in keyof Foo]: number;
  }
>();

// Prettier 3.9.5
foo<{
  // comment
  [key in keyof Foo]: number;
}>();
Less: Fix adjacent block comments being corrupted (#​19574 by @​kovsu)
// Input
/* a *//* b */
/* a */* {
  color: red;
}

// Prettier 3.9.4
/* a */
/* b */
/* a * {
  color: red;
}

// Prettier 3.9.5
/* a */ /* b */
/* a */
* {
  color: red;
}
JavaScript: Handle dangling comments in SwitchStatement (#​19581 by @​fisker)
// Input
switch (foo) {
 // comment
}

// Prettier 3.9.4
switch (
  foo
  // comment
) {
}

// Prettier 3.9.5
switch (foo) {
  // comment
}
TypeScript: Remove space in comment-only object type (#​19583 by @​fisker)
// Input
var foo = {
  /* comment */
};
type Foo = {
  /* comment */
};

// Prettier 3.9.4
var foo = {/* comment */};
type Foo = { /* comment */ };

// Prettier 3.9.5
var foo = {/* comment */};
type Foo = {/* comment */};

v3.9.4

Compare Source

v3.9.3

Compare Source

v3.9.2

Compare Source

v3.9.1

Compare Source

sveltejs/svelte (svelte)

v5.56.10

Compare Source

Patch Changes
  • fix: preserve CSS escape sequences when printing selectors (#​18667)

  • fix: parse :nth-child(2n of.foo) where of is not followed by whitespace (#​18611)

  • fix: transform expressions inside labeled statements during server compilation (#​18617)

  • docs: clarify that context lookup includes the current component and all ancestors (#​18581)

  • fix: apply CSS custom properties with falsy values on components (#​18634)

  • fix: correctly print {#await ... catch x} et al (#​18645)

  • fix: ignore comments of Program node during migration script (#​18656)

  • fix: reliably resolve append_style to its correct root (#​18614)

  • fix: clean up removed capture event handlers from spread attributes (#​18618)

  • fix: don't corrupt renderer type during SSR's legacy bind: retry loop (#​18616)

  • fix: treat concise arrow function bodies as implicit returns when calculating blockers (#​18613)

  • fix: give effect teardowns the value from before the first write in a flush (#​18620)

  • fix: avoid double-calling a derived reference when destructuring $derived of another $derived during server-side rendering (#​18668)

  • fix: preserve namespaces in CSS type selectors (#​18678)

  • fix: increment private state fields through a non-this receiver (#​18622)

  • chore: deduplicate client and server context helpers (#​18580)

  • fix: release last_propagated_event after event propagation settles so it no longer retains the last event's target subtree (#​18569)

  • fix: allow custom elements to receive async values as props (#​18661)

  • fix: strip comments from inline style values in linear time (#​18553)

  • fix: prevent declaration comments from breaking server derived references (#​18641)

  • perf: make async blocker analysis scale linearly with the number of top-level references (#​18549)

  • fix: preserve short-circuiting for logical assignments to private state fields (#​18594)

v5.56.9

Compare Source

Patch Changes
  • fix: skip controlled each fast path while another batch is pending (#​18625)

  • fix: better whitespace handling inside printer (#​18638)

  • fix: don't duplicate comments in attributes (#​18636)

  • fix: preserve CSS comments in the AST printer (#​18637)

v5.56.8

Compare Source

Patch Changes
  • fix: call onerror and provide a working reset when hydrating a failed boundary (#​18556)

  • fix: preserve select selection when spread attributes omit value (#​18561)

v5.56.7

Compare Source

Patch Changes
  • chore: provide indent option for print (#​18474)

v5.56.6

Compare Source

Patch Changes
  • perf: skip unnecessary blocker analysis when compiling components without top-level await (#​18548)

  • fix: rerun derived that had an abort controller on reconnection (#​18551)

v5.56.5

Compare Source

Patch Changes
  • chore: drop dead code that make TSGO fail (#​18496)

  • fix: don't (re)connect deriveds when read inside branch/root effects (#​18527)

  • fix: skip unnecessary derived effect in earlier batch (#​18525)

  • fix: avoid declaration tag warning in event handlers (#​18500)

  • fix: abort deriveds own AbortSignal when it disconnects (#​18400)

  • fix: ensure $state.eager() is correctly transormed for SSR output (#​18530)

  • fix: correctly transform declaration tags during SSR (#​18492)

  • fix: transform computed keys in keyed {#each} destructuring patterns (#​18521)

  • fix: chain preprocessor sourcemaps with an empty sources[0] instead of dropping them (#​18518)

  • fix: clear previous_task reference after abort in Tween to prevent memory leak on interrupted tweens (#​18541)

  • fix: don't treat declaration tags as parts inside each blocks (#​18507)

v5.56.4

Compare Source

Patch Changes
  • fix: include wrapping parentheses in {@const} declarator end position (#​18436)

  • fix: always unset reactivity context after restoring it (#​18453)

  • fix: don't notify searchParams subscribers when the URL changes without affecting the search string (#​18425)

  • fix: strip ? from optional parameters in <script lang="ts"> so generated JavaScript is valid (#​18448)

v5.56.3

Compare Source

Patch Changes
  • fix: ignore errors that occur in destroyed effects (#​18384)

  • fix: type BigInts in $state.snapshot(...) return values (#​18388)

v5.56.2

Compare Source

Patch Changes
  • fix: properly track effect end node for async sibling component (#​18371)

  • fix: prevent false-positive reactivity loss warning (#​18373)

  • chore: bump esrap dependency (#​18372)

  • fix: ignore declaration tags for animation directive (#​18366)

  • fix: reject pending async deriveds on discard (#​18308)

v5.56.1

Compare Source

Patch Changes
  • fix: error at compile time on duplicate snippet/declaration tag definitions (#​18351)

  • fix: parse declaration tag contents more robustly (#​18353)

  • fix: correctly transform references to earlier declarators in a declaration tag (e.g. {let a = $state(0), b = $derived(a * 2)}) (#​18348)

  • fix: avoid spurious state_referenced_locally warnings for $derived declarations in declaration tags (#​18348)

  • fix: tolerate whitespace before let/const in declaration tags (#​18348)

  • fix: prevent infinite loop when a tag's expression ends with a trailing / at the end of the input (#​18350)

  • fix: more robust parsing of declaration tags with regards to type (#​18330)

  • fix: preserve newlines in spread input values when the type attribute is applied after value (#​18345)

  • fix: update SvelteURLSearchParams when setting duplicate keys to the same joined value (#​18336)

  • fix: check references for blockers on server, too (#​18352)

v5.56.0

Compare Source

Minor Changes
  • feat: allow declarations in the template (#​18282)
Patch Changes
  • perf: use createElement instead of createElementNS for HTML elements (#​18262)

  • perf: store current_sources as a Set for O(1) membership checks (#​18278)

  • perf: deduplicate identical hoisted templates within a component (#​18320)

  • perf: hoist rest_props exclude list as a module-scope Set (#​18252)

v5.55.10

Compare Source

Patch Changes
  • fix: unlink errored and otherwise finished batch (#​18264)

  • perf: walk composedPath() directly in delegated event propagation (#​18268)

  • fix: transfer effects when merging batches (#​18254)

  • fix: allow $derived(await ...) in disconnected effect roots (#​18273)

  • fix: remove temporary raw-text hydration markers (#​18269)

  • fix: propagate async @const blockers through closure references so template expressions like {(() => host)()} correctly wait for the awaited value (#​18309)

  • fix: properly unlink batches (#​18298)

  • fix: settle discarded batch (#​18290)

  • fix: declare let: directives before {@const} declarations on slotted elements (#​18271)

  • fix: resume outro-ed branches if they were kept around (#​18291)

  • fix: avoid waterfall-warning when async resolves to same value (#​18297)

  • fix: correctly coordinate component-level effects inside async blocks (#​18260)

  • fix: make unnecessary commit work less likely (#​18263)

  • chore: add tag name to a11y_click_events_have_key_events warning (#​18272)

  • fix: catch rejected promises while merging/committing (#​18266)

v5.55.9

Compare Source

Patch Changes
  • fix: don't unset batch when calling {#await ...} promise (#​18243)

  • fix: promise-ify {#await await ...} expressions on the server and correctly hydrate them on the client (#​18243)

  • fix: deduplicate dependencies that are added outside the init/update cycle (#​18243)

  • fix: avoid false-positive batch invariant error (#​18246)

  • fix: inline primitive constants in attribute values during SSR (#​18232)

v5.55.8

Compare Source

Patch Changes
  • fix(print): handle svelte:body and fix keyframe percentage double-printing (#​18234)

  • fix: execute uninitialized derived even if it's destroyed (#​18228)

  • fix: use named symbols everywhere (#​18238)

  • fix: don't run teardown effects when deriveds are unfreezed (#​18227)

  • fix: unset context synchronously in run (#​18236)

v5.55.7

Compare Source

Patch Changes

v5.55.6

Compare Source

Patch Changes
  • fix: leave stale promises to wait for a later resolution, instead of rejecting (#​18180)

  • fix: keep dependencies of $state.eager/pending (#​18218)

  • fix: reapply context after transforming error during SSR (#​18099)

  • fix: don't rebase just-created batches (#​18117)

  • chore: allow null for pending in typings (#​18201)

  • fix: flush eager effects in production (#​18107)

  • fix: rethrow error of failed iterable after calling return() (#​18169)

  • fix: account for proxified instance when updating bind:this (#​18147)

  • fix: ensure scheduled batch is flushed if not obsolete (#​18131)

  • fix: resolve stale deriveds with latest value (#​18167)

  • chore: remove unnecessary increment_pending calls (#​18183)

  • fix: correctly compile component member expressions for SSR (#​18192)

  • fix: reset source.updated stack traces after flush (#​18196)

  • fix: replacing async 'blocking' strategy with 'merging' (#​18205)

  • fix: allow @debug tags to reference awaited variables (#​18138)

  • fix: re-run fallback props if dependencies update (#​18146)

  • fix: abort running obsolete async branches (#​18118)

  • fix: ignore comments when reading CSS values (#​18153)

  • fix: wrap Promise.all in save during SSR (#​18178)

  • fix: ignore false-positive errors of $inspect dependencies (#​18106)

v5.55.5

Compare Source

Patch Changes
  • fix: don't mark deriveds while an effect is updating (#​18124)

  • fix: do not dispatch introstart event with animation of animate directive (#​18122)

v5.55.4

Compare Source

Patch Changes
  • fix: never mark a child effect root as inert (#​18111)

  • fix: reset context after waiting on blockers of @const expressions (#​18100)

  • fix: keep flushing new eager effects (#​18102)

privatenumber/tsx (tsx)

v4.23.12

Compare Source

Bug Fixes

This release is also available on:

v4.23.11

Compare Source

v4.23.10

Compare Source

Bug Fixes

This release is also available on:

v4.23.9

Compare Source

Bug Fixes
  • map Node test locations (2f55884)
  • support data URLs in tsImport (b94f46f)

This release is also available on:

v4.23.8

Compare Source

Bug Fixes
  • preserve package subpath resolution (be1315e)
  • preserve typeless ESM dependency exports (70dfc5e)

This release is also available on:

v4.23.7

Compare Source

Bug Fixes
  • prevent tsImport cache collisions (4e5a138)

This release is also available on:

v4.23.6

Compare Source

v4.23.5

Compare Source

v4.23.4

Compare Source

Bug Fixes
  • cli: allow async process.once() signal handlers to finish (#​827) (2afc7bb)

This release is also available on:

v4.23.3

Compare Source

Bug Fixes

This release is also available on:

v4.23.2

Compare Source

v4.23.1

Compare Source

Bug Fixes
  • support tsImport after global preload (8d4ffc2)
  • watch: avoid clearing piped output (95d0672)
  • watch: treat script and dependency paths literally (79fddde)
Performance Improvements
  • index transform cache lazily (e818ad6)
  • load esbuild lazily in CLI (d067938)
  • map Node TypeScript formats directly (cdcc623)
  • use sync module hooks on Node v22.22.3+ (f8992f1)

This release is also available on:

v4.23.0

Compare Source

Bug Fixes
Features

This release is also available on:

v4.22.5

Compare Source

Bug Fixes
  • isolate hook state per async module.register() registration (a305f36)

This release is also available on:

v4.22.4

Compare Source

Bug Fixes
  • resolve CommonJS directory requires inside dependencies (#​803) (1ce8463)

This release is also available on:

microsoft/vscode-uri (vscode-uri)

v3.2.0

Compare Source

Changes:

  • #​65: chore: bump minor version to 3.2.0
  • #​59: Restore the default export
  • #​63: Bump brace-expansion from 2.1.1 to 2.1.4
  • #​64: Bump js-yaml from 4.3.0 to 4.3.1
  • #​62: Bump fast-uri from 3.1.4 to 3.1.5
  • #​61: Bump js-yaml from 4.2.0 to 4.3.0
  • #​60: Bump fast-uri from 3.1.2 to 3.1.4
  • #​58: chore: bump patch version to 3.1.1
  • #​57: Use Yarn resolutions to resolve remaining mocha audit alerts
  • #​56: Bump fast-uri from 3.1.0 to 3.1.2
See More
  • #​55: Bump picomatch from 2.3.1 to 2.3.2
  • #​54: Bump webpack from 5.94.0 to 5.104.1
  • #​52: Bump glob from 10.3.10 to 10.5.0
  • #​51: Bump js-yaml from 4.1.0 to 4.1.1
  • #​50: chore: bump action and node versions
  • #​49: Bump serialize-javascript from 6.0.1 to 6.0.2

This list of changes was auto generated.

yargs/yargs (yargs)

v18.1.0

Compare Source

Features
  • ignore bun when getting bin name (b77831c)
Bug Fixes

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

This PR contains the following updates:

Package Change Age Confidence
@fastify/middie ^9.1.0^9.3.3 age confidence
devalue ^5.8.1^5.9.0 age confidence
fastify (source) ^5.7.4^5.12.0 age confidence
node-mocks-http ^1.17.2^1.18.1 age confidence

Release Notes

fastify/middie (@​fastify/middie)

v9.3.3

Compare Source

⚠️ Security Release

Fix for:

What's Changed

Full Changelog: fastify/middie@v9.3.2...v9.3.3

sveltejs/devalue (devalue)

v5.9.0

Compare Source

Minor Changes
  • 07d6a38: feat: export filterArrayIndices, the array-index filtering used by the indicesOf stringify operation, so custom operations can reuse it instead of reimplementing it
  • 07d6a38: feat: add pluggable operations option to parse/unflatten, allowing customization of how values are constructed while reviving (e.g. cross-realm or foreign-runtime revival)
  • 5b53532: feat: add pluggable operations option to stringify/stringifyAsync, allowing customization of how values are introspected during serialization (e.g. side-effect-free or foreign-runtime serialization)

v5.8.2

Compare Source

Patch Changes
  • 48cc81f: fix: serialize DataView subviews with the correct byte offset and length
  • cd6da94: fix: resolve circular references through custom revivers when payload is already hydrated
  • 29a3382: fix: uneval now produces valid output for a repeated empty Map or Set
  • 8c0db06: fix: serialize Temporal values referenced more than once in uneval
  • 3770846: fix: emit valid JS for BigInt64Array and BigUint64Array in uneval
  • 756265a: fix: preserve shared-reference identity for Map keys in uneval
  • faa8a05: fix: emit uneval reconstructions before the statements that reference them
  • 06129ad: fix: do not grow sparse arrays by one slot in uneval
fastify/fastify (fastify)

v5.12.0

Compare Source

What's Changed

Full Changelog: fastify/fastify@v5.11.3...v5.12.0

v5.11.3

Compare Source

What's Changed

New Contributors

Full Changelog: fastify/fastify@v5.11.2...v5.11.3

v5.11.2

Compare Source

v5.11.1

Compare Source

What's Changed

New Contributors

Full Changelog: fastify/fastify@v5.11.0...v5.11.1

v5.11.0

Compare Source

What's Changed

New Contributors

Full Changelog: fastify/fastify@v5.10.0...v5.11.0

v5.10.0

Compare Source

v5.9.0

Compare Source

What's Changed

New Contributors

Full Changelog: fastify/fastify@v5.8.5...v5.9.0

eugef/node-mocks-http (node-mocks-http)

v1.18.1

Compare Source

  • fix(types): stop collapsing custom intersection types in createResponse/createMocks by @​MGough in #​337

v1.18.0

Compare Source


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

  • closes #17574
  • imageService: 'custom' (and the fallback case) left Astro's default dev image endpoint in place, which imports vite and node:fs and cannot load inside workerd, so every /_image request returned 500 in dev
  • use the generic fetch-based endpoint in dev, matching the other image service modes; a user-configured image.endpoint is left untouched
  • warn in dev when imageService: 'custom' resolves to the Sharp service (including when no image.service is configured), since Sharp's native binding cannot run inside workerd in dev or production (see #17574 (comment))

Testing

  • new custom-image-service.test.ts
  • new setImageConfig unit tests in image-config.test.ts
  • existing

Docs

  • none, bug fix
withastro/astro

Closes #17508

Changes

  • Adds neotraverse to the ALWAYS_NOEXTERNAL list in vite-plugin-environment/index.ts, forcing it to be bundled into the prerender output instead of emitted as a bare external import.
  • Before this fix, if any other package in the dependency tree required neotraverse@^0.6.x, npm would hoist that older copy to the project root. The prerender bundle (written to dist/.prerender/, outside node_modules/astro) would then resolve the bare import { forEach } from "neotraverse" to the hoisted 0.6.x copy — which doesn't export forEach — crashing the build. Bundling neotraverse ensures Astro's own copy is always used regardless of what's hoisted in the project.

Testing

  • No new tests added; the fix is a one-line config addition. Existing Content Layer integration tests cover the affected code paths and confirm no regression.

Docs

  • No docs update needed; this is an internal dependency resolution fix with no user-facing API changes.
withastro/astro

Changes

  • Fixes a crash in the Node adapter when a request arrives with a malformed port in the Host header (e.g. example.com:65536, example.com:8080:8080). The bad host made the request URL invalid, and the existing catch fallback rebuilt the URL from the same host and threw again.
  • buildRequestUrl (shared by createRequestFromNodeRequest and createRequest) now degrades in steps — full URL, origin only, then a server-controlled host (localhost, with the listening port when known) — so URL construction never throws.
  • parseHost now rejects a host with more than one hostname:port pair, which previously passed by inspecting only the first two colon-separated segments.

Testing

  • Unit tests in node.test.ts covering malformed hosts through createRequestFromNodeRequest (no throw, parseable URL) plus a valid max-port control, and a createRequest case asserting a duplicated-port host is rejected.
  • An end-to-end @astrojs/node test that drives a standalone server, sends a crafted Host over a raw socket, and asserts a follow-up request still succeeds.

Docs

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

Closes #17329

Changes

  • Cookies set via Astro.cookies.set() inside a custom 404.astro or 500.astro are now correctly included in the final response. Previously they were silently dropped.
  • Two bugs in mergeResponses (packages/astro/src/core/errors/default-handler.ts): (1) when both the original and error page had AstroCookies, the error page's cookies were appended to originalResponse.headers — an object already copied into newHeaders and no longer connected to the merged response — so they went nowhere; fixed by replacing the loop with originalCookies.merge(newCookies). (2) the seen-set guard that deduplicates merged headers treated set-cookie as a single-value header, blocking error-page cookies when the original response already set one; fixed by always appending set-cookie entries.

Testing

  • Added packages/astro/test/error-page-cookies.test.ts with three cases: error page cookies survive when the original page throws, error page cookies survive when no original cookies exist, and both middleware and 404 error page cookies are preserved together.

Docs

  • No docs update needed. This restores the behavior that Astro.cookies.set() is documented to provide; no API surface changed.
withastro/astro

Changes

  • @astrojs/vercel creates .vercel/output/server/ with a plain mkdirSync, so astro build crashes with EEXIST when that directory already exists, for example when two builds run against the same project root. This creates it with { recursive: true }, the same way the static/ directory one line above is already created.
  • It also awaits emptyDir(staticDir), which was fire-and-forget before and could race the copy calls that follow it.

Fixes #17568

Testing

The existing @astrojs/vercel test suite passes. Reproducing the race needs two overlapping builds sharing one project root, which the current integration harness has no way to set up, so I did not add a new test.

Docs

No docs changes. This is an internal bug fix with no change to the public API.

withastro/astro

Changes

  • Fixes fontProviders.googleicons() downloading the entire ~3.9MB Google Icons font instead of only the requested glyphs when experimental.glyphs contains more than one name. The root cause is a bug in unifont (unjs/unifont#336) where glyph names are joined with .join("") (no separator), producing an invalid icon_names query parameter that causes Google's API to silently return the full font. The workaround pre-joins multiple glyphs into a single comma-separated string before passing them to unifont, so unifont's .join("") produces the correct value.

Testing

  • Adds packages/astro/test/units/assets/fonts/googleicons-glyphs.test.ts covering the resolveFont call with multiple glyphs, a single glyph, undefined options, and an empty glyphs array — verifying the patching logic doesn't throw for any of these shapes.

Docs

  • No docs update needed; experimental.glyphs behavior is unchanged from the user's perspective — this restores the documented subsetting behavior.

Closes #17565


Last fetched:  | Scheduled refresh: Every Saturday

See Customizing GitHub Activity Pages to configure your own

Inspired by prs.atinux.com