From ff6036556096f0e282205325923a053dd595fa25 Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 06:00:17 +0300 Subject: [PATCH 01/21] prop fixes --- apps/tanstack-start/src/routes/admin/ndi.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/tanstack-start/src/routes/admin/ndi.tsx b/apps/tanstack-start/src/routes/admin/ndi.tsx index f3cb6f2..f2c2868 100644 --- a/apps/tanstack-start/src/routes/admin/ndi.tsx +++ b/apps/tanstack-start/src/routes/admin/ndi.tsx @@ -66,8 +66,10 @@ interface CompanyCardProps { submission: { id: string; companyName: string; - createdAt: string; + userId: string; status: string; + createdAt: Date; + updatedAt: Date; }; } From 556e7fe3b2d2e96502cfdffb9a4a231c952189a4 Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 06:00:40 +0300 Subject: [PATCH 02/21] runtime checking of required env variables --- services/ai-service/run.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/ai-service/run.py b/services/ai-service/run.py index f7d10af..3f054b6 100644 --- a/services/ai-service/run.py +++ b/services/ai-service/run.py @@ -1,8 +1,14 @@ """Run the API: python run.py (from ai-service directory). Use --reload for auto-restart on code changes.""" + import os import uvicorn +env_requirements = ["OPENROUTER_API_KEY", "HF_TOKEN", "GROQ_API_KEY"] + +for var in env_requirements: + if not os.getenv(var): + raise EnvironmentError(f"Environment variable {var} is not set.") host = os.getenv("SERVER_HOST", "0.0.0.0") port = int(os.getenv("SERVER_PORT", "8000")) uvicorn.run("src.api.app:app", host=host, port=port) From f822a201c1b9be76d4eac9b34696882799a5ca69 Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 06:08:28 +0300 Subject: [PATCH 03/21] Fixing Compose Issues --- docker-compose.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 2976c80..6ca6841 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,10 +11,16 @@ services: - PYTHONPATH=/app/src depends_on: vector_db: - condition: service_healthy + condition: service_started restart: unless-stopped healthcheck: - test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health')"] + test: + [ + "CMD", + "python", + "-c", + "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')", + ] interval: 30s timeout: 10s retries: 3 @@ -55,19 +61,13 @@ services: target: /qdrant/config/production.yaml volumes: - qdrant_data:/qdrant/storage - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:6333/health"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 20s application_db: image: postgres:15 restart: always environment: POSTGRES_USER: ${POSTGRES_USER:-postgres} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password} POSTGRES_DB: ${POSTGRES_DB:-app_db} ports: - "5432:5432" From 230e0b921ad551da5b9e9f55bb0b868c465c2811 Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 06:16:21 +0300 Subject: [PATCH 04/21] formatting --- .../tanstack-start/src/component/NotFound.tsx | 42 +- .../src/component/auth-showcase.tsx | 4 +- .../src/component/index/IndexCard.tsx | 101 ++-- .../src/component/layout/Header.tsx | 94 ++- apps/tanstack-start/src/env.ts | 3 +- apps/tanstack-start/src/lib/trpc.ts | 2 +- apps/tanstack-start/src/routes/__root.tsx | 5 +- .../src/routes/admin/company.$companyId.tsx | 125 ++-- .../tanstack-start/src/routes/admin/index.tsx | 61 +- apps/tanstack-start/src/routes/admin/ndi.tsx | 242 ++++---- .../src/routes/api/auth/callback.tsx | 8 +- apps/tanstack-start/src/routes/index.tsx | 11 +- apps/tanstack-start/src/routes/submit.tsx | 566 +++++++++--------- packages/api/src/ai-client/client.gen.ts | 15 +- .../api/src/ai-client/client/client.gen.ts | 171 +++--- packages/api/src/ai-client/client/index.ts | 16 +- .../api/src/ai-client/client/types.gen.ts | 102 ++-- .../api/src/ai-client/client/utils.gen.ts | 109 ++-- packages/api/src/ai-client/core/auth.gen.ts | 13 +- .../src/ai-client/core/bodySerializer.gen.ts | 30 +- packages/api/src/ai-client/core/params.gen.ts | 37 +- .../src/ai-client/core/pathSerializer.gen.ts | 92 +-- .../ai-client/core/queryKeySerializer.gen.ts | 37 +- .../ai-client/core/serverSentEvents.gen.ts | 81 ++- packages/api/src/ai-client/core/types.gen.ts | 44 +- packages/api/src/ai-client/core/utils.gen.ts | 43 +- packages/api/src/ai-client/index.ts | 31 +- packages/api/src/ai-client/sdk.gen.ts | 99 ++- packages/api/src/ai-client/types.gen.ts | 561 ++++++++--------- packages/api/src/lib/ai.ts | 27 +- packages/api/src/router/submission.ts | 11 +- packages/api/src/trpc.ts | 2 +- packages/api/tsconfig.json | 16 +- packages/db/src/schema/submissions.ts | 34 +- packages/ui/src/theme.tsx | 1 - packages/validators/package.json | 2 +- packages/validators/src/ndi-domains.ts | 154 ++--- packages/validators/tsconfig.json | 10 +- tooling/tailwind/theme.css | 2 +- 39 files changed, 1652 insertions(+), 1352 deletions(-) diff --git a/apps/tanstack-start/src/component/NotFound.tsx b/apps/tanstack-start/src/component/NotFound.tsx index c4e06aa..88028f0 100644 --- a/apps/tanstack-start/src/component/NotFound.tsx +++ b/apps/tanstack-start/src/component/NotFound.tsx @@ -1,26 +1,28 @@ import { Link, useLocation } from "@tanstack/react-router"; export function NotFound() { - const location = useLocation(); - console.log("NotFound triggered for path:", location.pathname); + const location = useLocation(); + console.log("NotFound triggered for path:", location.pathname); - return ( -
-

404

-
- Page Not Found -
-
-
- Oops! The page you asked for doesn't exist. -
- - Go Home - -
+ return ( +
+

+ 404 +

+
+ Page Not Found +
+
+
+ Oops! The page you asked for doesn't exist.
- ); + + Go Home + +
+
+ ); } diff --git a/apps/tanstack-start/src/component/auth-showcase.tsx b/apps/tanstack-start/src/component/auth-showcase.tsx index ff887d0..3fc65c0 100644 --- a/apps/tanstack-start/src/component/auth-showcase.tsx +++ b/apps/tanstack-start/src/component/auth-showcase.tsx @@ -1,6 +1,6 @@ -import { useAuth } from "@workos/authkit-tanstack-react-start/client"; -import { getSignInUrl } from "@workos/authkit-tanstack-react-start"; import { createServerFn } from "@tanstack/react-start"; +import { getSignInUrl } from "@workos/authkit-tanstack-react-start"; +import { useAuth } from "@workos/authkit-tanstack-react-start/client"; import { Button } from "@governance/ui/button"; diff --git a/apps/tanstack-start/src/component/index/IndexCard.tsx b/apps/tanstack-start/src/component/index/IndexCard.tsx index b0d5ee1..37ed317 100644 --- a/apps/tanstack-start/src/component/index/IndexCard.tsx +++ b/apps/tanstack-start/src/component/index/IndexCard.tsx @@ -1,63 +1,60 @@ import { Link } from "@tanstack/react-router"; + import { cn } from "@governance/ui"; interface IndexCardProps { - title: string; - subtitle: string; - isActive: boolean; - href?: string; + title: string; + subtitle: string; + isActive: boolean; + href?: string; } export function IndexCard({ title, subtitle, isActive, href }: IndexCardProps) { - const CardContent = ( -
- {/* Active Indicator */} - {isActive && ( -
-
-
-
-
-
- )} - - {/* Content */} -
-

- {title} -

-

- {subtitle} -

-
- - {/* Active Label */} - {isActive && ( -
-
- - Active - -
- )} - - {/* Hover Effect */} - {isActive && ( -
- )} + const CardContent = ( +
+ {/* Active Indicator */} + {isActive && ( +
+
+
+
+
- ); + )} + + {/* Content */} +
+

{title}

+

{subtitle}

+
+ + {/* Active Label */} + {isActive && ( +
+
+ + Active + +
+ )} + + {/* Hover Effect */} + {isActive && ( +
+ )} +
+ ); - if (isActive && href) { - return {CardContent}; - } + if (isActive && href) { + return {CardContent}; + } - return CardContent; + return CardContent; } diff --git a/apps/tanstack-start/src/component/layout/Header.tsx b/apps/tanstack-start/src/component/layout/Header.tsx index 8fa071c..b86ec24 100644 --- a/apps/tanstack-start/src/component/layout/Header.tsx +++ b/apps/tanstack-start/src/component/layout/Header.tsx @@ -2,61 +2,57 @@ import { Link } from "@tanstack/react-router"; import { createServerFn } from "@tanstack/react-start"; -import { useAuth } from "@workos/authkit-tanstack-react-start/client"; import { getSignInUrl } from "@workos/authkit-tanstack-react-start"; +import { useAuth } from "@workos/authkit-tanstack-react-start/client"; export function Header() { - const { user, signOut } = useAuth(); + const { user, signOut } = useAuth(); - return ( -
-
- {/* Logo */} - - NDMO - + return ( +
+
+ {/* Logo */} + + NDMO + - {/* Navigation */} - -
-
- ); + {/* Navigation */} + +
+
+ ); } const getSignInUrlFn = createServerFn({ method: "GET" }).handler(async () => { - return await getSignInUrl(); + return await getSignInUrl(); }); diff --git a/apps/tanstack-start/src/env.ts b/apps/tanstack-start/src/env.ts index 32477d3..445b620 100644 --- a/apps/tanstack-start/src/env.ts +++ b/apps/tanstack-start/src/env.ts @@ -1,8 +1,9 @@ -import { authEnv } from "@governance/auth/env"; import { createEnv } from "@t3-oss/env-core"; import { vercel } from "@t3-oss/env-core/presets-zod"; import { z } from "zod/v4"; +import { authEnv } from "@governance/auth/env"; + export const env = createEnv({ clientPrefix: "VITE_", extends: [authEnv(), vercel()], diff --git a/apps/tanstack-start/src/lib/trpc.ts b/apps/tanstack-start/src/lib/trpc.ts index c066fde..88acf20 100644 --- a/apps/tanstack-start/src/lib/trpc.ts +++ b/apps/tanstack-start/src/lib/trpc.ts @@ -7,8 +7,8 @@ import { unstable_localLink, } from "@trpc/client"; import { createTRPCContext } from "@trpc/tanstack-react-query"; -import SuperJSON from "superjson"; import { getAuth } from "@workos/authkit-tanstack-react-start"; +import SuperJSON from "superjson"; import * as Api from "@governance/api"; diff --git a/apps/tanstack-start/src/routes/__root.tsx b/apps/tanstack-start/src/routes/__root.tsx index 5c9c075..31903a5 100644 --- a/apps/tanstack-start/src/routes/__root.tsx +++ b/apps/tanstack-start/src/routes/__root.tsx @@ -20,9 +20,8 @@ import { import { Toaster } from "@governance/ui/toast"; import appCss from "~/styles.css?url"; - -import { NotFound } from "../component/NotFound"; import { Header } from "../component/layout/Header"; +import { NotFound } from "../component/NotFound"; export const Route = createRootRouteWithContext<{ queryClient: QueryClient; @@ -67,6 +66,6 @@ function RootDocument({ children }: { children: React.ReactNode }) { - + ); } diff --git a/apps/tanstack-start/src/routes/admin/company.$companyId.tsx b/apps/tanstack-start/src/routes/admin/company.$companyId.tsx index 76fe9b1..847dbb6 100644 --- a/apps/tanstack-start/src/routes/admin/company.$companyId.tsx +++ b/apps/tanstack-start/src/routes/admin/company.$companyId.tsx @@ -1,8 +1,9 @@ import { useState } from "react"; import { useQuery } from "@tanstack/react-query"; import { createFileRoute, Link } from "@tanstack/react-router"; -import { useTRPC } from "~/lib/trpc"; + import { NDI_DOMAINS } from "~/lib/ndi-domains"; +import { useTRPC } from "~/lib/trpc"; export const Route = createFileRoute("/admin/company/$companyId")({ component: RouteComponent, @@ -76,7 +77,7 @@ function RouteComponent() { if (isLoading) { return (
-
+
Loading report...
@@ -86,11 +87,9 @@ function RouteComponent() { if (error || !data) { return (
-
+

Failed to load submission

-

- {error?.message} -

+

{error?.message}

e.decisions, - ); + const allDecisions = Object.values(evalsByDomain).flatMap((e) => e.decisions); const overallScore = allDecisions.length > 0 ? allDecisions.reduce((sum, d) => sum + getScore(d.decision), 0) / @@ -165,7 +162,7 @@ function RouteComponent() { return (
-
+
{/* Header */}
-

+

{submission.companyName}

NDI Assessment Report

{report?.reportPath && ( - @@ -418,17 +428,17 @@ function DomainCard({ domain, files, evaluation }: DomainCardProps) { {/* Expanded Details */} {expanded && hasEval && ( -
+
{/* AI Summary */} {summaries.length > 0 && (
-

+

AI Assessment Summary

{summaries.map((summary, i) => (

{summary}

@@ -437,23 +447,20 @@ function DomainCard({ domain, files, evaluation }: DomainCardProps) { )} {/* Control Decisions Checklist */} -

+

Control Evaluations

{decisions.map((decision, i) => { const icon = getDecisionIcon(decision.decision); return ( -
+
{/* Status Icon */} -
+
{icon === "pass" && ( {/* Content */} -
-
- +
+
+ {decision.control_id} {decision.decision}
-

+

{decision.rationale}

diff --git a/apps/tanstack-start/src/routes/admin/index.tsx b/apps/tanstack-start/src/routes/admin/index.tsx index 389f3a6..455c63d 100644 --- a/apps/tanstack-start/src/routes/admin/index.tsx +++ b/apps/tanstack-start/src/routes/admin/index.tsx @@ -1,39 +1,40 @@ import { createFileRoute, Link } from "@tanstack/react-router"; + import { IndexCard } from "~/component/index/IndexCard"; export const Route = createFileRoute("/admin/")({ - component: RouteComponent, + component: RouteComponent, }); function RouteComponent() { - return ( -
-
- {/* Header Section */} -
-

- Admin Dashboard -

-

- Select an index to view submissions -

-
+ return ( +
+
+ {/* Header Section */} +
+

+ Admin Dashboard +

+

+ Select an index to view submissions +

+
- {/* Index Cards */} -
- - -
-
-
- ); + {/* Index Cards */} +
+ + +
+
+
+ ); } diff --git a/apps/tanstack-start/src/routes/admin/ndi.tsx b/apps/tanstack-start/src/routes/admin/ndi.tsx index f2c2868..0f9d3e8 100644 --- a/apps/tanstack-start/src/routes/admin/ndi.tsx +++ b/apps/tanstack-start/src/routes/admin/ndi.tsx @@ -1,125 +1,159 @@ import { useQuery } from "@tanstack/react-query"; import { createFileRoute, Link } from "@tanstack/react-router"; + import { useTRPC } from "~/lib/trpc"; export const Route = createFileRoute("/admin/ndi")({ - component: RouteComponent, + component: RouteComponent, }); - - function RouteComponent() { - const trpc = useTRPC(); - const { data: submissions, isLoading, error } = useQuery(trpc.submission.getAll.queryOptions()); + const trpc = useTRPC(); + const { + data: submissions, + isLoading, + error, + } = useQuery(trpc.submission.getAll.queryOptions()); - return ( -
-
- {/* Header */} -
- - - - - Back to Dashboard - -

- NDI Submissions -

-

- View and manage all company submissions -

-
+ return ( +
+
+ {/* Header */} +
+ + + + + Back to Dashboard + +

+ NDI Submissions +

+

+ View and manage all company submissions +

+
- {isLoading ? ( -
Loading submissions...
- ) : error ? ( -
-

Failed to load submissions

-

{error.message}

-
- ) : !submissions || submissions.length === 0 ? ( -
-

- No Submissions Yet -

-

- Company submissions will appear here -

-
- ) : ( -
- {submissions.map((submission) => ( - - ))} -
- )} -
-
- ); + {isLoading ? ( +
+ Loading submissions... +
+ ) : error ? ( +
+

Failed to load submissions

+

{error.message}

+
+ ) : !submissions || submissions.length === 0 ? ( +
+

+ No Submissions Yet +

+

+ Company submissions will appear here +

+
+ ) : ( +
+ {submissions.map((submission) => ( + + ))} +
+ )} +
+
+ ); } interface CompanyCardProps { - submission: { - id: string; - companyName: string; - userId: string; - status: string; - createdAt: Date; - updatedAt: Date; - }; + submission: { + id: string; + companyName: string; + userId: string; + status: string; + createdAt: Date; + updatedAt: Date; + }; } function CompanyCard({ submission }: CompanyCardProps) { - const statusColors = { - completed: "bg-ndmo-green text-primary", - processing: "bg-ndmo-yellow text-primary", - pending: "bg-ndmo-gray-medium text-primary", - failed: "bg-ndmo-red text-primary", - }; + const statusColors = { + completed: "bg-ndmo-green text-primary", + processing: "bg-ndmo-yellow text-primary", + pending: "bg-ndmo-gray-medium text-primary", + failed: "bg-ndmo-red text-primary", + }; - const statusColor = statusColors[submission.status as keyof typeof statusColors] || statusColors.pending; + const statusColor = + statusColors[submission.status as keyof typeof statusColors] || + statusColors.pending; - return ( - -
- {/* Company Name */} -

- {submission.companyName} -

+ return ( + +
+ {/* Company Name */} +

+ {submission.companyName} +

- {/* Metadata */} -
-
- - - - {new Date(submission.createdAt).toLocaleDateString()} -
-
+ {/* Metadata */} +
+
+ + + + {new Date(submission.createdAt).toLocaleDateString()} +
+
- {/* Status Badge */} -
- - {submission.status} - - - - -
-
- - ); + {/* Status Badge */} +
+ + {submission.status} + + + + +
+
+ + ); } diff --git a/apps/tanstack-start/src/routes/api/auth/callback.tsx b/apps/tanstack-start/src/routes/api/auth/callback.tsx index faf3097..5d655ec 100644 --- a/apps/tanstack-start/src/routes/api/auth/callback.tsx +++ b/apps/tanstack-start/src/routes/api/auth/callback.tsx @@ -2,9 +2,9 @@ import { createFileRoute } from "@tanstack/react-router"; import { handleCallbackRoute } from "@workos/authkit-tanstack-react-start"; export const Route = createFileRoute("/api/auth/callback")({ - server: { - handlers: { - GET: handleCallbackRoute(), - }, + server: { + handlers: { + GET: handleCallbackRoute(), }, + }, }); diff --git a/apps/tanstack-start/src/routes/index.tsx b/apps/tanstack-start/src/routes/index.tsx index 3637273..aaada67 100644 --- a/apps/tanstack-start/src/routes/index.tsx +++ b/apps/tanstack-start/src/routes/index.tsx @@ -1,4 +1,5 @@ import { createFileRoute } from "@tanstack/react-router"; + import { IndexCard } from "~/component/index/IndexCard"; export const Route = createFileRoute("/")({ @@ -8,19 +9,19 @@ export const Route = createFileRoute("/")({ function RouteComponent() { return (
-
+
{/* Header Section */} -
-

+
+

National Data Indices

-

+

Select an index to begin your assessment

{/* Index Cards */} -
+
=> { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.readAsDataURL(file); - reader.onload = () => { - // remove data:application/pdf;base64, prefix - const result = reader.result as string; - const base64 = result.split(',')[1]; - if (base64) resolve(base64); - else reject(new Error('Failed to convert file to base64')); - }; - reader.onerror = error => reject(error); - }); + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => { + // remove data:application/pdf;base64, prefix + const result = reader.result as string; + const base64 = result.split(",")[1]; + if (base64) resolve(base64); + else reject(new Error("Failed to convert file to base64")); + }; + reader.onerror = (error) => reject(error); + }); }; export const Route = createFileRoute("/submit")({ - component: RouteComponent, + component: RouteComponent, }); interface FileWithDomain { - file: File; - domainId: string; + file: File; + domainId: string; } function RouteComponent() { - const navigate = useNavigate(); - const [filesByDomain, setFilesByDomain] = useState>({}); - const [isSubmitting, setIsSubmitting] = useState(false); - const trpc = useTRPC(); - const createSubmission = useMutation(trpc.submission.create.mutationOptions()); + const navigate = useNavigate(); + const [filesByDomain, setFilesByDomain] = useState>( + {}, + ); + const [isSubmitting, setIsSubmitting] = useState(false); + const trpc = useTRPC(); + const createSubmission = useMutation( + trpc.submission.create.mutationOptions(), + ); - const form = useForm({ - defaultValues: { - companyName: "", - }, - onSubmit: async ({ value }) => { - // Validate company name - if (!value.companyName.trim()) { - toast.error("Please enter your company name"); - return; - } + const form = useForm({ + defaultValues: { + companyName: "", + }, + onSubmit: async ({ value }) => { + // Validate company name + if (!value.companyName.trim()) { + toast.error("Please enter your company name"); + return; + } - // Check if at least one file is uploaded - const totalFiles = Object.values(filesByDomain).reduce( - (sum, files) => sum + files.length, - 0 - ); - if (totalFiles === 0) { - toast.error("Please upload at least one file"); - return; - } + // Check if at least one file is uploaded + const totalFiles = Object.values(filesByDomain).reduce( + (sum, files) => sum + files.length, + 0, + ); + if (totalFiles === 0) { + toast.error("Please upload at least one file"); + return; + } - setIsSubmitting(true); + setIsSubmitting(true); - try { - const filesToUpload = []; - for (const [domainId, files] of Object.entries(filesByDomain)) { - const domain = NDI_DOMAINS.find(d => d.id === domainId); - const domainName = domain ? domain.name : "Unknown"; - for (const file of files) { - const content = await fileToBase64(file); - filesToUpload.push({ - name: file.name, - content, - type: file.type, - domainId, - domainName, - size: file.size - }); - } - } + try { + const filesToUpload = []; + for (const [domainId, files] of Object.entries(filesByDomain)) { + const domain = NDI_DOMAINS.find((d) => d.id === domainId); + const domainName = domain ? domain.name : "Unknown"; + for (const file of files) { + const content = await fileToBase64(file); + filesToUpload.push({ + name: file.name, + content, + type: file.type, + domainId, + domainName, + size: file.size, + }); + } + } - const result = await createSubmission.mutateAsync({ - companyName: value.companyName, - files: filesToUpload - }); + const result = await createSubmission.mutateAsync({ + companyName: value.companyName, + files: filesToUpload, + }); - if (result.evaluationFailed) { - toast.success("Submission saved. AI evaluation could not be completed — you can retry later."); - } else { - toast.success("Submission created and evaluated successfully!"); - } - await navigate({ to: "/admin/ndi" }); - } catch (error) { - toast.error("Failed to save submission. Please try again."); - console.error(error); - } finally { - setIsSubmitting(false); - } - }, - }); + if (result.evaluationFailed) { + toast.success( + "Submission saved. AI evaluation could not be completed — you can retry later.", + ); + } else { + toast.success("Submission created and evaluated successfully!"); + } + await navigate({ to: "/admin/ndi" }); + } catch (error) { + toast.error("Failed to save submission. Please try again."); + console.error(error); + } finally { + setIsSubmitting(false); + } + }, + }); - const handleFileChange = useCallback( - (domainId: string, files: FileList | null) => { - if (!files) return; + const handleFileChange = useCallback( + (domainId: string, files: FileList | null) => { + if (!files) return; - const fileArray = Array.from(files); - const currentFiles = filesByDomain[domainId] || []; + const fileArray = Array.from(files); + const currentFiles = filesByDomain[domainId] || []; - // Limit to 20 files per domain - const newFiles = [...currentFiles, ...fileArray].slice(0, 20); + // Limit to 20 files per domain + const newFiles = [...currentFiles, ...fileArray].slice(0, 20); - setFilesByDomain((prev) => ({ - ...prev, - [domainId]: newFiles, - })); - }, - [filesByDomain] - ); + setFilesByDomain((prev) => ({ + ...prev, + [domainId]: newFiles, + })); + }, + [filesByDomain], + ); - const removeFile = useCallback((domainId: string, index: number) => { - setFilesByDomain((prev) => ({ - ...prev, - [domainId]: (prev[domainId] || []).filter((_, i) => i !== index), - })); - }, []); + const removeFile = useCallback((domainId: string, index: number) => { + setFilesByDomain((prev) => ({ + ...prev, + [domainId]: (prev[domainId] || []).filter((_, i) => i !== index), + })); + }, []); - return ( -
-
- {/* Header */} -
-

- NDI Assessment Submission -

-

- Upload your documents for Nationality Data Index evaluation -

-
- - {/* Form */} -
{ - e.preventDefault(); - void form.handleSubmit(); - }} - className="space-y-8" - > - {/* Company Name */} -
- - {(field) => { - const isInvalid = - field.state.meta.isTouched && !field.state.meta.isValid; - return ( - - - - Company Name * - - - field.handleChange(e.target.value)} - aria-invalid={isInvalid} - placeholder="Enter your company name" - className="mt-2" - /> - {isInvalid && } - - ); - }} - -
+ return ( +
+
+ {/* Header */} +
+

+ NDI Assessment Submission +

+

+ Upload your documents for Nationality Data Index evaluation +

+
- {/* Upload Documents Section */} -
-

- Upload Documents -

+ {/* Form */} + { + e.preventDefault(); + void form.handleSubmit(); + }} + className="space-y-8" + > + {/* Company Name */} +
+ + {(field) => { + const isInvalid = + field.state.meta.isTouched && !field.state.meta.isValid; + return ( + + + + Company Name * + + + field.handleChange(e.target.value)} + aria-invalid={isInvalid} + placeholder="Enter your company name" + className="mt-2" + /> + {isInvalid && ( + + )} + + ); + }} + +
-
- {NDI_DOMAINS.map((domain) => ( - handleFileChange(domain.id, files)} - onRemoveFile={(index) => removeFile(domain.id, index)} - /> - ))} -
-
+ {/* Upload Documents Section */} +
+

+ Upload Documents +

- {/* Submit Button */} -
- -
- +
+ {NDI_DOMAINS.map((domain) => ( + handleFileChange(domain.id, files)} + onRemoveFile={(index) => removeFile(domain.id, index)} + /> + ))}
-
- ); +
+ + {/* Submit Button */} +
+ +
+ +
+

+ ); } interface DomainUploadSectionProps { - domain: (typeof NDI_DOMAINS)[number]; - files: File[]; - onFileChange: (files: FileList | null) => void; - onRemoveFile: (index: number) => void; + domain: (typeof NDI_DOMAINS)[number]; + files: File[]; + onFileChange: (files: FileList | null) => void; + onRemoveFile: (index: number) => void; } function DomainUploadSection({ - domain, - files, - onFileChange, - onRemoveFile, + domain, + files, + onFileChange, + onRemoveFile, }: DomainUploadSectionProps) { - return ( -
-
- {/* Domain Number */} -
- {domain.order} -
+ return ( +
+
+ {/* Domain Number */} +
+ {domain.order} +
- {/* Domain Content */} -
-

- {domain.name} -

+ {/* Domain Content */} +
+

+ {domain.name} +

- {/* File Upload */} -
- + {/* File Upload */} +
+ - {/* File List */} - {files.length > 0 && ( -
- {files.map((file, index) => ( -
-
- - - - - {file.name} - - - ({(file.size / 1024).toFixed(1)} KB) - -
- -
- ))} - {files.length >= 20 && ( -

- Maximum 20 files reached for this domain -

- )} -
- )} + {/* File List */} + {files.length > 0 && ( +
+ {files.map((file, index) => ( +
+
+ + + + + {file.name} + + + ({(file.size / 1024).toFixed(1)} KB) +
-
-
+ +
+ ))} + {files.length >= 20 && ( +

+ Maximum 20 files reached for this domain +

+ )} +
+ )} +
- ); +
+
+ ); } diff --git a/packages/api/src/ai-client/client.gen.ts b/packages/api/src/ai-client/client.gen.ts index 49f87f3..13eb4d3 100644 --- a/packages/api/src/ai-client/client.gen.ts +++ b/packages/api/src/ai-client/client.gen.ts @@ -1,7 +1,8 @@ -// This file is auto-generated by @hey-api/openapi-ts +import type { ClientOptions, Config } from "./client"; +import type { ClientOptions as ClientOptions2 } from "./types.gen"; +import { createClient, createConfig } from "./client"; -import { type ClientOptions, type Config, createClient, createConfig } from './client'; -import type { ClientOptions as ClientOptions2 } from './types.gen'; +// This file is auto-generated by @hey-api/openapi-ts /** * The `createClientConfig()` function will be called on client initialization @@ -11,6 +12,10 @@ import type { ClientOptions as ClientOptions2 } from './types.gen'; * `setConfig()`. This is useful for example if you're using Next.js * to ensure your client always has the correct values. */ -export type CreateClientConfig = (override?: Config) => Config & T>; +export type CreateClientConfig = ( + override?: Config, +) => Config & T>; -export const client = createClient(createConfig({ baseUrl: 'http://localhost:8000' })); +export const client = createClient( + createConfig({ baseUrl: "http://localhost:8000" }), +); diff --git a/packages/api/src/ai-client/client/client.gen.ts b/packages/api/src/ai-client/client/client.gen.ts index d2e55a1..64254d0 100644 --- a/packages/api/src/ai-client/client/client.gen.ts +++ b/packages/api/src/ai-client/client/client.gen.ts @@ -1,9 +1,14 @@ // This file is auto-generated by @hey-api/openapi-ts -import { createSseClient } from '../core/serverSentEvents.gen'; -import type { HttpMethod } from '../core/types.gen'; -import { getValidRequestBody } from '../core/utils.gen'; -import type { Client, Config, RequestOptions, ResolvedRequestOptions } from './types.gen'; +import type { HttpMethod } from "../core/types.gen"; +import type { + Client, + Config, + RequestOptions, + ResolvedRequestOptions, +} from "./types.gen"; +import { createSseClient } from "../core/serverSentEvents.gen"; +import { getValidRequestBody } from "../core/utils.gen"; import { buildUrl, createConfig, @@ -12,9 +17,9 @@ import { mergeConfigs, mergeHeaders, setAuthParams, -} from './utils.gen'; +} from "./utils.gen"; -type ReqInit = Omit & { +type ReqInit = Omit & { body?: any; headers: ReturnType; }; @@ -29,7 +34,12 @@ export const createClient = (config: Config = {}): Client => { return getConfig(); }; - const interceptors = createInterceptors(); + const interceptors = createInterceptors< + Request, + Response, + unknown, + ResolvedRequestOptions + >(); const beforeRequest = async (options: RequestOptions) => { const opts = { @@ -56,8 +66,8 @@ export const createClient = (config: Config = {}): Client => { } // remove Content-Type header if body is empty to avoid sending invalid requests - if (opts.body === undefined || opts.serializedBody === '') { - opts.headers.delete('Content-Type'); + if (opts.body === undefined || opts.serializedBody === "") { + opts.headers.delete("Content-Type"); } const url = buildUrl(opts); @@ -65,11 +75,11 @@ export const createClient = (config: Config = {}): Client => { return { opts, url }; }; - const request: Client['request'] = async (options) => { + const request: Client["request"] = async (options) => { // @ts-expect-error const { opts, url } = await beforeRequest(options); const requestInit: ReqInit = { - redirect: 'follow', + redirect: "follow", ...opts, body: getValidRequestBody(opts), }; @@ -95,7 +105,12 @@ export const createClient = (config: Config = {}): Client => { for (const fn of interceptors.error.fns) { if (fn) { - finalError = (await fn(error, undefined as any, request, opts)) as unknown; + finalError = (await fn( + error, + undefined as any, + request, + opts, + )) as unknown; } } @@ -106,7 +121,7 @@ export const createClient = (config: Config = {}): Client => { } // Return error response - return opts.responseStyle === 'data' + return opts.responseStyle === "data" ? undefined : { error: finalError, @@ -128,30 +143,33 @@ export const createClient = (config: Config = {}): Client => { if (response.ok) { const parseAs = - (opts.parseAs === 'auto' - ? getParseAs(response.headers.get('Content-Type')) - : opts.parseAs) ?? 'json'; - - if (response.status === 204 || response.headers.get('Content-Length') === '0') { + (opts.parseAs === "auto" + ? getParseAs(response.headers.get("Content-Type")) + : opts.parseAs) ?? "json"; + + if ( + response.status === 204 || + response.headers.get("Content-Length") === "0" + ) { let emptyData: any; switch (parseAs) { - case 'arrayBuffer': - case 'blob': - case 'text': + case "arrayBuffer": + case "blob": + case "text": emptyData = await response[parseAs](); break; - case 'formData': + case "formData": emptyData = new FormData(); break; - case 'stream': + case "stream": emptyData = response.body; break; - case 'json': + case "json": default: emptyData = {}; break; } - return opts.responseStyle === 'data' + return opts.responseStyle === "data" ? emptyData : { data: emptyData, @@ -161,21 +179,21 @@ export const createClient = (config: Config = {}): Client => { let data: any; switch (parseAs) { - case 'arrayBuffer': - case 'blob': - case 'formData': - case 'text': + case "arrayBuffer": + case "blob": + case "formData": + case "text": data = await response[parseAs](); break; - case 'json': { + case "json": { // Some servers return 200 with no Content-Length and empty body. // response.json() would throw; read as text and parse if non-empty. const text = await response.text(); data = text ? JSON.parse(text) : {}; break; } - case 'stream': - return opts.responseStyle === 'data' + case "stream": + return opts.responseStyle === "data" ? response.body : { data: response.body, @@ -183,7 +201,7 @@ export const createClient = (config: Config = {}): Client => { }; } - if (parseAs === 'json') { + if (parseAs === "json") { if (opts.responseValidator) { await opts.responseValidator(data); } @@ -193,7 +211,7 @@ export const createClient = (config: Config = {}): Client => { } } - return opts.responseStyle === 'data' + return opts.responseStyle === "data" ? data : { data, @@ -226,7 +244,7 @@ export const createClient = (config: Config = {}): Client => { } // TODO: we probably want to return error and improve types - return opts.responseStyle === 'data' + return opts.responseStyle === "data" ? undefined : { error: finalError, @@ -234,55 +252,60 @@ export const createClient = (config: Config = {}): Client => { }; }; - const makeMethodFn = (method: Uppercase) => (options: RequestOptions) => - request({ ...options, method }); + const makeMethodFn = + (method: Uppercase) => (options: RequestOptions) => + request({ ...options, method }); - const makeSseFn = (method: Uppercase) => async (options: RequestOptions) => { - const { opts, url } = await beforeRequest(options); - return createSseClient({ - ...opts, - body: opts.body as BodyInit | null | undefined, - headers: opts.headers as unknown as Record, - method, - onRequest: async (url, init) => { - let request = new Request(url, init); - for (const fn of interceptors.request.fns) { - if (fn) { - request = await fn(request, opts); + const makeSseFn = + (method: Uppercase) => async (options: RequestOptions) => { + const { opts, url } = await beforeRequest(options); + return createSseClient({ + ...opts, + body: opts.body as BodyInit | null | undefined, + headers: opts.headers as unknown as Record, + method, + onRequest: async (url, init) => { + let request = new Request(url, init); + for (const fn of interceptors.request.fns) { + if (fn) { + request = await fn(request, opts); + } } - } - return request; - }, - serializedBody: getValidRequestBody(opts) as BodyInit | null | undefined, - url, - }); - }; + return request; + }, + serializedBody: getValidRequestBody(opts) as + | BodyInit + | null + | undefined, + url, + }); + }; return { buildUrl, - connect: makeMethodFn('CONNECT'), - delete: makeMethodFn('DELETE'), - get: makeMethodFn('GET'), + connect: makeMethodFn("CONNECT"), + delete: makeMethodFn("DELETE"), + get: makeMethodFn("GET"), getConfig, - head: makeMethodFn('HEAD'), + head: makeMethodFn("HEAD"), interceptors, - options: makeMethodFn('OPTIONS'), - patch: makeMethodFn('PATCH'), - post: makeMethodFn('POST'), - put: makeMethodFn('PUT'), + options: makeMethodFn("OPTIONS"), + patch: makeMethodFn("PATCH"), + post: makeMethodFn("POST"), + put: makeMethodFn("PUT"), request, setConfig, sse: { - connect: makeSseFn('CONNECT'), - delete: makeSseFn('DELETE'), - get: makeSseFn('GET'), - head: makeSseFn('HEAD'), - options: makeSseFn('OPTIONS'), - patch: makeSseFn('PATCH'), - post: makeSseFn('POST'), - put: makeSseFn('PUT'), - trace: makeSseFn('TRACE'), + connect: makeSseFn("CONNECT"), + delete: makeSseFn("DELETE"), + get: makeSseFn("GET"), + head: makeSseFn("HEAD"), + options: makeSseFn("OPTIONS"), + patch: makeSseFn("PATCH"), + post: makeSseFn("POST"), + put: makeSseFn("PUT"), + trace: makeSseFn("TRACE"), }, - trace: makeMethodFn('TRACE'), + trace: makeMethodFn("TRACE"), } as Client; }; diff --git a/packages/api/src/ai-client/client/index.ts b/packages/api/src/ai-client/client/index.ts index b295ede..4602312 100644 --- a/packages/api/src/ai-client/client/index.ts +++ b/packages/api/src/ai-client/client/index.ts @@ -1,15 +1,15 @@ // This file is auto-generated by @hey-api/openapi-ts -export type { Auth } from '../core/auth.gen'; -export type { QuerySerializerOptions } from '../core/bodySerializer.gen'; +export type { Auth } from "../core/auth.gen"; +export type { QuerySerializerOptions } from "../core/bodySerializer.gen"; export { formDataBodySerializer, jsonBodySerializer, urlSearchParamsBodySerializer, -} from '../core/bodySerializer.gen'; -export { buildClientParams } from '../core/params.gen'; -export { serializeQueryKeyValue } from '../core/queryKeySerializer.gen'; -export { createClient } from './client.gen'; +} from "../core/bodySerializer.gen"; +export { buildClientParams } from "../core/params.gen"; +export { serializeQueryKeyValue } from "../core/queryKeySerializer.gen"; +export { createClient } from "./client.gen"; export type { Client, ClientOptions, @@ -21,5 +21,5 @@ export type { ResolvedRequestOptions, ResponseStyle, TDataShape, -} from './types.gen'; -export { createConfig, mergeHeaders } from './utils.gen'; +} from "./types.gen"; +export { createConfig, mergeHeaders } from "./utils.gen"; diff --git a/packages/api/src/ai-client/client/types.gen.ts b/packages/api/src/ai-client/client/types.gen.ts index cb6d0d5..5ff95be 100644 --- a/packages/api/src/ai-client/client/types.gen.ts +++ b/packages/api/src/ai-client/client/types.gen.ts @@ -1,21 +1,25 @@ // This file is auto-generated by @hey-api/openapi-ts -import type { Auth } from '../core/auth.gen'; +import type { Auth } from "../core/auth.gen"; import type { ServerSentEventsOptions, ServerSentEventsResult, -} from '../core/serverSentEvents.gen'; -import type { Client as CoreClient, Config as CoreConfig } from '../core/types.gen'; -import type { Middleware } from './utils.gen'; +} from "../core/serverSentEvents.gen"; +import type { + Client as CoreClient, + Config as CoreConfig, +} from "../core/types.gen"; +import type { Middleware } from "./utils.gen"; -export type ResponseStyle = 'data' | 'fields'; +export type ResponseStyle = "data" | "fields"; export interface Config - extends Omit, CoreConfig { + extends Omit, + CoreConfig { /** * Base URL for all requests made by this client. */ - baseUrl?: T['baseUrl']; + baseUrl?: T["baseUrl"]; /** * Fetch API implementation. You can use this option to provide a custom * fetch instance. @@ -38,7 +42,14 @@ export interface Config * * @default 'auto' */ - parseAs?: 'arrayBuffer' | 'auto' | 'blob' | 'formData' | 'json' | 'stream' | 'text'; + parseAs?: + | "arrayBuffer" + | "auto" + | "blob" + | "formData" + | "json" + | "stream" + | "text"; /** * Should we return only data or multiple fields (data, error, response, etc.)? * @@ -50,27 +61,25 @@ export interface Config * * @default false */ - throwOnError?: T['throwOnError']; + throwOnError?: T["throwOnError"]; } export interface RequestOptions< TData = unknown, - TResponseStyle extends ResponseStyle = 'fields', + TResponseStyle extends ResponseStyle = "fields", ThrowOnError extends boolean = boolean, Url extends string = string, -> - extends - Config<{ +> extends Config<{ responseStyle: TResponseStyle; throwOnError: ThrowOnError; }>, Pick< ServerSentEventsOptions, - | 'onSseError' - | 'onSseEvent' - | 'sseDefaultRetryDelay' - | 'sseMaxRetryAttempts' - | 'sseMaxRetryDelay' + | "onSseError" + | "onSseEvent" + | "sseDefaultRetryDelay" + | "sseMaxRetryAttempts" + | "sseMaxRetryDelay" > { /** * Any body that you want to add to your request. @@ -88,7 +97,7 @@ export interface RequestOptions< } export interface ResolvedRequestOptions< - TResponseStyle extends ResponseStyle = 'fields', + TResponseStyle extends ResponseStyle = "fields", ThrowOnError extends boolean = boolean, Url extends string = string, > extends RequestOptions { @@ -99,30 +108,40 @@ export type RequestResult< TData = unknown, TError = unknown, ThrowOnError extends boolean = boolean, - TResponseStyle extends ResponseStyle = 'fields', + TResponseStyle extends ResponseStyle = "fields", > = ThrowOnError extends true ? Promise< - TResponseStyle extends 'data' + TResponseStyle extends "data" ? TData extends Record ? TData[keyof TData] : TData : { - data: TData extends Record ? TData[keyof TData] : TData; + data: TData extends Record + ? TData[keyof TData] + : TData; request: Request; response: Response; } > : Promise< - TResponseStyle extends 'data' - ? (TData extends Record ? TData[keyof TData] : TData) | undefined + TResponseStyle extends "data" + ? + | (TData extends Record + ? TData[keyof TData] + : TData) + | undefined : ( | { - data: TData extends Record ? TData[keyof TData] : TData; + data: TData extends Record + ? TData[keyof TData] + : TData; error: undefined; } | { data: undefined; - error: TError extends Record ? TError[keyof TError] : TError; + error: TError extends Record + ? TError[keyof TError] + : TError; } ) & { request: Request; @@ -140,28 +159,31 @@ type MethodFn = < TData = unknown, TError = unknown, ThrowOnError extends boolean = false, - TResponseStyle extends ResponseStyle = 'fields', + TResponseStyle extends ResponseStyle = "fields", >( - options: Omit, 'method'>, + options: Omit, "method">, ) => RequestResult; type SseFn = < TData = unknown, TError = unknown, ThrowOnError extends boolean = false, - TResponseStyle extends ResponseStyle = 'fields', + TResponseStyle extends ResponseStyle = "fields", >( - options: Omit, 'method'>, + options: Omit, "method">, ) => Promise>; type RequestFn = < TData = unknown, TError = unknown, ThrowOnError extends boolean = false, - TResponseStyle extends ResponseStyle = 'fields', + TResponseStyle extends ResponseStyle = "fields", >( - options: Omit, 'method'> & - Pick>, 'method'>, + options: Omit, "method"> & + Pick< + Required>, + "method" + >, ) => RequestResult; type BuildUrlFn = < @@ -175,7 +197,13 @@ type BuildUrlFn = < options: TData & Options, ) => string; -export type Client = CoreClient & { +export type Client = CoreClient< + RequestFn, + Config, + MethodFn, + BuildUrlFn, + SseFn +> & { interceptors: Middleware; }; @@ -205,9 +233,9 @@ export type Options< TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean, TResponse = unknown, - TResponseStyle extends ResponseStyle = 'fields', + TResponseStyle extends ResponseStyle = "fields", > = OmitKeys< RequestOptions, - 'body' | 'path' | 'query' | 'url' + "body" | "path" | "query" | "url" > & - ([TData] extends [never] ? unknown : Omit); + ([TData] extends [never] ? unknown : Omit); diff --git a/packages/api/src/ai-client/client/utils.gen.ts b/packages/api/src/ai-client/client/utils.gen.ts index b4bd243..0aecd39 100644 --- a/packages/api/src/ai-client/client/utils.gen.ts +++ b/packages/api/src/ai-client/client/utils.gen.ts @@ -1,15 +1,20 @@ // This file is auto-generated by @hey-api/openapi-ts -import { getAuthToken } from '../core/auth.gen'; -import type { QuerySerializerOptions } from '../core/bodySerializer.gen'; -import { jsonBodySerializer } from '../core/bodySerializer.gen'; +import type { QuerySerializerOptions } from "../core/bodySerializer.gen"; +import type { + Client, + ClientOptions, + Config, + RequestOptions, +} from "./types.gen"; +import { getAuthToken } from "../core/auth.gen"; +import { jsonBodySerializer } from "../core/bodySerializer.gen"; import { serializeArrayParam, serializeObjectParam, serializePrimitiveParam, -} from '../core/pathSerializer.gen'; -import { getUrl } from '../core/utils.gen'; -import type { Client, ClientOptions, Config, RequestOptions } from './types.gen'; +} from "../core/pathSerializer.gen"; +import { getUrl } from "../core/utils.gen"; export const createQuerySerializer = ({ parameters = {}, @@ -17,7 +22,7 @@ export const createQuerySerializer = ({ }: QuerySerializerOptions = {}) => { const querySerializer = (queryParams: T) => { const search: string[] = []; - if (queryParams && typeof queryParams === 'object') { + if (queryParams && typeof queryParams === "object") { for (const name in queryParams) { const value = queryParams[name]; @@ -32,17 +37,17 @@ export const createQuerySerializer = ({ allowReserved: options.allowReserved, explode: true, name, - style: 'form', + style: "form", value, ...options.array, }); if (serializedArray) search.push(serializedArray); - } else if (typeof value === 'object') { + } else if (typeof value === "object") { const serializedObject = serializeObjectParam({ allowReserved: options.allowReserved, explode: true, name, - style: 'deepObject', + style: "deepObject", value: value as Record, ...options.object, }); @@ -57,7 +62,7 @@ export const createQuerySerializer = ({ } } } - return search.join('&'); + return search.join("&"); }; return querySerializer; }; @@ -65,42 +70,49 @@ export const createQuerySerializer = ({ /** * Infers parseAs value from provided Content-Type header. */ -export const getParseAs = (contentType: string | null): Exclude => { +export const getParseAs = ( + contentType: string | null, +): Exclude => { if (!contentType) { // If no Content-Type header is provided, the best we can do is return the raw response body, // which is effectively the same as the 'stream' option. - return 'stream'; + return "stream"; } - const cleanContent = contentType.split(';')[0]?.trim(); + const cleanContent = contentType.split(";")[0]?.trim(); if (!cleanContent) { return; } - if (cleanContent.startsWith('application/json') || cleanContent.endsWith('+json')) { - return 'json'; + if ( + cleanContent.startsWith("application/json") || + cleanContent.endsWith("+json") + ) { + return "json"; } - if (cleanContent === 'multipart/form-data') { - return 'formData'; + if (cleanContent === "multipart/form-data") { + return "formData"; } if ( - ['application/', 'audio/', 'image/', 'video/'].some((type) => cleanContent.startsWith(type)) + ["application/", "audio/", "image/", "video/"].some((type) => + cleanContent.startsWith(type), + ) ) { - return 'blob'; + return "blob"; } - if (cleanContent.startsWith('text/')) { - return 'text'; + if (cleanContent.startsWith("text/")) { + return "text"; } return; }; const checkForExistence = ( - options: Pick & { + options: Pick & { headers: Headers; }, name?: string, @@ -111,7 +123,7 @@ const checkForExistence = ( if ( options.headers.has(name) || options.query?.[name] || - options.headers.get('Cookie')?.includes(`${name}=`) + options.headers.get("Cookie")?.includes(`${name}=`) ) { return true; } @@ -121,8 +133,8 @@ const checkForExistence = ( export const setAuthParams = async ({ security, ...options -}: Pick, 'security'> & - Pick & { +}: Pick, "security"> & + Pick & { headers: Headers; }) => { for (const auth of security) { @@ -136,19 +148,19 @@ export const setAuthParams = async ({ continue; } - const name = auth.name ?? 'Authorization'; + const name = auth.name ?? "Authorization"; switch (auth.in) { - case 'query': + case "query": if (!options.query) { options.query = {}; } options.query[name] = token; break; - case 'cookie': - options.headers.append('Cookie', `${name}=${token}`); + case "cookie": + options.headers.append("Cookie", `${name}=${token}`); break; - case 'header': + case "header": default: options.headers.set(name, token); break; @@ -156,13 +168,13 @@ export const setAuthParams = async ({ } }; -export const buildUrl: Client['buildUrl'] = (options) => +export const buildUrl: Client["buildUrl"] = (options) => getUrl({ baseUrl: options.baseUrl as string, path: options.path, query: options.query, querySerializer: - typeof options.querySerializer === 'function' + typeof options.querySerializer === "function" ? options.querySerializer : createQuerySerializer(options.querySerializer), url: options.url, @@ -170,7 +182,7 @@ export const buildUrl: Client['buildUrl'] = (options) => export const mergeConfigs = (a: Config, b: Config): Config => { const config = { ...a, ...b }; - if (config.baseUrl?.endsWith('/')) { + if (config.baseUrl?.endsWith("/")) { config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1); } config.headers = mergeHeaders(a.headers, b.headers); @@ -186,7 +198,7 @@ const headersEntries = (headers: Headers): Array<[string, string]> => { }; export const mergeHeaders = ( - ...headers: Array['headers'] | undefined> + ...headers: Array["headers"] | undefined> ): Headers => { const mergedHeaders = new Headers(); for (const header of headers) { @@ -194,7 +206,10 @@ export const mergeHeaders = ( continue; } - const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header); + const iterator = + header instanceof Headers + ? headersEntries(header) + : Object.entries(header); for (const [key, value] of iterator) { if (value === null) { @@ -208,7 +223,7 @@ export const mergeHeaders = ( // content value in OpenAPI specification is 'application/json' mergedHeaders.set( key, - typeof value === 'object' ? JSON.stringify(value) : (value as string), + typeof value === "object" ? JSON.stringify(value) : (value as string), ); } } @@ -223,7 +238,10 @@ type ErrInterceptor = ( options: Options, ) => Err | Promise; -type ReqInterceptor = (request: Req, options: Options) => Req | Promise; +type ReqInterceptor = ( + request: Req, + options: Options, +) => Req | Promise; type ResInterceptor = ( response: Res, @@ -251,13 +269,16 @@ class Interceptors { } getInterceptorIndex(id: number | Interceptor): number { - if (typeof id === 'number') { + if (typeof id === "number") { return this.fns[id] ? id : -1; } return this.fns.indexOf(id); } - update(id: number | Interceptor, fn: Interceptor): number | Interceptor | false { + update( + id: number | Interceptor, + fn: Interceptor, + ): number | Interceptor | false { const index = this.getInterceptorIndex(id); if (this.fns[index]) { this.fns[index] = fn; @@ -293,16 +314,16 @@ const defaultQuerySerializer = createQuerySerializer({ allowReserved: false, array: { explode: true, - style: 'form', + style: "form", }, object: { explode: true, - style: 'deepObject', + style: "deepObject", }, }); const defaultHeaders = { - 'Content-Type': 'application/json', + "Content-Type": "application/json", }; export const createConfig = ( @@ -310,7 +331,7 @@ export const createConfig = ( ): Config & T> => ({ ...jsonBodySerializer, headers: defaultHeaders, - parseAs: 'auto', + parseAs: "auto", querySerializer: defaultQuerySerializer, ...override, }); diff --git a/packages/api/src/ai-client/core/auth.gen.ts b/packages/api/src/ai-client/core/auth.gen.ts index 3ebf994..3d74115 100644 --- a/packages/api/src/ai-client/core/auth.gen.ts +++ b/packages/api/src/ai-client/core/auth.gen.ts @@ -8,32 +8,33 @@ export interface Auth { * * @default 'header' */ - in?: 'header' | 'query' | 'cookie'; + in?: "header" | "query" | "cookie"; /** * Header or query parameter name. * * @default 'Authorization' */ name?: string; - scheme?: 'basic' | 'bearer'; - type: 'apiKey' | 'http'; + scheme?: "basic" | "bearer"; + type: "apiKey" | "http"; } export const getAuthToken = async ( auth: Auth, callback: ((auth: Auth) => Promise | AuthToken) | AuthToken, ): Promise => { - const token = typeof callback === 'function' ? await callback(auth) : callback; + const token = + typeof callback === "function" ? await callback(auth) : callback; if (!token) { return; } - if (auth.scheme === 'bearer') { + if (auth.scheme === "bearer") { return `Bearer ${token}`; } - if (auth.scheme === 'basic') { + if (auth.scheme === "basic") { return `Basic ${btoa(token)}`; } diff --git a/packages/api/src/ai-client/core/bodySerializer.gen.ts b/packages/api/src/ai-client/core/bodySerializer.gen.ts index 8ad92c9..2ed9d6d 100644 --- a/packages/api/src/ai-client/core/bodySerializer.gen.ts +++ b/packages/api/src/ai-client/core/bodySerializer.gen.ts @@ -1,6 +1,10 @@ // This file is auto-generated by @hey-api/openapi-ts -import type { ArrayStyle, ObjectStyle, SerializerOptions } from './pathSerializer.gen'; +import type { + ArrayStyle, + ObjectStyle, + SerializerOptions, +} from "./pathSerializer.gen"; export type QuerySerializer = (query: Record) => string; @@ -20,8 +24,12 @@ export type QuerySerializerOptions = QuerySerializerOptionsObject & { parameters?: Record; }; -const serializeFormDataPair = (data: FormData, key: string, value: unknown): void => { - if (typeof value === 'string' || value instanceof Blob) { +const serializeFormDataPair = ( + data: FormData, + key: string, + value: unknown, +): void => { + if (typeof value === "string" || value instanceof Blob) { data.append(key, value); } else if (value instanceof Date) { data.append(key, value.toISOString()); @@ -30,8 +38,12 @@ const serializeFormDataPair = (data: FormData, key: string, value: unknown): voi } }; -const serializeUrlSearchParamsPair = (data: URLSearchParams, key: string, value: unknown): void => { - if (typeof value === 'string') { +const serializeUrlSearchParamsPair = ( + data: URLSearchParams, + key: string, + value: unknown, +): void => { + if (typeof value === "string") { data.append(key, value); } else { data.append(key, JSON.stringify(value)); @@ -61,11 +73,15 @@ export const formDataBodySerializer = { export const jsonBodySerializer = { bodySerializer: (body: T): string => - JSON.stringify(body, (_key, value) => (typeof value === 'bigint' ? value.toString() : value)), + JSON.stringify(body, (_key, value) => + typeof value === "bigint" ? value.toString() : value, + ), }; export const urlSearchParamsBodySerializer = { - bodySerializer: | Array>>(body: T): string => { + bodySerializer: | Array>>( + body: T, + ): string => { const data = new URLSearchParams(); Object.entries(body).forEach(([key, value]) => { diff --git a/packages/api/src/ai-client/core/params.gen.ts b/packages/api/src/ai-client/core/params.gen.ts index 6099cab..fb9f992 100644 --- a/packages/api/src/ai-client/core/params.gen.ts +++ b/packages/api/src/ai-client/core/params.gen.ts @@ -1,10 +1,10 @@ // This file is auto-generated by @hey-api/openapi-ts -type Slot = 'body' | 'headers' | 'path' | 'query'; +type Slot = "body" | "headers" | "path" | "query"; export type Field = | { - in: Exclude; + in: Exclude; /** * Field name. This is the name we want the user to see and use. */ @@ -16,7 +16,7 @@ export type Field = map?: string; } | { - in: Extract; + in: Extract; /** * Key isn't required for bodies. */ @@ -43,10 +43,10 @@ export interface Fields { export type FieldsConfig = ReadonlyArray; const extraPrefixesMap: Record = { - $body_: 'body', - $headers_: 'headers', - $path_: 'path', - $query_: 'query', + $body_: "body", + $headers_: "headers", + $path_: "path", + $query_: "query", }; const extraPrefixes = Object.entries(extraPrefixesMap); @@ -68,14 +68,14 @@ const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { } for (const config of fields) { - if ('in' in config) { + if ("in" in config) { if (config.key) { map.set(config.key, { in: config.in, map: config.map, }); } - } else if ('key' in config) { + } else if ("key" in config) { map.set(config.key, { map: config.map, }); @@ -96,13 +96,16 @@ interface Params { const stripEmptySlots = (params: Params) => { for (const [slot, value] of Object.entries(params)) { - if (value && typeof value === 'object' && !Object.keys(value).length) { + if (value && typeof value === "object" && !Object.keys(value).length) { delete params[slot as Slot]; } } }; -export const buildClientParams = (args: ReadonlyArray, fields: FieldsConfig) => { +export const buildClientParams = ( + args: ReadonlyArray, + fields: FieldsConfig, +) => { const params: Params = { body: {}, headers: {}, @@ -123,7 +126,7 @@ export const buildClientParams = (args: ReadonlyArray, fields: FieldsCo continue; } - if ('in' in config) { + if ("in" in config) { if (config.key) { const field = map.get(config.key)!; const name = field.map || config.key; @@ -145,12 +148,16 @@ export const buildClientParams = (args: ReadonlyArray, fields: FieldsCo params[field.map] = value; } } else { - const extra = extraPrefixes.find(([prefix]) => key.startsWith(prefix)); + const extra = extraPrefixes.find(([prefix]) => + key.startsWith(prefix), + ); if (extra) { const [prefix, slot] = extra; - (params[slot] as Record)[key.slice(prefix.length)] = value; - } else if ('allowExtra' in config && config.allowExtra) { + (params[slot] as Record)[ + key.slice(prefix.length) + ] = value; + } else if ("allowExtra" in config && config.allowExtra) { for (const [slot, allowed] of Object.entries(config.allowExtra)) { if (allowed) { (params[slot as Slot] as Record)[key] = value; diff --git a/packages/api/src/ai-client/core/pathSerializer.gen.ts b/packages/api/src/ai-client/core/pathSerializer.gen.ts index 994b284..034aa68 100644 --- a/packages/api/src/ai-client/core/pathSerializer.gen.ts +++ b/packages/api/src/ai-client/core/pathSerializer.gen.ts @@ -1,6 +1,8 @@ // This file is auto-generated by @hey-api/openapi-ts -interface SerializeOptions extends SerializePrimitiveOptions, SerializerOptions {} +interface SerializeOptions + extends SerializePrimitiveOptions, + SerializerOptions {} interface SerializePrimitiveOptions { allowReserved?: boolean; @@ -15,10 +17,10 @@ export interface SerializerOptions { style: T; } -export type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited'; +export type ArrayStyle = "form" | "spaceDelimited" | "pipeDelimited"; export type ArraySeparatorStyle = ArrayStyle | MatrixStyle; -type MatrixStyle = 'label' | 'matrix' | 'simple'; -export type ObjectStyle = 'form' | 'deepObject'; +type MatrixStyle = "label" | "matrix" | "simple"; +export type ObjectStyle = "form" | "deepObject"; type ObjectSeparatorStyle = ObjectStyle | MatrixStyle; interface SerializePrimitiveParam extends SerializePrimitiveOptions { @@ -27,40 +29,40 @@ interface SerializePrimitiveParam extends SerializePrimitiveOptions { export const separatorArrayExplode = (style: ArraySeparatorStyle) => { switch (style) { - case 'label': - return '.'; - case 'matrix': - return ';'; - case 'simple': - return ','; + case "label": + return "."; + case "matrix": + return ";"; + case "simple": + return ","; default: - return '&'; + return "&"; } }; export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => { switch (style) { - case 'form': - return ','; - case 'pipeDelimited': - return '|'; - case 'spaceDelimited': - return '%20'; + case "form": + return ","; + case "pipeDelimited": + return "|"; + case "spaceDelimited": + return "%20"; default: - return ','; + return ","; } }; export const separatorObjectExplode = (style: ObjectSeparatorStyle) => { switch (style) { - case 'label': - return '.'; - case 'matrix': - return ';'; - case 'simple': - return ','; + case "label": + return "."; + case "matrix": + return ";"; + case "simple": + return ","; default: - return '&'; + return "&"; } }; @@ -78,11 +80,11 @@ export const serializeArrayParam = ({ allowReserved ? value : value.map((v) => encodeURIComponent(v as string)) ).join(separatorArrayNoExplode(style)); switch (style) { - case 'label': + case "label": return `.${joinedValues}`; - case 'matrix': + case "matrix": return `;${name}=${joinedValues}`; - case 'simple': + case "simple": return joinedValues; default: return `${name}=${joinedValues}`; @@ -92,7 +94,7 @@ export const serializeArrayParam = ({ const separator = separatorArrayExplode(style); const joinedValues = value .map((v) => { - if (style === 'label' || style === 'simple') { + if (style === "label" || style === "simple") { return allowReserved ? v : encodeURIComponent(v as string); } @@ -103,7 +105,9 @@ export const serializeArrayParam = ({ }); }) .join(separator); - return style === 'label' || style === 'matrix' ? separator + joinedValues : joinedValues; + return style === "label" || style === "matrix" + ? separator + joinedValues + : joinedValues; }; export const serializePrimitiveParam = ({ @@ -112,12 +116,12 @@ export const serializePrimitiveParam = ({ value, }: SerializePrimitiveParam) => { if (value === undefined || value === null) { - return ''; + return ""; } - if (typeof value === 'object') { + if (typeof value === "object") { throw new Error( - 'Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.', + "Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.", ); } @@ -139,18 +143,22 @@ export const serializeObjectParam = ({ return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`; } - if (style !== 'deepObject' && !explode) { + if (style !== "deepObject" && !explode) { let values: string[] = []; Object.entries(value).forEach(([key, v]) => { - values = [...values, key, allowReserved ? (v as string) : encodeURIComponent(v as string)]; + values = [ + ...values, + key, + allowReserved ? (v as string) : encodeURIComponent(v as string), + ]; }); - const joinedValues = values.join(','); + const joinedValues = values.join(","); switch (style) { - case 'form': + case "form": return `${name}=${joinedValues}`; - case 'label': + case "label": return `.${joinedValues}`; - case 'matrix': + case "matrix": return `;${name}=${joinedValues}`; default: return joinedValues; @@ -162,10 +170,12 @@ export const serializeObjectParam = ({ .map(([key, v]) => serializePrimitiveParam({ allowReserved, - name: style === 'deepObject' ? `${name}[${key}]` : key, + name: style === "deepObject" ? `${name}[${key}]` : key, value: v as string, }), ) .join(separator); - return style === 'label' || style === 'matrix' ? separator + joinedValues : joinedValues; + return style === "label" || style === "matrix" + ? separator + joinedValues + : joinedValues; }; diff --git a/packages/api/src/ai-client/core/queryKeySerializer.gen.ts b/packages/api/src/ai-client/core/queryKeySerializer.gen.ts index 5000df6..0713164 100644 --- a/packages/api/src/ai-client/core/queryKeySerializer.gen.ts +++ b/packages/api/src/ai-client/core/queryKeySerializer.gen.ts @@ -15,10 +15,14 @@ export type JsonValue = * Replacer that converts non-JSON values (bigint, Date, etc.) to safe substitutes. */ export const queryKeyJsonReplacer = (_key: string, value: unknown) => { - if (value === undefined || typeof value === 'function' || typeof value === 'symbol') { + if ( + value === undefined || + typeof value === "function" || + typeof value === "symbol" + ) { return undefined; } - if (typeof value === 'bigint') { + if (typeof value === "bigint") { return value.toString(); } if (value instanceof Date) { @@ -46,7 +50,7 @@ export const stringifyToJsonValue = (input: unknown): JsonValue | undefined => { * Detects plain objects (including objects with a null prototype). */ const isPlainObject = (value: unknown): value is Record => { - if (value === null || typeof value !== 'object') { + if (value === null || typeof value !== "object") { return false; } const prototype = Object.getPrototypeOf(value as object); @@ -57,7 +61,9 @@ const isPlainObject = (value: unknown): value is Record => { * Turns URLSearchParams into a sorted JSON object for deterministic keys. */ const serializeSearchParams = (params: URLSearchParams): JsonValue => { - const entries = Array.from(params.entries()).sort(([a], [b]) => a.localeCompare(b)); + const entries = Array.from(params.entries()).sort(([a], [b]) => + a.localeCompare(b), + ); const result: Record = {}; for (const [key, value] of entries) { @@ -80,20 +86,30 @@ const serializeSearchParams = (params: URLSearchParams): JsonValue => { /** * Normalizes any accepted value into a JSON-friendly shape for query keys. */ -export const serializeQueryKeyValue = (value: unknown): JsonValue | undefined => { +export const serializeQueryKeyValue = ( + value: unknown, +): JsonValue | undefined => { if (value === null) { return null; } - if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { + if ( + typeof value === "string" || + typeof value === "number" || + typeof value === "boolean" + ) { return value; } - if (value === undefined || typeof value === 'function' || typeof value === 'symbol') { + if ( + value === undefined || + typeof value === "function" || + typeof value === "symbol" + ) { return undefined; } - if (typeof value === 'bigint') { + if (typeof value === "bigint") { return value.toString(); } @@ -105,7 +121,10 @@ export const serializeQueryKeyValue = (value: unknown): JsonValue | undefined => return stringifyToJsonValue(value); } - if (typeof URLSearchParams !== 'undefined' && value instanceof URLSearchParams) { + if ( + typeof URLSearchParams !== "undefined" && + value instanceof URLSearchParams + ) { return serializeSearchParams(value); } diff --git a/packages/api/src/ai-client/core/serverSentEvents.gen.ts b/packages/api/src/ai-client/core/serverSentEvents.gen.ts index 6aa6cf0..60f825c 100644 --- a/packages/api/src/ai-client/core/serverSentEvents.gen.ts +++ b/packages/api/src/ai-client/core/serverSentEvents.gen.ts @@ -1,9 +1,12 @@ // This file is auto-generated by @hey-api/openapi-ts -import type { Config } from './types.gen'; +import type { Config } from "./types.gen"; -export type ServerSentEventsOptions = Omit & - Pick & { +export type ServerSentEventsOptions = Omit< + RequestInit, + "method" +> & + Pick & { /** * Fetch API implementation. You can use this option to provide a custom * fetch instance. @@ -32,7 +35,7 @@ export type ServerSentEventsOptions = Omit) => void; - serializedBody?: RequestInit['body']; + serializedBody?: RequestInit["body"]; /** * Default retry delay in milliseconds. * @@ -71,7 +74,11 @@ export interface StreamEvent { retry?: number; } -export type ServerSentEventsResult = { +export type ServerSentEventsResult< + TData = unknown, + TReturn = void, + TNext = unknown, +> = { stream: AsyncGenerator< TData extends Record ? TData[keyof TData] : TData, TReturn, @@ -94,7 +101,9 @@ export const createSseClient = ({ }: ServerSentEventsOptions): ServerSentEventsResult => { let lastEventId: string | undefined; - const sleep = sseSleepFn ?? ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms))); + const sleep = + sseSleepFn ?? + ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms))); const createStream = async function* () { let retryDelay: number = sseDefaultRetryDelay ?? 3000; @@ -112,12 +121,12 @@ export const createSseClient = ({ : new Headers(options.headers as Record | undefined); if (lastEventId !== undefined) { - headers.set('Last-Event-ID', lastEventId); + headers.set("Last-Event-ID", lastEventId); } try { const requestInit: RequestInit = { - redirect: 'follow', + redirect: "follow", ...options, body: options.serializedBody, headers, @@ -132,13 +141,18 @@ export const createSseClient = ({ const _fetch = options.fetch ?? globalThis.fetch; const response = await _fetch(request); - if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`); + if (!response.ok) + throw new Error( + `SSE failed: ${response.status} ${response.statusText}`, + ); - if (!response.body) throw new Error('No body in SSE response'); + if (!response.body) throw new Error("No body in SSE response"); - const reader = response.body.pipeThrough(new TextDecoderStream()).getReader(); + const reader = response.body + .pipeThrough(new TextDecoderStream()) + .getReader(); - let buffer = ''; + let buffer = ""; const abortHandler = () => { try { @@ -148,7 +162,7 @@ export const createSseClient = ({ } }; - signal.addEventListener('abort', abortHandler); + signal.addEventListener("abort", abortHandler); try { while (true) { @@ -156,25 +170,28 @@ export const createSseClient = ({ if (done) break; buffer += value; // Normalize line endings: CRLF -> LF, then CR -> LF - buffer = buffer.replace(/\r\n/g, '\n').replace(/\r/g, '\n'); + buffer = buffer.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); - const chunks = buffer.split('\n\n'); - buffer = chunks.pop() ?? ''; + const chunks = buffer.split("\n\n"); + buffer = chunks.pop() ?? ""; for (const chunk of chunks) { - const lines = chunk.split('\n'); + const lines = chunk.split("\n"); const dataLines: Array = []; let eventName: string | undefined; for (const line of lines) { - if (line.startsWith('data:')) { - dataLines.push(line.replace(/^data:\s*/, '')); - } else if (line.startsWith('event:')) { - eventName = line.replace(/^event:\s*/, ''); - } else if (line.startsWith('id:')) { - lastEventId = line.replace(/^id:\s*/, ''); - } else if (line.startsWith('retry:')) { - const parsed = Number.parseInt(line.replace(/^retry:\s*/, ''), 10); + if (line.startsWith("data:")) { + dataLines.push(line.replace(/^data:\s*/, "")); + } else if (line.startsWith("event:")) { + eventName = line.replace(/^event:\s*/, ""); + } else if (line.startsWith("id:")) { + lastEventId = line.replace(/^id:\s*/, ""); + } else if (line.startsWith("retry:")) { + const parsed = Number.parseInt( + line.replace(/^retry:\s*/, ""), + 10, + ); if (!Number.isNaN(parsed)) { retryDelay = parsed; } @@ -185,7 +202,7 @@ export const createSseClient = ({ let parsedJson = false; if (dataLines.length) { - const rawData = dataLines.join('\n'); + const rawData = dataLines.join("\n"); try { data = JSON.parse(rawData); parsedJson = true; @@ -217,7 +234,7 @@ export const createSseClient = ({ } } } finally { - signal.removeEventListener('abort', abortHandler); + signal.removeEventListener("abort", abortHandler); reader.releaseLock(); } @@ -226,12 +243,18 @@ export const createSseClient = ({ // connection failed or aborted; retry after delay onSseError?.(error); - if (sseMaxRetryAttempts !== undefined && attempt >= sseMaxRetryAttempts) { + if ( + sseMaxRetryAttempts !== undefined && + attempt >= sseMaxRetryAttempts + ) { break; // stop after firing error } // exponential backoff: double retry each attempt, cap at 30s - const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 30000); + const backoff = Math.min( + retryDelay * 2 ** (attempt - 1), + sseMaxRetryDelay ?? 30000, + ); await sleep(backoff); } } diff --git a/packages/api/src/ai-client/core/types.gen.ts b/packages/api/src/ai-client/core/types.gen.ts index 9746325..6b23d10 100644 --- a/packages/api/src/ai-client/core/types.gen.ts +++ b/packages/api/src/ai-client/core/types.gen.ts @@ -1,18 +1,22 @@ // This file is auto-generated by @hey-api/openapi-ts -import type { Auth, AuthToken } from './auth.gen'; -import type { BodySerializer, QuerySerializer, QuerySerializerOptions } from './bodySerializer.gen'; +import type { Auth, AuthToken } from "./auth.gen"; +import type { + BodySerializer, + QuerySerializer, + QuerySerializerOptions, +} from "./bodySerializer.gen"; export type HttpMethod = - | 'connect' - | 'delete' - | 'get' - | 'head' - | 'options' - | 'patch' - | 'post' - | 'put' - | 'trace'; + | "connect" + | "delete" + | "get" + | "head" + | "options" + | "patch" + | "post" + | "put" + | "trace"; export type Client< RequestFn = never, @@ -30,7 +34,9 @@ export type Client< setConfig: (config: Config) => Config; } & { [K in HttpMethod]: MethodFn; -} & ([SseFn] extends [never] ? { sse?: never } : { sse: { [K in HttpMethod]: SseFn } }); +} & ([SseFn] extends [never] + ? { sse?: never } + : { sse: { [K in HttpMethod]: SseFn } }); export interface Config { /** @@ -50,10 +56,16 @@ export interface Config { * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more} */ headers?: - | RequestInit['headers'] + | RequestInit["headers"] | Record< string, - string | number | boolean | (string | number | boolean)[] | null | undefined | unknown + | string + | number + | boolean + | (string | number | boolean)[] + | null + | undefined + | unknown >; /** * The request method. @@ -100,5 +112,7 @@ type IsExactlyNeverOrNeverUndefined = [T] extends [never] : false; export type OmitNever> = { - [K in keyof T as IsExactlyNeverOrNeverUndefined extends true ? never : K]: T[K]; + [K in keyof T as IsExactlyNeverOrNeverUndefined extends true + ? never + : K]: T[K]; }; diff --git a/packages/api/src/ai-client/core/utils.gen.ts b/packages/api/src/ai-client/core/utils.gen.ts index e7ddbe3..f6d82a9 100644 --- a/packages/api/src/ai-client/core/utils.gen.ts +++ b/packages/api/src/ai-client/core/utils.gen.ts @@ -1,12 +1,12 @@ // This file is auto-generated by @hey-api/openapi-ts -import type { BodySerializer, QuerySerializer } from './bodySerializer.gen'; +import type { BodySerializer, QuerySerializer } from "./bodySerializer.gen"; +import type { ArraySeparatorStyle } from "./pathSerializer.gen"; import { - type ArraySeparatorStyle, serializeArrayParam, serializeObjectParam, serializePrimitiveParam, -} from './pathSerializer.gen'; +} from "./pathSerializer.gen"; export interface PathSerializer { path: Record; @@ -22,19 +22,19 @@ export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { for (const match of matches) { let explode = false; let name = match.substring(1, match.length - 1); - let style: ArraySeparatorStyle = 'simple'; + let style: ArraySeparatorStyle = "simple"; - if (name.endsWith('*')) { + if (name.endsWith("*")) { explode = true; name = name.substring(0, name.length - 1); } - if (name.startsWith('.')) { + if (name.startsWith(".")) { name = name.substring(1); - style = 'label'; - } else if (name.startsWith(';')) { + style = "label"; + } else if (name.startsWith(";")) { name = name.substring(1); - style = 'matrix'; + style = "matrix"; } const value = path[name]; @@ -44,11 +44,14 @@ export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { } if (Array.isArray(value)) { - url = url.replace(match, serializeArrayParam({ explode, name, style, value })); + url = url.replace( + match, + serializeArrayParam({ explode, name, style, value }), + ); continue; } - if (typeof value === 'object') { + if (typeof value === "object") { url = url.replace( match, serializeObjectParam({ @@ -62,7 +65,7 @@ export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { continue; } - if (style === 'matrix') { + if (style === "matrix") { url = url.replace( match, `;${serializePrimitiveParam({ @@ -74,7 +77,7 @@ export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { } const replaceValue = encodeURIComponent( - style === 'label' ? `.${value as string}` : (value as string), + style === "label" ? `.${value as string}` : (value as string), ); url = url.replace(match, replaceValue); } @@ -95,13 +98,13 @@ export const getUrl = ({ querySerializer: QuerySerializer; url: string; }) => { - const pathUrl = _url.startsWith('/') ? _url : `/${_url}`; - let url = (baseUrl ?? '') + pathUrl; + const pathUrl = _url.startsWith("/") ? _url : `/${_url}`; + let url = (baseUrl ?? "") + pathUrl; if (path) { url = defaultPathSerializer({ path, url }); } - let search = query ? querySerializer(query) : ''; - if (search.startsWith('?')) { + let search = query ? querySerializer(query) : ""; + if (search.startsWith("?")) { search = search.substring(1); } if (search) { @@ -119,15 +122,15 @@ export function getValidRequestBody(options: { const isSerializedBody = hasBody && options.bodySerializer; if (isSerializedBody) { - if ('serializedBody' in options) { + if ("serializedBody" in options) { const hasSerializedBody = - options.serializedBody !== undefined && options.serializedBody !== ''; + options.serializedBody !== undefined && options.serializedBody !== ""; return hasSerializedBody ? options.serializedBody : null; } // not all clients implement a serializedBody property (i.e. client-axios) - return options.body !== '' ? options.body : null; + return options.body !== "" ? options.body : null; } // plain/text body diff --git a/packages/api/src/ai-client/index.ts b/packages/api/src/ai-client/index.ts index b34d48f..2e4a047 100644 --- a/packages/api/src/ai-client/index.ts +++ b/packages/api/src/ai-client/index.ts @@ -1,4 +1,31 @@ // This file is auto-generated by @hey-api/openapi-ts -export { healthHealthGet, type Options, setupFrameworkApiV1FrameworksSetupPost, submitEvaluationApiV1EvaluationsSubmitPost } from './sdk.gen'; -export type { BodySetupFrameworkApiV1FrameworksSetupPost, BodySubmitEvaluationApiV1EvaluationsSubmitPost, ClientOptions, ControlSummary, HealthHealthGetData, HealthHealthGetResponse, HealthHealthGetResponses, HttpValidationError, SetupFrameworkApiV1FrameworksSetupPostData, SetupFrameworkApiV1FrameworksSetupPostError, SetupFrameworkApiV1FrameworksSetupPostErrors, SetupFrameworkApiV1FrameworksSetupPostResponse, SetupFrameworkApiV1FrameworksSetupPostResponses, SetupFrameworkResponse, SubmitEvaluationApiV1EvaluationsSubmitPostData, SubmitEvaluationApiV1EvaluationsSubmitPostError, SubmitEvaluationApiV1EvaluationsSubmitPostErrors, SubmitEvaluationApiV1EvaluationsSubmitPostResponse, SubmitEvaluationApiV1EvaluationsSubmitPostResponses, SubmitEvaluationResponse, ValidationError } from './types.gen'; +export { + healthHealthGet, + type Options, + setupFrameworkApiV1FrameworksSetupPost, + submitEvaluationApiV1EvaluationsSubmitPost, +} from "./sdk.gen"; +export type { + BodySetupFrameworkApiV1FrameworksSetupPost, + BodySubmitEvaluationApiV1EvaluationsSubmitPost, + ClientOptions, + ControlSummary, + HealthHealthGetData, + HealthHealthGetResponse, + HealthHealthGetResponses, + HttpValidationError, + SetupFrameworkApiV1FrameworksSetupPostData, + SetupFrameworkApiV1FrameworksSetupPostError, + SetupFrameworkApiV1FrameworksSetupPostErrors, + SetupFrameworkApiV1FrameworksSetupPostResponse, + SetupFrameworkApiV1FrameworksSetupPostResponses, + SetupFrameworkResponse, + SubmitEvaluationApiV1EvaluationsSubmitPostData, + SubmitEvaluationApiV1EvaluationsSubmitPostError, + SubmitEvaluationApiV1EvaluationsSubmitPostErrors, + SubmitEvaluationApiV1EvaluationsSubmitPostResponse, + SubmitEvaluationApiV1EvaluationsSubmitPostResponses, + SubmitEvaluationResponse, + ValidationError, +} from "./types.gen"; diff --git a/packages/api/src/ai-client/sdk.gen.ts b/packages/api/src/ai-client/sdk.gen.ts index 0963048..420f804 100644 --- a/packages/api/src/ai-client/sdk.gen.ts +++ b/packages/api/src/ai-client/sdk.gen.ts @@ -1,21 +1,34 @@ -// This file is auto-generated by @hey-api/openapi-ts +import type { Client, Options as Options2, TDataShape } from "./client"; +import type { + HealthHealthGetData, + HealthHealthGetResponses, + SetupFrameworkApiV1FrameworksSetupPostData, + SetupFrameworkApiV1FrameworksSetupPostErrors, + SetupFrameworkApiV1FrameworksSetupPostResponses, + SubmitEvaluationApiV1EvaluationsSubmitPostData, + SubmitEvaluationApiV1EvaluationsSubmitPostErrors, + SubmitEvaluationApiV1EvaluationsSubmitPostResponses, +} from "./types.gen"; +import { formDataBodySerializer } from "./client"; +import { client } from "./client.gen"; -import { type Client, formDataBodySerializer, type Options as Options2, type TDataShape } from './client'; -import { client } from './client.gen'; -import type { HealthHealthGetData, HealthHealthGetResponses, SetupFrameworkApiV1FrameworksSetupPostData, SetupFrameworkApiV1FrameworksSetupPostErrors, SetupFrameworkApiV1FrameworksSetupPostResponses, SubmitEvaluationApiV1EvaluationsSubmitPostData, SubmitEvaluationApiV1EvaluationsSubmitPostErrors, SubmitEvaluationApiV1EvaluationsSubmitPostResponses } from './types.gen'; +// This file is auto-generated by @hey-api/openapi-ts -export type Options = Options2 & { - /** - * You can provide a client instance returned by `createClient()` instead of - * individual options. This might be also useful if you want to implement a - * custom client. - */ - client?: Client; - /** - * You can pass arbitrary values through the `meta` object. This can be - * used to access values that aren't defined as part of the SDK function. - */ - meta?: Record; +export type Options< + TData extends TDataShape = TDataShape, + ThrowOnError extends boolean = boolean, +> = Options2 & { + /** + * You can provide a client instance returned by `createClient()` instead of + * individual options. This might be also useful if you want to implement a + * custom client. + */ + client?: Client; + /** + * You can pass arbitrary values through the `meta` object. This can be + * used to access values that aren't defined as part of the SDK function. + */ + meta?: Record; }; /** @@ -23,7 +36,14 @@ export type Options(options?: Options) => (options?.client ?? client).get({ url: '/health', ...options }); +export const healthHealthGet = ( + options?: Options, +) => + (options?.client ?? client).get< + HealthHealthGetResponses, + unknown, + ThrowOnError + >({ url: "/health", ...options }); /** * Setup Framework @@ -32,15 +52,24 @@ export const healthHealthGet = (options?: * Each PDF has a section name; controls are saved as config/frameworks/{framework_name}/{section_name}.json. * Send section_names as one string: comma-separated names, one per file, in the same order as files. */ -export const setupFrameworkApiV1FrameworksSetupPost = (options: Options) => (options.client ?? client).post({ +export const setupFrameworkApiV1FrameworksSetupPost = < + ThrowOnError extends boolean = false, +>( + options: Options, +) => + (options.client ?? client).post< + SetupFrameworkApiV1FrameworksSetupPostResponses, + SetupFrameworkApiV1FrameworksSetupPostErrors, + ThrowOnError + >({ ...formDataBodySerializer, - url: '/api/v1/frameworks/setup', + url: "/api/v1/frameworks/setup", ...options, headers: { - 'Content-Type': null, - ...options.headers - } -}); + "Content-Type": null, + ...options.headers, + }, + }); /** * Submit Evaluation @@ -49,12 +78,24 @@ export const setupFrameworkApiV1FrameworksSetupPost = (options: Options) => (options.client ?? client).post({ +export const submitEvaluationApiV1EvaluationsSubmitPost = < + ThrowOnError extends boolean = false, +>( + options: Options< + SubmitEvaluationApiV1EvaluationsSubmitPostData, + ThrowOnError + >, +) => + (options.client ?? client).post< + SubmitEvaluationApiV1EvaluationsSubmitPostResponses, + SubmitEvaluationApiV1EvaluationsSubmitPostErrors, + ThrowOnError + >({ ...formDataBodySerializer, - url: '/api/v1/evaluations/submit', + url: "/api/v1/evaluations/submit", ...options, headers: { - 'Content-Type': null, - ...options.headers - } -}); + "Content-Type": null, + ...options.headers, + }, + }); diff --git a/packages/api/src/ai-client/types.gen.ts b/packages/api/src/ai-client/types.gen.ts index d6108f5..9af324e 100644 --- a/packages/api/src/ai-client/types.gen.ts +++ b/packages/api/src/ai-client/types.gen.ts @@ -1,169 +1,169 @@ // This file is auto-generated by @hey-api/openapi-ts export type ClientOptions = { - baseUrl: 'http://localhost:8000' | (string & {}); + baseUrl: "http://localhost:8000" | (string & {}); }; /** * Body_setup_framework_api_v1_frameworks_setup_post */ export type BodySetupFrameworkApiV1FrameworksSetupPost = { - /** - * Framework Name - * - * Framework identifier - */ - framework_name: string; - /** - * Section Names - * - * Comma-separated section names (one per PDF, same order as files). Example: policies,procedures,controls - */ - section_names: string; - /** - * Files - * - * PDF files (same order as section_names) - */ - files: Array; + /** + * Framework Name + * + * Framework identifier + */ + framework_name: string; + /** + * Section Names + * + * Comma-separated section names (one per PDF, same order as files). Example: policies,procedures,controls + */ + section_names: string; + /** + * Files + * + * PDF files (same order as section_names) + */ + files: Array; }; /** * Body_submit_evaluation_api_v1_evaluations_submit_post */ export type BodySubmitEvaluationApiV1EvaluationsSubmitPost = { - /** - * Framework Name - * - * Framework identifier (e.g. NDI) - */ - framework_name: string; - /** - * Files - * - * Files (PDF, DOCX, PPTX, CSV, XLSX); 1 or more - */ - files: Array; - /** - * Control Ids 1 - * - * Comma-separated control IDs for file 1 - */ - control_ids_1?: string; - /** - * Control Ids 2 - * - * Comma-separated control IDs for file 2 - */ - control_ids_2?: string; - /** - * Control Ids 3 - * - * Comma-separated control IDs for file 3 - */ - control_ids_3?: string; - /** - * Control Ids 4 - * - * Comma-separated control IDs for file 4 - */ - control_ids_4?: string; - /** - * Control Ids 5 - * - * Comma-separated control IDs for file 5 - */ - control_ids_5?: string; - /** - * Control Ids 6 - * - * Comma-separated control IDs for file 6 - */ - control_ids_6?: string; - /** - * Control Ids 7 - * - * Comma-separated control IDs for file 7 - */ - control_ids_7?: string; - /** - * Control Ids 8 - * - * Comma-separated control IDs for file 8 - */ - control_ids_8?: string; - /** - * Control Ids 9 - * - * Comma-separated control IDs for file 9 - */ - control_ids_9?: string; - /** - * Control Ids 10 - * - * Comma-separated control IDs for file 10 - */ - control_ids_10?: string; - /** - * Control Ids 11 - * - * Comma-separated control IDs for file 11 - */ - control_ids_11?: string; - /** - * Control Ids 12 - * - * Comma-separated control IDs for file 12 - */ - control_ids_12?: string; - /** - * Control Ids 13 - * - * Comma-separated control IDs for file 13 - */ - control_ids_13?: string; - /** - * Control Ids 14 - * - * Comma-separated control IDs for file 14 - */ - control_ids_14?: string; - /** - * Control Ids 15 - * - * Comma-separated control IDs for file 15 - */ - control_ids_15?: string; - /** - * Control Ids 16 - * - * Comma-separated control IDs for file 16 - */ - control_ids_16?: string; - /** - * Control Ids 17 - * - * Comma-separated control IDs for file 17 - */ - control_ids_17?: string; - /** - * Control Ids 18 - * - * Comma-separated control IDs for file 18 - */ - control_ids_18?: string; - /** - * Control Ids 19 - * - * Comma-separated control IDs for file 19 - */ - control_ids_19?: string; - /** - * Control Ids 20 - * - * Comma-separated control IDs for file 20 - */ - control_ids_20?: string; + /** + * Framework Name + * + * Framework identifier (e.g. NDI) + */ + framework_name: string; + /** + * Files + * + * Files (PDF, DOCX, PPTX, CSV, XLSX); 1 or more + */ + files: Array; + /** + * Control Ids 1 + * + * Comma-separated control IDs for file 1 + */ + control_ids_1?: string; + /** + * Control Ids 2 + * + * Comma-separated control IDs for file 2 + */ + control_ids_2?: string; + /** + * Control Ids 3 + * + * Comma-separated control IDs for file 3 + */ + control_ids_3?: string; + /** + * Control Ids 4 + * + * Comma-separated control IDs for file 4 + */ + control_ids_4?: string; + /** + * Control Ids 5 + * + * Comma-separated control IDs for file 5 + */ + control_ids_5?: string; + /** + * Control Ids 6 + * + * Comma-separated control IDs for file 6 + */ + control_ids_6?: string; + /** + * Control Ids 7 + * + * Comma-separated control IDs for file 7 + */ + control_ids_7?: string; + /** + * Control Ids 8 + * + * Comma-separated control IDs for file 8 + */ + control_ids_8?: string; + /** + * Control Ids 9 + * + * Comma-separated control IDs for file 9 + */ + control_ids_9?: string; + /** + * Control Ids 10 + * + * Comma-separated control IDs for file 10 + */ + control_ids_10?: string; + /** + * Control Ids 11 + * + * Comma-separated control IDs for file 11 + */ + control_ids_11?: string; + /** + * Control Ids 12 + * + * Comma-separated control IDs for file 12 + */ + control_ids_12?: string; + /** + * Control Ids 13 + * + * Comma-separated control IDs for file 13 + */ + control_ids_13?: string; + /** + * Control Ids 14 + * + * Comma-separated control IDs for file 14 + */ + control_ids_14?: string; + /** + * Control Ids 15 + * + * Comma-separated control IDs for file 15 + */ + control_ids_15?: string; + /** + * Control Ids 16 + * + * Comma-separated control IDs for file 16 + */ + control_ids_16?: string; + /** + * Control Ids 17 + * + * Comma-separated control IDs for file 17 + */ + control_ids_17?: string; + /** + * Control Ids 18 + * + * Comma-separated control IDs for file 18 + */ + control_ids_18?: string; + /** + * Control Ids 19 + * + * Comma-separated control IDs for file 19 + */ + control_ids_19?: string; + /** + * Control Ids 20 + * + * Comma-separated control IDs for file 20 + */ + control_ids_20?: string; }; /** @@ -172,34 +172,34 @@ export type BodySubmitEvaluationApiV1EvaluationsSubmitPost = { * Summary of extracted controls for one section (PDF). */ export type ControlSummary = { - /** - * Section Name - * - * Name of the section (PDF) - */ - section_name: string; - /** - * Controls Count - * - * Number of controls extracted - */ - controls_count: number; - /** - * Json Path - * - * Relative path to the saved JSON file - */ - json_path: string; + /** + * Section Name + * + * Name of the section (PDF) + */ + section_name: string; + /** + * Controls Count + * + * Number of controls extracted + */ + controls_count: number; + /** + * Json Path + * + * Relative path to the saved JSON file + */ + json_path: string; }; /** * HTTPValidationError */ export type HttpValidationError = { - /** - * Detail - */ - detail?: Array; + /** + * Detail + */ + detail?: Array; }; /** @@ -208,30 +208,30 @@ export type HttpValidationError = { * Response after successfully setting up a framework from multiple PDFs. */ export type SetupFrameworkResponse = { - /** - * Framework Name - * - * Framework identifier - */ - framework_name: string; - /** - * Total Controls - * - * Total controls across all sections - */ - total_controls: number; - /** - * Sections - * - * Per-section summary - */ - sections?: Array; - /** - * Created At - * - * When the setup completed - */ - created_at?: string; + /** + * Framework Name + * + * Framework identifier + */ + framework_name: string; + /** + * Total Controls + * + * Total controls across all sections + */ + total_controls: number; + /** + * Sections + * + * Per-section summary + */ + sections?: Array; + /** + * Created At + * + * When the setup completed + */ + created_at?: string; }; /** @@ -240,120 +240,125 @@ export type SetupFrameworkResponse = { * Response after submitting an evaluation (15 files + framework). */ export type SubmitEvaluationResponse = { - /** - * Evaluation Id - * - * Unique evaluation run ID - */ - evaluation_id: string; - /** - * Mimic Json - * - * DB-mimic: framework_name -> field_1..field_15 -> comma-separated control IDs - */ - mimic_json: { - [key: string]: unknown; - }; - /** - * Report Path - * - * Path to the generated report PDF - */ - report_path?: string; - /** - * File Evaluations - * - * Per-file assessment results - */ - file_evaluations?: Array<{ - [key: string]: unknown; - }>; + /** + * Evaluation Id + * + * Unique evaluation run ID + */ + evaluation_id: string; + /** + * Mimic Json + * + * DB-mimic: framework_name -> field_1..field_15 -> comma-separated control IDs + */ + mimic_json: { + [key: string]: unknown; + }; + /** + * Report Path + * + * Path to the generated report PDF + */ + report_path?: string; + /** + * File Evaluations + * + * Per-file assessment results + */ + file_evaluations?: Array<{ + [key: string]: unknown; + }>; }; /** * ValidationError */ export type ValidationError = { - /** - * Location - */ - loc: Array; - /** - * Message - */ - msg: string; - /** - * Error Type - */ - type: string; + /** + * Location + */ + loc: Array; + /** + * Message + */ + msg: string; + /** + * Error Type + */ + type: string; }; export type HealthHealthGetData = { - body?: never; - path?: never; - query?: never; - url: '/health'; + body?: never; + path?: never; + query?: never; + url: "/health"; }; export type HealthHealthGetResponses = { - /** - * Response Health Health Get - * - * Successful Response - */ - 200: { - [key: string]: string; - }; + /** + * Response Health Health Get + * + * Successful Response + */ + 200: { + [key: string]: string; + }; }; -export type HealthHealthGetResponse = HealthHealthGetResponses[keyof HealthHealthGetResponses]; +export type HealthHealthGetResponse = + HealthHealthGetResponses[keyof HealthHealthGetResponses]; export type SetupFrameworkApiV1FrameworksSetupPostData = { - body: BodySetupFrameworkApiV1FrameworksSetupPost; - path?: never; - query?: never; - url: '/api/v1/frameworks/setup'; + body: BodySetupFrameworkApiV1FrameworksSetupPost; + path?: never; + query?: never; + url: "/api/v1/frameworks/setup"; }; export type SetupFrameworkApiV1FrameworksSetupPostErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; + /** + * Validation Error + */ + 422: HttpValidationError; }; -export type SetupFrameworkApiV1FrameworksSetupPostError = SetupFrameworkApiV1FrameworksSetupPostErrors[keyof SetupFrameworkApiV1FrameworksSetupPostErrors]; +export type SetupFrameworkApiV1FrameworksSetupPostError = + SetupFrameworkApiV1FrameworksSetupPostErrors[keyof SetupFrameworkApiV1FrameworksSetupPostErrors]; export type SetupFrameworkApiV1FrameworksSetupPostResponses = { - /** - * Successful Response - */ - 200: SetupFrameworkResponse; + /** + * Successful Response + */ + 200: SetupFrameworkResponse; }; -export type SetupFrameworkApiV1FrameworksSetupPostResponse = SetupFrameworkApiV1FrameworksSetupPostResponses[keyof SetupFrameworkApiV1FrameworksSetupPostResponses]; +export type SetupFrameworkApiV1FrameworksSetupPostResponse = + SetupFrameworkApiV1FrameworksSetupPostResponses[keyof SetupFrameworkApiV1FrameworksSetupPostResponses]; export type SubmitEvaluationApiV1EvaluationsSubmitPostData = { - body: BodySubmitEvaluationApiV1EvaluationsSubmitPost; - path?: never; - query?: never; - url: '/api/v1/evaluations/submit'; + body: BodySubmitEvaluationApiV1EvaluationsSubmitPost; + path?: never; + query?: never; + url: "/api/v1/evaluations/submit"; }; export type SubmitEvaluationApiV1EvaluationsSubmitPostErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; + /** + * Validation Error + */ + 422: HttpValidationError; }; -export type SubmitEvaluationApiV1EvaluationsSubmitPostError = SubmitEvaluationApiV1EvaluationsSubmitPostErrors[keyof SubmitEvaluationApiV1EvaluationsSubmitPostErrors]; +export type SubmitEvaluationApiV1EvaluationsSubmitPostError = + SubmitEvaluationApiV1EvaluationsSubmitPostErrors[keyof SubmitEvaluationApiV1EvaluationsSubmitPostErrors]; export type SubmitEvaluationApiV1EvaluationsSubmitPostResponses = { - /** - * Successful Response - */ - 200: SubmitEvaluationResponse; + /** + * Successful Response + */ + 200: SubmitEvaluationResponse; }; -export type SubmitEvaluationApiV1EvaluationsSubmitPostResponse = SubmitEvaluationApiV1EvaluationsSubmitPostResponses[keyof SubmitEvaluationApiV1EvaluationsSubmitPostResponses]; +export type SubmitEvaluationApiV1EvaluationsSubmitPostResponse = + SubmitEvaluationApiV1EvaluationsSubmitPostResponses[keyof SubmitEvaluationApiV1EvaluationsSubmitPostResponses]; diff --git a/packages/api/src/lib/ai.ts b/packages/api/src/lib/ai.ts index d59ae9f..dd8116b 100644 --- a/packages/api/src/lib/ai.ts +++ b/packages/api/src/lib/ai.ts @@ -1,19 +1,18 @@ - -import { createClient, createConfig } from "../ai-client/client"; import type { ClientOptions } from "../ai-client/types.gen"; +import { createClient, createConfig } from "../ai-client/client"; export const getAIClient = () => { - const baseUrl = process.env.AI_SERVICE_URL || "http://localhost:8000"; - const apiKey = process.env.AI_SERVICE_KEY; + const baseUrl = process.env.AI_SERVICE_URL || "http://localhost:8000"; + const apiKey = process.env.AI_SERVICE_KEY; - return createClient( - createConfig({ - baseUrl, - headers: apiKey - ? { - Authorization: apiKey, - } - : undefined, - }) - ); + return createClient( + createConfig({ + baseUrl, + headers: apiKey + ? { + Authorization: apiKey, + } + : undefined, + }), + ); }; diff --git a/packages/api/src/router/submission.ts b/packages/api/src/router/submission.ts index c745d0b..cb60d3f 100644 --- a/packages/api/src/router/submission.ts +++ b/packages/api/src/router/submission.ts @@ -112,7 +112,11 @@ export const submissionRouter = { .update(schema.Submission) .set({ status: "failed" }) .where(eq(schema.Submission.id, submission.id)); - return { success: true, submissionId: submission.id, evaluationFailed: true }; + return { + success: true, + submissionId: submission.id, + evaluationFailed: true, + }; } }), @@ -133,7 +137,10 @@ export const submissionRouter = { .limit(1); if (!submission) { - throw new TRPCError({ code: "NOT_FOUND", message: "Submission not found" }); + throw new TRPCError({ + code: "NOT_FOUND", + message: "Submission not found", + }); } const files = await ctx.db diff --git a/packages/api/src/trpc.ts b/packages/api/src/trpc.ts index 7a1734c..60f8457 100644 --- a/packages/api/src/trpc.ts +++ b/packages/api/src/trpc.ts @@ -10,7 +10,7 @@ import { initTRPC, TRPCError } from "@trpc/server"; import superjson from "superjson"; import { z, ZodError } from "zod/v4"; -import type { UserInfo, NoUserInfo } from "@governance/auth"; +import type { NoUserInfo, UserInfo } from "@governance/auth"; import { db } from "@governance/db/client"; /** diff --git a/packages/api/tsconfig.json b/packages/api/tsconfig.json index cbcec5c..a635b50 100644 --- a/packages/api/tsconfig.json +++ b/packages/api/tsconfig.json @@ -1,16 +1,8 @@ { "extends": "@governance/tsconfig/compiled-package.json", "compilerOptions": { - "lib": [ - "ESNext", - "DOM", - "DOM.Iterable" - ] + "lib": ["ESNext", "DOM", "DOM.Iterable"] }, - "include": [ - "src" - ], - "exclude": [ - "node_modules" - ] -} \ No newline at end of file + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/packages/db/src/schema/submissions.ts b/packages/db/src/schema/submissions.ts index 6a1d59c..11948a7 100644 --- a/packages/db/src/schema/submissions.ts +++ b/packages/db/src/schema/submissions.ts @@ -1,9 +1,21 @@ -import { pgTable, uuid, varchar, text, timestamp, integer } from "drizzle-orm/pg-core"; +import { + integer, + pgTable, + text, + timestamp, + uuid, + varchar, +} from "drizzle-orm/pg-core"; import { createInsertSchema, createSelectSchema } from "drizzle-zod"; import { z } from "zod/v4"; // Submission status enum -export const submissionStatus = ["pending", "processing", "completed", "failed"] as const; +export const submissionStatus = [ + "pending", + "processing", + "completed", + "failed", +] as const; // Main submissions table export const Submission = pgTable("submission", (t) => ({ @@ -18,7 +30,10 @@ export const Submission = pgTable("submission", (t) => ({ // Submission files table - stores uploaded files per domain export const SubmissionFile = pgTable("submission_file", (t) => ({ id: t.uuid().notNull().primaryKey().defaultRandom(), - submissionId: t.uuid().notNull().references(() => Submission.id, { onDelete: "cascade" }), + submissionId: t + .uuid() + .notNull() + .references(() => Submission.id, { onDelete: "cascade" }), domainId: t.varchar({ length: 100 }).notNull(), domainName: t.varchar({ length: 255 }).notNull(), fileName: t.varchar({ length: 255 }).notNull(), @@ -30,7 +45,10 @@ export const SubmissionFile = pgTable("submission_file", (t) => ({ // Evaluation reports table - stores AI service evaluation results export const EvaluationReport = pgTable("evaluation_report", (t) => ({ id: t.uuid().notNull().primaryKey().defaultRandom(), - submissionId: t.uuid().notNull().references(() => Submission.id, { onDelete: "cascade" }), + submissionId: t + .uuid() + .notNull() + .references(() => Submission.id, { onDelete: "cascade" }), aiServiceReportId: t.varchar({ length: 255 }), reportPath: t.text(), reportData: t.text(), // JSON string of evaluation results @@ -41,7 +59,10 @@ export const EvaluationReport = pgTable("evaluation_report", (t) => ({ // Zod schemas for validation export const CreateSubmissionSchema = createInsertSchema(Submission, { - companyName: z.string().min(2, "Company name must be at least 2 characters").max(255), + companyName: z + .string() + .min(2, "Company name must be at least 2 characters") + .max(255), }).omit({ id: true, status: true, @@ -61,7 +82,8 @@ export const CreateSubmissionFileSchema = createInsertSchema(SubmissionFile, { export const SelectSubmissionSchema = createSelectSchema(Submission); export const SelectSubmissionFileSchema = createSelectSchema(SubmissionFile); -export const SelectEvaluationReportSchema = createSelectSchema(EvaluationReport); +export const SelectEvaluationReportSchema = + createSelectSchema(EvaluationReport); // Type exports export type Submission = typeof Submission.$inferSelect; diff --git a/packages/ui/src/theme.tsx b/packages/ui/src/theme.tsx index 9d0b4c4..886ef60 100644 --- a/packages/ui/src/theme.tsx +++ b/packages/ui/src/theme.tsx @@ -134,7 +134,6 @@ export function ThemeProvider({ children }: React.PropsWithChildren) { toggleMode, }} > - {children} ); diff --git a/packages/validators/package.json b/packages/validators/package.json index e36802f..eea0ca8 100644 --- a/packages/validators/package.json +++ b/packages/validators/package.json @@ -29,4 +29,4 @@ "typescript": "catalog:" }, "prettier": "@governance/prettier-config" -} \ No newline at end of file +} diff --git a/packages/validators/src/ndi-domains.ts b/packages/validators/src/ndi-domains.ts index 974eb70..700bf91 100644 --- a/packages/validators/src/ndi-domains.ts +++ b/packages/validators/src/ndi-domains.ts @@ -4,82 +4,82 @@ */ export const NDI_DOMAINS = [ - { - id: "DG", - name: "Data Governance", - order: 1, - }, - { - id: "DCM", - name: "Data Catalog & Metadata", - order: 2, - }, - { - id: "DQ", - name: "Data Quality", - order: 3, - }, - { - id: "DO", - name: "Data Operations", - order: 4, - }, - { - id: "DM", - name: "Document Management", - order: 5, - }, - { - id: "DA", - name: "Data Architecture", - order: 6, - }, - { - id: "DS", - name: "Data Sharing", - order: 7, - }, - { - id: "MD", - name: "Master Data", - order: 8, - }, - { - id: "ABI", - name: "Analytics & BI", - order: 9, - }, - { - id: "DV", - name: "Data Value", - order: 10, - }, - { - id: "OD", - name: "Open Data", - order: 11, - }, - { - id: "FOI", - name: "Freedom of Information", - order: 12, - }, - { - id: "DC", - name: "Data Classification", - order: 13, - }, - { - id: "PDP", - name: "Personal Data Protection", - order: 14, - }, - { - id: "DSec", - name: "Data Security", - order: 15, - }, + { + id: "DG", + name: "Data Governance", + order: 1, + }, + { + id: "DCM", + name: "Data Catalog & Metadata", + order: 2, + }, + { + id: "DQ", + name: "Data Quality", + order: 3, + }, + { + id: "DO", + name: "Data Operations", + order: 4, + }, + { + id: "DM", + name: "Document Management", + order: 5, + }, + { + id: "DA", + name: "Data Architecture", + order: 6, + }, + { + id: "DS", + name: "Data Sharing", + order: 7, + }, + { + id: "MD", + name: "Master Data", + order: 8, + }, + { + id: "ABI", + name: "Analytics & BI", + order: 9, + }, + { + id: "DV", + name: "Data Value", + order: 10, + }, + { + id: "OD", + name: "Open Data", + order: 11, + }, + { + id: "FOI", + name: "Freedom of Information", + order: 12, + }, + { + id: "DC", + name: "Data Classification", + order: 13, + }, + { + id: "PDP", + name: "Personal Data Protection", + order: 14, + }, + { + id: "DSec", + name: "Data Security", + order: 15, + }, ] as const; -export type NDIDomainId = typeof NDI_DOMAINS[number]["id"]; -export type NDIDomain = typeof NDI_DOMAINS[number]; +export type NDIDomainId = (typeof NDI_DOMAINS)[number]["id"]; +export type NDIDomain = (typeof NDI_DOMAINS)[number]; diff --git a/packages/validators/tsconfig.json b/packages/validators/tsconfig.json index 5d2d619..21a6764 100644 --- a/packages/validators/tsconfig.json +++ b/packages/validators/tsconfig.json @@ -8,10 +8,6 @@ "emitDeclarationOnly": false, "noEmit": false }, - "include": [ - "src" - ], - "exclude": [ - "node_modules" - ] -} \ No newline at end of file + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/tooling/tailwind/theme.css b/tooling/tailwind/theme.css index 95af4cb..5003557 100644 --- a/tooling/tailwind/theme.css +++ b/tooling/tailwind/theme.css @@ -158,4 +158,4 @@ --tracking-wide: calc(var(--tracking-normal) + 0.025em); --tracking-wider: calc(var(--tracking-normal) + 0.05em); --tracking-widest: calc(var(--tracking-normal) + 0.1em); -} \ No newline at end of file +} From 5de8b80c4ec774032e6d7fa0ab5912ce45fdbfd5 Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 06:51:16 +0300 Subject: [PATCH 05/21] inst --- .github/.copilot-instructions.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/.copilot-instructions.md b/.github/.copilot-instructions.md index f58ea44..da41686 100644 --- a/.github/.copilot-instructions.md +++ b/.github/.copilot-instructions.md @@ -32,6 +32,7 @@ - Use Tailwind CSS for styling. - Prefer shadcn/ui components where applicable. - Do not create ad-hoc UI components in app folders. +- [tanstack-start](https://tanstack.com/start/llms.txt) is the frontend application framework ## Forms & State From 63465c78a87501ce2484404f44199b15e8bea975 Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 08:45:03 +0300 Subject: [PATCH 06/21] redirect on unauthed submit --- apps/tanstack-start/package.json | 2 +- apps/tanstack-start/src/routes/__root.tsx | 22 ++++++++++++++++++++++ apps/tanstack-start/src/routes/submit.tsx | 10 +++++++++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/apps/tanstack-start/package.json b/apps/tanstack-start/package.json index e26f9de..898e72d 100644 --- a/apps/tanstack-start/package.json +++ b/apps/tanstack-start/package.json @@ -10,7 +10,7 @@ "format": "prettier --check . --ignore-path ../../.gitignore --ignore-path .prettierignore", "lint": "eslint --flag unstable_native_nodejs_ts_config", "typecheck": "tsc --noEmit", - "with-env": "dotenv -e ../../.env --" + "with-env": "dotenv -e ../../.env.local --" }, "dependencies": { "@fontsource-variable/geist": "^5.2.8", diff --git a/apps/tanstack-start/src/routes/__root.tsx b/apps/tanstack-start/src/routes/__root.tsx index 31903a5..f7c68bc 100644 --- a/apps/tanstack-start/src/routes/__root.tsx +++ b/apps/tanstack-start/src/routes/__root.tsx @@ -7,6 +7,8 @@ import { HeadContent, Outlet, Scripts, + ErrorComponent, + Link, } from "@tanstack/react-router"; import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; import { AuthKitProvider } from "@workos/authkit-tanstack-react-start/client"; @@ -18,6 +20,7 @@ import { ThemeToggle, } from "@governance/ui/theme"; import { Toaster } from "@governance/ui/toast"; +import { Button } from "@governance/ui/button"; import appCss from "~/styles.css?url"; import { Header } from "../component/layout/Header"; @@ -32,6 +35,25 @@ export const Route = createRootRouteWithContext<{ }), component: RootComponent, notFoundComponent: NotFound, + errorComponent: ({ error }) => { + return ( + +
+
+
+

Error

+

+ {error.message || "An unexpected error occurred"} +

+
+ +
+
+
+ ); + }, }); function RootComponent() { diff --git a/apps/tanstack-start/src/routes/submit.tsx b/apps/tanstack-start/src/routes/submit.tsx index 066ee94..7a35c0e 100644 --- a/apps/tanstack-start/src/routes/submit.tsx +++ b/apps/tanstack-start/src/routes/submit.tsx @@ -1,7 +1,8 @@ import { useCallback, useState } from "react"; import { useForm } from "@tanstack/react-form"; import { useMutation } from "@tanstack/react-query"; -import { createFileRoute, useNavigate } from "@tanstack/react-router"; +import { createFileRoute, redirect, useNavigate } from "@tanstack/react-router"; +import { getAuth, getSignInUrl } from "@governance/auth"; import { Button } from "@governance/ui/button"; import { @@ -33,6 +34,13 @@ const fileToBase64 = (file: File): Promise => { }; export const Route = createFileRoute("/submit")({ + beforeLoad: async ({ location }) => { + const auth = await getAuth(); + if (!auth.user) { + const signInUrl = await getSignInUrl(); + throw redirect({ href: signInUrl }); + } + }, component: RouteComponent, }); From f9225849e39a462213723121824a6234529e6e18 Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 08:45:09 +0300 Subject: [PATCH 07/21] updated max files --- .../ai-service/src/api/routers/evaluations.py | 50 +++++++++++++++---- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/services/ai-service/src/api/routers/evaluations.py b/services/ai-service/src/api/routers/evaluations.py index 17e14d0..00132bb 100644 --- a/services/ai-service/src/api/routers/evaluations.py +++ b/services/ai-service/src/api/routers/evaluations.py @@ -14,7 +14,7 @@ router = APIRouter(prefix="/api/v1/evaluations", tags=["evaluations"]) -_MAX_FILES = 20 +_MAX_FILES = 50 _MAX_UPLOAD_BYTES = int(os.getenv("MAX_UPLOAD_SIZE_MB", "50")) * 1024 * 1024 _FRAMEWORK_NAME_RE = re.compile(r"^[a-zA-Z0-9_\-]+$") _CONTROL_IDS_RE = re.compile(r"^[a-zA-Z0-9.,\-_\s]*$") @@ -29,13 +29,19 @@ def _sanitize_filename(filename: str) -> str: def _control_ids_form(i: int, default: str = ""): - return Form(default=default, description=f"Comma-separated control IDs for file {i}") + return Form( + default=default, description=f"Comma-separated control IDs for file {i}" + ) @router.post("/submit", response_model=SubmitEvaluationResponse) async def submit_evaluation( - framework_name: str = Form(..., min_length=1, max_length=64, description="Framework identifier (e.g. NDI)"), - files: list[UploadFile] = File(..., description="Files (PDF, DOCX, PPTX, CSV, XLSX); 1 or more"), + framework_name: str = Form( + ..., min_length=1, max_length=64, description="Framework identifier (e.g. NDI)" + ), + files: list[UploadFile] = File( + ..., description="Files (PDF, DOCX, PPTX, CSV, XLSX); 1 or more" + ), control_ids_1: str = _control_ids_form(1), control_ids_2: str = _control_ids_form(2), control_ids_3: str = _control_ids_form(3), @@ -73,25 +79,47 @@ async def submit_evaluation( n_files = len(files) if n_files > _MAX_FILES: - raise HTTPException(status_code=400, detail=f"Maximum {_MAX_FILES} files allowed") + raise HTTPException( + status_code=400, detail=f"Maximum {_MAX_FILES} files allowed" + ) control_ids_fields = [ - control_ids_1, control_ids_2, control_ids_3, control_ids_4, control_ids_5, - control_ids_6, control_ids_7, control_ids_8, control_ids_9, control_ids_10, - control_ids_11, control_ids_12, control_ids_13, control_ids_14, control_ids_15, - control_ids_16, control_ids_17, control_ids_18, control_ids_19, control_ids_20, + control_ids_1, + control_ids_2, + control_ids_3, + control_ids_4, + control_ids_5, + control_ids_6, + control_ids_7, + control_ids_8, + control_ids_9, + control_ids_10, + control_ids_11, + control_ids_12, + control_ids_13, + control_ids_14, + control_ids_15, + control_ids_16, + control_ids_17, + control_ids_18, + control_ids_19, + control_ids_20, ] control_ids_per_file = [] for s in control_ids_fields[:n_files]: ids = s.strip() if ids and not _CONTROL_IDS_RE.match(ids): - raise HTTPException(status_code=400, detail=f"Invalid control ID format: {ids[:100]}") + raise HTTPException( + status_code=400, detail=f"Invalid control ID format: {ids[:100]}" + ) control_ids_per_file.append(ids) file_tuples: list[tuple[str, bytes]] = [] for u in files: if not u.filename: - raise HTTPException(status_code=400, detail="Each file must have a filename") + raise HTTPException( + status_code=400, detail="Each file must have a filename" + ) body = await u.read() if not body: raise HTTPException(status_code=400, detail=f"File '{u.filename}' is empty") From 22106e763695ff455c46e5a0b1200e0c455a4b0a Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 09:26:47 +0300 Subject: [PATCH 08/21] permessions --- docs/RBAC_SETUP.md | 0 packages/api/package.json | 1 + packages/api/src/index.ts | 7 +++- packages/api/src/lib/workos.ts | 21 ++++++++++ packages/api/src/router/submission.ts | 56 ++++++++++++++++++++++----- packages/api/src/trpc.ts | 51 ++++++++++++++++++++++++ pnpm-lock.yaml | 14 ++++++- 7 files changed, 138 insertions(+), 12 deletions(-) create mode 100644 docs/RBAC_SETUP.md create mode 100644 packages/api/src/lib/workos.ts diff --git a/docs/RBAC_SETUP.md b/docs/RBAC_SETUP.md new file mode 100644 index 0000000..e69de29 diff --git a/packages/api/package.json b/packages/api/package.json index 0e522b8..d169caf 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -23,6 +23,7 @@ "@governance/validators": "workspace:*", "@hey-api/client-fetch": "^0.13.1", "@trpc/server": "catalog:", + "@workos-inc/node": "^8.1.0", "drizzle-orm": "^0.44.7", "superjson": "2.2.3", "zod": "catalog:" diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index 090ff68..7921ca1 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -18,6 +18,11 @@ type RouterInputs = inferRouterInputs; */ type RouterOutputs = inferRouterOutputs; +export type { RouterInputs, RouterOutputs }; + export { type AppRouter, appRouter } from "./root"; export { createTRPCContext } from "./trpc"; -export type { RouterInputs, RouterOutputs }; + +// Export WorkOS utilities and permissions +export { workos, SUBMISSION_PERMISSIONS } from "./lib/workos"; +export type { SubmissionPermission } from "./lib/workos"; diff --git a/packages/api/src/lib/workos.ts b/packages/api/src/lib/workos.ts new file mode 100644 index 0000000..09e1e69 --- /dev/null +++ b/packages/api/src/lib/workos.ts @@ -0,0 +1,21 @@ +import { WorkOS } from "@workos-inc/node"; + +const workosApiKey = process.env.WORKOS_API_KEY; + +if (!workosApiKey) { + throw new Error("WORKOS_API_KEY is not set"); +} + +export const workos = new WorkOS(workosApiKey); + +/** + * Submission permissions for RBAC + */ +export const SUBMISSION_PERMISSIONS = { + READ: "submissions:read", + WRITE: "submissions:write", + DELETE: "submissions:delete", +} as const; + +export type SubmissionPermission = + (typeof SUBMISSION_PERMISSIONS)[keyof typeof SUBMISSION_PERMISSIONS]; diff --git a/packages/api/src/router/submission.ts b/packages/api/src/router/submission.ts index cb60d3f..da43bc2 100644 --- a/packages/api/src/router/submission.ts +++ b/packages/api/src/router/submission.ts @@ -7,10 +7,11 @@ import * as schema from "@governance/db/schema"; import { submitEvaluationApiV1EvaluationsSubmitPost } from "../ai-client/sdk.gen"; import { getAIClient } from "../lib/ai"; -import { protectedProcedure } from "../trpc"; +import { SUBMISSION_PERMISSIONS } from "../lib/workos"; +import { createPermissionProcedure } from "../trpc"; export const submissionRouter = { - create: protectedProcedure + create: createPermissionProcedure([SUBMISSION_PERMISSIONS.WRITE]) .input( z.object({ companyName: z.string().min(1), @@ -78,7 +79,6 @@ export const submissionRouter = { }); if (response.error) { - // @ts-ignore throw new Error(JSON.stringify(response.error)); } @@ -120,14 +120,16 @@ export const submissionRouter = { } }), - getAll: protectedProcedure.query(async ({ ctx }) => { - return ctx.db - .select() - .from(schema.Submission) - .orderBy(desc(schema.Submission.createdAt)); - }), + getAll: createPermissionProcedure([SUBMISSION_PERMISSIONS.READ]).query( + async ({ ctx }) => { + return ctx.db + .select() + .from(schema.Submission) + .orderBy(desc(schema.Submission.createdAt)); + }, + ), - getById: protectedProcedure + getById: createPermissionProcedure([SUBMISSION_PERMISSIONS.READ]) .input(z.object({ id: z.string().uuid() })) .query(async ({ ctx, input }) => { const [submission] = await ctx.db @@ -156,4 +158,38 @@ export const submissionRouter = { return { submission, files, report: report ?? null }; }), + + delete: createPermissionProcedure([SUBMISSION_PERMISSIONS.DELETE]) + .input(z.object({ id: z.string().uuid() })) + .mutation(async ({ ctx, input }) => { + // Check if submission exists and belongs to the user + const [submission] = await ctx.db + .select() + .from(schema.Submission) + .where(eq(schema.Submission.id, input.id)) + .limit(1); + + if (!submission) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Submission not found", + }); + } + + // Delete related records first (cascade delete) + await ctx.db + .delete(schema.EvaluationReport) + .where(eq(schema.EvaluationReport.submissionId, input.id)); + + await ctx.db + .delete(schema.SubmissionFile) + .where(eq(schema.SubmissionFile.submissionId, input.id)); + + // Delete the submission + await ctx.db + .delete(schema.Submission) + .where(eq(schema.Submission.id, input.id)); + + return { success: true }; + }), } satisfies TRPCRouterRecord; diff --git a/packages/api/src/trpc.ts b/packages/api/src/trpc.ts index 60f8457..ff89a2a 100644 --- a/packages/api/src/trpc.ts +++ b/packages/api/src/trpc.ts @@ -26,13 +26,30 @@ import { db } from "@governance/db/client"; * @see https://trpc.io/docs/server/context */ +/** + * Extract permissions from the user session + * Permissions come from the access token JWT in the session + */ +function getPermissionsFromSession(session: UserInfo | NoUserInfo): string[] { + if (!session.user) { + return []; + } + + // WorkOS includes permissions in the access token + // They are available in the session.permissions field or decoded from the JWT + return session.permissions ?? []; +} + export const createTRPCContext = async (opts: { headers: Headers; auth: UserInfo | NoUserInfo; }) => { const session = opts.auth; + const permissions = getPermissionsFromSession(session); + return { session, + permissions, db, }; }; @@ -119,6 +136,40 @@ export const protectedProcedure = t.procedure ctx: { // infers the `session` as non-nullable session: ctx.session as UserInfo, + permissions: ctx.permissions, }, }); }); + +/** + * Permission-based procedure + * + * Use this to create procedures that require specific permissions. + * The permission check is based on the user's role permissions from WorkOS. + * + * @example + * ```ts + * const myProcedure = createPermissionProcedure(["submissions:read"]) + * .query(async ({ ctx }) => { + * // User has submissions:read permission + * }); + * ``` + */ +export const createPermissionProcedure = (requiredPermissions: string[]) => { + return protectedProcedure.use(({ ctx, next }) => { + const hasPermission = requiredPermissions.every((permission) => + ctx.permissions.includes(permission), + ); + + if (!hasPermission) { + throw new TRPCError({ + code: "FORBIDDEN", + message: `Missing required permissions: ${requiredPermissions.join(", ")}`, + }); + } + + return next({ + ctx, + }); + }); +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1f36c1f..4260258 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -225,6 +225,9 @@ importers: '@trpc/server': specifier: 'catalog:' version: 11.7.1(typescript@5.9.3) + '@workos-inc/node': + specifier: ^8.1.0 + version: 8.1.0 drizzle-orm: specifier: ^0.44.7 version: 0.44.7(@neondatabase/serverless@0.10.0)(@opentelemetry/api@1.9.0)(@planetscale/database@1.19.0)(@prisma/client@5.22.0(prisma@5.22.0))(@types/better-sqlite3@7.6.13)(@types/pg@8.11.10)(@vercel/postgres@0.10.0(utf-8-validate@6.0.4))(better-sqlite3@12.2.0)(gel@2.0.0)(kysely@0.28.5)(mysql2@3.11.3)(postgres@3.4.8)(prisma@5.22.0) @@ -2806,6 +2809,10 @@ packages: resolution: {integrity: sha512-D8VDfx0GXeiVm8vccAl0rElW7taebRnrteKPJzZwehwzI9W/Usa4qKfmwxj+7Lh1Z1deEocDRCpZpV7ml4GpWQ==} engines: {node: '>=20.15.0'} + '@workos-inc/node@8.1.0': + resolution: {integrity: sha512-Ep2QSP43y4ZdJIOuL4Hjaq5f0u8Z0qZe7QWzrrBV6cHc/kcicDBcB0AanMP6eB9x3x6FaHfevLbkbjPF4+TCYQ==} + engines: {node: '>=20.15.0'} + '@workos/authkit-session@0.3.4': resolution: {integrity: sha512-lbLP1y8MHWL1Op9athZ3SrzKLcL0+xBVpADCMQLI39mPgSQj+/lopVdOx0Cku96hYnJBOJTLVTK3Zox4FbZl4A==} engines: {node: '>=20.0.0'} @@ -3860,7 +3867,7 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + deprecated: Glob versions prior to v9 are no longer supported globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} @@ -8228,6 +8235,11 @@ snapshots: iron-webcrypto: 2.0.0 jose: 6.1.3 + '@workos-inc/node@8.1.0': + dependencies: + iron-webcrypto: 2.0.0 + jose: 6.1.3 + '@workos/authkit-session@0.3.4': dependencies: '@workos-inc/node': 8.0.0 From 39f6a5dc8f8b316ed876846dea79381212949bfb Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 09:36:46 +0300 Subject: [PATCH 09/21] frontend permissions --- .../src/component/layout/Header.tsx | 19 +- apps/tanstack-start/src/lib/permissions.ts | 48 +++++ .../src/routes/admin/company.$companyId.tsx | 20 +- .../tanstack-start/src/routes/admin/index.tsx | 20 +- apps/tanstack-start/src/routes/admin/ndi.tsx | 20 +- apps/tanstack-start/src/routes/index.tsx | 40 +++- apps/tanstack-start/src/routes/submit.tsx | 11 + docs/RBAC_SETUP.md | 199 ++++++++++++++++++ 8 files changed, 366 insertions(+), 11 deletions(-) create mode 100644 apps/tanstack-start/src/lib/permissions.ts diff --git a/apps/tanstack-start/src/component/layout/Header.tsx b/apps/tanstack-start/src/component/layout/Header.tsx index b86ec24..963c2cf 100644 --- a/apps/tanstack-start/src/component/layout/Header.tsx +++ b/apps/tanstack-start/src/component/layout/Header.tsx @@ -5,8 +5,11 @@ import { createServerFn } from "@tanstack/react-start"; import { getSignInUrl } from "@workos/authkit-tanstack-react-start"; import { useAuth } from "@workos/authkit-tanstack-react-start/client"; +import { hasPermission, SUBMISSION_PERMISSIONS } from "~/lib/permissions"; + export function Header() { - const { user, signOut } = useAuth(); + const { user, permissions, signOut } = useAuth(); + const canViewAdmin = hasPermission(permissions, SUBMISSION_PERMISSIONS.READ); return (
@@ -23,12 +26,14 @@ export function Header() { {user.email} - - Admin Dashboard - + {canViewAdmin && ( + + Admin Dashboard + + )} + )}
diff --git a/packages/api/src/router/submission.ts b/packages/api/src/router/submission.ts index da43bc2..af058b9 100644 --- a/packages/api/src/router/submission.ts +++ b/packages/api/src/router/submission.ts @@ -55,6 +55,8 @@ export const submissionRouter = { domainName: f.domainName, fileName: f.name, filePath: "ai-service-upload", // Placeholder + fileContent: f.content, // Store base64 content for rerun capability + fileType: f.type, // Store MIME type fileSize: f.size, })); @@ -192,4 +194,118 @@ export const submissionRouter = { return { success: true }; }), + + rerunEvaluation: createPermissionProcedure([SUBMISSION_PERMISSIONS.WRITE]) + .input(z.object({ id: z.string().uuid() })) + .mutation(async ({ ctx, input }) => { + const client = getAIClient(); + + // 1. Get submission + const [submission] = await ctx.db + .select() + .from(schema.Submission) + .where(eq(schema.Submission.id, input.id)) + .limit(1); + + if (!submission) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Submission not found", + }); + } + + // 2. Get existing files with content + const files = await ctx.db + .select() + .from(schema.SubmissionFile) + .where(eq(schema.SubmissionFile.submissionId, input.id)); + + if (files.length === 0) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "No files found for this submission", + }); + } + + // Check if files have content stored + const filesWithoutContent = files.filter((f) => !f.fileContent); + if (filesWithoutContent.length > 0) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: + "Some files do not have content stored. This submission was created before the rerun feature was implemented. Please create a new submission.", + }); + } + + // Update submission status to processing + await ctx.db + .update(schema.Submission) + .set({ status: "processing", updatedAt: new Date() }) + .where(eq(schema.Submission.id, submission.id)); + + // 3. Delete old evaluation report if exists + await ctx.db + .delete(schema.EvaluationReport) + .where(eq(schema.EvaluationReport.submissionId, input.id)); + + // 4. Prepare files for AI Service + const blobs = files.map((f) => { + const buffer = Buffer.from(f.fileContent!, "base64"); + return new File([buffer], f.fileName, { + type: f.fileType ?? "application/octet-stream", + }); + }); + + // 5. Call AI Service + try { + const response = await submitEvaluationApiV1EvaluationsSubmitPost({ + client, + body: { + framework_name: "NDI", + files: blobs, + }, + }); + + if (response.error) { + throw new Error(JSON.stringify(response.error)); + } + + const data = response.data; + if (!data) throw new Error("No data returned from AI service"); + + // 6. Create new Evaluation Report + await ctx.db.insert(schema.EvaluationReport).values({ + submissionId: submission.id, + aiServiceReportId: data.evaluation_id, + reportPath: data.report_path, + reportData: JSON.stringify({ + evaluation_id: data.evaluation_id, + mimic_json: data.mimic_json, + file_evaluations: data.file_evaluations, + }), + status: "completed", + completedAt: new Date(), + }); + + // Update submission status to completed + await ctx.db + .update(schema.Submission) + .set({ status: "completed", updatedAt: new Date() }) + .where(eq(schema.Submission.id, submission.id)); + + return { success: true }; + } catch (e) { + console.error("AI Service Rerun Failed", e); + await ctx.db + .update(schema.Submission) + .set({ status: "failed", updatedAt: new Date() }) + .where(eq(schema.Submission.id, submission.id)); + + throw new TRPCError({ + code: "INTERNAL_SERVER_ERROR", + message: + "Failed to rerun evaluation. The AI service may be unavailable.", + }); + } + }), } satisfies TRPCRouterRecord; diff --git a/packages/db/src/schema/submissions.ts b/packages/db/src/schema/submissions.ts index 11948a7..a70c0a2 100644 --- a/packages/db/src/schema/submissions.ts +++ b/packages/db/src/schema/submissions.ts @@ -38,6 +38,8 @@ export const SubmissionFile = pgTable("submission_file", (t) => ({ domainName: t.varchar({ length: 255 }).notNull(), fileName: t.varchar({ length: 255 }).notNull(), filePath: t.text().notNull(), + fileContent: t.text(), // Base64 encoded file content for rerun capability + fileType: t.varchar({ length: 100 }), // MIME type of the file fileSize: t.integer().notNull(), uploadedAt: t.timestamp().defaultNow().notNull(), })); From 897c28bfce137ffcbaef4afdb7339590226ae13a Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 10:33:45 +0300 Subject: [PATCH 13/21] reducing docker image size --- .dockerignore | 9 ++++++++ ai.dockerfile | 37 +++++++++++++++++++++++++++++- services/ai-service/pyproject.toml | 12 +++++++--- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/.dockerignore b/.dockerignore index d43f823..c39c107 100644 --- a/.dockerignore +++ b/.dockerignore @@ -56,6 +56,15 @@ build/ *.egg-info/ dist/ .pytest_cache/ +*.ipynb +.ipynb_checkpoints/ +*.coverage +htmlcov/ + +# AI service specific +services/ai-service/data/evaluations/ +services/ai-service/data/reports/ +services/ai-service/test.ipynb # Temporary files *.tmp diff --git a/ai.dockerfile b/ai.dockerfile index 9f59ff8..ab03547 100644 --- a/ai.dockerfile +++ b/ai.dockerfile @@ -1,18 +1,53 @@ -FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim +# Build stage +FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS builder WORKDIR /app ENV UV_COMPILE_BYTECODE=1 ENV PYTHONPATH=/app/src +ENV UV_INDEX_STRATEGY=unsafe-best-match COPY services/ai-service/pyproject.toml ./ +# Install CPU-only PyTorch to reduce image size dramatically +RUN uv pip install --system --no-cache \ + torch==2.5.1+cpu \ + --index-url https://download.pytorch.org/whl/cpu + +# Install other dependencies RUN uv sync --no-install-project --no-dev COPY services/ai-service/ ./ RUN uv sync --no-dev +# Remove unnecessary files +RUN find /app/.venv -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true +RUN find /app/.venv -type f -name "*.pyc" -delete +RUN find /app/.venv -type f -name "*.pyo" -delete +RUN find /app/.venv -name "tests" -type d -exec rm -rf {} + 2>/dev/null || true +RUN find /app/.venv -name "test" -type d -exec rm -rf {} + 2>/dev/null || true + +# Runtime stage +FROM python:3.13-slim-bookworm + +WORKDIR /app + +ENV PYTHONPATH=/app/src +ENV PYTHONUNBUFFERED=1 +ENV PYTHONDONTWRITEBYTECODE=1 + +# Install runtime dependencies only +RUN apt-get update && apt-get install -y --no-install-recommends \ + libgomp1 \ + && rm -rf /var/lib/apt/lists/* + +# Copy only the virtual environment and application code +COPY --from=builder /app/.venv /app/.venv +COPY --from=builder /app/src /app/src +COPY --from=builder /app/run.py /app/run.py +COPY --from=builder /app/main.py /app/main.py + # Create non-root user RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app USER appuser diff --git a/services/ai-service/pyproject.toml b/services/ai-service/pyproject.toml index ea7689e..036fbd3 100644 --- a/services/ai-service/pyproject.toml +++ b/services/ai-service/pyproject.toml @@ -9,12 +9,12 @@ dependencies = [ "pdfplumber>=0.10.0", "python-dotenv>=1.0.0", "pydantic>=2.0.0", - "pypdf>=3.0.0", - "ipykernel>=7.1.0", + # Removed pypdf (redundant with pdfplumber) + # Removed ipykernel (only needed for dev/notebooks) "qdrant-client>=1.8.0", "haystack-ai>=2.0.0", "transformers>=4.35.0", - "torch>=2.0.0", + # torch installed separately as CPU-only in Dockerfile "sentence-transformers>=2.2.0", "accelerate>=0.24.0", "python-multipart>=0.0.9", @@ -32,4 +32,10 @@ dependencies = [ "uvicorn>=0.40.0", ] +[tool.uv] +# Exclude torch from uv sync since we install CPU version manually +override-dependencies = [ + "torch==2.5.1", +] + From 42a775abe1f736e2b98f7082dda0b2b4a9491a5b Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 10:59:08 +0300 Subject: [PATCH 14/21] lower size --- ai.dockerfile | 5 +++++ services/ai-service/pyproject.toml | 11 ++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/ai.dockerfile b/ai.dockerfile index ab03547..2a405bb 100644 --- a/ai.dockerfile +++ b/ai.dockerfile @@ -14,6 +14,11 @@ RUN uv pip install --system --no-cache \ torch==2.5.1+cpu \ --index-url https://download.pytorch.org/whl/cpu +RUN uv pip install --system --no-cache transformers tqdm numpy scikit-learn scipy nltk sentencepiece + +RUN uv pip install --system --no-cache --no-deps sentence-transformers + + # Install other dependencies RUN uv sync --no-install-project --no-dev diff --git a/services/ai-service/pyproject.toml b/services/ai-service/pyproject.toml index 036fbd3..155dd72 100644 --- a/services/ai-service/pyproject.toml +++ b/services/ai-service/pyproject.toml @@ -9,13 +9,9 @@ dependencies = [ "pdfplumber>=0.10.0", "python-dotenv>=1.0.0", "pydantic>=2.0.0", - # Removed pypdf (redundant with pdfplumber) - # Removed ipykernel (only needed for dev/notebooks) "qdrant-client>=1.8.0", "haystack-ai>=2.0.0", "transformers>=4.35.0", - # torch installed separately as CPU-only in Dockerfile - "sentence-transformers>=2.2.0", "accelerate>=0.24.0", "python-multipart>=0.0.9", "aiofiles>=24.0.0", @@ -32,10 +28,11 @@ dependencies = [ "uvicorn>=0.40.0", ] -[tool.uv] -# Exclude torch from uv sync since we install CPU version manually -override-dependencies = [ + +[dependency-groups] +dev = [ "torch==2.5.1", + "sentence-transformers>=2.2.0", ] From d243545d6934a0ddf1406b949d81deab256ef9dd Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:04:50 +0300 Subject: [PATCH 15/21] widgets --- apps/tanstack-start/package.json | 3 + pnpm-lock.yaml | 946 ++++++++++++++++++++++++++++++- pnpm-workspace.yaml | 34 +- 3 files changed, 955 insertions(+), 28 deletions(-) diff --git a/apps/tanstack-start/package.json b/apps/tanstack-start/package.json index 898e72d..df5e667 100644 --- a/apps/tanstack-start/package.json +++ b/apps/tanstack-start/package.json @@ -19,6 +19,7 @@ "@governance/auth": "workspace:*", "@governance/db": "workspace:*", "@governance/ui": "workspace:*", + "@radix-ui/themes": "^3.3.0", "@t3-oss/env-core": "^0.13.8", "@tanstack/react-form": "catalog:", "@tanstack/react-query": "catalog:", @@ -29,6 +30,8 @@ "@trpc/client": "catalog:", "@trpc/server": "catalog:", "@trpc/tanstack-react-query": "catalog:", + "@workos-inc/widgets": "^1.8.0", + "@workos-inc/widgets-i18n": "^0.1.0", "@workos/authkit-tanstack-react-start": "^0.5.0", "nitro": "3.0.1-alpha.1", "react": "catalog:react19", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4260258..14a2dce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,7 +19,7 @@ catalogs: specifier: ^1.23.8 version: 1.23.8 '@tanstack/react-query': - specifier: ^5.90.8 + specifier: 5.90.8 version: 5.90.8 '@trpc/client': specifier: ^11.7.1 @@ -113,6 +113,9 @@ importers: '@governance/ui': specifier: workspace:* version: link:../../packages/ui + '@radix-ui/themes': + specifier: ^3.3.0 + version: 3.3.0(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) '@t3-oss/env-core': specifier: ^0.13.8 version: 0.13.8(arktype@2.1.20)(typescript@5.9.3)(valibot@1.0.0-beta.15(typescript@5.9.3))(zod@4.1.12) @@ -143,6 +146,12 @@ importers: '@trpc/tanstack-react-query': specifier: 'catalog:' version: 11.7.1(@tanstack/react-query@5.90.8(react@19.1.4))(@trpc/client@11.7.1(@trpc/server@11.7.1(typescript@5.9.3))(typescript@5.9.3))(@trpc/server@11.7.1(typescript@5.9.3))(react-dom@19.1.4(react@19.1.4))(react@19.1.4)(typescript@5.9.3) + '@workos-inc/widgets': + specifier: ^1.8.0 + version: 1.8.0(@radix-ui/themes@3.3.0(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4))(@tanstack/react-query@5.90.8(react@19.1.4))(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@workos-inc/widgets-i18n': + specifier: ^0.1.0 + version: 0.1.0(@workos-inc/widgets@1.8.0(@radix-ui/themes@3.3.0(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4))(@tanstack/react-query@5.90.8(react@19.1.4))(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4))(react@19.1.4)(typescript@5.9.3) '@workos/authkit-tanstack-react-start': specifier: ^0.5.0 version: 0.5.0(@tanstack/react-router@1.135.2(react-dom@19.1.4(react@19.1.4))(react@19.1.4))(@tanstack/react-start@1.135.2(crossws@0.4.1(srvx@0.9.6))(react-dom@19.1.4(react@19.1.4))(react@19.1.4)(vite@7.1.12(@types/node@22.18.12)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(react-dom@19.1.4(react@19.1.4))(react@19.1.4) @@ -1055,6 +1064,29 @@ packages: '@fontsource-variable/geist@5.2.8': resolution: {integrity: sha512-cJ6m9e+8MQ5dCYJsLylfZrgBh6KkG4bOLckB35Tr9J/EqdkEM6QllH5PxqP1dhTvFup+HtMRPuz9xOjxXJggxw==} + '@formatjs/ecma402-abstract@2.3.6': + resolution: {integrity: sha512-HJnTFeRM2kVFVr5gr5kH1XP6K0JcJtE7Lzvtr3FS/so5f1kpsqqqxy5JF+FRaO6H2qmcMfAUIox7AJteieRtVw==} + + '@formatjs/fast-memoize@2.2.7': + resolution: {integrity: sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ==} + + '@formatjs/icu-messageformat-parser@2.11.4': + resolution: {integrity: sha512-7kR78cRrPNB4fjGFZg3Rmj5aah8rQj9KPzuLsmcSn4ipLXQvC04keycTI1F7kJYDwIXtT2+7IDEto842CfZBtw==} + + '@formatjs/icu-skeleton-parser@1.8.16': + resolution: {integrity: sha512-H13E9Xl+PxBd8D5/6TVUluSpxGNvFSlN/b3coUp0e0JpuWXXnQDiavIpY3NnvSp4xhEMoXyyBvVfdFX8jglOHQ==} + + '@formatjs/intl-localematcher@0.6.2': + resolution: {integrity: sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA==} + + '@formatjs/intl@3.1.8': + resolution: {integrity: sha512-LWXgwI5zTMatvR8w8kCNh/priDTOF/ZssokMBHJ7ZWXFoYLVOYo0EJERD9Eajv+xsfQO1QkuAt77KWQ1OI4mOQ==} + peerDependencies: + typescript: ^5.6.0 + peerDependenciesMeta: + typescript: + optional: true + '@hey-api/client-fetch@0.13.1': resolution: {integrity: sha512-29jBRYNdxVGlx5oewFgOrkulZckpIpBIRHth3uHFn1PrL2ucMy52FvWOY3U3dVx2go1Z3kUmMi6lr07iOpUqqA==} deprecated: Starting with v0.73.0, this package is bundled directly inside @hey-api/openapi-ts. @@ -1509,6 +1541,9 @@ packages: '@prisma/get-platform@5.22.0': resolution: {integrity: sha512-pHhpQdr1UPFpt+zFfnPazhulaZYCUqeIcPpJViYoq9R+D/yw4fjE+CtnsnKzPYm0ddUbeXUzjGVGIRVgPDCk4Q==} + '@radix-ui/colors@3.0.0': + resolution: {integrity: sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==} + '@radix-ui/number@1.1.1': resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} @@ -2204,6 +2239,19 @@ packages: '@radix-ui/rect@1.1.1': resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@radix-ui/themes@3.3.0': + resolution: {integrity: sha512-I0/h2CRNTpYNB7Mi3xFIvSsQq5a108d7kK8dTO5zp5b9HR5QJXKag6B8tjpz2ITkVYkFdkGk45doNkSr7OxwNw==} + 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 + '@rolldown/pluginutils@1.0.0-beta.40': resolution: {integrity: sha512-s3GeJKSQOwBlzdUrj4ISjJj5SfSh+aqn0wjOar4Bx95iV1ETI7F6S/5hLcfAxZ9kXDcyrAkxPlqmd1ZITttf+w==} @@ -2682,6 +2730,11 @@ packages: '@types/glob@7.2.0': resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} + '@types/hoist-non-react-statics@3.3.7': + resolution: {integrity: sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==} + peerDependencies: + '@types/react': '*' + '@types/inquirer@6.5.0': resolution: {integrity: sha512-rjaYQ9b9y/VFGOpqBEXRavc3jh0a+e6evAbI31tMda8VlPaSy0AZJfXsvmIe3wklc7W6C3zCSfleuMXR7NOyXw==} @@ -2813,6 +2866,20 @@ packages: resolution: {integrity: sha512-Ep2QSP43y4ZdJIOuL4Hjaq5f0u8Z0qZe7QWzrrBV6cHc/kcicDBcB0AanMP6eB9x3x6FaHfevLbkbjPF4+TCYQ==} engines: {node: '>=20.15.0'} + '@workos-inc/widgets-i18n@0.1.0': + resolution: {integrity: sha512-AFDuNTxg/0QwcG/z0kBZkiXXzqgDY7/60s7jVfbNn3f3G4k4HZUKrYcXe/CBNru54StaQsw+8SueHPSd/VAK0A==} + peerDependencies: + '@workos-inc/widgets': ^1.8.0 + react: '>=18' + + '@workos-inc/widgets@1.8.0': + resolution: {integrity: sha512-UyDzWIaty5XH+Gh1bGoyBn0mzO4vLu6WM2XFTFojHFdyyxkvuUt8LkXPxarG3VmBHSkNffr4bKbEyDJ0LAh7MA==} + peerDependencies: + '@radix-ui/themes': ^3.1.0 + '@tanstack/react-query': ^5.0.0 + react: '>=18' + react-dom: '>=18' + '@workos/authkit-session@0.3.4': resolution: {integrity: sha512-lbLP1y8MHWL1Op9athZ3SrzKLcL0+xBVpADCMQLI39mPgSQj+/lopVdOx0Cku96hYnJBOJTLVTK3Zox4FbZl4A==} engines: {node: '>=20.0.0'} @@ -3000,6 +3067,9 @@ packages: boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + bowser@2.12.1: + resolution: {integrity: sha512-z4rE2Gxh7tvshQ4hluIT7XcFrgLIQaw9X3A+kTTRdovCz5PMukm/0QC/BKSYPj3omF5Qfypn9O/c5kgpmvYUCw==} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -3111,6 +3181,9 @@ packages: class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + classnames@2.5.1: + resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + clean-stack@2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} @@ -3276,6 +3349,9 @@ packages: supports-color: optional: true + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + decode-formdata@0.9.0: resolution: {integrity: sha512-q5uwOjR3Um5YD+ZWPOF/1sGHVW9A5rCrRwITQChRXlmPkxDFBqCm4jNTIVdGHNH9OnR+V9MoZVgRhsFb+ARbUw==} @@ -3966,6 +4042,9 @@ packages: hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + htmlparser2@10.0.0: resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} @@ -4038,6 +4117,9 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + intl-messageformat@10.7.18: + resolution: {integrity: sha512-m3Ofv/X/tV8Y3tHXLohcuVuhWKo7BBq62cqY15etqmLxg2DZ34AGGgQDeR+SCta2+zICb1NX83af0GJmbQ1++g==} + ip-address@10.0.1: resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} engines: {node: '>= 12'} @@ -4891,6 +4973,15 @@ packages: peerDependencies: react: ^19.2.3 + react-intl@7.1.14: + resolution: {integrity: sha512-VE/0Wi/lHJlBC7APQpCzLUdIt3GB5B0GZrRW8Q+ACbkHI4j+Wwgg9J1TniN6zmLHmPH5gxXcMy+fkSPfw5p1WQ==} + peerDependencies: + react: 16 || 17 || 18 || 19 + typescript: ^5.6.0 + peerDependenciesMeta: + typescript: + optional: true + react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -5570,6 +5661,12 @@ packages: '@types/react': optional: true + use-debounce@10.1.0: + resolution: {integrity: sha512-lu87Za35V3n/MyMoEpD5zJv0k7hCn0p+V/fK2kWD+3k2u3kOCwO593UArbczg1fhfs2rqPEnHpULJ3KmGdDzvg==} + engines: {node: '>= 16.0.0'} + peerDependencies: + react: '*' + use-sidecar@1.1.3: resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} engines: {node: '>=10'} @@ -6221,6 +6318,12 @@ snapshots: '@floating-ui/core': 1.7.3 '@floating-ui/utils': 0.2.10 + '@floating-ui/react-dom@2.1.6(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@floating-ui/dom': 1.7.4 + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + '@floating-ui/react-dom@2.1.6(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@floating-ui/dom': 1.7.4 @@ -6233,6 +6336,42 @@ snapshots: '@fontsource-variable/geist@5.2.8': {} + '@formatjs/ecma402-abstract@2.3.6': + dependencies: + '@formatjs/fast-memoize': 2.2.7 + '@formatjs/intl-localematcher': 0.6.2 + decimal.js: 10.6.0 + tslib: 2.8.1 + + '@formatjs/fast-memoize@2.2.7': + dependencies: + tslib: 2.8.1 + + '@formatjs/icu-messageformat-parser@2.11.4': + dependencies: + '@formatjs/ecma402-abstract': 2.3.6 + '@formatjs/icu-skeleton-parser': 1.8.16 + tslib: 2.8.1 + + '@formatjs/icu-skeleton-parser@1.8.16': + dependencies: + '@formatjs/ecma402-abstract': 2.3.6 + tslib: 2.8.1 + + '@formatjs/intl-localematcher@0.6.2': + dependencies: + tslib: 2.8.1 + + '@formatjs/intl@3.1.8(typescript@5.9.3)': + dependencies: + '@formatjs/ecma402-abstract': 2.3.6 + '@formatjs/fast-memoize': 2.2.7 + '@formatjs/icu-messageformat-parser': 2.11.4 + intl-messageformat: 10.7.18 + tslib: 2.8.1 + optionalDependencies: + typescript: 5.9.3 + '@hey-api/client-fetch@0.13.1(@hey-api/openapi-ts@0.91.1(typescript@5.9.3))': dependencies: '@hey-api/openapi-ts': 0.91.1(typescript@5.9.3) @@ -6596,10 +6735,21 @@ snapshots: '@prisma/debug': 5.22.0 optional: true + '@radix-ui/colors@3.0.0': {} + '@radix-ui/number@1.1.1': {} '@radix-ui/primitive@1.1.3': {} + '@radix-ui/react-accessible-icon@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-accessible-icon@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) @@ -6609,6 +6759,23 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6626,6 +6793,20 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6640,6 +6821,15 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) @@ -6649,6 +6839,15 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-aspect-ratio@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-aspect-ratio@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) @@ -6658,6 +6857,19 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-avatar@1.1.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-avatar@1.1.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) @@ -6671,6 +6883,22 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6687,6 +6915,22 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6703,6 +6947,18 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) @@ -6721,6 +6977,20 @@ snapshots: optionalDependencies: '@types/react': 19.1.12 + '@radix-ui/react-context-menu@2.2.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-context-menu@2.2.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6741,6 +7011,28 @@ snapshots: optionalDependencies: '@types/react': 19.1.12 + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + aria-hidden: 1.2.6 + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + react-remove-scroll: 2.7.1(@types/react@19.1.12)(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6769,6 +7061,19 @@ snapshots: optionalDependencies: '@types/react': 19.1.12 + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6782,6 +7087,21 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6803,6 +7123,17 @@ snapshots: optionalDependencies: '@types/react': 19.1.12 + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) @@ -6814,6 +7145,20 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-form@0.1.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-label': 2.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-form@0.1.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6828,6 +7173,23 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-hover-card@1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-hover-card@1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6856,6 +7218,15 @@ snapshots: optionalDependencies: '@types/react': 19.1.12 + '@radix-ui/react-label@2.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-label@2.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) @@ -6865,32 +7236,76 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) - '@radix-ui/react-menu@2.1.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.12)(react@19.1.4) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) '@radix-ui/react-slot': 1.2.3(@types/react@19.1.12)(react@19.1.4) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.4) aria-hidden: 1.2.6 react: 19.1.4 - react-dom: 19.2.3(react@19.1.4) + react-dom: 19.1.4(react@19.1.4) react-remove-scroll: 2.7.1(@types/react@19.1.12)(react@19.1.4) optionalDependencies: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.4) + aria-hidden: 1.2.6 + react: 19.1.4 + react-dom: 19.2.3(react@19.1.4) + react-remove-scroll: 2.7.1(@types/react@19.1.12)(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + + '@radix-ui/react-menubar@1.1.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-menubar@1.1.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6909,6 +7324,28 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6931,6 +7368,26 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-one-time-password-field@0.1.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-one-time-password-field@0.1.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/number': 1.1.1 @@ -6951,6 +7408,22 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-password-toggle-field@0.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-password-toggle-field@0.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6967,6 +7440,29 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-popover@1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + aria-hidden: 1.2.6 + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + react-remove-scroll: 2.7.1(@types/react@19.1.12)(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-popover@1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6990,6 +7486,24 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/rect': 1.1.1 + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@floating-ui/react-dom': 2.1.6(react-dom@19.2.3(react@19.1.4))(react@19.1.4) @@ -7008,6 +7522,16 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) @@ -7018,6 +7542,16 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) @@ -7028,6 +7562,15 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/react-slot': 1.2.3(@types/react@19.1.12)(react@19.1.4) @@ -7037,6 +7580,16 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-progress@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-progress@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) @@ -7047,6 +7600,24 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-radio-group@1.3.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-radio-group@1.3.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -7065,6 +7636,23 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -7082,6 +7670,23 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/number': 1.1.1 @@ -7099,6 +7704,35 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-select@2.2.6(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + aria-hidden: 1.2.6 + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + react-remove-scroll: 2.7.1(@types/react@19.1.12)(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-select@2.2.6(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/number': 1.1.1 @@ -7128,6 +7762,15 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-separator@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-separator@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) @@ -7137,6 +7780,25 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-slider@1.3.6(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-slider@1.3.6(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/number': 1.1.1 @@ -7163,6 +7825,21 @@ snapshots: optionalDependencies: '@types/react': 19.1.12 + '@radix-ui/react-switch@1.2.6(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-switch@1.2.6(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -7178,6 +7855,22 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -7194,6 +7887,26 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-toast@1.2.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-toast@1.2.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -7214,6 +7927,21 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -7229,6 +7957,17 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-toggle@1.1.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-toggle@1.1.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -7240,6 +7979,21 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-toolbar@1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-toolbar@1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -7255,6 +8009,26 @@ snapshots: '@types/react': 19.1.12 '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -7336,6 +8110,15 @@ snapshots: optionalDependencies: '@types/react': 19.1.12 + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4)': dependencies: '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4) @@ -7347,6 +8130,18 @@ snapshots: '@radix-ui/rect@1.1.1': {} + '@radix-ui/themes@3.3.0(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/colors': 3.0.0 + classnames: 2.5.1 + radix-ui: 1.4.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + react-remove-scroll-bar: 2.3.8(@types/react@19.1.12)(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + '@rolldown/pluginutils@1.0.0-beta.40': {} '@rolldown/pluginutils@1.0.0-beta.43': {} @@ -8032,6 +8827,11 @@ snapshots: '@types/minimatch': 5.1.2 '@types/node': 24.9.1 + '@types/hoist-non-react-statics@3.3.7(@types/react@19.1.12)': + dependencies: + '@types/react': 19.1.12 + hoist-non-react-statics: 3.3.2 + '@types/inquirer@6.5.0': dependencies: '@types/through': 0.0.33 @@ -8240,6 +9040,32 @@ snapshots: iron-webcrypto: 2.0.0 jose: 6.1.3 + '@workos-inc/widgets-i18n@0.1.0(@workos-inc/widgets@1.8.0(@radix-ui/themes@3.3.0(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4))(@tanstack/react-query@5.90.8(react@19.1.4))(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4))(react@19.1.4)(typescript@5.9.3)': + dependencies: + '@workos-inc/widgets': 1.8.0(@radix-ui/themes@3.3.0(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4))(@tanstack/react-query@5.90.8(react@19.1.4))(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + react: 19.1.4 + react-intl: 7.1.14(react@19.1.4)(typescript@5.9.3) + transitivePeerDependencies: + - typescript + + '@workos-inc/widgets@1.8.0(@radix-ui/themes@3.3.0(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4))(@tanstack/react-query@5.90.8(react@19.1.4))(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-form': 0.1.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-icons': 1.3.2(react@19.1.4) + '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/themes': 3.3.0(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@tanstack/react-query': 5.90.8(react@19.1.4) + bowser: 2.12.1 + clsx: 2.1.1 + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + use-debounce: 10.1.0(react@19.1.4) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + '@workos/authkit-session@0.3.4': dependencies: '@workos-inc/node': 8.0.0 @@ -8459,6 +9285,8 @@ snapshots: boolbase@1.0.0: {} + bowser@2.12.1: {} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -8635,6 +9463,8 @@ snapshots: dependencies: clsx: 2.1.1 + classnames@2.5.1: {} + clean-stack@2.2.0: {} cli-cursor@3.1.0: @@ -8754,6 +9584,8 @@ snapshots: dependencies: ms: 2.1.3 + decimal.js@10.6.0: {} + decode-formdata@0.9.0: {} decompress-response@6.0.0: @@ -9589,6 +10421,10 @@ snapshots: dependencies: hermes-estree: 0.25.1 + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 + htmlparser2@10.0.0: dependencies: domelementtype: 2.3.0 @@ -9690,6 +10526,13 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 + intl-messageformat@10.7.18: + dependencies: + '@formatjs/ecma402-abstract': 2.3.6 + '@formatjs/fast-memoize': 2.2.7 + '@formatjs/icu-messageformat-parser': 2.11.4 + tslib: 2.8.1 + ip-address@10.0.1: {} iron-webcrypto@2.0.0: @@ -10556,6 +11399,69 @@ snapshots: queue-microtask@1.2.3: {} + radix-ui@1.4.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4): + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-accessible-icon': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-aspect-ratio': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-avatar': 1.1.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-form': 0.1.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-label': 2.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-menubar': 1.1.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-one-time-password-field': 0.1.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-password-toggle-field': 0.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-progress': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-select': 2.2.6(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-slider': 1.3.6(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-switch': 1.2.6(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-toast': 1.2.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-toolbar': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.12)(react@19.1.4) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.4(react@19.1.4))(react@19.1.4) + react: 19.1.4 + react-dom: 19.1.4(react@19.1.4) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + radix-ui@1.4.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.2.3(react@19.1.4))(react@19.1.4): dependencies: '@radix-ui/primitive': 1.1.3 @@ -10641,6 +11547,20 @@ snapshots: react: 19.1.4 scheduler: 0.27.0 + react-intl@7.1.14(react@19.1.4)(typescript@5.9.3): + dependencies: + '@formatjs/ecma402-abstract': 2.3.6 + '@formatjs/icu-messageformat-parser': 2.11.4 + '@formatjs/intl': 3.1.8(typescript@5.9.3) + '@types/hoist-non-react-statics': 3.3.7(@types/react@19.1.12) + '@types/react': 19.1.12 + hoist-non-react-statics: 3.3.2 + intl-messageformat: 10.7.18 + react: 19.1.4 + tslib: 2.8.1 + optionalDependencies: + typescript: 5.9.3 + react-is@16.13.1: {} react-refresh@0.18.0: {} @@ -11325,6 +12245,10 @@ snapshots: optionalDependencies: '@types/react': 19.1.12 + use-debounce@10.1.0(react@19.1.4): + dependencies: + react: 19.1.4 + use-sidecar@1.1.3(@types/react@19.1.12)(react@19.1.4): dependencies: detect-node-es: 1.1.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 1f7fc66..db52ccf 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,43 +4,43 @@ packages: - tooling/* catalog: - "@better-auth/cli": 1.4.0-beta.9 - "@eslint/js": ^9.38.0 - "@tailwindcss/postcss": ^4.1.16 - "@tailwindcss/vite": ^4.1.16 - "@tanstack/react-form": ^1.23.8 - "@tanstack/react-query": ^5.90.8 - "@trpc/client": ^11.7.1 - "@trpc/server": ^11.7.1 - "@trpc/tanstack-react-query": ^11.7.1 - "@types/node": ^22.18.12 - "@vitejs/plugin-react": 5.1.0 + '@better-auth/cli': 1.4.0-beta.9 + '@eslint/js': ^9.38.0 + '@tailwindcss/postcss': ^4.1.16 + '@tailwindcss/vite': ^4.1.16 + '@tanstack/react-form': ^1.23.8 + '@tanstack/react-query': 5.90.8 + '@trpc/client': ^11.7.1 + '@trpc/server': ^11.7.1 + '@trpc/tanstack-react-query': ^11.7.1 + '@types/node': ^22.18.12 + '@vitejs/plugin-react': 5.1.0 better-auth: 1.4.0-beta.9 eslint: ^9.38.0 prettier: ^3.6.2 tailwindcss: ^4.1.16 typescript: ^5.9.3 - zod: ^4.1.12 vite: 7.1.12 + zod: ^4.1.12 catalogs: react19: - "@types/react": ~19.1.0 - "@types/react-dom": ~19.1.0 + '@types/react': ~19.1.0 + '@types/react-dom': ~19.1.0 react: 19.1.4 react-dom: 19.1.4 linkWorkspacePackages: true onlyBuiltDependencies: - - "@tailwindcss/oxide" + - '@tailwindcss/oxide' - esbuild overrides: - "@types/minimatch": 5.1.2 + '@types/minimatch': 5.1.2 lightningcss: 1.30.1 vite: 7.1.12 publicHoistPattern: - - "@ianvs/prettier-plugin-sort-imports" + - '@ianvs/prettier-plugin-sort-imports' - prettier-plugin-tailwindcss From 7fcd4832306688a2e2e629cda9edb38facb192c6 Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:26:48 +0300 Subject: [PATCH 16/21] md files --- .github/.copilot-instructions.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/.copilot-instructions.md b/.github/.copilot-instructions.md index da41686..0b6516c 100644 --- a/.github/.copilot-instructions.md +++ b/.github/.copilot-instructions.md @@ -4,6 +4,7 @@ - Treat all backends as APIs; do not couple services together. - The AI service is stateless and must not call application APIs directly. - always use pnpm and pnpx for package management +- don't write unnecessary markdown files or documentation, prefer inline code comments and self documenting code where possible. ## Monorepo Structure From 15832ec4c340d8bec8cea5319f779023a3ef5537 Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:33:02 +0300 Subject: [PATCH 17/21] u --- ai.dockerfile | 5 ----- services/ai-service/pyproject.toml | 11 +++++++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/ai.dockerfile b/ai.dockerfile index 2a405bb..ab03547 100644 --- a/ai.dockerfile +++ b/ai.dockerfile @@ -14,11 +14,6 @@ RUN uv pip install --system --no-cache \ torch==2.5.1+cpu \ --index-url https://download.pytorch.org/whl/cpu -RUN uv pip install --system --no-cache transformers tqdm numpy scikit-learn scipy nltk sentencepiece - -RUN uv pip install --system --no-cache --no-deps sentence-transformers - - # Install other dependencies RUN uv sync --no-install-project --no-dev diff --git a/services/ai-service/pyproject.toml b/services/ai-service/pyproject.toml index 155dd72..036fbd3 100644 --- a/services/ai-service/pyproject.toml +++ b/services/ai-service/pyproject.toml @@ -9,9 +9,13 @@ dependencies = [ "pdfplumber>=0.10.0", "python-dotenv>=1.0.0", "pydantic>=2.0.0", + # Removed pypdf (redundant with pdfplumber) + # Removed ipykernel (only needed for dev/notebooks) "qdrant-client>=1.8.0", "haystack-ai>=2.0.0", "transformers>=4.35.0", + # torch installed separately as CPU-only in Dockerfile + "sentence-transformers>=2.2.0", "accelerate>=0.24.0", "python-multipart>=0.0.9", "aiofiles>=24.0.0", @@ -28,11 +32,10 @@ dependencies = [ "uvicorn>=0.40.0", ] - -[dependency-groups] -dev = [ +[tool.uv] +# Exclude torch from uv sync since we install CPU version manually +override-dependencies = [ "torch==2.5.1", - "sentence-transformers>=2.2.0", ] From 4309f3e9e58c85950badcbf778d86a511d378854 Mon Sep 17 00:00:00 2001 From: rayidalshammari Date: Thu, 5 Feb 2026 15:15:09 +0300 Subject: [PATCH 18/21] wip --- docker-compose.dev.yml | 97 +++++++------- packages/api/src/ai-client/types.gen.ts | 120 +----------------- packages/api/src/router/submission.ts | 22 +++- services/ai-service/src/agent/run.py | 30 +++-- .../ai-service/src/api/routers/evaluations.py | 82 ++++-------- .../src/services/evaluation_service.py | 10 +- 6 files changed, 113 insertions(+), 248 deletions(-) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 0c8e7a5..bddf54d 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -4,58 +4,68 @@ services: context: . dockerfile: ai.dockerfile ports: - - "5050:8000" + - "5002:8000" env_file: - .env environment: - PYTHONPATH=/app/src - - PYTHONDONTWRITEBYTECODE=1 - - PYTHONUNBUFFERED=1 - volumes: - - ./services/ai-service:/app - - ./test_samples:/app/test_samples - - /app/.venv depends_on: vector_db: - condition: service_healthy + condition: service_started restart: unless-stopped - develop: - watch: - - action: sync - path: ./services/ai-service/src - target: /app/src + healthcheck: + test: + [ + "CMD", + "python", + "-c", + "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')", + ] + interval: 30s + timeout: 10s + retries: 3 + start_period: 60s frontend: build: context: . dockerfile: next.dockerfile - target: development ports: - - "5001:3001" + - "5001:3000" env_file: - .env environment: - - NODE_ENV=development - volumes: - - ./apps/tanstack-start:/app/apps/tanstack-start - - ./packages:/app/packages - - ./tooling:/app/tooling - - /app/node_modules - - /app/apps/tanstack-start/node_modules + - NODE_ENV=production + - AI_HOST=ai_service + - AI_SERVICE_URL=http://ai_service:8000 + - POSTGRES_URL=postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@application_db:5432/${POSTGRES_DB:-app_db} depends_on: - - ai_service + ai_service: + condition: service_started + application_db: + condition: service_healthy restart: unless-stopped - develop: - watch: - - action: sync - path: ./apps/tanstack-start/src - target: /app/apps/tanstack-start/src - - action: rebuild - path: ./apps/tanstack-start/package.json + + vector_db: + image: qdrant/qdrant:latest + restart: unless-stopped + container_name: qdrant + ports: + - "6333:6333" + - "6334:6334" + expose: + - 6333 + - 6334 + - 6335 + configs: + - source: qdrant_config + target: /qdrant/config/production.yaml + volumes: + - qdrant_data:/qdrant/storage application_db: image: postgres:15 - restart: unless-stopped + restart: always environment: POSTGRES_USER: ${POSTGRES_USER:-postgres} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password} @@ -63,7 +73,7 @@ services: ports: - "5432:5432" volumes: - - db_dev_data:/var/lib/postgresql/data + - db_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 30s @@ -71,24 +81,13 @@ services: retries: 5 start_period: 30s - vector_db: - image: qdrant/qdrant:latest - restart: unless-stopped - container_name: qdrant_dev - ports: - - "6333:6333" - - "6334:6334" - volumes: - - qdrant_dev_data:/qdrant/storage - healthcheck: - test: ["CMD-SHELL", "bash -c ':> /dev/tcp/localhost/6333'"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 10s +configs: + qdrant_config: + content: | + log_level: INFO volumes: - db_dev_data: + db_data: driver: local - qdrant_dev_data: + qdrant_data: driver: local diff --git a/packages/api/src/ai-client/types.gen.ts b/packages/api/src/ai-client/types.gen.ts index 9af324e..ab8a48a 100644 --- a/packages/api/src/ai-client/types.gen.ts +++ b/packages/api/src/ai-client/types.gen.ts @@ -45,125 +45,11 @@ export type BodySubmitEvaluationApiV1EvaluationsSubmitPost = { */ files: Array; /** - * Control Ids 1 + * Domain IDs * - * Comma-separated control IDs for file 1 + * Comma-separated domain IDs, one per file (e.g. '1_Data_Governance,1_Data_Governance,2_Data_Catalog') */ - control_ids_1?: string; - /** - * Control Ids 2 - * - * Comma-separated control IDs for file 2 - */ - control_ids_2?: string; - /** - * Control Ids 3 - * - * Comma-separated control IDs for file 3 - */ - control_ids_3?: string; - /** - * Control Ids 4 - * - * Comma-separated control IDs for file 4 - */ - control_ids_4?: string; - /** - * Control Ids 5 - * - * Comma-separated control IDs for file 5 - */ - control_ids_5?: string; - /** - * Control Ids 6 - * - * Comma-separated control IDs for file 6 - */ - control_ids_6?: string; - /** - * Control Ids 7 - * - * Comma-separated control IDs for file 7 - */ - control_ids_7?: string; - /** - * Control Ids 8 - * - * Comma-separated control IDs for file 8 - */ - control_ids_8?: string; - /** - * Control Ids 9 - * - * Comma-separated control IDs for file 9 - */ - control_ids_9?: string; - /** - * Control Ids 10 - * - * Comma-separated control IDs for file 10 - */ - control_ids_10?: string; - /** - * Control Ids 11 - * - * Comma-separated control IDs for file 11 - */ - control_ids_11?: string; - /** - * Control Ids 12 - * - * Comma-separated control IDs for file 12 - */ - control_ids_12?: string; - /** - * Control Ids 13 - * - * Comma-separated control IDs for file 13 - */ - control_ids_13?: string; - /** - * Control Ids 14 - * - * Comma-separated control IDs for file 14 - */ - control_ids_14?: string; - /** - * Control Ids 15 - * - * Comma-separated control IDs for file 15 - */ - control_ids_15?: string; - /** - * Control Ids 16 - * - * Comma-separated control IDs for file 16 - */ - control_ids_16?: string; - /** - * Control Ids 17 - * - * Comma-separated control IDs for file 17 - */ - control_ids_17?: string; - /** - * Control Ids 18 - * - * Comma-separated control IDs for file 18 - */ - control_ids_18?: string; - /** - * Control Ids 19 - * - * Comma-separated control IDs for file 19 - */ - control_ids_19?: string; - /** - * Control Ids 20 - * - * Comma-separated control IDs for file 20 - */ - control_ids_20?: string; + domain_ids?: string; }; /** diff --git a/packages/api/src/router/submission.ts b/packages/api/src/router/submission.ts index af058b9..a2bd118 100644 --- a/packages/api/src/router/submission.ts +++ b/packages/api/src/router/submission.ts @@ -70,13 +70,17 @@ export const submissionRouter = { return new File([buffer], f.name, { type: f.type }); }); - // 4. Call AI Service + // 4. Prepare domain_ids (one per file, comma-separated) + const domainIds = files.map((f) => f.domainId).join(","); + + // 5. Call AI Service try { const response = await submitEvaluationApiV1EvaluationsSubmitPost({ client, body: { framework_name: "NDI", files: blobs, + domain_ids: domainIds, }, }); @@ -228,7 +232,9 @@ export const submissionRouter = { } // Check if files have content stored - const filesWithoutContent = files.filter((f) => !f.fileContent); + const filesWithoutContent = files.filter( + (f) => !(f as unknown as { fileContent?: string }).fileContent + ); if (filesWithoutContent.length > 0) { throw new TRPCError({ code: "BAD_REQUEST", @@ -250,19 +256,25 @@ export const submissionRouter = { // 4. Prepare files for AI Service const blobs = files.map((f) => { - const buffer = Buffer.from(f.fileContent!, "base64"); + const fileContent = (f as unknown as { fileContent?: string }).fileContent; + const fileType = (f as unknown as { fileType?: string }).fileType; + const buffer = Buffer.from(fileContent!, "base64"); return new File([buffer], f.fileName, { - type: f.fileType ?? "application/octet-stream", + type: fileType ?? "application/octet-stream", }); }); - // 5. Call AI Service + // 5. Prepare domain_ids (one per file, comma-separated) + const domainIds = files.map((f) => f.domainId).join(","); + + // 6. Call AI Service try { const response = await submitEvaluationApiV1EvaluationsSubmitPost({ client, body: { framework_name: "NDI", files: blobs, + domain_ids: domainIds, }, }); diff --git a/services/ai-service/src/agent/run.py b/services/ai-service/src/agent/run.py index 7cc97ce..7ce01eb 100644 --- a/services/ai-service/src/agent/run.py +++ b/services/ai-service/src/agent/run.py @@ -19,7 +19,7 @@ def _project_root() -> Path: def run_evaluation_agent( framework_name: str, files: list[tuple[str, bytes]], - control_ids_per_file: list[str] | None = None, + domain_ids: list[str] | None = None, ) -> dict[str, Any]: """ Run the evaluation agent: persist files, build mimic JSON, run graph, return final state. @@ -27,8 +27,8 @@ def run_evaluation_agent( Args: framework_name: Framework name (e.g. NDI). files: List of (filename, bytes); 1 or more files. - control_ids_per_file: List of comma-separated control ID strings (one per file). - Must have the same length as files. Can be empty strings if not provided. + domain_ids: List of domain IDs (one per file). Each domain ID maps to a set of controls. + Must have the same length as files if provided. Returns: dict with mimic_json, evaluation_id, report_path, file_evaluations. @@ -36,15 +36,15 @@ def run_evaluation_agent( if not files: raise ValueError("At least one file is required") n = len(files) - if control_ids_per_file is not None and len(control_ids_per_file) != n: - raise ValueError(f"control_ids_per_file has {len(control_ids_per_file)} entries but {n} files; they must match") + if domain_ids is not None and len(domain_ids) != n: + raise ValueError(f"domain_ids has {len(domain_ids)} entries but {n} files; they must match") evaluation_id = str(uuid.uuid4()) root = _project_root() eval_dir = root / "data" / "evaluations" / evaluation_id eval_dir.mkdir(parents=True, exist_ok=True) - # Persist files and build file list with path and field_id + # Persist files and build file list with path, field_id, and domain_id file_list = [] for i, (filename, body) in enumerate(files): raw_name = Path(filename or f"file_{i+1}").name @@ -52,14 +52,20 @@ def run_evaluation_agent( path = eval_dir / safe_name path.write_bytes(body) field_id = f"field_{i + 1}" - file_list.append({"path": str(path), "extracted_text": "", "field_id": field_id}) + domain_id = domain_ids[i] if domain_ids else "" + file_list.append({ + "path": str(path), + "extracted_text": "", + "field_id": field_id, + "domain_id": domain_id, + }) - # Build mimic JSON: from client control_ids (must match file count) - if control_ids_per_file: - field_control_ids = [(f"field_{i+1}", s.strip()) for i, s in enumerate(control_ids_per_file)] + # Build mimic JSON from domain_ids + if domain_ids: + field_domain_ids = [(f"field_{i+1}", d) for i, d in enumerate(domain_ids)] else: - field_control_ids = [(f"field_{i+1}", "") for i in range(n)] - mimic_json = build_mimic_json(framework_name, field_control_ids) + field_domain_ids = [(f"field_{i+1}", "") for i in range(n)] + mimic_json = build_mimic_json(framework_name, field_domain_ids) initial_state: EvaluationState = { "evaluation_id": evaluation_id, diff --git a/services/ai-service/src/api/routers/evaluations.py b/services/ai-service/src/api/routers/evaluations.py index 00132bb..c0917d2 100644 --- a/services/ai-service/src/api/routers/evaluations.py +++ b/services/ai-service/src/api/routers/evaluations.py @@ -1,6 +1,6 @@ """ Evaluation endpoints: submit files + framework, get mimic JSON + report PDF path. -Number of files is flexible; one control_ids field per file (control_ids_1, control_ids_2, ...). +Supports domain_ids parameter to specify which domain each file belongs to. """ import os @@ -14,10 +14,10 @@ router = APIRouter(prefix="/api/v1/evaluations", tags=["evaluations"]) -_MAX_FILES = 50 +_MAX_FILES = 120 # 12 domains × 10 files per domain _MAX_UPLOAD_BYTES = int(os.getenv("MAX_UPLOAD_SIZE_MB", "50")) * 1024 * 1024 _FRAMEWORK_NAME_RE = re.compile(r"^[a-zA-Z0-9_\-]+$") -_CONTROL_IDS_RE = re.compile(r"^[a-zA-Z0-9.,\-_\s]*$") +_DOMAIN_IDS_RE = re.compile(r"^[a-zA-Z0-9_,\-\s]+$") def _sanitize_filename(filename: str) -> str: @@ -28,12 +28,6 @@ def _sanitize_filename(filename: str) -> str: return (name or "file")[:255] -def _control_ids_form(i: int, default: str = ""): - return Form( - default=default, description=f"Comma-separated control IDs for file {i}" - ) - - @router.post("/submit", response_model=SubmitEvaluationResponse) async def submit_evaluation( framework_name: str = Form( @@ -42,30 +36,15 @@ async def submit_evaluation( files: list[UploadFile] = File( ..., description="Files (PDF, DOCX, PPTX, CSV, XLSX); 1 or more" ), - control_ids_1: str = _control_ids_form(1), - control_ids_2: str = _control_ids_form(2), - control_ids_3: str = _control_ids_form(3), - control_ids_4: str = _control_ids_form(4), - control_ids_5: str = _control_ids_form(5), - control_ids_6: str = _control_ids_form(6), - control_ids_7: str = _control_ids_form(7), - control_ids_8: str = _control_ids_form(8), - control_ids_9: str = _control_ids_form(9), - control_ids_10: str = _control_ids_form(10), - control_ids_11: str = _control_ids_form(11), - control_ids_12: str = _control_ids_form(12), - control_ids_13: str = _control_ids_form(13), - control_ids_14: str = _control_ids_form(14), - control_ids_15: str = _control_ids_form(15), - control_ids_16: str = _control_ids_form(16), - control_ids_17: str = _control_ids_form(17), - control_ids_18: str = _control_ids_form(18), - control_ids_19: str = _control_ids_form(19), - control_ids_20: str = _control_ids_form(20), + domain_ids: str = Form( + default="", + description="Comma-separated domain IDs, one per file (e.g. '1_Data_Governance,1_Data_Governance,2_Data_Catalog')" + ), ) -> SubmitEvaluationResponse: """ - Submit an evaluation: files + framework name. Each file has its own control_ids field - (control_ids_1 for file 1, control_ids_2 for file 2, etc.). Each value = comma-separated IDs. + Submit an evaluation: files + framework name + domain_ids. + domain_ids is a comma-separated list of domain IDs (one per file). + Files are evaluated against the controls for their respective domains. Returns DB-mimic JSON + evaluation_id + report_path. """ if not _FRAMEWORK_NAME_RE.match(framework_name): @@ -83,36 +62,19 @@ async def submit_evaluation( status_code=400, detail=f"Maximum {_MAX_FILES} files allowed" ) - control_ids_fields = [ - control_ids_1, - control_ids_2, - control_ids_3, - control_ids_4, - control_ids_5, - control_ids_6, - control_ids_7, - control_ids_8, - control_ids_9, - control_ids_10, - control_ids_11, - control_ids_12, - control_ids_13, - control_ids_14, - control_ids_15, - control_ids_16, - control_ids_17, - control_ids_18, - control_ids_19, - control_ids_20, - ] - control_ids_per_file = [] - for s in control_ids_fields[:n_files]: - ids = s.strip() - if ids and not _CONTROL_IDS_RE.match(ids): + # Parse domain_ids + domain_ids_list = [] + if domain_ids.strip(): + if not _DOMAIN_IDS_RE.match(domain_ids): + raise HTTPException( + status_code=400, detail="Invalid domain_ids format" + ) + domain_ids_list = [d.strip() for d in domain_ids.split(",")] + if len(domain_ids_list) != n_files: raise HTTPException( - status_code=400, detail=f"Invalid control ID format: {ids[:100]}" + status_code=400, + detail=f"domain_ids has {len(domain_ids_list)} entries but {n_files} files; they must match" ) - control_ids_per_file.append(ids) file_tuples: list[tuple[str, bytes]] = [] for u in files: @@ -134,7 +96,7 @@ async def submit_evaluation( result = service.submit_evaluation( framework_name=framework_name, files=file_tuples, - control_ids_per_file=control_ids_per_file, + domain_ids=domain_ids_list if domain_ids_list else None, ) return SubmitEvaluationResponse( diff --git a/services/ai-service/src/services/evaluation_service.py b/services/ai-service/src/services/evaluation_service.py index b39ebeb..9c0e972 100644 --- a/services/ai-service/src/services/evaluation_service.py +++ b/services/ai-service/src/services/evaluation_service.py @@ -1,5 +1,5 @@ """ -Evaluation service: submit 15 files + framework, run agent, return mimic JSON + report path. +Evaluation service: submit files + framework, run agent, return mimic JSON + report path. No DB; files and report saved to filesystem. """ @@ -15,16 +15,16 @@ def submit_evaluation( self, framework_name: str, files: list[tuple[str, bytes]], - control_ids_per_file: list[str] | None = None, + domain_ids: list[str] | None = None, ) -> dict[str, Any]: """ - Submit an evaluation: files (1+) + framework name. control_ids_per_file must have the same - length as files (one comma-separated control ID string per file). + Submit an evaluation: files (1+) + framework name + domain_ids. + domain_ids must have the same length as files (one domain ID per file). Runs the LangGraph agent, saves report PDF to data/reports/{evaluation_id}.pdf. Returns mimic_json, evaluation_id, report_path, file_evaluations. """ return run_evaluation_agent( framework_name=framework_name, files=files, - control_ids_per_file=control_ids_per_file, + domain_ids=domain_ids, ) From 664f0e70fee536699c84960aa0ed239a28896700 Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 15:19:32 +0300 Subject: [PATCH 19/21] demo --- docker-compose.demo.yml | 169 ++++++++++++++++++++++++++++++++++ docs/DEMO_SETUP.md | 199 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 368 insertions(+) create mode 100644 docker-compose.demo.yml create mode 100644 docs/DEMO_SETUP.md diff --git a/docker-compose.demo.yml b/docker-compose.demo.yml new file mode 100644 index 0000000..d29e36f --- /dev/null +++ b/docker-compose.demo.yml @@ -0,0 +1,169 @@ +# Demo compose file with Keycloak SSO for WorkOS Admin Portal testing +# Usage: docker compose -f docker-compose.demo.yml up +# +# Access points: +# - Frontend: http://localhost:5001 +# - Keycloak Admin: http://localhost:8080 +# - Keycloak login: admin / admin + +services: + ai_service: + image: governance-agent-ai_service:latest + build: + context: . + dockerfile: ai.dockerfile + ports: + - "5000:8000" + env_file: + - .env + environment: + - PYTHONPATH=/app/src + depends_on: + vector_db: + condition: service_started + restart: unless-stopped + healthcheck: + test: + [ + "CMD", + "python", + "-c", + "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')", + ] + interval: 30s + timeout: 10s + retries: 3 + start_period: 60s + + frontend: + image: governance-agent-frontend:latest + build: + context: . + dockerfile: next.dockerfile + ports: + - "5001:3000" + env_file: + - .env + environment: + - NODE_ENV=production + - AI_HOST=ai_service + - POSTGRES_URL=postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@application_db:5432/${POSTGRES_DB:-app_db} + depends_on: + ai_service: + condition: service_started + application_db: + condition: service_healthy + keycloak: + condition: service_healthy + restart: unless-stopped + + vector_db: + image: qdrant/qdrant:latest + restart: unless-stopped + container_name: qdrant_demo + ports: + - "6333:6333" + - "6334:6334" + expose: + - 6333 + - 6334 + - 6335 + configs: + - source: qdrant_config + target: /qdrant/config/production.yaml + volumes: + - qdrant_demo_data:/qdrant/storage + + application_db: + image: postgres:15 + restart: always + environment: + POSTGRES_USER: ${POSTGRES_USER:-postgres} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password} + POSTGRES_DB: ${POSTGRES_DB:-app_db} + ports: + - "5432:5432" + volumes: + - db_demo_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 30s + + # Keycloak SSO Service for WorkOS Demo + keycloak_db: + image: postgres:15 + restart: always + environment: + POSTGRES_DB: keycloak + POSTGRES_USER: keycloak + POSTGRES_PASSWORD: keycloak_password + volumes: + - keycloak_db_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U keycloak"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s + + keycloak: + image: quay.io/keycloak/keycloak:23.0 + container_name: keycloak_demo + command: start-dev + restart: unless-stopped + environment: + # Admin credentials + KEYCLOAK_ADMIN: admin + KEYCLOAK_ADMIN_PASSWORD: admin + + # Database configuration + KC_DB: postgres + KC_DB_URL: jdbc:postgresql://keycloak_db:5432/keycloak + KC_DB_USERNAME: keycloak + KC_DB_PASSWORD: keycloak_password + + # Server configuration + KC_HOSTNAME_STRICT: false + KC_HOSTNAME_STRICT_HTTPS: false + KC_HTTP_ENABLED: true + KC_HEALTH_ENABLED: true + KC_METRICS_ENABLED: true + + # Proxy settings + KC_PROXY: edge + KC_LOG_LEVEL: INFO + ports: + - "8080:8080" + depends_on: + keycloak_db: + condition: service_healthy + healthcheck: + test: + [ + "CMD-SHELL", + "exec 3<>/dev/tcp/localhost/8080 && echo -e 'GET /health/ready HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n' >&3 && cat <&3 | grep -q '200 OK'", + ] + interval: 30s + timeout: 10s + retries: 5 + start_period: 90s + volumes: + - keycloak_data:/opt/keycloak/data + +configs: + qdrant_config: + content: | + log_level: INFO + +volumes: + db_demo_data: + driver: local + qdrant_demo_data: + driver: local + keycloak_db_data: + driver: local + keycloak_data: + driver: local diff --git a/docs/DEMO_SETUP.md b/docs/DEMO_SETUP.md new file mode 100644 index 0000000..3f77b7e --- /dev/null +++ b/docs/DEMO_SETUP.md @@ -0,0 +1,199 @@ +# WorkOS Admin Portal Demo Setup Guide + +This guide will help you set up and demonstrate the WorkOS Admin Portal with Keycloak SSO integration. + +## Quick Start + +1. **Start the demo environment:** + + ```bash + docker compose -f docker-compose.demo.yml up + ``` + +2. **Access points:** + - **Frontend Application:** http://localhost:5001 + - **Keycloak Admin Console:** http://localhost:8080 + - Username: `admin` + - Password: `admin` + +## Setting Up Keycloak for WorkOS Demo + +### Step 1: Configure Keycloak Realm + +1. Navigate to http://localhost:8080 and login with `admin / admin` + +2. Create a new realm (or use the master realm): + - Click the realm dropdown (top-left) + - Click "Create Realm" + - Name: `governance-demo` + - Click "Create" + +### Step 2: Configure SAML/OIDC Client for WorkOS + +#### For SAML: + +1. Go to **Clients** → **Create client** +2. Set: + - Client type: `SAML` + - Client ID: `workos-governance-app` +3. Click **Next**, then **Save** +4. Configure the client: + - Valid redirect URIs: `https://api.workos.com/sso/saml/acs/*` + - Master SAML Processing URL: `https://api.workos.com/sso/saml/acs` + - Name ID format: `email` +5. Save the configuration + +#### For OpenID Connect (OIDC): + +1. Go to **Clients** → **Create client** +2. Set: + - Client type: `OpenID Connect` + - Client ID: `workos-governance-app` +3. Click **Next** +4. Configure: + - Client authentication: `ON` + - Valid redirect URIs: `https://api.workos.com/sso/oauth/callback` + - Web origins: `http://localhost:5001` +5. Save and note the **Client Secret** from the Credentials tab + +### Step 3: Create Test Users + +1. Navigate to **Users** → **Create new user** +2. Create demo users: + - Username: `demo.user@company.com` + - Email: `demo.user@company.com` + - First name: `Demo` + - Last name: `User` + - Email verified: `ON` +3. Click **Create** +4. Set password: + - Go to **Credentials** tab + - Click **Set password** + - Password: `demo123` + - Temporary: `OFF` +5. Repeat for additional demo users (e.g., admin, manager, employee) + +### Step 4: Configure WorkOS Admin Portal + +1. **Get Keycloak metadata URL:** + - For SAML: `http://localhost:8080/realms/governance-demo/protocol/saml/descriptor` + - For OIDC: `http://localhost:8080/realms/governance-demo/.well-known/openid-configuration` + +2. **In WorkOS Dashboard** (https://dashboard.workos.com): + - Create an Organization + - Navigate to **SSO** → **Connections** → **Create Connection** + - Choose **SAML** or **OIDC** + - Enter the Keycloak metadata URL or configure manually: + - **SAML Endpoint:** `http://localhost:8080/realms/governance-demo/protocol/saml` + - **OIDC Discovery:** `http://localhost:8080/realms/governance-demo/.well-known/openid-configuration` + +3. **Configure Domain:** + - Add a domain (e.g., `company.com`) + - Link it to the Keycloak connection + +### Step 5: Test the Admin Portal + +1. **Access the WorkOS Admin Portal:** + + ```javascript + // Generate Admin Portal link in your application + const adminPortalUrl = `https://api.workos.com/portal/launch? + client_id=${WORKOS_CLIENT_ID}& + intent=sso& + organization=${organizationId}& + return_url=${encodeURIComponent("http://localhost:5001/dashboard")}`; + ``` + +2. **Via API:** + ```bash + curl -X POST https://api.workos.com/user_management/portal/generate_link \ + -H "Authorization: Bearer ${WORKOS_API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "organization": "org_...", + "intent": "sso" + }' + ``` + +## Demo Flow + +### For Your Presentation: + +1. **Show the Admin Portal UI:** + - "This is the WorkOS Admin Portal - IT admins can configure SSO without developer involvement" + +2. **Configure Keycloak SSO:** + - Show how an admin would paste the Keycloak SAML/OIDC metadata + - Demonstrate domain configuration + - Show the connection testing feature + +3. **Test SSO Login:** + - Navigate to your app's login + - Enter a user email with the configured domain + - Show the automatic redirect to Keycloak + - Complete authentication + - Show successful login to your app + +4. **Highlight Key Features:** + - Self-service SSO configuration + - No code deployments needed + - Support for multiple identity providers + - Domain-based routing + - User provisioning (SCIM) + +## Troubleshooting + +### Keycloak not accessible + +```bash +# Check if Keycloak is healthy +docker ps +docker logs keycloak_demo + +# Wait for Keycloak to fully start (can take 60-90 seconds) +``` + +### WorkOS can't reach Keycloak + +- Use ngrok or similar to expose Keycloak publicly for the demo: + ```bash + ngrok http 8080 + # Use the ngrok URL in WorkOS configuration + ``` + +### Reset everything + +```bash +docker compose -f docker-compose.demo.yml down -v +docker compose -f docker-compose.demo.yml up +``` + +## Environment Variables + +Make sure your `.env` file contains: + +```env +# WorkOS Configuration +WORKOS_CLIENT_ID=client_01KGHB6BFE17CZKTXGCH52J72X +WORKOS_API_KEY=sk_test_... +WORKOS_REDIRECT_URI=http://localhost:5001/api/auth/callback +WORKOS_COOKIE_PASSWORD=your-secure-cookie-password-here + +# Other required variables +POSTGRES_USER=postgres +POSTGRES_PASSWORD=your-db-password +POSTGRES_DB=app_db +``` + +## Useful Keycloak Endpoints + +- **Admin Console:** http://localhost:8080/admin +- **Account Console:** http://localhost:8080/realms/governance-demo/account +- **SAML Metadata:** http://localhost:8080/realms/governance-demo/protocol/saml/descriptor +- **OIDC Discovery:** http://localhost:8080/realms/governance-demo/.well-known/openid-configuration + +## Additional Resources + +- [WorkOS Admin Portal Docs](https://workos.com/docs/user-management/admin-portal) +- [Keycloak Documentation](https://www.keycloak.org/documentation) +- [WorkOS SSO QuickStart](https://workos.com/docs/sso/guide) From 1058a81eb99b78c112e8dda829cf20d718779098 Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 15:48:18 +0300 Subject: [PATCH 20/21] better dockerfile no cache invalidation every time --- ai.dockerfile | 4 +- services/ai-service/uv.lock | 488 +++--------------------------------- 2 files changed, 35 insertions(+), 457 deletions(-) diff --git a/ai.dockerfile b/ai.dockerfile index ab03547..f80fa5d 100644 --- a/ai.dockerfile +++ b/ai.dockerfile @@ -6,8 +6,10 @@ WORKDIR /app ENV UV_COMPILE_BYTECODE=1 ENV PYTHONPATH=/app/src ENV UV_INDEX_STRATEGY=unsafe-best-match +ENV UV_HTTP_TIMEOUT=300 -COPY services/ai-service/pyproject.toml ./ +# Copy dependency files for caching +COPY services/ai-service/pyproject.toml services/ai-service/uv.lock ./ # Install CPU-only PyTorch to reduce image size dramatically RUN uv pip install --system --no-cache \ diff --git a/services/ai-service/uv.lock b/services/ai-service/uv.lock index 42d15ed..838a05f 100644 --- a/services/ai-service/uv.lock +++ b/services/ai-service/uv.lock @@ -10,6 +10,9 @@ resolution-markers = [ "python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] +[manifest] +overrides = [{ name = "torch", specifier = "==2.5.1" }] + [[package]] name = "accelerate" version = "1.12.0" @@ -38,7 +41,6 @@ dependencies = [ { name = "fastapi" }, { name = "groq" }, { name = "haystack-ai" }, - { name = "ipykernel" }, { name = "langchain-core" }, { name = "langchain-groq" }, { name = "langgraph" }, @@ -47,7 +49,6 @@ dependencies = [ { name = "pandas" }, { name = "pdfplumber" }, { name = "pydantic" }, - { name = "pypdf" }, { name = "python-docx" }, { name = "python-dotenv" }, { name = "python-multipart" }, @@ -55,7 +56,6 @@ dependencies = [ { name = "qdrant-client" }, { name = "reportlab" }, { name = "sentence-transformers" }, - { name = "torch" }, { name = "transformers" }, { name = "uvicorn" }, ] @@ -67,7 +67,6 @@ requires-dist = [ { name = "fastapi", specifier = ">=0.128.0" }, { name = "groq", specifier = ">=0.4.0" }, { name = "haystack-ai", specifier = ">=2.0.0" }, - { name = "ipykernel", specifier = ">=7.1.0" }, { name = "langchain-core", specifier = ">=0.3.0" }, { name = "langchain-groq", specifier = ">=0.2.0" }, { name = "langgraph", specifier = ">=0.2.0" }, @@ -76,7 +75,6 @@ requires-dist = [ { name = "pandas", specifier = ">=2.0.0" }, { name = "pdfplumber", specifier = ">=0.10.0" }, { name = "pydantic", specifier = ">=2.0.0" }, - { name = "pypdf", specifier = ">=3.0.0" }, { name = "python-docx", specifier = ">=1.0.0" }, { name = "python-dotenv", specifier = ">=1.0.0" }, { name = "python-multipart", specifier = ">=0.0.9" }, @@ -84,7 +82,6 @@ requires-dist = [ { name = "qdrant-client", specifier = ">=1.8.0" }, { name = "reportlab", specifier = ">=4.0.0" }, { name = "sentence-transformers", specifier = ">=2.2.0" }, - { name = "torch", specifier = ">=2.0.0" }, { name = "transformers", specifier = ">=4.35.0" }, { name = "uvicorn", specifier = ">=0.40.0" }, ] @@ -128,24 +125,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, ] -[[package]] -name = "appnope" -version = "0.1.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, -] - -[[package]] -name = "asttokens" -version = "3.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, -] - [[package]] name = "attrs" version = "25.4.0" @@ -280,15 +259,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] -[[package]] -name = "comm" -version = "0.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, -] - [[package]] name = "cryptography" version = "46.0.3" @@ -345,54 +315,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740, upload-time = "2025-10-15T23:18:12.277Z" }, ] -[[package]] -name = "cuda-bindings" -version = "12.9.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cuda-pathfinder", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/63/56/e465c31dc9111be3441a9ba7df1941fe98f4aa6e71e8788a3fb4534ce24d/cuda_bindings-12.9.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:32bdc5a76906be4c61eb98f546a6786c5773a881f3b166486449b5d141e4a39f", size = 11906628, upload-time = "2025-10-21T14:51:49.905Z" }, - { url = "https://files.pythonhosted.org/packages/a3/84/1e6be415e37478070aeeee5884c2022713c1ecc735e6d82d744de0252eee/cuda_bindings-12.9.4-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56e0043c457a99ac473ddc926fe0dc4046694d99caef633e92601ab52cbe17eb", size = 11925991, upload-time = "2025-10-21T14:51:56.535Z" }, - { url = "https://files.pythonhosted.org/packages/d1/af/6dfd8f2ed90b1d4719bc053ff8940e494640fe4212dc3dd72f383e4992da/cuda_bindings-12.9.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8b72ee72a9cc1b531db31eebaaee5c69a8ec3500e32c6933f2d3b15297b53686", size = 11922703, upload-time = "2025-10-21T14:52:03.585Z" }, - { url = "https://files.pythonhosted.org/packages/6c/19/90ac264acc00f6df8a49378eedec9fd2db3061bf9263bf9f39fd3d8377c3/cuda_bindings-12.9.4-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d80bffc357df9988dca279734bc9674c3934a654cab10cadeed27ce17d8635ee", size = 11924658, upload-time = "2025-10-21T14:52:10.411Z" }, -] - -[[package]] -name = "cuda-pathfinder" -version = "1.3.3" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/02/4dbe7568a42e46582248942f54dc64ad094769532adbe21e525e4edf7bc4/cuda_pathfinder-1.3.3-py3-none-any.whl", hash = "sha256:9984b664e404f7c134954a771be8775dfd6180ea1e1aef4a5a37d4be05d9bbb1", size = 27154, upload-time = "2025-12-04T22:35:08.996Z" }, -] - -[[package]] -name = "debugpy" -version = "1.8.19" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/73/75/9e12d4d42349b817cd545b89247696c67917aab907012ae5b64bbfea3199/debugpy-1.8.19.tar.gz", hash = "sha256:eea7e5987445ab0b5ed258093722d5ecb8bb72217c5c9b1e21f64efe23ddebdb", size = 1644590, upload-time = "2025-12-15T21:53:28.044Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/71/3d/388035a31a59c26f1ecc8d86af607d0c42e20ef80074147cd07b180c4349/debugpy-1.8.19-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:91e35db2672a0abaf325f4868fcac9c1674a0d9ad9bb8a8c849c03a5ebba3e6d", size = 2538859, upload-time = "2025-12-15T21:53:50.478Z" }, - { url = "https://files.pythonhosted.org/packages/4a/19/c93a0772d0962294f083dbdb113af1a7427bb632d36e5314297068f55db7/debugpy-1.8.19-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:85016a73ab84dea1c1f1dcd88ec692993bcbe4532d1b49ecb5f3c688ae50c606", size = 4292575, upload-time = "2025-12-15T21:53:51.821Z" }, - { url = "https://files.pythonhosted.org/packages/5c/56/09e48ab796b0a77e3d7dc250f95251832b8bf6838c9632f6100c98bdf426/debugpy-1.8.19-cp313-cp313-win32.whl", hash = "sha256:b605f17e89ba0ecee994391194285fada89cee111cfcd29d6f2ee11cbdc40976", size = 5286209, upload-time = "2025-12-15T21:53:53.602Z" }, - { url = "https://files.pythonhosted.org/packages/fb/4e/931480b9552c7d0feebe40c73725dd7703dcc578ba9efc14fe0e6d31cfd1/debugpy-1.8.19-cp313-cp313-win_amd64.whl", hash = "sha256:c30639998a9f9cd9699b4b621942c0179a6527f083c72351f95c6ab1728d5b73", size = 5328206, upload-time = "2025-12-15T21:53:55.433Z" }, - { url = "https://files.pythonhosted.org/packages/f6/b9/cbec520c3a00508327476c7fce26fbafef98f412707e511eb9d19a2ef467/debugpy-1.8.19-cp314-cp314-macosx_15_0_universal2.whl", hash = "sha256:1e8c4d1bd230067bf1bbcdbd6032e5a57068638eb28b9153d008ecde288152af", size = 2537372, upload-time = "2025-12-15T21:53:57.318Z" }, - { url = "https://files.pythonhosted.org/packages/88/5e/cf4e4dc712a141e10d58405c58c8268554aec3c35c09cdcda7535ff13f76/debugpy-1.8.19-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:d40c016c1f538dbf1762936e3aeb43a89b965069d9f60f9e39d35d9d25e6b809", size = 4268729, upload-time = "2025-12-15T21:53:58.712Z" }, - { url = "https://files.pythonhosted.org/packages/82/a3/c91a087ab21f1047db328c1d3eb5d1ff0e52de9e74f9f6f6fa14cdd93d58/debugpy-1.8.19-cp314-cp314-win32.whl", hash = "sha256:0601708223fe1cd0e27c6cce67a899d92c7d68e73690211e6788a4b0e1903f5b", size = 5286388, upload-time = "2025-12-15T21:54:00.687Z" }, - { url = "https://files.pythonhosted.org/packages/17/b8/bfdc30b6e94f1eff09f2dc9cc1f9cd1c6cde3d996bcbd36ce2d9a4956e99/debugpy-1.8.19-cp314-cp314-win_amd64.whl", hash = "sha256:8e19a725f5d486f20e53a1dde2ab8bb2c9607c40c00a42ab646def962b41125f", size = 5327741, upload-time = "2025-12-15T21:54:02.148Z" }, - { url = "https://files.pythonhosted.org/packages/25/3e/e27078370414ef35fafad2c06d182110073daaeb5d3bf734b0b1eeefe452/debugpy-1.8.19-py2.py3-none-any.whl", hash = "sha256:360ffd231a780abbc414ba0f005dad409e71c78637efe8f2bd75837132a41d38", size = 5292321, upload-time = "2025-12-15T21:54:16.024Z" }, -] - -[[package]] -name = "decorator" -version = "5.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, -] - [[package]] name = "distro" version = "1.9.0" @@ -420,15 +342,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" }, ] -[[package]] -name = "executing" -version = "2.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, -] - [[package]] name = "fastapi" version = "0.128.0" @@ -691,75 +604,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] -[[package]] -name = "ipykernel" -version = "7.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "appnope", marker = "sys_platform == 'darwin'" }, - { name = "comm" }, - { name = "debugpy" }, - { name = "ipython" }, - { name = "jupyter-client" }, - { name = "jupyter-core" }, - { name = "matplotlib-inline" }, - { name = "nest-asyncio" }, - { name = "packaging" }, - { name = "psutil" }, - { name = "pyzmq" }, - { name = "tornado" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579, upload-time = "2025-10-27T09:46:39.471Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968, upload-time = "2025-10-27T09:46:37.805Z" }, -] - -[[package]] -name = "ipython" -version = "9.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "decorator" }, - { name = "ipython-pygments-lexers" }, - { name = "jedi" }, - { name = "matplotlib-inline" }, - { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "prompt-toolkit" }, - { name = "pygments" }, - { name = "stack-data" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/46/dd/fb08d22ec0c27e73c8bc8f71810709870d51cadaf27b7ddd3f011236c100/ipython-9.9.0.tar.gz", hash = "sha256:48fbed1b2de5e2c7177eefa144aba7fcb82dac514f09b57e2ac9da34ddb54220", size = 4425043, upload-time = "2026-01-05T12:36:46.233Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/92/162cfaee4ccf370465c5af1ce36a9eacec1becb552f2033bb3584e6f640a/ipython-9.9.0-py3-none-any.whl", hash = "sha256:b457fe9165df2b84e8ec909a97abcf2ed88f565970efba16b1f7229c283d252b", size = 621431, upload-time = "2026-01-05T12:36:44.669Z" }, -] - -[[package]] -name = "ipython-pygments-lexers" -version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, -] - -[[package]] -name = "jedi" -version = "0.19.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "parso" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, -] - [[package]] name = "jinja2" version = "3.1.6" @@ -880,35 +724,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, ] -[[package]] -name = "jupyter-client" -version = "8.8.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-core" }, - { name = "python-dateutil" }, - { name = "pyzmq" }, - { name = "tornado" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/05/e4/ba649102a3bc3fbca54e7239fb924fd434c766f855693d86de0b1f2bec81/jupyter_client-8.8.0.tar.gz", hash = "sha256:d556811419a4f2d96c869af34e854e3f059b7cc2d6d01a9cd9c85c267691be3e", size = 348020, upload-time = "2026-01-08T13:55:47.938Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/0b/ceb7694d864abc0a047649aec263878acb9f792e1fec3e676f22dc9015e3/jupyter_client-8.8.0-py3-none-any.whl", hash = "sha256:f93a5b99c5e23a507b773d3a1136bd6e16c67883ccdbd9a829b0bbdb98cd7d7a", size = 107371, upload-time = "2026-01-08T13:55:45.562Z" }, -] - -[[package]] -name = "jupyter-core" -version = "5.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "platformdirs" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814, upload-time = "2025-10-16T19:19:18.444Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032, upload-time = "2025-10-16T19:19:16.783Z" }, -] - [[package]] name = "langchain-core" version = "1.2.7" @@ -1151,18 +966,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, ] -[[package]] -name = "matplotlib-inline" -version = "0.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110, upload-time = "2025-10-23T09:00:22.126Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516, upload-time = "2025-10-23T09:00:20.675Z" }, -] - [[package]] name = "mdurl" version = "0.1.2" @@ -1190,15 +993,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, ] -[[package]] -name = "nest-asyncio" -version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, -] - [[package]] name = "networkx" version = "3.6.1" @@ -1260,77 +1054,69 @@ wheels = [ [[package]] name = "nvidia-cublas-cu12" -version = "12.8.4.1" +version = "12.4.5.8" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, + { url = "https://files.pythonhosted.org/packages/ae/71/1c91302526c45ab494c23f61c7a84aa568b8c1f9d196efa5993957faf906/nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_x86_64.whl", hash = "sha256:2fc8da60df463fdefa81e323eef2e36489e1c94335b5358bcb38360adf75ac9b", size = 363438805, upload-time = "2024-04-03T20:57:06.025Z" }, ] [[package]] name = "nvidia-cuda-cupti-cu12" -version = "12.8.90" +version = "12.4.127" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, + { url = "https://files.pythonhosted.org/packages/67/42/f4f60238e8194a3106d06a058d494b18e006c10bb2b915655bd9f6ea4cb1/nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:9dec60f5ac126f7bb551c055072b69d85392b13311fcc1bcda2202d172df30fb", size = 13813957, upload-time = "2024-04-03T20:55:01.564Z" }, ] [[package]] name = "nvidia-cuda-nvrtc-cu12" -version = "12.8.93" +version = "12.4.127" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, + { url = "https://files.pythonhosted.org/packages/2c/14/91ae57cd4db3f9ef7aa99f4019cfa8d54cb4caa7e00975df6467e9725a9f/nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a178759ebb095827bd30ef56598ec182b85547f1508941a3d560eb7ea1fbf338", size = 24640306, upload-time = "2024-04-03T20:56:01.463Z" }, ] [[package]] name = "nvidia-cuda-runtime-cu12" -version = "12.8.90" +version = "12.4.127" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, + { url = "https://files.pythonhosted.org/packages/ea/27/1795d86fe88ef397885f2e580ac37628ed058a92ed2c39dc8eac3adf0619/nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:64403288fa2136ee8e467cdc9c9427e0434110899d07c779f25b5c068934faa5", size = 883737, upload-time = "2024-04-03T20:54:51.355Z" }, ] [[package]] name = "nvidia-cudnn-cu12" -version = "9.10.2.21" +version = "9.1.0.70" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nvidia-cublas-cu12", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, + { url = "https://files.pythonhosted.org/packages/9f/fd/713452cd72343f682b1c7b9321e23829f00b842ceaedcda96e742ea0b0b3/nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl", hash = "sha256:165764f44ef8c61fcdfdfdbe769d687e06374059fbb388b6c89ecb0e28793a6f", size = 664752741, upload-time = "2024-04-22T15:24:15.253Z" }, ] [[package]] name = "nvidia-cufft-cu12" -version = "11.3.3.83" +version = "11.2.1.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nvidia-nvjitlink-cu12", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, -] - -[[package]] -name = "nvidia-cufile-cu12" -version = "1.13.1.3" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, + { url = "https://files.pythonhosted.org/packages/27/94/3266821f65b92b3138631e9c8e7fe1fb513804ac934485a8d05776e1dd43/nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f083fc24912aa410be21fa16d157fed2055dab1cc4b6934a0e03cba69eb242b9", size = 211459117, upload-time = "2024-04-03T20:57:40.402Z" }, ] [[package]] name = "nvidia-curand-cu12" -version = "10.3.9.90" +version = "10.3.5.147" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, + { url = "https://files.pythonhosted.org/packages/8a/6d/44ad094874c6f1b9c654f8ed939590bdc408349f137f9b98a3a23ccec411/nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a88f583d4e0bb643c49743469964103aa59f7f708d862c3ddb0fc07f851e3b8b", size = 56305206, upload-time = "2024-04-03T20:58:08.722Z" }, ] [[package]] name = "nvidia-cusolver-cu12" -version = "11.7.3.90" +version = "11.6.1.9" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nvidia-cublas-cu12", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, @@ -1338,58 +1124,42 @@ dependencies = [ { name = "nvidia-nvjitlink-cu12", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, + { url = "https://files.pythonhosted.org/packages/3a/e1/5b9089a4b2a4790dfdea8b3a006052cfecff58139d5a4e34cb1a51df8d6f/nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_x86_64.whl", hash = "sha256:19e33fa442bcfd085b3086c4ebf7e8debc07cfe01e11513cc6d332fd918ac260", size = 127936057, upload-time = "2024-04-03T20:58:28.735Z" }, ] [[package]] name = "nvidia-cusparse-cu12" -version = "12.5.8.93" +version = "12.3.1.170" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nvidia-nvjitlink-cu12", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, -] - -[[package]] -name = "nvidia-cusparselt-cu12" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, + { url = "https://files.pythonhosted.org/packages/db/f7/97a9ea26ed4bbbfc2d470994b8b4f338ef663be97b8f677519ac195e113d/nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ea4f11a2904e2a8dc4b1833cc1b5181cde564edd0d5cd33e3c168eff2d1863f1", size = 207454763, upload-time = "2024-04-03T20:58:59.995Z" }, ] [[package]] name = "nvidia-nccl-cu12" -version = "2.27.5" +version = "2.21.5" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229, upload-time = "2025-06-26T04:11:28.385Z" }, + { url = "https://files.pythonhosted.org/packages/df/99/12cd266d6233f47d00daf3a72739872bdc10267d0383508b0b9c84a18bb6/nvidia_nccl_cu12-2.21.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:8579076d30a8c24988834445f8d633c697d42397e92ffc3f63fa26766d25e0a0", size = 188654414, upload-time = "2024-04-03T15:32:57.427Z" }, ] [[package]] name = "nvidia-nvjitlink-cu12" -version = "12.8.93" +version = "12.4.127" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, -] - -[[package]] -name = "nvidia-nvshmem-cu12" -version = "3.4.5" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/09/6ea3ea725f82e1e76684f0708bbedd871fc96da89945adeba65c3835a64c/nvidia_nvshmem_cu12-3.4.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:042f2500f24c021db8a06c5eec2539027d57460e1c1a762055a6554f72c369bd", size = 139103095, upload-time = "2025-09-06T00:32:31.266Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ff/847841bacfbefc97a00036e0fce5a0f086b640756dc38caea5e1bb002655/nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:06b3b9b25bf3f8af351d664978ca26a16d2c5127dbd53c0497e28d1fb9611d57", size = 21066810, upload-time = "2024-04-03T20:59:46.957Z" }, ] [[package]] name = "nvidia-nvtx-cu12" -version = "12.8.90" +version = "12.4.127" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, + { url = "https://files.pythonhosted.org/packages/87/20/199b8713428322a2f22b722c62b8cc278cc53dffa9705d744484b5035ee9/nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:781e950d9b9f60d8241ccea575b32f5105a5baf4c2351cab5256a24869f12a1a", size = 99144, upload-time = "2024-04-03T20:56:12.406Z" }, ] [[package]] @@ -1544,15 +1314,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/3f/a80ac00acbc6b35166b42850e98a4f466e2c0d9c64054161ba9620f95680/pandas-3.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:1c39eab3ad38f2d7a249095f0a3d8f8c22cc0f847e98ccf5bbe732b272e2d9fa", size = 9441003, upload-time = "2026-01-21T15:52:02.281Z" }, ] -[[package]] -name = "parso" -version = "0.8.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, -] - [[package]] name = "pdfminer-six" version = "20251230" @@ -1580,18 +1341,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8b/c8/cdbc975f5b634e249cfa6597e37c50f3078412474f21c015e508bfbfe3c3/pdfplumber-0.11.9-py3-none-any.whl", hash = "sha256:33ec5580959ba524e9100138746e090879504c42955df1b8a997604dd326c443", size = 60045, upload-time = "2026-01-05T08:10:27.512Z" }, ] -[[package]] -name = "pexpect" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ptyprocess", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, -] - [[package]] name = "pillow" version = "11.3.0" @@ -1647,15 +1396,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" }, ] -[[package]] -name = "platformdirs" -version = "4.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, -] - [[package]] name = "portalocker" version = "3.2.0" @@ -1685,18 +1425,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ae/f6/8d4a2d1b67368fec425f32911e2f3638d5ac9e8abfebc698ac426fcf65db/posthog-7.6.0-py3-none-any.whl", hash = "sha256:c4dd78cf77c4fecceb965f86066e5ac37886ef867d68ffe75a1db5d681d7d9ad", size = 168426, upload-time = "2026-01-19T16:23:02.71Z" }, ] -[[package]] -name = "prompt-toolkit" -version = "3.0.52" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "wcwidth" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, -] - [[package]] name = "protobuf" version = "6.33.4" @@ -1740,24 +1468,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3e/73/2ce007f4198c80fcf2cb24c169884f833fe93fbc03d55d302627b094ee91/psutil-7.2.1-cp37-abi3-win_arm64.whl", hash = "sha256:0d67c1822c355aa6f7314d92018fb4268a76668a536f133599b91edd48759442", size = 133836, upload-time = "2025-12-29T08:26:43.086Z" }, ] -[[package]] -name = "ptyprocess" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, -] - -[[package]] -name = "pure-eval" -version = "0.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, -] - [[package]] name = "pycparser" version = "3.0" @@ -1844,15 +1554,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] -[[package]] -name = "pypdf" -version = "6.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/f4/801632a8b62a805378b6af2b5a3fcbfd8923abf647e0ed1af846a83433b2/pypdf-6.6.0.tar.gz", hash = "sha256:4c887ef2ea38d86faded61141995a3c7d068c9d6ae8477be7ae5de8a8e16592f", size = 5281063, upload-time = "2026-01-09T11:20:11.786Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b2/ba/96f99276194f720e74ed99905a080f6e77810558874e8935e580331b46de/pypdf-6.6.0-py3-none-any.whl", hash = "sha256:bca9091ef6de36c7b1a81e09327c554b7ce51e88dad68f5890c2b4a4417f1fd7", size = 328963, upload-time = "2026-01-09T11:20:09.278Z" }, -] - [[package]] name = "pypdfium2" version = "5.3.0" @@ -1989,49 +1690,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, ] -[[package]] -name = "pyzmq" -version = "27.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi", marker = "implementation_name == 'pypy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, - { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, - { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, - { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, - { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, - { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, - { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, - { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, - { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, - { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, - { url = "https://files.pythonhosted.org/packages/60/cb/84a13459c51da6cec1b7b1dc1a47e6db6da50b77ad7fd9c145842750a011/pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5", size = 1122436, upload-time = "2025-09-08T23:08:20.801Z" }, - { url = "https://files.pythonhosted.org/packages/dc/b6/94414759a69a26c3dd674570a81813c46a078767d931a6c70ad29fc585cb/pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6", size = 1156301, upload-time = "2025-09-08T23:08:22.47Z" }, - { url = "https://files.pythonhosted.org/packages/a5/ad/15906493fd40c316377fd8a8f6b1f93104f97a752667763c9b9c1b71d42d/pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7", size = 1341197, upload-time = "2025-09-08T23:08:24.286Z" }, - { url = "https://files.pythonhosted.org/packages/14/1d/d343f3ce13db53a54cb8946594e567410b2125394dafcc0268d8dda027e0/pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05", size = 897275, upload-time = "2025-09-08T23:08:26.063Z" }, - { url = "https://files.pythonhosted.org/packages/69/2d/d83dd6d7ca929a2fc67d2c3005415cdf322af7751d773524809f9e585129/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9", size = 660469, upload-time = "2025-09-08T23:08:27.623Z" }, - { url = "https://files.pythonhosted.org/packages/3e/cd/9822a7af117f4bc0f1952dbe9ef8358eb50a24928efd5edf54210b850259/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128", size = 847961, upload-time = "2025-09-08T23:08:29.672Z" }, - { url = "https://files.pythonhosted.org/packages/9a/12/f003e824a19ed73be15542f172fd0ec4ad0b60cf37436652c93b9df7c585/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39", size = 1650282, upload-time = "2025-09-08T23:08:31.349Z" }, - { url = "https://files.pythonhosted.org/packages/d5/4a/e82d788ed58e9a23995cee70dbc20c9aded3d13a92d30d57ec2291f1e8a3/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97", size = 2024468, upload-time = "2025-09-08T23:08:33.543Z" }, - { url = "https://files.pythonhosted.org/packages/d9/94/2da0a60841f757481e402b34bf4c8bf57fa54a5466b965de791b1e6f747d/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db", size = 1885394, upload-time = "2025-09-08T23:08:35.51Z" }, - { url = "https://files.pythonhosted.org/packages/4f/6f/55c10e2e49ad52d080dc24e37adb215e5b0d64990b57598abc2e3f01725b/pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c", size = 574964, upload-time = "2025-09-08T23:08:37.178Z" }, - { url = "https://files.pythonhosted.org/packages/87/4d/2534970ba63dd7c522d8ca80fb92777f362c0f321900667c615e2067cb29/pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2", size = 641029, upload-time = "2025-09-08T23:08:40.595Z" }, - { url = "https://files.pythonhosted.org/packages/f6/fa/f8aea7a28b0641f31d40dea42d7ef003fded31e184ef47db696bc74cd610/pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e", size = 561541, upload-time = "2025-09-08T23:08:42.668Z" }, - { url = "https://files.pythonhosted.org/packages/87/45/19efbb3000956e82d0331bafca5d9ac19ea2857722fa2caacefb6042f39d/pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a", size = 1341197, upload-time = "2025-09-08T23:08:44.973Z" }, - { url = "https://files.pythonhosted.org/packages/48/43/d72ccdbf0d73d1343936296665826350cb1e825f92f2db9db3e61c2162a2/pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea", size = 897175, upload-time = "2025-09-08T23:08:46.601Z" }, - { url = "https://files.pythonhosted.org/packages/2f/2e/a483f73a10b65a9ef0161e817321d39a770b2acf8bcf3004a28d90d14a94/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96", size = 660427, upload-time = "2025-09-08T23:08:48.187Z" }, - { url = "https://files.pythonhosted.org/packages/f5/d2/5f36552c2d3e5685abe60dfa56f91169f7a2d99bbaf67c5271022ab40863/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d", size = 847929, upload-time = "2025-09-08T23:08:49.76Z" }, - { url = "https://files.pythonhosted.org/packages/c4/2a/404b331f2b7bf3198e9945f75c4c521f0c6a3a23b51f7a4a401b94a13833/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146", size = 1650193, upload-time = "2025-09-08T23:08:51.7Z" }, - { url = "https://files.pythonhosted.org/packages/1c/0b/f4107e33f62a5acf60e3ded67ed33d79b4ce18de432625ce2fc5093d6388/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd", size = 2024388, upload-time = "2025-09-08T23:08:53.393Z" }, - { url = "https://files.pythonhosted.org/packages/0d/01/add31fe76512642fd6e40e3a3bd21f4b47e242c8ba33efb6809e37076d9b/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a", size = 1885316, upload-time = "2025-09-08T23:08:55.702Z" }, - { url = "https://files.pythonhosted.org/packages/c4/59/a5f38970f9bf07cee96128de79590bb354917914a9be11272cfc7ff26af0/pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92", size = 587472, upload-time = "2025-09-08T23:08:58.18Z" }, - { url = "https://files.pythonhosted.org/packages/70/d8/78b1bad170f93fcf5e3536e70e8fadac55030002275c9a29e8f5719185de/pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0", size = 661401, upload-time = "2025-09-08T23:08:59.802Z" }, - { url = "https://files.pythonhosted.org/packages/81/d6/4bfbb40c9a0b42fc53c7cf442f6385db70b40f74a783130c5d0a5aa62228/pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7", size = 575170, upload-time = "2025-09-08T23:09:01.418Z" }, -] - [[package]] name = "qdrant-client" version = "1.16.2" @@ -2410,20 +2068,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, ] -[[package]] -name = "stack-data" -version = "0.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "asttokens" }, - { name = "executing" }, - { name = "pure-eval" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, -] - [[package]] name = "starlette" version = "0.50.0" @@ -2438,14 +2082,14 @@ wheels = [ [[package]] name = "sympy" -version = "1.14.0" +version = "1.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mpmath" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/99/5a5b6f19ff9f083671ddf7b9632028436167cd3d33e11015754e41b249a4/sympy-1.13.1.tar.gz", hash = "sha256:9cebf7e04ff162015ce31c9c6c9144daa34a93bd082f54fd8f12deca4f47515f", size = 7533040, upload-time = "2024-07-19T09:26:51.238Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, + { url = "https://files.pythonhosted.org/packages/b2/fe/81695a1aa331a842b582453b605175f419fe8540355886031328089d840a/sympy-1.13.1-py3-none-any.whl", hash = "sha256:db36cdc64bf61b9b24578b6f7bab1ecdd2452cf008f34faa33776680c26d66f8", size = 6189177, upload-time = "2024-07-19T09:26:48.863Z" }, ] [[package]] @@ -2494,10 +2138,9 @@ wheels = [ [[package]] name = "torch" -version = "2.10.0" +version = "2.5.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cuda-bindings", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "filelock" }, { name = "fsspec" }, { name = "jinja2" }, @@ -2508,56 +2151,18 @@ dependencies = [ { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "setuptools" }, { name = "sympy" }, - { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "typing-extensions" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/c9/6f/f2e91e34e3fcba2e3fc8d8f74e7d6c22e74e480bbd1db7bc8900fdf3e95c/torch-2.10.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:5c4d217b14741e40776dd7074d9006fd28b8a97ef5654db959d8635b2fe5f29b", size = 146004247, upload-time = "2026-01-21T16:24:29.335Z" }, - { url = "https://files.pythonhosted.org/packages/98/fb/5160261aeb5e1ee12ee95fe599d0541f7c976c3701d607d8fc29e623229f/torch-2.10.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:6b71486353fce0f9714ca0c9ef1c850a2ae766b409808acd58e9678a3edb7738", size = 915716445, upload-time = "2026-01-21T16:22:45.353Z" }, - { url = "https://files.pythonhosted.org/packages/6a/16/502fb1b41e6d868e8deb5b0e3ae926bbb36dab8ceb0d1b769b266ad7b0c3/torch-2.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:c2ee399c644dc92ef7bc0d4f7e74b5360c37cdbe7c5ba11318dda49ffac2bc57", size = 113757050, upload-time = "2026-01-21T16:24:19.204Z" }, - { url = "https://files.pythonhosted.org/packages/1a/0b/39929b148f4824bc3ad6f9f72a29d4ad865bcf7ebfc2fa67584773e083d2/torch-2.10.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:3202429f58309b9fa96a614885eace4b7995729f44beb54d3e4a47773649d382", size = 79851305, upload-time = "2026-01-21T16:24:09.209Z" }, - { url = "https://files.pythonhosted.org/packages/d8/14/21fbce63bc452381ba5f74a2c0a959fdf5ad5803ccc0c654e752e0dbe91a/torch-2.10.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:aae1b29cd68e50a9397f5ee897b9c24742e9e306f88a807a27d617f07adb3bd8", size = 146005472, upload-time = "2026-01-21T16:22:29.022Z" }, - { url = "https://files.pythonhosted.org/packages/54/fd/b207d1c525cb570ef47f3e9f836b154685011fce11a2f444ba8a4084d042/torch-2.10.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:6021db85958db2f07ec94e1bc77212721ba4920c12a18dc552d2ae36a3eb163f", size = 915612644, upload-time = "2026-01-21T16:21:47.019Z" }, - { url = "https://files.pythonhosted.org/packages/36/53/0197f868c75f1050b199fe58f9bf3bf3aecac9b4e85cc9c964383d745403/torch-2.10.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff43db38af76fda183156153983c9a096fc4c78d0cd1e07b14a2314c7f01c2c8", size = 113997015, upload-time = "2026-01-21T16:23:00.767Z" }, - { url = "https://files.pythonhosted.org/packages/0e/13/e76b4d9c160e89fff48bf16b449ea324bda84745d2ab30294c37c2434c0d/torch-2.10.0-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:cdf2a523d699b70d613243211ecaac14fe9c5df8a0b0a9c02add60fb2a413e0f", size = 79498248, upload-time = "2026-01-21T16:23:09.315Z" }, - { url = "https://files.pythonhosted.org/packages/4f/93/716b5ac0155f1be70ed81bacc21269c3ece8dba0c249b9994094110bfc51/torch-2.10.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:bf0d9ff448b0218e0433aeb198805192346c4fd659c852370d5cc245f602a06a", size = 79464992, upload-time = "2026-01-21T16:23:05.162Z" }, - { url = "https://files.pythonhosted.org/packages/69/2b/51e663ff190c9d16d4a8271203b71bc73a16aa7619b9f271a69b9d4a936b/torch-2.10.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:233aed0659a2503b831d8a67e9da66a62c996204c0bba4f4c442ccc0c68a3f60", size = 146018567, upload-time = "2026-01-21T16:22:23.393Z" }, - { url = "https://files.pythonhosted.org/packages/5e/cd/4b95ef7f293b927c283db0b136c42be91c8ec6845c44de0238c8c23bdc80/torch-2.10.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:682497e16bdfa6efeec8cde66531bc8d1fbbbb4d8788ec6173c089ed3cc2bfe5", size = 915721646, upload-time = "2026-01-21T16:21:16.983Z" }, - { url = "https://files.pythonhosted.org/packages/56/97/078a007208f8056d88ae43198833469e61a0a355abc0b070edd2c085eb9a/torch-2.10.0-cp314-cp314-win_amd64.whl", hash = "sha256:6528f13d2a8593a1a412ea07a99812495bec07e9224c28b2a25c0a30c7da025c", size = 113752373, upload-time = "2026-01-21T16:22:13.471Z" }, - { url = "https://files.pythonhosted.org/packages/d8/94/71994e7d0d5238393df9732fdab607e37e2b56d26a746cb59fdb415f8966/torch-2.10.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:f5ab4ba32383061be0fb74bda772d470140a12c1c3b58a0cfbf3dae94d164c28", size = 79850324, upload-time = "2026-01-21T16:22:09.494Z" }, - { url = "https://files.pythonhosted.org/packages/e2/65/1a05346b418ea8ccd10360eef4b3e0ce688fba544e76edec26913a8d0ee0/torch-2.10.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:716b01a176c2a5659c98f6b01bf868244abdd896526f1c692712ab36dbaf9b63", size = 146006482, upload-time = "2026-01-21T16:22:18.42Z" }, - { url = "https://files.pythonhosted.org/packages/1d/b9/5f6f9d9e859fc3235f60578fa64f52c9c6e9b4327f0fe0defb6de5c0de31/torch-2.10.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:d8f5912ba938233f86361e891789595ff35ca4b4e2ac8fe3670895e5976731d6", size = 915613050, upload-time = "2026-01-21T16:20:49.035Z" }, - { url = "https://files.pythonhosted.org/packages/66/4d/35352043ee0eaffdeff154fad67cd4a31dbed7ff8e3be1cc4549717d6d51/torch-2.10.0-cp314-cp314t-win_amd64.whl", hash = "sha256:71283a373f0ee2c89e0f0d5f446039bdabe8dbc3c9ccf35f0f784908b0acd185", size = 113995816, upload-time = "2026-01-21T16:22:05.312Z" }, -] - -[[package]] -name = "tornado" -version = "6.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/1d/0a336abf618272d53f62ebe274f712e213f5a03c0b2339575430b8362ef2/tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7", size = 513632, upload-time = "2025-12-15T19:21:03.836Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9", size = 443909, upload-time = "2025-12-15T19:20:48.382Z" }, - { url = "https://files.pythonhosted.org/packages/db/7e/f7b8d8c4453f305a51f80dbb49014257bb7d28ccb4bbb8dd328ea995ecad/tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843", size = 442163, upload-time = "2025-12-15T19:20:49.791Z" }, - { url = "https://files.pythonhosted.org/packages/ba/b5/206f82d51e1bfa940ba366a8d2f83904b15942c45a78dd978b599870ab44/tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17", size = 445746, upload-time = "2025-12-15T19:20:51.491Z" }, - { url = "https://files.pythonhosted.org/packages/8e/9d/1a3338e0bd30ada6ad4356c13a0a6c35fbc859063fa7eddb309183364ac1/tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335", size = 445083, upload-time = "2025-12-15T19:20:52.778Z" }, - { url = "https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f", size = 445315, upload-time = "2025-12-15T19:20:53.996Z" }, - { url = "https://files.pythonhosted.org/packages/27/07/2273972f69ca63dbc139694a3fc4684edec3ea3f9efabf77ed32483b875c/tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84", size = 446003, upload-time = "2025-12-15T19:20:56.101Z" }, - { url = "https://files.pythonhosted.org/packages/d1/83/41c52e47502bf7260044413b6770d1a48dda2f0246f95ee1384a3cd9c44a/tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f", size = 445412, upload-time = "2025-12-15T19:20:57.398Z" }, - { url = "https://files.pythonhosted.org/packages/10/c7/bc96917f06cbee182d44735d4ecde9c432e25b84f4c2086143013e7b9e52/tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8", size = 445392, upload-time = "2025-12-15T19:20:58.692Z" }, - { url = "https://files.pythonhosted.org/packages/0c/1a/d7592328d037d36f2d2462f4bc1fbb383eec9278bc786c1b111cbbd44cfa/tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1", size = 446481, upload-time = "2025-12-15T19:21:00.008Z" }, - { url = "https://files.pythonhosted.org/packages/d6/6d/c69be695a0a64fd37a97db12355a035a6d90f79067a3cf936ec2b1dc38cd/tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc", size = 446886, upload-time = "2025-12-15T19:21:01.287Z" }, - { url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910, upload-time = "2025-12-15T19:21:02.571Z" }, + { url = "https://files.pythonhosted.org/packages/69/72/20cb30f3b39a9face296491a86adb6ff8f1a47a897e4d14667e6cf89d5c3/torch-2.5.1-cp313-cp313-manylinux1_x86_64.whl", hash = "sha256:9b61edf3b4f6e3b0e0adda8b3960266b9009d02b37555971f4d1c8f7a05afed7", size = 906393265, upload-time = "2024-10-29T17:35:06.866Z" }, ] [[package]] @@ -2572,15 +2177,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, ] -[[package]] -name = "traitlets" -version = "5.14.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, -] - [[package]] name = "transformers" version = "4.57.6" @@ -2602,17 +2198,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/03/b8/e484ef633af3887baeeb4b6ad12743363af7cce68ae51e938e00aaa0529d/transformers-4.57.6-py3-none-any.whl", hash = "sha256:4c9e9de11333ddfe5114bc872c9f370509198acf0b87a832a0ab9458e2bd0550", size = 11993498, upload-time = "2026-01-16T10:38:31.289Z" }, ] -[[package]] -name = "triton" -version = "3.6.0" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/0b/37d991d8c130ce81a8728ae3c25b6e60935838e9be1b58791f5997b24a54/triton-3.6.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10c7f76c6e72d2ef08df639e3d0d30729112f47a56b0c81672edc05ee5116ac9", size = 188289450, upload-time = "2026-01-20T16:00:49.136Z" }, - { url = "https://files.pythonhosted.org/packages/35/f8/9c66bfc55361ec6d0e4040a0337fb5924ceb23de4648b8a81ae9d33b2b38/triton-3.6.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d002e07d7180fd65e622134fbd980c9a3d4211fb85224b56a0a0efbd422ab72f", size = 188400296, upload-time = "2026-01-20T16:00:56.042Z" }, - { url = "https://files.pythonhosted.org/packages/df/3d/9e7eee57b37c80cec63322c0231bb6da3cfe535a91d7a4d64896fcb89357/triton-3.6.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a17a5d5985f0ac494ed8a8e54568f092f7057ef60e1b0fa09d3fd1512064e803", size = 188273063, upload-time = "2026-01-20T16:01:07.278Z" }, - { url = "https://files.pythonhosted.org/packages/f6/56/6113c23ff46c00aae423333eb58b3e60bdfe9179d542781955a5e1514cb3/triton-3.6.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:46bd1c1af4b6704e554cad2eeb3b0a6513a980d470ccfa63189737340c7746a7", size = 188397994, upload-time = "2026-01-20T16:01:14.236Z" }, -] - [[package]] name = "typing-extensions" version = "4.15.0" @@ -2687,15 +2272,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee", size = 68502, upload-time = "2025-12-21T14:16:21.041Z" }, ] -[[package]] -name = "wcwidth" -version = "0.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/38/75/2144b65e4fba12a2d9868e9a3f99db7fa0760670d064603634bef9ff1709/wcwidth-0.3.0.tar.gz", hash = "sha256:af1a2fb0b83ef4a7fc0682a4c95ca2576e14d0280bca2a9e67b7dc9f2733e123", size = 172238, upload-time = "2026-01-21T17:44:09.508Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/0e/a5f0257ab47492b7afb5fb60347d14ba19445e2773fc8352d4be6bd2f6f8/wcwidth-0.3.0-py3-none-any.whl", hash = "sha256:073a1acb250e4add96cfd5ef84e0036605cd6e0d0782c8c15c80e42202348458", size = 85520, upload-time = "2026-01-21T17:44:08.002Z" }, -] - [[package]] name = "xlsxwriter" version = "3.2.9" From 838e47ff8455ed3c19a0e9d9e93225477649f92a Mon Sep 17 00:00:00 2001 From: AF_Askar <68832286+abo3skr2019@users.noreply.github.com> Date: Thu, 5 Feb 2026 15:57:28 +0300 Subject: [PATCH 21/21] publish --- .github/workflows/publish.yml | 76 +++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..851a84e --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,76 @@ +name: Build and Push Docker Images + +on: + push: + branches: + - main + - dev + tags: + - 'v*' + pull_request: + branches: + - main + - dev + workflow_dispatch: + +env: + REGISTRY: docker.io + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + strategy: + matrix: + include: + - dockerfile: ai.dockerfile + image: governance-agent-ai_service + context: . + - dockerfile: next.dockerfile + image: governance-agent-frontend + context: . + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Extract metadata (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ secrets.DOCKERHUB_USERNAME }}/${{ matrix.image }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=sha,prefix={{branch}}- + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: ${{ matrix.context }} + file: ${{ matrix.dockerfile }} + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + platforms: linux/amd64 + + - name: Image digest + run: echo "Image pushed with digest ${{ steps.build.outputs.digest }}"