From 3b84e0105706a8fbbbd95cb0c4a6082abce78470 Mon Sep 17 00:00:00 2001 From: Avraham Sakal Date: Sun, 27 Jul 2025 17:22:58 -0400 Subject: [PATCH] refactor trpc procedures into domains --- layouts/LayoutDefault.tsx | 8 +-- pages/chat/@id/+Page.tsx | 4 +- pages/chat/@id/+data.ts | 6 +-- pages/chat/conversations.ts | 76 +++++++++++++++++++++++++++ pages/chat/facts.ts | 39 ++++++++++++++ pages/chat/messages.ts | 19 +++++++ pages/chat/trpc.ts | 101 +++--------------------------------- 7 files changed, 151 insertions(+), 102 deletions(-) create mode 100644 pages/chat/conversations.ts create mode 100644 pages/chat/facts.ts create mode 100644 pages/chat/messages.ts diff --git a/layouts/LayoutDefault.tsx b/layouts/LayoutDefault.tsx index 16f2309..27a5f4f 100644 --- a/layouts/LayoutDefault.tsx +++ b/layouts/LayoutDefault.tsx @@ -40,7 +40,7 @@ export default function LayoutDefault({ const conversationId = useStore((state) => state.selectedConversationId); useEffect(() => { - trpc.chat.listConversations.query().then((res) => { + trpc.chat.conversations.fetchAll.query().then((res) => { setConversations(res); }); }, [setConversations]); @@ -55,8 +55,8 @@ export default function LayoutDefault({ async function handleDeleteConversation(conversationId: string) { removeConversation(conversationId); - await trpc.chat.deleteConversation.mutate({ id: conversationId }); - const res = await trpc.chat.createConversation.mutate(); + await trpc.chat.conversations.deleteOne.mutate({ id: conversationId }); + const res = await trpc.chat.conversations.start.mutate(); if (!res?.id) return; addConversation(res); await navigate(`/chat/${res.id}`); @@ -108,7 +108,7 @@ export default function LayoutDefault({ onClick={(e) => { e.preventDefault(); e.stopPropagation(); - trpc.chat.createConversation.mutate().then((res) => { + trpc.chat.conversations.start.mutate().then((res) => { if (!res?.id) return; addConversation(res); navigate(`/chat/${res.id}`); diff --git a/pages/chat/@id/+Page.tsx b/pages/chat/@id/+Page.tsx index 929704f..60aec39 100644 --- a/pages/chat/@id/+Page.tsx +++ b/pages/chat/@id/+Page.tsx @@ -76,7 +76,7 @@ export default function ChatPage() { async function handleDeleteFact(factId: string) { removeFact(factId); - await trpc.chat.deleteFact.mutate({ factId }); + await trpc.chat.facts.deleteOne.mutate({ factId }); } return ( @@ -90,7 +90,7 @@ export default function ChatPage() { setConversationTitle(e.target.value); }} onBlur={(e) => { - trpc.chat.updateConversationTitle.mutate({ + trpc.chat.conversations.updateTitle.mutate({ id: conversationId, title: e.target.value, }); diff --git a/pages/chat/@id/+data.ts b/pages/chat/@id/+data.ts index 9d06411..1ce759f 100644 --- a/pages/chat/@id/+data.ts +++ b/pages/chat/@id/+data.ts @@ -6,13 +6,13 @@ export type Data = Awaited>; export const data = async (pageContext: PageContextServer) => { const { id } = pageContext.routeParams; const caller = createCaller({}); - const conversation = await caller.fetchConversation({ + const conversation = await caller.conversations.fetchOne({ id, }); - const messages = await caller.fetchMessages({ + const messages = await caller.conversations.fetchMessages({ conversationId: id, }); - const facts = await caller.fetchFacts({ + const facts = await caller.facts.fetchByConversationId({ conversationId: id, }); return { conversation, messages, facts }; diff --git a/pages/chat/conversations.ts b/pages/chat/conversations.ts new file mode 100644 index 0000000..09e4840 --- /dev/null +++ b/pages/chat/conversations.ts @@ -0,0 +1,76 @@ +import { + router, + publicProcedure, + createCallerFactory, +} from "../../trpc/server"; +import type { CommittedMessage } from "../../types.js"; +import { db } from "../../database/lowdb"; +import { nanoid } from "nanoid"; + +export const conversations = router({ + fetchAll: publicProcedure.query(async () => { + const rows = await db.data.conversations; + return rows; + }), + fetchOne: publicProcedure + .input((x) => x as { id: string }) + .query(async ({ input: { id } }) => { + const row = await db.data.conversations.find((c) => c.id === id); + return row; + }), + start: publicProcedure.mutation(async () => { + const title = "New Conversation"; + const row = { + id: nanoid(), + title, + userId: "1", + }; + await db.data.conversations.push(row); + db.write(); + return row; + }), + deleteOne: publicProcedure + .input((x) => x as { id: string }) + .mutation(async ({ input: { id } }) => { + db.data.conversations.splice( + db.data.conversations.findIndex((c) => c.id === id), + 1, + ); + const deletedMessageIds = db.data.messages + .filter((m) => m.conversationId === id) + .map((m) => m.id); + db.data.messages = db.data.messages.filter( + (m) => m.conversationId !== id, + ); + db.data.facts = db.data.facts.filter( + (fact) => !deletedMessageIds.includes(fact.sourceMessageId), + ); + db.write(); + return { ok: true }; + }), + updateTitle: publicProcedure + .input( + (x) => + x as { + id: string; + title: string; + }, + ) + .mutation(async ({ input: { id, title } }) => { + const conversation = await db.data.conversations.find((c) => c.id === id); + if (!conversation) throw new Error("Conversation not found"); + conversation.title = title; + db.write(); + return { ok: true }; + }), + fetchMessages: publicProcedure + .input((x) => x as { conversationId: string }) + .query(async ({ input: { conversationId } }) => { + const rows = await db.data.messages.filter( + (m) => m.conversationId === conversationId, + ); + return rows as Array; + }), +}); + +export const createCaller = createCallerFactory(conversations); diff --git a/pages/chat/facts.ts b/pages/chat/facts.ts new file mode 100644 index 0000000..f11b45e --- /dev/null +++ b/pages/chat/facts.ts @@ -0,0 +1,39 @@ +import { + router, + publicProcedure, + createCallerFactory, +} from "../../trpc/server.js"; +import { db, type Fact } from "../../database/lowdb.js"; + +export const facts = router({ + fetchByConversationId: publicProcedure + .input((x) => x as { conversationId: string }) + .query(async ({ input: { conversationId } }) => { + const conversationMessageIds = db.data.messages + .filter((m) => m.conversationId === conversationId) + .map((m) => m.id); + const rows = await db.data.facts.filter((f) => + conversationMessageIds.includes(f.sourceMessageId), + ); + return rows as Array; + }), + deleteOne: publicProcedure + .input( + (x) => + x as { + factId: string; + }, + ) + .mutation(async ({ input: { factId } }) => { + const deletedFact = db.data.facts.find((fact) => fact.id === factId); + if (!deletedFact) throw new Error("Fact not found"); + db.data.facts.splice( + db.data.facts.findIndex((fact) => fact.id === factId), + 1, + ); + db.write(); + return { ok: true }; + }), +}); + +export const createCaller = createCallerFactory(facts); diff --git a/pages/chat/messages.ts b/pages/chat/messages.ts new file mode 100644 index 0000000..54634f4 --- /dev/null +++ b/pages/chat/messages.ts @@ -0,0 +1,19 @@ +import { + router, + publicProcedure, + createCallerFactory, +} from "../../trpc/server"; +import { createCaller as createConversationsCaller } from "./conversations.js"; + +export const messages = router({ + fetchByConversationId: publicProcedure + .input((x) => x as { conversationId: string }) + .query(async ({ input: { conversationId } }) => { + const caller = createConversationsCaller({}); + return await caller.fetchMessages({ + conversationId, + }); + }), +}); + +export const createCaller = createCallerFactory(messages); diff --git a/pages/chat/trpc.ts b/pages/chat/trpc.ts index 40deec8..cd7cc03 100644 --- a/pages/chat/trpc.ts +++ b/pages/chat/trpc.ts @@ -2,7 +2,7 @@ import { router, publicProcedure, createCallerFactory, -} from "../../trpc/server"; +} from "../../trpc/server.js"; import { createOpenRouter } from "@openrouter/ai-sdk-provider"; import { generateObject, generateText, jsonSchema } from "ai"; import type { Message as UIMessage } from "ai"; @@ -17,8 +17,11 @@ import { env } from "../../server/env.js"; // ConsistencyLevelEnum, // type NumberArrayId, // } from "@zilliz/milvus2-sdk-node"; -import { db, type Fact } from "../../database/lowdb"; +import { db, type Fact } from "../../database/lowdb.js"; import { nanoid } from "nanoid"; +import { conversations } from "./conversations.js"; +import { messages } from "./messages.js"; +import { facts } from "./facts.js"; const mainSystemPrompt = ({ systemPrompt, @@ -111,69 +114,9 @@ const openrouter = createOpenRouter({ }); export const chat = router({ - listConversations: publicProcedure.query(async () => { - const rows = await db.data.conversations; - return rows; - }), - fetchConversation: publicProcedure - .input((x) => x as { id: string }) - .query(async ({ input: { id } }) => { - const row = await db.data.conversations.find((c) => c.id === id); - return row; - }), - createConversation: publicProcedure.mutation(async () => { - const title = "New Conversation"; - const row = { - id: nanoid(), - title, - userId: "1", - }; - await db.data.conversations.push(row); - db.write(); - return row; - }), - deleteConversation: publicProcedure - .input((x) => x as { id: string }) - .mutation(async ({ input: { id } }) => { - db.data.conversations.splice( - db.data.conversations.findIndex((c) => c.id === id), - 1, - ); - const deletedMessageIds = db.data.messages - .filter((m) => m.conversationId === id) - .map((m) => m.id); - db.data.messages = db.data.messages.filter( - (m) => m.conversationId !== id, - ); - db.data.facts = db.data.facts.filter( - (fact) => !deletedMessageIds.includes(fact.sourceMessageId), - ); - db.write(); - return { ok: true }; - }), - updateConversationTitle: publicProcedure - .input( - (x) => - x as { - id: string; - title: string; - }, - ) - .mutation(async ({ input: { id, title } }) => { - const conversation = await db.data.conversations.find((c) => c.id === id); - if (!conversation) throw new Error("Conversation not found"); - conversation.title = title; - db.write(); - return { ok: true }; - }), - fetchMessages: publicProcedure - .input((x) => x as { conversationId: string }) - .query(async ({ input: { conversationId } }) => { - const rows = await db.data.messages.filter( - (m) => m.conversationId === conversationId, - ); - return rows as Array; - }), + conversations, + messages, + facts, sendMessage: publicProcedure .input( (x) => @@ -395,34 +338,6 @@ export const chat = router({ }; }, ), - fetchFacts: publicProcedure - .input((x) => x as { conversationId: string }) - .query(async ({ input: { conversationId } }) => { - const conversationMessageIds = db.data.messages - .filter((m) => m.conversationId === conversationId) - .map((m) => m.id); - const rows = await db.data.facts.filter((f) => - conversationMessageIds.includes(f.sourceMessageId), - ); - return rows as Array; - }), - deleteFact: publicProcedure - .input( - (x) => - x as { - factId: string; - }, - ) - .mutation(async ({ input: { factId } }) => { - const deletedFact = db.data.facts.find((fact) => fact.id === factId); - if (!deletedFact) throw new Error("Fact not found"); - db.data.facts.splice( - db.data.facts.findIndex((fact) => fact.id === factId), - 1, - ); - db.write(); - return { ok: true }; - }), }); export const createCaller = createCallerFactory(chat);