aboutsummaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/web/app/(auth)/onboarding/page.tsx22
-rw-r--r--apps/web/app/(auth)/signin/page.tsx4
-rw-r--r--apps/web/app/(dash)/dialogContentContainer.tsx2
-rw-r--r--apps/web/app/(dash)/header/header.tsx32
-rw-r--r--apps/web/app/(dash)/home/history.tsx36
-rw-r--r--apps/web/app/(dash)/home/page.tsx51
-rw-r--r--apps/web/app/(dash)/home/queryinput.tsx31
-rw-r--r--apps/web/app/(dash)/layout.tsx8
-rw-r--r--apps/web/app/(dash)/menu.tsx2
-rw-r--r--apps/web/app/(landing)/Hero.tsx26
-rw-r--r--apps/web/app/actions/doers.ts147
-rw-r--r--apps/web/app/actions/fetchers.ts21
-rw-r--r--apps/web/env.d.ts2
-rw-r--r--apps/web/lib/utils.ts23
-rw-r--r--apps/web/migrations/0000_setup.sql (renamed from apps/web/migrations/0000_exotic_sway.sql)0
-rw-r--r--apps/web/migrations/0001_dear_sally_floyd.sql1
-rw-r--r--apps/web/migrations/meta/0000_snapshot.json1699
-rw-r--r--apps/web/migrations/meta/0001_snapshot.json903
-rw-r--r--apps/web/migrations/meta/_journal.json31
-rw-r--r--apps/web/server/db/index.ts5
-rw-r--r--apps/web/server/db/schema.ts1
-rw-r--r--apps/web/wrangler.toml25
22 files changed, 2143 insertions, 929 deletions
diff --git a/apps/web/app/(auth)/onboarding/page.tsx b/apps/web/app/(auth)/onboarding/page.tsx
index c402c560..9728d107 100644
--- a/apps/web/app/(auth)/onboarding/page.tsx
+++ b/apps/web/app/(auth)/onboarding/page.tsx
@@ -1,6 +1,5 @@
"use client";
-import Link from "next/link";
import {
ChevronLeftIcon,
ChevronRightIcon,
@@ -11,7 +10,7 @@ import { CheckIcon, PlusCircleIcon } from "@heroicons/react/24/outline";
import { motion } from "framer-motion";
import { useEffect, useState } from "react";
import { toast } from "sonner";
-import { createMemory } from "@repo/web/app/actions/doers";
+import { completeOnboarding, createMemory } from "@repo/web/app/actions/doers";
import { useRouter } from "next/navigation";
import Logo from "../../../public/logo.svg";
import Image from "next/image";
@@ -23,8 +22,13 @@ export default function Home() {
const { push } = useRouter();
useEffect(() => {
+ const updateDb = async () => {
+ await completeOnboarding();
+ }
if (currStep > 3) {
- push("/home?q=what%20is%20supermemory");
+ updateDb().then(() => {
+ push("/home?q=what%20is%20supermemory");
+ });
}
}, [currStep]);
@@ -182,7 +186,7 @@ function StepIndicator({
/>
<p>Step: {currStep}/3</p>
<ChevronRightIcon
- className="h-6"
+ className="h-6 cursor-pointer"
onClick={() => currStep <= 3 && setCurrStep(currStep + 1)}
/>
</div>
@@ -381,6 +385,12 @@ function StepTwo({ currStep }: { currStep: number }) {
}
function Navbar() {
+ const router = useRouter();
+ const handleSkip = async () => {
+ await completeOnboarding();
+ router.push("/home?q=what%20is%20supermemory");
+ }
+
return (
<div className="flex items-center justify-between p-4 fixed top-0 left-0 w-full">
<Image
@@ -389,9 +399,7 @@ function Navbar() {
className="hover:brightness-125 duration-200 size-12"
/>
- <Link href="/home">
- <button className="text-sm">Skip</button>
- </Link>
+ <button className="text-sm" onClick={handleSkip}>Skip</button>
</div>
);
}
diff --git a/apps/web/app/(auth)/signin/page.tsx b/apps/web/app/(auth)/signin/page.tsx
index a31343cd..3b563b90 100644
--- a/apps/web/app/(auth)/signin/page.tsx
+++ b/apps/web/app/(auth)/signin/page.tsx
@@ -18,7 +18,7 @@ async function Signin({
const user = await auth();
if (user) {
- await redirect("/home");
+ redirect("/home");
}
return (
@@ -64,7 +64,7 @@ async function Signin({
action={async () => {
"use server";
await signIn("google", {
- redirectTo: "/home?firstTime=true",
+ redirectTo: "/home",
});
}}
>
diff --git a/apps/web/app/(dash)/dialogContentContainer.tsx b/apps/web/app/(dash)/dialogContentContainer.tsx
index aae71237..4e8d81ef 100644
--- a/apps/web/app/(dash)/dialogContentContainer.tsx
+++ b/apps/web/app/(dash)/dialogContentContainer.tsx
@@ -100,7 +100,7 @@ export function DialogContentContainer({
}, []);
return (
- <DialogContent className="sm:max-w-[475px] text-[#F2F3F5] rounded-2xl bg-background z-[39] backdrop-blur-md">
+ <DialogContent className="sm:max-w-[475px] text-[#F2F3F5] rounded-2xl bg-background z-[39]">
<form
action={async (e: FormData) => {
const content = e.get("content")?.toString();
diff --git a/apps/web/app/(dash)/header/header.tsx b/apps/web/app/(dash)/header/header.tsx
index a3fba9b1..595666b0 100644
--- a/apps/web/app/(dash)/header/header.tsx
+++ b/apps/web/app/(dash)/header/header.tsx
@@ -7,6 +7,8 @@ import { getChatHistory } from "../../actions/fetchers";
import NewChatButton from "./newChatButton";
import AutoBreadCrumbs from "./autoBreadCrumbs";
import SignOutButton from "./signOutButton";
+import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@repo/ui/shadcn/dropdown-menu";
+import { CaretDownIcon } from "@radix-ui/react-icons";
async function Header() {
const chatThreads = await getChatHistory();
@@ -33,27 +35,31 @@ async function Header() {
<div className="flex items-center gap-2">
<NewChatButton />
- <div className="relative group">
- <button className="flex duration-200 items-center text-[#7D8994] hover:bg-[#1F2429] text-[13px] gap-2 px-3 py-2 rounded-xl">
- History
- </button>
-
- <div className="absolute p-4 hidden group-hover:block right-0 w-full md:w-[400px] max-h-[70vh] overflow-auto">
- <div className="bg-[#1F2429] rounded-xl p-2 flex flex-col shadow-lg">
- {chatThreads.data.map((thread) => (
+ <DropdownMenu>
+ <DropdownMenuTrigger className="inline-flex flex-row flex-nowrap items-center text-muted-foreground hover:text-foreground">
+ History
+ <CaretDownIcon />
+ </DropdownMenuTrigger>
+ <DropdownMenuContent className="p-4 w-full md:w-[400px] max-h-[70vh] overflow-auto border-none">
+ {chatThreads.data.map((thread) => (
+ <DropdownMenuItem asChild>
<Link
prefetch={false}
href={`/chat/${thread.id}`}
key={thread.id}
- className="p-2 rounded-md hover:bg-secondary"
+ className="p-2 rounded-md cursor-pointer focus:bg-secondary focus:text-current"
>
{thread.firstMessage}
</Link>
- ))}
- </div>
- </div>
- </div>
+ </DropdownMenuItem>
+ ))}
+ </DropdownMenuContent>
+ </DropdownMenu>
+
<SignOutButton />
+ </div>
+
+
</div>
</div>
</div>
diff --git a/apps/web/app/(dash)/home/history.tsx b/apps/web/app/(dash)/home/history.tsx
index 922734df..307ef4e3 100644
--- a/apps/web/app/(dash)/home/history.tsx
+++ b/apps/web/app/(dash)/home/history.tsx
@@ -5,26 +5,32 @@ import Link from "next/link";
import { memo, useEffect, useState } from "react";
import { motion } from "framer-motion";
import { chatThreads } from "@/server/db/schema";
+import { getQuerySuggestions } from "@/app/actions/doers";
+import { Button } from "@repo/ui/shadcn/button";
-const History = memo(() => {
- const [chatThreads_, setChatThreads] = useState<
- (typeof chatThreads.$inferSelect)[] | null
- >(null);
+const History = memo(({ setQuery }: { setQuery: (q: string) => void }) => {
+ const [suggestions, setSuggestions] = useState<string[] | null>(null);
useEffect(() => {
(async () => {
- const chatThreads = await getChatHistory();
- if (!chatThreads.success || !chatThreads.data) {
- console.error(chatThreads.error);
+ const suggestions = await getQuerySuggestions();
+ if (!suggestions.success || !suggestions.data) {
+ console.error(suggestions.error);
+ setSuggestions([]);
return;
}
- setChatThreads(chatThreads.data.reverse().slice(0, 3));
+ console.log(suggestions);
+ if (typeof suggestions.data === "string") {
+ setSuggestions(JSON.parse(suggestions.data));
+ return;
+ }
+ setSuggestions(suggestions.data.reverse().slice(0, 3));
})();
}, []);
return (
<ul className="text-base list-none space-y-3 text-[#b9b9b9] mt-8">
- {!chatThreads_ && (
+ {!suggestions && (
<>
<Skeleton
key="loader-1"
@@ -40,17 +46,15 @@ const History = memo(() => {
></Skeleton>
</>
)}
- {chatThreads_?.map((thread) => (
+ {suggestions?.map((suggestion) => (
<motion.li
initial={{ opacity: 0, filter: "blur(1px)" }}
animate={{ opacity: 1, filter: "blur(0px)" }}
- className="flex items-center gap-2 truncate"
- key={thread.id}
+ className="flex items-center gap-2 truncate cursor-pointer"
+ key={suggestion}
+ onClick={() => setQuery(suggestion)}
>
- <ArrowLongRightIcon className="h-5" />{" "}
- <Link prefetch={false} href={`/chat/${thread.id}`}>
- {thread.firstMessage}
- </Link>
+ <ArrowLongRightIcon className="h-5" /> {suggestion}
</motion.li>
))}
</ul>
diff --git a/apps/web/app/(dash)/home/page.tsx b/apps/web/app/(dash)/home/page.tsx
index ebd4d84b..d192d07d 100644
--- a/apps/web/app/(dash)/home/page.tsx
+++ b/apps/web/app/(dash)/home/page.tsx
@@ -4,12 +4,15 @@ import React, { useEffect, useState } from "react";
import QueryInput from "./queryinput";
import { getSessionAuthToken, getSpaces } from "@/app/actions/fetchers";
import { redirect, useRouter } from "next/navigation";
-import { createChatThread, linkTelegramToUser } from "@/app/actions/doers";
+import {
+ createChatThread,
+ getQuerySuggestions,
+ linkTelegramToUser,
+} from "@/app/actions/doers";
import { toast } from "sonner";
import { motion } from "framer-motion";
-import { ChromeIcon, GithubIcon, TwitterIcon } from "lucide-react";
+import { ChromeIcon, GithubIcon, MailIcon, TwitterIcon } from "lucide-react";
import Link from "next/link";
-import { homeSearchParamsCache } from "@/lib/searchParams";
import History from "./history";
const slap = {
@@ -26,28 +29,14 @@ const slap = {
};
function Page({ searchParams }: { searchParams: Record<string, string> }) {
- // TODO: use this to show a welcome page/modal
- const firstTime = searchParams.firstTime === "true";
+ const telegramUser = searchParams.telegramUser;
+ const extensionInstalled = searchParams.extension;
+ const [query, setQuery] = useState(searchParams.q || "");
- const query = searchParams.q || "";
-
- if (firstTime) {
- redirect("/onboarding");
- }
-
- const [queryPresent, setQueryPresent] = useState<boolean>(false);
-
- const [telegramUser, setTelegramUser] = useState<string | undefined>(
- searchParams.telegramUser as string,
- );
- const [extensionInstalled, setExtensionInstalled] = useState<
- string | undefined
- >(searchParams.extension as string);
+ const [spaces, setSpaces] = useState<{ id: number; name: string }[]>([]);
const { push } = useRouter();
- const [spaces, setSpaces] = useState<{ id: number; name: string }[]>([]);
-
useEffect(() => {
if (telegramUser) {
const linkTelegram = async () => {
@@ -63,10 +52,6 @@ function Page({ searchParams }: { searchParams: Record<string, string> }) {
linkTelegram();
}
- if (extensionInstalled) {
- toast.success("Extension installed successfully");
- }
-
getSpaces().then((res) => {
if (res.success && res.data) {
setSpaces(res.data);
@@ -77,15 +62,15 @@ function Page({ searchParams }: { searchParams: Record<string, string> }) {
getSessionAuthToken().then((token) => {
if (typeof window === "undefined") return;
+ if (extensionInstalled) {
+ toast.success("Extension installed successfully");
+ }
window.postMessage({ token: token.data }, "*");
});
}, [telegramUser]);
return (
<div className="max-w-3xl h-full justify-center flex mx-auto w-full flex-col px-2 md:px-0">
- {/* all content goes here */}
- {/* <div className="">hi {firstTime ? 'first time' : ''}</div> */}
-
<motion.h1
{...{
...slap,
@@ -101,8 +86,8 @@ function Page({ searchParams }: { searchParams: Record<string, string> }) {
<div className="w-full pb-20 mt-10">
<QueryInput
- initialQuery={query}
- setQueryPresent={setQueryPresent}
+ query={query}
+ setQuery={setQuery}
handleSubmit={async (q, spaces, proMode) => {
if (q.length === 0) {
toast.error("Query is required");
@@ -123,7 +108,7 @@ function Page({ searchParams }: { searchParams: Record<string, string> }) {
initialSpaces={spaces}
/>
- <History />
+ <History setQuery={setQuery} />
</div>
<div className="w-full fixed bottom-0 left-0 p-4">
@@ -138,12 +123,12 @@ function Page({ searchParams }: { searchParams: Record<string, string> }) {
Install extension
</Link>
<Link
- href="https://github.com/supermemoryai/supermemory/issues/new"
+ href="mailto:[email protected]"
target="_blank"
rel="noreferrer"
className="flex items-center gap-2 text-muted-foreground hover:text-grey-50 duration-300"
>
- <GithubIcon className="w-4 h-4" />
+ <MailIcon className="w-4 h-4" />
Bug report
</Link>
<Link
diff --git a/apps/web/app/(dash)/home/queryinput.tsx b/apps/web/app/(dash)/home/queryinput.tsx
index 9f1e7292..82561438 100644
--- a/apps/web/app/(dash)/home/queryinput.tsx
+++ b/apps/web/app/(dash)/home/queryinput.tsx
@@ -8,26 +8,24 @@ import { Switch } from "@repo/ui/shadcn/switch";
import { Label } from "@repo/ui/shadcn/label";
function QueryInput({
- setQueryPresent,
- initialQuery,
initialSpaces,
handleSubmit,
+ query,
+ setQuery,
}: {
- setQueryPresent: (t: boolean) => void;
initialSpaces?: {
id: number;
name: string;
}[];
- initialQuery?: string;
mini?: boolean;
handleSubmit: (
q: string,
spaces: { id: number; name: string }[],
proMode: boolean,
) => void;
+ query: string;
+ setQuery: (q: string) => void;
}) {
- const [q, setQ] = useState(initialQuery || "");
-
const [proMode, setProMode] = useState(false);
const [selectedSpaces, setSelectedSpaces] = useState<
@@ -42,11 +40,11 @@ function QueryInput({
{/* input and action button */}
<form
action={async () => {
- if (q.trim().length === 0) {
+ if (query.trim().length === 0) {
return;
}
- handleSubmit(q, selectedSpaces, proMode);
- setQ("");
+ handleSubmit(query, selectedSpaces, proMode);
+ setQuery("");
}}
>
<textarea
@@ -59,20 +57,15 @@ function QueryInput({
onKeyDown={(e) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
- if (q.trim().length === 0) {
+ if (query.trim().length === 0) {
return;
}
- handleSubmit(q, selectedSpaces, proMode);
- setQ("");
+ handleSubmit(query, selectedSpaces, proMode);
+ setQuery("");
}
}}
- onChange={(e) =>
- setQ((prev) => {
- setQueryPresent(!!e.target.value.length);
- return e.target.value;
- })
- }
- value={q}
+ onChange={(e) => setQuery(e.target.value)}
+ value={query}
/>
<div className="flex p-2 px-3 w-full items-center justify-between rounded-xl overflow-hidden">
<FilterSpaces
diff --git a/apps/web/app/(dash)/layout.tsx b/apps/web/app/(dash)/layout.tsx
index b2b27a4f..c6174945 100644
--- a/apps/web/app/(dash)/layout.tsx
+++ b/apps/web/app/(dash)/layout.tsx
@@ -4,6 +4,7 @@ import { redirect } from "next/navigation";
import { auth } from "../../server/auth";
import { Toaster } from "@repo/ui/shadcn/sonner";
import BackgroundPlus from "../(landing)/GridPatterns/PlusGrid";
+import { getUser } from "../actions/fetchers";
async function Layout({ children }: { children: React.ReactNode }) {
const info = await auth();
@@ -12,6 +13,13 @@ async function Layout({ children }: { children: React.ReactNode }) {
return redirect("/signin");
}
+ const user = await getUser();
+ const hasOnboarded = user.data?.hasOnboarded;
+
+ if (!hasOnboarded) {
+ redirect("/onboarding");
+ }
+
return (
<main className="h-screen flex flex-col">
<div className="fixed top-0 left-0 w-full z-40">
diff --git a/apps/web/app/(dash)/menu.tsx b/apps/web/app/(dash)/menu.tsx
index 34ef3b2d..c56a3247 100644
--- a/apps/web/app/(dash)/menu.tsx
+++ b/apps/web/app/(dash)/menu.tsx
@@ -176,7 +176,7 @@ function Menu() {
</div>
</div>
- <DialogContent className="sm:max-w-[475px] text-[#F2F3F5] rounded-2xl bg-background z-[39] backdrop-blur-md">
+ <DialogContent className="sm:max-w-[475px] text-[#F2F3F5] rounded-2xl bg-background z-[39]">
<form
action={async (e: FormData) => {
const content = e.get("content")?.toString();
diff --git a/apps/web/app/(landing)/Hero.tsx b/apps/web/app/(landing)/Hero.tsx
index c8d65244..1cdfced8 100644
--- a/apps/web/app/(landing)/Hero.tsx
+++ b/apps/web/app/(landing)/Hero.tsx
@@ -26,18 +26,6 @@ function Hero() {
return (
<>
<section className="flex relative flex-col gap-5 justify-center items-center mt-24 max-w-xl md:mt-32 md:max-w-2xl lg:max-w-3xl">
- <a
- href="https://www.producthunt.com/posts/supermemory?embed=true&utm_source=badge-featured&utm_medium=badge&utm_souce=badge-supermemory"
- target="_blank"
- >
- <img
- src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=472686&theme=dark"
- alt="Supermemory - AI&#0032;second&#0032;brain&#0032;for&#0032;all&#0032;your&#0032;saved&#0032;stuff | Product Hunt"
- style={{ width: "250px", height: "54px" }}
- width="250"
- height="54"
- />
- </a>
<TwitterBorder />
<motion.h1
{...{
@@ -65,7 +53,7 @@ function Hero() {
</motion.p>
<Link
href="/signin"
- className="inline-flex text-lg gap-x-2 mt-2 backdrop-blur-md text-white justify-center items-center py-3 px-5 ml-3 w-fit rounded-3xl border duration-200 group bg-page-gradient border-white/30 text-md font-geistSans hover:border-zinc-600 hover:bg-transparent/10 hover:text-zinc-100"
+ className="inline-flex text-lg gap-x-2 mt-2 backdrop-blur-md text-white justify-center items-center py-3 px-5 w-fit rounded-3xl border duration-200 group bg-page-gradient border-white/30 text-md font-geistSans hover:border-zinc-600 hover:bg-transparent/10 hover:text-zinc-100"
>
It's free. Sign up now
<div className="flex overflow-hidden relative justify-center items-center ml-1 w-5 h-5">
@@ -73,6 +61,18 @@ function Hero() {
<ArrowUpRight className="absolute transition-all duration-500 -translate-x-4 -translate-y-5 group-hover:translate-x-0 group-hover:translate-y-0" />
</div>
</Link>
+ <a
+ href="https://www.producthunt.com/posts/supermemory?embed=true&utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-supermemory"
+ target="_blank"
+ >
+ <img
+ src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=472686&theme=dark&period=daily"
+ alt="Supermemory - AI&#0032;second&#0032;brain&#0032;for&#0032;all&#0032;your&#0032;saved&#0032;stuff | Product Hunt"
+ style={{ width: "250px", height: "54px" }}
+ width="250"
+ height="54"
+ />
+ </a>
</section>
<AnimatedLogoCloud />
diff --git a/apps/web/app/actions/doers.ts b/apps/web/app/actions/doers.ts
index a2cdb4f5..fbccd195 100644
--- a/apps/web/app/actions/doers.ts
+++ b/apps/web/app/actions/doers.ts
@@ -22,6 +22,34 @@ import { ChatHistory } from "@repo/shared-types";
import { decipher } from "@/server/encrypt";
import { redirect } from "next/navigation";
import { tweetToMd } from "@repo/shared-types/utils";
+import { ensureAuth } from "../api/ensureAuth";
+import { getRandomSentences } from "@/lib/utils";
+import { getRequestContext } from "@cloudflare/next-on-pages";
+
+export const completeOnboarding = async (): ServerActionReturnType<boolean> => {
+ const data = await auth();
+
+ if (!data || !data.user || !data.user.id) {
+ redirect("/signin");
+ return { error: "Not authenticated", success: false };
+ }
+
+ try {
+ const res = await db
+ .update(users)
+ .set({ hasOnboarded: true })
+ .where(eq(users.id, data.user.id))
+ .returning({ hasOnboarded: users.hasOnboarded });
+
+ if (res.length === 0 || !res[0]?.hasOnboarded) {
+ return { success: false, data: false, error: "Failed to update user" };
+ }
+
+ return { success: true, data: res[0].hasOnboarded };
+ } catch (e) {
+ return { success: false, data: false, error: (e as Error).message };
+ }
+};
export const createSpace = async (
input: string | FormData,
@@ -708,3 +736,122 @@ export async function AddCanvasInfo({
};
}
}
+
+export async function getQuerySuggestions() {
+ const data = await auth();
+
+ if (!data || !data.user || !data.user.id) {
+ redirect("/signin");
+ return { error: "Not authenticated", success: false };
+ }
+
+ const { env } = getRequestContext();
+
+ try {
+ const recommendations = await env.RECOMMENDATIONS.get(data.user.id);
+
+ if (recommendations) {
+ return {
+ success: true,
+ data: JSON.parse(recommendations),
+ };
+ }
+
+ // Randomly choose some storedContent of the user.
+ const content = await db
+ .select()
+ .from(storedContent)
+ .where(eq(storedContent.userId, data.user.id))
+ .orderBy(sql`random()`)
+ .limit(5)
+ .all();
+
+ if (content.length === 0) {
+ return {
+ success: true,
+ data: [],
+ };
+ }
+
+ const fullQuery = content
+ .map((c) => `${c.title} \n\n${c.content}`)
+ .join(" ");
+
+ const suggestionsCall = (await env.AI.run(
+ // @ts-ignore
+ "@cf/meta/llama-3.1-8b-instruct",
+ {
+ messages: [
+ {
+ role: "system",
+ content: `You are a model that suggests questions based on the user's content. you MUST suggest atleast 1 question to ask. Create 3 suggestions at most.`,
+ },
+ {
+ role: "user",
+ content: `Run the function based on this input: ${fullQuery.slice(0, 2000)}`,
+ },
+ ],
+ tools: [
+ {
+ type: "function",
+ function: {
+ name: "querySuggestions",
+ description:
+ "Take the user's content to suggest some good questions that they could ask.",
+ parameters: {
+ type: "object",
+ properties: {
+ querySuggestions: {
+ type: "array",
+ description:
+ "Short questions that the user can ask. Give atleast 3 suggestions. No more than 5.",
+ items: {
+ type: "string",
+ },
+ },
+ },
+ required: ["querySuggestions"],
+ },
+ },
+ },
+ ],
+ },
+ )) as {
+ response: string;
+ tool_calls: { name: string; arguments: { querySuggestions: string[] } }[];
+ };
+
+ console.log(
+ "I RAN AN AI CALLS OWOWOWOWOW",
+ JSON.stringify(suggestionsCall, null, 2),
+ );
+
+ const suggestions =
+ suggestionsCall.tool_calls?.[0]?.arguments?.querySuggestions;
+
+ if (!suggestions || suggestions.length === 0) {
+ return {
+ success: false,
+ error: "Failed to get query suggestions",
+ };
+ }
+
+ if (suggestions.length > 0) {
+ await env.RECOMMENDATIONS.put(data.user.id, JSON.stringify(suggestions), {
+ expirationTtl: 60 * 2,
+ });
+ }
+
+ return {
+ success: true,
+ data: suggestions,
+ };
+ } catch (exception) {
+ const error = exception as Error;
+ return {
+ success: false,
+ error: error.message,
+ data: [],
+ };
+ }
+}
diff --git a/apps/web/app/actions/fetchers.ts b/apps/web/app/actions/fetchers.ts
index 688fe7f5..8d6802a7 100644
--- a/apps/web/app/actions/fetchers.ts
+++ b/apps/web/app/actions/fetchers.ts
@@ -1,6 +1,6 @@
"use server";
-import { and, asc, eq, exists, inArray, not, or, sql } from "drizzle-orm";
+import { and, asc, eq, exists, not, or } from "drizzle-orm";
import { db } from "../../server/db";
import {
canvas,
@@ -13,15 +13,32 @@ import {
spacesAccess,
storedContent,
StoredSpace,
+ User,
users,
} from "../../server/db/schema";
-import { ServerActionReturnType, Space } from "./types";
+import { ServerActionReturnType } from "./types";
import { auth } from "../../server/auth";
import { ChatHistory, SourceZod } from "@repo/shared-types";
import { z } from "zod";
import { redirect } from "next/navigation";
import { cookies, headers } from "next/headers";
+export const getUser = async (): ServerActionReturnType<User> => {
+ const data = await auth();
+
+ if (!data || !data.user || !data.user.id) {
+ redirect("/signin");
+ return { error: "Not authenticated", success: false };
+ }
+
+ console.log("data.user.id", data.user.id);
+ const user = await db.query.users.findFirst({
+ where: eq(users.id, data.user.id),
+ });
+
+ return { success: true, data: user };
+};
+
export const getSpaces = async (): ServerActionReturnType<StoredSpace[]> => {
const data = await auth();
diff --git a/apps/web/env.d.ts b/apps/web/env.d.ts
index b6a410f9..c80ac0a4 100644
--- a/apps/web/env.d.ts
+++ b/apps/web/env.d.ts
@@ -6,4 +6,6 @@ interface CloudflareEnv {
DATABASE: D1Database;
DEV_IMAGES: R2Bucket;
CANVAS_SNAPS: KVNamespace;
+ AI: Ai;
+ RECOMMENDATIONS: KVNamespace;
}
diff --git a/apps/web/lib/utils.ts b/apps/web/lib/utils.ts
new file mode 100644
index 00000000..98ec6e98
--- /dev/null
+++ b/apps/web/lib/utils.ts
@@ -0,0 +1,23 @@
+export function getRandomSentences(fullQuery: string): string {
+ // Split the fullQuery into sentences
+ const sentences = fullQuery.match(/[^.!?]+[.!?]+/g) || [];
+
+ // Function to get a random integer between min and max
+ function getRandomInt(min: number, max: number): number {
+ return Math.floor(Math.random() * (max - min)) + min;
+ }
+
+ let selectedSentences = "";
+ let totalCharacters = 0;
+
+ // Select random sentences until totalCharacters is at least 1000
+ while (totalCharacters < 1000 && sentences.length > 0) {
+ const randomIndex = getRandomInt(0, sentences.length);
+ const sentence = sentences[randomIndex];
+ selectedSentences += sentence;
+ totalCharacters += sentence?.length || 0;
+ sentences.splice(randomIndex, 1); // Remove the selected sentence from the array
+ }
+
+ return selectedSentences;
+}
diff --git a/apps/web/migrations/0000_exotic_sway.sql b/apps/web/migrations/0000_setup.sql
index 65a41795..65a41795 100644
--- a/apps/web/migrations/0000_exotic_sway.sql
+++ b/apps/web/migrations/0000_setup.sql
diff --git a/apps/web/migrations/0001_dear_sally_floyd.sql b/apps/web/migrations/0001_dear_sally_floyd.sql
new file mode 100644
index 00000000..8fa112f7
--- /dev/null
+++ b/apps/web/migrations/0001_dear_sally_floyd.sql
@@ -0,0 +1 @@
+ALTER TABLE `user` ADD `hasOnboarded` integer DEFAULT false; \ No newline at end of file
diff --git a/apps/web/migrations/meta/0000_snapshot.json b/apps/web/migrations/meta/0000_snapshot.json
index 0639eb77..7e502c8b 100644
--- a/apps/web/migrations/meta/0000_snapshot.json
+++ b/apps/web/migrations/meta/0000_snapshot.json
@@ -1,806 +1,895 @@
{
- "version": "6",
- "dialect": "sqlite",
- "id": "ab91d972-05ff-4916-84b7-1cfaab4c3879",
- "prevId": "00000000-0000-0000-0000-000000000000",
- "tables": {
- "account": {
- "name": "account",
- "columns": {
- "userId": {
- "name": "userId",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "type": {
- "name": "type",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "provider": {
- "name": "provider",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "providerAccountId": {
- "name": "providerAccountId",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "refresh_token": {
- "name": "refresh_token",
- "type": "text",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "access_token": {
- "name": "access_token",
- "type": "text",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "expires_at": {
- "name": "expires_at",
- "type": "integer",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "token_type": {
- "name": "token_type",
- "type": "text",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "scope": {
- "name": "scope",
- "type": "text",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "id_token": {
- "name": "id_token",
- "type": "text",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "session_state": {
- "name": "session_state",
- "type": "text",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- }
- },
- "indexes": {},
- "foreignKeys": {
- "account_userId_user_id_fk": {
- "name": "account_userId_user_id_fk",
- "tableFrom": "account",
- "tableTo": "user",
- "columnsFrom": ["userId"],
- "columnsTo": ["id"],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {
- "account_provider_providerAccountId_pk": {
- "columns": ["provider", "providerAccountId"],
- "name": "account_provider_providerAccountId_pk"
- }
- },
- "uniqueConstraints": {}
- },
- "authenticator": {
- "name": "authenticator",
- "columns": {
- "credentialID": {
- "name": "credentialID",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "userId": {
- "name": "userId",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "providerAccountId": {
- "name": "providerAccountId",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "credentialPublicKey": {
- "name": "credentialPublicKey",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "counter": {
- "name": "counter",
- "type": "integer",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "credentialDeviceType": {
- "name": "credentialDeviceType",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "credentialBackedUp": {
- "name": "credentialBackedUp",
- "type": "integer",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "transports": {
- "name": "transports",
- "type": "text",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- }
- },
- "indexes": {
- "authenticator_credentialID_unique": {
- "name": "authenticator_credentialID_unique",
- "columns": ["credentialID"],
- "isUnique": true
- }
- },
- "foreignKeys": {
- "authenticator_userId_user_id_fk": {
- "name": "authenticator_userId_user_id_fk",
- "tableFrom": "authenticator",
- "tableTo": "user",
- "columnsFrom": ["userId"],
- "columnsTo": ["id"],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {
- "authenticator_userId_credentialID_pk": {
- "columns": ["credentialID", "userId"],
- "name": "authenticator_userId_credentialID_pk"
- }
- },
- "uniqueConstraints": {}
- },
- "canvas": {
- "name": "canvas",
- "columns": {
- "id": {
- "name": "id",
- "type": "text",
- "primaryKey": true,
- "notNull": true,
- "autoincrement": false
- },
- "title": {
- "name": "title",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false,
- "default": "'Untitled'"
- },
- "description": {
- "name": "description",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false,
- "default": "'Untitled'"
- },
- "url": {
- "name": "url",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false,
- "default": "''"
- },
- "userId": {
- "name": "userId",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- }
- },
- "indexes": {
- "canvas_user_userId": {
- "name": "canvas_user_userId",
- "columns": ["userId"],
- "isUnique": false
- }
- },
- "foreignKeys": {
- "canvas_userId_user_id_fk": {
- "name": "canvas_userId_user_id_fk",
- "tableFrom": "canvas",
- "tableTo": "user",
- "columnsFrom": ["userId"],
- "columnsTo": ["id"],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {}
- },
- "chatHistory": {
- "name": "chatHistory",
- "columns": {
- "id": {
- "name": "id",
- "type": "integer",
- "primaryKey": true,
- "notNull": true,
- "autoincrement": true
- },
- "threadId": {
- "name": "threadId",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "question": {
- "name": "question",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "answerParts": {
- "name": "answerParts",
- "type": "text",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "answerSources": {
- "name": "answerSources",
- "type": "text",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "answerJustification": {
- "name": "answerJustification",
- "type": "text",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- }
- },
- "indexes": {
- "chatHistory_thread_idx": {
- "name": "chatHistory_thread_idx",
- "columns": ["threadId"],
- "isUnique": false
- }
- },
- "foreignKeys": {
- "chatHistory_threadId_chatThread_id_fk": {
- "name": "chatHistory_threadId_chatThread_id_fk",
- "tableFrom": "chatHistory",
- "tableTo": "chatThread",
- "columnsFrom": ["threadId"],
- "columnsTo": ["id"],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {}
- },
- "chatThread": {
- "name": "chatThread",
- "columns": {
- "id": {
- "name": "id",
- "type": "text",
- "primaryKey": true,
- "notNull": true,
- "autoincrement": false
- },
- "firstMessage": {
- "name": "firstMessage",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "userId": {
- "name": "userId",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- }
- },
- "indexes": {
- "chatThread_user_idx": {
- "name": "chatThread_user_idx",
- "columns": ["userId"],
- "isUnique": false
- }
- },
- "foreignKeys": {
- "chatThread_userId_user_id_fk": {
- "name": "chatThread_userId_user_id_fk",
- "tableFrom": "chatThread",
- "tableTo": "user",
- "columnsFrom": ["userId"],
- "columnsTo": ["id"],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {}
- },
- "contentToSpace": {
- "name": "contentToSpace",
- "columns": {
- "contentId": {
- "name": "contentId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "spaceId": {
- "name": "spaceId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- }
- },
- "indexes": {},
- "foreignKeys": {
- "contentToSpace_contentId_storedContent_id_fk": {
- "name": "contentToSpace_contentId_storedContent_id_fk",
- "tableFrom": "contentToSpace",
- "tableTo": "storedContent",
- "columnsFrom": ["contentId"],
- "columnsTo": ["id"],
- "onDelete": "cascade",
- "onUpdate": "no action"
- },
- "contentToSpace_spaceId_space_id_fk": {
- "name": "contentToSpace_spaceId_space_id_fk",
- "tableFrom": "contentToSpace",
- "tableTo": "space",
- "columnsFrom": ["spaceId"],
- "columnsTo": ["id"],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {
- "contentToSpace_contentId_spaceId_pk": {
- "columns": ["contentId", "spaceId"],
- "name": "contentToSpace_contentId_spaceId_pk"
- }
- },
- "uniqueConstraints": {}
- },
- "session": {
- "name": "session",
- "columns": {
- "sessionToken": {
- "name": "sessionToken",
- "type": "text",
- "primaryKey": true,
- "notNull": true,
- "autoincrement": false
- },
- "userId": {
- "name": "userId",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "expires": {
- "name": "expires",
- "type": "integer",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- }
- },
- "indexes": {},
- "foreignKeys": {
- "session_userId_user_id_fk": {
- "name": "session_userId_user_id_fk",
- "tableFrom": "session",
- "tableTo": "user",
- "columnsFrom": ["userId"],
- "columnsTo": ["id"],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {}
- },
- "space": {
- "name": "space",
- "columns": {
- "id": {
- "name": "id",
- "type": "integer",
- "primaryKey": true,
- "notNull": true,
- "autoincrement": true
- },
- "name": {
- "name": "name",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false,
- "default": "'none'"
- },
- "user": {
- "name": "user",
- "type": "text(255)",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "createdAt": {
- "name": "createdAt",
- "type": "integer",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "numItems": {
- "name": "numItems",
- "type": "integer",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false,
- "default": 0
- }
- },
- "indexes": {
- "space_name_unique": {
- "name": "space_name_unique",
- "columns": ["name"],
- "isUnique": true
- },
- "spaces_name_idx": {
- "name": "spaces_name_idx",
- "columns": ["name"],
- "isUnique": false
- },
- "spaces_user_idx": {
- "name": "spaces_user_idx",
- "columns": ["user"],
- "isUnique": false
- }
- },
- "foreignKeys": {
- "space_user_user_id_fk": {
- "name": "space_user_user_id_fk",
- "tableFrom": "space",
- "tableTo": "user",
- "columnsFrom": ["user"],
- "columnsTo": ["id"],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {}
- },
- "spacesAccess": {
- "name": "spacesAccess",
- "columns": {
- "spaceId": {
- "name": "spaceId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "userEmail": {
- "name": "userEmail",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- }
- },
- "indexes": {},
- "foreignKeys": {
- "spacesAccess_spaceId_space_id_fk": {
- "name": "spacesAccess_spaceId_space_id_fk",
- "tableFrom": "spacesAccess",
- "tableTo": "space",
- "columnsFrom": ["spaceId"],
- "columnsTo": ["id"],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {
- "spacesAccess_spaceId_userEmail_pk": {
- "columns": ["spaceId", "userEmail"],
- "name": "spacesAccess_spaceId_userEmail_pk"
- }
- },
- "uniqueConstraints": {}
- },
- "storedContent": {
- "name": "storedContent",
- "columns": {
- "id": {
- "name": "id",
- "type": "integer",
- "primaryKey": true,
- "notNull": true,
- "autoincrement": true
- },
- "content": {
- "name": "content",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "title": {
- "name": "title",
- "type": "text(255)",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "description": {
- "name": "description",
- "type": "text(255)",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "url": {
- "name": "url",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "savedAt": {
- "name": "savedAt",
- "type": "integer",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "baseUrl": {
- "name": "baseUrl",
- "type": "text(255)",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "ogImage": {
- "name": "ogImage",
- "type": "text(255)",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "type": {
- "name": "type",
- "type": "text",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false,
- "default": "'page'"
- },
- "image": {
- "name": "image",
- "type": "text(255)",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "user": {
- "name": "user",
- "type": "text",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "noteId": {
- "name": "noteId",
- "type": "integer",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- }
- },
- "indexes": {
- "storedContent_baseUrl_unique": {
- "name": "storedContent_baseUrl_unique",
- "columns": ["baseUrl"],
- "isUnique": true
- },
- "storedContent_url_idx": {
- "name": "storedContent_url_idx",
- "columns": ["url"],
- "isUnique": false
- },
- "storedContent_savedAt_idx": {
- "name": "storedContent_savedAt_idx",
- "columns": ["savedAt"],
- "isUnique": false
- },
- "storedContent_title_idx": {
- "name": "storedContent_title_idx",
- "columns": ["title"],
- "isUnique": false
- },
- "storedContent_user_idx": {
- "name": "storedContent_user_idx",
- "columns": ["user"],
- "isUnique": false
- }
- },
- "foreignKeys": {
- "storedContent_user_user_id_fk": {
- "name": "storedContent_user_user_id_fk",
- "tableFrom": "storedContent",
- "tableTo": "user",
- "columnsFrom": ["user"],
- "columnsTo": ["id"],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {}
- },
- "user": {
- "name": "user",
- "columns": {
- "id": {
- "name": "id",
- "type": "text",
- "primaryKey": true,
- "notNull": true,
- "autoincrement": false
- },
- "name": {
- "name": "name",
- "type": "text",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "email": {
- "name": "email",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "emailVerified": {
- "name": "emailVerified",
- "type": "integer",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "image": {
- "name": "image",
- "type": "text",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- },
- "telegramId": {
- "name": "telegramId",
- "type": "text",
- "primaryKey": false,
- "notNull": false,
- "autoincrement": false
- }
- },
- "indexes": {
- "users_email_idx": {
- "name": "users_email_idx",
- "columns": ["email"],
- "isUnique": false
- },
- "users_telegram_idx": {
- "name": "users_telegram_idx",
- "columns": ["telegramId"],
- "isUnique": false
- },
- "users_id_idx": {
- "name": "users_id_idx",
- "columns": ["id"],
- "isUnique": false
- }
- },
- "foreignKeys": {},
- "compositePrimaryKeys": {},
- "uniqueConstraints": {}
- },
- "verificationToken": {
- "name": "verificationToken",
- "columns": {
- "identifier": {
- "name": "identifier",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "token": {
- "name": "token",
- "type": "text",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- },
- "expires": {
- "name": "expires",
- "type": "integer",
- "primaryKey": false,
- "notNull": true,
- "autoincrement": false
- }
- },
- "indexes": {},
- "foreignKeys": {},
- "compositePrimaryKeys": {
- "verificationToken_identifier_token_pk": {
- "columns": ["identifier", "token"],
- "name": "verificationToken_identifier_token_pk"
- }
- },
- "uniqueConstraints": {}
- }
- },
- "enums": {},
- "_meta": {
- "schemas": {},
- "tables": {},
- "columns": {}
- }
-}
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "e8646bed-105d-4f69-b385-b8b6fee8a6a9",
+ "prevId": "00000000-0000-0000-0000-000000000000",
+ "tables": {
+ "account": {
+ "name": "account",
+ "columns": {
+ "userId": {
+ "name": "userId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "type": {
+ "name": "type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "provider": {
+ "name": "provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "providerAccountId": {
+ "name": "providerAccountId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "refresh_token": {
+ "name": "refresh_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "access_token": {
+ "name": "access_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "token_type": {
+ "name": "token_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "scope": {
+ "name": "scope",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "id_token": {
+ "name": "id_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "session_state": {
+ "name": "session_state",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "account_userId_user_id_fk": {
+ "name": "account_userId_user_id_fk",
+ "tableFrom": "account",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {
+ "account_provider_providerAccountId_pk": {
+ "columns": [
+ "provider",
+ "providerAccountId"
+ ],
+ "name": "account_provider_providerAccountId_pk"
+ }
+ },
+ "uniqueConstraints": {}
+ },
+ "authenticator": {
+ "name": "authenticator",
+ "columns": {
+ "credentialID": {
+ "name": "credentialID",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "userId": {
+ "name": "userId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "providerAccountId": {
+ "name": "providerAccountId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "credentialPublicKey": {
+ "name": "credentialPublicKey",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "counter": {
+ "name": "counter",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "credentialDeviceType": {
+ "name": "credentialDeviceType",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "credentialBackedUp": {
+ "name": "credentialBackedUp",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "transports": {
+ "name": "transports",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "authenticator_credentialID_unique": {
+ "name": "authenticator_credentialID_unique",
+ "columns": [
+ "credentialID"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "authenticator_userId_user_id_fk": {
+ "name": "authenticator_userId_user_id_fk",
+ "tableFrom": "authenticator",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {
+ "authenticator_userId_credentialID_pk": {
+ "columns": [
+ "credentialID",
+ "userId"
+ ],
+ "name": "authenticator_userId_credentialID_pk"
+ }
+ },
+ "uniqueConstraints": {}
+ },
+ "canvas": {
+ "name": "canvas",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "title": {
+ "name": "title",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'Untitled'"
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'Untitled'"
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "userId": {
+ "name": "userId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "canvas_user_userId": {
+ "name": "canvas_user_userId",
+ "columns": [
+ "userId"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "canvas_userId_user_id_fk": {
+ "name": "canvas_userId_user_id_fk",
+ "tableFrom": "canvas",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "chatHistory": {
+ "name": "chatHistory",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "integer",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": true
+ },
+ "threadId": {
+ "name": "threadId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "question": {
+ "name": "question",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "answerParts": {
+ "name": "answerParts",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "answerSources": {
+ "name": "answerSources",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "answerJustification": {
+ "name": "answerJustification",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "chatHistory_thread_idx": {
+ "name": "chatHistory_thread_idx",
+ "columns": [
+ "threadId"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "chatHistory_threadId_chatThread_id_fk": {
+ "name": "chatHistory_threadId_chatThread_id_fk",
+ "tableFrom": "chatHistory",
+ "tableTo": "chatThread",
+ "columnsFrom": [
+ "threadId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "chatThread": {
+ "name": "chatThread",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "firstMessage": {
+ "name": "firstMessage",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "userId": {
+ "name": "userId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "chatThread_user_idx": {
+ "name": "chatThread_user_idx",
+ "columns": [
+ "userId"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "chatThread_userId_user_id_fk": {
+ "name": "chatThread_userId_user_id_fk",
+ "tableFrom": "chatThread",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "contentToSpace": {
+ "name": "contentToSpace",
+ "columns": {
+ "contentId": {
+ "name": "contentId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "spaceId": {
+ "name": "spaceId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "contentToSpace_contentId_storedContent_id_fk": {
+ "name": "contentToSpace_contentId_storedContent_id_fk",
+ "tableFrom": "contentToSpace",
+ "tableTo": "storedContent",
+ "columnsFrom": [
+ "contentId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "contentToSpace_spaceId_space_id_fk": {
+ "name": "contentToSpace_spaceId_space_id_fk",
+ "tableFrom": "contentToSpace",
+ "tableTo": "space",
+ "columnsFrom": [
+ "spaceId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {
+ "contentToSpace_contentId_spaceId_pk": {
+ "columns": [
+ "contentId",
+ "spaceId"
+ ],
+ "name": "contentToSpace_contentId_spaceId_pk"
+ }
+ },
+ "uniqueConstraints": {}
+ },
+ "session": {
+ "name": "session",
+ "columns": {
+ "sessionToken": {
+ "name": "sessionToken",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "userId": {
+ "name": "userId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires": {
+ "name": "expires",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "session_userId_user_id_fk": {
+ "name": "session_userId_user_id_fk",
+ "tableFrom": "session",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "space": {
+ "name": "space",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "integer",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'none'"
+ },
+ "user": {
+ "name": "user",
+ "type": "text(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "numItems": {
+ "name": "numItems",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ }
+ },
+ "indexes": {
+ "space_name_unique": {
+ "name": "space_name_unique",
+ "columns": [
+ "name"
+ ],
+ "isUnique": true
+ },
+ "spaces_name_idx": {
+ "name": "spaces_name_idx",
+ "columns": [
+ "name"
+ ],
+ "isUnique": false
+ },
+ "spaces_user_idx": {
+ "name": "spaces_user_idx",
+ "columns": [
+ "user"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "space_user_user_id_fk": {
+ "name": "space_user_user_id_fk",
+ "tableFrom": "space",
+ "tableTo": "user",
+ "columnsFrom": [
+ "user"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "spacesAccess": {
+ "name": "spacesAccess",
+ "columns": {
+ "spaceId": {
+ "name": "spaceId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "userEmail": {
+ "name": "userEmail",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "spacesAccess_spaceId_space_id_fk": {
+ "name": "spacesAccess_spaceId_space_id_fk",
+ "tableFrom": "spacesAccess",
+ "tableTo": "space",
+ "columnsFrom": [
+ "spaceId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {
+ "spacesAccess_spaceId_userEmail_pk": {
+ "columns": [
+ "spaceId",
+ "userEmail"
+ ],
+ "name": "spacesAccess_spaceId_userEmail_pk"
+ }
+ },
+ "uniqueConstraints": {}
+ },
+ "storedContent": {
+ "name": "storedContent",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "integer",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": true
+ },
+ "content": {
+ "name": "content",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "title": {
+ "name": "title",
+ "type": "text(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "description": {
+ "name": "description",
+ "type": "text(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "savedAt": {
+ "name": "savedAt",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "baseUrl": {
+ "name": "baseUrl",
+ "type": "text(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "ogImage": {
+ "name": "ogImage",
+ "type": "text(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "type": {
+ "name": "type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false,
+ "default": "'page'"
+ },
+ "image": {
+ "name": "image",
+ "type": "text(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "user": {
+ "name": "user",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "noteId": {
+ "name": "noteId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "storedContent_baseUrl_unique": {
+ "name": "storedContent_baseUrl_unique",
+ "columns": [
+ "baseUrl"
+ ],
+ "isUnique": true
+ },
+ "storedContent_url_idx": {
+ "name": "storedContent_url_idx",
+ "columns": [
+ "url"
+ ],
+ "isUnique": false
+ },
+ "storedContent_savedAt_idx": {
+ "name": "storedContent_savedAt_idx",
+ "columns": [
+ "savedAt"
+ ],
+ "isUnique": false
+ },
+ "storedContent_title_idx": {
+ "name": "storedContent_title_idx",
+ "columns": [
+ "title"
+ ],
+ "isUnique": false
+ },
+ "storedContent_user_idx": {
+ "name": "storedContent_user_idx",
+ "columns": [
+ "user"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "storedContent_user_user_id_fk": {
+ "name": "storedContent_user_user_id_fk",
+ "tableFrom": "storedContent",
+ "tableTo": "user",
+ "columnsFrom": [
+ "user"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "user": {
+ "name": "user",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "emailVerified": {
+ "name": "emailVerified",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "telegramId": {
+ "name": "telegramId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "users_email_idx": {
+ "name": "users_email_idx",
+ "columns": [
+ "email"
+ ],
+ "isUnique": false
+ },
+ "users_telegram_idx": {
+ "name": "users_telegram_idx",
+ "columns": [
+ "telegramId"
+ ],
+ "isUnique": false
+ },
+ "users_id_idx": {
+ "name": "users_id_idx",
+ "columns": [
+ "id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "verificationToken": {
+ "name": "verificationToken",
+ "columns": {
+ "identifier": {
+ "name": "identifier",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "token": {
+ "name": "token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires": {
+ "name": "expires",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {
+ "verificationToken_identifier_token_pk": {
+ "columns": [
+ "identifier",
+ "token"
+ ],
+ "name": "verificationToken_identifier_token_pk"
+ }
+ },
+ "uniqueConstraints": {}
+ }
+ },
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ }
+} \ No newline at end of file
diff --git a/apps/web/migrations/meta/0001_snapshot.json b/apps/web/migrations/meta/0001_snapshot.json
new file mode 100644
index 00000000..461b3c72
--- /dev/null
+++ b/apps/web/migrations/meta/0001_snapshot.json
@@ -0,0 +1,903 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "1f43694b-f42b-4074-876e-8501fc18bf38",
+ "prevId": "e8646bed-105d-4f69-b385-b8b6fee8a6a9",
+ "tables": {
+ "account": {
+ "name": "account",
+ "columns": {
+ "userId": {
+ "name": "userId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "type": {
+ "name": "type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "provider": {
+ "name": "provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "providerAccountId": {
+ "name": "providerAccountId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "refresh_token": {
+ "name": "refresh_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "access_token": {
+ "name": "access_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "token_type": {
+ "name": "token_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "scope": {
+ "name": "scope",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "id_token": {
+ "name": "id_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "session_state": {
+ "name": "session_state",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "account_userId_user_id_fk": {
+ "name": "account_userId_user_id_fk",
+ "tableFrom": "account",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {
+ "account_provider_providerAccountId_pk": {
+ "columns": [
+ "provider",
+ "providerAccountId"
+ ],
+ "name": "account_provider_providerAccountId_pk"
+ }
+ },
+ "uniqueConstraints": {}
+ },
+ "authenticator": {
+ "name": "authenticator",
+ "columns": {
+ "credentialID": {
+ "name": "credentialID",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "userId": {
+ "name": "userId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "providerAccountId": {
+ "name": "providerAccountId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "credentialPublicKey": {
+ "name": "credentialPublicKey",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "counter": {
+ "name": "counter",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "credentialDeviceType": {
+ "name": "credentialDeviceType",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "credentialBackedUp": {
+ "name": "credentialBackedUp",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "transports": {
+ "name": "transports",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "authenticator_credentialID_unique": {
+ "name": "authenticator_credentialID_unique",
+ "columns": [
+ "credentialID"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {
+ "authenticator_userId_user_id_fk": {
+ "name": "authenticator_userId_user_id_fk",
+ "tableFrom": "authenticator",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {
+ "authenticator_userId_credentialID_pk": {
+ "columns": [
+ "credentialID",
+ "userId"
+ ],
+ "name": "authenticator_userId_credentialID_pk"
+ }
+ },
+ "uniqueConstraints": {}
+ },
+ "canvas": {
+ "name": "canvas",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "title": {
+ "name": "title",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'Untitled'"
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'Untitled'"
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "''"
+ },
+ "userId": {
+ "name": "userId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "canvas_user_userId": {
+ "name": "canvas_user_userId",
+ "columns": [
+ "userId"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "canvas_userId_user_id_fk": {
+ "name": "canvas_userId_user_id_fk",
+ "tableFrom": "canvas",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "chatHistory": {
+ "name": "chatHistory",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "integer",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": true
+ },
+ "threadId": {
+ "name": "threadId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "question": {
+ "name": "question",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "answerParts": {
+ "name": "answerParts",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "answerSources": {
+ "name": "answerSources",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "answerJustification": {
+ "name": "answerJustification",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "chatHistory_thread_idx": {
+ "name": "chatHistory_thread_idx",
+ "columns": [
+ "threadId"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "chatHistory_threadId_chatThread_id_fk": {
+ "name": "chatHistory_threadId_chatThread_id_fk",
+ "tableFrom": "chatHistory",
+ "tableTo": "chatThread",
+ "columnsFrom": [
+ "threadId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "chatThread": {
+ "name": "chatThread",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "firstMessage": {
+ "name": "firstMessage",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "userId": {
+ "name": "userId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "chatThread_user_idx": {
+ "name": "chatThread_user_idx",
+ "columns": [
+ "userId"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "chatThread_userId_user_id_fk": {
+ "name": "chatThread_userId_user_id_fk",
+ "tableFrom": "chatThread",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "contentToSpace": {
+ "name": "contentToSpace",
+ "columns": {
+ "contentId": {
+ "name": "contentId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "spaceId": {
+ "name": "spaceId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "contentToSpace_contentId_storedContent_id_fk": {
+ "name": "contentToSpace_contentId_storedContent_id_fk",
+ "tableFrom": "contentToSpace",
+ "tableTo": "storedContent",
+ "columnsFrom": [
+ "contentId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "contentToSpace_spaceId_space_id_fk": {
+ "name": "contentToSpace_spaceId_space_id_fk",
+ "tableFrom": "contentToSpace",
+ "tableTo": "space",
+ "columnsFrom": [
+ "spaceId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {
+ "contentToSpace_contentId_spaceId_pk": {
+ "columns": [
+ "contentId",
+ "spaceId"
+ ],
+ "name": "contentToSpace_contentId_spaceId_pk"
+ }
+ },
+ "uniqueConstraints": {}
+ },
+ "session": {
+ "name": "session",
+ "columns": {
+ "sessionToken": {
+ "name": "sessionToken",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "userId": {
+ "name": "userId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires": {
+ "name": "expires",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "session_userId_user_id_fk": {
+ "name": "session_userId_user_id_fk",
+ "tableFrom": "session",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "space": {
+ "name": "space",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "integer",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'none'"
+ },
+ "user": {
+ "name": "user",
+ "type": "text(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "numItems": {
+ "name": "numItems",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 0
+ }
+ },
+ "indexes": {
+ "space_name_unique": {
+ "name": "space_name_unique",
+ "columns": [
+ "name"
+ ],
+ "isUnique": true
+ },
+ "spaces_name_idx": {
+ "name": "spaces_name_idx",
+ "columns": [
+ "name"
+ ],
+ "isUnique": false
+ },
+ "spaces_user_idx": {
+ "name": "spaces_user_idx",
+ "columns": [
+ "user"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "space_user_user_id_fk": {
+ "name": "space_user_user_id_fk",
+ "tableFrom": "space",
+ "tableTo": "user",
+ "columnsFrom": [
+ "user"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "spacesAccess": {
+ "name": "spacesAccess",
+ "columns": {
+ "spaceId": {
+ "name": "spaceId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "userEmail": {
+ "name": "userEmail",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "spacesAccess_spaceId_space_id_fk": {
+ "name": "spacesAccess_spaceId_space_id_fk",
+ "tableFrom": "spacesAccess",
+ "tableTo": "space",
+ "columnsFrom": [
+ "spaceId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {
+ "spacesAccess_spaceId_userEmail_pk": {
+ "columns": [
+ "spaceId",
+ "userEmail"
+ ],
+ "name": "spacesAccess_spaceId_userEmail_pk"
+ }
+ },
+ "uniqueConstraints": {}
+ },
+ "storedContent": {
+ "name": "storedContent",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "integer",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": true
+ },
+ "content": {
+ "name": "content",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "title": {
+ "name": "title",
+ "type": "text(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "description": {
+ "name": "description",
+ "type": "text(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "savedAt": {
+ "name": "savedAt",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "baseUrl": {
+ "name": "baseUrl",
+ "type": "text(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "ogImage": {
+ "name": "ogImage",
+ "type": "text(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "type": {
+ "name": "type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false,
+ "default": "'page'"
+ },
+ "image": {
+ "name": "image",
+ "type": "text(255)",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "user": {
+ "name": "user",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "noteId": {
+ "name": "noteId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "storedContent_baseUrl_unique": {
+ "name": "storedContent_baseUrl_unique",
+ "columns": [
+ "baseUrl"
+ ],
+ "isUnique": true
+ },
+ "storedContent_url_idx": {
+ "name": "storedContent_url_idx",
+ "columns": [
+ "url"
+ ],
+ "isUnique": false
+ },
+ "storedContent_savedAt_idx": {
+ "name": "storedContent_savedAt_idx",
+ "columns": [
+ "savedAt"
+ ],
+ "isUnique": false
+ },
+ "storedContent_title_idx": {
+ "name": "storedContent_title_idx",
+ "columns": [
+ "title"
+ ],
+ "isUnique": false
+ },
+ "storedContent_user_idx": {
+ "name": "storedContent_user_idx",
+ "columns": [
+ "user"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "storedContent_user_user_id_fk": {
+ "name": "storedContent_user_user_id_fk",
+ "tableFrom": "storedContent",
+ "tableTo": "user",
+ "columnsFrom": [
+ "user"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "user": {
+ "name": "user",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "emailVerified": {
+ "name": "emailVerified",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "telegramId": {
+ "name": "telegramId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "hasOnboarded": {
+ "name": "hasOnboarded",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false,
+ "default": false
+ }
+ },
+ "indexes": {
+ "users_email_idx": {
+ "name": "users_email_idx",
+ "columns": [
+ "email"
+ ],
+ "isUnique": false
+ },
+ "users_telegram_idx": {
+ "name": "users_telegram_idx",
+ "columns": [
+ "telegramId"
+ ],
+ "isUnique": false
+ },
+ "users_id_idx": {
+ "name": "users_id_idx",
+ "columns": [
+ "id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "verificationToken": {
+ "name": "verificationToken",
+ "columns": {
+ "identifier": {
+ "name": "identifier",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "token": {
+ "name": "token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "expires": {
+ "name": "expires",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {
+ "verificationToken_identifier_token_pk": {
+ "columns": [
+ "identifier",
+ "token"
+ ],
+ "name": "verificationToken_identifier_token_pk"
+ }
+ },
+ "uniqueConstraints": {}
+ }
+ },
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ }
+} \ No newline at end of file
diff --git a/apps/web/migrations/meta/_journal.json b/apps/web/migrations/meta/_journal.json
index c7ab51e1..ba09e752 100644
--- a/apps/web/migrations/meta/_journal.json
+++ b/apps/web/migrations/meta/_journal.json
@@ -1,13 +1,20 @@
{
- "version": "6",
- "dialect": "sqlite",
- "entries": [
- {
- "idx": 0,
- "version": "6",
- "when": 1720360287793,
- "tag": "0000_exotic_sway",
- "breakpoints": true
- }
- ]
-}
+ "version": "6",
+ "dialect": "sqlite",
+ "entries": [
+ {
+ "idx": 0,
+ "version": "6",
+ "when": 1721746132570,
+ "tag": "0000_silky_havok",
+ "breakpoints": true
+ },
+ {
+ "idx": 1,
+ "version": "6",
+ "when": 1721775651258,
+ "tag": "0001_dear_sally_floyd",
+ "breakpoints": true
+ }
+ ]
+} \ No newline at end of file
diff --git a/apps/web/server/db/index.ts b/apps/web/server/db/index.ts
index 4d671bea..a9ec9106 100644
--- a/apps/web/server/db/index.ts
+++ b/apps/web/server/db/index.ts
@@ -2,4 +2,7 @@ import { drizzle } from "drizzle-orm/d1";
import * as schema from "./schema";
-export const db = drizzle(process.env.DATABASE, { schema, logger: true });
+export const db = drizzle(process.env.DATABASE, {
+ schema,
+ logger: process.env.NODE_ENV === "development",
+});
diff --git a/apps/web/server/db/schema.ts b/apps/web/server/db/schema.ts
index ae293a91..8486c788 100644
--- a/apps/web/server/db/schema.ts
+++ b/apps/web/server/db/schema.ts
@@ -22,6 +22,7 @@ export const users = createTable(
emailVerified: integer("emailVerified", { mode: "timestamp_ms" }),
image: text("image"),
telegramId: text("telegramId"),
+ hasOnboarded: integer("hasOnboarded", { mode: "boolean" }).default(false),
},
(user) => ({
emailIdx: index("users_email_idx").on(user.email),
diff --git a/apps/web/wrangler.toml b/apps/web/wrangler.toml
index ce38285b..7f3fa047 100644
--- a/apps/web/wrangler.toml
+++ b/apps/web/wrangler.toml
@@ -3,6 +3,20 @@ compatibility_date = "2024-03-29"
compatibility_flags = [ "nodejs_compat" ]
pages_build_output_dir = ".vercel/output/static"
+
+kv_namespaces = [
+ { binding = "CANVAS_SNAPS", id = "6df98c892b3744ccb0c631d9f60d6697" },
+ { binding = "RECOMMENDATIONS", id = "83bc7055226c4657948141c2ff9a5425" }
+]
+
+env.production.kv_namespaces = [
+ { binding = "CANVAS_SNAPS", id = "6df98c892b3744ccb0c631d9f60d6697" },
+ { binding = "RECOMMENDATIONS", id = "83bc7055226c4657948141c2ff9a5425" }
+]
+
+[ai]
+binding = "AI"
+
[placement]
mode = "smart"
@@ -15,16 +29,19 @@ binding = "DATABASE"
database_name = "dev-d1-anycontext"
database_id = "fc562605-157a-4f60-b439-2a24ffed5b4c"
-[[kv_namespaces]]
-binding = "CANVAS_SNAPS"
-id = "c6446f7190dd4afebe1c318df3400518"
[[env.production.d1_databases]]
binding = "DATABASE"
database_name = "prod-d1-supermemory"
database_id = "f527a727-c472-41d4-8eaf-3d7ba0f2f395"
+[env.preview.ai]
+binding = "AI"
+
[[env.preview.d1_databases]]
binding = "DATABASE"
database_name = "dev-d1-anycontext"
-database_id = "fc562605-157a-4f60-b439-2a24ffed5b4c" \ No newline at end of file
+database_id = "fc562605-157a-4f60-b439-2a24ffed5b4c"
+
+[env.production.ai]
+binding = "AI" \ No newline at end of file