Skip to content
Open
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
2 changes: 1 addition & 1 deletion docs/adapters/nestjs.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class GamesController {

### Typing your database

The guard does not thread a `Database` generic, so `@SupabaseCtx()` resolves to `SupabaseContext<unknown>` by default. To get typed table access, annotate the parameter at the handler:
The guard does not thread a `Database` generic, so `@SupabaseCtx()` resolves to `SupabaseContext<any>` by default. To get typed table access, annotate the parameter at the handler:

```ts
import type { SupabaseContext } from '@supabase/server'
Expand Down
12 changes: 6 additions & 6 deletions docs/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Complete reference for every export, organized by entry point.
### withSupabase

```ts
function withSupabase<Database = unknown>(
function withSupabase<Database = UntypedDatabase>(
config: WithSupabaseConfig,
handler: (req: Request, ctx: SupabaseContext<Database>) => Promise<Response>,
): (req: Request) => Promise<Response>
Expand All @@ -25,7 +25,7 @@ Wraps a fetch handler with auth, CORS, and client creation. Returns a `(req: Req
- Reading the raw `req.body` stream bypasses the buffer, so a handler that forwards the request with `fetch()` after another layer has read the body rebuilds it from `await req.arrayBuffer()`.

```ts
function withSupabase<Database = unknown>(
function withSupabase<Database = UntypedDatabase>(
config: WithSupabaseConfig,
): Entry<SupabaseContext<Database>>
```
Expand Down Expand Up @@ -56,7 +56,7 @@ Entries before `withSupabase` see every request, including unauthenticated ones,
### createSupabaseContext

```ts
function createSupabaseContext<Database = unknown>(
function createSupabaseContext<Database = UntypedDatabase>(
request: Request,
options?: WithSupabaseConfig,
): Promise<
Expand Down Expand Up @@ -122,7 +122,7 @@ Resolves Supabase environment configuration from runtime variables. `SUPABASE_UR
### createContextClient

```ts
function createContextClient<Database = unknown>(
function createContextClient<Database = UntypedDatabase>(
options?: CreateContextClientOptions,
): SupabaseClient<Database>
```
Expand All @@ -138,7 +138,7 @@ Configured with:
### createAdminClient

```ts
function createAdminClient<Database = unknown>(
function createAdminClient<Database = UntypedDatabase>(
options?: CreateAdminClientOptions,
): SupabaseClient<Database>
```
Expand Down Expand Up @@ -549,7 +549,7 @@ withSupabase({ auth: 'none' }, handler) // no credentials required
### SupabaseContext\<Database\>

```ts
interface SupabaseContext<Database = unknown> {
interface SupabaseContext<Database = UntypedDatabase> {
supabase: SupabaseClient<Database>
supabaseAdmin: SupabaseClient<Database>
userClaims: UserClaims | null
Expand Down
2 changes: 2 additions & 0 deletions docs/typescript-generics.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

All client-creating functions accept a `Database` generic parameter. When you pass your generated database types, every `.from('table').select()` call is fully typed — column names, return types, insert shapes, and RPC signatures.

Without one, `Database` defaults to `any` — the same default `createClient()` uses in `@supabase/supabase-js` — so `.from()`, `.select()`, `.insert()`, and `.update()` all type-check without a generated schema.

## Generating types

Use the Supabase CLI to generate TypeScript types from your database schema:
Expand Down
8 changes: 6 additions & 2 deletions src/adapters/elysia/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ 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'
import type {
SupabaseContext,
UntypedDatabase,
WithSupabaseConfig,
} from '../../types.js'

/**
* Wraps an {@link AuthError} as an Elysia-compatible error.
Expand Down Expand Up @@ -70,7 +74,7 @@ export class SupabaseError extends Error {
// `{}` 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<Database = unknown>(
export function withSupabase<Database = UntypedDatabase>(
config?: Omit<WithSupabaseConfig, 'cors'>,
): Elysia<
'',
Expand Down
8 changes: 6 additions & 2 deletions src/adapters/hono/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { createMiddleware } from 'hono/factory'
import { HTTPException } from 'hono/http-exception'

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

/**
* Hono middleware that creates a {@link SupabaseContext} and stores it in `c.var.supabaseContext`.
Expand Down Expand Up @@ -40,7 +44,7 @@ import type { SupabaseContext, WithSupabaseConfig } from '../../types.js'
*
* @category Adapters
*/
export function withSupabase<Database = unknown>(
export function withSupabase<Database = UntypedDatabase>(
config?: Omit<WithSupabaseConfig, 'cors'>,
): MiddlewareHandler<{
Variables: { supabaseContext: SupabaseContext<Database> }
Expand Down
4 changes: 2 additions & 2 deletions src/core/create-admin-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
MissingDefaultSecretKeyError,
MissingSecretKeyError,
} from '../errors.js'
import type { CreateAdminClientOptions } from '../types.js'
import type { CreateAdminClientOptions, UntypedDatabase } from '../types.js'
import { resolveEnv } from './resolve-env.js'

/**
Expand Down Expand Up @@ -39,7 +39,7 @@ import { resolveEnv } from './resolve-env.js'
*
* @category Primitives
*/
export function createAdminClient<Database = unknown>(
export function createAdminClient<Database = UntypedDatabase>(
options?: CreateAdminClientOptions,
): SupabaseClient<Database> {
const { data: resolved, error } = resolveEnv(options?.env)
Expand Down
4 changes: 2 additions & 2 deletions src/core/create-context-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
MissingDefaultPublishableKeyError,
MissingPublishableKeyError,
} from '../errors.js'
import type { CreateContextClientOptions } from '../types.js'
import type { CreateContextClientOptions, UntypedDatabase } from '../types.js'
import { resolveEnv } from './resolve-env.js'

/**
Expand Down Expand Up @@ -37,7 +37,7 @@ import { resolveEnv } from './resolve-env.js'
*
* @category Primitives
*/
export function createContextClient<Database = unknown>(
export function createContextClient<Database = UntypedDatabase>(
options?: CreateContextClientOptions,
): SupabaseClient<Database> {
const { data: resolved, error } = resolveEnv(options?.env)
Expand Down
8 changes: 6 additions & 2 deletions src/create-supabase-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import {
EnvError,
Errors,
} from './errors.js'
import type { SupabaseContext, WithSupabaseConfig } from './types.js'
import type {
SupabaseContext,
UntypedDatabase,
WithSupabaseConfig,
} from './types.js'

/**
* Creates a {@link SupabaseContext} directly from a request.
Expand All @@ -32,7 +36,7 @@ import type { SupabaseContext, WithSupabaseConfig } from './types.js'
* const { data } = await ctx.supabase.rpc('get_my_items')
* ```
*/
export async function createSupabaseContext<Database = unknown>(
export async function createSupabaseContext<Database = UntypedDatabase>(
request: Request,
options?: WithSupabaseConfig,
): Promise<
Expand Down
4 changes: 2 additions & 2 deletions src/middleware/admin-client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { createAdminClient } from '../../core/create-admin-client.js'
import { lazyClient } from '../../core/lazy-client.js'
import { readUpstreamAuth } from '../../core/read-upstream-auth.js'
import { CreateSupabaseClientError, EnvError, Errors } from '../../errors.js'
import type { CreateAdminClientOptions } from '../../types.js'
import type { CreateAdminClientOptions, UntypedDatabase } from '../../types.js'

/**
* **Alpha.** Configuration for {@link withSupabaseAdminClient} — the same
Expand Down Expand Up @@ -90,7 +90,7 @@ const base = defineMiddleware<
* @alpha
* @category Middleware
*/
export function withSupabaseAdminClient<Database = unknown>(
export function withSupabaseAdminClient<Database = UntypedDatabase>(
config?: WithSupabaseAdminClientConfig,
): Entry<{ supabaseAdmin: SupabaseClient<Database> }> {
return base(config) as unknown as Entry<{
Expand Down
7 changes: 5 additions & 2 deletions src/middleware/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import { extractCredentials } from '../../core/extract-credentials.js'
import { readUpstreamAuth } from '../../core/read-upstream-auth.js'
import { CreateSupabaseClientError, EnvError, Errors } from '../../errors.js'
import { markConstructionFailure } from '../../core/parts/construction-failure.js'
import type { CreateContextClientOptions } from '../../types.js'
import type {
CreateContextClientOptions,
UntypedDatabase,
} from '../../types.js'

/**
* **Alpha.** Configuration for {@link withSupabaseClient} — the same
Expand Down Expand Up @@ -97,7 +100,7 @@ const base = defineMiddleware<
* @alpha
* @category Middleware
*/
export function withSupabaseClient<Database = unknown>(
export function withSupabaseClient<Database = UntypedDatabase>(
config?: WithSupabaseClientConfig,
): Entry<{ supabase: SupabaseClient<Database> }> {
return base(config) as unknown as Entry<{
Expand Down
12 changes: 11 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,14 +452,24 @@ export interface CreateAdminClientOptions {
supabaseOptions?: SupabaseClientOptions<string>
}

/**
* Default for the `Database` generic on every client-creating function and on
* {@link SupabaseContext} itself — mirrors `createClient()` from
* `@supabase/supabase-js`, so an untyped `withSupabase(...)` call type-checks
* the same way an untyped `createClient()` does.
* @category Types
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type UntypedDatabase = any

/**
* The Supabase context created for each authenticated request.
*
* Contains pre-configured Supabase clients and the caller's identity.
* Identical regardless of which layer or adapter produced it.
* @category Types
*/
export interface SupabaseContext<Database = unknown> {
export interface SupabaseContext<Database = UntypedDatabase> {
/** Supabase client scoped to the caller's identity. RLS policies apply. */
supabase: SupabaseClient<Database>

Expand Down
5 changes: 3 additions & 2 deletions src/with-supabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { withSupabaseClient } from './middleware/client/index.js'
import type {
AuthModeWithKey,
SupabaseContext,
UntypedDatabase,
WithSupabaseConfig,
} from './types.js'

Expand Down Expand Up @@ -148,7 +149,7 @@ function rejectMiddlewareOption(config: WithSupabaseConfig): void {
* ```
*/
export function withSupabase<
Database = unknown,
Database = UntypedDatabase,
Base extends BaseContext = BaseContext,
>(
config: WithSupabaseConfig,
Expand Down Expand Up @@ -193,7 +194,7 @@ export function withSupabase<
* }
* ```
*/
export function withSupabase<Database = unknown>(
export function withSupabase<Database = UntypedDatabase>(
config: WithSupabaseConfig,
): Entry<SupabaseContext<Database>>

Expand Down
Loading