aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDhravya Shah <[email protected]>2024-07-25 17:30:23 -0500
committerDhravya Shah <[email protected]>2024-07-25 17:30:23 -0500
commit18dd5e4fd0355631dead478ca207cad13f410d0f (patch)
treec7bdb441375e590d9266dec36d0389c2d97677fd
parentmerge oopsies (diff)
downloadsupermemory-18dd5e4fd0355631dead478ca207cad13f410d0f.tar.xz
supermemory-18dd5e4fd0355631dead478ca207cad13f410d0f.zip
onboarding page changes and ratelimiting
-rw-r--r--apps/extension/manifest.json2
-rw-r--r--apps/web/app/(auth)/onboarding/page.tsx4
-rw-r--r--apps/web/app/actions/doers.ts1
-rw-r--r--apps/web/app/api/chat/route.ts47
-rw-r--r--apps/web/app/api/store/route.ts20
-rw-r--r--apps/web/cf-env.d.ts4
-rw-r--r--apps/web/migrations/0000_setup.sql133
-rw-r--r--apps/web/migrations/0001_dear_sally_floyd.sql1
-rw-r--r--apps/web/migrations/0003_organic_pet_avengers.sql1
-rw-r--r--apps/web/migrations/meta/0003_snapshot.json911
-rw-r--r--apps/web/migrations/meta/_journal.json16
-rw-r--r--apps/web/server/db/schema.ts2
-rw-r--r--package.json248
13 files changed, 1127 insertions, 263 deletions
diff --git a/apps/extension/manifest.json b/apps/extension/manifest.json
index 0edcd320..7f998412 100644
--- a/apps/extension/manifest.json
+++ b/apps/extension/manifest.json
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"$schema": "https://json.schemastore.org/chrome-manifest",
- "version": "2.63",
+ "version": "2.63.1",
"name": "supermemory",
"description": "An extension for https://supermemory.ai - an AI hub for all your bookmarks.",
"background": {
diff --git a/apps/web/app/(auth)/onboarding/page.tsx b/apps/web/app/(auth)/onboarding/page.tsx
index 9728d107..b40042d1 100644
--- a/apps/web/app/(auth)/onboarding/page.tsx
+++ b/apps/web/app/(auth)/onboarding/page.tsx
@@ -1,10 +1,10 @@
"use client";
import {
+ ArrowUturnDownIcon,
ChevronLeftIcon,
ChevronRightIcon,
QuestionMarkCircleIcon,
- ArrowTurnDownLeftIcon,
} from "@heroicons/react/24/solid";
import { CheckIcon, PlusCircleIcon } from "@heroicons/react/24/outline";
import { motion } from "framer-motion";
@@ -311,7 +311,7 @@ function StepThree({ currStep }: { currStep: number }) {
type="submit"
className="rounded-lg bg-[#369DFD1A] p-3 absolute bottom-4 right-2"
>
- <ArrowTurnDownLeftIcon className="w-4 h-4 text-[#369DFD]" />
+ <ArrowUturnDownIcon className="w-4 h-4 text-[#369DFD]" />
</button>
</form>
</li>
diff --git a/apps/web/app/actions/doers.ts b/apps/web/app/actions/doers.ts
index fbccd195..7ccee382 100644
--- a/apps/web/app/actions/doers.ts
+++ b/apps/web/app/actions/doers.ts
@@ -460,6 +460,7 @@ export const createChatObject = async (
answer: lastChat.answer.parts.map((part) => part.text).join(""),
answerSources: JSON.stringify(lastChat.answer.sources),
threadId,
+ createdAt: new Date(),
});
if (!saved) {
diff --git a/apps/web/app/api/chat/route.ts b/apps/web/app/api/chat/route.ts
index 3b8d971b..9127261c 100644
--- a/apps/web/app/api/chat/route.ts
+++ b/apps/web/app/api/chat/route.ts
@@ -7,6 +7,10 @@ import {
} from "@repo/shared-types";
import { ensureAuth } from "../ensureAuth";
import { z } from "zod";
+import { db } from "@/server/db";
+import { chatHistory as chatHistoryDb, chatThreads } from "@/server/db/schema";
+import { and, eq, gt, sql } from "drizzle-orm";
+import { join } from "path";
export const runtime = "edge";
@@ -21,6 +25,49 @@ export async function POST(req: NextRequest) {
return new Response("Missing BACKEND_SECURITY_KEY", { status: 500 });
}
+ const ip = req.headers.get("cf-connecting-ip");
+
+ if (ip) {
+ if (process.env.RATELIMITER) {
+ const { success } = await process.env.RATELIMITER.limit({
+ key: `chat-${ip}`,
+ });
+
+ if (!success) {
+ console.error("rate limit exceeded");
+ return new Response("Rate limit exceeded", { status: 429 });
+ }
+ } else {
+ console.info("RATELIMITER not found in env");
+ }
+ } else {
+ console.info("cf-connecting-ip not found in headers");
+ }
+
+ const lastHour = new Date(new Date().getTime() - 3600000);
+
+ // Only allow 5 requests per hour for each user, something lke this but this one is bad because chathistory.userid doesnt exist, we have to do a join and get it from the threads table
+ const result = await db
+ .select({
+ count: sql<number>`count(*)`.mapWith(Number),
+ })
+ .from(chatHistoryDb)
+ .innerJoin(chatThreads, eq(chatHistoryDb.threadId, chatThreads.id))
+ .where(
+ and(
+ eq(chatThreads.userId, session.user.id),
+ gt(chatHistoryDb.createdAt, lastHour)
+ )
+ )
+ .execute();
+
+ if (result[0]?.count && result[0]?.count >= 5) {
+ // return new Response(`Too many requests ${result[0]?.count}`, { status: 429 });
+ console.log(result[0]?.count)
+ } else {
+ console.log("count", result);
+ }
+
const url = new URL(req.url);
const query = url.searchParams.get("q");
diff --git a/apps/web/app/api/store/route.ts b/apps/web/app/api/store/route.ts
index f9ab7c01..da393d2e 100644
--- a/apps/web/app/api/store/route.ts
+++ b/apps/web/app/api/store/route.ts
@@ -4,7 +4,7 @@ import { ensureAuth } from "../ensureAuth";
import { z } from "zod";
import { db } from "@/server/db";
import { contentToSpace, space, storedContent } from "@/server/db/schema";
-import { and, eq, inArray } from "drizzle-orm";
+import { and, eq, gt, inArray, sql } from "drizzle-orm";
import { LIMITS } from "@/lib/constants";
import { limit } from "@/app/actions/doers";
@@ -22,6 +22,24 @@ const createMemoryFromAPI = async (input: {
};
}
+ // Get number of items saved in the last 2 hours
+ const last2Hours = new Date(Date.now() - 2 * 60 * 60 * 1000);
+
+ const numberOfItemsSavedInLast2Hours = await db
+ .select({
+ count: sql<number>`count(*)`.mapWith(Number),
+ })
+ .from(storedContent)
+ .where(and(gt(storedContent.savedAt, last2Hours), eq(storedContent.userId, input.userId)))
+
+ if (numberOfItemsSavedInLast2Hours[0]!.count >= 20) {
+ return {
+ success: false,
+ data: 0,
+ error: `You have exceeded the limit`,
+ };
+ }
+
const vectorSaveResponse = await fetch(
`${process.env.BACKEND_BASE_URL}/api/add`,
{
diff --git a/apps/web/cf-env.d.ts b/apps/web/cf-env.d.ts
index 7381d63e..ecf8f6a9 100644
--- a/apps/web/cf-env.d.ts
+++ b/apps/web/cf-env.d.ts
@@ -19,6 +19,10 @@ declare global {
CLOUDFLARE_D1_TOKEN: string;
MOBILE_TRUST_TOKEN: string;
+
+ RATELIMITER: {
+ limit: ({key: string}) => {success: boolean}
+ };
}
}
}
diff --git a/apps/web/migrations/0000_setup.sql b/apps/web/migrations/0000_setup.sql
deleted file mode 100644
index 65a41795..00000000
--- a/apps/web/migrations/0000_setup.sql
+++ /dev/null
@@ -1,133 +0,0 @@
-CREATE TABLE `account` (
- `userId` text NOT NULL,
- `type` text NOT NULL,
- `provider` text NOT NULL,
- `providerAccountId` text NOT NULL,
- `refresh_token` text,
- `access_token` text,
- `expires_at` integer,
- `token_type` text,
- `scope` text,
- `id_token` text,
- `session_state` text,
- PRIMARY KEY(`provider`, `providerAccountId`),
- FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
-);
---> statement-breakpoint
-CREATE TABLE `authenticator` (
- `credentialID` text NOT NULL,
- `userId` text NOT NULL,
- `providerAccountId` text NOT NULL,
- `credentialPublicKey` text NOT NULL,
- `counter` integer NOT NULL,
- `credentialDeviceType` text NOT NULL,
- `credentialBackedUp` integer NOT NULL,
- `transports` text,
- PRIMARY KEY(`credentialID`, `userId`),
- FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
-);
---> statement-breakpoint
-CREATE TABLE `canvas` (
- `id` text PRIMARY KEY NOT NULL,
- `title` text DEFAULT 'Untitled' NOT NULL,
- `description` text DEFAULT 'Untitled' NOT NULL,
- `url` text DEFAULT '' NOT NULL,
- `userId` text NOT NULL,
- FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
-);
---> statement-breakpoint
-CREATE TABLE `chatHistory` (
- `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
- `threadId` text NOT NULL,
- `question` text NOT NULL,
- `answerParts` text,
- `answerSources` text,
- `answerJustification` text,
- FOREIGN KEY (`threadId`) REFERENCES `chatThread`(`id`) ON UPDATE no action ON DELETE cascade
-);
---> statement-breakpoint
-CREATE TABLE `chatThread` (
- `id` text PRIMARY KEY NOT NULL,
- `firstMessage` text NOT NULL,
- `userId` text NOT NULL,
- FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
-);
---> statement-breakpoint
-CREATE TABLE `contentToSpace` (
- `contentId` integer NOT NULL,
- `spaceId` integer NOT NULL,
- PRIMARY KEY(`contentId`, `spaceId`),
- FOREIGN KEY (`contentId`) REFERENCES `storedContent`(`id`) ON UPDATE no action ON DELETE cascade,
- FOREIGN KEY (`spaceId`) REFERENCES `space`(`id`) ON UPDATE no action ON DELETE cascade
-);
---> statement-breakpoint
-CREATE TABLE `session` (
- `sessionToken` text PRIMARY KEY NOT NULL,
- `userId` text NOT NULL,
- `expires` integer NOT NULL,
- FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
-);
---> statement-breakpoint
-CREATE TABLE `space` (
- `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
- `name` text DEFAULT 'none' NOT NULL,
- `user` text(255),
- `createdAt` integer NOT NULL,
- `numItems` integer DEFAULT 0 NOT NULL,
- FOREIGN KEY (`user`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
-);
---> statement-breakpoint
-CREATE TABLE `spacesAccess` (
- `spaceId` integer NOT NULL,
- `userEmail` text NOT NULL,
- PRIMARY KEY(`spaceId`, `userEmail`),
- FOREIGN KEY (`spaceId`) REFERENCES `space`(`id`) ON UPDATE no action ON DELETE cascade
-);
---> statement-breakpoint
-CREATE TABLE `storedContent` (
- `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
- `content` text NOT NULL,
- `title` text(255),
- `description` text(255),
- `url` text NOT NULL,
- `savedAt` integer NOT NULL,
- `baseUrl` text(255),
- `ogImage` text(255),
- `type` text DEFAULT 'page',
- `image` text(255),
- `user` text,
- `noteId` integer,
- FOREIGN KEY (`user`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
-);
---> statement-breakpoint
-CREATE TABLE `user` (
- `id` text PRIMARY KEY NOT NULL,
- `name` text,
- `email` text NOT NULL,
- `emailVerified` integer,
- `image` text,
- `telegramId` text
-);
---> statement-breakpoint
-CREATE TABLE `verificationToken` (
- `identifier` text NOT NULL,
- `token` text NOT NULL,
- `expires` integer NOT NULL,
- PRIMARY KEY(`identifier`, `token`)
-);
---> statement-breakpoint
-CREATE UNIQUE INDEX `authenticator_credentialID_unique` ON `authenticator` (`credentialID`);--> statement-breakpoint
-CREATE INDEX `canvas_user_userId` ON `canvas` (`userId`);--> statement-breakpoint
-CREATE INDEX `chatHistory_thread_idx` ON `chatHistory` (`threadId`);--> statement-breakpoint
-CREATE INDEX `chatThread_user_idx` ON `chatThread` (`userId`);--> statement-breakpoint
-CREATE UNIQUE INDEX `space_name_unique` ON `space` (`name`);--> statement-breakpoint
-CREATE INDEX `spaces_name_idx` ON `space` (`name`);--> statement-breakpoint
-CREATE INDEX `spaces_user_idx` ON `space` (`user`);--> statement-breakpoint
-CREATE UNIQUE INDEX `storedContent_baseUrl_unique` ON `storedContent` (`baseUrl`);--> statement-breakpoint
-CREATE INDEX `storedContent_url_idx` ON `storedContent` (`url`);--> statement-breakpoint
-CREATE INDEX `storedContent_savedAt_idx` ON `storedContent` (`savedAt`);--> statement-breakpoint
-CREATE INDEX `storedContent_title_idx` ON `storedContent` (`title`);--> statement-breakpoint
-CREATE INDEX `storedContent_user_idx` ON `storedContent` (`user`);--> statement-breakpoint
-CREATE INDEX `users_email_idx` ON `user` (`email`);--> statement-breakpoint
-CREATE INDEX `users_telegram_idx` ON `user` (`telegramId`);--> statement-breakpoint
-CREATE INDEX `users_id_idx` ON `user` (`id`); \ No newline at end of file
diff --git a/apps/web/migrations/0001_dear_sally_floyd.sql b/apps/web/migrations/0001_dear_sally_floyd.sql
deleted file mode 100644
index 8fa112f7..00000000
--- a/apps/web/migrations/0001_dear_sally_floyd.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE `user` ADD `hasOnboarded` integer DEFAULT false; \ No newline at end of file
diff --git a/apps/web/migrations/0003_organic_pet_avengers.sql b/apps/web/migrations/0003_organic_pet_avengers.sql
new file mode 100644
index 00000000..8479daf3
--- /dev/null
+++ b/apps/web/migrations/0003_organic_pet_avengers.sql
@@ -0,0 +1 @@
+ALTER TABLE `chatHistory` ADD `createdAt` integer DEFAULT '"2024-07-25T16:09:15.141Z"' NOT NULL; \ No newline at end of file
diff --git a/apps/web/migrations/meta/0003_snapshot.json b/apps/web/migrations/meta/0003_snapshot.json
new file mode 100644
index 00000000..143c575c
--- /dev/null
+++ b/apps/web/migrations/meta/0003_snapshot.json
@@ -0,0 +1,911 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "492c2aac-d922-4743-8c7f-079ef007a759",
+ "prevId": "1f43694b-f42b-4074-876e-8501fc18bf38",
+ "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
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false,
+ "default": "'\"2024-07-25T16:09:15.141Z\"'"
+ }
+ },
+ "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 ba09e752..1790f1ba 100644
--- a/apps/web/migrations/meta/_journal.json
+++ b/apps/web/migrations/meta/_journal.json
@@ -6,7 +6,7 @@
"idx": 0,
"version": "6",
"when": 1721746132570,
- "tag": "0000_silky_havok",
+ "tag": "0000_setup",
"breakpoints": true
},
{
@@ -15,6 +15,20 @@
"when": 1721775651258,
"tag": "0001_dear_sally_floyd",
"breakpoints": true
+ },
+ {
+ "idx": 2,
+ "version": "6",
+ "when": 1721923624746,
+ "tag": "0002_giant_vin_gonzales",
+ "breakpoints": true
+ },
+ {
+ "idx": 3,
+ "version": "6",
+ "when": 1721923755148,
+ "tag": "0003_organic_pet_avengers",
+ "breakpoints": true
}
]
} \ No newline at end of file
diff --git a/apps/web/server/db/schema.ts b/apps/web/server/db/schema.ts
index 8486c788..35267eb8 100644
--- a/apps/web/server/db/schema.ts
+++ b/apps/web/server/db/schema.ts
@@ -1,3 +1,4 @@
+import { create } from "domain";
import { relations, sql } from "drizzle-orm";
import {
index,
@@ -211,6 +212,7 @@ export const chatHistory = createTable(
answer: text("answerParts"), // Single answer part as string
answerSources: text("answerSources"), // JSON stringified array of objects
answerJustification: text("answerJustification"),
+ createdAt: int("createdAt", { mode: "timestamp" }).notNull().default(new Date()),
},
(history) => ({
threadIdx: index("chatHistory_thread_idx").on(history.threadId),
diff --git a/package.json b/package.json
index 5a11d364..e10119d7 100644
--- a/package.json
+++ b/package.json
@@ -1,126 +1,126 @@
{
- "name": "supermemory-ai",
- "private": true,
- "type": "module",
- "scripts": {
- "build": "turbo build",
- "dev": "turbo dev",
- "lint": "turbo lint",
- "format": "prettier --write \"**/*.{ts,tsx,md}\"",
- "deploy": "turbo deploy"
- },
- "devDependencies": {
- "@clack/prompts": "^0.7.0",
- "@cloudflare/next-on-pages": "1",
- "@cloudflare/workers-types": "^4.20240614.0",
- "@repo/eslint-config": "*",
- "@repo/shared-types": "*",
- "@repo/tailwind-config": "*",
- "@repo/typescript-config": "*",
- "@repo/ui": "*",
- "@tailwindcss/typography": "^0.5.13",
- "@types/turndown": "^5.0.4",
- "autoprefixer": "^10.4.19",
- "drizzle-kit": "0.21.2",
- "eslint-plugin-next-on-pages": "^1.11.3",
- "lint-staged": "^15.2.5",
- "postcss": "^8.4.38",
- "prettier": "^3.3.3",
- "readline-sync": "^1.4.10",
- "tailwindcss": "^3.4.3",
- "tailwindcss-animate": "^1.0.7",
- "turbo": "2.0.3",
- "vercel": "^34.2.0"
- },
- "engines": {
- "node": ">=18"
- },
- "packageManager": "[email protected]",
- "workspaces": [
- "apps/*",
- "packages/*"
- ],
- "dependencies": {
- "@ai-sdk/anthropic": "^0.0.15",
- "@ai-sdk/google": "^0.0.15",
- "@ai-sdk/openai": "^0.0.14",
- "@auth/drizzle-adapter": "^1.1.0",
- "@aws-sdk/client-s3": "^3.577.0",
- "@aws-sdk/s3-request-presigner": "^3.577.0",
- "@babel/plugin-transform-runtime": "^7.24.7",
- "@cloudflare/puppeteer": "^0.0.11",
- "@headlessui/react": "^2.0.4",
- "@heroicons/react": "^2.1.4",
- "@hono/swagger-ui": "^0.2.2",
- "@hookform/resolvers": "^3.4.2",
- "@iarna/toml": "^2.2.5",
- "@langchain/cloudflare": "^0.0.6",
- "@million/lint": "^1.0.0-rc.81",
- "@mozilla/readability": "^0.5.0",
- "@radix-ui/react-accordion": "^1.1.2",
- "@radix-ui/react-dropdown-menu": "^2.1.1",
- "@radix-ui/react-icons": "^1.3.0",
- "@radix-ui/react-label": "^2.0.2",
- "@radix-ui/react-popover": "^1.1.1",
- "@radix-ui/react-progress": "^1.0.3",
- "@radix-ui/react-scroll-area": "^1.0.5",
- "@radix-ui/react-select": "^2.0.0",
- "@radix-ui/react-separator": "^1.0.3",
- "@radix-ui/react-slot": "^1.1.0",
- "@radix-ui/react-switch": "^1.1.0",
- "@radix-ui/react-tabs": "^1.0.4",
- "@radix-ui/react-toast": "^1.1.5",
- "@radix-ui/react-tooltip": "^1.1.2",
- "@tldraw/assets": "^2.2.0",
- "@types/jsonwebtoken": "^9.0.6",
- "@types/react-responsive-masonry": "^2.1.3",
- "@types/readline-sync": "^1.4.8",
- "ai": "^3.1.14",
- "aws4fetch": "^1.0.18",
- "cheerio": "^1.0.0-rc.12",
- "compromise": "^14.13.0",
- "crypto-browserify": "^3.12.0",
- "drizzle-orm": "0.30.0",
- "eslint-config-turbo": "^2.0.6",
- "framer-motion": "^11.2.6",
- "geist": "^1.3.0",
- "google-auth-library": "^9.11.0",
- "grammy": "^1.25.1",
- "http": "^0.0.1-security",
- "https": "^1.0.0",
- "jsonwebtoken": "^9.0.2",
- "katex": "^0.16.10",
- "lucide-react": "^0.379.0",
- "million": "^3.1.11",
- "next-app-theme": "^0.1.10",
- "next-auth": "^5.0.0-beta.18",
- "next-themes": "^0.3.0",
- "random-js": "^2.1.0",
- "react-dropzone": "^14.2.3",
- "react-hook-form": "^7.51.5",
- "react-layout-masonry": "^1.1.0",
- "react-markdown": "^9.0.1",
- "react-responsive-masonry": "^2.2.1",
- "react-tweet": "^3.2.1",
- "react-use-measure": "^2.1.1",
- "react-web-share": "^2.0.2",
- "rehype-highlight": "^7.0.0",
- "rehype-katex": "^7.0.0",
- "remark-gfm": "^4.0.0",
- "remark-math": "^6.0.0",
- "sonner": "^1.5.0",
- "tailwind-scrollbar": "^3.1.0",
- "tldraw": "^2.1.4",
- "turndown": "^7.2.0",
- "uploadthing": "^6.10.4",
- "vaul": "^0.9.1",
- "zod": "^3.23.8"
- },
- "trustedDependencies": [
- "core-js-pure",
- "es5-ext"
- ],
- "lint-staged": {
- "**/*": "prettier --write --ignore-unknown"
- }
+ "name": "supermemory-ai",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "build": "turbo build",
+ "dev": "turbo dev",
+ "lint": "turbo lint",
+ "format": "prettier --write \"**/*.{ts,tsx,md}\"",
+ "deploy": "turbo deploy"
+ },
+ "devDependencies": {
+ "@clack/prompts": "^0.7.0",
+ "@cloudflare/next-on-pages": "1",
+ "@cloudflare/workers-types": "^4.20240614.0",
+ "@repo/eslint-config": "*",
+ "@repo/shared-types": "*",
+ "@repo/tailwind-config": "*",
+ "@repo/typescript-config": "*",
+ "@repo/ui": "*",
+ "@tailwindcss/typography": "^0.5.13",
+ "@types/turndown": "^5.0.4",
+ "autoprefixer": "^10.4.19",
+ "drizzle-kit": "0.21.2",
+ "eslint-plugin-next-on-pages": "^1.11.3",
+ "lint-staged": "^15.2.5",
+ "postcss": "^8.4.38",
+ "prettier": "^3.3.3",
+ "readline-sync": "^1.4.10",
+ "tailwindcss": "^3.4.3",
+ "tailwindcss-animate": "^1.0.7",
+ "turbo": "2.0.3",
+ "vercel": "^34.2.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "packageManager": "[email protected]",
+ "workspaces": [
+ "apps/*",
+ "packages/*"
+ ],
+ "dependencies": {
+ "@ai-sdk/anthropic": "^0.0.15",
+ "@ai-sdk/google": "^0.0.15",
+ "@ai-sdk/openai": "^0.0.14",
+ "@auth/drizzle-adapter": "^1.1.0",
+ "@aws-sdk/client-s3": "^3.577.0",
+ "@aws-sdk/s3-request-presigner": "^3.577.0",
+ "@babel/plugin-transform-runtime": "^7.24.7",
+ "@cloudflare/puppeteer": "^0.0.11",
+ "@headlessui/react": "^2.0.4",
+ "@heroicons/react": "^2.1.4",
+ "@hono/swagger-ui": "^0.2.2",
+ "@hookform/resolvers": "^3.4.2",
+ "@iarna/toml": "^2.2.5",
+ "@langchain/cloudflare": "^0.0.6",
+ "@million/lint": "^1.0.0-rc.81",
+ "@mozilla/readability": "^0.5.0",
+ "@radix-ui/react-accordion": "^1.1.2",
+ "@radix-ui/react-dropdown-menu": "^2.1.1",
+ "@radix-ui/react-icons": "^1.3.0",
+ "@radix-ui/react-label": "^2.0.2",
+ "@radix-ui/react-popover": "^1.1.1",
+ "@radix-ui/react-progress": "^1.0.3",
+ "@radix-ui/react-scroll-area": "^1.0.5",
+ "@radix-ui/react-select": "^2.0.0",
+ "@radix-ui/react-separator": "^1.0.3",
+ "@radix-ui/react-slot": "^1.1.0",
+ "@radix-ui/react-switch": "^1.1.0",
+ "@radix-ui/react-tabs": "^1.0.4",
+ "@radix-ui/react-toast": "^1.1.5",
+ "@radix-ui/react-tooltip": "^1.1.2",
+ "@tldraw/assets": "^2.2.0",
+ "@types/jsonwebtoken": "^9.0.6",
+ "@types/react-responsive-masonry": "^2.1.3",
+ "@types/readline-sync": "^1.4.8",
+ "ai": "^3.1.14",
+ "aws4fetch": "^1.0.18",
+ "cheerio": "^1.0.0-rc.12",
+ "compromise": "^14.13.0",
+ "crypto-browserify": "^3.12.0",
+ "drizzle-orm": "0.30.0",
+ "eslint-config-turbo": "^2.0.6",
+ "framer-motion": "^11.2.6",
+ "geist": "^1.3.0",
+ "google-auth-library": "^9.11.0",
+ "grammy": "^1.25.1",
+ "http": "^0.0.1-security",
+ "https": "^1.0.0",
+ "jsonwebtoken": "^9.0.2",
+ "katex": "^0.16.10",
+ "lucide-react": "^0.379.0",
+ "million": "^3.1.11",
+ "next-app-theme": "^0.1.10",
+ "next-auth": "^5.0.0-beta.18",
+ "next-themes": "^0.3.0",
+ "random-js": "^2.1.0",
+ "react-dropzone": "^14.2.3",
+ "react-hook-form": "^7.51.5",
+ "react-layout-masonry": "^1.1.0",
+ "react-markdown": "^9.0.1",
+ "react-responsive-masonry": "^2.2.1",
+ "react-tweet": "^3.2.1",
+ "react-use-measure": "^2.1.1",
+ "react-web-share": "^2.0.2",
+ "rehype-highlight": "^7.0.0",
+ "rehype-katex": "^7.0.0",
+ "remark-gfm": "^4.0.0",
+ "remark-math": "^6.0.0",
+ "sonner": "^1.5.0",
+ "tailwind-scrollbar": "^3.1.0",
+ "tldraw": "^2.1.4",
+ "turndown": "^7.2.0",
+ "uploadthing": "^6.10.4",
+ "vaul": "^0.9.1",
+ "zod": "^3.23.8"
+ },
+ "trustedDependencies": [
+ "core-js-pure",
+ "es5-ext"
+ ],
+ "lint-staged": {
+ "**/*": "prettier --write --ignore-unknown"
+ }
}