Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
cfeade1
feat: Do the things
elliott-with-the-longest-name-on-github Dec 1, 2023
0f06fd1
changeset
elliott-with-the-longest-name-on-github Dec 1, 2023
20be7b5
better
elliott-with-the-longest-name-on-github Dec 1, 2023
3f5ae76
fix: types
elliott-with-the-longest-name-on-github Dec 1, 2023
d1920a2
feat: Replace `throw redirect` with `redirect`
elliott-with-the-longest-name-on-github Dec 1, 2023
1efdc9e
feat: Replace `throw error` with `error`
elliott-with-the-longest-name-on-github Dec 1, 2023
e12d34d
fix: Revert changes to migrations
elliott-with-the-longest-name-on-github Dec 2, 2023
017a494
fix: Internals
elliott-with-the-longest-name-on-github Dec 2, 2023
b07797f
Update .changeset/clean-cars-kiss.md
elliott-with-the-longest-name-on-github Dec 2, 2023
764e9e3
fix: lint
elliott-with-the-longest-name-on-github Dec 2, 2023
3df53ab
Merge branch 'elliott/kit-command-error-improvements' of github.com:s…
elliott-with-the-longest-name-on-github Dec 2, 2023
77ab3bb
Merge branch 'version-2' into elliott/kit-command-error-improvements
benmccann Dec 3, 2023
1588f50
Merge branch 'version-2' into elliott/kit-command-error-improvements
benmccann Dec 3, 2023
daf4d7a
fix jsdoc overload function description
teemingc Dec 4, 2023
0be2b5a
oops accidentally overwrote these while experimenting
teemingc Dec 4, 2023
3e6be33
Merge branch 'version-2' into elliott/kit-command-error-improvements
benmccann Dec 5, 2023
53ac369
Merge branch 'version-2' into elliott/kit-command-error-improvements
benmccann Dec 5, 2023
efffd3d
feat: Do the things
elliott-with-the-longest-name-on-github Dec 1, 2023
8e2a89e
changeset
elliott-with-the-longest-name-on-github Dec 1, 2023
ed210ba
better
elliott-with-the-longest-name-on-github Dec 1, 2023
e7d5295
fix: types
elliott-with-the-longest-name-on-github Dec 1, 2023
15dcd3e
feat: Replace `throw redirect` with `redirect`
elliott-with-the-longest-name-on-github Dec 1, 2023
4d1eb74
feat: Replace `throw error` with `error`
elliott-with-the-longest-name-on-github Dec 1, 2023
e534718
fix: Revert changes to migrations
elliott-with-the-longest-name-on-github Dec 2, 2023
862c8b0
fix: Internals
elliott-with-the-longest-name-on-github Dec 2, 2023
d0f5413
fix: lint
elliott-with-the-longest-name-on-github Dec 2, 2023
97b1828
Update .changeset/clean-cars-kiss.md
elliott-with-the-longest-name-on-github Dec 2, 2023
aa1c0a1
feat: Document errors thrown by error and redirect, add fancy numeric…
elliott-with-the-longest-name-on-github Dec 6, 2023
cf32083
Merge branch 'elliott/kit-command-error-improvements' of github.com:s…
elliott-with-the-longest-name-on-github Dec 6, 2023
e1bbc16
fix: meh
elliott-with-the-longest-name-on-github Dec 6, 2023
ea0747c
fix: type
elliott-with-the-longest-name-on-github Dec 6, 2023
b2b1b02
fix overloaded error method jsdocs
teemingc Dec 6, 2023
78763e3
merge version-2
Rich-Harris Dec 10, 2023
c93158e
tweak docs
Rich-Harris Dec 10, 2023
f84b2d4
tweak implementation
Rich-Harris Dec 10, 2023
dcf3c95
Merge branch 'version-2' into elliott/kit-command-error-improvements
Rich-Harris Dec 10, 2023
fcc4570
Merge branch 'version-2' into elliott/kit-command-error-improvements
Rich-Harris Dec 11, 2023
171d25c
update types
Rich-Harris Dec 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/clean-cars-kiss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': major
---

breaking: Turn `error` and `redirect` into commands
Comment thread
elliott-with-the-longest-name-on-github marked this conversation as resolved.
Outdated
8 changes: 4 additions & 4 deletions documentation/docs/20-core-concepts/10-routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export function load({ params }) {
};
}

throw error(404, 'Not found');
error(404, 'Not found');
}
```

Expand Down Expand Up @@ -104,7 +104,7 @@ export async function load({ params }) {
return post;
}

throw error(404, 'Not found');
error(404, 'Not found');
}
```

Expand Down Expand Up @@ -264,7 +264,7 @@ export function GET({ url }) {
const d = max - min;

if (isNaN(d) || d < 0) {
throw error(400, 'min and max must be numbers, and min must be less than max');
error(400, 'min and max must be numbers, and min must be less than max');
}

const random = min + Math.random() * d;
Expand All @@ -277,7 +277,7 @@ The first argument to `Response` can be a [`ReadableStream`](https://developer.m

You can use the [`error`](modules#sveltejs-kit-error), [`redirect`](modules#sveltejs-kit-redirect) and [`json`](modules#sveltejs-kit-json) methods from `@sveltejs/kit` for convenience (but you don't have to).

If an error is thrown (either `throw error(...)` or an unexpected error), the response will be a JSON representation of the error or a fallback error page — which can be customised via `src/error.html` — depending on the `Accept` header. The [`+error.svelte`](#error) component will _not_ be rendered in this case. You can read more about error handling [here](errors).
If an error is thrown (either `error(...)` or an unexpected error), the response will be a JSON representation of the error or a fallback error page — which can be customised via `src/error.html` — depending on the `Accept` header. The [`+error.svelte`](#error) component will _not_ be rendered in this case. You can read more about error handling [here](errors).

> When creating an `OPTIONS` handler, note that Vite will inject `Access-Control-Allow-Origin` and `Access-Control-Allow-Methods` headers — these will not be present in production unless you add them.

Expand Down
8 changes: 4 additions & 4 deletions documentation/docs/20-core-concepts/20-load.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,11 +397,11 @@ import { error } from '@sveltejs/kit';
/** @type {import('./$types').LayoutServerLoad} */
export function load({ locals }) {
if (!locals.user) {
throw error(401, 'not logged in');
error(401, 'not logged in');
}

if (!locals.user.isAdmin) {
throw error(403, 'not an admin');
error(403, 'not an admin');
}
}
```
Expand Down Expand Up @@ -430,12 +430,12 @@ import { redirect } from '@sveltejs/kit';
/** @type {import('./$types').LayoutServerLoad} */
export function load({ locals }) {
if (!locals.user) {
throw redirect(307, '/login');
redirect(307, '/login');
}
}
```

> Don't use `throw redirect()` from within a try-catch block, as the redirect will immediately trigger the catch statement.
> Don't use `redirect()` from within a try-catch block, as the redirect will immediately trigger the catch statement.

In the browser, you can also navigate programmatically outside of a `load` function using [`goto`](modules#$app-navigation-goto) from [`$app.navigation`](modules#$app-navigation).

Expand Down
2 changes: 1 addition & 1 deletion documentation/docs/20-core-concepts/30-form-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ export const actions = {
cookies.set('sessionid', await db.createSession(user));

+ if (url.searchParams.has('redirectTo')) {
+ throw redirect(303, url.searchParams.get('redirectTo'));
+ redirect(303, url.searchParams.get('redirectTo'));
+ }

return { success: true };
Expand Down
2 changes: 1 addition & 1 deletion documentation/docs/30-advanced/10-advanced-routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import { error } from '@sveltejs/kit';

/** @type {import('./$types').PageLoad} */
export function load(event) {
throw error(404, 'Not Found');
error(404, 'Not Found');
}
```

Expand Down
8 changes: 4 additions & 4 deletions documentation/docs/30-advanced/25-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export async function load({ params }) {
const post = await db.getPost(params.slug);

if (!post) {
throw error(404, {
error(404, {
message: 'Not found'
});
}
Expand All @@ -54,7 +54,7 @@ This tells SvelteKit to set the response status code to 404 and render an [`+err
You can add extra properties to the error object if needed...

```diff
throw error(404, {
error(404, {
message: 'Not found',
+ code: 'NOT_FOUND'
});
Expand All @@ -63,8 +63,8 @@ throw error(404, {
...otherwise, for convenience, you can pass a string as the second argument:

```diff
-throw error(404, { message: 'Not found' });
+throw error(404, 'Not found');
-error(404, { message: 'Not found' });
+error(404, 'Not found');
```

## Unexpected errors
Expand Down
41 changes: 32 additions & 9 deletions packages/kit/src/exports/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,17 @@ export { VERSION } from '../version.js';
* @overload
* @param {number} status
* @param {App.Error} body
* @return {HttpError}
* @return {never}
*/

/**
* @overload
* @param {number} status
* @param {{ message: string } extends App.Error ? App.Error | string | undefined : never} [body]
* @return {HttpError}
* @return {never}
*/

/**
* Creates an `HttpError` object with an HTTP status code and an optional message.
* This object, if thrown during request handling, will cause SvelteKit to
* Throws an error with a HTTP status code and an optional message.
* When called during request handling, this will cause SvelteKit to
* return an error response without invoking `handleError`.
* Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
* @param {number} status The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses). Must be in the range 400-599.
Expand All @@ -31,21 +29,46 @@ export function error(status, body) {
throw new Error(`HTTP error status codes must be between 400 and 599 — ${status} is invalid`);
}

return new HttpError(status, body);
throw new HttpError(status, body);
}

/**
* Create a `Redirect` object. If thrown during request handling, SvelteKit will return a redirect response.
* Checks whether this is an error thrown by {@link error}.
Comment thread
dummdidumm marked this conversation as resolved.
* @template {number} T
* @param {unknown} e
* @param {T} [status] The status to filter for.
* @return {e is (HttpError & { status: T extends undefined ? never : T })}
*/
export function isHttpError(e, status) {
const isInstance = e instanceof HttpError;
if (status) {
return isInstance && e.status === status;
}
return isInstance;
}

/**
* Redirect a request. When called during request handling, SvelteKit will return a redirect response.
* Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
* @param {300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308} status The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages). Must be in the range 300-308.
* @param {string | URL} location The location to redirect to.
* @return {never}
*/
export function redirect(status, location) {
if ((!BROWSER || DEV) && (isNaN(status) || status < 300 || status > 308)) {
throw new Error('Invalid status code');
}

return new Redirect(status, location.toString());
throw new Redirect(status, location.toString());
}

/**
* Checks whether this is a redirect thrown by {@link redirect}.
Comment thread
dummdidumm marked this conversation as resolved.
* @param {unknown} e The object to check.
* @return {e is Redirect}
*/
export function isRedirect(e) {
return e instanceof Redirect;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/kit/src/exports/node/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function get_raw_body(req, body_size_limit) {
if (!length) {
length = body_size_limit;
} else if (length > body_size_limit) {
throw error(
error(
413,
`Received content-length of ${length}, but only accept up to ${body_size_limit} bytes.`
);
Expand Down
6 changes: 2 additions & 4 deletions packages/kit/src/runtime/server/page/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,13 +231,11 @@ async function call_action(event, actions) {
/** @param {any} data */
function validate_action_return(data) {
if (data instanceof Redirect) {
throw new Error('Cannot `return redirect(...)` — use `throw redirect(...)` instead');
throw new Error('Cannot `return redirect(...)` — use `redirect(...)` instead');
}

if (data instanceof HttpError) {
throw new Error(
'Cannot `return error(...)` — use `throw error(...)` or `return fail(...)` instead'
);
throw new Error('Cannot `return error(...)` — use `error(...)` or `return fail(...)` instead');
}
}

Expand Down
8 changes: 4 additions & 4 deletions packages/kit/test/apps/basics/src/hooks.server.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export const handle = sequence(
if (event.url.pathname === '/errors/error-in-handle') {
throw new Error('Error in handle');
} else if (event.url.pathname === '/errors/expected-error-in-handle') {
throw error(500, 'Expected error in handle');
error(500, 'Expected error in handle');
}

const response = await resolve(event, {
Expand All @@ -105,10 +105,10 @@ export const handle = sequence(
async ({ event, resolve }) => {
if (event.url.pathname.includes('/redirect/in-handle')) {
if (event.url.search === '?throw') {
throw redirect(307, event.url.origin + '/redirect/c');
redirect(307, event.url.origin + '/redirect/c');
} else if (event.url.search.includes('cookies')) {
event.cookies.delete(COOKIE_NAME, { path: '/cookies' });
throw redirect(307, event.url.origin + '/cookies');
redirect(307, event.url.origin + '/cookies');
} else {
return new Response(undefined, { status: 307, headers: { location: '/redirect/c' } });
}
Expand All @@ -125,7 +125,7 @@ export const handle = sequence(
},
async ({ event, resolve }) => {
if (event.url.pathname === '/actions/redirect-in-handle' && event.request.method === 'POST') {
throw redirect(303, '/actions/enhance');
redirect(303, '/actions/enhance');
}

return resolve(event);
Expand Down
4 changes: 2 additions & 2 deletions packages/kit/test/apps/basics/src/routes/+layout.server.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ export async function load({ cookies, locals, fetch }) {
if (should_fail) {
cookies.delete('fail-type', { path: '/' });
if (should_fail === 'expected') {
throw error(401, 'Not allowed');
error(401, 'Not allowed');
} else if (should_fail === 'unexpected') {
throw new Error('Failed to load');
} else {
throw redirect(307, '/load');
redirect(307, '/load');
}
}
// Do NOT make this load function depend on something which would cause it to rerun
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const actions = {
};
},
error: () => {
throw error(400, 'error');
error(400, 'error');
},
echo: async ({ request }) => {
const data = await request.formData();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import { error } from '@sveltejs/kit';

export const actions = {
default: async () => {
throw error(502, 'something went wrong');
error(502, 'something went wrong');
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ export function load() {
/** @type {import('./$types').Actions} */
export const actions = {
default: async () => {
throw redirect(303, '/actions/enhance');
redirect(303, '/actions/enhance');
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import { COOKIE_NAME } from '../shared';
/** @type {import('@sveltejs/kit').RequestHandler} */
export const GET = (event) => {
event.cookies.delete(COOKIE_NAME);
throw redirect(303, '/cookies');
redirect(303, '/cookies');
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import { redirect } from '@sveltejs/kit';
export const GET = (event) => {
const sneaky = 'teapot%2C%20jane%20austen';
event.cookies.set('encoding', sneaky);
throw redirect(303, '/cookies/encoding');
redirect(303, '/cookies/encoding');
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import { redirect } from '@sveltejs/kit';
export const GET = (event) => {
const needsEncoding = 'teapot, jane austen';
event.cookies.set('encoding', needsEncoding);
throw redirect(303, '/cookies/encoding');
redirect(303, '/cookies/encoding');
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import { COOKIE_NAME } from '../shared';
/** @type {import('@sveltejs/kit').RequestHandler} */
export const GET = (event) => {
event.cookies.set(COOKIE_NAME, 'teapot');
throw redirect(303, '/cookies');
redirect(303, '/cookies');
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import { redirect } from '@sveltejs/kit';

/** @type {import('@sveltejs/kit').Load} */
export function load() {
throw redirect(307, 'redirected?embedded=' + encodeURIComponent('/苗条?foo=bar&fizz=buzz'));
redirect(307, 'redirected?embedded=' + encodeURIComponent('/苗条?foo=bar&fizz=buzz'));
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { redirect } from '@sveltejs/kit';

export function load() {
throw redirect(307, encodeURI('苗条'));
redirect(307, encodeURI('苗条'));
}
2 changes: 1 addition & 1 deletion packages/kit/test/apps/basics/src/routes/errors/+layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import { error } from '@sveltejs/kit';
export async function load({ fetch, url }) {
if (url.pathname.startsWith('/errors/error-in-layout')) {
const res = await fetch('/errors/error-in-layout/non-existent');
throw error(res.status);
error(res.status);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import { error } from '@sveltejs/kit';

/** @type {import('@sveltejs/kit').RequestHandler} */
export function load() {
throw error(555, undefined);
error(555, undefined);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { error } from '@sveltejs/kit';

export function GET() {
throw error(401, 'You shall not pass');
error(401, 'You shall not pass');
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { redirect } from '@sveltejs/kit';

export function GET() {
throw redirect(302, '/');
redirect(302, '/');
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { error } from '@sveltejs/kit';
/** @type {import('./$types').PageLoad} */
export async function load() {
if (typeof window !== 'undefined') {
throw error(555, 'Not found');
error(555, 'Not found');
}

return {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import { error } from '@sveltejs/kit';

/** @type {import('@sveltejs/kit').Load} */
export async function load() {
throw error(555, 'Not found');
error(555, 'Not found');
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import { error } from '@sveltejs/kit';

/** @type {import('@sveltejs/kit').Load} */
export async function load() {
throw error(555, 'Not found');
error(555, 'Not found');
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { error } from '@sveltejs/kit';

export async function load() {
if (typeof window !== 'undefined') {
throw error(401, undefined);
error(401, undefined);
}
return {};
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { error } from '@sveltejs/kit';

export const load = () => {
throw error(400, 'oops');
error(400, 'oops');
};
Loading