Skip to content

AstroEco is Contributing…

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

withastro/astro

Reverts #17287

withastro/astro

Changes

  • Dynamic endpoint routes with a file extension (e.g. [...slug].png.ts) no longer fail with NoMatchingStaticPathFound during astro build when trailingSlash: "always" is set. stringifyParams() now mirrors the trailingSlashForPath() logic already used in route pattern generation: when a route is an endpoint with a file extension, trailing slash is forced to 'never', so generated paths (e.g. /og/foo.png) match the route pattern (e.g. /^\/og\/(.*?)\.png$/). The mismatch affected both ASCII and non-ASCII params.

Closes #17306

Testing

  • Added three unit tests in packages/astro/test/units/routing/get-params.test.ts covering:
    • Spread file-extension endpoint with non-ASCII params + trailingSlash: 'always' — path must not get a trailing slash and must match the route pattern.
    • Single dynamic file-extension endpoint ([name].json) with the same config.
    • Endpoint without a file extension still gets a trailing slash, confirming the fix is scoped correctly.

Docs

  • No docs update needed — this is a bug fix for existing static build behavior with no API surface change.
withastro/astro

Changes

  • Fixes CSS module class names not matching between the element and the injected <style> tag in astro dev when using vite.css.transformer: 'lightningcss' with content collections. Production builds were unaffected.
  • Root cause: getStylesForURL() re-imports CSS modules with ?inline appended to get the raw CSS string. Lightning CSS uses the full module ID (including ?inline) as the filename for scoped-name hashing, producing a different hash than the original import. The fix shares the dev-css plugin's existing cssContentCache (which holds already-processed CSS with correct hashes) with the content asset propagation plugin, so ?inline re-imports are avoided when the cache has the result.

Testing

  • Adds packages/astro/test/lightningcss-css-modules-content.test.ts — regression test that starts a dev server with lightningcss enabled, renders a content collection page, and asserts the scoped class name on the element appears in the injected <style> tag.

Docs

  • No docs update needed — this is a bug fix with no API or configuration changes.

Closes #17312

withastro/astro

Changes

This PR fixes a memory leak in the dev server. The listener was never cleaned at the end of the request.

Testing

Manually tested. I tried an integration test, but it was ugly and weird.

Docs

N/A

withastro/astro

Fixes #17265

Changes

  • Prevents Astro from inlining script chunks when module metadata reports dynamic imports, including external dynamic imports omitted from Rolldown chunk metadata.
  • Extracts the script inlining decision into testable helpers.

Testing

  • Adds unit coverage for external dynamic imports reported through module info while chunk.dynamicImports is empty.

Docs

  • No docs update needed; this restores expected build output behavior.
withastro/astro
## Changes

- Adds dependency crawling using `vitefu` in the `@astrojs/solid-js` integration to dynamically discover Solid packages and populate `noExternal` and `external` in the Vite configuration. This ensures that SolidJS package exports (e.g. packages declaring `"solid"` fields in their `exports`) are bundled/resolved correctly during SSR and client build.
- Casts `originalEmit` to `any` in `solid-component.test.ts` when forwarding calls from the monkey-patched `process.emit`. This bypasses TypeScript's overload resolution error where the union of all Node event names is not assignable to the specific `"worker"` signature.

## Testing

- Re-enabled and updated `describe('Solid component build')` test suite in [solid-component.test.ts](file:///packages/astro/test/solid-component.test.ts) (reverted `.skip`, removed `@ts-expect-error` annotations, and replaced outdated assertions).
- Verified that all 10 Solid component build tests successfully compile and pass.
- Verified that all doctype tests in [astro-doctype.test.ts](file:///packages/astro/test/astro-doctype.test.ts) pass successfully.

## Docs

- No documentation changes needed since these are internal dependency crawling improvements and test suite fixes.
withastro/astro

Summary

  • add an Astro-specific SatteriFeatures type that overrides the upstream smartPunctuation JSDoc
  • export the type so consumers see the corrected default in satteri({ features })

Fixes #17305.

Testing

  • corepack pnpm --filter @astrojs/prism build
  • corepack pnpm --filter @astrojs/internal-helpers build
  • corepack pnpm --filter @astrojs/markdown-satteri build
  • corepack pnpm --filter @astrojs/markdown-satteri test
  • corepack pnpm exec prettier packages/markdown/satteri/src/processor.ts packages/markdown/satteri/src/index.ts --check
  • git diff --check

Notes

AI-assisted. I manually reviewed the final diff and verification output.

withastro/astro

Changes

  • Extracts the logger type from APIContext to an exported AstroComponentLogger interface.
  • This allows developers to easily type their custom middleware or integration functions that use the logger.
  • Added a minor changeset.

Testing

  • The change is type-only and relies on TypeScript's compilation.
  • Verified by running pnpm run typecheck and pnpm run test:match "exports".
  • No runtime behavioral changes were made.

Docs

withastro/astro

Changes

  • Removes the dev server socket close listener after request handling completes.
  • Also removes the listener when the request signal aborts, preserving the disconnect behavior added in #17133 while avoiding listener buildup on reused sockets.
  • Adds a regression test that sends repeated successful dev requests over one keep-alive dispatcher and asserts no MaxListenersExceededWarning is emitted for socket close listeners.

Testing

  • pnpm --filter @astrojs/node... run build:ci
  • pnpm --filter astro run build:ci
  • pnpm --filter astro exec astro-scripts test test/request-signal.test.ts --strip-types
  • pnpm exec prettier --check packages/astro/src/vite-plugin-app/app.ts packages/astro/test/request-signal.test.ts packages/astro/test/fixtures/request-signal/src/pages/dev-signal-test.ts .changeset/clean-dev-socket-listeners.md

Docs

No docs update needed. This is internal dev-server listener cleanup and does not change the public API.

withastro/astro

Changes

Follow-up to #17187, which pre-bundled astro/virtual-modules/transitions.js in the Cloudflare adapter's server dev environment to stop a mid-request dep optimizer reload. The same class of bug (#17166 / #16853 / #16529) still fires for pages that use the astro:components virtual module (e.g. import { Code } from "astro:components").

  • The adapter's server optimizeDeps excludes astro:* virtual modules, so the real module behind that virtual, astro/components, is never in the boot-time include list.
  • It is therefore discovered by the SSR dep optimizer only at first render. On the first request after a cold optimizer cache, that late discovery triggers optimized dependencies changed. reloading mid-render, which the workerd module runner does not survive cleanly: components resolve react from node_modules while react-dom/server comes from a freshly re-optimized deps_ssr chunk. Two copies of React in one render throw Invalid hook call / Cannot read properties of null (reading 'useState') in every island, and the page returns 200 with the islands empty.
  • Fix: add astro/components to the server-environment optimizeDeps.include list, right after the existing astro/virtual-modules/transitions.js entry, so it is pre-bundled at boot and the mid-render reload never happens.

This is the same one-line shape as #17187, for a different late-discovered virtual-module target.

Testing

Reproduced on a real Astro 7 + @astrojs/cloudflare 14.1.1 + @astrojs/react site (React 19) that renders astro:components:

  • Stock adapter (bug): cold astro dev (rm -rf node_modules/.vite), then requesting routes across the reload window. The dev log shows dependency optimized: astro/componentsoptimized dependencies changed. reloading → repeated Invalid hook call and TypeError: Cannot read properties of null (reading 'useState'). Every route still returns 200 but React islands render empty.
  • Patched adapter (this PR): identical cold-cache procedure. Zero optimizer reloads after startup, zero hook errors, all islands render, and warm-cache reboots stay clean.

I verified this by packing the patched adapter and pinning it into the site via a pnpm override; the bug reproduces reliably without the patch and disappears with it.

Docs

No docs needed — this is an internal dev-server dependency-optimization detail with no user-facing API change.

withastro/starlight

Add Hostgrid help center site to the showcase.

Site: https://hostgrid.dev/help/

withastro/starlight

Removed broken link to ⁠ecoping.earth⁠. The domain appears to be expired/inactive, which poses a potential security risk for documentation users.

withastro/starlight

Changes

Adds HitKeep to the Starlight showcase with an 800x450 PNG thumbnail captured from a 1280x720 desktop viewport and resized per the contributing guide.

Validation

  • pnpm --filter starlight-docs build
  • pnpm exec prettier --check docs/src/components/showcase-sites.astro
  • pnpm --filter starlight-docs typecheck
withastro/astro

Changes

  • Adds a deferRender?: boolean option to the glob() loader. When true, renderable content entries (e.g. Markdown) skip eager rendering during content sync and instead use the same deferred-render path that .mdx files already use — rendering happens on demand at page build time via the Vite markdown plugin.
  • This resolves OOM crashes during astro build for large Markdown collections that use heavy rehype plugins like rehype-katex, where rendered HTML can be 70× larger than source. Closes #17301.
  • Removes the // todo: add an explicit way to opt in to deferred rendering comment that tracked this gap since the Content Layer was introduced.

Testing

  • Unit tests in glob-loader.test.ts cover eager rendering (default), deferred rendering when deferRender: true, and that non-renderable data entries are unaffected.
  • Also verified by running node --max-old-space-size=256 astro build against a 200-file KaTeX-heavy fixture. The build previously OOM'd; with deferRender: true it succeeds. Confirmed working by the issue reporter (@integrable).

Docs

withastro/astro

Closes #17297

Changes

  • A .html or /index.html suffixed request to a dynamic endpoint route (e.g. GET /api/items/123/status.html for src/pages/api/items/[id]/status.ts) no longer crashes dev with TypeError: Missing parameter: id.
  • The dev route matcher strips .html / /index.html when retrying unmatched requests, but getParams() only stripped .html for route.type === 'page'. For a matched endpoint, params came back {} and stringifyParams threw. getParams now applies the same fallback for non-page routes: if the pattern doesn't match the original pathname, retry with the suffix stripped. Endpoints that legitimately capture .html in a param (e.g. [path] matching /file.html) match on the original pathname and are unaffected.
  • Especially impactful under netlify dev, which probes .html / /index.html variants on any 404 — firing the crash for every dynamic API endpoint.

Testing

  • Added getParams unit tests covering .html and /index.html requests to a dynamic endpoint route, plus a guard asserting endpoints that capture .html in a param keep the suffix.

Docs

No docs update needed — this restores the routing behavior users already expect.

withastro/astro

Changes

This PR adds a new experimental option called dataStore. It allows to split the data into multiple chunks.

I also did some refactor, so that we can prepare different data sources e.g. sqlite. For this reason, the functions of the interface are also async.

Chunks are created when:

  • a chunk is bigger than 10Mb in weight
  • every 1000 entries

Testing

Added various tests for:

  • string chucking
  • data store chunking
  • integration
  • e2e

Docs

withastro/docs#14210

/cc @withastro/maintainers-docs for feedback!

withastro/astro

Changes

  • CSS url('data:image/...') data URIs no longer crash astro build with ENAMETOOLONG when tsconfig.json has compilerOptions.baseUrl set. The vite-plugin-config-alias CSS transform now skips any url() reference that starts with data:, since data URIs are inline content and never valid file paths to resolve.
  • The regression was introduced in v7 by the cssUrlRE matching added to the CSS transform handler (commit 4766f3716d). The baseUrl alias regex /^(?!\.*\/|\.*$|\w:)(.+)$/ was designed to exclude Windows drive letters but \w: only matches a single character before the colon, so data: (4 chars) slipped through and was passed to fs.statSync().

Closes #17293

Testing

  • Adds packages/astro/test/alias-css-url-data-uri.test.ts with a fixture that combines tsconfig.json baseUrl: "." and a CSS url() data URI — verifies the build completes without error and the data URI is preserved in output.

Docs

  • No docs update needed; this restores previously working behavior from v6.
withastro/astro

Closes #16119

Changes

  • Fixes a v6 regression where scoped CSS from components nested inside a client:only island was silently dropped in production builds. In dev mode everything worked fine, making the bug particularly hard to spot.
  • Root cause: the CSS deduplication logic in plugin-css.ts correctly marks a child component's CSS for deletion (it was already bundled during SSR for another page), but the client:only page never participated in SSR so it never received that CSS. The getParentClientOnlys walk would add the CSS to pagesToCss, but the deleted asset was already gone by the time inlineStylesheetsPlugin ran.
  • Fix: when the getParentClientOnlys walk finds a CSS entry that was deleted, inline the CSS content directly into pageData.styles from deletedCssAssets, bypassing the need for the asset to survive to inlineStylesheetsPlugin. Content-based deduplication prevents double-injecting styles that survived deletion normally.

Testing

  • Added packages/astro/test/client-only-child-styles.test.ts with a fixture covering two scenarios: a page using client:only (where the child's scoped styles must be recovered from deletedCssAssets) and a page using client:load directly (to confirm no regression there).

Docs

  • No docs update needed — this restores behavior that already worked in v5 and is expected to work per existing docs.
withastro/astro

Changes

  • Prevents prototype pollution in config merge by filtering proto/constructor/prototype keys
  • Fixes XSS in <script> and <style> elements by escaping </script> and </style> sequences in raw string children before marking as HTML-safe
  • Blocks cross-origin POST regardless of Content-Type to prevent CSRF bypass (defense-in-depth; CORS preflight already protects fetch)

Testing

  • Updated 2 CSRF test assertions to expect 403 instead of 200 for cross-origin JSON/octet-stream POSTs

Docs

  • No docs update needed; all changes are internal hardening with no user-facing API changes
withastro/astro

Changes

Both "Advanced Routing" and "Blog" Example Template pages presented missing spaces between the HTML tags, the file locations are respectively examples/advanced-routing/src/pages/index.astro and examples/blog/src/pages/index.astro.

Image provided below for Before and After.

Testing

Testing was made by editing the files and opening the URL in both Firefox and Chromium-based browsers and seeing if:

  1. The problem was present and persistent between different Browser engines.
  2. The patch worked.

Both showed to be true.

Docs

Unneeded, very small text changes.

Images

"‎examples/blog/src/pages/index.astro":

Before After
Blog Before Blog After

"examples/advanced-routing/src/pages/index.astro":

Before After
Routing Before Routing After
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.0.7

Patch Changes

  • #17317 437401e Thanks @ematipico! - Fixes a dev server memory leak which caused Node.js to emit warnings in the console.

  • #17299 1170b6d Thanks @astrobot-houston! - Fixes a dev server crash when a .html or /index.html suffixed request (such as those netlify dev probes as pretty-URL fallbacks) matched a dynamic endpoint route, causing a TypeError: Missing parameter error

  • #17316 ed92e31 Thanks @matthewp! - Fixes a build regression that could leave unresolved preload markers in inlined scripts with external dynamic imports

  • Updated dependencies [a77af9d, 4aa78d8]:

    • @astrojs/telemetry@3.3.3

@astrojs/cloudflare@14.1.2

Patch Changes

  • #17285 6929e40 Thanks @adamchal! - Fixes build-time image optimization ignoring a custom image service registered by an integration

    Previously, when using imageService: 'compile' or imageService: 'custom', a custom image service was only respected if it was set directly in the image.service option of astro.config. If an integration registered the service instead, images were silently optimized with the default Sharp service at build time. A custom image service now transforms your images at build time no matter how it was configured.

  • #17303 464c46e Thanks @jkomyno! - Prebundles astro/components and the <ClientRouter /> transition runtime modules in the dev server environment so pages using them no longer trigger a mid-session dep optimizer reload, which caused React "Invalid hook call" errors in islands on the first request after a cold cache

  • #17275 6a99600 Thanks @matthewp! - Fixes an issue where vars weren't available at build time. Now the adapter loads vars from the Wrangler config so astro:env public variables resolve at build time

  • Updated dependencies []:

    • @astrojs/underscore-redirects@1.0.3

@astrojs/telemetry@3.3.3

Patch Changes

withastro/astro

Closes #17283

Changes

  • The first browser to connect after astro dev starts no longer receives an immediate, unprompted full-reload. Previously, invalidateDataStore() unconditionally sent a full-reload HMR signal during the buildStart hook — before any client connected — causing the signal to queue and fire the moment the first WebSocket client arrived.
  • Adds a notifyClient option to invalidateDataStore() (default true). The buildStart call now passes { notifyClient: false }, preserving the module invalidation that prevents the content layer race condition (#12866) while skipping the client reload during startup.

Testing

  • Added packages/astro/test/units/content-layer/content-virtual-mod.test.ts — verifies that buildStart invalidates the data store module but does not send a full-reload to the client HMR channel.

Docs

  • No docs update needed; this is a dev-server behavior fix with no API or config changes.
withastro/astro

Changes

Follow-up to #17099: a custom image.service was only respected during build-time image generation (imageService: 'compile' and 'custom') when set directly in the user config. A service registered by an integration via updateConfig() was silently replaced with Sharp, because the adapter's astro:config:setup runs before all integrations. The service is now resolved against the final config in astro:config:done.

Testing

  • New integration-defined-image-service.test.ts covers both modes with the service registered by an integration.
  • Existing image service tests pass unchanged.

Docs

Not required. Existing docs assumes this works.

withastro/astro

Changes

  • <Picture inferSize> with remote URLs no longer fails with FailedToFetchRemoteImageDimensions on rate-limiting servers (e.g. Wikimedia HTTP 429). The Picture component calls getImage() once per output format, and each call was independently invoking inferRemoteSize() — firing 2–4 HTTP requests to the same URL in rapid succession.
  • Fix: resolve remote dimensions once in Picture.astro before the getImage() loop, then pass explicit width/height (dropping inferSize) to each call. No global caches — the result is scoped to the single component render, matching the approach recommended by @matthewp.

Closes #17263

Testing

  • Covered by the existing core-image-infersize.test.ts suite, which includes a Picture component works case with inferSize in dev mode and passes without changes.
  • The specific failure mode (HTTP 429 from a rate-limiting server) is not easily reproducible in CI without a live server, and was verified manually by the reporter.

Docs

  • No docs update needed — inferSize behavior on <Picture> is unchanged from the user's perspective; this fixes a reliability regression.
withastro/astro

Changes

  • Fixes Image and Picture component layout styles being missing in astro dev when JavaScript is disabled. The dev CSS pipeline was caching content by raw module ID (with \0 prefix) in the transform hook, but looking it up via collected.id — the wrapId()-transformed version (/@id/__x00__...) — causing a cache miss for virtual CSS modules and producing empty <style> tags. Switching the lookup to collected.idKey (the raw ID) aligns both sides of the cache.

Testing

  • Adds packages/astro/test/units/dev/dev-css-virtual-modules.test.ts with three unit tests covering: wrapId() transformation behavior for virtual module IDs, the no-op behavior for filesystem paths, and the cache key mismatch that the fix resolves.

Docs

  • No docs update needed — this is a dev-mode bug fix with no API surface change.

Closes #17267

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

Patch Changes

  • #3911 1686ecc Thanks @timothyjordan! - Keeps keyboard focus inside the mobile menu while it is open, preventing focus moving to hidden interactive elements in page content.
withastro/astro

Fixes #16790

Changes

  • astro:env public variables defined under vars in a Wrangler config (wrangler.toml/.json/.jsonc) now resolve when imported from astro:env/client and astro:env/server. Previously only .dev.vars was loaded into the environment, so public vars from the Wrangler config were inlined as undefined at build time (only getSecret worked).
  • The adapter now resolves the effective env in astro:config:done via wrangler's unstable_readConfig + unstable_getVarsForDev, which merges config vars with .dev.vars/.dev.vars.<env>/.env overrides exactly as wrangler dev does (respecting CLOUDFLARE_ENV), and assigns the result to process.env. This replaces the previous hand-rolled .dev.vars reader, so there's a single source of truth that matches Wrangler's own precedence.

Testing

  • Removed the manual process.env.API_URL/process.env.PORT overrides from the astro-env SSR tests. Those overrides were masking the bug; the tests now rely on the adapter loading vars from the fixture's wrangler.jsonc, exercising the real code path for build and dev. The existing secret/action secret cases continue to cover .dev.vars loading through the unified path.

Docs

  • No docs update needed; this makes the adapter match the already-documented astro:env behavior.
withastro/astro

Changes

  • Adds a render() overload for LiveDataEntry<LiveLoaderDataType<C>> to packages/astro/templates/content/types.d.ts. Previously, the only overload covered entries from DataEntryMap (regular content collections). When a project only uses live.config.ts, DataEntryMap is empty, so keyof DataEntryMap resolves to never and render() rejects any live entry with a TypeScript error.
  • The new overload mirrors the pattern already used by getLiveEntry and getLiveCollection. Projects with only content.config.ts are unaffected — LiveContentConfig resolves to never so the overload is inert.

Closes #16688

Testing

  • No new test added — the bug is in a .d.ts type template; integration-level verification (astro sync + astro check) is covered by the existing live loaders and content collection type test suites, all of which continue to pass.

Docs

  • No docs update needed. This fixes a missing type overload to match already-documented runtime behavior.
withastro/astro

Changes

  • Island component paths (client:component-pathmetadata.componentUrl) now resolve extensionless relative imports (e.g. import { Counter } from '../components/Counter') to the real file on disk, probing Vite's default extension order and then directory index files. Previously the path stayed extensionless, so the include/exclude globs of JSX renderer integrations (e.g. react({ include: ['**/react/*.tsx'] })) could never match it.
  • This is what fixes the "Invalid hook call" warning. Because the extensionless path never matched the include glob, the React renderer declined the component, and Astro asked the MDX renderer next — which tests a candidate by calling it as a plain function, so any useState inside triggered React 19's warning. Now the glob matches, React claims the component, and MDX never probes it. (With multiple JSX frameworks configured, the same mismatch instead hard-failed with "Unable to render" — also fixed.)
  • Fixes #16767

Testing

  • New test/units/util/resolve-path.test.ts covering extension probing in Vite's order, directory index resolution, the existing .jsx.tsx remap, and pass-through of extension-ful, bare, and # subpath specifiers (all fail without the fix)
  • New multiple-jsx-renderers fixture page using an extensionless import matched by an include glob — the build hard-fails on it without the fix

Docs

  • No docs update needed — this makes behavior match what the integration docs already show (include globs written with file extensions).
withastro/astro

Svelte 5 renamed its internal SSR prop from $$payload to $$renderer starting in a newer patch (tracked in fix(svelte): detect Svelte components with renamed renderer prop #14433, which updated the Svelte renderer). That PR correctly updated @astrojs/svelte, but the Solid renderer has its own copy of the same Svelte-exclusion check and was not updated at the same time.

Impact: users who have both @astrojs/solid-js and @astrojs/svelte installed, and whose Svelte version compiles components with $$renderer, will see those Svelte components rendered as empty strings by the Solid renderer instead of being handed off to the Svelte renderer.

Fix: mirror the same two-prop check already used in @astrojs/svelte:

if (componentStr.includes('$$payload') || componentStr.includes('$$renderer')) return false; 
withastro/astro

Fixes #16078

Changes

  • "Go To References" invoked from a .ts file now finds usages inside .astro files that are reached through Astro.locals.*. Previously only .astro files with an explicit frontmatter import were discovered; a page using Astro.locals.utils.toUpper() was silently missed.
  • The @astrojs/ts-plugin now injects the installed Astro package's env.d.ts and astro-jsx.d.ts into the TypeScript program, mirroring the language server's addAstroTypes(). Without these the Astro global is undeclared, so the type chain through Astro.locals can't resolve and references aren't found. (.astro files themselves already enter the program via Volar's external-files mechanism, so no file-discovery change is needed.)
  • Passes includeScripts: false / includeStyles: false to convertToTSX() (matching the language server) so <script>/<style> bodies are no longer wrapped in {() => { ... }} arrow functions, where import declarations are syntactically invalid and pollute the virtual file.

Known limitation

References to symbols imported inside <script> tags still won't appear via the ts-plugin. Making script content reference-searchable requires getExtraServiceScripts(), which Volar explicitly does not support in the TS-plugin path (decorateLanguageServiceHost.js logs getExtraServiceScripts() is not available in TS plugin.). The Astro language server handles that case; the ts-plugin cannot without upstream Volar changes.

Note on verification

This fix ships in @astrojs/ts-plugin, which the Astro VS Code extension bundles (astro-ts-plugin-bundle, registered via typescriptServerPlugins). When the extension is installed, tsserver loads the bundled plugin, so installing a preview of the npm package into a project's node_modules does not exercise the fix. End-to-end verification requires an extension build (or disabling the extension and relying solely on the tsconfig plugins entry with the workspace TypeScript).

Testing

  • Adds test/units/astro-types.test.mts: builds the .astro.tsx output for a template that only uses Astro.locals.utils.toUpper(), then runs findReferences through the raw TypeScript language service. Asserts the reference is missed without type injection and found once addAstroTypes runs — a direct regression test for the reported behavior.

Docs

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

Closes #17206

Changes

  • The Container API no longer emits a false deprecation warning for markdown.gfm and markdown.smartypants when neither option was set by the user.
  • Root cause: AstroContainer.create() and createFromManifest() passed ASTRO_CONFIG_DEFAULTS directly to validateConfig(). Because ASTRO_CONFIG_DEFAULTS includes gfm: true and smartypants: true, the warnDeprecatedMarkdownOptions check saw them as user-specified values. Normal builds pass raw user config (without defaults pre-applied), so the warning never fires there. The fix strips those two keys from the markdown defaults before passing to validateConfig().

Testing

  • Added packages/astro/test/units/render/container-deprecation.test.ts: asserts that AstroContainer.create() with default config does not log the markdown.gfm/smartypants deprecation warning.

Docs

  • No docs update needed — this is a false-positive warning fix with no API or behavior change for users.
withastro/astro

Fixes #15627

Changes

  • A <script> inside a component rendered through Astro.slots.render() now stays at its original position instead of being hoisted to the start of the slot output (sometimes escaping its parent element entirely). This regressed in #15147 and broke Starlight components (withastro/starlight#3712) as well as any CSS relying on :first-child/sibling selectors.
  • SlotString now keeps its content as an ordered chunks stream with scripts inline, resolved and deduplicated lazily at stringify time — matching how the main render path already handles instructions.

Testing

  • Adds "Scripts rendered via Astro.slots.render() preserve their position", asserting the script renders inside its <li>/<ol> rather than before them.
  • Verified the existing #13847 test ("Scripts in Fragment slots are processed when another slot is unused") still passes alongside the new positional behavior.

Docs

  • No docs update needed; this restores previously documented <script> positioning behavior.
withastro/astro

Changes

  • create-astro now respects HTTP_PROXY/HTTPS_PROXY environment variables when downloading templates. When proxy env vars are set, the CLI re-execs itself with Node.js's --use-env-proxy flag so that native fetch() (used by @bluwy/giget-core) routes requests through the configured proxy.
  • Requires no new dependencies. Degrades gracefully on Node.js < v22.21.0 — older versions get the same behavior as before. The flag is available in Node.js v22.21.0+ and v24.5.0+.

Closes #13684

Testing

  • Added packages/create-astro/test/units/proxy.test.ts with two cases: one verifying that HTTPS_PROXY is respected (a non-existent proxy causes a connection error, proving the proxy was used), and one verifying normal operation is unaffected when no proxy env vars are set.

Docs

  • No docs update needed; this restores previously expected behavior with no new APIs or config options.
withastro/astro

Changes

  • Adds a format option to PaginateOptions that accepts a (url: string) => string callback. When provided, it is applied to all pagination URLs (current, next, prev, first, last) after they are constructed.
  • This is a non-breaking, opt-in addition — default behavior is completely unchanged. Users deploying to static file servers without URL rewrite rules can now use this to append .html (or apply any other transformation) to pagination URLs generated by paginate().
paginate(items, {
  pageSize: 10,
  format: (url) => `${url}.html`,
})

Closes #13604

Testing

  • Added 3 new describe blocks (8 test cases) to packages/astro/test/units/render/paginate.test.ts covering: format applied to all URL properties, format skipped for undefined URLs, format applied after base path is prepended, and no regression when format is omitted.

Docs

  • The new format option is documented inline via JSDoc on PaginateOptions. A docs-site update to the paginate() reference may be warranted to surface this option for users hitting 404s on static file servers.

withastro/docs#14201

@withastro/maintainers-docs for feedback

withastro/astro

Closes #17135

Changes

  • getPackage now imports packages using the absolute path returned by require.resolve() (converted to a file URL via pathToFileURL) instead of the bare package name. Previously, require.resolve() was correctly scoped to the project's cwd, but the subsequent await import(packageName) resolved from astro's own install location — causing astro check to fail when astro lives in a virtual store (e.g. pnpm) outside the project directory tree.
  • Affects both import sites in getPackage: the initial load and the post-install load.

Testing

  • Added packages/astro/test/units/cli/install-package.test.ts: creates a temporary project directory with a fake package in its node_modules, then verifies getPackage can find and load it when passed that directory as cwd.

Docs

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

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

Releases

astro@7.0.6

Patch Changes

  • #17261 79aa99c Thanks @astrobot-houston! - Fixes a false deprecation warning for markdown.gfm and markdown.smartypants when using the Container API

  • #17247 f94280d Thanks @chatman-media! - Fixes route generation throwing "Missing parameter" (or silently dropping the segment) when a dynamic param's value is 0. The generator used truthy checks instead of checking for undefined, so paginate(posts, { params: { categoryId: 0 } }) would crash even though 0 is a perfectly valid param value.

  • #17278 6f11739 Thanks @astrobot-houston! - Fixes missing CSS for virtual style modules (e.g., responsive image layout styles) in dev mode when JavaScript is disabled

  • #17250 0b30b35 Thanks @matthewp! - Fixes the security.checkOrigin check so it is applied consistently to Astro Actions and on-demand endpoints, regardless of how the request pipeline is composed. Previously, the origin check could be skipped in the composable astro/hono pipeline depending on the order of the middleware() primitive (or when it was omitted).

  • #17274 8c3579b Thanks @astrobot-houston! - Fixes missing render() type overload for live collection entries. Previously, calling render() on a LiveDataEntry produced a TypeScript error when using only live.config.ts without a content.config.ts.

  • #17257 4208297 Thanks @astrobot-houston! - Fixes astro check failing to find @astrojs/check and typescript when astro is installed in a directory outside the project tree (e.g. pnpm virtual store)

  • #17272 b428648 Thanks @matthewp! - Fixes island component paths so that extensionless imports (e.g. import { Counter } from '../components/Counter') resolve to the real file on disk, matching Vite's extension order and directory index resolution. This makes the include/exclude options of JSX renderer integrations (React, Preact, Solid) match components imported without a file extension, and removes the spurious React 19 "Invalid hook call" warning logged on every request in dev when include was set alongside another JSX renderer

  • #17279 2aeaa44 Thanks @astrobot-houston! - Fixes a bug where <Picture inferSize> with a remote image could fail with FailedToFetchRemoteImageDimensions when the image server rate-limits requests (e.g. HTTP 429). Remote dimensions are now resolved once per render instead of once per output format.

  • #17251 5240e26 Thanks @matthewp! - Hardens the handling of attribute rendering when using with custom elements.

  • #17248 429bd62 Thanks @astrobot-houston! - Fixes a crash when using Astro's getViteConfig with Vitest browser mode (e.g., Storybook vitest runner). Astro now skips dev server setup inside Vitest, preventing errors.

  • #17260 14524c0 Thanks @matthewp! - Fixes a regression where a <script> inside a component rendered through Astro.slots.render() was hoisted out of its original position instead of staying next to its component content

  • Updated dependencies [eb6f97e]:

    • @astrojs/internal-helpers@0.10.1
    • @astrojs/markdown-remark@7.2.1
    • @astrojs/markdown-satteri@0.3.3

create-astro@5.2.2

Patch Changes

  • #17259 ed6bea5 Thanks @astrobot-houston! - Fixes proxy support by respecting HTTP_PROXY and HTTPS_PROXY environment variables when downloading templates. On Node.js v22.21.0+ and v24.5.0+, create-astro now automatically enables the --use-env-proxy flag so that native fetch() routes requests through the configured proxy.

@astrojs/cloudflare@14.1.1

Patch Changes

  • Updated dependencies [eb6f97e]:
    • @astrojs/internal-helpers@0.10.1
    • @astrojs/underscore-redirects@1.0.3

@astrojs/markdoc@2.0.3

Patch Changes

  • Updated dependencies [eb6f97e]:
    • @astrojs/internal-helpers@0.10.1

@astrojs/mdx@7.0.2

Patch Changes

  • Updated dependencies [eb6f97e]:
    • @astrojs/internal-helpers@0.10.1
    • @astrojs/markdown-remark@7.2.1

@astrojs/netlify@8.1.1

Patch Changes

  • Updated dependencies [eb6f97e]:
    • @astrojs/internal-helpers@0.10.1
    • @astrojs/underscore-redirects@1.0.3

@astrojs/node@11.0.2

Patch Changes

  • #17252 eb6f97e Thanks @matthewp! - Fixes trailing-slash handling for request paths that begin with a backslash

    With trailingSlash: 'always', the standalone Node server could append a trailing slash to a request path that begins with a backslash (for example /\example.com/foo) and echo that path back in the Location header of a 301 response. Because browsers resolve a leading \ the same way as /, the resulting Location could point off-site.

    Such paths are now recognized as internal paths, matching the existing handling for paths that begin with //, so they are no longer rewritten with a trailing slash.

  • Updated dependencies [eb6f97e]:

    • @astrojs/internal-helpers@0.10.1

@astrojs/preact@6.0.1

Patch Changes

  • Updated dependencies [eb6f97e]:
    • @astrojs/internal-helpers@0.10.1

@astrojs/react@6.0.1

Patch Changes

  • Updated dependencies [eb6f97e]:
    • @astrojs/internal-helpers@0.10.1

@astrojs/solid-js@7.0.1

Patch Changes

  • #17270 0142964 Thanks @FrancoKaddour! - Fix @astrojs/solid-js incorrectly claiming Svelte 5 components compiled with the newer $$renderer prop (instead of the legacy $$payload). Projects mixing Solid and Svelte could see Svelte components silently rendered as empty strings by the Solid renderer.

@astrojs/vercel@11.0.2

Patch Changes

  • Updated dependencies [eb6f97e]:
    • @astrojs/internal-helpers@0.10.1

@astrojs/internal-helpers@0.10.1

Patch Changes

  • #17252 eb6f97e Thanks @matthewp! - Fixes trailing-slash handling for request paths that begin with a backslash

    With trailingSlash: 'always', the standalone Node server could append a trailing slash to a request path that begins with a backslash (for example /\example.com/foo) and echo that path back in the Location header of a 301 response. Because browsers resolve a leading \ the same way as /, the resulting Location could point off-site.

    Such paths are now recognized as internal paths, matching the existing handling for paths that begin with //, so they are no longer rewritten with a trailing slash.

@astrojs/language-server@2.16.11

Patch Changes

@astrojs/ts-plugin@1.10.10

Patch Changes

  • #17269 c72d4f2 Thanks @matthewp! - Fixes "Go To References" from .ts files missing usages inside .astro files that are reached through Astro.locals. The plugin now injects Astro's ambient types so type chains like Astro.locals.utils.toUpper() resolve, matching the language server.

@astrojs/markdown-remark@7.2.1

Patch Changes

  • Updated dependencies [eb6f97e]:
    • @astrojs/internal-helpers@0.10.1

@astrojs/markdown-satteri@0.3.3

Patch Changes

  • Updated dependencies [eb6f97e]:
    • @astrojs/internal-helpers@0.10.1
withastro/astro

Changes

  • Prefetch hover listeners now attach to links injected by server:defer components. Previously, onPageLoad() scanned for <a> tags once on page load, but server islands resolve asynchronously after that scan completes — so their links were never registered.
  • Adds a MutationObserver inside onPageLoad() that watches for dynamically added DOM nodes. When a new anchor (or element containing one) is detected, the prefetch callback re-runs. The existing listenedAnchors WeakSet prevents duplicate listener attachment.

Closes #13297

Testing

  • No automated tests added — the prefetch module is entirely client-side browser code (document, MutationObserver, event listeners) with no existing test infrastructure in the repo. Fix was verified manually and confirmed by the reporter.

Docs

  • No docs update needed; this is a bug fix restoring expected behavior for an existing feature combination.
withastro/astro

Changes

  • Fixes VS Code syntax highlighting breaking when @property (or any CSS construct with angle brackets like syntax: "<color>") is used inside a <style> block. Previously, the </style> closing tag and all subsequent <style> and <script> blocks would be incorrectly tokenized.
  • Updates all 7 style injection patterns in astro.tmLanguage.src.yaml from a single begin/end approach to the same two-pattern begin/end (single-line) + begin/while (multi-line) approach already used by script injection patterns since PR #15109. The while pattern is evaluated at the start of each line before child patterns run, so </style> is always detected regardless of the embedded CSS grammar's internal state.

Testing

  • Adds packages/language-tools/vscode/test/grammar/fixtures/style/at-property.astro — a new grammar snapshot fixture verifying that all blocks are correctly scoped when @property with a syntax: "<color>" descriptor is present.
  • Updates the dummy CSS grammar (css.tmLanguage-dummy.json) to include selector patterns that simulate VS Code's real CSS grammar behavior, making the existing snapshot tests more realistic.
  • Updates expression.astro.snap and style.astro.snap snapshots to reflect that leading whitespace before </style> is no longer scoped as CSS content (matches the existing script behavior).

Docs

No docs update needed — this is a VS Code extension grammar fix with no user-facing API changes.

Closes #16751

withastro/astro

Summary

With trailingSlash: 'always', the standalone @astrojs/node server could append a trailing slash to a request path beginning with a backslash (e.g. /\example.com/foo) and echo it back in the Location header of a 301. Since browsers resolve a leading \ like /, that Location could point off-site.

isInternalPath now folds backslashes to forward slashes before comparing the prefix, so /\host is recognized as an internal path just like //host and is no longer rewritten with a trailing slash (it falls through to a 404). The core trailing-slash handlers already normalized this via URL parsing; this brings the raw-request path in the Node adapter in line.

Testing

  • Unit tests for isInternalPath covering backslash prefixes.
  • Integration test in the Node adapter using a raw request line (a literal backslash, which URL parsers would otherwise normalize) asserting a 404 with no Location header.
withastro/astro

Changes

  • Applies the existing attribute name validation to custom HTML element rendering during SSR. Attribute names containing characters invalid per the HTML spec (" ' > / = or whitespace) are now dropped instead of interpolated raw, preventing unsafe HTML output.

Testing

  • Adds renderHTMLElement rejects invalid attribute keys test suite covering malicious keys (event handler injection, script tag injection) and valid keys (namespaced, data-*).

Docs

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

Changes

  • Applies the security.checkOrigin check at the request dispatch points (Astro Actions and on-demand endpoints/pages), so it holds consistently regardless of how the composable astro/hono pipeline is ordered. Previously the check only ran inside the middleware() primitive, so it could be skipped depending on primitive order — or when middleware() was omitted entirely.
  • Extracts the shared origin-check logic into core/app/origin-check.ts (a predicate + response builder) consumed by the pipeline middleware, the actions dispatch, and the pages() endpoint dispatch. No behavior change to the classic pipeline: the check remains a no-op at the dispatch sinks when the middleware already ran, for prerendered/static routes, for safe methods, and when checkOrigin is disabled.

Testing

  • Adds action-origin-check.test.ts: composes a Hono app with actions() before middleware() and asserts a cross-origin action request is rejected before the handler runs, while same-origin succeeds.
  • Adds pages-origin-check.test.ts: composes a Hono app with pages() and no middleware() and asserts a cross-origin POST to an on-demand endpoint is rejected before the handler runs, while same-origin succeeds.

Docs

  • No docs update needed; existing security.checkOrigin behavior is unchanged from the user's perspective.
withastro/astro

Changes

Our packages still had the alpha versions in their peerDependencies fields. This PR fixes the problem by using the non-alpha packages.

Testing

Green CI.

Docs

N/A

withastro/astro

Closes #16275

Changes

  • When process.env.VITEST is set, configureServer in vite-plugin-astro-server now returns early instead of setting up Astro's dev server middleware. Vitest's browser mode (used by the Storybook vitest runner) boots its own Vite server, which triggers this hook — but its module evaluator doesn't implement wrapDynamicImport, causing a TypeError when Astro's SSR runner tries to load createAstroServerApp via dynamic imports.
  • The dev server middleware (SSR handler, prerender handler, trailing-slash redirects) is only meaningful for astro dev, so skipping it in Vitest contexts is safe.

Testing

  • Added packages/astro/test/units/vite-plugin-astro-server/vitest-guard.test.ts with two cases: one confirming the early return when VITEST is set (using a bare fake server with no environments), and one confirming normal execution proceeds when VITEST is absent.

Docs

  • No docs update needed — this is a bug fix with no user-facing API changes.

Last fetched:  | Scheduled refresh: Every Saturday

See Customizing GitHub Activity Pages to configure your own

Inspired by prs.atinux.com