diff --git a/benchmark/apps/cli/package.json b/benchmark/apps/cli/package.json index 0263052d27..1f45ceaf14 100644 --- a/benchmark/apps/cli/package.json +++ b/benchmark/apps/cli/package.json @@ -11,8 +11,7 @@ "dependencies": { "@benchmark/db": "workspace:^", "@vscode/test-electron": "^2.4.0", - "gluegun": "^5.1.2", - "uuid": "^11.1.0" + "gluegun": "^5.1.2" }, "devDependencies": { "@benchmark/eslint-config": "workspace:^", diff --git a/benchmark/apps/cli/src/index.ts b/benchmark/apps/cli/src/index.ts index 9333677f42..a2e0907d02 100644 --- a/benchmark/apps/cli/src/index.ts +++ b/benchmark/apps/cli/src/index.ts @@ -2,7 +2,6 @@ import * as fs from "fs" import * as path from "path" import * as os from "os" -import { v4 as uuidv4 } from "uuid" import { build, filesystem, GluegunPrompt, GluegunToolbox } from "gluegun" import { runTests } from "@vscode/test-electron" @@ -152,7 +151,11 @@ const askExercise = async (prompt: GluegunPrompt, language: Language) => { const findOrCreateRun = async ({ id, model = "anthropic/claude-3.7-sonnet" }: { id?: number; model?: string }) => id ? findRun(id) - : createRun({ model, pid: process.pid, socketPath: path.resolve(os.tmpdir(), `benchmark-${uuidv4()}.sock`) }) + : createRun({ + model, + pid: process.pid, + socketPath: path.resolve(os.tmpdir(), `benchmark-${crypto.randomUUID()}.sock`), + }) const findOrCreatePendingTask = async ({ runId, diff --git a/benchmark/apps/web/package.json b/benchmark/apps/web/package.json index 6f3f2ee985..da27e02e8b 100644 --- a/benchmark/apps/web/package.json +++ b/benchmark/apps/web/package.json @@ -14,6 +14,7 @@ "@benchmark/ipc": "workspace:^", "@hookform/resolvers": "^4.1.3", "@radix-ui/react-label": "^2.1.2", + "@radix-ui/react-scroll-area": "^1.2.3", "@radix-ui/react-select": "^2.1.6", "@radix-ui/react-slot": "^1.1.2", "@tanstack/react-query": "^5.69.0", @@ -25,9 +26,9 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "react-hook-form": "^7.54.2", + "react-use": "^17.6.0", "tailwind-merge": "^3.0.2", "tailwindcss-animate": "^1.0.7", - "uuid": "^11.1.0", "zod": "^3.24.2" }, "devDependencies": { diff --git a/benchmark/apps/web/src/app/api/runs/[id]/stream/route.ts b/benchmark/apps/web/src/app/api/runs/[id]/stream/route.ts index a2f13c7907..864d2566f4 100644 --- a/benchmark/apps/web/src/app/api/runs/[id]/stream/route.ts +++ b/benchmark/apps/web/src/app/api/runs/[id]/stream/route.ts @@ -1,5 +1,4 @@ import type { NextRequest } from "next/server" -import { v4 as uuidv4 } from "uuid" import { findRun } from "@benchmark/db" import { IpcClient } from "@benchmark/ipc" @@ -10,7 +9,7 @@ export const dynamic = "force-dynamic" export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) { const { id } = await params - const requestId = uuidv4() + const requestId = crypto.randomUUID() const stream = new SSEStream() const run = await findRun(Number(id)) const client = new IpcClient(run.socketPath, () => {}) diff --git a/benchmark/apps/web/src/app/api/runs/[id]/tasks/route.ts b/benchmark/apps/web/src/app/api/runs/[id]/tasks/route.ts new file mode 100644 index 0000000000..864d2566f4 --- /dev/null +++ b/benchmark/apps/web/src/app/api/runs/[id]/tasks/route.ts @@ -0,0 +1,37 @@ +import type { NextRequest } from "next/server" + +import { findRun } from "@benchmark/db" +import { IpcClient } from "@benchmark/ipc" + +import { SSEStream } from "@/lib/server/sse-stream" + +export const dynamic = "force-dynamic" + +export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) { + const { id } = await params + const requestId = crypto.randomUUID() + const stream = new SSEStream() + const run = await findRun(Number(id)) + const client = new IpcClient(run.socketPath, () => {}) + + const write = async (data: string | object) => { + const success = await stream.write(data) + + if (!success) { + client.disconnect() + } + } + + console.log(`[stream#${requestId}] connect`) + client.on("connect", () => write("connect")) + client.on("disconnect", () => write("disconnect")) + client.on("message", write) + + request.signal.addEventListener("abort", () => { + console.log(`[stream#${requestId}] abort`) + client.disconnect() + stream.close().catch(() => {}) + }) + + return stream.getResponse() +} diff --git a/benchmark/apps/web/src/app/globals.css b/benchmark/apps/web/src/app/globals.css index 22506c2526..6cff4c4208 100644 --- a/benchmark/apps/web/src/app/globals.css +++ b/benchmark/apps/web/src/app/globals.css @@ -109,6 +109,20 @@ --radius-md: calc(var(--radius) - 2px); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) + 4px); + + --animate-hop: hop 0.8s ease-in-out infinite; + + @keyframes hop { + 0%, + 100% { + transform: none; + animation-timing-function: cubic-bezier(0.8, 0, 1, 1); + } + 50% { + transform: translateY(-8px); + animation-timing-function: cubic-bezier(0, 0, 0.2, 1); + } + } } @layer base { diff --git a/benchmark/apps/web/src/app/home.tsx b/benchmark/apps/web/src/app/home.tsx index 58d99d33d9..314c9f7788 100644 --- a/benchmark/apps/web/src/app/home.tsx +++ b/benchmark/apps/web/src/app/home.tsx @@ -5,8 +5,8 @@ import { Rocket } from "lucide-react" import { getRuns } from "@benchmark/db" -import { Button, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui" import { formatCurrency, formatDuration } from "@/lib" +import { Button, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui" type Run = Awaited>[number] @@ -15,39 +15,37 @@ export function Home({ runs }: { runs: Run[] }) { return ( <> -
- - - - ID - Model - Timestamp - Passed - Failed - % Correct - Cost - Duration +
+ + + ID + Model + Timestamp + Passed + Failed + % Correct + Cost + Duration + + + + {runs.map((run) => ( + + {run.id} + {run.model} + {new Date(run.createdAt).toLocaleString()} + {run.passed} + {run.failed} + {(run.rate * 100).toFixed(1)}% + {formatCurrency(run.cost)} + {formatDuration(run.duration)} - - - {runs.map((run) => ( - - {run.id} - {run.model} - {new Date(run.createdAt).toLocaleString()} - {run.passed} - {run.failed} - {(run.rate * 100).toFixed(1)}% - {formatCurrency(run.cost)} - {formatDuration(run.duration)} - - ))} - -
-
+ ))} + + diff --git a/benchmark/apps/web/src/app/layout.tsx b/benchmark/apps/web/src/app/layout.tsx index 7362b413b1..0b13629311 100644 --- a/benchmark/apps/web/src/app/layout.tsx +++ b/benchmark/apps/web/src/app/layout.tsx @@ -2,6 +2,7 @@ import type { Metadata } from "next" import { Geist, Geist_Mono } from "next/font/google" import { ThemeProvider, ReactQueryProvider } from "@/components/providers" +import { Header } from "@/components/layout/header" import "./globals.css" @@ -21,7 +22,10 @@ export default function RootLayout({ - {children} + +
+
{children}
+ diff --git a/benchmark/apps/web/src/app/runs/[id]/page.tsx b/benchmark/apps/web/src/app/runs/[id]/page.tsx index 09d6e3f9c8..ec7b266891 100644 --- a/benchmark/apps/web/src/app/runs/[id]/page.tsx +++ b/benchmark/apps/web/src/app/runs/[id]/page.tsx @@ -1,14 +1,16 @@ -import { findRun } from "@benchmark/db" +import { findRun, getTasks, getPendingTasks } from "@benchmark/db" import { ShowRun } from "./show-run" export default async function Page({ params }: { params: Promise<{ id: string }> }) { const { id } = await params const run = await findRun(Number(id)) + const tasks = await getTasks(run.id) + const pendingTasks = await getPendingTasks(run.id) if (!run) { return
Run not found
} - return + return } diff --git a/benchmark/apps/web/src/app/runs/[id]/show-run.tsx b/benchmark/apps/web/src/app/runs/[id]/show-run.tsx index ac0f3a2add..c4215d5fb6 100644 --- a/benchmark/apps/web/src/app/runs/[id]/show-run.tsx +++ b/benchmark/apps/web/src/app/runs/[id]/show-run.tsx @@ -1,19 +1,156 @@ "use client" -import { useCallback } from "react" +import { useCallback, useState } from "react" +import { z } from "zod" +import { CircleDashed, CircleCheck, CircleSlash, LoaderCircle, Dot } from "lucide-react" -import { Run } from "@benchmark/db" +import { type Run, type PendingTask, Task } from "@benchmark/db" import { useEventSource } from "@/hooks/use-event-source" +import { cn } from "@/lib/utils" -export function ShowRun({ run }: { run: Run }) { +const messageSchema = z.object({ + type: z.enum(["hello", "data"]), + data: z.record(z.string(), z.unknown()), +}) + +const taskEventSchema = z.discriminatedUnion("event", [ + // {"event":"client","runId":4,"language":"cpp","exercise":"queen-attack","prompt":"Your job is to complete a coding exercise described by `.docs/instructions.md`...","workspacePath":"/Users/cte/Documents/exercises/cpp/queen-attack"} + z.object({ + event: z.literal("client"), + runId: z.number(), + language: z.string(), + exercise: z.string(), + prompt: z.string(), + workspacePath: z.string(), + }), + // {"event":"message","taskId":"acfdc39d-2c21-484b-9fb0-c6670b1a7439","action":"updated","message":{"ts":1742574782085,"type":"say","say":"text","text":"Great! All the tests have passed...","partial":true}} + z.object({ + event: z.literal("message"), + taskId: z.string(), + action: z.enum(["created", "updated"]), + message: z.object({ + ts: z.number(), + type: z.enum(["ask", "say"]), + text: z.string(), + partial: z.boolean(), + }), + }), + // {"event":"taskTokenUsageUpdated","taskId":"acfdc39d-2c21-484b-9fb0-c6670b1a7439","usage":{"totalTokensIn":102069,"totalTokensOut":1700,"totalCacheWrites":0,"totalCacheReads":0,"totalCost":0.1212111,"contextTokens":19286}} + z.object({ + event: z.literal("taskTokenUsageUpdated"), + taskId: z.string(), + usage: z.object({ + totalTokensIn: z.number(), + totalTokensOut: z.number(), + totalCacheWrites: z.number(), + totalCacheReads: z.number(), + totalCost: z.number(), + contextTokens: z.number(), + }), + }), +]) + +type CurrentRun = Run & { tasks: Task[]; pendingTasks: PendingTask[] } + +export function ShowRun({ run }: { run: CurrentRun }) { + const [clientId, setClientId] = useState() + const [runningTask, setRunningTask] = useState() const url = `/api/runs/${run.id}/stream` - const onMessage = useCallback(({ data }: MessageEvent) => console.log(data), []) + + const onMessage = useCallback((messageEvent: MessageEvent) => { + // console.log(messageEvent.data) + let data + + try { + data = JSON.parse(messageEvent.data) + } catch (_) { + // console.log(`invalid JSON: ${messageEvent.data}`) + return + } + + const result = messageSchema.safeParse(data) + + if (!result.success) { + // console.log(`unrecognized messageEvent.data: ${messageEvent.data}`) + return + } + + const payload = result.data + + if (payload.type === "hello") { + setClientId(payload.data.clientId as string) + } else if (payload.type === "data") { + const taskEvent = taskEventSchema.safeParse(payload.data) + + if (!taskEvent.success) { + console.log(`unrecognized payload.data`, payload.data, taskEvent.error) + return + } + + if (taskEvent.data.event === "client") { + console.log(`client`, taskEvent.data) + const { language, exercise } = taskEvent.data + setRunningTask(`${language}/${exercise}`) + } else if (taskEvent.data.event === "message") { + console.log(`message: ${taskEvent.data.message.text}`) + } else if (taskEvent.data.event === "taskTokenUsageUpdated") { + console.log(`taskTokenUsageUpdated: ${taskEvent.data.usage}`) + } + } + }, []) + const status = useEventSource({ url, onMessage }) + const pendingTasks = run.pendingTasks.filter((pendingTask) => !run.tasks.find((task) => task.id === pendingTask.id)) + return ( -
- Show Run: {run.id} | {status} -
+ <> +
+
+
Run #{run.id}
+
{run.model}
+ {run.description &&
{run.description}
} +
+ {run.tasks.map((task) => ( +
+ {task.passed ? ( + + ) : ( + + )} +
+ {task.language}/{task.exercise} +
+
+ ))} + {pendingTasks.map((task) => ( +
+ {runningTask === `${task.language}/${task.exercise}` ? ( + + ) : ( + + )} +
+ {task.language}/{task.exercise} +
+
+ ))} +
+
+
+
+
+
+
{clientId}
+
+
+ ) } diff --git a/benchmark/apps/web/src/app/runs/new/actions.ts b/benchmark/apps/web/src/app/runs/new/actions.ts index f06b8086f8..e41b7381f5 100644 --- a/benchmark/apps/web/src/app/runs/new/actions.ts +++ b/benchmark/apps/web/src/app/runs/new/actions.ts @@ -1,12 +1,16 @@ "use server" import { spawn } from "child_process" +import path from "path" +import os from "os" + import { revalidatePath } from "next/cache" import * as db from "@benchmark/db" -export async function createRun(data: db.InsertRun) { - const run = await db.createRun(data) +export async function createRun(data: Omit) { + const socketPath = path.join(os.tmpdir(), `benchmark-${crypto.randomUUID()}.sock`) + const run = await db.createRun({ ...data, socketPath }) revalidatePath("/runs") try { @@ -20,8 +24,10 @@ export async function createRun(data: db.InsertRun) { ) process.unref() - return process.pid - } catch (_) { - return undefined + await db.updateRun(run.id, { pid: process.pid }) + } catch (error) { + console.error(error) } + + return run } diff --git a/benchmark/apps/web/src/app/runs/new/new-run.tsx b/benchmark/apps/web/src/app/runs/new/new-run.tsx index 6ce415c679..9e068090a6 100644 --- a/benchmark/apps/web/src/app/runs/new/new-run.tsx +++ b/benchmark/apps/web/src/app/runs/new/new-run.tsx @@ -51,8 +51,7 @@ export function NewRun() { try { const run = await createRun(data) router.push(`/runs/${run.id}`) - } catch (error) { - console.error("Error creating run:", error) + } catch (_) { setIsSubmitting(false) } } @@ -60,10 +59,7 @@ export function NewRun() { return ( <> -
-
__dirname: {__dirname}
+ diff --git a/benchmark/apps/web/src/components/layout/header.tsx b/benchmark/apps/web/src/components/layout/header.tsx new file mode 100644 index 0000000000..44fcbc1787 --- /dev/null +++ b/benchmark/apps/web/src/components/layout/header.tsx @@ -0,0 +1,7 @@ +import { HoppingLogo } from "./logo" + +export const Header = () => ( +
+ +
+) diff --git a/benchmark/apps/web/src/components/layout/logo.tsx b/benchmark/apps/web/src/components/layout/logo.tsx new file mode 100644 index 0000000000..f1ba133283 --- /dev/null +++ b/benchmark/apps/web/src/components/layout/logo.tsx @@ -0,0 +1,54 @@ +"use client" + +import { SVGProps, useEffect, useRef } from "react" +import { useRouter } from "next/navigation" +import { useHover } from "react-use" + +import { cn } from "@/lib/utils" + +type LogoProps = Omit, "xmlns" | "viewBox" | "onClick"> + +export const Logo = ({ width = 50, height = 32, fill = "#fff", className, ...props }: LogoProps) => { + const router = useRouter() + + return ( + router.push("/")} + className={cn("logo cursor-pointer", className)} + {...props}> + + + ) +} + +export const HoppingLogo = (props: LogoProps) => { + const ref = useRef(null) + const logo = + const [hoverable, hovered] = useHover(logo) + + useEffect(() => { + const element = ref.current + const isHopping = element !== null && element.classList.contains("animate-hop") + + if (hovered && element && !isHopping) { + element.classList.add("animate-hop") + } else if (element && isHopping) { + const onAnimationEnd = () => { + element.classList.remove("animate-hop") + element.removeEventListener("animationiteration", onAnimationEnd) + } + + element.addEventListener("animationiteration", onAnimationEnd) + } + }, [hovered]) + + return hoverable +} diff --git a/benchmark/apps/web/src/components/ui/index.ts b/benchmark/apps/web/src/components/ui/index.ts index 138c5c0fcf..30182e7e52 100644 --- a/benchmark/apps/web/src/components/ui/index.ts +++ b/benchmark/apps/web/src/components/ui/index.ts @@ -2,6 +2,7 @@ export * from "./button" export * from "./form" export * from "./input" export * from "./label" +export * from "./scroll-area" export * from "./select" export * from "./table" export * from "./textarea" diff --git a/benchmark/apps/web/src/components/ui/scroll-area.tsx b/benchmark/apps/web/src/components/ui/scroll-area.tsx new file mode 100644 index 0000000000..17efdd3e7e --- /dev/null +++ b/benchmark/apps/web/src/components/ui/scroll-area.tsx @@ -0,0 +1,46 @@ +"use client" + +import * as React from "react" +import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area" + +import { cn } from "@/lib/utils" + +function ScrollArea({ className, children, ...props }: React.ComponentProps) { + return ( + + + {children} + + + + + ) +} + +function ScrollBar({ + className, + orientation = "vertical", + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +export { ScrollArea, ScrollBar } diff --git a/benchmark/packages/db/src/index.ts b/benchmark/packages/db/src/index.ts index b15bf68231..6200d48676 100644 --- a/benchmark/packages/db/src/index.ts +++ b/benchmark/packages/db/src/index.ts @@ -1,24 +1,24 @@ -export { db } from "./db.js" +// export { db } from "./db.js" export { type Language, languages } from "./enums.js" -export { schema } from "./schema.js" +// export { schema } from "./schema.js" /** * runs */ -export { type Run, type InsertRun, insertRunSchema } from "./schema.js" -export { findRun, createRun, getRuns } from "./queries/runs.js" +export type { Run, InsertRun, UpdateRun } from "./schema.js" +export * from "./queries/runs.js" /** * tasks */ -export { type Task, type InsertTask, insertTaskSchema } from "./schema.js" -export { findTask, createTask, getTask } from "./queries/tasks.js" +export type { Task, InsertTask, UpdateTask } from "./schema.js" +export * from "./queries/tasks.js" /** * pendingTasks */ -export { type PendingTask, type InsertPendingTask, insertPendingTaskSchema } from "./schema.js" -export { findPendingTask, createPendingTask, getPendingTask } from "./queries/pendingTasks.js" +export type { PendingTask, InsertPendingTask, UpdatePendingTask } from "./schema.js" +export * from "./queries/pendingTasks.js" diff --git a/benchmark/packages/db/src/queries/pendingTasks.ts b/benchmark/packages/db/src/queries/pendingTasks.ts index 08bc62e6bc..75b1a761fd 100644 --- a/benchmark/packages/db/src/queries/pendingTasks.ts +++ b/benchmark/packages/db/src/queries/pendingTasks.ts @@ -1,13 +1,15 @@ import { and, eq } from "drizzle-orm" -import { db } from "../db.js" -import { type InsertPendingTask, insertPendingTaskSchema, pendingTasks } from "../schema.js" - -import { Language } from "../enums.js" +import type { Language } from "../enums.js" import { RecordNotFoundError, RecordNotCreatedError } from "./errors.js" +import type { InsertPendingTask, UpdatePendingTask } from "../schema.js" +import { insertPendingTaskSchema, pendingTasks } from "../schema.js" +import { db } from "../db.js" + +const table = pendingTasks export const findPendingTask = async (id: number) => { - const run = await db.query.pendingTasks.findFirst({ where: eq(pendingTasks.id, id) }) + const run = await db.query.pendingTasks.findFirst({ where: eq(table.id, id) }) if (!run) { throw new RecordNotFoundError() @@ -17,21 +19,32 @@ export const findPendingTask = async (id: number) => { } export const createPendingTask = async (args: InsertPendingTask) => { - const result = await db - .insert(pendingTasks) + const records = await db + .insert(table) .values({ ...insertPendingTaskSchema.parse(args), createdAt: new Date(), }) .returning() - const task = result[0] + const record = records[0] - if (!task) { + if (!record) { throw new RecordNotCreatedError() } - return task + return record +} + +export const updatePendingTask = async (id: number, values: UpdatePendingTask) => { + const records = await db.update(table).set(values).where(eq(table.id, id)).returning() + const record = records[0] + + if (!record) { + throw new RecordNotFoundError() + } + + return record } type GetPendingTask = { @@ -42,9 +55,8 @@ type GetPendingTask = { export const getPendingTask = async ({ runId, language, exercise }: GetPendingTask) => db.query.pendingTasks.findFirst({ - where: and( - eq(pendingTasks.runId, runId), - eq(pendingTasks.language, language), - eq(pendingTasks.exercise, exercise), - ), + where: and(eq(table.runId, runId), eq(table.language, language), eq(table.exercise, exercise)), }) + +export const getPendingTasks = async (runId: number) => + db.query.pendingTasks.findMany({ where: eq(table.runId, runId) }) diff --git a/benchmark/packages/db/src/queries/runs.ts b/benchmark/packages/db/src/queries/runs.ts index 8f4dd17ff5..07c5723716 100644 --- a/benchmark/packages/db/src/queries/runs.ts +++ b/benchmark/packages/db/src/queries/runs.ts @@ -1,12 +1,14 @@ import { desc, eq, sql } from "drizzle-orm" -import { db } from "../db.js" -import { type InsertRun, insertRunSchema, runs, tasks } from "../schema.js" - import { RecordNotFoundError, RecordNotCreatedError } from "./errors.js" +import type { InsertRun, UpdateRun } from "../schema.js" +import { insertRunSchema, runs, tasks } from "../schema.js" +import { db } from "../db.js" + +const table = runs export const findRun = async (id: number) => { - const run = await db.query.runs.findFirst({ where: eq(runs.id, id) }) + const run = await db.query.runs.findFirst({ where: eq(table.id, id) }) if (!run) { throw new RecordNotFoundError() @@ -16,30 +18,41 @@ export const findRun = async (id: number) => { } export const createRun = async (args: InsertRun) => { - const result = await db - .insert(runs) + const records = await db + .insert(table) .values({ ...insertRunSchema.parse(args), createdAt: new Date(), }) .returning() - const run = result[0] + const record = records[0] - if (!run) { + if (!record) { throw new RecordNotCreatedError() } - return run + return record +} + +export const updateRun = async (id: number, values: UpdateRun) => { + const records = await db.update(table).set(values).where(eq(table.id, id)).returning() + const record = records[0] + + if (!record) { + throw new RecordNotFoundError() + } + + return record } export const getRuns = () => db .select({ - id: runs.id, - model: runs.model, - description: runs.description, - createdAt: runs.createdAt, + id: table.id, + model: table.model, + description: table.description, + createdAt: table.createdAt, passed: sql`sum(${tasks.passed})`, failed: sql`sum(${tasks.passed} = 0)`, total: sql`count(${tasks.id})`, @@ -47,6 +60,6 @@ export const getRuns = () => cost: sql`sum(${tasks.cost})`, duration: sql`sum(${tasks.duration})`, }) - .from(runs) - .leftJoin(tasks, eq(runs.id, tasks.runId)) - .orderBy(desc(runs.id)) + .from(table) + .leftJoin(tasks, eq(table.id, tasks.runId)) + .orderBy(desc(table.id)) diff --git a/benchmark/packages/db/src/queries/tasks.ts b/benchmark/packages/db/src/queries/tasks.ts index c8ccf0707e..a3f6e1b590 100644 --- a/benchmark/packages/db/src/queries/tasks.ts +++ b/benchmark/packages/db/src/queries/tasks.ts @@ -1,13 +1,15 @@ import { and, eq } from "drizzle-orm" -import { db } from "../db.js" -import { type InsertTask, insertTaskSchema, tasks } from "../schema.js" - -import { type Language } from "../enums.js" +import type { Language } from "../enums.js" import { RecordNotFoundError, RecordNotCreatedError } from "./errors.js" +import type { InsertTask, UpdateTask } from "../schema.js" +import { insertTaskSchema, tasks } from "../schema.js" +import { db } from "../db.js" + +const table = tasks export const findTask = async (id: number) => { - const run = await db.query.tasks.findFirst({ where: eq(tasks.id, id) }) + const run = await db.query.tasks.findFirst({ where: eq(table.id, id) }) if (!run) { throw new RecordNotFoundError() @@ -17,23 +19,33 @@ export const findTask = async (id: number) => { } export const createTask = async (args: InsertTask) => { - const result = await db - .insert(tasks) + const records = await db + .insert(table) .values({ ...insertTaskSchema.parse(args), createdAt: new Date(), }) .returning() - const task = result[0] + const record = records[0] - if (!task) { + if (!record) { throw new RecordNotCreatedError() } - return task + return record } +export const updateTask = async (id: number, values: UpdateTask) => { + const records = await db.update(table).set(values).where(eq(table.id, id)).returning() + const record = records[0] + + if (!record) { + throw new RecordNotFoundError() + } + + return record +} type GetTask = { runId: number language: Language @@ -42,5 +54,7 @@ type GetTask = { export const getTask = async ({ runId, language, exercise }: GetTask) => db.query.tasks.findFirst({ - where: and(eq(tasks.runId, runId), eq(tasks.language, language), eq(tasks.exercise, exercise)), + where: and(eq(table.runId, runId), eq(table.language, language), eq(table.exercise, exercise)), }) + +export const getTasks = async (runId: number) => db.query.tasks.findMany({ where: eq(table.runId, runId) }) diff --git a/benchmark/packages/db/src/schema.ts b/benchmark/packages/db/src/schema.ts index 7c4d57ec61..b93021beaa 100644 --- a/benchmark/packages/db/src/schema.ts +++ b/benchmark/packages/db/src/schema.ts @@ -27,6 +27,8 @@ export const insertRunSchema = createInsertSchema(runs).omit({ export type InsertRun = z.infer +export type UpdateRun = Partial> + /** * tasks */ @@ -60,6 +62,8 @@ export const insertTaskSchema = createInsertSchema(tasks).omit({ export type InsertTask = z.infer +export type UpdateTask = Partial> + /** * pendingTasks */ @@ -86,6 +90,8 @@ export const insertPendingTaskSchema = createInsertSchema(pendingTasks).omit({ export type InsertPendingTask = z.infer +export type UpdatePendingTask = Partial> + /** * schema */ diff --git a/benchmark/pnpm-lock.yaml b/benchmark/pnpm-lock.yaml index 27867bad6f..deda92dc4d 100644 --- a/benchmark/pnpm-lock.yaml +++ b/benchmark/pnpm-lock.yaml @@ -53,9 +53,6 @@ importers: gluegun: specifier: ^5.1.2 version: 5.2.0 - uuid: - specifier: ^11.1.0 - version: 11.1.0 devDependencies: '@benchmark/eslint-config': specifier: workspace:^ @@ -78,6 +75,9 @@ importers: '@radix-ui/react-label': specifier: ^2.1.2 version: 2.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-scroll-area': + specifier: ^1.2.3 + version: 1.2.3(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@radix-ui/react-select': specifier: ^2.1.6 version: 2.1.6(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -111,15 +111,15 @@ importers: react-hook-form: specifier: ^7.54.2 version: 7.54.2(react@19.0.0) + react-use: + specifier: ^17.6.0 + version: 17.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) tailwind-merge: specifier: ^3.0.2 version: 3.0.2 tailwindcss-animate: specifier: ^1.0.7 version: 1.0.7(tailwindcss@4.0.14) - uuid: - specifier: ^11.1.0 - version: 11.1.0 zod: specifier: ^3.24.2 version: 3.24.2 @@ -258,6 +258,10 @@ packages: resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.26.10': + resolution: {integrity: sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==} + engines: {node: '>=6.9.0'} + '@dotenvx/dotenvx@1.39.0': resolution: {integrity: sha512-qGfDpL/3S17MQYXpR3HkBS5xNQ7wiFlqLdpr+iIQzv17aMRcSlgL4EjMIsYFZ540Dq17J+y5FVElA1AkVoXiUA==} hasBin: true @@ -1188,6 +1192,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-presence@1.1.2': + resolution: {integrity: sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-primitive@2.0.2': resolution: {integrity: sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==} peerDependencies: @@ -1201,6 +1218,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-scroll-area@1.2.3': + resolution: {integrity: sha512-l7+NNBfBYYJa9tNqVcP2AGvxdE3lmE6kFTBXdvHgUaZuy+4wGCL1Cl2AfaR7RKyimj7lZURGLwFO59k4eBnDJQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-select@2.1.6': resolution: {integrity: sha512-T6ajELxRvTuAMWH0YmRJ1qez+x4/7Nq7QIx7zJ0VK3qaEWdnWpNbEDnmWldG1zBDwqrLy5aLMUWcoGirVj5kMg==} peerDependencies: @@ -1493,6 +1523,9 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/js-cookie@2.2.7': + resolution: {integrity: sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -1570,6 +1603,9 @@ packages: resolution: {integrity: sha512-Gc6EdaLANdktQ1t+zozoBVRynfIsMKMc94Svu1QreOBC8y76x4tvaK32TljrLi1LI2+PK58sDVbL7ALdqf3VRQ==} engines: {node: '>=16'} + '@xobotyi/scrollbar-width@1.9.5': + resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1819,6 +1855,9 @@ packages: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} + copy-to-clipboard@3.3.3: + resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + copyfiles@2.4.1: resolution: {integrity: sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==} hasBin: true @@ -1838,6 +1877,13 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + css-in-js-utils@3.1.0: + resolution: {integrity: sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==} + + css-tree@1.1.3: + resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} + engines: {node: '>=8.0.0'} + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -2046,6 +2092,9 @@ packages: error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + error-stack-parser@2.1.4: + resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + es-abstract@1.23.9: resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} engines: {node: '>= 0.4'} @@ -2205,6 +2254,12 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-shallow-equal@1.0.0: + resolution: {integrity: sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==} + + fastest-stable-stringify@2.0.2: + resolution: {integrity: sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q==} + fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} @@ -2406,6 +2461,9 @@ packages: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} + hyphenate-style-name@1.1.0: + resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -2431,6 +2489,9 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + inline-style-prefixer@7.0.1: + resolution: {integrity: sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -2600,6 +2661,9 @@ packages: js-base64@3.7.7: resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} + js-cookie@2.2.1: + resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} + js-message@1.0.7: resolution: {integrity: sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==} engines: {node: '>=0.6.0'} @@ -2810,6 +2874,9 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + mdn-data@2.0.14: + resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -2855,6 +2922,12 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nano-css@5.6.2: + resolution: {integrity: sha512-+6bHaC8dSDGALM1HJjOHVXpuastdu2xFoZlC77Jh4cg+33Zcgm+Gxd+1xsnpZK14eyHObSp82+ll5y3SX75liw==} + peerDependencies: + react: '*' + react-dom: '*' + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -3131,6 +3204,18 @@ packages: '@types/react': optional: true + react-universal-interface@0.6.2: + resolution: {integrity: sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==} + peerDependencies: + react: '*' + tslib: '*' + + react-use@17.6.0: + resolution: {integrity: sha512-OmedEScUMKFfzn1Ir8dBxiLLSOzhKe/dPZwVxcujweSj45aNM7BEGPb9BEVIgVEqEXx6f3/TsXzwIktNgUR02g==} + peerDependencies: + react: '*' + react-dom: '*' + react@19.0.0: resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} engines: {node: '>=0.10.0'} @@ -3153,6 +3238,9 @@ packages: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + regexp.prototype.flags@1.5.4: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} @@ -3161,6 +3249,9 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + resize-observer-polyfill@1.5.1: + resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -3203,6 +3294,9 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rtl-css-js@1.16.1: + resolution: {integrity: sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -3227,6 +3321,10 @@ packages: scheduler@0.25.0: resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + screenfull@5.2.0: + resolution: {integrity: sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==} + engines: {node: '>=0.10.0'} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -3249,6 +3347,10 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} + set-harmonic-interval@1.0.1: + resolution: {integrity: sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==} + engines: {node: '>=6.9'} + set-proto@1.0.0: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} @@ -3305,6 +3407,10 @@ packages: source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map@0.5.6: + resolution: {integrity: sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==} + engines: {node: '>=0.10.0'} + source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -3313,6 +3419,18 @@ packages: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + stack-generator@2.0.10: + resolution: {integrity: sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==} + + stackframe@1.3.4: + resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + + stacktrace-gps@3.1.2: + resolution: {integrity: sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==} + + stacktrace-js@2.0.2: + resolution: {integrity: sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==} + stdin-discarder@0.1.0: resolution: {integrity: sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -3402,6 +3520,9 @@ packages: babel-plugin-macros: optional: true + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} @@ -3441,6 +3562,10 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + throttle-debounce@3.0.1: + resolution: {integrity: sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==} + engines: {node: '>=10'} + through2@2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} @@ -3455,6 +3580,9 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toggle-selection@1.0.6: + resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} + tr46@1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} @@ -3468,6 +3596,9 @@ packages: peerDependencies: typescript: '>=4.8.4' + ts-easing@0.2.0: + resolution: {integrity: sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==} + ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} @@ -3601,10 +3732,6 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - uuid@11.1.0: - resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} - hasBin: true - wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} @@ -3717,6 +3844,10 @@ snapshots: '@babel/helper-validator-identifier@7.25.9': {} + '@babel/runtime@7.26.10': + dependencies: + regenerator-runtime: 0.14.1 + '@dotenvx/dotenvx@1.39.0': dependencies: commander: 11.1.0 @@ -4370,6 +4501,16 @@ snapshots: '@types/react': 19.0.12 '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@radix-ui/react-presence@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.12)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.12 + '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@radix-ui/react-primitive@2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/react-slot': 1.1.2(@types/react@19.0.12)(react@19.0.0) @@ -4379,6 +4520,23 @@ snapshots: '@types/react': 19.0.12 '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@radix-ui/react-scroll-area@1.2.3(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/number': 1.1.0 + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-direction': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.12)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.12)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.12 + '@types/react-dom': 19.0.4(@types/react@19.0.12) + '@radix-ui/react-select@2.1.6(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/number': 1.1.0 @@ -4608,6 +4766,8 @@ snapshots: '@types/estree@1.0.6': {} + '@types/js-cookie@2.2.7': {} + '@types/json-schema@7.0.15': {} '@types/node-ipc@9.2.3': @@ -4721,6 +4881,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@xobotyi/scrollbar-width@1.9.5': {} + acorn-jsx@5.3.2(acorn@8.14.1): dependencies: acorn: 8.14.1 @@ -4985,6 +5147,10 @@ snapshots: consola@3.4.2: {} + copy-to-clipboard@3.3.3: + dependencies: + toggle-selection: 1.0.6 + copyfiles@2.4.1: dependencies: glob: 7.2.3 @@ -5017,6 +5183,15 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + css-in-js-utils@3.1.0: + dependencies: + hyphenate-style-name: 1.1.0 + + css-tree@1.1.3: + dependencies: + mdn-data: 2.0.14 + source-map: 0.6.1 + csstype@3.1.3: {} data-uri-to-buffer@4.0.1: {} @@ -5137,6 +5312,10 @@ snapshots: dependencies: is-arrayish: 0.2.1 + error-stack-parser@2.1.4: + dependencies: + stackframe: 1.3.4 + es-abstract@1.23.9: dependencies: array-buffer-byte-length: 1.0.2 @@ -5473,6 +5652,10 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-shallow-equal@1.0.0: {} + + fastest-stable-stringify@2.0.2: {} + fastq@1.19.1: dependencies: reusify: 1.1.0 @@ -5718,6 +5901,8 @@ snapshots: human-signals@2.1.0: {} + hyphenate-style-name@1.1.0: {} + ieee754@1.2.1: {} ignore@5.3.2: {} @@ -5738,6 +5923,10 @@ snapshots: inherits@2.0.4: {} + inline-style-prefixer@7.0.1: + dependencies: + css-in-js-utils: 3.1.0 + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 @@ -5906,6 +6095,8 @@ snapshots: js-base64@3.7.7: {} + js-cookie@2.2.1: {} + js-message@1.0.7: {} js-queue@2.0.2: @@ -6082,6 +6273,8 @@ snapshots: math-intrinsics@1.1.0: {} + mdn-data@2.0.14: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -6121,6 +6314,19 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 + nano-css@5.6.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + css-tree: 1.1.3 + csstype: 3.1.3 + fastest-stable-stringify: 2.0.2 + inline-style-prefixer: 7.0.1 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + rtl-css-js: 1.16.1 + stacktrace-js: 2.0.2 + stylis: 4.3.6 + nanoid@3.3.11: {} natural-compare@1.4.0: {} @@ -6393,6 +6599,30 @@ snapshots: optionalDependencies: '@types/react': 19.0.12 + react-universal-interface@0.6.2(react@19.0.0)(tslib@2.8.1): + dependencies: + react: 19.0.0 + tslib: 2.8.1 + + react-use@17.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + '@types/js-cookie': 2.2.7 + '@xobotyi/scrollbar-width': 1.9.5 + copy-to-clipboard: 3.3.3 + fast-deep-equal: 3.1.3 + fast-shallow-equal: 1.0.0 + js-cookie: 2.2.1 + nano-css: 5.6.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + react-universal-interface: 0.6.2(react@19.0.0)(tslib@2.8.1) + resize-observer-polyfill: 1.5.1 + screenfull: 5.2.0 + set-harmonic-interval: 1.0.1 + throttle-debounce: 3.0.1 + ts-easing: 0.2.0 + tslib: 2.8.1 + react@19.0.0: {} readable-stream@1.0.34: @@ -6431,6 +6661,8 @@ snapshots: get-proto: 1.0.1 which-builtin-type: 1.2.1 + regenerator-runtime@0.14.1: {} + regexp.prototype.flags@1.5.4: dependencies: call-bind: 1.0.8 @@ -6442,6 +6674,8 @@ snapshots: require-directory@2.1.1: {} + resize-observer-polyfill@1.5.1: {} + resolve-from@4.0.0: {} resolve-from@5.0.0: {} @@ -6500,6 +6734,10 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.36.0 fsevents: 2.3.3 + rtl-css-js@1.16.1: + dependencies: + '@babel/runtime': 7.26.10 + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -6529,6 +6767,8 @@ snapshots: scheduler@0.25.0: {} + screenfull@5.2.0: {} + semver@6.3.1: {} semver@7.3.5: @@ -6553,6 +6793,8 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + set-harmonic-interval@1.0.1: {} + set-proto@1.0.0: dependencies: dunder-proto: 1.0.1 @@ -6640,12 +6882,31 @@ snapshots: buffer-from: 1.1.2 source-map: 0.6.1 + source-map@0.5.6: {} + source-map@0.6.1: {} source-map@0.8.0-beta.0: dependencies: whatwg-url: 7.1.0 + stack-generator@2.0.10: + dependencies: + stackframe: 1.3.4 + + stackframe@1.3.4: {} + + stacktrace-gps@3.1.2: + dependencies: + source-map: 0.5.6 + stackframe: 1.3.4 + + stacktrace-js@2.0.2: + dependencies: + error-stack-parser: 2.1.4 + stack-generator: 2.0.10 + stacktrace-gps: 3.1.2 + stdin-discarder@0.1.0: dependencies: bl: 5.1.0 @@ -6749,6 +7010,8 @@ snapshots: client-only: 0.0.1 react: 19.0.0 + stylis@4.3.6: {} + sucrase@3.35.0: dependencies: '@jridgewell/gen-mapping': 0.3.8 @@ -6787,6 +7050,8 @@ snapshots: dependencies: any-promise: 1.3.0 + throttle-debounce@3.0.1: {} + through2@2.0.5: dependencies: readable-stream: 2.3.8 @@ -6803,6 +7068,8 @@ snapshots: dependencies: is-number: 7.0.0 + toggle-selection@1.0.6: {} + tr46@1.0.1: dependencies: punycode: 2.3.1 @@ -6813,6 +7080,8 @@ snapshots: dependencies: typescript: 5.8.2 + ts-easing@0.2.0: {} + ts-interface-checker@0.1.13: {} tslib@2.8.1: {} @@ -6959,8 +7228,6 @@ snapshots: util-deprecate@1.0.2: {} - uuid@11.1.0: {} - wcwidth@1.0.1: dependencies: defaults: 1.0.4