From 1eadfbdf38cd0c08d0865306c30730ab089d6efa Mon Sep 17 00:00:00 2001 From: Jon Meyers Date: Tue, 23 May 2023 21:54:13 +1000 Subject: [PATCH 1/3] add explicit return types for createClient functions --- packages/nextjs/src/clientComponentClient.ts | 16 +++++++---- packages/nextjs/src/deprecated.ts | 29 ++++++++++++++------ packages/nextjs/src/middlewareClient.ts | 15 +++++++--- packages/nextjs/src/pagesServerClient.ts | 12 ++++++-- packages/nextjs/src/routeHandlerClient.ts | 11 ++++++-- packages/nextjs/src/serverComponentClient.ts | 21 ++++++++------ 6 files changed, 72 insertions(+), 32 deletions(-) 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..9973bf0b 100644 --- a/packages/nextjs/src/deprecated.ts +++ b/packages/nextjs/src/deprecated.ts @@ -4,9 +4,13 @@ import { } from '@supabase/auth-helpers-shared'; import { createPagesBrowserClient } from './pagesBrowserClient'; import { createPagesServerClient } from './pagesServerClient'; -import { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from 'next'; -import { NextRequest, NextResponse } from 'next/server'; +import { NextResponse } from 'next/server'; import { createMiddlewareClient } from './middlewareClient'; +import { createClientComponentClient } from './clientComponentClient'; + +import type { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from 'next'; +import type { NextRequest } from 'next/server'; +import type { GenericSchema } from '@supabase/supabase-js/dist/module/lib/types'; /** * @deprecated utilize the `createPagesBrowserClient` function instead @@ -15,7 +19,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, @@ -30,7 +37,7 @@ export function createBrowserSupabaseClient< console.warn( 'Please utilize the `createPagesBrowserClient` function instead of the deprecated `createBrowserSupabaseClient` function.' ); - return createPagesBrowserClient({ + return createPagesBrowserClient({ supabaseUrl, supabaseKey, options, @@ -45,7 +52,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 }, { @@ -63,7 +73,7 @@ export function createServerSupabaseClient< console.warn( 'Please utilize the `createPagesServerClient` function instead of the deprecated `createServerSupabaseClient` function.' ); - return createPagesServerClient(context, { + return createPagesServerClient(context, { supabaseUrl, supabaseKey, options, @@ -78,7 +88,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 }, { @@ -97,7 +110,7 @@ export function createMiddlewareSupabaseClient< 'Please utilize the `createMiddlewareClient function instead of the deprecated `createMiddlewareSupabaseClient` function.' ); - return createMiddlewareClient(context, { + return createMiddlewareClient(context, { supabaseUrl, supabaseKey, options, 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, From f969c92e8785825307c3f601271b7a002a3b112a Mon Sep 17 00:00:00 2001 From: Jon Meyers Date: Tue, 23 May 2023 22:14:16 +1000 Subject: [PATCH 2/3] add deprecated functions for App Router createClient functions --- packages/nextjs/src/deprecated.ts | 127 +++++++++++++++++++++++++++++- 1 file changed, 123 insertions(+), 4 deletions(-) diff --git a/packages/nextjs/src/deprecated.ts b/packages/nextjs/src/deprecated.ts index 9973bf0b..298e9ca4 100644 --- a/packages/nextjs/src/deprecated.ts +++ b/packages/nextjs/src/deprecated.ts @@ -2,15 +2,20 @@ import { SupabaseClientOptionsWithoutAuth, CookieOptionsWithName } from '@supabase/auth-helpers-shared'; +import { NextResponse } from 'next/server'; import { createPagesBrowserClient } from './pagesBrowserClient'; import { createPagesServerClient } from './pagesServerClient'; -import { 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 @@ -35,7 +40,7 @@ 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({ supabaseUrl, @@ -71,7 +76,7 @@ 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, { supabaseUrl, @@ -107,7 +112,7 @@ 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, { @@ -117,3 +122,117 @@ export function createMiddlewareSupabaseClient< 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 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 + } + ); +} From 207c4e3a6422801bcbdf9555ff37d6202b4aa418 Mon Sep 17 00:00:00 2001 From: Jon Meyers Date: Tue, 23 May 2023 22:19:41 +1000 Subject: [PATCH 3/3] add changeset --- .changeset/curly-stingrays-peel.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/curly-stingrays-peel.md 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