Reference
Routes and context
For your agentCopy this and give it to the AI you're building with.
Run `cubek skill`, read all of it and follow it exactly (no CLI: download https://cubek.dev/SKILL.md verbatim with curl; don't summarize it); when you write routes and handlers, follow its "Routes and context" section. Run `cubek check` after every edit until it is clean.
import { app, crypto, db, validate, type Context } from "cubek"
import { Home } from "./pages/home"
app.get("/", async (c) => c.render(<Home notes={await db.notes.find({ limit: 20 })} />))
app.get("/api/notes/:id", async (c) => {
const note = await db.notes.get(c.param("id"))
return note === null ? c.notFound() : c.json(note)
})
const noteInput = validate.object({ title: validate.string({ min: 1, max: 200 }), body: validate.string() })
app.post("/notes", async (c) => {
const parsed = noteInput.safeParse(await c.body()) // JSON, urlencoded or multipart; malformed: 400 for you
if (!parsed.success) return c.json({ error: parsed.error }, 400)
const note = await db.notes.insert(parsed.data)
return c.redirect(`/notes/${note.id}`, 303) // 303 after a POST
})
app.use("/admin/*", async (c, next) => c.header("x-admin") === "yes" ? next() : c.text("forbidden", 403))app.get/post/put/patch/delete(path, [middleware,] handler),app.use([path,] ...middleware)(also for unmatched paths). First registered wins:/:slugand the catch-all/*(afterpublic/) go last.c.param/query/header/cookie(name)→string | null(Number(c.query("page") ?? "1"));c.url(),c.path()(no query),c.origin()(absolute links: RSS, mail, ICS),c.ip()(not spoofable);await c.body<T>()is unvalidated;await c.rawBody()→ exactBytes; file fields:{ name, type, size, bytes }(storage.md).- Responses (
type Response):c.json/text/html(body, status?, headers?)(headers replace the content-type),c.body(bytes, status?, headers?),c.render(jsx, status?);c.status(code),c.setHeader. - Middleware:
rateLimit({ limit: 20, window: "1m" }),cors({ origin })(http.md). - Forms send strings:
validate.number({ coerce: true }),validate.boolean({ coerce: true });tags[]fields →string[](repeated fields: http.md). - A thrown
Erroris an empty 500 (details:cubek devoutput,cubek logs).