this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Wire chat app to typed API backend

- Add Hono API routes for characters, chats, and streaming messages
- Add Drizzle SQLite schema, db config, validation, ids, and seed script
- Seed Kitsune and Neko characters with system prompts
- Use character prompt as the system prompt for streamed chat responses
- Replace shared package types with Hono client inferred frontend types
- Connect frontend chat/character hooks to the API client
- Add message sending hook with chat creation, navigation, optimistic
messages, and streaming
updates
- Add typing indicator for pending assistant responses
- Update character select to display character names while using ids
internally
- Remove unused shared package workspace

+851 -157
+2
.gitignore
··· 1 1 dist/ 2 2 node_modules/ 3 3 .tanstack/ 4 + .env* 5 + *.db
+10
apps/api/drizzle.config.ts
··· 1 + import { defineConfig } from "drizzle-kit"; 2 + 3 + export default defineConfig({ 4 + out: "./drizzle", 5 + dialect: "sqlite", 6 + schema: "./src/lib/db/schema.ts", 7 + dbCredentials: { 8 + url: process.env.DB_FILE_NAME ?? "sqlite.db", 9 + }, 10 + });
+16 -4
apps/api/package.json
··· 6 6 ".": "./src/index.ts" 7 7 }, 8 8 "scripts": { 9 - "dev": "bun --watch src/index.ts" 9 + "dev": "bun --watch src/index.ts", 10 + "db:seed": "bun src/seed.ts", 11 + "db:generate": "drizzle-kit generate", 12 + "db:migrate": "drizzle-kit migrate", 13 + "db:push": "drizzle-kit push", 14 + "db:studio": "drizzle-kit studio" 10 15 }, 11 16 "dependencies": { 12 - "@cai/shared": "workspace:*", 13 - "hono": "^4.12.15" 17 + "@ai-sdk/openai": "^3.0.53", 18 + "@hono/zod-validator": "^0.7.6", 19 + "ai": "^6.0.168", 20 + "drizzle-orm": "^0.45.2", 21 + "hono": "^4.12.15", 22 + "nanoid": "^5.1.9", 23 + "zod": "^4.3.6" 14 24 }, 15 25 "devDependencies": { 16 - "@types/bun": "^1.3.13" 26 + "@libsql/client": "^0.17.3", 27 + "@types/bun": "^1.3.13", 28 + "drizzle-kit": "^0.31.10" 17 29 } 18 30 }
+3 -21
apps/api/src/index.ts
··· 1 - import { characters, chats } from "@cai/shared"; 2 1 import { Hono } from "hono"; 3 - 4 - const api = new Hono() 5 - .get("/health", (c) => c.json({ ok: true })) 6 - .get("/characters", (c) => c.json(characters)) 7 - .get("/chats", (c) => { 8 - return c.json( 9 - chats.map((chat) => { 10 - const { messages, ...chatSummary } = chat; 11 - return chatSummary; 12 - }), 13 - ); 14 - }) 15 - .get("/chats/:id", (c) => { 16 - const chat = chats.find((item) => item.id === c.req.param("id")); 17 - 18 - if (!chat) { 19 - return c.json({ message: "Chat not found" }, 404); 20 - } 2 + import { characters } from "./routes/characters"; 3 + import { chats } from "./routes/chats"; 21 4 22 - return c.json(chat); 23 - }); 5 + const api = new Hono().route("/characters", characters).route("/chats", chats); 24 6 25 7 export const app = new Hono().route("/api", api); 26 8
+8
apps/api/src/lib/db/index.ts
··· 1 + import { Database } from "bun:sqlite"; 2 + import { drizzle } from "drizzle-orm/bun-sqlite"; 3 + import * as schema from "./schema"; 4 + 5 + const sqlite = new Database(process.env.DB_FILE_NAME ?? "sqlite.db"); 6 + const db = drizzle({ client: sqlite, schema }); 7 + 8 + export { db, schema, sqlite };
+53
apps/api/src/lib/db/schema.ts
··· 1 + import { relations } from "drizzle-orm"; 2 + import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; 3 + 4 + export const characters = sqliteTable("characters", { 5 + id: text("id").primaryKey(), 6 + name: text("name").notNull(), 7 + prompt: text("prompt").notNull().default(""), 8 + createdAt: integer("created_at", { mode: "timestamp_ms" }) 9 + .notNull() 10 + .$defaultFn(() => new Date()), 11 + }); 12 + 13 + export const chats = sqliteTable("chats", { 14 + id: text("id").primaryKey(), 15 + title: text("title").notNull(), 16 + characterId: text("character_id") 17 + .notNull() 18 + .references(() => characters.id), 19 + createdAt: integer("created_at", { mode: "timestamp_ms" }) 20 + .notNull() 21 + .$defaultFn(() => new Date()), 22 + }); 23 + 24 + export const messages = sqliteTable("messages", { 25 + id: text("id").primaryKey(), 26 + chatId: text("chat_id") 27 + .notNull() 28 + .references(() => chats.id, { onDelete: "cascade" }), 29 + role: text("role", { enum: ["assistant", "user"] }).notNull(), 30 + text: text("text").notNull(), 31 + createdAt: integer("created_at", { mode: "timestamp_ms" }) 32 + .notNull() 33 + .$defaultFn(() => new Date()), 34 + }); 35 + 36 + export const charactersRelations = relations(characters, ({ many }) => ({ 37 + chats: many(chats), 38 + })); 39 + 40 + export const chatsRelations = relations(chats, ({ many, one }) => ({ 41 + character: one(characters, { 42 + fields: [chats.characterId], 43 + references: [characters.id], 44 + }), 45 + messages: many(messages), 46 + })); 47 + 48 + export const messagesRelations = relations(messages, ({ one }) => ({ 49 + chat: one(chats, { 50 + fields: [messages.chatId], 51 + references: [chats.id], 52 + }), 53 + }));
+8
apps/api/src/lib/db/types.ts
··· 1 + import type { characters, chats, messages } from "./schema"; 2 + 3 + export type Character = typeof characters.$inferSelect; 4 + export type NewCharacter = typeof characters.$inferInsert; 5 + export type Chat = typeof chats.$inferSelect; 6 + export type NewChat = typeof chats.$inferInsert; 7 + export type Message = typeof messages.$inferSelect; 8 + export type NewMessage = typeof messages.$inferInsert;
+6
apps/api/src/lib/id.ts
··· 1 + import { customAlphabet } from "nanoid"; 2 + 3 + export const nanoid = customAlphabet( 4 + "abcdefghijklmnopqrstuvwxyz0123456789", 5 + 10, 6 + );
+15
apps/api/src/lib/schema.ts
··· 1 + import z from "zod"; 2 + 3 + export const characterSchema = z.object({ 4 + name: z.string().min(1), 5 + prompt: z.string().min(1), 6 + }); 7 + 8 + export const chatSchema = z.object({ 9 + title: z.string().min(1), 10 + characterId: z.string().min(1), 11 + }); 12 + 13 + export const messageSchema = z.object({ 14 + text: z.string().min(1), 15 + });
+54
apps/api/src/routes/characters.ts
··· 1 + import { zValidator } from "@hono/zod-validator"; 2 + import { eq } from "drizzle-orm"; 3 + import { Hono } from "hono"; 4 + import { db, schema } from "../lib/db"; 5 + import { nanoid } from "../lib/id"; 6 + import { characterSchema } from "../lib/schema"; 7 + 8 + const app = new Hono() 9 + .get("/", async (c) => { 10 + const res = await db.query.characters.findMany(); 11 + 12 + return c.json(res, 200); 13 + }) 14 + .get("/:id", async (c) => { 15 + const { id } = c.req.param(); 16 + 17 + const res = await db.query.characters.findFirst({ 18 + where: eq(schema.characters.id, id), 19 + }); 20 + 21 + if (!res) return c.json({ message: "Not found" }, 404); 22 + 23 + return c.json(res, 200); 24 + }) 25 + .post("/", zValidator("json", characterSchema), async (c) => { 26 + const body = c.req.valid("json"); 27 + const id = nanoid(); 28 + 29 + db.insert(schema.characters) 30 + .values({ id, ...body }) 31 + .run(); 32 + 33 + return c.json({ id }, 201); 34 + }) 35 + .patch("/:id", zValidator("json", characterSchema.partial()), async (c) => { 36 + const { id } = c.req.param(); 37 + const body = c.req.valid("json"); 38 + 39 + db.update(schema.characters) 40 + .set({ ...body }) 41 + .where(eq(schema.characters.id, id)) 42 + .run(); 43 + 44 + return c.json({ id }); 45 + }) 46 + .delete("/:id", async (c) => { 47 + const { id } = c.req.param(); 48 + 49 + db.delete(schema.characters).where(eq(schema.characters.id, id)).run(); 50 + 51 + return c.json({ id }); 52 + }); 53 + 54 + export { app as characters };
+105
apps/api/src/routes/chats.ts
··· 1 + import { openai } from "@ai-sdk/openai"; 2 + import { zValidator } from "@hono/zod-validator"; 3 + import { streamText } from "ai"; 4 + import { asc, desc, eq } from "drizzle-orm"; 5 + import { Hono } from "hono"; 6 + import { db, schema } from "../lib/db"; 7 + import { nanoid } from "../lib/id"; 8 + import { chatSchema, messageSchema } from "../lib/schema"; 9 + 10 + const app = new Hono() 11 + .get("/", async (c) => { 12 + const res = await db.query.chats.findMany({ 13 + orderBy: desc(schema.chats.createdAt), 14 + }); 15 + 16 + return c.json(res, 200); 17 + }) 18 + .get("/:id", async (c) => { 19 + const { id } = c.req.param(); 20 + 21 + const res = await db.query.chats.findFirst({ 22 + where: eq(schema.chats.id, id), 23 + with: { messages: true }, 24 + }); 25 + 26 + if (!res) return c.json({ message: "Not found" }, 404); 27 + 28 + return c.json(res, 200); 29 + }) 30 + .post("/", zValidator("json", chatSchema), async (c) => { 31 + const body = c.req.valid("json"); 32 + const id = nanoid(); 33 + 34 + db.insert(schema.chats) 35 + .values({ id, ...body }) 36 + .run(); 37 + 38 + const chat = await db.query.chats.findFirst({ 39 + where: eq(schema.chats.id, id), 40 + }); 41 + 42 + if (!chat) return c.json({ message: "Not found" }, 404); 43 + 44 + return c.json(chat, 201); 45 + }) 46 + .post("/:id/messages", zValidator("json", messageSchema), async (c) => { 47 + const { id } = c.req.param(); 48 + const body = c.req.valid("json"); 49 + const messageId = nanoid(); 50 + 51 + db.insert(schema.messages) 52 + .values({ id: messageId, chatId: id, role: "user", ...body }) 53 + .run(); 54 + 55 + const chat = await db.query.chats.findFirst({ 56 + where: eq(schema.chats.id, id), 57 + with: { character: true }, 58 + }); 59 + 60 + if (!chat) return c.json({ message: "Not found" }, 404); 61 + 62 + const messages = await db.query.messages.findMany({ 63 + where: eq(schema.messages.chatId, id), 64 + orderBy: asc(schema.messages.createdAt), 65 + }); 66 + 67 + const res = streamText({ 68 + model: openai("gpt-5.4-mini"), 69 + system: chat.character.prompt, 70 + messages: messages.map((message) => ({ 71 + role: message.role, 72 + content: message.text, 73 + })), 74 + async onFinish({ text }) { 75 + db.insert(schema.messages) 76 + .values({ id: nanoid(), chatId: id, role: "assistant", text }) 77 + .run(); 78 + }, 79 + }); 80 + 81 + return res.toTextStreamResponse(); 82 + }) 83 + .patch("/:id", zValidator("json", chatSchema.partial()), async (c) => { 84 + const { id } = c.req.param(); 85 + const body = c.req.valid("json"); 86 + 87 + db.update(schema.chats).set(body).where(eq(schema.chats.id, id)).run(); 88 + 89 + const chat = await db.query.chats.findFirst({ 90 + where: eq(schema.chats.id, id), 91 + }); 92 + 93 + if (!chat) return c.json({ message: "Not found" }, 404); 94 + 95 + return c.json(chat, 200); 96 + }) 97 + .delete("/:id", (c) => { 98 + const { id } = c.req.param(); 99 + 100 + db.delete(schema.chats).where(eq(schema.chats.id, id)).run(); 101 + 102 + return c.json({ id, deleted: true }); 103 + }); 104 + 105 + export { app as chats };
+30
apps/api/src/seed.ts
··· 1 + import { sql } from "drizzle-orm"; 2 + import { db, schema } from "./lib/db"; 3 + 4 + const characters = [ 5 + { 6 + id: "kitsune", 7 + name: "Kitsune", 8 + prompt: 9 + "You are Kitsune, a clever and warm AI character. You speak with playful confidence, offer thoughtful help, and keep responses concise unless the user asks for depth.", 10 + }, 11 + { 12 + id: "neko", 13 + name: "Neko", 14 + prompt: 15 + "You are Neko, a curious and upbeat AI character. You are friendly, direct, and lightly playful while still giving useful answers.", 16 + }, 17 + ]; 18 + 19 + db.insert(schema.characters) 20 + .values(characters) 21 + .onConflictDoUpdate({ 22 + target: schema.characters.id, 23 + set: { 24 + name: sql`excluded.name`, 25 + prompt: sql`excluded.prompt`, 26 + }, 27 + }) 28 + .run(); 29 + 30 + console.log("Seeded default characters");
+2 -1
apps/api/tsconfig.json
··· 2 2 "extends": "../../tsconfig.json", 3 3 "include": ["src/**/*.ts"], 4 4 "compilerOptions": { 5 - "lib": ["ES2022", "DOM"] 5 + "lib": ["ES2022", "DOM"], 6 + "types": ["bun"] 6 7 } 7 8 }
-1
apps/web/package.json
··· 10 10 "dependencies": { 11 11 "@base-ui/react": "^1.4.1", 12 12 "@cai/api": "workspace:*", 13 - "@cai/shared": "workspace:*", 14 13 "@fontsource-variable/dm-sans": "^5.2.8", 15 14 "@tailwindcss/vite": "^4.1.18", 16 15 "@tanstack/react-query": "^5.100.5",
+9 -9
apps/web/src/components/character-select.tsx
··· 1 - import { DynamicIcon } from "lucide-react/dynamic"; 2 1 import type * as React from "react"; 3 2 import { useCharacters } from "#/hooks/use-characters"; 4 3 import { ··· 13 12 14 13 export function CharacterSelect(props: React.ComponentProps<typeof Select>) { 15 14 const { data: characters = [] } = useCharacters(); 15 + const characterNames = new Map( 16 + characters.map((character) => [character.id, character.name]), 17 + ); 16 18 17 19 return ( 18 20 <Select {...props}> 19 21 <SelectTrigger className="min-w-40 px-4 data-[size=default]:h-10"> 20 - <SelectValue placeholder="Characters" /> 22 + <SelectValue placeholder="Characters"> 23 + {(value) => 24 + typeof value === "string" ? (characterNames.get(value) ?? value) : null 25 + } 26 + </SelectValue> 21 27 </SelectTrigger> 22 28 <SelectContent alignItemWithTrigger={false}> 23 29 <SelectGroup> 24 30 <SelectLabel>Characters</SelectLabel> 25 31 {characters.map((character) => ( 26 - <SelectItem key={character.id} value={character.name}> 32 + <SelectItem key={character.id} value={character.id}> 27 33 {character.name} 28 - <DynamicIcon 29 - name={character.icon} 30 - className="size-4 self-center" 31 - strokeWidth={0} 32 - fill="currentColor" 33 - /> 34 34 </SelectItem> 35 35 ))} 36 36 </SelectGroup>
+49 -5
apps/web/src/components/chat-form.tsx
··· 1 1 import { SendIcon } from "lucide-react"; 2 + import { useEffect, useState } from "react"; 3 + import { useCharacters } from "#/hooks/use-characters"; 4 + import { useSendMessage } from "#/hooks/use-send-message"; 2 5 import { CharacterSelect } from "./character-select"; 3 6 import { Row, Stack } from "./layout"; 4 7 import { Button } from "./ui/button"; 5 8 import { Textarea } from "./ui/textarea"; 6 9 7 - export function ChatForm() { 10 + interface ChatFormProps { 11 + chatId?: string; 12 + characterId?: string; 13 + } 14 + 15 + export function ChatForm({ chatId, characterId: chatCharacterId }: ChatFormProps) { 16 + const { data: characters = [] } = useCharacters(); 17 + const sendMessage = useSendMessage(); 18 + const [characterId, setCharacterId] = useState<string | null>(null); 19 + const [text, setText] = useState(""); 20 + const selectedCharacterId = chatCharacterId ?? characterId; 21 + 22 + useEffect(() => { 23 + if (!chatCharacterId && !characterId && characters[0]) { 24 + setCharacterId(characters[0].id); 25 + } 26 + }, [chatCharacterId, characterId, characters]); 27 + 28 + const isDisabled = 29 + sendMessage.isPending || !text.trim() || (!chatId && !selectedCharacterId); 30 + 8 31 return ( 9 - <form> 32 + <form 33 + onSubmit={(event) => { 34 + event.preventDefault(); 35 + sendMessage.mutate( 36 + { chatId, characterId: selectedCharacterId, text }, 37 + { 38 + onSuccess: () => setText(""), 39 + }, 40 + ); 41 + }} 42 + > 10 43 <Stack gap="sm"> 11 44 <Textarea 12 45 placeholder="Write your message here..." 13 46 className="wrap-anywhere min-h-25 focus-visible:border-transparent focus-visible:ring-0" 47 + value={text} 48 + onChange={(event) => setText(event.currentTarget.value)} 49 + disabled={sendMessage.isPending} 14 50 /> 15 51 <Row justify="between" items="end"> 16 - <CharacterSelect /> 17 - <Button type="submit" size="lg"> 18 - Send 52 + <CharacterSelect 53 + value={selectedCharacterId} 54 + onValueChange={(value) => { 55 + if (typeof value === "string") { 56 + setCharacterId(value); 57 + } 58 + }} 59 + disabled={sendMessage.isPending || Boolean(chatId)} 60 + /> 61 + <Button type="submit" size="lg" disabled={isDisabled}> 62 + {sendMessage.isPending ? "Sending" : "Send"} 19 63 <SendIcon /> 20 64 </Button> 21 65 </Row>
+7 -2
apps/web/src/components/chat-messages.tsx
··· 1 1 import type { ChatMessage as ChatMessageType } from "#/lib/types"; 2 2 import { ChatMessage } from "./chat-message"; 3 3 import { Stack } from "./layout"; 4 + import { TypingIndicator } from "./typing-indicator"; 4 5 5 6 interface ChatMessageProps { 6 7 messages: ChatMessageType[]; ··· 10 11 return ( 11 12 <Stack> 12 13 {messages.map((message) => ( 13 - <ChatMessage key={message.id} author={message.author}> 14 - <p>{message.text}</p> 14 + <ChatMessage key={message.id} author={message.role}> 15 + {message.role === "assistant" && message.text.length === 0 ? ( 16 + <TypingIndicator /> 17 + ) : ( 18 + <p>{message.text}</p> 19 + )} 15 20 </ChatMessage> 16 21 ))} 17 22 </Stack>
+2 -2
apps/web/src/components/chat.tsx
··· 8 8 } 9 9 10 10 export function Chat({ chatId }: ChatProps) { 11 - const { messages } = useChat({ id: chatId }); 11 + const { chat, messages } = useChat({ id: chatId }); 12 12 13 13 return ( 14 14 <Stack justify="between" className="flex-1 py-4 md:py-8"> 15 15 <ChatMessages messages={messages} /> 16 - <ChatForm /> 16 + <ChatForm chatId={chatId} characterId={chat?.characterId} /> 17 17 </Stack> 18 18 ); 19 19 }
+2 -1
apps/web/src/components/layout.tsx
··· 1 1 import { cva, type VariantProps } from "class-variance-authority"; 2 2 import { cn } from "#/lib/utils"; 3 3 4 - const layout = cva("flex flex-wrap", { 4 + const layout = cva("flex", { 5 5 variants: { 6 6 direction: { 7 7 horizontal: "flex-row", 8 8 vertical: "flex-col", 9 9 }, 10 10 gap: { 11 + xs: "gap-1", 11 12 sm: "gap-2", 12 13 md: "gap-4", 13 14 lg: "gap-6",
+11
apps/web/src/components/typing-indicator.tsx
··· 1 + import { Row } from "./layout"; 2 + 3 + export function TypingIndicator() { 4 + return ( 5 + <Row items="center" gap="xs" className="h-lh" aria-label="Assistant typing"> 6 + <span className="size-1 animate-bounce rounded-full bg-current [animation-delay:-240ms]" /> 7 + <span className="size-1 animate-bounce rounded-full bg-current [animation-delay:-120ms]" /> 8 + <span className="size-1 animate-bounce rounded-full bg-current" /> 9 + </Row> 10 + ); 11 + }
+2 -2
apps/web/src/hooks/use-characters.ts
··· 1 1 import { useQuery } from "@tanstack/react-query"; 2 - import { api } from "#/lib/api"; 2 + import { client } from "#/lib/api"; 3 3 4 4 export function useCharacters() { 5 5 return useQuery({ 6 6 queryKey: ["characters"], 7 7 queryFn: async () => { 8 - const response = await api.api.characters.$get(); 8 + const response = await client.api.characters.$get(); 9 9 10 10 if (!response.ok) { 11 11 throw new Error("Failed to load characters");
+2 -2
apps/web/src/hooks/use-chat.ts
··· 1 1 import { useQuery } from "@tanstack/react-query"; 2 - import { api } from "#/lib/api"; 2 + import { client } from "#/lib/api"; 3 3 4 4 interface UseChatOptions { 5 5 id: string; ··· 9 9 const chatQuery = useQuery({ 10 10 queryKey: ["chat", id], 11 11 queryFn: async () => { 12 - const response = await api.api.chats[":id"].$get({ 12 + const response = await client.api.chats[":id"].$get({ 13 13 param: { id }, 14 14 }); 15 15
+2 -2
apps/web/src/hooks/use-chats.ts
··· 1 1 import { useQuery } from "@tanstack/react-query"; 2 - import { api } from "#/lib/api"; 2 + import { client } from "#/lib/api"; 3 3 4 4 export function useChats() { 5 5 return useQuery({ 6 6 queryKey: ["chats"], 7 7 queryFn: async () => { 8 - const response = await api.api.chats.$get(); 8 + const response = await client.api.chats.$get(); 9 9 10 10 if (!response.ok) { 11 11 throw new Error("Failed to load chats");
+182
apps/web/src/hooks/use-send-message.ts
··· 1 + import { 2 + type QueryClient, 3 + useMutation, 4 + useQueryClient, 5 + } from "@tanstack/react-query"; 6 + import { useNavigate } from "@tanstack/react-router"; 7 + import { client } from "#/lib/api"; 8 + import type { Chat, ChatMessage } from "#/lib/types"; 9 + 10 + const chatQueryKey = (chatId: string) => ["chat", chatId] as const; 11 + 12 + interface SendMessageInput { 13 + chatId?: string; 14 + characterId: string | null; 15 + text: string; 16 + } 17 + 18 + function createMessage(chatId: string, role: ChatMessage["role"], text = "") { 19 + return { 20 + id: `optimistic-${role}-${crypto.randomUUID()}`, 21 + chatId, 22 + role, 23 + text, 24 + createdAt: new Date().toISOString(), 25 + }; 26 + } 27 + 28 + function setMessages( 29 + queryClient: QueryClient, 30 + chatId: string, 31 + update: (messages: ChatMessage[]) => ChatMessage[], 32 + ) { 33 + queryClient.setQueryData<Chat | undefined>(chatQueryKey(chatId), (chat) => { 34 + if (!chat) return chat; 35 + 36 + return { 37 + ...chat, 38 + messages: update(chat.messages), 39 + }; 40 + }); 41 + } 42 + 43 + function patchMessage( 44 + queryClient: QueryClient, 45 + chatId: string, 46 + messageId: string, 47 + update: (message: ChatMessage) => ChatMessage, 48 + ) { 49 + setMessages(queryClient, chatId, (messages) => 50 + messages.map((message) => 51 + message.id === messageId ? update(message) : message, 52 + ), 53 + ); 54 + } 55 + 56 + async function sendMessageToChat(chatId: string, text: string) { 57 + const response = await client.api.chats[":id"].messages.$post({ 58 + param: { id: chatId }, 59 + json: { text }, 60 + }); 61 + 62 + if (!response.ok) { 63 + throw new Error("Failed to send message"); 64 + } 65 + 66 + return response; 67 + } 68 + 69 + async function readTextStream( 70 + response: Response, 71 + onChunk: (chunk: string) => void, 72 + ) { 73 + if (!response.body) { 74 + onChunk(await response.text()); 75 + return; 76 + } 77 + 78 + const reader = response.body.getReader(); 79 + const decoder = new TextDecoder(); 80 + 81 + while (true) { 82 + const { done, value } = await reader.read(); 83 + 84 + if (done) break; 85 + 86 + onChunk(decoder.decode(value, { stream: true })); 87 + } 88 + 89 + const remainingText = decoder.decode(); 90 + 91 + if (remainingText) { 92 + onChunk(remainingText); 93 + } 94 + } 95 + 96 + export function useSendMessage() { 97 + const navigate = useNavigate(); 98 + const queryClient = useQueryClient(); 99 + 100 + async function getChatId({ 101 + chatId, 102 + characterId, 103 + text, 104 + }: SendMessageInput) { 105 + if (chatId) return chatId; 106 + 107 + if (!characterId) { 108 + throw new Error("Character is required"); 109 + } 110 + 111 + const response = await client.api.chats.$post({ 112 + json: { 113 + title: text, 114 + characterId, 115 + }, 116 + }); 117 + 118 + if (!response.ok) { 119 + throw new Error("Failed to create chat"); 120 + } 121 + 122 + const chat = await response.json(); 123 + 124 + queryClient.setQueryData<Chat>(chatQueryKey(chat.id), { 125 + ...chat, 126 + messages: [], 127 + }); 128 + await queryClient.invalidateQueries({ queryKey: ["chats"] }); 129 + await navigate({ to: "/chats/$chatId", params: { chatId: chat.id } }); 130 + 131 + return chat.id; 132 + } 133 + 134 + return useMutation({ 135 + mutationFn: async ({ chatId, characterId, text }: SendMessageInput) => { 136 + const trimmedText = text.trim(); 137 + 138 + if (!trimmedText) { 139 + throw new Error("Message is required"); 140 + } 141 + 142 + const id = await getChatId({ 143 + chatId, 144 + characterId, 145 + text: trimmedText, 146 + }); 147 + 148 + await queryClient.cancelQueries({ queryKey: chatQueryKey(id) }); 149 + 150 + const userMessage = createMessage(id, "user", trimmedText); 151 + const assistantMessage = createMessage(id, "assistant"); 152 + 153 + setMessages(queryClient, id, (messages) => [ 154 + ...messages, 155 + userMessage, 156 + assistantMessage, 157 + ]); 158 + 159 + try { 160 + const response = await sendMessageToChat(id, trimmedText); 161 + 162 + await readTextStream(response, (chunk) => { 163 + patchMessage(queryClient, id, assistantMessage.id, (message) => ({ 164 + ...message, 165 + text: `${message.text}${chunk}`, 166 + })); 167 + }); 168 + } catch (error) { 169 + patchMessage(queryClient, id, assistantMessage.id, (message) => ({ 170 + ...message, 171 + text: "Failed to stream response.", 172 + })); 173 + throw error; 174 + } finally { 175 + await queryClient.invalidateQueries({ queryKey: chatQueryKey(id) }); 176 + await queryClient.invalidateQueries({ queryKey: ["chats"] }); 177 + } 178 + 179 + return { id }; 180 + }, 181 + }); 182 + }
+1 -1
apps/web/src/lib/api.ts
··· 1 1 import type { AppType } from "@cai/api"; 2 2 import { hc } from "hono/client"; 3 3 4 - export const api = hc<AppType>("/"); 4 + export const client = hc<AppType>("/");
+11 -1
apps/web/src/lib/types.ts
··· 1 - export type { Character, Chat, ChatMessage, ChatSummary } from "@cai/shared"; 1 + import type { InferResponseType } from "hono/client"; 2 + import type { client } from "./api"; 3 + 4 + type GetCharacters = typeof client.api.characters.$get; 5 + type GetChats = typeof client.api.chats.$get; 6 + type GetChat = (typeof client.api.chats)[":id"]["$get"]; 7 + 8 + export type Character = InferResponseType<GetCharacters>[number]; 9 + export type ChatSummary = InferResponseType<GetChats>[number]; 10 + export type Chat = InferResponseType<GetChat, 200>; 11 + export type ChatMessage = Chat["messages"][number];
+1 -1
apps/web/tsconfig.json
··· 7 7 "#/*": ["./src/*"] 8 8 }, 9 9 "lib": ["ES2022", "DOM", "DOM.Iterable"], 10 - "types": ["vite/client", "node"] 10 + "types": ["vite/client", "node", "bun"] 11 11 } 12 12 }
-1
biome.json
··· 3 3 "files": { 4 4 "includes": [ 5 5 "apps/**/*.{html,css,js,jsx,ts,tsx,json}", 6 - "packages/**/*.{html,css,js,jsx,ts,tsx,json}", 7 6 "!**/dist", 8 7 "!apps/web/src/routeTree.gen.ts" 9 8 ]
+256 -10
bun.lock
··· 6 6 "name": "cai", 7 7 "devDependencies": { 8 8 "@biomejs/biome": "^2.4.13", 9 + "@types/bun": "^1.3.13", 9 10 }, 10 11 }, 11 12 "apps/api": { 12 13 "name": "@cai/api", 13 14 "dependencies": { 14 - "@cai/shared": "workspace:*", 15 + "@ai-sdk/openai": "^3.0.53", 16 + "@hono/zod-validator": "^0.7.6", 17 + "ai": "^6.0.168", 18 + "drizzle-orm": "^0.45.2", 15 19 "hono": "^4.12.15", 20 + "nanoid": "^5.1.9", 21 + "zod": "^4.3.6", 16 22 }, 17 23 "devDependencies": { 24 + "@libsql/client": "^0.17.3", 18 25 "@types/bun": "^1.3.13", 26 + "drizzle-kit": "^0.31.10", 19 27 }, 20 28 }, 21 29 "apps/web": { ··· 23 31 "dependencies": { 24 32 "@base-ui/react": "^1.4.1", 25 33 "@cai/api": "workspace:*", 26 - "@cai/shared": "workspace:*", 27 34 "@fontsource-variable/dm-sans": "^5.2.8", 28 35 "@tailwindcss/vite": "^4.1.18", 29 36 "@tanstack/react-query": "^5.100.5", ··· 49 56 "vite": "^8.0.0", 50 57 }, 51 58 }, 52 - "packages/shared": { 53 - "name": "@cai/shared", 54 - }, 55 59 }, 56 60 "packages": { 61 + "@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.104", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZKX5n74io8VIRlhIMSLWVlvT3sXC8Z7cZ9GHuWBWZDVi96+62AIsWuLGvMfcBA1STYuSoDrp6rIziZmvrTq0TA=="], 62 + 63 + "@ai-sdk/openai": ["@ai-sdk/openai@3.0.53", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Wld+Rbc05KaUn08uBt06eEuwcgalcIFtIl32Yp+GxuZXUQwOb6YeAuq+C6da4ch6BurFoqEaLemJVwjBb7x+PQ=="], 64 + 65 + "@ai-sdk/provider": ["@ai-sdk/provider@3.0.8", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ=="], 66 + 67 + "@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.23", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-z8GlDaCmRSDlqkMF2f4/RFgWxdarvIbyuk+m6WXT1LYgsnGiXRJGTD2Z1+SDl3LqtFuRtGX1aghYvQLoHL/9pg=="], 68 + 57 69 "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], 58 70 59 71 "@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="], ··· 136 148 137 149 "@cai/api": ["@cai/api@workspace:apps/api"], 138 150 139 - "@cai/shared": ["@cai/shared@workspace:packages/shared"], 140 - 141 151 "@cai/web": ["@cai/web@workspace:apps/web"], 142 152 143 153 "@dotenvx/dotenvx": ["@dotenvx/dotenvx@1.63.0", "", { "dependencies": { "commander": "^11.1.0", "dotenv": "^17.2.1", "eciesjs": "^0.4.10", "execa": "^5.1.1", "fdir": "^6.2.0", "ignore": "^5.3.0", "object-treeify": "1.1.33", "picomatch": "^4.0.4", "which": "^4.0.0", "yocto-spinner": "^1.1.0" }, "bin": { "dotenvx": "src/cli/dotenvx.js" } }, "sha512-jjkmzIRu19uH78AjFInqfcALehbDCZZ7M09hurVawyqNxtOXEg2LR73L59y4QnzfYDEzjbhVzGAd2uDHu0D1aQ=="], 154 + 155 + "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], 144 156 145 157 "@ecies/ciphers": ["@ecies/ciphers@0.2.6", "", { "peerDependencies": { "@noble/ciphers": "^1.0.0" } }, "sha512-patgsRPKGkhhoBjETV4XxD0En4ui5fbX0hzayqI3M8tvNMGUoUvmyYAIWwlxBc1KX5cturfqByYdj5bYGRpN9g=="], 146 158 ··· 150 162 151 163 "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], 152 164 165 + "@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="], 166 + 167 + "@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="], 168 + 169 + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], 170 + 171 + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], 172 + 173 + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], 174 + 175 + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], 176 + 177 + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], 178 + 179 + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], 180 + 181 + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], 182 + 183 + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], 184 + 185 + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], 186 + 187 + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], 188 + 189 + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], 190 + 191 + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], 192 + 193 + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], 194 + 195 + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], 196 + 197 + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], 198 + 199 + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], 200 + 201 + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], 202 + 203 + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], 204 + 205 + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], 206 + 207 + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], 208 + 209 + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], 210 + 211 + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], 212 + 213 + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], 214 + 215 + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], 216 + 217 + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], 218 + 219 + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], 220 + 153 221 "@floating-ui/core": ["@floating-ui/core@1.7.5", "", { "dependencies": { "@floating-ui/utils": "^0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="], 154 222 155 223 "@floating-ui/dom": ["@floating-ui/dom@1.7.6", "", { "dependencies": { "@floating-ui/core": "^1.7.5", "@floating-ui/utils": "^0.2.11" } }, "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ=="], ··· 161 229 "@fontsource-variable/dm-sans": ["@fontsource-variable/dm-sans@5.2.8", "", {}, "sha512-AxkvMTvNWgfrmlyjiV05vlHYJa+nRQCf1EfvIrQAPBpFJW0O9VTz7oAFr9S3lvbWdmnFoBk7yFqQL86u64nl2g=="], 162 230 163 231 "@hono/node-server": ["@hono/node-server@1.19.14", "", { "peerDependencies": { "hono": "^4" } }, "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw=="], 232 + 233 + "@hono/zod-validator": ["@hono/zod-validator@0.7.6", "", { "peerDependencies": { "hono": ">=3.9.0", "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Io1B6d011Gj1KknV4rXYz4le5+5EubcWEU/speUjuw9XMMIaP3n78yXLhjd2A3PXaXaUwEAluOiAyLqhBEJgsw=="], 164 234 165 235 "@inquirer/ansi": ["@inquirer/ansi@2.0.5", "", {}, "sha512-doc2sWgJpbFQ64UflSVd17ibMGDuxO1yKgOgLMwavzESnXjFWJqUeG8saYosqKpHp4kWiM5x1nXvEjbpx90gzw=="], 166 236 ··· 182 252 183 253 "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], 184 254 255 + "@libsql/client": ["@libsql/client@0.17.3", "", { "dependencies": { "@libsql/core": "^0.17.3", "@libsql/hrana-client": "^0.10.0", "js-base64": "^3.7.5", "libsql": "^0.5.28", "promise-limit": "^2.7.0" } }, "sha512-HXk9wiAoJbKFbyBH4O+aEhN6ir5ERXuXvwE5OD2eR4/5RUa3Pw/8L9zrnVdU+iNJitRvisPWaIwmhkO3bH7giA=="], 256 + 257 + "@libsql/core": ["@libsql/core@0.17.3", "", { "dependencies": { "js-base64": "^3.7.5" } }, "sha512-2UjK1i7JBkMduJo4WdvvBxMMvVJ31pArBZNONyz/GCJJAH+1UHat2X6vn10S/WpY5fKzIT98WqYFl2vzWRLOfg=="], 258 + 259 + "@libsql/darwin-arm64": ["@libsql/darwin-arm64@0.5.29", "", { "os": "darwin", "cpu": "arm64" }, "sha512-K+2RIB1OGFPYQbfay48GakLhqf3ArcbHqPFu7EZiaUcRgFcdw8RoltsMyvbj5ix2fY0HV3Q3Ioa/ByvQdaSM0A=="], 260 + 261 + "@libsql/darwin-x64": ["@libsql/darwin-x64@0.5.29", "", { "os": "darwin", "cpu": "x64" }, "sha512-OtT+KFHsKFy1R5FVadr8FJ2Bb1mghtXTyJkxv0trocq7NuHntSki1eUbxpO5ezJesDvBlqFjnWaYYY516QNLhQ=="], 262 + 263 + "@libsql/hrana-client": ["@libsql/hrana-client@0.10.0", "", { "dependencies": { "@libsql/isomorphic-ws": "^0.1.5", "js-base64": "^3.7.5" } }, "sha512-OoA4EMqRAC7kn7V2P6EQqRcpZf2W+AjsNIyCizBg339Tq/aMC7sRnzs3SklderhmQWAqEzvv8A2vhxVmWpkVvw=="], 264 + 265 + "@libsql/isomorphic-ws": ["@libsql/isomorphic-ws@0.1.5", "", { "dependencies": { "@types/ws": "^8.5.4", "ws": "^8.13.0" } }, "sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg=="], 266 + 267 + "@libsql/linux-arm-gnueabihf": ["@libsql/linux-arm-gnueabihf@0.5.29", "", { "os": "linux", "cpu": "arm" }, "sha512-CD4n4zj7SJTHso4nf5cuMoWoMSS7asn5hHygsDuhRl8jjjCTT3yE+xdUvI4J7zsyb53VO5ISh4cwwOtf6k2UhQ=="], 268 + 269 + "@libsql/linux-arm-musleabihf": ["@libsql/linux-arm-musleabihf@0.5.29", "", { "os": "linux", "cpu": "arm" }, "sha512-2Z9qBVpEJV7OeflzIR3+l5yAd4uTOLxklScYTwpZnkm2vDSGlC1PRlueLaufc4EFITkLKXK2MWBpexuNJfMVcg=="], 270 + 271 + "@libsql/linux-arm64-gnu": ["@libsql/linux-arm64-gnu@0.5.29", "", { "os": "linux", "cpu": "arm64" }, "sha512-gURBqaiXIGGwFNEaUj8Ldk7Hps4STtG+31aEidCk5evMMdtsdfL3HPCpvys+ZF/tkOs2MWlRWoSq7SOuCE9k3w=="], 272 + 273 + "@libsql/linux-arm64-musl": ["@libsql/linux-arm64-musl@0.5.29", "", { "os": "linux", "cpu": "arm64" }, "sha512-fwgYZ0H8mUkyVqXZHF3mT/92iIh1N94Owi/f66cPVNsk9BdGKq5gVpoKO+7UxaNzuEH1roJp2QEwsCZMvBLpqg=="], 274 + 275 + "@libsql/linux-x64-gnu": ["@libsql/linux-x64-gnu@0.5.29", "", { "os": "linux", "cpu": "x64" }, "sha512-y14V0vY0nmMC6G0pHeJcEarcnGU2H6cm21ZceRkacWHvQAEhAG0latQkCtoS2njFOXiYIg+JYPfAoWKbi82rkg=="], 276 + 277 + "@libsql/linux-x64-musl": ["@libsql/linux-x64-musl@0.5.29", "", { "os": "linux", "cpu": "x64" }, "sha512-gquqwA/39tH4pFl+J9n3SOMSymjX+6kZ3kWgY3b94nXFTwac9bnFNMffIomgvlFaC4ArVqMnOZD3nuJ3H3VO1w=="], 278 + 279 + "@libsql/win32-x64-msvc": ["@libsql/win32-x64-msvc@0.5.29", "", { "os": "win32", "cpu": "x64" }, "sha512-4/0CvEdhi6+KjMxMaVbFM2n2Z44escBRoEYpR+gZg64DdetzGnYm8mcNLcoySaDJZNaBd6wz5DNdgRmcI4hXcg=="], 280 + 185 281 "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="], 186 282 187 283 "@mswjs/interceptors": ["@mswjs/interceptors@0.41.6", "", { "dependencies": { "@open-draft/deferred-promise": "^2.2.0", "@open-draft/logger": "^0.3.0", "@open-draft/until": "^2.0.0", "is-node-process": "^1.2.0", "outvariant": "^1.4.3", "strict-event-emitter": "^0.5.1" } }, "sha512-qmDvJIjcNsZ6tXWy2G9yuCgMPTTn35GMA3dPpSLm7QJVpbQzYdw0ALy1bKoivXnEM3U93/OrK+/M719b+fg84Q=="], 188 284 189 285 "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], 286 + 287 + "@neon-rs/load": ["@neon-rs/load@0.0.4", "", {}, "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw=="], 190 288 191 289 "@noble/ciphers": ["@noble/ciphers@1.3.0", "", {}, "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw=="], 192 290 ··· 205 303 "@open-draft/logger": ["@open-draft/logger@0.3.0", "", { "dependencies": { "is-node-process": "^1.2.0", "outvariant": "^1.4.0" } }, "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ=="], 206 304 207 305 "@open-draft/until": ["@open-draft/until@2.1.0", "", {}, "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg=="], 306 + 307 + "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], 208 308 209 309 "@oxc-project/types": ["@oxc-project/types@0.127.0", "", {}, "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ=="], 210 310 ··· 243 343 "@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="], 244 344 245 345 "@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="], 346 + 347 + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], 246 348 247 349 "@tailwindcss/node": ["@tailwindcss/node@4.2.4", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.4" } }, "sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA=="], 248 350 ··· 316 418 317 419 "@types/validate-npm-package-name": ["@types/validate-npm-package-name@4.0.2", "", {}, "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw=="], 318 420 421 + "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], 422 + 423 + "@vercel/oidc": ["@vercel/oidc@3.2.0", "", {}, "sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug=="], 424 + 319 425 "@vitejs/plugin-react": ["@vitejs/plugin-react@6.0.1", "", { "dependencies": { "@rolldown/pluginutils": "1.0.0-rc.7" }, "peerDependencies": { "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", "babel-plugin-react-compiler": "^1.0.0", "vite": "^8.0.0" }, "optionalPeers": ["@rolldown/plugin-babel", "babel-plugin-react-compiler"] }, "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ=="], 320 426 321 427 "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], 322 428 323 429 "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], 430 + 431 + "ai": ["ai@6.0.168", "", { "dependencies": { "@ai-sdk/gateway": "3.0.104", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-2HqCJuO+1V2aV7vfYs5LFEUfxbkGX+5oa54q/gCCTL7KLTdbxcCu5D7TdLA5kwsrs3Szgjah9q6D9tpjHM3hUQ=="], 324 432 325 433 "ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], 326 434 ··· 353 461 "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], 354 462 355 463 "browserslist": ["browserslist@4.28.2", "", { "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="], 464 + 465 + "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], 356 466 357 467 "bun-types": ["bun-types@1.3.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-QXKeHLlOLqQX9LgYaHJfzdBaV21T63HhFJnvuRCcjZiaUDpbs5ED1MgxbMra71CsryN/1dAoXuJJJwIv/2drVA=="], 358 468 ··· 430 540 431 541 "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], 432 542 433 - "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], 543 + "detect-libc": ["detect-libc@2.0.2", "", {}, "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw=="], 434 544 435 545 "diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], 436 546 437 547 "dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="], 548 + 549 + "drizzle-kit": ["drizzle-kit@0.31.10", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "tsx": "^4.21.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw=="], 550 + 551 + "drizzle-orm": ["drizzle-orm@0.45.2", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q=="], 438 552 439 553 "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], 440 554 ··· 459 573 "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], 460 574 461 575 "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], 576 + 577 + "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], 462 578 463 579 "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], 464 580 ··· 530 646 531 647 "get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="], 532 648 649 + "get-tsconfig": ["get-tsconfig@4.14.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA=="], 650 + 533 651 "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], 534 652 535 653 "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], ··· 608 726 609 727 "jose": ["jose@6.2.2", "", {}, "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ=="], 610 728 729 + "js-base64": ["js-base64@3.7.8", "", {}, "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow=="], 730 + 611 731 "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], 612 732 613 733 "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], ··· 615 735 "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], 616 736 617 737 "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="], 738 + 739 + "json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="], 618 740 619 741 "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], 620 742 ··· 626 748 627 749 "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], 628 750 751 + "libsql": ["libsql@0.5.29", "", { "dependencies": { "@neon-rs/load": "^0.0.4", "detect-libc": "2.0.2" }, "optionalDependencies": { "@libsql/darwin-arm64": "0.5.29", "@libsql/darwin-x64": "0.5.29", "@libsql/linux-arm-gnueabihf": "0.5.29", "@libsql/linux-arm-musleabihf": "0.5.29", "@libsql/linux-arm64-gnu": "0.5.29", "@libsql/linux-arm64-musl": "0.5.29", "@libsql/linux-x64-gnu": "0.5.29", "@libsql/linux-x64-musl": "0.5.29", "@libsql/win32-x64-msvc": "0.5.29" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "arm", "x64", "arm64", ] }, "sha512-8lMP8iMgiBzzoNbAPQ59qdVcj6UaE/Vnm+fiwX4doX4Narook0a4GPKWBEv+CR8a1OwbfkgL18uBfBjWdF0Fzg=="], 752 + 629 753 "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], 630 754 631 755 "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], ··· 690 814 691 815 "mute-stream": ["mute-stream@3.0.0", "", {}, "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw=="], 692 816 693 - "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], 817 + "nanoid": ["nanoid@5.1.9", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-ZUvP7KeBLe3OZ1ypw6dI/TzYJuvHP77IM4Ry73waSQTLn8/g8rpdjfyVAh7t1/+FjBtG4lCP42MEbDxOsRpBMw=="], 694 818 695 819 "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], 696 820 ··· 754 878 755 879 "pretty-ms": ["pretty-ms@9.3.0", "", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ=="], 756 880 881 + "promise-limit": ["promise-limit@2.7.0", "", {}, "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw=="], 882 + 757 883 "prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="], 758 884 759 885 "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], ··· 781 907 "reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="], 782 908 783 909 "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], 910 + 911 + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], 784 912 785 913 "restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], 786 914 ··· 836 964 837 965 "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], 838 966 967 + "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], 968 + 839 969 "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], 840 970 841 971 "stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="], ··· 879 1009 "tsconfig-paths": ["tsconfig-paths@4.2.0", "", { "dependencies": { "json5": "^2.2.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg=="], 880 1010 881 1011 "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], 1012 + 1013 + "tsx": ["tsx@4.21.0", "", { "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw=="], 882 1014 883 1015 "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="], 884 1016 ··· 920 1052 921 1053 "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], 922 1054 1055 + "ws": ["ws@8.20.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA=="], 1056 + 923 1057 "wsl-utils": ["wsl-utils@0.3.1", "", { "dependencies": { "is-wsl": "^3.1.0", "powershell-utils": "^0.1.0" } }, "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg=="], 924 1058 925 1059 "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], ··· 934 1068 935 1069 "yoctocolors": ["yoctocolors@2.1.2", "", {}, "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug=="], 936 1070 937 - "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], 1071 + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], 938 1072 939 1073 "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], 940 1074 ··· 942 1076 943 1077 "@dotenvx/dotenvx/execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], 944 1078 1079 + "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], 1080 + 1081 + "@modelcontextprotocol/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], 1082 + 945 1083 "@mswjs/interceptors/@open-draft/deferred-promise": ["@open-draft/deferred-promise@2.2.0", "", {}, "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA=="], 946 1084 947 1085 "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], ··· 956 1094 957 1095 "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], 958 1096 1097 + "@tanstack/router-generator/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], 1098 + 1099 + "@tanstack/router-plugin/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], 1100 + 959 1101 "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], 960 1102 961 1103 "cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], ··· 966 1108 967 1109 "express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], 968 1110 1111 + "lightningcss/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], 1112 + 969 1113 "log-symbols/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="], 970 1114 971 1115 "micromatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], 972 1116 973 1117 "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], 1118 + 1119 + "postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], 974 1120 975 1121 "prompts/kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], 976 1122 ··· 984 1130 985 1131 "shadcn/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="], 986 1132 1133 + "shadcn/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], 1134 + 1135 + "tsx/esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="], 1136 + 987 1137 "wrap-ansi/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], 988 1138 989 1139 "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], ··· 1002 1152 1003 1153 "@dotenvx/dotenvx/execa/strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="], 1004 1154 1155 + "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="], 1156 + 1157 + "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="], 1158 + 1159 + "@esbuild-kit/core-utils/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="], 1160 + 1161 + "@esbuild-kit/core-utils/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="], 1162 + 1163 + "@esbuild-kit/core-utils/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="], 1164 + 1165 + "@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="], 1166 + 1167 + "@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="], 1168 + 1169 + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="], 1170 + 1171 + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="], 1172 + 1173 + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="], 1174 + 1175 + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="], 1176 + 1177 + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="], 1178 + 1179 + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="], 1180 + 1181 + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="], 1182 + 1183 + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="], 1184 + 1185 + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="], 1186 + 1187 + "@esbuild-kit/core-utils/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="], 1188 + 1189 + "@esbuild-kit/core-utils/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="], 1190 + 1191 + "@esbuild-kit/core-utils/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="], 1192 + 1193 + "@esbuild-kit/core-utils/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="], 1194 + 1195 + "@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="], 1196 + 1197 + "@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], 1198 + 1005 1199 "cliui/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], 1006 1200 1007 1201 "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], 1008 1202 1009 1203 "cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], 1204 + 1205 + "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], 1206 + 1207 + "tsx/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="], 1208 + 1209 + "tsx/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.7", "", { "os": "android", "cpu": "arm64" }, "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ=="], 1210 + 1211 + "tsx/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.7", "", { "os": "android", "cpu": "x64" }, "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg=="], 1212 + 1213 + "tsx/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw=="], 1214 + 1215 + "tsx/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ=="], 1216 + 1217 + "tsx/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.7", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w=="], 1218 + 1219 + "tsx/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ=="], 1220 + 1221 + "tsx/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.7", "", { "os": "linux", "cpu": "arm" }, "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA=="], 1222 + 1223 + "tsx/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A=="], 1224 + 1225 + "tsx/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.7", "", { "os": "linux", "cpu": "ia32" }, "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg=="], 1226 + 1227 + "tsx/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q=="], 1228 + 1229 + "tsx/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw=="], 1230 + 1231 + "tsx/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.7", "", { "os": "linux", "cpu": "ppc64" }, "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ=="], 1232 + 1233 + "tsx/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ=="], 1234 + 1235 + "tsx/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.7", "", { "os": "linux", "cpu": "s390x" }, "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw=="], 1236 + 1237 + "tsx/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.7", "", { "os": "linux", "cpu": "x64" }, "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA=="], 1238 + 1239 + "tsx/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w=="], 1240 + 1241 + "tsx/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.7", "", { "os": "none", "cpu": "x64" }, "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw=="], 1242 + 1243 + "tsx/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.7", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A=="], 1244 + 1245 + "tsx/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.7", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg=="], 1246 + 1247 + "tsx/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw=="], 1248 + 1249 + "tsx/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.7", "", { "os": "sunos", "cpu": "x64" }, "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA=="], 1250 + 1251 + "tsx/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA=="], 1252 + 1253 + "tsx/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.7", "", { "os": "win32", "cpu": "ia32" }, "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw=="], 1254 + 1255 + "tsx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="], 1010 1256 1011 1257 "wrap-ansi/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], 1012 1258
+2 -4
package.json
··· 2 2 "name": "cai", 3 3 "private": true, 4 4 "type": "module", 5 - "workspaces": [ 6 - "apps/*", 7 - "packages/*" 8 - ], 5 + "workspaces": ["apps/*"], 9 6 "scripts": { 10 7 "dev": "bun run dev:api & bun run --cwd apps/web dev", 11 8 "dev:web": "bun run --cwd apps/web dev", ··· 19 16 }, 20 17 "dependencies": {}, 21 18 "devDependencies": { 19 + "@types/bun": "^1.3.13", 22 20 "@biomejs/biome": "^2.4.13" 23 21 } 24 22 }
-8
packages/shared/package.json
··· 1 - { 2 - "name": "@cai/shared", 3 - "private": true, 4 - "type": "module", 5 - "exports": { 6 - ".": "./src/index.ts" 7 - } 8 - }
-72
packages/shared/src/index.ts
··· 1 - export type CharacterIcon = "heart" | "cat"; 2 - 3 - export interface Character { 4 - id: string; 5 - name: string; 6 - icon: CharacterIcon; 7 - } 8 - 9 - export interface Chat { 10 - id: string; 11 - title: string; 12 - character: Character; 13 - messages: ChatMessage[]; 14 - } 15 - 16 - export type ChatSummary = Omit<Chat, "messages">; 17 - 18 - export interface ChatMessage { 19 - id: string; 20 - author: "assistant" | "user"; 21 - text: string; 22 - } 23 - 24 - export const characters: Character[] = [ 25 - { 26 - id: "1", 27 - name: "Katsune", 28 - icon: "heart", 29 - }, 30 - { 31 - id: "2", 32 - name: "Neko", 33 - icon: "cat", 34 - }, 35 - ]; 36 - 37 - export const chats: Chat[] = [ 38 - { 39 - id: "1", 40 - title: "Hello", 41 - character: characters[0], 42 - messages: [ 43 - { 44 - id: "1", 45 - author: "user", 46 - text: "Hello!", 47 - }, 48 - { 49 - id: "2", 50 - author: "assistant", 51 - text: "hello! :3", 52 - }, 53 - ], 54 - }, 55 - { 56 - id: "2", 57 - title: "Kia ora", 58 - character: characters[1], 59 - messages: [ 60 - { 61 - id: "3", 62 - author: "user", 63 - text: "kia ora!", 64 - }, 65 - { 66 - id: "4", 67 - author: "assistant", 68 - text: "teenaa koe! :3", 69 - }, 70 - ], 71 - }, 72 - ];
-7
packages/shared/tsconfig.json
··· 1 - { 2 - "extends": "../../tsconfig.json", 3 - "include": ["src/**/*.ts"], 4 - "compilerOptions": { 5 - "lib": ["ES2022"] 6 - } 7 - }