diff --git a/.changeset/curvy-trains-dress.md b/.changeset/curvy-trains-dress.md new file mode 100644 index 000000000000..2d29ff1b47b2 --- /dev/null +++ b/.changeset/curvy-trains-dress.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: strip internal data before passing URL to `reroute` diff --git a/packages/kit/src/runtime/server/respond.js b/packages/kit/src/runtime/server/respond.js index e260a08b00f1..ab51505a897c 100644 --- a/packages/kit/src/runtime/server/respond.js +++ b/packages/kit/src/runtime/server/respond.js @@ -85,6 +85,21 @@ export async function respond(request, options, manifest, state) { return text('Not found', { status: 404 }); } + const is_data_request = has_data_suffix(url.pathname); + /** @type {boolean[] | undefined} */ + let invalidated_data_nodes; + if (is_data_request) { + url.pathname = + strip_data_suffix(url.pathname) + + (url.searchParams.get(TRAILING_SLASH_PARAM) === '1' ? '/' : '') || '/'; + url.searchParams.delete(TRAILING_SLASH_PARAM); + invalidated_data_nodes = url.searchParams + .get(INVALIDATED_PARAM) + ?.split('') + .map((node) => node === '1'); + url.searchParams.delete(INVALIDATED_PARAM); + } + // reroute could alter the given URL, so we pass a copy let rerouted_path; try { @@ -126,22 +141,6 @@ export async function respond(request, options, manifest, state) { return text('Not found', { status: 404, headers }); } - const is_data_request = has_data_suffix(decoded); - /** @type {boolean[] | undefined} */ - let invalidated_data_nodes; - if (is_data_request) { - decoded = strip_data_suffix(decoded) || '/'; - url.pathname = - strip_data_suffix(url.pathname) + - (url.searchParams.get(TRAILING_SLASH_PARAM) === '1' ? '/' : '') || '/'; - url.searchParams.delete(TRAILING_SLASH_PARAM); - invalidated_data_nodes = url.searchParams - .get(INVALIDATED_PARAM) - ?.split('') - .map((node) => node === '1'); - url.searchParams.delete(INVALIDATED_PARAM); - } - if (!state.prerendering?.fallback) { // TODO this could theoretically break — should probably be inside a try-catch const matchers = await manifest._.matchers(); diff --git a/packages/kit/test/apps/basics/src/hooks.js b/packages/kit/test/apps/basics/src/hooks.js index deb1576401b0..3897bb949252 100644 --- a/packages/kit/test/apps/basics/src/hooks.js +++ b/packages/kit/test/apps/basics/src/hooks.js @@ -4,7 +4,8 @@ import { Foo } from './lib'; const mapping = { '/reroute/basic/a': '/reroute/basic/b', '/reroute/client-only-redirect/a': '/reroute/client-only-redirect/b', - '/reroute/preload-data/a': '/reroute/preload-data/b' + '/reroute/preload-data/a': '/reroute/preload-data/b', + '/reroute/invalidate/a': '/reroute/invalidate' }; /** @type {import("@sveltejs/kit").Reroute} */ diff --git a/packages/kit/test/apps/basics/src/routes/reroute/invalidate/+page.server.js b/packages/kit/test/apps/basics/src/routes/reroute/invalidate/+page.server.js new file mode 100644 index 000000000000..e410319baae7 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/reroute/invalidate/+page.server.js @@ -0,0 +1,5 @@ +export function load({ isDataRequest }) { + return { + request: isDataRequest + }; +} diff --git a/packages/kit/test/apps/basics/src/routes/reroute/invalidate/+page.svelte b/packages/kit/test/apps/basics/src/routes/reroute/invalidate/+page.svelte new file mode 100644 index 000000000000..4f4589198f8d --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/reroute/invalidate/+page.svelte @@ -0,0 +1,11 @@ + + + + +{#if data.request} +

data request: {data.request}

+{/if} diff --git a/packages/kit/test/apps/basics/test/client.test.js b/packages/kit/test/apps/basics/test/client.test.js index c8f15f518348..65ead7cb3e1e 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -1399,6 +1399,12 @@ test.describe('reroute', () => { expect(await page.textContent('h1')).toContain('Full Navigation'); }); + + test('reroute works with invalidate', async ({ page }) => { + await page.goto('/reroute/invalidate/a'); + await page.click('button'); + await expect(page.locator('p')).toHaveText('data request: true'); + }); }); test.describe('init', () => {