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 /apps | |
| parent | merge oopsies (diff) | |
| download | supermemory-18dd5e4fd0355631dead478ca207cad13f410d0f.tar.xz supermemory-18dd5e4fd0355631dead478ca207cad13f410d0f.zip | |
onboarding page changes and ratelimiting
Diffstat (limited to 'apps')
| -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 |
12 files changed, 1003 insertions, 139 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), |