Credentials provider (#192)

* email password functionality

* feedback
This commit is contained in:
Brendan Kellam 2025-02-14 21:00:45 -08:00 committed by GitHub
parent 354b004402
commit 86a80a4f73
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 511 additions and 112 deletions

View file

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "User" ADD COLUMN "hashedPassword" TEXT;

View file

@ -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[]
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?
stripeCustomerId String?
/// List of pending invites to this organization
invites Invite[]
invites Invite[]
}
enum OrgRole {
@ -157,13 +157,14 @@ 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
hashedPassword String?
emailVerified DateTime?
image String?
accounts Account[]
orgs UserToOrg[]
/// List of pending invites that the user has created
invites Invite[]

View file

@ -75,6 +75,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",
@ -124,6 +125,7 @@
"zod": "^3.23.8"
},
"devDependencies": {
"@types/bcrypt": "^5.0.2",
"@types/node": "^20",
"@types/psl": "^1.1.3",
"@types/react": "^18",

View file

@ -0,0 +1,74 @@
import { ErrorCode } from "@/lib/errorCodes";
import { verifyCredentialsRequestSchema } from "@/lib/schemas";
import { schemaValidationError, serviceErrorResponse } from "@/lib/serviceError";
import { prisma } from "@/prisma";
import { User as NextAuthUser } from "next-auth";
import bcrypt from 'bcrypt';
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<NextAuthUser | null> {
const user = await prisma.user.findUnique({
where: { email }
});
// The user doesn't exist, so create a new one.
if (!user) {
const hashedPassword = bcrypt.hashSync(password, 10);
const newUser = await prisma.user.create({
data: {
email,
hashedPassword,
}
});
return {
id: newUser.id,
email: newUser.email,
}
// Otherwise, the user exists, so verify the password.
} else {
if (!user.hashedPassword) {
return null;
}
if (!bcrypt.compareSync(password, user.hashedPassword)) {
return null;
}
return {
id: user.id,
email: user.email,
name: user.name ?? undefined,
image: user.image ?? undefined,
};
}
}

View file

@ -0,0 +1,151 @@
'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, useMemo } 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<z.infer<typeof verifyCredentialsRequestSchema>>({
resolver: zodResolver(verifyCredentialsRequestSchema),
defaultValues: {
email: "",
password: "",
},
});
const onSignInWithEmailPassword = (values: z.infer<typeof verifyCredentialsRequestSchema>) => {
signIn("credentials", {
email: values.email,
password: values.password,
redirectTo: callbackUrl ?? "/"
});
}
const onSignInWithOauth = useCallback((provider: string) => {
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 (
<div className="flex flex-col items-center border p-16 rounded-lg gap-6 w-[500px]">
{error && (
<div className="text-sm text-destructive text-center text-wrap border p-2 rounded-md border-destructive">
{errorMessage}
</div>
)}
<div>
<Image
src={logoDark}
className="h-16 w-auto hidden dark:block"
alt={"Sourcebot logo"}
priority={true}
/>
<Image
src={logoLight}
className="h-16 w-auto block dark:hidden"
alt={"Sourcebot logo"}
priority={true}
/>
</div>
<ProviderButton
name="GitHub"
logo={githubLogo}
onClick={() => {
onSignInWithOauth("github")
}}
/>
<ProviderButton
name="Google"
logo={googleLogo}
onClick={() => {
onSignInWithOauth("google")
}}
/>
<div className="flex items-center w-full gap-4">
<div className="h-[1px] flex-1 bg-border" />
<span className="text-muted-foreground text-sm">or</span>
<div className="h-[1px] flex-1 bg-border" />
</div>
<div className="flex flex-col w-60">
<Form {...form}>
<form onSubmit={form.handleSubmit(onSignInWithEmailPassword)}>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem className="mb-4">
<FormLabel>Email</FormLabel>
<FormControl>
<Input placeholder="email@example.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem className="mb-8">
<FormLabel>Password</FormLabel>
<FormControl>
<Input type="password" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit" className="w-full">
Sign in
</Button>
</form>
</Form>
</div>
</div >
)
}
const ProviderButton = ({
name,
logo,
onClick,
}: {
name: string;
logo: string;
onClick: () => void;
}) => {
return (
<Button onClick={onClick}>
{logo && <Image src={logo} alt={name} className="w-5 h-5 invert dark:invert-0 mr-2" />}
Sign in with {name}
</Button>
)
}

View file

@ -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 (
<div className="flex flex-col justify-center items-center h-screen">
<div className="flex flex-col items-center border p-16 rounded-lg gap-6">
<div>
<Image
src={logoDark}
className="h-16 w-auto hidden dark:block"
alt={"Sourcebot logo"}
priority={true}
/>
<Image
src={logoLight}
className="h-16 w-auto block dark:hidden"
alt={"Sourcebot logo"}
priority={true}
/>
</div>
{
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 }) => (
<form
key={provider.id}
action={async () => {
"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
}
}}
>
<Button
type="submit"
>
{logo && (
<Image
src={logo}
alt={provider.name}
className="w-5 h-5 invert dark:invert-0 mr-2"
/>
)}
Sign in with {provider.name}
</Button>
</form>
))
}
</div>
<LoginForm />
</div>
)
}

View file

@ -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

View file

@ -12,5 +12,6 @@ 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',
MEMBER_NOT_OWNER = 'MEMBER_NOT_OWNER',
}

View file

@ -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(),
});

215
yarn.lock
View file

@ -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"
@ -2381,6 +2396,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"
@ -2432,7 +2454,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==
@ -2799,6 +2821,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"
@ -2816,6 +2843,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"
@ -2885,6 +2919,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"
@ -3059,6 +3106,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"
@ -3234,6 +3289,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"
@ -3475,6 +3535,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"
@ -3526,6 +3591,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"
@ -3720,6 +3790,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"
@ -3730,7 +3805,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==
@ -4469,6 +4544,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"
@ -4504,6 +4586,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"
@ -4750,6 +4847,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"
@ -4811,6 +4913,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"
@ -5482,6 +5592,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"
@ -5619,11 +5736,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"
@ -5729,12 +5871,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==
@ -5748,6 +5895,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"
@ -5778,6 +5932,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"
@ -6422,7 +6586,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==
@ -6656,11 +6820,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"
@ -6671,6 +6840,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"
@ -6820,6 +6994,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"
@ -6954,7 +7133,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==
@ -7205,6 +7384,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"
@ -7817,6 +8008,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"
@ -7891,6 +8089,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"