mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
## Problem `@supabase/middleware` ships as 1.0.0. The docs still label the `pipeline` entry form of `withSupabase` alpha, and several snippets import `npm:@supabase/server` and `npm:@supabase/middleware` with no version or with a `^0.5.0` pin. A snippet without a version leaves readers and tools to guess one, and a guessed version fails on deploy. ## Solution - Removes the alpha wording from the middleware reference intro and usage examples, the server frameworks partial, and the Bring your own MCP guide. The `@supabase/server` 1.6.0 floor stays. - Pins every `npm:@supabase/server` and `npm:@supabase/middleware` import in the guides to a major range, `@1`, following the `npm:@supabase/supabase-js@2` convention in Managing dependencies. - Bumps the authenticated-mcp-server example to middleware `^1.0.0` and server `^1.9.0`. ~~Blocked by supabase/middleware#49. The `@1` range resolves once 1.0.0 is on npm.~~ <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Updated authentication, API key, and MCP examples to use versioned Supabase server and middleware packages. * Clarified that pipeline and nested composition behave the same, and that both require `@supabase/server` 1.6.0 or later. * Removed alpha-status labels from `withSupabase` guidance while retaining the 1.6.0 minimum-version requirement. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
89 lines
3.8 KiB
Plaintext
89 lines
3.8 KiB
Plaintext
---
|
|
id: usage-examples
|
|
title: Usage examples
|
|
---
|
|
|
|
Each example builds one Fetch handler with `pipeline`. Entries run in array order on the request. The handler runs last and reads what the entries contributed to `ctx`.
|
|
|
|
### Gate a route behind CORS and a feature flag
|
|
|
|
<RefSubLayout.EducationRow>
|
|
<RefSubLayout.Details>
|
|
|
|
`withCors` runs first. It answers the CORS preflight (an `OPTIONS` request carrying `Access-Control-Request-Method`) with `204` before anything else runs. On the way out, it stamps `Access-Control-*` headers onto the response when the request's `Origin` is allowed.
|
|
|
|
`withFeatureFlag` runs second. `evaluate` receives the request and decides: `true` admits it, `false` rejects it. It can be async, and it can return a verdict object instead of a boolean. A rejected request gets a `404` and never reaches the handler. An admitted request reaches the handler with `ctx.featureFlag` set.
|
|
|
|
Both middleware ship in `@supabase/middleware`. The handler is plain Fetch, so the same stack runs on Node, Deno, Bun, and Cloudflare Workers; only the host entry point differs.
|
|
|
|
</RefSubLayout.Details>
|
|
|
|
<RefSubLayout.Examples>
|
|
|
|
```ts
|
|
import { pipeline } from '@supabase/middleware'
|
|
import { withCors } from '@supabase/middleware/cors'
|
|
import { withFeatureFlag } from '@supabase/middleware/feature-flag'
|
|
|
|
export default {
|
|
fetch: pipeline(
|
|
[
|
|
withCors({ origin: ['https://app.example.com'], credentials: true }),
|
|
withFeatureFlag({
|
|
name: 'beta-checkout',
|
|
evaluate: (req) => req.headers.get('x-beta') === '1',
|
|
}),
|
|
],
|
|
async (_req, ctx) => Response.json({ feature: ctx.featureFlag.name }),
|
|
),
|
|
}
|
|
```
|
|
|
|
</RefSubLayout.Examples>
|
|
</RefSubLayout.EducationRow>
|
|
|
|
### Roll out an authenticated endpoint behind a flag
|
|
|
|
<RefSubLayout.EducationRow>
|
|
<RefSubLayout.Details>
|
|
|
|
Middleware from [`@supabase/server`](/docs/reference/server/introduction) drop into the same array. `withCors` runs first, so the preflight is answered before the auth gate. `withSupabase` runs second with `cors: 'disabled'`, because `withCors` owns CORS here. It verifies the caller's JWT and puts an RLS-scoped client on `ctx.supabase`. A request without valid credentials gets a `401` and never reaches the flag or the handler.
|
|
|
|
The flag runs last. `evaluate` reads an environment variable through `getEnv`, so the endpoint returns `404` to every signed-in caller until `BETA_CHECKOUT` is set to `on`. Flip the variable to roll the endpoint out.
|
|
|
|
Without `withCors`, `withSupabase` answers every `OPTIONS` request itself with `204` and wildcard CORS headers (`Access-Control-Allow-Origin: *`). That is enough when you do not need an origin allowlist. A layer that owns CORS must sit before `withSupabase` in the array. Placed after it, the preflight reaches the auth gate and gets a `401`.
|
|
|
|
The entry form of `withSupabase` needs `@supabase/server` 1.6.0 or later.
|
|
|
|
</RefSubLayout.Details>
|
|
|
|
<RefSubLayout.Examples>
|
|
|
|
```ts
|
|
import { getEnv, pipeline } from '@supabase/middleware'
|
|
import { withCors } from '@supabase/middleware/cors'
|
|
import { withFeatureFlag } from '@supabase/middleware/feature-flag'
|
|
import { withSupabase } from '@supabase/server'
|
|
|
|
export default {
|
|
fetch: pipeline(
|
|
[
|
|
withCors({ origin: ['https://app.example.com'] }),
|
|
withSupabase({ auth: 'user', cors: 'disabled' }),
|
|
withFeatureFlag({
|
|
name: 'beta-checkout',
|
|
evaluate: () => getEnv('BETA_CHECKOUT') === 'on',
|
|
}),
|
|
],
|
|
async (_req, ctx) => {
|
|
const { data, error } = await ctx.supabase.from('carts').select()
|
|
if (error) return Response.json({ error: 'query_failed' }, { status: 500 })
|
|
return Response.json(data)
|
|
},
|
|
),
|
|
}
|
|
```
|
|
|
|
</RefSubLayout.Examples>
|
|
</RefSubLayout.EducationRow>
|