From 075f45986fd4d198292226e64afb71b3515576b4 Mon Sep 17 00:00:00 2001 From: Dhravya Date: Sat, 25 May 2024 18:41:26 -0500 Subject: refactored UI, with shared components and UI, better rules and million lint --- apps/web/src/actions/db.ts | 676 -------------------- apps/web/src/app/MessagePoster.tsx | 24 - apps/web/src/app/api/[...nextauth]/route.ts | 2 - apps/web/src/app/api/addTweetsToDb/route.ts | 91 --- apps/web/src/app/api/ask/route.ts | 78 --- apps/web/src/app/api/chat/route.ts | 109 ---- apps/web/src/app/api/getCount/route.ts | 80 --- apps/web/src/app/api/me/route.ts | 48 -- apps/web/src/app/api/query/route.ts | 88 --- apps/web/src/app/api/spaces/route.ts | 72 --- apps/web/src/app/api/store/route.ts | 165 ----- apps/web/src/app/api/vectorizeTweets/route.ts | 63 -- apps/web/src/app/content.tsx | 18 - apps/web/src/app/globals.css | 140 ---- apps/web/src/app/layout.tsx | 65 -- apps/web/src/app/not-found.tsx | 58 -- apps/web/src/app/page.tsx | 97 --- apps/web/src/app/privacy/page.tsx | 15 - apps/web/src/app/privacy/privacy.ts | 49 -- apps/web/src/assets/Bin.tsx | 104 --- apps/web/src/assets/Memories.tsx | 69 -- apps/web/src/assets/MemoryWithImages.tsx | 531 --------------- apps/web/src/assets/Note.tsx | 0 apps/web/src/components/ChatMessage.tsx | 128 ---- apps/web/src/components/Main-2.tsx | 709 --------------------- apps/web/src/components/Main.tsx | 533 ---------------- apps/web/src/components/MemoryDrawer.tsx | 51 -- apps/web/src/components/ProfileDrawer.tsx | 40 -- apps/web/src/components/SearchResults.tsx | 40 -- .../web/src/components/Sidebar/AddMemoryDialog.tsx | 480 -------------- .../src/components/Sidebar/DeleteConfirmation.tsx | 47 -- apps/web/src/components/Sidebar/EditNoteDialog.tsx | 155 ----- apps/web/src/components/Sidebar/ExpandedSpace.tsx | 287 --------- apps/web/src/components/Sidebar/FilterCombobox.tsx | 303 --------- apps/web/src/components/Sidebar/MemoriesBar.tsx | 709 --------------------- apps/web/src/components/Sidebar/SettingsTab.tsx | 99 --- apps/web/src/components/Sidebar/index.tsx | 172 ----- apps/web/src/components/WordMark.tsx | 12 - .../src/components/dev/SessionProviderWrapper.tsx | 12 - apps/web/src/components/dev/tailwindindicator.tsx | 16 - apps/web/src/components/ui/avatar.tsx | 50 -- apps/web/src/components/ui/badge.tsx | 36 -- apps/web/src/components/ui/button.tsx | 56 -- apps/web/src/components/ui/card.tsx | 86 --- apps/web/src/components/ui/command.tsx | 161 ----- apps/web/src/components/ui/dialog.tsx | 119 ---- apps/web/src/components/ui/drawer.tsx | 124 ---- apps/web/src/components/ui/dropdown-menu.tsx | 200 ------ apps/web/src/components/ui/input.tsx | 53 -- apps/web/src/components/ui/label.tsx | 26 - apps/web/src/components/ui/popover.tsx | 40 -- apps/web/src/components/ui/textarea.tsx | 57 -- apps/web/src/contexts/MemoryContext.tsx | 241 ------- apps/web/src/env.js | 59 -- apps/web/src/hooks/useDebounce.ts | 27 - apps/web/src/hooks/useTouchHold.ts | 27 - apps/web/src/hooks/useViewport.ts | 34 - apps/web/src/lib/icons.tsx | 34 - apps/web/src/lib/searchParams.ts | 12 - apps/web/src/lib/utils.ts | 111 ---- apps/web/src/server/auth.ts | 29 - apps/web/src/server/db/index.ts | 5 - apps/web/src/server/db/schema.ts | 143 ----- apps/web/src/server/db/test.ts | 6 - apps/web/src/server/helpers.ts | 39 -- 65 files changed, 8210 deletions(-) delete mode 100644 apps/web/src/actions/db.ts delete mode 100644 apps/web/src/app/MessagePoster.tsx delete mode 100644 apps/web/src/app/api/[...nextauth]/route.ts delete mode 100644 apps/web/src/app/api/addTweetsToDb/route.ts delete mode 100644 apps/web/src/app/api/ask/route.ts delete mode 100644 apps/web/src/app/api/chat/route.ts delete mode 100644 apps/web/src/app/api/getCount/route.ts delete mode 100644 apps/web/src/app/api/me/route.ts delete mode 100644 apps/web/src/app/api/query/route.ts delete mode 100644 apps/web/src/app/api/spaces/route.ts delete mode 100644 apps/web/src/app/api/store/route.ts delete mode 100644 apps/web/src/app/api/vectorizeTweets/route.ts delete mode 100644 apps/web/src/app/content.tsx delete mode 100644 apps/web/src/app/globals.css delete mode 100644 apps/web/src/app/layout.tsx delete mode 100644 apps/web/src/app/not-found.tsx delete mode 100644 apps/web/src/app/page.tsx delete mode 100644 apps/web/src/app/privacy/page.tsx delete mode 100644 apps/web/src/app/privacy/privacy.ts delete mode 100644 apps/web/src/assets/Bin.tsx delete mode 100644 apps/web/src/assets/Memories.tsx delete mode 100644 apps/web/src/assets/MemoryWithImages.tsx delete mode 100644 apps/web/src/assets/Note.tsx delete mode 100644 apps/web/src/components/ChatMessage.tsx delete mode 100644 apps/web/src/components/Main-2.tsx delete mode 100644 apps/web/src/components/Main.tsx delete mode 100644 apps/web/src/components/MemoryDrawer.tsx delete mode 100644 apps/web/src/components/ProfileDrawer.tsx delete mode 100644 apps/web/src/components/SearchResults.tsx delete mode 100644 apps/web/src/components/Sidebar/AddMemoryDialog.tsx delete mode 100644 apps/web/src/components/Sidebar/DeleteConfirmation.tsx delete mode 100644 apps/web/src/components/Sidebar/EditNoteDialog.tsx delete mode 100644 apps/web/src/components/Sidebar/ExpandedSpace.tsx delete mode 100644 apps/web/src/components/Sidebar/FilterCombobox.tsx delete mode 100644 apps/web/src/components/Sidebar/MemoriesBar.tsx delete mode 100644 apps/web/src/components/Sidebar/SettingsTab.tsx delete mode 100644 apps/web/src/components/Sidebar/index.tsx delete mode 100644 apps/web/src/components/WordMark.tsx delete mode 100644 apps/web/src/components/dev/SessionProviderWrapper.tsx delete mode 100644 apps/web/src/components/dev/tailwindindicator.tsx delete mode 100644 apps/web/src/components/ui/avatar.tsx delete mode 100644 apps/web/src/components/ui/badge.tsx delete mode 100644 apps/web/src/components/ui/button.tsx delete mode 100644 apps/web/src/components/ui/card.tsx delete mode 100644 apps/web/src/components/ui/command.tsx delete mode 100644 apps/web/src/components/ui/dialog.tsx delete mode 100644 apps/web/src/components/ui/drawer.tsx delete mode 100644 apps/web/src/components/ui/dropdown-menu.tsx delete mode 100644 apps/web/src/components/ui/input.tsx delete mode 100644 apps/web/src/components/ui/label.tsx delete mode 100644 apps/web/src/components/ui/popover.tsx delete mode 100644 apps/web/src/components/ui/textarea.tsx delete mode 100644 apps/web/src/contexts/MemoryContext.tsx delete mode 100644 apps/web/src/env.js delete mode 100644 apps/web/src/hooks/useDebounce.ts delete mode 100644 apps/web/src/hooks/useTouchHold.ts delete mode 100644 apps/web/src/hooks/useViewport.ts delete mode 100644 apps/web/src/lib/icons.tsx delete mode 100644 apps/web/src/lib/searchParams.ts delete mode 100644 apps/web/src/lib/utils.ts delete mode 100644 apps/web/src/server/auth.ts delete mode 100644 apps/web/src/server/db/index.ts delete mode 100644 apps/web/src/server/db/schema.ts delete mode 100644 apps/web/src/server/db/test.ts delete mode 100644 apps/web/src/server/helpers.ts (limited to 'apps/web/src') diff --git a/apps/web/src/actions/db.ts b/apps/web/src/actions/db.ts deleted file mode 100644 index 59eb8976..00000000 --- a/apps/web/src/actions/db.ts +++ /dev/null @@ -1,676 +0,0 @@ -"use server"; -import { cookies, headers } from "next/headers"; -import { db } from "@/server/db"; -import { - contentToSpace, - sessions, - storedContent, - users, - space, - StoredContent, -} from "@/server/db/schema"; -import { SearchResult } from "@/contexts/MemoryContext"; -import { - like, - eq, - and, - sql, - exists, - asc, - notExists, - inArray, - notInArray, -} from "drizzle-orm"; -import { union } from "drizzle-orm/sqlite-core"; -import { env } from "@/env"; - -// @todo: (future) pagination not yet needed -export async function searchMemoriesAndSpaces( - query: string, - opts?: { - filter?: { memories?: boolean; spaces?: boolean }; - range?: { offset: number; limit: number }; - memoriesRelativeToSpace?: { - fromSpaces?: number[]; - notInSpaces?: number[]; - }; - }, -): Promise { - const user = await getUser(); - - if (!user) { - return []; - } - - const defaultWhere = and( - eq(storedContent.user, user.id), - like(storedContent.title, `%${query}%`), - ); - const extraWheres = []; - - if (opts?.memoriesRelativeToSpace) { - if (opts.memoriesRelativeToSpace.fromSpaces) { - extraWheres.push( - exists( - db - .select() - .from(contentToSpace) - .where( - and( - eq(contentToSpace.contentId, storedContent.id), - inArray( - contentToSpace.spaceId, - opts.memoriesRelativeToSpace.fromSpaces, - ), - ), - ), - ), - ); - } - if (opts.memoriesRelativeToSpace.notInSpaces) { - extraWheres.push( - notExists( - db - .select() - .from(contentToSpace) - .where( - and( - eq(contentToSpace.contentId, storedContent.id), - inArray( - contentToSpace.spaceId, - opts.memoriesRelativeToSpace.notInSpaces, - ), - ), - ), - ), - ); - } - } - - try { - let searchMemoriesQuery = db - .select({ - type: sql`'memory'`, - space: sql`NULL`, - memory: storedContent as any, - }) - .from(storedContent) - .where( - extraWheres.length == 2 - ? and(and(...extraWheres), defaultWhere) - : extraWheres.length == 1 - ? and(...extraWheres, defaultWhere) - : defaultWhere, - ) - .orderBy(asc(storedContent.savedAt)); - - let searchSpacesQuery = db - .select({ - type: sql`'space'`, - space: space as any, - memory: sql`NULL`, - }) - .from(space) - .where(and(eq(space.user, user.id), like(space.name, `%${query}%`))) - .orderBy(asc(space.name)); - - let queries = []; - - console.log("adding"); - - [undefined, true].includes(opts?.filter?.memories) && - queries.push(searchMemoriesQuery); - [undefined, true].includes(opts?.filter?.spaces) && - queries.push(searchSpacesQuery); - - if (opts?.range) { - queries = queries.map((q) => - q.offset(opts.range!.offset).limit(opts.range!.limit), - ); - } else { - queries = queries.map((q) => q.all()); - } - - const data = await Promise.all(queries); - - console.log("resp", data); - - return data.reduce((acc, i) => [...acc, ...i]) as SearchResult[]; - } catch { - return []; - } -} - -export async function getMemoriesFromUrl(urls: string[]) { - const user = await getUser(); - - if (!user) { - return []; - } - - return urls.length > 0 - ? await db - .select() - .from(storedContent) - .where( - and( - inArray(storedContent.url, urls), - eq(storedContent.user, user.id), - ), - ) - .all() - : []; -} - -async function getUser() { - const token = - cookies().get("next-auth.session-token")?.value ?? - cookies().get("__Secure-authjs.session-token")?.value ?? - cookies().get("authjs.session-token")?.value ?? - headers().get("Authorization")?.replace("Bearer ", ""); - - if (!token) { - return null; - } - - const session = await db - .select() - .from(sessions) - .where(eq(sessions.sessionToken, token!)); - - if (!session || session.length === 0) { - return null; - } - - const [userData] = await db - .select() - .from(users) - .where(eq(users.id, session[0].userId)) - .limit(1); - - if (!userData) { - return null; - } - - return userData; -} - -export async function getSpace(id: number) { - const user = await getUser(); - - if (!user) { - return null; - } - - return ( - await db - .select() - .from(space) - .where(and(eq(space.id, id), eq(space.user, user.id))) - )[0]; -} - -export async function addSpace(name: string, memories: number[]) { - const user = await getUser(); - - if (!user) { - return null; - } - - const [addedSpace] = await db - .insert(space) - .values({ - name: name, - user: user.id, - }) - .returning(); - - const addedMemories = - memories.length > 0 - ? await db - .insert(contentToSpace) - .values( - memories.map((m) => ({ - contentId: m, - spaceId: addedSpace.id, - })), - ) - .returning() - : []; - - return { - space: addedSpace, - addedMemories, - }; -} - -export async function fetchContent(id: number) { - const user = await getUser(); - - if (!user) { - return null; - } - - const fetchedMemory = await db - .select() - .from(storedContent) - .where(and(eq(storedContent.id, id), eq(storedContent.user, user.id))); - - const memory = fetchedMemory.length > 0 ? fetchedMemory[0] : null; - - const spaces = memory - ? await db - .select() - .from(contentToSpace) - .where(eq(contentToSpace.contentId, memory.id)) - : []; - - return { - memory, - spaces: spaces.map((s) => s.spaceId), - }; -} - -export async function fetchContentForSpace( - spaceId: number, - range?: { - offset: number; - limit: number; - }, -) { - const user = await getUser(); - - if (!user) { - return null; - } - - const query = db - .select() - .from(storedContent) - .where( - exists( - db - .select() - .from(contentToSpace) - .where( - and( - and( - eq(contentToSpace.spaceId, spaceId), - eq(contentToSpace.contentId, storedContent.id), - ), - exists( - db - .select() - .from(space) - .where( - and( - eq(space.user, user.id), - eq(space.id, contentToSpace.spaceId), - ), - ), - ), - ), - ), - ), - ) - .orderBy(asc(storedContent.savedAt)); - - return range - ? await query.limit(range.limit).offset(range.offset) - : await query.all(); -} - -export async function fetchFreeMemories(range?: { - offset: number; - limit: number; -}) { - const user = await getUser(); - - if (!user) { - return []; - } - - try { - const query = db - .select() - .from(storedContent) - .where( - and( - notExists( - db - .select() - .from(contentToSpace) - .where(eq(contentToSpace.contentId, storedContent.id)), - ), - eq(storedContent.user, user.id), - ), - ) - .orderBy(asc(storedContent.savedAt)); - - return range - ? await query.limit(range.limit).offset(range.offset) - : await query.all(); - } catch { - return []; - } -} - -export async function updateSpaceTitle(id: number, title: string) { - const user = await getUser(); - - if (!user) { - return null; - } - - return ( - await db - .update(space) - .set({ name: title }) - .where(and(eq(space.id, id), eq(space.user, user.id))) - .returning() - )[0]; -} - -export async function addMemory( - content: typeof storedContent.$inferInsert, - spaces: number[], -) { - const user = await getUser(); - - if (!user) { - return null; - } - - if (!content.content || content.content.trim() === "") { - const resp = await fetch( - `https://cf-ai-backend.dhravya.workers.dev/getPageContent?url=${content.url}`, - { - headers: { - "X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY, - }, - }, - ); - - const data = await resp.text(); - - console.log(data); - - content.content = data; - } - - if (!content.content || content.content == "") { - return null; - } - - let [addedMemory] = await db - .insert(storedContent) - .values({ - user: user.id, - ...content, - }) - .returning(); - - const addedToSpaces = - spaces.length > 0 - ? await db - .insert(contentToSpace) - .values( - spaces.map((s) => ({ - contentId: addedMemory.id, - spaceId: s, - })), - ) - .returning() - : []; - - if (content.type === "note") { - addedMemory = ( - await db - .update(storedContent) - .set({ - url: addedMemory.url + addedMemory.id, - }) - .where(eq(storedContent.id, addedMemory.id)) - .returning() - )[0]; - } - - console.log("adding with:", `${addedMemory.url}-${user.email}`); - // Add to vectorDB - const res = (await Promise.race([ - fetch("https://cf-ai-backend.dhravya.workers.dev/add", { - method: "POST", - headers: { - "X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY, - }, - body: JSON.stringify({ - pageContent: addedMemory.content, - title: addedMemory.title, - url: addedMemory.url, - user: user.email, - }), - }), - new Promise((_, reject) => - setTimeout(() => reject(new Error("Request timed out")), 40000), - ), - ])) as Response; - - return { - memory: addedMemory, - addedToSpaces, - }; -} - -export async function addContentInSpaces(id: number, contents: number[]) { - const user = await getUser(); - - if (!user) { - return null; - } - - const data = - contents.length > 0 - ? await db - .insert(contentToSpace) - .values( - contents.map((i) => ({ - spaceId: id, - contentId: i, - })), - ) - .returning() - : []; - - return data; -} - -export async function updateMemory( - id: number, - { - title, - content, - spaces, - removedFromSpaces: removeSpaces, - }: { - title?: string; - content?: string; - spaces?: number[]; - removedFromSpaces?: number[]; - }, -) { - const user = await getUser(); - - if (!user) { - return null; - } - - let updatedMemory: StoredContent | null = null; - - if (title && content) { - const [prev] = await db - .select() - .from(storedContent) - .where(and(eq(storedContent.user, user.id), eq(storedContent.id, id))); - - if (!prev) { - return null; - } - - const newContent = { - ...(title ? { title } : {}), - ...(content ? { content } : {}), - }; - - const updated = { - ...newContent, - ...prev, - }; - - console.log("adding with:", `${updated.url}-${user.email}`); - // Add to vectorDB - const res = (await Promise.race([ - fetch("https://cf-ai-backend.dhravya.workers.dev/edit", { - method: "POST", - headers: { - "X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY, - }, - body: JSON.stringify({ - pageContent: updated.content, - title: updated.title, - url: updated.url, - user: user.email, - uniqueUrl: updated.url, - }), - }), - new Promise((_, reject) => - setTimeout(() => reject(new Error("Request timed out")), 40000), - ), - ])) as Response; - - [updatedMemory] = await db - .update(storedContent) - .set(newContent) - .where(and(eq(storedContent.id, id), eq(storedContent.user, user.id))) - .returning(); - - console.log(updatedMemory, newContent); - } - - if (!updatedMemory) { - [updatedMemory] = await db - .select() - .from(storedContent) - .where(and(eq(storedContent.id, id), eq(storedContent.user, user.id))); - } - - const removedFromSpaces = removeSpaces - ? removeSpaces.length > 0 - ? await db - .delete(contentToSpace) - .where( - and( - inArray(contentToSpace.spaceId, removeSpaces), - eq(contentToSpace.contentId, id), - ), - ) - .returning() - : [] - : spaces - ? spaces.length > 0 - ? await db - .delete(contentToSpace) - .where( - and( - notInArray(contentToSpace.spaceId, spaces), - eq(contentToSpace.contentId, id), - ), - ) - .returning() - : await db - .delete(contentToSpace) - .where(eq(contentToSpace.contentId, id)) - : []; - - const addedToSpaces = - spaces && spaces.length > 0 - ? await db - .insert(contentToSpace) - .values( - spaces.map((s) => ({ - contentId: id, - spaceId: s, - })), - ) - .onConflictDoNothing() - .returning() - : []; - - const resultedSpaces = - ( - await db - .select() - .from(contentToSpace) - .where(eq(contentToSpace.contentId, id)) - .all() - ).map((i) => i.spaceId) ?? []; - - return { - memory: updatedMemory, - addedToSpaces, - removedFromSpaces, - resultedSpaces, - }; -} - -export async function deleteSpace(id: number) { - const user = await getUser(); - - if (!user) { - return null; - } - - await db.delete(contentToSpace).where(eq(contentToSpace.spaceId, id)); - - const [deleted] = await db - .delete(space) - .where(and(eq(space.user, user.id), eq(space.id, id))) - .returning(); - - return deleted; -} - -export async function deleteMemory(id: number) { - const user = await getUser(); - - if (!user) { - return null; - } - - await db.delete(contentToSpace).where(eq(contentToSpace.contentId, id)); - - const [deleted] = await db - .delete(storedContent) - .where(and(eq(storedContent.user, user.id), eq(storedContent.id, id))) - .returning(); - - if (deleted) { - console.log("adding with:", `${deleted.url}-${user.email}`); - const res = (await Promise.race([ - fetch(`https://cf-ai-backend.dhravya.workers.dev/delete`, { - method: "DELETE", - headers: { - "X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY, - }, - body: JSON.stringify({ - websiteUrl: deleted.url, - user: user.email, - }), - }), - new Promise((_, reject) => - setTimeout(() => reject(new Error("Request timed out")), 40000), - ), - ])) as Response; - } - - return deleted; -} diff --git a/apps/web/src/app/MessagePoster.tsx b/apps/web/src/app/MessagePoster.tsx deleted file mode 100644 index 1abad1be..00000000 --- a/apps/web/src/app/MessagePoster.tsx +++ /dev/null @@ -1,24 +0,0 @@ -"use client"; - -import { useEffect } from "react"; - -function MessagePoster({ jwt }: { jwt: string }) { - useEffect(() => { - if (typeof window === "undefined") return; - window.postMessage({ jwt }, "*"); - }, [jwt]); - - return ( - - ); -} - -export default MessagePoster; diff --git a/apps/web/src/app/api/[...nextauth]/route.ts b/apps/web/src/app/api/[...nextauth]/route.ts deleted file mode 100644 index db7d1fb8..00000000 --- a/apps/web/src/app/api/[...nextauth]/route.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { GET, POST } from "@/server/auth"; -export const runtime = "edge"; diff --git a/apps/web/src/app/api/addTweetsToDb/route.ts b/apps/web/src/app/api/addTweetsToDb/route.ts deleted file mode 100644 index 7fe2edba..00000000 --- a/apps/web/src/app/api/addTweetsToDb/route.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { db } from "@/server/db"; -import { eq } from "drizzle-orm"; -import { sessions, storedContent, users } from "@/server/db/schema"; -import { type NextRequest, NextResponse } from "next/server"; - -export const runtime = "edge"; - -interface TweetData { - tweetText: string; - postUrl: string; - authorName: string; - handle: string; - time: string; - saveToUser: string; -} - -export async function POST(req: NextRequest) { - const token = - req.cookies.get("next-auth.session-token")?.value ?? - req.cookies.get("__Secure-authjs.session-token")?.value ?? - req.cookies.get("authjs.session-token")?.value ?? - req.headers.get("Authorization")?.replace("Bearer ", ""); - - if (!token) { - return new Response( - JSON.stringify({ message: "Invalid Key, TOKEN not found." }), - { status: 404 }, - ); - } - - const sessionData = await db - .select() - .from(sessions) - .where(eq(sessions.sessionToken, token!)); - - if (!sessionData || sessionData.length === 0) { - return new Response( - JSON.stringify({ message: "Invalid Key, session not found." }), - { status: 404 }, - ); - } - - const user = await db - .select() - .from(users) - .where(eq(users.id, sessionData[0].userId)) - .limit(1); - - if (!user || user.length === 0) { - return NextResponse.json( - { message: "Invalid Key, session not found." }, - { status: 404 }, - ); - } - - const session = { session: sessionData[0], user: user[0] }; - - const data = (await req.json()) as TweetData[]; - - for (const tweet of data) { - const { id } = ( - await db - .insert(storedContent) - .values({ - content: tweet.tweetText, - title: "Twitter Bookmark", - description: "", - url: tweet.postUrl, - baseUrl: "https://twitter.com", - image: "https://supermemory.dhr.wtf/twitter.svg", - savedAt: new Date(), - user: session.user.id, - type: "twitter-bookmark", - }) - .returning({ id: storedContent.id }) - )[0]; - - if (!id) { - return NextResponse.json( - { - message: "Error", - error: - "Something went wrong when inserting the tweet to storedContent", - }, - { status: 500 }, - ); - } - } - - return NextResponse.json({ message: "OK", data: "Success" }, { status: 200 }); -} diff --git a/apps/web/src/app/api/ask/route.ts b/apps/web/src/app/api/ask/route.ts deleted file mode 100644 index 17b24b3e..00000000 --- a/apps/web/src/app/api/ask/route.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { db } from "@/server/db"; -import { eq } from "drizzle-orm"; -import { sessions, users } from "@/server/db/schema"; -import { type NextRequest, NextResponse } from "next/server"; -import { env } from "@/env"; - -export const runtime = "edge"; - -export async function POST(req: NextRequest) { - const token = - req.cookies.get("next-auth.session-token")?.value ?? - req.cookies.get("__Secure-authjs.session-token")?.value ?? - req.cookies.get("authjs.session-token")?.value ?? - req.headers.get("Authorization")?.replace("Bearer ", ""); - - if (process.env.RATELIMITER) { - const { success } = await process.env.RATELIMITER.limit({ key: token }); - - if (!success) { - return new Response(JSON.stringify({ message: "Rate limit exceeded" }), { - status: 429, - }); - } - } - - const sessionData = await db - .select() - .from(sessions) - .where(eq(sessions.sessionToken, token!)); - - if (!sessionData || sessionData.length === 0) { - return new Response( - JSON.stringify({ message: "Invalid Key, session not found." }), - { status: 404 }, - ); - } - - const user = await db - .select() - .from(users) - .where(eq(users.id, sessionData[0].userId)) - .limit(1); - - if (!user || user.length === 0) { - return NextResponse.json( - { message: "Invalid Key, session not found." }, - { status: 404 }, - ); - } - - const body = (await req.json()) as { - query: string; - }; - - const resp = await fetch(`https://cf-ai-backend.dhravya.workers.dev/ask`, { - headers: { - "X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY, - }, - method: "POST", - body: JSON.stringify({ - query: body.query, - }), - }); - - if (resp.status !== 200 || !resp.ok) { - const errorData = await resp.json(); - return new Response( - JSON.stringify({ message: "Error in CF function", error: errorData }), - { status: resp.status }, - ); - } - - // Stream the response back to the client - const { readable, writable } = new TransformStream(); - resp && resp.body!.pipeTo(writable); - - return new Response(readable, { status: 200 }); -} diff --git a/apps/web/src/app/api/chat/route.ts b/apps/web/src/app/api/chat/route.ts deleted file mode 100644 index c815070b..00000000 --- a/apps/web/src/app/api/chat/route.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { db } from "@/server/db"; -import { eq } from "drizzle-orm"; -import { sessions, users } from "@/server/db/schema"; -import { type NextRequest, NextResponse } from "next/server"; -import { env } from "@/env"; -import { ChatHistory } from "../../../../types/memory"; - -export const runtime = "edge"; - -export async function POST(req: NextRequest) { - const token = - req.cookies.get("next-auth.session-token")?.value ?? - req.cookies.get("__Secure-authjs.session-token")?.value ?? - req.cookies.get("authjs.session-token")?.value ?? - req.headers.get("Authorization")?.replace("Bearer ", ""); - - if (process.env.RATELIMITER) { - const { success } = await process.env.RATELIMITER.limit({ key: token }); - - if (!success) { - return new Response(JSON.stringify({ message: "Rate limit exceeded" }), { - status: 429, - }); - } - } - - const sessionData = await db - .select() - .from(sessions) - .where(eq(sessions.sessionToken, token!)); - - if (!sessionData || sessionData.length === 0) { - return new Response( - JSON.stringify({ message: "Invalid Key, session not found." }), - { status: 404 }, - ); - } - - const user = await db - .select() - .from(users) - .where(eq(users.id, sessionData[0].userId)) - .limit(1); - - if (!user || user.length === 0) { - return NextResponse.json( - { message: "Invalid Key, session not found." }, - { status: 404 }, - ); - } - - const session = { session: sessionData[0], user: user[0] }; - - const query = new URL(req.url).searchParams.get("q"); - const spaces = new URL(req.url).searchParams.get("spaces"); - - const sourcesOnly = - new URL(req.url).searchParams.get("sourcesOnly") ?? "false"; - - const chatHistory = (await req.json()) as { - chatHistory: ChatHistory[]; - }; - - console.log("CHathistory", chatHistory); - - if (!query) { - return new Response(JSON.stringify({ message: "Invalid query" }), { - status: 400, - }); - } - - try { - const resp = await fetch( - `https://cf-ai-backend.dhravya.workers.dev/chat?q=${query}&user=${session.user.email ?? session.user.name}&sourcesOnly=${sourcesOnly}&spaces=${spaces}`, - { - headers: { - "X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY, - }, - method: "POST", - body: JSON.stringify({ - chatHistory: chatHistory.chatHistory ?? [], - }), - }, - ); - - console.log("sourcesOnly", sourcesOnly); - - if (sourcesOnly == "true") { - const data = await resp.json(); - console.log("data", data); - return new Response(JSON.stringify(data), { status: 200 }); - } - - if (resp.status !== 200 || !resp.ok) { - const errorData = await resp.json(); - console.log(errorData); - return new Response( - JSON.stringify({ message: "Error in CF function", error: errorData }), - { status: resp.status }, - ); - } - - // Stream the response back to the client - const { readable, writable } = new TransformStream(); - resp && resp.body!.pipeTo(writable); - - return new Response(readable, { status: 200 }); - } catch {} -} diff --git a/apps/web/src/app/api/getCount/route.ts b/apps/web/src/app/api/getCount/route.ts deleted file mode 100644 index 9fe54f78..00000000 --- a/apps/web/src/app/api/getCount/route.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { db } from "@/server/db"; -import { and, eq, ne, sql } from "drizzle-orm"; -import { sessions, storedContent, users } from "@/server/db/schema"; -import { type NextRequest, NextResponse } from "next/server"; - -export const runtime = "edge"; - -export async function GET(req: NextRequest) { - const token = - req.cookies.get("next-auth.session-token")?.value ?? - req.cookies.get("__Secure-authjs.session-token")?.value ?? - req.cookies.get("authjs.session-token")?.value ?? - req.headers.get("Authorization")?.replace("Bearer ", ""); - - if (!token) { - return new Response( - JSON.stringify({ message: "Invalid Key, session not found." }), - { status: 404 }, - ); - } - - const sessionData = await db - .select() - .from(sessions) - .where(eq(sessions.sessionToken, token!)); - - if (!sessionData || sessionData.length === 0) { - return new Response( - JSON.stringify({ message: "Invalid Key, session not found." }), - { status: 404 }, - ); - } - - const user = await db - .select() - .from(users) - .where(eq(users.id, sessionData[0].userId)) - .limit(1); - - if (!user || user.length === 0) { - return NextResponse.json( - { message: "Invalid Key, session not found." }, - { status: 404 }, - ); - } - - const session = { session: sessionData[0], user: user[0] }; - - const tweetsCount = await db - .select({ - count: sql`count(*)`.mapWith(Number), - }) - .from(storedContent) - .where( - and( - eq(storedContent.user, session.user.id), - eq(storedContent.type, "twitter-bookmark"), - ), - ); - - const pageCount = await db - .select({ - count: sql`count(*)`.mapWith(Number), - }) - .from(storedContent) - .where( - and( - eq(storedContent.user, session.user.id), - ne(storedContent.type, "twitter-bookmark"), - ), - ); - - return NextResponse.json({ - tweetsCount: tweetsCount[0].count, - tweetsLimit: 1000, - pageCount: pageCount[0].count, - pageLimit: 100, - user: session.user.email, - }); -} diff --git a/apps/web/src/app/api/me/route.ts b/apps/web/src/app/api/me/route.ts deleted file mode 100644 index 6d269872..00000000 --- a/apps/web/src/app/api/me/route.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { db } from "@/server/db"; -import { eq } from "drizzle-orm"; -import { sessions, users } from "@/server/db/schema"; -import { type NextRequest, NextResponse } from "next/server"; -import { env } from "@/env"; - -export const runtime = "edge"; - -export async function GET(req: NextRequest) { - const token = - req.cookies.get("next-auth.session-token")?.value ?? - req.cookies.get("__Secure-authjs.session-token")?.value ?? - req.cookies.get("authjs.session-token")?.value ?? - req.headers.get("Authorization")?.replace("Bearer ", ""); - - const session = await db - .select() - .from(sessions) - .where(eq(sessions.sessionToken, token!)); - - if (!session || session.length === 0) { - return new Response( - JSON.stringify({ message: "Invalid Key, session not found." }), - { status: 404 }, - ); - } - - const user = await db - .select() - .from(users) - .where(eq(users.id, session[0].userId)) - .limit(1); - - if (!user || user.length === 0) { - return NextResponse.json( - { message: "Invalid Key, session not found." }, - { status: 404 }, - ); - } - - return new Response( - JSON.stringify({ - message: "OK", - data: { session: session[0], user: user[0] }, - }), - { status: 200 }, - ); -} diff --git a/apps/web/src/app/api/query/route.ts b/apps/web/src/app/api/query/route.ts deleted file mode 100644 index 5806841e..00000000 --- a/apps/web/src/app/api/query/route.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { db } from "@/server/db"; -import { eq } from "drizzle-orm"; -import { sessions, users } from "@/server/db/schema"; -import { type NextRequest, NextResponse } from "next/server"; -import { env } from "@/env"; - -export const runtime = "edge"; - -export async function GET(req: NextRequest) { - const token = - req.cookies.get("next-auth.session-token")?.value ?? - req.cookies.get("__Secure-authjs.session-token")?.value ?? - req.cookies.get("authjs.session-token")?.value ?? - req.headers.get("Authorization")?.replace("Bearer ", ""); - - if (process.env.RATELIMITER) { - const { success } = await process.env.RATELIMITER.limit({ key: token }); - - if (!success) { - return new Response(JSON.stringify({ message: "Rate limit exceeded" }), { - status: 429, - }); - } - } - - const sessionData = await db - .select() - .from(sessions) - .where(eq(sessions.sessionToken, token!)); - - if (!sessionData || sessionData.length === 0) { - return new Response( - JSON.stringify({ message: "Invalid Key, session not found." }), - { status: 404 }, - ); - } - - const user = await db - .select() - .from(users) - .where(eq(users.id, sessionData[0].userId)) - .limit(1); - - if (!user || user.length === 0) { - return NextResponse.json( - { message: "Invalid Key, session not found." }, - { status: 404 }, - ); - } - - const session = { session: sessionData[0], user: user[0] }; - - const query = new URL(req.url).searchParams.get("q"); - const sourcesOnly = - new URL(req.url).searchParams.get("sourcesOnly") ?? "false"; - - if (!query) { - return new Response(JSON.stringify({ message: "Invalid query" }), { - status: 400, - }); - } - - const resp = await fetch( - `https://cf-ai-backend.dhravya.workers.dev/query?q=${query}&user=${session.user.email ?? session.user.name}&sourcesOnly=${sourcesOnly}`, - { - headers: { - "X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY, - }, - }, - ); - - console.log(resp.status); - - if (resp.status !== 200 || !resp.ok) { - const errorData = await resp.json(); - console.log(errorData); - return new Response( - JSON.stringify({ message: "Error in CF function", error: errorData }), - { status: resp.status }, - ); - } - - // Stream the response back to the client - const { readable, writable } = new TransformStream(); - resp && resp.body!.pipeTo(writable); - - return new Response(readable, { status: 200 }); -} diff --git a/apps/web/src/app/api/spaces/route.ts b/apps/web/src/app/api/spaces/route.ts deleted file mode 100644 index d2685e9f..00000000 --- a/apps/web/src/app/api/spaces/route.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { db } from "@/server/db"; -import { sessions, space, users } from "@/server/db/schema"; -import { eq } from "drizzle-orm"; -import { NextRequest, NextResponse } from "next/server"; - -export const runtime = "edge"; - -export async function GET(req: NextRequest) { - const token = - req.cookies.get("next-auth.session-token")?.value ?? - req.cookies.get("__Secure-authjs.session-token")?.value ?? - req.cookies.get("authjs.session-token")?.value ?? - req.headers.get("Authorization")?.replace("Bearer ", ""); - - if (!token) { - return new Response( - JSON.stringify({ message: "Invalid Key, session not found." }), - { status: 404 }, - ); - } - - if (process.env.RATELIMITER) { - const { success } = await process.env.RATELIMITER.limit({ key: token }); - - if (!success) { - return new Response(JSON.stringify({ message: "Rate limit exceeded" }), { - status: 429, - }); - } - } - - const sessionData = await db - .select() - .from(sessions) - .where(eq(sessions.sessionToken, token!)); - - if (!sessionData || sessionData.length === 0) { - return new Response( - JSON.stringify({ message: "Invalid Key, session not found." }), - { status: 404 }, - ); - } - - const userData = await db - .select() - .from(users) - .where(eq(users.id, sessionData[0].userId)) - .limit(1); - - if (!userData || userData.length === 0) { - return NextResponse.json( - { message: "Invalid Key, session not found." }, - { status: 404 }, - ); - } - - const user = userData[0]; - - const spaces = await db - .select() - .from(space) - .where(eq(space.user, user.id)) - .all(); - - return NextResponse.json( - { - message: "OK", - data: spaces, - }, - { status: 200 }, - ); -} diff --git a/apps/web/src/app/api/store/route.ts b/apps/web/src/app/api/store/route.ts deleted file mode 100644 index 457eae2e..00000000 --- a/apps/web/src/app/api/store/route.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { db } from "@/server/db"; -import { and, eq, sql, inArray } from "drizzle-orm"; -import { - contentToSpace, - sessions, - storedContent, - users, - space, -} from "@/server/db/schema"; -import { type NextRequest, NextResponse } from "next/server"; -import { env } from "@/env"; -import { getMetaData } from "@/server/helpers"; - -export const runtime = "edge"; - -export async function POST(req: NextRequest) { - const token = - req.cookies.get("next-auth.session-token")?.value ?? - req.cookies.get("__Secure-authjs.session-token")?.value ?? - req.cookies.get("authjs.session-token")?.value ?? - req.headers.get("Authorization")?.replace("Bearer ", ""); - - if (!token) { - return new Response( - JSON.stringify({ message: "Invalid Key, session not found." }), - { status: 404 }, - ); - } - - if (process.env.RATELIMITER) { - const { success } = await process.env.RATELIMITER.limit({ key: token }); - - if (!success) { - return new Response(JSON.stringify({ message: "Rate limit exceeded" }), { - status: 429, - }); - } - } - - const sessionData = await db - .select() - .from(sessions) - .where(eq(sessions.sessionToken, token!)); - - if (!sessionData || sessionData.length === 0) { - return new Response( - JSON.stringify({ message: "Invalid Key, session not found." }), - { status: 404 }, - ); - } - - const user = await db - .select() - .from(users) - .where(eq(users.id, sessionData[0].userId)) - .limit(1); - - if (!user || user.length === 0) { - return NextResponse.json( - { message: "Invalid Key, session not found." }, - { status: 404 }, - ); - } - - const session = { session: sessionData[0], user: user[0] }; - - const data = (await req.json()) as { - pageContent: string; - url: string; - spaces?: string[]; - }; - - const metadata = await getMetaData(data.url); - let storeToSpaces = data.spaces; - - if (!storeToSpaces) { - storeToSpaces = []; - } - - const count = await db - .select({ - count: sql`count(*)`.mapWith(Number), - }) - .from(storedContent) - .where( - and( - eq(storedContent.user, session.user.id), - eq(storedContent.type, "page"), - ), - ); - - if (count[0].count > 100) { - return NextResponse.json( - { message: "Error", error: "Limit exceeded" }, - { status: 499 }, - ); - } - - const { id } = ( - await db - .insert(storedContent) - .values({ - content: data.pageContent, - title: metadata.title, - description: metadata.description, - url: data.url, - baseUrl: metadata.baseUrl, - image: metadata.image, - savedAt: new Date(), - user: session.user.id, - }) - .returning({ id: storedContent.id }) - )[0]; - - if (!id) { - return NextResponse.json( - { message: "Error", error: "Error in CF function" }, - { status: 500 }, - ); - } - - if (storeToSpaces.length > 0) { - const spaceData = await db - .select() - .from(space) - .where( - and( - inArray(space.name, storeToSpaces ?? []), - eq(space.user, session.user.id), - ), - ) - .all(); - - await Promise.all([ - spaceData.forEach(async (space) => { - await db - .insert(contentToSpace) - .values({ contentId: id, spaceId: space.id }); - }), - ]); - } - - const res = (await Promise.race([ - fetch("https://cf-ai-backend.dhravya.workers.dev/add", { - method: "POST", - headers: { - "X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY, - }, - body: JSON.stringify({ ...data, user: session.user.email }), - }), - new Promise((_, reject) => - setTimeout(() => reject(new Error("Request timed out")), 40000), - ), - ])) as Response; - - if (res.status !== 200) { - console.log(res.status, res.statusText); - return NextResponse.json( - { message: "Error", error: "Error in CF function" }, - { status: 500 }, - ); - } - - return NextResponse.json({ message: "OK", data: "Success" }, { status: 200 }); -} diff --git a/apps/web/src/app/api/vectorizeTweets/route.ts b/apps/web/src/app/api/vectorizeTweets/route.ts deleted file mode 100644 index 63aa38f0..00000000 --- a/apps/web/src/app/api/vectorizeTweets/route.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { db } from "@/server/db"; -import { eq } from "drizzle-orm"; -import { sessions, storedContent, users } from "@/server/db/schema"; -import { type NextRequest, NextResponse } from "next/server"; -import { env } from "@/env"; - -export const runtime = "edge"; - -interface TweetData { - tweetText: string; - postUrl: string; - authorName: string; - handle: string; - time: string; - saveToUser: string; -} - -export async function POST(req: NextRequest) { - const token = - req.cookies.get("next-auth.session-token")?.value ?? - req.cookies.get("__Secure-authjs.session-token")?.value ?? - req.cookies.get("authjs.session-token")?.value ?? - req.headers.get("Authorization")?.replace("Bearer ", ""); - - if (!token) { - return new Response( - JSON.stringify({ message: "Invalid Key, session not found." }), - { status: 404 }, - ); - } - - const sessionData = await db - .select() - .from(sessions) - .where(eq(sessions.sessionToken, token!)); - - if (!sessionData || sessionData.length === 0) { - return new Response( - JSON.stringify({ message: "Invalid Key, session not found." }), - { status: 404 }, - ); - } - - const body = (await req.json()) as TweetData[]; - - console.log(body); - - const resp = await fetch( - `https://cf-ai-backend.dhravya.workers.dev/batchUploadTweets`, - { - headers: { - "X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY, - }, - method: "POST", - body: JSON.stringify(body), - }, - ); - - return new Response(await resp.text(), { - status: resp.status, - headers: resp.headers, - }); -} diff --git a/apps/web/src/app/content.tsx b/apps/web/src/app/content.tsx deleted file mode 100644 index 5a68d902..00000000 --- a/apps/web/src/app/content.tsx +++ /dev/null @@ -1,18 +0,0 @@ -"use client"; -import SessionProviderWrapper from "@/components/dev/SessionProviderWrapper"; -import Main from "@/components/Main"; -import Sidebar from "@/components/Sidebar/index"; -import { useState } from "react"; - -export default function Content({ jwt }: { jwt: string }) { - const [selectedItem, setSelectedItem] = useState(null); - - return ( - -
- -
-
-
- ); -} diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css deleted file mode 100644 index bed9278b..00000000 --- a/apps/web/src/app/globals.css +++ /dev/null @@ -1,140 +0,0 @@ -@import "@radix-ui/colors/gray"; -@import "@radix-ui/colors/gray-dark"; - -@tailwind base; -@tailwind components; -@tailwind utilities; - -:root { - --foreground-rgb: 0, 0, 0; - --background-start-rgb: 214, 219, 220; - --background-end-rgb: 255, 255, 255; -} - -@media (prefers-color-scheme: dark) { - :root { - --foreground-rgb: 255, 255, 255; - --background-start-rgb: 0, 0, 0; - --background-end-rgb: 0, 0, 0; - } -} - -body { - @apply text-rgray-11 max-h-screen overflow-y-hidden bg-white; - /* color: rgb(var(--foreground-rgb)); - background: linear-gradient( - to bottom, - transparent, - rgb(var(--background-end-rgb)) - ) - rgb(var(--background-start-rgb)); */ -} - -[vaul-drawer-wrapper] { - @apply bg-rgray-2; -} - -@layer utilities { - .text-balance { - text-wrap: balance; - } -} - -.sidebar { - height: 100vh; - height: 100dvh; - max-height: 100vh; - max-height: 100dvh; -} - -.DrawerContent { - padding-top: 5vh; - padding-top: 5dvh; -} - -.main-hidden { - padding-bottom: 20vh; - padding-bottom: 15dvh; -} - -.bottom-padding { - bottom: 20vh; - bottom: 20dvh; -} - -@media (min-width: 768px) { - .bottom-padding { - bottom: 0; - } -} - -.chat-answer code { - @apply bg-rgray-3 border-rgray-5 text-rgray-11 text-wrap rounded-md border p-1 text-sm; -} - -.novel-editor pre { - @apply bg-rgray-3 border-rgray-5 text-rgray-11 my-5 rounded-md border p-4 text-sm; -} - -.chat-answer h1 { - @apply text-rgray-11 my-5 text-xl font-medium; -} - -.chat-answer a { - @apply underline underline-offset-1 opacity-90 hover:opacity-100; -} - -.chat-answer img { - @apply my-5 rounded-md font-medium; -} - -.tippy-box { - @apply bg-rgray-3 text-rgray-11 border-rgray-5 rounded-md border py-0; -} - -.tippy-content #slash-command { - @apply text-rgray-11 border-none bg-transparent; -} - -#slash-command button { - @apply text-rgray-11 py-2; -} - -#slash-command button div:first-child { - @apply text-rgray-11 bg-rgray-4 border-rgray-5; -} - -#slash-command button.novel-bg-stone-100 { - @apply bg-rgray-1; -} - -.novel-editor [data-type="taskList"] > li { - @apply my-0; -} - -.novel-editor input[type="checkbox"] { - @apply accent-rgray-4 rounded-md; - - background: var(--gray-4) !important; - border: 1px solid var(--gray-10) !important; -} - -.novel-editor .is-empty::before { - content: "Press '/' for commands" !important; -} - -.novel-editor h1 { - @apply text-2xl; -} - -.novel-editor h2 { - @apply text-xl; -} - -.novel-editor h3 { - @apply text-lg; -} - -.novel-editor .drag-handle { - @apply hidden; -} diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx deleted file mode 100644 index e96df271..00000000 --- a/apps/web/src/app/layout.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import type { Metadata } from "next"; -import { Roboto, Inter } from "next/font/google"; -import "./globals.css"; - -const inter = Inter({ weight: ["300", "400", "500"], subsets: ["latin"] }); - -export const metadata: Metadata = { - title: "Supermemory - Your second brain", - description: "Save your memories forever, build your own second brain.", - openGraph: { - images: [ - { - url: "https://supermemory.dhr.wtf/og-image.png", - width: 1200, - height: 630, - }, - ], - siteName: "Supermemory", - title: "Supermemory - Your second brain", - description: "Save your memories forever, build your own second brain.", - }, - twitter: { - card: "summary_large_image", - site: "https://supermemory.dhr.wtf", - creator: "@dhravyashah", - description: "Save your memories forever, build your own second brain.", - images: [ - { - url: "https://supermemory.dhr.wtf/og-image.png", - width: 1200, - height: 630, - }, - ], - }, -}; - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( - - - - - - -
- {children} -
- - - ); -} diff --git a/apps/web/src/app/not-found.tsx b/apps/web/src/app/not-found.tsx deleted file mode 100644 index 3409889a..00000000 --- a/apps/web/src/app/not-found.tsx +++ /dev/null @@ -1,58 +0,0 @@ -export const runtime = "edge"; - -export default function NotFound() { - return ( - <> - 404: This page could not be found. -
-
-