From ba7a1dcc2c92407a55e353d0b75e3fbec69594e2 Mon Sep 17 00:00:00 2001 From: Akhileshrangani4 Date: Fri, 29 Nov 2024 13:05:35 -0500 Subject: [PATCH] chore: formatting the code of recent changes --- backend/database/src/index.ts | 849 +++++++++--------- backend/database/src/schema.ts | 160 ++-- frontend/app/api/ai/route.ts | 34 +- frontend/app/api/user/upgrade-tier/route.ts | 6 +- frontend/components/editor/AIChat/index.tsx | 12 +- .../components/editor/AIChat/lib/chatUtils.ts | 27 +- frontend/components/editor/generate.tsx | 12 +- frontend/components/editor/index.tsx | 104 +-- frontend/components/profile/index.tsx | 13 +- frontend/components/ui/userButton.tsx | 40 +- frontend/lib/data/index.ts | 2 +- frontend/lib/templates/index.ts | 572 ++++++------ frontend/lib/tiers.ts | 36 +- 13 files changed, 956 insertions(+), 911 deletions(-) diff --git a/backend/database/src/index.ts b/backend/database/src/index.ts index 5fd6f50..80e38e4 100644 --- a/backend/database/src/index.ts +++ b/backend/database/src/index.ts @@ -6,18 +6,18 @@ import { z } from "zod" import { and, eq, sql } from "drizzle-orm" import * as schema from "./schema" import { - Sandbox, - sandbox, - sandboxLikes, - user, - usersToSandboxes, + Sandbox, + sandbox, + sandboxLikes, + user, + usersToSandboxes, } from "./schema" export interface Env { - DB: D1Database - STORAGE: any - KEY: string - STORAGE_WORKER_URL: string + DB: D1Database + STORAGE: any + KEY: string + STORAGE_WORKER_URL: string } // https://github.com/drizzle-team/drizzle-orm/tree/main/examples/cloudflare-d1 @@ -25,469 +25,488 @@ export interface Env { // npm run generate // npx wrangler d1 execute d1-sandbox --local --file=./drizzle/ interface SandboxWithLiked extends Sandbox { - liked: boolean + liked: boolean } interface UserResponse extends Omit { - sandbox: SandboxWithLiked[] + sandbox: SandboxWithLiked[] } export default { - async fetch( - request: Request, - env: Env, - ctx: ExecutionContext - ): Promise { - const success = new Response("Success", { status: 200 }) - const invalidRequest = new Response("Invalid Request", { status: 400 }) - const notFound = new Response("Not Found", { status: 404 }) - const methodNotAllowed = new Response("Method Not Allowed", { status: 405 }) + async fetch( + request: Request, + env: Env, + ctx: ExecutionContext + ): Promise { + const success = new Response("Success", { status: 200 }) + const invalidRequest = new Response("Invalid Request", { status: 400 }) + const notFound = new Response("Not Found", { status: 404 }) + const methodNotAllowed = new Response("Method Not Allowed", { status: 405 }) - const url = new URL(request.url) - const path = url.pathname - const method = request.method + const url = new URL(request.url) + const path = url.pathname + const method = request.method - if (request.headers.get("Authorization") !== env.KEY) { - return new Response("Unauthorized", { status: 401 }) - } + if (request.headers.get("Authorization") !== env.KEY) { + return new Response("Unauthorized", { status: 401 }) + } - const db = drizzle(env.DB, { schema }) + const db = drizzle(env.DB, { schema }) - if (path === "/api/sandbox") { - if (method === "GET") { - const params = url.searchParams - if (params.has("id")) { - const id = params.get("id") as string - const res = await db.query.sandbox.findFirst({ - where: (sandbox, { eq }) => eq(sandbox.id, id), - with: { - usersToSandboxes: true, - }, - }) - return json(res ?? {}) - } else { - const res = await db.select().from(sandbox).all() - return json(res ?? {}) - } - } else if (method === "DELETE") { - const params = url.searchParams - if (params.has("id")) { - const id = params.get("id") as string - await db - .delete(usersToSandboxes) - .where(eq(usersToSandboxes.sandboxId, id)) - await db.delete(sandbox).where(eq(sandbox.id, id)) + if (path === "/api/sandbox") { + if (method === "GET") { + const params = url.searchParams + if (params.has("id")) { + const id = params.get("id") as string + const res = await db.query.sandbox.findFirst({ + where: (sandbox, { eq }) => eq(sandbox.id, id), + with: { + usersToSandboxes: true, + }, + }) + return json(res ?? {}) + } else { + const res = await db.select().from(sandbox).all() + return json(res ?? {}) + } + } else if (method === "DELETE") { + const params = url.searchParams + if (params.has("id")) { + const id = params.get("id") as string + await db + .delete(usersToSandboxes) + .where(eq(usersToSandboxes.sandboxId, id)) + await db.delete(sandbox).where(eq(sandbox.id, id)) - const deleteStorageRequest = new Request( - `${env.STORAGE_WORKER_URL}/api/project`, - { - method: "DELETE", - body: JSON.stringify({ sandboxId: id }), - headers: { - "Content-Type": "application/json", - Authorization: `${env.KEY}`, - }, - } - ) - await env.STORAGE.fetch(deleteStorageRequest) + const deleteStorageRequest = new Request( + `${env.STORAGE_WORKER_URL}/api/project`, + { + method: "DELETE", + body: JSON.stringify({ sandboxId: id }), + headers: { + "Content-Type": "application/json", + Authorization: `${env.KEY}`, + }, + } + ) + await env.STORAGE.fetch(deleteStorageRequest) - return success - } else { - return invalidRequest - } - } else if (method === "POST") { - const postSchema = z.object({ - id: z.string(), - name: z.string().optional(), - visibility: z.enum(["public", "private"]).optional(), - }) + return success + } else { + return invalidRequest + } + } else if (method === "POST") { + const postSchema = z.object({ + id: z.string(), + name: z.string().optional(), + visibility: z.enum(["public", "private"]).optional(), + }) - const body = await request.json() - const { id, name, visibility } = postSchema.parse(body) - const sb = await db - .update(sandbox) - .set({ name, visibility }) - .where(eq(sandbox.id, id)) - .returning() - .get() + const body = await request.json() + const { id, name, visibility } = postSchema.parse(body) + const sb = await db + .update(sandbox) + .set({ name, visibility }) + .where(eq(sandbox.id, id)) + .returning() + .get() - return success - } else if (method === "PUT") { - const initSchema = z.object({ - type: z.string(), - name: z.string(), - userId: z.string(), - visibility: z.enum(["public", "private"]), - }) + return success + } else if (method === "PUT") { + const initSchema = z.object({ + type: z.string(), + name: z.string(), + userId: z.string(), + visibility: z.enum(["public", "private"]), + }) - const body = await request.json() - const { type, name, userId, visibility } = initSchema.parse(body) + const body = await request.json() + const { type, name, userId, visibility } = initSchema.parse(body) - const userSandboxes = await db - .select() - .from(sandbox) - .where(eq(sandbox.userId, userId)) - .all() + const userSandboxes = await db + .select() + .from(sandbox) + .where(eq(sandbox.userId, userId)) + .all() - if (userSandboxes.length >= 8) { - return new Response("You reached the maximum # of sandboxes.", { - status: 400, - }) - } + if (userSandboxes.length >= 8) { + return new Response("You reached the maximum # of sandboxes.", { + status: 400, + }) + } - const sb = await db - .insert(sandbox) - .values({ type, name, userId, visibility, createdAt: new Date() }) - .returning() - .get() + const sb = await db + .insert(sandbox) + .values({ type, name, userId, visibility, createdAt: new Date() }) + .returning() + .get() - const initStorageRequest = new Request( - `${env.STORAGE_WORKER_URL}/api/init`, - { - method: "POST", - body: JSON.stringify({ sandboxId: sb.id, type }), - headers: { - "Content-Type": "application/json", - Authorization: `${env.KEY}`, - }, - } - ) + const initStorageRequest = new Request( + `${env.STORAGE_WORKER_URL}/api/init`, + { + method: "POST", + body: JSON.stringify({ sandboxId: sb.id, type }), + headers: { + "Content-Type": "application/json", + Authorization: `${env.KEY}`, + }, + } + ) - await env.STORAGE.fetch(initStorageRequest) + await env.STORAGE.fetch(initStorageRequest) - return new Response(sb.id, { status: 200 }) - } else { - return methodNotAllowed - } - } else if (path === "/api/sandbox/share") { - if (method === "GET") { - const params = url.searchParams - if (params.has("id")) { - const id = params.get("id") as string - const res = await db.query.usersToSandboxes.findMany({ - where: (uts, { eq }) => eq(uts.userId, id), - }) + return new Response(sb.id, { status: 200 }) + } else { + return methodNotAllowed + } + } else if (path === "/api/sandbox/share") { + if (method === "GET") { + const params = url.searchParams + if (params.has("id")) { + const id = params.get("id") as string + const res = await db.query.usersToSandboxes.findMany({ + where: (uts, { eq }) => eq(uts.userId, id), + }) - const owners = await Promise.all( - res.map(async (r) => { - const sb = await db.query.sandbox.findFirst({ - where: (sandbox, { eq }) => eq(sandbox.id, r.sandboxId), - with: { - author: true, - }, - }) - if (!sb) return - return { - id: sb.id, - name: sb.name, - type: sb.type, - author: sb.author.name, - authorAvatarUrl: sb.author.avatarUrl, - sharedOn: r.sharedOn, - } - }) - ) + const owners = await Promise.all( + res.map(async (r) => { + const sb = await db.query.sandbox.findFirst({ + where: (sandbox, { eq }) => eq(sandbox.id, r.sandboxId), + with: { + author: true, + }, + }) + if (!sb) return + return { + id: sb.id, + name: sb.name, + type: sb.type, + author: sb.author.name, + authorAvatarUrl: sb.author.avatarUrl, + sharedOn: r.sharedOn, + } + }) + ) - return json(owners ?? {}) - } else return invalidRequest - } else if (method === "POST") { - const shareSchema = z.object({ - sandboxId: z.string(), - email: z.string(), - }) + return json(owners ?? {}) + } else return invalidRequest + } else if (method === "POST") { + const shareSchema = z.object({ + sandboxId: z.string(), + email: z.string(), + }) - const body = await request.json() - const { sandboxId, email } = shareSchema.parse(body) + const body = await request.json() + const { sandboxId, email } = shareSchema.parse(body) - const user = await db.query.user.findFirst({ - where: (user, { eq }) => eq(user.email, email), - with: { - sandbox: true, - usersToSandboxes: true, - }, - }) + const user = await db.query.user.findFirst({ + where: (user, { eq }) => eq(user.email, email), + with: { + sandbox: true, + usersToSandboxes: true, + }, + }) - if (!user) { - return new Response("No user associated with email.", { status: 400 }) - } + if (!user) { + return new Response("No user associated with email.", { status: 400 }) + } - if (user.sandbox.find((sb) => sb.id === sandboxId)) { - return new Response("Cannot share with yourself!", { status: 400 }) - } + if (user.sandbox.find((sb) => sb.id === sandboxId)) { + return new Response("Cannot share with yourself!", { status: 400 }) + } - if (user.usersToSandboxes.find((uts) => uts.sandboxId === sandboxId)) { - return new Response("User already has access.", { status: 400 }) - } + if (user.usersToSandboxes.find((uts) => uts.sandboxId === sandboxId)) { + return new Response("User already has access.", { status: 400 }) + } - await db - .insert(usersToSandboxes) - .values({ userId: user.id, sandboxId, sharedOn: new Date() }) - .get() + await db + .insert(usersToSandboxes) + .values({ userId: user.id, sandboxId, sharedOn: new Date() }) + .get() - return success - } else if (method === "DELETE") { - const deleteShareSchema = z.object({ - sandboxId: z.string(), - userId: z.string(), - }) + return success + } else if (method === "DELETE") { + const deleteShareSchema = z.object({ + sandboxId: z.string(), + userId: z.string(), + }) - const body = await request.json() - const { sandboxId, userId } = deleteShareSchema.parse(body) + const body = await request.json() + const { sandboxId, userId } = deleteShareSchema.parse(body) - await db - .delete(usersToSandboxes) - .where( - and( - eq(usersToSandboxes.userId, userId), - eq(usersToSandboxes.sandboxId, sandboxId) - ) - ) + await db + .delete(usersToSandboxes) + .where( + and( + eq(usersToSandboxes.userId, userId), + eq(usersToSandboxes.sandboxId, sandboxId) + ) + ) - return success - } else return methodNotAllowed - } else if (path === "/api/user") { - if (method === "GET") { - const params = url.searchParams + return success + } else return methodNotAllowed + } else if (path === "/api/user") { + if (method === "GET") { + const params = url.searchParams - if (params.has("id")) { - const id = params.get("id") as string + if (params.has("id")) { + const id = params.get("id") as string - const res = await db.query.user.findFirst({ - where: (user, { eq }) => eq(user.id, id), - with: { - sandbox: { - orderBy: (sandbox, { desc }) => [desc(sandbox.createdAt)], - with: { - likes: true, - }, - }, - usersToSandboxes: true, - }, - }) - if (res) { - const transformedUser: UserResponse = { - ...res, - sandbox: res.sandbox.map( - (sb): SandboxWithLiked => ({ - ...sb, - liked: sb.likes.some((like) => like.userId === id), - }) - ), - } - return json(transformedUser) - } - return json(res ?? {}) - } else if (params.has("username")) { - const username = params.get("username") as string - const userId = params.get("currentUserId") - const res = await db.query.user.findFirst({ - where: (user, { eq }) => eq(user.username, username), - with: { - sandbox: { - orderBy: (sandbox, { desc }) => [desc(sandbox.createdAt)], - with: { - likes: true, - }, - }, - usersToSandboxes: true, - }, - }) - if (res) { - const transformedUser: UserResponse = { - ...res, - sandbox: res.sandbox.map( - (sb): SandboxWithLiked => ({ - ...sb, - liked: sb.likes.some((like) => like.userId === userId), - }) - ), - } - return json(transformedUser) - } - return json(res ?? {}) - } else { - const res = await db.select().from(user).all() - return json(res ?? {}) - } - } else if (method === "POST") { - const userSchema = z.object({ - id: z.string(), - name: z.string(), - email: z.string().email(), - username: z.string(), - avatarUrl: z.string().optional(), - createdAt: z.string().optional(), - generations: z.number().optional(), - tier: z.enum(["FREE", "PRO", "ENTERPRISE"]).optional(), - tierExpiresAt: z.number().optional(), - lastResetDate: z.number().optional(), - }) + const res = await db.query.user.findFirst({ + where: (user, { eq }) => eq(user.id, id), + with: { + sandbox: { + orderBy: (sandbox, { desc }) => [desc(sandbox.createdAt)], + with: { + likes: true, + }, + }, + usersToSandboxes: true, + }, + }) + if (res) { + const transformedUser: UserResponse = { + ...res, + sandbox: res.sandbox.map( + (sb): SandboxWithLiked => ({ + ...sb, + liked: sb.likes.some((like) => like.userId === id), + }) + ), + } + return json(transformedUser) + } + return json(res ?? {}) + } else if (params.has("username")) { + const username = params.get("username") as string + const userId = params.get("currentUserId") + const res = await db.query.user.findFirst({ + where: (user, { eq }) => eq(user.username, username), + with: { + sandbox: { + orderBy: (sandbox, { desc }) => [desc(sandbox.createdAt)], + with: { + likes: true, + }, + }, + usersToSandboxes: true, + }, + }) + if (res) { + const transformedUser: UserResponse = { + ...res, + sandbox: res.sandbox.map( + (sb): SandboxWithLiked => ({ + ...sb, + liked: sb.likes.some((like) => like.userId === userId), + }) + ), + } + return json(transformedUser) + } + return json(res ?? {}) + } else { + const res = await db.select().from(user).all() + return json(res ?? {}) + } + } else if (method === "POST") { + const userSchema = z.object({ + id: z.string(), + name: z.string(), + email: z.string().email(), + username: z.string(), + avatarUrl: z.string().optional(), + createdAt: z.string().optional(), + generations: z.number().optional(), + tier: z.enum(["FREE", "PRO", "ENTERPRISE"]).optional(), + tierExpiresAt: z.number().optional(), + lastResetDate: z.number().optional(), + }) - const body = await request.json() + const body = await request.json() - const { id, name, email, username, avatarUrl, createdAt, generations, tier, tierExpiresAt, lastResetDate } = userSchema.parse(body) - const res = await db - .insert(user) - .values({ - id, - name, - email, - username, - avatarUrl, - createdAt: createdAt ? new Date(createdAt) : new Date(), - generations, - tier, - tierExpiresAt, - lastResetDate, - }) - .returning() - .get() - return json({ res }) - } else if (method === "DELETE") { - const params = url.searchParams - if (params.has("id")) { - const id = params.get("id") as string - await db.delete(user).where(eq(user.id, id)) - return success - } else return invalidRequest - } else if (method === "PUT") { - const updateUserSchema = z.object({ - id: z.string(), - name: z.string().optional(), - email: z.string().email().optional(), - username: z.string().optional(), - avatarUrl: z.string().optional(), - generations: z.number().optional(), - }) + const { + id, + name, + email, + username, + avatarUrl, + createdAt, + generations, + tier, + tierExpiresAt, + lastResetDate, + } = userSchema.parse(body) + const res = await db + .insert(user) + .values({ + id, + name, + email, + username, + avatarUrl, + createdAt: createdAt ? new Date(createdAt) : new Date(), + generations, + tier, + tierExpiresAt, + lastResetDate, + }) + .returning() + .get() + return json({ res }) + } else if (method === "DELETE") { + const params = url.searchParams + if (params.has("id")) { + const id = params.get("id") as string + await db.delete(user).where(eq(user.id, id)) + return success + } else return invalidRequest + } else if (method === "PUT") { + const updateUserSchema = z.object({ + id: z.string(), + name: z.string().optional(), + email: z.string().email().optional(), + username: z.string().optional(), + avatarUrl: z.string().optional(), + generations: z.number().optional(), + }) - try { - const body = await request.json() - const validatedData = updateUserSchema.parse(body) + try { + const body = await request.json() + const validatedData = updateUserSchema.parse(body) - const { id, username, ...updateData } = validatedData + const { id, username, ...updateData } = validatedData - // If username is being updated, check for existing username - if (username) { - const existingUser = await db - .select() - .from(user) - .where(eq(user.username, username)) - .get() - if (existingUser && existingUser.id !== id) { - return json({ error: "Username already exists" }, { status: 409 }) - } - } + // If username is being updated, check for existing username + if (username) { + const existingUser = await db + .select() + .from(user) + .where(eq(user.username, username)) + .get() + if (existingUser && existingUser.id !== id) { + return json({ error: "Username already exists" }, { status: 409 }) + } + } - const cleanUpdateData = { - ...updateData, - ...(username ? { username } : {}), - } + const cleanUpdateData = { + ...updateData, + ...(username ? { username } : {}), + } - const res = await db - .update(user) - .set(cleanUpdateData) - .where(eq(user.id, id)) - .returning() - .get() + const res = await db + .update(user) + .set(cleanUpdateData) + .where(eq(user.id, id)) + .returning() + .get() - if (!res) { - return json({ error: "User not found" }, { status: 404 }) - } + if (!res) { + return json({ error: "User not found" }, { status: 404 }) + } - return json({ res }) - } catch (error) { - if (error instanceof z.ZodError) { - return json({ error: error.errors }, { status: 400 }) - } - return json({ error: "Internal server error" }, { status: 500 }) - } - } else { - return methodNotAllowed - } - } else if (path === "/api/user/check-username") { - if (method === "GET") { - const params = url.searchParams - const username = params.get("username") + return json({ res }) + } catch (error) { + if (error instanceof z.ZodError) { + return json({ error: error.errors }, { status: 400 }) + } + return json({ error: "Internal server error" }, { status: 500 }) + } + } else { + return methodNotAllowed + } + } else if (path === "/api/user/check-username") { + if (method === "GET") { + const params = url.searchParams + const username = params.get("username") - if (!username) return invalidRequest + if (!username) return invalidRequest - const exists = await db.query.user.findFirst({ - where: (user, { eq }) => eq(user.username, username), - }) + const exists = await db.query.user.findFirst({ + where: (user, { eq }) => eq(user.username, username), + }) - return json({ exists: !!exists }) - } - return methodNotAllowed - } else if (path === "/api/user/increment-generations" && method === "POST") { - const schema = z.object({ - userId: z.string(), - }) + return json({ exists: !!exists }) + } + return methodNotAllowed + } else if ( + path === "/api/user/increment-generations" && + method === "POST" + ) { + const schema = z.object({ + userId: z.string(), + }) - const body = await request.json() - const { userId } = schema.parse(body) + const body = await request.json() + const { userId } = schema.parse(body) - await db - .update(user) - .set({ generations: sql`${user.generations} + 1` }) - .where(eq(user.id, userId)) - .get() + await db + .update(user) + .set({ generations: sql`${user.generations} + 1` }) + .where(eq(user.id, userId)) + .get() - return success - } else if (path === "/api/user/update-tier" && method === "POST") { - const schema = z.object({ - userId: z.string(), - tier: z.enum(["FREE", "PRO", "ENTERPRISE"]), - tierExpiresAt: z.date(), - }) + return success + } else if (path === "/api/user/update-tier" && method === "POST") { + const schema = z.object({ + userId: z.string(), + tier: z.enum(["FREE", "PRO", "ENTERPRISE"]), + tierExpiresAt: z.date(), + }) - const body = await request.json() - const { userId, tier, tierExpiresAt } = schema.parse(body) + const body = await request.json() + const { userId, tier, tierExpiresAt } = schema.parse(body) - await db - .update(user) - .set({ - tier, - tierExpiresAt: tierExpiresAt.getTime(), - // Reset generations when upgrading tier - generations: 0 - }) - .where(eq(user.id, userId)) - .get() + await db + .update(user) + .set({ + tier, + tierExpiresAt: tierExpiresAt.getTime(), + // Reset generations when upgrading tier + generations: 0, + }) + .where(eq(user.id, userId)) + .get() - return success - } else if (path === "/api/user/check-reset" && method === "POST") { - const schema = z.object({ - userId: z.string(), - }) + return success + } else if (path === "/api/user/check-reset" && method === "POST") { + const schema = z.object({ + userId: z.string(), + }) - const body = await request.json() - const { userId } = schema.parse(body) + const body = await request.json() + const { userId } = schema.parse(body) - const dbUser = await db.query.user.findFirst({ - where: (user, { eq }) => eq(user.id, userId), - }) + const dbUser = await db.query.user.findFirst({ + where: (user, { eq }) => eq(user.id, userId), + }) - if (!dbUser) { - return new Response("User not found", { status: 404 }) - } + if (!dbUser) { + return new Response("User not found", { status: 404 }) + } - const now = new Date() - const lastReset = dbUser.lastResetDate ? new Date(dbUser.lastResetDate) : new Date(0) + const now = new Date() + const lastReset = dbUser.lastResetDate + ? new Date(dbUser.lastResetDate) + : new Date(0) - if (now.getMonth() !== lastReset.getMonth() || now.getFullYear() !== lastReset.getFullYear()) { - await db - .update(user) - .set({ - generations: 0, - lastResetDate: now.getTime() - }) - .where(eq(user.id, userId)) - .get() - - return new Response("Reset successful", { status: 200 }) - } + if ( + now.getMonth() !== lastReset.getMonth() || + now.getFullYear() !== lastReset.getFullYear() + ) { + await db + .update(user) + .set({ + generations: 0, + lastResetDate: now.getTime(), + }) + .where(eq(user.id, userId)) + .get() - return new Response("No reset needed", { status: 200 }) - } else return notFound - }, + return new Response("Reset successful", { status: 200 }) + } + + return new Response("No reset needed", { status: 200 }) + } else return notFound + }, } diff --git a/backend/database/src/schema.ts b/backend/database/src/schema.ts index 655c897..33c86f3 100644 --- a/backend/database/src/schema.ts +++ b/backend/database/src/schema.ts @@ -4,112 +4,112 @@ import { integer, primaryKey, sqliteTable, text } from "drizzle-orm/sqlite-core" // #region Tables export const user = sqliteTable("user", { - id: text("id") - .$defaultFn(() => createId()) - .primaryKey() - .unique(), - name: text("name").notNull(), - email: text("email").notNull(), - username: text("username").notNull().unique(), - avatarUrl: text("avatarUrl"), - createdAt: integer("createdAt", { mode: "timestamp_ms" }).default( - sql`CURRENT_TIMESTAMP` - ), - generations: integer("generations").default(0), - tier: text("tier", { enum: ["FREE", "PRO", "ENTERPRISE"] }).default("FREE"), - tierExpiresAt: integer("tierExpiresAt"), - lastResetDate: integer("lastResetDate"), + id: text("id") + .$defaultFn(() => createId()) + .primaryKey() + .unique(), + name: text("name").notNull(), + email: text("email").notNull(), + username: text("username").notNull().unique(), + avatarUrl: text("avatarUrl"), + createdAt: integer("createdAt", { mode: "timestamp_ms" }).default( + sql`CURRENT_TIMESTAMP` + ), + generations: integer("generations").default(0), + tier: text("tier", { enum: ["FREE", "PRO", "ENTERPRISE"] }).default("FREE"), + tierExpiresAt: integer("tierExpiresAt"), + lastResetDate: integer("lastResetDate"), }) export type User = typeof user.$inferSelect export const sandbox = sqliteTable("sandbox", { - id: text("id") - .$defaultFn(() => createId()) - .primaryKey() - .unique(), - name: text("name").notNull(), - type: text("type").notNull(), - visibility: text("visibility", { enum: ["public", "private"] }), - createdAt: integer("createdAt", { mode: "timestamp_ms" }).default( - sql`CURRENT_TIMESTAMP` - ), - userId: text("user_id") - .notNull() - .references(() => user.id), - likeCount: integer("likeCount").default(0), - viewCount: integer("viewCount").default(0), + id: text("id") + .$defaultFn(() => createId()) + .primaryKey() + .unique(), + name: text("name").notNull(), + type: text("type").notNull(), + visibility: text("visibility", { enum: ["public", "private"] }), + createdAt: integer("createdAt", { mode: "timestamp_ms" }).default( + sql`CURRENT_TIMESTAMP` + ), + userId: text("user_id") + .notNull() + .references(() => user.id), + likeCount: integer("likeCount").default(0), + viewCount: integer("viewCount").default(0), }) export type Sandbox = typeof sandbox.$inferSelect export const sandboxLikes = sqliteTable( - "sandbox_likes", - { - userId: text("user_id") - .notNull() - .references(() => user.id), - sandboxId: text("sandbox_id") - .notNull() - .references(() => sandbox.id), - createdAt: integer("createdAt", { mode: "timestamp_ms" }).default( - sql`CURRENT_TIMESTAMP` - ), - }, - (table) => ({ - pk: primaryKey({ columns: [table.sandboxId, table.userId] }), - }) + "sandbox_likes", + { + userId: text("user_id") + .notNull() + .references(() => user.id), + sandboxId: text("sandbox_id") + .notNull() + .references(() => sandbox.id), + createdAt: integer("createdAt", { mode: "timestamp_ms" }).default( + sql`CURRENT_TIMESTAMP` + ), + }, + (table) => ({ + pk: primaryKey({ columns: [table.sandboxId, table.userId] }), + }) ) export const usersToSandboxes = sqliteTable("users_to_sandboxes", { - userId: text("userId") - .notNull() - .references(() => user.id), - sandboxId: text("sandboxId") - .notNull() - .references(() => sandbox.id), - sharedOn: integer("sharedOn", { mode: "timestamp_ms" }), + userId: text("userId") + .notNull() + .references(() => user.id), + sandboxId: text("sandboxId") + .notNull() + .references(() => sandbox.id), + sharedOn: integer("sharedOn", { mode: "timestamp_ms" }), }) // #region Relations export const userRelations = relations(user, ({ many }) => ({ - sandbox: many(sandbox), - usersToSandboxes: many(usersToSandboxes), - likes: many(sandboxLikes), + sandbox: many(sandbox), + usersToSandboxes: many(usersToSandboxes), + likes: many(sandboxLikes), })) export const sandboxRelations = relations(sandbox, ({ one, many }) => ({ - author: one(user, { - fields: [sandbox.userId], - references: [user.id], - }), - usersToSandboxes: many(usersToSandboxes), - likes: many(sandboxLikes), + author: one(user, { + fields: [sandbox.userId], + references: [user.id], + }), + usersToSandboxes: many(usersToSandboxes), + likes: many(sandboxLikes), })) export const sandboxLikesRelations = relations(sandboxLikes, ({ one }) => ({ - user: one(user, { - fields: [sandboxLikes.userId], - references: [user.id], - }), - sandbox: one(sandbox, { - fields: [sandboxLikes.sandboxId], - references: [sandbox.id], - }), + user: one(user, { + fields: [sandboxLikes.userId], + references: [user.id], + }), + sandbox: one(sandbox, { + fields: [sandboxLikes.sandboxId], + references: [sandbox.id], + }), })) export const usersToSandboxesRelations = relations( - usersToSandboxes, - ({ one }) => ({ - group: one(sandbox, { - fields: [usersToSandboxes.sandboxId], - references: [sandbox.id], - }), - user: one(user, { - fields: [usersToSandboxes.userId], - references: [user.id], - }), - }) + usersToSandboxes, + ({ one }) => ({ + group: one(sandbox, { + fields: [usersToSandboxes.sandboxId], + references: [sandbox.id], + }), + user: one(user, { + fields: [usersToSandboxes.userId], + references: [user.id], + }), + }) ) // #endregion diff --git a/frontend/app/api/ai/route.ts b/frontend/app/api/ai/route.ts index 7a95a8b..01e189c 100644 --- a/frontend/app/api/ai/route.ts +++ b/frontend/app/api/ai/route.ts @@ -43,42 +43,45 @@ export async function POST(request: Request) { const userData = await dbUser.json() // Get tier settings - const tierSettings = TIERS[userData.tier as keyof typeof TIERS] || TIERS.FREE + const tierSettings = + TIERS[userData.tier as keyof typeof TIERS] || TIERS.FREE if (userData.generations >= tierSettings.generations) { return new Response( - `AI generation limit reached for your ${userData.tier || "FREE"} tier`, + `AI generation limit reached for your ${userData.tier || "FREE"} tier`, { status: 429 } ) } - const { - messages, - context, - activeFileContent, + const { + messages, + context, + activeFileContent, isEditMode, fileName, line, - templateType + templateType, } = await request.json() // Get template configuration const templateConfig = templateConfigs[templateType] // Create template context - const templateContext = templateConfig ? ` + const templateContext = templateConfig + ? ` Project Template: ${templateConfig.name} File Structure: ${Object.entries(templateConfig.fileStructure) .map(([path, info]) => `${path} - ${info.description}`) - .join('\n')} + .join("\n")} Conventions: -${templateConfig.conventions.join('\n')} +${templateConfig.conventions.join("\n")} Dependencies: ${JSON.stringify(templateConfig.dependencies, null, 2)} -` : '' +` + : "" // Create system message based on mode let systemMessage @@ -146,7 +149,10 @@ ${activeFileContent ? `Active File Content:\n${activeFileContent}\n` : ""}` new ReadableStream({ async start(controller) { for await (const chunk of stream) { - if (chunk.type === "content_block_delta" && chunk.delta.type === "text_delta") { + if ( + chunk.type === "content_block_delta" && + chunk.delta.type === "text_delta" + ) { controller.enqueue(encoder.encode(chunk.delta.text)) } } @@ -164,8 +170,8 @@ ${activeFileContent ? `Active File Content:\n${activeFileContent}\n` : ""}` } catch (error) { console.error("AI generation error:", error) return new Response( - error instanceof Error ? error.message : "Internal Server Error", + error instanceof Error ? error.message : "Internal Server Error", { status: 500 } ) } -} \ No newline at end of file +} diff --git a/frontend/app/api/user/upgrade-tier/route.ts b/frontend/app/api/user/upgrade-tier/route.ts index 20bc728..0302c2d 100644 --- a/frontend/app/api/user/upgrade-tier/route.ts +++ b/frontend/app/api/user/upgrade-tier/route.ts @@ -8,9 +8,9 @@ export async function POST(request: Request) { } const { tier } = await request.json() - + // handle payment processing here - + const response = await fetch( `${process.env.NEXT_PUBLIC_DATABASE_WORKER_URL}/api/user/update-tier`, { @@ -39,4 +39,4 @@ export async function POST(request: Request) { { status: 500 } ) } -} \ No newline at end of file +} diff --git a/frontend/components/editor/AIChat/index.tsx b/frontend/components/editor/AIChat/index.tsx index bb6db27..11f4c10 100644 --- a/frontend/components/editor/AIChat/index.tsx +++ b/frontend/components/editor/AIChat/index.tsx @@ -53,7 +53,7 @@ export default function AIChat({ // scroll to bottom of chat when messages change const scrollToBottom = (force: boolean = false) => { if (!chatContainerRef.current || (!autoScroll && !force)) return - + chatContainerRef.current.scrollTo({ top: chatContainerRef.current.scrollHeight, behavior: force ? "smooth" : "auto", @@ -63,10 +63,10 @@ export default function AIChat({ // function to handle scroll events const handleScroll = () => { if (!chatContainerRef.current) return - + const { scrollTop, scrollHeight, clientHeight } = chatContainerRef.current const isAtBottom = Math.abs(scrollHeight - scrollTop - clientHeight) < 50 - + setAutoScroll(isAtBottom) setShowScrollButton(!isAtBottom) } @@ -75,8 +75,8 @@ export default function AIChat({ useEffect(() => { const container = chatContainerRef.current if (container) { - container.addEventListener('scroll', handleScroll) - return () => container.removeEventListener('scroll', handleScroll) + container.addEventListener("scroll", handleScroll) + return () => container.removeEventListener("scroll", handleScroll) } }, []) @@ -200,7 +200,7 @@ export default function AIChat({ /> ))} {isLoading && } - + {/* Add scroll to bottom button */} {showScrollButton && (