@supabase/server 0.2.0 → 1.0.0-rc.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -92
- package/dist/adapters/h3/index.cjs +3 -3
- package/dist/adapters/h3/index.d.cts +3 -3
- package/dist/adapters/h3/index.d.mts +3 -3
- package/dist/adapters/h3/index.mjs +3 -3
- package/dist/adapters/hono/index.cjs +2 -2
- package/dist/adapters/hono/index.d.cts +2 -2
- package/dist/adapters/hono/index.d.mts +2 -2
- package/dist/adapters/hono/index.mjs +2 -2
- package/dist/core/index.cjs +1 -1
- package/dist/core/index.d.cts +25 -9
- package/dist/core/index.d.mts +25 -9
- package/dist/core/index.mjs +1 -1
- package/dist/{create-supabase-context-C_8SbO5w.cjs → create-supabase-context-B-2NDJhL.cjs} +10 -9
- package/dist/{create-supabase-context-DXD5rxi1.mjs → create-supabase-context-BBZtr3D2.mjs} +10 -9
- package/dist/{errors-Dyj5Cjt6.d.cts → errors-0dbzn5gA.d.mts} +1 -1
- package/dist/{errors-m42mkqhD.d.mts → errors-CZFEYnV_.d.cts} +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +5 -5
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +3 -3
- package/dist/{types-DKe8uOwI.d.mts → types-B2yXZjmG.d.mts} +40 -23
- package/dist/{types-DqhOaSlC.d.cts → types-u7fYLtzC.d.cts} +40 -23
- package/dist/{verify-auth-C4zqDlfj.cjs → verify-auth-BKZK83Y8.cjs} +66 -34
- package/dist/{verify-auth-CxFZy9rl.mjs → verify-auth-CZQd36s0.mjs} +66 -34
- package/docs/adapters/h3.md +180 -0
- package/docs/{hono-adapter.md → adapters/hono.md} +14 -25
- package/docs/api-reference.md +28 -15
- package/docs/auth-modes.md +38 -34
- package/docs/core-primitives.md +13 -13
- package/docs/environment-variables.md +17 -17
- package/docs/error-handling.md +4 -4
- package/docs/getting-started.md +17 -17
- package/docs/security.md +15 -15
- package/docs/ssr-frameworks.md +148 -172
- package/docs/typescript-generics.md +6 -6
- package/package.json +5 -3
- package/skills/supabase-server/SKILL.md +51 -44
package/README.md
CHANGED
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
[](./LICENSE)
|
|
4
4
|
[](https://www.npmjs.com/package/@supabase/server)
|
|
5
5
|
[](https://pkg.pr.new/~/supabase/server)
|
|
6
|
+
[](https://supabase.github.io/server/)
|
|
6
7
|
|
|
7
|
-
> **Beta
|
|
8
|
+
> **v1.0 — Public Beta.** First stable release under SemVer: breaking changes only ship as a major bump. The package is still early — expect new adapters, ergonomic improvements, and features to land frequently in minor releases. Found a rough edge? [Open an issue](https://github.com/supabase/server/issues) or [submit a PR](https://github.com/supabase/server/blob/main/CONTRIBUTING.md).
|
|
9
|
+
|
|
10
|
+
> **Coming from a `0.x` release?** See [MIGRATION.md](MIGRATION.md) for the v0 → v1 rename map (`allow` → `auth`, `'public'` → `'publishable'`, `authType` → `authMode`, `claims` → `jwtClaims`, …).
|
|
8
11
|
|
|
9
12
|
`@supabase/server` gives you batteries included access to the
|
|
10
13
|
[supabase-js SDK](https://github.com/supabase/supabase-js), including client
|
|
@@ -15,7 +18,7 @@ Edge Functions and APIs.
|
|
|
15
18
|
import { withSupabase } from '@supabase/server'
|
|
16
19
|
|
|
17
20
|
export default {
|
|
18
|
-
fetch: withSupabase({
|
|
21
|
+
fetch: withSupabase({ auth: 'user' }, async (_req, ctx) => {
|
|
19
22
|
// RLS-scoped — this user only sees their own favorites
|
|
20
23
|
const { data: myGames } = await ctx.supabase.from('favorite_games').select()
|
|
21
24
|
return Response.json(myGames)
|
|
@@ -48,20 +51,20 @@ npx skills add supabase/server
|
|
|
48
51
|
|
|
49
52
|
## Quick Start
|
|
50
53
|
|
|
51
|
-
Imagine you're building an app where users track their favorite games. They sign in and manage their own list. An admin dashboard curates featured titles. A cron job refreshes the "popular this week" rankings. Here's how each piece looks:
|
|
54
|
+
Imagine you're building an app where users track their favorite games. They sign in and manage their own list. Pre-login screens browse the public catalog. An admin dashboard curates featured titles. A cron job refreshes the "popular this week" rankings. Here's how each piece looks:
|
|
52
55
|
|
|
53
56
|
### Authenticated endpoint
|
|
54
57
|
|
|
55
58
|
```ts
|
|
56
59
|
// A signed-in user fetches their favorite games.
|
|
57
60
|
export default {
|
|
58
|
-
fetch: withSupabase({
|
|
59
|
-
const { supabase, supabaseAdmin, userClaims,
|
|
61
|
+
fetch: withSupabase({ auth: 'user' }, async (_req, ctx) => {
|
|
62
|
+
const { supabase, supabaseAdmin, userClaims, jwtClaims, authMode } = ctx
|
|
60
63
|
// supabase — RLS-scoped to the authenticated user
|
|
61
64
|
// supabaseAdmin — bypasses RLS (service role)
|
|
62
65
|
// userClaims — user identity from JWT (id, email, role)
|
|
63
|
-
//
|
|
64
|
-
//
|
|
66
|
+
// jwtClaims — full JWT claims
|
|
67
|
+
// authMode — which auth mode matched
|
|
65
68
|
|
|
66
69
|
// RLS-scoped — this user only sees their own favorites
|
|
67
70
|
const { data: myGames } = await supabase.from('favorite_games').select()
|
|
@@ -74,21 +77,51 @@ export default {
|
|
|
74
77
|
|
|
75
78
|
```ts
|
|
76
79
|
// The frontend hits this before showing the login screen.
|
|
77
|
-
//
|
|
80
|
+
// auth: 'none' means no credentials required.
|
|
78
81
|
export default {
|
|
79
|
-
fetch: withSupabase({
|
|
82
|
+
fetch: withSupabase({ auth: 'none' }, async (_req, _ctx) => {
|
|
80
83
|
return Response.json({ status: 'ok' })
|
|
81
84
|
}),
|
|
82
85
|
}
|
|
83
86
|
```
|
|
84
87
|
|
|
88
|
+
### Publishable-key endpoint
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
// The mobile app browses the game catalog before the user signs in.
|
|
92
|
+
// auth: 'publishable' validates the apikey header against a publishable key —
|
|
93
|
+
// gating the endpoint to your own clients while staying anonymous to the DB.
|
|
94
|
+
export default {
|
|
95
|
+
fetch: withSupabase({ auth: 'publishable' }, async (_req, ctx) => {
|
|
96
|
+
// ctx.supabase — anonymous (anon role); RLS still applies
|
|
97
|
+
// ctx.userClaims, ctx.jwtClaims — null (no JWT)
|
|
98
|
+
// ctx.authMode === 'publishable', ctx.authKeyName === 'default'
|
|
99
|
+
const { data: catalog } = await ctx.supabase
|
|
100
|
+
.from('games')
|
|
101
|
+
.select('id, name, cover_url')
|
|
102
|
+
return Response.json(catalog)
|
|
103
|
+
}),
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The mobile app sends the publishable key in the `apikey` header:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
const catalogEndpoint = 'https://<project>.supabase.co/functions/v1/catalog'
|
|
111
|
+
const publishableKey = 'sb_publishable_...'
|
|
112
|
+
|
|
113
|
+
await fetch(catalogEndpoint, { headers: { apikey: publishableKey } })
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
> Unlike `auth: 'secret'`, the `supabase` client here is anonymous, not admin — RLS is the source of truth for what's visible. The publishable key acts as a coarse "this request came from a known client" gate; it isn't a user identity.
|
|
117
|
+
|
|
85
118
|
### API key protected
|
|
86
119
|
|
|
87
120
|
```ts
|
|
88
121
|
// An admin dashboard fetches the list of featured games to curate.
|
|
89
122
|
// Secret key auth (not a user JWT) — supabaseAdmin bypasses RLS.
|
|
90
123
|
export default {
|
|
91
|
-
fetch: withSupabase({
|
|
124
|
+
fetch: withSupabase({ auth: 'secret' }, async (_req, ctx) => {
|
|
92
125
|
const { data: featuredGames } = await ctx.supabaseAdmin
|
|
93
126
|
.from('featured_games')
|
|
94
127
|
.select()
|
|
@@ -103,8 +136,8 @@ export default {
|
|
|
103
136
|
// Users view their own play stats from the app (JWT).
|
|
104
137
|
// A backend service pulls stats for any user (secret key + user_id in body).
|
|
105
138
|
export default {
|
|
106
|
-
fetch: withSupabase({
|
|
107
|
-
const callerIsUser = ctx.
|
|
139
|
+
fetch: withSupabase({ auth: ['user', 'secret'] }, async (req, ctx) => {
|
|
140
|
+
const callerIsUser = ctx.authMode === 'user'
|
|
108
141
|
|
|
109
142
|
if (callerIsUser) {
|
|
110
143
|
// RLS-scoped — the database enforces "own stats only"
|
|
@@ -129,7 +162,7 @@ export default {
|
|
|
129
162
|
// A cron job refreshes the "popular this week" list every hour.
|
|
130
163
|
// Named key ("cron") so it can be rotated without touching other services.
|
|
131
164
|
export default {
|
|
132
|
-
fetch: withSupabase({
|
|
165
|
+
fetch: withSupabase({ auth: 'secret:cron' }, async (_req, ctx) => {
|
|
133
166
|
const oneWeekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
|
|
134
167
|
const { data: popularThisWeek } = await ctx.supabaseAdmin.rpc(
|
|
135
168
|
'get_most_favorited_since',
|
|
@@ -163,15 +196,15 @@ await fetch(refreshEndpoint, {
|
|
|
163
196
|
| Mode | Credential | Use case |
|
|
164
197
|
| ------------------ | --------------------- | --------------------------------------------------- |
|
|
165
198
|
| `"user"` (default) | Valid JWT | Authenticated user endpoints |
|
|
166
|
-
| `"
|
|
199
|
+
| `"publishable"` | Valid publishable key | Client-facing, key-validated endpoints |
|
|
167
200
|
| `"secret"` | Valid secret key | Server-to-server, internal calls |
|
|
168
|
-
| `"
|
|
201
|
+
| `"none"` | None | Open endpoints, wrappers that handle their own auth |
|
|
169
202
|
|
|
170
|
-
Array syntax (`
|
|
203
|
+
Array syntax (`auth: ["user", "secret"]`) accepts multiple auth methods — first match wins. An absent credential falls through to the next mode; a present-but-invalid JWT rejects the request (no silent downgrade). See [`docs/auth-modes.md`](docs/auth-modes.md).
|
|
171
204
|
|
|
172
|
-
Named key validation: `
|
|
205
|
+
Named key validation: `auth: "publishable:web_app"` or `auth: "secret:automations"` validates against a specific named key in `SUPABASE_PUBLISHABLE_KEYS` or `SUPABASE_SECRET_KEYS`.
|
|
173
206
|
|
|
174
|
-
> **Supabase Edge Functions:** By default, the platform requires a valid JWT on every request. If your function uses `
|
|
207
|
+
> **Supabase Edge Functions:** By default, the platform requires a valid JWT on every request. If your function uses `auth: 'publishable'`, `auth: 'secret'`, or `auth: 'none'`, disable the platform-level JWT check in `supabase/config.toml`:
|
|
175
208
|
>
|
|
176
209
|
> ```toml
|
|
177
210
|
> [functions.my-function]
|
|
@@ -187,13 +220,13 @@ interface SupabaseContext {
|
|
|
187
220
|
supabase: SupabaseClient // RLS-scoped (user or anon depending on auth)
|
|
188
221
|
supabaseAdmin: SupabaseClient // Bypasses RLS
|
|
189
222
|
userClaims: UserClaims | null // JWT-derived identity (for full User, call supabase.auth.getUser())
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
authKeyName?: string
|
|
223
|
+
jwtClaims: JWTClaims | null // Present when auth is JWT
|
|
224
|
+
authMode: AuthMode // Which auth mode matched
|
|
225
|
+
authKeyName?: string // Auth key name of the API key that was used for this request (omitted for `'user'` / `'none'`)
|
|
193
226
|
}
|
|
194
227
|
```
|
|
195
228
|
|
|
196
|
-
`supabase` is always the safe client — it respects RLS. When `
|
|
229
|
+
`supabase` is always the safe client — it respects RLS. When `authMode` is `"user"`, it's scoped to that user's permissions. Otherwise, it's initialized as anonymous.
|
|
197
230
|
|
|
198
231
|
`supabaseAdmin` always bypasses RLS. Use it for operations that need full database access.
|
|
199
232
|
|
|
@@ -202,7 +235,7 @@ interface SupabaseContext {
|
|
|
202
235
|
```ts
|
|
203
236
|
withSupabase(
|
|
204
237
|
{
|
|
205
|
-
|
|
238
|
+
auth: 'user', // who can call this function
|
|
206
239
|
cors: false, // disable CORS (default: supabase-js CORS headers)
|
|
207
240
|
env: { url: '...' }, // env overrides (optional)
|
|
208
241
|
},
|
|
@@ -215,7 +248,7 @@ withSupabase(
|
|
|
215
248
|
```ts
|
|
216
249
|
withSupabase(
|
|
217
250
|
{
|
|
218
|
-
|
|
251
|
+
auth: 'user',
|
|
219
252
|
cors: {
|
|
220
253
|
'Access-Control-Allow-Origin': 'https://myapp.com',
|
|
221
254
|
'Access-Control-Allow-Headers': 'authorization, content-type',
|
|
@@ -229,6 +262,13 @@ withSupabase(
|
|
|
229
262
|
|
|
230
263
|
## Framework Adapters
|
|
231
264
|
|
|
265
|
+
Adapters wrap `withSupabase` for a specific framework's middleware contract. **All adapters are community-maintained** — both Hono and H3 originated as community contributions. They live in this repo and ship with the core package, so a single `npm install @supabase/server` covers the framework you're using. See [`src/adapters/README.md`](src/adapters/README.md) for the maintenance model and the requirements for contributing a new adapter.
|
|
266
|
+
|
|
267
|
+
| Framework | Import | Framework version | Docs |
|
|
268
|
+
| --------- | -------------------------------- | ----------------- | ---------------------------------------------- |
|
|
269
|
+
| Hono | `@supabase/server/adapters/hono` | `^4.0.0` | [docs/adapters/hono.md](docs/adapters/hono.md) |
|
|
270
|
+
| H3 / Nuxt | `@supabase/server/adapters/h3` | `^2.0.0` | [docs/adapters/h3.md](docs/adapters/h3.md) |
|
|
271
|
+
|
|
232
272
|
### Hono
|
|
233
273
|
|
|
234
274
|
```ts
|
|
@@ -236,21 +276,12 @@ import { Hono } from 'hono'
|
|
|
236
276
|
import { withSupabase } from '@supabase/server/adapters/hono'
|
|
237
277
|
|
|
238
278
|
const app = new Hono()
|
|
239
|
-
|
|
240
|
-
// Protected — withSupabase middleware validates the JWT before the handler runs
|
|
241
|
-
app.get('/games', withSupabase({ allow: 'user' }), async (c) => {
|
|
242
|
-
const { supabase } = c.var.supabaseContext
|
|
243
|
-
const { data: myGames } = await supabase.from('favorite_games').select()
|
|
244
|
-
return c.json(myGames)
|
|
245
|
-
})
|
|
246
|
-
|
|
247
|
-
// Public — no middleware means no auth
|
|
248
|
-
app.get('/health', (c) => c.json({ status: 'ok' }))
|
|
279
|
+
app.use('*', withSupabase({ auth: 'user' }))
|
|
249
280
|
|
|
250
281
|
export default { fetch: app.fetch }
|
|
251
282
|
```
|
|
252
283
|
|
|
253
|
-
|
|
284
|
+
See [docs/adapters/hono.md](docs/adapters/hono.md) for per-route auth, CORS, error handling, and other patterns.
|
|
254
285
|
|
|
255
286
|
### H3 / Nuxt
|
|
256
287
|
|
|
@@ -259,48 +290,12 @@ import { H3 } from 'h3'
|
|
|
259
290
|
import { withSupabase } from '@supabase/server/adapters/h3'
|
|
260
291
|
|
|
261
292
|
const app = new H3()
|
|
262
|
-
|
|
263
|
-
// Protected — withSupabase validates the JWT before the handler runs
|
|
264
|
-
app.use(withSupabase({ allow: 'user' }))
|
|
265
|
-
|
|
266
|
-
app.get('/games', async (event) => {
|
|
267
|
-
const { supabase } = event.context.supabaseContext
|
|
268
|
-
const { data: myGames } = await supabase.from('favorite_games').select()
|
|
269
|
-
return myGames
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
// Public — no middleware means no auth
|
|
273
|
-
app.get('/health', () => ({ status: 'ok' }))
|
|
293
|
+
app.use(withSupabase({ auth: 'user' }))
|
|
274
294
|
|
|
275
295
|
export default { fetch: app.fetch }
|
|
276
296
|
```
|
|
277
297
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
```ts
|
|
281
|
-
// server/api/games.get.ts
|
|
282
|
-
import { defineHandler } from 'h3'
|
|
283
|
-
import { withSupabase } from '@supabase/server/adapters/h3'
|
|
284
|
-
|
|
285
|
-
export default defineHandler({
|
|
286
|
-
middleware: [withSupabase({ allow: 'user' })],
|
|
287
|
-
handler: async (event) => {
|
|
288
|
-
const { supabase } = event.context.supabaseContext
|
|
289
|
-
return supabase.from('favorite_games').select()
|
|
290
|
-
},
|
|
291
|
-
})
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
For app-wide auth, register it as a server middleware:
|
|
295
|
-
|
|
296
|
-
```ts
|
|
297
|
-
// server/middleware/supabase.ts
|
|
298
|
-
import { withSupabase } from '@supabase/server/adapters/h3'
|
|
299
|
-
|
|
300
|
-
export default withSupabase({ allow: 'user' })
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
The adapter does not handle CORS — use H3's CORS utilities for that.
|
|
298
|
+
See [docs/adapters/h3.md](docs/adapters/h3.md) for per-route auth, Nuxt server-middleware patterns, CORS, and more.
|
|
304
299
|
|
|
305
300
|
## Primitives
|
|
306
301
|
|
|
@@ -318,10 +313,10 @@ import {
|
|
|
318
313
|
|
|
319
314
|
### verifyAuth
|
|
320
315
|
|
|
321
|
-
Extracts credentials from a Request and validates against the
|
|
316
|
+
Extracts credentials from a Request and validates against the auth config.
|
|
322
317
|
|
|
323
318
|
```ts
|
|
324
|
-
const { data: auth, error } = await verifyAuth(req, {
|
|
319
|
+
const { data: auth, error } = await verifyAuth(req, { auth: 'user' })
|
|
325
320
|
if (error) {
|
|
326
321
|
return Response.json({ message: error.message }, { status: error.status })
|
|
327
322
|
}
|
|
@@ -333,8 +328,8 @@ Low-level — works with raw credentials instead of a Request. Used by SSR adapt
|
|
|
333
328
|
|
|
334
329
|
```ts
|
|
335
330
|
const credentials = { token: myToken, apikey: null }
|
|
336
|
-
const { data:
|
|
337
|
-
|
|
331
|
+
const { data: result, error } = await verifyCredentials(credentials, {
|
|
332
|
+
auth: 'user',
|
|
338
333
|
})
|
|
339
334
|
```
|
|
340
335
|
|
|
@@ -351,7 +346,7 @@ const adminClient = createAdminClient() // bypasses RLS entirely
|
|
|
351
346
|
Full context assembly from a Request — `verifyAuth` + client creation in one call.
|
|
352
347
|
|
|
353
348
|
```ts
|
|
354
|
-
const { data: ctx, error } = await createSupabaseContext(req, {
|
|
349
|
+
const { data: ctx, error } = await createSupabaseContext(req, { auth: 'user' })
|
|
355
350
|
```
|
|
356
351
|
|
|
357
352
|
### resolveEnv
|
|
@@ -382,14 +377,14 @@ export default {
|
|
|
382
377
|
|
|
383
378
|
// Protected — verify the JWT, then create a user-scoped client
|
|
384
379
|
if (url.pathname === '/games') {
|
|
385
|
-
const { data:
|
|
380
|
+
const { data: result, error } = await verifyAuth(req, { auth: 'user' })
|
|
386
381
|
if (error)
|
|
387
382
|
return Response.json(
|
|
388
383
|
{ message: error.message },
|
|
389
384
|
{ status: error.status },
|
|
390
385
|
)
|
|
391
386
|
|
|
392
|
-
const userScopedClient = createContextClient(
|
|
387
|
+
const userScopedClient = createContextClient(result.token)
|
|
393
388
|
const { data: myGames } = await userScopedClient
|
|
394
389
|
.from('favorite_games')
|
|
395
390
|
.select()
|
|
@@ -430,7 +425,11 @@ For other environments, pass overrides via the `env` config option or `resolveEn
|
|
|
430
425
|
- **Node.js** — use the [Hono adapter](#hono), [H3 adapter](#h3--nuxt), or [core primitives](#primitives) with your framework of choice.
|
|
431
426
|
- **Cloudflare Workers** — enable `nodejs_compat` in `wrangler.toml` or pass env overrides via the `env` config option.
|
|
432
427
|
- **Nuxt** — use the [H3 adapter](#h3--nuxt) directly as a server middleware.
|
|
433
|
-
- **Next.js / SvelteKit / Remix** —
|
|
428
|
+
- **Next.js / SvelteKit / Remix** — compose with [`@supabase/ssr`](https://github.com/supabase/ssr): `@supabase/ssr` owns cookies + refresh-token rotation, `@supabase/server` adds verified claims and typed RLS / admin clients on top. See [`docs/ssr-frameworks.md`](docs/ssr-frameworks.md).
|
|
429
|
+
|
|
430
|
+
### Does this replace `@supabase/ssr`?
|
|
431
|
+
|
|
432
|
+
No. `@supabase/ssr` handles cookie-based session management for frameworks like Next.js and SvelteKit. `@supabase/server` handles stateless, header-based auth for Edge Functions, Workers, and other backend runtimes. The composable primitives already work in SSR environments but require more setup — see [`docs/ssr-frameworks.md`](docs/ssr-frameworks.md) for the Next.js example. The two packages coexist and are not replacements for each other. Deeper integration with `@supabase/ssr` is on the roadmap.
|
|
434
433
|
|
|
435
434
|
## Exports
|
|
436
435
|
|
|
@@ -443,17 +442,19 @@ For other environments, pass overrides via the `env` config option or `resolveEn
|
|
|
443
442
|
|
|
444
443
|
## Documentation
|
|
445
444
|
|
|
446
|
-
| Question
|
|
447
|
-
|
|
|
448
|
-
| How do I create a basic endpoint?
|
|
449
|
-
| What auth modes are available? Array syntax? Named keys?
|
|
450
|
-
| How do I
|
|
451
|
-
| How do I use
|
|
452
|
-
| How do
|
|
453
|
-
| How do I
|
|
454
|
-
| How do
|
|
455
|
-
| How do I
|
|
456
|
-
|
|
|
445
|
+
| Question | Doc file |
|
|
446
|
+
| ------------------------------------------------------------------- | ---------------------------------------------------------------- |
|
|
447
|
+
| How do I create a basic endpoint? | [`docs/getting-started.md`](docs/getting-started.md) |
|
|
448
|
+
| What auth modes are available? Array syntax? Named keys? | [`docs/auth-modes.md`](docs/auth-modes.md) |
|
|
449
|
+
| Which framework adapters exist? How do I contribute one? | [`src/adapters/README.md`](src/adapters/README.md) |
|
|
450
|
+
| How do I use this with Hono? | [`docs/adapters/hono.md`](docs/adapters/hono.md) |
|
|
451
|
+
| How do I use this with H3 / Nuxt? | [`docs/adapters/h3.md`](docs/adapters/h3.md) |
|
|
452
|
+
| How do I use low-level primitives for custom flows? | [`docs/core-primitives.md`](docs/core-primitives.md) |
|
|
453
|
+
| How do environment variables work across runtimes? | [`docs/environment-variables.md`](docs/environment-variables.md) |
|
|
454
|
+
| How do I handle errors? What codes exist? | [`docs/error-handling.md`](docs/error-handling.md) |
|
|
455
|
+
| How do I get typed database queries? | [`docs/typescript-generics.md`](docs/typescript-generics.md) |
|
|
456
|
+
| How do I use this with `@supabase/ssr` (Next.js, SvelteKit, Remix)? | [`docs/ssr-frameworks.md`](docs/ssr-frameworks.md) |
|
|
457
|
+
| What's the complete API surface? | [`docs/api-reference.md`](docs/api-reference.md) |
|
|
457
458
|
|
|
458
459
|
## Development
|
|
459
460
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
const require_create_supabase_context = require('../../create-supabase-context-
|
|
2
|
+
const require_create_supabase_context = require('../../create-supabase-context-B-2NDJhL.cjs');
|
|
3
3
|
let h3 = require("h3");
|
|
4
4
|
|
|
5
5
|
//#region src/adapters/h3/middleware.ts
|
|
@@ -18,7 +18,7 @@ let h3 = require("h3");
|
|
|
18
18
|
* import { withSupabase } from '@supabase/server/adapters/h3'
|
|
19
19
|
*
|
|
20
20
|
* const app = new H3()
|
|
21
|
-
* app.use(withSupabase({
|
|
21
|
+
* app.use(withSupabase({ auth: 'user' }))
|
|
22
22
|
*
|
|
23
23
|
* app.get('/games', async (event) => {
|
|
24
24
|
* const { supabase } = event.context.supabaseContext
|
|
@@ -34,7 +34,7 @@ let h3 = require("h3");
|
|
|
34
34
|
* import { withSupabase } from '@supabase/server/adapters/h3'
|
|
35
35
|
*
|
|
36
36
|
* export default defineHandler({
|
|
37
|
-
* middleware: [withSupabase({
|
|
37
|
+
* middleware: [withSupabase({ auth: 'user' })],
|
|
38
38
|
* handler: async (event) => {
|
|
39
39
|
* const { supabase } = event.context.supabaseContext
|
|
40
40
|
* return supabase.from('favorite_games').select()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as SupabaseContext, m as WithSupabaseConfig } from "../../types-u7fYLtzC.cjs";
|
|
2
2
|
import { Middleware } from "h3";
|
|
3
3
|
|
|
4
4
|
//#region src/adapters/h3/middleware.d.ts
|
|
@@ -17,7 +17,7 @@ import { Middleware } from "h3";
|
|
|
17
17
|
* import { withSupabase } from '@supabase/server/adapters/h3'
|
|
18
18
|
*
|
|
19
19
|
* const app = new H3()
|
|
20
|
-
* app.use(withSupabase({
|
|
20
|
+
* app.use(withSupabase({ auth: 'user' }))
|
|
21
21
|
*
|
|
22
22
|
* app.get('/games', async (event) => {
|
|
23
23
|
* const { supabase } = event.context.supabaseContext
|
|
@@ -33,7 +33,7 @@ import { Middleware } from "h3";
|
|
|
33
33
|
* import { withSupabase } from '@supabase/server/adapters/h3'
|
|
34
34
|
*
|
|
35
35
|
* export default defineHandler({
|
|
36
|
-
* middleware: [withSupabase({
|
|
36
|
+
* middleware: [withSupabase({ auth: 'user' })],
|
|
37
37
|
* handler: async (event) => {
|
|
38
38
|
* const { supabase } = event.context.supabaseContext
|
|
39
39
|
* return supabase.from('favorite_games').select()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as SupabaseContext, m as WithSupabaseConfig } from "../../types-B2yXZjmG.mjs";
|
|
2
2
|
import { Middleware } from "h3";
|
|
3
3
|
|
|
4
4
|
//#region src/adapters/h3/middleware.d.ts
|
|
@@ -17,7 +17,7 @@ import { Middleware } from "h3";
|
|
|
17
17
|
* import { withSupabase } from '@supabase/server/adapters/h3'
|
|
18
18
|
*
|
|
19
19
|
* const app = new H3()
|
|
20
|
-
* app.use(withSupabase({
|
|
20
|
+
* app.use(withSupabase({ auth: 'user' }))
|
|
21
21
|
*
|
|
22
22
|
* app.get('/games', async (event) => {
|
|
23
23
|
* const { supabase } = event.context.supabaseContext
|
|
@@ -33,7 +33,7 @@ import { Middleware } from "h3";
|
|
|
33
33
|
* import { withSupabase } from '@supabase/server/adapters/h3'
|
|
34
34
|
*
|
|
35
35
|
* export default defineHandler({
|
|
36
|
-
* middleware: [withSupabase({
|
|
36
|
+
* middleware: [withSupabase({ auth: 'user' })],
|
|
37
37
|
* handler: async (event) => {
|
|
38
38
|
* const { supabase } = event.context.supabaseContext
|
|
39
39
|
* return supabase.from('favorite_games').select()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as createSupabaseContext } from "../../create-supabase-context-
|
|
1
|
+
import { t as createSupabaseContext } from "../../create-supabase-context-BBZtr3D2.mjs";
|
|
2
2
|
import { HTTPError, defineMiddleware } from "h3";
|
|
3
3
|
|
|
4
4
|
//#region src/adapters/h3/middleware.ts
|
|
@@ -17,7 +17,7 @@ import { HTTPError, defineMiddleware } from "h3";
|
|
|
17
17
|
* import { withSupabase } from '@supabase/server/adapters/h3'
|
|
18
18
|
*
|
|
19
19
|
* const app = new H3()
|
|
20
|
-
* app.use(withSupabase({
|
|
20
|
+
* app.use(withSupabase({ auth: 'user' }))
|
|
21
21
|
*
|
|
22
22
|
* app.get('/games', async (event) => {
|
|
23
23
|
* const { supabase } = event.context.supabaseContext
|
|
@@ -33,7 +33,7 @@ import { HTTPError, defineMiddleware } from "h3";
|
|
|
33
33
|
* import { withSupabase } from '@supabase/server/adapters/h3'
|
|
34
34
|
*
|
|
35
35
|
* export default defineHandler({
|
|
36
|
-
* middleware: [withSupabase({
|
|
36
|
+
* middleware: [withSupabase({ auth: 'user' })],
|
|
37
37
|
* handler: async (event) => {
|
|
38
38
|
* const { supabase } = event.context.supabaseContext
|
|
39
39
|
* return supabase.from('favorite_games').select()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
const require_create_supabase_context = require('../../create-supabase-context-
|
|
2
|
+
const require_create_supabase_context = require('../../create-supabase-context-B-2NDJhL.cjs');
|
|
3
3
|
let hono_http_exception = require("hono/http-exception");
|
|
4
4
|
let hono_factory = require("hono/factory");
|
|
5
5
|
|
|
@@ -19,7 +19,7 @@ let hono_factory = require("hono/factory");
|
|
|
19
19
|
* import { withSupabase } from '@supabase/server/adapters/hono'
|
|
20
20
|
*
|
|
21
21
|
* const app = new Hono()
|
|
22
|
-
* app.use('*', withSupabase({
|
|
22
|
+
* app.use('*', withSupabase({ auth: 'user' }))
|
|
23
23
|
*
|
|
24
24
|
* app.get('/profile', async (c) => {
|
|
25
25
|
* const { supabase } = c.var.supabaseContext
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as SupabaseContext, m as WithSupabaseConfig } from "../../types-u7fYLtzC.cjs";
|
|
2
2
|
import { MiddlewareHandler } from "hono";
|
|
3
3
|
|
|
4
4
|
//#region src/adapters/hono/middleware.d.ts
|
|
@@ -17,7 +17,7 @@ import { MiddlewareHandler } from "hono";
|
|
|
17
17
|
* import { withSupabase } from '@supabase/server/adapters/hono'
|
|
18
18
|
*
|
|
19
19
|
* const app = new Hono()
|
|
20
|
-
* app.use('*', withSupabase({
|
|
20
|
+
* app.use('*', withSupabase({ auth: 'user' }))
|
|
21
21
|
*
|
|
22
22
|
* app.get('/profile', async (c) => {
|
|
23
23
|
* const { supabase } = c.var.supabaseContext
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as SupabaseContext, m as WithSupabaseConfig } from "../../types-B2yXZjmG.mjs";
|
|
2
2
|
import { MiddlewareHandler } from "hono";
|
|
3
3
|
|
|
4
4
|
//#region src/adapters/hono/middleware.d.ts
|
|
@@ -17,7 +17,7 @@ import { MiddlewareHandler } from "hono";
|
|
|
17
17
|
* import { withSupabase } from '@supabase/server/adapters/hono'
|
|
18
18
|
*
|
|
19
19
|
* const app = new Hono()
|
|
20
|
-
* app.use('*', withSupabase({
|
|
20
|
+
* app.use('*', withSupabase({ auth: 'user' }))
|
|
21
21
|
*
|
|
22
22
|
* app.get('/profile', async (c) => {
|
|
23
23
|
* const { supabase } = c.var.supabaseContext
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as createSupabaseContext } from "../../create-supabase-context-
|
|
1
|
+
import { t as createSupabaseContext } from "../../create-supabase-context-BBZtr3D2.mjs";
|
|
2
2
|
import { HTTPException } from "hono/http-exception";
|
|
3
3
|
import { createMiddleware } from "hono/factory";
|
|
4
4
|
|
|
@@ -18,7 +18,7 @@ import { createMiddleware } from "hono/factory";
|
|
|
18
18
|
* import { withSupabase } from '@supabase/server/adapters/hono'
|
|
19
19
|
*
|
|
20
20
|
* const app = new Hono()
|
|
21
|
-
* app.use('*', withSupabase({
|
|
21
|
+
* app.use('*', withSupabase({ auth: 'user' }))
|
|
22
22
|
*
|
|
23
23
|
* app.get('/profile', async (c) => {
|
|
24
24
|
* const { supabase } = c.var.supabaseContext
|
package/dist/core/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
const require_verify_auth = require('../verify-auth-
|
|
2
|
+
const require_verify_auth = require('../verify-auth-BKZK83Y8.cjs');
|
|
3
3
|
|
|
4
4
|
exports.createAdminClient = require_verify_auth.createAdminClient;
|
|
5
5
|
exports.createContextClient = require_verify_auth.createContextClient;
|
package/dist/core/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import { i as EnvError, t as AuthError } from "../errors-
|
|
1
|
+
import { a as AuthResult, c as CreateContextClientOptions, f as SupabaseEnv, i as AuthModeWithKey, l as Credentials, o as ClientAuth, s as CreateAdminClientOptions } from "../types-u7fYLtzC.cjs";
|
|
2
|
+
import { i as EnvError, t as AuthError } from "../errors-CZFEYnV_.cjs";
|
|
3
3
|
import { SupabaseClient } from "@supabase/supabase-js";
|
|
4
4
|
|
|
5
5
|
//#region src/core/resolve-env.d.ts
|
|
@@ -63,9 +63,17 @@ interface VerifyCredentialsOptions {
|
|
|
63
63
|
/**
|
|
64
64
|
* Auth mode(s) to try. Modes are attempted in order — the first match wins.
|
|
65
65
|
*
|
|
66
|
-
* @see {@link
|
|
66
|
+
* @see {@link AuthModeWithKey} for the full syntax including named keys.
|
|
67
|
+
*
|
|
68
|
+
* @defaultValue `"user"`
|
|
69
|
+
*/
|
|
70
|
+
auth?: AuthModeWithKey | AuthModeWithKey[];
|
|
71
|
+
/**
|
|
72
|
+
* @deprecated Use {@link VerifyCredentialsOptions.auth} instead. Kept for
|
|
73
|
+
* backward compatibility; will be removed in a future major release. When
|
|
74
|
+
* both are provided, `auth` wins.
|
|
67
75
|
*/
|
|
68
|
-
allow
|
|
76
|
+
allow?: AuthModeWithKey | AuthModeWithKey[];
|
|
69
77
|
/** Optional environment overrides (passed through to {@link resolveEnv}). */
|
|
70
78
|
env?: Partial<SupabaseEnv>;
|
|
71
79
|
}
|
|
@@ -86,7 +94,7 @@ interface VerifyCredentialsOptions {
|
|
|
86
94
|
* ```ts
|
|
87
95
|
* const credentials = extractCredentials(request)
|
|
88
96
|
* const { data: auth, error } = await verifyCredentials(credentials, {
|
|
89
|
-
*
|
|
97
|
+
* auth: ['user', 'publishable'],
|
|
90
98
|
* })
|
|
91
99
|
* if (error) {
|
|
92
100
|
* return Response.json({ message: error.message }, { status: error.status })
|
|
@@ -109,9 +117,17 @@ interface VerifyAuthOptions {
|
|
|
109
117
|
/**
|
|
110
118
|
* Auth mode(s) to try. Modes are attempted in order — the first match wins.
|
|
111
119
|
*
|
|
112
|
-
* @see {@link
|
|
120
|
+
* @see {@link AuthModeWithKey} for the full syntax including named keys.
|
|
121
|
+
*
|
|
122
|
+
* @defaultValue `"user"`
|
|
123
|
+
*/
|
|
124
|
+
auth?: AuthModeWithKey | AuthModeWithKey[];
|
|
125
|
+
/**
|
|
126
|
+
* @deprecated Use {@link VerifyAuthOptions.auth} instead. Kept for backward
|
|
127
|
+
* compatibility; will be removed in a future major release. When both are
|
|
128
|
+
* provided, `auth` wins.
|
|
113
129
|
*/
|
|
114
|
-
allow
|
|
130
|
+
allow?: AuthModeWithKey | AuthModeWithKey[];
|
|
115
131
|
/** Optional environment overrides (passed through to {@link resolveEnv}). */
|
|
116
132
|
env?: Partial<SupabaseEnv>;
|
|
117
133
|
}
|
|
@@ -134,7 +150,7 @@ interface VerifyAuthOptions {
|
|
|
134
150
|
* import { verifyAuth } from '@supabase/server/core'
|
|
135
151
|
*
|
|
136
152
|
* const { data: auth, error } = await verifyAuth(request, {
|
|
137
|
-
*
|
|
153
|
+
* auth: 'user',
|
|
138
154
|
* })
|
|
139
155
|
*
|
|
140
156
|
* if (error) {
|
|
@@ -163,7 +179,7 @@ declare function verifyAuth(request: Request, options: VerifyAuthOptions): Promi
|
|
|
163
179
|
*
|
|
164
180
|
* @example
|
|
165
181
|
* ```ts
|
|
166
|
-
* const { data: auth } = await verifyAuth(request, {
|
|
182
|
+
* const { data: auth } = await verifyAuth(request, { auth: 'user' })
|
|
167
183
|
* const supabase = createContextClient({
|
|
168
184
|
* auth: { token: auth.token, keyName: auth.keyName },
|
|
169
185
|
* })
|