diff --git a/.changeset/curly-stingrays-peel.md b/.changeset/curly-stingrays-peel.md new file mode 100644 index 00000000..b066f409 --- /dev/null +++ b/.changeset/curly-stingrays-peel.md @@ -0,0 +1,5 @@ +--- +'@supabase/auth-helpers-nextjs': patch +--- + +Fix typedefs and add deprecated functions for App Router createClient functions diff --git a/packages/nextjs/src/clientComponentClient.ts b/packages/nextjs/src/clientComponentClient.ts index 7e3179fc..5655311d 100644 --- a/packages/nextjs/src/clientComponentClient.ts +++ b/packages/nextjs/src/clientComponentClient.ts @@ -4,15 +4,21 @@ import { SupabaseClientOptionsWithoutAuth, createSupabaseClient } from '@supabase/auth-helpers-shared'; -import { SupabaseClient } from '@supabase/supabase-js'; -let supabase: SupabaseClient | undefined; +import type { SupabaseClient } from '@supabase/supabase-js'; +import type { GenericSchema } from '@supabase/supabase-js/dist/module/lib/types'; + +// can't type this properly as `Database`, `SchemaName` and `Schema` are only available within `createClientComponentClient` function +let supabase: any; export function createClientComponentClient< Database = any, SchemaName extends string & keyof Database = 'public' extends keyof Database ? 'public' - : string & keyof Database + : string & keyof Database, + Schema extends GenericSchema = Database[SchemaName] extends GenericSchema + ? Database[SchemaName] + : any >({ supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL, supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, @@ -23,7 +29,7 @@ export function createClientComponentClient< supabaseKey?: string; options?: SupabaseClientOptionsWithoutAuth; cookieOptions?: CookieOptionsWithName; -} = {}) { +} = {}): SupabaseClient { if (!supabaseUrl || !supabaseKey) { throw new Error( 'either NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY env variables or supabaseUrl and supabaseKey are required!' @@ -32,7 +38,7 @@ export function createClientComponentClient< const _supabase = supabase ?? - createSupabaseClient(supabaseUrl, supabaseKey, { + createSupabaseClient(supabaseUrl, supabaseKey, { ...options, global: { ...options?.global, diff --git a/packages/nextjs/src/deprecated.ts b/packages/nextjs/src/deprecated.ts index 1052b1c6..298e9ca4 100644 --- a/packages/nextjs/src/deprecated.ts +++ b/packages/nextjs/src/deprecated.ts @@ -2,11 +2,20 @@ import { SupabaseClientOptionsWithoutAuth, CookieOptionsWithName } from '@supabase/auth-helpers-shared'; +import { NextResponse } from 'next/server'; import { createPagesBrowserClient } from './pagesBrowserClient'; import { createPagesServerClient } from './pagesServerClient'; -import { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from 'next'; -import { NextRequest, NextResponse } from 'next/server'; import { createMiddlewareClient } from './middlewareClient'; +import { createClientComponentClient } from './clientComponentClient'; +import { createServerComponentClient } from './serverComponentClient'; +import { createRouteHandlerClient } from './routeHandlerClient'; +import { createServerActionClient } from './serverActionClient'; + +import type { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from 'next'; +import type { NextRequest } from 'next/server'; +import type { GenericSchema } from '@supabase/supabase-js/dist/module/lib/types'; +import type { ReadonlyHeaders } from 'next/dist/server/web/spec-extension/adapters/headers'; +import type { ReadonlyRequestCookies } from 'next/dist/server/web/spec-extension/adapters/request-cookies'; /** * @deprecated utilize the `createPagesBrowserClient` function instead @@ -15,7 +24,10 @@ export function createBrowserSupabaseClient< Database = any, SchemaName extends string & keyof Database = 'public' extends keyof Database ? 'public' - : string & keyof Database + : string & keyof Database, + Schema extends GenericSchema = Database[SchemaName] extends GenericSchema + ? Database[SchemaName] + : any >({ supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL, supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, @@ -28,9 +40,9 @@ export function createBrowserSupabaseClient< cookieOptions?: CookieOptionsWithName; } = {}) { console.warn( - 'Please utilize the `createPagesBrowserClient` function instead of the deprecated `createBrowserSupabaseClient` function.' + 'Please utilize the `createPagesBrowserClient` function instead of the deprecated `createBrowserSupabaseClient` function. Learn more: https://supabase.com/docs/guides/auth/auth-helpers/nextjs-pages' ); - return createPagesBrowserClient({ + return createPagesBrowserClient({ supabaseUrl, supabaseKey, options, @@ -45,7 +57,10 @@ export function createServerSupabaseClient< Database = any, SchemaName extends string & keyof Database = 'public' extends keyof Database ? 'public' - : string & keyof Database + : string & keyof Database, + Schema extends GenericSchema = Database[SchemaName] extends GenericSchema + ? Database[SchemaName] + : any >( context: GetServerSidePropsContext | { req: NextApiRequest; res: NextApiResponse }, { @@ -61,9 +76,9 @@ export function createServerSupabaseClient< } = {} ) { console.warn( - 'Please utilize the `createPagesServerClient` function instead of the deprecated `createServerSupabaseClient` function.' + 'Please utilize the `createPagesServerClient` function instead of the deprecated `createServerSupabaseClient` function. Learn more: https://supabase.com/docs/guides/auth/auth-helpers/nextjs-pages' ); - return createPagesServerClient(context, { + return createPagesServerClient(context, { supabaseUrl, supabaseKey, options, @@ -78,7 +93,10 @@ export function createMiddlewareSupabaseClient< Database = any, SchemaName extends string & keyof Database = 'public' extends keyof Database ? 'public' - : string & keyof Database + : string & keyof Database, + Schema extends GenericSchema = Database[SchemaName] extends GenericSchema + ? Database[SchemaName] + : any >( context: { req: NextRequest; res: NextResponse }, { @@ -94,13 +112,127 @@ export function createMiddlewareSupabaseClient< } = {} ) { console.warn( - 'Please utilize the `createMiddlewareClient function instead of the deprecated `createMiddlewareSupabaseClient` function.' + 'Please utilize the `createMiddlewareClient` function instead of the deprecated `createMiddlewareSupabaseClient` function. Learn more: https://supabase.com/docs/guides/auth/auth-helpers/nextjs#middleware' + ); + + return createMiddlewareClient(context, { + supabaseUrl, + supabaseKey, + options, + cookieOptions + }); +} + +/** + * @deprecated utilize the `createClientComponentClient` function instead + */ +export function createClientComponentSupabaseClient< + Database = any, + SchemaName extends string & keyof Database = 'public' extends keyof Database + ? 'public' + : string & keyof Database, + Schema extends GenericSchema = Database[SchemaName] extends GenericSchema + ? Database[SchemaName] + : any +>({ + supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL, + supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, + options, + cookieOptions +}: { + supabaseUrl?: string; + supabaseKey?: string; + options?: SupabaseClientOptionsWithoutAuth; + cookieOptions?: CookieOptionsWithName; +} = {}) { + console.warn( + 'Please utilize the `createClientComponentClient` function instead of the deprecated `createClientComponentSupabaseClient` function. Learn more: https://supabase.com/docs/guides/auth/auth-helpers/nextjs#client-component' ); - return createMiddlewareClient(context, { + return createClientComponentClient({ supabaseUrl, supabaseKey, options, cookieOptions }); } + +/** + * @deprecated utilize the `createServerComponentClient` function instead + */ +export function createServerComponentSupabaseClient< + Database = any, + SchemaName extends string & keyof Database = 'public' extends keyof Database + ? 'public' + : string & keyof Database, + Schema extends GenericSchema = Database[SchemaName] extends GenericSchema + ? Database[SchemaName] + : any +>( + context: { headers: () => ReadonlyHeaders; cookies: () => ReadonlyRequestCookies }, + { + supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL, + supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, + options, + cookieOptions + }: { + supabaseUrl?: string; + supabaseKey?: string; + options?: SupabaseClientOptionsWithoutAuth; + cookieOptions?: CookieOptionsWithName; + } = {} +) { + console.warn( + 'Please utilize the `createServerComponentClient` function instead of the deprecated `createServerComponentSupabaseClient` function. Additionally, this function no longer requires the `headers` function as a parameter. Learn more: https://supabase.com/docs/guides/auth/auth-helpers/nextjs#server-component' + ); + + return createServerComponentClient( + { cookies: context.cookies }, + { + supabaseUrl, + supabaseKey, + options, + cookieOptions + } + ); +} + +/** + * @deprecated utilize the `createRouteHandlerClient` function instead + */ +export function createRouteHandlerSupabaseClient< + Database = any, + SchemaName extends string & keyof Database = 'public' extends keyof Database + ? 'public' + : string & keyof Database, + Schema extends GenericSchema = Database[SchemaName] extends GenericSchema + ? Database[SchemaName] + : any +>( + context: { headers: () => ReadonlyHeaders; cookies: () => ReadonlyRequestCookies }, + { + supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL, + supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, + options, + cookieOptions + }: { + supabaseUrl?: string; + supabaseKey?: string; + options?: SupabaseClientOptionsWithoutAuth; + cookieOptions?: CookieOptionsWithName; + } = {} +) { + console.warn( + 'Please utilize the `createRouteHandlerClient` function instead of the deprecated `createRouteHandlerSupabaseClient` function. Additionally, this function no longer requires the `headers` function as a parameter. Learn more: https://supabase.com/docs/guides/auth/auth-helpers/nextjs#route-handler' + ); + + return createRouteHandlerClient( + { cookies: context.cookies }, + { + supabaseUrl, + supabaseKey, + options, + cookieOptions + } + ); +} diff --git a/packages/nextjs/src/middlewareClient.ts b/packages/nextjs/src/middlewareClient.ts index 21217c3f..6d53abb1 100644 --- a/packages/nextjs/src/middlewareClient.ts +++ b/packages/nextjs/src/middlewareClient.ts @@ -7,9 +7,13 @@ import { serializeCookie, SupabaseClientOptionsWithoutAuth } from '@supabase/auth-helpers-shared'; -import { NextRequest, NextResponse } from 'next/server'; +import { NextResponse } from 'next/server'; import { splitCookiesString } from 'set-cookie-parser'; +import type { NextRequest } from 'next/server'; +import type { GenericSchema } from '@supabase/supabase-js/dist/module/lib/types'; +import type { SupabaseClient } from '@supabase/supabase-js'; + class NextMiddlewareAuthStorageAdapter extends CookieAuthStorageAdapter { constructor( private readonly context: { req: NextRequest; res: NextResponse }, @@ -60,7 +64,10 @@ export function createMiddlewareClient< Database = any, SchemaName extends string & keyof Database = 'public' extends keyof Database ? 'public' - : string & keyof Database + : string & keyof Database, + Schema extends GenericSchema = Database[SchemaName] extends GenericSchema + ? Database[SchemaName] + : any >( context: { req: NextRequest; res: NextResponse }, { @@ -74,14 +81,14 @@ export function createMiddlewareClient< options?: SupabaseClientOptionsWithoutAuth; cookieOptions?: CookieOptionsWithName; } = {} -) { +): SupabaseClient { if (!supabaseUrl || !supabaseKey) { throw new Error( 'either NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY env variables or supabaseUrl and supabaseKey are required!' ); } - return createSupabaseClient(supabaseUrl, supabaseKey, { + return createSupabaseClient(supabaseUrl, supabaseKey, { ...options, global: { ...options?.global, diff --git a/packages/nextjs/src/pagesServerClient.ts b/packages/nextjs/src/pagesServerClient.ts index 707dadd0..d69fabfa 100644 --- a/packages/nextjs/src/pagesServerClient.ts +++ b/packages/nextjs/src/pagesServerClient.ts @@ -10,6 +10,9 @@ import { import { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from 'next'; import { splitCookiesString } from 'set-cookie-parser'; +import type { GenericSchema } from '@supabase/supabase-js/dist/module/lib/types'; +import type { SupabaseClient } from '@supabase/supabase-js'; + class NextServerAuthStorageAdapter extends CookieAuthStorageAdapter { constructor( private readonly context: @@ -57,7 +60,10 @@ export function createPagesServerClient< Database = any, SchemaName extends string & keyof Database = 'public' extends keyof Database ? 'public' - : string & keyof Database + : string & keyof Database, + Schema extends GenericSchema = Database[SchemaName] extends GenericSchema + ? Database[SchemaName] + : any >( context: GetServerSidePropsContext | { req: NextApiRequest; res: NextApiResponse }, { @@ -71,14 +77,14 @@ export function createPagesServerClient< options?: SupabaseClientOptionsWithoutAuth; cookieOptions?: CookieOptionsWithName; } = {} -) { +): SupabaseClient { if (!supabaseUrl || !supabaseKey) { throw new Error( 'either NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY env variables or supabaseUrl and supabaseKey are required!' ); } - return createSupabaseClient(supabaseUrl, supabaseKey, { + return createSupabaseClient(supabaseUrl, supabaseKey, { ...options, global: { ...options?.global, diff --git a/packages/nextjs/src/routeHandlerClient.ts b/packages/nextjs/src/routeHandlerClient.ts index 813d09c7..df27c72c 100644 --- a/packages/nextjs/src/routeHandlerClient.ts +++ b/packages/nextjs/src/routeHandlerClient.ts @@ -7,6 +7,8 @@ import { } from '@supabase/auth-helpers-shared'; import type { ReadonlyRequestCookies } from 'next/dist/server/web/spec-extension/adapters/request-cookies'; +import type { GenericSchema } from '@supabase/supabase-js/dist/module/lib/types'; +import type { SupabaseClient } from '@supabase/supabase-js'; class NextRouteHandlerAuthStorageAdapter extends CookieAuthStorageAdapter { constructor( @@ -39,7 +41,10 @@ export function createRouteHandlerClient< Database = any, SchemaName extends string & keyof Database = 'public' extends keyof Database ? 'public' - : string & keyof Database + : string & keyof Database, + Schema extends GenericSchema = Database[SchemaName] extends GenericSchema + ? Database[SchemaName] + : any >( context: { cookies: () => ReadonlyRequestCookies; @@ -55,14 +60,14 @@ export function createRouteHandlerClient< options?: SupabaseClientOptionsWithoutAuth; cookieOptions?: CookieOptionsWithName; } = {} -) { +): SupabaseClient { if (!supabaseUrl || !supabaseKey) { throw new Error( 'either NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY env variables or supabaseUrl and supabaseKey are required!' ); } - return createSupabaseClient(supabaseUrl, supabaseKey, { + return createSupabaseClient(supabaseUrl, supabaseKey, { ...options, global: { ...options?.global, diff --git a/packages/nextjs/src/serverComponentClient.ts b/packages/nextjs/src/serverComponentClient.ts index 12d322de..c14ba5d1 100644 --- a/packages/nextjs/src/serverComponentClient.ts +++ b/packages/nextjs/src/serverComponentClient.ts @@ -6,6 +6,8 @@ import { createSupabaseClient } from '@supabase/auth-helpers-shared'; +import type { SupabaseClient } from '@supabase/supabase-js'; +import type { GenericSchema } from '@supabase/supabase-js/dist/module/lib/types'; import type { ReadonlyRequestCookies } from 'next/dist/server/web/spec-extension/adapters/request-cookies'; class NextServerComponentAuthStorageAdapter extends CookieAuthStorageAdapter { @@ -23,14 +25,12 @@ class NextServerComponentAuthStorageAdapter extends CookieAuthStorageAdapter { return nextCookies.get(name)?.value; } protected setCookie(name: string, value: string): void { - // Note: The Next.js team at Vercel is working on adding the ability to - // set cookies in addition to the cookies function. - // https://beta.nextjs.org/docs/api-reference/cookies + // Server Components cannot set cookies. Must use Middleware, Server Action or Route Handler + // https://github.com/vercel/next.js/discussions/41745#discussioncomment-5198848 } protected deleteCookie(name: string): void { - // Note: The Next.js team at Vercel is working on adding the ability to - // set cookies in addition to the cookies function. - // https://beta.nextjs.org/docs/api-reference/cookies + // Server Components cannot set cookies. Must use Middleware, Server Action or Route Handler + // https://github.com/vercel/next.js/discussions/41745#discussioncomment-5198848 } } @@ -38,7 +38,10 @@ export function createServerComponentClient< Database = any, SchemaName extends string & keyof Database = 'public' extends keyof Database ? 'public' - : string & keyof Database + : string & keyof Database, + Schema extends GenericSchema = Database[SchemaName] extends GenericSchema + ? Database[SchemaName] + : any >( context: { cookies: () => ReadonlyRequestCookies; @@ -54,14 +57,14 @@ export function createServerComponentClient< options?: SupabaseClientOptionsWithoutAuth; cookieOptions?: CookieOptionsWithName; } = {} -) { +): SupabaseClient { if (!supabaseUrl || !supabaseKey) { throw new Error( 'either NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY env variables or supabaseUrl and supabaseKey are required!' ); } - return createSupabaseClient(supabaseUrl, supabaseKey, { + return createSupabaseClient(supabaseUrl, supabaseKey, { ...options, global: { ...options?.global,