diff --git a/.changeset/all-badgers-peel.md b/.changeset/all-badgers-peel.md
new file mode 100644
index 000000000000..358c66daf1c5
--- /dev/null
+++ b/.changeset/all-badgers-peel.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Fixes `getRelativeLocaleUrl`, `getAbsoluteLocaleUrl`, and `getAbsoluteLocaleUrlList` to strip trailing slashes when `trailingSlash: 'never'` is configured
diff --git a/.changeset/itchy-snails-march.md b/.changeset/itchy-snails-march.md
new file mode 100644
index 000000000000..5e3f74bdef28
--- /dev/null
+++ b/.changeset/itchy-snails-march.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Fixes CSS from `client:only` islands leaking to unrelated pages when Rollup bundles non-CSS-importing modules into the same chunk as CSS-importing modules
diff --git a/.changeset/long-cloths-smoke.md b/.changeset/long-cloths-smoke.md
new file mode 100644
index 000000000000..d9579ab1f022
--- /dev/null
+++ b/.changeset/long-cloths-smoke.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Fixes HMR not triggering for files inside the `src/middleware/` directory during dev
diff --git a/packages/astro/src/core/build/plugins/plugin-css.ts b/packages/astro/src/core/build/plugins/plugin-css.ts
index 9da995748592..2f1103f7a0a2 100644
--- a/packages/astro/src/core/build/plugins/plugin-css.ts
+++ b/packages/astro/src/core/build/plugins/plugin-css.ts
@@ -177,6 +177,11 @@ function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] {
// client:only component and if so, add its CSS to the page it belongs to.
if (this.environment?.name === ASTRO_VITE_ENVIRONMENT_NAMES.client) {
for (const id of Object.keys(chunk.modules)) {
+ // Only walk from CSS modules to find client:only parents. When Rollup
+ // merges unrelated modules into the same chunk, walking from every module
+ // would incorrectly attribute the chunk's CSS to pages reached through
+ // modules that have no CSS dependency.
+ if (!isCSSRequest(id)) continue;
for (const pageData of getParentClientOnlys(id, this, internals)) {
for (const importedCssImport of meta.importedCss) {
const cssToInfoRecord = (pagesToCss[pageData.moduleSpecifier] ??= {});
diff --git a/packages/astro/src/core/middleware/vite-plugin.ts b/packages/astro/src/core/middleware/vite-plugin.ts
index 2de16d29232b..86848c9111cc 100644
--- a/packages/astro/src/core/middleware/vite-plugin.ts
+++ b/packages/astro/src/core/middleware/vite-plugin.ts
@@ -20,6 +20,13 @@ export const MIDDLEWARE_MODULE_ID = 'virtual:astro:middleware';
const MIDDLEWARE_RESOLVED_MODULE_ID = '\0' + MIDDLEWARE_MODULE_ID;
const NOOP_MIDDLEWARE = '\0noop-middleware';
+export function isMiddlewarePath(relativePath: string): boolean {
+ return (
+ relativePath.startsWith(`${MIDDLEWARE_PATH_SEGMENT_NAME}.`) ||
+ relativePath.startsWith(`${MIDDLEWARE_PATH_SEGMENT_NAME}/`)
+ );
+}
+
export function vitePluginMiddleware({ settings }: { settings: AstroSettings }): VitePlugin {
let resolvedMiddlewareId: string | undefined = undefined;
const hasIntegrationMiddleware =
@@ -43,8 +50,7 @@ export function vitePluginMiddleware({ settings }: { settings: AstroSettings }):
// Check if the changed file is a middleware file under srcDir
if (!normalizedPath.startsWith(normalizedSrcDir)) return;
const relativePath = normalizedPath.slice(normalizedSrcDir.length);
- // Dot ensures we match "middleware.ts" but not e.g. "middleware-utils.ts"
- if (!relativePath.startsWith(`${MIDDLEWARE_PATH_SEGMENT_NAME}.`)) return;
+ if (!isMiddlewarePath(relativePath)) return;
for (const name of [
ASTRO_VITE_ENVIRONMENT_NAMES.ssr,
diff --git a/packages/astro/src/i18n/index.ts b/packages/astro/src/i18n/index.ts
index 8e963eb4dc33..f9a1c85231fa 100644
--- a/packages/astro/src/i18n/index.ts
+++ b/packages/astro/src/i18n/index.ts
@@ -1,4 +1,8 @@
-import { appendForwardSlash, joinPaths } from '@astrojs/internal-helpers/path';
+import {
+ appendForwardSlash,
+ joinPaths,
+ removeTrailingForwardSlash,
+} from '@astrojs/internal-helpers/path';
import type { RoutingStrategies } from '../core/app/common.js';
import type { SSRManifest } from '../core/app/types.js';
import { shouldAppendForwardSlash } from '../core/build/util.js';
@@ -106,7 +110,7 @@ export function getLocaleRelativeUrl({
if (shouldAppendForwardSlash(trailingSlash, format)) {
relativePath = appendForwardSlash(joinPaths(...pathsToJoin));
} else {
- relativePath = joinPaths(...pathsToJoin);
+ relativePath = removeTrailingForwardSlash(joinPaths(...pathsToJoin));
}
if (relativePath === '') {
diff --git a/packages/astro/test/client-only-css-chunk-leak.test.ts b/packages/astro/test/client-only-css-chunk-leak.test.ts
new file mode 100644
index 000000000000..fcffba736893
--- /dev/null
+++ b/packages/astro/test/client-only-css-chunk-leak.test.ts
@@ -0,0 +1,39 @@
+import assert from 'node:assert/strict';
+import { before, describe, it } from 'node:test';
+import { load as cheerioLoad } from 'cheerio';
+import { type Fixture, loadFixture } from './test-utils.ts';
+
+describe('client:only CSS chunk leak', () => {
+ let fixture: Fixture;
+
+ before(async () => {
+ fixture = await loadFixture({
+ root: './fixtures/client-only-css-chunk-leak/',
+ });
+ await fixture.build();
+ });
+
+ it('does not leak CSS to pages that do not use CSS-importing client:only components', async () => {
+ const html = await fixture.readFile('/about/index.html');
+ const $ = cheerioLoad(html);
+
+ const stylesheets = $('link[rel=stylesheet]');
+ // The about page only uses CurrentTime (no CSS imports).
+ // It should have no stylesheets from the shared chunk.
+ assert.equal(stylesheets.length, 0, 'About page should have no stylesheet links');
+ });
+
+ it('includes CSS on the page that uses the CSS-importing client:only component', async () => {
+ const html = await fixture.readFile('/index.html');
+ const $ = cheerioLoad(html);
+
+ const stylesheets = await Promise.all(
+ $('link[rel=stylesheet]').map((_, el) => {
+ return fixture.readFile(el.attribs.href);
+ }),
+ );
+ const css = stylesheets.join('');
+
+ assert.match(css, /\.heavy-widget/, 'Home page should include .heavy-widget CSS');
+ });
+});
diff --git a/packages/astro/test/fixtures/client-only-css-chunk-leak/astro.config.mjs b/packages/astro/test/fixtures/client-only-css-chunk-leak/astro.config.mjs
new file mode 100644
index 000000000000..9c9e4c9115c3
--- /dev/null
+++ b/packages/astro/test/fixtures/client-only-css-chunk-leak/astro.config.mjs
@@ -0,0 +1,23 @@
+import { defineConfig } from 'astro/config';
+import react from '@astrojs/react';
+
+export default defineConfig({
+ integrations: [react()],
+ build: { inlineStylesheets: 'never' },
+ vite: {
+ build: {
+ rollupOptions: {
+ output: {
+ // Force StyledPanel (which imports CSS) and formatLabel (a pure utility)
+ // into the same chunk. This simulates what Rollup's default heuristics
+ // do naturally in large apps.
+ manualChunks(id) {
+ if (id.includes('StyledPanel') || id.includes('formatLabel')) {
+ return 'shared-utils';
+ }
+ },
+ },
+ },
+ },
+ },
+});
diff --git a/packages/astro/test/fixtures/client-only-css-chunk-leak/package.json b/packages/astro/test/fixtures/client-only-css-chunk-leak/package.json
new file mode 100644
index 000000000000..1e0d3ee844cd
--- /dev/null
+++ b/packages/astro/test/fixtures/client-only-css-chunk-leak/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "@test/client-only-css-chunk-leak",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "astro": "workspace:*",
+ "@astrojs/react": "workspace:*",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0"
+ }
+}
diff --git a/packages/astro/test/fixtures/client-only-css-chunk-leak/src/components/CurrentTime.tsx b/packages/astro/test/fixtures/client-only-css-chunk-leak/src/components/CurrentTime.tsx
new file mode 100644
index 000000000000..5cd2bef1a6f8
--- /dev/null
+++ b/packages/astro/test/fixtures/client-only-css-chunk-leak/src/components/CurrentTime.tsx
@@ -0,0 +1,5 @@
+import { formatLabel } from './formatLabel';
+
+export default function CurrentTime() {
+ return {formatLabel('time')};
+}
diff --git a/packages/astro/test/fixtures/client-only-css-chunk-leak/src/components/HeavyWidget.tsx b/packages/astro/test/fixtures/client-only-css-chunk-leak/src/components/HeavyWidget.tsx
new file mode 100644
index 000000000000..55cf4404c412
--- /dev/null
+++ b/packages/astro/test/fixtures/client-only-css-chunk-leak/src/components/HeavyWidget.tsx
@@ -0,0 +1,6 @@
+import StyledPanel from './StyledPanel';
+import { formatLabel } from './formatLabel';
+
+export default function HeavyWidget() {
+ return {formatLabel('Widget')};
+}
diff --git a/packages/astro/test/fixtures/client-only-css-chunk-leak/src/components/StyledPanel.css b/packages/astro/test/fixtures/client-only-css-chunk-leak/src/components/StyledPanel.css
new file mode 100644
index 000000000000..43a37e9ce1b3
--- /dev/null
+++ b/packages/astro/test/fixtures/client-only-css-chunk-leak/src/components/StyledPanel.css
@@ -0,0 +1 @@
+.heavy-widget { color: red; font-size: 72px; background: limegreen; padding: 2rem; }
diff --git a/packages/astro/test/fixtures/client-only-css-chunk-leak/src/components/StyledPanel.tsx b/packages/astro/test/fixtures/client-only-css-chunk-leak/src/components/StyledPanel.tsx
new file mode 100644
index 000000000000..a5721e37dd92
--- /dev/null
+++ b/packages/astro/test/fixtures/client-only-css-chunk-leak/src/components/StyledPanel.tsx
@@ -0,0 +1,5 @@
+import './StyledPanel.css';
+
+export default function StyledPanel({ children }: { children: React.ReactNode }) {
+ return
{children}
;
+}
diff --git a/packages/astro/test/fixtures/client-only-css-chunk-leak/src/components/formatLabel.ts b/packages/astro/test/fixtures/client-only-css-chunk-leak/src/components/formatLabel.ts
new file mode 100644
index 000000000000..c610fdd018a1
--- /dev/null
+++ b/packages/astro/test/fixtures/client-only-css-chunk-leak/src/components/formatLabel.ts
@@ -0,0 +1,3 @@
+export function formatLabel(text: string): string {
+ return `[ ${text.toUpperCase()} ]`;
+}
diff --git a/packages/astro/test/fixtures/client-only-css-chunk-leak/src/layouts/Layout.astro b/packages/astro/test/fixtures/client-only-css-chunk-leak/src/layouts/Layout.astro
new file mode 100644
index 000000000000..0baf5ff9bf25
--- /dev/null
+++ b/packages/astro/test/fixtures/client-only-css-chunk-leak/src/layouts/Layout.astro
@@ -0,0 +1,14 @@
+---
+import CurrentTime from '../components/CurrentTime';
+---
+
+
+
+
+ CSS Leak Test
+
+
+
+
+
+
diff --git a/packages/astro/test/fixtures/client-only-css-chunk-leak/src/pages/about.astro b/packages/astro/test/fixtures/client-only-css-chunk-leak/src/pages/about.astro
new file mode 100644
index 000000000000..9b1135ce7a3d
--- /dev/null
+++ b/packages/astro/test/fixtures/client-only-css-chunk-leak/src/pages/about.astro
@@ -0,0 +1,7 @@
+---
+import Layout from '../layouts/Layout.astro';
+---
+
+
+ About
+
diff --git a/packages/astro/test/fixtures/client-only-css-chunk-leak/src/pages/index.astro b/packages/astro/test/fixtures/client-only-css-chunk-leak/src/pages/index.astro
new file mode 100644
index 000000000000..75f2d8aa594b
--- /dev/null
+++ b/packages/astro/test/fixtures/client-only-css-chunk-leak/src/pages/index.astro
@@ -0,0 +1,9 @@
+---
+import Layout from '../layouts/Layout.astro';
+import HeavyWidget from '../components/HeavyWidget';
+---
+
+
+ Home
+
+
diff --git a/packages/astro/test/units/i18n/astro_i18n.test.ts b/packages/astro/test/units/i18n/astro_i18n.test.ts
index fd051bf04f83..3a4f92767244 100644
--- a/packages/astro/test/units/i18n/astro_i18n.test.ts
+++ b/packages/astro/test/units/i18n/astro_i18n.test.ts
@@ -263,6 +263,88 @@ describe('getLocaleRelativeUrl', () => {
);
});
+ it('should not add trailing slash when trailingSlash is "never" and path is empty or "/" (#17034)', () => {
+ const config = {
+ i18n: {
+ defaultLocale: 'en',
+ locales: ['en', 'pl'],
+ },
+ };
+
+ // path omitted vs path='' should produce the same result
+ assert.equal(
+ relativeUrl({
+ locale: 'pl',
+ base: '/',
+ ...config.i18n,
+ trailingSlash: 'never',
+ format: 'directory',
+ }),
+ '/pl',
+ );
+ assert.equal(
+ relativeUrl({
+ locale: 'pl',
+ base: '/',
+ ...config.i18n,
+ trailingSlash: 'never',
+ format: 'directory',
+ path: '',
+ }),
+ '/pl',
+ );
+ assert.equal(
+ relativeUrl({
+ locale: 'pl',
+ base: '/',
+ ...config.i18n,
+ trailingSlash: 'never',
+ format: 'directory',
+ path: '/',
+ }),
+ '/pl',
+ );
+
+ // prependWith + trailing slash in path
+ assert.equal(
+ relativeUrl({
+ locale: 'pl',
+ base: '/',
+ ...config.i18n,
+ trailingSlash: 'never',
+ format: 'directory',
+ path: 'docs/setup/',
+ prependWith: 'blog',
+ }),
+ '/blog/pl/docs/setup',
+ );
+
+ // absolute URL should also strip trailing slash
+ assert.equal(
+ absoluteUrl({
+ locale: 'pl',
+ base: '/',
+ ...config.i18n,
+ trailingSlash: 'never',
+ format: 'directory',
+ path: '',
+ site: 'https://example.com',
+ }),
+ 'https://example.com/pl',
+ );
+
+ // absoluteUrlList should be consistent across all locales
+ const list = absoluteUrlList({
+ base: '/',
+ ...config.i18n,
+ trailingSlash: 'never',
+ format: 'directory',
+ path: '',
+ site: 'https://example.com',
+ });
+ assert.deepEqual(list, ['https://example.com', 'https://example.com/pl']);
+ });
+
it('should normalize locales by default', () => {
const config = {
base: '/blog',
diff --git a/packages/astro/test/units/middleware/middleware-hmr.test.ts b/packages/astro/test/units/middleware/middleware-hmr.test.ts
new file mode 100644
index 000000000000..113d73be88af
--- /dev/null
+++ b/packages/astro/test/units/middleware/middleware-hmr.test.ts
@@ -0,0 +1,37 @@
+import assert from 'node:assert/strict';
+import { describe, it } from 'node:test';
+import { isMiddlewarePath } from '../../../dist/core/middleware/vite-plugin.js';
+
+describe('middleware HMR path matching', () => {
+ it('matches middleware.ts (single-file pattern)', () => {
+ assert.ok(isMiddlewarePath('middleware.ts'));
+ });
+
+ it('matches middleware.js', () => {
+ assert.ok(isMiddlewarePath('middleware.js'));
+ });
+
+ it('matches middleware/index.ts (directory pattern)', () => {
+ assert.ok(isMiddlewarePath('middleware/index.ts'));
+ });
+
+ it('matches middleware/test.ts (file inside middleware directory)', () => {
+ assert.ok(isMiddlewarePath('middleware/test.ts'));
+ });
+
+ it('matches middleware/nested/deep.ts (nested file)', () => {
+ assert.ok(isMiddlewarePath('middleware/nested/deep.ts'));
+ });
+
+ it('does not match middleware-utils.ts (similarly named file)', () => {
+ assert.ok(!isMiddlewarePath('middleware-utils.ts'));
+ });
+
+ it('does not match pages/middleware.ts (wrong directory)', () => {
+ assert.ok(!isMiddlewarePath('pages/middleware.ts'));
+ });
+
+ it('does not match other unrelated files', () => {
+ assert.ok(!isMiddlewarePath('components/Header.astro'));
+ });
+});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 2ac5b4394611..52c1c353ed67 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -2515,6 +2515,21 @@ importers:
specifier: workspace:*
version: link:../../..
+ packages/astro/test/fixtures/client-only-css-chunk-leak:
+ dependencies:
+ '@astrojs/react':
+ specifier: workspace:*
+ version: link:../../../../integrations/react
+ astro:
+ specifier: workspace:*
+ version: link:../../..
+ react:
+ specifier: ^19.0.0
+ version: 19.2.7
+ react-dom:
+ specifier: ^19.0.0
+ version: 19.2.7(react@19.2.7)
+
packages/astro/test/fixtures/code-component:
dependencies:
astro:
@@ -4839,7 +4854,7 @@ importers:
version: link:../../astro-prism
'@markdoc/markdoc':
specifier: ^0.5.4
- version: 0.5.4(@types/react@18.3.28)(react@19.2.4)
+ version: 0.5.4(@types/react@19.2.17)(react@19.2.7)
esbuild:
specifier: ^0.27.3
version: 0.27.3
@@ -6020,7 +6035,7 @@ importers:
version: link:../../internal-helpers
'@vercel/analytics':
specifier: ^1.6.1
- version: 1.6.1(react@19.2.4)(svelte@5.55.3)(vue@3.5.30)
+ version: 1.6.1(react@19.2.7)(svelte@5.55.3)(vue@3.5.30)
'@vercel/functions':
specifier: ^3.4.3
version: 3.4.3(@aws-sdk/credential-provider-web-identity@3.972.48)
@@ -6854,6 +6869,30 @@ importers:
specifier: ^4.21.0
version: 4.21.0
+ triage/gh-17043:
+ dependencies:
+ '@astrojs/node':
+ specifier: workspace:*
+ version: link:../../packages/integrations/node
+ '@astrojs/react':
+ specifier: workspace:*
+ version: link:../../packages/integrations/react
+ '@types/react':
+ specifier: ^19.2.14
+ version: 19.2.17
+ '@types/react-dom':
+ specifier: ^19.2.3
+ version: 19.2.3(@types/react@19.2.17)
+ astro:
+ specifier: workspace:*
+ version: link:../../packages/astro
+ react:
+ specifier: ^19.2.5
+ version: 19.2.7
+ react-dom:
+ specifier: ^19.2.5
+ version: 19.2.7(react@19.2.7)
+
packages:
'@anthropic-ai/sdk@0.91.1':
@@ -10336,9 +10375,17 @@ packages:
peerDependencies:
'@types/react': ^18.0.0
+ '@types/react-dom@19.2.3':
+ resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==}
+ peerDependencies:
+ '@types/react': ^19.2.0
+
'@types/react@18.3.28':
resolution: {integrity: sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==}
+ '@types/react@19.2.17':
+ resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==}
+
'@types/retry@0.12.0':
resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==}
@@ -14568,6 +14615,11 @@ packages:
peerDependencies:
react: ^19.2.4
+ react-dom@19.2.7:
+ resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==}
+ peerDependencies:
+ react: ^19.2.7
+
react-is@17.0.2:
resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
@@ -14583,6 +14635,10 @@ packages:
resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==}
engines: {node: '>=0.10.0'}
+ react@19.2.7:
+ resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==}
+ engines: {node: '>=0.10.0'}
+
read-package-up@11.0.0:
resolution: {integrity: sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==}
engines: {node: '>=18'}
@@ -18492,12 +18548,12 @@ snapshots:
- encoding
- supports-color
- '@markdoc/markdoc@0.5.4(@types/react@18.3.28)(react@19.2.4)':
+ '@markdoc/markdoc@0.5.4(@types/react@19.2.17)(react@19.2.7)':
optionalDependencies:
'@types/linkify-it': 3.0.5
'@types/markdown-it': 12.2.3
- '@types/react': 18.3.28
- react: 19.2.4
+ '@types/react': 19.2.17
+ react: 19.2.7
'@mdx-js/mdx@3.1.1':
dependencies:
@@ -19982,11 +20038,19 @@ snapshots:
dependencies:
'@types/react': 18.3.28
+ '@types/react-dom@19.2.3(@types/react@19.2.17)':
+ dependencies:
+ '@types/react': 19.2.17
+
'@types/react@18.3.28':
dependencies:
'@types/prop-types': 15.7.15
csstype: 3.2.3
+ '@types/react@19.2.17':
+ dependencies:
+ csstype: 3.2.3
+
'@types/retry@0.12.0': {}
'@types/retry@0.12.2': {}
@@ -20183,9 +20247,9 @@ snapshots:
dependencies:
valibot: 1.2.0(typescript@6.0.3)
- '@vercel/analytics@1.6.1(react@19.2.4)(svelte@5.55.3)(vue@3.5.30)':
+ '@vercel/analytics@1.6.1(react@19.2.7)(svelte@5.55.3)(vue@3.5.30)':
optionalDependencies:
- react: 19.2.4
+ react: 19.2.7
svelte: 5.55.3
vue: 3.5.30(typescript@6.0.3)
@@ -25005,6 +25069,11 @@ snapshots:
react: 19.2.4
scheduler: 0.27.0
+ react-dom@19.2.7(react@19.2.7):
+ dependencies:
+ react: 19.2.7
+ scheduler: 0.27.0
+
react-is@17.0.2: {}
react-refresh@0.18.0: {}
@@ -25015,6 +25084,8 @@ snapshots:
react@19.2.4: {}
+ react@19.2.7: {}
+
read-package-up@11.0.0:
dependencies:
find-up-simple: 1.0.1