Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 14 additions & 0 deletions docs/adapters/h3.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@ 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).

## Typing `event.context.supabaseContext`

The middleware stores the context on `event.context.supabaseContext`. Add this declaration once in your project (e.g. in `types/h3.d.ts`) for typed access:

```ts
import type { SupabaseContext } from '@supabase/server'

declare module 'h3' {
interface H3EventContext {
supabaseContext: SupabaseContext
}
}
```

## Basic app with auth

```ts
Expand Down
2 changes: 1 addition & 1 deletion src/adapters/elysia/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
* @packageDocumentation
*/

export { withSupabase } from './plugin.js'
export { SupabaseError, withSupabase } from './plugin.js'
38 changes: 35 additions & 3 deletions src/adapters/elysia/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Elysia } from 'elysia'
import { Elysia, type ExtractErrorFromHandle } from 'elysia'

import { createSupabaseContext } from '../../create-supabase-context.js'
import type { AuthError } from '../../errors.js'
import type { SupabaseContext, WithSupabaseConfig } from '../../types.js'

class SupabaseError extends Error {
export class SupabaseError extends Error {
status: number
declare cause: AuthError
constructor(inner: AuthError) {
Expand Down Expand Up @@ -56,7 +56,39 @@ class SupabaseError extends Error {
* app.listen(3000)
* ```
*/
export function withSupabase(config?: Omit<WithSupabaseConfig, 'cors'>) {
// The explicit return type below mirrors Elysia's own generic defaults, which use
// `{}` literals — switching to `object` or `Record<string, never>` would not satisfy
// the corresponding generic constraints.
/* eslint-disable @typescript-eslint/no-empty-object-type */
export function withSupabase(config?: Omit<WithSupabaseConfig, 'cors'>): Elysia<
'',
{ decorator: {}; store: {}; derive: {}; resolve: {} },
{ typebox: {}; error: { readonly SupabaseError: SupabaseError } },
{
schema: {}
standaloneSchema: {}
macro: {}
macroFn: {}
parser: {}
response: {}
},
{},
{
derive: {}
resolve: { supabaseContext: SupabaseContext }
schema: {}
standaloneSchema: {}
response: ExtractErrorFromHandle<{ supabaseContext: SupabaseContext }>
},
{
derive: {}
resolve: {}
schema: {}
standaloneSchema: {}
response: {}
}
> {
/* eslint-enable @typescript-eslint/no-empty-object-type */
return new Elysia()
.error({ SupabaseError })
.resolve(async (ctx): Promise<{ supabaseContext: SupabaseContext }> => {
Expand Down
8 changes: 8 additions & 0 deletions src/adapters/h3/middleware.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import { H3, HTTPError, onError } from 'h3'
import { describe, expect, it } from 'vitest'

import type { SupabaseContext } from '../../types.js'

import { withSupabase } from './middleware.js'

declare module 'h3' {
interface H3EventContext {
supabaseContext: SupabaseContext
}
}

describe('h3 supabase middleware', () => {
const env = {
url: 'https://test.supabase.co',
Expand Down
11 changes: 3 additions & 8 deletions src/adapters/h3/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,13 @@ export function withSupabase(
config?: Omit<WithSupabaseConfig, 'cors'>,
): Middleware {
return defineMiddleware(async (event, next) => {
if (event.context.supabaseContext) return next()
const context = event.context as { supabaseContext?: SupabaseContext }
if (context.supabaseContext) return next()
const { data: ctx, error } = await createSupabaseContext(event.req, config)
if (error) {
throw new HTTPError(error.message, { status: error.status, cause: error })
}
event.context.supabaseContext = ctx
context.supabaseContext = ctx
return next()
})
}

declare module 'h3' {
interface H3EventContext {
supabaseContext: SupabaseContext
}
}
Loading