diff --git a/drizzle/0000_loose_catseye.sql b/drizzle/0000_loose_catseye.sql new file mode 100644 index 0000000..e7d7fd7 --- /dev/null +++ b/drizzle/0000_loose_catseye.sql @@ -0,0 +1,56 @@ +-- Current sql file was generated after introspecting the database +-- If you want to run this migration please uncomment this code before executing migrations +/* +CREATE TABLE "session" ( + "sessionToken" text PRIMARY KEY NOT NULL, + "userId" text NOT NULL, + "expires" timestamp NOT NULL +); +--> statement-breakpoint +CREATE TABLE "user" ( + "id" text PRIMARY KEY NOT NULL, + "name" text, + "email" text NOT NULL, + "emailVerified" timestamp, + "image" text +); +--> statement-breakpoint +CREATE TABLE "verificationToken" ( + "identifier" text NOT NULL, + "token" text NOT NULL, + "expires" timestamp NOT NULL, + CONSTRAINT "verificationToken_identifier_token_pk" PRIMARY KEY("identifier","token") +); +--> statement-breakpoint +CREATE TABLE "authenticator" ( + "credentialID" text NOT NULL, + "userId" text NOT NULL, + "providerAccountId" text NOT NULL, + "credentialPublicKey" text NOT NULL, + "counter" integer NOT NULL, + "credentialDeviceType" text NOT NULL, + "credentialBackedUp" boolean NOT NULL, + "transports" text, + CONSTRAINT "authenticator_userId_credentialID_pk" PRIMARY KEY("credentialID","userId"), + CONSTRAINT "authenticator_credentialID_unique" UNIQUE("credentialID") +); +--> statement-breakpoint +CREATE TABLE "account" ( + "userId" text NOT NULL, + "type" text NOT NULL, + "provider" text NOT NULL, + "providerAccountId" text NOT NULL, + "refresh_token" text, + "access_token" text, + "expires_at" text, + "token_type" text, + "scope" text, + "id_token" text, + "session_state" text, + CONSTRAINT "account_provider_providerAccountId_pk" PRIMARY KEY("provider","providerAccountId") +); +--> statement-breakpoint +ALTER TABLE "session" ADD CONSTRAINT "session_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "authenticator" ADD CONSTRAINT "authenticator_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "account" ADD CONSTRAINT "account_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +*/ \ No newline at end of file diff --git a/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json new file mode 100644 index 0000000..2034f91 --- /dev/null +++ b/drizzle/meta/0000_snapshot.json @@ -0,0 +1,344 @@ +{ + "id": "00000000-0000-0000-0000-000000000000", + "prevId": "", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "schemaTo": "public", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {}, + "policies": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {}, + "policies": {}, + "isRLSEnabled": false + }, + "public.verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraints": {}, + "policies": {}, + "isRLSEnabled": false + }, + "public.authenticator": { + "name": "authenticator", + "schema": "", + "columns": { + "credentialID": { + "name": "credentialID", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credentialPublicKey": { + "name": "credentialPublicKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "counter": { + "name": "counter", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "credentialDeviceType": { + "name": "credentialDeviceType", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credentialBackedUp": { + "name": "credentialBackedUp", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "transports": { + "name": "transports", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "authenticator_userId_user_id_fk": { + "name": "authenticator_userId_user_id_fk", + "tableFrom": "authenticator", + "tableTo": "user", + "schemaTo": "public", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "authenticator_userId_credentialID_pk": { + "name": "authenticator_userId_credentialID_pk", + "columns": [ + "credentialID", + "userId" + ] + } + }, + "uniqueConstraints": { + "authenticator_credentialID_unique": { + "columns": [ + "credentialID" + ], + "nullsNotDistinct": false, + "name": "authenticator_credentialID_unique" + } + }, + "checkConstraints": {}, + "policies": {}, + "isRLSEnabled": false + }, + "public.account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "schemaTo": "public", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraints": {}, + "policies": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json new file mode 100644 index 0000000..612f104 --- /dev/null +++ b/drizzle/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "7", + "dialect": "postgresql", + "entries": [ + { + "idx": 0, + "version": "7", + "when": 1755586325384, + "tag": "0000_loose_catseye", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/drizzle/relations.ts b/drizzle/relations.ts new file mode 100644 index 0000000..9be20fe --- /dev/null +++ b/drizzle/relations.ts @@ -0,0 +1,29 @@ +import { relations } from "drizzle-orm/relations"; +import { user, session, authenticator, account } from "./schema"; + +export const sessionRelations = relations(session, ({one}) => ({ + user: one(user, { + fields: [session.userId], + references: [user.id] + }), +})); + +export const userRelations = relations(user, ({many}) => ({ + sessions: many(session), + authenticators: many(authenticator), + accounts: many(account), +})); + +export const authenticatorRelations = relations(authenticator, ({one}) => ({ + user: one(user, { + fields: [authenticator.userId], + references: [user.id] + }), +})); + +export const accountRelations = relations(account, ({one}) => ({ + user: one(user, { + fields: [account.userId], + references: [user.id] + }), +})); \ No newline at end of file diff --git a/drizzle/schema.ts b/drizzle/schema.ts new file mode 100644 index 0000000..84beebe --- /dev/null +++ b/drizzle/schema.ts @@ -0,0 +1,72 @@ +import { pgTable, foreignKey, text, timestamp, primaryKey, unique, integer, boolean } from "drizzle-orm/pg-core" +import { sql } from "drizzle-orm" + + + +export const session = pgTable("session", { + sessionToken: text().primaryKey().notNull(), + userId: text().notNull(), + expires: timestamp({ mode: 'string' }).notNull(), +}, (table) => [ + foreignKey({ + columns: [table.userId], + foreignColumns: [user.id], + name: "session_userId_user_id_fk" + }).onDelete("cascade"), +]); + +export const user = pgTable("user", { + id: text().primaryKey().notNull(), + name: text(), + email: text().notNull(), + emailVerified: timestamp({ mode: 'string' }), + image: text(), +}); + +export const verificationToken = pgTable("verificationToken", { + identifier: text().notNull(), + token: text().notNull(), + expires: timestamp({ mode: 'string' }).notNull(), +}, (table) => [ + primaryKey({ columns: [table.identifier, table.token], name: "verificationToken_identifier_token_pk"}), +]); + +export const authenticator = pgTable("authenticator", { + credentialId: text().notNull(), + userId: text().notNull(), + providerAccountId: text().notNull(), + credentialPublicKey: text().notNull(), + counter: integer().notNull(), + credentialDeviceType: text().notNull(), + credentialBackedUp: boolean().notNull(), + transports: text(), +}, (table) => [ + foreignKey({ + columns: [table.userId], + foreignColumns: [user.id], + name: "authenticator_userId_user_id_fk" + }).onDelete("cascade"), + primaryKey({ columns: [table.credentialId, table.userId], name: "authenticator_userId_credentialID_pk"}), + unique("authenticator_credentialID_unique").on(table.credentialId), +]); + +export const account = pgTable("account", { + userId: text().notNull(), + type: text().notNull(), + provider: text().notNull(), + providerAccountId: text().notNull(), + refreshToken: text("refresh_token"), + accessToken: text("access_token"), + expiresAt: text("expires_at"), + tokenType: text("token_type"), + scope: text(), + idToken: text("id_token"), + sessionState: text("session_state"), +}, (table) => [ + foreignKey({ + columns: [table.userId], + foreignColumns: [user.id], + name: "account_userId_user_id_fk" + }).onDelete("cascade"), + primaryKey({ columns: [table.provider, table.providerAccountId], name: "account_provider_providerAccountId_pk"}), +]); diff --git a/src/app/api/ai-event/route.ts b/src/app/api/ai-event/route.ts index 25ddc16..b355a95 100644 --- a/src/app/api/ai-event/route.ts +++ b/src/app/api/ai-event/route.ts @@ -1,6 +1,16 @@ import { NextResponse } from "next/server"; +import { auth } from "@/auth"; export async function POST(request: Request) { + const session = await auth(); + + if (!session?.user) { + return NextResponse.json( + { error: "Authentication required" }, + { status: 401 } + ); + } + const { prompt } = await request.json(); const systemPrompt = ` diff --git a/src/app/components/sign-in.tsx b/src/app/components/sign-in.tsx index e393d37..3d6c66f 100644 --- a/src/app/components/sign-in.tsx +++ b/src/app/components/sign-in.tsx @@ -1,37 +1,43 @@ -import { signIn, signOut } from "@/auth" -import { auth } from "@/auth" -import { Button } from "@/components/ui/button" +"use client" -export default async function SignIn() { - const session = await auth() +import { signOut, useSession } from "next-auth/react" +import { Button } from "@/components/ui/button" +import { useRouter } from "next/navigation" + +export default function SignIn() { + const { data: session, status } = useSession() + const router = useRouter() + + const handleSignOut = async () => { + await signOut({ redirect: false }) + router.push("/") + router.refresh() + } + + if (status === "loading") { + return
+ } if (session?.user) { return (