diff --git a/app/api/webhooks/clerk/route.ts b/app/api/webhooks/clerk/route.ts index 329d049..736f7ea 100644 --- a/app/api/webhooks/clerk/route.ts +++ b/app/api/webhooks/clerk/route.ts @@ -1,91 +1,92 @@ -import { Webhook } from 'svix' -import { headers } from 'next/headers' -import { WebhookEvent } from '@clerk/nextjs/server' -import { db } from '@/lib/db' +import { Webhook } from "svix"; +import { headers } from "next/headers"; +import { WebhookEvent } from "@clerk/nextjs/server"; +import { db } from "@/lib/db"; export async function POST(req: Request) { + // You can find this in the Clerk Dashboard -> Webhooks -> choose the webhook + const WEBHOOK_SECRET = process.env.CLERK_WEBHOOK_SECRET; - // You can find this in the Clerk Dashboard -> Webhooks -> choose the webhook - const WEBHOOK_SECRET = process.env.CLERK_WEBHOOK_SECRET + if (!WEBHOOK_SECRET) { + throw new Error( + "Please add CLERK_WEBHOOK_SECRET from Clerk Dashboard to .env or .env.local" + ); + } - if (!WEBHOOK_SECRET) { - throw new Error('Please add CLERK_WEBHOOK_SECRET from Clerk Dashboard to .env or .env.local') - } + // Get the headers + const headerPayload = headers(); + const svix_id = headerPayload.get("svix-id"); + const svix_timestamp = headerPayload.get("svix-timestamp"); + const svix_signature = headerPayload.get("svix-signature"); - // Get the headers - const headerPayload = headers(); - const svix_id = headerPayload.get("svix-id"); - const svix_timestamp = headerPayload.get("svix-timestamp"); - const svix_signature = headerPayload.get("svix-signature"); + // If there are no headers, error out + if (!svix_id || !svix_timestamp || !svix_signature) { + return new Response("Error occured -- no svix headers", { + status: 400, + }); + } - // If there are no headers, error out - if (!svix_id || !svix_timestamp || !svix_signature) { - return new Response('Error occured -- no svix headers', { - status: 400 - }) - } + // Get the body + const payload = await req.json(); + const body = JSON.stringify(payload); - // Get the body - const payload = await req.json() - const body = JSON.stringify(payload); + // Create a new Svix instance with your secret. + const wh = new Webhook(WEBHOOK_SECRET); - // Create a new Svix instance with your secret. - const wh = new Webhook(WEBHOOK_SECRET); + let evt: WebhookEvent; - let evt: WebhookEvent + // Verify the payload with the headers + try { + evt = wh.verify(body, { + "svix-id": svix_id, + "svix-timestamp": svix_timestamp, + "svix-signature": svix_signature, + }) as WebhookEvent; + } catch (err) { + console.error("Error verifying webhook:", err); + return new Response("Error occured", { + status: 400, + }); + } - // Verify the payload with the headers - try { - evt = wh.verify(body, { - "svix-id": svix_id, - "svix-timestamp": svix_timestamp, - "svix-signature": svix_signature, - }) as WebhookEvent - } catch (err) { - console.error('Error verifying webhook:', err); - return new Response('Error occured', { - status: 400 - }) - } + const eventType = evt.type; - const eventType = evt.type; + if (eventType === "user.created") { + await db.user.create({ + data: { + externalUserId: payload.data.id, + username: payload.data.username, + imageUrl: payload.data.image_url, + //stream: { + // create: { + // name: `${payload.data.username}'s stream`, + // }, + //}, + }, + }); + } - if (eventType === 'user.created') { - await db.user.create({ - data: { - externalUserId: payload.data.id, - username: payload.data.username, - imageUrl: payload.data.image_url, - //stream: { - // create: { - // name: `${payload.data.username}'s stream`, - // }, - //}, - }, - }) - } + if (eventType === "user.updated") { + await db.user.update({ + where: { + externalUserId: payload.data.id, + }, + data: { + username: payload.data.username, + imageUrl: payload.data.image_url, + }, + }); + } - if (eventType === "user.updated") { - await db.user.update({ - where: { - externalUserId: payload.data.id, - }, - data: { - username: payload.data.username, - imageUrl: payload.data.image_url, - }, - }); - } + if (eventType === "user.deleted") { + // await resetIngresses(payload.data.id); - if (eventType === "user.deleted") { - // await resetIngresses(payload.data.id); + await db.user.delete({ + where: { + externalUserId: payload.data.id, + }, + }); + } - await db.user.delete({ - where: { - externalUserId: payload.data.id, - }, - }); - } - - return new Response('', { status: 200 }) + return new Response("", { status: 200 }); } diff --git a/package-lock.json b/package-lock.json index 86743f1..3a6c690 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@clerk/nextjs": "^4.27.7", "@clerk/themes": "^1.7.9", - "@prisma/client": "^5.7.0", + "@prisma/client": "^5.7.1", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-tooltip": "^1.0.7", @@ -37,7 +37,7 @@ "eslint": "^8", "eslint-config-next": "14.0.4", "postcss": "^8", - "prisma": "^5.7.0", + "prisma": "^5.7.1", "tailwindcss": "^3.3.0", "typescript": "^5" } @@ -615,9 +615,9 @@ } }, "node_modules/@prisma/client": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.7.0.tgz", - "integrity": "sha512-cZmglCrfNbYpzUtz7HscVHl38e9CrUs31nrVoGUK1nIPXGgt8hT4jj2s657UXcNdQ/jBUxDgGmHyu2Nyrq1txg==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.7.1.tgz", + "integrity": "sha512-TUSa4nUcC4nf/e7X3jyO1pEd6XcI/TLRCA0KjkA46RDIpxUaRsBYEOqITwXRW2c0bMFyKcCRXrH4f7h4q9oOlg==", "hasInstallScript": true, "engines": { "node": ">=16.13" @@ -632,48 +632,48 @@ } }, "node_modules/@prisma/debug": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.7.0.tgz", - "integrity": "sha512-tZ+MOjWlVvz1kOEhNYMa4QUGURY+kgOUBqLHYIV8jmCsMuvA1tWcn7qtIMLzYWCbDcQT4ZS8xDgK0R2gl6/0wA==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.7.1.tgz", + "integrity": "sha512-yrVSO/YZOxdeIxcBtZ5BaNqUfPrZkNsAKQIQg36cJKMxj/VYK3Vk5jMKkI+gQLl0KReo1YvX8GWKfV788SELjw==", "devOptional": true }, "node_modules/@prisma/engines": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.7.0.tgz", - "integrity": "sha512-TkOMgMm60n5YgEKPn9erIvFX2/QuWnl3GBo6yTRyZKk5O5KQertXiNnrYgSLy0SpsKmhovEPQb+D4l0SzyE7XA==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.7.1.tgz", + "integrity": "sha512-R+Pqbra8tpLP2cvyiUpx+SIKglav3nTCpA+rn6826CThviQ8yvbNG0s8jNpo51vS9FuZO3pOkARqG062vKX7uA==", "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/debug": "5.7.0", - "@prisma/engines-version": "5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9", - "@prisma/fetch-engine": "5.7.0", - "@prisma/get-platform": "5.7.0" + "@prisma/debug": "5.7.1", + "@prisma/engines-version": "5.7.1-1.0ca5ccbcfa6bdc81c003cf549abe4269f59c41e5", + "@prisma/fetch-engine": "5.7.1", + "@prisma/get-platform": "5.7.1" } }, "node_modules/@prisma/engines-version": { - "version": "5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9.tgz", - "integrity": "sha512-V6tgRVi62jRwTm0Hglky3Scwjr/AKFBFtS+MdbsBr7UOuiu1TKLPc6xfPiyEN1+bYqjEtjxwGsHgahcJsd1rNg==", + "version": "5.7.1-1.0ca5ccbcfa6bdc81c003cf549abe4269f59c41e5", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.7.1-1.0ca5ccbcfa6bdc81c003cf549abe4269f59c41e5.tgz", + "integrity": "sha512-dIR5IQK/ZxEoWRBDOHF87r1Jy+m2ih3Joi4vzJRP+FOj5yxCwS2pS5SBR3TWoVnEK1zxtLI/3N7BjHyGF84fgw==", "devOptional": true }, "node_modules/@prisma/fetch-engine": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.7.0.tgz", - "integrity": "sha512-zIn/qmO+N/3FYe7/L9o+yZseIU8ivh4NdPKSkQRIHfg2QVTVMnbhGoTcecbxfVubeTp+DjcbjS0H9fCuM4W04w==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.7.1.tgz", + "integrity": "sha512-9ELauIEBkIaEUpMIYPRlh5QELfoC6pyHolHVQgbNxglaINikZ9w9X7r1TIePAcm05pCNp2XPY1ObQIJW5nYfBQ==", "devOptional": true, "dependencies": { - "@prisma/debug": "5.7.0", - "@prisma/engines-version": "5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9", - "@prisma/get-platform": "5.7.0" + "@prisma/debug": "5.7.1", + "@prisma/engines-version": "5.7.1-1.0ca5ccbcfa6bdc81c003cf549abe4269f59c41e5", + "@prisma/get-platform": "5.7.1" } }, "node_modules/@prisma/get-platform": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.7.0.tgz", - "integrity": "sha512-ZeV/Op4bZsWXuw5Tg05WwRI8BlKiRFhsixPcAM+5BKYSiUZiMKIi713tfT3drBq8+T0E1arNZgYSA9QYcglWNA==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.7.1.tgz", + "integrity": "sha512-eDlswr3a1m5z9D/55Iyt/nZqS5UpD+DZ9MooBB3hvrcPhDQrcf9m4Tl7buy4mvAtrubQ626ECtb8c6L/f7rGSQ==", "devOptional": true, "dependencies": { - "@prisma/debug": "5.7.0" + "@prisma/debug": "5.7.1" } }, "node_modules/@radix-ui/primitive": { @@ -4438,13 +4438,13 @@ } }, "node_modules/prisma": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.7.0.tgz", - "integrity": "sha512-0rcfXO2ErmGAtxnuTNHQT9ztL0zZheQjOI/VNJzdq87C3TlGPQtMqtM+KCwU6XtmkoEr7vbCQqA7HF9IY0ST+Q==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.7.1.tgz", + "integrity": "sha512-ekho7ziH0WEJvC4AxuJz+ewRTMskrebPcrKuBwcNzVDniYxx+dXOGcorNeIb9VEMO5vrKzwNYvhD271Ui2jnNw==", "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/engines": "5.7.0" + "@prisma/engines": "5.7.1" }, "bin": { "prisma": "build/index.js" diff --git a/package.json b/package.json index 97f6bfc..5c40363 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "dependencies": { "@clerk/nextjs": "^4.27.7", "@clerk/themes": "^1.7.9", - "@prisma/client": "^5.7.0", + "@prisma/client": "^5.7.1", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-tooltip": "^1.0.7", @@ -38,7 +38,7 @@ "eslint": "^8", "eslint-config-next": "14.0.4", "postcss": "^8", - "prisma": "^5.7.0", + "prisma": "^5.7.1", "tailwindcss": "^3.3.0", "typescript": "^5" } diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 7d238bb..a5f51ac 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -24,6 +24,8 @@ model User { blocking Block[] @relation("Blocking") blockedBy Block[] @relation("BlockedBy") + Stream Stream? + createAt DateTime @default(now()) updatedAt DateTime @updatedAt } @@ -32,6 +34,25 @@ model Stream { id String @id @default(uuid()) name String @db.Text thumbnailUrl String? @db.Text + + ingressId String? @unique + serverUrl String? @db.Text + streamKey String? @db.Text + + isLive Boolean @default(false) + isChatEnabled Boolean @default(true) + isChatDelayed Boolean @default(false) + isChatFollowersOnly Boolean @default(false) + + userId String @unique + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + // @@fulltext([name]) + + @@index([userId]) + @@index([ingressId]) } model Follow {