diff --git a/src/helpers/with-page-auth-required.ts b/src/helpers/with-page-auth-required.ts index e356bacf3..2be641b45 100644 --- a/src/helpers/with-page-auth-required.ts +++ b/src/helpers/with-page-auth-required.ts @@ -36,7 +36,7 @@ export type PageRoute = ( ) => Promise>; /** - * Objects containing the route parameters and search parameters of th page. + * Objects containing the route parameters and search parameters of the page. * * @category Server */ @@ -50,7 +50,7 @@ export type AppRouterPageRouteOpts = { * * @category Server */ -export type AppRouterPageRoute = (obj: AppRouterPageRouteOpts) => Promise; +export type AppRouterPageRoute = (obj: PageProps) => Promise; /** * If you have a custom returnTo url you should specify it in `returnTo`. @@ -124,8 +124,8 @@ export type WithPageAuthRequiredPageRouter = < * * @category Server */ -export type WithPageAuthRequiredAppRouterOptions = { - returnTo?: string | ((obj: AppRouterPageRouteOpts) => Promise | string); +export type WithPageAuthRequiredAppRouterOptions = { + returnTo?: string | ((obj: PageProps) => Promise | string); }; /** @@ -136,7 +136,7 @@ export type WithPageAuthRequiredAppRouterOptions = { * // app/protected-page/page.js * import { withPageAuthRequired } from '@auth0/nextjs-auth0'; * - * export default function withPageAuthRequired(ProtectedPage() { + * export default withPageAuthRequired(function ProtectedPage() { * return
Protected content
; * }, { returnTo: '/protected-page' }); * ``` @@ -155,7 +155,7 @@ export type WithPageAuthRequiredAppRouterOptions = { * // app/protected-page/[slug]/page.js * import { withPageAuthRequired } from '@auth0/nextjs-auth0'; * - * export default function withPageAuthRequired(ProtectedPage() { + * export default withPageAuthRequired(function ProtectedPage({ params }: { params: { slug: string } ) { * return
Protected content
; * }, { * returnTo({ params }) { @@ -166,10 +166,17 @@ export type WithPageAuthRequiredAppRouterOptions = { * * @category Server */ -export type WithPageAuthRequiredAppRouter = ( - fn: AppRouterPageRoute, - opts?: WithPageAuthRequiredAppRouterOptions -) => AppRouterPageRoute; +export type WithPageAuthRequiredAppRouter = < + T extends { + params: T['params'] extends undefined ? undefined : { [K in keyof T['params']]: string }; + searchParams: T['searchParams'] extends undefined + ? undefined + : { [K in keyof T['searchParams']]: string | undefined }; + } +>( + fn: (obj: T) => Promise, + opts?: WithPageAuthRequiredAppRouterOptions +) => AppRouterPageRoute; /** * Protects Page router pages {@link WithPageAuthRequiredPageRouter} or @@ -190,8 +197,8 @@ export default function withPageAuthRequiredFactory( const pageRouteHandler = pageRouteHandlerFactory(getConfig, sessionCache); return (( - fnOrOpts?: WithPageAuthRequiredPageRouterOptions | AppRouterPageRoute, - opts?: WithPageAuthRequiredAppRouterOptions + fnOrOpts?: WithPageAuthRequiredPageRouterOptions | AppRouterPageRoute, + opts?: WithPageAuthRequiredAppRouterOptions ) => { if (typeof fnOrOpts === 'function') { return appRouteHandler(fnOrOpts, opts); diff --git a/tests/helpers/with-page-auth-required.test.ts b/tests/helpers/with-page-auth-required.test.ts index 32944969e..77e932b14 100644 --- a/tests/helpers/with-page-auth-required.test.ts +++ b/tests/helpers/with-page-auth-required.test.ts @@ -1,14 +1,68 @@ +import { expectTypeOf } from 'expect-type'; +import { NextResponse } from 'next/server'; import React from 'react'; import ReactDOMServer from 'react-dom/server'; -import { NextResponse } from 'next/server'; import { URL } from 'url'; -import { login, setup, teardown } from '../fixtures/setup'; +import { initAuth0 } from '../../src'; +import { get } from '../auth0-session/fixtures/helpers'; import { login as appRouterLogin } from '../fixtures/app-router-helpers'; import { withApi, withoutApi } from '../fixtures/default-settings'; -import { get } from '../auth0-session/fixtures/helpers'; -import { initAuth0 } from '../../src'; +import { login, setup, teardown } from '../fixtures/setup'; describe('with-page-auth-required ssr', () => { + describe('typed app route', () => { + let redirect: jest.Mock; + + beforeEach(() => { + jest.doMock('next/headers', () => ({ cookies: () => new NextResponse().cookies })); + jest.doMock('next/navigation', () => { + const navigation = jest.requireActual('next/navigation'); + redirect = jest.fn(navigation.redirect); + return { + ...navigation, + redirect + }; + }); + }); + + test('basic with params', async () => { + const instance = initAuth0(withApi); + const handler = instance.withPageAuthRequired( + ({ params }: { params: { lang: string; slug: string } }) => + Promise.resolve(React.createElement('div', {}, `${params.lang}/${params.slug}`)), + { returnTo: '/foo' } + ); + expectTypeOf(handler).parameter(0).toMatchTypeOf<{ params: { lang: string } }>(); + }); + + test('basic with search param', async () => { + const instance = initAuth0(withApi); + const handler = instance.withPageAuthRequired( + ({ searchParams }: { searchParams: { limit: string | undefined } }) => + Promise.resolve(React.createElement('div', {}, `${searchParams.limit}`)), + { returnTo: '/foo' } + ); + expectTypeOf(handler).parameter(0).toMatchTypeOf<{ searchParams: { limit: string | undefined } }>(); + }); + + test('basic with params and search param', async () => { + const instance = initAuth0(withApi); + const handler = instance.withPageAuthRequired( + ({ + searchParams, + params: { lang } + }: { + params: { lang: string }; + searchParams: { limit: string | undefined }; + }) => Promise.resolve(React.createElement('div', {}, `${lang}${searchParams.limit}`)), + { returnTo: ({ params, searchParams }) => `/foo/${params.lang}?limit=${searchParams.limit}` } + ); + expectTypeOf(handler) + .parameter(0) + .toMatchTypeOf<{ params: { lang: string }; searchParams: { limit: string | undefined } }>(); + }); + }); + describe('app route', () => { let redirect: jest.Mock;