Ajout de la configuration Keycloak et intégration de NextAuth pour l'authentification

This commit is contained in:
Kevin 2025-02-19 00:47:01 +01:00
parent 06acc30ff7
commit 9e22498072
13 changed files with 498 additions and 156 deletions

8
.env Normal file
View File

@ -0,0 +1,8 @@
# URL
MAIN_DOMAIN=
KEYCLOAK_HOST=connect
KEYCLOAK_HOST_IP=
# Keycloak
KEYCLOAK_USER=
KEYCLOAK_PASSWORD=

View File

@ -1,6 +1,9 @@
networks: networks:
default: default:
volumes:
keycloak_data:
services: services:
traefik: traefik:
container_name: neah-traefik container_name: neah-traefik
@ -28,6 +31,8 @@ services:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.neah-front.rule=Host(`${MAIN_DOMAIN}`)" - "traefik.http.routers.neah-front.rule=Host(`${MAIN_DOMAIN}`)"
- "traefik.http.services.neah-front.loadbalancer.server.port=3000" - "traefik.http.services.neah-front.loadbalancer.server.port=3000"
extra_hosts:
- "${KEYCLOAK_HOST}.${MAIN_DOMAIN}:${KEYCLOAK_HOST_IP}"
networks: networks:
- default - default
@ -43,5 +48,9 @@ services:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.neah-keycloak.rule=Host(`${KEYCLOAK_HOST}.${MAIN_DOMAIN}`)" - "traefik.http.routers.neah-keycloak.rule=Host(`${KEYCLOAK_HOST}.${MAIN_DOMAIN}`)"
- "traefik.http.services.neah-keycloak.loadbalancer.server.port=8080" - "traefik.http.services.neah-keycloak.loadbalancer.server.port=8080"
volumes:
- keycloak_data:/opt/keycloak/data
ports:
- "8090:8080"
networks: networks:
- default - default

7
front/.env.production Normal file
View File

@ -0,0 +1,7 @@
NEXTAUTH_URL=http://neah.local
NEXTAUTH_SECRET=9eff5ad2f4b5ea744a34d9d8004cb5236f1931b26bf75f01a0a26203312fe1ec
KEYCLOAK_CLIENT_ID=front
KEYCLOAK_CLIENT_SECRET=Klsbm7hzyXscypXU0wUPPVBrttFPt6Pn
KEYCLOAK_REALM=master
KEYCLOAK_ISSUER=http://connect.neah.local/realms/master

View File

@ -0,0 +1,51 @@
import NextAuth, { NextAuthOptions } from "next-auth";
import KeycloakProvider from "next-auth/providers/keycloak";
export const authOptions: NextAuthOptions = {
providers: [
KeycloakProvider({
clientId: process.env.KEYCLOAK_CLIENT_ID!,
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET!,
issuer: process.env.KEYCLOAK_ISSUER!,
// Personnalisation de la fonction profile pour inclure le rôle de Keycloak
profile(profileData) {
return {
id: profileData.sub,
name: profileData.name || profileData.preferred_username,
email: profileData.email,
image: null,
// Extraction du rôle ou groupe de l'utilisateur depuis Keycloak
role: Array.isArray(profileData.realm_access?.roles)
? profileData.realm_access.roles
: [],
};
},
}),
],
callbacks: {
async jwt({ token, account, profile }) {
// Au moment de la première connexion, sauvegarde de l'access token et du rôle dans le JWT
if (account && profile) {
token.accessToken = account.access_token;
token.role = profile.role;
}
return token;
},
async session({ session, token }) {
// On injecte l'access token et le rôle dans la session accessible côté client
session.accessToken = token.accessToken as string;
session.user.role =
typeof token.role == "string" || Array.isArray(token.role)
? token.role
: [];
return session;
},
},
session: {
strategy: "jwt",
},
};
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };

View File

@ -1,45 +1,47 @@
import type { Metadata } from "next" "use client";
import { Inter } from "next/font/google"
import "./globals.css"
import { MainNav } from "@/components/main-nav"
const inter = Inter({ subsets: ["latin"] }) import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import { MainNav } from "@/components/main-nav";
import Link from "next/link";
import { SessionProvider } from "next-auth/react";
export const metadata: Metadata = { const inter = Inter({ subsets: ["latin"] });
title: "Space Dashboard",
description: "A modern space-themed dashboard", interface RootLayoutProps {
children: React.ReactNode;
} }
export default function RootLayout({ export default function RootLayout({
children, children,
}: { }: Readonly<RootLayoutProps>): JSX.Element {
children: React.ReactNode
}) {
return ( return (
<html lang="en"> <html lang='en'>
<body className={`${inter.className} bg-background text-foreground`}> <body className={`${inter.className} bg-background text-foreground`}>
<div className="min-h-screen flex flex-col"> <SessionProvider>
<MainNav /> <div className='min-h-screen flex flex-col'>
<main className="flex-1">{children}</main> <MainNav />
<footer className="w-full p-4 bg-black text-white/80"> <main className='flex-1'>{children}</main>
<div className="flex space-x-4 text-sm"> <footer className='w-full p-4 bg-black text-white/80'>
<a href="#" className="hover:text-white"> <div className='flex space-x-4 text-sm'>
Support <Link href='/support' className='hover:text-white'>
</a> Support
<a href="#" className="hover:text-white"> </Link>
Help Center <Link href='/help' className='hover:text-white'>
</a> Help Center
<a href="#" className="hover:text-white"> </Link>
Privacy <Link href='/privacy' className='hover:text-white'>
</a> Privacy
<a href="#" className="hover:text-white"> </Link>
Terms of Service <Link href='/tos' className='hover:text-white'>
</a> Terms of Service
</div> </Link>
</footer> </div>
</div> </footer>
</div>
</SessionProvider>
</body> </body>
</html> </html>
) );
} }

View File

@ -1,93 +1,84 @@
"use client" "use client";
import { useState } from 'react' import { useState } from "react";
import { Calendar, MessageSquare, BotIcon as Robot, PenTool, Bell } from 'lucide-react'
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { import {
DropdownMenu, Calendar,
DropdownMenuContent, MessageSquare,
DropdownMenuItem, BotIcon as Robot,
DropdownMenuTrigger, PenTool,
} from "@/components/ui/dropdown-menu" Bell,
import Image from 'next/image' } from "lucide-react";
import Link from 'next/link' import Image from "next/image";
import { Sidebar } from './sidebar' import Link from "next/link";
import { Sidebar } from "./sidebar";
import { useSession } from "next-auth/react";
export function MainNav() { export function MainNav() {
const [isSidebarOpen, setIsSidebarOpen] = useState(false) const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const { data: session } = useSession();
return ( return (
<> <>
<div className="flex items-center justify-between p-4 bg-black"> <div className='flex items-center justify-between p-4 bg-black'>
<div className="flex items-center space-x-4"> <div className='flex items-center space-x-4'>
<button <button
className="text-white/80 hover:text-white" className='text-white/80 hover:text-white'
onClick={() => setIsSidebarOpen(true)} onClick={() => setIsSidebarOpen(true)}
> >
<span className="sr-only">Toggle menu</span> <span className='sr-only'>Toggle menu</span>
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns='http://www.w3.org/2000/svg'
width="24" width='24'
height="24" height='24'
viewBox="0 0 24 24" viewBox='0 0 24 24'
fill="none" fill='none'
stroke="currentColor" stroke='currentColor'
strokeWidth="2" strokeWidth='2'
strokeLinecap="round" strokeLinecap='round'
strokeLinejoin="round" strokeLinejoin='round'
> >
<line x1="3" y1="12" x2="21" y2="12"></line> <line x1='3' y1='12' x2='21' y2='12'></line>
<line x1="3" y1="6" x2="21" y2="6"></line> <line x1='3' y1='6' x2='21' y2='6'></line>
<line x1="3" y1="18" x2="21" y2="18"></line> <line x1='3' y1='18' x2='21' y2='18'></line>
</svg> </svg>
</button> </button>
<Link href="/"> <Link href='/'>
<Image <Image
src="https://hebbkx1anhila5yf.public.blob.vercel-storage.com/enkun-4TNAp6sm9vEQNPg8XpLlizNyWW3jPD.svg" src='https://hebbkx1anhila5yf.public.blob.vercel-storage.com/enkun-4TNAp6sm9vEQNPg8XpLlizNyWW3jPD.svg'
alt="Logo" alt='Logo'
width={32} width={32}
height={32} height={32}
className="text-white" className='text-white'
/> />
</Link> </Link>
<Link href="/calendar" className="text-white/80 hover:text-white"> <Link href='/calendar' className='text-white/80 hover:text-white'>
<Calendar className="w-6 h-6" /> <Calendar className='w-6 h-6' />
</Link> </Link>
<Link href="/messages" className="text-white/80 hover:text-white"> <Link href='/messages' className='text-white/80 hover:text-white'>
<MessageSquare className="w-6 h-6" /> <MessageSquare className='w-6 h-6' />
</Link> </Link>
<Link href="/ai-assistant" className="text-white/80 hover:text-white"> <Link href='/ai-assistant' className='text-white/80 hover:text-white'>
<Robot className="w-6 h-6" /> <Robot className='w-6 h-6' />
</Link> </Link>
<Link href="/design" className="text-white/80 hover:text-white"> <Link href='/design' className='text-white/80 hover:text-white'>
<PenTool className="w-6 h-6" /> <PenTool className='w-6 h-6' />
</Link> </Link>
<Link href="/notifications" className="text-white/80 hover:text-white"> <Link
<Bell className="w-6 h-6" /> href='/notifications'
className='text-white/80 hover:text-white'
>
<Bell className='w-6 h-6' />
</Link> </Link>
</div> </div>
<DropdownMenu> <div className='cursor-pointer text-white/80 hover:text-white'>
<DropdownMenuTrigger asChild> {session ? (
<Avatar> <span>{session.user.name}</span>
<AvatarImage src="/placeholder.svg" /> ) : (
<AvatarFallback>U</AvatarFallback> <Link href='/api/auth/signin'>Login</Link>
</Avatar> )}
</DropdownMenuTrigger> </div>
<DropdownMenuContent align="end">
<DropdownMenuItem>
<a href="/signin">Sign In</a>
</DropdownMenuItem>
<DropdownMenuItem>
<a href="/signup">Sign Up</a>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div> </div>
<Sidebar <Sidebar isOpen={isSidebarOpen} onClose={() => setIsSidebarOpen(false)} />
isOpen={isSidebarOpen}
onClose={() => setIsSidebarOpen(false)}
/>
</> </>
) );
} }

View File

@ -1,27 +1,27 @@
"use client" "use client";
import * as React from "react" import * as React from "react";
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
import { Check, ChevronRight, Circle } from "lucide-react" import { Check, ChevronRight, Circle } from "lucide-react";
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils";
const DropdownMenu = DropdownMenuPrimitive.Root const DropdownMenu = DropdownMenuPrimitive.Root;
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
const DropdownMenuGroup = DropdownMenuPrimitive.Group const DropdownMenuGroup = DropdownMenuPrimitive.Group;
const DropdownMenuPortal = DropdownMenuPrimitive.Portal const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
const DropdownMenuSub = DropdownMenuPrimitive.Sub const DropdownMenuSub = DropdownMenuPrimitive.Sub;
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
const DropdownMenuSubTrigger = React.forwardRef< const DropdownMenuSubTrigger = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>, React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & { React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
inset?: boolean inset?: boolean;
} }
>(({ className, inset, children, ...props }, ref) => ( >(({ className, inset, children, ...props }, ref) => (
<DropdownMenuPrimitive.SubTrigger <DropdownMenuPrimitive.SubTrigger
@ -34,11 +34,11 @@ const DropdownMenuSubTrigger = React.forwardRef<
{...props} {...props}
> >
{children} {children}
<ChevronRight className="ml-auto" /> <ChevronRight className='ml-auto' />
</DropdownMenuPrimitive.SubTrigger> </DropdownMenuPrimitive.SubTrigger>
)) ));
DropdownMenuSubTrigger.displayName = DropdownMenuSubTrigger.displayName =
DropdownMenuPrimitive.SubTrigger.displayName DropdownMenuPrimitive.SubTrigger.displayName;
const DropdownMenuSubContent = React.forwardRef< const DropdownMenuSubContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>, React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
@ -52,9 +52,9 @@ const DropdownMenuSubContent = React.forwardRef<
)} )}
{...props} {...props}
/> />
)) ));
DropdownMenuSubContent.displayName = DropdownMenuSubContent.displayName =
DropdownMenuPrimitive.SubContent.displayName DropdownMenuPrimitive.SubContent.displayName;
const DropdownMenuContent = React.forwardRef< const DropdownMenuContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Content>, React.ElementRef<typeof DropdownMenuPrimitive.Content>,
@ -71,13 +71,13 @@ const DropdownMenuContent = React.forwardRef<
{...props} {...props}
/> />
</DropdownMenuPrimitive.Portal> </DropdownMenuPrimitive.Portal>
)) ));
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
const DropdownMenuItem = React.forwardRef< const DropdownMenuItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Item>, React.ElementRef<typeof DropdownMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean inset?: boolean;
} }
>(({ className, inset, ...props }, ref) => ( >(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Item <DropdownMenuPrimitive.Item
@ -89,8 +89,8 @@ const DropdownMenuItem = React.forwardRef<
)} )}
{...props} {...props}
/> />
)) ));
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
const DropdownMenuCheckboxItem = React.forwardRef< const DropdownMenuCheckboxItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>, React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
@ -105,16 +105,16 @@ const DropdownMenuCheckboxItem = React.forwardRef<
checked={checked} checked={checked}
{...props} {...props}
> >
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"> <span className='absolute left-2 flex h-3.5 w-3.5 items-center justify-center'>
<DropdownMenuPrimitive.ItemIndicator> <DropdownMenuPrimitive.ItemIndicator>
<Check className="h-4 w-4" /> <Check className='h-4 w-4' />
</DropdownMenuPrimitive.ItemIndicator> </DropdownMenuPrimitive.ItemIndicator>
</span> </span>
{children} {children}
</DropdownMenuPrimitive.CheckboxItem> </DropdownMenuPrimitive.CheckboxItem>
)) ));
DropdownMenuCheckboxItem.displayName = DropdownMenuCheckboxItem.displayName =
DropdownMenuPrimitive.CheckboxItem.displayName DropdownMenuPrimitive.CheckboxItem.displayName;
const DropdownMenuRadioItem = React.forwardRef< const DropdownMenuRadioItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>, React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
@ -128,20 +128,20 @@ const DropdownMenuRadioItem = React.forwardRef<
)} )}
{...props} {...props}
> >
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"> <span className='absolute left-2 flex h-3.5 w-3.5 items-center justify-center'>
<DropdownMenuPrimitive.ItemIndicator> <DropdownMenuPrimitive.ItemIndicator>
<Circle className="h-2 w-2 fill-current" /> <Circle className='h-2 w-2 fill-current' />
</DropdownMenuPrimitive.ItemIndicator> </DropdownMenuPrimitive.ItemIndicator>
</span> </span>
{children} {children}
</DropdownMenuPrimitive.RadioItem> </DropdownMenuPrimitive.RadioItem>
)) ));
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
const DropdownMenuLabel = React.forwardRef< const DropdownMenuLabel = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Label>, React.ElementRef<typeof DropdownMenuPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
inset?: boolean inset?: boolean;
} }
>(({ className, inset, ...props }, ref) => ( >(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Label <DropdownMenuPrimitive.Label
@ -153,8 +153,8 @@ const DropdownMenuLabel = React.forwardRef<
)} )}
{...props} {...props}
/> />
)) ));
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
const DropdownMenuSeparator = React.forwardRef< const DropdownMenuSeparator = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Separator>, React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
@ -165,8 +165,8 @@ const DropdownMenuSeparator = React.forwardRef<
className={cn("-mx-1 my-1 h-px bg-muted", className)} className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props} {...props}
/> />
)) ));
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
const DropdownMenuShortcut = ({ const DropdownMenuShortcut = ({
className, className,
@ -177,9 +177,9 @@ const DropdownMenuShortcut = ({
className={cn("ml-auto text-xs tracking-widest opacity-60", className)} className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props} {...props}
/> />
) );
} };
DropdownMenuShortcut.displayName = "DropdownMenuShortcut" DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
export { export {
DropdownMenu, DropdownMenu,
@ -197,4 +197,4 @@ export {
DropdownMenuSubContent, DropdownMenuSubContent,
DropdownMenuSubTrigger, DropdownMenuSubTrigger,
DropdownMenuRadioGroup, DropdownMenuRadioGroup,
} };

View File

@ -1,6 +1,6 @@
let userConfig = undefined let userConfig;
try { try {
userConfig = await import('./v0-user-next.config') userConfig = await import("./v0-user-next.config");
} catch (e) { } catch (e) {
// ignore error // ignore error
} }
@ -21,28 +21,28 @@ const nextConfig = {
parallelServerBuildTraces: true, parallelServerBuildTraces: true,
parallelServerCompiles: true, parallelServerCompiles: true,
}, },
} };
mergeConfig(nextConfig, userConfig) mergeConfig(nextConfig, userConfig);
function mergeConfig(nextConfig, userConfig) { function mergeConfig(nextConfig, userConfig) {
if (!userConfig) { if (!userConfig) {
return return;
} }
for (const key in userConfig) { for (const key in userConfig) {
if ( if (
typeof nextConfig[key] === 'object' && typeof nextConfig[key] === "object" &&
!Array.isArray(nextConfig[key]) !Array.isArray(nextConfig[key])
) { ) {
nextConfig[key] = { nextConfig[key] = {
...nextConfig[key], ...nextConfig[key],
...userConfig[key], ...userConfig[key],
} };
} else { } else {
nextConfig[key] = userConfig[key] nextConfig[key] = userConfig[key];
} }
} }
} }
export default nextConfig export default nextConfig;

154
front/package-lock.json generated
View File

@ -45,6 +45,7 @@
"input-otp": "1.4.1", "input-otp": "1.4.1",
"lucide-react": "^0.454.0", "lucide-react": "^0.454.0",
"next": "14.2.24", "next": "14.2.24",
"next-auth": "^4.24.11",
"next-themes": "^0.4.4", "next-themes": "^0.4.4",
"react": "^18", "react": "^18",
"react-day-picker": "8.10.1", "react-day-picker": "8.10.1",
@ -373,6 +374,15 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/@panva/hkdf": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz",
"integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/panva"
}
},
"node_modules/@pkgjs/parseargs": { "node_modules/@pkgjs/parseargs": {
"version": "0.11.0", "version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@ -2505,6 +2515,15 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/cookie": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.6", "version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@ -2994,6 +3013,15 @@
"jiti": "bin/jiti.js" "jiti": "bin/jiti.js"
} }
}, },
"node_modules/jose": {
"version": "4.15.9",
"resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz",
"integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/panva"
}
},
"node_modules/js-tokens": { "node_modules/js-tokens": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -3163,6 +3191,38 @@
} }
} }
}, },
"node_modules/next-auth": {
"version": "4.24.11",
"resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.11.tgz",
"integrity": "sha512-pCFXzIDQX7xmHFs4KVH4luCjaCbuPRtZ9oBUjUhOk84mZ9WVPf94n87TxYI4rSRf9HmfHEF8Yep3JrYDVOo3Cw==",
"license": "ISC",
"dependencies": {
"@babel/runtime": "^7.20.13",
"@panva/hkdf": "^1.0.2",
"cookie": "^0.7.0",
"jose": "^4.15.5",
"oauth": "^0.9.15",
"openid-client": "^5.4.0",
"preact": "^10.6.3",
"preact-render-to-string": "^5.1.19",
"uuid": "^8.3.2"
},
"peerDependencies": {
"@auth/core": "0.34.2",
"next": "^12.2.5 || ^13 || ^14 || ^15",
"nodemailer": "^6.6.5",
"react": "^17.0.2 || ^18 || ^19",
"react-dom": "^17.0.2 || ^18 || ^19"
},
"peerDependenciesMeta": {
"@auth/core": {
"optional": true
},
"nodemailer": {
"optional": true
}
}
},
"node_modules/next-themes": { "node_modules/next-themes": {
"version": "0.4.4", "version": "0.4.4",
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.4.tgz", "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.4.tgz",
@ -3220,6 +3280,12 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/oauth": {
"version": "0.9.15",
"resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
"integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==",
"license": "MIT"
},
"node_modules/object-assign": { "node_modules/object-assign": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@ -3236,6 +3302,51 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/oidc-token-hash": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz",
"integrity": "sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==",
"license": "MIT",
"engines": {
"node": "^10.13.0 || >=12.0.0"
}
},
"node_modules/openid-client": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.7.1.tgz",
"integrity": "sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==",
"license": "MIT",
"dependencies": {
"jose": "^4.15.9",
"lru-cache": "^6.0.0",
"object-hash": "^2.2.0",
"oidc-token-hash": "^5.0.3"
},
"funding": {
"url": "https://github.com/sponsors/panva"
}
},
"node_modules/openid-client/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/openid-client/node_modules/object-hash": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
"integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
"license": "MIT",
"engines": {
"node": ">= 6"
}
},
"node_modules/package-json-from-dist": { "node_modules/package-json-from-dist": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
@ -3437,6 +3548,34 @@
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
}, },
"node_modules/preact": {
"version": "10.26.2",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.26.2.tgz",
"integrity": "sha512-0gNmv4qpS9HaN3+40CLBAnKe0ZfyE4ZWo5xKlC1rVrr0ckkEvJvAQqKaHANdFKsGstoxrY4AItZ7kZSGVoVjgg==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
}
},
"node_modules/preact-render-to-string": {
"version": "5.2.6",
"resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz",
"integrity": "sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==",
"license": "MIT",
"dependencies": {
"pretty-format": "^3.8.0"
},
"peerDependencies": {
"preact": ">=10"
}
},
"node_modules/pretty-format": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
"integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==",
"license": "MIT"
},
"node_modules/prop-types": { "node_modules/prop-types": {
"version": "15.8.1", "version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@ -4148,6 +4287,15 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
}, },
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/vaul": { "node_modules/vaul": {
"version": "0.9.9", "version": "0.9.9",
"resolved": "https://registry.npmjs.org/vaul/-/vaul-0.9.9.tgz", "resolved": "https://registry.npmjs.org/vaul/-/vaul-0.9.9.tgz",
@ -4279,6 +4427,12 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"license": "ISC"
},
"node_modules/yaml": { "node_modules/yaml": {
"version": "2.7.0", "version": "2.7.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz",

View File

@ -46,6 +46,7 @@
"input-otp": "1.4.1", "input-otp": "1.4.1",
"lucide-react": "^0.454.0", "lucide-react": "^0.454.0",
"next": "14.2.24", "next": "14.2.24",
"next-auth": "^4.24.11",
"next-themes": "^0.4.4", "next-themes": "^0.4.4",
"react": "^18", "react": "^18",
"react-day-picker": "8.10.1", "react-day-picker": "8.10.1",

View File

@ -2,17 +2,18 @@
"compilerOptions": { "compilerOptions": {
"lib": ["dom", "dom.iterable", "esnext"], "lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true, "allowJs": true,
"target": "ES6", "target": "ES2024",
"skipLibCheck": true, "skipLibCheck": true,
"strict": true, "strict": true,
"noEmit": true, "noEmit": true,
"esModuleInterop": true, "esModuleInterop": true,
"module": "esnext", "module": "ESNext",
"moduleResolution": "bundler", "moduleResolution": "bundler",
"resolveJsonModule": true, "resolveJsonModule": true,
"isolatedModules": true, "isolatedModules": true,
"jsx": "preserve", "jsx": "preserve",
"incremental": true, "incremental": true,
"forceConsistentCasingInFileNames": true,
"plugins": [ "plugins": [
{ {
"name": "next" "name": "next"
@ -22,6 +23,12 @@
"@/*": ["./*"] "@/*": ["./*"]
} }
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
"types/**/*.d.ts"
],
"exclude": ["node_modules"] "exclude": ["node_modules"]
} }

23
front/types/next-auth.d.ts vendored Normal file
View File

@ -0,0 +1,23 @@
import NextAuth, { DefaultSession, DefaultUser } from "next-auth";
declare module "next-auth" {
interface Session {
user: {
role?: string[] | string | null;
} & DefaultSession["user"];
accessToken?: string;
}
interface JWT {
accessToken?: string;
role?: string[] | string | null;
}
interface User extends DefaultUser {
role?: string[] | string | null;
}
interface Profile {
role?: string[] | string | null;
}
}

View File

@ -7,7 +7,7 @@
resolved "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz" resolved "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz"
integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
"@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": "@babel/runtime@^7.20.13", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
version "7.26.0" version "7.26.0"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz"
integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw== integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==
@ -121,6 +121,11 @@
"@nodelib/fs.scandir" "2.1.5" "@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0" fastq "^1.6.0"
"@panva/hkdf@^1.0.2":
version "1.2.1"
resolved "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz"
integrity sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==
"@pkgjs/parseargs@^0.11.0": "@pkgjs/parseargs@^0.11.0":
version "0.11.0" version "0.11.0"
resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz" resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz"
@ -1083,6 +1088,11 @@ commander@^4.0.0:
resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz" resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz"
integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
cookie@^0.7.0:
version "0.7.2"
resolved "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz"
integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==
cross-spawn@^7.0.0: cross-spawn@^7.0.0:
version "7.0.6" version "7.0.6"
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz"
@ -1422,6 +1432,11 @@ jiti@^1.21.6:
resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz" resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz"
integrity sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A== integrity sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==
jose@^4.15.5, jose@^4.15.9:
version "4.15.9"
resolved "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz"
integrity sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==
"js-tokens@^3.0.0 || ^4.0.0": "js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0" version "4.0.0"
resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
@ -1454,6 +1469,13 @@ lru-cache@^10.2.0:
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz"
integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"
lucide-react@^0.454.0: lucide-react@^0.454.0:
version "0.454.0" version "0.454.0"
resolved "https://registry.npmjs.org/lucide-react/-/lucide-react-0.454.0.tgz" resolved "https://registry.npmjs.org/lucide-react/-/lucide-react-0.454.0.tgz"
@ -1498,12 +1520,27 @@ nanoid@^3.3.6, nanoid@^3.3.7:
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz" resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz"
integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==
next-auth@^4.24.11:
version "4.24.11"
resolved "https://registry.npmjs.org/next-auth/-/next-auth-4.24.11.tgz"
integrity sha512-pCFXzIDQX7xmHFs4KVH4luCjaCbuPRtZ9oBUjUhOk84mZ9WVPf94n87TxYI4rSRf9HmfHEF8Yep3JrYDVOo3Cw==
dependencies:
"@babel/runtime" "^7.20.13"
"@panva/hkdf" "^1.0.2"
cookie "^0.7.0"
jose "^4.15.5"
oauth "^0.9.15"
openid-client "^5.4.0"
preact "^10.6.3"
preact-render-to-string "^5.1.19"
uuid "^8.3.2"
next-themes@^0.4.4: next-themes@^0.4.4:
version "0.4.4" version "0.4.4"
resolved "https://registry.npmjs.org/next-themes/-/next-themes-0.4.4.tgz" resolved "https://registry.npmjs.org/next-themes/-/next-themes-0.4.4.tgz"
integrity sha512-LDQ2qIOJF0VnuVrrMSMLrWGjRMkq+0mpgl6e0juCLqdJ+oo8Q84JRWT6Wh11VDQKkMMe+dVzDKLWs5n87T+PkQ== integrity sha512-LDQ2qIOJF0VnuVrrMSMLrWGjRMkq+0mpgl6e0juCLqdJ+oo8Q84JRWT6Wh11VDQKkMMe+dVzDKLWs5n87T+PkQ==
next@14.2.24: "next@^12.2.5 || ^13 || ^14 || ^15", next@14.2.24:
version "14.2.24" version "14.2.24"
resolved "https://registry.npmjs.org/next/-/next-14.2.24.tgz" resolved "https://registry.npmjs.org/next/-/next-14.2.24.tgz"
integrity sha512-En8VEexSJ0Py2FfVnRRh8gtERwDRaJGNvsvad47ShkC2Yi8AXQPXEA2vKoDJlGFSj5WE5SyF21zNi4M5gyi+SQ== integrity sha512-En8VEexSJ0Py2FfVnRRh8gtERwDRaJGNvsvad47ShkC2Yi8AXQPXEA2vKoDJlGFSj5WE5SyF21zNi4M5gyi+SQ==
@ -1541,16 +1578,41 @@ normalize-range@^0.1.2:
resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz" resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz"
integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==
oauth@^0.9.15:
version "0.9.15"
resolved "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz"
integrity sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==
object-assign@^4.0.1, object-assign@^4.1.1: object-assign@^4.0.1, object-assign@^4.1.1:
version "4.1.1" version "4.1.1"
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
object-hash@^2.2.0:
version "2.2.0"
resolved "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz"
integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==
object-hash@^3.0.0: object-hash@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz" resolved "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz"
integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==
oidc-token-hash@^5.0.3:
version "5.0.3"
resolved "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz"
integrity sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==
openid-client@^5.4.0:
version "5.7.1"
resolved "https://registry.npmjs.org/openid-client/-/openid-client-5.7.1.tgz"
integrity sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==
dependencies:
jose "^4.15.9"
lru-cache "^6.0.0"
object-hash "^2.2.0"
oidc-token-hash "^5.0.3"
package-json-from-dist@^1.0.0: package-json-from-dist@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz" resolved "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz"
@ -1656,6 +1718,23 @@ postcss@8.4.31:
picocolors "^1.0.0" picocolors "^1.0.0"
source-map-js "^1.0.2" source-map-js "^1.0.2"
preact-render-to-string@^5.1.19:
version "5.2.6"
resolved "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz"
integrity sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==
dependencies:
pretty-format "^3.8.0"
preact@^10.6.3, preact@>=10:
version "10.26.2"
resolved "https://registry.npmjs.org/preact/-/preact-10.26.2.tgz"
integrity sha512-0gNmv4qpS9HaN3+40CLBAnKe0ZfyE4ZWo5xKlC1rVrr0ckkEvJvAQqKaHANdFKsGstoxrY4AItZ7kZSGVoVjgg==
pretty-format@^3.8.0:
version "3.8.0"
resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz"
integrity sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==
prop-types@^15.6.2, prop-types@^15.8.1: prop-types@^15.6.2, prop-types@^15.8.1:
version "15.8.1" version "15.8.1"
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
@ -1675,7 +1754,7 @@ react-day-picker@8.10.1:
resolved "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.10.1.tgz" resolved "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.10.1.tgz"
integrity sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA== integrity sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA==
"react-dom@^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom@^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom@^16.8 || ^17.0 || ^18.0", "react-dom@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom@^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", react-dom@^18, "react-dom@^18 || ^19 || ^19.0.0-rc", "react-dom@^18.0.0 || ^19.0.0 || ^19.0.0-rc", react-dom@^18.2.0, react-dom@>=16.6.0, react-dom@>=16.8.0: "react-dom@^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom@^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom@^16.8 || ^17.0 || ^18.0", "react-dom@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom@^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^17.0.2 || ^18 || ^19", react-dom@^18, "react-dom@^18 || ^19 || ^19.0.0-rc", "react-dom@^18.0.0 || ^19.0.0 || ^19.0.0-rc", react-dom@^18.2.0, react-dom@>=16.6.0, react-dom@>=16.8.0:
version "18.3.1" version "18.3.1"
resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz" resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz"
integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
@ -1754,7 +1833,7 @@ react-transition-group@^4.4.5:
loose-envify "^1.4.0" loose-envify "^1.4.0"
prop-types "^15.6.2" prop-types "^15.6.2"
react@*, "react@^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc", "react@^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react@^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.8.0 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", react@^18, "react@^18 || ^19 || ^19.0.0-rc", "react@^18.0.0 || ^19.0.0 || ^19.0.0-rc", react@^18.2.0, react@^18.3.1, "react@>= 16.8.0 || 17.x.x || ^18.0.0-0", react@>=16.6.0, react@>=16.8.0: react@*, "react@^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc", "react@^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react@^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.8.0 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^17.0.2 || ^18 || ^19", react@^18, "react@^18 || ^19 || ^19.0.0-rc", "react@^18.0.0 || ^19.0.0 || ^19.0.0-rc", react@^18.2.0, react@^18.3.1, "react@>= 16.8.0 || 17.x.x || ^18.0.0-0", react@>=16.6.0, react@>=16.8.0:
version "18.3.1" version "18.3.1"
resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz" resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz"
integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
@ -2051,6 +2130,11 @@ util-deprecate@^1.0.2:
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
uuid@^8.3.2:
version "8.3.2"
resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
vaul@^0.9.6: vaul@^0.9.6:
version "0.9.9" version "0.9.9"
resolved "https://registry.npmjs.org/vaul/-/vaul-0.9.9.tgz" resolved "https://registry.npmjs.org/vaul/-/vaul-0.9.9.tgz"
@ -2103,6 +2187,11 @@ wrap-ansi@^8.1.0:
string-width "^5.0.1" string-width "^5.0.1"
strip-ansi "^7.0.1" strip-ansi "^7.0.1"
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yaml@^2.3.4: yaml@^2.3.4:
version "2.7.0" version "2.7.0"
resolved "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz" resolved "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz"