Elysia
Run withBetterSupabase around an Elysia app, with the caller's repositories derived into every route.
Elysia has no middleware slot that sees the response it produces, so
toElysia(entries) from better-supabase/elysia wraps the app's fetch.
bridge.wrap runs the entries around app.handle, and bridge.context hands
the contributions to routes:
import { Elysia } from "elysia";
import { toElysia } from "better-supabase/elysia";
import { createServer, withBetterSupabase } from "better-supabase/server";
import { betterSupabase } from "./lib/supabase";
const bs = createServer(betterSupabase);
const bridge = toElysia([withBetterSupabase(bs, { allow: ["user"] })]);
const app = new Elysia()
.derive(({ request }) => bridge.context(request))
.get("/notes", ({ db }) => db.notes.findMany().orThrow());
export default { fetch: bridge.wrap((request) => app.handle(request)) };A guard refusal answers 401 or 403 Problem Details before Elysia routes the
request, and the route's response passes back through the entries, so
refreshed cookies and bs-primary-until reach it.
guard(bridge, options) from better-supabase/elysia is a beforeHandle
hook that refuses callers per route, with the options every adapter takes
(allow, aal, scopes, roles, requireTenant, permission,
authorize, signIn, mfa). A permission is decided by the guard's
authorizer (see Authorizers); without one,
the route refuses every caller:
import { guard, problemOnError } from "better-supabase/elysia";
const app = new Elysia()
.onError(problemOnError())
.derive(({ request }) => bridge.context(request))
.get("/reports", ({ db }) => db.reports.findMany().orThrow(), {
beforeHandle: guard(bridge, { permission: "reports:read", authorizer }),
});bridge.context(request) throws for a request that didn't come through
bridge.wrap, so a route served another way fails closed instead of running
without a caller. Serve the app with the wrapped fetch, not app.listen.
Last updated on