--- alwaysApply: true --- # Svelte Remote Functions (Experimental) This project uses SvelteKit's experimental `remoteFunctions` feature. Follow these rules when working with server-side logic and data fetching. ## 1. Definition & Structure - Logic MUST be defined in `*.remote.ts` files co-located with the route. - Import `form`, `query`, and `command` from `$app/server`. - Import `z` from `zod/v4`. ## 2. Creating Remote Functions ### Queries (Data Fetching) Use `query` for reading data. It behaves like a GET request. ```typescript import { query } from '$app/server'; import z from 'zod/v4'; export const getData = query(z.object({ id: z.string() }), async ({ id }) => { return await db.select(...); }); ``` ### Commands (Mutations) Use `command` for direct logic execution (RPC style), typically for actions like delete, toggle, or specific updates. ```typescript import { command } from '$app/server'; export const deleteItem = command(z.string(), async (id) => { await db.delete(...); }); ``` ### Forms (Form Submissions) Use `form` for handling HTML form submissions with progressive enhancement and field validation. ```typescript import { form } from '$app/server'; export const updateItem = form(schema, async (data) => { await db.update(...); return { success: true }; }); ``` ## 3. Frontend Usage ### Reactivity with Queries Queries can be called inside `$derived` to create reactive promises that update when their arguments change. ```svelte {#await itemsPromise then items} {/await} ``` ### Executing Commands & Invalidating Data Commands are called as functions. To refresh relevant data after a command finishes, use the `.updates()` method and pass it the query call that should be refreshed. ```svelte ``` ### Using Forms Use `.enhance` on the form object. You can also use `.updates()` on the `submit()` result. ```svelte
{ await submit().updates(fetchItems({ search })); })} >
``` ## 4. Invalidation Patterns ### Client-Side (Selective) Use `.updates(queryCall())` on the mutation result in the frontend. This is preferred for fine-grained updates. ### Server-Side (Global for that file) You can refresh queries directly in the remote function definition in `data.remote.ts`: ```typescript export const deleteItem = command(z.string(), async (id) => { await db.delete(...); // Refresh listItems query for all clients await listItems().refresh(); }); ``` ### Global Refresh If logic requires a full page refresh (all loaders), use `refreshAll()` from `$app/navigation`. ```typescript import { refreshAll } from '$app/navigation'; // ... await myCommand(); await refreshAll(); ```