Skip to content

Commit f9faa3e

Browse files
authored
Merge branch 'main' into main
2 parents ed7ac8c + d66890a commit f9faa3e

File tree

19 files changed

+1483
-60
lines changed

19 files changed

+1483
-60
lines changed

apps/svelte.dev/content/docs/kit/20-core-concepts/60-remote-functions.md

Lines changed: 748 additions & 0 deletions
Large diffs are not rendered by default.

apps/svelte.dev/content/docs/kit/30-advanced/20-hooks.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,38 @@ export async function handleFetch({ event, request, fetch }) {
144144
}
145145
```
146146

147+
### handleValidationError
148+
149+
This hook is called when a remote function is called with an argument that does not match the provided [Standard Schema](https://standardschema.dev/). It must return an object matching the shape of [`App.Error`](types#Error).
150+
151+
Say you have a remote function that expects a string as its argument ...
152+
153+
```js
154+
/// file: todos.remote.js
155+
import * as v from 'valibot';
156+
import { query } from '$app/server';
157+
158+
export const getTodo = query(v.string(), (id) => {
159+
// implementation...
160+
});
161+
```
162+
163+
...but it is called with something that doesn't match the schema — such as a number (e.g `await getTodos(1)`) — then validation will fail, the server will respond with a [400 status code](https://http.dog/400), and the function will throw with the message 'Bad Request'.
164+
165+
To customise this message and add additional properties to the error object, implement `handleValidationError`:
166+
167+
```js
168+
/// file: src/hooks.server.js
169+
/** @type {import('@sveltejs/kit').HandleValidationError} */
170+
export function handleValidationError({ issues }) {
171+
return {
172+
message: 'No thank you'
173+
};
174+
}
175+
```
176+
177+
Be thoughtful about what information you expose here, as the most likely reason for validation to fail is that someone is sending malicious requests to your server.
178+
147179
## Shared hooks
148180

149181
The following can be added to `src/hooks.server.js` _and_ `src/hooks.client.js`:

apps/svelte.dev/content/docs/kit/98-reference/[email protected]

Lines changed: 272 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,10 @@ function fail(status: number): ActionFailure<undefined>;
118118
<div class="ts-block">
119119

120120
```dts
121-
function fail<
122-
T extends Record<string, unknown> | undefined = undefined
123-
>(status: number, data: T): ActionFailure<T>;
121+
function fail<T = undefined>(
122+
status: number,
123+
data: T
124+
): ActionFailure<T>;
124125
```
125126

126127
</div>
@@ -305,9 +306,7 @@ type Action<
305306
<div class="ts-block">
306307

307308
```dts
308-
interface ActionFailure<
309-
T extends Record<string, unknown> | undefined = undefined
310-
> {/*…*/}
309+
interface ActionFailure<T = undefined> {/*…*/}
311310
```
312311

313312
<div class="ts-block-property">
@@ -1142,6 +1141,26 @@ type HandleServerError = (input: {
11421141

11431142
</div>
11441143

1144+
## HandleValidationError
1145+
1146+
The [`handleValidationError`](/docs/kit/hooks#Server-hooks-handleValidationError) hook runs when the argument to a remote function fails validation.
1147+
1148+
It will be called with the validation issues and the event, and must return an object shape that matches `App.Error`.
1149+
1150+
<div class="ts-block">
1151+
1152+
```dts
1153+
type HandleValidationError<
1154+
Issue extends
1155+
StandardSchemaV1.Issue = StandardSchemaV1.Issue
1156+
> = (input: {
1157+
issues: Issue[];
1158+
event: RequestEvent;
1159+
}) => MaybePromise<App.Error>;
1160+
```
1161+
1162+
</div>
1163+
11451164
## HttpError
11461165

11471166
The object returned by the [`error`](/docs/kit/@sveltejs-kit#error) function.
@@ -1908,6 +1927,227 @@ The location to redirect to.
19081927
</div>
19091928
</div></div>
19101929

1930+
## RemoteCommand
1931+
1932+
The return value of a remote `command` function. See [Remote functions](/docs/kit/remote-functions#command) for full documentation.
1933+
1934+
<div class="ts-block">
1935+
1936+
```dts
1937+
type RemoteCommand<Input, Output> = (arg: Input) => Promise<
1938+
Awaited<Output>
1939+
> & {
1940+
updates(
1941+
...queries: Array<
1942+
RemoteQuery<any> | RemoteQueryOverride
1943+
>
1944+
): Promise<Awaited<Output>>;
1945+
};
1946+
```
1947+
1948+
</div>
1949+
1950+
## RemoteForm
1951+
1952+
The return value of a remote `form` function. See [Remote functions](/docs/kit/remote-functions#form) for full documentation.
1953+
1954+
<div class="ts-block">
1955+
1956+
```dts
1957+
type RemoteForm<Result> = {
1958+
method: 'POST';
1959+
/** The URL to send the form to. */
1960+
action: string;
1961+
/** Event handler that intercepts the form submission on the client to prevent a full page reload */
1962+
onsubmit: (event: SubmitEvent) => void;
1963+
/** Use the `enhance` method to influence what happens when the form is submitted. */
1964+
enhance(
1965+
callback: (opts: {
1966+
form: HTMLFormElement;
1967+
data: FormData;
1968+
submit: () => Promise<void> & {
1969+
updates: (
1970+
...queries: Array<
1971+
RemoteQuery<any> | RemoteQueryOverride
1972+
>
1973+
) => Promise<void>;
1974+
};
1975+
}) => void
1976+
): {
1977+
method: 'POST';
1978+
action: string;
1979+
onsubmit: (event: SubmitEvent) => void;
1980+
};
1981+
/**
1982+
* Create an instance of the form for the given key.
1983+
* The key is stringified and used for deduplication to potentially reuse existing instances.
1984+
* Useful when you have multiple forms that use the same remote form action, for example in a loop.
1985+
* ```svelte
1986+
* {#each todos as todo}
1987+
* {@const todoForm = updateTodo.for(todo.id)}
1988+
* <form {...todoForm}>
1989+
* {#if todoForm.result?.invalid}<p>Invalid data</p>{/if}
1990+
* ...
1991+
* </form>
1992+
* {/each}
1993+
* ```
1994+
*/
1995+
for(
1996+
key: string | number | boolean
1997+
): Omit<RemoteForm<Result>, 'for'>;
1998+
/** The result of the form submission */
1999+
get result(): Result | undefined;
2000+
/** Spread this onto a `<button>` or `<input type="submit">` */
2001+
buttonProps: {
2002+
type: 'submit';
2003+
formmethod: 'POST';
2004+
formaction: string;
2005+
onclick: (event: Event) => void;
2006+
/** Use the `enhance` method to influence what happens when the form is submitted. */
2007+
enhance(
2008+
callback: (opts: {
2009+
form: HTMLFormElement;
2010+
data: FormData;
2011+
submit: () => Promise<void> & {
2012+
updates: (
2013+
...queries: Array<
2014+
RemoteQuery<any> | RemoteQueryOverride
2015+
>
2016+
) => Promise<void>;
2017+
};
2018+
}) => void
2019+
): {
2020+
type: 'submit';
2021+
formmethod: 'POST';
2022+
formaction: string;
2023+
onclick: (event: Event) => void;
2024+
};
2025+
};
2026+
};
2027+
```
2028+
2029+
</div>
2030+
2031+
## RemotePrerenderFunction
2032+
2033+
The return value of a remote `prerender` function. See [Remote functions](/docs/kit/remote-functions#prerender) for full documentation.
2034+
2035+
<div class="ts-block">
2036+
2037+
```dts
2038+
type RemotePrerenderFunction<Input, Output> = (
2039+
arg: Input
2040+
) => RemoteResource<Output>;
2041+
```
2042+
2043+
</div>
2044+
2045+
## RemoteQuery
2046+
2047+
<div class="ts-block">
2048+
2049+
```dts
2050+
type RemoteQuery<T> = RemoteResource<T> & {
2051+
/**
2052+
* On the client, this function will re-fetch the query from the server.
2053+
*
2054+
* On the server, this can be called in the context of a `command` or `form` and the refreshed data will accompany the action response back to the client.
2055+
* This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.
2056+
*/
2057+
refresh(): Promise<void>;
2058+
/**
2059+
* Temporarily override the value of a query. This is used with the `updates` method of a [command](https://svelte.dev/docs/kit/remote-functions#command-Single-flight-mutations) or [enhanced form submission](https://svelte.dev/docs/kit/remote-functions#form-enhance) to provide optimistic updates.
2060+
*
2061+
* ```svelte
2062+
* <script>
2063+
* import { getTodos, addTodo } from './todos.remote.js';
2064+
* const todos = getTodos();
2065+
* </script>
2066+
*
2067+
* <form {...addTodo.enhance(async ({ data, submit }) => {
2068+
* await submit().updates(
2069+
* todos.withOverride((todos) => [...todos, { text: data.get('text') }])
2070+
* );
2071+
* }}>
2072+
* <input type="text" name="text" />
2073+
* <button type="submit">Add Todo</button>
2074+
* </form>
2075+
* ```
2076+
*/
2077+
withOverride(
2078+
update: (current: Awaited<T>) => Awaited<T>
2079+
): RemoteQueryOverride;
2080+
};
2081+
```
2082+
2083+
</div>
2084+
2085+
## RemoteQueryFunction
2086+
2087+
The return value of a remote `query` function. See [Remote functions](/docs/kit/remote-functions#query) for full documentation.
2088+
2089+
<div class="ts-block">
2090+
2091+
```dts
2092+
type RemoteQueryFunction<Input, Output> = (
2093+
arg: Input
2094+
) => RemoteQuery<Output>;
2095+
```
2096+
2097+
</div>
2098+
2099+
## RemoteQueryOverride
2100+
2101+
<div class="ts-block">
2102+
2103+
```dts
2104+
interface RemoteQueryOverride {/*…*/}
2105+
```
2106+
2107+
<div class="ts-block-property">
2108+
2109+
```dts
2110+
_key: string;
2111+
```
2112+
2113+
<div class="ts-block-property-details"></div>
2114+
</div>
2115+
2116+
<div class="ts-block-property">
2117+
2118+
```dts
2119+
release(): void;
2120+
```
2121+
2122+
<div class="ts-block-property-details"></div>
2123+
</div></div>
2124+
2125+
## RemoteResource
2126+
2127+
<div class="ts-block">
2128+
2129+
```dts
2130+
type RemoteResource<T> = Promise<Awaited<T>> & {
2131+
/** The error in case the query fails. Most often this is a [`HttpError`](https://svelte.dev/docs/kit/@sveltejs-kit#HttpError) but it isn't guaranteed to be. */
2132+
get error(): any;
2133+
/** `true` before the first result is available and during refreshes */
2134+
get loading(): boolean;
2135+
} & (
2136+
| {
2137+
/** The current value of the query. Undefined until `ready` is `true` */
2138+
get current(): undefined;
2139+
ready: false;
2140+
}
2141+
| {
2142+
/** The current value of the query. Undefined until `ready` is `true` */
2143+
get current(): Awaited<T>;
2144+
ready: true;
2145+
}
2146+
);
2147+
```
2148+
2149+
</div>
2150+
19112151
## RequestEvent
19122152

19132153
<div class="ts-block">
@@ -2115,6 +2355,20 @@ isSubRequest: boolean;
21152355

21162356
`true` for `+server.js` calls coming from SvelteKit without the overhead of actually making an HTTP request. This happens when you make same-origin `fetch` requests on the server.
21172357

2358+
</div>
2359+
</div>
2360+
2361+
<div class="ts-block-property">
2362+
2363+
```dts
2364+
isRemoteRequest: boolean;
2365+
```
2366+
2367+
<div class="ts-block-property-details">
2368+
2369+
`true` if the request comes from the client via a remote function. The `url` property will be stripped of the internal information
2370+
related to the data request in this case. Use this property instead if the distinction is important to you.
2371+
21182372
</div>
21192373
</div></div>
21202374

@@ -2389,6 +2643,18 @@ nodes: SSRNodeLoader[];
23892643
</div>
23902644
<div class="ts-block-property">
23912645

2646+
```dts
2647+
remotes: Record<string, () => Promise<any>>;
2648+
```
2649+
2650+
<div class="ts-block-property-details">
2651+
2652+
hashed filename -> import to that file
2653+
2654+
</div>
2655+
</div>
2656+
<div class="ts-block-property">
2657+
23922658
```dts
23932659
routes: SSRRoute[];
23942660
```

apps/svelte.dev/content/docs/kit/98-reference/20-$app-navigation.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
preloadCode,
1919
preloadData,
2020
pushState,
21+
refreshAll,
2122
replaceState
2223
} from '$app/navigation';
2324
```
@@ -248,6 +249,27 @@ function pushState(
248249

249250

250251

252+
## refreshAll
253+
254+
Causes all currently active remote functions to refresh, and all `load` functions belonging to the currently active page to re-run (unless disabled via the option argument).
255+
Returns a `Promise` that resolves when the page is subsequently updated.
256+
257+
<div class="ts-block">
258+
259+
```dts
260+
function refreshAll({
261+
includeLoadFunctions
262+
}?:
263+
| {
264+
includeLoadFunctions?: boolean;
265+
}
266+
| undefined): Promise<void>;
267+
```
268+
269+
</div>
270+
271+
272+
251273
## replaceState
252274

253275
Programmatically replace the current history entry with the given `page.state`. To use the current URL, you can pass `''` as the first argument. Used for [shallow routing](/docs/kit/shallow-routing).

0 commit comments

Comments
 (0)