Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
785577e
feat(gates): add composable gate primitives for fetch handlers
johnstonmatt May 2, 2026
44365a9
feat(gates): add x402 paywall gate
johnstonmatt May 2, 2026
d240d9b
feat(gates): add Cloudflare Turnstile gate
johnstonmatt May 2, 2026
eac3548
feat(gates): add Cloudflare Access gate
johnstonmatt May 2, 2026
4318b35
feat(gates): add webhook signature verification gate
johnstonmatt May 2, 2026
9b784b8
feat(gates): add fixed-window rate-limit gate
johnstonmatt May 2, 2026
fe612da
feat(gates): add provider-agnostic feature-flag gate
johnstonmatt May 2, 2026
5e33c35
chore(gates): register flag, rate-limit, and webhook subpath exports
johnstonmatt May 2, 2026
ac38951
refactor(gates)!: replace chain composer with direct nesting
johnstonmatt May 2, 2026
ecd985d
refactor(gates)!: replace pluggable stores with Supabase RPC persistence
johnstonmatt May 2, 2026
7dfb762
Merge branch 'main' of https://github.com/supabase/server into FUNC-5…
johnstonmatt May 2, 2026
b579ea5
refactor(gates)!: replace GateResult union with direct Response or ke…
johnstonmatt May 7, 2026
6508c4a
refactor(gates)!: infer nested ctx without explicit Base annotations
johnstonmatt May 7, 2026
20e2b89
test(gates): add regression tests and runtime check for missing gate key
johnstonmatt May 7, 2026
b65339e
Merge branch 'main' of https://github.com/supabase/server into FUNC-5…
johnstonmatt May 7, 2026
0683053
test(gates): rename authType to authMode in nested ctx test
johnstonmatt May 7, 2026
359f757
refactor(gates): annotate built-in gates with explicit GateFactory types
johnstonmatt May 7, 2026
e62e830
refactor(gates)!: rename GateFactory type to Gate
johnstonmatt May 7, 2026
4b6827f
feat(gates/webhook): add built-in GitHub provider
johnstonmatt May 8, 2026
69eda65
docs(gates): reframe as portable extensibility layer
johnstonmatt May 8, 2026
b5b4851
docs(gates): document composition rules for stacking gates
johnstonmatt May 8, 2026
64af25e
docs(gates): lead README with withSupabase analogy
johnstonmatt May 8, 2026
677efea
docs(gates): tighten README prose and drop internal asides
johnstonmatt May 8, 2026
8ff9455
Merge branch 'main' of https://github.com/supabase/server into FUNC-5…
johnstonmatt May 11, 2026
cbffc47
refactor(gates): consolidate built-ins to feature-flag worked example
johnstonmatt May 15, 2026
402965c
Merge branch 'main' of https://github.com/supabase/server into FUNC-5…
johnstonmatt May 20, 2026
2ecbdf8
feat(adapters): add two-arg withSupabase form for gate composition
johnstonmatt May 20, 2026
78aaa21
test(adapters): add contract test for two-arg withSupabase delegation
johnstonmatt May 20, 2026
b25723c
fix: throw helpful TypeError when two-arg form receives framework con…
johnstonmatt May 22, 2026
3c5bf4e
feat(adapters): accept framework context directly in two-arg withSupa…
johnstonmatt May 22, 2026
b6f5fbb
refactor(adapters): extract two-arg withSupabase into defineAdapter h…
johnstonmatt May 22, 2026
23059f6
Merge branch 'main' of https://github.com/supabase/server into FUNC-5…
johnstonmatt May 22, 2026
e614521
feat(adapters): add onAuthError hook and skip-if-set context to two-a…
johnstonmatt May 22, 2026
d94a774
docs(adapters): document two-arg form behavior and defineAdapter pattern
johnstonmatt May 23, 2026
5a8e582
feat(core): expose defineAdapter via @supabase/server/core/adapters s…
johnstonmatt May 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,22 @@

## [1.1.0](https://github.com/supabase/server/compare/server-v1.0.0...server-v1.1.0) (2026-05-19)


### Features

* add Elysia adapter ([#46](https://github.com/supabase/server/issues/46)) ([148169e](https://github.com/supabase/server/commit/148169e5f7737ea50049f3649056f5a44a266a1f))
* **env:** add support for JWKS discovery endpoints ([#53](https://github.com/supabase/server/issues/53)) ([45d677a](https://github.com/supabase/server/commit/45d677ae6539cfa58e0c339960f53e9a7ca90e7d))

- add Elysia adapter ([#46](https://github.com/supabase/server/issues/46)) ([148169e](https://github.com/supabase/server/commit/148169e5f7737ea50049f3649056f5a44a266a1f))
- **env:** add support for JWKS discovery endpoints ([#53](https://github.com/supabase/server/issues/53)) ([45d677a](https://github.com/supabase/server/commit/45d677ae6539cfa58e0c339960f53e9a7ca90e7d))

### Bug Fixes

* **auth:** skip user mode when token has sb_ prefix ([#67](https://github.com/supabase/server/issues/67)) ([b193216](https://github.com/supabase/server/commit/b1932169e28163040b9b22db73b0f84739d9bb8b))
* **ci:** update node packages ([#57](https://github.com/supabase/server/issues/57)) ([f275907](https://github.com/supabase/server/commit/f2759071fd84932e15ebd48f21c04ab311bd5237))
* **jsr:** resolve slow-type errors in elysia and h3 adapters ([#69](https://github.com/supabase/server/issues/69)) ([7c56b13](https://github.com/supabase/server/commit/7c56b132985bd04673108dab7251b1939326d18e))
- **auth:** skip user mode when token has sb\_ prefix ([#67](https://github.com/supabase/server/issues/67)) ([b193216](https://github.com/supabase/server/commit/b1932169e28163040b9b22db73b0f84739d9bb8b))
- **ci:** update node packages ([#57](https://github.com/supabase/server/issues/57)) ([f275907](https://github.com/supabase/server/commit/f2759071fd84932e15ebd48f21c04ab311bd5237))
- **jsr:** resolve slow-type errors in elysia and h3 adapters ([#69](https://github.com/supabase/server/issues/69)) ([7c56b13](https://github.com/supabase/server/commit/7c56b132985bd04673108dab7251b1939326d18e))

## [1.0.0](https://github.com/supabase/server/compare/server-v0.2.0...server-v1.0.0) (2026-05-06)


### Miscellaneous Chores

* release 1.0.0 ([#50](https://github.com/supabase/server/issues/50)) ([67de77f](https://github.com/supabase/server/commit/67de77f00b7ebbf4e1de973489703959c7e3a838))
- release 1.0.0 ([#50](https://github.com/supabase/server/issues/50)) ([67de77f](https://github.com/supabase/server/commit/67de77f00b7ebbf4e1de973489703959c7e3a838))

## [0.2.0](https://github.com/supabase/server/compare/server-v0.1.4...server-v0.2.0) (2026-04-24)

Expand Down
29 changes: 10 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,20 +301,13 @@ For per-route auth, use scoped groups:
import { Elysia } from 'elysia'
import { withSupabase } from '@supabase/server/adapters/elysia'

const app = new Elysia()
.get('/health', () => ({ status: 'ok' }))
.group('/api', (app) =>
app
.use(withSupabase({ auth: 'user' }))
.get('/profile', async ({ supabaseContext }) => {
return supabaseContext.userClaims
}),
)
const app = new H3()
app.use(withSupabase({ auth: 'user' }))

app.listen(3000)
export default { fetch: app.fetch }
```

The adapter does not handle CORS — use `@elysiajs/cors` for that.
See [docs/adapters/h3.md](docs/adapters/h3.md) for per-route auth, Nuxt server-middleware patterns, CORS, and more.

## Primitives

Expand Down Expand Up @@ -458,13 +451,12 @@ No. `@supabase/ssr` handles cookie-based session management for frameworks like

## Exports

| Export | What's in it |
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `@supabase/server` | `withSupabase`, `createSupabaseContext` |
| `@supabase/server/core` | `verifyAuth`, `verifyCredentials`, `extractCredentials`, `createContextClient`, `createAdminClient`, `resolveEnv` |
| `@supabase/server/adapters/hono` | `withSupabase` (Hono middleware) |
| `@supabase/server/adapters/h3` | `withSupabase` (H3 / Nuxt middleware) |
| `@supabase/server/adapters/elysia` | `withSupabase` (Elysia plugin) |
| Export | What's in it |
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `@supabase/server` | `withSupabase`, `createSupabaseContext` |
| `@supabase/server/core` | `verifyAuth`, `verifyCredentials`, `extractCredentials`, `createContextClient`, `createAdminClient`, `resolveEnv` |
| `@supabase/server/adapters/hono` | `withSupabase` (Hono middleware) |
| `@supabase/server/adapters/h3` | `withSupabase` (H3 / Nuxt middleware) |

## Documentation

Expand All @@ -475,7 +467,6 @@ No. `@supabase/ssr` handles cookie-based session management for frameworks like
| Which framework adapters exist? How do I contribute one? | [`src/adapters/README.md`](src/adapters/README.md) |
| How do I use this with Hono? | [`docs/adapters/hono.md`](docs/adapters/hono.md) |
| How do I use this with H3 / Nuxt? | [`docs/adapters/h3.md`](docs/adapters/h3.md) |
| How do I use this with Elysia? | [`docs/adapters/elysia.md`](docs/adapters/elysia.md) |
| How do I use low-level primitives for custom flows? | [`docs/core-primitives.md`](docs/core-primitives.md) |
| How do environment variables work across runtimes? | [`docs/environment-variables.md`](docs/environment-variables.md) |
| How do I handle errors? What codes exist? | [`docs/error-handling.md`](docs/error-handling.md) |
Expand Down
34 changes: 33 additions & 1 deletion docs/adapters/elysia.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ Install Elysia as a peer dependency:
pnpm add elysia
```

The adapter exports its own `withSupabase` that returns an Elysia plugin instead of a fetch handler.
The adapter exports `withSupabase` with two call shapes:

- **One arg** — `withSupabase(config)` — returns an Elysia plugin. Everything in this document describes this form.
- **Two args** — `withSupabase(config, handler)` — the base `withSupabase` from `@supabase/server`, re-exported here for ergonomics. Returns a Web Fetch handler. Use it when you want to compose with [gates](../../src/core/gates/README.md). See the "Composing with gates" section at the bottom.

## Basic app with auth

Expand Down Expand Up @@ -138,3 +141,32 @@ app.use(
}),
)
```

## Composing with gates

For routes that compose with a [gate](../../src/core/gates/README.md), call `withSupabase` with two args. That form returns a dual-mode handler — it accepts either an Elysia route context (when mounted on a route) or a plain `Request` (Web Fetch) — and extracts the underlying Request automatically. Mount directly with `.all(path, withSupabase(...))`:

```ts
import { Elysia } from 'elysia'
import { withSupabase } from '@supabase/server/adapters/elysia'
import { withFeatureFlag } from '@supabase/server/gates/feature-flag'

new Elysia()
.all(
'/beta',
withSupabase(
{ auth: 'user' },
withFeatureFlag(
{ name: 'beta', evaluate: (req) => req.headers.has('x-beta') },
async (_req, ctx) =>
Response.json({
user: ctx.userClaims?.id,
flag: ctx.featureFlag.name,
}),
),
),
)
.listen(3000)
```

Routes that don't need a gate continue to use the one-arg plugin form documented above. The two coexist in one app; each route picks the form that fits.
31 changes: 30 additions & 1 deletion docs/adapters/h3.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ Install H3 as a peer dependency:
pnpm add h3
```

The adapter exports its own `withSupabase` that returns H3 middleware instead of a fetch handler. Works with standalone H3 servers and Nuxt server routes (which run on H3 under the hood).
The adapter exports `withSupabase` with two call shapes:

- **One arg** — `withSupabase(config)` — returns H3 middleware. Everything in this document describes this form. Works with standalone H3 servers and Nuxt server routes (which run on H3 under the hood).
- **Two args** — `withSupabase(config, handler)` — the base `withSupabase` from `@supabase/server`, re-exported here for ergonomics. Returns a Web Fetch handler. Use it when you want to compose with [gates](../../src/core/gates/README.md). See the "Composing with gates" section at the bottom.

## Typing `event.context.supabaseContext`

Expand Down Expand Up @@ -192,3 +195,29 @@ app.use(
}),
)
```

## Composing with gates

For routes that compose with a [gate](../../src/core/gates/README.md), call `withSupabase` with two args. That form returns a dual-mode handler — it accepts either an `H3Event` (when mounted on a route) or a plain `Request` (Web Fetch) — and extracts the underlying Request automatically. Mount directly with `app.all(path, withSupabase(...))`:

```ts
import { H3 } from 'h3'
import { withSupabase } from '@supabase/server/adapters/h3'
import { withFeatureFlag } from '@supabase/server/gates/feature-flag'

const app = new H3()

app.all(
'/beta',
withSupabase(
{ auth: 'user' },
withFeatureFlag(
{ name: 'beta', evaluate: (req) => req.headers.has('x-beta') },
async (_req, ctx) =>
Response.json({ user: ctx.userClaims?.id, flag: ctx.featureFlag.name }),
),
),
)
```

Routes that don't need a gate continue to use the one-arg middleware form documented above. The two coexist in one app; each route picks the form that fits.
31 changes: 30 additions & 1 deletion docs/adapters/hono.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ Install Hono as a peer dependency:
pnpm add hono
```

The adapter exports its own `withSupabase` that returns Hono middleware instead of a fetch handler.
The adapter exports `withSupabase` with two call shapes:

- **One arg** — `withSupabase(config)` — returns Hono middleware. Everything in this document describes this form.
- **Two args** — `withSupabase(config, handler)` — the base `withSupabase` from `@supabase/server`, re-exported here for ergonomics. Returns a Web Fetch handler. Use it when you want to compose with [gates](../../src/core/gates/README.md). See the "Composing with gates" section at the bottom.

## Basic app with auth

Expand Down Expand Up @@ -172,3 +175,29 @@ app.use(
}),
)
```

## Composing with gates

For routes that compose with a [gate](../../src/core/gates/README.md), call `withSupabase` with two args. That form returns a dual-mode handler — it accepts either a Hono `Context` (when mounted on a route) or a plain `Request` (Web Fetch) — and extracts the underlying Request automatically. Mount directly with `app.all(path, withSupabase(...))`:

```ts
import { Hono } from 'hono'
import { withSupabase } from '@supabase/server/adapters/hono'
import { withFeatureFlag } from '@supabase/server/gates/feature-flag'

const app = new Hono()

app.all(
'/beta',
withSupabase(
{ auth: 'user' },
withFeatureFlag(
{ name: 'beta', evaluate: (req) => req.headers.has('x-beta') },
async (_req, ctx) =>
Response.json({ user: ctx.userClaims?.id, flag: ctx.featureFlag.name }),
),
),
)
```

Routes that don't need a gate continue to use the one-arg middleware form documented above. The two coexist in one app; each route picks the form that fits.
16 changes: 6 additions & 10 deletions jsr.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,15 @@
"exports": {
".": "./src/index.ts",
"./core": "./src/core/index.ts",
"./core/gates": "./src/core/gates/index.ts",
"./core/adapters": "./src/core/adapters/index.ts",
"./adapters/hono": "./src/adapters/hono/index.ts",
"./adapters/h3": "./src/adapters/h3/index.ts",
"./adapters/elysia": "./src/adapters/elysia/index.ts"
"./adapters/elysia": "./src/adapters/elysia/index.ts",
"./gates/feature-flag": "./src/gates/feature-flag/index.ts"
},
"publish": {
"include": [
"src/**/*.ts",
"README.md",
"LICENSE"
],
"exclude": [
"src/**/*.test.ts",
"src/**/*.spec.ts"
]
"include": ["src/**/*.ts", "README.md", "LICENSE"],
"exclude": ["src/**/*.test.ts", "src/**/*.spec.ts"]
}
}
15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@
"import": "./dist/core/index.mjs",
"require": "./dist/core/index.cjs"
},
"./core/gates": {
"types": "./dist/core/gates/index.d.mts",
"import": "./dist/core/gates/index.mjs",
"require": "./dist/core/gates/index.cjs"
},
"./core/adapters": {
"types": "./dist/core/adapters/index.d.mts",
"import": "./dist/core/adapters/index.mjs",
"require": "./dist/core/adapters/index.cjs"
},
"./adapters/hono": {
"types": "./dist/adapters/hono/index.d.mts",
"import": "./dist/adapters/hono/index.mjs",
Expand All @@ -39,6 +49,11 @@
"import": "./dist/adapters/h3/index.mjs",
"require": "./dist/adapters/h3/index.cjs"
},
"./gates/feature-flag": {
"types": "./dist/gates/feature-flag/index.d.mts",
"import": "./dist/gates/feature-flag/index.mjs",
"require": "./dist/gates/feature-flag/index.cjs"
},
"./adapters/elysia": {
"types": "./dist/adapters/elysia/index.d.mts",
"import": "./dist/adapters/elysia/index.mjs",
Expand Down
Loading
Loading