Migrating from SvelteKit

These tables map the form and mutation features of SvelteKit to Silgi. They cover forms and handlers only; the tables on pages, data and the server in Migrating from Nuxt apply to any app. none means Silgi has no equivalent today.

The shape is one thing in Silgi: a handler, a typed function that runs on the server, exported from server/index.ts. A form posts to it (Form action={fn}), a component calls it (useAction(fn), useAsyncData(fn, input)), and with a route a URL answers it. It works without JavaScript, it is a public endpoint that must check who calls it, and it needs no directive.

Form actions

SvelteKitSilgiDifferences
+page.server.ts with export const actionsa handler for each action, exported from server/index.tsone handler per intent, or a field in input; there is no ?/name
actions = { default }one handler
async ({ request }) => { const data = await request.formData() }defineHandler({ input, handler(input) })the form is decoded by formToObject before the handler; with raw: true and a route, await event.request.formData()
fail(400, { errors })fail(400, { errors })status 400 to 499 only; the page gets it from useAction(fn).failure
redirect(303, "/x")redirect("/x")status is the optional second argument, 302 by default; a form post is answered with 303
error(404, "x")throw createError({ status: 404, message: "x" })
form prop of the page, $page.formuseAction(fn) and useForm(fn)state, failure, error, pending and result; typed from the handler
use:enhanceForm (@silgi/svelte), or enhance(form, options) from silgi/appForm renders a plain form that works with JavaScript off; onSubmit replaces the callback form of enhance
invalidateAll()useRouter().refresh()after a successful handler call the page's data is read again without a call
data-sveltekit-reloadreloadDocument on Form, or data-silgi-reload
a submitting variable set in the use:enhance callbackuseForm(fn).pending, useFormStatus()useNavigation().state is idle or loading and tells navigations only
a Standard Schema validated by hand in the actiondefineHandler({ input, handler })issues and the typed values come back as a 400 with data: { issues, values }; useForm spreads them on the fields
request.formData() and a file fieldform: { maxFileSize, maxFiles, onFile }streaming parser, 413 for limits

Remote functions

SvelteKitSilgiDifferences
*.remote.ts, query(schema, fn)defineHandler({ method: "GET", input, handler })a GET handler is cacheable; add cache: { maxAge }
query.batchdefineHandler({ batch: true, handler(inputs) })calls of one tick are one request
command(schema, fn)defineHandler({ input, handler })a POST; call it from useAction(fn) for pending state and the refresh
form(schema, fn)<Form action={fn}>works without JavaScript: the form posts to the page with ?_fn=<id>
getRequestEvent()ctx.eventthe handler's second argument
.refresh() and single-flight mutationsrefresh(event, getPost, input) in the handlerthe answer carries the value of that read, and the client's next read sends nothing
prerender(fn)prerender: true | { inputs } on a GET handlerthe static preset writes the answers as files
the experimental flagnonehandlers need no flag
import { x } from "./data.remote"import { x } from "#server"the import becomes a stub in the browser; server/index.ts has to export x