0.3.2 came out of two products being built on 0.3.1 — YallaDo and Khepra — and the list of things they had to work around. It's a big release for a patch number: @devorajs/core and @devorajs/cli 0.3.2, the adapters 0.2.3, @devorajs/adapter-node published for the first time (0.2.1), and create-devora 0.3.1. Upgrade core and the CLI together.
Pages can read the request and answer forms properly
Loaders and actions now get ctx.url (query string included), ctx.headers and ctx.ip. An action can return data for the page, or fail() with a status, instead of only redirecting:
export async function action(formData: FormData, ctx: RequestContext) {
ctx.verifyCsrf(formData);
const text = String(formData.get("text") ?? "").trim();
if (!text) return fail(400, { error: "Write something first." }); // re-render, status 400
await addNote({ text }, ctx);
return redirect("/notes"); // 303 See Other
}That's from the multi-app example, where CI posts an empty note and checks for the 400. Thrown errors keep their status too — requireAuth() is a 401, verifyCsrf() a 403 — and render the app's error.tsx. Multipart uploads arrive as File objects, and there's a <head> API for stylesheets, fonts and meta tags. All of it is on Pages, forms and errors.
Deploying stopped being the hard part
- The Vercel function runtime was hardcoded to
nodejs20.x, which Vercel now rejects. It's picked from your Node version andenginesnow, and printed. - CommonJS dependencies like
pgcrashed the bundled function on its first request. They work now. - A top-level
api/folder collides with Vercel's own functions folder. New apps keep API routes inendpoints/(apiDir); URLs stay under/api. devora build --adapterruns preflight checks first (session secret and store, runtime, that folder), so a deploy that can't work fails in seconds.
Sessions behind proxies and across subdomains
Cookie secure (true, "auto", false), sameSite and domain are configurable, with trustProxy for apps behind nginx, Caddy or a load balancer. A login served over plain HTTP used to fail silently because the cookie was always Secure; now the server warns. Bearer-only APIs can turn the CSRF cookie off with csrf: false, and API routes get CORS:
// apps/api/app.config.ts — from the api-bearer example
export default defineApp({
backendOnly: true,
apiDir: "endpoints",
csrf: false,
cors: { origins: ["http://localhost:5173"], allowHeaders: ["content-type", "authorization"] },
});What an existing app has to do
Most of the release is new options. These can change how an existing app behaves:
- Redirects after a POST are 303 (were 302). Update tests that expect 302.
- Page errors keep their status instead of becoming 500s.
- The framework stylesheet is only added to pages that render
PageShell. A page that relied on it without the shell needshead: { theme: true }. .envfiles in the project root are loaded automatically, anddevora startreadsPORTandHOST.- Request bodies are capped at 10 MB by default (
maxBodyBytes).
The full list, each with what to do, is on Upgrading to 0.3.2. The terminal got a new look too: devora dev prints every app's URLs first, then its routes, and --quiet keeps only the URLs.