Skip to content

Commit 8d5c781

Browse files
authored
fix: add Database type override to elysia adapter (#106)
1 parent ca53801 commit 8d5c781

5 files changed

Lines changed: 70 additions & 23 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
## [1.4.0](https://github.com/supabase/server/compare/server-v1.3.1...server-v1.4.0) (2026-07-13)
44

5-
65
### Features
76

8-
* explicit cors config shape ('default' | 'disabled' | { headers }) ([#102](https://github.com/supabase/server/issues/102)) ([297925f](https://github.com/supabase/server/commit/297925fa1149a61d148306fdb6ba28e66bc0a737))
7+
- explicit cors config shape ('default' | 'disabled' | { headers }) ([#102](https://github.com/supabase/server/issues/102)) ([297925f](https://github.com/supabase/server/commit/297925fa1149a61d148306fdb6ba28e66bc0a737))
98

109
## [1.3.1](https://github.com/supabase/server/compare/server-v1.3.0...server-v1.3.1) (2026-07-03)
1110

docs/typescript-generics.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,25 @@ const todosApp = new Hono()
121121
app.route('/todos', todosApp)
122122
```
123123

124+
The elysia adapter works the same way: thread `Database` through the `withSupabase<Database>()` generic and elysia infers the `supabaseContext` type, so `supabaseContext.supabase` is a fully typed `SupabaseClient<Database>` in every handler.
125+
126+
```ts
127+
import { Elysia } from 'elysia'
128+
import { withSupabase } from '@supabase/server/adapters/elysia'
129+
import type { Database } from './database.types.ts'
130+
131+
const app = new Elysia()
132+
.use(withSupabase<Database>({ auth: 'user' }))
133+
.get('/todos', async ({ supabaseContext }) => {
134+
const { data } = await supabaseContext.supabase
135+
.from('todos')
136+
.select('id, title')
137+
return data
138+
})
139+
140+
app.listen(3000)
141+
```
142+
124143
## Custom schema
125144

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

jsr.json

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,7 @@
1111
"./adapters/nestjs": "./src/adapters/nestjs/index.ts"
1212
},
1313
"publish": {
14-
"include": [
15-
"src/**/*.ts",
16-
"README.md",
17-
"LICENSE"
18-
],
19-
"exclude": [
20-
"src/**/*.test.ts",
21-
"src/**/*.spec.ts"
22-
]
14+
"include": ["src/**/*.ts", "README.md", "LICENSE"],
15+
"exclude": ["src/**/*.test.ts", "src/**/*.spec.ts"]
2316
}
2417
}

src/adapters/elysia/plugin.test.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
11
import { Elysia } from 'elysia'
2-
import { describe, expect, it } from 'vitest'
2+
import { describe, expect, expectTypeOf, it } from 'vitest'
33

4+
import type { SupabaseContext } from '../../types.js'
45
import { withSupabase } from './plugin.js'
56

7+
type Database = {
8+
public: {
9+
Tables: {
10+
todos: {
11+
Row: { id: number; title: string }
12+
Insert: { id?: number; title: string }
13+
Update: { id?: number; title?: string }
14+
Relationships: []
15+
}
16+
}
17+
}
18+
}
19+
620
describe('elysia supabase plugin', () => {
721
const env = {
822
url: 'https://test.supabase.co',
@@ -28,6 +42,18 @@ describe('elysia supabase plugin', () => {
2842
expect(body.hasAdmin).toBe(true)
2943
})
3044

45+
it('threads the Database generic into the Supabase context', async () => {
46+
const app = new Elysia()
47+
.use(withSupabase<Database>({ auth: 'none', env }))
48+
.get('/', ({ supabaseContext }) => {
49+
expectTypeOf(supabaseContext).toEqualTypeOf<SupabaseContext<Database>>()
50+
return { authMode: supabaseContext.authMode }
51+
})
52+
53+
const res = await app.handle(new Request('http://localhost/'))
54+
expect(res.status).toBe(200)
55+
})
56+
3157
it('throws error on auth failure', async () => {
3258
const app = new Elysia()
3359
.use(withSupabase({ auth: 'user', env }))

src/adapters/elysia/plugin.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ export class SupabaseError extends Error {
7070
// `{}` literals — switching to `object` or `Record<string, never>` would not satisfy
7171
// the corresponding generic constraints.
7272
/* eslint-disable @typescript-eslint/no-empty-object-type */
73-
export function withSupabase(config?: Omit<WithSupabaseConfig, 'cors'>): Elysia<
73+
export function withSupabase<Database = unknown>(
74+
config?: Omit<WithSupabaseConfig, 'cors'>,
75+
): Elysia<
7476
'',
7577
{ decorator: {}; store: {}; derive: {}; resolve: {} },
7678
{ typebox: {}; error: { readonly SupabaseError: SupabaseError } },
@@ -85,10 +87,12 @@ export function withSupabase(config?: Omit<WithSupabaseConfig, 'cors'>): Elysia<
8587
{},
8688
{
8789
derive: {}
88-
resolve: { supabaseContext: SupabaseContext }
90+
resolve: { supabaseContext: SupabaseContext<Database> }
8991
schema: {}
9092
standaloneSchema: {}
91-
response: ExtractErrorFromHandle<{ supabaseContext: SupabaseContext }>
93+
response: ExtractErrorFromHandle<{
94+
supabaseContext: SupabaseContext<Database>
95+
}>
9296
},
9397
{
9498
derive: {}
@@ -101,15 +105,21 @@ export function withSupabase(config?: Omit<WithSupabaseConfig, 'cors'>): Elysia<
101105
/* eslint-enable @typescript-eslint/no-empty-object-type */
102106
return new Elysia()
103107
.error({ SupabaseError })
104-
.resolve(async (ctx): Promise<{ supabaseContext: SupabaseContext }> => {
105-
const existing = (ctx as { supabaseContext?: SupabaseContext })
106-
.supabaseContext
107-
if (existing) return { supabaseContext: existing }
108+
.resolve(
109+
async (ctx): Promise<{ supabaseContext: SupabaseContext<Database> }> => {
110+
const existing = (
111+
ctx as { supabaseContext?: SupabaseContext<Database> }
112+
).supabaseContext
113+
if (existing) return { supabaseContext: existing }
108114

109-
const { data, error } = await createSupabaseContext(ctx.request, config)
110-
if (error) throw new SupabaseError(error)
115+
const { data, error } = await createSupabaseContext<Database>(
116+
ctx.request,
117+
config,
118+
)
119+
if (error) throw new SupabaseError(error)
111120

112-
return { supabaseContext: data }
113-
})
121+
return { supabaseContext: data }
122+
},
123+
)
114124
.as('scoped')
115125
}

0 commit comments

Comments
 (0)