mirror of
https://github.com/TheRealOwenRees/echecsfrance.git
synced 2026-07-23 04:26:57 +00:00
Sign in mechanism
This commit is contained in:
+9
-1
@@ -5,4 +5,12 @@ DISCORD_WEBHOOK_ERROR_LOGS_URL=
|
||||
DISCORD_WEBHOOK_CONTACT_URL=
|
||||
|
||||
RESULTS_SCRAPER_URL=
|
||||
RESULTS_API_KEY=
|
||||
RESULTS_API_KEY=
|
||||
|
||||
SMTP_USER=
|
||||
SMTP_PASSWORD=
|
||||
SMTP_HOST=
|
||||
SMTP_PORT=
|
||||
EMAIL_FROM=
|
||||
|
||||
NEXTAUTH_SECRET=
|
||||
|
||||
+5
-1
@@ -2,10 +2,12 @@
|
||||
|
||||
/.idea/
|
||||
|
||||
/.yarn/
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
.pnp.*
|
||||
|
||||
# pwa
|
||||
sw.*
|
||||
@@ -41,3 +43,5 @@ yarn-error.log*
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
certificates
|
||||
|
||||
Vendored
+2
@@ -3,6 +3,8 @@
|
||||
"ajouter",
|
||||
"approximative",
|
||||
"Armes",
|
||||
"bgcolor",
|
||||
"cellspacing",
|
||||
"colour",
|
||||
"colours",
|
||||
"contactez",
|
||||
|
||||
+4
-1
@@ -12,6 +12,7 @@
|
||||
"format:fix": "prettier --write \"**/*.{js,jsx,ts,tsx}\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@auth/mongodb-adapter": "^2.5.0",
|
||||
"@headlessui/react": "^1.7.17",
|
||||
"@headlessui/tailwindcss": "^0.2.0",
|
||||
"@hookform/resolvers": "^3.3.3",
|
||||
@@ -29,11 +30,13 @@
|
||||
"leaflet.markercluster": "^1.5.3",
|
||||
"leaflet.smooth_marker_bouncing": "^3.0.3",
|
||||
"lodash": "^4.17.21",
|
||||
"mongodb": "^6.1.0",
|
||||
"mongodb": "^6.4.0",
|
||||
"next": "^14.0.4",
|
||||
"next-auth": "^5.0.0-beta.16",
|
||||
"next-intl": "^3.3.2",
|
||||
"next-pwa": "^5.6.0",
|
||||
"next-safe-action": "^6.2.0",
|
||||
"nodemailer": "^6.9.12",
|
||||
"postcss": "8.4.33",
|
||||
"react": "^18.2.0",
|
||||
"react-date-range": "^1.4.0",
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { signIn } from "next-auth/react";
|
||||
import { useLocale, useTranslations } from "next-intl";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
import { clearMessage } from "@/components/InfoMessage";
|
||||
import InfoMessage from "@/components/InfoMessage";
|
||||
import { TextField } from "@/components/form/TextField";
|
||||
|
||||
const signInSchema = z.object({
|
||||
email: z.string().email(),
|
||||
});
|
||||
|
||||
type SignInFormValues = z.infer<typeof signInSchema>;
|
||||
|
||||
export default function SignIn() {
|
||||
const t = useTranslations("SignIn");
|
||||
const locale = useLocale();
|
||||
|
||||
const [responseMessage, setResponseMessage] = useState({
|
||||
isSuccessful: false,
|
||||
message: "",
|
||||
});
|
||||
|
||||
const form = useForm<SignInFormValues>({
|
||||
resolver: zodResolver(signInSchema),
|
||||
});
|
||||
|
||||
const onSubmit = async ({ email }: SignInFormValues) => {
|
||||
try {
|
||||
const result = await signIn("nodemailer", {
|
||||
email,
|
||||
redirect: false,
|
||||
callbackUrl: `/${locale}/tournaments`,
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
throw new Error(result.error);
|
||||
} else if (result?.ok) {
|
||||
setResponseMessage({
|
||||
isSuccessful: true,
|
||||
message: t("checkEmail"),
|
||||
});
|
||||
|
||||
form.reset();
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
console.log(err);
|
||||
|
||||
setResponseMessage({
|
||||
isSuccessful: true,
|
||||
message: t("failure"),
|
||||
});
|
||||
|
||||
clearMessage(setResponseMessage);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="grid place-items-center bg-white pb-20 dark:bg-gray-800">
|
||||
<div className="mx-auto max-w-screen-md px-4 py-8 lg:py-16">
|
||||
<h2
|
||||
className="mb-4 text-center text-4xl font-extrabold tracking-tight text-gray-900 dark:text-white"
|
||||
data-test="header2"
|
||||
>
|
||||
{t("title")}
|
||||
</h2>
|
||||
<p className="mb-8 text-center font-light text-gray-500 dark:text-gray-400 sm:text-xl lg:mb-16">
|
||||
{t("info")}
|
||||
</p>
|
||||
|
||||
<FormProvider {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
|
||||
<TextField
|
||||
name="email"
|
||||
control={form.control}
|
||||
label={t("emailLabel")}
|
||||
placeholder={t("emailPlaceholder")}
|
||||
required
|
||||
/>
|
||||
|
||||
<button
|
||||
disabled={form.formState.isSubmitting}
|
||||
type="submit"
|
||||
className="rounded-lg bg-primary-600 px-5 py-3 text-center text-sm font-medium text-white hover:bg-primary-800 focus:outline-none focus:ring-4 focus:ring-primary-300 disabled:opacity-25 dark:text-white dark:hover:bg-primary-700 dark:focus:ring-primary-800 sm:w-fit"
|
||||
>
|
||||
{t("signInButton")}
|
||||
</button>
|
||||
|
||||
<InfoMessage
|
||||
className="text-center"
|
||||
responseMessage={responseMessage}
|
||||
/>
|
||||
</form>
|
||||
</FormProvider>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
import AuthButton from "@/components/AuthButton";
|
||||
import { Link } from "@/utils/navigation";
|
||||
|
||||
import Hamburger from "./Hamburger";
|
||||
@@ -47,6 +48,8 @@ export default function Navbar() {
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
|
||||
<AuthButton />
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,6 @@ import "@/css/globals.css";
|
||||
import Providers from "@/providers";
|
||||
|
||||
import Footer from "./(main)/components/Footer";
|
||||
import Navbar from "./(main)/components/Navbar";
|
||||
|
||||
const inter = Inter({ subsets: ["latin"], variable: "--font-inter" });
|
||||
const title = Julius_Sans_One({
|
||||
@@ -77,10 +76,11 @@ export default async function RootLayout({
|
||||
|
||||
<Footer />
|
||||
</NextIntlClientProvider>
|
||||
|
||||
<Script
|
||||
defer
|
||||
src="https://app.tinyanalytics.io/pixel/HyoumUokLr9exPgX"
|
||||
></Script>
|
||||
/>
|
||||
</Providers>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { GET, POST } from "@/auth";
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
import { MongoDBAdapter } from "@auth/mongodb-adapter";
|
||||
import NextAuth from "next-auth";
|
||||
|
||||
import clientPromise from "@/lib/mongodb";
|
||||
import Email from "@/utils/nodemailerProvider";
|
||||
|
||||
export const {
|
||||
handlers: { GET, POST },
|
||||
auth,
|
||||
} = NextAuth({
|
||||
adapter: MongoDBAdapter(clientPromise, { databaseName: "userData" }),
|
||||
|
||||
providers: [
|
||||
Email({
|
||||
server: {
|
||||
host: process.env.SMTP_HOST,
|
||||
port: Number(process.env.SMTP_PORT),
|
||||
auth: {
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PASSWORD,
|
||||
},
|
||||
},
|
||||
from: process.env.EMAIL_FROM,
|
||||
}),
|
||||
],
|
||||
|
||||
pages: {
|
||||
signIn: "/auth/sign-in",
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
|
||||
import { signIn, signOut, useSession } from "next-auth/react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
const AuthButton = () => {
|
||||
const t = useTranslations("Nav");
|
||||
const router = useRouter();
|
||||
const [signingOut, setSigningOut] = useState(false);
|
||||
const { data: sessionData } = useSession();
|
||||
|
||||
const handleSignOut = async () => {
|
||||
setSigningOut(true);
|
||||
try {
|
||||
await signOut({ redirect: false });
|
||||
router.push("/");
|
||||
} finally {
|
||||
setSigningOut(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (sessionData) {
|
||||
return (
|
||||
<button disabled={signingOut} onClick={handleSignOut}>
|
||||
{t("signOut")}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
return <button onClick={() => signIn()}>{t("signIn")}</button>;
|
||||
};
|
||||
|
||||
export default AuthButton;
|
||||
@@ -1,16 +1,22 @@
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { ResponseMessage } from "@/types";
|
||||
|
||||
const InfoMessage = ({
|
||||
responseMessage,
|
||||
className,
|
||||
}: {
|
||||
responseMessage: ResponseMessage;
|
||||
className?: string;
|
||||
}) => (
|
||||
<p
|
||||
className={`${
|
||||
responseMessage.isSuccessful ? "text-green-600" : "text-red-600"
|
||||
} italic`}
|
||||
className={twMerge(
|
||||
"italic",
|
||||
responseMessage.isSuccessful ? "text-green-600" : "text-red-600",
|
||||
className,
|
||||
)}
|
||||
data-test="info-message"
|
||||
>
|
||||
{responseMessage.message}
|
||||
|
||||
+23
-2
@@ -27,7 +27,9 @@
|
||||
"title": "Échecs France",
|
||||
"tournaments": "Tournaments",
|
||||
"clubs": "Clubs",
|
||||
"elo": "Elo Calculator"
|
||||
"elo": "Elo Calculator",
|
||||
"signIn": "Sign In",
|
||||
"signOut": "Sign Out"
|
||||
},
|
||||
|
||||
"Footer": {
|
||||
@@ -204,6 +206,25 @@
|
||||
"kFactorInfo5": "10 once a player's published rating has reached 2400 and remains at that level subsequently, even if the rating drops below 2400.",
|
||||
"kFactorInfo6": "40 for all players until their 18th birthday, as long as their rating remains under 2300.",
|
||||
|
||||
"unknownError": "We were unable to fetch results from this URL. Please <contact>contact us</contact> if the problem persists."
|
||||
"unknownError": "We were unable to fetch results from this URL. Please <contact>contact us</contact> if the problem persists.",
|
||||
"ERR_TOURNAMENT_NOT_FOUND": "Tournament not found",
|
||||
"ERR_NO_TOURNAMENT_ID": "The link you provided is incorrect"
|
||||
},
|
||||
|
||||
"SignIn": {
|
||||
"title": "Sign In",
|
||||
"info": "Sign in to access additional features, such as receiving email notifications for tournaments in your area. There's no need to create an account, just sign in with your email address and we'll send you a link.",
|
||||
"emailLabel": "Email",
|
||||
"emailPlaceholder": "Your email",
|
||||
"signInButton": "Sign In",
|
||||
"failure": "Oops, something went wrong. Please try again.",
|
||||
"checkEmail": "Please check your email for a sign-in link.",
|
||||
|
||||
"email": {
|
||||
"subject": "Sign in to ${host}",
|
||||
"button": "Sign in",
|
||||
"ignore": "If you didn't request this, you can safely ignore this email.",
|
||||
"textMessage": "Click the following link to sign in to ${host}: {url}\n\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+23
-2
@@ -27,7 +27,9 @@
|
||||
"title": "Échecs France",
|
||||
"tournaments": "Tournois",
|
||||
"clubs": "Clubs",
|
||||
"elo": "Calculette Elo"
|
||||
"elo": "Calculette Elo",
|
||||
"signIn": "Se connecter",
|
||||
"signOut": "Se déconnecter"
|
||||
},
|
||||
|
||||
"Footer": {
|
||||
@@ -205,6 +207,25 @@
|
||||
"kFactorInfo5": "<b>10</b> une fois que le classement publié d'un joueur a atteint 2400 et reste à ce niveau par la suite, même s'il redescend en dessous de 2400.",
|
||||
"kFactorInfo6": "<b>40</b> pour tous les joueurs jusqu'à leur 18e anniversaire, tant que leur classement reste inférieur à 2300.",
|
||||
|
||||
"unknownError": "Nous n'avons pas pu récupérer les résultats à partir de cette URL. Veuillez <contact>nous contacter</contact> si le problème persiste."
|
||||
"unknownError": "Nous n'avons pas pu récupérer les résultats à partir de cette URL. Veuillez <contact>nous contacter</contact> si le problème persiste.",
|
||||
"ERR_TOURNAMENT_NOT_FOUND": "Tournoi introuvable",
|
||||
"ERR_NO_TOURNAMENT_ID": "L'identifiant du tournoi fourni est incorrect"
|
||||
},
|
||||
|
||||
"SignIn": {
|
||||
"title": "Se connecter",
|
||||
"info": "Connectez-vous pour accéder à des fonctionnalités supplémentaires, telles que la réception de notifications par e-mail pour les tournois dans votre région. Pas besoin de créer un compte, connectez-vous simplement avec votre adresse e-mail et nous vous enverrons un lien.",
|
||||
"emailLabel": "E-mail",
|
||||
"emailPlaceholder": "Votre e-mail",
|
||||
"signInButton": "Se connecter",
|
||||
"failure": "Oups, quelque chose s'est mal passé. Veuillez réessayer.",
|
||||
"checkEmail": "Veuillez vérifier votre e-mail pour un lien de connexion.",
|
||||
|
||||
"email": {
|
||||
"subject": "Connexion à ${host}",
|
||||
"button": "Se connecter",
|
||||
"ignore": "Si vous n'avez pas demandé cela, vous pouvez ignorer en toute sécurité cet e-mail.",
|
||||
"textMessage": "Cliquez sur le lien suivant pour vous connecter à ${host}: {url}\n\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-4
@@ -1,7 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { Provider } from "jotai";
|
||||
import { Provider as JotaiProvider } from "jotai";
|
||||
import { SessionProvider } from "next-auth/react";
|
||||
|
||||
import { useDynamicViewportUnits } from "@/hooks/useDynamicViewportUnits";
|
||||
|
||||
@@ -9,9 +10,14 @@ export default function Providers({ children }: { children: React.ReactNode }) {
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
useDynamicViewportUnits();
|
||||
|
||||
return (
|
||||
<Provider>
|
||||
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
||||
</Provider>
|
||||
<SessionProvider>
|
||||
<JotaiProvider>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
{children}
|
||||
</QueryClientProvider>
|
||||
</JotaiProvider>
|
||||
</SessionProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
import { AuthError } from "next-auth";
|
||||
import { EmailConfig } from "next-auth/providers/email";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { createTransport } from "nodemailer";
|
||||
import type { Transport, TransportOptions } from "nodemailer";
|
||||
import * as JSONTransport from "nodemailer/lib/json-transport/index.js";
|
||||
import * as SendmailTransport from "nodemailer/lib/sendmail-transport/index.js";
|
||||
import * as SESTransport from "nodemailer/lib/ses-transport/index.js";
|
||||
import * as SMTPPool from "nodemailer/lib/smtp-pool/index.js";
|
||||
import * as SMTPTransport from "nodemailer/lib/smtp-transport/index.js";
|
||||
import * as StreamTransport from "nodemailer/lib/stream-transport/index.js";
|
||||
|
||||
type Awaitable<T> = T | PromiseLike<T>;
|
||||
|
||||
export function html(params: {
|
||||
url: string;
|
||||
host: string;
|
||||
t: Awaited<ReturnType<typeof getTranslations<"SignIn">>>;
|
||||
}) {
|
||||
const { url, host, t } = params;
|
||||
|
||||
const escapedHost = host.replace(/\./g, "​.");
|
||||
|
||||
const brandColor = "#346df1";
|
||||
const buttonText = "#fff";
|
||||
|
||||
const color = {
|
||||
background: "#f9f9f9",
|
||||
text: "#444",
|
||||
mainBackground: "#fff",
|
||||
buttonBackground: brandColor,
|
||||
buttonBorder: brandColor,
|
||||
buttonText,
|
||||
};
|
||||
|
||||
return `
|
||||
<body style="background: ${color.background};">
|
||||
<table width="100%" border="0" cellspacing="20" cellpadding="0"
|
||||
style="background: ${color.mainBackground}; max-width: 600px; margin: auto; border-radius: 10px;">
|
||||
<tr>
|
||||
<td align="center"
|
||||
style="padding: 10px 0px; font-size: 22px; font-family: Helvetica, Arial, sans-serif; color: ${color.text};">
|
||||
${t("email.subject", { host })}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" style="padding: 20px 0;">
|
||||
<table border="0" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td align="center" style="border-radius: 5px;" bgcolor="${color.buttonBackground}">
|
||||
<a href="${url}"
|
||||
target="_blank"
|
||||
style="font-size: 18px; font-family: Helvetica, Arial, sans-serif; color: ${color.buttonText}; text-decoration: none; border-radius: 5px; padding: 10px 20px; border: 1px solid ${color.buttonBorder}; display: inline-block; font-weight: bold;">
|
||||
${t("email.button")}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"
|
||||
style="padding: 0px 0px 10px 0px; font-size: 16px; line-height: 22px; font-family: Helvetica, Arial, sans-serif; color: ${color.text};">
|
||||
${t("email.ignore")}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
`;
|
||||
}
|
||||
|
||||
/** Email Text body (fallback for email clients that don't render HTML, e.g. feature phones) */
|
||||
export function text({
|
||||
url,
|
||||
host,
|
||||
t,
|
||||
}: {
|
||||
url: string;
|
||||
host: string;
|
||||
t: Awaited<ReturnType<typeof getTranslations<"SignIn">>>;
|
||||
}) {
|
||||
return t("email.textMessage", { host, url });
|
||||
}
|
||||
|
||||
type AllTransportOptions =
|
||||
| string
|
||||
| SMTPTransport
|
||||
| SMTPTransport.Options
|
||||
| SMTPPool
|
||||
| SMTPPool.Options
|
||||
| SendmailTransport
|
||||
| SendmailTransport.Options
|
||||
| StreamTransport
|
||||
| StreamTransport.Options
|
||||
| JSONTransport
|
||||
| JSONTransport.Options
|
||||
| SESTransport
|
||||
| SESTransport.Options
|
||||
| Transport<any>
|
||||
| TransportOptions;
|
||||
|
||||
export interface NodemailerConfig extends EmailConfig {
|
||||
server?: AllTransportOptions;
|
||||
sendVerificationRequest: (params: {
|
||||
identifier: string;
|
||||
url: string;
|
||||
expires: Date;
|
||||
provider: NodemailerConfig;
|
||||
token: string;
|
||||
theme: any;
|
||||
request: Request;
|
||||
}) => Awaitable<void>;
|
||||
options: NodemailerUserConfig;
|
||||
}
|
||||
|
||||
export type NodemailerUserConfig = Omit<
|
||||
Partial<NodemailerConfig>,
|
||||
"options" | "type"
|
||||
>;
|
||||
|
||||
export default function Nodemailer(
|
||||
config: NodemailerUserConfig,
|
||||
): NodemailerConfig {
|
||||
if (!config.server)
|
||||
throw new AuthError("Nodemailer requires a `server` configuration");
|
||||
|
||||
return {
|
||||
id: "nodemailer",
|
||||
type: "email",
|
||||
name: "Nodemailer",
|
||||
server: { host: "localhost", port: 25, auth: { user: "", pass: "" } },
|
||||
from: "Echecs France <no-reply@echecsfrance.com>",
|
||||
maxAge: 24 * 60 * 60,
|
||||
|
||||
async sendVerificationRequest(params) {
|
||||
let locale = "fr";
|
||||
const { searchParams } = new URL(params.url);
|
||||
if (searchParams.has("callbackUrl")) {
|
||||
const { pathname } = new URL(searchParams.get("callbackUrl")!);
|
||||
locale = pathname.split("/")[1];
|
||||
}
|
||||
|
||||
const t = await getTranslations({ locale, namespace: "SignIn" });
|
||||
|
||||
const { identifier, url, provider } = params;
|
||||
const { host } = new URL(url);
|
||||
const transport = createTransport(provider.server);
|
||||
const result = await transport.sendMail({
|
||||
to: identifier,
|
||||
from: provider.from,
|
||||
subject: t("email.subject", { host }),
|
||||
text: text({ url, host, t }),
|
||||
html: html({ url, host, t }),
|
||||
});
|
||||
|
||||
const failed = result.rejected.concat(result.pending).filter(Boolean);
|
||||
if (failed.length) {
|
||||
throw new Error(`Email (${failed.join(", ")}) could not be sent`);
|
||||
}
|
||||
},
|
||||
|
||||
options: config,
|
||||
};
|
||||
}
|
||||
@@ -34,6 +34,39 @@
|
||||
jsonpointer "^5.0.0"
|
||||
leven "^3.1.0"
|
||||
|
||||
"@auth/core@0.28.1":
|
||||
version "0.28.1"
|
||||
resolved "https://registry.yarnpkg.com/@auth/core/-/core-0.28.1.tgz#a60f509424089cf2041efb6d3ff42e2c16791350"
|
||||
integrity sha512-gvp74mypYZADpTlfGRp6HE0G3pIHWvtJpy+KZ+8FvY0cmlIpHog+jdMOdd29dQtLtN25kF2YbfHsesCFuGUQbg==
|
||||
dependencies:
|
||||
"@panva/hkdf" "^1.1.1"
|
||||
"@types/cookie" "0.6.0"
|
||||
cookie "0.6.0"
|
||||
jose "^5.1.3"
|
||||
oauth4webapi "^2.4.0"
|
||||
preact "10.11.3"
|
||||
preact-render-to-string "5.2.3"
|
||||
|
||||
"@auth/core@0.29.0":
|
||||
version "0.29.0"
|
||||
resolved "https://registry.yarnpkg.com/@auth/core/-/core-0.29.0.tgz#764c3cf4ebfb4ab248f24a1ee18d67ae1c5e433b"
|
||||
integrity sha512-MdfEjU6WRjUnPG1+XeBWrTIlAsLZU6V0imCIqVDDDPxLI6UZWldXVqAA2EsDazGofV78jqiCLHaN85mJITDqdg==
|
||||
dependencies:
|
||||
"@panva/hkdf" "^1.1.1"
|
||||
"@types/cookie" "0.6.0"
|
||||
cookie "0.6.0"
|
||||
jose "^5.1.3"
|
||||
oauth4webapi "^2.4.0"
|
||||
preact "10.11.3"
|
||||
preact-render-to-string "5.2.3"
|
||||
|
||||
"@auth/mongodb-adapter@^2.5.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@auth/mongodb-adapter/-/mongodb-adapter-2.6.0.tgz#60870e3fde0e5c0756261e9ddc638ed56767475a"
|
||||
integrity sha512-q3He1+etx3c80v+L8RxaHAAoj3b/x0HlL1IctnYa2JXjA38t6WIacR9o1DfEN1Xp0zBs94OocHemGirWrv1ucg==
|
||||
dependencies:
|
||||
"@auth/core" "0.29.0"
|
||||
|
||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1", "@babel/code-frame@^7.24.2":
|
||||
version "7.24.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae"
|
||||
@@ -1525,6 +1558,11 @@
|
||||
"@nodelib/fs.scandir" "2.1.5"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@panva/hkdf@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@panva/hkdf/-/hkdf-1.1.1.tgz#ab9cd8755d1976e72fc77a00f7655a64efe6cd5d"
|
||||
integrity sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==
|
||||
|
||||
"@pkgjs/parseargs@^0.11.0":
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
|
||||
@@ -1669,9 +1707,9 @@
|
||||
redent "^3.0.0"
|
||||
|
||||
"@testing-library/react@^14.0.0":
|
||||
version "14.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-14.2.2.tgz#74f855215c57d423282486a395a4348a837d3c5a"
|
||||
integrity sha512-SOUuM2ysCvjUWBXTNfQ/ztmnKDmqaiPV3SvoIuyxMUca45rbSWWAT/qB8CUs/JQ/ux/8JFs9DNdFQ3f6jH3crA==
|
||||
version "14.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-14.3.0.tgz#8183eb5a5f465b5b8cc495fcbd9bad0a16b8dd3b"
|
||||
integrity sha512-AYJGvNFMbCa5vt1UtDCa/dcaABrXq8gph6VN+cffIx0UeA0qiGqS+sT60+sb+Gjc8tGXdECWYQgaF0khf8b+Lg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
"@testing-library/dom" "^9.0.0"
|
||||
@@ -1694,6 +1732,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.4.tgz#1a31c3d378850d2778dabb6374d036dcba4ba708"
|
||||
integrity sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==
|
||||
|
||||
"@types/cookie@0.6.0":
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.6.0.tgz#eac397f28bf1d6ae0ae081363eca2f425bedf0d5"
|
||||
integrity sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==
|
||||
|
||||
"@types/estree@0.0.39":
|
||||
version "0.0.39"
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
|
||||
@@ -1747,9 +1790,9 @@
|
||||
integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==
|
||||
|
||||
"@types/node@*", "@types/node@^20.8.4":
|
||||
version "20.12.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.5.tgz#74c4f31ab17955d0b5808cdc8fd2839526ad00b3"
|
||||
integrity sha512-BD+BjQ9LS/D8ST9p5uqBxghlN+S42iuNxjsUGjeZobe/ciXzk2qb1B6IXc6AnRLS+yFJRpN2IPEHMzwspfDJNw==
|
||||
version "20.12.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.6.tgz#72d068870518d7da1d97b49db401e2d6a1805294"
|
||||
integrity sha512-3KurE8taB8GCvZBPngVbp0lk5CKi8M9f9k1rsADh0Evdz5SzJ+Q+Hx9uHoFGsLnLnd1xmkDQr2hVhlA0Mn0lKQ==
|
||||
dependencies:
|
||||
undici-types "~5.26.4"
|
||||
|
||||
@@ -1810,9 +1853,9 @@
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@^18.2.27":
|
||||
version "18.2.74"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.74.tgz#2d52eb80e4e7c4ea8812c89181d6d590b53f958c"
|
||||
integrity sha512-9AEqNZZyBx8OdZpxzQlaFEVCSFUM2YXJH46yPOiOpm078k6ZLOCcuAzGum/zK8YBwY+dbahVNbHrbgrAwIRlqw==
|
||||
version "18.2.75"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.75.tgz#45d18f384939306d35312def1bf532eb38a68562"
|
||||
integrity sha512-+DNnF7yc5y0bHkBTiLKqXFe+L4B3nvOphiMY3tuA5X10esmjqk7smyBZzbGTy2vsiy/Bnzj8yFIBL8xhRacoOg==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
csstype "^3.0.2"
|
||||
@@ -2440,6 +2483,11 @@ convert-source-map@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
|
||||
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
|
||||
|
||||
cookie@0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
|
||||
integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
|
||||
|
||||
copy-anything@^3.0.2:
|
||||
version "3.0.5"
|
||||
resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-3.0.5.tgz#2d92dce8c498f790fa7ad16b01a1ae5a45b020a0"
|
||||
@@ -2694,9 +2742,9 @@ ejs@^3.1.6:
|
||||
jake "^10.8.5"
|
||||
|
||||
electron-to-chromium@^1.4.668:
|
||||
version "1.4.729"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.729.tgz#8477d21e2a50993781950885b2731d92ad532c00"
|
||||
integrity sha512-bx7+5Saea/qu14kmPTDHQxkp2UnziG3iajUQu3BxFvCOnpAJdDbMV4rSl+EqFDkkpNNVUFlR1kDfpL59xfy1HA==
|
||||
version "1.4.730"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.730.tgz#5e382c83085b50b9c63cb08692e8fcd875c1b9eb"
|
||||
integrity sha512-oJRPo82XEqtQAobHpJIR3zW5YO3sSRRkPz2an4yxi1UvqhsGm54vR/wzTFV74a3soDOJ8CKW7ajOOX5ESzddwg==
|
||||
|
||||
emoji-regex@^8.0.0:
|
||||
version "8.0.0"
|
||||
@@ -3848,6 +3896,11 @@ jiti@^1.21.0:
|
||||
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d"
|
||||
integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==
|
||||
|
||||
jose@^5.1.3:
|
||||
version "5.2.4"
|
||||
resolved "https://registry.yarnpkg.com/jose/-/jose-5.2.4.tgz#c0d296caeeed0b8444a8b8c3b68403d61aa4ed72"
|
||||
integrity sha512-6ScbIk2WWCeXkmzF6bRPmEuaqy1m8SbsRFMa/FLrSCkGIhj8OLVG/IH+XHVmNMx/KUo8cVWEE6oKR4dJ+S0Rkg==
|
||||
|
||||
jotai@^2.6.1:
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/jotai/-/jotai-2.8.0.tgz#5a6585cd5576c400c2c5f8e157b83ad2ba70b2ab"
|
||||
@@ -4185,7 +4238,7 @@ mongodb-connection-string-url@^3.0.0:
|
||||
"@types/whatwg-url" "^11.0.2"
|
||||
whatwg-url "^13.0.0"
|
||||
|
||||
mongodb@^6.1.0:
|
||||
mongodb@^6.4.0:
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-6.5.0.tgz#3735b4fba085b26ca06f7744e9639bc538e93d87"
|
||||
integrity sha512-Fozq68InT+JKABGLqctgtb8P56pRrJFkbhW0ux+x1mdHeyinor8oNzJqwLjV/t5X5nJGfTlluxfyMnOXNggIUA==
|
||||
@@ -4233,6 +4286,13 @@ negotiator@^0.6.3:
|
||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
|
||||
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
|
||||
|
||||
next-auth@^5.0.0-beta.16:
|
||||
version "5.0.0-beta.16"
|
||||
resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-5.0.0-beta.16.tgz#cf02c9e5bbf4b91463943c0391604fcb5f46b22d"
|
||||
integrity sha512-dX2snB+ezN23tFzSes3n3uosT9iBf0eILPYWH/R2fd9n3ZzdMQlRzq7JIOPeS1aLc84IuRlyuyXyx9XmmZB6og==
|
||||
dependencies:
|
||||
"@auth/core" "0.28.1"
|
||||
|
||||
next-intl@^3.3.2:
|
||||
version "3.11.1"
|
||||
resolved "https://registry.yarnpkg.com/next-intl/-/next-intl-3.11.1.tgz#28abe4febdaa713b6bb743a5b5033bc0ff9d58b9"
|
||||
@@ -4291,6 +4351,11 @@ node-releases@^2.0.14:
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b"
|
||||
integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==
|
||||
|
||||
nodemailer@^6.9.12:
|
||||
version "6.9.13"
|
||||
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.13.tgz#5b292bf1e92645f4852ca872c56a6ba6c4a3d3d6"
|
||||
integrity sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==
|
||||
|
||||
normalize-path@^3.0.0, normalize-path@~3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||
@@ -4301,6 +4366,11 @@ normalize-range@^0.1.2:
|
||||
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
|
||||
integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==
|
||||
|
||||
oauth4webapi@^2.4.0:
|
||||
version "2.10.4"
|
||||
resolved "https://registry.yarnpkg.com/oauth4webapi/-/oauth4webapi-2.10.4.tgz#4194b784e0ff995edd64bd90177fd7f25b7fbb17"
|
||||
integrity sha512-DSoj8QoChzOCQlJkRmYxAJCIpnXFW32R0Uq7avyghIeB6iJq0XAblOD7pcq3mx4WEBDwMuKr0Y1qveCBleG2Xw==
|
||||
|
||||
object-assign@^4.0.1, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
@@ -4622,6 +4692,18 @@ postcss@^8.4.23:
|
||||
picocolors "^1.0.0"
|
||||
source-map-js "^1.2.0"
|
||||
|
||||
preact-render-to-string@5.2.3:
|
||||
version "5.2.3"
|
||||
resolved "https://registry.yarnpkg.com/preact-render-to-string/-/preact-render-to-string-5.2.3.tgz#23d17376182af720b1060d5a4099843c7fe92fe4"
|
||||
integrity sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==
|
||||
dependencies:
|
||||
pretty-format "^3.8.0"
|
||||
|
||||
preact@10.11.3:
|
||||
version "10.11.3"
|
||||
resolved "https://registry.yarnpkg.com/preact/-/preact-10.11.3.tgz#8a7e4ba19d3992c488b0785afcc0f8aa13c78d19"
|
||||
integrity sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==
|
||||
|
||||
prelude-ls@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
||||
@@ -4651,6 +4733,11 @@ pretty-format@^27.0.2:
|
||||
ansi-styles "^5.0.0"
|
||||
react-is "^17.0.1"
|
||||
|
||||
pretty-format@^3.8.0:
|
||||
version "3.8.0"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-3.8.0.tgz#bfbed56d5e9a776645f4b1ff7aa1a3ac4fa3c385"
|
||||
integrity sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==
|
||||
|
||||
prop-types@15, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
|
||||
Reference in New Issue
Block a user