diff --git a/README.md b/README.md index c2b8fa9..8630dcf 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ pnpm i ### Setting up the environment - Copy the env.example file into .env -- Setup google oauth required for auth https://next-auth.js.org/providers/google +- Setup google oauth required for auth https://next-auth.js.org/providers/google or Email provider by setting SMTP details - Login to minio console using `splitpro` user and password `password` and [create access keys](http://localhost:9001/access-keys/new-account) and the R2 related env variables ### Run the app diff --git a/next.config.js b/next.config.js index b4d1e03..306d735 100644 --- a/next.config.js +++ b/next.config.js @@ -13,12 +13,6 @@ import pwa from 'next-pwa'; // @ts-ignore import nextra from 'nextra'; -import { fileURLToPath } from 'node:url'; -import createJiti from 'jiti'; -const jiti = createJiti(fileURLToPath(import.meta.url)); - -jiti('./src/env.js'); - // eslint-disable-next-line @typescript-eslint/no-unsafe-call const withPwa = pwa({ dest: 'public', @@ -28,6 +22,9 @@ const withPwa = pwa({ const config = { reactStrictMode: true, output: process.env.DOCKER_OUTPUT ? 'standalone' : undefined, + experimental: { + instrumentationHook: true, + }, /** * If you are using `appDir` then you must comment the below `i18n` config out. * diff --git a/package.json b/package.json index 7b574bd..726eaf1 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,6 @@ "framer-motion": "^11.0.3", "geist": "^1.2.1", "input-otp": "^1.2.3", - "jiti": "^1.21.6", "lucide-react": "^0.312.0", "nanoid": "^5.0.6", "next": "^14.0.4", @@ -106,4 +105,4 @@ "seed": "tsx prisma/seed.ts" }, "packageManager": "pnpm@8.9.2" -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 24463f8..c615858 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -95,9 +95,6 @@ dependencies: input-otp: specifier: ^1.2.3 version: 1.2.3(react-dom@18.2.0)(react@18.2.0) - jiti: - specifier: ^1.21.6 - version: 1.21.6 lucide-react: specifier: ^0.312.0 version: 0.312.0(react@18.2.0) diff --git a/src/env.js b/src/env.js index 3863229..52606ba 100644 --- a/src/env.js +++ b/src/env.js @@ -23,7 +23,6 @@ export const env = createEnv({ // VERCEL_URL doesn't include `https` so it cant be validated as a URL process.env.VERCEL ? z.string() : z.string().url(), ), - AUTH_PROVIDERS: z.string(), ENABLE_SENDING_INVITES: z.boolean(), FROM_EMAIL: z.string().optional(), EMAIL_SERVER_HOST: z.string().optional(), @@ -62,7 +61,6 @@ export const env = createEnv({ NODE_ENV: process.env.NODE_ENV, NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET, NEXTAUTH_URL: process.env.NEXTAUTH_URL, - AUTH_PROVIDERS: process.env.AUTH_PROVIDERS, ENABLE_SENDING_INVITES: process.env.ENABLE_SENDING_INVITES === 'true', FROM_EMAIL: process.env.FROM_EMAIL, EMAIL_SERVER_HOST: process.env.EMAIL_SERVER_HOST, diff --git a/src/instrumentation.ts b/src/instrumentation.ts new file mode 100644 index 0000000..b463eaa --- /dev/null +++ b/src/instrumentation.ts @@ -0,0 +1,12 @@ +/** + * Add things here to be executed during server startup. + * + * more details here: https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation + */ +export async function register() { + if (process.env.NEXT_RUNTIME === 'nodejs') { + console.log('Registering instrumentation'); + const { validateAuthEnv } = await import('./server/auth'); + validateAuthEnv(); + } +} diff --git a/src/pages/auth/signin.tsx b/src/pages/auth/signin.tsx index d6d3bc1..2592250 100644 --- a/src/pages/auth/signin.tsx +++ b/src/pages/auth/signin.tsx @@ -1,5 +1,5 @@ 'use client'; -import { signIn } from 'next-auth/react'; +import { type ClientSafeProvider, getProviders, signIn } from 'next-auth/react'; import Head from 'next/head'; import { Button } from '~/components/ui/button'; import Image from 'next/image'; @@ -39,15 +39,33 @@ const otpSchema = z.object({ otp: z.string({ required_error: 'OTP is required' }).length(5, { message: 'Invalid OTP' }), }); +const providerSvgs = { + github: ( + + + + ), + google: ( + + + + ), +}; -const Home: NextPage<{ authProviders: string; feedbackEmail: string }> = ({ - authProviders, +const Home: NextPage<{ feedbackEmail: string; providers: ClientSafeProvider[] }> = ({ + providers, feedbackEmail, }) => { const [emailStatus, setEmailStatus] = useState<'idle' | 'sending' | 'success'>('idle'); - const providers = authProviders.split(',').map((provider) => provider.trim().toUpperCase()); - const emailForm = useForm>({ resolver: zodResolver(emailSchema), }); @@ -85,30 +103,26 @@ const Home: NextPage<{ authProviders: string; feedbackEmail: string }> = ({

SplitPro

- {providers?.includes('GOOGLE') && ( - - )} + {providers + .filter((provider) => provider.id !== 'email') + .map((provider) => ( + + ))} {providers && providers.length === 2 && (

or

)} - {providers?.includes('EMAIL') && - (emailStatus === 'success' ? ( + {providers.find((provider) => provider.id === 'email') ? ( + emailStatus === 'success' ? ( <>

We have sent an email with the OTP. Please check your inbox @@ -181,10 +195,10 @@ const Home: NextPage<{ authProviders: string; feedbackEmail: string }> = ({ - ))} + ) + ) : null}

Trouble logging in? contact -
{feedbackEmail ?? ''} @@ -200,7 +214,9 @@ export default Home; export const getServerSideProps: GetServerSideProps = async (context) => { const session = await getServerAuthSession(context); - const feedbackEmail = process.env.FEEDBACK_EMAIL; + const providers = await getProviders(); + + console.log('providers', providers); if (session) { return { @@ -213,8 +229,8 @@ export const getServerSideProps: GetServerSideProps = async (context) => { return { props: { - authProviders: env.AUTH_PROVIDERS, feedbackEmail: env.FEEDBACK_EMAIL ?? '', + providers: Object.values(providers ?? {}), }, }; }; diff --git a/src/server/auth.ts b/src/server/auth.ts index 8e2def8..159a1ff 100644 --- a/src/server/auth.ts +++ b/src/server/auth.ts @@ -108,11 +108,8 @@ export const getServerAuthSessionForSSG = async (context: GetServerSidePropsCont */ function getProviders() { const providersList = []; - const envProviders = env.AUTH_PROVIDERS?.split(',').map((provider) => - provider.trim().toUpperCase(), - ); - if (envProviders?.includes('GOOGLE') && env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET) { + if (env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET) { providersList.push( GoogleProvider({ clientId: env.GOOGLE_CLIENT_ID, @@ -122,7 +119,7 @@ function getProviders() { ); } - if (envProviders?.includes('EMAIL')) { + if (env.EMAIL_SERVER_HOST) { providersList.push( EmailProvider({ from: env.FROM_EMAIL, @@ -149,3 +146,21 @@ function getProviders() { return providersList; } + +/** + * Validates the environment variables that are related to authentication. + * this will check if atleat one provider is set properly. + * + * this function should be updated if new providers are added. + */ +export function validateAuthEnv() { + console.log('Validating auth env'); + if (!process.env.SKIP_ENV_VALIDATION) { + const providers = getProviders(); + if (providers.length === 0) { + throw new Error( + 'No authentication providers are configured, at least one is required. Learn more here: https://github.com/oss-apps/split-pro?tab=readme-ov-file#setting-up-the-environment', + ); + } + } +}