From c9f5e39f42e65cd705df21c8e1671cb8c8b8134f Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Sun, 5 Oct 2025 17:57:14 -0600 Subject: [PATCH 01/45] commits --- apps/web/package.json | 3 + apps/web/src/components/ui/separator.tsx | 26 + .../lib/{functions/api.ts => api-client.ts} | 2 +- apps/web/src/lib/auth-client.ts | 7 +- apps/web/src/lib/functions/auth.ts | 13 + apps/web/src/lib/queries.ts | 2 +- apps/web/src/main.tsx | 12 +- apps/web/src/providers.tsx | 27 + apps/web/src/routeTree.gen.ts | 263 +- apps/web/src/router.tsx | 5 +- apps/web/src/routes/__root.tsx | 22 +- apps/web/src/routes/index.tsx | 55 +- apps/web/src/routes/profile/index.tsx | 9 + apps/web/src/routes/sign-in/index.tsx | 31 + apps/web/src/routes/sign-up/index.tsx | 30 + apps/web/src/routes/team/$teamId.tsx | 11 - apps/web/src/routes/team/$teamId/index.tsx | 11 + apps/web/src/routes/team/$teamId/join.tsx | 17 + apps/web/src/routes/team/index.tsx | 5 + apps/web/src/styles.css | 1 + packages/db/drizzle.config.ts | 1 - packages/db/package.json | 3 +- packages/db/schema.ts | 7 +- packages/shared/constants.ts | 4 + packages/shared/zod.ts | 6 + pnpm-lock.yaml | 2307 ++++++++++++++--- 26 files changed, 2456 insertions(+), 424 deletions(-) create mode 100644 apps/web/src/components/ui/separator.tsx rename apps/web/src/lib/{functions/api.ts => api-client.ts} (87%) create mode 100644 apps/web/src/providers.tsx create mode 100644 apps/web/src/routes/profile/index.tsx create mode 100644 apps/web/src/routes/sign-in/index.tsx create mode 100644 apps/web/src/routes/sign-up/index.tsx delete mode 100644 apps/web/src/routes/team/$teamId.tsx create mode 100644 apps/web/src/routes/team/$teamId/index.tsx create mode 100644 apps/web/src/routes/team/$teamId/join.tsx diff --git a/apps/web/package.json b/apps/web/package.json index 30c83de..1b128c0 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -10,6 +10,9 @@ "test": "vitest run" }, "dependencies": { + "@daveyplate/better-auth-tanstack": "^1.3.6", + "@daveyplate/better-auth-ui": "^3.1.10", + "@radix-ui/react-separator": "^1.1.7", "@radix-ui/react-slot": "^1.2.3", "@tailwindcss/vite": "^4.1.11", "@tanstack/react-query": "^5.87.4", diff --git a/apps/web/src/components/ui/separator.tsx b/apps/web/src/components/ui/separator.tsx new file mode 100644 index 0000000..bb3ad74 --- /dev/null +++ b/apps/web/src/components/ui/separator.tsx @@ -0,0 +1,26 @@ +import * as React from "react" +import * as SeparatorPrimitive from "@radix-ui/react-separator" + +import { cn } from "@/lib/utils" + +function Separator({ + className, + orientation = "horizontal", + decorative = true, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Separator } diff --git a/apps/web/src/lib/functions/api.ts b/apps/web/src/lib/api-client.ts similarity index 87% rename from apps/web/src/lib/functions/api.ts rename to apps/web/src/lib/api-client.ts index 908a00f..3c8aa56 100644 --- a/apps/web/src/lib/functions/api.ts +++ b/apps/web/src/lib/api-client.ts @@ -1,7 +1,7 @@ import type { ApiType } from "api"; -// import {env} from "../../env" import { hc } from "hono/client"; + export const apiClient = hc( import.meta.env.VITE_FALLBACK_API_URL || "http://localhost:8787", { diff --git a/apps/web/src/lib/auth-client.ts b/apps/web/src/lib/auth-client.ts index cd2771a..c78c3f2 100644 --- a/apps/web/src/lib/auth-client.ts +++ b/apps/web/src/lib/auth-client.ts @@ -1,6 +1,9 @@ import { createAuthClient } from "better-auth/react"; -// import {env} from "../env" +console.log( + "api url for better auth client", + import.meta.env.VITE_FALLBACK_API_URL, +); export const authClient = createAuthClient({ - baseURL: import.meta.env.FALLBACK_PUBLIC_API_URL, + baseURL: import.meta.env.VITE_FALLBACK_API_URL, }); diff --git a/apps/web/src/lib/functions/auth.ts b/apps/web/src/lib/functions/auth.ts index a25f51d..5bce68e 100644 --- a/apps/web/src/lib/functions/auth.ts +++ b/apps/web/src/lib/functions/auth.ts @@ -6,6 +6,7 @@ import { getFirstName, getRandomSignUpGreeting, } from "../utils"; +import { PUBLIC_ROUTES } from "shared/constants"; const callbackURL = "/dashboard"; // A URL to redirect to after the user verifies their email (optional) @@ -83,6 +84,18 @@ export async function signInOauth(provider: string, redirectUrl?: string) { ); } +export function isPublicRoute(pathname:string){ + return PUBLIC_ROUTES.includes(pathname); +} + +export function isProtectedRoute(pathname:string){ + return !isPublicRoute(pathname); +} + +export async function getSession(){ + return authClient.getSession(); +} + export async function signOut() { const { data, error } = await authClient.signOut(); return { data, error }; diff --git a/apps/web/src/lib/queries.ts b/apps/web/src/lib/queries.ts index 5375bc5..6f473c9 100644 --- a/apps/web/src/lib/queries.ts +++ b/apps/web/src/lib/queries.ts @@ -1,5 +1,5 @@ import { queryOptions } from "@tanstack/react-query"; -import { apiClient } from "./functions/api"; +import { apiClient } from "./api-client"; export const pingServerQuery = queryOptions({ queryKey: ["ping"], diff --git a/apps/web/src/main.tsx b/apps/web/src/main.tsx index a8f4189..852570e 100644 --- a/apps/web/src/main.tsx +++ b/apps/web/src/main.tsx @@ -5,6 +5,8 @@ import { Toaster } from "./components/ui/sonner.tsx"; import "./styles.css"; import reportWebVitals from "./reportWebVitals.ts"; import { createAppRouter } from "./router.tsx"; +import { Providers } from "./providers.tsx"; + // Create a new router instance const router = createAppRouter(); @@ -21,10 +23,12 @@ const rootElement = document.getElementById("app"); if (rootElement && !rootElement.innerHTML) { const root = ReactDOM.createRoot(rootElement); root.render( - - - - , + + + + + + , ); } diff --git a/apps/web/src/providers.tsx b/apps/web/src/providers.tsx new file mode 100644 index 0000000..946f9df --- /dev/null +++ b/apps/web/src/providers.tsx @@ -0,0 +1,27 @@ +import { AuthUIProviderTanstack } from "@daveyplate/better-auth-ui/tanstack"; +import { AuthQueryProvider } from "@daveyplate/better-auth-tanstack"; +import { authClient } from "@/lib/auth-client"; +import { Link, useRouter } from "@tanstack/react-router"; +import { QueryClientProvider } from "@tanstack/react-query"; +import { queryClient } from "./router"; + +export function Providers({ children }: { children: React.ReactNode }) { + const router = useRouter(); + + return ( + + + router.navigate({ href })} + replace={(href) => router.navigate({ href, replace: true })} + Link={({ href, ...props }) => } + persistClient={false} + basePath="/" + > + {children} + + + + ); +} diff --git a/apps/web/src/routeTree.gen.ts b/apps/web/src/routeTree.gen.ts index daae5fc..50bae10 100644 --- a/apps/web/src/routeTree.gen.ts +++ b/apps/web/src/routeTree.gen.ts @@ -8,106 +8,203 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. -import { Route as rootRouteImport } from "./routes/__root"; -import { Route as IndexRouteImport } from "./routes/index"; -import { Route as TeamIndexRouteImport } from "./routes/team/index"; -import { Route as TeamNewRouteImport } from "./routes/team/new"; -import { Route as TeamTeamIdRouteImport } from "./routes/team/$teamId"; +import { Route as rootRouteImport } from './routes/__root' +import { Route as IndexRouteImport } from './routes/index' +import { Route as TeamIndexRouteImport } from './routes/team/index' +import { Route as SignUpIndexRouteImport } from './routes/sign-up/index' +import { Route as SignInIndexRouteImport } from './routes/sign-in/index' +import { Route as ProfileIndexRouteImport } from './routes/profile/index' +import { Route as TeamNewRouteImport } from './routes/team/new' +import { Route as TeamTeamIdIndexRouteImport } from './routes/team/$teamId/index' +import { Route as TeamTeamIdJoinRouteImport } from './routes/team/$teamId/join' const IndexRoute = IndexRouteImport.update({ - id: "/", - path: "/", - getParentRoute: () => rootRouteImport, -} as any); + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) const TeamIndexRoute = TeamIndexRouteImport.update({ - id: "/team/", - path: "/team/", - getParentRoute: () => rootRouteImport, -} as any); + id: '/team/', + path: '/team/', + getParentRoute: () => rootRouteImport, +} as any) +const SignUpIndexRoute = SignUpIndexRouteImport.update({ + id: '/sign-up/', + path: '/sign-up/', + getParentRoute: () => rootRouteImport, +} as any) +const SignInIndexRoute = SignInIndexRouteImport.update({ + id: '/sign-in/', + path: '/sign-in/', + getParentRoute: () => rootRouteImport, +} as any) +const ProfileIndexRoute = ProfileIndexRouteImport.update({ + id: '/profile/', + path: '/profile/', + getParentRoute: () => rootRouteImport, +} as any) const TeamNewRoute = TeamNewRouteImport.update({ - id: "/team/new", - path: "/team/new", - getParentRoute: () => rootRouteImport, -} as any); -const TeamTeamIdRoute = TeamTeamIdRouteImport.update({ - id: "/team/$teamId", - path: "/team/$teamId", - getParentRoute: () => rootRouteImport, -} as any); + id: '/team/new', + path: '/team/new', + getParentRoute: () => rootRouteImport, +} as any) +const TeamTeamIdIndexRoute = TeamTeamIdIndexRouteImport.update({ + id: '/team/$teamId/', + path: '/team/$teamId/', + getParentRoute: () => rootRouteImport, +} as any) +const TeamTeamIdJoinRoute = TeamTeamIdJoinRouteImport.update({ + id: '/team/$teamId/join', + path: '/team/$teamId/join', + getParentRoute: () => rootRouteImport, +} as any) export interface FileRoutesByFullPath { - "/": typeof IndexRoute; - "/team/$teamId": typeof TeamTeamIdRoute; - "/team/new": typeof TeamNewRoute; - "/team": typeof TeamIndexRoute; + '/': typeof IndexRoute + '/team/new': typeof TeamNewRoute + '/profile': typeof ProfileIndexRoute + '/sign-in': typeof SignInIndexRoute + '/sign-up': typeof SignUpIndexRoute + '/team': typeof TeamIndexRoute + '/team/$teamId/join': typeof TeamTeamIdJoinRoute + '/team/$teamId': typeof TeamTeamIdIndexRoute } export interface FileRoutesByTo { - "/": typeof IndexRoute; - "/team/$teamId": typeof TeamTeamIdRoute; - "/team/new": typeof TeamNewRoute; - "/team": typeof TeamIndexRoute; + '/': typeof IndexRoute + '/team/new': typeof TeamNewRoute + '/profile': typeof ProfileIndexRoute + '/sign-in': typeof SignInIndexRoute + '/sign-up': typeof SignUpIndexRoute + '/team': typeof TeamIndexRoute + '/team/$teamId/join': typeof TeamTeamIdJoinRoute + '/team/$teamId': typeof TeamTeamIdIndexRoute } export interface FileRoutesById { - __root__: typeof rootRouteImport; - "/": typeof IndexRoute; - "/team/$teamId": typeof TeamTeamIdRoute; - "/team/new": typeof TeamNewRoute; - "/team/": typeof TeamIndexRoute; + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/team/new': typeof TeamNewRoute + '/profile/': typeof ProfileIndexRoute + '/sign-in/': typeof SignInIndexRoute + '/sign-up/': typeof SignUpIndexRoute + '/team/': typeof TeamIndexRoute + '/team/$teamId/join': typeof TeamTeamIdJoinRoute + '/team/$teamId/': typeof TeamTeamIdIndexRoute } export interface FileRouteTypes { - fileRoutesByFullPath: FileRoutesByFullPath; - fullPaths: "/" | "/team/$teamId" | "/team/new" | "/team"; - fileRoutesByTo: FileRoutesByTo; - to: "/" | "/team/$teamId" | "/team/new" | "/team"; - id: "__root__" | "/" | "/team/$teamId" | "/team/new" | "/team/"; - fileRoutesById: FileRoutesById; + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: + | '/' + | '/team/new' + | '/profile' + | '/sign-in' + | '/sign-up' + | '/team' + | '/team/$teamId/join' + | '/team/$teamId' + fileRoutesByTo: FileRoutesByTo + to: + | '/' + | '/team/new' + | '/profile' + | '/sign-in' + | '/sign-up' + | '/team' + | '/team/$teamId/join' + | '/team/$teamId' + id: + | '__root__' + | '/' + | '/team/new' + | '/profile/' + | '/sign-in/' + | '/sign-up/' + | '/team/' + | '/team/$teamId/join' + | '/team/$teamId/' + fileRoutesById: FileRoutesById } export interface RootRouteChildren { - IndexRoute: typeof IndexRoute; - TeamTeamIdRoute: typeof TeamTeamIdRoute; - TeamNewRoute: typeof TeamNewRoute; - TeamIndexRoute: typeof TeamIndexRoute; + IndexRoute: typeof IndexRoute + TeamNewRoute: typeof TeamNewRoute + ProfileIndexRoute: typeof ProfileIndexRoute + SignInIndexRoute: typeof SignInIndexRoute + SignUpIndexRoute: typeof SignUpIndexRoute + TeamIndexRoute: typeof TeamIndexRoute + TeamTeamIdJoinRoute: typeof TeamTeamIdJoinRoute + TeamTeamIdIndexRoute: typeof TeamTeamIdIndexRoute } -declare module "@tanstack/react-router" { - interface FileRoutesByPath { - "/": { - id: "/"; - path: "/"; - fullPath: "/"; - preLoaderRoute: typeof IndexRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/team/": { - id: "/team/"; - path: "/team"; - fullPath: "/team"; - preLoaderRoute: typeof TeamIndexRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/team/new": { - id: "/team/new"; - path: "/team/new"; - fullPath: "/team/new"; - preLoaderRoute: typeof TeamNewRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/team/$teamId": { - id: "/team/$teamId"; - path: "/team/$teamId"; - fullPath: "/team/$teamId"; - preLoaderRoute: typeof TeamTeamIdRouteImport; - parentRoute: typeof rootRouteImport; - }; - } +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + '/team/': { + id: '/team/' + path: '/team' + fullPath: '/team' + preLoaderRoute: typeof TeamIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/sign-up/': { + id: '/sign-up/' + path: '/sign-up' + fullPath: '/sign-up' + preLoaderRoute: typeof SignUpIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/sign-in/': { + id: '/sign-in/' + path: '/sign-in' + fullPath: '/sign-in' + preLoaderRoute: typeof SignInIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/profile/': { + id: '/profile/' + path: '/profile' + fullPath: '/profile' + preLoaderRoute: typeof ProfileIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/team/new': { + id: '/team/new' + path: '/team/new' + fullPath: '/team/new' + preLoaderRoute: typeof TeamNewRouteImport + parentRoute: typeof rootRouteImport + } + '/team/$teamId/': { + id: '/team/$teamId/' + path: '/team/$teamId' + fullPath: '/team/$teamId' + preLoaderRoute: typeof TeamTeamIdIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/team/$teamId/join': { + id: '/team/$teamId/join' + path: '/team/$teamId/join' + fullPath: '/team/$teamId/join' + preLoaderRoute: typeof TeamTeamIdJoinRouteImport + parentRoute: typeof rootRouteImport + } + } } const rootRouteChildren: RootRouteChildren = { - IndexRoute: IndexRoute, - TeamTeamIdRoute: TeamTeamIdRoute, - TeamNewRoute: TeamNewRoute, - TeamIndexRoute: TeamIndexRoute, -}; + IndexRoute: IndexRoute, + TeamNewRoute: TeamNewRoute, + ProfileIndexRoute: ProfileIndexRoute, + SignInIndexRoute: SignInIndexRoute, + SignUpIndexRoute: SignUpIndexRoute, + TeamIndexRoute: TeamIndexRoute, + TeamTeamIdJoinRoute: TeamTeamIdJoinRoute, + TeamTeamIdIndexRoute: TeamTeamIdIndexRoute, +} export const routeTree = rootRouteImport - ._addFileChildren(rootRouteChildren) - ._addFileTypes(); + ._addFileChildren(rootRouteChildren) + ._addFileTypes() diff --git a/apps/web/src/router.tsx b/apps/web/src/router.tsx index 26772ab..24aa502 100644 --- a/apps/web/src/router.tsx +++ b/apps/web/src/router.tsx @@ -4,9 +4,10 @@ import { createRouter } from "@tanstack/react-router"; import { setupRouterSsrQueryIntegration } from "@tanstack/react-router-ssr-query"; import { routeTree } from "./routeTree.gen"; +// Create a new query client instance +export const queryClient = new QueryClient(); + export function createAppRouter() { - // Create a new query client instance - const queryClient = new QueryClient(); const router = createRouter({ routeTree, diff --git a/apps/web/src/routes/__root.tsx b/apps/web/src/routes/__root.tsx index fd1e4aa..8265764 100644 --- a/apps/web/src/routes/__root.tsx +++ b/apps/web/src/routes/__root.tsx @@ -1,16 +1,36 @@ import type { QueryClient } from "@tanstack/react-query"; import { Outlet, createRootRouteWithContext } from "@tanstack/react-router"; import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; +import { getSession } from "@/lib/functions/auth"; +import { redirect } from "@tanstack/react-router"; +import { isProtectedRoute } from "@/lib/functions/auth"; type RouterContext = { queryClient: QueryClient; }; export const Route = createRootRouteWithContext()({ + + beforeLoad: async({location}) =>{ + if (isProtectedRoute(location.pathname)) { + const auth = await getSession(); + + if (!auth.data){ + throw redirect({ + to:"/sign-in", + // Used to power a redirect after successful login + search:{ + redirect:location.href + } + }) + } + } + }, + component: () => ( <> ), -}); +}) diff --git a/apps/web/src/routes/index.tsx b/apps/web/src/routes/index.tsx index a129d24..866d39f 100644 --- a/apps/web/src/routes/index.tsx +++ b/apps/web/src/routes/index.tsx @@ -4,6 +4,7 @@ import { Button } from "@/components/ui/button"; import { toast } from "sonner"; import { pingServerQuery } from "@/lib/queries"; import { useQuery } from "@tanstack/react-query"; +import { SignedIn, SignedOut, UserButton } from "@daveyplate/better-auth-ui"; export const Route = createFileRoute("/")({ loader: ({ context: { queryClient } }) => @@ -12,29 +13,39 @@ export const Route = createFileRoute("/")({ }); function App() { - console.log("App rendered"); - console.log(import.meta.env); const { data, refetch } = useQuery(pingServerQuery); return ( -
-

Connection Status: {data || "Not Connected"}

-

Welcome to {APP_NAME}!

-

- This is a simple app using create-tsrouter-app. -

- -
+ <> + +
+

Connection Status: {data || "Not Connected"}

+

+ Welcome to {APP_NAME}! +

+

+ This is a simple app using{" "} + create-tsrouter-app. +

+ + +
+
+ + + + + ); } diff --git a/apps/web/src/routes/profile/index.tsx b/apps/web/src/routes/profile/index.tsx new file mode 100644 index 0000000..bc3d6d8 --- /dev/null +++ b/apps/web/src/routes/profile/index.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/profile/')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/profile/"!
+} diff --git a/apps/web/src/routes/sign-in/index.tsx b/apps/web/src/routes/sign-in/index.tsx new file mode 100644 index 0000000..d04ce67 --- /dev/null +++ b/apps/web/src/routes/sign-in/index.tsx @@ -0,0 +1,31 @@ +import { createFileRoute } from '@tanstack/react-router' +import { AuthView } from '@daveyplate/better-auth-ui' +import {redirect} from "@tanstack/react-router" +import { APP_NAME } from 'shared/constants'; +import { getSession } from '@/lib/functions/auth'; + + +export const Route = createFileRoute('/sign-in/')({ + component: RouteComponent, + loader: async () => getSession() +}) + +function RouteComponent() { + const authData = Route.useLoaderData() + if (authData.data){ + return redirect({ + to:"/", + }) + } + return ( +
+
+

Welcome back 👋

+

Sign back into {APP_NAME} to pick up where you left off

+
+
+ +
+
+ ); +} diff --git a/apps/web/src/routes/sign-up/index.tsx b/apps/web/src/routes/sign-up/index.tsx new file mode 100644 index 0000000..ccd4d9f --- /dev/null +++ b/apps/web/src/routes/sign-up/index.tsx @@ -0,0 +1,30 @@ +import { createFileRoute } from '@tanstack/react-router' +import { AuthView } from '@daveyplate/better-auth-ui' +import { authClient } from "@/lib/auth-client"; +import { redirect } from "@tanstack/react-router"; +import { APP_NAME } from "shared/constants"; + +export const Route = createFileRoute("/sign-up/")({ + component: RouteComponent, + loader: async () => authClient.getSession(), +}); + +function RouteComponent() { + const authData = Route.useLoaderData() + if (authData.data){ + return redirect({ + to:"/profile", + }) + } + return ( +
+
+

Welcome to {APP_NAME} 👋

+

Take a quick second to sign up and you'll be on your way to the most seamless baclup experience

+
+
+ +
+
+ ); +} diff --git a/apps/web/src/routes/team/$teamId.tsx b/apps/web/src/routes/team/$teamId.tsx deleted file mode 100644 index b0e7470..0000000 --- a/apps/web/src/routes/team/$teamId.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { createFileRoute } from "@tanstack/react-router"; - -export const Route = createFileRoute("/team/$teamId")({ - component: RouteComponent, -}); - -function RouteComponent() { - const { teamId } = Route.useParams(); - - return
Slug is {teamId}
; -} diff --git a/apps/web/src/routes/team/$teamId/index.tsx b/apps/web/src/routes/team/$teamId/index.tsx new file mode 100644 index 0000000..a0f4328 --- /dev/null +++ b/apps/web/src/routes/team/$teamId/index.tsx @@ -0,0 +1,11 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/team/$teamId/')({ + component: RouteComponent, +}) + +function RouteComponent() { + const { teamId } = Route.useParams(); + + return
Slug is {teamId}
; +} diff --git a/apps/web/src/routes/team/$teamId/join.tsx b/apps/web/src/routes/team/$teamId/join.tsx new file mode 100644 index 0000000..396c9a9 --- /dev/null +++ b/apps/web/src/routes/team/$teamId/join.tsx @@ -0,0 +1,17 @@ +import { createFileRoute } from '@tanstack/react-router' +import { joinTeamSchema } from "shared/zod"; + + +export const Route = createFileRoute('/team/$teamId/join')({ + component: RouteComponent, + validateSearch:(searchParams)=>joinTeamSchema.parse(searchParams) +}) + +function RouteComponent() { + const {inv} = Route.useSearch(); + if (!inv){ + // We would want to render a card that accepts a code if it is blank + + } + return
Hello "/team/$teamId/join"! Invite code is {inv}
+} diff --git a/apps/web/src/routes/team/index.tsx b/apps/web/src/routes/team/index.tsx index 4da561f..5e7d058 100644 --- a/apps/web/src/routes/team/index.tsx +++ b/apps/web/src/routes/team/index.tsx @@ -1,5 +1,10 @@ import { createFileRoute } from "@tanstack/react-router"; +/* +* Team index route +* This route will display the teams you are a part of and manage +* NOTE: Not too sure this is needed +*/ export const Route = createFileRoute("/team/")({ component: RouteComponent, }); diff --git a/apps/web/src/styles.css b/apps/web/src/styles.css index 603a4c2..2c659af 100644 --- a/apps/web/src/styles.css +++ b/apps/web/src/styles.css @@ -1,5 +1,6 @@ @import "tailwindcss"; @import "tw-animate-css"; +@import "@daveyplate/better-auth-ui/css"; @custom-variant dark (&:is(.dark *)); diff --git a/packages/db/drizzle.config.ts b/packages/db/drizzle.config.ts index 7079a90..95ae77e 100644 --- a/packages/db/drizzle.config.ts +++ b/packages/db/drizzle.config.ts @@ -1,6 +1,5 @@ import { defineConfig } from "drizzle-kit"; import dotenv from "dotenv"; -import path from "path"; dotenv.config({ path: "../../.env", diff --git a/packages/db/package.json b/packages/db/package.json index caff56e..6d8921e 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -18,7 +18,8 @@ "drizzle-orm": "^0.44.4", "drizzle-zod": "^0.8.2", "nanoid": "^5.1.5", - "zod": "^3.25.67" + "zod": "^3.25.67", + "shared":"workspace:*" }, "devDependencies": { "@types/node": "20.14.11", diff --git a/packages/db/schema.ts b/packages/db/schema.ts index 8b2502c..64d7880 100644 --- a/packages/db/schema.ts +++ b/packages/db/schema.ts @@ -4,12 +4,9 @@ import { text, sqliteTable, primaryKey, - integer, - text, - sqliteTable, - primaryKey, } from "drizzle-orm/sqlite-core"; import { nanoid } from "nanoid"; +import {STANDARD_NANOID_SIZE} from "shared/constants"; const STANDARD_VARCHAR_LENGTH = 255; @@ -28,7 +25,7 @@ function standardDateFactory() { function standardIdFactory(prefix?: string) { return text("id") .notNull() - .$defaultFn(() => `${prefix ?? ""}${nanoid()}`); + .$defaultFn(() => `${prefix ?? ""}${nanoid(STANDARD_NANOID_SIZE)}`); } const logType = text({ enum: ["INFO", "WARNING", "ERROR"] }); diff --git a/packages/shared/constants.ts b/packages/shared/constants.ts index af96feb..56910c2 100644 --- a/packages/shared/constants.ts +++ b/packages/shared/constants.ts @@ -47,3 +47,7 @@ export const GREETINGS_FUNCTIONS = { (name: string) => `Welcome aboard ${name}!`, ], }; + +export const PUBLIC_ROUTES = ["/","/sign-in", "/sign-up"]; + +export const STANDARD_NANOID_SIZE = 12; \ No newline at end of file diff --git a/packages/shared/zod.ts b/packages/shared/zod.ts index e69de29..0081ff8 100644 --- a/packages/shared/zod.ts +++ b/packages/shared/zod.ts @@ -0,0 +1,6 @@ +import z from "zod" + + +export const joinTeamSchema = z.object({ + inv: z.string().min(1).max(30).catch("") +}) \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index febff32..0ea3515 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -88,6 +88,15 @@ importers: apps/web: dependencies: + '@daveyplate/better-auth-tanstack': + specifier: ^1.3.6 + version: 1.3.6(@tanstack/query-core@5.87.4)(@tanstack/react-query@5.87.4(react@19.1.1))(better-auth@1.3.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@daveyplate/better-auth-ui': + specifier: ^3.1.10 + version: 3.1.10(@daveyplate/better-auth-tanstack@1.3.6(@tanstack/query-core@5.87.4)(@tanstack/react-query@5.87.4(react@19.1.1))(better-auth@1.3.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@hookform/resolvers@5.2.2(react-hook-form@7.63.0(react@19.1.1)))(@instantdb/react@0.21.18(react@19.1.1))(@marsidev/react-turnstile@1.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-avatar@1.1.10(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-context@1.1.2(@types/react@19.1.9)(react@19.1.1))(@radix-ui/react-dialog@1.1.15(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-label@2.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-select@2.2.6(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-separator@1.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-slot@1.2.3(@types/react@19.1.9)(react@19.1.1))(@radix-ui/react-tabs@1.1.13(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.9)(react@19.1.1))(@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.9)(react@19.1.1))(@tanstack/react-query@5.87.4(react@19.1.1))(@triplit/client@1.0.50(typescript@5.8.3))(@triplit/react@1.0.51(react@19.1.1)(typescript@5.8.3))(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(better-auth@1.3.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(class-variance-authority@0.7.1)(clsx@2.1.1)(input-otp@1.4.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(lucide-react@0.539.0(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react-hook-form@7.63.0(react@19.1.1))(react@19.1.1)(sonner@2.0.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(tailwind-merge@3.3.1)(tailwindcss@4.1.11)(zod@3.25.76) + '@radix-ui/react-separator': + specifier: ^1.1.7 + version: 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@radix-ui/react-slot': specifier: ^1.2.3 version: 1.2.3(@types/react@19.1.9)(react@19.1.1) @@ -215,6 +224,9 @@ importers: nanoid: specifier: ^5.1.5 version: 5.1.5 + shared: + specifier: workspace:* + version: link:../shared zod: specifier: ^3.25.67 version: 3.25.76 @@ -671,6 +683,51 @@ packages: resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} + '@daveyplate/better-auth-tanstack@1.3.6': + resolution: {integrity: sha512-GvIGdbjRMZCEfAffU7LeWpGpie4vSli8V9jmNFCQOziZZMEFbO4cd53HBFmAushC9oEYIyhSNZBgV2ADzW94Ww==} + peerDependencies: + '@tanstack/query-core': '>=5.65.0' + '@tanstack/react-query': '>=5.65.0' + better-auth: '>=1.2.8' + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@daveyplate/better-auth-ui@3.1.10': + resolution: {integrity: sha512-DRaGhn1mYNruEvO9ylxy4bzX0vF4hyti3j1k9HhtGFFUPViJ+Mabsd+muNL1gb9AI2T3/M2xt0mCfAxnHST15w==} + peerDependencies: + '@daveyplate/better-auth-tanstack': ^1.3.6 + '@hookform/resolvers': '>=5.2.0' + '@instantdb/react': '>=0.18.0' + '@marsidev/react-turnstile': '>=1.1.0' + '@radix-ui/react-avatar': '>=1.1.0' + '@radix-ui/react-checkbox': '>=1.1.0' + '@radix-ui/react-context': '>=1.1.0' + '@radix-ui/react-dialog': '>=1.1.0' + '@radix-ui/react-dropdown-menu': '>=2.1.0' + '@radix-ui/react-label': '>=2.1.0' + '@radix-ui/react-primitive': '>=2.0.0' + '@radix-ui/react-select': '>=2.2.0' + '@radix-ui/react-separator': '>=1.1.0' + '@radix-ui/react-slot': '>=1.1.0' + '@radix-ui/react-tabs': '>=1.1.0' + '@radix-ui/react-use-callback-ref': '>=1.1.0' + '@radix-ui/react-use-layout-effect': '>=1.1.0' + '@tanstack/react-query': '>=5.66.0' + '@triplit/client': '>=1.0.0' + '@triplit/react': '>=1.0.0' + better-auth: ^1.3.4 + class-variance-authority: '>=0.7.0' + clsx: '>=2.1.0' + input-otp: '>=1.4.0' + lucide-react: '>=0.469.0' + react: '>=18.0.0' + react-dom: '>=18.0.0' + react-hook-form: '>=7.55.0' + sonner: '>=1.7.0' + tailwind-merge: '>=2.6.0' + tailwindcss: '>=3.0.0' + zod: '>=3.0.0' + '@drizzle-team/brocli@0.10.2': resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} @@ -967,6 +1024,30 @@ packages: cpu: [x64] os: [win32] + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@hcaptcha/loader@2.1.0': + resolution: {integrity: sha512-9HagrYGQmHD4zvZ3H5z/2U9MObl/q+ls0SRj/JVzl6L3cNFJp6LsxBL9Sg+8YjRDdtj/e7xWBgHuIgZ9cggY7w==} + + '@hcaptcha/react-hcaptcha@1.12.1': + resolution: {integrity: sha512-/A08MOAHa5L9B8UfNRkTR/+x2dOyfk3pI1/qgXI4NpDl/z4CjnSxaYCDtkbD21vEocN1KKCggQD3wJ7OcY494w==} + peerDependencies: + react: '>= 16.3.0' + react-dom: '>= 16.3.0' + '@hexagon/base64@1.1.28': resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==} @@ -976,6 +1057,11 @@ packages: hono: '>=3.9.0' zod: ^3.25.0 || ^4.0.0 + '@hookform/resolvers@5.2.2': + resolution: {integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==} + peerDependencies: + react-hook-form: ^7.55.0 + '@img/sharp-darwin-arm64@0.33.5': resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -1081,6 +1167,17 @@ packages: cpu: [x64] os: [win32] + '@instantdb/core@0.21.18': + resolution: {integrity: sha512-eURo27ynSrlKu2g4ovVnVEFJvix+epGsbxi7DGatkho3z3PapuhM4LJ2NJupneVgXsMEP/e5nWeN0NFOhXZPCg==} + + '@instantdb/react@0.21.18': + resolution: {integrity: sha512-kuo3yVFI6JKOZ4t1LWQEs5zfpJeYRWKfec8fWJjaBOIouZiQxfxpwOm9JU+tyvu7UBfsGmoatJzFzEe6kdkpxQ==} + peerDependencies: + react: '>=16' + + '@instantdb/version@0.21.18': + resolution: {integrity: sha512-dMGrAwJc22uPg+ZmxSsBMpRN3AYJuWO3ImSnbtqik9VFZ+fteRrlLd/rChpGX4rvNcuFc4ehiLGBHeC/8gaqyw==} + '@isaacs/fs-minipass@4.0.1': resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} @@ -1165,6 +1262,12 @@ packages: cpu: [x64] os: [win32] + '@marsidev/react-turnstile@1.3.1': + resolution: {integrity: sha512-h2THG/75k4Y049hgjSGPIcajxXnh+IZAiXVbryQyVmagkboN7pJtBgR16g8akjwUBSfRrg6jw6KvPDjscQflog==} + peerDependencies: + react: ^17.0.2 || ^18.0.0 || ^19.0 + react-dom: ^17.0.2 || ^18.0.0 || ^19.0 + '@mjackson/node-fetch-server@0.6.1': resolution: {integrity: sha512-9ZJnk/DJjt805uv5PPv11haJIW+HHf3YEEyVXv+8iLQxLD/iXA68FH220XoiTPBC4gCg5q+IMadDw8qPqlA5wg==} @@ -1178,6 +1281,10 @@ packages: resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} + '@noble/hashes@2.0.0': + resolution: {integrity: sha512-h8VUBlE8R42+XIDO229cgisD287im3kdY6nbNZJFjc6ZvKIXPYXe6Vc/t+kyjFdMFyt5JpapzTsEg8n63w5/lw==} + engines: {node: '>= 20.19.0'} + '@peculiar/asn1-android@2.4.0': resolution: {integrity: sha512-YFueREq97CLslZZBI8dKzis7jMfEHSLxM+nr0Zdx1POiXFLjqqwoY5s0F1UimdBiEw/iKlHey2m56MRDv7Jtyg==} @@ -1202,310 +1309,811 @@ packages: '@poppinss/exception@1.2.2': resolution: {integrity: sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg==} - '@radix-ui/react-compose-refs@1.1.2': - resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + '@radix-ui/number@1.1.1': + resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-arrow@1.1.7': + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} peerDependencies: '@types/react': '*' + '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true + '@types/react-dom': + optional: true - '@radix-ui/react-slot@1.2.3': - resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + '@radix-ui/react-avatar@1.1.10': + resolution: {integrity: sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==} 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.27': - resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} - - '@rollup/plugin-replace@6.0.2': - resolution: {integrity: sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ==} - engines: {node: '>=14.0.0'} + '@radix-ui/react-checkbox@1.3.3': + resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==} peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + '@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: - rollup: + '@types/react': + optional: true + '@types/react-dom': optional: true - '@rollup/pluginutils@5.2.0': - resolution: {integrity: sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==} - engines: {node: '>=14.0.0'} + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + '@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: - rollup: + '@types/react': + optional: true + '@types/react-dom': optional: true - '@rollup/rollup-android-arm-eabi@4.46.2': - resolution: {integrity: sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==} - cpu: [arm] - os: [android] + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@rollup/rollup-android-arm64@4.46.2': - resolution: {integrity: sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==} - cpu: [arm64] - os: [android] + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@rollup/rollup-darwin-arm64@4.46.2': - resolution: {integrity: sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==} - cpu: [arm64] - os: [darwin] + '@radix-ui/react-dialog@1.1.15': + resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} + 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 - '@rollup/rollup-darwin-x64@4.46.2': - resolution: {integrity: sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==} - cpu: [x64] - os: [darwin] + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@rollup/rollup-freebsd-arm64@4.46.2': - resolution: {integrity: sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==} - cpu: [arm64] - os: [freebsd] + '@radix-ui/react-dismissable-layer@1.1.11': + resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} + 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 - '@rollup/rollup-freebsd-x64@4.46.2': - resolution: {integrity: sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==} - cpu: [x64] - os: [freebsd] + '@radix-ui/react-dropdown-menu@2.1.16': + resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} + 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 - '@rollup/rollup-linux-arm-gnueabihf@4.46.2': - resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==} - cpu: [arm] - os: [linux] + '@radix-ui/react-focus-guards@1.1.3': + resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@rollup/rollup-linux-arm-musleabihf@4.46.2': - resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==} - cpu: [arm] - os: [linux] + '@radix-ui/react-focus-scope@1.1.7': + resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + 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 - '@rollup/rollup-linux-arm64-gnu@4.46.2': - resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==} - cpu: [arm64] - os: [linux] + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@rollup/rollup-linux-arm64-musl@4.46.2': - resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==} - cpu: [arm64] - os: [linux] + '@radix-ui/react-label@2.1.7': + resolution: {integrity: sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==} + 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 - '@rollup/rollup-linux-loongarch64-gnu@4.46.2': - resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==} - cpu: [loong64] - os: [linux] + '@radix-ui/react-menu@2.1.16': + resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} + 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 - '@rollup/rollup-linux-ppc64-gnu@4.46.2': - resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==} - cpu: [ppc64] - os: [linux] + '@radix-ui/react-popper@1.2.8': + resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} + 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 - '@rollup/rollup-linux-riscv64-gnu@4.46.2': - resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==} - cpu: [riscv64] - os: [linux] + '@radix-ui/react-portal@1.1.9': + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + 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 - '@rollup/rollup-linux-riscv64-musl@4.46.2': - resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==} - cpu: [riscv64] - os: [linux] + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + 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 - '@rollup/rollup-linux-s390x-gnu@4.46.2': - resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==} - cpu: [s390x] - os: [linux] + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + 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 - '@rollup/rollup-linux-x64-gnu@4.46.2': - resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==} - cpu: [x64] - os: [linux] + '@radix-ui/react-roving-focus@1.1.11': + resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} + 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 - '@rollup/rollup-linux-x64-musl@4.46.2': - resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==} - cpu: [x64] - os: [linux] + '@radix-ui/react-select@2.2.6': + resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} + 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 - '@rollup/rollup-win32-arm64-msvc@4.46.2': - resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.46.2': - resolution: {integrity: sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==} - cpu: [ia32] - os: [win32] + '@radix-ui/react-separator@1.1.7': + resolution: {integrity: sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==} + 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 - '@rollup/rollup-win32-x64-msvc@4.46.2': - resolution: {integrity: sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==} - cpu: [x64] - os: [win32] + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@simplewebauthn/browser@13.1.2': - resolution: {integrity: sha512-aZnW0KawAM83fSBUgglP5WofbrLbLyr7CoPqYr66Eppm7zO86YX6rrCjRB3hQKPrL7ATvY4FVXlykZ6w6FwYYw==} + '@radix-ui/react-tabs@1.1.13': + resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} + 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 - '@simplewebauthn/server@13.1.2': - resolution: {integrity: sha512-VwoDfvLXSCaRiD+xCIuyslU0HLxVggeE5BL06+GbsP2l1fGf5op8e0c3ZtKoi+vSg1q4ikjtAghC23ze2Q3H9g==} - engines: {node: '>=20.0.0'} + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@sindresorhus/is@7.0.2': - resolution: {integrity: sha512-d9xRovfKNz1SKieM0qJdO+PQonjnnIfSNWfHYnBSJ9hkjm0ZPw6HlxscDXYstp3z+7V2GOFHc+J0CYrYTjqCJw==} - engines: {node: '>=18'} + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@smithy/abort-controller@4.0.4': - resolution: {integrity: sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==} - engines: {node: '>=18.0.0'} + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@smithy/chunked-blob-reader-native@4.0.0': - resolution: {integrity: sha512-R9wM2yPmfEMsUmlMlIgSzOyICs0x9uu7UTHoccMyt7BWw8shcGM8HqB355+BZCPBcySvbTYMs62EgEQkNxz2ig==} - engines: {node: '>=18.0.0'} + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@smithy/chunked-blob-reader@5.0.0': - resolution: {integrity: sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw==} - engines: {node: '>=18.0.0'} + '@radix-ui/react-use-is-hydrated@0.1.0': + resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@smithy/config-resolver@4.1.4': - resolution: {integrity: sha512-prmU+rDddxHOH0oNcwemL+SwnzcG65sBF2yXRO7aeXIn/xTlq2pX7JLVbkBnVLowHLg4/OL4+jBmv9hVrVGS+w==} - engines: {node: '>=18.0.0'} + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@smithy/core@3.7.2': - resolution: {integrity: sha512-JoLw59sT5Bm8SAjFCYZyuCGxK8y3vovmoVbZWLDPTH5XpPEIwpFd9m90jjVMwoypDuB/SdVgje5Y4T7w50lJaw==} - engines: {node: '>=18.0.0'} + '@radix-ui/react-use-previous@1.1.1': + resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@smithy/credential-provider-imds@4.0.6': - resolution: {integrity: sha512-hKMWcANhUiNbCJouYkZ9V3+/Qf9pteR1dnwgdyzR09R4ODEYx8BbUysHwRSyex4rZ9zapddZhLFTnT4ZijR4pw==} - engines: {node: '>=18.0.0'} + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@smithy/eventstream-codec@4.0.4': - resolution: {integrity: sha512-7XoWfZqWb/QoR/rAU4VSi0mWnO2vu9/ltS6JZ5ZSZv0eovLVfDfu0/AX4ub33RsJTOth3TiFWSHS5YdztvFnig==} - engines: {node: '>=18.0.0'} + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@smithy/eventstream-serde-browser@4.0.4': - resolution: {integrity: sha512-3fb/9SYaYqbpy/z/H3yIi0bYKyAa89y6xPmIqwr2vQiUT2St+avRt8UKwsWt9fEdEasc5d/V+QjrviRaX1JRFA==} - engines: {node: '>=18.0.0'} + '@radix-ui/react-visually-hidden@1.2.3': + resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} + 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 - '@smithy/eventstream-serde-config-resolver@4.1.2': - resolution: {integrity: sha512-JGtambizrWP50xHgbzZI04IWU7LdI0nh/wGbqH3sJesYToMi2j/DcoElqyOcqEIG/D4tNyxgRuaqBXWE3zOFhQ==} - engines: {node: '>=18.0.0'} + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - '@smithy/eventstream-serde-node@4.0.4': - resolution: {integrity: sha512-RD6UwNZ5zISpOWPuhVgRz60GkSIp0dy1fuZmj4RYmqLVRtejFqQ16WmfYDdoSoAjlp1LX+FnZo+/hkdmyyGZ1w==} - engines: {node: '>=18.0.0'} + '@react-email/body@0.1.0': + resolution: {integrity: sha512-o1bcSAmDYNNHECbkeyceCVPGmVsYvT+O3sSO/Ct7apKUu3JphTi31hu+0Nwqr/pgV5QFqdoT5vdS3SW5DJFHgQ==} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/eventstream-serde-universal@4.0.4': - resolution: {integrity: sha512-UeJpOmLGhq1SLox79QWw/0n2PFX+oPRE1ZyRMxPIaFEfCqWaqpB7BU9C8kpPOGEhLF7AwEqfFbtwNxGy4ReENA==} + '@react-email/button@0.2.0': + resolution: {integrity: sha512-8i+v6cMxr2emz4ihCrRiYJPp2/sdYsNNsBzXStlcA+/B9Umpm5Jj3WJKYpgTPM+aeyiqlG/MMI1AucnBm4f1oQ==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/fetch-http-handler@5.1.0': - resolution: {integrity: sha512-mADw7MS0bYe2OGKkHYMaqarOXuDwRbO6ArD91XhHcl2ynjGCFF+hvqf0LyQcYxkA1zaWjefSkU7Ne9mqgApSgQ==} + '@react-email/code-block@0.1.0': + resolution: {integrity: sha512-jSpHFsgqnQXxDIssE4gvmdtFncaFQz5D6e22BnVjcCPk/udK+0A9jRwGFEG8JD2si9ZXBmU4WsuqQEczuZn4ww==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/hash-blob-browser@4.0.4': - resolution: {integrity: sha512-WszRiACJiQV3QG6XMV44i5YWlkrlsM5Yxgz4jvsksuu7LDXA6wAtypfPajtNTadzpJy3KyJPoWehYpmZGKUFIQ==} + '@react-email/code-inline@0.0.5': + resolution: {integrity: sha512-MmAsOzdJpzsnY2cZoPHFPk6uDO/Ncpb4Kh1hAt9UZc1xOW3fIzpe1Pi9y9p6wwUmpaeeDalJxAxH6/fnTquinA==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/hash-node@4.0.4': - resolution: {integrity: sha512-qnbTPUhCVnCgBp4z4BUJUhOEkVwxiEi1cyFM+Zj6o+aY8OFGxUQleKWq8ltgp3dujuhXojIvJWdoqpm6dVO3lQ==} + '@react-email/column@0.0.13': + resolution: {integrity: sha512-Lqq17l7ShzJG/d3b1w/+lVO+gp2FM05ZUo/nW0rjxB8xBICXOVv6PqjDnn3FXKssvhO5qAV20lHM6S+spRhEwQ==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/hash-stream-node@4.0.4': - resolution: {integrity: sha512-wHo0d8GXyVmpmMh/qOR0R7Y46/G1y6OR8U+bSTB4ppEzRxd1xVAQ9xOE9hOc0bSjhz0ujCPAbfNLkLrpa6cevg==} + '@react-email/components@0.5.3': + resolution: {integrity: sha512-8G5vsoMehuGOT4cDqaYLdpagtqCYPl4vThXNylClxO6SrN2w9Mh1+i2RNGj/rdqh/woamHORjlXMYCA/kzDMew==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/invalid-dependency@4.0.4': - resolution: {integrity: sha512-bNYMi7WKTJHu0gn26wg8OscncTt1t2b8KcsZxvOv56XA6cyXtOAAAaNP7+m45xfppXfOatXF3Sb1MNsLUgVLTw==} + '@react-email/container@0.0.15': + resolution: {integrity: sha512-Qo2IQo0ru2kZq47REmHW3iXjAQaKu4tpeq/M8m1zHIVwKduL2vYOBQWbC2oDnMtWPmkBjej6XxgtZByxM6cCFg==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/is-array-buffer@2.2.0': - resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} - engines: {node: '>=14.0.0'} - - '@smithy/is-array-buffer@4.0.0': - resolution: {integrity: sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==} - engines: {node: '>=18.0.0'} + '@react-email/font@0.0.9': + resolution: {integrity: sha512-4zjq23oT9APXkerqeslPH3OZWuh5X4crHK6nx82mVHV2SrLba8+8dPEnWbaACWTNjOCbcLIzaC9unk7Wq2MIXw==} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/md5-js@4.0.4': - resolution: {integrity: sha512-uGLBVqcOwrLvGh/v/jw423yWHq/ofUGK1W31M2TNspLQbUV1Va0F5kTxtirkoHawODAZcjXTSGi7JwbnPcDPJg==} + '@react-email/head@0.0.12': + resolution: {integrity: sha512-X2Ii6dDFMF+D4niNwMAHbTkeCjlYYnMsd7edXOsi0JByxt9wNyZ9EnhFiBoQdqkE+SMDcu8TlNNttMrf5sJeMA==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/middleware-content-length@4.0.4': - resolution: {integrity: sha512-F7gDyfI2BB1Kc+4M6rpuOLne5LOcEknH1n6UQB69qv+HucXBR1rkzXBnQTB2q46sFy1PM/zuSJOB532yc8bg3w==} + '@react-email/heading@0.0.15': + resolution: {integrity: sha512-xF2GqsvBrp/HbRHWEfOgSfRFX+Q8I5KBEIG5+Lv3Vb2R/NYr0s8A5JhHHGf2pWBMJdbP4B2WHgj/VUrhy8dkIg==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/middleware-endpoint@4.1.17': - resolution: {integrity: sha512-S3hSGLKmHG1m35p/MObQCBCdRsrpbPU8B129BVzRqRfDvQqPMQ14iO4LyRw+7LNizYc605COYAcjqgawqi+6jA==} + '@react-email/hr@0.0.11': + resolution: {integrity: sha512-S1gZHVhwOsd1Iad5IFhpfICwNPMGPJidG/Uysy1AwmspyoAP5a4Iw3OWEpINFdgh9MHladbxcLKO2AJO+cA9Lw==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/middleware-retry@4.1.18': - resolution: {integrity: sha512-bYLZ4DkoxSsPxpdmeapvAKy7rM5+25gR7PGxq2iMiecmbrRGBHj9s75N74Ylg+aBiw9i5jIowC/cLU2NR0qH8w==} + '@react-email/html@0.0.11': + resolution: {integrity: sha512-qJhbOQy5VW5qzU74AimjAR9FRFQfrMa7dn4gkEXKMB/S9xZN8e1yC1uA9C15jkXI/PzmJ0muDIWmFwatm5/+VA==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/middleware-serde@4.0.8': - resolution: {integrity: sha512-iSSl7HJoJaGyMIoNn2B7czghOVwJ9nD7TMvLhMWeSB5vt0TnEYyRRqPJu/TqW76WScaNvYYB8nRoiBHR9S1Ddw==} + '@react-email/img@0.0.11': + resolution: {integrity: sha512-aGc8Y6U5C3igoMaqAJKsCpkbm1XjguQ09Acd+YcTKwjnC2+0w3yGUJkjWB2vTx4tN8dCqQCXO8FmdJpMfOA9EQ==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/middleware-stack@4.0.4': - resolution: {integrity: sha512-kagK5ggDrBUCCzI93ft6DjteNSfY8Ulr83UtySog/h09lTIOAJ/xUSObutanlPT0nhoHAkpmW9V5K8oPyLh+QA==} + '@react-email/link@0.0.12': + resolution: {integrity: sha512-vF+xxQk2fGS1CN7UPQDbzvcBGfffr+GjTPNiWM38fhBfsLv6A/YUfaqxWlmL7zLzVmo0K2cvvV9wxlSyNba1aQ==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/node-config-provider@4.1.3': - resolution: {integrity: sha512-HGHQr2s59qaU1lrVH6MbLlmOBxadtzTsoO4c+bF5asdgVik3I8o7JIOzoeqWc5MjVa+vD36/LWE0iXKpNqooRw==} + '@react-email/markdown@0.0.15': + resolution: {integrity: sha512-UQA9pVm5sbflgtg3EX3FquUP4aMBzmLReLbGJ6DZQZnAskBF36aI56cRykDq1o+1jT+CKIK1CducPYziaXliag==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/node-http-handler@4.1.0': - resolution: {integrity: sha512-vqfSiHz2v8b3TTTrdXi03vNz1KLYYS3bhHCDv36FYDqxT7jvTll1mMnCrkD+gOvgwybuunh/2VmvOMqwBegxEg==} + '@react-email/preview@0.0.13': + resolution: {integrity: sha512-F7j9FJ0JN/A4d7yr+aw28p4uX7VLWs7hTHtLo7WRyw4G+Lit6Zucq4UWKRxJC8lpsUdzVmG7aBJnKOT+urqs/w==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/property-provider@4.0.4': - resolution: {integrity: sha512-qHJ2sSgu4FqF4U/5UUp4DhXNmdTrgmoAai6oQiM+c5RZ/sbDwJ12qxB1M6FnP+Tn/ggkPZf9ccn4jqKSINaquw==} + '@react-email/render@1.2.3': + resolution: {integrity: sha512-qu3XYNkHGao3teJexVD5CrcgFkNLrzbZvpZN17a7EyQYUN3kHkTkE9saqY4VbvGx6QoNU3p8rsk/Xm++D/+pTw==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/protocol-http@5.1.2': - resolution: {integrity: sha512-rOG5cNLBXovxIrICSBm95dLqzfvxjEmuZx4KK3hWwPFHGdW3lxY0fZNXfv2zebfRO7sJZ5pKJYHScsqopeIWtQ==} + '@react-email/row@0.0.12': + resolution: {integrity: sha512-HkCdnEjvK3o+n0y0tZKXYhIXUNPDx+2vq1dJTmqappVHXS5tXS6W5JOPZr5j+eoZ8gY3PShI2LWj5rWF7ZEtIQ==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/querystring-builder@4.0.4': - resolution: {integrity: sha512-SwREZcDnEYoh9tLNgMbpop+UTGq44Hl9tdj3rf+yeLcfH7+J8OXEBaMc2kDxtyRHu8BhSg9ADEx0gFHvpJgU8w==} + '@react-email/section@0.0.16': + resolution: {integrity: sha512-FjqF9xQ8FoeUZYKSdt8sMIKvoT9XF8BrzhT3xiFKdEMwYNbsDflcjfErJe3jb7Wj/es/lKTbV5QR1dnLzGpL3w==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/querystring-parser@4.0.4': - resolution: {integrity: sha512-6yZf53i/qB8gRHH/l2ZwUG5xgkPgQF15/KxH0DdXMDHjesA9MeZje/853ifkSY0x4m5S+dfDZ+c4x439PF0M2w==} + '@react-email/tailwind@1.2.2': + resolution: {integrity: sha512-heO9Khaqxm6Ulm6p7HQ9h01oiiLRrZuuEQuYds/O7Iyp3c58sMVHZGIxiRXO/kSs857NZQycpjewEVKF3jhNTw==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/service-error-classification@4.0.6': - resolution: {integrity: sha512-RRoTDL//7xi4tn5FrN2NzH17jbgmnKidUqd4KvquT0954/i6CXXkh1884jBiunq24g9cGtPBEXlU40W6EpNOOg==} + '@react-email/text@0.1.5': + resolution: {integrity: sha512-o5PNHFSE085VMXayxH+SJ1LSOtGsTv+RpNKnTiJDrJUwoBu77G3PlKOsZZQHCNyD28WsQpl9v2WcJLbQudqwPg==} engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc - '@smithy/shared-ini-file-loader@4.0.4': - resolution: {integrity: sha512-63X0260LoFBjrHifPDs+nM9tV0VMkOTl4JRMYNuKh/f5PauSjowTfvF3LogfkWdcPoxsA9UjqEOgjeYIbhb7Nw==} - engines: {node: '>=18.0.0'} + '@rolldown/pluginutils@1.0.0-beta.27': + resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} - '@smithy/signature-v4@5.1.2': - resolution: {integrity: sha512-d3+U/VpX7a60seHziWnVZOHuEgJlclufjkS6zhXvxcJgkJq4UWdH5eOBLzHRMx6gXjsdT9h6lfpmLzbrdupHgQ==} - engines: {node: '>=18.0.0'} + '@rollup/plugin-replace@6.0.2': + resolution: {integrity: sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true - '@smithy/smithy-client@4.4.9': - resolution: {integrity: sha512-mbMg8mIUAWwMmb74LoYiArP04zWElPzDoA1jVOp3or0cjlDMgoS6WTC3QXK0Vxoc9I4zdrX0tq6qsOmaIoTWEQ==} - engines: {node: '>=18.0.0'} + '@rollup/pluginutils@5.2.0': + resolution: {integrity: sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true - '@smithy/types@4.3.1': - resolution: {integrity: sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==} - engines: {node: '>=18.0.0'} + '@rollup/rollup-android-arm-eabi@4.46.2': + resolution: {integrity: sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==} + cpu: [arm] + os: [android] - '@smithy/url-parser@4.0.4': - resolution: {integrity: sha512-eMkc144MuN7B0TDA4U2fKs+BqczVbk3W+qIvcoCY6D1JY3hnAdCuhCZODC+GAeaxj0p6Jroz4+XMUn3PCxQQeQ==} - engines: {node: '>=18.0.0'} + '@rollup/rollup-android-arm64@4.46.2': + resolution: {integrity: sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==} + cpu: [arm64] + os: [android] - '@smithy/util-base64@4.0.0': - resolution: {integrity: sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==} - engines: {node: '>=18.0.0'} + '@rollup/rollup-darwin-arm64@4.46.2': + resolution: {integrity: sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==} + cpu: [arm64] + os: [darwin] - '@smithy/util-body-length-browser@4.0.0': - resolution: {integrity: sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==} - engines: {node: '>=18.0.0'} + '@rollup/rollup-darwin-x64@4.46.2': + resolution: {integrity: sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==} + cpu: [x64] + os: [darwin] - '@smithy/util-body-length-node@4.0.0': - resolution: {integrity: sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==} + '@rollup/rollup-freebsd-arm64@4.46.2': + resolution: {integrity: sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.46.2': + resolution: {integrity: sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.46.2': + resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.46.2': + resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.46.2': + resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.46.2': + resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.46.2': + resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.46.2': + resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.46.2': + resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.46.2': + resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.46.2': + resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.46.2': + resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.46.2': + resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.46.2': + resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.46.2': + resolution: {integrity: sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.46.2': + resolution: {integrity: sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==} + cpu: [x64] + os: [win32] + + '@selderee/plugin-htmlparser2@0.11.0': + resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==} + + '@simplewebauthn/browser@13.1.2': + resolution: {integrity: sha512-aZnW0KawAM83fSBUgglP5WofbrLbLyr7CoPqYr66Eppm7zO86YX6rrCjRB3hQKPrL7ATvY4FVXlykZ6w6FwYYw==} + + '@simplewebauthn/server@13.1.2': + resolution: {integrity: sha512-VwoDfvLXSCaRiD+xCIuyslU0HLxVggeE5BL06+GbsP2l1fGf5op8e0c3ZtKoi+vSg1q4ikjtAghC23ze2Q3H9g==} + engines: {node: '>=20.0.0'} + + '@sindresorhus/is@7.0.2': + resolution: {integrity: sha512-d9xRovfKNz1SKieM0qJdO+PQonjnnIfSNWfHYnBSJ9hkjm0ZPw6HlxscDXYstp3z+7V2GOFHc+J0CYrYTjqCJw==} + engines: {node: '>=18'} + + '@smithy/abort-controller@4.0.4': + resolution: {integrity: sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==} + engines: {node: '>=18.0.0'} + + '@smithy/chunked-blob-reader-native@4.0.0': + resolution: {integrity: sha512-R9wM2yPmfEMsUmlMlIgSzOyICs0x9uu7UTHoccMyt7BWw8shcGM8HqB355+BZCPBcySvbTYMs62EgEQkNxz2ig==} + engines: {node: '>=18.0.0'} + + '@smithy/chunked-blob-reader@5.0.0': + resolution: {integrity: sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw==} + engines: {node: '>=18.0.0'} + + '@smithy/config-resolver@4.1.4': + resolution: {integrity: sha512-prmU+rDddxHOH0oNcwemL+SwnzcG65sBF2yXRO7aeXIn/xTlq2pX7JLVbkBnVLowHLg4/OL4+jBmv9hVrVGS+w==} + engines: {node: '>=18.0.0'} + + '@smithy/core@3.7.2': + resolution: {integrity: sha512-JoLw59sT5Bm8SAjFCYZyuCGxK8y3vovmoVbZWLDPTH5XpPEIwpFd9m90jjVMwoypDuB/SdVgje5Y4T7w50lJaw==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.0.6': + resolution: {integrity: sha512-hKMWcANhUiNbCJouYkZ9V3+/Qf9pteR1dnwgdyzR09R4ODEYx8BbUysHwRSyex4rZ9zapddZhLFTnT4ZijR4pw==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-codec@4.0.4': + resolution: {integrity: sha512-7XoWfZqWb/QoR/rAU4VSi0mWnO2vu9/ltS6JZ5ZSZv0eovLVfDfu0/AX4ub33RsJTOth3TiFWSHS5YdztvFnig==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-browser@4.0.4': + resolution: {integrity: sha512-3fb/9SYaYqbpy/z/H3yIi0bYKyAa89y6xPmIqwr2vQiUT2St+avRt8UKwsWt9fEdEasc5d/V+QjrviRaX1JRFA==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-config-resolver@4.1.2': + resolution: {integrity: sha512-JGtambizrWP50xHgbzZI04IWU7LdI0nh/wGbqH3sJesYToMi2j/DcoElqyOcqEIG/D4tNyxgRuaqBXWE3zOFhQ==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-node@4.0.4': + resolution: {integrity: sha512-RD6UwNZ5zISpOWPuhVgRz60GkSIp0dy1fuZmj4RYmqLVRtejFqQ16WmfYDdoSoAjlp1LX+FnZo+/hkdmyyGZ1w==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-universal@4.0.4': + resolution: {integrity: sha512-UeJpOmLGhq1SLox79QWw/0n2PFX+oPRE1ZyRMxPIaFEfCqWaqpB7BU9C8kpPOGEhLF7AwEqfFbtwNxGy4ReENA==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.1.0': + resolution: {integrity: sha512-mADw7MS0bYe2OGKkHYMaqarOXuDwRbO6ArD91XhHcl2ynjGCFF+hvqf0LyQcYxkA1zaWjefSkU7Ne9mqgApSgQ==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-blob-browser@4.0.4': + resolution: {integrity: sha512-WszRiACJiQV3QG6XMV44i5YWlkrlsM5Yxgz4jvsksuu7LDXA6wAtypfPajtNTadzpJy3KyJPoWehYpmZGKUFIQ==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-node@4.0.4': + resolution: {integrity: sha512-qnbTPUhCVnCgBp4z4BUJUhOEkVwxiEi1cyFM+Zj6o+aY8OFGxUQleKWq8ltgp3dujuhXojIvJWdoqpm6dVO3lQ==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-stream-node@4.0.4': + resolution: {integrity: sha512-wHo0d8GXyVmpmMh/qOR0R7Y46/G1y6OR8U+bSTB4ppEzRxd1xVAQ9xOE9hOc0bSjhz0ujCPAbfNLkLrpa6cevg==} + engines: {node: '>=18.0.0'} + + '@smithy/invalid-dependency@4.0.4': + resolution: {integrity: sha512-bNYMi7WKTJHu0gn26wg8OscncTt1t2b8KcsZxvOv56XA6cyXtOAAAaNP7+m45xfppXfOatXF3Sb1MNsLUgVLTw==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/is-array-buffer@4.0.0': + resolution: {integrity: sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==} + engines: {node: '>=18.0.0'} + + '@smithy/md5-js@4.0.4': + resolution: {integrity: sha512-uGLBVqcOwrLvGh/v/jw423yWHq/ofUGK1W31M2TNspLQbUV1Va0F5kTxtirkoHawODAZcjXTSGi7JwbnPcDPJg==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-content-length@4.0.4': + resolution: {integrity: sha512-F7gDyfI2BB1Kc+4M6rpuOLne5LOcEknH1n6UQB69qv+HucXBR1rkzXBnQTB2q46sFy1PM/zuSJOB532yc8bg3w==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-endpoint@4.1.17': + resolution: {integrity: sha512-S3hSGLKmHG1m35p/MObQCBCdRsrpbPU8B129BVzRqRfDvQqPMQ14iO4LyRw+7LNizYc605COYAcjqgawqi+6jA==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-retry@4.1.18': + resolution: {integrity: sha512-bYLZ4DkoxSsPxpdmeapvAKy7rM5+25gR7PGxq2iMiecmbrRGBHj9s75N74Ylg+aBiw9i5jIowC/cLU2NR0qH8w==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-serde@4.0.8': + resolution: {integrity: sha512-iSSl7HJoJaGyMIoNn2B7czghOVwJ9nD7TMvLhMWeSB5vt0TnEYyRRqPJu/TqW76WScaNvYYB8nRoiBHR9S1Ddw==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-stack@4.0.4': + resolution: {integrity: sha512-kagK5ggDrBUCCzI93ft6DjteNSfY8Ulr83UtySog/h09lTIOAJ/xUSObutanlPT0nhoHAkpmW9V5K8oPyLh+QA==} + engines: {node: '>=18.0.0'} + + '@smithy/node-config-provider@4.1.3': + resolution: {integrity: sha512-HGHQr2s59qaU1lrVH6MbLlmOBxadtzTsoO4c+bF5asdgVik3I8o7JIOzoeqWc5MjVa+vD36/LWE0iXKpNqooRw==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.1.0': + resolution: {integrity: sha512-vqfSiHz2v8b3TTTrdXi03vNz1KLYYS3bhHCDv36FYDqxT7jvTll1mMnCrkD+gOvgwybuunh/2VmvOMqwBegxEg==} + engines: {node: '>=18.0.0'} + + '@smithy/property-provider@4.0.4': + resolution: {integrity: sha512-qHJ2sSgu4FqF4U/5UUp4DhXNmdTrgmoAai6oQiM+c5RZ/sbDwJ12qxB1M6FnP+Tn/ggkPZf9ccn4jqKSINaquw==} + engines: {node: '>=18.0.0'} + + '@smithy/protocol-http@5.1.2': + resolution: {integrity: sha512-rOG5cNLBXovxIrICSBm95dLqzfvxjEmuZx4KK3hWwPFHGdW3lxY0fZNXfv2zebfRO7sJZ5pKJYHScsqopeIWtQ==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-builder@4.0.4': + resolution: {integrity: sha512-SwREZcDnEYoh9tLNgMbpop+UTGq44Hl9tdj3rf+yeLcfH7+J8OXEBaMc2kDxtyRHu8BhSg9ADEx0gFHvpJgU8w==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-parser@4.0.4': + resolution: {integrity: sha512-6yZf53i/qB8gRHH/l2ZwUG5xgkPgQF15/KxH0DdXMDHjesA9MeZje/853ifkSY0x4m5S+dfDZ+c4x439PF0M2w==} + engines: {node: '>=18.0.0'} + + '@smithy/service-error-classification@4.0.6': + resolution: {integrity: sha512-RRoTDL//7xi4tn5FrN2NzH17jbgmnKidUqd4KvquT0954/i6CXXkh1884jBiunq24g9cGtPBEXlU40W6EpNOOg==} + engines: {node: '>=18.0.0'} + + '@smithy/shared-ini-file-loader@4.0.4': + resolution: {integrity: sha512-63X0260LoFBjrHifPDs+nM9tV0VMkOTl4JRMYNuKh/f5PauSjowTfvF3LogfkWdcPoxsA9UjqEOgjeYIbhb7Nw==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.1.2': + resolution: {integrity: sha512-d3+U/VpX7a60seHziWnVZOHuEgJlclufjkS6zhXvxcJgkJq4UWdH5eOBLzHRMx6gXjsdT9h6lfpmLzbrdupHgQ==} + engines: {node: '>=18.0.0'} + + '@smithy/smithy-client@4.4.9': + resolution: {integrity: sha512-mbMg8mIUAWwMmb74LoYiArP04zWElPzDoA1jVOp3or0cjlDMgoS6WTC3QXK0Vxoc9I4zdrX0tq6qsOmaIoTWEQ==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.3.1': + resolution: {integrity: sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==} + engines: {node: '>=18.0.0'} + + '@smithy/url-parser@4.0.4': + resolution: {integrity: sha512-eMkc144MuN7B0TDA4U2fKs+BqczVbk3W+qIvcoCY6D1JY3hnAdCuhCZODC+GAeaxj0p6Jroz4+XMUn3PCxQQeQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-base64@4.0.0': + resolution: {integrity: sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-browser@4.0.0': + resolution: {integrity: sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-node@4.0.0': + resolution: {integrity: sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==} engines: {node: '>=18.0.0'} '@smithy/util-buffer-from@2.2.0': @@ -1567,6 +2175,9 @@ packages: '@speed-highlight/core@1.2.7': resolution: {integrity: sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==} + '@standard-schema/utils@0.3.0': + resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + '@t3-oss/env-core@0.13.8': resolution: {integrity: sha512-L1inmpzLQyYu4+Q1DyrXsGJYCXbtXjC4cICw1uAKv0ppYPQv656lhZPU91Qd1VS6SO/bou1/q5ufVzBGbNsUpw==} peerDependencies: @@ -1795,14 +2406,45 @@ packages: '@types/react-dom': optional: true - '@types/aria-query@5.0.4': - resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} - - '@types/aws-lambda@8.10.152': - resolution: {integrity: sha512-soT/c2gYBnT5ygwiHPmd9a1bftj462NWVk2tKCc1PYHSIacB2UwbTS2zYG4jzag1mRDuzg/OjtxQjQ2NKRB6Rw==} - - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + '@triplit/client@1.0.50': + resolution: {integrity: sha512-3vjXTSdDQ3fzLDrewCK7elkAQc7CiDg0eZEOZInQbVMFRiakdieO5C2voSnNjSepIYHxDxFSBllgg32QsNpL9Q==} + engines: {node: '>=18.0.0'} + + '@triplit/db@1.1.10': + resolution: {integrity: sha512-9BHDrlDvJOyA9Wl8AsmbUSLhilaReA8gpFoWYjS9VEcm5d6TtqKazPQrFm0/o2WNJdrs01+qR6CysAo449MAyA==} + peerDependencies: + better-sqlite3: '*' + expo-sqlite: '*' + lmdb: '*' + uuidv7: '*' + peerDependenciesMeta: + better-sqlite3: + optional: true + expo-sqlite: + optional: true + lmdb: + optional: true + uuidv7: + optional: true + + '@triplit/logger@0.0.3': + resolution: {integrity: sha512-hHcoD6/BsNwBtXjEp8Wiy0/YA2SqIYXd1nMukEPBmFkjT7Cd30eqtsBRT0NRq2mIFX2mr5h9JaO27zDToKnwdw==} + peerDependencies: + typescript: ^5.0.0 + + '@triplit/react@1.0.51': + resolution: {integrity: sha512-yGmYWACWycrNHMEfnR1k6CQ398ESIBgFeM47fXFhrdhMJ84QgdRk6VF/C21P80D1Rk/AQePfB0TUIaY4U9BRJg==} + peerDependencies: + react: '*' + + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + + '@types/aws-lambda@8.10.152': + resolution: {integrity: sha512-soT/c2gYBnT5ygwiHPmd9a1bftj462NWVk2tKCc1PYHSIacB2UwbTS2zYG4jzag1mRDuzg/OjtxQjQ2NKRB6Rw==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} '@types/babel__generator@7.27.0': resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} @@ -1874,6 +2516,16 @@ packages: '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + '@wojtekmaj/react-recaptcha-v3@0.1.4': + resolution: {integrity: sha512-zszMOdgI+y1Dz3496pRFr3t68n9+OmX/puLQNnOBDC7WrjM+nOKGyjIMCTe+3J14KDvzcxETeiglyDMGl0Yh/Q==} + peerDependencies: + '@types/react': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + acorn-walk@8.3.2: resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} engines: {node: '>=0.4.0'} @@ -1908,6 +2560,10 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} @@ -2006,6 +2662,9 @@ packages: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} + comlink@4.4.2: + resolution: {integrity: sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -2016,6 +2675,13 @@ packages: resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} engines: {node: '>=18'} + copy-anything@3.0.5: + resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} + engines: {node: '>=12.13'} + + core-js@3.45.1: + resolution: {integrity: sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -2051,6 +2717,10 @@ packages: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} @@ -2058,6 +2728,9 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + detect-europe-js@0.1.2: + resolution: {integrity: sha512-lgdERlL3u0aUdHocoouzT10d9I89VVhk0qNRmll7mXdGfJT1/wqZ2ZLA4oJAjeACPY5fT1wsbq2AT+GkuInsow==} + detect-libc@2.0.2: resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} engines: {node: '>=8'} @@ -2066,6 +2739,9 @@ packages: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + diff@8.0.2: resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} engines: {node: '>=0.3.1'} @@ -2073,6 +2749,19 @@ packages: dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + dotenv-cli@10.0.0: resolution: {integrity: sha512-lnOnttzfrzkRx2echxJHQRB6vOAMSCzzZg79IxpC00tU42wZPuZkQxNNrrwVAxaQZIIh001l4PxVlCrBxngBzA==} hasBin: true @@ -2194,10 +2883,17 @@ packages: electron-to-chromium@1.5.194: resolution: {integrity: sha512-SdnWJwSUot04UR51I2oPD8kuP2VI37/CADR1OHsFOUzZIvfWJBO6q11k5P/uKNyTT3cdOsnyjkrZ+DDShqYqJA==} + elen@1.0.10: + resolution: {integrity: sha512-ZL799/V/kzxYJ6Wlfktreq6qQWfGc3VkGUQJW5lZQ8/MhsQiKTAwERPfhEwIsV2movRGe2DfV7H2MjRw76Z7Wg==} + enhanced-resolve@5.18.2: resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==} engines: {node: '>=10.13.0'} + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + entities@6.0.1: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} @@ -2249,6 +2945,9 @@ packages: exsolve@1.0.7: resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} + fast-deep-equal@2.0.1: + resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==} + fast-xml-parser@5.2.5: resolution: {integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==} hasBin: true @@ -2282,6 +2981,10 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + get-port@7.1.0: resolution: {integrity: sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==} engines: {node: '>=16'} @@ -2304,6 +3007,9 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + hono@4.8.12: resolution: {integrity: sha512-MQSKk1Mg7b74k8l+A025LfysnLtXDKkE4pLaSsYRQC5iy85lgZnuyeQ1Wynair9mmECzoLu+FtJtqNZSoogBDQ==} engines: {node: '>=16.9.0'} @@ -2312,6 +3018,13 @@ packages: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} + html-to-text@9.0.5: + resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==} + engines: {node: '>=14'} + + htmlparser2@8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + http-proxy-agent@7.0.2: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} @@ -2324,6 +3037,12 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + input-otp@1.4.2: + resolution: {integrity: sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + is-arrayish@0.3.2: resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} @@ -2346,6 +3065,13 @@ packages: is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-standalone-pwa@0.1.1: + resolution: {integrity: sha512-9Cbovsa52vNQCjdXOzeQq5CnCbAcRk05aU62K20WO372NrTv0NxibLFCK6lQ4/iZEFdEA3p3t2VNOn8AJ53F5g==} + + is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + isbot@5.1.29: resolution: {integrity: sha512-DelDWWoa3mBoyWTq3wjp+GIWx/yZdN7zLUE7NFhKjAiJ+uJVRkbLlwykdduCE4sPUUy8mlTYTmdhBUYu91F+sw==} engines: {node: '>=18'} @@ -2396,6 +3122,9 @@ packages: resolution: {integrity: sha512-rlB0I/c6FBDWPcQoDtkxi9zIvpmnV5xoIalfCMSMCa7nuA6VGA3F54TW9mEgX4DVf10sXAWCF5fDbamI/5ZpKA==} engines: {node: '>=20.0.0'} + leac@0.6.0: + resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==} + libsql@0.5.17: resolution: {integrity: sha512-RRlj5XQI9+Wq+/5UY8EnugSWfRmHEw4hn3DKlPrkUgZONsge1PwTtHcpStP6MSNi8ohcbsRgEHJaymA33a8cBw==} cpu: [x64, arm64, wasm32, arm] @@ -2465,6 +3194,10 @@ packages: resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} engines: {node: '>= 12.0.0'} + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + loupe@3.2.0: resolution: {integrity: sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==} @@ -2486,6 +3219,16 @@ packages: magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + marked@7.0.4: + resolution: {integrity: sha512-t8eP0dXRJMtMvBojtkcsA7n48BkauktUKzfkPSCq85ZMTJ0v76Rke4DYz01omYpPTUh4p/f7HePgRo3ebG8+QQ==} + engines: {node: '>= 16'} + hasBin: true + + md-to-react-email@5.0.5: + resolution: {integrity: sha512-OvAXqwq57uOk+WZqFFNCMZz8yDp8BD3WazW1wAKHUrPbbdr89K9DWS6JXY09vd9xNdPNeurI8DU/X4flcfaD8A==} + peerDependencies: + react: ^18.0 || ^19.0 + mime@3.0.0: resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} engines: {node: '>=10.0.0'} @@ -2520,6 +3263,10 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mutative@1.3.0: + resolution: {integrity: sha512-8MJj6URmOZAV70dpFe1YnSppRTKC4DsMkXQiBDFayLcDI4ljGokHxmpqaBQuDWa4iAxWaJJ1PS8vAmbntjjKmQ==} + engines: {node: '>=14.0'} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -2559,12 +3306,19 @@ packages: nwsapi@2.2.21: resolution: {integrity: sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==} + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + ohash@2.0.11: resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parseley@0.12.1: + resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -2579,6 +3333,9 @@ packages: resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} + peberminta@0.9.0: + resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -2602,9 +3359,16 @@ packages: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + promise-limit@2.7.0: resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==} + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -2616,18 +3380,78 @@ packages: resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==} engines: {node: '>=6.0.0'} + qr.js@0.0.0: + resolution: {integrity: sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==} + + react-async-script@1.2.0: + resolution: {integrity: sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==} + peerDependencies: + react: '>=16.4.1' + react-dom@19.1.1: resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==} peerDependencies: react: ^19.1.1 + react-google-recaptcha@3.1.0: + resolution: {integrity: sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==} + peerDependencies: + react: '>=16.4.1' + + react-hook-form@7.63.0: + resolution: {integrity: sha512-ZwueDMvUeucovM2VjkCf7zIHcs1aAlDimZu2Hvel5C5907gUzMpm4xCrQXtRzCvsBqFjonB4m3x4LzCFI1ZKWA==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react-promise-suspense@0.3.4: + resolution: {integrity: sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==} + + react-qr-code@2.0.18: + resolution: {integrity: sha512-v1Jqz7urLMhkO6jkgJuBYhnqvXagzceg3qJUWayuCK/c6LTIonpWbwxR1f1APGd4xrW/QcQEovNrAojbUz65Tg==} + peerDependencies: + react: '*' + react-refresh@0.17.0: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.1: + resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + react@19.1.1: resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} engines: {node: '>=0.10.0'} @@ -2664,6 +3488,9 @@ packages: scheduler@0.26.0: resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + selderee@0.11.0: + resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -2713,6 +3540,9 @@ packages: react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + sorted-btree@1.8.1: + resolution: {integrity: sha512-395+XIP+wqNn3USkFSrNz7G3Ss/MXlZEqesxvzCRFwL14h6e8LukDHdLBePn5pwbm5OQ9vGu8mDyz2lLDIqamQ==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -2744,6 +3574,10 @@ packages: strnum@2.1.1: resolution: {integrity: sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==} + superjson@2.2.2: + resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} + engines: {node: '>=16'} + supports-color@10.0.0: resolution: {integrity: sha512-HRVVSbCCMbj7/kdWF9Q+bbckjBHLtHMEoJWlkmYzzdwhYMkjkOwubLM6t7NbWKjgKamGDrWL1++KrjUO1t9oAQ==} engines: {node: '>=18'} @@ -2861,6 +3695,13 @@ packages: resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} engines: {node: '>=14.17'} + ua-is-frozen@0.1.2: + resolution: {integrity: sha512-RwKDW2p3iyWn4UbaxpP2+VxwqXh0jpvdxsYpZ5j/MLLiQOfbsV5shpgQiw93+KMYQPcteeMQ289MaAFzs3G9pw==} + + ua-parser-js@2.0.5: + resolution: {integrity: sha512-sZErtx3rhpvZQanWW5umau4o/snfoLqRcQwQIZ54377WtRzIecnIKvjpkd5JwPcSUMglGnbIgcsQBGAbdi3S9Q==} + hasBin: true + ufo@1.6.1: resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} @@ -2887,15 +3728,45 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + use-sync-external-store@1.5.0: resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + uuid@11.1.0: + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} + hasBin: true + uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true + vaul@1.1.2: + resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + vite-node@3.2.4: resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -2973,6 +3844,9 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} + warning@4.0.3: + resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} + web-streams-polyfill@3.3.3: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} @@ -2980,6 +3854,9 @@ packages: web-vitals@4.2.4: resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} + web-worker@1.5.0: + resolution: {integrity: sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==} + webidl-conversions@7.0.0: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} @@ -3847,6 +4724,61 @@ snapshots: '@csstools/css-tokenizer@3.0.4': {} + '@daveyplate/better-auth-tanstack@1.3.6(@tanstack/query-core@5.87.4)(@tanstack/react-query@5.87.4(react@19.1.1))(better-auth@1.3.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@tanstack/query-core': 5.87.4 + '@tanstack/react-query': 5.87.4(react@19.1.1) + better-auth: 1.3.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + ? '@daveyplate/better-auth-ui@3.1.10(@daveyplate/better-auth-tanstack@1.3.6(@tanstack/query-core@5.87.4)(@tanstack/react-query@5.87.4(react@19.1.1))(better-auth@1.3.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@hookform/resolvers@5.2.2(react-hook-form@7.63.0(react@19.1.1)))(@instantdb/react@0.21.18(react@19.1.1))(@marsidev/react-turnstile@1.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-avatar@1.1.10(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-context@1.1.2(@types/react@19.1.9)(react@19.1.1))(@radix-ui/react-dialog@1.1.15(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-label@2.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-select@2.2.6(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-separator@1.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-slot@1.2.3(@types/react@19.1.9)(react@19.1.1))(@radix-ui/react-tabs@1.1.13(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.9)(react@19.1.1))(@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.9)(react@19.1.1))(@tanstack/react-query@5.87.4(react@19.1.1))(@triplit/client@1.0.50(typescript@5.8.3))(@triplit/react@1.0.51(react@19.1.1)(typescript@5.8.3))(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(better-auth@1.3.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(class-variance-authority@0.7.1)(clsx@2.1.1)(input-otp@1.4.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(lucide-react@0.539.0(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react-hook-form@7.63.0(react@19.1.1))(react@19.1.1)(sonner@2.0.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(tailwind-merge@3.3.1)(tailwindcss@4.1.11)(zod@3.25.76)' + : dependencies: + '@better-fetch/fetch': 1.1.18 + '@daveyplate/better-auth-tanstack': 1.3.6(@tanstack/query-core@5.87.4)(@tanstack/react-query@5.87.4(react@19.1.1))(better-auth@1.3.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@hcaptcha/react-hcaptcha': 1.12.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@hookform/resolvers': 5.2.2(react-hook-form@7.63.0(react@19.1.1)) + '@instantdb/react': 0.21.18(react@19.1.1) + '@marsidev/react-turnstile': 1.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@noble/hashes': 2.0.0 + '@radix-ui/react-avatar': 1.1.10(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-label': 2.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-select': 2.2.6(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@react-email/components': 0.5.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@tanstack/react-query': 5.87.4(react@19.1.1) + '@triplit/client': 1.0.50(typescript@5.8.3) + '@triplit/react': 1.0.51(react@19.1.1)(typescript@5.8.3) + '@wojtekmaj/react-recaptcha-v3': 0.1.4(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + better-auth: 1.3.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + class-variance-authority: 0.7.1 + clsx: 2.1.1 + input-otp: 1.4.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + lucide-react: 0.539.0(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-google-recaptcha: 3.1.0(react@19.1.1) + react-hook-form: 7.63.0(react@19.1.1) + react-qr-code: 2.0.18(react@19.1.1) + sonner: 2.0.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + tailwind-merge: 3.3.1 + tailwindcss: 4.1.11 + ua-parser-js: 2.0.5 + vaul: 1.1.2(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + zod: 3.25.76 + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + '@drizzle-team/brocli@0.10.2': {} '@emnapi/runtime@1.4.5': @@ -4005,6 +4937,32 @@ snapshots: '@esbuild/win32-x64@0.25.4': optional: true + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.4': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@floating-ui/dom': 1.7.4 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@floating-ui/utils@0.2.10': {} + + '@hcaptcha/loader@2.1.0': {} + + '@hcaptcha/react-hcaptcha@1.12.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@babel/runtime': 7.28.2 + '@hcaptcha/loader': 2.1.0 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + '@hexagon/base64@1.1.28': {} '@hono/zod-validator@0.7.2(hono@4.8.12)(zod@3.25.76)': @@ -4012,6 +4970,11 @@ snapshots: hono: 4.8.12 zod: 3.25.76 + '@hookform/resolvers@5.2.2(react-hook-form@7.63.0(react@19.1.1))': + dependencies: + '@standard-schema/utils': 0.3.0 + react-hook-form: 7.63.0(react@19.1.1) + '@img/sharp-darwin-arm64@0.33.5': optionalDependencies: '@img/sharp-libvips-darwin-arm64': 1.0.4 @@ -4087,6 +5050,20 @@ snapshots: '@img/sharp-win32-x64@0.33.5': optional: true + '@instantdb/core@0.21.18': + dependencies: + '@instantdb/version': 0.21.18 + mutative: 1.3.0 + uuid: 11.1.0 + + '@instantdb/react@0.21.18(react@19.1.1)': + dependencies: + '@instantdb/core': 0.21.18 + '@instantdb/version': 0.21.18 + react: 19.1.1 + + '@instantdb/version@0.21.18': {} + '@isaacs/fs-minipass@4.0.1': dependencies: minipass: 7.1.2 @@ -4123,122 +5100,606 @@ snapshots: - bufferutil - utf-8-validate - '@libsql/core@0.15.10': + '@libsql/core@0.15.10': + dependencies: + js-base64: 3.7.7 + + '@libsql/darwin-arm64@0.5.17': + optional: true + + '@libsql/darwin-x64@0.5.17': + optional: true + + '@libsql/hrana-client@0.7.0': + dependencies: + '@libsql/isomorphic-fetch': 0.3.1 + '@libsql/isomorphic-ws': 0.1.5 + js-base64: 3.7.7 + node-fetch: 3.3.2 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/isomorphic-fetch@0.3.1': {} + + '@libsql/isomorphic-ws@0.1.5': + dependencies: + '@types/ws': 8.18.1 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/linux-arm-gnueabihf@0.5.17': + optional: true + + '@libsql/linux-arm-musleabihf@0.5.17': + optional: true + + '@libsql/linux-arm64-gnu@0.5.17': + optional: true + + '@libsql/linux-arm64-musl@0.5.17': + optional: true + + '@libsql/linux-x64-gnu@0.5.17': + optional: true + + '@libsql/linux-x64-musl@0.5.17': + optional: true + + '@libsql/win32-x64-msvc@0.5.17': + optional: true + + '@marsidev/react-turnstile@1.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@mjackson/node-fetch-server@0.6.1': {} + + '@neon-rs/load@0.0.4': {} + + '@noble/ciphers@0.6.0': {} + + '@noble/hashes@1.8.0': {} + + '@noble/hashes@2.0.0': {} + + '@peculiar/asn1-android@2.4.0': + dependencies: + '@peculiar/asn1-schema': 2.4.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-ecc@2.4.0': + dependencies: + '@peculiar/asn1-schema': 2.4.0 + '@peculiar/asn1-x509': 2.4.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-rsa@2.4.0': + dependencies: + '@peculiar/asn1-schema': 2.4.0 + '@peculiar/asn1-x509': 2.4.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-schema@2.4.0': + dependencies: + asn1js: 3.0.6 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/asn1-x509@2.4.0': + dependencies: + '@peculiar/asn1-schema': 2.4.0 + asn1js: 3.0.6 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@poppinss/colors@4.1.5': + dependencies: + kleur: 4.1.5 + + '@poppinss/dumper@0.6.4': + dependencies: + '@poppinss/colors': 4.1.5 + '@sindresorhus/is': 7.0.2 + supports-color: 10.0.0 + + '@poppinss/exception@1.2.2': {} + + '@radix-ui/number@1.1.1': {} + + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-avatar@1.1.10(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-context': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.9)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.9 + + '@radix-ui/react-context@1.1.2(@types/react@19.1.9)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.9 + + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.9)(react@19.1.1) + aria-hidden: 1.2.6 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-remove-scroll: 2.7.1(@types/react@19.1.9)(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-direction@1.1.1(@types/react@19.1.9)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.9 + + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.1.9)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.9 + + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-id@1.1.1(@types/react@19.1.9)(react@19.1.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.9 + + '@radix-ui/react-label@2.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.9)(react@19.1.1) + aria-hidden: 1.2.6 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-remove-scroll: 2.7.1(@types/react@19.1.9)(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/rect': 1.1.1 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-select@2.2.6(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + 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.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + aria-hidden: 1.2.6 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-remove-scroll: 2.7.1(@types/react@19.1.9)(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-separator@1.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-slot@1.2.3(@types/react@19.1.9)(react@19.1.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.9 + + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.9)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.9 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.1.9)(react@19.1.1)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.9 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.9)(react@19.1.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.9 + + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.1.9)(react@19.1.1)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.9 + + '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.1.9)(react@19.1.1)': + dependencies: + react: 19.1.1 + use-sync-external-store: 1.5.0(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.9)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.9 + + '@radix-ui/react-use-previous@1.1.1(@types/react@19.1.9)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.9 + + '@radix-ui/react-use-rect@1.1.1(@types/react@19.1.9)(react@19.1.1)': dependencies: - js-base64: 3.7.7 - - '@libsql/darwin-arm64@0.5.17': - optional: true + '@radix-ui/rect': 1.1.1 + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.9 - '@libsql/darwin-x64@0.5.17': - optional: true + '@radix-ui/react-use-size@1.1.1(@types/react@19.1.9)(react@19.1.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.9 - '@libsql/hrana-client@0.7.0': + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@libsql/isomorphic-fetch': 0.3.1 - '@libsql/isomorphic-ws': 0.1.5 - js-base64: 3.7.7 - node-fetch: 3.3.2 - transitivePeerDependencies: - - bufferutil - - utf-8-validate + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) - '@libsql/isomorphic-fetch@0.3.1': {} + '@radix-ui/rect@1.1.1': {} - '@libsql/isomorphic-ws@0.1.5': + '@react-email/body@0.1.0(react@19.1.1)': dependencies: - '@types/ws': 8.18.1 - ws: 8.18.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@libsql/linux-arm-gnueabihf@0.5.17': - optional: true + react: 19.1.1 - '@libsql/linux-arm-musleabihf@0.5.17': - optional: true + '@react-email/button@0.2.0(react@19.1.1)': + dependencies: + react: 19.1.1 - '@libsql/linux-arm64-gnu@0.5.17': - optional: true + '@react-email/code-block@0.1.0(react@19.1.1)': + dependencies: + prismjs: 1.30.0 + react: 19.1.1 - '@libsql/linux-arm64-musl@0.5.17': - optional: true + '@react-email/code-inline@0.0.5(react@19.1.1)': + dependencies: + react: 19.1.1 - '@libsql/linux-x64-gnu@0.5.17': - optional: true + '@react-email/column@0.0.13(react@19.1.1)': + dependencies: + react: 19.1.1 - '@libsql/linux-x64-musl@0.5.17': - optional: true + '@react-email/components@0.5.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-email/body': 0.1.0(react@19.1.1) + '@react-email/button': 0.2.0(react@19.1.1) + '@react-email/code-block': 0.1.0(react@19.1.1) + '@react-email/code-inline': 0.0.5(react@19.1.1) + '@react-email/column': 0.0.13(react@19.1.1) + '@react-email/container': 0.0.15(react@19.1.1) + '@react-email/font': 0.0.9(react@19.1.1) + '@react-email/head': 0.0.12(react@19.1.1) + '@react-email/heading': 0.0.15(react@19.1.1) + '@react-email/hr': 0.0.11(react@19.1.1) + '@react-email/html': 0.0.11(react@19.1.1) + '@react-email/img': 0.0.11(react@19.1.1) + '@react-email/link': 0.0.12(react@19.1.1) + '@react-email/markdown': 0.0.15(react@19.1.1) + '@react-email/preview': 0.0.13(react@19.1.1) + '@react-email/render': 1.2.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-email/row': 0.0.12(react@19.1.1) + '@react-email/section': 0.0.16(react@19.1.1) + '@react-email/tailwind': 1.2.2(react@19.1.1) + '@react-email/text': 0.1.5(react@19.1.1) + react: 19.1.1 + transitivePeerDependencies: + - react-dom - '@libsql/win32-x64-msvc@0.5.17': - optional: true + '@react-email/container@0.0.15(react@19.1.1)': + dependencies: + react: 19.1.1 - '@mjackson/node-fetch-server@0.6.1': {} + '@react-email/font@0.0.9(react@19.1.1)': + dependencies: + react: 19.1.1 - '@neon-rs/load@0.0.4': {} + '@react-email/head@0.0.12(react@19.1.1)': + dependencies: + react: 19.1.1 - '@noble/ciphers@0.6.0': {} + '@react-email/heading@0.0.15(react@19.1.1)': + dependencies: + react: 19.1.1 - '@noble/hashes@1.8.0': {} + '@react-email/hr@0.0.11(react@19.1.1)': + dependencies: + react: 19.1.1 - '@peculiar/asn1-android@2.4.0': + '@react-email/html@0.0.11(react@19.1.1)': dependencies: - '@peculiar/asn1-schema': 2.4.0 - asn1js: 3.0.6 - tslib: 2.8.1 + react: 19.1.1 - '@peculiar/asn1-ecc@2.4.0': + '@react-email/img@0.0.11(react@19.1.1)': dependencies: - '@peculiar/asn1-schema': 2.4.0 - '@peculiar/asn1-x509': 2.4.0 - asn1js: 3.0.6 - tslib: 2.8.1 + react: 19.1.1 - '@peculiar/asn1-rsa@2.4.0': + '@react-email/link@0.0.12(react@19.1.1)': dependencies: - '@peculiar/asn1-schema': 2.4.0 - '@peculiar/asn1-x509': 2.4.0 - asn1js: 3.0.6 - tslib: 2.8.1 + react: 19.1.1 - '@peculiar/asn1-schema@2.4.0': + '@react-email/markdown@0.0.15(react@19.1.1)': dependencies: - asn1js: 3.0.6 - pvtsutils: 1.3.6 - tslib: 2.8.1 + md-to-react-email: 5.0.5(react@19.1.1) + react: 19.1.1 - '@peculiar/asn1-x509@2.4.0': + '@react-email/preview@0.0.13(react@19.1.1)': dependencies: - '@peculiar/asn1-schema': 2.4.0 - asn1js: 3.0.6 - pvtsutils: 1.3.6 - tslib: 2.8.1 + react: 19.1.1 - '@poppinss/colors@4.1.5': + '@react-email/render@1.2.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - kleur: 4.1.5 + html-to-text: 9.0.5 + prettier: 3.6.2 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-promise-suspense: 0.3.4 - '@poppinss/dumper@0.6.4': + '@react-email/row@0.0.12(react@19.1.1)': dependencies: - '@poppinss/colors': 4.1.5 - '@sindresorhus/is': 7.0.2 - supports-color: 10.0.0 + react: 19.1.1 - '@poppinss/exception@1.2.2': {} + '@react-email/section@0.0.16(react@19.1.1)': + dependencies: + react: 19.1.1 - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.9)(react@19.1.1)': + '@react-email/tailwind@1.2.2(react@19.1.1)': dependencies: react: 19.1.1 - optionalDependencies: - '@types/react': 19.1.9 - '@radix-ui/react-slot@1.2.3(@types/react@19.1.9)(react@19.1.1)': + '@react-email/text@0.1.5(react@19.1.1)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.9)(react@19.1.1) react: 19.1.1 - optionalDependencies: - '@types/react': 19.1.9 '@rolldown/pluginutils@1.0.0-beta.27': {} @@ -4317,6 +5778,11 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.46.2': optional: true + '@selderee/plugin-htmlparser2@0.11.0': + dependencies: + domhandler: 5.0.3 + selderee: 0.11.0 + '@simplewebauthn/browser@13.1.2': {} '@simplewebauthn/server@13.1.2': @@ -4666,6 +6132,8 @@ snapshots: '@speed-highlight/core@1.2.7': {} + '@standard-schema/utils@0.3.0': {} + '@t3-oss/env-core@0.13.8(typescript@5.8.3)(zod@3.25.76)': optionalDependencies: typescript: 5.8.3 @@ -4888,6 +6356,45 @@ snapshots: '@types/react': 19.1.9 '@types/react-dom': 19.1.7(@types/react@19.1.9) + '@triplit/client@1.0.50(typescript@5.8.3)': + dependencies: + '@triplit/db': 1.1.10(typescript@5.8.3) + '@triplit/logger': 0.0.3(typescript@5.8.3) + comlink: 4.4.2 + superjson: 2.2.2 + transitivePeerDependencies: + - better-sqlite3 + - expo-sqlite + - lmdb + - typescript + - uuidv7 + + '@triplit/db@1.1.10(typescript@5.8.3)': + dependencies: + '@triplit/logger': 0.0.3(typescript@5.8.3) + core-js: 3.45.1 + elen: 1.0.10 + nanoid: 5.1.5 + sorted-btree: 1.8.1 + web-worker: 1.5.0 + transitivePeerDependencies: + - typescript + + '@triplit/logger@0.0.3(typescript@5.8.3)': + dependencies: + typescript: 5.8.3 + + '@triplit/react@1.0.51(react@19.1.1)(typescript@5.8.3)': + dependencies: + '@triplit/client': 1.0.50(typescript@5.8.3) + react: 19.1.1 + transitivePeerDependencies: + - better-sqlite3 + - expo-sqlite + - lmdb + - typescript + - uuidv7 + '@types/aria-query@5.0.4': {} '@types/aws-lambda@8.10.152': {} @@ -4993,6 +6500,14 @@ snapshots: loupe: 3.2.0 tinyrainbow: 2.0.0 + '@wojtekmaj/react-recaptcha-v3@0.1.4(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + warning: 4.0.3 + optionalDependencies: + '@types/react': 19.1.9 + acorn-walk@8.3.2: {} acorn@8.14.0: {} @@ -5012,6 +6527,10 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + aria-query@5.3.0: dependencies: dequal: 2.0.3 @@ -5131,12 +6650,20 @@ snapshots: color-convert: 2.0.1 color-string: 1.9.1 + comlink@4.4.2: {} + convert-source-map@2.0.0: {} cookie-es@1.2.2: {} cookie@1.0.2: {} + copy-anything@3.0.5: + dependencies: + is-what: 4.1.16 + + core-js@3.45.1: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -5165,18 +6692,42 @@ snapshots: deep-eql@5.0.2: {} + deepmerge@4.3.1: {} + defu@6.1.4: {} dequal@2.0.3: {} + detect-europe-js@0.1.2: {} + detect-libc@2.0.2: {} detect-libc@2.0.4: {} + detect-node-es@1.1.0: {} + diff@8.0.2: {} dom-accessibility-api@0.5.16: {} + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dotenv-cli@10.0.0: dependencies: cross-spawn: 7.0.6 @@ -5214,11 +6765,15 @@ snapshots: electron-to-chromium@1.5.194: {} + elen@1.0.10: {} + enhanced-resolve@5.18.2: dependencies: graceful-fs: 4.2.11 tapable: 2.2.2 + entities@4.5.0: {} + entities@6.0.1: {} error-stack-parser-es@1.0.5: {} @@ -5301,6 +6856,8 @@ snapshots: exsolve@1.0.7: {} + fast-deep-equal@2.0.1: {} + fast-xml-parser@5.2.5: dependencies: strnum: 2.1.1 @@ -5327,6 +6884,8 @@ snapshots: gensync@1.0.0-beta.2: {} + get-nonce@1.0.1: {} + get-port@7.1.0: {} get-tsconfig@4.10.1: @@ -5345,12 +6904,31 @@ snapshots: graceful-fs@4.2.11: {} + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 + hono@4.8.12: {} html-encoding-sniffer@4.0.0: dependencies: whatwg-encoding: 3.1.1 + html-to-text@9.0.5: + dependencies: + '@selderee/plugin-htmlparser2': 0.11.0 + deepmerge: 4.3.1 + dom-serializer: 2.0.0 + htmlparser2: 8.0.2 + selderee: 0.11.0 + + htmlparser2@8.0.2: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 4.5.0 + http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 @@ -5369,6 +6947,11 @@ snapshots: dependencies: safer-buffer: 2.1.2 + input-otp@1.4.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + is-arrayish@0.3.2: {} is-binary-path@2.1.0: @@ -5385,6 +6968,10 @@ snapshots: is-potential-custom-element-name@1.0.1: {} + is-standalone-pwa@0.1.1: {} + + is-what@4.1.16: {} + isbot@5.1.29: {} isexe@2.0.0: {} @@ -5434,6 +7021,8 @@ snapshots: kysely@0.28.5: {} + leac@0.6.0: {} + libsql@0.5.17: dependencies: '@neon-rs/load': 0.0.4 @@ -5494,6 +7083,10 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.1 lightningcss-win32-x64-msvc: 1.30.1 + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + loupe@3.2.0: {} lru-cache@10.4.3: {} @@ -5512,6 +7105,13 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.4 + marked@7.0.4: {} + + md-to-react-email@5.0.5(react@19.1.1): + dependencies: + marked: 7.0.4 + react: 19.1.1 + mime@3.0.0: {} miniflare@4.20250730.0: @@ -5562,6 +7162,8 @@ snapshots: ms@2.1.3: {} + mutative@1.3.0: {} + nanoid@3.3.11: {} nanoid@5.1.5: {} @@ -5587,12 +7189,19 @@ snapshots: nwsapi@2.2.21: {} + object-assign@4.1.1: {} + ohash@2.0.11: {} parse5@7.3.0: dependencies: entities: 6.0.1 + parseley@0.12.1: + dependencies: + leac: 0.6.0 + peberminta: 0.9.0 + path-key@3.1.1: {} path-to-regexp@6.3.0: {} @@ -5601,6 +7210,8 @@ snapshots: pathval@2.0.1: {} + peberminta@0.9.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -5621,8 +7232,16 @@ snapshots: ansi-styles: 5.2.0 react-is: 17.0.2 + prismjs@1.30.0: {} + promise-limit@2.7.0: {} + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + punycode@2.3.1: {} pvtsutils@1.3.6: @@ -5631,15 +7250,72 @@ snapshots: pvutils@1.1.3: {} + qr.js@0.0.0: {} + + react-async-script@1.2.0(react@19.1.1): + dependencies: + hoist-non-react-statics: 3.3.2 + prop-types: 15.8.1 + react: 19.1.1 + react-dom@19.1.1(react@19.1.1): dependencies: react: 19.1.1 scheduler: 0.26.0 + react-google-recaptcha@3.1.0(react@19.1.1): + dependencies: + prop-types: 15.8.1 + react: 19.1.1 + react-async-script: 1.2.0(react@19.1.1) + + react-hook-form@7.63.0(react@19.1.1): + dependencies: + react: 19.1.1 + + react-is@16.13.1: {} + react-is@17.0.2: {} + react-promise-suspense@0.3.4: + dependencies: + fast-deep-equal: 2.0.1 + + react-qr-code@2.0.18(react@19.1.1): + dependencies: + prop-types: 15.8.1 + qr.js: 0.0.0 + react: 19.1.1 + react-refresh@0.17.0: {} + react-remove-scroll-bar@2.3.8(@types/react@19.1.9)(react@19.1.1): + dependencies: + react: 19.1.1 + react-style-singleton: 2.2.3(@types/react@19.1.9)(react@19.1.1) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.9 + + react-remove-scroll@2.7.1(@types/react@19.1.9)(react@19.1.1): + dependencies: + react: 19.1.1 + react-remove-scroll-bar: 2.3.8(@types/react@19.1.9)(react@19.1.1) + react-style-singleton: 2.2.3(@types/react@19.1.9)(react@19.1.1) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.1.9)(react@19.1.1) + use-sidecar: 1.1.3(@types/react@19.1.9)(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + + react-style-singleton@2.2.3(@types/react@19.1.9)(react@19.1.1): + dependencies: + get-nonce: 1.0.1 + react: 19.1.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.9 + react@19.1.1: {} readdirp@3.6.0: @@ -5694,6 +7370,10 @@ snapshots: scheduler@0.26.0: {} + selderee@0.11.0: + dependencies: + parseley: 0.12.1 + semver@6.3.1: {} semver@7.7.2: {} @@ -5755,6 +7435,8 @@ snapshots: react: 19.1.1 react-dom: 19.1.1(react@19.1.1) + sorted-btree@1.8.1: {} + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -5778,6 +7460,10 @@ snapshots: strnum@2.1.1: {} + superjson@2.2.2: + dependencies: + copy-anything: 3.0.5 + supports-color@10.0.0: {} symbol-tree@3.2.4: {} @@ -5874,6 +7560,15 @@ snapshots: typescript@5.8.3: {} + ua-is-frozen@0.1.2: {} + + ua-parser-js@2.0.5: + dependencies: + detect-europe-js: 0.1.2 + is-standalone-pwa: 0.1.1 + ua-is-frozen: 0.1.2 + undici: 7.13.0 + ufo@1.6.1: {} uncrypto@0.1.3: {} @@ -5902,12 +7597,38 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + use-callback-ref@1.3.3(@types/react@19.1.9)(react@19.1.1): + dependencies: + react: 19.1.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.9 + + use-sidecar@1.1.3(@types/react@19.1.9)(react@19.1.1): + dependencies: + detect-node-es: 1.1.0 + react: 19.1.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.9 + use-sync-external-store@1.5.0(react@19.1.1): dependencies: react: 19.1.1 + uuid@11.1.0: {} + uuid@9.0.1: {} + vaul@1.1.2(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + vite-node@3.2.4(@types/node@20.14.11)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.3): dependencies: cac: 6.7.14 @@ -5990,10 +7711,16 @@ snapshots: dependencies: xml-name-validator: 5.0.0 + warning@4.0.3: + dependencies: + loose-envify: 1.4.0 + web-streams-polyfill@3.3.3: {} web-vitals@4.2.4: {} + web-worker@1.5.0: {} + webidl-conversions@7.0.0: {} webpack-virtual-modules@0.6.2: {} From 712a37be11ca6371105253c9a6511270d4f7c191 Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Sat, 18 Oct 2025 18:48:59 -0600 Subject: [PATCH 02/45] updates db and adds email + password sign up --- apps/api/src/env.ts | 2 +- apps/api/src/lib/auth.ts | 21 +- apps/api/src/lib/functions/cors.ts | 4 +- apps/web/src/components/shared/error.tsx | 9 + apps/web/src/lib/auth-client.ts | 6 +- apps/web/src/providers.tsx | 44 +- apps/web/src/router.tsx | 1 + apps/web/src/routes/__root.tsx | 10 +- apps/web/src/routes/sign-in/index.tsx | 8 +- apps/web/src/routes/sign-up/index.tsx | 10 +- .../db/drizzle/0003_reflective_shiver_man.sql | 64 ++ packages/db/drizzle/meta/0003_snapshot.json | 725 ++++++++++++++++++ packages/db/drizzle/meta/_journal.json | 7 + packages/db/schema.ts | 9 +- packages/shared/constants.ts | 13 +- 15 files changed, 888 insertions(+), 45 deletions(-) create mode 100644 apps/web/src/components/shared/error.tsx create mode 100644 packages/db/drizzle/0003_reflective_shiver_man.sql create mode 100644 packages/db/drizzle/meta/0003_snapshot.json diff --git a/apps/api/src/env.ts b/apps/api/src/env.ts index 7758c9b..bc113dd 100644 --- a/apps/api/src/env.ts +++ b/apps/api/src/env.ts @@ -6,7 +6,7 @@ export const env = createEnv({ description: "Account ID for the Cloudflare account. Note that this ID should be the same one the bucket is hosted in.", }), - FALLBACK_WEB_URL: z + VITE_FALLBACK_WEB_URL: z .string({ description: "The URL of the frontend. DO NOT ADD A TRAILING SLASH", diff --git a/apps/api/src/lib/auth.ts b/apps/api/src/lib/auth.ts index 0bf0a32..201634e 100644 --- a/apps/api/src/lib/auth.ts +++ b/apps/api/src/lib/auth.ts @@ -2,17 +2,20 @@ import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { db } from "db"; // your drizzle instance import { APP_NAME, AUTH_CONFIG } from "shared/constants"; +import { env } from "../env"; export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "sqlite", debugLogs: true, }), + trustedOrigins:[env.VITE_FALLBACK_WEB_URL], databaseHooks: { user: { create: { // used in order to break up the first and last name into separate fields before: async (user) => { + console.log("Creating user. Raw inputs are: ", user); // split the name into first and last name (name object is mapped to the first name by the config) const [firstName, ...rest] = user.name.split(" "); const lastName = rest.join(" "); @@ -40,22 +43,18 @@ export const auth = betterAuth({ }, lastSeen: { type: "date", - required: true, - defaultValue: Date.now(), + required: false, input: false, }, - // role: { - // type: "string", - // defaultValue: "user", - // validator: { - // input: z.enum(["user", "admin"]), - // output: z.enum(["user", "admin"]), - // }, - // }, + siteRole:{ + type:"string", + defaultValue:"USER", + input:false, + } }, }, advanced: { - cookiePrefix: APP_NAME, + cookiePrefix: APP_NAME.toLocaleLowerCase(), }, emailAndPassword: { enabled: AUTH_CONFIG.emailAndPassword.enabled, diff --git a/apps/api/src/lib/functions/cors.ts b/apps/api/src/lib/functions/cors.ts index 34f1a3f..035cefa 100644 --- a/apps/api/src/lib/functions/cors.ts +++ b/apps/api/src/lib/functions/cors.ts @@ -5,7 +5,7 @@ import { env } from "../../env"; * General CORS policy for the API. Will run on every request, but others can be specified for individual routes. */ export const generalCorsPolicy = cors({ - origin: env.FALLBACK_WEB_URL, + origin: env.VITE_FALLBACK_WEB_URL, allowHeaders: [ "Content-Type", "Authorization", @@ -21,7 +21,7 @@ export const generalCorsPolicy = cors({ * CORS policy specifically for the Better Auth routes. */ export const betterAuthCorsPolicy = cors({ - origin: env.FALLBACK_WEB_URL, + origin: env.VITE_FALLBACK_WEB_URL, allowHeaders: ["Content-Type", "Authorization"], allowMethods: ["POST", "GET", "OPTIONS"], exposeHeaders: ["Content-Length"], diff --git a/apps/web/src/components/shared/error.tsx b/apps/web/src/components/shared/error.tsx new file mode 100644 index 0000000..6330a69 --- /dev/null +++ b/apps/web/src/components/shared/error.tsx @@ -0,0 +1,9 @@ +// TODO(https://github.com/acmutsa/Fallback/issues/13): Implement proper error logging here and an appropriate display for some common errors +/// @ts-expect-error - remove after above bug complete +export default function ErrorComponent({ errorToLog }: { errorToLog: Error }) { + return ( +
+ Uh oh. An unrecoverale error has occured. Please refresh the page. +
+ ); +} \ No newline at end of file diff --git a/apps/web/src/lib/auth-client.ts b/apps/web/src/lib/auth-client.ts index c78c3f2..7da01cd 100644 --- a/apps/web/src/lib/auth-client.ts +++ b/apps/web/src/lib/auth-client.ts @@ -1,9 +1,7 @@ import { createAuthClient } from "better-auth/react"; -console.log( - "api url for better auth client", - import.meta.env.VITE_FALLBACK_API_URL, -); + export const authClient = createAuthClient({ baseURL: import.meta.env.VITE_FALLBACK_API_URL, + }); diff --git a/apps/web/src/providers.tsx b/apps/web/src/providers.tsx index 946f9df..3621f78 100644 --- a/apps/web/src/providers.tsx +++ b/apps/web/src/providers.tsx @@ -6,18 +6,54 @@ import { QueryClientProvider } from "@tanstack/react-query"; import { queryClient } from "./router"; export function Providers({ children }: { children: React.ReactNode }) { - const router = useRouter(); return ( router.navigate({ href })} - replace={(href) => router.navigate({ href, replace: true })} + navigate={(href) => useRouter().navigate({ href })} + replace={(href) => useRouter().navigate({ href, replace: true })} Link={({ href, ...props }) => } persistClient={false} - basePath="/" + basePath="/" + baseURL={ + import.meta.env.VITE_FALLBACK_WEB_URL || + "http://localhost:3000" + } + social={{ + providers: ["github", "google", "discord", "linear"], + }} + localization={{ + SIGN_IN:"Sign In", + SIGN_IN_DESCRIPTION:"Welcome back! Please enter your details.", + SIGN_UP:"Create Account", + SIGN_UP_DESCRIPTION:"Let's get you started with a free account.", + }} + + + // avatar={{ + // upload: async (file) => { + // const formData = new FormData(); + // formData.append("avatar", file); + // const res = await fetch("/api/uploadAvatar", { + // method: "POST", + // body: formData, + // }); + // const { data } = await res.json(); + // return data.url; + // }, + // delete: async (url) => { + // await fetch("/api/deleteAvatar", { + // method: "POST", + // headers: { "Content-Type": "application/json" }, + // body: JSON.stringify({ url }), + // }); + // }, + // // Custom Image component for rendering avatar images + // // Useful for CDN optimization (Cloudinary, Imgix, ImgProxy, etc.) + // Image: Image, // Use Next.js Image component for avatars + // }} > {children} diff --git a/apps/web/src/router.tsx b/apps/web/src/router.tsx index 24aa502..887395c 100644 --- a/apps/web/src/router.tsx +++ b/apps/web/src/router.tsx @@ -4,6 +4,7 @@ import { createRouter } from "@tanstack/react-router"; import { setupRouterSsrQueryIntegration } from "@tanstack/react-router-ssr-query"; import { routeTree } from "./routeTree.gen"; + // Create a new query client instance export const queryClient = new QueryClient(); diff --git a/apps/web/src/routes/__root.tsx b/apps/web/src/routes/__root.tsx index 8265764..d27cbd7 100644 --- a/apps/web/src/routes/__root.tsx +++ b/apps/web/src/routes/__root.tsx @@ -4,16 +4,17 @@ import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; import { getSession } from "@/lib/functions/auth"; import { redirect } from "@tanstack/react-router"; import { isProtectedRoute } from "@/lib/functions/auth"; +import ErrorComponent from "@/components/shared/error"; type RouterContext = { queryClient: QueryClient; + auth?: Awaited>; }; export const Route = createRootRouteWithContext()({ - beforeLoad: async({location}) =>{ + const auth = await getSession(); if (isProtectedRoute(location.pathname)) { - const auth = await getSession(); if (!auth.data){ throw redirect({ @@ -25,12 +26,15 @@ export const Route = createRootRouteWithContext()({ }) } } + return { + auth + } }, - component: () => ( <> ), + errorComponent: ({ error }) => }) diff --git a/apps/web/src/routes/sign-in/index.tsx b/apps/web/src/routes/sign-in/index.tsx index d04ce67..9ac6528 100644 --- a/apps/web/src/routes/sign-in/index.tsx +++ b/apps/web/src/routes/sign-in/index.tsx @@ -2,17 +2,15 @@ import { createFileRoute } from '@tanstack/react-router' import { AuthView } from '@daveyplate/better-auth-ui' import {redirect} from "@tanstack/react-router" import { APP_NAME } from 'shared/constants'; -import { getSession } from '@/lib/functions/auth'; export const Route = createFileRoute('/sign-in/')({ component: RouteComponent, - loader: async () => getSession() }) function RouteComponent() { - const authData = Route.useLoaderData() - if (authData.data){ + const {auth} = Route.useRouteContext() + if (auth?.data){ return redirect({ to:"/", }) @@ -24,7 +22,7 @@ function RouteComponent() {

Sign back into {APP_NAME} to pick up where you left off

- +
); diff --git a/apps/web/src/routes/sign-up/index.tsx b/apps/web/src/routes/sign-up/index.tsx index ccd4d9f..2d5e3bd 100644 --- a/apps/web/src/routes/sign-up/index.tsx +++ b/apps/web/src/routes/sign-up/index.tsx @@ -1,17 +1,15 @@ import { createFileRoute } from '@tanstack/react-router' import { AuthView } from '@daveyplate/better-auth-ui' -import { authClient } from "@/lib/auth-client"; import { redirect } from "@tanstack/react-router"; import { APP_NAME } from "shared/constants"; export const Route = createFileRoute("/sign-up/")({ component: RouteComponent, - loader: async () => authClient.getSession(), }); function RouteComponent() { - const authData = Route.useLoaderData() - if (authData.data){ + const {auth} = Route.useRouteContext() + if (auth?.data){ return redirect({ to:"/profile", }) @@ -20,10 +18,10 @@ function RouteComponent() {

Welcome to {APP_NAME} 👋

-

Take a quick second to sign up and you'll be on your way to the most seamless baclup experience

+

Take a quick second to sign up and you'll be on your way to the most seamless backup experience

- +
); diff --git a/packages/db/drizzle/0003_reflective_shiver_man.sql b/packages/db/drizzle/0003_reflective_shiver_man.sql new file mode 100644 index 0000000..3c9c759 --- /dev/null +++ b/packages/db/drizzle/0003_reflective_shiver_man.sql @@ -0,0 +1,64 @@ +PRAGMA foreign_keys=OFF;--> statement-breakpoint +CREATE TABLE `__new_backup_job` ( + `id` text PRIMARY KEY NOT NULL, + `name` text(255) NOT NULL, + `authentication_data` text NOT NULL, + `database_type` text NOT NULL, + `cron_string` text(255) NOT NULL, + `team_id` text NOT NULL, + FOREIGN KEY (`team_id`) REFERENCES `team`(`id`) ON UPDATE no action ON DELETE cascade +); +--> statement-breakpoint +INSERT INTO `__new_backup_job`("id", "name", "authentication_data", "database_type", "cron_string", "team_id") SELECT "id", "name", "authentication_data", "database_type", "cron_string", "team_id" FROM `backup_job`;--> statement-breakpoint +DROP TABLE `backup_job`;--> statement-breakpoint +ALTER TABLE `__new_backup_job` RENAME TO `backup_job`;--> statement-breakpoint +PRAGMA foreign_keys=ON;--> statement-breakpoint +CREATE TABLE `__new_backup_job_run` ( + `id` text PRIMARY KEY NOT NULL, + `invocation_type` text NOT NULL, + `backup_job_id` text NOT NULL, + `started_at` integer DEFAULT (current_timestamp) NOT NULL, + `completed_at` integer, + `result` text, + FOREIGN KEY (`backup_job_id`) REFERENCES `backup_job`(`id`) ON UPDATE no action ON DELETE cascade +); +--> statement-breakpoint +INSERT INTO `__new_backup_job_run`("id", "invocation_type", "backup_job_id", "started_at", "completed_at", "result") SELECT "id", "invocation_type", "backup_job_id", "started_at", "completed_at", "result" FROM `backup_job_run`;--> statement-breakpoint +DROP TABLE `backup_job_run`;--> statement-breakpoint +ALTER TABLE `__new_backup_job_run` RENAME TO `backup_job_run`;--> statement-breakpoint +CREATE TABLE `__new_log` ( + `id` text PRIMARY KEY NOT NULL, + `log_type` text NOT NULL, + `message` text(255) NOT NULL, + `occurred_at` integer DEFAULT (current_timestamp) NOT NULL, + `team_id` text +); +--> statement-breakpoint +INSERT INTO `__new_log`("id", "log_type", "message", "occurred_at", "team_id") SELECT "id", "log_type", "message", "occurred_at", "team_id" FROM `log`;--> statement-breakpoint +DROP TABLE `log`;--> statement-breakpoint +ALTER TABLE `__new_log` RENAME TO `log`;--> statement-breakpoint +CREATE TABLE `__new_team` ( + `id` text PRIMARY KEY NOT NULL, + `name` text(255) NOT NULL, + `created_at` integer DEFAULT (current_timestamp) NOT NULL, + `updated_at` integer DEFAULT (current_timestamp) NOT NULL, + `isprivate` integer DEFAULT true NOT NULL +); +--> statement-breakpoint +INSERT INTO `__new_team`("id", "name", "created_at", "updated_at", "isprivate") SELECT "id", "name", "created_at", "updated_at", "isprivate" FROM `team`;--> statement-breakpoint +DROP TABLE `team`;--> statement-breakpoint +ALTER TABLE `__new_team` RENAME TO `team`;--> statement-breakpoint +CREATE TABLE `__new_team_invite` ( + `id` text PRIMARY KEY NOT NULL, + `team_id` text NOT NULL, + `email` text NOT NULL, + `created_at` integer DEFAULT (current_timestamp) NOT NULL, + `expires_at` integer NOT NULL, + `accepted_at` integer, + FOREIGN KEY (`team_id`) REFERENCES `team`(`id`) ON UPDATE no action ON DELETE cascade +); +--> statement-breakpoint +INSERT INTO `__new_team_invite`("id", "team_id", "email", "created_at", "expires_at", "accepted_at") SELECT "id", "team_id", "email", "created_at", "expires_at", "accepted_at" FROM `team_invite`;--> statement-breakpoint +DROP TABLE `team_invite`;--> statement-breakpoint +ALTER TABLE `__new_team_invite` RENAME TO `team_invite`;--> statement-breakpoint +ALTER TABLE `user` DROP COLUMN `pronouns`; \ No newline at end of file diff --git a/packages/db/drizzle/meta/0003_snapshot.json b/packages/db/drizzle/meta/0003_snapshot.json new file mode 100644 index 0000000..c2e2dab --- /dev/null +++ b/packages/db/drizzle/meta/0003_snapshot.json @@ -0,0 +1,725 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "3e94e0c8-ed12-4cad-9de9-25ab1c05cad9", + "prevId": "ca9f58f3-935d-4f73-ac8e-bb440a3560d6", + "tables": { + "account": { + "name": "account", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "backup_job": { + "name": "backup_job", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "authentication_data": { + "name": "authentication_data", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "database_type": { + "name": "database_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cron_string": { + "name": "cron_string", + "type": "text(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_job_team_id_team_id_fk": { + "name": "backup_job_team_id_team_id_fk", + "tableFrom": "backup_job", + "tableTo": "team", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "backup_job_run": { + "name": "backup_job_run", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "invocation_type": { + "name": "invocation_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "backup_job_id": { + "name": "backup_job_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "started_at": { + "name": "started_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "completed_at": { + "name": "completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "result": { + "name": "result", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_job_run_backup_job_id_backup_job_id_fk": { + "name": "backup_job_run_backup_job_id_backup_job_id_fk", + "tableFrom": "backup_job_run", + "tableTo": "backup_job", + "columnsFrom": [ + "backup_job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "log": { + "name": "log", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "log_type": { + "name": "log_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "occurred_at": { + "name": "occurred_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "session_token_unique": { + "name": "session_token_unique", + "columns": [ + "token" + ], + "isUnique": true + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "team": { + "name": "team", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "isprivate": { + "name": "isprivate", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "team_invite": { + "name": "team_invite", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "accepted_at": { + "name": "accepted_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "team_invite_team_id_team_id_fk": { + "name": "team_invite_team_id_team_id_fk", + "tableFrom": "team_invite", + "tableTo": "team", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "first_name": { + "name": "first_name", + "type": "text(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_name": { + "name": "last_name", + "type": "text(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_seen": { + "name": "last_seen", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "site_role": { + "name": "site_role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'USER'" + } + }, + "indexes": { + "user_email_unique": { + "name": "user_email_unique", + "columns": [ + "email" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_to_team": { + "name": "user_to_team", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'MEMBER'" + } + }, + "indexes": {}, + "foreignKeys": { + "user_to_team_user_id_user_id_fk": { + "name": "user_to_team_user_id_user_id_fk", + "tableFrom": "user_to_team", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_to_team_team_id_team_id_fk": { + "name": "user_to_team_team_id_team_id_fk", + "tableFrom": "user_to_team", + "tableTo": "team", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_to_team_user_id_team_id_pk": { + "columns": [ + "user_id", + "team_id" + ], + "name": "user_to_team_user_id_team_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verification": { + "name": "verification", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/packages/db/drizzle/meta/_journal.json b/packages/db/drizzle/meta/_journal.json index cbdb726..ec1ace7 100644 --- a/packages/db/drizzle/meta/_journal.json +++ b/packages/db/drizzle/meta/_journal.json @@ -22,6 +22,13 @@ "when": 1757908757865, "tag": "0002_sleepy_gladiator", "breakpoints": true + }, + { + "idx": 3, + "version": "6", + "when": 1759733480178, + "tag": "0003_reflective_shiver_man", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/db/schema.ts b/packages/db/schema.ts index 64d7880..f6405d8 100644 --- a/packages/db/schema.ts +++ b/packages/db/schema.ts @@ -32,7 +32,7 @@ const logType = text({ enum: ["INFO", "WARNING", "ERROR"] }); const invocationType = text({ enum: ["MANUAL", "CRON"] }); const databaseType = text({ enum: ["SQLITE", "POSTGRESQL"] }); const backupResult = text({ enum: ["SUCCESS", "FAILURE", "CANCELED"] }); -const roleType = text({ enum: ["ADMIN", "MEMBER"] }); +const memberRoleType = text({ enum: ["ADMIN", "MEMBER"] }); const siteRoleType = text({ enum: ["SUPER_ADMIN", "ADMIN", "USER"] }); export const user = sqliteTable("user", { @@ -40,8 +40,9 @@ export const user = sqliteTable("user", { firstName: text("first_name", { length: 255 }).notNull(), lastName: text("last_name", { length: 255 }).notNull(), email: text("email").notNull().unique(), - pronouns: text("pronouns", { length: 255 }), - createdAt: standardDateFactory(), + createdAt: integer("created_at", { mode: "timestamp_ms" }) + .notNull() + .default(sql`(current_timestamp)`), emailVerified: integer("email_verified", { mode: "boolean" }).notNull(), image: text("image"), updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(), @@ -77,7 +78,7 @@ export const userToTeam = sqliteTable( teamId: text("team_id") .notNull() .references(() => team.id, { onDelete: "cascade" }), - role: roleType.notNull().default("MEMBER"), + role: memberRoleType.notNull().default("MEMBER"), }, (table) => [ primaryKey({ columns: [table.userId, table.teamId] }), // composite primary key diff --git a/packages/shared/constants.ts b/packages/shared/constants.ts index 56910c2..e69c7ac 100644 --- a/packages/shared/constants.ts +++ b/packages/shared/constants.ts @@ -1,10 +1,13 @@ export const APP_NAME = "Fallback"; -export const USER_PERMISSIONS = { - member: { - canView: true, - canEdit: false, - canDelete: false, +export const PERMISSIONS_CONFIG = { + siteRoles:{ + }, + teamRoles:{ + MEMBER:{ + canRead:true, + } + } }; export const AUTH_CONFIG = { emailAndPassword: { From 4d1c40fe2e31db17cfd3fb715555446955858726 Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Sat, 18 Oct 2025 18:59:14 -0600 Subject: [PATCH 03/45] Adds bugs to todos --- apps/api/src/env.ts | 2 +- apps/api/src/index.ts | 2 +- apps/api/src/lib/auth.ts | 14 +++++++------- apps/api/src/lib/functions/middleware.ts | 3 +-- apps/api/src/routes/user.ts | 1 - apps/web/vite.config.ts | 4 ++-- 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/apps/api/src/env.ts b/apps/api/src/env.ts index bc113dd..bfe0709 100644 --- a/apps/api/src/env.ts +++ b/apps/api/src/env.ts @@ -15,7 +15,7 @@ export const env = createEnv({ R2_ACCESS_KEY_ID: z.string(), R2_SECRET_ACCESS_KEY: z.string(), BETTER_AUTH_SECRET: z.string(), - // TODO: add these back once the oauth stuff is implemented. + // TODO(https://github.com/acmutsa/Fallback/issues/14): add these back once the oauth stuff is implemented. // GOOGLE_CLIENT_ID: z.string(), // GOOGLE_CLIENT_SECRET: z.string(), // DISCORD_CLIENT_ID: z.string(), diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index aeeabb7..84345df 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -31,7 +31,7 @@ export const api = HonoBetterAuth() .route("/log", logHandler) .route("/backup", backupHandler) .route("/user", userhandler) - .route("/api/auth/*", authHandler); //TODO: Ensure that this is the correct route segment to start requests from. + .route("/api/auth/*", authHandler); /// diff --git a/apps/api/src/lib/auth.ts b/apps/api/src/lib/auth.ts index 201634e..79325ec 100644 --- a/apps/api/src/lib/auth.ts +++ b/apps/api/src/lib/auth.ts @@ -9,7 +9,7 @@ export const auth = betterAuth({ provider: "sqlite", debugLogs: true, }), - trustedOrigins:[env.VITE_FALLBACK_WEB_URL], + trustedOrigins: [env.VITE_FALLBACK_WEB_URL], databaseHooks: { user: { create: { @@ -46,11 +46,11 @@ export const auth = betterAuth({ required: false, input: false, }, - siteRole:{ - type:"string", - defaultValue:"USER", - input:false, - } + siteRole: { + type: "string", + defaultValue: "USER", + input: false, + }, }, }, advanced: { @@ -61,7 +61,7 @@ export const auth = betterAuth({ minPasswordLength: AUTH_CONFIG.emailAndPassword.minPasswordLength, maxPasswordLength: AUTH_CONFIG.emailAndPassword.maxPasswordLength, }, - // TODO: Reference the following link to see if it is easier to have the social provider's returned values map to first and last name instead + // TODO(https://github.com/acmutsa/Fallback/issues/14): Reference the following link to see if it is easier to have the social provider's returned values map to first and last name instead // https://www.better-auth.com/docs/concepts/database#extending-core-schema:~:text=Example%3A%20Mapping%20Profile%20to%20User%20For%20firstName%20and%20lastName // socialProviders: { // google: { diff --git a/apps/api/src/lib/functions/middleware.ts b/apps/api/src/lib/functions/middleware.ts index 484b359..df9ce98 100644 --- a/apps/api/src/lib/functions/middleware.ts +++ b/apps/api/src/lib/functions/middleware.ts @@ -2,9 +2,8 @@ import type { Context, Next } from "hono"; import { auth } from "../auth"; export const MIDDLEWARE_PUBLIC_ROUTES = ["/health", "/api/auth"]; +//TODO(https://github.com/acmutsa/Fallback/issues/16): Make these function's context types safe -// We need to grab the specific type of context here as we know for the middleware it will always be the same as the overall api -// TODO: Make this type safe export async function setUserSessionContextMiddleware(c: Context, next: Next) { const session = await auth.api.getSession({ headers: c.req.raw.headers }); diff --git a/apps/api/src/routes/user.ts b/apps/api/src/routes/user.ts index 159deb3..f5b4442 100644 --- a/apps/api/src/routes/user.ts +++ b/apps/api/src/routes/user.ts @@ -17,7 +17,6 @@ const userhandler = HonoBetterAuth() zValidator( "query", z.object({ - // TODO: Tighten up a little bit userId: z.string().min(1, "User ID is required"), }), ), diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index aac6114..f09fc00 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -29,5 +29,5 @@ export default defineConfig({ }, }); -// TODO: Come back and look for a way to validate the environment variables before the app starts up and fail if they are not validated -// TODO: Add intellisense for import.meta.env - https://vite.dev/guide/env-and-mode.html#intellisense-for-typescript +// TODO(https://github.com/acmutsa/Fallback/issues/15): Come back and look for a way to validate the environment variables before the app starts up and fail if they are not validated +// TODO(https://github.com/acmutsa/Fallback/issues/15): Add intellisense for import.meta.env - https://vite.dev/guide/env-and-mode.html#intellisense-for-typescript From 7c585f52e9c8157f826aa8aa565a57800023a019 Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Sat, 18 Oct 2025 22:05:45 -0600 Subject: [PATCH 04/45] ensures protection of sign in and sign up routes --- apps/web/src/lib/functions/auth.ts | 93 +++------------------------ apps/web/src/lib/types.ts | 6 ++ apps/web/src/providers.tsx | 1 + apps/web/src/routes/__root.tsx | 6 +- apps/web/src/routes/sign-in/index.tsx | 11 ++-- apps/web/src/routes/sign-up/index.tsx | 15 ++--- 6 files changed, 29 insertions(+), 103 deletions(-) diff --git a/apps/web/src/lib/functions/auth.ts b/apps/web/src/lib/functions/auth.ts index 5bce68e..1e69dd6 100644 --- a/apps/web/src/lib/functions/auth.ts +++ b/apps/web/src/lib/functions/auth.ts @@ -1,88 +1,7 @@ import { authClient } from "../auth-client"; -import type { EmailSignUpType, EmailSignInType } from "../types"; -import { toast } from "sonner"; -import { - getRandomSignInGreeting, - getFirstName, - getRandomSignUpGreeting, -} from "../utils"; import { PUBLIC_ROUTES } from "shared/constants"; - -const callbackURL = "/dashboard"; // A URL to redirect to after the user verifies their email (optional) - -export async function signUpEmail(inputs: EmailSignUpType) { - const { redirectUrl, ...restInputs } = inputs; - await authClient.signUp.email( - { - ...restInputs, - callbackURL: redirectUrl || callbackURL, - }, - { - onSuccess: (ctx) => { - // This could be wrong - const firstName = getFirstName(ctx.data.user.name); - toast.success(getRandomSignUpGreeting(firstName)); - }, - onError: () => { - toast.error( - "Something went wrong signing you up. Please try again later.", - ); - }, - }, - ); -} - -export async function signInEmail(inputs: EmailSignInType) { - const { redirectUrl, ...restInputs } = inputs; - const { data, error } = await authClient.signIn.email( - { - ...restInputs, - callbackURL: redirectUrl || callbackURL, - }, - { - onSuccess: (ctx) => { - const firstName = getFirstName(ctx.data.user.name); - toast.success(getRandomSignInGreeting(firstName)); - }, - onError: () => { - toast.error( - "Something went wrong signing you in. Please try again later.", - ); - }, - }, - ); - - return { name: data?.user.name, error: error?.message }; -} - -export async function signInOauth(provider: string, redirectUrl?: string) { - await authClient.signIn.social( - { - provider, - /** - * A URL to redirect after the user authenticates with the provider - * @default "/" - */ - callbackURL: redirectUrl || callbackURL, - /** - * A URL to redirect if an error occurs during the sign in process - */ - errorCallbackURL: "/error", // come back and confiure this later maybe for logging purposes - }, - { - onSuccess: (ctx) => { - const firstName = getFirstName(ctx.data.user.name); - toast.success(getRandomSignInGreeting(firstName)); - }, - onError: () => { - // display the error message - toast.error( - "Something went wrong signing you in. Please try again later.", - ); - }, - }, - ); -} +import type { RouterContext } from "../types"; +import { redirect } from "@tanstack/react-router"; export function isPublicRoute(pathname:string){ return PUBLIC_ROUTES.includes(pathname); @@ -100,3 +19,11 @@ export async function signOut() { const { data, error } = await authClient.signOut(); return { data, error }; } + +export function redirectIfSignedIn(ctx: RouterContext, to:string = '/') { + if (ctx.auth?.data){ + throw redirect({ + to + }) + } +} \ No newline at end of file diff --git a/apps/web/src/lib/types.ts b/apps/web/src/lib/types.ts index 3fc43bb..a3db4fa 100644 --- a/apps/web/src/lib/types.ts +++ b/apps/web/src/lib/types.ts @@ -1,5 +1,11 @@ import z from "zod"; import { emailSignUpSchema, emailSignInSchema } from "./zod"; +import { QueryClient } from "@tanstack/react-query"; +import { getSession } from "@/lib/functions/auth"; export type EmailSignUpType = z.infer; export type EmailSignInType = z.infer; +export type RouterContext = { + queryClient: QueryClient; + auth?: Awaited>; +}; \ No newline at end of file diff --git a/apps/web/src/providers.tsx b/apps/web/src/providers.tsx index 3621f78..ff2bde9 100644 --- a/apps/web/src/providers.tsx +++ b/apps/web/src/providers.tsx @@ -30,6 +30,7 @@ export function Providers({ children }: { children: React.ReactNode }) { SIGN_UP:"Create Account", SIGN_UP_DESCRIPTION:"Let's get you started with a free account.", }} + // avatar={{ diff --git a/apps/web/src/routes/__root.tsx b/apps/web/src/routes/__root.tsx index d27cbd7..b1af4f4 100644 --- a/apps/web/src/routes/__root.tsx +++ b/apps/web/src/routes/__root.tsx @@ -1,15 +1,11 @@ -import type { QueryClient } from "@tanstack/react-query"; import { Outlet, createRootRouteWithContext } from "@tanstack/react-router"; import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; import { getSession } from "@/lib/functions/auth"; import { redirect } from "@tanstack/react-router"; import { isProtectedRoute } from "@/lib/functions/auth"; import ErrorComponent from "@/components/shared/error"; +import type { RouterContext } from "@/lib/types"; -type RouterContext = { - queryClient: QueryClient; - auth?: Awaited>; -}; export const Route = createRootRouteWithContext()({ beforeLoad: async({location}) =>{ diff --git a/apps/web/src/routes/sign-in/index.tsx b/apps/web/src/routes/sign-in/index.tsx index 9ac6528..9f04cbd 100644 --- a/apps/web/src/routes/sign-in/index.tsx +++ b/apps/web/src/routes/sign-in/index.tsx @@ -1,20 +1,17 @@ import { createFileRoute } from '@tanstack/react-router' import { AuthView } from '@daveyplate/better-auth-ui' -import {redirect} from "@tanstack/react-router" import { APP_NAME } from 'shared/constants'; +import { redirectIfSignedIn } from '@/lib/functions/auth'; export const Route = createFileRoute('/sign-in/')({ component: RouteComponent, + beforeLoad(ctx) { + redirectIfSignedIn(ctx.context); + } }) function RouteComponent() { - const {auth} = Route.useRouteContext() - if (auth?.data){ - return redirect({ - to:"/", - }) - } return (
diff --git a/apps/web/src/routes/sign-up/index.tsx b/apps/web/src/routes/sign-up/index.tsx index 2d5e3bd..669137f 100644 --- a/apps/web/src/routes/sign-up/index.tsx +++ b/apps/web/src/routes/sign-up/index.tsx @@ -1,19 +1,18 @@ import { createFileRoute } from '@tanstack/react-router' import { AuthView } from '@daveyplate/better-auth-ui' -import { redirect } from "@tanstack/react-router"; import { APP_NAME } from "shared/constants"; +import { redirectIfSignedIn } from '@/lib/functions/auth'; export const Route = createFileRoute("/sign-up/")({ component: RouteComponent, -}); + beforeLoad(ctx) { + redirectIfSignedIn(ctx.context); + } + }, +); function RouteComponent() { - const {auth} = Route.useRouteContext() - if (auth?.data){ - return redirect({ - to:"/profile", - }) - } + return (
From 717a3f92537bad8f956d152896651fe64bd72919 Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Mon, 20 Oct 2025 20:40:08 -0600 Subject: [PATCH 05/45] fix providers setup --- apps/web/src/main.tsx | 2 -- apps/web/src/providers.tsx | 6 +++--- apps/web/src/routes/__root.tsx | 6 ++++-- apps/web/src/routes/index.tsx | 2 ++ 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/web/src/main.tsx b/apps/web/src/main.tsx index 852570e..6f078eb 100644 --- a/apps/web/src/main.tsx +++ b/apps/web/src/main.tsx @@ -23,12 +23,10 @@ const rootElement = document.getElementById("app"); if (rootElement && !rootElement.innerHTML) { const root = ReactDOM.createRoot(rootElement); root.render( - - , ); } diff --git a/apps/web/src/providers.tsx b/apps/web/src/providers.tsx index ff2bde9..5896db7 100644 --- a/apps/web/src/providers.tsx +++ b/apps/web/src/providers.tsx @@ -6,14 +6,14 @@ import { QueryClientProvider } from "@tanstack/react-query"; import { queryClient } from "./router"; export function Providers({ children }: { children: React.ReactNode }) { - + const router = useRouter(); return ( useRouter().navigate({ href })} - replace={(href) => useRouter().navigate({ href, replace: true })} + navigate={(href) => router.navigate({ href })} + replace={(href) => router.navigate({ href, replace: true })} Link={({ href, ...props }) => } persistClient={false} basePath="/" diff --git a/apps/web/src/routes/__root.tsx b/apps/web/src/routes/__root.tsx index b1af4f4..ab08606 100644 --- a/apps/web/src/routes/__root.tsx +++ b/apps/web/src/routes/__root.tsx @@ -5,13 +5,13 @@ import { redirect } from "@tanstack/react-router"; import { isProtectedRoute } from "@/lib/functions/auth"; import ErrorComponent from "@/components/shared/error"; import type { RouterContext } from "@/lib/types"; +import { Providers } from "@/providers"; export const Route = createRootRouteWithContext()({ beforeLoad: async({location}) =>{ const auth = await getSession(); if (isProtectedRoute(location.pathname)) { - if (!auth.data){ throw redirect({ to:"/sign-in", @@ -28,7 +28,9 @@ export const Route = createRootRouteWithContext()({ }, component: () => ( <> - + + + ), diff --git a/apps/web/src/routes/index.tsx b/apps/web/src/routes/index.tsx index 866d39f..1f5dbb7 100644 --- a/apps/web/src/routes/index.tsx +++ b/apps/web/src/routes/index.tsx @@ -5,6 +5,7 @@ import { toast } from "sonner"; import { pingServerQuery } from "@/lib/queries"; import { useQuery } from "@tanstack/react-query"; import { SignedIn, SignedOut, UserButton } from "@daveyplate/better-auth-ui"; +import { Link } from "@tanstack/react-router"; export const Route = createFileRoute("/")({ loader: ({ context: { queryClient } }) => @@ -45,6 +46,7 @@ function App() { + Go to protected route ); From 5969492121018bee56f3d51f7bc19665c91f102c Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Thu, 23 Oct 2025 21:58:52 -0600 Subject: [PATCH 06/45] fixes up stuff --- apps/web/src/main.tsx | 1 - apps/web/src/providers.tsx | 37 +++++++++++++++++++------- apps/web/src/routeTree.gen.ts | 21 +++++++++++++++ apps/web/src/routes/settings/index.tsx | 11 ++++++++ apps/web/src/routes/sign-in/index.tsx | 10 ++++--- 5 files changed, 66 insertions(+), 14 deletions(-) create mode 100644 apps/web/src/routes/settings/index.tsx diff --git a/apps/web/src/main.tsx b/apps/web/src/main.tsx index 6f078eb..5a99efe 100644 --- a/apps/web/src/main.tsx +++ b/apps/web/src/main.tsx @@ -5,7 +5,6 @@ import { Toaster } from "./components/ui/sonner.tsx"; import "./styles.css"; import reportWebVitals from "./reportWebVitals.ts"; import { createAppRouter } from "./router.tsx"; -import { Providers } from "./providers.tsx"; // Create a new router instance diff --git a/apps/web/src/providers.tsx b/apps/web/src/providers.tsx index 5896db7..8a6d0d2 100644 --- a/apps/web/src/providers.tsx +++ b/apps/web/src/providers.tsx @@ -1,13 +1,15 @@ import { AuthUIProviderTanstack } from "@daveyplate/better-auth-ui/tanstack"; import { AuthQueryProvider } from "@daveyplate/better-auth-tanstack"; import { authClient } from "@/lib/auth-client"; -import { Link, useRouter } from "@tanstack/react-router"; +import { Link, useRouter, } from "@tanstack/react-router"; import { QueryClientProvider } from "@tanstack/react-query"; import { queryClient } from "./router"; +import { AUTH_CONFIG } from "shared/constants"; export function Providers({ children }: { children: React.ReactNode }) { const router = useRouter(); return ( + // Query client is caching something it def should not be so we need to look at this later router.navigate({ href })} replace={(href) => router.navigate({ href, replace: true })} Link={({ href, ...props }) => } + onSessionChange={() => { + router.invalidate(); + }} persistClient={false} basePath="/" + account={{ + basePath:"/" + }} baseURL={ import.meta.env.VITE_FALLBACK_WEB_URL || "http://localhost:3000" @@ -24,15 +32,24 @@ export function Providers({ children }: { children: React.ReactNode }) { social={{ providers: ["github", "google", "discord", "linear"], }} - localization={{ - SIGN_IN:"Sign In", - SIGN_IN_DESCRIPTION:"Welcome back! Please enter your details.", - SIGN_UP:"Create Account", - SIGN_UP_DESCRIPTION:"Let's get you started with a free account.", - }} - - - + localization={{ + SIGN_IN: "Sign In", + SIGN_IN_DESCRIPTION: + "Welcome back! Please enter your details.", + SIGN_UP: "Create Account", + SIGN_UP_DESCRIPTION: + "Let's get you started with a free account.", + }} + credentials={{ + passwordValidation:{ + minLength:AUTH_CONFIG.emailAndPassword.minPasswordLength, + maxLength:AUTH_CONFIG.emailAndPassword.maxPasswordLength + }, + confirmPassword:true, + forgotPassword:true, + rememberMe:true, +}} + // TODO:(https://github.com/acmutsa/Fallback/issues/20):Enable avatar upload handling // avatar={{ // upload: async (file) => { // const formData = new FormData(); diff --git a/apps/web/src/routeTree.gen.ts b/apps/web/src/routeTree.gen.ts index 50bae10..8f4b57a 100644 --- a/apps/web/src/routeTree.gen.ts +++ b/apps/web/src/routeTree.gen.ts @@ -13,6 +13,7 @@ import { Route as IndexRouteImport } from './routes/index' import { Route as TeamIndexRouteImport } from './routes/team/index' import { Route as SignUpIndexRouteImport } from './routes/sign-up/index' import { Route as SignInIndexRouteImport } from './routes/sign-in/index' +import { Route as SettingsIndexRouteImport } from './routes/settings/index' import { Route as ProfileIndexRouteImport } from './routes/profile/index' import { Route as TeamNewRouteImport } from './routes/team/new' import { Route as TeamTeamIdIndexRouteImport } from './routes/team/$teamId/index' @@ -38,6 +39,11 @@ const SignInIndexRoute = SignInIndexRouteImport.update({ path: '/sign-in/', getParentRoute: () => rootRouteImport, } as any) +const SettingsIndexRoute = SettingsIndexRouteImport.update({ + id: '/settings/', + path: '/settings/', + getParentRoute: () => rootRouteImport, +} as any) const ProfileIndexRoute = ProfileIndexRouteImport.update({ id: '/profile/', path: '/profile/', @@ -63,6 +69,7 @@ export interface FileRoutesByFullPath { '/': typeof IndexRoute '/team/new': typeof TeamNewRoute '/profile': typeof ProfileIndexRoute + '/settings': typeof SettingsIndexRoute '/sign-in': typeof SignInIndexRoute '/sign-up': typeof SignUpIndexRoute '/team': typeof TeamIndexRoute @@ -73,6 +80,7 @@ export interface FileRoutesByTo { '/': typeof IndexRoute '/team/new': typeof TeamNewRoute '/profile': typeof ProfileIndexRoute + '/settings': typeof SettingsIndexRoute '/sign-in': typeof SignInIndexRoute '/sign-up': typeof SignUpIndexRoute '/team': typeof TeamIndexRoute @@ -84,6 +92,7 @@ export interface FileRoutesById { '/': typeof IndexRoute '/team/new': typeof TeamNewRoute '/profile/': typeof ProfileIndexRoute + '/settings/': typeof SettingsIndexRoute '/sign-in/': typeof SignInIndexRoute '/sign-up/': typeof SignUpIndexRoute '/team/': typeof TeamIndexRoute @@ -96,6 +105,7 @@ export interface FileRouteTypes { | '/' | '/team/new' | '/profile' + | '/settings' | '/sign-in' | '/sign-up' | '/team' @@ -106,6 +116,7 @@ export interface FileRouteTypes { | '/' | '/team/new' | '/profile' + | '/settings' | '/sign-in' | '/sign-up' | '/team' @@ -116,6 +127,7 @@ export interface FileRouteTypes { | '/' | '/team/new' | '/profile/' + | '/settings/' | '/sign-in/' | '/sign-up/' | '/team/' @@ -127,6 +139,7 @@ export interface RootRouteChildren { IndexRoute: typeof IndexRoute TeamNewRoute: typeof TeamNewRoute ProfileIndexRoute: typeof ProfileIndexRoute + SettingsIndexRoute: typeof SettingsIndexRoute SignInIndexRoute: typeof SignInIndexRoute SignUpIndexRoute: typeof SignUpIndexRoute TeamIndexRoute: typeof TeamIndexRoute @@ -164,6 +177,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof SignInIndexRouteImport parentRoute: typeof rootRouteImport } + '/settings/': { + id: '/settings/' + path: '/settings' + fullPath: '/settings' + preLoaderRoute: typeof SettingsIndexRouteImport + parentRoute: typeof rootRouteImport + } '/profile/': { id: '/profile/' path: '/profile' @@ -199,6 +219,7 @@ const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, TeamNewRoute: TeamNewRoute, ProfileIndexRoute: ProfileIndexRoute, + SettingsIndexRoute: SettingsIndexRoute, SignInIndexRoute: SignInIndexRoute, SignUpIndexRoute: SignUpIndexRoute, TeamIndexRoute: TeamIndexRoute, diff --git a/apps/web/src/routes/settings/index.tsx b/apps/web/src/routes/settings/index.tsx new file mode 100644 index 0000000..4405cb2 --- /dev/null +++ b/apps/web/src/routes/settings/index.tsx @@ -0,0 +1,11 @@ +import { createFileRoute } from '@tanstack/react-router' +import { AccountSettingsCards } from '@daveyplate/better-auth-ui' + +export const Route = createFileRoute('/settings/')({ + component: RouteComponent, +}) + +// TODO: Rip this out and replace with our own. This is just for demo purposes +function RouteComponent() { + return ; +} diff --git a/apps/web/src/routes/sign-in/index.tsx b/apps/web/src/routes/sign-in/index.tsx index 9f04cbd..d50ac64 100644 --- a/apps/web/src/routes/sign-in/index.tsx +++ b/apps/web/src/routes/sign-in/index.tsx @@ -15,11 +15,15 @@ function RouteComponent() { return (
-

Welcome back 👋

-

Sign back into {APP_NAME} to pick up where you left off

+

+ Welcome back 👋{" "} +

+

+ Sign back into {APP_NAME} to pick up where you left off +

- +
); From b68a3a60488815607678769940d340280c661bed Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Fri, 24 Oct 2025 07:56:20 -0600 Subject: [PATCH 07/45] Adds sidebar --- apps/web/components.json | 2 +- apps/web/package.json | 2 + apps/web/src/components/ui/input.tsx | 21 + apps/web/src/components/ui/sheet.tsx | 139 +++++ apps/web/src/components/ui/sidebar.tsx | 726 ++++++++++++++++++++++++ apps/web/src/components/ui/skeleton.tsx | 13 + apps/web/src/components/ui/tooltip.tsx | 59 ++ apps/web/src/hooks/use-mobile.ts | 19 + pnpm-lock.yaml | 39 ++ 9 files changed, 1019 insertions(+), 1 deletion(-) create mode 100644 apps/web/src/components/ui/input.tsx create mode 100644 apps/web/src/components/ui/sheet.tsx create mode 100644 apps/web/src/components/ui/sidebar.tsx create mode 100644 apps/web/src/components/ui/skeleton.tsx create mode 100644 apps/web/src/components/ui/tooltip.tsx create mode 100644 apps/web/src/hooks/use-mobile.ts diff --git a/apps/web/components.json b/apps/web/components.json index cfbafe2..e60cc81 100644 --- a/apps/web/components.json +++ b/apps/web/components.json @@ -5,7 +5,7 @@ "tsx": true, "tailwind": { "config": "", - "css": "src/styles/globals.css", + "css": "src/styles.css", "baseColor": "neutral", "cssVariables": true, "prefix": "" diff --git a/apps/web/package.json b/apps/web/package.json index 1b128c0..c2a7791 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -12,8 +12,10 @@ "dependencies": { "@daveyplate/better-auth-tanstack": "^1.3.6", "@daveyplate/better-auth-ui": "^3.1.10", + "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-separator": "^1.1.7", "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-tooltip": "^1.2.8", "@tailwindcss/vite": "^4.1.11", "@tanstack/react-query": "^5.87.4", "@tanstack/react-router": "^1.130.2", diff --git a/apps/web/src/components/ui/input.tsx b/apps/web/src/components/ui/input.tsx new file mode 100644 index 0000000..8916905 --- /dev/null +++ b/apps/web/src/components/ui/input.tsx @@ -0,0 +1,21 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Input({ className, type, ...props }: React.ComponentProps<"input">) { + return ( + + ) +} + +export { Input } diff --git a/apps/web/src/components/ui/sheet.tsx b/apps/web/src/components/ui/sheet.tsx new file mode 100644 index 0000000..84649ad --- /dev/null +++ b/apps/web/src/components/ui/sheet.tsx @@ -0,0 +1,139 @@ +"use client" + +import * as React from "react" +import * as SheetPrimitive from "@radix-ui/react-dialog" +import { XIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Sheet({ ...props }: React.ComponentProps) { + return +} + +function SheetTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function SheetClose({ + ...props +}: React.ComponentProps) { + return +} + +function SheetPortal({ + ...props +}: React.ComponentProps) { + return +} + +function SheetOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SheetContent({ + className, + children, + side = "right", + ...props +}: React.ComponentProps & { + side?: "top" | "right" | "bottom" | "left" +}) { + return ( + + + + {children} + + + Close + + + + ) +} + +function SheetHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function SheetFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function SheetTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SheetDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Sheet, + SheetTrigger, + SheetClose, + SheetContent, + SheetHeader, + SheetFooter, + SheetTitle, + SheetDescription, +} diff --git a/apps/web/src/components/ui/sidebar.tsx b/apps/web/src/components/ui/sidebar.tsx new file mode 100644 index 0000000..30638ac --- /dev/null +++ b/apps/web/src/components/ui/sidebar.tsx @@ -0,0 +1,726 @@ +"use client" + +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" +import { PanelLeftIcon } from "lucide-react" + +import { useIsMobile } from "@/hooks/use-mobile" +import { cn } from "@/lib/utils" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Separator } from "@/components/ui/separator" +import { + Sheet, + SheetContent, + SheetDescription, + SheetHeader, + SheetTitle, +} from "@/components/ui/sheet" +import { Skeleton } from "@/components/ui/skeleton" +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip" + +const SIDEBAR_COOKIE_NAME = "sidebar_state" +const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7 +const SIDEBAR_WIDTH = "16rem" +const SIDEBAR_WIDTH_MOBILE = "18rem" +const SIDEBAR_WIDTH_ICON = "3rem" +const SIDEBAR_KEYBOARD_SHORTCUT = "b" + +type SidebarContextProps = { + state: "expanded" | "collapsed" + open: boolean + setOpen: (open: boolean) => void + openMobile: boolean + setOpenMobile: (open: boolean) => void + isMobile: boolean + toggleSidebar: () => void +} + +const SidebarContext = React.createContext(null) + +function useSidebar() { + const context = React.useContext(SidebarContext) + if (!context) { + throw new Error("useSidebar must be used within a SidebarProvider.") + } + + return context +} + +function SidebarProvider({ + defaultOpen = true, + open: openProp, + onOpenChange: setOpenProp, + className, + style, + children, + ...props +}: React.ComponentProps<"div"> & { + defaultOpen?: boolean + open?: boolean + onOpenChange?: (open: boolean) => void +}) { + const isMobile = useIsMobile() + const [openMobile, setOpenMobile] = React.useState(false) + + // This is the internal state of the sidebar. + // We use openProp and setOpenProp for control from outside the component. + const [_open, _setOpen] = React.useState(defaultOpen) + const open = openProp ?? _open + const setOpen = React.useCallback( + (value: boolean | ((value: boolean) => boolean)) => { + const openState = typeof value === "function" ? value(open) : value + if (setOpenProp) { + setOpenProp(openState) + } else { + _setOpen(openState) + } + + // This sets the cookie to keep the sidebar state. + document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}` + }, + [setOpenProp, open] + ) + + // Helper to toggle the sidebar. + const toggleSidebar = React.useCallback(() => { + return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open) + }, [isMobile, setOpen, setOpenMobile]) + + // Adds a keyboard shortcut to toggle the sidebar. + React.useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if ( + event.key === SIDEBAR_KEYBOARD_SHORTCUT && + (event.metaKey || event.ctrlKey) + ) { + event.preventDefault() + toggleSidebar() + } + } + + window.addEventListener("keydown", handleKeyDown) + return () => window.removeEventListener("keydown", handleKeyDown) + }, [toggleSidebar]) + + // We add a state so that we can do data-state="expanded" or "collapsed". + // This makes it easier to style the sidebar with Tailwind classes. + const state = open ? "expanded" : "collapsed" + + const contextValue = React.useMemo( + () => ({ + state, + open, + setOpen, + isMobile, + openMobile, + setOpenMobile, + toggleSidebar, + }), + [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar] + ) + + return ( + + +
+ {children} +
+
+
+ ) +} + +function Sidebar({ + side = "left", + variant = "sidebar", + collapsible = "offcanvas", + className, + children, + ...props +}: React.ComponentProps<"div"> & { + side?: "left" | "right" + variant?: "sidebar" | "floating" | "inset" + collapsible?: "offcanvas" | "icon" | "none" +}) { + const { isMobile, state, openMobile, setOpenMobile } = useSidebar() + + if (collapsible === "none") { + return ( +
+ {children} +
+ ) + } + + if (isMobile) { + return ( + + + + Sidebar + Displays the mobile sidebar. + +
{children}
+
+
+ ) + } + + return ( +
+ {/* This is what handles the sidebar gap on desktop */} +
+ +
+ ) +} + +function SidebarTrigger({ + className, + onClick, + ...props +}: React.ComponentProps) { + const { toggleSidebar } = useSidebar() + + return ( + + ) +} + +function SidebarRail({ className, ...props }: React.ComponentProps<"button">) { + const { toggleSidebar } = useSidebar() + + return ( + +
+ or +
+ + { + setTeamId(input.target.value) + }} className="border-r-0" /> + +
+ + ); + +} \ No newline at end of file diff --git a/apps/web/src/components/shared/AppSidebar/nav-user.tsx b/apps/web/src/components/shared/AppSidebar/nav-user.tsx new file mode 100644 index 0000000..58066f2 --- /dev/null +++ b/apps/web/src/components/shared/AppSidebar/nav-user.tsx @@ -0,0 +1,125 @@ +import { + BadgeCheck, + Bell, + ChevronsUpDown, + CreditCard, + LogOut, + Sparkles, +} from "lucide-react" + +import { + Avatar, + AvatarFallback, + AvatarImage, +} from "@/components/ui/avatar" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from "@/components/ui/sidebar" +import { Button } from "@/components/ui/button" +import { Link } from "@tanstack/react-router" +import { type UserType } from "api/src/lib/types" + +export function NavUser({ + // userData, +}: { + // user: GetSessionType +}) { + // const userData = user?.data; + + // if (!userData){ + + // } + + return null; + + +} + + +function NavUserAuthenticated({ user }: { user: UserType }) { + const { isMobile } = useSidebar() + + + return ( + + + + + + + + CN + +
+ {user!.name} + {user!.email} +
+ +
+
+ + +
+ + + CN + +
+ {user!.name} + {user!.email} +
+
+
+ + + + + Upgrade to Pro + + + + + + + Account + + + + Billing + + + + Notifications + + + + + + Log out + +
+
+
+
+ ) +} \ No newline at end of file diff --git a/apps/web/src/components/shared/AppSidebar/team-switcher.tsx b/apps/web/src/components/shared/AppSidebar/team-switcher.tsx new file mode 100644 index 0000000..083e9ec --- /dev/null +++ b/apps/web/src/components/shared/AppSidebar/team-switcher.tsx @@ -0,0 +1,91 @@ +"use client" + +import * as React from "react" +import { ChevronsUpDown, Plus } from "lucide-react" + +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from "@/components/ui/sidebar" + +export function TeamSwitcher({ + teams, +}: { + teams: { + name: string + logo: React.ElementType + plan: string + }[] +}) { + const { isMobile } = useSidebar() + const [activeTeam, setActiveTeam] = React.useState(teams[0]) + + if (!activeTeam) { + return null + } + + return ( + + + + + +
+ +
+
+ {activeTeam.name} + {activeTeam.plan} +
+ +
+
+ + + Teams + + {teams.map((team, index) => ( + setActiveTeam(team)} + className="gap-2 p-2" + > +
+ +
+ {team.name} + ⌘{index + 1} +
+ ))} + + +
+ +
+
Add team
+
+
+
+
+
+ ) +} diff --git a/apps/web/src/components/ui/avatar.tsx b/apps/web/src/components/ui/avatar.tsx new file mode 100644 index 0000000..71e428b --- /dev/null +++ b/apps/web/src/components/ui/avatar.tsx @@ -0,0 +1,53 @@ +"use client" + +import * as React from "react" +import * as AvatarPrimitive from "@radix-ui/react-avatar" + +import { cn } from "@/lib/utils" + +function Avatar({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarImage({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarFallback({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Avatar, AvatarImage, AvatarFallback } diff --git a/apps/web/src/components/ui/breadcrumb.tsx b/apps/web/src/components/ui/breadcrumb.tsx new file mode 100644 index 0000000..eb88f32 --- /dev/null +++ b/apps/web/src/components/ui/breadcrumb.tsx @@ -0,0 +1,109 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { ChevronRight, MoreHorizontal } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { + return
); -} \ No newline at end of file +} diff --git a/apps/web/src/components/ui/avatar.tsx b/apps/web/src/components/ui/avatar.tsx index 71e428b..3f19c82 100644 --- a/apps/web/src/components/ui/avatar.tsx +++ b/apps/web/src/components/ui/avatar.tsx @@ -1,53 +1,53 @@ -"use client" +"use client"; -import * as React from "react" -import * as AvatarPrimitive from "@radix-ui/react-avatar" +import * as React from "react"; +import * as AvatarPrimitive from "@radix-ui/react-avatar"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; function Avatar({ - className, - ...props + className, + ...props }: React.ComponentProps) { - return ( - - ) + return ( + + ); } function AvatarImage({ - className, - ...props + className, + ...props }: React.ComponentProps) { - return ( - - ) + return ( + + ); } function AvatarFallback({ - className, - ...props + className, + ...props }: React.ComponentProps) { - return ( - - ) + return ( + + ); } -export { Avatar, AvatarImage, AvatarFallback } +export { Avatar, AvatarImage, AvatarFallback }; diff --git a/apps/web/src/components/ui/breadcrumb.tsx b/apps/web/src/components/ui/breadcrumb.tsx index eb88f32..9392996 100644 --- a/apps/web/src/components/ui/breadcrumb.tsx +++ b/apps/web/src/components/ui/breadcrumb.tsx @@ -1,109 +1,109 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { ChevronRight, MoreHorizontal } from "lucide-react" +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { ChevronRight, MoreHorizontal } from "lucide-react"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { - return