camelon

Loaders & actions

A route loads data with two functions. loader runs on GET, action runs on POST. Both take the args bag and return data that the page's default export renders.

A page route with a loader must export LoaderOutput — the type its loader returns and its default renders.

import type { RouteArgs } from 'camelon';

export type LoaderInput = { query: { name?: string } };
export type LoaderOutput = { greeting: string };

export function loader({ query }: RouteArgs) {
  return { greeting: `Hello, ${query.name ?? 'world'}` };
}

export default function Data({ greeting }: LoaderOutput) {
  return (
    <div class="d-card">
      <strong safe>{greeting}</strong>
      <p>Try adding <code>?name=Ada</code> to the URL above.</p>
    </div>
  );
}
service worker
export type LoaderInput = { query: { name?: string } };
export type LoaderOutput = { greeting: string };

export function loader({ query }: RouteArgs) {
  return { greeting: `Hello, ${query.name ?? 'world'}` };
}

export default function Page({ greeting }: LoaderOutput) {
  return <h1 safe>{greeting}</h1>;
}

The args bag

Every loader, action, and middleware gets the same object. There is no req, res, or cookies. Read through request, write through response, scratch on ctx, manage state through session.

Key What it is
params path params (:id, :splat)
query parsed query string
body parsed request body
signals Datastar state ({} if not a reactive request)
files multipart uploads by field; .data is a Uint8Array
request raw read: .url .headers .method .signal, .json() .text() .formData()
response .status(code), .header(name, val)
ctx middleware → loader scratch
stream server → client SSE channel
session signed cookie store; auto-commits on change
db your injected client; throws if unconfigured
logger request-bound; carries { requestId, method, path }

Return values

A page route always renders HTML. A resource route returns a string for HTML, an object for JSON, or a Response for full control.

export function loader() {
  return { ok: true, items: [1, 2, 3] }; // → application/json
}

Next: typed contracts.