From 7defc17e3a99c9068edb3e5f7342d4bf4068e9a5 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 12:11:19 +0300 Subject: [PATCH 001/125] Copied pages/login.tsx file from old login branch --- pages/login.tsx | 116 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 pages/login.tsx diff --git a/pages/login.tsx b/pages/login.tsx new file mode 100644 index 0000000..6dcf640 --- /dev/null +++ b/pages/login.tsx @@ -0,0 +1,116 @@ +import { Inter } from 'next/font/google'; +import { useRouter } from 'next/router'; +import { FormEvent, useState } from 'react'; +import { Input } from '~/components/Input'; +import { LoginAndSignOutButton } from '~/components/LoginAndSignOutButton'; +import { TitleText } from '~/components/TitleText'; +import { signIn } from 'next-auth/react'; + +const inter = Inter({ subsets: ['latin'] }); + +export default function Login() { + const [email, setEmail] = useState('john.doe@doemail.com'); + const [password, setPassword] = useState('1'); + const [isError, setIsError] = useState(false); + const [errorText, setErrorText] = useState(''); + + const router = useRouter(); + + function handleRegisterRedirect( + e: React.MouseEvent, + ) { + e.preventDefault(); + router.push('/register').catch((e) => console.error(e)); + } + + async function handleSubmit(e: FormEvent) { + e.preventDefault(); + const loggingAttempt = await signIn('credentials', { + email: email, + password: password, + callbackUrl: '/', + redirect: false, + }); + console.log(loggingAttempt); + if (loggingAttempt === undefined) { + return handleUndefinedLogging(); + } + + if (loggingAttempt.ok === false) { + if (loggingAttempt.error === 'CredentialsSignin') { + setErrorText('Virheellinen sähköposti tai salasana.'); + setIsError(true); + } + return; + } + + return await router.push('/'); + } + + function handleUndefinedLogging() { + setErrorText('Palvelin virhe!'); + setIsError(true); + } + + return ( +
+
+ {isError ? ( +
+
+ {errorText} +
+
+ ) : null} +
+
+
void handleSubmit(e)}> + Kirjaudu sisään +
+ + setEmail(e.currentTarget.value)} + value={email} + className="border border-black pl-8 pr-8" + autoComplete="off" + type="text" + placeholder="matti.meikalainen@email.com" + name="username" + spellCheck="false" + /> +
+
+ + setPassword(e.currentTarget.value)} + value={password} + className="border border-black" + autoComplete="off" + type="password" + placeholder="************" + name="username" + /> +
+
+ +
+ + +

+ Sinulla ei ole vielä tunnuksia?{' '} + handleRegisterRedirect(e)} + > + Luo tunnus + +

+
+
+
+
+ ); +} From f028cfba3dc0a862ac5c3b7b7c3847254a3897e1 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 12:14:46 +0300 Subject: [PATCH 002/125] Fixed imports and deleted unnecessary stuff --- pages/login.tsx | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/pages/login.tsx b/pages/login.tsx index 6dcf640..1fcbe72 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -1,12 +1,8 @@ -import { Inter } from 'next/font/google'; import { useRouter } from 'next/router'; import { FormEvent, useState } from 'react'; +import { Button } from '~/components/Button'; import { Input } from '~/components/Input'; -import { LoginAndSignOutButton } from '~/components/LoginAndSignOutButton'; import { TitleText } from '~/components/TitleText'; -import { signIn } from 'next-auth/react'; - -const inter = Inter({ subsets: ['latin'] }); export default function Login() { const [email, setEmail] = useState('john.doe@doemail.com'); @@ -25,33 +21,10 @@ export default function Login() { async function handleSubmit(e: FormEvent) { e.preventDefault(); - const loggingAttempt = await signIn('credentials', { - email: email, - password: password, - callbackUrl: '/', - redirect: false, - }); - console.log(loggingAttempt); - if (loggingAttempt === undefined) { - return handleUndefinedLogging(); - } - - if (loggingAttempt.ok === false) { - if (loggingAttempt.error === 'CredentialsSignin') { - setErrorText('Virheellinen sähköposti tai salasana.'); - setIsError(true); - } - return; - } return await router.push('/'); } - function handleUndefinedLogging() { - setErrorText('Palvelin virhe!'); - setIsError(true); - } - return (
@@ -97,7 +70,7 @@ export default function Login() { Muista minut
- +

Sinulla ei ole vielä tunnuksia?{' '} From 3d680e14d18d52979e283c2d69cd607094509566 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 12:17:02 +0300 Subject: [PATCH 003/125] Fixed some frontend code in login.tsx --- pages/login.tsx | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/pages/login.tsx b/pages/login.tsx index 1fcbe72..3eb98d3 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -1,3 +1,4 @@ +import Link from 'next/link'; import { useRouter } from 'next/router'; import { FormEvent, useState } from 'react'; import { Button } from '~/components/Button'; @@ -12,21 +13,13 @@ export default function Login() { const router = useRouter(); - function handleRegisterRedirect( - e: React.MouseEvent, - ) { - e.preventDefault(); - router.push('/register').catch((e) => console.error(e)); - } - async function handleSubmit(e: FormEvent) { e.preventDefault(); - return await router.push('/'); } return ( -

+
{isError ? (
@@ -72,14 +65,14 @@ export default function Login() {
-

+

Sinulla ei ole vielä tunnuksia?{' '} - handleRegisterRedirect(e)} + Luo tunnus - +

From 7a987a7ec156a435a99bf4f0f679bdf5d7c0002d Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 12:18:25 +0300 Subject: [PATCH 004/125] Fixed name attributes in Inputs --- pages/login.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/login.tsx b/pages/login.tsx index 3eb98d3..dec7176 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -41,7 +41,7 @@ export default function Login() { autoComplete="off" type="text" placeholder="matti.meikalainen@email.com" - name="username" + name="email" spellCheck="false" /> @@ -54,7 +54,7 @@ export default function Login() { autoComplete="off" type="password" placeholder="************" - name="username" + name="password" />
From ed507b493ed6523d3ce299ac65220bce60fbd323 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 12:44:18 +0300 Subject: [PATCH 005/125] Installed lucia and oslo packages --- package-lock.json | 3439 +++++++++++++++++++++++++++++---------------- package.json | 2 + 2 files changed, 2252 insertions(+), 1189 deletions(-) diff --git a/package-lock.json b/package-lock.json index 000047b..1fd25bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,9 @@ "dotenv": "16.4.5", "eslint": "8.57.0", "eslint-config-next": "14.1.4", + "lucia": "3.1.1", "next": "14.1.4", + "oslo": "1.2.0", "postcss": "8.4.38", "prisma": "5.12.0", "react": "18.2.0", @@ -1969,6 +1971,15 @@ "node": ">=6.9.0" } }, + "node_modules/@emnapi/core": { + "version": "0.45.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-0.45.0.tgz", + "integrity": "sha512-DPWjcUDQkCeEM4VnljEOEcXdAD7pp8zSZsgOujk/LGIwCXWbXJngin+MO4zbH429lzeC3WbYLGjE2MaUOwzpyw==", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emnapi/runtime": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.1.1.tgz", @@ -2732,6 +2743,26 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.1.2.tgz", + "integrity": "sha512-8JuczewTFIZ/XIjHQ+YlQUydHvlKx2hkcxtuGwh+t/t5zWyZct6YG4+xjHcq8xyc/e7FmFwf42Zj2YgICwmlvA==", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.1.0", + "@emnapi/runtime": "^1.1.0", + "@tybys/wasm-util": "^0.8.1" + } + }, + "node_modules/@napi-rs/wasm-runtime/node_modules/@emnapi/core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.1.1.tgz", + "integrity": "sha512-eu4KjHfXg3I+UUR7vSuwZXpRo4c8h4Rtb5Lu2F7Z4JqJFl/eidquONEBiRs6viXKpWBC3BaJBy68xGJ2j56idw==", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@next/env": { "version": "14.1.4", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.1.4.tgz", @@ -2901,164 +2932,660 @@ "node": ">= 10" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "node_modules/@node-rs/argon2": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2/-/argon2-1.7.0.tgz", + "integrity": "sha512-zfULc+/tmcWcxn+nHkbyY8vP3+MpEqKORbszt4UkpqZgBgDAAIYvuDN/zukfTgdmo6tmJKKVfzigZOPk4LlIog==", + "engines": { + "node": ">= 10" }, + "optionalDependencies": { + "@node-rs/argon2-android-arm-eabi": "1.7.0", + "@node-rs/argon2-android-arm64": "1.7.0", + "@node-rs/argon2-darwin-arm64": "1.7.0", + "@node-rs/argon2-darwin-x64": "1.7.0", + "@node-rs/argon2-freebsd-x64": "1.7.0", + "@node-rs/argon2-linux-arm-gnueabihf": "1.7.0", + "@node-rs/argon2-linux-arm64-gnu": "1.7.0", + "@node-rs/argon2-linux-arm64-musl": "1.7.0", + "@node-rs/argon2-linux-x64-gnu": "1.7.0", + "@node-rs/argon2-linux-x64-musl": "1.7.0", + "@node-rs/argon2-wasm32-wasi": "1.7.0", + "@node-rs/argon2-win32-arm64-msvc": "1.7.0", + "@node-rs/argon2-win32-ia32-msvc": "1.7.0", + "@node-rs/argon2-win32-x64-msvc": "1.7.0" + } + }, + "node_modules/@node-rs/argon2-android-arm-eabi": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm-eabi/-/argon2-android-arm-eabi-1.7.0.tgz", + "integrity": "sha512-udDqkr5P9E+wYX1SZwAVPdyfYvaF4ry9Tm+R9LkfSHbzWH0uhU6zjIwNRp7m+n4gx691rk+lqqDAIP8RLKwbhg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">= 8" + "node": ">= 10" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@node-rs/argon2-android-arm64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm64/-/argon2-android-arm64-1.7.0.tgz", + "integrity": "sha512-s9j/G30xKUx8WU50WIhF0fIl1EdhBGq0RQ06lEhZ0Gi0ap8lhqbE2Bn5h3/G2D1k0Dx+yjeVVNmt/xOQIRG38A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">= 8" + "node": ">= 10" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, + "node_modules/@node-rs/argon2-darwin-arm64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-darwin-arm64/-/argon2-darwin-arm64-1.7.0.tgz", + "integrity": "sha512-ZIz4L6HGOB9U1kW23g+m7anGNuTZ0RuTw0vNp3o+2DWpb8u8rODq6A8tH4JRL79S+Co/Nq608m9uackN2pe0Rw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 8" + "node": ">= 10" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@node-rs/argon2-darwin-x64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-darwin-x64/-/argon2-darwin-x64-1.7.0.tgz", + "integrity": "sha512-5oi/pxqVhODW/pj1+3zElMTn/YukQeywPHHYDbcAW3KsojFjKySfhcJMd1DjKTc+CHQI+4lOxZzSUzK7mI14Hw==", + "cpu": [ + "x64" + ], "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=14" + "node": ">= 10" } }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true, + "node_modules/@node-rs/argon2-freebsd-x64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-freebsd-x64/-/argon2-freebsd-x64-1.7.0.tgz", + "integrity": "sha512-Ify08683hA4QVXYoIm5SUWOY5DPIT/CMB0CQT+IdxQAg/F+qp342+lUkeAtD5bvStQuCx/dFO3bnnzoe2clMhA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" + "node": ">= 10" } }, - "node_modules/@prisma/client": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.12.0.tgz", - "integrity": "sha512-bk/+KPpRm0+IzqFCtAxrj+/TNiHzulspnO+OkysaYY/atc/eX0Gx8V3tTLxbHKVX0LKD4Hi8KKCcSbU1U72n7Q==", - "hasInstallScript": true, + "node_modules/@node-rs/argon2-linux-arm-gnueabihf": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm-gnueabihf/-/argon2-linux-arm-gnueabihf-1.7.0.tgz", + "integrity": "sha512-7DjDZ1h5AUHAtRNjD19RnQatbhL+uuxBASuuXIBu4/w6Dx8n7YPxwTP4MXfsvuRgKuMWiOb/Ub/HJ3kXVCXRkg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=16.13" - }, - "peerDependencies": { - "prisma": "*" - }, - "peerDependenciesMeta": { - "prisma": { - "optional": true - } + "node": ">= 10" } }, - "node_modules/@prisma/debug": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.12.0.tgz", - "integrity": "sha512-wK3fQLxPLMqf5riT5ZIhl8NffPSzFUwtzFX5CH7z/oI9Swmo9UhQlUgZABIVgdXSJ5OAlmRcDZtDKaMApIl8sg==" + "node_modules/@node-rs/argon2-linux-arm64-gnu": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm64-gnu/-/argon2-linux-arm64-gnu-1.7.0.tgz", + "integrity": "sha512-nJDoMP4Y3YcqGswE4DvP080w6O24RmnFEDnL0emdI8Nou17kNYBzP2546Nasx9GCyLzRcYQwZOUjrtUuQ+od2g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } }, - "node_modules/@prisma/engines": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.12.0.tgz", - "integrity": "sha512-rFNRul9JGu0d3tf8etBgmDQ4NVoDwgGrRguvQOc8i+c6g7xPjRuu4aKzMMvHWUuccvRx5+fs1KMBxQ0x2THt+Q==", - "hasInstallScript": true, - "dependencies": { - "@prisma/debug": "5.12.0", - "@prisma/engines-version": "5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab", - "@prisma/fetch-engine": "5.12.0", - "@prisma/get-platform": "5.12.0" + "node_modules/@node-rs/argon2-linux-arm64-musl": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm64-musl/-/argon2-linux-arm64-musl-1.7.0.tgz", + "integrity": "sha512-BKWS8iVconhE3jrb9mj6t1J9vwUqQPpzCbUKxfTGJfc+kNL58F1SXHBoe2cDYGnHrFEHTY0YochzXoAfm4Dm/A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/@prisma/engines-version": { - "version": "5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab.tgz", - "integrity": "sha512-6yvO8s80Tym61aB4QNtYZfWVmE3pwqe807jEtzm8C5VDe7nw8O1FGX3TXUaXmWV0fQTIAfRbeL2Gwrndabp/0g==" + "node_modules/@node-rs/argon2-linux-x64-gnu": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-x64-gnu/-/argon2-linux-x64-gnu-1.7.0.tgz", + "integrity": "sha512-EmgqZOlf4Jurk/szW1iTsVISx25bKksVC5uttJDUloTgsAgIGReCpUUO1R24pBhu9ESJa47iv8NSf3yAfGv6jQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } }, - "node_modules/@prisma/fetch-engine": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.12.0.tgz", - "integrity": "sha512-qkHQbZ1hspvOwcImvqY4yj7+FUlw0+uP+6tu3g24V4ULHOXLLkvr5ZZc6vy26OF0hkbD3kcDJCeutFis3poKgg==", + "node_modules/@node-rs/argon2-linux-x64-musl": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-x64-musl/-/argon2-linux-x64-musl-1.7.0.tgz", + "integrity": "sha512-/o1efYCYIxjfuoRYyBTi2Iy+1iFfhqHCvvVsnjNSgO1xWiWrX0Rrt/xXW5Zsl7vS2Y+yu8PL8KFWRzZhaVxfKA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/argon2-wasm32-wasi": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-wasm32-wasi/-/argon2-wasm32-wasi-1.7.0.tgz", + "integrity": "sha512-Evmk9VcxqnuwQftfAfYEr6YZYSPLzmKUsbFIMep5nTt9PT4XYRFAERj7wNYp+rOcBenF3X4xoB+LhwcOMTNE5w==", + "cpu": [ + "wasm32" + ], + "optional": true, "dependencies": { - "@prisma/debug": "5.12.0", - "@prisma/engines-version": "5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab", - "@prisma/get-platform": "5.12.0" + "@emnapi/core": "^0.45.0", + "@emnapi/runtime": "^0.45.0", + "@tybys/wasm-util": "^0.8.1", + "memfs-browser": "^3.4.13000" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@prisma/get-platform": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.12.0.tgz", - "integrity": "sha512-81Ptv9YJnwTArEBPQ2Lvu58sZPxy4OixKxVVgysFan6A3bFP7q8gIg15WTjsRuH4WXh6B667EM9sqoMTNu0fLQ==", + "node_modules/@node-rs/argon2-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "0.45.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-0.45.0.tgz", + "integrity": "sha512-Txumi3td7J4A/xTTwlssKieHKTGl3j4A1tglBx72auZ49YK7ePY6XZricgIg9mnZT4xPfA+UPCUdnhRuEFDL+w==", + "optional": true, "dependencies": { - "@prisma/debug": "5.12.0" + "tslib": "^2.4.0" } }, - "node_modules/@rushstack/eslint-patch": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.8.0.tgz", - "integrity": "sha512-0HejFckBN2W+ucM6cUOlwsByTKt9/+0tWhqUffNIcHqCXkthY/mZ7AuYPK/2IIaGWhdl0h+tICDO0ssLMd6XMQ==" + "node_modules/@node-rs/argon2-win32-arm64-msvc": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-arm64-msvc/-/argon2-win32-arm64-msvc-1.7.0.tgz", + "integrity": "sha512-qgsU7T004COWWpSA0tppDqDxbPLgg8FaU09krIJ7FBl71Sz8SFO40h7fDIjfbTT5w7u6mcaINMQ5bSHu75PCaA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } }, - "node_modules/@svgr/babel-plugin-add-jsx-attribute": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", - "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", - "dev": true, + "node_modules/@node-rs/argon2-win32-ia32-msvc": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-ia32-msvc/-/argon2-win32-ia32-msvc-1.7.0.tgz", + "integrity": "sha512-JGafwWYQ/HpZ3XSwP4adQ6W41pRvhcdXvpzIWtKvX+17+xEXAe2nmGWM6s27pVkg1iV2ZtoYLRDkOUoGqZkCcg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">= 10" } }, - "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", - "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", - "dev": true, + "node_modules/@node-rs/argon2-win32-x64-msvc": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-x64-msvc/-/argon2-win32-x64-msvc-1.7.0.tgz", + "integrity": "sha512-9oq4ShyFakw8AG3mRls0AoCpxBFcimYx7+jvXeAf2OqKNO+mSA6eZ9z7KQeVCi0+SOEUYxMGf5UiGiDb9R6+9Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">= 10" } }, - "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", - "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", - "dev": true, + "node_modules/@node-rs/bcrypt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt/-/bcrypt-1.9.0.tgz", + "integrity": "sha512-u2OlIxW264bFUfvbFqDz9HZKFjwe8FHFtn7T/U8mYjPZ7DWYpbUB+/dkW/QgYfMSfR0ejkyuWaBBe0coW7/7ig==", "engines": { - "node": ">=14" + "node": ">= 10" }, "funding": { "type": "github", - "url": "https://github.com/sponsors/gregberge" + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@node-rs/bcrypt-android-arm-eabi": "1.9.0", + "@node-rs/bcrypt-android-arm64": "1.9.0", + "@node-rs/bcrypt-darwin-arm64": "1.9.0", + "@node-rs/bcrypt-darwin-x64": "1.9.0", + "@node-rs/bcrypt-freebsd-x64": "1.9.0", + "@node-rs/bcrypt-linux-arm-gnueabihf": "1.9.0", + "@node-rs/bcrypt-linux-arm64-gnu": "1.9.0", + "@node-rs/bcrypt-linux-arm64-musl": "1.9.0", + "@node-rs/bcrypt-linux-x64-gnu": "1.9.0", + "@node-rs/bcrypt-linux-x64-musl": "1.9.0", + "@node-rs/bcrypt-wasm32-wasi": "1.9.0", + "@node-rs/bcrypt-win32-arm64-msvc": "1.9.0", + "@node-rs/bcrypt-win32-ia32-msvc": "1.9.0", + "@node-rs/bcrypt-win32-x64-msvc": "1.9.0" + } + }, + "node_modules/@node-rs/bcrypt-android-arm-eabi": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm-eabi/-/bcrypt-android-arm-eabi-1.9.0.tgz", + "integrity": "sha512-nOCFISGtnodGHNiLrG0WYLWr81qQzZKYfmwHc7muUeq+KY0sQXyHOwZk9OuNQAWv/lnntmtbwkwT0QNEmOyLvA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/bcrypt-android-arm64": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm64/-/bcrypt-android-arm64-1.9.0.tgz", + "integrity": "sha512-+ZrIAtigVmjYkqZQTThHVlz0+TG6D+GDHWhVKvR2DifjtqJ0i+mb9gjo++hN+fWEQdWNGxKCiBBjwgT4EcXd6A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/bcrypt-darwin-arm64": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-arm64/-/bcrypt-darwin-arm64-1.9.0.tgz", + "integrity": "sha512-CQiS+F9Pa0XozvkXR1g7uXE9QvBOPOplDg0iCCPRYTN9PqA5qYxhwe48G3o+v2UeQceNRrbnEtWuANm7JRqIhw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/bcrypt-darwin-x64": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-x64/-/bcrypt-darwin-x64-1.9.0.tgz", + "integrity": "sha512-4pTKGawYd7sNEjdJ7R/R67uwQH1VvwPZ0SSUMmeNHbxD5QlwAPXdDH11q22uzVXsvNFZ6nGQBg8No5OUGpx6Ug==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/bcrypt-freebsd-x64": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-freebsd-x64/-/bcrypt-freebsd-x64-1.9.0.tgz", + "integrity": "sha512-UmWzySX4BJhT/B8xmTru6iFif3h0Rpx3TqxRLCcbgmH43r7k5/9QuhpiyzpvKGpKHJCFNm4F3rC2wghvw5FCIg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/bcrypt-linux-arm-gnueabihf": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm-gnueabihf/-/bcrypt-linux-arm-gnueabihf-1.9.0.tgz", + "integrity": "sha512-8qoX4PgBND2cVwsbajoAWo3NwdfJPEXgpCsZQZURz42oMjbGyhhSYbovBCskGU3EBLoC8RA2B1jFWooeYVn5BA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/bcrypt-linux-arm64-gnu": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-gnu/-/bcrypt-linux-arm64-gnu-1.9.0.tgz", + "integrity": "sha512-TuAC6kx0SbcIA4mSEWPi+OCcDjTQUMl213v5gMNlttF+D4ieIZx6pPDGTaMO6M2PDHTeCG0CBzZl0Lu+9b0c7Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/bcrypt-linux-arm64-musl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-musl/-/bcrypt-linux-arm64-musl-1.9.0.tgz", + "integrity": "sha512-/sIvKDABOI8QOEnLD7hIj02BVaNOuCIWBKvxcJOt8+TuwJ6zmY1UI5kSv9d99WbiHjTp97wtAUbZQwauU4b9ew==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/bcrypt-linux-x64-gnu": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-gnu/-/bcrypt-linux-x64-gnu-1.9.0.tgz", + "integrity": "sha512-DyyhDHDsLBsCKz1tZ1hLvUZSc1DK0FU0v52jK6IBQxrj24WscSU9zZe7ie/V9kdmA4Ep57BfpWX8Dsa2JxGdgQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/bcrypt-linux-x64-musl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-musl/-/bcrypt-linux-x64-musl-1.9.0.tgz", + "integrity": "sha512-duIiuqQ+Lew8ASSAYm6ZRqcmfBGWwsi81XLUwz86a2HR7Qv6V4yc3ZAUQovAikhjCsIqe8C11JlAZSK6+PlXYg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/bcrypt-wasm32-wasi": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-wasm32-wasi/-/bcrypt-wasm32-wasi-1.9.0.tgz", + "integrity": "sha512-ylaGmn9Wjwv/D5lxtawttx3H6Uu2WTTR7lWlRHGT6Ga/MB1Vj4OjSGUW8G8zIVnKuXpGbZ92pgHlt4HUpSLctw==", + "cpu": [ + "wasm32" + ], + "optional": true, + "dependencies": { + "@emnapi/core": "^0.45.0", + "@emnapi/runtime": "^0.45.0", + "@tybys/wasm-util": "^0.8.1", + "memfs-browser": "^3.4.13000" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@node-rs/bcrypt-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "0.45.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-0.45.0.tgz", + "integrity": "sha512-Txumi3td7J4A/xTTwlssKieHKTGl3j4A1tglBx72auZ49YK7ePY6XZricgIg9mnZT4xPfA+UPCUdnhRuEFDL+w==", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@node-rs/bcrypt-win32-arm64-msvc": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-arm64-msvc/-/bcrypt-win32-arm64-msvc-1.9.0.tgz", + "integrity": "sha512-2h86gF7QFyEzODuDFml/Dp1MSJoZjxJ4yyT2Erf4NkwsiA5MqowUhUsorRwZhX6+2CtlGa7orbwi13AKMsYndw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/bcrypt-win32-ia32-msvc": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-ia32-msvc/-/bcrypt-win32-ia32-msvc-1.9.0.tgz", + "integrity": "sha512-kqxalCvhs4FkN0+gWWfa4Bdy2NQAkfiqq/CEf6mNXC13RSV673Ev9V8sRlQyNpCHCNkeXfOT9pgoBdJmMs9muA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/bcrypt-win32-x64-msvc": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-x64-msvc/-/bcrypt-win32-x64-msvc-1.9.0.tgz", + "integrity": "sha512-2y0Tuo6ZAT2Cz8V7DHulSlv1Bip3zbzeXyeur+uR25IRNYXKvI/P99Zl85Fbuu/zzYAZRLLlGTRe6/9IHofe/w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@prisma/client": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.12.0.tgz", + "integrity": "sha512-bk/+KPpRm0+IzqFCtAxrj+/TNiHzulspnO+OkysaYY/atc/eX0Gx8V3tTLxbHKVX0LKD4Hi8KKCcSbU1U72n7Q==", + "hasInstallScript": true, + "engines": { + "node": ">=16.13" + }, + "peerDependencies": { + "prisma": "*" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + } + } + }, + "node_modules/@prisma/debug": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.12.0.tgz", + "integrity": "sha512-wK3fQLxPLMqf5riT5ZIhl8NffPSzFUwtzFX5CH7z/oI9Swmo9UhQlUgZABIVgdXSJ5OAlmRcDZtDKaMApIl8sg==" + }, + "node_modules/@prisma/engines": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.12.0.tgz", + "integrity": "sha512-rFNRul9JGu0d3tf8etBgmDQ4NVoDwgGrRguvQOc8i+c6g7xPjRuu4aKzMMvHWUuccvRx5+fs1KMBxQ0x2THt+Q==", + "hasInstallScript": true, + "dependencies": { + "@prisma/debug": "5.12.0", + "@prisma/engines-version": "5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab", + "@prisma/fetch-engine": "5.12.0", + "@prisma/get-platform": "5.12.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab.tgz", + "integrity": "sha512-6yvO8s80Tym61aB4QNtYZfWVmE3pwqe807jEtzm8C5VDe7nw8O1FGX3TXUaXmWV0fQTIAfRbeL2Gwrndabp/0g==" + }, + "node_modules/@prisma/fetch-engine": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.12.0.tgz", + "integrity": "sha512-qkHQbZ1hspvOwcImvqY4yj7+FUlw0+uP+6tu3g24V4ULHOXLLkvr5ZZc6vy26OF0hkbD3kcDJCeutFis3poKgg==", + "dependencies": { + "@prisma/debug": "5.12.0", + "@prisma/engines-version": "5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab", + "@prisma/get-platform": "5.12.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.12.0.tgz", + "integrity": "sha512-81Ptv9YJnwTArEBPQ2Lvu58sZPxy4OixKxVVgysFan6A3bFP7q8gIg15WTjsRuH4WXh6B667EM9sqoMTNu0fLQ==", + "dependencies": { + "@prisma/debug": "5.12.0" + } + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.8.0.tgz", + "integrity": "sha512-0HejFckBN2W+ucM6cUOlwsByTKt9/+0tWhqUffNIcHqCXkthY/mZ7AuYPK/2IIaGWhdl0h+tICDO0ssLMd6XMQ==" + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" }, "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -3353,6 +3880,15 @@ "node": ">=10.13.0" } }, + "node_modules/@tybys/wasm-util": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.8.1.tgz", + "integrity": "sha512-GSsTwyBl4pIzsxAY5wroZdyQKyhXk0d8PCRZtrSZ2WEB1cBdrp2EgGBwHOGCZtIIPun/DL3+AykCv+J6fyRH4Q==", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/bcrypt": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz", @@ -5546,50 +6082,252 @@ "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", "dev": true, "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", + "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", + "dependencies": { + "@babel/runtime": "^7.23.2", + "aria-query": "^5.3.0", + "array-includes": "^3.1.7", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "=4.7.0", + "axobject-query": "^3.2.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.15", + "hasown": "^2.0.0", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "dependencies": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "peerDependencies": { + "eslint": ">=5.16.0" + } + }, + "node_modules/eslint-plugin-node/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-node/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" }, "engines": { - "node": ">=8.10.0" + "node": "^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://opencollective.com/eslint-plugin-prettier" }, "peerDependencies": { - "eslint": ">=4.19.1" + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } } }, - "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "node_modules/eslint-plugin-react": { + "version": "7.34.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", + "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", "dependencies": { "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "array.prototype.flat": "^1.3.2", + "array.prototype.findlast": "^1.2.4", "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.3", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", - "is-glob": "^4.0.3", + "es-iterator-helpers": "^1.0.17", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", + "object.entries": "^1.1.7", "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", + "object.hasown": "^1.1.3", "object.values": "^1.1.7", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "tsconfig-paths": "^3.15.0" + "string.prototype.matchall": "^4.0.10" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" } }, - "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", @@ -5598,15 +6336,7 @@ "concat-map": "0.0.1" } }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { + "node_modules/eslint-plugin-react/node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", @@ -5617,7 +6347,7 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { + "node_modules/eslint-plugin-react/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", @@ -5628,36 +6358,73 @@ "node": "*" } }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", - "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", "dependencies": { - "@babel/runtime": "^7.23.2", - "aria-query": "^5.3.0", - "array-includes": "^3.1.7", - "array.prototype.flatmap": "^1.3.2", - "ast-types-flow": "^0.0.8", - "axe-core": "=4.7.0", - "axobject-query": "^3.2.1", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "es-iterator-helpers": "^1.0.15", - "hasown": "^2.0.0", - "jsx-ast-utils": "^3.3.5", - "language-tags": "^1.0.9", - "minimatch": "^3.1.2", - "object.entries": "^1.1.7", - "object.fromentries": "^2.0.7" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=4.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", @@ -5666,411 +6433,517 @@ "concat-map": "0.0.1" } }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dependencies": { - "brace-expansion": "^1.1.7" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" }, "engines": { - "node": "*" + "node": ">=8.6.0" } }, - "node_modules/eslint-plugin-node": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", - "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", - "dev": true, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dependencies": { - "eslint-plugin-es": "^3.0.0", - "eslint-utils": "^2.0.0", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" + "is-glob": "^4.0.1" }, "engines": { - "node": ">=8.10.0" - }, - "peerDependencies": { - "eslint": ">=5.16.0" + "node": ">= 6" } }, - "node_modules/eslint-plugin-node/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "reusify": "^1.0.4" } }, - "node_modules/eslint-plugin-node/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dependencies": { - "brace-expansion": "^1.1.7" + "flat-cache": "^3.0.4" }, "engines": { - "node": "*" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/eslint-plugin-prettier": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", - "dev": true, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" + "to-regex-range": "^5.0.1" }, "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": "*", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } + "node": ">=8" } }, - "node_modules/eslint-plugin-react": { - "version": "7.34.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", - "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlast": "^1.2.4", - "array.prototype.flatmap": "^1.3.2", - "array.prototype.toreversed": "^1.1.2", - "array.prototype.tosorted": "^1.1.3", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.17", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.7", - "object.fromentries": "^2.0.7", - "object.hasown": "^1.1.3", - "object.values": "^1.1.7", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.10" - }, - "engines": { - "node": ">=4" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", "engines": { "node": ">=10" }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dependencies": { - "esutils": "^2.0.2" + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" }, "engines": { - "node": ">=0.10.0" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/eslint-plugin-react/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==" + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], "engines": { - "node": "*" + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "is-callable": "^1.1.3" } }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=14" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "engines": { - "node": ">=6" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, "engines": { - "node": ">=4" + "node": ">= 6" } }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "*" }, "funding": { - "url": "https://opencollective.com/eslint" + "type": "patreon", + "url": "https://github.com/sponsors/rawify" } }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dependencies": { - "type-fest": "^0.20.2" + "yallist": "^4.0.0" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", + "optional": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "*" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "engines": { - "node": ">=10" - }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "dependencies": { - "estraverse": "^5.2.0" + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" }, "engines": { - "node": ">=4.0" + "node": ">=10" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, "engines": { - "node": ">=4.0" + "node": ">=6.9.0" } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" }, "engines": { - "node": ">=8.6.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/get-tsconfig": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", + "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", "dependencies": { - "is-glob": "^4.0.1" + "resolve-pkg-maps": "^1.0.0" }, - "engines": { - "node": ">= 6" + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dependencies": { - "reusify": "^1.0.4" + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" } }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, "dependencies": { - "flat-cache": "^3.0.4" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=10" } }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", "dependencies": { - "to-regex-range": "^5.0.1" + "define-properties": "^1.1.3" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" }, "engines": { "node": ">=10" @@ -6079,234 +6952,183 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "get-intrinsic": "^1.1.3" }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==" + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, - "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dependencies": { - "is-callable": "^1.1.3" + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" } }, - "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" + "es-define-property": "^1.0.0" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "engines": { - "node": ">=14" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "engines": { - "node": ">=14" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "has-symbols": "^1.0.3" }, "engines": { - "node": ">= 6" - } - }, - "node_modules/fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", - "engines": { - "node": "*" + "node": ">= 0.4" }, "funding": { - "type": "patreon", - "url": "https://github.com/sponsors/rawify" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { - "minipass": "^3.0.0" + "function-bind": "^1.1.2" }, "engines": { - "node": ">= 8" + "node": ">= 0.4" } }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dependencies": { - "yallist": "^4.0.0" + "agent-base": "6", + "debug": "4" }, "engines": { - "node": ">=8" + "node": ">= 6" } }, - "node_modules/fs-minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 4" } }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" } }, - "node_modules/gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" - }, - "engines": { - "node": ">=10" + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dependencies": { "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "hasown": "^2.0.0", + "side-channel": "^1.0.4" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -6315,75 +7137,67 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-tsconfig": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", - "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true }, - "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=12" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dependencies": { - "is-glob": "^4.0.3" + "has-bigints": "^1.0.1" }, - "engines": { - "node": ">=10.13.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dependencies": { - "brace-expansion": "^2.0.1" + "binary-extensions": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dependencies": { - "define-properties": "^1.1.3" - }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "engines": { "node": ">= 0.4" }, @@ -6391,88 +7205,79 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" + "hasown": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gopd": { + "node_modules/is-data-view": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", "dependencies": { - "get-intrinsic": "^1.1.3" + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/has-property-descriptors": { + "node_modules/is-finalizationregistry": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", "dependencies": { - "es-define-property": "^1.0.0" + "call-bind": "^1.0.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -6480,13 +7285,21 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dependencies": { - "has-symbols": "^1.0.3" + "is-extglob": "^2.1.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "engines": { "node": ">= 0.4" }, @@ -6494,99 +7307,79 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dependencies": { - "function-bind": "^1.1.2" - }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "engines": { "node": ">= 0.4" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dependencies": { - "agent-base": "6", - "debug": "4" }, - "engines": { - "node": ">= 6" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "engines": { - "node": ">= 4" + "node": ">=0.12.0" } }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "engines": { - "node": ">=0.8.19" + "node": ">=8" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" + "call-bind": "^1.0.7" }, "engines": { "node": ">= 0.4" @@ -6595,16 +7388,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -6615,36 +7402,38 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-bigint": { + "node_modules/is-symbol": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dependencies": { - "has-bigints": "^1.0.1" + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dependencies": { - "binary-extensions": "^2.0.0" + "which-typed-array": "^1.1.14" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "engines": { "node": ">= 0.4" }, @@ -6652,502 +7441,744 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "engines": { - "node": ">= 0.4" + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", "dependencies": { - "hasown": "^2.0.0" + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-data-view": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", "dependencies": { - "is-typed-array": "^1.1.13" + "@isaacs/cliui": "^8.0.2" }, "engines": { - "node": ">= 0.4" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dependencies": { - "has-tostringtag": "^1.0.0" + "argparse": "^2.0.1" }, - "engines": { - "node": ">= 0.4" + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=4" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "dependencies": { - "call-bind": "^1.0.2" + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=4.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dependencies": { + "json-buffer": "3.0.1" } }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", "dependencies": { - "has-tostringtag": "^1.0.0" + "language-subtag-registry": "^0.3.20" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dependencies": { - "is-extglob": "^2.1.1" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10" } }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "js-tokens": "^3.0.0 || ^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "loose-envify": "cli.js" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "engines": { - "node": ">=8" + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" } }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "yallist": "^3.0.2" + } + }, + "node_modules/lucia": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lucia/-/lucia-3.1.1.tgz", + "integrity": "sha512-Ygvgnqq7Ha7lYVaZATPwkPD2s2Qlsm71Z2o0byx/abNBfFldCRow5sNii6RqMsuMpK957RAI3Gw4/aWoagkc7A==", + "dependencies": { + "oslo": "1.0.1" } }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "node_modules/lucia/node_modules/@node-rs/argon2": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2/-/argon2-1.7.2.tgz", + "integrity": "sha512-+H6pc3M1vIX9YnG59YW7prHhhpv19P8YyxlXHnnFzTimf2q+kKDF7mGWbhvN9STqIY+P70Patn0Q6qb6Ib5/4g==", "engines": { - "node": ">= 0.4" + "node": ">= 10" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "optionalDependencies": { + "@node-rs/argon2-android-arm-eabi": "1.7.2", + "@node-rs/argon2-android-arm64": "1.7.2", + "@node-rs/argon2-darwin-arm64": "1.7.2", + "@node-rs/argon2-darwin-x64": "1.7.2", + "@node-rs/argon2-freebsd-x64": "1.7.2", + "@node-rs/argon2-linux-arm-gnueabihf": "1.7.2", + "@node-rs/argon2-linux-arm64-gnu": "1.7.2", + "@node-rs/argon2-linux-arm64-musl": "1.7.2", + "@node-rs/argon2-linux-x64-gnu": "1.7.2", + "@node-rs/argon2-linux-x64-musl": "1.7.2", + "@node-rs/argon2-wasm32-wasi": "1.7.2", + "@node-rs/argon2-win32-arm64-msvc": "1.7.2", + "@node-rs/argon2-win32-ia32-msvc": "1.7.2", + "@node-rs/argon2-win32-x64-msvc": "1.7.2" + } + }, + "node_modules/lucia/node_modules/@node-rs/argon2-android-arm-eabi": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm-eabi/-/argon2-android-arm-eabi-1.7.2.tgz", + "integrity": "sha512-WhW84XOzdR4AOGc4BJvIg5lCRVBL0pXp/PPCe8QCyWw493p7VdNCdYpr2xdtjS/0zImmY85HNB/6zpzjLRTT/A==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", - "dependencies": { - "call-bind": "^1.0.7" - }, + "node_modules/lucia/node_modules/@node-rs/argon2-android-arm64": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm64/-/argon2-android-arm64-1.7.2.tgz", + "integrity": "sha512-CdtayHSMIyDuVhSYFirwA757c4foQuyTjpysgFJLHweP9C7uDiBf9WBYij+UyabpaCadJ0wPyK6Vakinvlk4/g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 10" } }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, + "node_modules/lucia/node_modules/@node-rs/argon2-darwin-arm64": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-darwin-arm64/-/argon2-darwin-arm64-1.7.2.tgz", + "integrity": "sha512-hUOhtgYHTEyzX5sgMZVdXunONOus2HWpWydF5D/RYJ1mZ76FXRnFpQE40DqbzisdPIraKdn40m7JqkPP7wqdyg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 10" } }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dependencies": { - "has-symbols": "^1.0.2" - }, + "node_modules/lucia/node_modules/@node-rs/argon2-darwin-x64": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-darwin-x64/-/argon2-darwin-x64-1.7.2.tgz", + "integrity": "sha512-lfs5HX+t542yUfcv6Aa/NeGD1nUCwyQNgnPEGcik71Ow6V13hkR1bHgmT1u3CHN4fBts0gW+DQEDsq1xlVgkvw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 10" } }, - "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", - "dependencies": { - "which-typed-array": "^1.1.14" - }, + "node_modules/lucia/node_modules/@node-rs/argon2-freebsd-x64": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-freebsd-x64/-/argon2-freebsd-x64-1.7.2.tgz", + "integrity": "sha512-ROoF+4VaCBJUjddrTN1hjuqSl89ppRcjVXJscSPJjWzTlbzFmGGovJvIzUBmCr/Oq3yM1zKHj6MP9oRD5cB+/g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 10" } }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "node_modules/lucia/node_modules/@node-rs/argon2-linux-arm-gnueabihf": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm-gnueabihf/-/argon2-linux-arm-gnueabihf-1.7.2.tgz", + "integrity": "sha512-CBSB8KPI8LS74Bcz3dYaa2/khULutz4vSDvFWUERlSLX+mPdDhoZi6UPuUPPF9e01w8AbiK1YCqlLUTm3tIMfw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 10" } }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/lucia/node_modules/@node-rs/argon2-linux-arm64-gnu": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm64-gnu/-/argon2-linux-arm64-gnu-1.7.2.tgz", + "integrity": "sha512-6LBTug6ZiWFakP3X3Nqs7ZTM03gmcSWX4YvEn20HhhQE5NDrsrw3zNqGj0cJiNzKKIMSDDuj7uGy+ITEfNo4CA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/is-weakset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", - "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4" - }, + "node_modules/lucia/node_modules/@node-rs/argon2-linux-arm64-musl": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm64-musl/-/argon2-linux-arm64-musl-1.7.2.tgz", + "integrity": "sha512-KjhQ+ZPne29t9VRVeIif7JdKwQba+tM6CBNYBoJB1iON0CUKeqSQtZcHuTj9gkf2SNRG5bsU4ABcfxd0OKsKHg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 10" } }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "node_modules/lucia/node_modules/@node-rs/argon2-linux-x64-gnu": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-x64-gnu/-/argon2-linux-x64-gnu-1.7.2.tgz", + "integrity": "sha512-BQvp+iLtKqomHz4q5t1aKoni9osgvUDU5sZtHAlFm5dRTlGHnympcQVATRE5GHyH9C6MIM9W7P1kqEeCLGPolQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } }, - "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", - "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" + "node_modules/lucia/node_modules/@node-rs/argon2-linux-x64-musl": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-x64-musl/-/argon2-linux-x64-musl-1.7.2.tgz", + "integrity": "sha512-yXJudpBZQ98g+lWaHn9EzZ5KsAyqRdlpub/K+5NP7gHehb8wzBRIFAejIHAG0fvzQEEc86VOnV2koWIVZxWAvw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "node_modules/lucia/node_modules/@node-rs/argon2-wasm32-wasi": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-wasm32-wasi/-/argon2-wasm32-wasi-1.7.2.tgz", + "integrity": "sha512-diXlVjJZY2GIV8ZDwUqXPhacXsFR0klGSv5D9f+XidwWXK4udtzDhkM/7N/Mb7h1HAWaxZ6IN9spYFjvWH1wqg==", + "cpu": [ + "wasm32" + ], + "optional": true, "dependencies": { - "@isaacs/cliui": "^8.0.2" + "@napi-rs/wasm-runtime": "^0.1.1" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "node": ">=14.0.0" } }, - "node_modules/jiti": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", - "bin": { - "jiti": "bin/jiti.js" + "node_modules/lucia/node_modules/@node-rs/argon2-win32-arm64-msvc": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-arm64-msvc/-/argon2-win32-arm64-msvc-1.7.2.tgz", + "integrity": "sha512-dhIBrY04P9nbmwzBpgERQDmmSu4YBZyeEE32t4TikMz5rQ07iaVC+JpGmtCBZoDIsLDHGC8cikENd3YEqpqIcA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "node_modules/lucia/node_modules/@node-rs/argon2-win32-ia32-msvc": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-ia32-msvc/-/argon2-win32-ia32-msvc-1.7.2.tgz", + "integrity": "sha512-o1tfqr8gyALCzuxBoQfvhxkeYMaw/0H8Gmt7klTYyEIBvEFu7SD5qytXO9Px7t5420nZL/Wy5cflg3IB1s57Pg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "node_modules/lucia/node_modules/@node-rs/argon2-win32-x64-msvc": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-x64-msvc/-/argon2-win32-x64-msvc-1.7.2.tgz", + "integrity": "sha512-v0h53XUc7hNgWiWi0qcMcHvj9/kwuItI9NwLK4C+gtzT3UB0cedhfIL8HFMKThMXasy41ZdbpCF2Bi0kJoLNEg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" + "node_modules/lucia/node_modules/@node-rs/bcrypt": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt/-/bcrypt-1.9.2.tgz", + "integrity": "sha512-FKUo9iCSIti+ldwoOlY1ztyIFhZxEgT7jZ/UCt/9bg1rLmNdbQQD2JKIMImDCqmTWuLPY4ZF4Q5MyOMIfDCd8Q==", + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" }, + "optionalDependencies": { + "@node-rs/bcrypt-android-arm-eabi": "1.9.2", + "@node-rs/bcrypt-android-arm64": "1.9.2", + "@node-rs/bcrypt-darwin-arm64": "1.9.2", + "@node-rs/bcrypt-darwin-x64": "1.9.2", + "@node-rs/bcrypt-freebsd-x64": "1.9.2", + "@node-rs/bcrypt-linux-arm-gnueabihf": "1.9.2", + "@node-rs/bcrypt-linux-arm64-gnu": "1.9.2", + "@node-rs/bcrypt-linux-arm64-musl": "1.9.2", + "@node-rs/bcrypt-linux-x64-gnu": "1.9.2", + "@node-rs/bcrypt-linux-x64-musl": "1.9.2", + "@node-rs/bcrypt-wasm32-wasi": "1.9.2", + "@node-rs/bcrypt-win32-arm64-msvc": "1.9.2", + "@node-rs/bcrypt-win32-ia32-msvc": "1.9.2", + "@node-rs/bcrypt-win32-x64-msvc": "1.9.2" + } + }, + "node_modules/lucia/node_modules/@node-rs/bcrypt-android-arm-eabi": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm-eabi/-/bcrypt-android-arm-eabi-1.9.2.tgz", + "integrity": "sha512-er/Q2khwpan9pczvTTqY/DJE4UU65u31xd0NkZlHUTKyB7djRhWfzoGexGx2GN+k831/RR3U8kKE/8QUHeO3hQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=4" + "node": ">= 10" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + "node_modules/lucia/node_modules/@node-rs/bcrypt-android-arm64": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm64/-/bcrypt-android-arm64-1.9.2.tgz", + "integrity": "sha512-OUYatOEG5vbLbF73q2TC8UqrDO81zUQxnaFD/OAB1hcm6J+ur0zJ8E53c35/DIqkTp7JarPMraC4rouJ2ugN4w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, + "node_modules/lucia/node_modules/@node-rs/bcrypt-darwin-arm64": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-arm64/-/bcrypt-darwin-arm64-1.9.2.tgz", + "integrity": "sha512-svJKsGbzMAxOB5oluOYneN4YkKUy26WSMgm3KOIhgoX30IeMilj+2jFN/5qrI0oDZ0Iczb3XyL5DuZFtEkdP8A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6" + "node": ">= 10" } }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, + "node_modules/lucia/node_modules/@node-rs/bcrypt-darwin-x64": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-x64/-/bcrypt-darwin-x64-1.9.2.tgz", + "integrity": "sha512-9OrySjBi/rWix8NZWD/TrNbNcwMY0pAiMHdL09aJnJ07uPih83GGh1pq4UHCYFCMy7iTX8swOmDlGBUImkOZbg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=4.0" + "node": ">= 10" } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dependencies": { - "json-buffer": "3.0.1" + "node_modules/lucia/node_modules/@node-rs/bcrypt-freebsd-x64": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-freebsd-x64/-/bcrypt-freebsd-x64-1.9.2.tgz", + "integrity": "sha512-/djXV71RO6g5L1mI2pVvmp3x3pH7G4uKI3ODG1JBIXoz334oOcCMh40sB0uq0ljP8WEadker01p4T1rJE98fpg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==" + "node_modules/lucia/node_modules/@node-rs/bcrypt-linux-arm-gnueabihf": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm-gnueabihf/-/bcrypt-linux-arm-gnueabihf-1.9.2.tgz", + "integrity": "sha512-F7wP950OTAooxEleUN4I2hqryGZK7hi1cSgRF13Wvbc597RFux35KiSxIXUA3mNt2DE7lV2PeceEtCOScaThWQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } }, - "node_modules/language-tags": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", - "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", - "dependencies": { - "language-subtag-registry": "^0.3.20" - }, + "node_modules/lucia/node_modules/@node-rs/bcrypt-linux-arm64-gnu": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-gnu/-/bcrypt-linux-arm64-gnu-1.9.2.tgz", + "integrity": "sha512-MehG+yQ0TgKMgKR1rO4hdvHkVsTM91Cof8qI9EJlS5+7+QSwfFA5O0zGwCkISD7bsyauJ5uJgcByGjpEobAHOg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=0.10" + "node": ">= 10" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, + "node_modules/lucia/node_modules/@node-rs/bcrypt-linux-arm64-musl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-musl/-/bcrypt-linux-arm64-musl-1.9.2.tgz", + "integrity": "sha512-PRZTAJjOwKEGsIhmBvfNh81So+wGl4QyCFAt23j+KwBujLStjC0N3YaqtTlWVKG9tcriPtmMYiAQtXWIyIgg/w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.8.0" + "node": ">= 10" } }, - "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "node_modules/lucia/node_modules/@node-rs/bcrypt-linux-x64-gnu": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-gnu/-/bcrypt-linux-x64-gnu-1.9.2.tgz", + "integrity": "sha512-5WfGO+O1m7nJ55WZ8XDq+ItA98Z4O7sNWsR+1nIj9YGT+Tx5zkQ2RBhpK6oCWZMluuZ0eKQ0FDmyP6K+2NDRIA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" + "node": ">= 10" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + "node_modules/lucia/node_modules/@node-rs/bcrypt-linux-x64-musl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-musl/-/bcrypt-linux-x64-musl-1.9.2.tgz", + "integrity": "sha512-VjCn0388p6PMCVUYHgYmHZrKNc7WwNJRr2WLJsHbQRGDOKbpNL6YolCjQxUchcSPDhzwrq1cIdy4j0fpoXEsdw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/lucia/node_modules/@node-rs/bcrypt-wasm32-wasi": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-wasm32-wasi/-/bcrypt-wasm32-wasi-1.9.2.tgz", + "integrity": "sha512-P06aHfMzm9makwU+nM7WA65yQnS1xuqJ8l/6I/LvXjnl+lfB3DtJ2B0CSLtjnUGpUgcHbWl5gEbNnTPxSAirjQ==", + "cpu": [ + "wasm32" + ], + "optional": true, "dependencies": { - "p-locate": "^5.0.0" + "@napi-rs/wasm-runtime": "^0.1.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=14.0.0" } }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + "node_modules/lucia/node_modules/@node-rs/bcrypt-win32-arm64-msvc": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-arm64-msvc/-/bcrypt-win32-arm64-msvc-1.9.2.tgz", + "integrity": "sha512-Iyo/Q5/eNw27VRd3mLBgh1b9b5fnT3QHTVwxv3Siv/MRAIfJXH/cTOe18qSwYQzNh0ZioW4yemFPYCWSZi7szA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" + "node_modules/lucia/node_modules/@node-rs/bcrypt-win32-ia32-msvc": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-ia32-msvc/-/bcrypt-win32-ia32-msvc-1.9.2.tgz", + "integrity": "sha512-6LHWMaPylyyHoS5863YpxAACVB8DWCxro5W6pQ4h8WKSgHpJp8Um9jphTdN0A2w45HZjUnfcFuiFFC+TbftjCw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, - "dependencies": { - "tslib": "^2.0.3" + "node_modules/lucia/node_modules/@node-rs/bcrypt-win32-x64-msvc": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-x64-msvc/-/bcrypt-win32-x64-msvc-1.9.2.tgz", + "integrity": "sha512-vZ9T1MOaYkLO9FTyl28YX0SYJneiYTKNFgM8PUv8nas8xrD+7OzokA0fEtlNp6413T7IKSD/iG9qi8nTWsiyGg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, + "node_modules/lucia/node_modules/oslo": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/oslo/-/oslo-1.0.1.tgz", + "integrity": "sha512-esfzZry+HfGgK/GCYkg7BRlLd3RH5aHa08wgLJPYjENXybi0BvXxGk0LbUj+lXfz2TkjPDHe4rB/o6JxRLHxBg==", "dependencies": { - "yallist": "^3.0.2" + "@node-rs/argon2": "1.7.2", + "@node-rs/bcrypt": "1.9.2" } }, "node_modules/make-dir": { @@ -7170,6 +8201,27 @@ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", "dev": true }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "optional": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/memfs-browser": { + "version": "3.5.10302", + "resolved": "https://registry.npmjs.org/memfs-browser/-/memfs-browser-3.5.10302.tgz", + "integrity": "sha512-JJTc/nh3ig05O0gBBGZjTCPOyydaTxNF0uHYBrcc1gHNnO+KIHIvo0Y1FKCJsaei6FCl8C6xfQomXqu+cuzkIw==", + "optional": true, + "dependencies": { + "memfs": "3.5.3" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -7623,6 +8675,15 @@ "node": ">= 0.8.0" } }, + "node_modules/oslo": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/oslo/-/oslo-1.2.0.tgz", + "integrity": "sha512-OoFX6rDsNcOQVAD2gQD/z03u4vEjWZLzJtwkmgfRF+KpQUXwdgEXErD7zNhyowmHwHefP+PM9Pw13pgpHMRlzw==", + "dependencies": { + "@node-rs/argon2": "1.7.0", + "@node-rs/bcrypt": "1.9.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", diff --git a/package.json b/package.json index 7dd1de2..cf798be 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,9 @@ "dotenv": "16.4.5", "eslint": "8.57.0", "eslint-config-next": "14.1.4", + "lucia": "3.1.1", "next": "14.1.4", + "oslo": "1.2.0", "postcss": "8.4.38", "prisma": "5.12.0", "react": "18.2.0", From 44da0e4c6513cd3e73a7b75917c4a987b593f447 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 12:45:53 +0300 Subject: [PATCH 006/125] Installed @lucia-auth/adapter-prisma package --- package-lock.json | 10 ++++++++++ package.json | 1 + 2 files changed, 11 insertions(+) diff --git a/package-lock.json b/package-lock.json index 1fd25bd..12e2f28 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "hasInstallScript": true, "dependencies": { + "@lucia-auth/adapter-prisma": "4.0.1", "@prisma/client": "5.12.0", "@types/node": "20.12.4", "@types/react": "18.2.74", @@ -2694,6 +2695,15 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lucia-auth/adapter-prisma": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@lucia-auth/adapter-prisma/-/adapter-prisma-4.0.1.tgz", + "integrity": "sha512-3SztRhj1RAHbbhI/0aB7YC5zl6Z6aktPhkWpn2CHhiB03B9x/+A+M6pqJuAt1usU8PzkjVilgRPhrPymMar66A==", + "peerDependencies": { + "@prisma/client": "^4.2.0 || ^5.0.0", + "lucia": "3.x" + } + }, "node_modules/@mapbox/node-pre-gyp": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", diff --git a/package.json b/package.json index cf798be..fc02c95 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "prisma": "dotenv -c .env.local -- prisma" }, "dependencies": { + "@lucia-auth/adapter-prisma": "4.0.1", "@prisma/client": "5.12.0", "@types/node": "20.12.4", "@types/react": "18.2.74", From 0e507331f9d36980e7d13d782c99d481c18ddc4d Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 13:24:14 +0300 Subject: [PATCH 007/125] Updated favicon.ico with working icon --- public/favicon.ico | Bin 39535 -> 1150 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/public/favicon.ico b/public/favicon.ico index 4570eb8d9269ad58b17fecbec6d630cded56f507..f138a4eab76ef6ace135a808c30feebe405c0a5a 100644 GIT binary patch literal 1150 zcmd6nJ4*vW6on_?53teNQbd%HjjNk|#8*le| zNePmq+@eT+EEMBpEs9HKLcCW#*Z;s*{w04Bp7q=PN44mzANKEWgDZ;!b3gOC29Nfl zXUX#iOX&4f)bE1G=k;CW^nJiXFMFQk{hg?eJM*``^30k0q&La;6zi3~!$w@sPm1*I z)g@zHYcXcd@br@5`k1F+pT6E@j-Mqr*Ni>R!i%^gq3qeGI3FyF*yW~>Aq&O7t@Qqb zWbIo?r>oN6e`$_cF{kv-SH&8rX_2GMyR}yTjy=G=9eKOb3f6GO ziSV3``>0v+j`tYuA2oXDC4)5&*aP%s%Nu^x9v|bNb1zo57V}p2M(6yIcMln|d=Rga zw}%>%^PVIaZC$v*%Ocj^q!=^jpk_M_;Tm98LR#}3c)x_sq3PjKNtv1%gKB1w151fdDZGiScP-lmIaZ#3;EsX?LYkO6+oC zcdDGkvDZqaDp3tdY$sinwH#S?96PaNCzdTaPIp(T)A^x$b@xBe-*@+Ug9%7NAcSPy z_3eH3nfKXypK~woT|m<dO#S`!I@|I?JhGKxc0jfnSEBfEGWE_{%f^i zf7dG>nYG%kx13|yul4r5llB}t3ACbZQ&SU4HVXp-11rXN%*eTqIdYCx@$vDSH95v9 zDk^e}ykf3Z=5}o{GBUD3JzPgyuk7vZeHXJwMn~h=naE?`? z%e9}uV7SFRVgc9otIC{%m+SggmGkoQP+nPCxoYjIBj^Kz-K$;A@i+Sfvg>SyaOW$P zmh5x8Ya=K3?Z$rS>UozmgRCIlLG=sw*$rMM^v?vfgVypf>)3{EH~Y%KfNRaW-g1t$ z(JK}Mtask^w&xsoa~(#f_0F}C_MC4$*901GWWJ5`<=l62-A^4|*LOR8o3I$y_S-?G zPODupDBKSEt)&C?TY0V3cDt3k>djlgcGGVyebQVMU#rcEa*M@+k_QESeSItRzpZy@ z63^SVa*P@m7x$nT1A4Z$wmLMw!!^4hWyu7@&p(Qdi zGabHK*NWD?e%H}!YHGHLEnKzQdij1CAtEB;?!3N{>3y#>o39v+0$@%a>f+y6h{D_58WU^|}k|qx-783JMBPeizT` ztB$r}7FV4qN3W>AlQFik&1ydfQ||}qvj*zR>p}S(N3^}a`rhudCcBRIbi04fXxDQ) ze^zVPk?D5(jN4T=%J=&_fR*|@%0IHeBMUqP7T|*&UIEfco*m%Ufvj+(>8#H zL2Erv~w%d?)K#%_g^bHyK^-WaJ08 zjs3l8SKB7__OI5 z7JVNG>ISNNsKHrdZG6 z1^cItn>cD!Rn=$2GY%_mmi73VEJY-eK4E`YJs={ULM3 zdM$8=?QiuB$X#3Cb?yh<4e~yr>xv#MdB=_&50DFnhK4pJ>b8TAw*NEjCO&iCcdu>F z=hRJqj=Z&<@A+vi`)d0r6+%Y8HuU)|Mz{<6Z~W=&zC0bd zezLluZv*bmYIpY(wZ%_4uF>H7EdfK#wQkGgJAWR!UmDUhE3W(Yoh00{Dz^B^!!tdk z=Q_NW;u|dgEd5S|tEp1&qrdrkHd}r1_lfS+&;I;9sQdBzN~_t>{&ojH&AioT@b*uU z?Vr)DHrAuEM;3Twfkzg2WPwK(cw~V`7IbQ3qm;e&g$Ex#QUOsgn9SNn$>bGeKsYCv zQ%Fo#zX)C@1^m;U{PzJ3{4^NY1=_Le{b!iH`Yc#vR1F6M&h=S;|Bp|I3?36Q>-EOh zAiQ%~%I3!$b*@4?GV_aI>VI%N=2|IoF_KrmOx*;#D)}EaLP5b6PHqIbH_|MI9x%Y_ z3l=bFoJA5`eqQrO%JuTEY?azL#U4;LC>6xU(;$v$HiH3%Jtpv-e*7I0;2ko+3i|0c zTEI2d47qn2X}aD@WzA@0X2!udqaTRQI0_nk=b2i+0V@Xud`hB32wk9si)`lcL@Sq( z2Kw1Q@n!ePc@Dv$=pSW%HW8Rjr?g*Pab(@X7Ix)^AnTJ$I{;<%VBtPs94 z!BeX{NUhlBz(RR)eO0`tpJyYLT>Rxz3rHNGg3GK3A2cU>=bJeKyDsE_y?R;8)*6j- z94CpTf(|77l^@Q^e?kIq5s@5=LjgB`C@DM94;PfWVP<6L)=76T&p6XyP%r*c8N*Ol zxUzwv_ZVH|Zc+a(CEmAom|ae~$JQ=*%?3f_KfC~15^3n;k^z735|~yad8;JFwj5hZ zE|=wB3uYbWJWH8ibO}(;Wn_9zrDt<6>aR8hq)PtRkv5Q96E~+JeF>cVIp7FKoc2gQ zVGcL_;X7aB`rA{$_JUSGppWB*>V*^ z=O>U6lptY%(BoFKy*^_;B?$$LNRHkKa{K+0mwIVOz)%V{pmj@*o?{^>7(^c=m^dzw zX^R2hqu$`$6H(~SZB#-to-}1wfB1E-*n#PC4zQ0_0n$M1$W=Me7kl&a`SB8Z++y6x zMFEBYADZ{IOJM%v^PEC3VyJ!Nd5Fq;YG4$c1ikxT{P!W*lb;Gse*yW^2So6Y1pMEh z{;tSvTnfi#Th`M*TrI$GRIcY)6PmMhRw@iUC;;wb>pa*D3pmoLo(QFuHg7yb`vX-c z3{H#e;xW-OeF&W4Vv19`LFP(0JtqTt(k1O{;IyTZDYc%6bPlE_sA(TTZCEcDPfz7= z=^#8kPg44m-3LIN{?$JR1J2rbrgks0Zdr=Jl_%8xkmCRL4`1O?S@O|y;Js9NMk>^- zoS_O-$=w5JAa4-2KR2s#S2brcadWXBjek_%qFg(dODB%*=OzMtts$Y#MRSBHMLf>| zT8-Z72bF=;A6t#z3AxS!re+NZgKXhO;;aYqZhR+sztWq!odyBi%DY7zHl7iosxw4) zB4as~feN&8Kagk;1GNU&0O+pCixw%uCMi#&ggCHKeN2vfjn?l49ae3uO(&6S1p(I6 zRL$`AOEjs9!*eHC#G3%XFpab~p7v9vD69rm8m-`g?>q&*0{PY?DN$B&Zz#}EP$7l! z$+bK?v_8*4PQZ=oR$c3xG;wZMC=WD%cjija|9#=_pO6wB=o8bUHBBAIA?Zp+YN-$n z#@2z#s33Z;093_p#;GyzjMrZPcc7Rd3@kC~xndwQ8BB|(lMO9k4C3>FVD)A&3XIxH zzkmDUrFNcTGwhez!0?N82m9mS{utc1l|zPv*>#9GW{H}0w`j@PLv)b`dji}`?yp@u zrs7r#xtbnOh-6t;DB|lEy-(7m0?uYFpuhS-oC$DeFE-b%JufAU)0~W8BMqe6gq0xG zAvvLrhX|wI7sNZn{*0_Vo40X{3l3#d?@%z>1$h0Nl_EHJgGjUkqgaj0eg_k!ip5Q8 zV~6U731%yaiGW$Eo0xo>Jp{%&q!y8zh9tFckZ2CbcG2p@vvke!=$P8K13a5?1MFoG zgq=-|y8f5+peLgpm^ufhU4I%}ou!bDG03w_`K$t+0=We$O)_|Eq#T(QK zGZ=lMG*DraF@PdKb^V|J@e(rC`pUSN9Z}c+3`vf5BG2s{1Gf?6z%fYnvuoTL3k);? zw^{7s40YfH@4q0$;8A&I)36N!4I0Z$0x-m8>tjnLS1SoSR)}cG3-V|CBsTP^ENQn4 zGb@;KNP!`EE;vC0R4gp;6x-PjMnAfNjQM*~kO1j%Py#7E)W>l9}r7Mh~Dr5{IjCN7>)Ztu6?$ zo`^EGLT;P}%cOOOL2v#O7*GOI6G7q;&KPjO3dt71P>Nq(0MF`*=A>y&N5Fw!e;#bI zdiJC5N&d!*NJkgn{u;NAE4ZbAYd-=jiBfR_IZ*9{gA6aAy?&UnelB-b^58okJ6{;3 z#l7`hX%}*X9i`yjQp+S2lyJI;-m?t8`#jGcUP+}BK?2O2Y|Mkk3QE>AT9d|Sn?Cgyng72nnc7Xu)r7D8p zq-qFi2STE`1;-heCtW8zORB;1wI1Fqs+;!byN5>}D2Lov z=ct9i*ec-`^(X-=4M+lSn&Ul*i#CIRUvj_{-uJ?#0DQSzKQBzdkn6bf1y2P1Nhs4adTxldIiuS`L^^E?@+PHYG02abvk#_yY7 z@1e7RMHQbT(H0&wD{%Ec(RlBEtLF8uB5eYl{pkDW!ZVLT8dLg1Je|$Cd(B{nXJf$y zx&}0lK(}&XZyzJQ5i}2qh>|+t41#>xVbZk}GRv~AzcM+1G)h%+TMU8J5=!3GtW#wJSC3|~*ed(NE1B=t`XHkM4Zh0sJc!Ss@A~+u;{6T7)Nx6kb(2U4$ zJzMbl%M09$L1p@}qfEnPMkx*7{yZ|YEszPS+9|T|D79=O4J6L)k&fA9o1?FZj{|4T@m5sD1J^FtYasE9Y&t`q%csaoPAMH?)=wt)MBMdaeli`0=Bh zE280pr_{quW1-sc=WafimfWAqe)0a+BS=Ooz-~Ts47{PZ1biWR!tJ=X?K zvjA<~wET2u)~9BUfA!nlRLz@%2gh(Ifa_OhQ5eK|+L_7$Ehi++V_a~$y3AuK^q{iL zQkbtaaNR>vasUZOiVtMa2XZR`AsIivC=z)8J}~Z14`WE!a_*d?f}^_+f>k?;AaH(w zIsyxvIaFjzC-ps`&MGNu8$ik~UbQX#QZ#UeCXA2_IBf{nZ8R>~wB5!ak%XT`(s%ty z4hJYF?T{Q789L8dloOO)BH#E9%6@tI7ta>3AGND#S@__Uy|$WY$iV-3@te;e$py7b zN#BP*=+wWLxPAo%mGo1()PQ$0mK}KWt0K}Aw4ZYFTzoV>0C%*qiliT=5S2@trF4Em zt)BfO*p$w2U?IB)^7}6bGOB^I3u^t6?UUpJk`7RPB{vOYrmQo5ts9WsHYP1;3gEq;NV*@1HT$S!z^6Gg!%#Kf6YDN@vq*{$ zHPc|WuuonZQ}#!;S1+4_k+y*XKylVVj!>0L9T}DY z@4ZtW{ouW4MuM)r+$d$jk0BXWf$P(n#Go@Q^#1pM`B9eHs6vM8@MouNkihuc7j2Mw z=fUP0z|^g_kRH1FH892ya2nK;nh1UhWSacNUl+@LqMe#0_=5o%qs`<|98)m%n{V@} z!+{|S13+y#DIJXB!NL#;J}V`z{AW)gM@yB0<`07DGya;E63lcuM0FBHISO0_%ZVya zlk-T^KX#~;1_@n^ow7yA#q2E^`QUs09A$J&ig;dWWy9xN%9E5qjv7sVC{(`Xu~{Bv~b87b!tR#am66OpK<=imy7$&zkME3mi{Fk1kMDgML-H>d|r^! z(ei2DpckW$zWw*K;baBakXEKzbHkUq1*m&R#4>GT-pvTpl|h=VKY05FL97RHv$*2G zwdZgAS$-~~$_)DX-=!24AT6?j9pYRmAb@-1t#648u9nA9hv_&9T;^jSKhX4Z}6AY}={Z_)HjztGN)|2Be}XwAG?N4Q zbmdVH_qADyTVsQ6{&+@YR`XEg0l<{U1<#>=(477p^!DG;NS>fsI%c>$Fe-ef3Lb7l zYDL$x)$k-&ELh+{JsbJXOGx&eIy%MR2kc$wFa0~G!oBPn19CnbsV#GXTJg?E%d2yZ z-pM-JrVdDCfO1d_N1^tA_{v{{yTW8f&c=yLIgl@#2QvDAUXTw+=^ZYm;QHfI-~vs@ zdU|=k2ge7>RcDB_8E017IX!_gfE@<$Gpuu5DX(flN}B=|A72FDFBz6C(KqKn@BQnd zl!EUAz4mn1JFggvATbO8#+v>CZ;@6W3%Q=Xmd+G{1Nu)KNS$^?#?2$APAztq3Q2=B zzy1YD!Rb#xoi>md;2f3b$AJ%@$p7H088gLBU)R)s%s{2Pcmy%1PJ;jz0W|p@kgtUX zi_%OBUW|vRxak>F)4zTH64#SjA3;s^pN)`~(?o(%>)uRAbiEg&yHtw7U1kcDLaKfU zw8#G4-=V!y;oxqb)B$K=mmUyx{gWkghdE%*DgUp}JvHWACMEyx>3@9z(u8qNKPn;a zV2lAaNx+Zr7#B=SQdn3>?HPl>#BoW-kuZXQ!!4Y2A3L6^kInY1j#C~;TH>A*OmgQq z5Z0KIfsFp{kre*)Z#bQ$hK>NDNnB`7M@hzP3Iq*!_H3k)64yF|%9bXA|AgA<6gvbczdA#f&0{-d~ zhCC$tC*!RHi?j&`jPdqVJE55?bHI>ii*<%NijDDHGqsJQ3IOK-DnYp?tc+7Y)ky|i z`I3DFoULmLjP8N%)znHbZX1En-43SjZ=`BFR3vp+@NHbkX`IWviHO}6*bGq3F5S*UbZRKy;bbjOk=k!@!$vamBsjsb6dc_O-YtxJ#u)EMz_qWp*CQ#_zt``TGLJSc zYE*Y-J|r5hD7}0#7^$+}yjzoz`r5x#t&BoOFs5~lu>V*+S3WC+^hFyFnLcYz1iqx4 zpu%)|4G7>aQA0oWDZe=;pm7EC(!lW+uFCG4G@EBGwR`m&W{w13micu<0CFS&kL{;( zVjOu_;kAp-@ll@8PrL8z1Y0=a+KvH{&5+pvl5mgw-3woLG?`#b6~}|^mNK<-9StCO zgTw}-RS*L!!$y#ls%2XsyCQ+#>9){Z2e^Zpjf|jJcGMSt^DiLLgK5SkR#>@4C}vO& zS>(P5HG+?U0Ieh7;MI$fUb-kn!qpa218Pc9 z_B{K$D;K3r?9J~(=<{Pd14iCS3vE?5KgV8Fn+K2^DDf?BLTsp5&X6Ep;( zT1aw1+)CwINb6E61R#=&phg~&XFV`)9*slN$K?rVaDWlT6A5UG=Ag=o*ZvYRZ~r*H z)B>9hFD0I{F9J19TC6XZS&pL%iQmmHuwjxFtPgaaGlU*|>scf~2zPVH4z8UBO``{# z8yuMq6(06G$ygd)$7nwT;yRqKq96lUhrya?N5GI9C<1uCO!q+{|9i^?FKnu z9QSS7j~vZ4-2}!hvP*vxtQFGxPlE}H8EFm#aJrK`?@T4L)c>d+OZGPqY2<5v1$K%9 z1KblAtks%&iAxHF?>@v0K18DfXFM!TE8E4OJRek;8m-Z`{>{`B_|5Z@zIsv8y)@Oa z$X5NagptV;mAn5KC?wAoW8@<)z%75UwO|y9!8|~VGt>ZUhc(f3=D4kZ^Np6Xw03{~ zI3s#FdT__pOCDz-o}CUdBXNL-z_7L2szx`d6F}-a6C`z;bq2B<-4Y&j0sP&6OlLHj zc-obL=%UVqJyBW+1QngUEZ1X*g?tXw{b2|fhJW%J1`EErX+=1vEyffiaQY z-7r;dPKnU})OT z4$h-SV3;csA(GK2put)|zxe?eHwT+9*l3XsV?put#~}dw7)gm)`q#(25dfjx9{adB z&r{r3z%*#Arom%Q3t}rDcN+yS!~r6DZGFjpma;C!i7o&mVxh<-Cad>{aY0$P7Nj;|jERK;#cP!fgN{lF`_wUK7z|?2T8&3IpNg`B5NQSO#(o}U z&fjW4rdBBn5s2;p(?2z8gfP`L%}&XnRiS@!rGK$vHs)(IS5GQ8MX(03fzrjs*?#4 z54tSti6CfYYKLrpfv?10^RG}_!GBSU_RStbt@{E;oIL<0n4s5Y+~N)PCw{I(f7}_; zEP;I|EEpFh9Xxwo5v_lhjuLG?FwIRF)}1D&SLW#MYcE^?Uj|KrI0|5u#BG^w@>HW5 l#`JGjT2VCQKBy&!+avXpR|1Bm1Aq0ZuBx#Tx&1b<{|~G@=I{Uj From 43d310805b9bd8a51cb189ed0b4fae4062c6cd74 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 14:31:03 +0300 Subject: [PATCH 008/125] Added Sessions to schema.prisma --- prisma/schema.prisma | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 4cc612e..fef9f47 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -17,6 +17,7 @@ model User { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt gift Gift[] + Session Session? } model Gift { @@ -29,3 +30,10 @@ model Gift { userUUID String? user User? @relation(fields: [userUUID], references: [uuid]) } + +model Session { + sessionId String @id @default(uuid()) + userUUID String @unique + expiresAt DateTime + user User @relation(references: [uuid], fields: [userUUID], onDelete: Cascade) +} From 7aa985d378d3f1ac766102c9652e27b071b9c874 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 14:31:58 +0300 Subject: [PATCH 009/125] Changed default password for development only --- pages/login.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/login.tsx b/pages/login.tsx index dec7176..f2285cc 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -7,7 +7,7 @@ import { TitleText } from '~/components/TitleText'; export default function Login() { const [email, setEmail] = useState('john.doe@doemail.com'); - const [password, setPassword] = useState('1'); + const [password, setPassword] = useState('!JohnDoePassword123'); const [isError, setIsError] = useState(false); const [errorText, setErrorText] = useState(''); From 59b6a17e3112993351ae3087ee6dc5e6c579b435 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 14:32:41 +0300 Subject: [PATCH 010/125] Rewriting register.tsx. Currently added some debugging console.logs --- pages/register.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pages/register.tsx b/pages/register.tsx index 55281c7..c6f4766 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -31,6 +31,8 @@ export default function Login() { try { e.preventDefault(); if (!isAllFieldsValid()) return; + console.log('Registering'); + /* await createUser({ email: email, firstName: firstName, @@ -38,6 +40,7 @@ export default function Login() { password: password, }); userCreatedSuccesfully(); + */ } catch (e) { handleUserError(e); } From 7aadfbcc43c923ff13f503965f8a707e01823e39 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 14:34:02 +0300 Subject: [PATCH 011/125] Copied an example of middleware from lucia-auth's website. Reference: https://lucia-auth.com/getting-started/nextjs-pages --- middleware.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 middleware.ts diff --git a/middleware.ts b/middleware.ts new file mode 100644 index 0000000..e632f58 --- /dev/null +++ b/middleware.ts @@ -0,0 +1,20 @@ +import { verifyRequestOrigin } from 'lucia'; +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; + +export async function middleware(req: NextRequest): Promise { + if (req.method === 'GET') { + return NextResponse.next(); + } + const originHeader = req.headers.get('Origin'); + const hostHeader = req.headers.get('Host'); + + if ( + !originHeader || + !hostHeader || + !verifyRequestOrigin(originHeader, [hostHeader]) + ) { + return new NextResponse(null, { status: 403 }); + } + return NextResponse.next(); +} From c0cb21a6490f8eabc59117e64962da89780c693c Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 14:34:43 +0300 Subject: [PATCH 012/125] Copied an example of auth from lucia-auth's website: References: https://lucia-auth.com/getting-started/nextjs-pages and https://lucia-auth.com/tutorials/username-and-password/nextjs-pages --- backend/auth.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 backend/auth.ts diff --git a/backend/auth.ts b/backend/auth.ts new file mode 100644 index 0000000..4527ad3 --- /dev/null +++ b/backend/auth.ts @@ -0,0 +1,31 @@ +import { PrismaAdapter } from '@lucia-auth/adapter-prisma'; +import { Lucia } from 'lucia'; +import prisma from '~/prisma'; +import { webcrypto } from 'crypto'; +import type { User } from '~/shared/types'; + +globalThis.crypto = webcrypto as Crypto; + +const adapter = new PrismaAdapter(prisma.session, prisma.user); + +export const lucia = new Lucia(adapter, { + sessionCookie: { + attributes: { + secure: process.env.NODE_ENV === 'production', + }, + }, + getUserAttributes(attributes: Partial) { + return { + email: attributes.email, + }; + }, +}); + +declare module 'lucia' { + interface Register { + Lucia: typeof lucia; + DatabaseUserAttributes: DatabaseUserAttributes; + } +} + +type DatabaseUserAttributes = {} & User; From 9d494c13b1042b55ccbbbef6b1a51db9dbfdbbb9 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 14:36:58 +0300 Subject: [PATCH 013/125] Created a new folder pages/api/auth and added register.ts file there to handle registering. Added some basic handler functions there --- pages/api/auth/register.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 pages/api/auth/register.ts diff --git a/pages/api/auth/register.ts b/pages/api/auth/register.ts new file mode 100644 index 0000000..6310d8b --- /dev/null +++ b/pages/api/auth/register.ts @@ -0,0 +1,26 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import { handleError } from '~/backend/handleError'; +import { HttpError } from '~/backend/HttpError'; +import type { CreateUser } from '~/shared/types'; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse, +) { + try { + if (req.method !== 'POST') { + throw new HttpError('Invalid request method!', 405); + } + const requestBody = req.body as CreateUser; + if ( + !requestBody.email || + !requestBody.firstName || + !requestBody.lastName || + !requestBody.password + ) { + throw new HttpError('Invalid request body!', 400); + } + } catch (e) { + return handleError(res, e); + } +} From 4f580c3c79602c64860de684639e142d5854463c Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 14:41:59 +0300 Subject: [PATCH 014/125] Added checks if values given in registering are valid or not --- pages/api/auth/register.ts | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/pages/api/auth/register.ts b/pages/api/auth/register.ts index 6310d8b..3e5e571 100644 --- a/pages/api/auth/register.ts +++ b/pages/api/auth/register.ts @@ -2,6 +2,7 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { handleError } from '~/backend/handleError'; import { HttpError } from '~/backend/HttpError'; import type { CreateUser } from '~/shared/types'; +import { emailRegex, passwordRegex } from '~/utils/regexPatterns'; export default async function handler( req: NextApiRequest, @@ -24,3 +25,46 @@ export default async function handler( return handleError(res, e); } } + +function isFirstNameValid(firstName: string): boolean { + if (firstName.length <= 0) { + throw new HttpError('First name is mandatory!', 400); + } + return true; +} + +function isLastNameValid(lastName: string): boolean { + if (lastName.length <= 0) { + throw new HttpError('Last name is mandatory!', 400); + } + return true; +} + +function isEmailValid(email: string): boolean { + if (email.length <= 0) { + throw new HttpError('Email is mandatory!', 400); + } + // this should check with regex that there cannot be multiple dots etc + const checkedEmailAddress = email.toLowerCase().match(emailRegex); + + if (!checkedEmailAddress) { + throw new HttpError('Invalid email!', 400); + } + + // email is ready to be used + return true; +} + +function isPasswordValid(password: string): boolean { + if (password.length <= 0) { + throw new HttpError('Password is mandatory!', 400); + } + // TLDR: 8 merkkiä pitkä, maksimissaan 128, vähintään 1 numero, 1 pieni ja iso kirjain sekä yksi erikoismerkki + const checkedPassword = password.match(passwordRegex); + + if (!checkedPassword) { + throw new HttpError('Invalid password!', 400); + } + + return true; +} From e7f4640831d5d6b11547470e674ed56212f9c098 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 17:38:17 +0300 Subject: [PATCH 015/125] Created a file for URLs to images that have been taken from internet so credits can be given easier --- public/credits_for_images.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 public/credits_for_images.txt diff --git a/public/credits_for_images.txt b/public/credits_for_images.txt new file mode 100644 index 0000000..1331254 --- /dev/null +++ b/public/credits_for_images.txt @@ -0,0 +1 @@ +favicon.ico = https://www.flaticon.com/free-icon/giftbox_1139982 \ No newline at end of file From de68abf70da29f0fee57ff44a221c9410808a50c Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 17:39:54 +0300 Subject: [PATCH 016/125] Created a custom header check so backend can call backend APIs without middleware interfering. Most likely will be replaced / deleted, but it works for now in development stage --- middleware.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/middleware.ts b/middleware.ts index e632f58..5a355ce 100644 --- a/middleware.ts +++ b/middleware.ts @@ -2,6 +2,11 @@ import { verifyRequestOrigin } from 'lucia'; import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; +const CUSTOM_HEADER = { + key: process.env.HEADER_KEY, + value: process.env.HEADER_VALUE, +} as const; + export async function middleware(req: NextRequest): Promise { if (req.method === 'GET') { return NextResponse.next(); @@ -9,6 +14,12 @@ export async function middleware(req: NextRequest): Promise { const originHeader = req.headers.get('Origin'); const hostHeader = req.headers.get('Host'); + if (CUSTOM_HEADER.key !== undefined && CUSTOM_HEADER.value !== undefined) { + if (req.headers.get(CUSTOM_HEADER.key) === CUSTOM_HEADER.value) { + return NextResponse.next(); + } + } + if ( !originHeader || !hostHeader || From 0787a7781705449fcb38be03dcf0290e0b366104 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 17:41:10 +0300 Subject: [PATCH 017/125] Created a simple request for registering. Added default values for first name etc to make development easier and faster --- pages/register.tsx | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/pages/register.tsx b/pages/register.tsx index c6f4766..6821358 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -1,3 +1,4 @@ +import axios from 'axios'; import Link from 'next/link'; import { useRouter } from 'next/router'; import { FormEvent, HTMLAttributes, useState } from 'react'; @@ -7,6 +8,7 @@ import { Input } from '~/components/Input'; import { Modal } from '~/components/Modal'; import { TitleText } from '~/components/TitleText'; import { SvgCheckMarkIcon } from '~/icons/CheckMarkIcon'; +import type { CreateUser } from '~/shared/types'; import { createUser } from '~/utils/apiRequests'; import { handleUserError } from '~/utils/handleError'; import { emailRegex, passwordRegex } from '~/utils/regexPatterns'; @@ -16,10 +18,10 @@ type ErrorFieldNames = 'firstName' | 'lastName' | 'email' | 'password'; type ErrorTypes = Partial>; export default function Login() { - const [firstName, setFirstName] = useState(''); - const [lastName, setLastName] = useState(''); - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); + const [firstName, setFirstName] = useState('a'); + const [lastName, setLastName] = useState('a'); + const [email, setEmail] = useState('a@a.aa'); + const [password, setPassword] = useState('!TeppoTesteri123123'); const [errors, setErrors] = useState({}); @@ -31,7 +33,12 @@ export default function Login() { try { e.preventDefault(); if (!isAllFieldsValid()) return; - console.log('Registering'); + await axios.post('/api/auth/register', { + email: email, + firstName: firstName, + lastName: lastName, + password: password, + } as CreateUser); /* await createUser({ email: email, From e61837fda9078a7a8f7e218275ef63e773dda5c9 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 17:43:30 +0300 Subject: [PATCH 018/125] Commented isEmailValid function out for now --- pages/api/users/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index d69b22f..3221818 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -49,7 +49,7 @@ async function handleGET(req: NextApiRequest, res: NextApiResponse) { async function handlePOST(req: NextApiRequest, res: NextApiResponse) { const userDetails = req.body as CreateUser; - isEmailValid(userDetails.email); + //isEmailValid(userDetails.email); // should not be needed because the check is done in /api/auth/register.ts const password = await hashPassword(userDetails.password); const addedUser = await prisma.user.create({ From 6f33e735f7c3e55cadb3c3c7998a61182b8200a5 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 17:53:59 +0300 Subject: [PATCH 019/125] Made the CUSTOM_HEADER variable exportable so it does not need to be written multiple times --- middleware.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/middleware.ts b/middleware.ts index 5a355ce..61138fd 100644 --- a/middleware.ts +++ b/middleware.ts @@ -2,7 +2,7 @@ import { verifyRequestOrigin } from 'lucia'; import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; -const CUSTOM_HEADER = { +export const CUSTOM_HEADER = { key: process.env.HEADER_KEY, value: process.env.HEADER_VALUE, } as const; From a73c27499b56d786e054115c01e7b4f13f0519a0 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 17:55:43 +0300 Subject: [PATCH 020/125] Removed old createUser function and made userCreatedSuccesfully function callable --- pages/register.tsx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pages/register.tsx b/pages/register.tsx index 6821358..9b52c30 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -39,15 +39,7 @@ export default function Login() { lastName: lastName, password: password, } as CreateUser); - /* - await createUser({ - email: email, - firstName: firstName, - lastName: lastName, - password: password, - }); userCreatedSuccesfully(); - */ } catch (e) { handleUserError(e); } From 5eed34650f96d53388217a532acfa50c30e17316 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 18:10:27 +0300 Subject: [PATCH 021/125] Added a simple text that will tell if it is in production or not --- pages/register.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pages/register.tsx b/pages/register.tsx index 9b52c30..4c1e98f 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -142,6 +142,9 @@ export default function Login() {
+

+ {process.env.NODE_ENV} +

void handleRegister(e)}> Luo käyttäjätunnus
From 21d9f98629aeda8af19ea83382f3de37ca2a1a31 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 18:10:59 +0300 Subject: [PATCH 022/125] Added functions for checking that given values are valid. Added request for user creation --- pages/api/auth/register.ts | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/pages/api/auth/register.ts b/pages/api/auth/register.ts index 3e5e571..b8568dd 100644 --- a/pages/api/auth/register.ts +++ b/pages/api/auth/register.ts @@ -1,7 +1,9 @@ +import axios from 'axios'; import { NextApiRequest, NextApiResponse } from 'next'; import { handleError } from '~/backend/handleError'; import { HttpError } from '~/backend/HttpError'; -import type { CreateUser } from '~/shared/types'; +import { CUSTOM_HEADER } from '~/middleware'; +import type { CreateUser, User } from '~/shared/types'; import { emailRegex, passwordRegex } from '~/utils/regexPatterns'; export default async function handler( @@ -21,6 +23,34 @@ export default async function handler( ) { throw new HttpError('Invalid request body!', 400); } + isFirstNameValid(requestBody.firstName); + isLastNameValid(requestBody.lastName); + isEmailValid(requestBody.email); + isPasswordValid(requestBody.password); + + if (CUSTOM_HEADER.key === undefined || CUSTOM_HEADER.value === undefined) { + throw new HttpError('Server error!', 500); + } + const userCreationRequest = (await ( + await axios.post( + process.env.NODE_ENV === 'production' + ? '/api/users' + : 'http://localhost:3000/api/users', + { + email: requestBody.email, + firstName: requestBody.firstName, + lastName: requestBody.lastName, + password: requestBody.password, + } as CreateUser, + { + headers: { + [CUSTOM_HEADER.key]: CUSTOM_HEADER.value, + }, + }, + ) + ).data) as User; + + return res.status(200).json(userCreationRequest); } catch (e) { return handleError(res, e); } From 6913f2ee5eef580a8b8f94be3f6c303431a54705 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 18:16:39 +0300 Subject: [PATCH 023/125] ESLint fixes --- backend/auth.ts | 2 +- middleware.ts | 1 + pages/api/auth/register.ts | 2 +- pages/api/users/index.ts | 13 ------------- pages/login.tsx | 9 --------- pages/register.tsx | 1 - 6 files changed, 3 insertions(+), 25 deletions(-) diff --git a/backend/auth.ts b/backend/auth.ts index 4527ad3..633d3b5 100644 --- a/backend/auth.ts +++ b/backend/auth.ts @@ -28,4 +28,4 @@ declare module 'lucia' { } } -type DatabaseUserAttributes = {} & User; +interface DatabaseUserAttributes extends User {} diff --git a/middleware.ts b/middleware.ts index 61138fd..a0b793e 100644 --- a/middleware.ts +++ b/middleware.ts @@ -7,6 +7,7 @@ export const CUSTOM_HEADER = { value: process.env.HEADER_VALUE, } as const; +//eslint-disable-next-line export async function middleware(req: NextRequest): Promise { if (req.method === 'GET') { return NextResponse.next(); diff --git a/pages/api/auth/register.ts b/pages/api/auth/register.ts index b8568dd..003d128 100644 --- a/pages/api/auth/register.ts +++ b/pages/api/auth/register.ts @@ -70,7 +70,7 @@ function isLastNameValid(lastName: string): boolean { return true; } -function isEmailValid(email: string): boolean { +export function isEmailValid(email: string): boolean { if (email.length <= 0) { throw new HttpError('Email is mandatory!', 400); } diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 3221818..f1d87ef 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -98,19 +98,6 @@ export function errorFound(res: NextApiResponse, e: unknown) { return res.status(500).send('Unexpected error occurred!'); } -function isEmailValid(emailAddress: string): boolean { - const checkedEmailAddress = emailAddress - .toLowerCase() - .match(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/); - - if (checkedEmailAddress === null) { - throw new Error('Invalid email!'); - } - - // email is ready to be used - return true; -} - async function hashPassword(password: string): Promise { const saltRounds = 10; const hashedPassword = await hash(password, saltRounds); diff --git a/pages/login.tsx b/pages/login.tsx index f2285cc..106a1b5 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -8,8 +8,6 @@ import { TitleText } from '~/components/TitleText'; export default function Login() { const [email, setEmail] = useState('john.doe@doemail.com'); const [password, setPassword] = useState('!JohnDoePassword123'); - const [isError, setIsError] = useState(false); - const [errorText, setErrorText] = useState(''); const router = useRouter(); @@ -21,13 +19,6 @@ export default function Login() { return (
- {isError ? ( -
-
- {errorText} -
-
- ) : null}
void handleSubmit(e)}> diff --git a/pages/register.tsx b/pages/register.tsx index 4c1e98f..c4d0df4 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -9,7 +9,6 @@ import { Modal } from '~/components/Modal'; import { TitleText } from '~/components/TitleText'; import { SvgCheckMarkIcon } from '~/icons/CheckMarkIcon'; import type { CreateUser } from '~/shared/types'; -import { createUser } from '~/utils/apiRequests'; import { handleUserError } from '~/utils/handleError'; import { emailRegex, passwordRegex } from '~/utils/regexPatterns'; From 2b9c5fd729523e40ace824b336ebeac53f1a7e3e Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 4 Apr 2024 18:23:59 +0300 Subject: [PATCH 024/125] Updated .env.example file --- .env.example | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index bf24af7..4ae1e60 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,5 @@ -DATABASE_URL="postgresql://databaseusername:databasepassword@localhost:5432/mydb?schema=public" \ No newline at end of file +DATABASE_URL="postgresql://databaseusername:databasepassword@localhost:5432/mydb?schema=public" # README.md's section "Setting the environment variables" will help with this +POSTGRES_USERNAME="databaseusername" # Postgres database's username. It is same as DATABASE_URL's databaseusername +POSTGRES_PASSWORD="databasepassword" # Postgres database's password. It is same as DATABASE_URL's databasepassword +HEADER_KEY="your-secret-key-here" # used in custom header +HEADER_VALUE="your-secret-key-here" # used in custom header \ No newline at end of file From 3a4ac71c2878b3a17e08fa513aa3916943fc2b14 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 5 Apr 2024 12:44:00 +0300 Subject: [PATCH 025/125] Removed paragraph that tells if is in production or development stage --- pages/register.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/pages/register.tsx b/pages/register.tsx index c4d0df4..b0a6f52 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -141,9 +141,6 @@ export default function Login() {
-

- {process.env.NODE_ENV} -

void handleRegister(e)}> Luo käyttäjätunnus
From 62714961b68141f7d5c2b3035548bb5767c97310 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 5 Apr 2024 19:25:35 +0300 Subject: [PATCH 026/125] Created a type when creating session into database --- shared/types.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/shared/types.ts b/shared/types.ts index d64e9c5..52f0e41 100644 --- a/shared/types.ts +++ b/shared/types.ts @@ -11,3 +11,10 @@ export type CreateUser = Omit< Prisma.UserCreateInput, 'uuid' | 'createdAt' | 'updatedAt' | 'gift' >; + +export type CreateSession = Omit< + Prisma.SessionCreateInput, + 'id' | 'expiresAt' | 'userId' +> & { + user: Prisma.UserCreateNestedOneWithoutSessionInput; +}; From 15f0d57361ffc84a6856e6aba1391b92859e364d Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 5 Apr 2024 19:27:15 +0300 Subject: [PATCH 027/125] Changed sessionId to id, added userId, createdAt and updatedAt. Made user relation optional --- prisma/schema.prisma | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index fef9f47..23e6106 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -32,8 +32,11 @@ model Gift { } model Session { - sessionId String @id @default(uuid()) + id String @id @default(uuid()) + userId String @unique userUUID String @unique expiresAt DateTime - user User @relation(references: [uuid], fields: [userUUID], onDelete: Cascade) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + user User? @relation(fields: [userUUID], references: [uuid], onDelete: Cascade) } From 050eb73f5d7258878a54aa8154fecb5e64bead42 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 5 Apr 2024 19:28:34 +0300 Subject: [PATCH 028/125] Removed globalThis.crypto variable. Added DatabaseSessionAttributes type into Register interface --- backend/auth.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/auth.ts b/backend/auth.ts index 633d3b5..59cd5f8 100644 --- a/backend/auth.ts +++ b/backend/auth.ts @@ -1,10 +1,7 @@ import { PrismaAdapter } from '@lucia-auth/adapter-prisma'; import { Lucia } from 'lucia'; import prisma from '~/prisma'; -import { webcrypto } from 'crypto'; -import type { User } from '~/shared/types'; - -globalThis.crypto = webcrypto as Crypto; +import type { CreateSession, User } from '~/shared/types'; const adapter = new PrismaAdapter(prisma.session, prisma.user); @@ -25,7 +22,10 @@ declare module 'lucia' { interface Register { Lucia: typeof lucia; DatabaseUserAttributes: DatabaseUserAttributes; + DatabaseSessionAttributes: DatabaseSessionAttributes; } } interface DatabaseUserAttributes extends User {} + +interface DatabaseSessionAttributes extends CreateSession {} From e9f014fac23c1c5b09fc6cbaca707149804c9657 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 5 Apr 2024 19:30:17 +0300 Subject: [PATCH 029/125] Added a function to create a session when user registers and made it to be appended into header before returning data to the client user --- pages/api/auth/register.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/pages/api/auth/register.ts b/pages/api/auth/register.ts index 003d128..19bb991 100644 --- a/pages/api/auth/register.ts +++ b/pages/api/auth/register.ts @@ -1,5 +1,6 @@ import axios from 'axios'; import { NextApiRequest, NextApiResponse } from 'next'; +import { lucia } from '~/backend/auth'; import { handleError } from '~/backend/handleError'; import { HttpError } from '~/backend/HttpError'; import { CUSTOM_HEADER } from '~/middleware'; @@ -50,7 +51,20 @@ export default async function handler( ) ).data) as User; - return res.status(200).json(userCreationRequest); + const session = await lucia.createSession(userCreationRequest.uuid, { + user: { + connect: { + uuid: userCreationRequest.uuid, + }, + }, + }); + res + .appendHeader( + 'Set-Cookie', + lucia.createSessionCookie(session.id).serialize(), + ) + .status(200) + .end(); } catch (e) { return handleError(res, e); } From 882ec6f00310886a5b109ef882c58bf8a7bff364 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 5 Apr 2024 20:28:22 +0300 Subject: [PATCH 030/125] Created a new file utils.ts to backend to have all isEmailValid etc functions in one place --- backend/utils.ts | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 backend/utils.ts diff --git a/backend/utils.ts b/backend/utils.ts new file mode 100644 index 0000000..434c09d --- /dev/null +++ b/backend/utils.ts @@ -0,0 +1,54 @@ +import { emailRegex, passwordRegex } from '~/utils/regexPatterns'; +import { HttpError } from './HttpError'; +import { compare as bcryptCompare } from 'bcrypt'; + +export function isEmailValid(email: string): boolean { + if (email.length <= 0) { + throw new HttpError('Email is mandatory!', 400); + } + // this should check with regex that there cannot be multiple dots etc + const checkedEmailAddress = email.toLowerCase().match(emailRegex); + + if (!checkedEmailAddress) { + throw new HttpError('Invalid email!', 400); + } + + // email is ready to be used + return true; +} + +export function isFirstNameValid(firstName: string): boolean { + if (firstName.length <= 0) { + throw new HttpError('First name is mandatory!', 400); + } + return true; +} + +export function isLastNameValid(lastName: string): boolean { + if (lastName.length <= 0) { + throw new HttpError('Last name is mandatory!', 400); + } + return true; +} + +export function isPasswordValid(password: string): boolean { + if (password.length <= 0) { + throw new HttpError('Password is mandatory!', 400); + } + // TLDR: 8 merkkiä pitkä, maksimissaan 128, vähintään 1 numero, 1 pieni ja iso kirjain sekä yksi erikoismerkki + const checkedPassword = password.match(passwordRegex); + + if (!checkedPassword) { + throw new HttpError('Invalid password!', 400); + } + + return true; +} + +export async function verifyPassword( + givenPassword: string, + hashedPassword: string, +): Promise { + const isMatch = await bcryptCompare(givenPassword, hashedPassword); + return isMatch; +} From add75ca5229cf6c43bde688145af96de0388f5d6 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 5 Apr 2024 20:28:58 +0300 Subject: [PATCH 031/125] Created login file into /api/auth. Added some basic code into it --- pages/api/auth/login.ts | 62 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 pages/api/auth/login.ts diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts new file mode 100644 index 0000000..8faa809 --- /dev/null +++ b/pages/api/auth/login.ts @@ -0,0 +1,62 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; +import { lucia } from '~/backend/auth'; +import { handleError } from '~/backend/handleError'; +import { HttpError } from '~/backend/HttpError'; +import { User, UserLoginDetails } from '~/shared/types'; +import { isEmailValid, isPasswordValid, verifyPassword } from '~/backend/utils'; +import prisma from '~/prisma'; + +export default async function handleR( + req: NextApiRequest, + res: NextApiResponse, +) { + try { + if (req.method !== 'POST') { + throw new HttpError('Invalid request method!', 405); + } + + const requestBody = req.body as UserLoginDetails; + const email = requestBody.email; + const password = requestBody.password; + + if ( + !email || + !password || + typeof email !== 'string' || + typeof password !== 'string' || + email.length <= 0 || + password.length <= 0 + ) { + throw new HttpError('Invalid request body!', 400); + } + + isEmailValid(email); + isPasswordValid(password); + + const userData = await prisma.user.findUnique({ + where: { + email: email, + }, + }); + + if (!userData) { + throw new HttpError('Server error!', 500); + } + + const isPasswordSame = await verifyPassword(password, userData.password); + + /* + if ( + (typeof email === 'string' && + email.length <= 0 && + typeof password === 'string' && + password.length <= 0) || + email === undefined || + password === undefined + ) { + } + */ + } catch (e) { + return handleError(res, e); + } +} From c871d5b8f4e95f30e28924471ef0570067e539b7 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 5 Apr 2024 20:29:29 +0300 Subject: [PATCH 032/125] Moved isPasswordValid etc into backend/utils --- pages/api/auth/register.ts | 50 +++++--------------------------------- 1 file changed, 6 insertions(+), 44 deletions(-) diff --git a/pages/api/auth/register.ts b/pages/api/auth/register.ts index 19bb991..80ec1cd 100644 --- a/pages/api/auth/register.ts +++ b/pages/api/auth/register.ts @@ -3,9 +3,14 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { lucia } from '~/backend/auth'; import { handleError } from '~/backend/handleError'; import { HttpError } from '~/backend/HttpError'; +import { + isFirstNameValid, + isLastNameValid, + isPasswordValid, +} from '~/backend/utils'; +import { isEmailValid } from '~/backend/utils'; import { CUSTOM_HEADER } from '~/middleware'; import type { CreateUser, User } from '~/shared/types'; -import { emailRegex, passwordRegex } from '~/utils/regexPatterns'; export default async function handler( req: NextApiRequest, @@ -69,46 +74,3 @@ export default async function handler( return handleError(res, e); } } - -function isFirstNameValid(firstName: string): boolean { - if (firstName.length <= 0) { - throw new HttpError('First name is mandatory!', 400); - } - return true; -} - -function isLastNameValid(lastName: string): boolean { - if (lastName.length <= 0) { - throw new HttpError('Last name is mandatory!', 400); - } - return true; -} - -export function isEmailValid(email: string): boolean { - if (email.length <= 0) { - throw new HttpError('Email is mandatory!', 400); - } - // this should check with regex that there cannot be multiple dots etc - const checkedEmailAddress = email.toLowerCase().match(emailRegex); - - if (!checkedEmailAddress) { - throw new HttpError('Invalid email!', 400); - } - - // email is ready to be used - return true; -} - -function isPasswordValid(password: string): boolean { - if (password.length <= 0) { - throw new HttpError('Password is mandatory!', 400); - } - // TLDR: 8 merkkiä pitkä, maksimissaan 128, vähintään 1 numero, 1 pieni ja iso kirjain sekä yksi erikoismerkki - const checkedPassword = password.match(passwordRegex); - - if (!checkedPassword) { - throw new HttpError('Invalid password!', 400); - } - - return true; -} From 143e7ba19e0c41f1d958b81126f20385a84d1038 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 5 Apr 2024 20:29:48 +0300 Subject: [PATCH 033/125] Made a new type for user when logging in --- shared/types.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shared/types.ts b/shared/types.ts index 52f0e41..634649e 100644 --- a/shared/types.ts +++ b/shared/types.ts @@ -11,6 +11,10 @@ export type CreateUser = Omit< Prisma.UserCreateInput, 'uuid' | 'createdAt' | 'updatedAt' | 'gift' >; +export type UserLoginDetails = Omit< + PrismaUser, + 'id' | 'uuid' | 'createdAt' | 'updatedAt' | 'gift' +>; export type CreateSession = Omit< Prisma.SessionCreateInput, From 5a8a25e34eab5dcd133048e3f982f7eab12078a6 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 5 Apr 2024 20:34:35 +0300 Subject: [PATCH 034/125] Made functions in backend/utils.ts to return false instead of throwing an error --- backend/utils.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/utils.ts b/backend/utils.ts index 434c09d..ae48c1a 100644 --- a/backend/utils.ts +++ b/backend/utils.ts @@ -19,27 +19,27 @@ export function isEmailValid(email: string): boolean { export function isFirstNameValid(firstName: string): boolean { if (firstName.length <= 0) { - throw new HttpError('First name is mandatory!', 400); + return false; } return true; } export function isLastNameValid(lastName: string): boolean { if (lastName.length <= 0) { - throw new HttpError('Last name is mandatory!', 400); + return false; } return true; } export function isPasswordValid(password: string): boolean { if (password.length <= 0) { - throw new HttpError('Password is mandatory!', 400); + return false; } // TLDR: 8 merkkiä pitkä, maksimissaan 128, vähintään 1 numero, 1 pieni ja iso kirjain sekä yksi erikoismerkki const checkedPassword = password.match(passwordRegex); if (!checkedPassword) { - throw new HttpError('Invalid password!', 400); + return false; } return true; From 76e6afbabbb768df3ab1fb6b30920098244b4485 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 5 Apr 2024 20:35:37 +0300 Subject: [PATCH 035/125] Changed the way how errors were handled --- pages/api/auth/register.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pages/api/auth/register.ts b/pages/api/auth/register.ts index 80ec1cd..feca958 100644 --- a/pages/api/auth/register.ts +++ b/pages/api/auth/register.ts @@ -29,10 +29,15 @@ export default async function handler( ) { throw new HttpError('Invalid request body!', 400); } - isFirstNameValid(requestBody.firstName); - isLastNameValid(requestBody.lastName); - isEmailValid(requestBody.email); - isPasswordValid(requestBody.password); + + if ( + !isFirstNameValid(requestBody.firstName) || + !isLastNameValid(requestBody.lastName) || + !isEmailValid(requestBody.email) || + !isPasswordValid(requestBody.password) + ) { + throw new HttpError('Invalid request body!', 400); + } if (CUSTOM_HEADER.key === undefined || CUSTOM_HEADER.value === undefined) { throw new HttpError('Server error!', 500); From 2fe00c41547d99996c4430c61b4e36012e0fed29 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Sun, 7 Apr 2024 16:30:22 +0300 Subject: [PATCH 036/125] Created a function base for session handler --- backend/auth.ts | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/backend/auth.ts b/backend/auth.ts index 59cd5f8..d1e43a0 100644 --- a/backend/auth.ts +++ b/backend/auth.ts @@ -1,7 +1,9 @@ import { PrismaAdapter } from '@lucia-auth/adapter-prisma'; +import type { IncomingMessage, ServerResponse } from 'http'; import { Lucia } from 'lucia'; import prisma from '~/prisma'; import type { CreateSession, User } from '~/shared/types'; +import type { Session, User as LuciaUser } from 'lucia'; const adapter = new PrismaAdapter(prisma.session, prisma.user); @@ -25,7 +27,35 @@ declare module 'lucia' { DatabaseSessionAttributes: DatabaseSessionAttributes; } } - interface DatabaseUserAttributes extends User {} - interface DatabaseSessionAttributes extends CreateSession {} + +export async function validateRequest( + req: IncomingMessage, + res: ServerResponse, +): Promise< + { user: LuciaUser; session: Session } | { user: null; session: null } +> { + const sessionId = lucia.readSessionCookie(req.headers.cookie ?? ''); + if (!sessionId) { + return { + user: null, + session: null, + }; + } + const result = await lucia.validateSession(sessionId); + if (result.session && result.session.fresh) { + res.appendHeader( + 'Set-Cookie', + lucia.createSessionCookie(result.session.id).serialize(), + ); + } + if (!result.session) { + res.appendHeader( + 'Set-Cookie', + lucia.createBlankSessionCookie().serialize(), + ); + } + + return result; +} From e742dfa29dcfb7f5eec66a983f2370d0b440097d Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Sun, 7 Apr 2024 16:31:26 +0300 Subject: [PATCH 037/125] Changed default email and password values for development only --- pages/login.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/login.tsx b/pages/login.tsx index 106a1b5..1a0724f 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -6,8 +6,8 @@ import { Input } from '~/components/Input'; import { TitleText } from '~/components/TitleText'; export default function Login() { - const [email, setEmail] = useState('john.doe@doemail.com'); - const [password, setPassword] = useState('!JohnDoePassword123'); + const [email, setEmail] = useState('a@a.aa'); + const [password, setPassword] = useState('!TeppoTesteri123123'); const router = useRouter(); From b12f3e9e8103db467f3300d793697ceb0edc72ed Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Sun, 7 Apr 2024 16:32:27 +0300 Subject: [PATCH 038/125] Due to modification to isEmailValid etc functions had to change them to throw an error. Session will be created now if registering is ok --- pages/api/auth/login.ts | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts index 8faa809..77badba 100644 --- a/pages/api/auth/login.ts +++ b/pages/api/auth/login.ts @@ -30,8 +30,9 @@ export default async function handleR( throw new HttpError('Invalid request body!', 400); } - isEmailValid(email); - isPasswordValid(password); + if (!isEmailValid(email) || !isPasswordValid(password)) { + throw new HttpError('Invalid credentials!', 400); + } const userData = await prisma.user.findUnique({ where: { @@ -45,17 +46,25 @@ export default async function handleR( const isPasswordSame = await verifyPassword(password, userData.password); - /* - if ( - (typeof email === 'string' && - email.length <= 0 && - typeof password === 'string' && - password.length <= 0) || - email === undefined || - password === undefined - ) { + if (!isPasswordSame) { + throw new HttpError('Invalid credentials!', 400); } - */ + + const session = await lucia.createSession(userData.uuid, { + user: { + connect: { + uuid: userData.uuid, + }, + }, + }); + + res + .appendHeader( + 'Set-cookie', + lucia.createSessionCookie(session.id).serialize(), + ) + .status(200) + .end(); } catch (e) { return handleError(res, e); } From 94ab4766dffd56fd3b1958756e3583af42746fcf Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 14:18:38 +0300 Subject: [PATCH 039/125] Took exact values from req.body to make code a lot easier to read --- pages/api/auth/register.ts | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/pages/api/auth/register.ts b/pages/api/auth/register.ts index feca958..48bf98b 100644 --- a/pages/api/auth/register.ts +++ b/pages/api/auth/register.ts @@ -20,21 +20,16 @@ export default async function handler( if (req.method !== 'POST') { throw new HttpError('Invalid request method!', 405); } - const requestBody = req.body as CreateUser; - if ( - !requestBody.email || - !requestBody.firstName || - !requestBody.lastName || - !requestBody.password - ) { + const { email, firstName, lastName, password } = req.body as CreateUser; + if (!email || !firstName || !lastName || !password) { throw new HttpError('Invalid request body!', 400); } if ( - !isFirstNameValid(requestBody.firstName) || - !isLastNameValid(requestBody.lastName) || - !isEmailValid(requestBody.email) || - !isPasswordValid(requestBody.password) + !isFirstNameValid(firstName) || + !isLastNameValid(lastName) || + !isEmailValid(email) || + !isPasswordValid(password) ) { throw new HttpError('Invalid request body!', 400); } @@ -48,10 +43,10 @@ export default async function handler( ? '/api/users' : 'http://localhost:3000/api/users', { - email: requestBody.email, - firstName: requestBody.firstName, - lastName: requestBody.lastName, - password: requestBody.password, + email: email, + firstName: firstName, + lastName: lastName, + password: password, } as CreateUser, { headers: { From 6c1ea145ed6dff218427158e84a080f3c71c6aab Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 14:22:36 +0300 Subject: [PATCH 040/125] Removed errorFound function. Replaced it with backend's handleError function --- pages/api/users/[uuid].ts | 4 ++-- pages/api/users/index.ts | 29 ++--------------------------- 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/pages/api/users/[uuid].ts b/pages/api/users/[uuid].ts index f9100d0..1e45ad1 100644 --- a/pages/api/users/[uuid].ts +++ b/pages/api/users/[uuid].ts @@ -1,7 +1,7 @@ import { User } from '~/shared/types'; import { NextApiRequest, NextApiResponse } from 'next'; import prisma from '~/prisma'; -import { errorFound } from '.'; +import { handleError } from '~/backend/handleError'; type HandlerParams = { req: NextApiRequest; @@ -36,7 +36,7 @@ export default async function handlePrisma( ); } } catch (e) { - return errorFound(res, e); + return handleError(res, e); } } diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index f1d87ef..79c5bf4 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -3,6 +3,7 @@ import { CreateUser, User } from '~/shared/types'; import prisma from '~/prisma'; import { hash } from 'bcrypt'; import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library'; +import { handleError } from '~/backend/handleError'; const HANDLER: Record< string, @@ -28,7 +29,7 @@ export default async function handlePrisma( ); } } catch (e) { - return errorFound(res, e); + return handleError(res, e); } } @@ -72,32 +73,6 @@ async function handlePOST(req: NextApiRequest, res: NextApiResponse) { return res.status(200).json(addedUser); } -export function errorFound(res: NextApiResponse, e: unknown) { - if (e instanceof PrismaClientKnownRequestError) { - if (e.code === 'P2025') { - return res.status(404).send('Record was not found!'); - } - if (e.code === 'P2002') { - return res.status(400).send('Record was not unique!'); - } - return res.status(500).send('Server error!'); - } - if (e instanceof Error) { - if (e.message.toLowerCase() === 'no gift found') { - return res.status(400).send('Gift was not found!'); - } - if (e.message === 'Invalid email!') { - return res.status(400).send(e.message); - } - if (e.message === 'Email is used already!') { - return res.status(400).send(e.message); - } - if (e.cause === 'idError') return res.status(400).send('Invalid ID!'); - return res.status(500).send('Server error!'); - } - return res.status(500).send('Unexpected error occurred!'); -} - async function hashPassword(password: string): Promise { const saltRounds = 10; const hashedPassword = await hash(password, saltRounds); From 61bf1d777f4f9537c956778a839d142cd45bcfe9 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 14:23:43 +0300 Subject: [PATCH 041/125] Moved hashPassword from /api/users/index.ts to -> backend/utils.ts to make it 'global'. Probably will be changed in the future, but this for now" --- backend/utils.ts | 8 +++++++- pages/api/users/index.ts | 8 +------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/backend/utils.ts b/backend/utils.ts index ae48c1a..ff16465 100644 --- a/backend/utils.ts +++ b/backend/utils.ts @@ -1,6 +1,6 @@ import { emailRegex, passwordRegex } from '~/utils/regexPatterns'; import { HttpError } from './HttpError'; -import { compare as bcryptCompare } from 'bcrypt'; +import { compare as bcryptCompare, hash } from 'bcrypt'; export function isEmailValid(email: string): boolean { if (email.length <= 0) { @@ -52,3 +52,9 @@ export async function verifyPassword( const isMatch = await bcryptCompare(givenPassword, hashedPassword); return isMatch; } + +export async function hashPassword(password: string): Promise { + const saltRounds = 10; + const hashedPassword = await hash(password, saltRounds); + return hashedPassword; +} diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 79c5bf4..4fe717a 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -1,9 +1,9 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { CreateUser, User } from '~/shared/types'; import prisma from '~/prisma'; -import { hash } from 'bcrypt'; import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library'; import { handleError } from '~/backend/handleError'; +import { hashPassword } from '~/backend/utils'; const HANDLER: Record< string, @@ -72,9 +72,3 @@ async function handlePOST(req: NextApiRequest, res: NextApiResponse) { return res.status(200).json(addedUser); } - -async function hashPassword(password: string): Promise { - const saltRounds = 10; - const hashedPassword = await hash(password, saltRounds); - return hashedPassword; -} From b2d29502e9f4509ce75782e1104f5dbbcb14bbe7 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 14:25:58 +0300 Subject: [PATCH 042/125] Removed isEmailValid function due to check is done in backend. Removed unused import --- pages/api/users/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 4fe717a..4035b27 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -1,7 +1,6 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { CreateUser, User } from '~/shared/types'; import prisma from '~/prisma'; -import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library'; import { handleError } from '~/backend/handleError'; import { hashPassword } from '~/backend/utils'; @@ -50,7 +49,6 @@ async function handleGET(req: NextApiRequest, res: NextApiResponse) { async function handlePOST(req: NextApiRequest, res: NextApiResponse) { const userDetails = req.body as CreateUser; - //isEmailValid(userDetails.email); // should not be needed because the check is done in /api/auth/register.ts const password = await hashPassword(userDetails.password); const addedUser = await prisma.user.create({ From 39b279a088f9d20678663ea9aab51f2cc4ae8ef4 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 14:34:48 +0300 Subject: [PATCH 043/125] Created a new function for creating user --- pages/api/users/index.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 4035b27..783fe97 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -50,6 +50,17 @@ async function handleGET(req: NextApiRequest, res: NextApiResponse) { async function handlePOST(req: NextApiRequest, res: NextApiResponse) { const userDetails = req.body as CreateUser; + const addedUser = await createUser({ + email: userDetails.email.toLowerCase(), + firstName: userDetails.firstName, + lastName: userDetails.lastName, + password: userDetails.password, + }); + + return res.status(200).json(addedUser); +} + +async function createUser(userDetails: CreateUser) { const password = await hashPassword(userDetails.password); const addedUser = await prisma.user.create({ data: { @@ -67,6 +78,5 @@ async function handlePOST(req: NextApiRequest, res: NextApiResponse) { updatedAt: true, }, }); - - return res.status(200).json(addedUser); + return addedUser; } From b2af52d2b6b8839ad16777fdba9bcc7197a1c29f Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 15:03:11 +0300 Subject: [PATCH 044/125] Added a check if given userDetails are valid --- pages/api/users/index.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 783fe97..af1d2b2 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -2,7 +2,14 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { CreateUser, User } from '~/shared/types'; import prisma from '~/prisma'; import { handleError } from '~/backend/handleError'; -import { hashPassword } from '~/backend/utils'; +import { + hashPassword, + isEmailValid, + isFirstNameValid, + isLastNameValid, + isPasswordValid, +} from '~/backend/utils'; +import { HttpError } from '~/backend/HttpError'; const HANDLER: Record< string, @@ -61,6 +68,14 @@ async function handlePOST(req: NextApiRequest, res: NextApiResponse) { } async function createUser(userDetails: CreateUser) { + if ( + !isEmailValid(userDetails.email) || + !isFirstNameValid(userDetails.firstName) || + !isLastNameValid(userDetails.lastName) || + !isPasswordValid(userDetails.password) + ) { + throw new HttpError('Invalid credentials', 400); + } const password = await hashPassword(userDetails.password); const addedUser = await prisma.user.create({ data: { From 430ceb8f0d148755bd228828b5c85f9a3bbb68c6 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 15:07:38 +0300 Subject: [PATCH 045/125] ESLint fixes --- pages/api/auth/login.ts | 2 +- pages/api/auth/register.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts index 77badba..d351483 100644 --- a/pages/api/auth/login.ts +++ b/pages/api/auth/login.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { lucia } from '~/backend/auth'; import { handleError } from '~/backend/handleError'; import { HttpError } from '~/backend/HttpError'; -import { User, UserLoginDetails } from '~/shared/types'; +import { UserLoginDetails } from '~/shared/types'; import { isEmailValid, isPasswordValid, verifyPassword } from '~/backend/utils'; import prisma from '~/prisma'; diff --git a/pages/api/auth/register.ts b/pages/api/auth/register.ts index 48bf98b..aaf2a96 100644 --- a/pages/api/auth/register.ts +++ b/pages/api/auth/register.ts @@ -7,8 +7,8 @@ import { isFirstNameValid, isLastNameValid, isPasswordValid, + isEmailValid, } from '~/backend/utils'; -import { isEmailValid } from '~/backend/utils'; import { CUSTOM_HEADER } from '~/middleware'; import type { CreateUser, User } from '~/shared/types'; From ddef858e9918f5db6a60b47ecd0cc926d181fbbd Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 15:12:51 +0300 Subject: [PATCH 046/125] Changed the way how email and password variables are declared --- pages/api/auth/login.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts index d351483..92afffa 100644 --- a/pages/api/auth/login.ts +++ b/pages/api/auth/login.ts @@ -15,9 +15,7 @@ export default async function handleR( throw new HttpError('Invalid request method!', 405); } - const requestBody = req.body as UserLoginDetails; - const email = requestBody.email; - const password = requestBody.password; + const { email, password } = req.body as UserLoginDetails; if ( !email || From 01951183140fbbdddb9048a0361b29adf39fb8e0 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 15:39:59 +0300 Subject: [PATCH 047/125] Removed couple values in .env.example. Not used right now. In /api/auth/register.ts -> Removed isValid functions. Replaced the user creation request with a function that creates an user. Removed unnecessary imports" --- .env.example | 4 +--- pages/api/auth/register.ts | 45 ++++++-------------------------------- 2 files changed, 8 insertions(+), 41 deletions(-) diff --git a/.env.example b/.env.example index 4ae1e60..e41d765 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,3 @@ DATABASE_URL="postgresql://databaseusername:databasepassword@localhost:5432/mydb?schema=public" # README.md's section "Setting the environment variables" will help with this POSTGRES_USERNAME="databaseusername" # Postgres database's username. It is same as DATABASE_URL's databaseusername -POSTGRES_PASSWORD="databasepassword" # Postgres database's password. It is same as DATABASE_URL's databasepassword -HEADER_KEY="your-secret-key-here" # used in custom header -HEADER_VALUE="your-secret-key-here" # used in custom header \ No newline at end of file +POSTGRES_PASSWORD="databasepassword" # Postgres database's password. It is same as DATABASE_URL's databasepassword \ No newline at end of file diff --git a/pages/api/auth/register.ts b/pages/api/auth/register.ts index aaf2a96..fcd933e 100644 --- a/pages/api/auth/register.ts +++ b/pages/api/auth/register.ts @@ -1,16 +1,9 @@ -import axios from 'axios'; import { NextApiRequest, NextApiResponse } from 'next'; import { lucia } from '~/backend/auth'; import { handleError } from '~/backend/handleError'; import { HttpError } from '~/backend/HttpError'; -import { - isFirstNameValid, - isLastNameValid, - isPasswordValid, - isEmailValid, -} from '~/backend/utils'; -import { CUSTOM_HEADER } from '~/middleware'; import type { CreateUser, User } from '~/shared/types'; +import { createUser } from '~/utils/apiRequests'; export default async function handler( req: NextApiRequest, @@ -25,36 +18,12 @@ export default async function handler( throw new HttpError('Invalid request body!', 400); } - if ( - !isFirstNameValid(firstName) || - !isLastNameValid(lastName) || - !isEmailValid(email) || - !isPasswordValid(password) - ) { - throw new HttpError('Invalid request body!', 400); - } - - if (CUSTOM_HEADER.key === undefined || CUSTOM_HEADER.value === undefined) { - throw new HttpError('Server error!', 500); - } - const userCreationRequest = (await ( - await axios.post( - process.env.NODE_ENV === 'production' - ? '/api/users' - : 'http://localhost:3000/api/users', - { - email: email, - firstName: firstName, - lastName: lastName, - password: password, - } as CreateUser, - { - headers: { - [CUSTOM_HEADER.key]: CUSTOM_HEADER.value, - }, - }, - ) - ).data) as User; + const userCreationRequest = await createUser({ + email: email, + firstName: firstName, + lastName: lastName, + password: password, + }); const session = await lucia.createSession(userCreationRequest.uuid, { user: { From f26ddedcbe64291719a800acec14eaf7c3626e2b Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 15:49:32 +0300 Subject: [PATCH 048/125] Removed an import that was not used in /api/auth/register.ts --- pages/api/auth/register.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/auth/register.ts b/pages/api/auth/register.ts index fcd933e..9a2f004 100644 --- a/pages/api/auth/register.ts +++ b/pages/api/auth/register.ts @@ -2,7 +2,7 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { lucia } from '~/backend/auth'; import { handleError } from '~/backend/handleError'; import { HttpError } from '~/backend/HttpError'; -import type { CreateUser, User } from '~/shared/types'; +import type { CreateUser } from '~/shared/types'; import { createUser } from '~/utils/apiRequests'; export default async function handler( From 594dbf3bb0829b4367093a339bb258c1531a8511 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 17:40:36 +0300 Subject: [PATCH 049/125] Removed CUSTOM_HEADER in middleware.ts --- middleware.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/middleware.ts b/middleware.ts index a0b793e..924f1b3 100644 --- a/middleware.ts +++ b/middleware.ts @@ -2,11 +2,6 @@ import { verifyRequestOrigin } from 'lucia'; import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; -export const CUSTOM_HEADER = { - key: process.env.HEADER_KEY, - value: process.env.HEADER_VALUE, -} as const; - //eslint-disable-next-line export async function middleware(req: NextRequest): Promise { if (req.method === 'GET') { @@ -15,12 +10,6 @@ export async function middleware(req: NextRequest): Promise { const originHeader = req.headers.get('Origin'); const hostHeader = req.headers.get('Host'); - if (CUSTOM_HEADER.key !== undefined && CUSTOM_HEADER.value !== undefined) { - if (req.headers.get(CUSTOM_HEADER.key) === CUSTOM_HEADER.value) { - return NextResponse.next(); - } - } - if ( !originHeader || !hostHeader || From 356244a8a5807d04f8d4f59a3fdeba2ce76b687c Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 17:46:52 +0300 Subject: [PATCH 050/125] Made createUser function in backend exportable. Fixed the import in /api/auth/register.ts to be imported from backend instead of frontend --- pages/api/auth/register.ts | 2 +- pages/api/users/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/api/auth/register.ts b/pages/api/auth/register.ts index 9a2f004..661c4cc 100644 --- a/pages/api/auth/register.ts +++ b/pages/api/auth/register.ts @@ -3,7 +3,7 @@ import { lucia } from '~/backend/auth'; import { handleError } from '~/backend/handleError'; import { HttpError } from '~/backend/HttpError'; import type { CreateUser } from '~/shared/types'; -import { createUser } from '~/utils/apiRequests'; +import { createUser } from '../users'; export default async function handler( req: NextApiRequest, diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index af1d2b2..f8f9131 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -67,7 +67,7 @@ async function handlePOST(req: NextApiRequest, res: NextApiResponse) { return res.status(200).json(addedUser); } -async function createUser(userDetails: CreateUser) { +export async function createUser(userDetails: CreateUser) { if ( !isEmailValid(userDetails.email) || !isFirstNameValid(userDetails.firstName) || From b7d34691bca9868508dac3af197d09073e7895eb Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 17:58:41 +0300 Subject: [PATCH 051/125] Made isEmailValid function to return false instead throwing an error --- backend/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/utils.ts b/backend/utils.ts index ff16465..54de01d 100644 --- a/backend/utils.ts +++ b/backend/utils.ts @@ -4,13 +4,13 @@ import { compare as bcryptCompare, hash } from 'bcrypt'; export function isEmailValid(email: string): boolean { if (email.length <= 0) { - throw new HttpError('Email is mandatory!', 400); + return false; } // this should check with regex that there cannot be multiple dots etc const checkedEmailAddress = email.toLowerCase().match(emailRegex); if (!checkedEmailAddress) { - throw new HttpError('Invalid email!', 400); + return false; } // email is ready to be used From 765d283dc3c888c509513b29a1920460c304e61d Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 18:15:34 +0300 Subject: [PATCH 052/125] Fixed regexes imports and removed HttpError due to no usage --- backend/utils.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/utils.ts b/backend/utils.ts index 54de01d..72f3db8 100644 --- a/backend/utils.ts +++ b/backend/utils.ts @@ -1,5 +1,4 @@ -import { emailRegex, passwordRegex } from '~/utils/regexPatterns'; -import { HttpError } from './HttpError'; +import { emailRegex, passwordRegex } from '~/shared/regexPatterns'; import { compare as bcryptCompare, hash } from 'bcrypt'; export function isEmailValid(email: string): boolean { From 2ab6d2a76ebeb9b1e7bb141b7590834447880335 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 20:05:33 +0300 Subject: [PATCH 053/125] Added a simple checker that checks if the error is known --- utils/handleError.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/utils/handleError.ts b/utils/handleError.ts index ce208bf..b4c4ac7 100644 --- a/utils/handleError.ts +++ b/utils/handleError.ts @@ -23,9 +23,24 @@ export function handleGiftError(e: unknown) { } } +type KnownFrontEndErrorTexts = 'email was not unique!' | string; + +const USER_ERROR_HANDLER: Record = { + 'email was not unique!': 'Sähköposti on jo käytössä', +}; + export function handleUserError(e: unknown) { if (isAxiosError(e) && e.response?.status === 400) { - console.error('Sähköposti on jo käytössä!'); + const responseText = e.response.data.toLowerCase(); + if ( + typeof e.response.data === 'string' && + USER_ERROR_HANDLER[responseText] + ) { + console.error(USER_ERROR_HANDLER[responseText]); + } else { + console.error('Unexpected error occured!'); + console.error('Unexpected error: ', e.response.data); + } } else if (e instanceof Error) { console.error(e.message); } else { From e19df78fd7315f48da0484c2250fb1d32e5f1ae3 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 20:24:12 +0300 Subject: [PATCH 054/125] handleError file's handleUserError now returns a string. Added a new useState to /pages/register.tsx to show if error occured during registering --- pages/register.tsx | 11 ++++++++++- utils/handleError.ts | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/pages/register.tsx b/pages/register.tsx index b468013..15acb55 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -22,6 +22,8 @@ export default function Login() { const [email, setEmail] = useState('a@a.aa'); const [password, setPassword] = useState('!TeppoTesteri123123'); + const [registerError, setRegisterError] = useState(''); + const [errors, setErrors] = useState({}); const [isUserCreated, setIsUserCreated] = useState(false); @@ -40,7 +42,8 @@ export default function Login() { } as CreateUser); userCreatedSuccesfully(); } catch (e) { - handleUserError(e); + const errorText = handleUserError(e); + setRegisterError(errorText); } } @@ -49,6 +52,7 @@ export default function Login() { setLastName(''); setEmail(''); setPassword(''); + setRegisterError(''); setIsUserCreated(true); setTimeout(() => { router.push('/').catch((e) => console.error(e)); @@ -141,6 +145,11 @@ export default function Login() {
+ {registerError.length > 0 ? ( +
+ {registerError} +
+ ) : null} void handleRegister(e)}> Luo käyttäjätunnus
diff --git a/utils/handleError.ts b/utils/handleError.ts index b4c4ac7..989cf4f 100644 --- a/utils/handleError.ts +++ b/utils/handleError.ts @@ -37,6 +37,7 @@ export function handleUserError(e: unknown) { USER_ERROR_HANDLER[responseText] ) { console.error(USER_ERROR_HANDLER[responseText]); + return USER_ERROR_HANDLER[responseText]; } else { console.error('Unexpected error occured!'); console.error('Unexpected error: ', e.response.data); @@ -46,4 +47,5 @@ export function handleUserError(e: unknown) { } else { console.error(e); } + return ''; } From bf30cfdd257ff6b4a2205ce71c05b560f6b5f788 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 8 Apr 2024 20:43:28 +0300 Subject: [PATCH 055/125] Added eye_open.svg and eye_slash.svg. Converted them to .tsx files by running 'npm run svgr' command. icons/index.ts might get deleted in the future but I will let it be there for now --- icons/eye_open.tsx | 26 ++++++++++++++++++++++++++ icons/eye_slash.tsx | 21 +++++++++++++++++++++ icons/index.ts | 4 ++++ public/images/icons/eye_open.svg | 4 ++++ public/images/icons/eye_slash.svg | 3 +++ 5 files changed, 58 insertions(+) create mode 100644 icons/eye_open.tsx create mode 100644 icons/eye_slash.tsx create mode 100644 icons/index.ts create mode 100644 public/images/icons/eye_open.svg create mode 100644 public/images/icons/eye_slash.svg diff --git a/icons/eye_open.tsx b/icons/eye_open.tsx new file mode 100644 index 0000000..260a4d2 --- /dev/null +++ b/icons/eye_open.tsx @@ -0,0 +1,26 @@ +// Credits: https://heroicons.com/ + +import type { SVGProps } from 'react'; +const SvgEyeOpen = (props: SVGProps) => ( + + + + +); +export default SvgEyeOpen; diff --git a/icons/eye_slash.tsx b/icons/eye_slash.tsx new file mode 100644 index 0000000..5f48048 --- /dev/null +++ b/icons/eye_slash.tsx @@ -0,0 +1,21 @@ +// Credits: https://heroicons.com/ + +import type { SVGProps } from 'react'; +const SvgEyeSlash = (props: SVGProps) => ( + + + +); +export default SvgEyeSlash; diff --git a/icons/index.ts b/icons/index.ts new file mode 100644 index 0000000..238f8b0 --- /dev/null +++ b/icons/index.ts @@ -0,0 +1,4 @@ +export { default as AcceptButtonIcon } from './accept_button_icon'; +export { default as DeclineButtonIcon } from './decline_button_icon'; +export { default as EyeOpen } from './eye_open'; +export { default as EyeSlash } from './eye_slash'; diff --git a/public/images/icons/eye_open.svg b/public/images/icons/eye_open.svg new file mode 100644 index 0000000..7b4a843 --- /dev/null +++ b/public/images/icons/eye_open.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/images/icons/eye_slash.svg b/public/images/icons/eye_slash.svg new file mode 100644 index 0000000..2275a28 --- /dev/null +++ b/public/images/icons/eye_slash.svg @@ -0,0 +1,3 @@ + + + From 7a7000d833bfc0e20d7ce16fee458941a9f64512 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Wed, 10 Apr 2024 12:55:03 +0300 Subject: [PATCH 056/125] Added eye icon behind password which will show the password. Added functionality to show the password --- pages/register.tsx | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/pages/register.tsx b/pages/register.tsx index 15acb55..7f975de 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -11,6 +11,8 @@ import { SvgCheckMarkIcon } from '~/icons/CheckMarkIcon'; import type { CreateUser } from '~/shared/types'; import { handleUserError } from '~/utils/handleError'; import { emailRegex, passwordRegex } from '~/shared/regexPatterns'; +import SvgEyeOpen from '~/icons/eye_open'; +import SvgEyeSlash from '~/icons/eye_slash'; type ErrorFieldNames = 'firstName' | 'lastName' | 'email' | 'password'; @@ -26,6 +28,7 @@ export default function Login() { const [errors, setErrors] = useState({}); + const [showPassword, setShowPassword] = useState(false); const [isUserCreated, setIsUserCreated] = useState(false); const router = useRouter(); @@ -193,19 +196,38 @@ export default function Login() { - setPassword(e.currentTarget.value)} - className="border border-black" - autoComplete="off" - type="password" - placeholder="************" - name="password" - /> +
+ setPassword(e.currentTarget.value)} + className="pl-1 pt-3 pb-3 border-0 outline-none group-hover/password:bg-gray-100" + autoComplete="off" + type={showPassword ? 'text' : 'password'} + placeholder="************" + name="password" + /> +
+ {showPassword ? ( + { + setShowPassword((prevValue) => !prevValue); + }} + /> + ) : ( + { + setShowPassword((prevValue) => !prevValue); + }} + /> + )} +
+
- -

+ +

Onko sinulla jo tunnus?{' '} Date: Wed, 10 Apr 2024 13:41:13 +0300 Subject: [PATCH 057/125] Added firstName and lastName that should not be taken when user tries to login --- shared/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/types.ts b/shared/types.ts index 634649e..06ea686 100644 --- a/shared/types.ts +++ b/shared/types.ts @@ -13,7 +13,7 @@ export type CreateUser = Omit< >; export type UserLoginDetails = Omit< PrismaUser, - 'id' | 'uuid' | 'createdAt' | 'updatedAt' | 'gift' + 'id' | 'uuid' | 'createdAt' | 'updatedAt' | 'gift' | 'firstName' | 'lastName' >; export type CreateSession = Omit< From 755d369a90c5803a79510326fec3f58239fb6367 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Wed, 10 Apr 2024 13:45:33 +0300 Subject: [PATCH 058/125] Changed UserLoginDetails type --- pages/login.tsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pages/login.tsx b/pages/login.tsx index 1a0724f..a9fe289 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -1,9 +1,11 @@ +import axios from 'axios'; import Link from 'next/link'; import { useRouter } from 'next/router'; import { FormEvent, useState } from 'react'; import { Button } from '~/components/Button'; import { Input } from '~/components/Input'; import { TitleText } from '~/components/TitleText'; +import { UserLoginDetails } from '~/shared/types'; export default function Login() { const [email, setEmail] = useState('a@a.aa'); @@ -13,7 +15,20 @@ export default function Login() { async function handleSubmit(e: FormEvent) { e.preventDefault(); - return await router.push('/'); + try { + const loginCredentials: UserLoginDetails = { + email: email, + password: password, + }; + const loginRequest = await axios.post( + '/api/auth/login', + loginCredentials, + ); + return await router.push('/'); + } catch (e) { + console.error(e); + return null; + } } return ( From 734fa1050c53301dd740fa0f305446a5532e2b2d Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Wed, 10 Apr 2024 18:00:22 +0300 Subject: [PATCH 059/125] Created a prototype of cookie validation --- pages/index.tsx | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/pages/index.tsx b/pages/index.tsx index 175691d..b4da948 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -7,8 +7,38 @@ import { EditModal } from '~/components/EditModal'; import { createGift, getAllGifts } from '~/utils/apiRequests'; import { Gift, CreateGift } from '~/shared/types'; import { handleGeneralError } from '~/utils/handleError'; +import { + GetServerSidePropsContext, + GetServerSidePropsResult, + InferGetServerSidePropsType, +} from 'next'; +import { User } from 'lucia'; +import { validateRequest } from '~/backend/auth'; -export default function Home() { +async function getServerSideProps( + context: GetServerSidePropsContext, +): Promise> { + console.log('jeps'); + const validatingRequest = await validateRequest(context.req, context.res); + if (!validatingRequest.user) { + return { + redirect: { + permanent: false, + destination: '/login', + }, + }; + } + const user = validatingRequest.user; + return { + props: { + user, + }, + }; +} + +export default function Home({ + user, +}: InferGetServerSidePropsType) { const [isAnyKindOfError, setIsAnyKindOfError] = useState(false); const [isAnyKindOfErrorMessage, setIsAnyKindOfErrorMessage] = useState(''); const [giftData, setGiftData] = useState([]); @@ -90,6 +120,7 @@ export default function Home() {

+ {user ?

{user.email}

:

Error!

} void handleSubmit(e)}> Lahjalistaidea
From a91e5ff925dffca59dd5f5cf0c25d231bd7c2114 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Wed, 10 Apr 2024 18:01:10 +0300 Subject: [PATCH 060/125] Fixed a few errors. Fixed session creation --- pages/api/auth/login.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts index 92afffa..5965bca 100644 --- a/pages/api/auth/login.ts +++ b/pages/api/auth/login.ts @@ -29,7 +29,7 @@ export default async function handleR( } if (!isEmailValid(email) || !isPasswordValid(password)) { - throw new HttpError('Invalid credentials!', 400); + throw new HttpError('Invalid request body!', 400); } const userData = await prisma.user.findUnique({ @@ -39,7 +39,7 @@ export default async function handleR( }); if (!userData) { - throw new HttpError('Server error!', 500); + throw new HttpError('Invalid credentials!', 400); } const isPasswordSame = await verifyPassword(password, userData.password); @@ -48,6 +48,21 @@ export default async function handleR( throw new HttpError('Invalid credentials!', 400); } + const sessionExists = await prisma.session.findUnique({ + where: { userUUID: userData.uuid }, + }); + + if (sessionExists) { + res + .appendHeader( + 'Set-cookie', + lucia.createSessionCookie(sessionExists.id).serialize(), + ) + .status(200) + .end(); + return; + } + const session = await lucia.createSession(userData.uuid, { user: { connect: { @@ -63,6 +78,7 @@ export default async function handleR( ) .status(200) .end(); + return; } catch (e) { return handleError(res, e); } From 91d633c4dc12fcc0c8ae2c38e3efde082de4948e Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Wed, 10 Apr 2024 20:12:41 +0300 Subject: [PATCH 061/125] Changed Login function name to Register --- pages/register.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/register.tsx b/pages/register.tsx index 7f975de..9f56214 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -18,7 +18,7 @@ type ErrorFieldNames = 'firstName' | 'lastName' | 'email' | 'password'; type ErrorTypes = Partial>; -export default function Login() { +export default function Register() { const [firstName, setFirstName] = useState('a'); const [lastName, setLastName] = useState('a'); const [email, setEmail] = useState('a@a.aa'); From 50a4100fef299e78b3b6ffef61cea39b0cbc15e8 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 11 Apr 2024 18:59:26 +0300 Subject: [PATCH 062/125] Added a check to see if user is logged in. Removed return from the router --- pages/login.tsx | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/pages/login.tsx b/pages/login.tsx index a9fe289..8b51116 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -1,11 +1,32 @@ import axios from 'axios'; +import { GetServerSidePropsContext, GetServerSidePropsResult } from 'next'; import Link from 'next/link'; import { useRouter } from 'next/router'; import { FormEvent, useState } from 'react'; +import { validateRequest } from '~/backend/auth'; import { Button } from '~/components/Button'; import { Input } from '~/components/Input'; import { TitleText } from '~/components/TitleText'; -import { UserLoginDetails } from '~/shared/types'; +import { User, UserLoginDetails } from '~/shared/types'; + +export async function getServerSideProps( + context: GetServerSidePropsContext, +): Promise }>> { + const cookieData = await validateRequest(context.req, context.res); + if (!cookieData.user) { + return { + props: { + user: {}, + }, + }; + } + return { + redirect: { + permanent: false, + destination: '/', + }, + }; +} export default function Login() { const [email, setEmail] = useState('a@a.aa'); @@ -24,10 +45,9 @@ export default function Login() { '/api/auth/login', loginCredentials, ); - return await router.push('/'); + await router.push('/'); } catch (e) { console.error(e); - return null; } } From 7b051aa7649fbd866a346b05fddde7058fa18b81 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 11 Apr 2024 19:19:22 +0300 Subject: [PATCH 063/125] Changed LuciaUser to User and added session to express in two days for now --- backend/auth.ts | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/backend/auth.ts b/backend/auth.ts index d1e43a0..b2e30f7 100644 --- a/backend/auth.ts +++ b/backend/auth.ts @@ -1,21 +1,34 @@ import { PrismaAdapter } from '@lucia-auth/adapter-prisma'; import type { IncomingMessage, ServerResponse } from 'http'; -import { Lucia } from 'lucia'; +import { Lucia, TimeSpan } from 'lucia'; import prisma from '~/prisma'; import type { CreateSession, User } from '~/shared/types'; -import type { Session, User as LuciaUser } from 'lucia'; +import type { Session } from 'lucia'; const adapter = new PrismaAdapter(prisma.session, prisma.user); export const lucia = new Lucia(adapter, { + sessionExpiresIn: new TimeSpan(2, 'd'), sessionCookie: { attributes: { secure: process.env.NODE_ENV === 'production', }, }, - getUserAttributes(attributes: Partial) { + getUserAttributes({ + createdAt, + email, + firstName, + lastName, + updatedAt, + uuid, + }: User): User { return { - email: attributes.email, + uuid: uuid, + firstName: firstName, + lastName: lastName, + email: email, + createdAt: createdAt, + updatedAt: updatedAt, }; }, }); @@ -33,9 +46,7 @@ interface DatabaseSessionAttributes extends CreateSession {} export async function validateRequest( req: IncomingMessage, res: ServerResponse, -): Promise< - { user: LuciaUser; session: Session } | { user: null; session: null } -> { +): Promise<{ user: User; session: Session } | { user: null; session: null }> { const sessionId = lucia.readSessionCookie(req.headers.cookie ?? ''); if (!sessionId) { return { From c8ef5d4f3dd17d0cbe8da97824108988c037c2ba Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 11 Apr 2024 19:21:50 +0300 Subject: [PATCH 064/125] Added a session checker into index.tsx --- pages/index.tsx | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index b4da948..9d17b74 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -5,22 +5,22 @@ import { Input } from '../components/Input'; import { DeleteModal } from '~/components/DeleteModal'; import { EditModal } from '~/components/EditModal'; import { createGift, getAllGifts } from '~/utils/apiRequests'; -import { Gift, CreateGift } from '~/shared/types'; +import { Gift, CreateGift, User } from '~/shared/types'; import { handleGeneralError } from '~/utils/handleError'; import { GetServerSidePropsContext, GetServerSidePropsResult, InferGetServerSidePropsType, } from 'next'; -import { User } from 'lucia'; import { validateRequest } from '~/backend/auth'; +import axios from 'axios'; +import { useRouter } from 'next/router'; -async function getServerSideProps( +export async function getServerSideProps( context: GetServerSidePropsContext, ): Promise> { - console.log('jeps'); - const validatingRequest = await validateRequest(context.req, context.res); - if (!validatingRequest.user) { + const cookieData = await validateRequest(context.req, context.res); + if (!cookieData.user) { return { redirect: { permanent: false, @@ -28,10 +28,9 @@ async function getServerSideProps( }, }; } - const user = validatingRequest.user; return { props: { - user, + user: JSON.parse(JSON.stringify(cookieData.user)), }, }; } @@ -51,9 +50,10 @@ export default function Home({ const [isEditModalOpen, setIsEditModalOpen] = useState(false); const [editModalGiftData, setEditModalGiftData] = useState(); + const router = useRouter(); + useEffect(() => { console.log('effect'); - async function fetchGifts() { try { const gifts = await getAllGifts(); @@ -120,7 +120,11 @@ export default function Home({
- {user ?

{user.email}

:

Error!

} + {user ? ( +

+ {user.firstName} {user.lastName} +

+ ) : null} void handleSubmit(e)}> Lahjalistaidea
@@ -218,6 +222,15 @@ export default function Home({
)} + +
From 8cbdff2fb7f7a7e9f40e87f2cfe75d09ee80b457 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 11 Apr 2024 19:22:14 +0300 Subject: [PATCH 065/125] Created a logout function --- pages/api/auth/logout.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 pages/api/auth/logout.ts diff --git a/pages/api/auth/logout.ts b/pages/api/auth/logout.ts new file mode 100644 index 0000000..b60fcf9 --- /dev/null +++ b/pages/api/auth/logout.ts @@ -0,0 +1,21 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; +import { lucia, validateRequest } from '~/backend/auth'; +import { HttpError } from '~/backend/HttpError'; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse, +) { + if (req.method !== 'POST') { + throw new HttpError('Invalid request method!', 405); + } + const { session } = await validateRequest(req, res); + if (!session) { + throw new HttpError('Unauthorized', 401); + } + await lucia.invalidateSession(session.id); + res + .setHeader('Set-Cookie', lucia.createBlankSessionCookie().serialize()) + .status(200) + .end(); +} From 2500743697863b6fde5c1ba35038387e3fd9827c Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 11 Apr 2024 22:41:57 +0300 Subject: [PATCH 066/125] Created a new SVG user and converted it to .tsx file" --- icons/user.tsx | 19 +++++++++++++++++++ public/images/icons/user.svg | 3 +++ 2 files changed, 22 insertions(+) create mode 100644 icons/user.tsx create mode 100644 public/images/icons/user.svg diff --git a/icons/user.tsx b/icons/user.tsx new file mode 100644 index 0000000..1326982 --- /dev/null +++ b/icons/user.tsx @@ -0,0 +1,19 @@ +import type { SVGProps } from 'react'; +const SvgUser = (props: SVGProps) => ( + + + +); +export default SvgUser; diff --git a/public/images/icons/user.svg b/public/images/icons/user.svg new file mode 100644 index 0000000..d01948f --- /dev/null +++ b/public/images/icons/user.svg @@ -0,0 +1,3 @@ + + + From 8cd8c4f971ba9fb41d948096b2a3b9b62d6caf05 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 11 Apr 2024 22:52:20 +0300 Subject: [PATCH 067/125] Added credits for the images --- icons/eye_open.tsx | 2 -- icons/eye_slash.tsx | 2 -- icons/index.ts | 1 + public/credits_for_images.txt | 6 +++++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/icons/eye_open.tsx b/icons/eye_open.tsx index 260a4d2..f59199a 100644 --- a/icons/eye_open.tsx +++ b/icons/eye_open.tsx @@ -1,5 +1,3 @@ -// Credits: https://heroicons.com/ - import type { SVGProps } from 'react'; const SvgEyeOpen = (props: SVGProps) => ( ) => ( Date: Fri, 12 Apr 2024 22:43:30 +0300 Subject: [PATCH 068/125] Added credits for the SVG image and converted a .tsx file of it --- icons/arrow_right_start_on_rectangle.tsx | 19 +++++++++++++++++++ icons/index.ts | 1 + public/credits_for_images.txt | 3 ++- .../icons/arrow-right-start-on-rectangle.svg | 3 +++ 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 icons/arrow_right_start_on_rectangle.tsx create mode 100644 public/images/icons/arrow-right-start-on-rectangle.svg diff --git a/icons/arrow_right_start_on_rectangle.tsx b/icons/arrow_right_start_on_rectangle.tsx new file mode 100644 index 0000000..726a871 --- /dev/null +++ b/icons/arrow_right_start_on_rectangle.tsx @@ -0,0 +1,19 @@ +import type { SVGProps } from 'react'; +const SvgArrowRightStartOnRectangle = (props: SVGProps) => ( + + + +); +export default SvgArrowRightStartOnRectangle; diff --git a/icons/index.ts b/icons/index.ts index 5118cd1..0aed5c3 100644 --- a/icons/index.ts +++ b/icons/index.ts @@ -1,4 +1,5 @@ export { default as AcceptButtonIcon } from './accept_button_icon'; +export { default as ArrowRightStartOnRectangle } from './arrow_right_start_on_rectangle'; export { default as DeclineButtonIcon } from './decline_button_icon'; export { default as EyeOpen } from './eye_open'; export { default as EyeSlash } from './eye_slash'; diff --git a/public/credits_for_images.txt b/public/credits_for_images.txt index 8ab514a..918480c 100644 --- a/public/credits_for_images.txt +++ b/public/credits_for_images.txt @@ -2,4 +2,5 @@ favicon.ico = https://www.flaticon.com/free-icon/giftbox_1139982 eye_open.svg = https://heroicons.com/ eye_slash.svg = https://heroicons.com/ -user.svg = https://heroicons.com/ \ No newline at end of file +user.svg = https://heroicons.com/ +arrow-right-start-on-rectangle.svg = https://heroicons.com/ \ No newline at end of file diff --git a/public/images/icons/arrow-right-start-on-rectangle.svg b/public/images/icons/arrow-right-start-on-rectangle.svg new file mode 100644 index 0000000..60d3fb9 --- /dev/null +++ b/public/images/icons/arrow-right-start-on-rectangle.svg @@ -0,0 +1,3 @@ + + + From d5445dc2b3219d2652213bbba34f406844facc7b Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 12 Apr 2024 22:56:45 +0300 Subject: [PATCH 069/125] Added a prototype of small info box when clicking user icon --- pages/index.tsx | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index 9d17b74..db47daf 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -15,6 +15,8 @@ import { import { validateRequest } from '~/backend/auth'; import axios from 'axios'; import { useRouter } from 'next/router'; +import SvgUser from '~/icons/user'; +import { Modal } from '~/components/Modal'; export async function getServerSideProps( context: GetServerSidePropsContext, @@ -118,15 +120,33 @@ export default function Home({ return (
+
+
+
Greetbook
+ +
+
+ {user ? ( +
+

+ {user.firstName} {user.lastName} +

+

{user.email}

+
+ ) : null} +
+
+
+
- {user ? ( -

- {user.firstName} {user.lastName} -

- ) : null} + {user ?

{user.email}

: null} void handleSubmit(e)}> - Lahjalistaidea + Uusi idea
Date: Sun, 14 Apr 2024 11:49:41 +0300 Subject: [PATCH 070/125] Added a prototype of logout button --- pages/index.tsx | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index db47daf..45da583 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -17,6 +17,7 @@ import axios from 'axios'; import { useRouter } from 'next/router'; import SvgUser from '~/icons/user'; import { Modal } from '~/components/Modal'; +import SvgArrowRightStartOnRectangle from '~/icons/arrow_right_start_on_rectangle'; export async function getServerSideProps( context: GetServerSidePropsContext, @@ -122,13 +123,13 @@ export default function Home({
-
Greetbook
+
Lahjalista
-
+
{user ? (
@@ -136,6 +137,18 @@ export default function Home({ {user.firstName} {user.lastName}

{user.email}

+
+
+

+ Kirjaudu ulos +

+ +
+
) : null}
From 54674475508b16667c58e5bc0b2184f7f09a1a96 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Sun, 14 Apr 2024 14:33:54 +0300 Subject: [PATCH 071/125] Installed the needed packages on my laptop --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 12e2f28..79aa039 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10078,9 +10078,9 @@ } }, "node_modules/tar": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", - "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", From be218f158119d07b7c1488020b757b543bf5ec49 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Sun, 14 Apr 2024 14:39:45 +0300 Subject: [PATCH 072/125] Added error related useStates --- pages/login.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pages/login.tsx b/pages/login.tsx index 8b51116..0369a24 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -31,6 +31,8 @@ export async function getServerSideProps( export default function Login() { const [email, setEmail] = useState('a@a.aa'); const [password, setPassword] = useState('!TeppoTesteri123123'); + const [isError, setIsError] = useState(false); + const [errorText, setErrorText] = useState(''); const router = useRouter(); From 8561fc7f880a00fc568f6ca4d7e46f4583ebad9d Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Sun, 14 Apr 2024 14:43:05 +0300 Subject: [PATCH 073/125] Renamed handleUserError to handleRegisterError --- pages/register.tsx | 4 ++-- utils/handleError.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pages/register.tsx b/pages/register.tsx index 9f56214..d77ba41 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -9,7 +9,7 @@ import { Modal } from '~/components/Modal'; import { TitleText } from '~/components/TitleText'; import { SvgCheckMarkIcon } from '~/icons/CheckMarkIcon'; import type { CreateUser } from '~/shared/types'; -import { handleUserError } from '~/utils/handleError'; +import { handleRegisterError } from '~/utils/handleError'; import { emailRegex, passwordRegex } from '~/shared/regexPatterns'; import SvgEyeOpen from '~/icons/eye_open'; import SvgEyeSlash from '~/icons/eye_slash'; @@ -45,7 +45,7 @@ export default function Register() { } as CreateUser); userCreatedSuccesfully(); } catch (e) { - const errorText = handleUserError(e); + const errorText = handleRegisterError(e); setRegisterError(errorText); } } diff --git a/utils/handleError.ts b/utils/handleError.ts index 989cf4f..b531b6f 100644 --- a/utils/handleError.ts +++ b/utils/handleError.ts @@ -29,7 +29,7 @@ const USER_ERROR_HANDLER: Record = { 'email was not unique!': 'Sähköposti on jo käytössä', }; -export function handleUserError(e: unknown) { +export function handleRegisterError(e: unknown) { if (isAxiosError(e) && e.response?.status === 400) { const responseText = e.response.data.toLowerCase(); if ( From 8075932e52cee59b2b75df22cd3fa98e65df7e50 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Sun, 14 Apr 2024 20:45:56 +0300 Subject: [PATCH 074/125] Created a new file isValidFunctions.ts to shared folder to be able to use both in front- and backend. Fixed the imports as well --- backend/utils.ts | 44 -------------------------------------- pages/api/auth/login.ts | 3 ++- pages/api/users/index.ts | 4 ++-- shared/isValidFunctions.ts | 44 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 47 deletions(-) create mode 100644 shared/isValidFunctions.ts diff --git a/backend/utils.ts b/backend/utils.ts index 72f3db8..619088b 100644 --- a/backend/utils.ts +++ b/backend/utils.ts @@ -1,49 +1,5 @@ -import { emailRegex, passwordRegex } from '~/shared/regexPatterns'; import { compare as bcryptCompare, hash } from 'bcrypt'; -export function isEmailValid(email: string): boolean { - if (email.length <= 0) { - return false; - } - // this should check with regex that there cannot be multiple dots etc - const checkedEmailAddress = email.toLowerCase().match(emailRegex); - - if (!checkedEmailAddress) { - return false; - } - - // email is ready to be used - return true; -} - -export function isFirstNameValid(firstName: string): boolean { - if (firstName.length <= 0) { - return false; - } - return true; -} - -export function isLastNameValid(lastName: string): boolean { - if (lastName.length <= 0) { - return false; - } - return true; -} - -export function isPasswordValid(password: string): boolean { - if (password.length <= 0) { - return false; - } - // TLDR: 8 merkkiä pitkä, maksimissaan 128, vähintään 1 numero, 1 pieni ja iso kirjain sekä yksi erikoismerkki - const checkedPassword = password.match(passwordRegex); - - if (!checkedPassword) { - return false; - } - - return true; -} - export async function verifyPassword( givenPassword: string, hashedPassword: string, diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts index 5965bca..942edc1 100644 --- a/pages/api/auth/login.ts +++ b/pages/api/auth/login.ts @@ -3,7 +3,8 @@ import { lucia } from '~/backend/auth'; import { handleError } from '~/backend/handleError'; import { HttpError } from '~/backend/HttpError'; import { UserLoginDetails } from '~/shared/types'; -import { isEmailValid, isPasswordValid, verifyPassword } from '~/backend/utils'; +import { verifyPassword } from '~/backend/utils'; +import { isEmailValid, isPasswordValid } from '~/shared/isValidFunctions'; import prisma from '~/prisma'; export default async function handleR( diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 503f81e..f1d8ec9 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -2,13 +2,13 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { CreateUser, User } from '~/shared/types'; import prisma from '~/prisma'; import { handleError } from '~/backend/handleError'; +import { hashPassword } from '~/backend/utils'; import { - hashPassword, isEmailValid, isFirstNameValid, isLastNameValid, isPasswordValid, -} from '~/backend/utils'; +} from '~/shared/isValidFunctions'; import { HttpError } from '~/backend/HttpError'; const HANDLER: Record< diff --git a/shared/isValidFunctions.ts b/shared/isValidFunctions.ts new file mode 100644 index 0000000..edb329d --- /dev/null +++ b/shared/isValidFunctions.ts @@ -0,0 +1,44 @@ +import { emailRegex, passwordRegex } from './regexPatterns'; + +export function isEmailValid(email: string): boolean { + if (email.length <= 0) { + return false; + } + // this should check with regex that there cannot be multiple dots etc + const checkedEmailAddress = email.toLowerCase().match(emailRegex); + + if (!checkedEmailAddress) { + return false; + } + + // email is ready to be used + return true; +} + +export function isFirstNameValid(firstName: string): boolean { + if (firstName.length <= 0) { + return false; + } + return true; +} + +export function isLastNameValid(lastName: string): boolean { + if (lastName.length <= 0) { + return false; + } + return true; +} + +export function isPasswordValid(password: string): boolean { + if (password.length <= 0) { + return false; + } + // TLDR: 8 merkkiä pitkä, maksimissaan 128, vähintään 1 numero, 1 pieni ja iso kirjain sekä yksi erikoismerkki + const checkedPassword = password.match(passwordRegex); + + if (!checkedPassword) { + return false; + } + + return true; +} From 1eb0088a838a5eeaac4212b1789c5c028d20a623 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Sun, 14 Apr 2024 20:47:43 +0300 Subject: [PATCH 075/125] Created useState to determite if the user details should be shown. Added some functionality to it --- pages/index.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index 45da583..cb3d923 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -52,6 +52,7 @@ export default function Home({ const [deleteModalGiftData, setDeleteModalGiftData] = useState(); const [isEditModalOpen, setIsEditModalOpen] = useState(false); const [editModalGiftData, setEditModalGiftData] = useState(); + const [showUserWindow, setShowUserWindow] = useState(false); const router = useRouter(); @@ -128,10 +129,11 @@ export default function Home({ width={32} height={32} className="cursor-pointer hover:stroke-yellow-600" + onClick={() => setShowUserWindow((prevValue) => !prevValue)} /> -
-
- {user ? ( + {user && showUserWindow ? ( +
+

{user.firstName} {user.lastName} @@ -150,14 +152,13 @@ export default function Home({

- ) : null} +
-
+ ) : null}
- {user ?

{user.email}

: null} void handleSubmit(e)}> Uusi idea
From c9d21be44b6f164dd37782b27540d0566301d89a Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Sun, 14 Apr 2024 21:01:16 +0300 Subject: [PATCH 076/125] Moved error text block a bit more up so it will not resize the whole form. Added a check for email if it is valild to avoid possible unnecessary requests --- pages/login.tsx | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/pages/login.tsx b/pages/login.tsx index 0369a24..c4d8d89 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -7,7 +7,9 @@ import { validateRequest } from '~/backend/auth'; import { Button } from '~/components/Button'; import { Input } from '~/components/Input'; import { TitleText } from '~/components/TitleText'; +import { isEmailValid } from '~/shared/isValidFunctions'; import { User, UserLoginDetails } from '~/shared/types'; +import { handleLoginError } from '~/utils/handleError'; export async function getServerSideProps( context: GetServerSidePropsContext, @@ -31,7 +33,6 @@ export async function getServerSideProps( export default function Login() { const [email, setEmail] = useState('a@a.aa'); const [password, setPassword] = useState('!TeppoTesteri123123'); - const [isError, setIsError] = useState(false); const [errorText, setErrorText] = useState(''); const router = useRouter(); @@ -39,23 +40,32 @@ export default function Login() { async function handleSubmit(e: FormEvent) { e.preventDefault(); try { - const loginCredentials: UserLoginDetails = { - email: email, - password: password, - }; - const loginRequest = await axios.post( - '/api/auth/login', - loginCredentials, - ); - await router.push('/'); + if (isEmailValid(email)) { + const loginCredentials: UserLoginDetails = { + email: email, + password: password, + }; + await axios.post('/api/auth/login', loginCredentials); + await router.push('/'); + } else { + setErrorText('Sähköposti ei ole sääntöjen mukainen!'); + } } catch (e) { console.error(e); + setErrorText(handleLoginError(e)); } } return (
+ {errorText.length > 0 ? ( +
+
+ {errorText} +
+
+ ) : null}
void handleSubmit(e)}> From 70901bad689eda4ef018d56923301b2b05f61553 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Sun, 14 Apr 2024 21:03:58 +0300 Subject: [PATCH 077/125] Created a function for login errors and added login error to known front end errors --- utils/handleError.ts | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/utils/handleError.ts b/utils/handleError.ts index b531b6f..1b1153e 100644 --- a/utils/handleError.ts +++ b/utils/handleError.ts @@ -23,10 +23,14 @@ export function handleGiftError(e: unknown) { } } -type KnownFrontEndErrorTexts = 'email was not unique!' | string; +type KnownFrontEndErrorTexts = + | 'email was not unique!' + | 'invalid credentials!' + | string; -const USER_ERROR_HANDLER: Record = { +const FRONT_END_HANDLER: Record = { 'email was not unique!': 'Sähköposti on jo käytössä', + 'invalid credentials!': 'Sähköposti tai salasana on virheellinen!', }; export function handleRegisterError(e: unknown) { @@ -34,10 +38,10 @@ export function handleRegisterError(e: unknown) { const responseText = e.response.data.toLowerCase(); if ( typeof e.response.data === 'string' && - USER_ERROR_HANDLER[responseText] + FRONT_END_HANDLER[responseText] ) { - console.error(USER_ERROR_HANDLER[responseText]); - return USER_ERROR_HANDLER[responseText]; + console.error(FRONT_END_HANDLER[responseText]); + return FRONT_END_HANDLER[responseText]; } else { console.error('Unexpected error occured!'); console.error('Unexpected error: ', e.response.data); @@ -49,3 +53,25 @@ export function handleRegisterError(e: unknown) { } return ''; } + +export function handleLoginError(e: unknown) { + if (isAxiosError(e) && e.response?.status === 400) { + const responseText = e.response.data.toLowerCase(); + if ( + typeof e.response.data === 'string' && + FRONT_END_HANDLER[responseText] + ) { + console.error(FRONT_END_HANDLER[responseText]); + return FRONT_END_HANDLER[responseText]; + } else { + console.error('Unexpected error occured!'); + console.error('Unexpected error: ', e.response.data); + return 'Palvelin virhe!'; + } + } else if (e instanceof Error) { + console.error(e.message); + } else { + console.error(e); + } + return ''; +} From 74a295301fd537e04d82846007a3b206a3d6f45c Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Sun, 14 Apr 2024 21:16:33 +0300 Subject: [PATCH 078/125] Added an eye that will reval the password. Copied it from register.tsx --- pages/login.tsx | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/pages/login.tsx b/pages/login.tsx index c4d8d89..37bd26b 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -7,6 +7,8 @@ import { validateRequest } from '~/backend/auth'; import { Button } from '~/components/Button'; import { Input } from '~/components/Input'; import { TitleText } from '~/components/TitleText'; +import SvgEyeOpen from '~/icons/eye_open'; +import SvgEyeSlash from '~/icons/eye_slash'; import { isEmailValid } from '~/shared/isValidFunctions'; import { User, UserLoginDetails } from '~/shared/types'; import { handleLoginError } from '~/utils/handleError'; @@ -34,6 +36,7 @@ export default function Login() { const [email, setEmail] = useState('a@a.aa'); const [password, setPassword] = useState('!TeppoTesteri123123'); const [errorText, setErrorText] = useState(''); + const [showPassword, setShowPassword] = useState(false); const router = useRouter(); @@ -85,15 +88,34 @@ export default function Login() {
- setPassword(e.currentTarget.value)} - value={password} - className="border border-black" - autoComplete="off" - type="password" - placeholder="************" - name="password" - /> +
+ setPassword(e.currentTarget.value)} + className="pl-1 pt-3 pb-3 border-0 outline-none group-hover/password:bg-gray-100" + autoComplete="off" + type={showPassword ? 'text' : 'password'} + placeholder="************" + name="password" + /> +
+ {showPassword ? ( + { + setShowPassword((prevValue) => !prevValue); + }} + /> + ) : ( + { + setShowPassword((prevValue) => !prevValue); + }} + /> + )} +
+
From b3e9573aec66b2390435b20d017b3b7ecac372bb Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Sun, 14 Apr 2024 21:57:58 +0300 Subject: [PATCH 082/125] Created a new function luciaLongSession and changed default lucia to luciaShortSession. Created a variable value for lucia to see if the lucia should be short or long sessioned. This should be fine due to it not being global variable --- pages/api/auth/login.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts index 942edc1..b188218 100644 --- a/pages/api/auth/login.ts +++ b/pages/api/auth/login.ts @@ -1,11 +1,16 @@ import type { NextApiRequest, NextApiResponse } from 'next'; -import { lucia } from '~/backend/auth'; +import { adapter, lucia as luciaShortSession } from '~/backend/auth'; import { handleError } from '~/backend/handleError'; import { HttpError } from '~/backend/HttpError'; import { UserLoginDetails } from '~/shared/types'; import { verifyPassword } from '~/backend/utils'; import { isEmailValid, isPasswordValid } from '~/shared/isValidFunctions'; import prisma from '~/prisma'; +import { Lucia, TimeSpan } from 'lucia'; + +const luciaLongSession = new Lucia(adapter, { + sessionExpiresIn: new TimeSpan(90, 'd'), +}); export default async function handleR( req: NextApiRequest, @@ -16,7 +21,9 @@ export default async function handleR( throw new HttpError('Invalid request method!', 405); } - const { email, password } = req.body as UserLoginDetails; + const { email, password, rememberMe } = req.body as UserLoginDetails; + + let lucia = rememberMe ? luciaLongSession : luciaShortSession; if ( !email || From f9f28c77c6d59561cb8b0287e60ab49ac316001c Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 15 Apr 2024 15:56:02 +0300 Subject: [PATCH 083/125] Changed 'regular' session to be 2 weeks. Remember me wil be 30 days --- backend/auth.ts | 2 +- pages/api/auth/login.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/auth.ts b/backend/auth.ts index 28dd860..475e9d2 100644 --- a/backend/auth.ts +++ b/backend/auth.ts @@ -8,7 +8,7 @@ import type { Session } from 'lucia'; export const adapter = new PrismaAdapter(prisma.session, prisma.user); export const lucia = new Lucia(adapter, { - sessionExpiresIn: new TimeSpan(2, 'd'), + sessionExpiresIn: new TimeSpan(14, 'd'), sessionCookie: { attributes: { secure: process.env.NODE_ENV === 'production', diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts index b188218..fce3fe5 100644 --- a/pages/api/auth/login.ts +++ b/pages/api/auth/login.ts @@ -9,7 +9,7 @@ import prisma from '~/prisma'; import { Lucia, TimeSpan } from 'lucia'; const luciaLongSession = new Lucia(adapter, { - sessionExpiresIn: new TimeSpan(90, 'd'), + sessionExpiresIn: new TimeSpan(30, 'd'), }); export default async function handleR( From 23a46da01bc0d74b0471b68ff5a7de52ed942411 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 15 Apr 2024 16:00:06 +0300 Subject: [PATCH 084/125] Added frontend styling --- pages/index.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index cb3d923..673e4c9 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -124,7 +124,7 @@ export default function Home({
-
Lahjalista
+
Lahjaidealista
setShowUserWindow((prevValue) => !prevValue)} /> {user && showUserWindow ? ( -
+

{user.firstName} {user.lastName}

{user.email}

-
+

Kirjaudu ulos @@ -160,9 +160,11 @@ export default function Home({

void handleSubmit(e)}> - Uusi idea + Uusi idea
- + setNewReceiver(event.target.value)} autoComplete="off" @@ -176,7 +178,9 @@ export default function Home({ )}
- + setNewGiftName(event.target.value)} autoComplete="off" From b285acfe95fcd4d0b1b3b4e9802d601702872014 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 15 Apr 2024 16:09:30 +0300 Subject: [PATCH 085/125] Created a local component for user detail modal. Might change it in the future --- pages/index.tsx | 63 +++++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index 673e4c9..9ddf165 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,4 +1,4 @@ -import { FormEvent, useEffect, useState } from 'react'; +import { FormEvent, HTMLAttributes, useEffect, useState } from 'react'; import { Button } from '~/components/Button'; import { TitleText } from '~/components/TitleText'; import { Input } from '../components/Input'; @@ -16,7 +16,6 @@ import { validateRequest } from '~/backend/auth'; import axios from 'axios'; import { useRouter } from 'next/router'; import SvgUser from '~/icons/user'; -import { Modal } from '~/components/Modal'; import SvgArrowRightStartOnRectangle from '~/icons/arrow_right_start_on_rectangle'; export async function getServerSideProps( @@ -131,30 +130,7 @@ export default function Home({ className="cursor-pointer hover:stroke-yellow-600" onClick={() => setShowUserWindow((prevValue) => !prevValue)} /> - {user && showUserWindow ? ( -
-
-
-

- {user.firstName} {user.lastName} -

-

{user.email}

-
-
-

- Kirjaudu ulos -

- -
-
-
-
-
- ) : null} +
@@ -275,3 +251,38 @@ export default function Home({
); } + +function UserDetailModal({ + className, + user, + showUserWindow, + ...rest +}: HTMLAttributes & { user: User; showUserWindow: boolean }) { + if (user && showUserWindow) { + return ( +
+
+
+

+ {user.firstName} {user.lastName} +

+

{user.email}

+
+
+

+ Kirjaudu ulos +

+ +
+
+
+
+
+ ); + } + return null; +} From 4c9563dddddec5e35536482740f3dbcacc0e7491 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 15 Apr 2024 16:16:28 +0300 Subject: [PATCH 086/125] Created a function called handleLogout and added it to UserDetailsModal to be callable --- pages/index.tsx | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index 9ddf165..6ec8257 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -119,6 +119,11 @@ export default function Home({ setIsAnyKindOfErrorMessage(errorMessage); } + async function handleLogout() { + const request = await axios.post('/api/auth/logout'); + if (request) router.push('/login'); + } + return (
@@ -130,7 +135,11 @@ export default function Home({ className="cursor-pointer hover:stroke-yellow-600" onClick={() => setShowUserWindow((prevValue) => !prevValue)} /> - +
@@ -256,8 +265,13 @@ function UserDetailModal({ className, user, showUserWindow, + handleLogout, ...rest -}: HTMLAttributes & { user: User; showUserWindow: boolean }) { +}: HTMLAttributes & { + user: User; + showUserWindow: boolean; + handleLogout: () => void; +}) { if (user && showUserWindow) { return (
@@ -268,7 +282,10 @@ function UserDetailModal({

{user.email}

-
+
handleLogout()} + >

Kirjaudu ulos

From ae6f4b9a4800cff21202f5c9ab66e2ea05efe08c Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 15 Apr 2024 16:17:11 +0300 Subject: [PATCH 087/125] Removed the extra sign out button --- pages/index.tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index 6ec8257..f25dadd 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -245,15 +245,6 @@ export default function Home({
)} - -
From c0876b1a0107a29191c493192f9e2ae50c74b801 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 15 Apr 2024 17:25:54 +0300 Subject: [PATCH 088/125] Added hoverOnlyWhenSupported to be true to make hover elements work as intended when using mobile --- tailwind.config.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tailwind.config.ts b/tailwind.config.ts index 47183f6..7c3d6a7 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,6 +1,9 @@ import type { Config } from 'tailwindcss'; const config: Config = { + future: { + hoverOnlyWhenSupported: true, + }, content: [ './pages/**/*.{js,ts,jsx,tsx,mdx}', './components/**/*.{js,ts,jsx,tsx,mdx}', From 412c37fd064273c0929be6455c06b408156b629b Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 15 Apr 2024 17:27:55 +0300 Subject: [PATCH 089/125] Added some functionality to classname rendering. Created a new parameter to UserDetailsModal component that will close the modal. Added a full page sized div-wrapper to get clicks that are not inside the modal or is not the user icon --- pages/index.tsx | 51 +++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index f25dadd..93528d4 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -132,13 +132,14 @@ export default function Home({ setShowUserWindow((prevValue) => !prevValue)} /> setShowUserWindow(false)} />
@@ -256,40 +257,44 @@ function UserDetailModal({ className, user, showUserWindow, + closeUserWindow, handleLogout, ...rest }: HTMLAttributes & { user: User; showUserWindow: boolean; + closeUserWindow: () => void; handleLogout: () => void; }) { if (user && showUserWindow) { return ( -
-
-
-

- {user.firstName} {user.lastName} -

-

{user.email}

-
-
handleLogout()} - > -

- Kirjaudu ulos -

- -
+ <> +
closeUserWindow()} + /> +
+

+ {user.firstName} {user.lastName} +

+

{user.email}

+
+
handleLogout()} + > +

+ Kirjaudu ulos +

+
-
+ ); } return null; From 99b8d7d86fec1291cb4000e520a11e2e49beac59 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 15 Apr 2024 17:29:24 +0300 Subject: [PATCH 090/125] Removed development placeholder values --- pages/login.tsx | 4 ++-- pages/register.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pages/login.tsx b/pages/login.tsx index d8445a3..f3ecf2d 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -33,8 +33,8 @@ export async function getServerSideProps( } export default function Login() { - const [email, setEmail] = useState('a@a.aa'); - const [password, setPassword] = useState('!TeppoTesteri123123'); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); const [rememberMe, setRememberMe] = useState(false); const [errorText, setErrorText] = useState(''); const [showPassword, setShowPassword] = useState(false); diff --git a/pages/register.tsx b/pages/register.tsx index d77ba41..207ba82 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -21,8 +21,8 @@ type ErrorTypes = Partial>; export default function Register() { const [firstName, setFirstName] = useState('a'); const [lastName, setLastName] = useState('a'); - const [email, setEmail] = useState('a@a.aa'); - const [password, setPassword] = useState('!TeppoTesteri123123'); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); const [registerError, setRegisterError] = useState(''); From 513cb3a1bcf3341df6df7a0690a52e6360f2c8c2 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Tue, 16 Apr 2024 19:45:14 +0300 Subject: [PATCH 091/125] Removed development placeholder values --- pages/register.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/register.tsx b/pages/register.tsx index 207ba82..d92e161 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -19,8 +19,8 @@ type ErrorFieldNames = 'firstName' | 'lastName' | 'email' | 'password'; type ErrorTypes = Partial>; export default function Register() { - const [firstName, setFirstName] = useState('a'); - const [lastName, setLastName] = useState('a'); + const [firstName, setFirstName] = useState(''); + const [lastName, setLastName] = useState(''); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); From 5bce27780f76f658eb8dde2a76c6d81ff236281d Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Tue, 16 Apr 2024 19:48:31 +0300 Subject: [PATCH 092/125] ESLint fixes --- icons/arrow_right_start_on_rectangle.tsx | 1 + icons/eye_open.tsx | 1 + icons/eye_slash.tsx | 1 + icons/index.ts | 2 -- icons/user.tsx | 1 + pages/api/auth/login.ts | 2 +- pages/index.tsx | 10 ++++------ utils/handleError.ts | 15 ++++++++++++++- 8 files changed, 23 insertions(+), 10 deletions(-) diff --git a/icons/arrow_right_start_on_rectangle.tsx b/icons/arrow_right_start_on_rectangle.tsx index 726a871..d6038bb 100644 --- a/icons/arrow_right_start_on_rectangle.tsx +++ b/icons/arrow_right_start_on_rectangle.tsx @@ -1,4 +1,5 @@ import type { SVGProps } from 'react'; + const SvgArrowRightStartOnRectangle = (props: SVGProps) => ( ) => ( ) => ( ) => ( console.error(e)); } return ( @@ -254,17 +254,15 @@ export default function Home({ } function UserDetailModal({ - className, user, showUserWindow, closeUserWindow, handleLogout, - ...rest }: HTMLAttributes & { user: User; showUserWindow: boolean; closeUserWindow: () => void; - handleLogout: () => void; + handleLogout: () => void | Promise; }) { if (user && showUserWindow) { return ( @@ -281,7 +279,7 @@ function UserDetailModal({
handleLogout()} + onClick={() => void handleLogout()} >

Kirjaudu ulos diff --git a/utils/handleError.ts b/utils/handleError.ts index 1b1153e..a39067c 100644 --- a/utils/handleError.ts +++ b/utils/handleError.ts @@ -26,15 +26,22 @@ export function handleGiftError(e: unknown) { type KnownFrontEndErrorTexts = | 'email was not unique!' | 'invalid credentials!' - | string; + | 'invalid request body!' + | (string & Record); const FRONT_END_HANDLER: Record = { 'email was not unique!': 'Sähköposti on jo käytössä', 'invalid credentials!': 'Sähköposti tai salasana on virheellinen!', + 'invalid request body!': 'Sähköposti tai salasana on virheellinen', }; export function handleRegisterError(e: unknown) { if (isAxiosError(e) && e.response?.status === 400) { + if (typeof e.response.data !== 'string') { + console.error('Unexpected error occured!'); + console.error('Unexpected error: ', e.response.data); + return 'Palvelin virhe!'; + } const responseText = e.response.data.toLowerCase(); if ( typeof e.response.data === 'string' && @@ -45,6 +52,7 @@ export function handleRegisterError(e: unknown) { } else { console.error('Unexpected error occured!'); console.error('Unexpected error: ', e.response.data); + return 'Palvelin virhe!'; } } else if (e instanceof Error) { console.error(e.message); @@ -56,6 +64,11 @@ export function handleRegisterError(e: unknown) { export function handleLoginError(e: unknown) { if (isAxiosError(e) && e.response?.status === 400) { + if (typeof e.response.data !== 'string') { + console.error('Unexpected error occured!'); + console.error('Unexpected error: ', e.response.data); + return 'Palvelin virhe!'; + } const responseText = e.response.data.toLowerCase(); if ( typeof e.response.data === 'string' && From 60688a6e7e2a21e0f9c5d11d21713cee84b0372f Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Tue, 16 Apr 2024 20:13:09 +0300 Subject: [PATCH 093/125] Added secure value to /api/login.ts's Lucia class constructor --- pages/api/auth/login.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts index 4bbcc67..f12cb39 100644 --- a/pages/api/auth/login.ts +++ b/pages/api/auth/login.ts @@ -10,6 +10,11 @@ import { Lucia, TimeSpan } from 'lucia'; const luciaLongSession = new Lucia(adapter, { sessionExpiresIn: new TimeSpan(30, 'd'), + sessionCookie: { + attributes: { + secure: process.env.NODE_ENV === 'production', + }, + }, }); export default async function handleR( From 0c44e77cb69882b54cdee89f2da218e62fb22205 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Sat, 20 Apr 2024 22:04:50 +0300 Subject: [PATCH 094/125] Created a migration of Session Model --- .../migration.sql | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 prisma/migrations/20240420183952_session_model/migration.sql diff --git a/prisma/migrations/20240420183952_session_model/migration.sql b/prisma/migrations/20240420183952_session_model/migration.sql new file mode 100644 index 0000000..32ccdc0 --- /dev/null +++ b/prisma/migrations/20240420183952_session_model/migration.sql @@ -0,0 +1,20 @@ +-- CreateTable +CREATE TABLE "Session" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "userUUID" TEXT NOT NULL, + "expiresAt" TIMESTAMP(3) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Session_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Session_userId_key" ON "Session"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Session_userUUID_key" ON "Session"("userUUID"); + +-- AddForeignKey +ALTER TABLE "Session" ADD CONSTRAINT "Session_userUUID_fkey" FOREIGN KEY ("userUUID") REFERENCES "User"("uuid") ON DELETE CASCADE ON UPDATE CASCADE; From abcb4a68a8714b971d3e3ec492c1f70d058960ef Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 22 Apr 2024 10:24:18 +0300 Subject: [PATCH 095/125] Removed unnecessary lines in .env.example --- .env.example | 2 -- 1 file changed, 2 deletions(-) diff --git a/.env.example b/.env.example index e41d765..dae146c 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1 @@ DATABASE_URL="postgresql://databaseusername:databasepassword@localhost:5432/mydb?schema=public" # README.md's section "Setting the environment variables" will help with this -POSTGRES_USERNAME="databaseusername" # Postgres database's username. It is same as DATABASE_URL's databaseusername -POSTGRES_PASSWORD="databasepassword" # Postgres database's password. It is same as DATABASE_URL's databasepassword \ No newline at end of file From c1678cff0724e712f96304b98e0e1487bdceac62 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 29 Apr 2024 12:42:49 +0300 Subject: [PATCH 096/125] Moved handleLogout function from Home function to UserDetailModal function. Changed router.push to window.location.href --- pages/index.tsx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index 9d2c3e3..6a7a29b 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -119,11 +119,6 @@ export default function Home({ setIsAnyKindOfErrorMessage(errorMessage); } - async function handleLogout() { - const request = await axios.post('/api/auth/logout'); - if (request) await router.push('/login').catch((e) => console.error(e)); - } - return (

@@ -138,7 +133,6 @@ export default function Home({ setShowUserWindow(false)} />
@@ -257,13 +251,16 @@ function UserDetailModal({ user, showUserWindow, closeUserWindow, - handleLogout, }: HTMLAttributes & { user: User; showUserWindow: boolean; closeUserWindow: () => void; - handleLogout: () => void | Promise; }) { + async function handleLogout() { + const request = await axios.post('/api/auth/logout'); + if (request) window.location.href = '/login'; + } + if (user && showUserWindow) { return ( <> From 00b11dad0b9f962faca0da7b1d2c12d69f9e5529 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 29 Apr 2024 13:07:08 +0300 Subject: [PATCH 097/125] Changed the way how frontend error texts are set --- utils/handleError.ts | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/utils/handleError.ts b/utils/handleError.ts index a39067c..1f2a539 100644 --- a/utils/handleError.ts +++ b/utils/handleError.ts @@ -23,17 +23,13 @@ export function handleGiftError(e: unknown) { } } -type KnownFrontEndErrorTexts = - | 'email was not unique!' - | 'invalid credentials!' - | 'invalid request body!' - | (string & Record); - -const FRONT_END_HANDLER: Record = { +const FRONT_END_HANDLER = { 'email was not unique!': 'Sähköposti on jo käytössä', 'invalid credentials!': 'Sähköposti tai salasana on virheellinen!', 'invalid request body!': 'Sähköposti tai salasana on virheellinen', -}; +} as const; + +type KnownFrontEndErrorTexts = keyof typeof FRONT_END_HANDLER; export function handleRegisterError(e: unknown) { if (isAxiosError(e) && e.response?.status === 400) { @@ -43,12 +39,11 @@ export function handleRegisterError(e: unknown) { return 'Palvelin virhe!'; } const responseText = e.response.data.toLowerCase(); - if ( - typeof e.response.data === 'string' && - FRONT_END_HANDLER[responseText] - ) { - console.error(FRONT_END_HANDLER[responseText]); - return FRONT_END_HANDLER[responseText]; + const frontendText = + FRONT_END_HANDLER[responseText as KnownFrontEndErrorTexts]; + if (frontendText) { + console.error(frontendText); + return frontendText; } else { console.error('Unexpected error occured!'); console.error('Unexpected error: ', e.response.data); @@ -70,12 +65,11 @@ export function handleLoginError(e: unknown) { return 'Palvelin virhe!'; } const responseText = e.response.data.toLowerCase(); - if ( - typeof e.response.data === 'string' && - FRONT_END_HANDLER[responseText] - ) { - console.error(FRONT_END_HANDLER[responseText]); - return FRONT_END_HANDLER[responseText]; + const frontendText = + FRONT_END_HANDLER[responseText as KnownFrontEndErrorTexts]; + if (frontendText) { + console.error(frontendText); + return frontendText; } else { console.error('Unexpected error occured!'); console.error('Unexpected error: ', e.response.data); From 300226e8e12859fca507beb7c4003920c229d0e6 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 29 Apr 2024 13:12:56 +0300 Subject: [PATCH 098/125] Combined login and register errors and fixed the imports --- pages/login.tsx | 4 ++-- pages/register.tsx | 4 ++-- utils/handleError.ts | 28 +--------------------------- 3 files changed, 5 insertions(+), 31 deletions(-) diff --git a/pages/login.tsx b/pages/login.tsx index f3ecf2d..fb533c7 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -11,7 +11,7 @@ import SvgEyeOpen from '~/icons/eye_open'; import SvgEyeSlash from '~/icons/eye_slash'; import { isEmailValid } from '~/shared/isValidFunctions'; import { User, UserLoginDetails } from '~/shared/types'; -import { handleLoginError } from '~/utils/handleError'; +import { handleAuthErrors } from '~/utils/handleError'; export async function getServerSideProps( context: GetServerSidePropsContext, @@ -57,7 +57,7 @@ export default function Login() { } } catch (e) { console.error(e); - setErrorText(handleLoginError(e)); + setErrorText(handleAuthErrors(e)); } } diff --git a/pages/register.tsx b/pages/register.tsx index d92e161..99ce222 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -9,7 +9,7 @@ import { Modal } from '~/components/Modal'; import { TitleText } from '~/components/TitleText'; import { SvgCheckMarkIcon } from '~/icons/CheckMarkIcon'; import type { CreateUser } from '~/shared/types'; -import { handleRegisterError } from '~/utils/handleError'; +import { handleAuthErrors } from '~/utils/handleError'; import { emailRegex, passwordRegex } from '~/shared/regexPatterns'; import SvgEyeOpen from '~/icons/eye_open'; import SvgEyeSlash from '~/icons/eye_slash'; @@ -45,7 +45,7 @@ export default function Register() { } as CreateUser); userCreatedSuccesfully(); } catch (e) { - const errorText = handleRegisterError(e); + const errorText = handleAuthErrors(e); setRegisterError(errorText); } } diff --git a/utils/handleError.ts b/utils/handleError.ts index 1f2a539..49987ce 100644 --- a/utils/handleError.ts +++ b/utils/handleError.ts @@ -31,33 +31,7 @@ const FRONT_END_HANDLER = { type KnownFrontEndErrorTexts = keyof typeof FRONT_END_HANDLER; -export function handleRegisterError(e: unknown) { - if (isAxiosError(e) && e.response?.status === 400) { - if (typeof e.response.data !== 'string') { - console.error('Unexpected error occured!'); - console.error('Unexpected error: ', e.response.data); - return 'Palvelin virhe!'; - } - const responseText = e.response.data.toLowerCase(); - const frontendText = - FRONT_END_HANDLER[responseText as KnownFrontEndErrorTexts]; - if (frontendText) { - console.error(frontendText); - return frontendText; - } else { - console.error('Unexpected error occured!'); - console.error('Unexpected error: ', e.response.data); - return 'Palvelin virhe!'; - } - } else if (e instanceof Error) { - console.error(e.message); - } else { - console.error(e); - } - return ''; -} - -export function handleLoginError(e: unknown) { +export function handleAuthErrors(e: unknown) { if (isAxiosError(e) && e.response?.status === 400) { if (typeof e.response.data !== 'string') { console.error('Unexpected error occured!'); From 994ca510fd1a3104731d7084ad22ce0a8481b13c Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 29 Apr 2024 16:12:50 +0300 Subject: [PATCH 099/125] Moved luciaLongSession to .auth file --- backend/auth.ts | 26 ++++++++++++++++++++++++++ pages/api/auth/login.ts | 16 +++++----------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/backend/auth.ts b/backend/auth.ts index 475e9d2..b5a23ab 100644 --- a/backend/auth.ts +++ b/backend/auth.ts @@ -33,6 +33,32 @@ export const lucia = new Lucia(adapter, { }, }); +export const luciaLongSession = new Lucia(adapter, { + sessionExpiresIn: new TimeSpan(30, 'd'), + sessionCookie: { + attributes: { + secure: process.env.NODE_ENV === 'production', + }, + }, + getUserAttributes({ + createdAt, + email, + firstName, + lastName, + updatedAt, + uuid, + }: User): User { + return { + uuid: uuid, + firstName: firstName, + lastName: lastName, + email: email, + createdAt: createdAt, + updatedAt: updatedAt, + }; + }, +}); + declare module 'lucia' { interface Register { Lucia: typeof lucia; diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts index f12cb39..de1eebc 100644 --- a/pages/api/auth/login.ts +++ b/pages/api/auth/login.ts @@ -1,21 +1,15 @@ import type { NextApiRequest, NextApiResponse } from 'next'; -import { adapter, lucia as luciaShortSession } from '~/backend/auth'; +import { + adapter, + luciaLongSession, + lucia as luciaShortSession, +} from '~/backend/auth'; import { handleError } from '~/backend/handleError'; import { HttpError } from '~/backend/HttpError'; import { UserLoginDetails } from '~/shared/types'; import { verifyPassword } from '~/backend/utils'; import { isEmailValid, isPasswordValid } from '~/shared/isValidFunctions'; import prisma from '~/prisma'; -import { Lucia, TimeSpan } from 'lucia'; - -const luciaLongSession = new Lucia(adapter, { - sessionExpiresIn: new TimeSpan(30, 'd'), - sessionCookie: { - attributes: { - secure: process.env.NODE_ENV === 'production', - }, - }, -}); export default async function handleR( req: NextApiRequest, From 5d5d95e0180f89b8dc7125cd37d7759f0c28db0a Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 29 Apr 2024 21:48:03 +0300 Subject: [PATCH 100/125] Changed shortLuciaSession to be 1 hour instead of 14 days --- backend/auth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/auth.ts b/backend/auth.ts index b5a23ab..a542b0d 100644 --- a/backend/auth.ts +++ b/backend/auth.ts @@ -8,7 +8,7 @@ import type { Session } from 'lucia'; export const adapter = new PrismaAdapter(prisma.session, prisma.user); export const lucia = new Lucia(adapter, { - sessionExpiresIn: new TimeSpan(14, 'd'), + sessionExpiresIn: new TimeSpan(1, 'h'), sessionCookie: { attributes: { secure: process.env.NODE_ENV === 'production', From a1c770b1487185b10b2281e705a8d806bac23a12 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 2 May 2024 00:30:29 +0300 Subject: [PATCH 101/125] Created a new file getServerSideProps --- utils/getServerSideProps.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 utils/getServerSideProps.ts diff --git a/utils/getServerSideProps.ts b/utils/getServerSideProps.ts new file mode 100644 index 0000000..986e971 --- /dev/null +++ b/utils/getServerSideProps.ts @@ -0,0 +1,23 @@ +import { GetServerSidePropsContext, GetServerSidePropsResult } from 'next'; +import { validateRequest } from '~/backend/auth'; +import { User } from '~/shared/types'; + +export async function getServerSideProps( + context: GetServerSidePropsContext, + customDestination?: string, +): Promise> { + const cookieData = await validateRequest(context.req, context.res); + if (!cookieData.user) { + return { + redirect: { + permanent: false, + destination: customDestination || '/login', + }, + }; + } + return { + props: { + user: JSON.parse(JSON.stringify(cookieData.user)) as User, + }, + }; +} From a7861a1f704178dbe0e613fe4df31f0b2646878c Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 2 May 2024 00:31:22 +0300 Subject: [PATCH 102/125] Changes to backend/auth.ts file --- backend/auth.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/backend/auth.ts b/backend/auth.ts index a542b0d..9fe28e1 100644 --- a/backend/auth.ts +++ b/backend/auth.ts @@ -2,7 +2,7 @@ import { PrismaAdapter } from '@lucia-auth/adapter-prisma'; import type { IncomingMessage, ServerResponse } from 'http'; import { Lucia, TimeSpan } from 'lucia'; import prisma from '~/prisma'; -import type { CreateSession, User } from '~/shared/types'; +import type { PrismaUser, User } from '~/shared/types'; import type { Session } from 'lucia'; export const adapter = new PrismaAdapter(prisma.session, prisma.user); @@ -62,12 +62,9 @@ export const luciaLongSession = new Lucia(adapter, { declare module 'lucia' { interface Register { Lucia: typeof lucia; - DatabaseUserAttributes: DatabaseUserAttributes; - DatabaseSessionAttributes: DatabaseSessionAttributes; + DatabaseUserAttributes: PrismaUser; } } -interface DatabaseUserAttributes extends User {} -interface DatabaseSessionAttributes extends CreateSession {} export async function validateRequest( req: IncomingMessage, From 1d87410c9810a4792d59328214db89973df25fbc Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 2 May 2024 00:31:58 +0300 Subject: [PATCH 103/125] Debugging --- pages/index.tsx | 17 ++++++++++++++--- pages/login.tsx | 8 +++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index 6a7a29b..78309e6 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -17,7 +17,9 @@ import axios from 'axios'; import { useRouter } from 'next/router'; import SvgUser from '~/icons/user'; import SvgArrowRightStartOnRectangle from '~/icons/arrow_right_start_on_rectangle'; - +import { getServerSideProps } from '~/utils/getServerSideProps'; +export { getServerSideProps }; +/* export async function getServerSideProps( context: GetServerSidePropsContext, ): Promise> { @@ -36,6 +38,7 @@ export async function getServerSideProps( }, }; } +*/ export default function Home({ user, @@ -57,6 +60,7 @@ export default function Home({ useEffect(() => { console.log('effect'); + console.log(user); async function fetchGifts() { try { const gifts = await getAllGifts(); @@ -257,8 +261,15 @@ function UserDetailModal({ closeUserWindow: () => void; }) { async function handleLogout() { - const request = await axios.post('/api/auth/logout'); - if (request) window.location.href = '/login'; + try { + const request = await axios.post('/api/auth/logout'); + if (request) { + window.location.href = '/login'; + } + } catch (e) { + console.error(e); + window.location.href = '/'; + } } if (user && showUserWindow) { diff --git a/pages/login.tsx b/pages/login.tsx index fb533c7..487df5c 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -13,16 +13,13 @@ import { isEmailValid } from '~/shared/isValidFunctions'; import { User, UserLoginDetails } from '~/shared/types'; import { handleAuthErrors } from '~/utils/handleError'; +/* export async function getServerSideProps( context: GetServerSidePropsContext, ): Promise }>> { const cookieData = await validateRequest(context.req, context.res); if (!cookieData.user) { - return { - props: { - user: {}, - }, - }; + return; } return { redirect: { @@ -31,6 +28,7 @@ export async function getServerSideProps( }, }; } +*/ export default function Login() { const [email, setEmail] = useState(''); From c74d47a0617d297982d7beec3df98ba34c81158a Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 6 May 2024 16:02:45 +0300 Subject: [PATCH 104/125] Added export types --- shared/types.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/shared/types.ts b/shared/types.ts index 06e9045..52796e9 100644 --- a/shared/types.ts +++ b/shared/types.ts @@ -24,3 +24,9 @@ export type CreateSession = Omit< > & { user: Prisma.UserCreateNestedOneWithoutSessionInput; }; + +export type { + Gift as PrismaGift, + User as PrismaUser, + Session as PrismaSession, +} from '@prisma/client'; From 0766e188d6444d39225209496bd952d349dffedd Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 6 May 2024 16:03:59 +0300 Subject: [PATCH 105/125] Imported User as LuciaUser from lucia module --- backend/auth.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/auth.ts b/backend/auth.ts index 9fe28e1..320b86d 100644 --- a/backend/auth.ts +++ b/backend/auth.ts @@ -3,7 +3,7 @@ import type { IncomingMessage, ServerResponse } from 'http'; import { Lucia, TimeSpan } from 'lucia'; import prisma from '~/prisma'; import type { PrismaUser, User } from '~/shared/types'; -import type { Session } from 'lucia'; +import type { Session, User as LuciaUser } from 'lucia'; export const adapter = new PrismaAdapter(prisma.session, prisma.user); @@ -69,7 +69,9 @@ declare module 'lucia' { export async function validateRequest( req: IncomingMessage, res: ServerResponse, -): Promise<{ user: User; session: Session } | { user: null; session: null }> { +): Promise< + { user: LuciaUser; session: Session } | { user: null; session: null } +> { const sessionId = lucia.readSessionCookie(req.headers.cookie ?? ''); if (!sessionId) { return { From d5a4543ec396590fe4ce2f269d58770296ead6ab Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 6 May 2024 16:04:56 +0300 Subject: [PATCH 106/125] Removed as statement in pages/register.tsx --- pages/register.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/register.tsx b/pages/register.tsx index 99ce222..101245e 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -42,7 +42,7 @@ export default function Register() { firstName: firstName, lastName: lastName, password: password, - } as CreateUser); + }); userCreatedSuccesfully(); } catch (e) { const errorText = handleAuthErrors(e); From 7d85f3f2dd707e552b8f911714ca38e4b006d972 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 6 May 2024 16:13:26 +0300 Subject: [PATCH 107/125] Added a new variable SvgEye to determine which SVG icon will be shown. Added this both in pages/register.tsx and pages/login.tsx --- pages/login.tsx | 23 ++++++++--------------- pages/register.tsx | 23 ++++++++--------------- 2 files changed, 16 insertions(+), 30 deletions(-) diff --git a/pages/login.tsx b/pages/login.tsx index 487df5c..ec01378 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -59,6 +59,8 @@ export default function Login() { } } + const SvgEye = showPassword ? SvgEyeSlash : SvgEyeOpen; + return (
@@ -99,21 +101,12 @@ export default function Login() { name="password" />
- {showPassword ? ( - { - setShowPassword((prevValue) => !prevValue); - }} - /> - ) : ( - { - setShowPassword((prevValue) => !prevValue); - }} - /> - )} + { + setShowPassword((prevValue) => !prevValue); + }} + />
diff --git a/pages/register.tsx b/pages/register.tsx index 101245e..62167bd 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -143,6 +143,8 @@ export default function Register() { return true; } + const SvgEye = showPassword ? SvgEyeSlash : SvgEyeOpen; + return (
@@ -207,21 +209,12 @@ export default function Register() { name="password" />
- {showPassword ? ( - { - setShowPassword((prevValue) => !prevValue); - }} - /> - ) : ( - { - setShowPassword((prevValue) => !prevValue); - }} - /> - )} + { + setShowPassword((prevValue) => !prevValue); + }} + />
From 58133a12e95f0b5205e741723ddfdb25d815ad8f Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 10 May 2024 17:21:15 +0300 Subject: [PATCH 108/125] Edited getServerSideProps in login.tsx to not get the return an object error, works for now --- pages/login.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pages/login.tsx b/pages/login.tsx index ec01378..1d3d1a1 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -13,13 +13,12 @@ import { isEmailValid } from '~/shared/isValidFunctions'; import { User, UserLoginDetails } from '~/shared/types'; import { handleAuthErrors } from '~/utils/handleError'; -/* -export async function getServerSideProps( - context: GetServerSidePropsContext, -): Promise }>> { +export async function getServerSideProps(context: GetServerSidePropsContext) { const cookieData = await validateRequest(context.req, context.res); if (!cookieData.user) { - return; + return { + props: {}, + }; } return { redirect: { @@ -28,7 +27,6 @@ export async function getServerSideProps( }, }; } -*/ export default function Login() { const [email, setEmail] = useState(''); From d8e4758a5f756b3c70f9bfef45656be870aa8374 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 10 May 2024 20:08:30 +0300 Subject: [PATCH 109/125] Removed commented getServerSideProps function --- pages/index.tsx | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index 78309e6..4f22be3 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -19,26 +19,6 @@ import SvgUser from '~/icons/user'; import SvgArrowRightStartOnRectangle from '~/icons/arrow_right_start_on_rectangle'; import { getServerSideProps } from '~/utils/getServerSideProps'; export { getServerSideProps }; -/* -export async function getServerSideProps( - context: GetServerSidePropsContext, -): Promise> { - const cookieData = await validateRequest(context.req, context.res); - if (!cookieData.user) { - return { - redirect: { - permanent: false, - destination: '/login', - }, - }; - } - return { - props: { - user: JSON.parse(JSON.stringify(cookieData.user)) as User, - }, - }; -} -*/ export default function Home({ user, @@ -60,7 +40,6 @@ export default function Home({ useEffect(() => { console.log('effect'); - console.log(user); async function fetchGifts() { try { const gifts = await getAllGifts(); From 2bf07663a7399b135fdbff6793455484c6466120 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 10 May 2024 20:09:15 +0300 Subject: [PATCH 110/125] Made code easier to read --- backend/auth.ts | 38 ++++++-------------------------------- 1 file changed, 6 insertions(+), 32 deletions(-) diff --git a/backend/auth.ts b/backend/auth.ts index 320b86d..1d40ea8 100644 --- a/backend/auth.ts +++ b/backend/auth.ts @@ -14,22 +14,9 @@ export const lucia = new Lucia(adapter, { secure: process.env.NODE_ENV === 'production', }, }, - getUserAttributes({ - createdAt, - email, - firstName, - lastName, - updatedAt, - uuid, - }: User): User { - return { - uuid: uuid, - firstName: firstName, - lastName: lastName, - email: email, - createdAt: createdAt, - updatedAt: updatedAt, - }; + getUserAttributes(user): User { + const { uuid, firstName, lastName, email, createdAt, updatedAt } = user; + return { uuid, firstName, lastName, email, createdAt, updatedAt }; }, }); @@ -40,22 +27,9 @@ export const luciaLongSession = new Lucia(adapter, { secure: process.env.NODE_ENV === 'production', }, }, - getUserAttributes({ - createdAt, - email, - firstName, - lastName, - updatedAt, - uuid, - }: User): User { - return { - uuid: uuid, - firstName: firstName, - lastName: lastName, - email: email, - createdAt: createdAt, - updatedAt: updatedAt, - }; + getUserAttributes(user): User { + const { uuid, firstName, lastName, email, createdAt, updatedAt } = user; + return { uuid, firstName, lastName, email, createdAt, updatedAt }; }, }); From 318e45cc9f449aa4ae8edc66ca2dbc07ea362fdd Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 10 May 2024 20:10:08 +0300 Subject: [PATCH 111/125] Removed customDestination parameter. Removed an as statement --- utils/getServerSideProps.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/utils/getServerSideProps.ts b/utils/getServerSideProps.ts index 986e971..9d1452e 100644 --- a/utils/getServerSideProps.ts +++ b/utils/getServerSideProps.ts @@ -4,14 +4,13 @@ import { User } from '~/shared/types'; export async function getServerSideProps( context: GetServerSidePropsContext, - customDestination?: string, ): Promise> { const cookieData = await validateRequest(context.req, context.res); if (!cookieData.user) { return { redirect: { permanent: false, - destination: customDestination || '/login', + destination: '/login', }, }; } From 1c4c157b88abbaee93c60fc003f67f4c5ee9c70e Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 10 May 2024 20:17:14 +0300 Subject: [PATCH 112/125] ESLint fixes --- pages/api/auth/login.ts | 6 +----- pages/index.tsx | 11 ++--------- pages/login.tsx | 4 ++-- pages/register.tsx | 1 - 4 files changed, 5 insertions(+), 17 deletions(-) diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts index de1eebc..49c7834 100644 --- a/pages/api/auth/login.ts +++ b/pages/api/auth/login.ts @@ -1,9 +1,5 @@ import type { NextApiRequest, NextApiResponse } from 'next'; -import { - adapter, - luciaLongSession, - lucia as luciaShortSession, -} from '~/backend/auth'; +import { luciaLongSession, lucia as luciaShortSession } from '~/backend/auth'; import { handleError } from '~/backend/handleError'; import { HttpError } from '~/backend/HttpError'; import { UserLoginDetails } from '~/shared/types'; diff --git a/pages/index.tsx b/pages/index.tsx index 4f22be3..9f114b3 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -7,17 +7,12 @@ import { EditModal } from '~/components/EditModal'; import { createGift, getAllGifts } from '~/utils/apiRequests'; import { Gift, CreateGift, User } from '~/shared/types'; import { handleGeneralError } from '~/utils/handleError'; -import { - GetServerSidePropsContext, - GetServerSidePropsResult, - InferGetServerSidePropsType, -} from 'next'; -import { validateRequest } from '~/backend/auth'; +import { InferGetServerSidePropsType } from 'next'; import axios from 'axios'; -import { useRouter } from 'next/router'; import SvgUser from '~/icons/user'; import SvgArrowRightStartOnRectangle from '~/icons/arrow_right_start_on_rectangle'; import { getServerSideProps } from '~/utils/getServerSideProps'; + export { getServerSideProps }; export default function Home({ @@ -36,8 +31,6 @@ export default function Home({ const [editModalGiftData, setEditModalGiftData] = useState(); const [showUserWindow, setShowUserWindow] = useState(false); - const router = useRouter(); - useEffect(() => { console.log('effect'); async function fetchGifts() { diff --git a/pages/login.tsx b/pages/login.tsx index 1d3d1a1..a33e80c 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -1,5 +1,5 @@ import axios from 'axios'; -import { GetServerSidePropsContext, GetServerSidePropsResult } from 'next'; +import { GetServerSidePropsContext } from 'next'; import Link from 'next/link'; import { useRouter } from 'next/router'; import { FormEvent, useState } from 'react'; @@ -10,7 +10,7 @@ import { TitleText } from '~/components/TitleText'; import SvgEyeOpen from '~/icons/eye_open'; import SvgEyeSlash from '~/icons/eye_slash'; import { isEmailValid } from '~/shared/isValidFunctions'; -import { User, UserLoginDetails } from '~/shared/types'; +import { UserLoginDetails } from '~/shared/types'; import { handleAuthErrors } from '~/utils/handleError'; export async function getServerSideProps(context: GetServerSidePropsContext) { diff --git a/pages/register.tsx b/pages/register.tsx index 62167bd..c997c30 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -8,7 +8,6 @@ import { Input } from '~/components/Input'; import { Modal } from '~/components/Modal'; import { TitleText } from '~/components/TitleText'; import { SvgCheckMarkIcon } from '~/icons/CheckMarkIcon'; -import type { CreateUser } from '~/shared/types'; import { handleAuthErrors } from '~/utils/handleError'; import { emailRegex, passwordRegex } from '~/shared/regexPatterns'; import SvgEyeOpen from '~/icons/eye_open'; From 22ac78b073cf726394278ee6526ba7cba1bba241 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Fri, 10 May 2024 20:25:29 +0300 Subject: [PATCH 113/125] Rewrote isValidFunctions.ts isEmailValid function --- shared/isValidFunctions.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/shared/isValidFunctions.ts b/shared/isValidFunctions.ts index edb329d..34d567c 100644 --- a/shared/isValidFunctions.ts +++ b/shared/isValidFunctions.ts @@ -4,14 +4,11 @@ export function isEmailValid(email: string): boolean { if (email.length <= 0) { return false; } - // this should check with regex that there cannot be multiple dots etc - const checkedEmailAddress = email.toLowerCase().match(emailRegex); - if (!checkedEmailAddress) { + if (!email.toLowerCase().match(emailRegex)) { return false; } - // email is ready to be used return true; } From 508d84a81534d38171c78765303f33ebd96c621d Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 13 May 2024 15:20:17 +0300 Subject: [PATCH 114/125] Added a check to only return the gifts the requester has an access to. Added a new parameter userData that contains requester's data (id, uuid, etc...) --- pages/api/gifts/index.ts | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/pages/api/gifts/index.ts b/pages/api/gifts/index.ts index 0007eb6..860607f 100644 --- a/pages/api/gifts/index.ts +++ b/pages/api/gifts/index.ts @@ -3,10 +3,16 @@ import { CreateGift, Gift } from '~/shared/types'; import prisma from '~/prisma'; import { handleError } from '~/backend/handleError'; import { HttpError } from '~/backend/HttpError'; +import { validateRequest } from '~/backend/auth'; +import { User as LuciaUser } from 'lucia'; const HANDLER: Record< string, - (req: NextApiRequest, res: NextApiResponse) => Promise + ( + req: NextApiRequest, + res: NextApiResponse, + userData: LuciaUser, + ) => Promise > = { GET: handleGET, POST: handlePOST, @@ -17,9 +23,13 @@ export default async function handlePrisma( res: NextApiResponse, ) { try { + const validationRequest = await validateRequest(req, res); + if (!validationRequest.session || !validationRequest.user) { + throw new HttpError('You are unauthorized!', 401); + } const reqHandler = req.method !== undefined && HANDLER[req.method]; if (reqHandler) { - await reqHandler(req, res); + await reqHandler(req, res, validationRequest.user); } else { throw new HttpError( `${req.method} is not a valid method. Only GET and POST requests are valid!`, @@ -31,7 +41,11 @@ export default async function handlePrisma( } } -async function handleGET(req: NextApiRequest, res: NextApiResponse) { +async function handleGET( + req: NextApiRequest, + res: NextApiResponse, + userData: LuciaUser, +) { const gifts = await prisma.gift.findMany({ select: { createdAt: true, @@ -40,17 +54,29 @@ async function handleGET(req: NextApiRequest, res: NextApiResponse) { updatedAt: true, uuid: true, }, + where: { + userUUID: userData.uuid, + }, }); return res.status(200).json(gifts); } -async function handlePOST(req: NextApiRequest, res: NextApiResponse) { +async function handlePOST( + req: NextApiRequest, + res: NextApiResponse, + userData: LuciaUser, +) { const giftData = req.body as CreateGift; const addedGift = await prisma.gift.create({ data: { gift: giftData.gift, receiver: giftData.receiver, + user: { + connect: { + uuid: userData.uuid, + }, + }, }, select: { createdAt: true, From 9c973aca49f5301efd41836e8500cc8c81f8533d Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 13 May 2024 15:26:26 +0300 Subject: [PATCH 115/125] Added a check to only return the gifts, allow updating the gift and deleting the gift that the requester has an access to. Changed queryUUID to giftUUID and added userData parameter to get user's id and uuid and so on --- pages/api/gifts/[uuid].ts | 67 ++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/pages/api/gifts/[uuid].ts b/pages/api/gifts/[uuid].ts index 52d348a..15a04e2 100644 --- a/pages/api/gifts/[uuid].ts +++ b/pages/api/gifts/[uuid].ts @@ -3,11 +3,14 @@ import { NextApiRequest, NextApiResponse } from 'next'; import prisma from '~/prisma'; import { handleError } from '~/backend/handleError'; import { HttpError } from '~/backend/HttpError'; +import { validateRequest } from '~/backend/auth'; +import { User as LuciaUser } from 'lucia'; type HandlerParams = { req: NextApiRequest; res: NextApiResponse; - queryUUID: string; + giftUUID: string; + userData: LuciaUser; }; const HANDLERS: Record Promise> = { @@ -22,13 +25,24 @@ export default async function handlePrisma( res: NextApiResponse, ) { try { + const validationRequest = await validateRequest(req, res); + if (!validationRequest.session || !validationRequest.user) { + throw new HttpError('You are unauthorized!', 401); + } + const userData = validationRequest.user; + console.log(userData); const reqHandler = req.method !== undefined && HANDLERS[req.method]; if (reqHandler) { if (typeof req.query.uuid !== 'string') { throw new HttpError('Invalid ID', 400); } - const queryUUID = req.query.uuid; - await reqHandler({ req, res, queryUUID }); + const giftUUID = req.query.uuid; + await reqHandler({ + req, + res, + giftUUID, + userData, + }); } else { throw new HttpError( `${req.method} is not a valid method. GET, PATCH, PUT and DELETE request are valid.`, @@ -40,10 +54,15 @@ export default async function handlePrisma( } } -async function handleGET({ res, queryUUID }: HandlerParams) { +async function handleGET({ res, giftUUID, userData }: HandlerParams) { const gift = await prisma.gift.findUniqueOrThrow({ where: { - uuid: queryUUID, + uuid: giftUUID, + AND: { + user: { + uuid: userData.uuid, + }, + }, }, select: { createdAt: true, @@ -53,15 +72,26 @@ async function handleGET({ res, queryUUID }: HandlerParams) { uuid: true, }, }); + console.log(gift, 'asdasd'); return res.status(200).json(gift); } -async function handlePATCH({ req, res, queryUUID }: HandlerParams) { +async function handlePATCH({ + req, + res, + giftUUID, + userData, +}: HandlerParams) { const newGiftData = req.body as Gift; const updatedGift = await prisma.gift.update({ where: { - uuid: queryUUID, + uuid: giftUUID, + AND: { + user: { + uuid: userData.uuid, + }, + }, }, data: { receiver: newGiftData.receiver, @@ -79,12 +109,22 @@ async function handlePATCH({ req, res, queryUUID }: HandlerParams) { return res.status(200).json(updatedGift); } -async function handlePUT({ req, res, queryUUID }: HandlerParams) { +async function handlePUT({ + req, + res, + giftUUID, + userData, +}: HandlerParams) { const newGiftData = req.body as Gift; const updatedGift = await prisma.gift.update({ where: { - uuid: queryUUID, + uuid: giftUUID, + AND: { + user: { + uuid: userData.uuid, + }, + }, }, data: newGiftData, select: { @@ -99,10 +139,15 @@ async function handlePUT({ req, res, queryUUID }: HandlerParams) { return res.status(200).json(updatedGift); } -async function handleDELETE({ res, queryUUID }: HandlerParams) { +async function handleDELETE({ res, giftUUID, userData }: HandlerParams) { await prisma.gift.delete({ where: { - uuid: queryUUID, + uuid: giftUUID, + AND: { + user: { + uuid: userData.uuid, + }, + }, }, }); From efc91710fa24a828d836c6a0b276b4c1b977c20c Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Mon, 13 May 2024 15:30:24 +0300 Subject: [PATCH 116/125] Removed debugging console.logs --- pages/api/gifts/[uuid].ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/pages/api/gifts/[uuid].ts b/pages/api/gifts/[uuid].ts index 15a04e2..6cc6c10 100644 --- a/pages/api/gifts/[uuid].ts +++ b/pages/api/gifts/[uuid].ts @@ -30,7 +30,6 @@ export default async function handlePrisma( throw new HttpError('You are unauthorized!', 401); } const userData = validationRequest.user; - console.log(userData); const reqHandler = req.method !== undefined && HANDLERS[req.method]; if (reqHandler) { if (typeof req.query.uuid !== 'string') { @@ -72,7 +71,6 @@ async function handleGET({ res, giftUUID, userData }: HandlerParams) { uuid: true, }, }); - console.log(gift, 'asdasd'); return res.status(200).json(gift); } From 1f6afac2ae8adcfae4fce7507ae68a1c9364014a Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Wed, 15 May 2024 15:24:15 +0300 Subject: [PATCH 117/125] Re-positioned Gift, User, Session export --- shared/types.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/shared/types.ts b/shared/types.ts index 52796e9..04bf3db 100644 --- a/shared/types.ts +++ b/shared/types.ts @@ -1,4 +1,9 @@ import { Prisma, Gift as PrismaGift, User as PrismaUser } from '@prisma/client'; +export type { + Gift as PrismaGift, + User as PrismaUser, + Session as PrismaSession, +} from '@prisma/client'; export type Gift = Omit; export type CreateGift = Omit< @@ -24,9 +29,3 @@ export type CreateSession = Omit< > & { user: Prisma.UserCreateNestedOneWithoutSessionInput; }; - -export type { - Gift as PrismaGift, - User as PrismaUser, - Session as PrismaSession, -} from '@prisma/client'; From db064d0ffcf52adb858aac7aa41666098237533a Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Wed, 15 May 2024 17:24:43 +0300 Subject: [PATCH 118/125] Reverting the removal of userId in Session model inside schema.prisma file From ef0882faa3fc9b6cd85879286858886ddd1c5884 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Wed, 15 May 2024 18:12:45 +0300 Subject: [PATCH 119/125] Added DatabaseSessionAttributes to have string value called userUUID --- backend/auth.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/auth.ts b/backend/auth.ts index 1d40ea8..5dfcb04 100644 --- a/backend/auth.ts +++ b/backend/auth.ts @@ -37,6 +37,7 @@ declare module 'lucia' { interface Register { Lucia: typeof lucia; DatabaseUserAttributes: PrismaUser; + DatabaseSessionAttributes: { userUUID: string }; } } From 724178ad92514b8fa0d1aecd1fe5e7e7cc7301fc Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Wed, 15 May 2024 18:14:58 +0300 Subject: [PATCH 120/125] Changed variable userCreationRequest to be userData. Replaced the connect method while creating a session --- pages/api/auth/register.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/pages/api/auth/register.ts b/pages/api/auth/register.ts index 661c4cc..ed8d47d 100644 --- a/pages/api/auth/register.ts +++ b/pages/api/auth/register.ts @@ -18,19 +18,15 @@ export default async function handler( throw new HttpError('Invalid request body!', 400); } - const userCreationRequest = await createUser({ + const userData = await createUser({ email: email, firstName: firstName, lastName: lastName, password: password, }); - const session = await lucia.createSession(userCreationRequest.uuid, { - user: { - connect: { - uuid: userCreationRequest.uuid, - }, - }, + const session = await lucia.createSession(userData.uuid, { + userUUID: userData.uuid, }); res .appendHeader( From 7e9373bcdeb84223b3e256749e41e6d798077603 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Wed, 15 May 2024 18:16:57 +0300 Subject: [PATCH 121/125] Replaced AND statments with a better solution --- pages/api/gifts/[uuid].ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/pages/api/gifts/[uuid].ts b/pages/api/gifts/[uuid].ts index 6cc6c10..244e112 100644 --- a/pages/api/gifts/[uuid].ts +++ b/pages/api/gifts/[uuid].ts @@ -85,11 +85,7 @@ async function handlePATCH({ const updatedGift = await prisma.gift.update({ where: { uuid: giftUUID, - AND: { - user: { - uuid: userData.uuid, - }, - }, + userUUID: userData.uuid, }, data: { receiver: newGiftData.receiver, @@ -118,11 +114,7 @@ async function handlePUT({ const updatedGift = await prisma.gift.update({ where: { uuid: giftUUID, - AND: { - user: { - uuid: userData.uuid, - }, - }, + userUUID: userData.uuid, }, data: newGiftData, select: { From 135dfe597c2437c7ad26a979e91edfb67c80b35b Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Wed, 15 May 2024 18:17:50 +0300 Subject: [PATCH 122/125] Replaced connects with a better solution --- pages/api/auth/login.ts | 6 +----- pages/api/gifts/index.ts | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts index 49c7834..5e590a5 100644 --- a/pages/api/auth/login.ts +++ b/pages/api/auth/login.ts @@ -67,11 +67,7 @@ export default async function handleR( } const session = await lucia.createSession(userData.uuid, { - user: { - connect: { - uuid: userData.uuid, - }, - }, + userUUID: userData.uuid, }); res diff --git a/pages/api/gifts/index.ts b/pages/api/gifts/index.ts index 860607f..b427dec 100644 --- a/pages/api/gifts/index.ts +++ b/pages/api/gifts/index.ts @@ -72,11 +72,7 @@ async function handlePOST( data: { gift: giftData.gift, receiver: giftData.receiver, - user: { - connect: { - uuid: userData.uuid, - }, - }, + userUUID: userData.uuid, }, select: { createdAt: true, From 7e4a63a223ca2323b2b25d01e29a43d1fab12bb4 Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 16 May 2024 14:27:53 +0300 Subject: [PATCH 123/125] Fixed handleDELETE to not use AND statement in pages/api/gifts/[uuid].ts" --- pages/api/gifts/[uuid].ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pages/api/gifts/[uuid].ts b/pages/api/gifts/[uuid].ts index 244e112..20b2ce7 100644 --- a/pages/api/gifts/[uuid].ts +++ b/pages/api/gifts/[uuid].ts @@ -133,11 +133,7 @@ async function handleDELETE({ res, giftUUID, userData }: HandlerParams) { await prisma.gift.delete({ where: { uuid: giftUUID, - AND: { - user: { - uuid: userData.uuid, - }, - }, + userUUID: userData.uuid, }, }); From bb966a58e88a3bf36f6839cd6e82d7729893729a Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 16 May 2024 14:29:36 +0300 Subject: [PATCH 124/125] Fixed import/newline-after-import error --- shared/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/types.ts b/shared/types.ts index 04bf3db..d790e46 100644 --- a/shared/types.ts +++ b/shared/types.ts @@ -1,4 +1,5 @@ import { Prisma, Gift as PrismaGift, User as PrismaUser } from '@prisma/client'; + export type { Gift as PrismaGift, User as PrismaUser, From 57a8e30cbf23e15b3cd9b4e877cdb391eb5a67ef Mon Sep 17 00:00:00 2001 From: Antti Asmala Date: Thu, 16 May 2024 15:04:04 +0300 Subject: [PATCH 125/125] Fixed handleGET to not use AND statement in /pages/api/gifts/[uuid].ts --- pages/api/gifts/[uuid].ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pages/api/gifts/[uuid].ts b/pages/api/gifts/[uuid].ts index 20b2ce7..95f9641 100644 --- a/pages/api/gifts/[uuid].ts +++ b/pages/api/gifts/[uuid].ts @@ -57,11 +57,7 @@ async function handleGET({ res, giftUUID, userData }: HandlerParams) { const gift = await prisma.gift.findUniqueOrThrow({ where: { uuid: giftUUID, - AND: { - user: { - uuid: userData.uuid, - }, - }, + userUUID: userData.uuid, }, select: { createdAt: true,