feat: v1 — persistent shell, model gateway, artifact improvements (#1462)

This commit is contained in:
dancer 2026-03-20 09:37:02 +00:00 committed by GitHub
parent 3651670fb9
commit f9652b452a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
161 changed files with 5166 additions and 8009 deletions

View file

@ -1,25 +1,14 @@
import type { UserType } from "@/lib/auth";
import type { UserType } from "@/app/(auth)/auth";
type Entitlements = {
maxMessagesPerHour: number;
};
export const entitlementsByUserType: Record<UserType, Entitlements> = {
/*
* For users without an account
*/
guest: {
maxMessagesPerHour: 10,
},
/*
* For users with an account
*/
regular: {
maxMessagesPerHour: 10,
},
/*
* TODO: For users with an account and a paid membership
*/
};

View file

@ -73,54 +73,6 @@ const createMockModel = (): LanguageModel => {
} as unknown as LanguageModel;
};
const createMockReasoningModel = (): LanguageModel => {
return {
specificationVersion: "v3",
provider: "mock",
modelId: "mock-reasoning-model",
defaultObjectGenerationMode: "tool",
supportedUrls: {},
doGenerate: async () => ({
finishReason: "stop",
usage: mockUsage,
content: [{ type: "text", text: "This is a reasoned response." }],
reasoning: [
{ type: "text", text: "Let me think through this step by step..." },
],
warnings: [],
}),
doStream: () => ({
stream: new ReadableStream({
async start(controller) {
controller.enqueue({ type: "reasoning-start", id: "r1" });
controller.enqueue({
type: "reasoning-delta",
id: "r1",
delta: "Let me think through this step by step... ",
});
controller.enqueue({ type: "reasoning-end", id: "r1" });
await new Promise((resolve) => {
setTimeout(resolve, 10);
});
controller.enqueue({ type: "text-start", id: "t1" });
controller.enqueue({
type: "text-delta",
id: "t1",
delta: "This is a reasoned response.",
});
controller.enqueue({ type: "text-end", id: "t1" });
controller.enqueue({
type: "finish",
finishReason: "stop",
usage: mockUsage,
});
controller.close();
},
}),
}),
} as unknown as LanguageModel;
};
const createMockTitleModel = (): LanguageModel => {
return {
specificationVersion: "v3",
@ -168,6 +120,4 @@ const createMockTitleModel = (): LanguageModel => {
};
export const chatModel = createMockModel();
export const reasoningModel = createMockReasoningModel();
export const titleModel = createMockTitleModel();
export const artifactModel = createMockModel();

View file

@ -1,3 +1,4 @@
import type { LanguageModelV3GenerateResult } from "@ai-sdk/provider";
import { simulateReadableStream } from "ai";
import { MockLanguageModelV3 } from "ai/test";
import { getResponseChunksByPrompt } from "@/tests/prompts/utils";
@ -7,13 +8,24 @@ const mockUsage = {
outputTokens: { total: 20, text: 20, reasoning: 0 },
};
const mockFinishReason = { unified: "stop" as const, raw: undefined };
const mockGenerateResult: LanguageModelV3GenerateResult = {
finishReason: mockFinishReason,
usage: mockUsage,
content: [{ type: "text", text: "Hello, world!" }],
warnings: [],
};
const titleGenerateResult: LanguageModelV3GenerateResult = {
finishReason: mockFinishReason,
usage: mockUsage,
content: [{ type: "text", text: "This is a test title" }],
warnings: [],
};
export const chatModel = new MockLanguageModelV3({
doGenerate: async () => ({
finishReason: "stop",
usage: mockUsage,
content: [{ type: "text", text: "Hello, world!" }],
warnings: [],
}),
doGenerate: mockGenerateResult,
doStream: async ({ prompt }) => ({
stream: simulateReadableStream({
chunkDelayInMs: 500,
@ -24,12 +36,7 @@ export const chatModel = new MockLanguageModelV3({
});
export const reasoningModel = new MockLanguageModelV3({
doGenerate: async () => ({
finishReason: "stop",
usage: mockUsage,
content: [{ type: "text", text: "Hello, world!" }],
warnings: [],
}),
doGenerate: mockGenerateResult,
doStream: async ({ prompt }) => ({
stream: simulateReadableStream({
chunkDelayInMs: 500,
@ -40,42 +47,21 @@ export const reasoningModel = new MockLanguageModelV3({
});
export const titleModel = new MockLanguageModelV3({
doGenerate: async () => ({
finishReason: "stop",
usage: mockUsage,
content: [{ type: "text", text: "This is a test title" }],
warnings: [],
}),
doGenerate: titleGenerateResult,
doStream: async () => ({
stream: simulateReadableStream({
chunkDelayInMs: 500,
initialDelayInMs: 1000,
chunks: [
{ id: "1", type: "text-start" },
{ id: "1", type: "text-delta", delta: "This is a test title" },
{ id: "1", type: "text-end" },
{ id: "1", type: "text-start" as const },
{ id: "1", type: "text-delta" as const, delta: "This is a test title" },
{ id: "1", type: "text-end" as const },
{
type: "finish",
finishReason: "stop",
type: "finish" as const,
finishReason: mockFinishReason,
usage: mockUsage,
},
],
}),
}),
});
export const artifactModel = new MockLanguageModelV3({
doGenerate: async () => ({
finishReason: "stop",
usage: mockUsage,
content: [{ type: "text", text: "Hello, world!" }],
warnings: [],
}),
doStream: async ({ prompt }) => ({
stream: simulateReadableStream({
chunkDelayInMs: 50,
initialDelayInMs: 100,
chunks: getResponseChunksByPrompt(prompt),
}),
}),
});

View file

@ -1,70 +1,179 @@
// Curated list of top models from Vercel AI Gateway
export const DEFAULT_CHAT_MODEL = "openai/gpt-4.1-mini";
export const DEFAULT_CHAT_MODEL = "moonshotai/kimi-k2-0905";
export const titleModel = {
id: "mistral/mistral-small",
name: "Mistral Small",
provider: "mistral",
description: "Fast model for title generation",
gatewayOrder: ["mistral"],
};
export type ModelCapabilities = {
tools: boolean;
vision: boolean;
reasoning: boolean;
};
export type ChatModel = {
id: string;
name: string;
provider: string;
description: string;
gatewayOrder?: string[];
reasoningEffort?: "none" | "minimal" | "low" | "medium" | "high";
};
export const chatModels: ChatModel[] = [
// Anthropic
{
id: "anthropic/claude-haiku-4.5",
name: "Claude Haiku 4.5",
provider: "anthropic",
description: "Fast and affordable, great for everyday tasks",
id: "deepseek/deepseek-v3.2",
name: "DeepSeek V3.2",
provider: "deepseek",
description: "Fast and capable model with tool use",
gatewayOrder: ["bedrock", "deepinfra"],
},
// OpenAI
{
id: "openai/gpt-4.1-mini",
name: "GPT-4.1 Mini",
id: "mistral/codestral",
name: "Codestral",
provider: "mistral",
description: "Code-focused model with tool use",
gatewayOrder: ["mistral"],
},
{
id: "mistral/mistral-small",
name: "Mistral Small",
provider: "mistral",
description: "Fast vision model with tool use",
gatewayOrder: ["mistral"],
},
{
id: "moonshotai/kimi-k2-0905",
name: "Kimi K2 0905",
provider: "moonshotai",
description: "Fast model with tool use",
gatewayOrder: ["baseten", "fireworks"],
},
{
id: "moonshotai/kimi-k2.5",
name: "Kimi K2.5",
provider: "moonshotai",
description: "Moonshot AI flagship model",
gatewayOrder: ["fireworks", "bedrock"],
},
{
id: "openai/gpt-oss-20b",
name: "GPT OSS 20B",
provider: "openai",
description: "Fast and cost-effective for simple tasks",
description: "Compact reasoning model",
gatewayOrder: ["groq", "bedrock"],
reasoningEffort: "low",
},
{
id: "openai/gpt-5-mini",
name: "GPT-5 Mini",
id: "openai/gpt-oss-120b",
name: "GPT OSS 120B",
provider: "openai",
description: "Most capable OpenAI model",
description: "Open-source 120B parameter model",
gatewayOrder: ["fireworks", "bedrock"],
reasoningEffort: "low",
},
// Google
{
id: "google/gemini-2.5-flash-lite",
name: "Gemini 2.5 Flash Lite",
provider: "google",
description: "Ultra fast and affordable",
},
{
id: "google/gemini-3-pro-preview",
name: "Gemini 3 Pro",
provider: "google",
description: "Most capable Google model",
},
// xAI
{
id: "xai/grok-4.1-fast-non-reasoning",
name: "Grok 4.1 Fast",
provider: "xai",
description: "Fast with 30K context",
},
// Reasoning models (extended thinking)
{
id: "anthropic/claude-3.7-sonnet-thinking",
name: "Claude 3.7 Sonnet",
provider: "reasoning",
description: "Extended thinking for complex problems",
},
{
id: "xai/grok-code-fast-1-thinking",
name: "Grok Code Fast",
provider: "reasoning",
description: "Reasoning optimized for code",
description: "Fast non-reasoning model with tool use",
gatewayOrder: ["xai"],
},
];
// Group models by provider for UI
export async function getCapabilities(): Promise<
Record<string, ModelCapabilities>
> {
const results = await Promise.all(
chatModels.map(async (model) => {
try {
const res = await fetch(
`https://ai-gateway.vercel.sh/v1/models/${model.id}/endpoints`,
{ next: { revalidate: 86_400 } }
);
if (!res.ok) {
return [model.id, { tools: false, vision: false, reasoning: false }];
}
const json = await res.json();
const endpoints = json.data?.endpoints ?? [];
const params = new Set(
endpoints.flatMap(
(e: { supported_parameters?: string[] }) =>
e.supported_parameters ?? []
)
);
const inputModalities = new Set(
json.data?.architecture?.input_modalities ?? []
);
return [
model.id,
{
tools: params.has("tools"),
vision: inputModalities.has("image"),
reasoning: params.has("reasoning"),
},
];
} catch {
return [model.id, { tools: false, vision: false, reasoning: false }];
}
})
);
return Object.fromEntries(results);
}
export const isDemo = process.env.IS_DEMO === "1";
type GatewayModel = {
id: string;
name: string;
type?: string;
tags?: string[];
};
export type GatewayModelWithCapabilities = ChatModel & {
capabilities: ModelCapabilities;
};
export async function getAllGatewayModels(): Promise<
GatewayModelWithCapabilities[]
> {
try {
const res = await fetch("https://ai-gateway.vercel.sh/v1/models", {
next: { revalidate: 86_400 },
});
if (!res.ok) {
return [];
}
const json = await res.json();
return (json.data ?? [])
.filter((m: GatewayModel) => m.type === "language")
.map((m: GatewayModel) => ({
id: m.id,
name: m.name,
provider: m.id.split("/")[0],
description: "",
capabilities: {
tools: m.tags?.includes("tool-use") ?? false,
vision: m.tags?.includes("vision") ?? false,
reasoning: m.tags?.includes("reasoning") ?? false,
},
}));
} catch {
return [];
}
}
export function getActiveModels(): ChatModel[] {
return chatModels;
}
export const allowedModelIds = new Set(chatModels.map((m) => m.id));
export const modelsByProvider = chatModels.reduce(

View file

@ -1,45 +1,52 @@
import type { Geo } from "@vercel/functions";
import type { ArtifactKind } from "@/components/artifact";
import type { ArtifactKind } from "@/components/chat/artifact";
export const artifactsPrompt = `
Artifacts is a special user interface mode that helps users with writing, editing, and other content creation tasks. When artifact is open, it is on the right side of the screen, while the conversation is on the left side. When creating or updating documents, changes are reflected in real-time on the artifacts and visible to the user.
Artifacts is a side panel that displays content alongside the conversation. It supports scripts (code), documents (text), and spreadsheets. Changes appear in real-time.
When asked to write code, always use artifacts. When writing code, specify the language in the backticks, e.g. \`\`\`python\`code here\`\`\`. The default language is Python. Other languages are not yet supported, so let the user know if they request a different language.
DO NOT UPDATE DOCUMENTS IMMEDIATELY AFTER CREATING THEM. WAIT FOR USER FEEDBACK OR REQUEST TO UPDATE IT.
This is a guide for using artifacts tools: \`createDocument\` and \`updateDocument\`, which render content on a artifacts beside the conversation.
CRITICAL RULES:
1. Only call ONE tool per response. After calling any create/edit/update tool, STOP. Do not chain tools.
2. After creating or editing an artifact, NEVER output its content in chat. The user can already see it. Respond with only a 1-2 sentence confirmation.
**When to use \`createDocument\`:**
- For substantial content (>10 lines) or code
- For content users will likely save/reuse (emails, code, essays, etc.)
- When explicitly requested to create a document
- For when content contains a single code snippet
- When the user asks to write, create, or generate content (essays, stories, emails, reports)
- When the user asks to write code, build a script, or implement an algorithm
- You MUST specify kind: 'code' for programming, 'text' for writing, 'sheet' for data
- Include ALL content in the createDocument call. Do not create then edit.
**When NOT to use \`createDocument\`:**
- For informational/explanatory content
- For conversational responses
- When asked to keep it in chat
- For answering questions, explanations, or conversational responses
- For short code snippets or examples shown inline
- When the user asks "what is", "how does", "explain", etc.
**Using \`updateDocument\`:**
- Default to full document rewrites for major changes
- Use targeted updates only for specific, isolated changes
- Follow user instructions for which parts to modify
**Using \`editDocument\` (preferred for targeted changes):**
- For scripts: fixing bugs, adding/removing lines, renaming variables, adding logs
- For documents: fixing typos, rewording paragraphs, inserting sections
- Uses find-and-replace: provide exact old_string and new_string
- Include 3-5 surrounding lines in old_string to ensure a unique match
- Use replace_all:true for renaming across the whole artifact
- Can call multiple times for several independent edits
**When NOT to use \`updateDocument\`:**
- Immediately after creating a document
**Using \`updateDocument\` (full rewrite only):**
- Only when most of the content needs to change
- When editDocument would require too many individual edits
Do not update document right after creating it. Wait for user feedback or request to update it.
**When NOT to use \`editDocument\` or \`updateDocument\`:**
- Immediately after creating an artifact
- In the same response as createDocument
- Without explicit user request to modify
**After any create/edit/update:**
- NEVER repeat, summarize, or output the artifact content in chat
- Only respond with a short confirmation
**Using \`requestSuggestions\`:**
- ONLY use when the user explicitly asks for suggestions on an existing document
- Requires a valid document ID from a previously created document
- Never use for general questions or information requests
- ONLY when the user explicitly asks for suggestions on an existing document
`;
export const regularPrompt = `You are a friendly assistant! Keep your responses concise and helpful.
export const regularPrompt = `You are a helpful assistant. Keep responses concise and direct.
When asked to write, create, or help with something, just do it directly. Don't ask clarifying questions unless absolutely necessary - make reasonable assumptions and proceed with the task.`;
When asked to write, create, or build something, do it immediately. Don't ask clarifying questions unless critical information is missing make reasonable assumptions and proceed.`;
export type RequestHints = {
latitude: Geo["latitude"];
@ -57,19 +64,15 @@ About the origin of user's request:
`;
export const systemPrompt = ({
selectedChatModel,
requestHints,
supportsTools,
}: {
selectedChatModel: string;
requestHints: RequestHints;
supportsTools: boolean;
}) => {
const requestPrompt = getRequestPromptFromHints(requestHints);
// reasoning models don't need artifacts prompt (they can't use tools)
if (
selectedChatModel.includes("reasoning") ||
selectedChatModel.includes("thinking")
) {
if (!supportsTools) {
return `${regularPrompt}\n\n${requestPrompt}`;
}
@ -77,48 +80,40 @@ export const systemPrompt = ({
};
export const codePrompt = `
You are a Python code generator that creates self-contained, executable code snippets. When writing code:
You are a code generator that creates self-contained, executable code snippets. When writing code:
1. Each snippet should be complete and runnable on its own
2. Prefer using print() statements to display outputs
3. Include helpful comments explaining the code
4. Keep snippets concise (generally under 15 lines)
5. Avoid external dependencies - use Python standard library
6. Handle potential errors gracefully
7. Return meaningful output that demonstrates the code's functionality
8. Don't use input() or other interactive functions
9. Don't access files or network resources
10. Don't use infinite loops
Examples of good snippets:
# Calculate factorial iteratively
def factorial(n):
result = 1
for i in range(1, n + 1):
result *= i
return result
print(f"Factorial of 5 is: {factorial(5)}")
1. Each snippet must be complete and runnable on its own
2. Use print/console.log to display outputs
3. Keep snippets concise and focused
4. Prefer standard library over external dependencies
5. Handle potential errors gracefully
6. Return meaningful output that demonstrates functionality
7. Don't use interactive input functions
8. Don't access files or network resources
9. Don't use infinite loops
`;
export const sheetPrompt = `
You are a spreadsheet creation assistant. Create a spreadsheet in csv format based on the given prompt. The spreadsheet should contain meaningful column headers and data.
You are a spreadsheet creation assistant. Create a spreadsheet in CSV format based on the given prompt.
Requirements:
- Use clear, descriptive column headers
- Include realistic sample data
- Format numbers and dates consistently
- Keep the data well-structured and meaningful
`;
export const updateDocumentPrompt = (
currentContent: string | null,
type: ArtifactKind
) => {
let mediaType = "document";
const mediaTypes: Record<string, string> = {
code: "script",
sheet: "spreadsheet",
};
const mediaType = mediaTypes[type] ?? "document";
if (type === "code") {
mediaType = "code snippet";
} else if (type === "sheet") {
mediaType = "spreadsheet";
}
return `Improve the following contents of the ${mediaType} based on the given prompt.
return `Rewrite the following ${mediaType} based on the given prompt.
${currentContent}`;
};
@ -133,7 +128,4 @@ Examples:
- "hi" New Conversation
- "debug my python code" Python Debugging
Bad outputs (never do this):
- "# Space Essay" (no hashtags)
- "Title: Weather" (no prefixes)
- ""NYC Weather"" (no quotes)`;
Never output hashtags, prefixes like "Title:", or quotes.`;

View file

@ -1,27 +1,14 @@
import { gateway } from "@ai-sdk/gateway";
import {
customProvider,
extractReasoningMiddleware,
wrapLanguageModel,
} from "ai";
import { customProvider, gateway } from "ai";
import { isTestEnvironment } from "../constants";
const THINKING_SUFFIX_REGEX = /-thinking$/;
import { titleModel } from "./models";
export const myProvider = isTestEnvironment
? (() => {
const {
artifactModel,
chatModel,
reasoningModel,
titleModel,
} = require("./models.mock");
const { chatModel, titleModel } = require("./models.mock");
return customProvider({
languageModels: {
"chat-model": chatModel,
"chat-model-reasoning": reasoningModel,
"title-model": titleModel,
"artifact-model": artifactModel,
},
});
})()
@ -32,19 +19,6 @@ export function getLanguageModel(modelId: string) {
return myProvider.languageModel(modelId);
}
const isReasoningModel =
modelId.endsWith("-thinking") ||
(modelId.includes("reasoning") && !modelId.includes("non-reasoning"));
if (isReasoningModel) {
const gatewayModelId = modelId.replace(THINKING_SUFFIX_REGEX, "");
return wrapLanguageModel({
model: gateway.languageModel(gatewayModelId),
middleware: extractReasoningMiddleware({ tagName: "thinking" }),
});
}
return gateway.languageModel(modelId);
}
@ -52,12 +26,5 @@ export function getTitleModel() {
if (isTestEnvironment && myProvider) {
return myProvider.languageModel("title-model");
}
return gateway.languageModel("google/gemini-2.5-flash-lite");
}
export function getArtifactModel() {
if (isTestEnvironment && myProvider) {
return myProvider.languageModel("artifact-model");
}
return gateway.languageModel("anthropic/claude-haiku-4.5");
return gateway.languageModel(titleModel.id);
}

View file

@ -1,25 +1,34 @@
import { tool, type UIMessageStreamWriter } from "ai";
import type { Session } from "next-auth";
import { z } from "zod";
import {
artifactKinds,
documentHandlersByArtifactKind,
} from "@/lib/artifacts/server";
import type { AuthSession } from "@/lib/auth";
import type { ChatMessage } from "@/lib/types";
import { generateUUID } from "@/lib/utils";
type CreateDocumentProps = {
session: NonNullable<AuthSession>;
session: Session;
dataStream: UIMessageStreamWriter<ChatMessage>;
modelId: string;
};
export const createDocument = ({ session, dataStream }: CreateDocumentProps) =>
export const createDocument = ({
session,
dataStream,
modelId,
}: CreateDocumentProps) =>
tool({
description:
"Create a document for a writing or content creation activities. This tool will call other functions that will generate the contents of the document based on the title and kind.",
"Create an artifact. You MUST specify kind: use 'code' for any programming/algorithm request (creates a script), 'text' for essays/writing (creates a document), 'sheet' for spreadsheets/data.",
inputSchema: z.object({
title: z.string(),
kind: z.enum(artifactKinds),
title: z.string().describe("The title of the artifact"),
kind: z
.enum(artifactKinds)
.describe(
"REQUIRED. 'code' for programming/algorithms, 'text' for essays/writing, 'sheet' for spreadsheets"
),
}),
execute: async ({ title, kind }) => {
const id = generateUUID();
@ -62,6 +71,7 @@ export const createDocument = ({ session, dataStream }: CreateDocumentProps) =>
title,
dataStream,
session,
modelId,
});
dataStream.write({ type: "data-finish", data: null, transient: true });
@ -70,7 +80,10 @@ export const createDocument = ({ session, dataStream }: CreateDocumentProps) =>
id,
title,
kind,
content: "A document was created and is now visible to the user.",
content:
kind === "code"
? "A script was created and is now visible to the user."
: "A document was created and is now visible to the user.",
};
},
});

View file

@ -0,0 +1,100 @@
import { tool, type UIMessageStreamWriter } from "ai";
import type { Session } from "next-auth";
import { z } from "zod";
import { getDocumentById, saveDocument } from "@/lib/db/queries";
import type { ChatMessage } from "@/lib/types";
type EditDocumentProps = {
session: Session;
dataStream: UIMessageStreamWriter<ChatMessage>;
};
export const editDocument = ({ session, dataStream }: EditDocumentProps) =>
tool({
description:
"Make a targeted edit to an existing artifact by finding and replacing an exact string. Preferred over updateDocument for small changes. The old_string must match exactly.",
inputSchema: z.object({
id: z.string().describe("The ID of the artifact to edit"),
old_string: z
.string()
.describe(
"Exact string to find. Include 3-5 surrounding lines for uniqueness."
),
new_string: z.string().describe("Replacement string"),
replace_all: z
.boolean()
.optional()
.describe(
"Replace all occurrences instead of just the first (default false)"
),
}),
execute: async ({ id, old_string, new_string, replace_all }) => {
const document = await getDocumentById({ id });
if (!document) {
return { error: "Document not found" };
}
if (document.userId !== session.user?.id) {
return { error: "Forbidden" };
}
if (!document.content) {
return { error: "Document has no content" };
}
if (!document.content.includes(old_string)) {
return { error: "old_string not found in document" };
}
const updated = replace_all
? document.content.replaceAll(old_string, new_string)
: document.content.replace(old_string, new_string);
await saveDocument({
id: document.id,
title: document.title,
kind: document.kind,
content: updated,
userId: document.userId,
});
dataStream.write({
type: "data-clear",
data: null,
transient: true,
});
if (document.kind === "code") {
dataStream.write({
type: "data-codeDelta",
data: updated,
transient: true,
});
} else if (document.kind === "sheet") {
dataStream.write({
type: "data-sheetDelta",
data: updated,
transient: true,
});
} else {
dataStream.write({
type: "data-textDelta",
data: updated,
transient: true,
});
}
dataStream.write({ type: "data-finish", data: null, transient: true });
return {
id,
title: document.title,
kind: document.kind,
content:
document.kind === "code"
? "The script has been edited successfully."
: "The document has been edited successfully.",
};
},
});

View file

@ -40,7 +40,6 @@ export const getWeather = tool({
.describe("City name (e.g., 'San Francisco', 'New York', 'London')")
.optional(),
}),
needsApproval: true,
execute: async (input) => {
let latitude: number;
let longitude: number;

View file

@ -1,20 +1,22 @@
import { Output, streamText, tool, type UIMessageStreamWriter } from "ai";
import type { Session } from "next-auth";
import { z } from "zod";
import type { AuthSession } from "@/lib/auth";
import { getDocumentById, saveSuggestions } from "@/lib/db/queries";
import type { Suggestion } from "@/lib/db/schema";
import type { ChatMessage } from "@/lib/types";
import { generateUUID } from "@/lib/utils";
import { getArtifactModel } from "../providers";
import { getLanguageModel } from "../providers";
type RequestSuggestionsProps = {
session: NonNullable<AuthSession>;
session: Session;
dataStream: UIMessageStreamWriter<ChatMessage>;
modelId: string;
};
export const requestSuggestions = ({
session,
dataStream,
modelId,
}: RequestSuggestionsProps) =>
tool({
description:
@ -35,15 +37,19 @@ export const requestSuggestions = ({
};
}
if (document.userId !== session.user?.id) {
return { error: "Forbidden" };
}
const suggestions: Omit<
Suggestion,
"userId" | "createdAt" | "documentCreatedAt"
>[] = [];
const { partialOutputStream } = streamText({
model: getArtifactModel(),
model: getLanguageModel(modelId),
system:
"You are a help writing assistant. Given a piece of writing, please offer suggestions to improve the piece of writing and describe the change. It is very important for the edits to contain full sentences instead of just words. Max 5 suggestions.",
"You are a writing assistant. Given a piece of writing, offer up to 5 suggestions to improve it. Each suggestion must contain full sentences, not just individual words. Describe what changed and why.",
prompt: document.content,
output: Output.array({
element: z.object({

View file

@ -1,22 +1,29 @@
import { tool, type UIMessageStreamWriter } from "ai";
import type { Session } from "next-auth";
import { z } from "zod";
import { documentHandlersByArtifactKind } from "@/lib/artifacts/server";
import type { AuthSession } from "@/lib/auth";
import { getDocumentById } from "@/lib/db/queries";
import type { ChatMessage } from "@/lib/types";
type UpdateDocumentProps = {
session: NonNullable<AuthSession>;
session: Session;
dataStream: UIMessageStreamWriter<ChatMessage>;
modelId: string;
};
export const updateDocument = ({ session, dataStream }: UpdateDocumentProps) =>
export const updateDocument = ({
session,
dataStream,
modelId,
}: UpdateDocumentProps) =>
tool({
description: "Update a document with the given description.",
description:
"Full rewrite of an existing artifact. Only use for major changes where most content needs replacing. Prefer editDocument for targeted changes.",
inputSchema: z.object({
id: z.string().describe("The ID of the document to update"),
id: z.string().describe("The ID of the artifact to rewrite"),
description: z
.string()
.default("Improve the content")
.describe("The description of changes that need to be made"),
}),
execute: async ({ id, description }) => {
@ -28,6 +35,10 @@ export const updateDocument = ({ session, dataStream }: UpdateDocumentProps) =>
};
}
if (document.userId !== session.user?.id) {
return { error: "Forbidden" };
}
dataStream.write({
type: "data-clear",
data: null,
@ -48,6 +59,7 @@ export const updateDocument = ({ session, dataStream }: UpdateDocumentProps) =>
description,
dataStream,
session,
modelId,
});
dataStream.write({ type: "data-finish", data: null, transient: true });
@ -56,7 +68,10 @@ export const updateDocument = ({ session, dataStream }: UpdateDocumentProps) =>
id,
title: document.title,
kind: document.kind,
content: "The document has been updated successfully.",
content:
document.kind === "code"
? "The script has been updated successfully."
: "The document has been updated successfully.",
};
},
});

View file

@ -1,9 +1,9 @@
import type { UIMessageStreamWriter } from "ai";
import type { Session } from "next-auth";
import { codeDocumentHandler } from "@/artifacts/code/server";
import { sheetDocumentHandler } from "@/artifacts/sheet/server";
import { textDocumentHandler } from "@/artifacts/text/server";
import type { ArtifactKind } from "@/components/artifact";
import type { AuthSession } from "@/lib/auth";
import type { ArtifactKind } from "@/components/chat/artifact";
import { saveDocument } from "../db/queries";
import type { Document } from "../db/schema";
import type { ChatMessage } from "../types";
@ -20,14 +20,16 @@ export type CreateDocumentCallbackProps = {
id: string;
title: string;
dataStream: UIMessageStreamWriter<ChatMessage>;
session: NonNullable<AuthSession>;
session: Session;
modelId: string;
};
export type UpdateDocumentCallbackProps = {
document: Document;
description: string;
dataStream: UIMessageStreamWriter<ChatMessage>;
session: NonNullable<AuthSession>;
session: Session;
modelId: string;
};
export type DocumentHandler<T = ArtifactKind> = {
@ -49,6 +51,7 @@ export function createDocumentHandler<T extends ArtifactKind>(config: {
title: args.title,
dataStream: args.dataStream,
session: args.session,
modelId: args.modelId,
});
if (args.session?.user?.id) {
@ -69,6 +72,7 @@ export function createDocumentHandler<T extends ArtifactKind>(config: {
description: args.description,
dataStream: args.dataStream,
session: args.session,
modelId: args.modelId,
});
if (args.session?.user?.id) {
@ -86,9 +90,6 @@ export function createDocumentHandler<T extends ArtifactKind>(config: {
};
}
/*
* Use this array to define the document handlers for each artifact kind.
*/
export const documentHandlersByArtifactKind: DocumentHandler[] = [
textDocumentHandler,
codeDocumentHandler,

View file

@ -1,58 +0,0 @@
import { compare, genSaltSync, hashSync } from "bcrypt-ts";
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { nextCookies } from "better-auth/next-js";
import { anonymous } from "better-auth/plugins";
import { drizzle } from "drizzle-orm/postgres-js";
import { headers } from "next/headers";
import postgres from "postgres";
import { account, session, user, verification } from "./db/schema";
// biome-ignore lint: Forbidden non-null assertion.
const client = postgres(process.env.POSTGRES_URL!);
const db = drizzle(client);
export const auth = betterAuth({
basePath: "/api/auth",
baseURL: process.env.BETTER_AUTH_URL,
database: drizzleAdapter(db, {
provider: "pg",
schema: { user, session, account, verification },
}),
emailAndPassword: {
enabled: true,
password: {
hash: async (password) => hashSync(password, genSaltSync(10)),
verify: async ({ hash, password }) => compare(password, hash),
},
},
...(process.env.VERCEL_CLIENT_ID && process.env.VERCEL_CLIENT_SECRET
? {
socialProviders: {
vercel: {
clientId: process.env.VERCEL_CLIENT_ID,
clientSecret: process.env.VERCEL_CLIENT_SECRET,
},
},
}
: {}),
advanced: {
database: {
generateId: () => crypto.randomUUID(),
},
},
plugins: [anonymous(), nextCookies()],
});
export type UserType = "guest" | "regular";
export function getUserType(user: Record<string, unknown>): UserType {
return (user as { isAnonymous?: boolean }).isAnonymous ? "guest" : "regular";
}
export async function getSession() {
return auth.api.getSession({ headers: await headers() });
}
export type AuthSession = Awaited<ReturnType<typeof getSession>>;
export type AuthUser = NonNullable<AuthSession>["user"];

View file

@ -1,9 +0,0 @@
import { anonymousClient } from "better-auth/client/plugins";
import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient({
basePath: `${process.env.NEXT_PUBLIC_BASE_PATH ?? ""}/api/auth`,
plugins: [anonymousClient()],
});
export const { useSession, signIn, signUp, signOut } = authClient;

View file

@ -1,3 +1,5 @@
import { generateDummyPassword } from "./db/utils";
export const isProductionEnvironment = process.env.NODE_ENV === "production";
export const isDevelopmentEnvironment = process.env.NODE_ENV === "development";
export const isTestEnvironment = Boolean(
@ -5,3 +7,14 @@ export const isTestEnvironment = Boolean(
process.env.PLAYWRIGHT ||
process.env.CI_PLAYWRIGHT
);
export const guestRegex = /^guest-\d+$/;
export const DUMMY_PASSWORD = generateDummyPassword();
export const suggestions = [
"What are the advantages of using Next.js?",
"Write code to demonstrate Dijkstra's algorithm",
"Help me write an essay about Silicon Valley",
"What is the weather in San Francisco?",
];

View file

@ -1,253 +0,0 @@
// This is a helper for an older version of ai, v4.3.13
// import { config } from 'dotenv';
// import postgres from 'postgres';
// import {
// chat,
// message,
// type MessageDeprecated,
// messageDeprecated,
// vote,
// voteDeprecated,
// } from '../schema';
// import { drizzle } from 'drizzle-orm/postgres-js';
// import { inArray } from 'drizzle-orm';
// import { appendResponseMessages, type UIMessage } from 'ai';
// config({
// path: '.env.local',
// });
// if (!process.env.POSTGRES_URL) {
// throw new Error('POSTGRES_URL environment variable is not set');
// }
// const client = postgres(process.env.POSTGRES_URL);
// const db = drizzle(client);
// const BATCH_SIZE = 100; // Process 100 chats at a time
// const INSERT_BATCH_SIZE = 1000; // Insert 1000 messages at a time
// type NewMessageInsert = {
// id: string;
// chatId: string;
// parts: any[];
// role: string;
// attachments: any[];
// createdAt: Date;
// };
// type NewVoteInsert = {
// messageId: string;
// chatId: string;
// isUpvoted: boolean;
// };
// interface MessageDeprecatedContentPart {
// type: string;
// content: unknown;
// }
// function getMessageRank(message: MessageDeprecated): number {
// if (
// message.role === 'assistant' &&
// (message.content as MessageDeprecatedContentPart[]).some(
// (contentPart) => contentPart.type === 'tool-call',
// )
// ) {
// return 0;
// }
// if (
// message.role === 'tool' &&
// (message.content as MessageDeprecatedContentPart[]).some(
// (contentPart) => contentPart.type === 'tool-result',
// )
// ) {
// return 1;
// }
// if (message.role === 'assistant') {
// return 2;
// }
// return 3;
// }
// function dedupeParts<T extends { type: string; [k: string]: any }>(
// parts: T[],
// ): T[] {
// const seen = new Set<string>();
// return parts.filter((p) => {
// const key = `${p.type}|${JSON.stringify(p.content ?? p)}`;
// if (seen.has(key)) return false;
// seen.add(key);
// return true;
// });
// }
// function sanitizeParts<T extends { type: string; [k: string]: any }>(
// parts: T[],
// ): T[] {
// return parts.filter(
// (part) => !(part.type === 'reasoning' && part.reasoning === 'undefined'),
// );
// }
// async function migrateMessages() {
// const chats = await db.select().from(chat);
// let processedCount = 0;
// for (let i = 0; i < chats.length; i += BATCH_SIZE) {
// const chatBatch = chats.slice(i, i + BATCH_SIZE);
// const chatIds = chatBatch.map((chat) => chat.id);
// const allMessages = await db
// .select()
// .from(messageDeprecated)
// .where(inArray(messageDeprecated.chatId, chatIds));
// const allVotes = await db
// .select()
// .from(voteDeprecated)
// .where(inArray(voteDeprecated.chatId, chatIds));
// const newMessagesToInsert: NewMessageInsert[] = [];
// const newVotesToInsert: NewVoteInsert[] = [];
// for (const chat of chatBatch) {
// processedCount++;
// console.info(`Processed ${processedCount}/${chats.length} chats`);
// const messages = allMessages
// .filter((message) => message.chatId === chat.id)
// .sort((a, b) => {
// const differenceInTime =
// new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
// if (differenceInTime !== 0) return differenceInTime;
// return getMessageRank(a) - getMessageRank(b);
// });
// const votes = allVotes.filter((v) => v.chatId === chat.id);
// const messageSection: Array<UIMessage> = [];
// const messageSections: Array<Array<UIMessage>> = [];
// for (const message of messages) {
// const { role } = message;
// if (role === 'user' && messageSection.length > 0) {
// messageSections.push([...messageSection]);
// messageSection.length = 0;
// }
// // @ts-expect-error message.content has different type
// messageSection.push(message);
// }
// if (messageSection.length > 0) {
// messageSections.push([...messageSection]);
// }
// for (const section of messageSections) {
// const [userMessage, ...assistantMessages] = section;
// const [firstAssistantMessage] = assistantMessages;
// try {
// const uiSection = appendResponseMessages({
// messages: [userMessage],
// // @ts-expect-error: message.content has different type
// responseMessages: assistantMessages,
// _internal: {
// currentDate: () => firstAssistantMessage.createdAt ?? new Date(),
// },
// });
// const projectedUISection = uiSection
// .map((message) => {
// if (message.role === 'user') {
// return {
// id: message.id,
// chatId: chat.id,
// parts: [{ type: 'text', text: message.content }],
// role: message.role,
// createdAt: message.createdAt,
// attachments: [],
// } as NewMessageInsert;
// } else if (message.role === 'assistant') {
// const cleanParts = sanitizeParts(
// dedupeParts(message.parts || []),
// );
// return {
// id: message.id,
// chatId: chat.id,
// parts: cleanParts,
// role: message.role,
// createdAt: message.createdAt,
// attachments: [],
// } as NewMessageInsert;
// }
// return null;
// })
// .filter((msg): msg is NewMessageInsert => msg !== null);
// for (const msg of projectedUISection) {
// newMessagesToInsert.push(msg);
// if (msg.role === 'assistant') {
// const voteByMessage = votes.find((v) => v.messageId === msg.id);
// if (voteByMessage) {
// newVotesToInsert.push({
// messageId: msg.id,
// chatId: msg.chatId,
// isUpvoted: voteByMessage.isUpvoted,
// });
// }
// }
// }
// } catch (error) {
// console.error(`Error processing chat ${chat.id}: ${error}`);
// }
// }
// }
// for (let j = 0; j < newMessagesToInsert.length; j += INSERT_BATCH_SIZE) {
// const messageBatch = newMessagesToInsert.slice(j, j + INSERT_BATCH_SIZE);
// if (messageBatch.length > 0) {
// const validMessageBatch = messageBatch.map((msg) => ({
// id: msg.id,
// chatId: msg.chatId,
// parts: msg.parts,
// role: msg.role,
// attachments: msg.attachments,
// createdAt: msg.createdAt,
// }));
// await db.insert(message).values(validMessageBatch);
// }
// }
// for (let j = 0; j < newVotesToInsert.length; j += INSERT_BATCH_SIZE) {
// const voteBatch = newVotesToInsert.slice(j, j + INSERT_BATCH_SIZE);
// if (voteBatch.length > 0) {
// await db.insert(vote).values(voteBatch);
// }
// }
// }
// console.info(`Migration completed: ${processedCount} chats processed`);
// }
// migrateMessages()
// .then(() => {
// console.info('Script completed successfully');
// process.exit(0);
// })
// .catch((error) => {
// console.error('Script failed:', error);
// process.exit(1);
// });

View file

@ -9,25 +9,25 @@ config({
const runMigrate = async () => {
if (!process.env.POSTGRES_URL) {
console.log("⏭️ POSTGRES_URL not defined, skipping migrations");
console.log("POSTGRES_URL not defined, skipping migrations");
process.exit(0);
}
const connection = postgres(process.env.POSTGRES_URL, { max: 1 });
const db = drizzle(connection);
console.log("Running migrations...");
console.log("Running migrations...");
const start = Date.now();
await migrate(db, { migrationsFolder: "./lib/db/migrations" });
const end = Date.now();
console.log("Migrations completed in", end - start, "ms");
console.log("Migrations completed in", end - start, "ms");
process.exit(0);
};
runMigrate().catch((err) => {
console.error("Migration failed");
console.error("Migration failed");
console.error(err);
process.exit(1);
});

View file

@ -0,0 +1,67 @@
CREATE TABLE IF NOT EXISTS "User" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"email" varchar(64) NOT NULL,
"password" varchar(64),
"name" text,
"emailVerified" boolean NOT NULL DEFAULT false,
"image" text,
"isAnonymous" boolean NOT NULL DEFAULT false,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp DEFAULT now() NOT NULL
);
CREATE TABLE IF NOT EXISTS "Chat" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"createdAt" timestamp NOT NULL,
"title" text NOT NULL,
"userId" uuid NOT NULL REFERENCES "User"("id"),
"visibility" varchar NOT NULL DEFAULT 'private'
);
CREATE TABLE IF NOT EXISTS "Message_v2" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"chatId" uuid NOT NULL REFERENCES "Chat"("id"),
"role" varchar NOT NULL,
"parts" json NOT NULL,
"attachments" json NOT NULL,
"createdAt" timestamp NOT NULL
);
CREATE TABLE IF NOT EXISTS "Vote_v2" (
"chatId" uuid NOT NULL REFERENCES "Chat"("id"),
"messageId" uuid NOT NULL REFERENCES "Message_v2"("id"),
"isUpvoted" boolean NOT NULL,
PRIMARY KEY ("chatId", "messageId")
);
CREATE TABLE IF NOT EXISTS "Document" (
"id" uuid DEFAULT gen_random_uuid() NOT NULL,
"createdAt" timestamp NOT NULL,
"title" text NOT NULL,
"content" text,
"text" varchar NOT NULL DEFAULT 'text',
"userId" uuid NOT NULL REFERENCES "User"("id"),
PRIMARY KEY ("id", "createdAt")
);
CREATE TABLE IF NOT EXISTS "Suggestion" (
"id" uuid DEFAULT gen_random_uuid() NOT NULL,
"documentId" uuid NOT NULL,
"documentCreatedAt" timestamp NOT NULL,
"originalText" text NOT NULL,
"suggestedText" text NOT NULL,
"description" text,
"isResolved" boolean NOT NULL DEFAULT false,
"userId" uuid NOT NULL REFERENCES "User"("id"),
"createdAt" timestamp NOT NULL,
PRIMARY KEY ("id"),
FOREIGN KEY ("documentId", "documentCreatedAt") REFERENCES "Document"("id", "createdAt")
);
CREATE TABLE IF NOT EXISTS "Stream" (
"id" uuid DEFAULT gen_random_uuid() NOT NULL,
"chatId" uuid NOT NULL,
"createdAt" timestamp NOT NULL,
PRIMARY KEY ("id"),
FOREIGN KEY ("chatId") REFERENCES "Chat"("id")
);

View file

@ -1,18 +0,0 @@
CREATE TABLE IF NOT EXISTS "Chat" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"createdAt" timestamp NOT NULL,
"messages" json NOT NULL,
"userId" uuid NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "User" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"email" varchar(64) NOT NULL,
"password" varchar(64)
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Chat" ADD CONSTRAINT "Chat_userId_User_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View file

@ -1,39 +0,0 @@
CREATE TABLE IF NOT EXISTS "Suggestion" (
"id" uuid DEFAULT gen_random_uuid() NOT NULL,
"documentId" uuid NOT NULL,
"documentCreatedAt" timestamp NOT NULL,
"originalText" text NOT NULL,
"suggestedText" text NOT NULL,
"description" text,
"isResolved" boolean DEFAULT false NOT NULL,
"userId" uuid NOT NULL,
"createdAt" timestamp NOT NULL,
CONSTRAINT "Suggestion_id_pk" PRIMARY KEY("id")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "Document" (
"id" uuid DEFAULT gen_random_uuid() NOT NULL,
"createdAt" timestamp NOT NULL,
"title" text NOT NULL,
"content" text,
"userId" uuid NOT NULL,
CONSTRAINT "Document_id_createdAt_pk" PRIMARY KEY("id","createdAt")
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Suggestion" ADD CONSTRAINT "Suggestion_userId_User_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Suggestion" ADD CONSTRAINT "Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk" FOREIGN KEY ("documentId","documentCreatedAt") REFERENCES "public"."Document"("id","createdAt") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Document" ADD CONSTRAINT "Document_userId_User_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View file

@ -1,35 +0,0 @@
CREATE TABLE IF NOT EXISTS "Message" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"chatId" uuid NOT NULL,
"role" varchar NOT NULL,
"content" json NOT NULL,
"createdAt" timestamp NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "Vote" (
"chatId" uuid NOT NULL,
"messageId" uuid NOT NULL,
"isUpvoted" boolean NOT NULL,
CONSTRAINT "Vote_chatId_messageId_pk" PRIMARY KEY("chatId","messageId")
);
--> statement-breakpoint
ALTER TABLE "Chat" ADD COLUMN "title" text NOT NULL;--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Message" ADD CONSTRAINT "Message_chatId_Chat_id_fk" FOREIGN KEY ("chatId") REFERENCES "public"."Chat"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Vote" ADD CONSTRAINT "Vote_chatId_Chat_id_fk" FOREIGN KEY ("chatId") REFERENCES "public"."Chat"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Vote" ADD CONSTRAINT "Vote_messageId_Message_id_fk" FOREIGN KEY ("messageId") REFERENCES "public"."Message"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
ALTER TABLE "Chat" DROP COLUMN IF EXISTS "messages";

View file

@ -1 +0,0 @@
ALTER TABLE "Chat" ADD COLUMN "visibility" varchar DEFAULT 'private' NOT NULL;

View file

@ -1 +0,0 @@
ALTER TABLE "Document" ADD COLUMN "text" varchar DEFAULT 'text' NOT NULL;

View file

@ -1,33 +0,0 @@
CREATE TABLE IF NOT EXISTS "Message_v2" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"chatId" uuid NOT NULL,
"role" varchar NOT NULL,
"parts" json NOT NULL,
"attachments" json NOT NULL,
"createdAt" timestamp NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "Vote_v2" (
"chatId" uuid NOT NULL,
"messageId" uuid NOT NULL,
"isUpvoted" boolean NOT NULL,
CONSTRAINT "Vote_v2_chatId_messageId_pk" PRIMARY KEY("chatId","messageId")
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Message_v2" ADD CONSTRAINT "Message_v2_chatId_Chat_id_fk" FOREIGN KEY ("chatId") REFERENCES "public"."Chat"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Vote_v2" ADD CONSTRAINT "Vote_v2_chatId_Chat_id_fk" FOREIGN KEY ("chatId") REFERENCES "public"."Chat"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Vote_v2" ADD CONSTRAINT "Vote_v2_messageId_Message_v2_id_fk" FOREIGN KEY ("messageId") REFERENCES "public"."Message_v2"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View file

@ -1,12 +0,0 @@
CREATE TABLE IF NOT EXISTS "Stream" (
"id" uuid DEFAULT gen_random_uuid() NOT NULL,
"chatId" uuid NOT NULL,
"createdAt" timestamp NOT NULL,
CONSTRAINT "Stream_id_pk" PRIMARY KEY("id")
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "Stream" ADD CONSTRAINT "Stream_chatId_Chat_id_fk" FOREIGN KEY ("chatId") REFERENCES "public"."Chat"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View file

@ -1 +0,0 @@
ALTER TABLE "Chat" ADD COLUMN "lastContext" jsonb;

View file

@ -1 +0,0 @@
ALTER TABLE "Chat" DROP COLUMN IF EXISTS "lastContext";

View file

@ -1,49 +0,0 @@
ALTER TABLE "User" ADD COLUMN IF NOT EXISTS "name" text;
ALTER TABLE "User" ADD COLUMN IF NOT EXISTS "emailVerified" boolean NOT NULL DEFAULT false;
ALTER TABLE "User" ADD COLUMN IF NOT EXISTS "image" text;
ALTER TABLE "User" ADD COLUMN IF NOT EXISTS "isAnonymous" boolean NOT NULL DEFAULT false;
ALTER TABLE "User" ADD COLUMN IF NOT EXISTS "createdAt" timestamp DEFAULT now() NOT NULL;
ALTER TABLE "User" ADD COLUMN IF NOT EXISTS "updatedAt" timestamp DEFAULT now() NOT NULL;
CREATE TABLE IF NOT EXISTS "Session" (
"id" text PRIMARY KEY,
"expiresAt" timestamp NOT NULL,
"token" text NOT NULL UNIQUE,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp DEFAULT now() NOT NULL,
"ipAddress" text,
"userAgent" text,
"userId" uuid NOT NULL REFERENCES "User"("id") ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS "Account" (
"id" text PRIMARY KEY,
"accountId" text NOT NULL,
"providerId" text NOT NULL,
"userId" uuid NOT NULL REFERENCES "User"("id") ON DELETE CASCADE,
"accessToken" text,
"refreshToken" text,
"idToken" text,
"accessTokenExpiresAt" timestamp,
"refreshTokenExpiresAt" timestamp,
"scope" text,
"password" text,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp DEFAULT now() NOT NULL
);
CREATE TABLE IF NOT EXISTS "Verification" (
"id" text PRIMARY KEY,
"identifier" text NOT NULL,
"value" text NOT NULL,
"expiresAt" timestamp NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp DEFAULT now() NOT NULL
);
UPDATE "User" SET "isAnonymous" = true WHERE email ~ '^guest-\d+$';
INSERT INTO "Account" ("id", "accountId", "providerId", "userId", "password", "createdAt", "updatedAt")
SELECT gen_random_uuid()::text, id::text, 'credential', id, password, now(), now()
FROM "User" WHERE password IS NOT NULL
ON CONFLICT DO NOTHING;

View file

@ -1,90 +0,0 @@
{
"id": "715ec9ec-6715-4d0f-9f6c-9b5c7f09827c",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.Chat": {
"name": "Chat",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"messages": {
"name": "messages",
"type": "json",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Chat_userId_User_id_fk": {
"name": "Chat_userId_User_id_fk",
"tableFrom": "Chat",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"email": {
"name": "email",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"password": {
"name": "password",
"type": "varchar(64)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View file

@ -1,236 +0,0 @@
{
"id": "f3d3437c-4735-4c91-80af-1014048a904e",
"prevId": "715ec9ec-6715-4d0f-9f6c-9b5c7f09827c",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.Suggestion": {
"name": "Suggestion",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"documentId": {
"name": "documentId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"documentCreatedAt": {
"name": "documentCreatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"originalText": {
"name": "originalText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"suggestedText": {
"name": "suggestedText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"isResolved": {
"name": "isResolved",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Suggestion_userId_User_id_fk": {
"name": "Suggestion_userId_User_id_fk",
"tableFrom": "Suggestion",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk": {
"name": "Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk",
"tableFrom": "Suggestion",
"tableTo": "Document",
"columnsFrom": ["documentId", "documentCreatedAt"],
"columnsTo": ["id", "createdAt"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Suggestion_id_pk": {
"name": "Suggestion_id_pk",
"columns": ["id"]
}
},
"uniqueConstraints": {}
},
"public.Chat": {
"name": "Chat",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"messages": {
"name": "messages",
"type": "json",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Chat_userId_User_id_fk": {
"name": "Chat_userId_User_id_fk",
"tableFrom": "Chat",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Document": {
"name": "Document",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "text",
"primaryKey": false,
"notNull": false
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Document_userId_User_id_fk": {
"name": "Document_userId_User_id_fk",
"tableFrom": "Document",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Document_id_createdAt_pk": {
"name": "Document_id_createdAt_pk",
"columns": ["id", "createdAt"]
}
},
"uniqueConstraints": {}
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"email": {
"name": "email",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"password": {
"name": "password",
"type": "varchar(64)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View file

@ -1,339 +0,0 @@
{
"id": "b5d8e862-936f-4419-a50f-97be3e7fe665",
"prevId": "f3d3437c-4735-4c91-80af-1014048a904e",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.Suggestion": {
"name": "Suggestion",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"documentId": {
"name": "documentId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"documentCreatedAt": {
"name": "documentCreatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"originalText": {
"name": "originalText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"suggestedText": {
"name": "suggestedText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"isResolved": {
"name": "isResolved",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Suggestion_userId_User_id_fk": {
"name": "Suggestion_userId_User_id_fk",
"tableFrom": "Suggestion",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk": {
"name": "Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk",
"tableFrom": "Suggestion",
"tableTo": "Document",
"columnsFrom": ["documentId", "documentCreatedAt"],
"columnsTo": ["id", "createdAt"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Suggestion_id_pk": {
"name": "Suggestion_id_pk",
"columns": ["id"]
}
},
"uniqueConstraints": {}
},
"public.Chat": {
"name": "Chat",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Chat_userId_User_id_fk": {
"name": "Chat_userId_User_id_fk",
"tableFrom": "Chat",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Document": {
"name": "Document",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "text",
"primaryKey": false,
"notNull": false
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Document_userId_User_id_fk": {
"name": "Document_userId_User_id_fk",
"tableFrom": "Document",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Document_id_createdAt_pk": {
"name": "Document_id_createdAt_pk",
"columns": ["id", "createdAt"]
}
},
"uniqueConstraints": {}
},
"public.Message": {
"name": "Message",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "varchar",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "json",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Message_chatId_Chat_id_fk": {
"name": "Message_chatId_Chat_id_fk",
"tableFrom": "Message",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"email": {
"name": "email",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"password": {
"name": "password",
"type": "varchar(64)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Vote": {
"name": "Vote",
"schema": "",
"columns": {
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"messageId": {
"name": "messageId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"isUpvoted": {
"name": "isUpvoted",
"type": "boolean",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Vote_chatId_Chat_id_fk": {
"name": "Vote_chatId_Chat_id_fk",
"tableFrom": "Vote",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Vote_messageId_Message_id_fk": {
"name": "Vote_messageId_Message_id_fk",
"tableFrom": "Vote",
"tableTo": "Message",
"columnsFrom": ["messageId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Vote_chatId_messageId_pk": {
"name": "Vote_chatId_messageId_pk",
"columns": ["chatId", "messageId"]
}
},
"uniqueConstraints": {}
}
},
"enums": {},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View file

@ -1,346 +0,0 @@
{
"id": "011efa9e-42c7-4ff6-830a-02106f6638c9",
"prevId": "b5d8e862-936f-4419-a50f-97be3e7fe665",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.Chat": {
"name": "Chat",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"visibility": {
"name": "visibility",
"type": "varchar",
"primaryKey": false,
"notNull": true,
"default": "'private'"
}
},
"indexes": {},
"foreignKeys": {
"Chat_userId_User_id_fk": {
"name": "Chat_userId_User_id_fk",
"tableFrom": "Chat",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Document": {
"name": "Document",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "text",
"primaryKey": false,
"notNull": false
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Document_userId_User_id_fk": {
"name": "Document_userId_User_id_fk",
"tableFrom": "Document",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Document_id_createdAt_pk": {
"name": "Document_id_createdAt_pk",
"columns": ["id", "createdAt"]
}
},
"uniqueConstraints": {}
},
"public.Message": {
"name": "Message",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "varchar",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "json",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Message_chatId_Chat_id_fk": {
"name": "Message_chatId_Chat_id_fk",
"tableFrom": "Message",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Suggestion": {
"name": "Suggestion",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"documentId": {
"name": "documentId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"documentCreatedAt": {
"name": "documentCreatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"originalText": {
"name": "originalText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"suggestedText": {
"name": "suggestedText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"isResolved": {
"name": "isResolved",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Suggestion_userId_User_id_fk": {
"name": "Suggestion_userId_User_id_fk",
"tableFrom": "Suggestion",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk": {
"name": "Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk",
"tableFrom": "Suggestion",
"tableTo": "Document",
"columnsFrom": ["documentId", "documentCreatedAt"],
"columnsTo": ["id", "createdAt"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Suggestion_id_pk": {
"name": "Suggestion_id_pk",
"columns": ["id"]
}
},
"uniqueConstraints": {}
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"email": {
"name": "email",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"password": {
"name": "password",
"type": "varchar(64)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Vote": {
"name": "Vote",
"schema": "",
"columns": {
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"messageId": {
"name": "messageId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"isUpvoted": {
"name": "isUpvoted",
"type": "boolean",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Vote_chatId_Chat_id_fk": {
"name": "Vote_chatId_Chat_id_fk",
"tableFrom": "Vote",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Vote_messageId_Message_id_fk": {
"name": "Vote_messageId_Message_id_fk",
"tableFrom": "Vote",
"tableTo": "Message",
"columnsFrom": ["messageId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Vote_chatId_messageId_pk": {
"name": "Vote_chatId_messageId_pk",
"columns": ["chatId", "messageId"]
}
},
"uniqueConstraints": {}
}
},
"enums": {},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View file

@ -1,353 +0,0 @@
{
"id": "30ad8233-1432-428b-93fc-2bb1ba867ff1",
"prevId": "011efa9e-42c7-4ff6-830a-02106f6638c9",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.Chat": {
"name": "Chat",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"visibility": {
"name": "visibility",
"type": "varchar",
"primaryKey": false,
"notNull": true,
"default": "'private'"
}
},
"indexes": {},
"foreignKeys": {
"Chat_userId_User_id_fk": {
"name": "Chat_userId_User_id_fk",
"tableFrom": "Chat",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Document": {
"name": "Document",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "text",
"primaryKey": false,
"notNull": false
},
"text": {
"name": "text",
"type": "varchar",
"primaryKey": false,
"notNull": true,
"default": "'text'"
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Document_userId_User_id_fk": {
"name": "Document_userId_User_id_fk",
"tableFrom": "Document",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Document_id_createdAt_pk": {
"name": "Document_id_createdAt_pk",
"columns": ["id", "createdAt"]
}
},
"uniqueConstraints": {}
},
"public.Message": {
"name": "Message",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "varchar",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "json",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Message_chatId_Chat_id_fk": {
"name": "Message_chatId_Chat_id_fk",
"tableFrom": "Message",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Suggestion": {
"name": "Suggestion",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"documentId": {
"name": "documentId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"documentCreatedAt": {
"name": "documentCreatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"originalText": {
"name": "originalText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"suggestedText": {
"name": "suggestedText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"isResolved": {
"name": "isResolved",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Suggestion_userId_User_id_fk": {
"name": "Suggestion_userId_User_id_fk",
"tableFrom": "Suggestion",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk": {
"name": "Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk",
"tableFrom": "Suggestion",
"tableTo": "Document",
"columnsFrom": ["documentId", "documentCreatedAt"],
"columnsTo": ["id", "createdAt"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Suggestion_id_pk": {
"name": "Suggestion_id_pk",
"columns": ["id"]
}
},
"uniqueConstraints": {}
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"email": {
"name": "email",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"password": {
"name": "password",
"type": "varchar(64)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Vote": {
"name": "Vote",
"schema": "",
"columns": {
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"messageId": {
"name": "messageId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"isUpvoted": {
"name": "isUpvoted",
"type": "boolean",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Vote_chatId_Chat_id_fk": {
"name": "Vote_chatId_Chat_id_fk",
"tableFrom": "Vote",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Vote_messageId_Message_id_fk": {
"name": "Vote_messageId_Message_id_fk",
"tableFrom": "Vote",
"tableTo": "Message",
"columnsFrom": ["messageId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Vote_chatId_messageId_pk": {
"name": "Vote_chatId_messageId_pk",
"columns": ["chatId", "messageId"]
}
},
"uniqueConstraints": {}
}
},
"enums": {},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View file

@ -1,462 +0,0 @@
{
"id": "c6c102e6-b64e-4f0c-a7a6-32df758de437",
"prevId": "30ad8233-1432-428b-93fc-2bb1ba867ff1",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.Chat": {
"name": "Chat",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"visibility": {
"name": "visibility",
"type": "varchar",
"primaryKey": false,
"notNull": true,
"default": "'private'"
}
},
"indexes": {},
"foreignKeys": {
"Chat_userId_User_id_fk": {
"name": "Chat_userId_User_id_fk",
"tableFrom": "Chat",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Document": {
"name": "Document",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "text",
"primaryKey": false,
"notNull": false
},
"text": {
"name": "text",
"type": "varchar",
"primaryKey": false,
"notNull": true,
"default": "'text'"
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Document_userId_User_id_fk": {
"name": "Document_userId_User_id_fk",
"tableFrom": "Document",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Document_id_createdAt_pk": {
"name": "Document_id_createdAt_pk",
"columns": ["id", "createdAt"]
}
},
"uniqueConstraints": {}
},
"public.Message_v2": {
"name": "Message_v2",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "varchar",
"primaryKey": false,
"notNull": true
},
"parts": {
"name": "parts",
"type": "json",
"primaryKey": false,
"notNull": true
},
"attachments": {
"name": "attachments",
"type": "json",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Message_v2_chatId_Chat_id_fk": {
"name": "Message_v2_chatId_Chat_id_fk",
"tableFrom": "Message_v2",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Message": {
"name": "Message",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "varchar",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "json",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Message_chatId_Chat_id_fk": {
"name": "Message_chatId_Chat_id_fk",
"tableFrom": "Message",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Suggestion": {
"name": "Suggestion",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"documentId": {
"name": "documentId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"documentCreatedAt": {
"name": "documentCreatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"originalText": {
"name": "originalText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"suggestedText": {
"name": "suggestedText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"isResolved": {
"name": "isResolved",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Suggestion_userId_User_id_fk": {
"name": "Suggestion_userId_User_id_fk",
"tableFrom": "Suggestion",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk": {
"name": "Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk",
"tableFrom": "Suggestion",
"tableTo": "Document",
"columnsFrom": ["documentId", "documentCreatedAt"],
"columnsTo": ["id", "createdAt"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Suggestion_id_pk": {
"name": "Suggestion_id_pk",
"columns": ["id"]
}
},
"uniqueConstraints": {}
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"email": {
"name": "email",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"password": {
"name": "password",
"type": "varchar(64)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Vote_v2": {
"name": "Vote_v2",
"schema": "",
"columns": {
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"messageId": {
"name": "messageId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"isUpvoted": {
"name": "isUpvoted",
"type": "boolean",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Vote_v2_chatId_Chat_id_fk": {
"name": "Vote_v2_chatId_Chat_id_fk",
"tableFrom": "Vote_v2",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Vote_v2_messageId_Message_v2_id_fk": {
"name": "Vote_v2_messageId_Message_v2_id_fk",
"tableFrom": "Vote_v2",
"tableTo": "Message_v2",
"columnsFrom": ["messageId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Vote_v2_chatId_messageId_pk": {
"name": "Vote_v2_chatId_messageId_pk",
"columns": ["chatId", "messageId"]
}
},
"uniqueConstraints": {}
},
"public.Vote": {
"name": "Vote",
"schema": "",
"columns": {
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"messageId": {
"name": "messageId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"isUpvoted": {
"name": "isUpvoted",
"type": "boolean",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Vote_chatId_Chat_id_fk": {
"name": "Vote_chatId_Chat_id_fk",
"tableFrom": "Vote",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Vote_messageId_Message_id_fk": {
"name": "Vote_messageId_Message_id_fk",
"tableFrom": "Vote",
"tableTo": "Message",
"columnsFrom": ["messageId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Vote_chatId_messageId_pk": {
"name": "Vote_chatId_messageId_pk",
"columns": ["chatId", "messageId"]
}
},
"uniqueConstraints": {}
}
},
"enums": {},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View file

@ -1,506 +0,0 @@
{
"id": "443de550-b7e8-4bfb-b229-c12dc6c132f0",
"prevId": "c6c102e6-b64e-4f0c-a7a6-32df758de437",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.Chat": {
"name": "Chat",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"visibility": {
"name": "visibility",
"type": "varchar",
"primaryKey": false,
"notNull": true,
"default": "'private'"
}
},
"indexes": {},
"foreignKeys": {
"Chat_userId_User_id_fk": {
"name": "Chat_userId_User_id_fk",
"tableFrom": "Chat",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Document": {
"name": "Document",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "text",
"primaryKey": false,
"notNull": false
},
"text": {
"name": "text",
"type": "varchar",
"primaryKey": false,
"notNull": true,
"default": "'text'"
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Document_userId_User_id_fk": {
"name": "Document_userId_User_id_fk",
"tableFrom": "Document",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Document_id_createdAt_pk": {
"name": "Document_id_createdAt_pk",
"columns": ["id", "createdAt"]
}
},
"uniqueConstraints": {}
},
"public.Message_v2": {
"name": "Message_v2",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "varchar",
"primaryKey": false,
"notNull": true
},
"parts": {
"name": "parts",
"type": "json",
"primaryKey": false,
"notNull": true
},
"attachments": {
"name": "attachments",
"type": "json",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Message_v2_chatId_Chat_id_fk": {
"name": "Message_v2_chatId_Chat_id_fk",
"tableFrom": "Message_v2",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Message": {
"name": "Message",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "varchar",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "json",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Message_chatId_Chat_id_fk": {
"name": "Message_chatId_Chat_id_fk",
"tableFrom": "Message",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Stream": {
"name": "Stream",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Stream_chatId_Chat_id_fk": {
"name": "Stream_chatId_Chat_id_fk",
"tableFrom": "Stream",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Stream_id_pk": {
"name": "Stream_id_pk",
"columns": ["id"]
}
},
"uniqueConstraints": {}
},
"public.Suggestion": {
"name": "Suggestion",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"documentId": {
"name": "documentId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"documentCreatedAt": {
"name": "documentCreatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"originalText": {
"name": "originalText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"suggestedText": {
"name": "suggestedText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"isResolved": {
"name": "isResolved",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Suggestion_userId_User_id_fk": {
"name": "Suggestion_userId_User_id_fk",
"tableFrom": "Suggestion",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk": {
"name": "Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk",
"tableFrom": "Suggestion",
"tableTo": "Document",
"columnsFrom": ["documentId", "documentCreatedAt"],
"columnsTo": ["id", "createdAt"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Suggestion_id_pk": {
"name": "Suggestion_id_pk",
"columns": ["id"]
}
},
"uniqueConstraints": {}
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"email": {
"name": "email",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"password": {
"name": "password",
"type": "varchar(64)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Vote_v2": {
"name": "Vote_v2",
"schema": "",
"columns": {
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"messageId": {
"name": "messageId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"isUpvoted": {
"name": "isUpvoted",
"type": "boolean",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Vote_v2_chatId_Chat_id_fk": {
"name": "Vote_v2_chatId_Chat_id_fk",
"tableFrom": "Vote_v2",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Vote_v2_messageId_Message_v2_id_fk": {
"name": "Vote_v2_messageId_Message_v2_id_fk",
"tableFrom": "Vote_v2",
"tableTo": "Message_v2",
"columnsFrom": ["messageId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Vote_v2_chatId_messageId_pk": {
"name": "Vote_v2_chatId_messageId_pk",
"columns": ["chatId", "messageId"]
}
},
"uniqueConstraints": {}
},
"public.Vote": {
"name": "Vote",
"schema": "",
"columns": {
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"messageId": {
"name": "messageId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"isUpvoted": {
"name": "isUpvoted",
"type": "boolean",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Vote_chatId_Chat_id_fk": {
"name": "Vote_chatId_Chat_id_fk",
"tableFrom": "Vote",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Vote_messageId_Message_id_fk": {
"name": "Vote_messageId_Message_id_fk",
"tableFrom": "Vote",
"tableTo": "Message",
"columnsFrom": ["messageId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Vote_chatId_messageId_pk": {
"name": "Vote_chatId_messageId_pk",
"columns": ["chatId", "messageId"]
}
},
"uniqueConstraints": {}
}
},
"enums": {},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View file

@ -1,512 +0,0 @@
{
"id": "097660a7-976a-4b3e-8ebb-79312e3ece6f",
"prevId": "443de550-b7e8-4bfb-b229-c12dc6c132f0",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.Chat": {
"name": "Chat",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"visibility": {
"name": "visibility",
"type": "varchar",
"primaryKey": false,
"notNull": true,
"default": "'private'"
},
"lastContext": {
"name": "lastContext",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"Chat_userId_User_id_fk": {
"name": "Chat_userId_User_id_fk",
"tableFrom": "Chat",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Document": {
"name": "Document",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "text",
"primaryKey": false,
"notNull": false
},
"text": {
"name": "text",
"type": "varchar",
"primaryKey": false,
"notNull": true,
"default": "'text'"
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Document_userId_User_id_fk": {
"name": "Document_userId_User_id_fk",
"tableFrom": "Document",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Document_id_createdAt_pk": {
"name": "Document_id_createdAt_pk",
"columns": ["id", "createdAt"]
}
},
"uniqueConstraints": {}
},
"public.Message_v2": {
"name": "Message_v2",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "varchar",
"primaryKey": false,
"notNull": true
},
"parts": {
"name": "parts",
"type": "json",
"primaryKey": false,
"notNull": true
},
"attachments": {
"name": "attachments",
"type": "json",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Message_v2_chatId_Chat_id_fk": {
"name": "Message_v2_chatId_Chat_id_fk",
"tableFrom": "Message_v2",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Message": {
"name": "Message",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "varchar",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "json",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Message_chatId_Chat_id_fk": {
"name": "Message_chatId_Chat_id_fk",
"tableFrom": "Message",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Stream": {
"name": "Stream",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Stream_chatId_Chat_id_fk": {
"name": "Stream_chatId_Chat_id_fk",
"tableFrom": "Stream",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Stream_id_pk": {
"name": "Stream_id_pk",
"columns": ["id"]
}
},
"uniqueConstraints": {}
},
"public.Suggestion": {
"name": "Suggestion",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"documentId": {
"name": "documentId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"documentCreatedAt": {
"name": "documentCreatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"originalText": {
"name": "originalText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"suggestedText": {
"name": "suggestedText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"isResolved": {
"name": "isResolved",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Suggestion_userId_User_id_fk": {
"name": "Suggestion_userId_User_id_fk",
"tableFrom": "Suggestion",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk": {
"name": "Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk",
"tableFrom": "Suggestion",
"tableTo": "Document",
"columnsFrom": ["documentId", "documentCreatedAt"],
"columnsTo": ["id", "createdAt"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Suggestion_id_pk": {
"name": "Suggestion_id_pk",
"columns": ["id"]
}
},
"uniqueConstraints": {}
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"email": {
"name": "email",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"password": {
"name": "password",
"type": "varchar(64)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Vote_v2": {
"name": "Vote_v2",
"schema": "",
"columns": {
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"messageId": {
"name": "messageId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"isUpvoted": {
"name": "isUpvoted",
"type": "boolean",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Vote_v2_chatId_Chat_id_fk": {
"name": "Vote_v2_chatId_Chat_id_fk",
"tableFrom": "Vote_v2",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Vote_v2_messageId_Message_v2_id_fk": {
"name": "Vote_v2_messageId_Message_v2_id_fk",
"tableFrom": "Vote_v2",
"tableTo": "Message_v2",
"columnsFrom": ["messageId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Vote_v2_chatId_messageId_pk": {
"name": "Vote_v2_chatId_messageId_pk",
"columns": ["chatId", "messageId"]
}
},
"uniqueConstraints": {}
},
"public.Vote": {
"name": "Vote",
"schema": "",
"columns": {
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"messageId": {
"name": "messageId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"isUpvoted": {
"name": "isUpvoted",
"type": "boolean",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Vote_chatId_Chat_id_fk": {
"name": "Vote_chatId_Chat_id_fk",
"tableFrom": "Vote",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Vote_messageId_Message_id_fk": {
"name": "Vote_messageId_Message_id_fk",
"tableFrom": "Vote",
"tableTo": "Message",
"columnsFrom": ["messageId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Vote_chatId_messageId_pk": {
"name": "Vote_chatId_messageId_pk",
"columns": ["chatId", "messageId"]
}
},
"uniqueConstraints": {}
}
},
"enums": {},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View file

@ -1,506 +0,0 @@
{
"id": "31934f42-f6af-42a3-9320-b2e86fb67e81",
"prevId": "097660a7-976a-4b3e-8ebb-79312e3ece6f",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.Chat": {
"name": "Chat",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"visibility": {
"name": "visibility",
"type": "varchar",
"primaryKey": false,
"notNull": true,
"default": "'private'"
}
},
"indexes": {},
"foreignKeys": {
"Chat_userId_User_id_fk": {
"name": "Chat_userId_User_id_fk",
"tableFrom": "Chat",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Document": {
"name": "Document",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "text",
"primaryKey": false,
"notNull": false
},
"text": {
"name": "text",
"type": "varchar",
"primaryKey": false,
"notNull": true,
"default": "'text'"
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Document_userId_User_id_fk": {
"name": "Document_userId_User_id_fk",
"tableFrom": "Document",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Document_id_createdAt_pk": {
"name": "Document_id_createdAt_pk",
"columns": ["id", "createdAt"]
}
},
"uniqueConstraints": {}
},
"public.Message_v2": {
"name": "Message_v2",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "varchar",
"primaryKey": false,
"notNull": true
},
"parts": {
"name": "parts",
"type": "json",
"primaryKey": false,
"notNull": true
},
"attachments": {
"name": "attachments",
"type": "json",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Message_v2_chatId_Chat_id_fk": {
"name": "Message_v2_chatId_Chat_id_fk",
"tableFrom": "Message_v2",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Message": {
"name": "Message",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"role": {
"name": "role",
"type": "varchar",
"primaryKey": false,
"notNull": true
},
"content": {
"name": "content",
"type": "json",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Message_chatId_Chat_id_fk": {
"name": "Message_chatId_Chat_id_fk",
"tableFrom": "Message",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Stream": {
"name": "Stream",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Stream_chatId_Chat_id_fk": {
"name": "Stream_chatId_Chat_id_fk",
"tableFrom": "Stream",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Stream_id_pk": {
"name": "Stream_id_pk",
"columns": ["id"]
}
},
"uniqueConstraints": {}
},
"public.Suggestion": {
"name": "Suggestion",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"documentId": {
"name": "documentId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"documentCreatedAt": {
"name": "documentCreatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
},
"originalText": {
"name": "originalText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"suggestedText": {
"name": "suggestedText",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"isResolved": {
"name": "isResolved",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Suggestion_userId_User_id_fk": {
"name": "Suggestion_userId_User_id_fk",
"tableFrom": "Suggestion",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk": {
"name": "Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk",
"tableFrom": "Suggestion",
"tableTo": "Document",
"columnsFrom": ["documentId", "documentCreatedAt"],
"columnsTo": ["id", "createdAt"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Suggestion_id_pk": {
"name": "Suggestion_id_pk",
"columns": ["id"]
}
},
"uniqueConstraints": {}
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"email": {
"name": "email",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true
},
"password": {
"name": "password",
"type": "varchar(64)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.Vote_v2": {
"name": "Vote_v2",
"schema": "",
"columns": {
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"messageId": {
"name": "messageId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"isUpvoted": {
"name": "isUpvoted",
"type": "boolean",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Vote_v2_chatId_Chat_id_fk": {
"name": "Vote_v2_chatId_Chat_id_fk",
"tableFrom": "Vote_v2",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Vote_v2_messageId_Message_v2_id_fk": {
"name": "Vote_v2_messageId_Message_v2_id_fk",
"tableFrom": "Vote_v2",
"tableTo": "Message_v2",
"columnsFrom": ["messageId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Vote_v2_chatId_messageId_pk": {
"name": "Vote_v2_chatId_messageId_pk",
"columns": ["chatId", "messageId"]
}
},
"uniqueConstraints": {}
},
"public.Vote": {
"name": "Vote",
"schema": "",
"columns": {
"chatId": {
"name": "chatId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"messageId": {
"name": "messageId",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"isUpvoted": {
"name": "isUpvoted",
"type": "boolean",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Vote_chatId_Chat_id_fk": {
"name": "Vote_chatId_Chat_id_fk",
"tableFrom": "Vote",
"tableTo": "Chat",
"columnsFrom": ["chatId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Vote_messageId_Message_id_fk": {
"name": "Vote_messageId_Message_id_fk",
"tableFrom": "Vote",
"tableTo": "Message",
"columnsFrom": ["messageId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"Vote_chatId_messageId_pk": {
"name": "Vote_chatId_messageId_pk",
"columns": ["chatId", "messageId"]
}
},
"uniqueConstraints": {}
}
},
"enums": {},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View file

@ -5,64 +5,8 @@
{
"idx": 0,
"version": "7",
"when": 1728598022383,
"tag": "0000_keen_devos",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1730207363999,
"tag": "0001_sparkling_blue_marvel",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1730725226313,
"tag": "0002_wandering_riptide",
"breakpoints": true
},
{
"idx": 3,
"version": "7",
"when": 1733403031014,
"tag": "0003_cloudy_glorian",
"breakpoints": true
},
{
"idx": 4,
"version": "7",
"when": 1733945232355,
"tag": "0004_odd_slayback",
"breakpoints": true
},
{
"idx": 5,
"version": "7",
"when": 1741934630596,
"tag": "0005_wooden_whistler",
"breakpoints": true
},
{
"idx": 6,
"version": "7",
"when": 1746118166211,
"tag": "0006_marvelous_frog_thor",
"breakpoints": true
},
{
"idx": 7,
"version": "7",
"when": 1757362773211,
"tag": "0007_flowery_ben_parker",
"breakpoints": true
},
{
"idx": 8,
"version": "7",
"when": 1768479010084,
"tag": "0008_flat_forgotten_one",
"when": 1710000000000,
"tag": "0000_initial",
"breakpoints": true
}
]

View file

@ -14,10 +14,10 @@ import {
} from "drizzle-orm";
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
import type { ArtifactKind } from "@/components/artifact";
import type { VisibilityType } from "@/components/visibility-selector";
import type { ArtifactKind } from "@/components/chat/artifact";
import type { VisibilityType } from "@/components/chat/visibility-selector";
import { ChatbotError } from "../errors";
import { generateUUID } from "../utils";
import {
type Chat,
chat,
@ -27,13 +27,53 @@ import {
type Suggestion,
stream,
suggestion,
type User,
user,
vote,
} from "./schema";
import { generateHashedPassword } from "./utils";
// biome-ignore lint: Forbidden non-null assertion.
const client = postgres(process.env.POSTGRES_URL!);
const client = postgres(process.env.POSTGRES_URL ?? "");
const db = drizzle(client);
export async function getUser(email: string): Promise<User[]> {
try {
return await db.select().from(user).where(eq(user.email, email));
} catch (_error) {
throw new ChatbotError(
"bad_request:database",
"Failed to get user by email"
);
}
}
export async function createUser(email: string, password: string) {
const hashedPassword = generateHashedPassword(password);
try {
return await db.insert(user).values({ email, password: hashedPassword });
} catch (_error) {
throw new ChatbotError("bad_request:database", "Failed to create user");
}
}
export async function createGuestUser() {
const email = `guest-${Date.now()}`;
const password = generateHashedPassword(generateUUID());
try {
return await db.insert(user).values({ email, password }).returning({
id: user.id,
email: user.email,
});
} catch (_error) {
throw new ChatbotError(
"bad_request:database",
"Failed to create guest user"
);
}
}
export async function saveChat({
id,
userId,
@ -122,7 +162,7 @@ export async function getChatsByUserId({
try {
const extendedLimit = limit + 1;
const query = (whereCondition?: SQL<any>) =>
const query = (whereCondition?: SQL<unknown>) =>
db
.select()
.from(chat)
@ -306,6 +346,42 @@ export async function saveDocument({
}
}
export async function updateDocumentContent({
id,
content,
}: {
id: string;
content: string;
}) {
try {
const docs = await db
.select()
.from(document)
.where(eq(document.id, id))
.orderBy(desc(document.createdAt))
.limit(1);
const latest = docs[0];
if (!latest) {
throw new ChatbotError("not_found:database", "Document not found");
}
return await db
.update(document)
.set({ content })
.where(and(eq(document.id, id), eq(document.createdAt, latest.createdAt)))
.returning();
} catch (_error) {
if (_error instanceof ChatbotError) {
throw _error;
}
throw new ChatbotError(
"bad_request:database",
"Failed to update document content"
);
}
}
export async function getDocumentsById({ id }: { id: string }) {
try {
const documents = await db
@ -479,8 +555,7 @@ export async function updateChatTitleById({
}) {
try {
return await db.update(chat).set({ title }).where(eq(chat.id, chatId));
} catch (error) {
console.warn("Failed to update title for chat", chatId, error);
} catch (_error) {
return;
}
}
@ -493,7 +568,7 @@ export async function getMessageCountByUserId({
differenceInHours: number;
}) {
try {
const twentyFourHoursAgo = new Date(
const cutoffTime = new Date(
Date.now() - differenceInHours * 60 * 60 * 1000
);
@ -504,7 +579,7 @@ export async function getMessageCountByUserId({
.where(
and(
eq(chat.userId, id),
gte(message.createdAt, twentyFourHoursAgo),
gte(message.createdAt, cutoffTime),
eq(message.role, "user")
)
)

View file

@ -25,52 +25,6 @@ export const user = pgTable("User", {
export type User = InferSelectModel<typeof user>;
export const session = pgTable("Session", {
id: text("id").primaryKey(),
expiresAt: timestamp("expiresAt").notNull(),
token: text("token").notNull().unique(),
createdAt: timestamp("createdAt").notNull().defaultNow(),
updatedAt: timestamp("updatedAt").notNull().defaultNow(),
ipAddress: text("ipAddress"),
userAgent: text("userAgent"),
userId: uuid("userId")
.notNull()
.references(() => user.id, { onDelete: "cascade" }),
});
export type Session = InferSelectModel<typeof session>;
export const account = pgTable("Account", {
id: text("id").primaryKey(),
accountId: text("accountId").notNull(),
providerId: text("providerId").notNull(),
userId: uuid("userId")
.notNull()
.references(() => user.id, { onDelete: "cascade" }),
accessToken: text("accessToken"),
refreshToken: text("refreshToken"),
idToken: text("idToken"),
accessTokenExpiresAt: timestamp("accessTokenExpiresAt"),
refreshTokenExpiresAt: timestamp("refreshTokenExpiresAt"),
scope: text("scope"),
password: text("password"),
createdAt: timestamp("createdAt").notNull().defaultNow(),
updatedAt: timestamp("updatedAt").notNull().defaultNow(),
});
export type Account = InferSelectModel<typeof account>;
export const verification = pgTable("Verification", {
id: text("id").primaryKey(),
identifier: text("identifier").notNull(),
value: text("value").notNull(),
expiresAt: timestamp("expiresAt").notNull(),
createdAt: timestamp("createdAt").notNull().defaultNow(),
updatedAt: timestamp("updatedAt").notNull().defaultNow(),
});
export type Verification = InferSelectModel<typeof verification>;
export const chat = pgTable("Chat", {
id: uuid("id").primaryKey().notNull().defaultRandom(),
createdAt: timestamp("createdAt").notNull(),
@ -85,20 +39,6 @@ export const chat = pgTable("Chat", {
export type Chat = InferSelectModel<typeof chat>;
// DEPRECATED: The following schema is deprecated and will be removed in the future.
// Read the migration guide at https://chatbot.dev/docs/migration-guides/message-parts
export const messageDeprecated = pgTable("Message", {
id: uuid("id").primaryKey().notNull().defaultRandom(),
chatId: uuid("chatId")
.notNull()
.references(() => chat.id),
role: varchar("role").notNull(),
content: json("content").notNull(),
createdAt: timestamp("createdAt").notNull(),
});
export type MessageDeprecated = InferSelectModel<typeof messageDeprecated>;
export const message = pgTable("Message_v2", {
id: uuid("id").primaryKey().notNull().defaultRandom(),
chatId: uuid("chatId")
@ -112,28 +52,6 @@ export const message = pgTable("Message_v2", {
export type DBMessage = InferSelectModel<typeof message>;
// DEPRECATED: The following schema is deprecated and will be removed in the future.
// Read the migration guide at https://chatbot.dev/docs/migration-guides/message-parts
export const voteDeprecated = pgTable(
"Vote",
{
chatId: uuid("chatId")
.notNull()
.references(() => chat.id),
messageId: uuid("messageId")
.notNull()
.references(() => messageDeprecated.id),
isUpvoted: boolean("isUpvoted").notNull(),
},
(table) => {
return {
pk: primaryKey({ columns: [table.chatId, table.messageId] }),
};
}
);
export type VoteDeprecated = InferSelectModel<typeof voteDeprecated>;
export const vote = pgTable(
"Vote_v2",
{
@ -145,11 +63,9 @@ export const vote = pgTable(
.references(() => message.id),
isUpvoted: boolean("isUpvoted").notNull(),
},
(table) => {
return {
pk: primaryKey({ columns: [table.chatId, table.messageId] }),
};
}
(table) => ({
pk: primaryKey({ columns: [table.chatId, table.messageId] }),
})
);
export type Vote = InferSelectModel<typeof vote>;
@ -168,11 +84,9 @@ export const document = pgTable(
.notNull()
.references(() => user.id),
},
(table) => {
return {
pk: primaryKey({ columns: [table.id, table.createdAt] }),
};
}
(table) => ({
pk: primaryKey({ columns: [table.id, table.createdAt] }),
})
);
export type Document = InferSelectModel<typeof document>;

16
lib/db/utils.ts Normal file
View file

@ -0,0 +1,16 @@
import { generateId } from "ai";
import { genSaltSync, hashSync } from "bcrypt-ts";
export function generateHashedPassword(password: string) {
const salt = genSaltSync(10);
const hash = hashSync(password, salt);
return hash;
}
export function generateDummyPassword() {
const password = generateId();
const hashedPassword = generateHashedPassword(password);
return hashedPassword;
}

View file

@ -8,7 +8,7 @@ import { renderToString } from "react-dom/server";
import { MessageResponse } from "@/components/ai-elements/message";
import { documentSchema } from "./config";
import { createSuggestionWidget, type UISuggestion } from "./suggestions";
import type { UISuggestion } from "./suggestions";
export const buildDocumentFromContent = (content: string) => {
const parser = DOMParser.fromSchema(documentSchema);
@ -26,7 +26,7 @@ export const buildContentFromDocument = (document: Node) => {
export const createDecorations = (
suggestions: UISuggestion[],
view: EditorView
_view: EditorView
) => {
const decorations: Decoration[] = [];
@ -37,6 +37,7 @@ export const createDecorations = (
suggestion.selectionEnd,
{
class: "suggestion-highlight",
"data-suggestion-id": suggestion.id,
},
{
suggestionId: suggestion.id,
@ -44,21 +45,7 @@ export const createDecorations = (
}
)
);
decorations.push(
Decoration.widget(
suggestion.selectionStart,
(currentView) => {
const { dom } = createSuggestionWidget(suggestion, currentView);
return dom;
},
{
suggestionId: suggestion.id,
type: "widget",
}
)
);
}
return DecorationSet.create(view.state.doc, decorations);
return DecorationSet.create(_view.state.doc, decorations);
};

View file

@ -1,13 +1,13 @@
import { createRoot } from "react-dom/client";
// biome-ignore lint/complexity/noStaticOnlyClass: "Needs to be static"
export class ReactRenderer {
static render(component: React.ReactElement, dom: HTMLElement) {
const root = createRoot(dom);
root.render(component);
export function renderReactComponent(
component: React.ReactElement,
dom: HTMLElement
) {
const root = createRoot(dom);
root.render(component);
return {
destroy: () => root.unmount(),
};
}
return {
destroy: () => root.unmount(),
};
}

View file

@ -1,13 +1,6 @@
import type { Node } from "prosemirror-model";
import { Plugin, PluginKey } from "prosemirror-state";
import {
type Decoration,
DecorationSet,
type EditorView,
} from "prosemirror-view";
import { createRoot } from "react-dom/client";
import type { ArtifactKind } from "@/components/artifact";
import { Suggestion as PreviewSuggestion } from "@/components/suggestion";
import { DecorationSet } from "prosemirror-view";
import type { Suggestion } from "@/lib/db/schema";
export interface UISuggestion extends Suggestion {
@ -66,71 +59,6 @@ export function projectWithPositions(
});
}
export function createSuggestionWidget(
suggestion: UISuggestion,
view: EditorView,
artifactKind: ArtifactKind = "text"
): { dom: HTMLElement; destroy: () => void } {
const dom = document.createElement("span");
const root = createRoot(dom);
dom.addEventListener("mousedown", (event) => {
event.preventDefault();
view.dom.blur();
});
const onApply = () => {
const { state, dispatch } = view;
const decorationTransaction = state.tr;
const currentState = suggestionsPluginKey.getState(state);
const currentDecorations = currentState?.decorations;
if (currentDecorations) {
const newDecorations = DecorationSet.create(
state.doc,
currentDecorations.find().filter((decoration: Decoration) => {
return decoration.spec.suggestionId !== suggestion.id;
})
);
decorationTransaction.setMeta(suggestionsPluginKey, {
decorations: newDecorations,
selected: null,
});
dispatch(decorationTransaction);
}
const textTransaction = view.state.tr.replaceWith(
suggestion.selectionStart,
suggestion.selectionEnd,
state.schema.text(suggestion.suggestedText)
);
textTransaction.setMeta("no-debounce", true);
dispatch(textTransaction);
};
root.render(
<PreviewSuggestion
artifactKind={artifactKind}
onApply={onApply}
suggestion={suggestion}
/>
);
return {
dom,
destroy: () => {
// Wrapping unmount in setTimeout to avoid synchronous unmounting during render
setTimeout(() => {
root.unmount();
}, 0);
},
};
}
export const suggestionsPluginKey = new PluginKey("suggestions");
export const suggestionsPlugin = new Plugin({
key: suggestionsPluginKey,
@ -154,5 +82,15 @@ export const suggestionsPlugin = new Plugin({
decorations(state) {
return this.getState(state)?.decorations ?? DecorationSet.empty;
},
handleDOMEvents: {
mousedown(_view, event) {
const target = event.target as HTMLElement;
if (target.closest(".suggestion-highlight")) {
event.preventDefault();
return true;
}
return false;
},
},
},
});

View file

@ -93,7 +93,7 @@ export function getMessageByErrorCode(errorCode: ErrorCode): string {
return "Your account does not have access to this feature.";
case "rate_limit:chat":
return "You have exceeded your maximum number of messages for the day. Please try again later.";
return "You've reached the message limit. Come back in 1 hour to continue chatting.";
case "not_found:chat":
return "The requested chat was not found. Please check the chat ID and try again.";
case "forbidden:chat":

View file

@ -1,14 +1,12 @@
import type { InferUITool, UIMessage } from "ai";
import { z } from "zod";
import type { ArtifactKind } from "@/components/artifact";
import type { ArtifactKind } from "@/components/chat/artifact";
import type { createDocument } from "./ai/tools/create-document";
import type { getWeather } from "./ai/tools/get-weather";
import type { requestSuggestions } from "./ai/tools/request-suggestions";
import type { updateDocument } from "./ai/tools/update-document";
import type { Suggestion } from "./db/schema";
export type DataPart = { type: "append-message"; message: string };
export const messageMetadataSchema = z.object({
createdAt: z.string(),
});

View file

@ -1,6 +1,4 @@
import type {
AssistantModelMessage,
ToolModelMessage,
UIMessage,
UIMessagePart,
} from 'ai';
@ -48,13 +46,6 @@ export async function fetchWithErrorHandlers(
}
}
export function getLocalStorage(key: string) {
if (typeof window !== 'undefined') {
return JSON.parse(localStorage.getItem(key) || '[]');
}
return [];
}
export function generateUUID(): string {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (Math.random() * 16) | 0;
@ -63,14 +54,6 @@ export function generateUUID(): string {
});
}
type ResponseMessageWithoutId = ToolModelMessage | AssistantModelMessage;
type ResponseMessage = ResponseMessageWithoutId & { id: string };
export function getMostRecentUserMessage(messages: UIMessage[]) {
const userMessages = messages.filter((message) => message.role === 'user');
return userMessages.at(-1);
}
export function getDocumentTimestampByIndex(
documents: Document[],
index: number,
@ -81,18 +64,6 @@ export function getDocumentTimestampByIndex(
return documents[index].createdAt;
}
export function getTrailingMessageId({
messages,
}: {
messages: ResponseMessage[];
}): string | null {
const trailingMessage = messages.at(-1);
if (!trailingMessage) { return null; }
return trailingMessage.id;
}
export function sanitizeText(text: string) {
return text.replace('<has_function_call>', '');
}