@supabase/server 1.1.0-rc.63 → 1.1.0-rc.65

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 CHANGED
@@ -5,7 +5,7 @@
5
5
  [![pkg.pr.new](https://pkg.pr.new/badge/supabase/server)](https://pkg.pr.new/~/supabase/server)
6
6
  [![Docs](https://img.shields.io/badge/docs-supabase.github.io-3ECF8E?logo=readthedocs&logoColor=white)](https://supabase.github.io/server/)
7
7
 
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).
8
+ > **v1.X — 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
9
 
10
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`, …).
11
11
 
@@ -262,40 +262,59 @@ withSupabase(
262
262
 
263
263
  ## Framework Adapters
264
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.
265
+ Adapters wrap `withSupabase` for a specific framework's middleware contract. They ship inside `@supabase/server`, so a single `npm install @supabase/server` covers the framework you're using no separate package per adapter.
266
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) |
267
+ > **Adapters are a community-driven initiative.** They're developed, maintained, and evolved by contributors — including responding to upstream framework changes. See [`src/adapters/README.md`](src/adapters/README.md) for the contribution requirements (tests, types, docs, build wiring) if you'd like to add or help maintain one.
271
268
 
272
- ### Hono
269
+ | Framework | Import | Framework version | Docs |
270
+ | --------- | ---------------------------------- | ----------------- | -------------------------------------------------- |
271
+ | Hono | `@supabase/server/adapters/hono` | `^4.0.0` | [docs/adapters/hono.md](docs/adapters/hono.md) |
272
+ | H3 / Nuxt | `@supabase/server/adapters/h3` | `^2.0.0` | [docs/adapters/h3.md](docs/adapters/h3.md) |
273
+ | Elysia | `@supabase/server/adapters/elysia` | `^1.4.0` | [docs/adapters/elysia.md](docs/adapters/elysia.md) |
273
274
 
274
- ```ts
275
- import { Hono } from 'hono'
276
- import { withSupabase } from '@supabase/server/adapters/hono'
275
+ See the per-adapter docs above for setup, per-route auth, CORS, error handling, and other patterns.
277
276
 
278
- const app = new Hono()
279
- app.use('*', withSupabase({ auth: 'user' }))
277
+ ### Elysia
280
278
 
281
- export default { fetch: app.fetch }
282
- ```
279
+ ```ts
280
+ import { Elysia } from 'elysia'
281
+ import { withSupabase } from '@supabase/server/adapters/elysia'
282
+
283
+ const app = new Elysia()
284
+ // Protected — plugin resolves supabaseContext before handlers run
285
+ .use(withSupabase({ auth: 'user' }))
286
+ .get('/games', async ({ supabaseContext }) => {
287
+ const { data: myGames } = await supabaseContext.supabase
288
+ .from('favorite_games')
289
+ .select()
290
+ return myGames
291
+ })
292
+ // Public — no plugin means no auth
293
+ .get('/health', () => ({ status: 'ok' }))
283
294
 
284
- See [docs/adapters/hono.md](docs/adapters/hono.md) for per-route auth, CORS, error handling, and other patterns.
295
+ app.listen(3000)
296
+ ```
285
297
 
286
- ### H3 / Nuxt
298
+ For per-route auth, use scoped groups:
287
299
 
288
300
  ```ts
289
- import { H3 } from 'h3'
290
- import { withSupabase } from '@supabase/server/adapters/h3'
291
-
292
- const app = new H3()
293
- app.use(withSupabase({ auth: 'user' }))
294
-
295
- export default { fetch: app.fetch }
301
+ import { Elysia } from 'elysia'
302
+ import { withSupabase } from '@supabase/server/adapters/elysia'
303
+
304
+ const app = new Elysia()
305
+ .get('/health', () => ({ status: 'ok' }))
306
+ .group('/api', (app) =>
307
+ app
308
+ .use(withSupabase({ auth: 'user' }))
309
+ .get('/profile', async ({ supabaseContext }) => {
310
+ return supabaseContext.userClaims
311
+ }),
312
+ )
313
+
314
+ app.listen(3000)
296
315
  ```
297
316
 
298
- See [docs/adapters/h3.md](docs/adapters/h3.md) for per-route auth, Nuxt server-middleware patterns, CORS, and more.
317
+ The adapter does not handle CORS use `@elysiajs/cors` for that.
299
318
 
300
319
  ## Primitives
301
320
 
@@ -421,12 +440,17 @@ For other environments, pass overrides via the `env` config option or `resolveEn
421
440
 
422
441
  ## Runtimes
423
442
 
424
- - **Supabase Edge Functions**environment variables are auto-injected. Zero config.
425
- - **Deno / Bun** — works out of the box with the `export default { fetch }` pattern.
426
- - **Node.js** — use the [Hono adapter](#hono), [H3 adapter](#h3--nuxt), or [core primitives](#primitives) with your framework of choice.
427
- - **Cloudflare Workers** enable `nodejs_compat` in `wrangler.toml` or pass env overrides via the `env` config option.
428
- - **Nuxt** use the [H3 adapter](#h3--nuxt) directly as a server middleware.
429
- - **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).
443
+ `@supabase/server` runs anywhere standard Web `fetch` does pick the row that matches your deployment target.
444
+
445
+ | Target | Notes |
446
+ | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
447
+ | **Supabase Edge Functions** | Zero config environment variables are auto-injected. |
448
+ | **Vercel Functions** | Edge runtime: `export default { fetch }`. Node runtime: use a [framework adapter](#framework-adapters) or [core primitives](#primitives). |
449
+ | **Cloudflare Workers** | Enable `nodejs_compat` in `wrangler.toml`, or pass overrides via the `env` config option. |
450
+ | **Deno / Bun** | Works out of the box via `export default { fetch }`. |
451
+ | **Node.js** | Use a [framework adapter](#framework-adapters) or [core primitives](#primitives) with your framework of choice. |
452
+
453
+ Using a framework? See [Framework Adapters](#framework-adapters) for Hono, H3 / Nuxt, and Elysia, or [`docs/ssr-frameworks.md`](docs/ssr-frameworks.md) for Next.js / SvelteKit / Remix (compose with [`@supabase/ssr`](https://github.com/supabase/ssr)).
430
454
 
431
455
  ### Does this replace `@supabase/ssr`?
432
456
 
@@ -434,12 +458,13 @@ No. `@supabase/ssr` handles cookie-based session management for frameworks like
434
458
 
435
459
  ## Exports
436
460
 
437
- | Export | What's in it |
438
- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
439
- | `@supabase/server` | `withSupabase`, `createSupabaseContext` |
440
- | `@supabase/server/core` | `verifyAuth`, `verifyCredentials`, `extractCredentials`, `createContextClient`, `createAdminClient`, `resolveEnv` |
441
- | `@supabase/server/adapters/hono` | `withSupabase` (Hono middleware) |
442
- | `@supabase/server/adapters/h3` | `withSupabase` (H3 / Nuxt middleware) |
461
+ | Export | What's in it |
462
+ | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
463
+ | `@supabase/server` | `withSupabase`, `createSupabaseContext` |
464
+ | `@supabase/server/core` | `verifyAuth`, `verifyCredentials`, `extractCredentials`, `createContextClient`, `createAdminClient`, `resolveEnv` |
465
+ | `@supabase/server/adapters/hono` | `withSupabase` (Hono middleware) |
466
+ | `@supabase/server/adapters/h3` | `withSupabase` (H3 / Nuxt middleware) |
467
+ | `@supabase/server/adapters/elysia` | `withSupabase` (Elysia plugin) |
443
468
 
444
469
  ## Documentation
445
470
 
@@ -450,6 +475,7 @@ No. `@supabase/ssr` handles cookie-based session management for frameworks like
450
475
  | Which framework adapters exist? How do I contribute one? | [`src/adapters/README.md`](src/adapters/README.md) |
451
476
  | How do I use this with Hono? | [`docs/adapters/hono.md`](docs/adapters/hono.md) |
452
477
  | How do I use this with H3 / Nuxt? | [`docs/adapters/h3.md`](docs/adapters/h3.md) |
478
+ | How do I use this with Elysia? | [`docs/adapters/elysia.md`](docs/adapters/elysia.md) |
453
479
  | How do I use low-level primitives for custom flows? | [`docs/core-primitives.md`](docs/core-primitives.md) |
454
480
  | How do environment variables work across runtimes? | [`docs/environment-variables.md`](docs/environment-variables.md) |
455
481
  | How do I handle errors? What codes exist? | [`docs/error-handling.md`](docs/error-handling.md) |
@@ -0,0 +1,66 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_create_supabase_context = require('../../create-supabase-context-CKv-4AIg.cjs');
3
+ let elysia = require("elysia");
4
+
5
+ //#region src/adapters/elysia/plugin.ts
6
+ var SupabaseError = class extends Error {
7
+ constructor(inner) {
8
+ super(inner.message, { cause: inner });
9
+ this.status = inner.status;
10
+ }
11
+ };
12
+ /**
13
+ * Elysia plugin that creates a {@link SupabaseContext} and makes it available in route handlers.
14
+ *
15
+ * Skips if a previous plugin already set the context, enabling route-level overrides.
16
+ * Throws a `SupabaseError` on auth failure. `.status` is on the error directly; the original
17
+ * `AuthError` is available as the typed `.cause`. Discriminate in `onError` via `code === 'SupabaseError'`.
18
+ *
19
+ * @param config - Auth modes and optional environment overrides. CORS is excluded — use Elysia's CORS utilities.
20
+ * @returns An Elysia plugin that exposes `supabaseContext`.
21
+ *
22
+ * @example App-wide auth via `.use()`
23
+ * ```ts
24
+ * import { Elysia } from 'elysia'
25
+ * import { withSupabase } from '@supabase/server/adapters/elysia'
26
+ *
27
+ * const app = new Elysia()
28
+ * .use(withSupabase({ allow: 'user' }))
29
+ * .get('/games', async ({ supabaseContext }) => {
30
+ * const { data } = await supabaseContext.supabase.from('favorite_games').select()
31
+ * return data
32
+ * })
33
+ *
34
+ * app.listen(3000)
35
+ * ```
36
+ *
37
+ * @example Per-route auth via scoped `.use()`
38
+ * ```ts
39
+ * import { Elysia } from 'elysia'
40
+ * import { withSupabase } from '@supabase/server/adapters/elysia'
41
+ *
42
+ * const app = new Elysia()
43
+ * .get('/health', () => ({ status: 'ok' }))
44
+ * .group('/api', (app) =>
45
+ * app
46
+ * .use(withSupabase({ allow: 'user' }))
47
+ * .get('/profile', async ({ supabaseContext }) => {
48
+ * return supabaseContext.userClaims
49
+ * })
50
+ * )
51
+ *
52
+ * app.listen(3000)
53
+ * ```
54
+ */
55
+ function withSupabase(config) {
56
+ return new elysia.Elysia().error({ SupabaseError }).resolve(async (ctx) => {
57
+ const existing = ctx.supabaseContext;
58
+ if (existing) return { supabaseContext: existing };
59
+ const { data, error } = await require_create_supabase_context.createSupabaseContext(ctx.request, config);
60
+ if (error) throw new SupabaseError(error);
61
+ return { supabaseContext: data };
62
+ }).as("scoped");
63
+ }
64
+
65
+ //#endregion
66
+ exports.withSupabase = withSupabase;
@@ -0,0 +1,90 @@
1
+ import { t as AuthError } from "../../errors-fa-CyugW.cjs";
2
+ import { d as SupabaseContext, m as WithSupabaseConfig } from "../../types-CwKZOVIv.cjs";
3
+ import * as elysia from "elysia";
4
+ import { Elysia } from "elysia";
5
+
6
+ //#region src/adapters/elysia/plugin.d.ts
7
+ declare class SupabaseError extends Error {
8
+ status: number;
9
+ cause: AuthError;
10
+ constructor(inner: AuthError);
11
+ }
12
+ /**
13
+ * Elysia plugin that creates a {@link SupabaseContext} and makes it available in route handlers.
14
+ *
15
+ * Skips if a previous plugin already set the context, enabling route-level overrides.
16
+ * Throws a `SupabaseError` on auth failure. `.status` is on the error directly; the original
17
+ * `AuthError` is available as the typed `.cause`. Discriminate in `onError` via `code === 'SupabaseError'`.
18
+ *
19
+ * @param config - Auth modes and optional environment overrides. CORS is excluded — use Elysia's CORS utilities.
20
+ * @returns An Elysia plugin that exposes `supabaseContext`.
21
+ *
22
+ * @example App-wide auth via `.use()`
23
+ * ```ts
24
+ * import { Elysia } from 'elysia'
25
+ * import { withSupabase } from '@supabase/server/adapters/elysia'
26
+ *
27
+ * const app = new Elysia()
28
+ * .use(withSupabase({ allow: 'user' }))
29
+ * .get('/games', async ({ supabaseContext }) => {
30
+ * const { data } = await supabaseContext.supabase.from('favorite_games').select()
31
+ * return data
32
+ * })
33
+ *
34
+ * app.listen(3000)
35
+ * ```
36
+ *
37
+ * @example Per-route auth via scoped `.use()`
38
+ * ```ts
39
+ * import { Elysia } from 'elysia'
40
+ * import { withSupabase } from '@supabase/server/adapters/elysia'
41
+ *
42
+ * const app = new Elysia()
43
+ * .get('/health', () => ({ status: 'ok' }))
44
+ * .group('/api', (app) =>
45
+ * app
46
+ * .use(withSupabase({ allow: 'user' }))
47
+ * .get('/profile', async ({ supabaseContext }) => {
48
+ * return supabaseContext.userClaims
49
+ * })
50
+ * )
51
+ *
52
+ * app.listen(3000)
53
+ * ```
54
+ */
55
+ declare function withSupabase(config?: Omit<WithSupabaseConfig, 'cors'>): Elysia<"", {
56
+ decorator: {};
57
+ store: {};
58
+ derive: {};
59
+ resolve: {};
60
+ }, {
61
+ typebox: {};
62
+ error: {
63
+ readonly SupabaseError: SupabaseError;
64
+ };
65
+ }, {
66
+ schema: {};
67
+ standaloneSchema: {};
68
+ macro: {};
69
+ macroFn: {};
70
+ parser: {};
71
+ response: {};
72
+ }, {}, {
73
+ derive: {};
74
+ resolve: {
75
+ supabaseContext: SupabaseContext;
76
+ };
77
+ schema: {};
78
+ standaloneSchema: {};
79
+ response: elysia.ExtractErrorFromHandle<{
80
+ supabaseContext: SupabaseContext;
81
+ }>;
82
+ }, {
83
+ derive: {};
84
+ resolve: {};
85
+ schema: {};
86
+ standaloneSchema: {};
87
+ response: {};
88
+ }>;
89
+ //#endregion
90
+ export { withSupabase };
@@ -0,0 +1,90 @@
1
+ import { t as AuthError } from "../../errors-C43um2Gg.mjs";
2
+ import { d as SupabaseContext, m as WithSupabaseConfig } from "../../types-DbvLfq25.mjs";
3
+ import * as elysia from "elysia";
4
+ import { Elysia } from "elysia";
5
+
6
+ //#region src/adapters/elysia/plugin.d.ts
7
+ declare class SupabaseError extends Error {
8
+ status: number;
9
+ cause: AuthError;
10
+ constructor(inner: AuthError);
11
+ }
12
+ /**
13
+ * Elysia plugin that creates a {@link SupabaseContext} and makes it available in route handlers.
14
+ *
15
+ * Skips if a previous plugin already set the context, enabling route-level overrides.
16
+ * Throws a `SupabaseError` on auth failure. `.status` is on the error directly; the original
17
+ * `AuthError` is available as the typed `.cause`. Discriminate in `onError` via `code === 'SupabaseError'`.
18
+ *
19
+ * @param config - Auth modes and optional environment overrides. CORS is excluded — use Elysia's CORS utilities.
20
+ * @returns An Elysia plugin that exposes `supabaseContext`.
21
+ *
22
+ * @example App-wide auth via `.use()`
23
+ * ```ts
24
+ * import { Elysia } from 'elysia'
25
+ * import { withSupabase } from '@supabase/server/adapters/elysia'
26
+ *
27
+ * const app = new Elysia()
28
+ * .use(withSupabase({ allow: 'user' }))
29
+ * .get('/games', async ({ supabaseContext }) => {
30
+ * const { data } = await supabaseContext.supabase.from('favorite_games').select()
31
+ * return data
32
+ * })
33
+ *
34
+ * app.listen(3000)
35
+ * ```
36
+ *
37
+ * @example Per-route auth via scoped `.use()`
38
+ * ```ts
39
+ * import { Elysia } from 'elysia'
40
+ * import { withSupabase } from '@supabase/server/adapters/elysia'
41
+ *
42
+ * const app = new Elysia()
43
+ * .get('/health', () => ({ status: 'ok' }))
44
+ * .group('/api', (app) =>
45
+ * app
46
+ * .use(withSupabase({ allow: 'user' }))
47
+ * .get('/profile', async ({ supabaseContext }) => {
48
+ * return supabaseContext.userClaims
49
+ * })
50
+ * )
51
+ *
52
+ * app.listen(3000)
53
+ * ```
54
+ */
55
+ declare function withSupabase(config?: Omit<WithSupabaseConfig, 'cors'>): Elysia<"", {
56
+ decorator: {};
57
+ store: {};
58
+ derive: {};
59
+ resolve: {};
60
+ }, {
61
+ typebox: {};
62
+ error: {
63
+ readonly SupabaseError: SupabaseError;
64
+ };
65
+ }, {
66
+ schema: {};
67
+ standaloneSchema: {};
68
+ macro: {};
69
+ macroFn: {};
70
+ parser: {};
71
+ response: {};
72
+ }, {}, {
73
+ derive: {};
74
+ resolve: {
75
+ supabaseContext: SupabaseContext;
76
+ };
77
+ schema: {};
78
+ standaloneSchema: {};
79
+ response: elysia.ExtractErrorFromHandle<{
80
+ supabaseContext: SupabaseContext;
81
+ }>;
82
+ }, {
83
+ derive: {};
84
+ resolve: {};
85
+ schema: {};
86
+ standaloneSchema: {};
87
+ response: {};
88
+ }>;
89
+ //#endregion
90
+ export { withSupabase };
@@ -0,0 +1,65 @@
1
+ import { t as createSupabaseContext } from "../../create-supabase-context-BxSEJN8a.mjs";
2
+ import { Elysia } from "elysia";
3
+
4
+ //#region src/adapters/elysia/plugin.ts
5
+ var SupabaseError = class extends Error {
6
+ constructor(inner) {
7
+ super(inner.message, { cause: inner });
8
+ this.status = inner.status;
9
+ }
10
+ };
11
+ /**
12
+ * Elysia plugin that creates a {@link SupabaseContext} and makes it available in route handlers.
13
+ *
14
+ * Skips if a previous plugin already set the context, enabling route-level overrides.
15
+ * Throws a `SupabaseError` on auth failure. `.status` is on the error directly; the original
16
+ * `AuthError` is available as the typed `.cause`. Discriminate in `onError` via `code === 'SupabaseError'`.
17
+ *
18
+ * @param config - Auth modes and optional environment overrides. CORS is excluded — use Elysia's CORS utilities.
19
+ * @returns An Elysia plugin that exposes `supabaseContext`.
20
+ *
21
+ * @example App-wide auth via `.use()`
22
+ * ```ts
23
+ * import { Elysia } from 'elysia'
24
+ * import { withSupabase } from '@supabase/server/adapters/elysia'
25
+ *
26
+ * const app = new Elysia()
27
+ * .use(withSupabase({ allow: 'user' }))
28
+ * .get('/games', async ({ supabaseContext }) => {
29
+ * const { data } = await supabaseContext.supabase.from('favorite_games').select()
30
+ * return data
31
+ * })
32
+ *
33
+ * app.listen(3000)
34
+ * ```
35
+ *
36
+ * @example Per-route auth via scoped `.use()`
37
+ * ```ts
38
+ * import { Elysia } from 'elysia'
39
+ * import { withSupabase } from '@supabase/server/adapters/elysia'
40
+ *
41
+ * const app = new Elysia()
42
+ * .get('/health', () => ({ status: 'ok' }))
43
+ * .group('/api', (app) =>
44
+ * app
45
+ * .use(withSupabase({ allow: 'user' }))
46
+ * .get('/profile', async ({ supabaseContext }) => {
47
+ * return supabaseContext.userClaims
48
+ * })
49
+ * )
50
+ *
51
+ * app.listen(3000)
52
+ * ```
53
+ */
54
+ function withSupabase(config) {
55
+ return new Elysia().error({ SupabaseError }).resolve(async (ctx) => {
56
+ const existing = ctx.supabaseContext;
57
+ if (existing) return { supabaseContext: existing };
58
+ const { data, error } = await createSupabaseContext(ctx.request, config);
59
+ if (error) throw new SupabaseError(error);
60
+ return { supabaseContext: data };
61
+ }).as("scoped");
62
+ }
63
+
64
+ //#endregion
65
+ export { withSupabase };
@@ -1,4 +1,4 @@
1
- import { d as SupabaseContext, m as WithSupabaseConfig } from "../../types-Bjy1j07i.cjs";
1
+ import { d as SupabaseContext, m as WithSupabaseConfig } from "../../types-CwKZOVIv.cjs";
2
2
  import { Middleware } from "h3";
3
3
 
4
4
  //#region src/adapters/h3/middleware.d.ts
@@ -1,4 +1,4 @@
1
- import { d as SupabaseContext, m as WithSupabaseConfig } from "../../types-DP9l5Cvf.mjs";
1
+ import { d as SupabaseContext, m as WithSupabaseConfig } from "../../types-DbvLfq25.mjs";
2
2
  import { Middleware } from "h3";
3
3
 
4
4
  //#region src/adapters/h3/middleware.d.ts
@@ -1,4 +1,4 @@
1
- import { d as SupabaseContext, m as WithSupabaseConfig } from "../../types-Bjy1j07i.cjs";
1
+ import { d as SupabaseContext, m as WithSupabaseConfig } from "../../types-CwKZOVIv.cjs";
2
2
  import { MiddlewareHandler } from "hono";
3
3
 
4
4
  //#region src/adapters/hono/middleware.d.ts
@@ -1,4 +1,4 @@
1
- import { d as SupabaseContext, m as WithSupabaseConfig } from "../../types-DP9l5Cvf.mjs";
1
+ import { d as SupabaseContext, m as WithSupabaseConfig } from "../../types-DbvLfq25.mjs";
2
2
  import { MiddlewareHandler } from "hono";
3
3
 
4
4
  //#region src/adapters/hono/middleware.d.ts
@@ -1,5 +1,5 @@
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-Bjy1j07i.cjs";
2
- import { i as EnvError, t as AuthError } from "../errors-CZFEYnV_.cjs";
1
+ import { i as EnvError, t as AuthError } from "../errors-fa-CyugW.cjs";
2
+ import { a as AuthResult, c as CreateContextClientOptions, f as SupabaseEnv, i as AuthModeWithKey, l as Credentials, o as ClientAuth, s as CreateAdminClientOptions } from "../types-CwKZOVIv.cjs";
3
3
  import { SupabaseClient } from "@supabase/supabase-js";
4
4
 
5
5
  //#region src/core/resolve-env.d.ts
@@ -1,5 +1,5 @@
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-DP9l5Cvf.mjs";
2
- import { i as EnvError, t as AuthError } from "../errors-0dbzn5gA.mjs";
1
+ import { i as EnvError, t as AuthError } from "../errors-C43um2Gg.mjs";
2
+ import { a as AuthResult, c as CreateContextClientOptions, f as SupabaseEnv, i as AuthModeWithKey, l as Credentials, o as ClientAuth, s as CreateAdminClientOptions } from "../types-DbvLfq25.mjs";
3
3
  import { SupabaseClient } from "@supabase/supabase-js";
4
4
 
5
5
  //#region src/core/resolve-env.d.ts
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as AuthResult, c as CreateContextClientOptions, d as SupabaseContext, f as SupabaseEnv, i as AuthModeWithKey, l as Credentials, m as WithSupabaseConfig, n as AllowWithKey, o as ClientAuth, p as UserClaims, r as AuthMode, s as CreateAdminClientOptions, t as Allow, u as JWTClaims } from "./types-Bjy1j07i.cjs";
2
- import { a as EnvGenericError, c as MissingDefaultPublishableKeyError, d as MissingSecretKeyError, f as MissingSupabaseURLError, i as EnvError, l as MissingDefaultSecretKeyError, n as AuthGenericError, o as Errors, r as CreateSupabaseClientError, s as InvalidCredentialsError, t as AuthError, u as MissingPublishableKeyError } from "./errors-CZFEYnV_.cjs";
1
+ import { a as EnvGenericError, c as MissingDefaultPublishableKeyError, d as MissingSecretKeyError, f as MissingSupabaseURLError, i as EnvError, l as MissingDefaultSecretKeyError, n as AuthGenericError, o as Errors, r as CreateSupabaseClientError, s as InvalidCredentialsError, t as AuthError, u as MissingPublishableKeyError } from "./errors-fa-CyugW.cjs";
2
+ import { a as AuthResult, c as CreateContextClientOptions, d as SupabaseContext, f as SupabaseEnv, i as AuthModeWithKey, l as Credentials, m as WithSupabaseConfig, n as AllowWithKey, o as ClientAuth, p as UserClaims, r as AuthMode, s as CreateAdminClientOptions, t as Allow, u as JWTClaims } from "./types-CwKZOVIv.cjs";
3
3
 
4
4
  //#region src/with-supabase.d.ts
5
5
  /**
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as AuthResult, c as CreateContextClientOptions, d as SupabaseContext, f as SupabaseEnv, i as AuthModeWithKey, l as Credentials, m as WithSupabaseConfig, n as AllowWithKey, o as ClientAuth, p as UserClaims, r as AuthMode, s as CreateAdminClientOptions, t as Allow, u as JWTClaims } from "./types-DP9l5Cvf.mjs";
2
- import { a as EnvGenericError, c as MissingDefaultPublishableKeyError, d as MissingSecretKeyError, f as MissingSupabaseURLError, i as EnvError, l as MissingDefaultSecretKeyError, n as AuthGenericError, o as Errors, r as CreateSupabaseClientError, s as InvalidCredentialsError, t as AuthError, u as MissingPublishableKeyError } from "./errors-0dbzn5gA.mjs";
1
+ import { a as EnvGenericError, c as MissingDefaultPublishableKeyError, d as MissingSecretKeyError, f as MissingSupabaseURLError, i as EnvError, l as MissingDefaultSecretKeyError, n as AuthGenericError, o as Errors, r as CreateSupabaseClientError, s as InvalidCredentialsError, t as AuthError, u as MissingPublishableKeyError } from "./errors-C43um2Gg.mjs";
2
+ import { a as AuthResult, c as CreateContextClientOptions, d as SupabaseContext, f as SupabaseEnv, i as AuthModeWithKey, l as Credentials, m as WithSupabaseConfig, n as AllowWithKey, o as ClientAuth, p as UserClaims, r as AuthMode, s as CreateAdminClientOptions, t as Allow, u as JWTClaims } from "./types-DbvLfq25.mjs";
3
3
 
4
4
  //#region src/with-supabase.d.ts
5
5
  /**
@@ -0,0 +1,140 @@
1
+ # Elysia Adapter
2
+
3
+ ## Setup
4
+
5
+ Install Elysia as a peer dependency:
6
+
7
+ ```bash
8
+ pnpm add elysia
9
+ ```
10
+
11
+ The adapter exports its own `withSupabase` that returns an Elysia plugin instead of a fetch handler.
12
+
13
+ ## Basic app with auth
14
+
15
+ ```ts
16
+ import { Elysia } from 'elysia'
17
+ import { withSupabase } from '@supabase/server/adapters/elysia'
18
+
19
+ const app = new Elysia()
20
+ .use(withSupabase({ auth: 'user' }))
21
+ .get('/todos', async ({ supabaseContext }) => {
22
+ const { data } = await supabaseContext.supabase.from('todos').select()
23
+ return data
24
+ })
25
+
26
+ app.listen(3000)
27
+ ```
28
+
29
+ The context is available as `supabaseContext` in your route handlers and contains the same `SupabaseContext` fields as the main `withSupabase` wrapper: `supabase`, `supabaseAdmin`, `userClaims`, `jwtClaims`, and `authMode`.
30
+
31
+ ## Per-route auth
32
+
33
+ Apply different auth modes to different routes by using the plugin on scoped route groups:
34
+
35
+ ```ts
36
+ import { Elysia } from 'elysia'
37
+ import { withSupabase } from '@supabase/server/adapters/elysia'
38
+
39
+ const app = new Elysia()
40
+ // Public route — no auth
41
+ .get('/health', () => ({ status: 'ok' }))
42
+ // User-authenticated routes
43
+ .group('/api', (app) =>
44
+ app
45
+ .use(withSupabase({ auth: 'user' }))
46
+ .get('/todos', async ({ supabaseContext }) => {
47
+ const { data } = await supabaseContext.supabase.from('todos').select()
48
+ return data
49
+ }),
50
+ )
51
+ // Secret-key-protected admin routes
52
+ .group('/admin', (app) =>
53
+ app
54
+ .use(withSupabase({ auth: 'secret' }))
55
+ .post('/sync', async ({ supabaseContext }) => {
56
+ const { data } = await supabaseContext.supabaseAdmin
57
+ .from('audit_log')
58
+ .insert({ action: 'sync' })
59
+ return data
60
+ }),
61
+ )
62
+
63
+ app.listen(3000)
64
+ ```
65
+
66
+ ## Skip behavior
67
+
68
+ If a previous plugin already resolved `supabaseContext`, subsequent `withSupabase` calls skip auth. This allows chaining plugins without redundant work.
69
+
70
+ **Important:** The plugin calls `.as('scoped')` so its `resolve` hook propagates one level up to the parent app — routes registered after `.use(withSupabase(...))` will see `supabaseContext`. The skip-if-set pattern cannot make a route stricter than an already-resolved context.
71
+
72
+ For routes that need different auth than the rest of the app, use scoped `.group()` with `.use(withSupabase(...))` without an app-wide plugin (see the "Per-route auth" section above).
73
+
74
+ ## CORS
75
+
76
+ The Elysia adapter does not handle CORS — the `cors` option is excluded from its config type. Use Elysia's CORS plugin:
77
+
78
+ ```ts
79
+ import { Elysia } from 'elysia'
80
+ import { cors } from '@elysiajs/cors'
81
+ import { withSupabase } from '@supabase/server/adapters/elysia'
82
+
83
+ const app = new Elysia()
84
+ .use(cors())
85
+ .use(withSupabase({ auth: 'user' }))
86
+ .get('/todos', async ({ supabaseContext }) => {
87
+ const { data } = await supabaseContext.supabase.from('todos').select()
88
+ return data
89
+ })
90
+
91
+ app.listen(3000)
92
+ ```
93
+
94
+ ## Error handling
95
+
96
+ When auth fails, the plugin throws a `SupabaseError`. The HTTP status is on `.status` directly, and the original `AuthError` is available as the typed `.cause`. Discriminate in `onError` via `code === 'SupabaseError'`:
97
+
98
+ ```ts
99
+ import { Elysia } from 'elysia'
100
+ import { withSupabase } from '@supabase/server/adapters/elysia'
101
+
102
+ const app = new Elysia()
103
+ .use(withSupabase({ auth: 'user' }))
104
+ .onError(({ code, error, status }) => {
105
+ if (code !== 'SupabaseError') return
106
+ return status(error.status as 401, {
107
+ error: error.message,
108
+ code: error.cause.code,
109
+ })
110
+ })
111
+ .get('/todos', async ({ supabaseContext }) => {
112
+ const { data } = await supabaseContext.supabase.from('todos').select()
113
+ return data
114
+ })
115
+
116
+ app.listen(3000)
117
+ ```
118
+
119
+ Without a custom `onError`, Elysia uses the `status` property on the thrown `SupabaseError` to set the response status automatically (401 for auth failures, 500 for internal errors).
120
+
121
+ ## Environment overrides
122
+
123
+ Pass `env` to override auto-detected environment variables, same as the main wrapper:
124
+
125
+ ```ts
126
+ app.use(withSupabase({ auth: 'user', env: { url: 'http://localhost:54321' } }))
127
+ ```
128
+
129
+ ## Supabase client options
130
+
131
+ Forward options to the underlying `createClient()` calls:
132
+
133
+ ```ts
134
+ app.use(
135
+ withSupabase({
136
+ auth: 'user',
137
+ supabaseOptions: { db: { schema: 'api' } },
138
+ }),
139
+ )
140
+ ```
@@ -134,6 +134,38 @@ Defaults to `auth: 'user'` when config is omitted.
134
134
 
135
135
  ---
136
136
 
137
+ ## @supabase/server/adapters/h3
138
+
139
+ ### withSupabase (H3)
140
+
141
+ ```ts
142
+ function withSupabase(config?: Omit<WithSupabaseConfig, 'cors'>): Middleware
143
+ ```
144
+
145
+ H3 middleware. Sets `event.context.supabaseContext` on the H3 event. Throws `HTTPError` on auth failure with `cause: AuthError`.
146
+
147
+ Skips if `event.context.supabaseContext` is already set (enables chained middleware).
148
+
149
+ Defaults to `auth: 'user'` when config is omitted.
150
+
151
+ ---
152
+
153
+ ## @supabase/server/adapters/elysia
154
+
155
+ ### withSupabase (Elysia)
156
+
157
+ ```ts
158
+ function withSupabase(config?: Omit<WithSupabaseConfig, 'cors'>): Elysia
159
+ ```
160
+
161
+ Elysia plugin that resolves `supabaseContext` into the request context. Throws an error on auth failure with `cause: AuthError`.
162
+
163
+ Skips if `supabaseContext` is already resolved by a prior plugin.
164
+
165
+ Defaults to `auth: 'user'` when config is omitted.
166
+
167
+ ---
168
+
137
169
  ## Types
138
170
 
139
171
  ### AuthMode
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supabase/server",
3
- "version": "1.1.0-rc.63",
3
+ "version": "1.1.0-rc.65",
4
4
  "description": "Server-side utilities for Supabase. Handles auth, client creation, and context injection so you write business logic, not boilerplate.",
5
5
  "keywords": [
6
6
  "edge",
@@ -39,6 +39,11 @@
39
39
  "import": "./dist/adapters/h3/index.mjs",
40
40
  "require": "./dist/adapters/h3/index.cjs"
41
41
  },
42
+ "./adapters/elysia": {
43
+ "types": "./dist/adapters/elysia/index.d.mts",
44
+ "import": "./dist/adapters/elysia/index.mjs",
45
+ "require": "./dist/adapters/elysia/index.cjs"
46
+ },
42
47
  "./package.json": "./package.json"
43
48
  },
44
49
  "main": "./dist/index.cjs",
@@ -72,7 +77,8 @@
72
77
  "peerDependencies": {
73
78
  "@supabase/supabase-js": "^2.0.0",
74
79
  "h3": "^2.0.0",
75
- "hono": "^4.0.0"
80
+ "hono": "^4.0.0",
81
+ "elysia": "^1.4.0"
76
82
  },
77
83
  "peerDependenciesMeta": {
78
84
  "h3": {
@@ -80,6 +86,9 @@
80
86
  },
81
87
  "hono": {
82
88
  "optional": true
89
+ },
90
+ "elysia": {
91
+ "optional": true
83
92
  }
84
93
  },
85
94
  "devDependencies": {
@@ -87,6 +96,7 @@
87
96
  "@commitlint/config-conventional": "^20.4.2",
88
97
  "@supabase/supabase-js": "^2.105.4",
89
98
  "eslint": "^10.0.2",
99
+ "elysia": "^1.4.0",
90
100
  "h3": "2.0.1-rc.20",
91
101
  "hono": "^4.12.5",
92
102
  "prettier": "3.8.1",