Update VSCode settings: Configure ESLint with flat config, set working directories for apps and packages, enable format on save, and specify default formatters for TypeScript, JSONC, and Svelte files.

This commit is contained in:
2026-01-08 11:21:30 -03:00
parent 0fbd56d39e
commit 91925a9dea
6 changed files with 490 additions and 4 deletions

View File

@@ -0,0 +1,145 @@
---
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
<script>
import { fetchItems } from './data.remote';
let search = $state('');
// This promise re-runs automatically when 'search' changes
let itemsPromise = $derived(fetchItems({ search }));
</script>
{#await itemsPromise then items}
<ul>
{#each items as item}
...
{/each}
</ul>
{/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
<script>
import { deleteItem, fetchItems } from './data.remote';
let { search } = $props();
</script>
<button
onclick={async () => {
try {
// Execute command and refresh the items list
await deleteItem(id).updates(fetchItems({ search }));
toast.success('Deleted');
} catch (e) {
toast.error('Error');
}
}}
>
Delete
</button>
```
### Using Forms
Use `.enhance` on the form object. You can also use `.updates()` on the `submit()` result.
```svelte
<form
{...updateItem.enhance(async ({ submit }) => {
await submit().updates(fetchItems({ search }));
})}
>
<input {...updateItem.fields.name.as('text')} />
<button type="submit">Save</button>
</form>
```
## 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();
```