diff --git a/orm/clerk-nextjs/.gitignore b/orm/clerk-nextjs/.gitignore index ffa74efaabc7..bf8d09458d6e 100644 --- a/orm/clerk-nextjs/.gitignore +++ b/orm/clerk-nextjs/.gitignore @@ -21,10 +21,8 @@ /build # misc -**/generated/prisma .DS_Store *.pem -prisma/dev.db* # debug npm-debug.log* @@ -43,5 +41,4 @@ yarn-error.log* *.tsbuildinfo next-env.d.ts -# clerk configuration (can include secrets) -/.clerk/ +/app/generated/prisma diff --git a/orm/clerk-nextjs/README.md b/orm/clerk-nextjs/README.md index e3ce2713f466..c891f26411ab 100644 --- a/orm/clerk-nextjs/README.md +++ b/orm/clerk-nextjs/README.md @@ -43,6 +43,7 @@ This example uses a [Prisma Postgres](https://prisma.io/postgres) database by de 1. Set up a new Prisma Postgres instance in the [Prisma Data Platform Console](https://console.prisma.io) and copy the database connection URL. 2. Add your database url to the `.env` +3. Run `npx prisma migrate dev --name init` That's it, your project is now configured to use Prisma Postgres! diff --git a/orm/clerk-nextjs/src/app/api/posts/route.ts b/orm/clerk-nextjs/app/api/posts/route.ts similarity index 100% rename from orm/clerk-nextjs/src/app/api/posts/route.ts rename to orm/clerk-nextjs/app/api/posts/route.ts diff --git a/orm/clerk-nextjs/app/api/webhooks/clerk/route.ts b/orm/clerk-nextjs/app/api/webhooks/clerk/route.ts new file mode 100644 index 000000000000..c26f1b144762 --- /dev/null +++ b/orm/clerk-nextjs/app/api/webhooks/clerk/route.ts @@ -0,0 +1,30 @@ +import { verifyWebhook } from '@clerk/nextjs/webhooks' +import { NextRequest } from 'next/server' +import prisma from '@/lib/prisma' + +export async function POST(req: NextRequest) { + try { + const evt = await verifyWebhook(req) + const { id } = evt.data + const eventType = evt.type + console.log(`Received webhook with ID ${id} and event type of ${eventType}`) + + if (eventType === 'user.created') { + const { id, email_addresses, first_name, last_name } = evt.data + await prisma.user.upsert({ + where: { clerkId: id }, + update: {}, + create: { + clerkId: id, + email: email_addresses[0].email_address, + name: `${first_name} ${last_name}`, + }, + }) + } + + return new Response('Webhook received', { status: 200 }) + } catch (err) { + console.error('Error verifying webhook:', err) + return new Response('Error verifying webhook', { status: 400 }) + } +} diff --git a/orm/clerk-nextjs/src/app/components/PostInputs.tsx b/orm/clerk-nextjs/app/components/PostInputs.tsx similarity index 65% rename from orm/clerk-nextjs/src/app/components/PostInputs.tsx rename to orm/clerk-nextjs/app/components/PostInputs.tsx index f183d43944f8..6d0a6725cb62 100644 --- a/orm/clerk-nextjs/src/app/components/PostInputs.tsx +++ b/orm/clerk-nextjs/app/components/PostInputs.tsx @@ -1,24 +1,24 @@ -'use client' +"use client"; -import { useState } from 'react' +import { useState } from "react"; export default function PostInputs() { - const [title, setTitle] = useState('') - const [content, setContent] = useState('') + const [title, setTitle] = useState(""); + const [content, setContent] = useState(""); async function createPost(e: React.FormEvent) { - e.preventDefault() - if (!title || !content) return + e.preventDefault(); + if (!title || !content) return; - await fetch('/api/posts', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, + await fetch("/api/posts", { + method: "POST", + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ title, content }), - }) + }); - setTitle('') - setContent('') - location.reload() + setTitle(""); + setContent(""); + location.reload(); } return ( @@ -40,5 +40,5 @@ export default function PostInputs() { Post - ) -} + ); +} \ No newline at end of file diff --git a/orm/clerk-nextjs/src/app/favicon.ico b/orm/clerk-nextjs/app/favicon.ico similarity index 100% rename from orm/clerk-nextjs/src/app/favicon.ico rename to orm/clerk-nextjs/app/favicon.ico diff --git a/orm/clerk-nextjs/src/app/globals.css b/orm/clerk-nextjs/app/globals.css similarity index 100% rename from orm/clerk-nextjs/src/app/globals.css rename to orm/clerk-nextjs/app/globals.css diff --git a/orm/clerk-nextjs/src/app/layout.tsx b/orm/clerk-nextjs/app/layout.tsx similarity index 65% rename from orm/clerk-nextjs/src/app/layout.tsx rename to orm/clerk-nextjs/app/layout.tsx index 9bd1894a539e..7e584607d4ed 100644 --- a/orm/clerk-nextjs/src/app/layout.tsx +++ b/orm/clerk-nextjs/app/layout.tsx @@ -1,6 +1,6 @@ -import type { Metadata } from 'next' -import { Geist, Geist_Mono } from 'next/font/google' -import './globals.css' +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; import { ClerkProvider, UserButton, @@ -8,40 +8,39 @@ import { SignUpButton, SignedOut, SignedIn, -} from '@clerk/nextjs' +} from "@clerk/nextjs"; const geistSans = Geist({ - variable: '--font-geist-sans', - subsets: ['latin'], -}) + variable: "--font-geist-sans", + subsets: ["latin"], +}); const geistMono = Geist_Mono({ - variable: '--font-geist-mono', - subsets: ['latin'], -}) + variable: "--font-geist-mono", + subsets: ["latin"], +}); export const metadata: Metadata = { - title: 'Create Next App', - description: 'Generated by create next app', -} + title: "Create Next App", + description: "Generated by create next app", +}; export default function RootLayout({ children, }: Readonly<{ - children: React.ReactNode + children: React.ReactNode; }>) { return ( + className={`${geistSans.variable} ${geistMono.variable} antialiased`}> {children} - ) + ); } const Navbar = () => { @@ -55,5 +54,5 @@ const Navbar = () => { - ) -} + ); +}; \ No newline at end of file diff --git a/orm/clerk-nextjs/src/app/page.tsx b/orm/clerk-nextjs/app/page.tsx similarity index 63% rename from orm/clerk-nextjs/src/app/page.tsx rename to orm/clerk-nextjs/app/page.tsx index 12198a103b84..1f0dc62c4271 100644 --- a/orm/clerk-nextjs/src/app/page.tsx +++ b/orm/clerk-nextjs/app/page.tsx @@ -1,15 +1,15 @@ -import { currentUser } from '@clerk/nextjs/server' -import prisma from '@/lib/prisma' -import PostInputs from './components/PostInputs' +import { currentUser } from "@clerk/nextjs/server"; +import prisma from "@/lib/prisma"; +import PostInputs from "@/app/components/PostInputs"; export default async function Home() { - const user = await currentUser() - if (!user) return
Sign in to post
+ const user = await currentUser(); + if (!user) return
Sign in to post
; const posts = await prisma.post.findMany({ where: { author: { clerkId: user.id } }, - orderBy: { createdAt: 'desc' }, - }) + orderBy: { createdAt: "desc" }, + }); return (
@@ -18,13 +18,12 @@ export default async function Home() { {posts.map((post) => (
+ className="p-4 border border-zinc-800 rounded mt-4">

{post.title}

{post.content}

))}
- ) -} + ); +} \ No newline at end of file diff --git a/orm/clerk-nextjs/eslint.config.mjs b/orm/clerk-nextjs/eslint.config.mjs deleted file mode 100644 index c85fb67c463f..000000000000 --- a/orm/clerk-nextjs/eslint.config.mjs +++ /dev/null @@ -1,16 +0,0 @@ -import { dirname } from "path"; -import { fileURLToPath } from "url"; -import { FlatCompat } from "@eslint/eslintrc"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); - -const compat = new FlatCompat({ - baseDirectory: __dirname, -}); - -const eslintConfig = [ - ...compat.extends("next/core-web-vitals", "next/typescript"), -]; - -export default eslintConfig; diff --git a/orm/clerk-nextjs/lib/prisma.ts b/orm/clerk-nextjs/lib/prisma.ts new file mode 100644 index 000000000000..726d1611985f --- /dev/null +++ b/orm/clerk-nextjs/lib/prisma.ts @@ -0,0 +1,13 @@ +import { PrismaClient } from '../app/generated/prisma/client' +import { withAccelerate } from '@prisma/extension-accelerate' + +const globalForPrisma = global as unknown as { + prisma: PrismaClient +} + +const prisma = + globalForPrisma.prisma || new PrismaClient().$extends(withAccelerate()) + +if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma + +export default prisma diff --git a/orm/clerk-nextjs/src/middleware.ts b/orm/clerk-nextjs/middleware.ts similarity index 100% rename from orm/clerk-nextjs/src/middleware.ts rename to orm/clerk-nextjs/middleware.ts diff --git a/orm/clerk-nextjs/package.json b/orm/clerk-nextjs/package.json index 4786fdb2385f..235b2d6bbd89 100644 --- a/orm/clerk-nextjs/package.json +++ b/orm/clerk-nextjs/package.json @@ -1,5 +1,5 @@ { - "name": "clerk-nextjs", + "name": "clerk2", "version": "0.1.0", "private": true, "scripts": { @@ -9,25 +9,20 @@ "lint": "next lint" }, "dependencies": { - "@clerk/nextjs": "6.28.1", - "@prisma/client": "6.9.0", - "@prisma/extension-accelerate": "2.0.2", - "next": "15.3.5", + "@clerk/nextjs": "^6.30.1", + "@prisma/extension-accelerate": "^2.0.2", + "next": "15.4.6", "react": "19.1.0", - "react-dom": "19.1.0", - "svix": "1.68.0" + "react-dom": "19.1.0" }, "devDependencies": { - "@eslint/eslintrc": "3.3.1", - "@tailwindcss/postcss": "4.1.11", - "@types/node": "22.15.32", - "@types/react": "19.1.8", - "@types/react-dom": "19.1.6", - "eslint": "9.30.1", - "eslint-config-next": "15.3.5", - "prisma": "6.9.0", - "tailwindcss": "4.1.11", - "tsx": "4.20.3", - "typescript": "5.8.3" + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "prisma": "^6.14.0", + "tailwindcss": "^4", + "tsx": "^4.20.4", + "typescript": "^5" } } diff --git a/orm/clerk-nextjs/prisma/schema.prisma b/orm/clerk-nextjs/prisma/schema.prisma index 0cb97b26e5b4..57b0a2d400b6 100644 --- a/orm/clerk-nextjs/prisma/schema.prisma +++ b/orm/clerk-nextjs/prisma/schema.prisma @@ -1,12 +1,6 @@ -// This is your Prisma schema file, -// learn more about it in the docs: https://pris.ly/d/prisma-schema - -// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? -// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init - generator client { - provider = "prisma-client-js" - output = "../src/app/generated/prisma" + provider = "prisma-client" + output = "../app/generated/prisma" } datasource db { @@ -15,7 +9,7 @@ datasource db { } model User { - id String @id @default(cuid()) + id Int @id @default(autoincrement()) clerkId String @unique email String @unique name String? @@ -23,11 +17,11 @@ model User { } model Post { - id String @id @default(cuid()) + id Int @id @default(autoincrement()) title String content String? published Boolean @default(false) - authorId String + authorId Int author User @relation(fields: [authorId], references: [id]) createdAt DateTime @default(now()) } diff --git a/orm/clerk-nextjs/src/app/api/webhooks/clerk/route.ts b/orm/clerk-nextjs/src/app/api/webhooks/clerk/route.ts deleted file mode 100644 index 0ee6769f89d8..000000000000 --- a/orm/clerk-nextjs/src/app/api/webhooks/clerk/route.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Webhook } from 'svix' -import { WebhookEvent } from '@clerk/nextjs/server' -import { headers } from 'next/headers' -import prisma from '@/lib/prisma' - -export async function POST(req: Request) { - const secret = process.env.SIGNING_SECRET - if (!secret) return new Response('Missing secret', { status: 500 }) - - const wh = new Webhook(secret) - const body = await req.text() - const headerPayload = await headers() - - const event = wh.verify(body, { - 'svix-id': headerPayload.get('svix-id')!, - 'svix-timestamp': headerPayload.get('svix-timestamp')!, - 'svix-signature': headerPayload.get('svix-signature')!, - }) as WebhookEvent - - if (event.type === 'user.created') { - const { id, email_addresses, first_name, last_name } = event.data - await prisma.user.upsert({ - where: { clerkId: id }, - update: {}, - create: { - clerkId: id, - email: email_addresses[0].email_address, - name: `${first_name} ${last_name}`, - }, - }) - } - - return new Response('OK') -} diff --git a/orm/clerk-nextjs/src/lib/prisma.ts b/orm/clerk-nextjs/src/lib/prisma.ts deleted file mode 100644 index 15880f69129b..000000000000 --- a/orm/clerk-nextjs/src/lib/prisma.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { PrismaClient } from '../app/generated/prisma' -import { withAccelerate } from '@prisma/extension-accelerate' - -const prisma = new PrismaClient().$extends(withAccelerate()) - -const globalForPrisma = global as unknown as { prisma: typeof prisma } - -if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma - -export default prisma diff --git a/orm/clerk-nextjs/tsconfig.json b/orm/clerk-nextjs/tsconfig.json index c1334095f876..d8b93235f205 100644 --- a/orm/clerk-nextjs/tsconfig.json +++ b/orm/clerk-nextjs/tsconfig.json @@ -19,7 +19,7 @@ } ], "paths": { - "@/*": ["./src/*"] + "@/*": ["./*"] } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],