diff --git a/.changeset/nasty-lemons-provide.md b/.changeset/nasty-lemons-provide.md new file mode 100644 index 000000000000..66e7d1f02a46 --- /dev/null +++ b/.changeset/nasty-lemons-provide.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +[breaking] remove fallthrough routes diff --git a/documentation/docs/01-routing.md b/documentation/docs/01-routing.md index 28c1c90a3fcd..979fde396046 100644 --- a/documentation/docs/01-routing.md +++ b/documentation/docs/01-routing.md @@ -323,11 +323,10 @@ A route can have multiple dynamic parameters, for example `src/routes/[category] It's possible for multiple routes to match a given path. For example each of these routes would match `/foo-abc`: ```bash +src/routes/[...catchall].svelte src/routes/[a].js src/routes/[b].svelte -src/routes/[c].svelte -src/routes/[...catchall].svelte -src/routes/foo-[bar].svelte +src/routes/foo-[c].svelte ``` SvelteKit needs to know which route is being requested. To do so, it sorts them according to the following rules... @@ -340,48 +339,8 @@ SvelteKit needs to know which route is being requested. To do so, it sorts them ...resulting in this ordering, meaning that `/foo-abc` will invoke `src/routes/foo-[bar].svelte` rather than a less specific route: ```bash -src/routes/foo-[bar].svelte +src/routes/foo-[c].svelte src/routes/[a].js src/routes/[b].svelte -src/routes/[c].svelte src/routes/[...catchall].svelte ``` - -#### Fallthrough routes - -In rare cases, the ordering above might not be what you want for a given path. For example, perhaps `/foo-abc` should resolve to `src/routes/foo-[bar].svelte`, but `/foo-def` should resolve to `src/routes/[b].svelte`. - -Higher priority routes can _fall through_ to lower priority routes by returning `{ fallthrough: true }`, either from `load` (for pages) or a request handler (for endpoints): - -```svelte -/// file: src/routes/foo-[bar].svelte - -``` - -```js -/// file: src/routes/[a].js - -// @filename: [a].d.ts -import type { RequestHandler as GenericRequestHandler } from '@sveltejs/kit'; -export type RequestHandler = GenericRequestHandler<{ a: string }, Body>; - -// @filename: index.js -// @errors: 2366 -// ---cut--- -/** @type {import('./[a]').RequestHandler} */ -export function get({ params }) { - if (params.a === 'foo-def') { - return { fallthrough: true }; - } - - // ... -} -``` diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index 0c9701d98c82..65a3ca39bbc1 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -177,7 +177,7 @@ export function create_client({ target, session, base, trailing_slash }) { const intent = get_navigation_intent(url); - load_cache.promise = get_navigation_result(intent, false); + load_cache.promise = load_route(intent, false); load_cache.id = intent.id; return load_cache.promise; @@ -191,7 +191,7 @@ export function create_client({ target, session, base, trailing_slash }) { */ async function update(intent, redirect_chain, no_cache, opts) { const current_token = (token = {}); - let navigation_result = await get_navigation_result(intent, no_cache); + let navigation_result = await load_route(intent, no_cache); if (!navigation_result && intent.url.pathname === location.pathname) { // this could happen in SPA fallback mode if the user navigated to @@ -341,36 +341,6 @@ export function create_client({ target, session, base, trailing_slash }) { } } - /** - * @param {import('./types').NavigationIntent} intent - * @param {boolean} no_cache - */ - async function get_navigation_result(intent, no_cache) { - if (load_cache.id === intent.id && load_cache.promise) { - return load_cache.promise; - } - - for (let i = 0; i < intent.routes.length; i += 1) { - const route = intent.routes[i]; - - // load code for subsequent routes immediately, if they are as - // likely to match the current path/query as the current one - let j = i + 1; - while (j < intent.routes.length) { - const next = intent.routes[j]; - if (next[0].toString() === route[0].toString()) { - next[1].forEach((loader) => loader()); - j += 1; - } else { - break; - } - } - - const result = await load_route(route, intent, no_cache); - if (result) return result; - } - } - /** * * @param {{ @@ -557,11 +527,16 @@ export function create_client({ target, session, base, trailing_slash }) { } /** - * @param {import('types').CSRRoute} route * @param {import('./types').NavigationIntent} intent * @param {boolean} no_cache */ - async function load_route(route, { id, url, path, routes }, no_cache) { + async function load_route({ id, url, path, route }, no_cache) { + if (!route) return; + + if (load_cache.id === id && load_cache.promise) { + return load_cache.promise; + } + if (!no_cache) { const cached = cache.get(id); if (cached) return cached; @@ -625,7 +600,7 @@ export function create_client({ target, session, base, trailing_slash }) { `${url.pathname}${url.pathname.endsWith('/') ? '' : '/'}__data.json${url.search}`, { headers: { - 'x-sveltekit-load': /** @type {string} */ (shadow_key) + 'x-sveltekit-load': 'true' } } ); @@ -641,15 +616,7 @@ export function create_client({ target, session, base, trailing_slash }) { }; } - if (res.status === 204) { - if (route !== routes[routes.length - 1]) { - // fallthrough - return; - } - props = {}; - } else { - props = await res.json(); - } + props = res.status === 204 ? {} : await res.json(); } else { status = res.status; error = new Error('Failed to load data'); @@ -672,9 +639,12 @@ export function create_client({ target, session, base, trailing_slash }) { } if (node.loaded) { + // TODO remove for 1.0 + // @ts-expect-error if (node.loaded.fallthrough) { - return; + throw new Error('fallthrough is no longer supported'); } + if (node.loaded.error) { status = node.loaded.status; error = node.loaded.error; @@ -811,6 +781,7 @@ export function create_client({ target, session, base, trailing_slash }) { /** @param {URL} url */ function owns(url) { + // TODO now that we've got rid of fallthrough, check against routes immediately return url.origin === location.origin && url.pathname.startsWith(base); } @@ -821,7 +792,7 @@ export function create_client({ target, session, base, trailing_slash }) { /** @type {import('./types').NavigationIntent} */ const intent = { id: url.pathname + url.search, - routes: routes.filter(([pattern]) => pattern.test(path)), + route: routes.find(([pattern]) => pattern.test(path)), url, path }; @@ -860,14 +831,14 @@ export function create_client({ target, session, base, trailing_slash }) { return; } - if (!owns(url)) { + const pathname = normalize_path(url.pathname, trailing_slash); + const normalized = new URL(url.origin + pathname + url.search + url.hash); + + if (!owns(normalized)) { await native_navigation(url); } - const pathname = normalize_path(url.pathname, trailing_slash); - url = new URL(url.origin + pathname + url.search + url.hash); - - const intent = get_navigation_intent(url); + const intent = get_navigation_intent(normalized); update_scroll_positions(current_history_index); @@ -896,7 +867,7 @@ export function create_client({ target, session, base, trailing_slash }) { if (navigating_token !== current_navigating_token) return; if (!navigating) { - const navigation = { from, to: url }; + const navigation = { from, to: normalized }; callbacks.after_navigate.forEach((fn) => fn(navigation)); stores.navigating.set(null); diff --git a/packages/kit/src/runtime/client/types.d.ts b/packages/kit/src/runtime/client/types.d.ts index 7709e5e4f302..107d10363e80 100644 --- a/packages/kit/src/runtime/client/types.d.ts +++ b/packages/kit/src/runtime/client/types.d.ts @@ -38,9 +38,9 @@ export type NavigationIntent = { */ path: string; /** - * The routes that could satisfy this navigation intent + * The route that matches `path` */ - routes: CSRRoute[]; + route: CSRRoute | undefined; // TODO i'm pretty sure we can make this required, and simplify some stuff /** * The destination URL */ diff --git a/packages/kit/src/runtime/server/endpoint.js b/packages/kit/src/runtime/server/endpoint.js index 8cea0ea439b0..c99fbcf00bf5 100644 --- a/packages/kit/src/runtime/server/endpoint.js +++ b/packages/kit/src/runtime/server/endpoint.js @@ -59,8 +59,10 @@ export async function render_endpoint(event, mod) { return error(`${preface}: expected an object, got ${typeof response}`); } + // TODO remove for 1.0 + // @ts-expect-error if (response.fallthrough) { - return; + throw new Error('fallthrough is no longer supported'); } const { status = 200, body = {} } = response; diff --git a/packages/kit/src/runtime/server/index.js b/packages/kit/src/runtime/server/index.js index a571d1f1ee1b..3634d43145cb 100644 --- a/packages/kit/src/runtime/server/index.js +++ b/packages/kit/src/runtime/server/index.js @@ -165,17 +165,7 @@ export async function respond(request, options, state) { event.url = new URL(event.url.origin + normalized + event.url.search); } - // `key` will be set if this request came from a client-side navigation - // to a page with a matching endpoint - const key = request.headers.get('x-sveltekit-load'); - for (const route of options.manifest._.routes) { - if (key) { - // client is requesting data for a specific endpoint - if (route.type !== 'page') continue; - if (route.key !== key) continue; - } - const match = route.pattern.exec(decoded); if (!match) continue; @@ -188,7 +178,7 @@ export async function respond(request, options, state) { response = await render_endpoint(event, await route.shadow()); // loading data for a client-side transition is a special case - if (key) { + if (request.headers.has('x-sveltekit-load')) { if (response) { // since redirects are opaque to the browser, we need to repackage // 3xx responses as 200s with a custom header @@ -205,12 +195,8 @@ export async function respond(request, options, state) { } } } else { - // fallthrough response = new Response(undefined, { - status: 204, - headers: { - 'content-type': 'application/json' - } + status: 204 }); } } @@ -257,6 +243,8 @@ export async function respond(request, options, state) { return response; } + + break; } // if this request came direct from the user, rather than diff --git a/packages/kit/src/runtime/server/page/load_node.js b/packages/kit/src/runtime/server/page/load_node.js index ee01caf65057..7857a66da403 100644 --- a/packages/kit/src/runtime/server/page/load_node.js +++ b/packages/kit/src/runtime/server/page/load_node.js @@ -21,7 +21,7 @@ import { coalesce_to_error } from '../../../utils/error.js'; * status?: number; * error?: Error; * }} opts - * @returns {Promise} undefined for fallthrough + * @returns {Promise} */ export async function load_node({ event, @@ -50,7 +50,7 @@ export async function load_node({ */ let set_cookie_headers = []; - /** @type {import('types').Either} */ + /** @type {import('types').LoadOutput} */ let loaded; /** @type {import('types').ShadowData} */ @@ -63,8 +63,6 @@ export async function load_node({ ) : {}; - if (shadow.fallthrough) return; - if (shadow.cookies) { set_cookie_headers.push(...shadow.cookies); } @@ -325,8 +323,15 @@ export async function load_node({ loaded = await module.load.call(null, load_input); if (!loaded) { + // TODO do we still want to enforce this now that there's no fallthrough? throw new Error(`load function must return a value${options.dev ? ` (${node.entry})` : ''}`); } + + // TODO remove for 1.0 + // @ts-expect-error + if (loaded.fallthrough) { + throw new Error('fallthrough is no longer supported'); + } } else if (shadow.body) { loaded = { props: shadow.body @@ -335,10 +340,6 @@ export async function load_node({ loaded = {}; } - if (loaded.fallthrough && !is_error) { - return; - } - // generate __data.json files when prerendering if (shadow.body && state.prerender) { const pathname = `${event.url.pathname.replace(/\/$/, '')}/__data.json`; @@ -401,7 +402,11 @@ async function load_shadow_data(route, event, options, prerender) { if (!is_get) { const result = await handler(event); - if (result.fallthrough) return result; + // TODO remove for 1.0 + // @ts-expect-error + if (result.fallthrough) { + throw new Error('fallthrough is no longer supported'); + } const { status, headers, body } = validate_shadow_output(result); data.status = status; @@ -426,7 +431,11 @@ async function load_shadow_data(route, event, options, prerender) { if (get) { const result = await get(event); - if (result.fallthrough) return result; + // TODO remove for 1.0 + // @ts-expect-error + if (result.fallthrough) { + throw new Error('fallthrough is no longer supported'); + } const { status, headers, body } = validate_shadow_output(result); add_cookies(/** @type {string[]} */ (data.cookies), headers); diff --git a/packages/kit/test/apps/basics/src/routes/endpoint-output/empty.js b/packages/kit/test/apps/basics/src/routes/endpoint-output/empty.js index e396a880ac27..75f45f44c15e 100644 --- a/packages/kit/test/apps/basics/src/routes/endpoint-output/empty.js +++ b/packages/kit/test/apps/basics/src/routes/endpoint-output/empty.js @@ -2,8 +2,3 @@ export function get() { return {}; } - -/** @type {import('@sveltejs/kit').RequestHandler} */ -export function del() { - return { fallthrough: true }; -} diff --git a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[animal].json.js b/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[animal].json.js deleted file mode 100644 index 6a38766dbf37..000000000000 --- a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[animal].json.js +++ /dev/null @@ -1,11 +0,0 @@ -const animals = new Set(['antelope', 'barracuda', 'camel', 'dingo', 'elephant']); - -/** @type {import("@sveltejs/kit").RequestHandler} */ -export function get({ params }) { - if (animals.has(params.animal)) { - return { - body: { type: 'animal' } - }; - } - return { fallthrough: true }; -} diff --git a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[animal].svelte b/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[animal].svelte deleted file mode 100644 index 8cbc2adf6990..000000000000 --- a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[animal].svelte +++ /dev/null @@ -1,26 +0,0 @@ - - - - -

{animal} is an animal

diff --git a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[mineral].json.js b/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[mineral].json.js deleted file mode 100644 index b214adea3672..000000000000 --- a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[mineral].json.js +++ /dev/null @@ -1,11 +0,0 @@ -const minerals = new Set(['aluminium', 'borax', 'chromium', 'diamond', 'edenite']); - -/** @type {import("@sveltejs/kit").RequestHandler} */ -export function get({ params }) { - if (minerals.has(params.mineral)) { - return { - body: { type: 'mineral' } - }; - } - return { fallthrough: true }; -} diff --git a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[mineral].svelte b/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[mineral].svelte deleted file mode 100644 index 29e2affd9ee1..000000000000 --- a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[mineral].svelte +++ /dev/null @@ -1,26 +0,0 @@ - - - - -

{mineral} is a mineral

diff --git a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[vegetable].json.js b/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[vegetable].json.js deleted file mode 100644 index 03e967133c15..000000000000 --- a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[vegetable].json.js +++ /dev/null @@ -1,11 +0,0 @@ -const vegetables = new Set(['asparagus', 'broccoli', 'carrot', 'daikon', 'endive']); - -/** @type {import("@sveltejs/kit").RequestHandler} */ -export function get({ params }) { - if (vegetables.has(params.vegetable)) { - return { - body: { type: 'vegetable' } - }; - } - return { fallthrough: true }; -} diff --git a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[vegetable].svelte b/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[vegetable].svelte deleted file mode 100644 index 8182e2187a38..000000000000 --- a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/[vegetable].svelte +++ /dev/null @@ -1,26 +0,0 @@ - - - - -

{vegetable} is a vegetable

diff --git a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/__layout.svelte b/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/__layout.svelte deleted file mode 100644 index 11fe7e83e199..000000000000 --- a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-advanced/__layout.svelte +++ /dev/null @@ -1,7 +0,0 @@ - - -aluminium -broccoli -camel - -potato diff --git a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-layout/[foo]/__layout.svelte b/packages/kit/test/apps/basics/src/routes/routing/fallthrough-layout/[foo]/__layout.svelte deleted file mode 100644 index 7d5da461c75a..000000000000 --- a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-layout/[foo]/__layout.svelte +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-layout/[foo]/index.svelte b/packages/kit/test/apps/basics/src/routes/routing/fallthrough-layout/[foo]/index.svelte deleted file mode 100644 index 9272a8854586..000000000000 --- a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-layout/[foo]/index.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - -

foo is {$page.params.foo}

diff --git a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-layout/[xyz]/__layout.svelte b/packages/kit/test/apps/basics/src/routes/routing/fallthrough-layout/[xyz]/__layout.svelte deleted file mode 100644 index 977ae9b680ba..000000000000 --- a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-layout/[xyz]/__layout.svelte +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-layout/[xyz]/index.svelte b/packages/kit/test/apps/basics/src/routes/routing/fallthrough-layout/[xyz]/index.svelte deleted file mode 100644 index dbdf18b80545..000000000000 --- a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-layout/[xyz]/index.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - -

xyz is {$page.params.xyz}

diff --git a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-layout/__layout.svelte b/packages/kit/test/apps/basics/src/routes/routing/fallthrough-layout/__layout.svelte deleted file mode 100644 index 6efc36c2dcfe..000000000000 --- a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-layout/__layout.svelte +++ /dev/null @@ -1,5 +0,0 @@ -okay -ok -notok - - diff --git a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-simple/[legal].svelte b/packages/kit/test/apps/basics/src/routes/routing/fallthrough-simple/[legal].svelte deleted file mode 100644 index 8cfadc579533..000000000000 --- a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-simple/[legal].svelte +++ /dev/null @@ -1,13 +0,0 @@ - - -

Legal

diff --git a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-simple/[page].svelte b/packages/kit/test/apps/basics/src/routes/routing/fallthrough-simple/[page].svelte deleted file mode 100644 index a3a6b8392d2e..000000000000 --- a/packages/kit/test/apps/basics/src/routes/routing/fallthrough-simple/[page].svelte +++ /dev/null @@ -1,10 +0,0 @@ - - -

Page

diff --git a/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/[a].js b/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/[a].js deleted file mode 100644 index 458e9f018f74..000000000000 --- a/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/[a].js +++ /dev/null @@ -1,15 +0,0 @@ -/** @type {import('./[a]').RequestHandler} */ -export async function get({ params }) { - const param = params.a; - - if (param !== 'a') { - return { - fallthrough: true - }; - } - - return { - status: 200, - body: { param } - }; -} diff --git a/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/[a].svelte b/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/[a].svelte deleted file mode 100644 index 1d367966bb1e..000000000000 --- a/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/[a].svelte +++ /dev/null @@ -1,6 +0,0 @@ - - -

a-{param}

diff --git a/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/[b].js b/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/[b].js deleted file mode 100644 index a7712b014dd3..000000000000 --- a/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/[b].js +++ /dev/null @@ -1,15 +0,0 @@ -/** @type {import('./[b]').RequestHandler} */ -export async function get({ params }) { - const param = params.b; - - if (param !== 'b') { - return { - fallthrough: true - }; - } - - return { - status: 200, - body: { param } - }; -} diff --git a/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/[b].svelte b/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/[b].svelte deleted file mode 100644 index d216e0cbff2f..000000000000 --- a/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/[b].svelte +++ /dev/null @@ -1,6 +0,0 @@ - - -

b-{param}

diff --git a/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/[c].svelte b/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/[c].svelte deleted file mode 100644 index 53379894746e..000000000000 --- a/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/[c].svelte +++ /dev/null @@ -1 +0,0 @@ -

c

diff --git a/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/index.svelte b/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/index.svelte deleted file mode 100644 index 8e3b7ad45318..000000000000 --- a/packages/kit/test/apps/basics/src/routes/shadowed/fallthrough/index.svelte +++ /dev/null @@ -1,3 +0,0 @@ -fallthrough to shadow a -fallthrough to shadow b -fallthrough to no shadow c diff --git a/packages/kit/test/apps/basics/test/test.js b/packages/kit/test/apps/basics/test/test.js index a3b9401317cc..158a49c05bb5 100644 --- a/packages/kit/test/apps/basics/test/test.js +++ b/packages/kit/test/apps/basics/test/test.js @@ -505,18 +505,6 @@ test.describe.parallel('Shadowed pages', () => { expect(await page.textContent('h1')).toBe('slug: bar'); }); - test('Shadow fallthrough to shadowed page', async ({ page, clicknav }) => { - await page.goto('/shadowed/fallthrough'); - await clicknav('[href="/shadowed/fallthrough/b"]'); - expect(await page.textContent('h2')).toBe('b-b'); - }); - - test('Shadow fallthrough to unshadowed page', async ({ page, clicknav }) => { - await page.goto('/shadowed/fallthrough'); - await clicknav('[href="/shadowed/fallthrough/c"]'); - expect(await page.textContent('h2')).toBe('c'); - }); - test('Shadow redirect', async ({ page, clicknav }) => { await page.goto('/shadowed/redirect'); await clicknav('[href="/shadowed/redirect/a"]'); @@ -550,11 +538,6 @@ test.describe.parallel('Endpoints', () => { } }); - test('not ok on void endpoint', async ({ request }) => { - const response = await request.delete('/endpoint-output/empty'); - expect(response.ok()).toBe(false); - }); - test('200 status on empty endpoint', async ({ request }) => { const response = await request.get('/endpoint-output/empty'); expect(/** @type {import('@playwright/test').APIResponse} */ (response).status()).toBe(200); @@ -2032,33 +2015,6 @@ test.describe.parallel('Routing', () => { } }); - test('fallthrough', async ({ page }) => { - await page.goto('/routing/fallthrough-simple/invalid'); - expect(await page.textContent('h1')).toBe('Page'); - }); - - test('dynamic fallthrough of pages and endpoints', async ({ page, clicknav }) => { - await page.goto('/routing/fallthrough-advanced/borax'); - expect(await page.textContent('h1')).toBe('borax is a mineral'); - - await clicknav('[href="/routing/fallthrough-advanced/camel"]'); - expect(await page.textContent('h1')).toBe('camel is an animal'); - - await clicknav('[href="/routing/fallthrough-advanced/potato"]'); - expect(await page.textContent('h1')).toBe('404'); - }); - - test('dynamic fallthrough of layout', async ({ page, clicknav }) => { - await page.goto('/routing/fallthrough-layout/okay'); - expect(await page.textContent('h1')).toBe('foo is okay'); - - await clicknav('[href="/routing/fallthrough-layout/ok"]'); - expect(await page.textContent('h1')).toBe('xyz is ok'); - - await clicknav('[href="/routing/fallthrough-layout/notok"]'); - expect(await page.textContent('h1')).toBe('404'); - }); - test('last parameter in a segment wins in cases of ambiguity', async ({ page, clicknav }) => { await page.goto('/routing/split-params'); await clicknav('[href="/routing/split-params/x-y-z"]'); diff --git a/packages/kit/test/typings/endpoint.test.ts b/packages/kit/test/typings/endpoint.test.ts index 9f5af8ec3fc5..5fcb44ce8e31 100644 --- a/packages/kit/test/typings/endpoint.test.ts +++ b/packages/kit/test/typings/endpoint.test.ts @@ -105,18 +105,3 @@ export const error_nested_instances: RequestHandler = () => { body: { typed: new Uint8Array() } }; }; - -// @ts-expect-error - fallthrough must be isolated -export const error_fallthrough_not_isolated: RequestHandler = () => { - return { - body: {}, - fallthrough: true - }; -}; - -// @ts-expect-error - fallthrough must be of value `true` -export const error_fallthrough_not_true: RequestHandler = () => { - return { - fallthrough: null - }; -}; diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index cc289bf32c7e..03f18c1b7ab9 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -9,7 +9,6 @@ import { CspDirectives, Either, ErrorLoadInput, - Fallthrough, JSONValue, LoadInput, LoadOutput, @@ -194,9 +193,7 @@ export interface Load< InputProps extends Record = Record, OutputProps extends Record = InputProps > { - (input: LoadInput): MaybePromise< - Either> - >; + (input: LoadInput): MaybePromise>; } export interface Navigation { @@ -228,16 +225,11 @@ export interface RequestHandler< (event: RequestEvent): RequestHandlerOutput; } -export type RequestHandlerOutput = MaybePromise< - Either< - { - status?: number; - headers?: Headers | Partial; - body?: Output; - }, - Fallthrough - > ->; +export type RequestHandlerOutput = MaybePromise<{ + status?: number; + headers?: Headers | Partial; + body?: Output; +}>; export type ResponseBody = JSONValue | Uint8Array | ReadableStream | import('stream').Readable; diff --git a/packages/kit/types/internal.d.ts b/packages/kit/types/internal.d.ts index ccff7b02ce11..7b2be0d9aaff 100644 --- a/packages/kit/types/internal.d.ts +++ b/packages/kit/types/internal.d.ts @@ -12,7 +12,6 @@ import { } from './index'; import { Either, - Fallthrough, HttpMethod, JSONObject, MaybePromise, @@ -111,17 +110,14 @@ export interface MethodOverride { allowed: string[]; } -export type NormalizedLoadOutput = Either< - { - status: number; - error?: Error; - redirect?: string; - props?: Record | Promise>; - stuff?: Record; - maxage?: number; - }, - Fallthrough ->; +export type NormalizedLoadOutput = { + status: number; + error?: Error; + redirect?: string; + props?: Record | Promise>; + stuff?: Record; + maxage?: number; +}; export interface PageData { type: 'page'; @@ -183,11 +179,10 @@ export interface ShadowEndpointOutput { type ShadowKey = string; export interface ShadowRequestHandler { - (event: RequestEvent): MaybePromise, Fallthrough>>; + (event: RequestEvent): MaybePromise>; } export interface ShadowData { - fallthrough?: boolean; status?: number; error?: Error; redirect?: string; diff --git a/packages/kit/types/private.d.ts b/packages/kit/types/private.d.ts index a5d108d14da3..3e3a30838bec 100644 --- a/packages/kit/types/private.d.ts +++ b/packages/kit/types/private.d.ts @@ -144,10 +144,6 @@ export interface ErrorLoadInput = Record