Skip to content

Commit

Permalink
feat(types): automatically pass database typings to clients (#366)
Browse files Browse the repository at this point in the history
  • Loading branch information
IsraelOrtuno authored Jul 5, 2024
1 parent 23b0b40 commit 132307a
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 7 deletions.
18 changes: 18 additions & 0 deletions docs/content/2.get-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,24 @@ Cookie name used for storing the redirect path when using the `redirect` option,
Options for cookies used to share tokens between server and client, refer to [cookieOptions](https://nuxt.com/docs/api/composables/use-cookie#options) for available settings. Please note that the lifetime set here does not determine the Supabase session lifetime.
### `types`
Default: `./types/database.types.ts`
The path for the generated Supabase TypeScript definitions. The database definitions will be automatically passed to all clients: `useSupabaseClient`, `serverSupabaseClient` and `serverSupabaseServiceRole`.
```shell
## Generate types from live database
supabase gen types typescript --project-id YourProjectId > types/database.types.ts

## Generate types when using local environment
supabase gen types typescript --local > types/database.types.ts
```
Set to `false` to disable.
Check Supabase [documentation](https://supabase.com/docs/reference/javascript/release-notes#typescript-support) for further information.
### `clientOptions`
Default:
Expand Down
12 changes: 11 additions & 1 deletion docs/content/4.usage/composables/useSupabaseClient.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,17 @@ onUnmounted(() => {

## Typescript

You can pass Database typings to the client. Check Supabase [documentation](https://supabase.com/docs/reference/javascript/release-notes#typescript-support) for further information.
Database typings are passed to the client out of the box if the database generated types are found at `./types/database.types.ts` or [your configured types path](/get-started#types). Check Supabase [documentation](https://supabase.com/docs/reference/javascript/release-notes#typescript-support) for further information.

```shell
## Generate types from live database
supabase gen types typescript --project-id YourProjectId > types/database.types.ts

## Generate types when using local environment
supabase gen types typescript --local > types/database.types.ts
```

You can also pass Database typings to the client manually:

```vue
<script setup lang="ts">
Expand Down
4 changes: 3 additions & 1 deletion playground/server/api/test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { createError } from 'h3'
import { serverSupabaseClient, serverSupabaseUser, serverSupabaseSession } from '#supabase/server'
import type { Database } from '#build/types/supabase-database'

export default defineEventHandler(async (event) => {
const supabase = await serverSupabaseClient(event)
const supabase = await serverSupabaseClient<Database>(event)

if (!supabase) {
throw createError({ statusMessage: 'Supabase client not found' })
}
Expand Down
3 changes: 3 additions & 0 deletions playground/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "./.nuxt/tsconfig.json"
}
24 changes: 22 additions & 2 deletions src/module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { fileURLToPath } from 'node:url'
import fs from 'node:fs'
import { defu } from 'defu'
import { defineNuxtModule, addPlugin, createResolver, addTemplate, resolveModule, extendViteConfig } from '@nuxt/kit'
import type { CookieOptions } from 'nuxt/app'
Expand Down Expand Up @@ -74,6 +75,13 @@ export interface ModuleOptions {
*/
cookieOptions?: CookieOptions

/**
* Path to Supabase database type definitions file
* @default '~/types/database.types.ts'
* @type string
*/
types?: string | false

/**
* Supabase client options (overrides default options from `@supabase/ssr`)
* @default { }
Expand Down Expand Up @@ -108,10 +116,11 @@ export default defineNuxtModule<ModuleOptions>({
sameSite: 'lax',
secure: true,
} as CookieOptions,
types: '~/types/database.types.ts',
clientOptions: {} as SupabaseClientOptions<string>,
},
setup(options, nuxt) {
const { resolve } = createResolver(import.meta.url)
const { resolve, resolvePath } = createResolver(import.meta.url)
const resolveRuntimeModule = (path: string) => resolveModule(path, { paths: resolve('./runtime') })

// Public runtimeConfig
Expand Down Expand Up @@ -191,7 +200,18 @@ export default defineNuxtModule<ModuleOptions>({
].join('\n'),
})

nuxt.hook('prepare:types', (options) => {
addTemplate({
filename: 'types/supabase-database.d.ts',
getContents: async () => {
if (!!options.types && fs.existsSync(await resolvePath(options.types))) {
return `export * from '${await resolvePath(options.types)}'`
}

return `export type Database = unknown`
},
})

nuxt.hook('prepare:types', async (options) => {
options.references.push({ path: resolve(nuxt.options.buildDir, 'types/supabase.d.ts') })
})

Expand Down
3 changes: 2 additions & 1 deletion src/runtime/composables/useSupabaseClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { SupabaseClient } from '@supabase/supabase-js'
import { useNuxtApp } from '#imports'
import type { Database } from '#build/types/supabase-database'

export const useSupabaseClient = <T>() => {
export const useSupabaseClient = <T = Database>() => {
return useNuxtApp().$supabase?.client as SupabaseClient<T>
}
3 changes: 2 additions & 1 deletion src/runtime/server/services/serverSupabaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import type { SupabaseClient } from '@supabase/supabase-js'
import { createServerClient, parseCookieHeader, type CookieOptions } from '@supabase/ssr'
import { getHeader, setCookie, type H3Event } from 'h3'
import { useRuntimeConfig } from '#imports'
import type { Database } from '#build/types/supabase-database'

export const serverSupabaseClient = async <T>(event: H3Event): Promise<SupabaseClient<T>> => {
export const serverSupabaseClient = async <T = Database>(event: H3Event): Promise<SupabaseClient<T>> => {
// No need to recreate client if exists in request context
if (!event.context._supabaseClient) {
// get settings from runtime config
Expand Down
3 changes: 2 additions & 1 deletion src/runtime/server/services/serverSupabaseServiceRole.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import type { SupabaseClient } from '@supabase/supabase-js'
import { createClient } from '@supabase/supabase-js'
import type { H3Event } from 'h3'
import { useRuntimeConfig } from '#imports'
import type { Database } from '#build/types/supabase-database'

export const serverSupabaseServiceRole = <T>(event: H3Event): SupabaseClient<T> => {
export const serverSupabaseServiceRole = <T = Database>(event: H3Event): SupabaseClient<T> => {
const {
supabase: { serviceKey },
public: {
Expand Down
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ declare module '@nuxt/schema' {
redirectOptions: RedirectOptions
cookieName: string
cookieOptions: CookieOptions
types: string | false
clientOptions: SupabaseClientOptions<string>
}
}
Expand Down

0 comments on commit 132307a

Please sign in to comment.