Skip to content

Commit ca53801

Browse files
fix: add hono adapter Database type override (#100)
adds generic Database type override to hono adapter added test to ensure chained declarations preserve context type updated docs to include alternative hono declaration
1 parent 54f869e commit ca53801

3 files changed

Lines changed: 45 additions & 4 deletions

File tree

docs/typescript-generics.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,26 @@ app.get('/todos', async (c) => {
101101
})
102102
```
103103

104+
Alternatively, skip the `Env` type and thread `Database` through the `withSupabase<Database>()` generic when using chained declarations. Hono infers the `supabaseContext` variable type from the middleware, so `c.var.supabaseContext.supabase` is still a fully typed `SupabaseClient<Database>`. This plays a little nicer with hono [sub-application routes](https://hono.dev/docs/helpers/route#working-with-sub-applications).
105+
106+
```ts
107+
import { Hono } from 'hono'
108+
import { withSupabase } from '@supabase/server/adapters/hono'
109+
import type { Database } from './database.types.ts'
110+
111+
const app = new Hono()
112+
113+
const todosApp = new Hono()
114+
.use(withSupabase<Database>({ auth: 'user' }))
115+
.get('/', async (c) => {
116+
const { supabase } = c.var.supabaseContext
117+
const { data } = await supabase.from('todos').select('id, title')
118+
return c.json(data)
119+
})
120+
121+
app.route('/todos', todosApp)
122+
```
123+
104124
## Custom schema
105125

106126
If your tables are in a schema other than `public`, pass it via `supabaseOptions`:

src/adapters/hono/middleware.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,22 @@ describe('hono supabase middleware', () => {
6969
expect(res.status).toBe(200)
7070
})
7171

72+
it('uses the Hono adapter to type the Supabase context', async () => {
73+
// match docs example in typescript-generics.md
74+
const app = new Hono()
75+
const rootApp = new Hono()
76+
.use(withSupabase<Database>({ auth: 'none', env }))
77+
.get('/', (c) => {
78+
const ctx = c.var.supabaseContext
79+
expectTypeOf(ctx).toEqualTypeOf<SupabaseContext<Database>>()
80+
return c.json({ authMode: ctx.authMode })
81+
})
82+
app.route('/', rootApp)
83+
84+
const res = await app.request('/')
85+
expect(res.status).toBe(200)
86+
})
87+
7288
it('throws HTTPException on auth failure', async () => {
7389
const app = new Hono()
7490
app.use('*', withSupabase({ auth: 'user', env }))

src/adapters/hono/middleware.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,13 @@ import type { SupabaseContext, WithSupabaseConfig } from '../../types.js'
4040
*
4141
* @category Adapters
4242
*/
43-
export function withSupabase(
43+
export function withSupabase<Database = unknown>(
4444
config?: Omit<WithSupabaseConfig, 'cors'>,
45-
): MiddlewareHandler<{ Variables: { supabaseContext: SupabaseContext } }> {
45+
): MiddlewareHandler<{
46+
Variables: { supabaseContext: SupabaseContext<Database> }
47+
}> {
4648
return createMiddleware<{
47-
Variables: { supabaseContext: SupabaseContext }
49+
Variables: { supabaseContext: SupabaseContext<Database> }
4850
}>(async (c, next) => {
4951
// Skip if a previous middleware already set the context.
5052
// This enables route-level overrides: a route can use withSupabase({ auth: 'secret' })
@@ -55,7 +57,10 @@ export function withSupabase(
5557
return
5658
}
5759

58-
const { data: ctx, error } = await createSupabaseContext(c.req.raw, config)
60+
const { data: ctx, error } = await createSupabaseContext<Database>(
61+
c.req.raw,
62+
config,
63+
)
5964
if (error) {
6065
throw new HTTPException(error.status as 401 | 500, {
6166
message: error.message,

0 commit comments

Comments
 (0)