diff options
| author | Dhravya Shah <[email protected]> | 2024-07-25 17:30:23 -0500 |
|---|---|---|
| committer | Dhravya Shah <[email protected]> | 2024-07-25 17:30:23 -0500 |
| commit | 18dd5e4fd0355631dead478ca207cad13f410d0f (patch) | |
| tree | c7bdb441375e590d9266dec36d0389c2d97677fd | |
| parent | merge oopsies (diff) | |
| download | supermemory-18dd5e4fd0355631dead478ca207cad13f410d0f.tar.xz supermemory-18dd5e4fd0355631dead478ca207cad13f410d0f.zip | |
onboarding page changes and ratelimiting
| -rw-r--r-- | apps/extension/manifest.json | 2 | ||||
| -rw-r--r-- | apps/web/app/(auth)/onboarding/page.tsx | 4 | ||||
| -rw-r--r-- | apps/web/app/actions/doers.ts | 1 | ||||
| -rw-r--r-- | apps/web/app/api/chat/route.ts | 47 | ||||
| -rw-r--r-- | apps/web/app/api/store/route.ts | 20 | ||||
| -rw-r--r-- | apps/web/cf-env.d.ts | 4 | ||||
| -rw-r--r-- | apps/web/migrations/0000_setup.sql | 133 | ||||
| -rw-r--r-- | apps/web/migrations/0001_dear_sally_floyd.sql | 1 | ||||
| -rw-r--r-- | apps/web/migrations/0003_organic_pet_avengers.sql | 1 | ||||
| -rw-r--r-- | apps/web/migrations/meta/0003_snapshot.json | 911 | ||||
| -rw-r--r-- | apps/web/migrations/meta/_journal.json | 16 | ||||
| -rw-r--r-- | apps/web/server/db/schema.ts | 2 | ||||
| -rw-r--r-- | package.json | 248 |
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" + } } |