From a79497c4b591de27a79652802cf28a52d9545963 Mon Sep 17 00:00:00 2001 From: bkellam Date: Thu, 13 Feb 2025 19:13:09 -0800 Subject: [PATCH 1/2] email password functionality --- .../migration.sql | 3 + packages/db/prisma/schema.prisma | 40 ++--- .../(server)/auth/verifyCredentials/route.ts | 76 ++++++++++ .../src/app/login/components/loginForm.tsx | 137 ++++++++++++++++++ packages/web/src/app/login/page.tsx | 91 +----------- packages/web/src/auth.ts | 37 +++++ packages/web/src/lib/errorCodes.ts | 1 + packages/web/src/lib/schemas.ts | 13 ++ 8 files changed, 291 insertions(+), 107 deletions(-) create mode 100644 packages/db/prisma/migrations/20250214014146_add_encrypted_password_to_user/migration.sql create mode 100644 packages/web/src/app/api/(server)/auth/verifyCredentials/route.ts create mode 100644 packages/web/src/app/login/components/loginForm.tsx diff --git a/packages/db/prisma/migrations/20250214014146_add_encrypted_password_to_user/migration.sql b/packages/db/prisma/migrations/20250214014146_add_encrypted_password_to_user/migration.sql new file mode 100644 index 00000000..d8269f29 --- /dev/null +++ b/packages/db/prisma/migrations/20250214014146_add_encrypted_password_to_user/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "User" ADD COLUMN "encryptedPassword" TEXT, +ADD COLUMN "iv" TEXT; diff --git a/packages/db/prisma/schema.prisma b/packages/db/prisma/schema.prisma index 8c7e421d..7598230c 100644 --- a/packages/db/prisma/schema.prisma +++ b/packages/db/prisma/schema.prisma @@ -105,20 +105,20 @@ model Invite { } model Org { - id Int @id @default(autoincrement()) - name String - domain String @unique - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - members UserToOrg[] - connections Connection[] - repos Repo[] - secrets Secret[] - - stripeCustomerId String? + id Int @id @default(autoincrement()) + name String + domain String @unique + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + members UserToOrg[] + connections Connection[] + repos Repo[] + secrets Secret[] + + stripeCustomerId String? /// List of pending invites to this organization - invites Invite[] + invites Invite[] } enum OrgRole { @@ -157,13 +157,15 @@ model Secret { // @see : https://authjs.dev/concepts/database-models#user model User { - id String @id @default(cuid()) - name String? - email String? @unique - emailVerified DateTime? - image String? - accounts Account[] - orgs UserToOrg[] + id String @id @default(cuid()) + name String? + email String? @unique + encryptedPassword String? + iv String? + emailVerified DateTime? + image String? + accounts Account[] + orgs UserToOrg[] /// List of pending invites that the user has created invites Invite[] diff --git a/packages/web/src/app/api/(server)/auth/verifyCredentials/route.ts b/packages/web/src/app/api/(server)/auth/verifyCredentials/route.ts new file mode 100644 index 00000000..5b695b90 --- /dev/null +++ b/packages/web/src/app/api/(server)/auth/verifyCredentials/route.ts @@ -0,0 +1,76 @@ +import { ErrorCode } from "@/lib/errorCodes"; +import { verifyCredentialsRequestSchema } from "@/lib/schemas"; +import { schemaValidationError, serviceErrorResponse } from "@/lib/serviceError"; +import { prisma } from "@/prisma"; +import { decrypt, encrypt } from "@sourcebot/crypto"; +import { User as NextAuthUser } from "next-auth"; + +export const runtime = 'nodejs'; + +export async function POST(request: Request) { + const body = await request.json(); + const parsed = await verifyCredentialsRequestSchema.safeParseAsync(body); + + if (!parsed.success) { + return serviceErrorResponse( + schemaValidationError(parsed.error) + ) + } + + const { email, password } = parsed.data; + const user = await getOrCreateUser(email, password); + + if (!user) { + return serviceErrorResponse( + { + statusCode: 401, + errorCode: ErrorCode.INVALID_CREDENTIALS, + message: 'Invalid email or password', + } + ) + } + + return Response.json(user); +} + +async function getOrCreateUser(email: string, password: string): Promise { + const user = await prisma.user.findUnique({ + where: { email } + }); + + // The user doesn't exist, so create a new one. + if (!user) { + const { encryptedData, iv } = encrypt(password); + const newUser = await prisma.user.create({ + data: { + email, + encryptedPassword: encryptedData, + iv, + } + }); + + return { + id: newUser.id, + email: newUser.email, + } + + // Otherwise, the user exists, so verify the password. + } else { + if (!user.encryptedPassword || !user.iv) { + return null; + } + + const decryptedPassword = decrypt(user.iv, user.encryptedPassword); + if (decryptedPassword !== password) { + return null; + } + + return { + id: user.id, + email: user.email, + name: user.name ?? undefined, + image: user.image ?? undefined, + }; + } + +} \ No newline at end of file diff --git a/packages/web/src/app/login/components/loginForm.tsx b/packages/web/src/app/login/components/loginForm.tsx new file mode 100644 index 00000000..0c97b458 --- /dev/null +++ b/packages/web/src/app/login/components/loginForm.tsx @@ -0,0 +1,137 @@ +'use client'; + +import { Button } from "@/components/ui/button"; +import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; +import logoDark from "@/public/sb_logo_dark_large.png"; +import logoLight from "@/public/sb_logo_light_large.png"; +import githubLogo from "@/public/github.svg"; +import googleLogo from "@/public/google.svg"; +import Image from "next/image"; +import { signIn } from "next-auth/react"; +import { useCallback } from "react"; +import { useNonEmptyQueryParam } from "@/hooks/useNonEmptyQueryParam"; +import { verifyCredentialsRequestSchema } from "@/lib/schemas"; + +export const LoginForm = () => { + const callbackUrl = useNonEmptyQueryParam("callbackUrl"); + const error = useNonEmptyQueryParam("error"); + + const form = useForm>({ + resolver: zodResolver(verifyCredentialsRequestSchema), + defaultValues: { + email: "", + password: "", + }, + }); + + const onSignInWithEmailPassword = (values: z.infer) => { + signIn("credentials", { + email: values.email, + password: values.password, + redirectTo: callbackUrl ?? "/" + }); + } + + const onSignInWithOauth = useCallback((provider: string) => { + signIn(provider, { redirectTo: callbackUrl ?? "/" }); + }, [callbackUrl]); + + return ( +
+ {error && ( +
+ There was a problem when trying to authenticate. code: {error} +
+ )} +
+ {"Sourcebot + {"Sourcebot +
+ { + onSignInWithOauth("github") + }} + /> + { + onSignInWithOauth("google") + }} + /> +
+
+ or +
+
+
+
+ + ( + + Email + + + + + + )} + /> + ( + + Password + + + + + + )} + /> + + + +
+
+ ) +} + +const ProviderButton = ({ + name, + logo, + onClick, +}: { + name: string; + logo: string; + onClick: () => void; +}) => { + return ( + + ) +} \ No newline at end of file diff --git a/packages/web/src/app/login/page.tsx b/packages/web/src/app/login/page.tsx index f226673a..b4146bf1 100644 --- a/packages/web/src/app/login/page.tsx +++ b/packages/web/src/app/login/page.tsx @@ -1,94 +1,9 @@ -import { providerMap, signIn } from "@/auth" -import { AuthError } from "next-auth" -import { redirect } from "next/navigation" -import logoDark from "@/public/sb_logo_dark_large.png"; -import logoLight from "@/public/sb_logo_light_large.png"; -import githubLogo from "@/public/github.svg"; -import googleLogo from "@/public/google.svg"; -import Image from "next/image"; -import { Button } from "@/components/ui/button"; -const SIGNIN_ERROR_URL = "/login"; +import { LoginForm } from "./components/loginForm"; -export default async function Login(props: { - searchParams: { callbackUrl: string | undefined } -}) { +export default async function Login() { return (
-
-
- {"Sourcebot - {"Sourcebot -
- { - Object.values(providerMap) - .map((provider) => { - if (provider.id === "github") { - return { - provider, - logo: githubLogo, - } - } - - if (provider.id === "google") { - return { - provider, - logo: googleLogo, - } - } - - return { provider } - }) - .map(({ provider, logo }) => ( -
{ - "use server" - try { - await signIn(provider.id, { - redirectTo: props.searchParams?.callbackUrl ?? "/" - }) - } catch (error) { - // Signin can fail for a number of reasons, such as the user - // not existing, or the user not having the correct role. - // In some cases, you may want to redirect to a custom error - if (error instanceof AuthError) { - return redirect(`${SIGNIN_ERROR_URL}?error=${error.type}`) - } - - // Otherwise if a redirects happens Next.js can handle it - // so you can just re-thrown the error and let Next.js handle it. - // Docs: - // https://nextjs.org/docs/app/api-reference/functions/redirect#server-component - throw error - } - }} - > - -
- )) - } -
+
) } diff --git a/packages/web/src/auth.ts b/packages/web/src/auth.ts index 84063fbe..2d0afb9f 100644 --- a/packages/web/src/auth.ts +++ b/packages/web/src/auth.ts @@ -2,12 +2,16 @@ import 'next-auth/jwt'; import NextAuth, { DefaultSession } from "next-auth" import GitHub from "next-auth/providers/github" import Google from "next-auth/providers/google" +import Credentials from "next-auth/providers/credentials" import { PrismaAdapter } from "@auth/prisma-adapter" import { prisma } from "@/prisma"; import { AUTH_GITHUB_CLIENT_ID, AUTH_GITHUB_CLIENT_SECRET, AUTH_GOOGLE_CLIENT_ID, AUTH_GOOGLE_CLIENT_SECRET, AUTH_SECRET, AUTH_URL } from "./lib/environment"; import { User } from '@sourcebot/db'; import 'next-auth/jwt'; import type { Provider } from "next-auth/providers"; +import { verifyCredentialsRequestSchema, verifyCredentialsResponseSchema } from './lib/schemas'; + +export const runtime = 'nodejs'; declare module 'next-auth' { interface Session { @@ -32,6 +36,39 @@ const providers: Provider[] = [ clientId: AUTH_GOOGLE_CLIENT_ID, clientSecret: AUTH_GOOGLE_CLIENT_SECRET, }), + Credentials({ + credentials: { + email: {}, + password: {} + }, + type: "credentials", + authorize: async (credentials) => { + const body = verifyCredentialsRequestSchema.safeParse(credentials); + if (!body.success) { + return null; + } + const { email, password } = body.data; + + // authorize runs in the edge runtime (where we cannot make DB calls / access environment variables), + // so we need to make a request to the server to verify the credentials. + const response = await fetch(new URL('/api/auth/verifyCredentials', AUTH_URL), { + method: 'POST', + body: JSON.stringify({ email, password }), + }); + + if (!response.ok) { + return null; + } + + const user = verifyCredentialsResponseSchema.parse(await response.json()); + return { + id: user.id, + email: user.email, + name: user.name, + image: user.image, + } + } + }) ]; // @see: https://authjs.dev/guides/pages/signin diff --git a/packages/web/src/lib/errorCodes.ts b/packages/web/src/lib/errorCodes.ts index 5ac33d6d..f75b6c03 100644 --- a/packages/web/src/lib/errorCodes.ts +++ b/packages/web/src/lib/errorCodes.ts @@ -12,4 +12,5 @@ export enum ErrorCode { ORG_DOMAIN_ALREADY_EXISTS = 'ORG_DOMAIN_ALREADY_EXISTS', ORG_INVALID_SUBSCRIPTION = 'ORG_INVALID_SUBSCRIPTION', MEMBER_NOT_FOUND = 'MEMBER_NOT_FOUND', + INVALID_CREDENTIALS = 'INVALID_CREDENTIALS', } diff --git a/packages/web/src/lib/schemas.ts b/packages/web/src/lib/schemas.ts index d9d4b46f..06ae5b3e 100644 --- a/packages/web/src/lib/schemas.ts +++ b/packages/web/src/lib/schemas.ts @@ -162,3 +162,16 @@ export const listRepositoriesResponseSchema = z.object({ Stats: repoStatsSchema, }) }); + +export const verifyCredentialsRequestSchema = z.object({ + email: z.string().email(), + password: z.string().min(8), +}); + + +export const verifyCredentialsResponseSchema = z.object({ + id: z.string().optional(), + name: z.string().optional(), + email: z.string().optional(), + image: z.string().optional(), +}); From f991b6536c127462561ed6c96b676d72d7455a73 Mon Sep 17 00:00:00 2001 From: bkellam Date: Thu, 13 Feb 2025 21:35:24 -0800 Subject: [PATCH 2/2] feedback --- .../migration.sql | 3 - .../migration.sql | 2 + packages/db/prisma/schema.prisma | 3 +- packages/web/package.json | 2 + .../(server)/auth/verifyCredentials/route.ts | 12 +- .../src/app/login/components/loginForm.tsx | 18 +- yarn.lock | 215 +++++++++++++++++- 7 files changed, 235 insertions(+), 20 deletions(-) delete mode 100644 packages/db/prisma/migrations/20250214014146_add_encrypted_password_to_user/migration.sql create mode 100644 packages/db/prisma/migrations/20250214051339_add_hashed_password/migration.sql diff --git a/packages/db/prisma/migrations/20250214014146_add_encrypted_password_to_user/migration.sql b/packages/db/prisma/migrations/20250214014146_add_encrypted_password_to_user/migration.sql deleted file mode 100644 index d8269f29..00000000 --- a/packages/db/prisma/migrations/20250214014146_add_encrypted_password_to_user/migration.sql +++ /dev/null @@ -1,3 +0,0 @@ --- AlterTable -ALTER TABLE "User" ADD COLUMN "encryptedPassword" TEXT, -ADD COLUMN "iv" TEXT; diff --git a/packages/db/prisma/migrations/20250214051339_add_hashed_password/migration.sql b/packages/db/prisma/migrations/20250214051339_add_hashed_password/migration.sql new file mode 100644 index 00000000..3a8b10c8 --- /dev/null +++ b/packages/db/prisma/migrations/20250214051339_add_hashed_password/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "User" ADD COLUMN "hashedPassword" TEXT; diff --git a/packages/db/prisma/schema.prisma b/packages/db/prisma/schema.prisma index 7598230c..92bd0505 100644 --- a/packages/db/prisma/schema.prisma +++ b/packages/db/prisma/schema.prisma @@ -160,8 +160,7 @@ model User { id String @id @default(cuid()) name String? email String? @unique - encryptedPassword String? - iv String? + hashedPassword String? emailVerified DateTime? image String? accounts Account[] diff --git a/packages/web/package.json b/packages/web/package.json index a4f614f6..7e8cc0bb 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -74,6 +74,7 @@ "@viz-js/lang-dot": "^1.0.4", "@xiechao/codemirror-lang-handlebars": "^1.0.4", "ajv": "^8.17.1", + "bcrypt": "^5.1.1", "class-variance-authority": "^0.7.0", "client-only": "^0.0.1", "clsx": "^2.1.1", @@ -123,6 +124,7 @@ "zod": "^3.23.8" }, "devDependencies": { + "@types/bcrypt": "^5.0.2", "@types/node": "^20", "@types/psl": "^1.1.3", "@types/react": "^18", diff --git a/packages/web/src/app/api/(server)/auth/verifyCredentials/route.ts b/packages/web/src/app/api/(server)/auth/verifyCredentials/route.ts index 5b695b90..52320b7a 100644 --- a/packages/web/src/app/api/(server)/auth/verifyCredentials/route.ts +++ b/packages/web/src/app/api/(server)/auth/verifyCredentials/route.ts @@ -2,8 +2,8 @@ import { ErrorCode } from "@/lib/errorCodes"; import { verifyCredentialsRequestSchema } from "@/lib/schemas"; import { schemaValidationError, serviceErrorResponse } from "@/lib/serviceError"; import { prisma } from "@/prisma"; -import { decrypt, encrypt } from "@sourcebot/crypto"; import { User as NextAuthUser } from "next-auth"; +import bcrypt from 'bcrypt'; export const runtime = 'nodejs'; @@ -40,12 +40,11 @@ async function getOrCreateUser(email: string, password: string): Promise { signIn(provider, { redirectTo: callbackUrl ?? "/" }); }, [callbackUrl]); + const errorMessage = useMemo(() => { + if (!error) { + return ""; + } + switch (error) { + case "CredentialsSignin": + return "Invalid email or password. Please try again."; + case "OAuthAccountNotLinked": + return "This email is already associated with a different sign-in method."; + default: + return "An error occurred during authentication. Please try again."; + } + }, [error]); + return (
{error && (
- There was a problem when trying to authenticate. code: {error} + {errorMessage}
)}
diff --git a/yarn.lock b/yarn.lock index a4ede7e3..7309a8af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1121,6 +1121,21 @@ "@lezer/highlight" "^1.0.0" "@lezer/lr" "^1.4.0" +"@mapbox/node-pre-gyp@^1.0.11": + version "1.0.11" + resolved "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa" + integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ== + dependencies: + detect-libc "^2.0.0" + https-proxy-agent "^5.0.0" + make-dir "^3.1.0" + node-fetch "^2.6.7" + nopt "^5.0.0" + npmlog "^5.0.1" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.11" + "@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3": version "3.0.3" resolved "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz" @@ -2310,6 +2325,13 @@ resolved "https://registry.npmjs.org/@types/argparse/-/argparse-2.0.16.tgz" integrity sha512-aMqBra2JlqpFeCWOinCtpRpiCkPIXH8hahW2+FkGzvWjfE5sAqtOcrjN5DRcMnTQqFDe6gb1CVYuGnBH0lhXwA== +"@types/bcrypt@^5.0.2": + version "5.0.2" + resolved "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz#22fddc11945ea4fbc3655b3e8b8847cc9f811477" + integrity sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ== + dependencies: + "@types/node" "*" + "@types/braces@*": version "3.0.4" resolved "https://registry.npmjs.org/@types/braces/-/braces-3.0.4.tgz" @@ -2361,7 +2383,7 @@ dependencies: "@types/braces" "*" -"@types/node@>=8.1.0": +"@types/node@*", "@types/node@>=8.1.0": version "22.13.4" resolved "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz#3fe454d77cd4a2d73c214008b3e331bfaaf5038a" integrity sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg== @@ -2728,6 +2750,11 @@ "@lezer/lr" "^1.0.0" codemirror "^6.0.1" +abbrev@1: + version "1.1.1" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz" @@ -2745,6 +2772,13 @@ acorn@^8.9.0: resolved "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz" integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== +agent-base@6: + version "6.0.2" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + agent-base@^7.0.2, agent-base@^7.1.0: version "7.1.1" resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz" @@ -2814,6 +2848,19 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" +"aproba@^1.0.3 || ^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + arg@^5.0.2: version "5.0.2" resolved "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz" @@ -2988,6 +3035,14 @@ base64-js@^1.3.1: resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +bcrypt@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz#0f732c6dcb4e12e5b70a25e326a72965879ba6e2" + integrity sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww== + dependencies: + "@mapbox/node-pre-gyp" "^1.0.11" + node-addon-api "^5.0.0" + before-after-hook@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz" @@ -3163,6 +3218,11 @@ chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + class-variance-authority@^0.7.0: version "0.7.0" resolved "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz" @@ -3404,6 +3464,11 @@ color-string@^1.6.0, color-string@^1.9.0: color-name "^1.0.0" simple-swizzle "^0.2.2" +color-support@^1.1.2: + version "1.1.3" + resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + color@^3.1.3: version "3.2.1" resolved "https://registry.npmjs.org/color/-/color-3.2.1.tgz" @@ -3455,6 +3520,11 @@ concat-map@0.0.1: resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +console-control-strings@^1.0.0, console-control-strings@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== + cookie@0.7.1: version "0.7.1" resolved "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz" @@ -3649,6 +3719,11 @@ delayed-stream@~1.0.0: resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== + denque@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz" @@ -3659,7 +3734,7 @@ dequal@^2.0.0: resolved "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== -detect-libc@^2.0.1, detect-libc@^2.0.3: +detect-libc@^2.0.0, detect-libc@^2.0.1, detect-libc@^2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz" integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== @@ -4398,6 +4473,13 @@ from@~0: resolved "https://registry.npmjs.org/from/-/from-0.1.7.tgz" integrity sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g== +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" @@ -4433,6 +4515,21 @@ fuse.js@^7.0.0: resolved "https://registry.npmjs.org/fuse.js/-/fuse.js-7.0.0.tgz" integrity sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q== +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== + 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" + get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: version "1.2.4" resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz" @@ -4679,6 +4776,11 @@ has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: dependencies: has-symbols "^1.0.3" +has-unicode@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== + hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" @@ -4740,6 +4842,14 @@ http-status-codes@^2.3.0: resolved "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz" integrity sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA== +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + https-proxy-agent@^7.0.5: version "7.0.5" resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz" @@ -5411,6 +5521,13 @@ magic-string@^0.30.12: dependencies: "@jridgewell/sourcemap-codec" "^1.5.0" +make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + map-stream@~0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz" @@ -5548,11 +5665,36 @@ minimist@^1.2.0, minimist@^1.2.6, minimist@^1.2.8: resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +minipass@^3.0.0: + version "3.3.6" + resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== + dependencies: + yallist "^4.0.0" + +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + "minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: version "7.1.2" resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + moo@^0.5.0: version "0.5.2" resolved "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz" @@ -5658,12 +5800,17 @@ node-abort-controller@^3.1.1: resolved "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz" integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ== +node-addon-api@^5.0.0: + version "5.1.0" + resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" + integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== + node-cleanup@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz" integrity sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw== -node-fetch@^2.6.12: +node-fetch@^2.6.12, node-fetch@^2.6.7: version "2.7.0" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -5677,6 +5824,13 @@ node-gyp-build-optional-packages@5.2.2: dependencies: detect-libc "^2.0.1" +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + normalize-package-data@^2.3.2: version "2.5.0" resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz" @@ -5707,6 +5861,16 @@ npm-run-all@^4.1.5: shell-quote "^1.6.1" string.prototype.padend "^3.0.0" +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== + dependencies: + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + set-blocking "^2.0.0" + nullthrows@^1.0.0: version "1.1.1" resolved "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz" @@ -6351,7 +6515,7 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" -readable-stream@^3.4.0: +readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.2" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -6585,11 +6749,16 @@ scheduler@^0.23.2: resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^6.3.1: +semver@^6.0.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== +semver@^7.3.5: + version "7.7.1" + resolved "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" + integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== + semver@^7.5.4, semver@^7.6.0, semver@^7.6.3: version "7.6.3" resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" @@ -6600,6 +6769,11 @@ server-only@^0.0.1: resolved "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz" integrity sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA== +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + set-function-length@^1.2.1: version "1.2.2" resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz" @@ -6749,6 +6923,11 @@ siginfo@^2.0.0: resolved "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz" integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== +signal-exit@^3.0.0: + version "3.0.7" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + signal-exit@^4.0.1: version "4.1.0" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" @@ -6883,7 +7062,7 @@ string-argv@^0.3.1: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^4.1.0: +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -7127,6 +7306,18 @@ tapable@^2.2.0: resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== +tar@^6.1.11: + version "6.2.1" + resolved "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + text-hex@1.0.x: version "1.0.0" resolved "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz" @@ -7739,6 +7930,13 @@ why-is-node-running@^2.3.0: siginfo "^2.0.0" stackback "0.0.2" +wide-align@^1.1.2: + version "1.1.5" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + winston-transport@^4.7.0: version "4.8.0" resolved "https://registry.npmjs.org/winston-transport/-/winston-transport-4.8.0.tgz" @@ -7813,6 +8011,11 @@ xmlchars@^2.2.0: resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yaml@^2.3.4: version "2.5.1" resolved "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz"