From e7852aba91ae21ffc133bb250a9ad393f1db086d Mon Sep 17 00:00:00 2001 From: mrevanzak Date: Mon, 30 Oct 2023 11:28:24 +0700 Subject: [PATCH] feat: replace next-auth with clerk --- apps/nextjs/next.config.mjs | 3 +- apps/nextjs/package.json | 1 - .../src/app/_components/auth-showcase.tsx | 50 ++--- .../src/app/api/auth/[...nextauth]/route.ts | 3 - apps/nextjs/src/app/api/webhook/route.ts | 100 ++++++++++ apps/nextjs/src/components/auth.tsx | 44 ++--- apps/nextjs/src/env.mjs | 8 +- apps/nextjs/src/middleware.ts | 9 + .../{app => pages}/api/trpc/[trpc]/route.ts | 12 +- apps/nextjs/src/pages/trpc/[trpc]/route.ts | 44 +++++ apps/nextjs/tsconfig.json | 16 +- packages/api/index.ts | 2 +- packages/api/package.json | 2 +- packages/api/src/router/auth.ts | 2 +- packages/api/src/trpc.ts | 64 ++++--- packages/auth/env.mjs | 28 --- packages/auth/index.ts | 59 ------ packages/auth/package.json | 40 ---- packages/auth/tsconfig.json | 8 - packages/db/index.ts | 2 +- packages/db/schema/auth.ts | 115 ------------ packages/db/schema/product.ts | 2 +- packages/db/schema/user.ts | 50 +++++ pnpm-lock.yaml | 174 +----------------- 24 files changed, 319 insertions(+), 519 deletions(-) delete mode 100644 apps/nextjs/src/app/api/auth/[...nextauth]/route.ts create mode 100644 apps/nextjs/src/app/api/webhook/route.ts create mode 100644 apps/nextjs/src/middleware.ts rename apps/nextjs/src/{app => pages}/api/trpc/[trpc]/route.ts (75%) create mode 100644 apps/nextjs/src/pages/trpc/[trpc]/route.ts delete mode 100644 packages/auth/env.mjs delete mode 100644 packages/auth/index.ts delete mode 100644 packages/auth/package.json delete mode 100644 packages/auth/tsconfig.json delete mode 100644 packages/db/schema/auth.ts create mode 100644 packages/db/schema/user.ts diff --git a/apps/nextjs/next.config.mjs b/apps/nextjs/next.config.mjs index 7661493..f999c12 100644 --- a/apps/nextjs/next.config.mjs +++ b/apps/nextjs/next.config.mjs @@ -1,12 +1,11 @@ // Importing env files here to validate on build import "./src/env.mjs"; -import "@vivat/auth/env.mjs"; /** @type {import("next").NextConfig} */ const config = { reactStrictMode: true, /** Enables hot reloading for local packages without a build step */ - transpilePackages: ["@vivat/api", "@vivat/auth", "@vivat/db"], + transpilePackages: ["@vivat/api", "@vivat/db"], /** We already do linting and typechecking as separate tasks in CI */ eslint: { ignoreDuringBuilds: true }, typescript: { ignoreBuildErrors: true }, diff --git a/apps/nextjs/package.json b/apps/nextjs/package.json index bd87ae5..64591a7 100644 --- a/apps/nextjs/package.json +++ b/apps/nextjs/package.json @@ -23,7 +23,6 @@ "@trpc/react-query": "^10.40.0", "@trpc/server": "^10.40.0", "@vivat/api": "^0.1.0", - "@vivat/auth": "^0.1.0", "@vivat/db": "^0.1.0", "next": "^13.5.4", "react": "18.2.0", diff --git a/apps/nextjs/src/app/_components/auth-showcase.tsx b/apps/nextjs/src/app/_components/auth-showcase.tsx index 046f76a..2ec3252 100644 --- a/apps/nextjs/src/app/_components/auth-showcase.tsx +++ b/apps/nextjs/src/app/_components/auth-showcase.tsx @@ -1,30 +1,30 @@ -import { auth } from "@vivat/auth"; +// import { auth } from "@vivat/auth"; -import { SignIn, SignOut } from "~/components/auth"; +// import { SignIn, SignOut } from "~/components/auth"; -export async function AuthShowcase() { - const session = await auth(); +// export async function AuthShowcase() { +// const session = await auth(); - if (!session) { - return ( - - Sign in with Discord - - ); - } +// if (!session) { +// return ( +// +// Sign in with Discord +// +// ); +// } - return ( -
-

- {session && Logged in as {session.user.name}} -

+// return ( +//
+//

+// {session && Logged in as {session.user.name}} +//

- - Sign out - -
- ); -} +// +// Sign out +// +//
+// ); +// } diff --git a/apps/nextjs/src/app/api/auth/[...nextauth]/route.ts b/apps/nextjs/src/app/api/auth/[...nextauth]/route.ts deleted file mode 100644 index c80ed89..0000000 --- a/apps/nextjs/src/app/api/auth/[...nextauth]/route.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { GET, POST } from "@vivat/auth"; - -export const runtime = "edge"; diff --git a/apps/nextjs/src/app/api/webhook/route.ts b/apps/nextjs/src/app/api/webhook/route.ts new file mode 100644 index 0000000..401b84a --- /dev/null +++ b/apps/nextjs/src/app/api/webhook/route.ts @@ -0,0 +1,100 @@ +import { headers } from "next/headers"; +import type { User } from "@clerk/nextjs/api"; +import { Webhook } from "svix"; + +import { db, eq } from "@vivat/db"; +import { users } from "@vivat/db/schema/user"; + +type UnwantedKeys = + | "emailAddresses" + | "firstName" + | "lastName" + | "primaryEmailAddressId" + | "primaryPhoneNumberId" + | "phoneNumbers"; + +interface UserInterface extends Omit { + email_addresses: { + email_address: string; + id: string; + }[]; + primary_email_address_id: string; + first_name: string; + last_name: string; + primary_phone_number_id: string; + phone_numbers: { + phone_number: string; + id: string; + }[]; + image_url: string; +} + +const webhookSecret: string = process.env.WEBHOOK_SECRET ?? ""; + +export async function POST(req: Request) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const payload = await req.json(); + const payloadString = JSON.stringify(payload); + const headerPayload = headers(); + const svixId = headerPayload.get("svix-id"); + const svixIdTimeStamp = headerPayload.get("svix-timestamp"); + const svixSignature = headerPayload.get("svix-signature"); + if (!svixId || !svixIdTimeStamp || !svixSignature) { + console.log("svixId", svixId); + console.log("svixIdTimeStamp", svixIdTimeStamp); + console.log("svixSignature", svixSignature); + return new Response("Error occured", { + status: 400, + }); + } + const svixHeaders = { + "svix-id": svixId, + "svix-timestamp": svixIdTimeStamp, + "svix-signature": svixSignature, + }; + const wh = new Webhook(webhookSecret); + let evt: Event | null = null; + try { + evt = wh.verify(payloadString, svixHeaders) as Event; + } catch (_) { + console.log("error"); + return new Response("Error occured", { + status: 400, + }); + } + const { id } = evt.data; + // Handle the webhook + const eventType: EventType = evt.type; + if (eventType === "user.created" || eventType === "user.updated") { + const { email_addresses, primary_email_address_id } = evt.data; + const emailObject = email_addresses?.find((email) => { + return email.id === primary_email_address_id; + }); + if (!emailObject) { + return new Response("Error locating user", { + status: 400, + }); + } + await db.insert(users).values({ + id, + email: emailObject.email_address, + name: evt.data.first_name + " " + evt.data.last_name, + imageUrl: evt.data.image_url, + }); + } + if (eventType === "user.deleted") { + await db.delete(users).where(eq(users.id, id)); + } + console.log(`User ${id} was ${eventType}`); + return new Response("", { + status: 201, + }); +} + +interface Event { + data: UserInterface; + object: "event"; + type: EventType; +} + + type EventType = "user.created" | "user.updated" | "user.deleted"; \ No newline at end of file diff --git a/apps/nextjs/src/components/auth.tsx b/apps/nextjs/src/components/auth.tsx index 7236745..dfa591b 100644 --- a/apps/nextjs/src/components/auth.tsx +++ b/apps/nextjs/src/components/auth.tsx @@ -1,25 +1,25 @@ -import type { ComponentProps } from "react"; +// import type { ComponentProps } from "react"; -import type { OAuthProviders } from "@vivat/auth"; -import { CSRF_experimental } from "@vivat/auth"; +// import type { OAuthProviders } from "@vivat/auth"; +// import { CSRF_experimental } from "@vivat/auth"; -export function SignIn({ - provider, - ...props -}: { provider: OAuthProviders } & ComponentProps<"button">) { - return ( -
-