camelon

Sessions

The session arg is a signed cookie store, wired into every loader, action, and middleware. Mutations commit before the response. There is no manual save.

import { redirect } from 'camelon';
import type { RouteArgs } from 'camelon';

export async function action({ body, session }: RouteArgs) {
  const user = await authenticate(body);
  session.set('userId', user.id);
  session.flash('toast', 'Welcome back'); // read once on the next page
  throw redirect('/dashboard');
}
import { redirect } from 'camelon';
import type { RouteArgs } from 'camelon';

export async function action({ session }: RouteArgs) {
  session.destroy(); // clears state, expires the cookie
  throw redirect('/');
}

API

Method Effect
get<T>(key) read a value
set(key, val) write a value
has(key) check a key
unset(key) remove a key
flash(key, val) write a one-read value
destroy() clear state, expire the cookie

Guarding a section

Check the session in a _middleware.ts:

export const middleware = [
  ({ session }) => {
    if (!session.has('userId')) throw redirect('/login');
  },
];

The secret

Set SESSION_SECRET to sign cookies. In dev without one, camelon uses an ephemeral per-boot secret and warns. In production without one, the first session use throws. There is no default secret.

Custom store

Pass your own store for max-age or key rotation. createSessionStore is on the camelon/session subpath.

import { createSessionStore } from 'camelon/session';

await createHandler({
  routes: manifest,
  session: createSessionStore({
    secrets: [process.env.SESSION_SECRET],
    maxAge: 60 * 60 * 24,
  }),
});

CSRF

camelon checks the Origin header on POST, PUT, PATCH, and DELETE in production, blocking cross-origin writes. Allow extra origins for third-party callbacks, or disable with ['*'].

await createHandler({
  routes: manifest,
  csrf: { trustedOrigins: ['https://pay.example.com'] },
});

There is no raw cookies arg. For a one-off cookie, read request.headers.get('cookie') or write response.header('set-cookie', ...).