mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-08 23:15:24 +02:00
work on auth replacement
This commit is contained in:
parent
63c39e2067
commit
3c7b461fb1
23 changed files with 726 additions and 46 deletions
|
@ -22,4 +22,4 @@ AWS_SESSION_TOKEN=
|
|||
NX_PLAID_SECRET=
|
||||
NX_FINICITY_APP_KEY=
|
||||
NX_FINICITY_PARTNER_SECRET=
|
||||
NX_CONVERTKIT_SECRET=
|
||||
NX_CONVERTKIT_SECRET=
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { PropsWithChildren, ReactElement } from 'react'
|
||||
import { useEffect, type PropsWithChildren, type ReactElement } from 'react'
|
||||
import type { AppProps } from 'next/app'
|
||||
import { ErrorBoundary } from 'react-error-boundary'
|
||||
import { Analytics } from '@vercel/analytics/react'
|
||||
|
@ -16,10 +16,11 @@ import * as Sentry from '@sentry/react'
|
|||
import { BrowserTracing } from '@sentry/tracing'
|
||||
import env from '../env'
|
||||
import '../styles.css'
|
||||
import { withAuthenticationRequired } from '@auth0/auth0-react'
|
||||
import { SessionProvider, useSession } from 'next-auth/react'
|
||||
import ModalManager from '../components/ModalManager'
|
||||
import Meta from '../components/Meta'
|
||||
import APM from '../components/APM'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
Sentry.init({
|
||||
dsn: env.NEXT_PUBLIC_SENTRY_DSN,
|
||||
|
@ -33,20 +34,32 @@ Sentry.init({
|
|||
})
|
||||
|
||||
// Providers and components only relevant to a logged-in user
|
||||
const WithAuth = withAuthenticationRequired(function ({ children }: PropsWithChildren) {
|
||||
return (
|
||||
<ModalManager>
|
||||
<UserAccountContextProvider>
|
||||
<AccountContextProvider>
|
||||
{children}
|
||||
const WithAuth = function ({ children }: PropsWithChildren) {
|
||||
const { data: session } = useSession()
|
||||
const router = useRouter()
|
||||
|
||||
{/* Add, edit, delete connections and manual accounts */}
|
||||
<AccountsManager />
|
||||
</AccountContextProvider>
|
||||
</UserAccountContextProvider>
|
||||
</ModalManager>
|
||||
)
|
||||
})
|
||||
useEffect(() => {
|
||||
if (!session) {
|
||||
router.push('/login')
|
||||
}
|
||||
}, [session, router])
|
||||
|
||||
if (session) {
|
||||
return (
|
||||
<ModalManager>
|
||||
<UserAccountContextProvider>
|
||||
<AccountContextProvider>
|
||||
{children}
|
||||
|
||||
{/* Add, edit, delete connections and manual accounts */}
|
||||
<AccountsManager />
|
||||
</AccountContextProvider>
|
||||
</UserAccountContextProvider>
|
||||
</ModalManager>
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export default function App({
|
||||
Component: Page,
|
||||
|
@ -72,16 +85,18 @@ export default function App({
|
|||
<Analytics />
|
||||
<QueryProvider>
|
||||
<AuthProvider>
|
||||
<AxiosProvider>
|
||||
<>
|
||||
<APM />
|
||||
{Page.isPublic === true ? (
|
||||
getLayout(<Page {...pageProps} />)
|
||||
) : (
|
||||
<WithAuth>{getLayout(<Page {...pageProps} />)}</WithAuth>
|
||||
)}
|
||||
</>
|
||||
</AxiosProvider>
|
||||
<SessionProvider>
|
||||
<AxiosProvider>
|
||||
<>
|
||||
<APM />
|
||||
{Page.isPublic === true ? (
|
||||
getLayout(<Page {...pageProps} />)
|
||||
) : (
|
||||
<WithAuth>{getLayout(<Page {...pageProps} />)}</WithAuth>
|
||||
)}
|
||||
</>
|
||||
</AxiosProvider>
|
||||
</SessionProvider>
|
||||
</AuthProvider>
|
||||
</QueryProvider>
|
||||
</ErrorBoundary>
|
||||
|
|
83
apps/client/pages/api/auth/[...nextauth].ts
Normal file
83
apps/client/pages/api/auth/[...nextauth].ts
Normal file
|
@ -0,0 +1,83 @@
|
|||
import NextAuth from 'next-auth'
|
||||
import CredentialsProvider from 'next-auth/providers/credentials'
|
||||
import { z } from 'zod'
|
||||
import type { SharedType } from '@maybe-finance/shared'
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
import { PrismaAdapter } from '@auth/prisma-adapter'
|
||||
import axios from 'axios'
|
||||
import bcrypt from 'bcrypt'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
axios.defaults.baseURL = `${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3333'}/v1`
|
||||
|
||||
const authPrisma = {
|
||||
account: prisma.authAccount,
|
||||
user: prisma.authUser,
|
||||
session: prisma.authSession,
|
||||
verificationToken: prisma.authVerificationToken,
|
||||
} as unknown as PrismaClient
|
||||
|
||||
export const authOptions = {
|
||||
adapter: PrismaAdapter(authPrisma),
|
||||
secret: process.env.AUTH_SECRET || 'CHANGE_ME',
|
||||
pages: {
|
||||
signIn: '/login',
|
||||
},
|
||||
providers: [
|
||||
CredentialsProvider({
|
||||
name: 'Credentials',
|
||||
type: 'credentials',
|
||||
credentials: {
|
||||
email: { label: 'Email', type: 'email', placeholder: 'hello@maybe.co' },
|
||||
password: { label: 'Password', type: 'password' },
|
||||
},
|
||||
async authorize(credentials) {
|
||||
console.log('inside the authorize method')
|
||||
const parsedCredentials = z
|
||||
.object({
|
||||
email: z.string().email(),
|
||||
password: z.string().min(6),
|
||||
provider: z.string().optional(),
|
||||
})
|
||||
.safeParse(credentials)
|
||||
|
||||
if (parsedCredentials.success) {
|
||||
console.log("Credentials are valid, let's authorize")
|
||||
const { email, password } = parsedCredentials.data
|
||||
console.log('Here are the params', email, password)
|
||||
const { data } = await axios.get(`/auth-users`, {
|
||||
params: { email: email },
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
})
|
||||
|
||||
const user = data.data['json']
|
||||
|
||||
console.log('This is User', user)
|
||||
|
||||
if (!user.id) {
|
||||
console.log('User does not exist, creating new user')
|
||||
const hashedPassword = await bcrypt.hash(password, 10)
|
||||
const { data: newUser } = await axios.post<SharedType.AuthUser>(
|
||||
'/auth-users',
|
||||
{
|
||||
email,
|
||||
password: hashedPassword,
|
||||
}
|
||||
)
|
||||
console.log('Created new user', newUser)
|
||||
if (newUser) return newUser
|
||||
throw new Error('Could not create user')
|
||||
}
|
||||
|
||||
const passwordsMatch = await bcrypt.compare(password, user.password)
|
||||
if (passwordsMatch) return user
|
||||
}
|
||||
|
||||
console.log('Invalid credentials')
|
||||
return null
|
||||
},
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
export default NextAuth(authOptions)
|
|
@ -1,20 +1,88 @@
|
|||
import { useAuth0 } from '@auth0/auth0-react'
|
||||
import { LoadingSpinner } from '@maybe-finance/design-system'
|
||||
import type { ReactElement } from 'react'
|
||||
import { useState } from 'react'
|
||||
import { FullPageLayout } from '@maybe-finance/client/features'
|
||||
import { Input, InputPassword, Button } from '@maybe-finance/design-system'
|
||||
import { AiOutlineLoading3Quarters as LoadingIcon } from 'react-icons/ai'
|
||||
import { signIn, useSession } from 'next-auth/react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
import Script from 'next/script'
|
||||
|
||||
export default function LoginPage() {
|
||||
const { isAuthenticated } = useAuth0()
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const [isValid, setIsValid] = useState(false)
|
||||
|
||||
const { data: session } = useSession()
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
if (isAuthenticated) router.push('/')
|
||||
}, [isAuthenticated, router])
|
||||
if (session) router.push('/')
|
||||
}, [session, router])
|
||||
|
||||
const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault()
|
||||
setEmail('')
|
||||
setPassword('')
|
||||
await signIn('credentials', {
|
||||
email,
|
||||
password,
|
||||
callbackUrl: '/',
|
||||
})
|
||||
}
|
||||
|
||||
// _app.tsx will automatically redirect if not authenticated
|
||||
return (
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<LoadingSpinner />
|
||||
</div>
|
||||
<>
|
||||
<Script
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/zxcvbn/4.4.2/zxcvbn.js"
|
||||
strategy="lazyOnload"
|
||||
/>
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center">
|
||||
<img
|
||||
className="mb-8"
|
||||
src="/assets/maybe.svg"
|
||||
alt="Maybe Finance Logo"
|
||||
height={140}
|
||||
width={140}
|
||||
/>
|
||||
<form className="space-y-4" onSubmit={onSubmit}>
|
||||
<Input
|
||||
type="text"
|
||||
label="Email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.currentTarget.value)}
|
||||
/>
|
||||
|
||||
<InputPassword
|
||||
autoComplete="password"
|
||||
label="Password"
|
||||
value={password}
|
||||
showPasswordRequirements={!isValid}
|
||||
onValidityChange={(checks) => {
|
||||
const passwordValid = checks.filter((c) => !c.isValid).length === 0
|
||||
setIsValid(passwordValid)
|
||||
}}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setPassword(e.target.value)
|
||||
}
|
||||
/>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={!isValid}
|
||||
variant={isValid ? 'primary' : 'secondary'}
|
||||
>
|
||||
Log in
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
LoginPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return <FullPageLayout>{page}</FullPageLayout>
|
||||
}
|
||||
|
||||
LoginPage.isPublic = true
|
||||
|
|
|
@ -1,20 +1,30 @@
|
|||
import { useAuth0 } from '@auth0/auth0-react'
|
||||
import { LoadingSpinner } from '@maybe-finance/design-system'
|
||||
import type { ReactElement } from 'react'
|
||||
import { Input, InputPassword } from '@maybe-finance/design-system'
|
||||
import { FullPageLayout } from '@maybe-finance/client/features'
|
||||
import { useSession } from 'next-auth/react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
export default function RegisterPage() {
|
||||
const { isAuthenticated } = useAuth0()
|
||||
const { data: session } = useSession()
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
if (isAuthenticated) router.push('/')
|
||||
}, [isAuthenticated, router])
|
||||
if (session) router.push('/')
|
||||
}, [session, router])
|
||||
|
||||
// _app.tsx will automatically redirect if not authenticated
|
||||
return (
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<LoadingSpinner />
|
||||
<div className="text-4xl font-bold text-white">THIS IS THE LOGIN PAGE</div>
|
||||
<Input type="text" placeholder="Email" />
|
||||
<InputPassword placeholder="Password" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
RegisterPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return <FullPageLayout>{page}</FullPageLayout>
|
||||
}
|
||||
|
||||
RegisterPage.isPublic = true
|
||||
|
|
|
@ -28,6 +28,7 @@ import {
|
|||
} from './middleware'
|
||||
import {
|
||||
usersRouter,
|
||||
authUserRouter,
|
||||
accountsRouter,
|
||||
connectionsRouter,
|
||||
adminRouter,
|
||||
|
@ -149,6 +150,7 @@ app.use('/tools', devOnly, toolsRouter)
|
|||
app.use('/v1', webhooksRouter)
|
||||
|
||||
app.use('/v1', publicRouter)
|
||||
app.use('/v1/auth-users', authUserRouter)
|
||||
|
||||
// All routes AFTER this line are protected via OAuth
|
||||
app.use('/v1', validateAuth0Jwt)
|
||||
|
|
|
@ -24,6 +24,7 @@ import Redis from 'ioredis'
|
|||
import {
|
||||
AccountService,
|
||||
AccountConnectionService,
|
||||
AuthUserService,
|
||||
UserService,
|
||||
EmailService,
|
||||
AccountQueryService,
|
||||
|
@ -208,6 +209,10 @@ const accountService = new AccountService(
|
|||
balanceSyncStrategyFactory
|
||||
)
|
||||
|
||||
// auth-user
|
||||
|
||||
const authUserService = new AuthUserService(logger.child({ service: 'AuthUserService' }), prisma)
|
||||
|
||||
// user
|
||||
|
||||
const userService = new UserService(
|
||||
|
@ -291,6 +296,7 @@ async function getCurrentUser(jwt: NonNullable<Request['user']>) {
|
|||
where: { auth0Id: jwt.sub },
|
||||
create: {
|
||||
auth0Id: jwt.sub,
|
||||
authId: jwt.sub,
|
||||
email: jwt['https://maybe.co/email'],
|
||||
picture: jwt[SharedType.Auth0CustomNamespace.Picture],
|
||||
firstName: jwt[SharedType.Auth0CustomNamespace.UserMetadata]?.['firstName'],
|
||||
|
@ -326,6 +332,7 @@ export async function createContext(req: Request) {
|
|||
transactionService,
|
||||
holdingService,
|
||||
accountConnectionService,
|
||||
authUserService,
|
||||
userService,
|
||||
valuationService,
|
||||
institutionService,
|
||||
|
|
38
apps/server/src/app/routes/auth-user.router.ts
Normal file
38
apps/server/src/app/routes/auth-user.router.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { Router } from 'express'
|
||||
import { z } from 'zod'
|
||||
import endpoint from '../lib/endpoint'
|
||||
|
||||
const router = Router()
|
||||
|
||||
router.get(
|
||||
'/',
|
||||
endpoint.create({
|
||||
resolve: async ({ ctx, req }) => {
|
||||
const email = req.query.email
|
||||
console.log('Going to get the user for email', email)
|
||||
const user = await ctx.authUserService.getByEmail(email as string)
|
||||
console.log('Got the user', user)
|
||||
if (user) return user
|
||||
console.log('No user found')
|
||||
return { data: null }
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
router.post(
|
||||
'/',
|
||||
endpoint.create({
|
||||
input: z.object({
|
||||
email: z.string().email(),
|
||||
password: z.string().min(6),
|
||||
}),
|
||||
resolve: async ({ input, ctx }) => {
|
||||
return await ctx.authUserService.create({
|
||||
email: input.email,
|
||||
password: input.password,
|
||||
})
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
export default router
|
|
@ -54,6 +54,7 @@ router.post(
|
|||
ctx.prisma.user.create({
|
||||
data: {
|
||||
auth0Id: ctx.user!.auth0Id,
|
||||
authId: ctx.user!.authId,
|
||||
email: 'REPLACE_THIS',
|
||||
dob: new Date('1990-01-01'),
|
||||
linkAccountDismissedAt: new Date(), // ensures our auto-account link doesn't trigger
|
||||
|
|
|
@ -2,6 +2,7 @@ export { default as accountsRouter } from './accounts.router'
|
|||
export { default as accountRollupRouter } from './account-rollup.router'
|
||||
export { default as connectionsRouter } from './connections.router'
|
||||
export { default as usersRouter } from './users.router'
|
||||
export { default as authUserRouter } from './auth-user.router'
|
||||
export { default as webhooksRouter } from './webhooks.router'
|
||||
export { default as plaidRouter } from './plaid.router'
|
||||
export { default as finicityRouter } from './finicity.router'
|
||||
|
|
|
@ -19,13 +19,11 @@ import {
|
|||
RiMore2Fill,
|
||||
RiPieChart2Line,
|
||||
RiFlagLine,
|
||||
RiChatPollLine,
|
||||
RiArrowRightSLine,
|
||||
} from 'react-icons/ri'
|
||||
import { Button, Tooltip } from '@maybe-finance/design-system'
|
||||
import { useAuth0 } from '@auth0/auth0-react'
|
||||
import { MenuPopover } from './MenuPopover'
|
||||
import { UpgradePrompt } from '../user-billing'
|
||||
import { SidebarOnboarding } from '../onboarding'
|
||||
|
||||
export interface DesktopLayoutProps {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { motion } from 'framer-motion'
|
||||
import {
|
||||
RiChatPollLine,
|
||||
RiCloseLine,
|
||||
RiFlagLine,
|
||||
RiFolderOpenLine,
|
||||
|
@ -15,7 +14,6 @@ import Link from 'next/link'
|
|||
import { useRouter } from 'next/router'
|
||||
import { ProfileCircle } from '@maybe-finance/client/shared'
|
||||
import { usePopoutContext, LayoutContextProvider } from '@maybe-finance/client/shared'
|
||||
import { UpgradePrompt } from '../user-billing'
|
||||
import classNames from 'classnames'
|
||||
import type { IconType } from 'react-icons'
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
export * from './useAccountApi'
|
||||
export * from './useAccountConnectionApi'
|
||||
export * from './useAuthUserApi'
|
||||
export * from './useFinicityApi'
|
||||
export * from './useInstitutionApi'
|
||||
export * from './useUserApi'
|
||||
|
|
88
libs/client/shared/src/api/useAuthUserApi.ts
Normal file
88
libs/client/shared/src/api/useAuthUserApi.ts
Normal file
|
@ -0,0 +1,88 @@
|
|||
import type { UseMutationOptions, UseQueryOptions } from '@tanstack/react-query'
|
||||
import type { SharedType } from '@maybe-finance/shared'
|
||||
import type { AxiosInstance } from 'axios'
|
||||
import Axios from 'axios'
|
||||
import * as Sentry from '@sentry/react'
|
||||
import { useMemo } from 'react'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { toast } from 'react-hot-toast'
|
||||
import { DateTime } from 'luxon'
|
||||
import { useAxiosWithAuth } from '../hooks/useAxiosWithAuth'
|
||||
|
||||
const AuthUserApi = (axios: AxiosInstance) => ({
|
||||
async getByEmail(email: string) {
|
||||
const { data } = await axios.get<SharedType.AuthUser>(`/auth-users/${email}`)
|
||||
return data
|
||||
},
|
||||
|
||||
async update(userData: SharedType.UpdateUser) {
|
||||
const { data } = await axios.put<SharedType.User>('/users', userData)
|
||||
return data
|
||||
},
|
||||
|
||||
async get() {
|
||||
const { data } = await axios.get<SharedType.User>('/users')
|
||||
return data
|
||||
},
|
||||
|
||||
async delete() {
|
||||
return axios.delete('/users', { data: { confirm: true } })
|
||||
},
|
||||
|
||||
async updateOnboarding(input: {
|
||||
flow: SharedType.OnboardingFlow
|
||||
updates: { key: string; markedComplete: boolean }[]
|
||||
markedComplete?: boolean
|
||||
}) {
|
||||
const { data } = await axios.put<SharedType.User>('/users/onboarding', input)
|
||||
return data
|
||||
},
|
||||
|
||||
async changePassword(newPassword: SharedType.PasswordReset) {
|
||||
const { data } = await axios.put<
|
||||
SharedType.PasswordReset,
|
||||
SharedType.ApiResponse<{ success: boolean; error?: string }>
|
||||
>('/users/change-password', newPassword)
|
||||
return data
|
||||
},
|
||||
})
|
||||
|
||||
const staleTimes = {
|
||||
user: 30_000,
|
||||
netWorth: 30_000,
|
||||
insights: 30_000,
|
||||
}
|
||||
|
||||
export function useAuthUserApi() {
|
||||
const queryClient = useQueryClient()
|
||||
const { axios } = useAxiosWithAuth()
|
||||
const api = useMemo(() => AuthUserApi(axios), [axios])
|
||||
|
||||
const useGetByEmail = (email: string) =>
|
||||
useQuery(['auth-users', email], () => api.getByEmail(email), { staleTime: staleTimes.user })
|
||||
|
||||
const useUpdateOnboarding = (
|
||||
options?: UseMutationOptions<
|
||||
SharedType.User,
|
||||
unknown,
|
||||
{
|
||||
flow: SharedType.OnboardingFlow
|
||||
updates: { key: string; markedComplete: boolean }[]
|
||||
markedComplete?: boolean
|
||||
}
|
||||
>
|
||||
) =>
|
||||
useMutation(api.updateOnboarding, {
|
||||
onSettled: () => queryClient.invalidateQueries(['users', 'onboarding']),
|
||||
...options,
|
||||
})
|
||||
|
||||
const useDelete = (options?: UseMutationOptions<{}, unknown, any>) =>
|
||||
useMutation(api.delete, options)
|
||||
|
||||
return {
|
||||
useGetByEmail,
|
||||
useUpdateOnboarding,
|
||||
useDelete,
|
||||
}
|
||||
}
|
38
libs/server/features/src/auth-user/auth-user.service.ts
Normal file
38
libs/server/features/src/auth-user/auth-user.service.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import type { AuthUser, PrismaClient, Prisma } from '@prisma/client'
|
||||
import type { Logger } from 'winston'
|
||||
|
||||
export interface IAuthUserService {
|
||||
get(id: AuthUser['id']): Promise<AuthUser>
|
||||
delete(id: AuthUser['id']): Promise<AuthUser>
|
||||
}
|
||||
|
||||
export class AuthUserService implements IAuthUserService {
|
||||
constructor(private readonly logger: Logger, private readonly prisma: PrismaClient) {}
|
||||
|
||||
async get(id: AuthUser['id']) {
|
||||
return await this.prisma.authUser.findUniqueOrThrow({
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
async getByEmail(email: AuthUser['email']) {
|
||||
if (!email) throw new Error('No email provided')
|
||||
return await this.prisma.authUser.findUnique({
|
||||
where: { email },
|
||||
})
|
||||
}
|
||||
|
||||
async create(data: Prisma.AuthUserCreateInput): Promise<AuthUser> {
|
||||
const user = await this.prisma.authUser.create({ data: { ...data } })
|
||||
return user
|
||||
}
|
||||
|
||||
async delete(id: AuthUser['id']) {
|
||||
const authUser = await this.get(id)
|
||||
|
||||
// Delete user from prisma
|
||||
this.logger.info(`Removing user ${authUser.id} from Prisma`)
|
||||
const user = await this.prisma.authUser.delete({ where: { id } })
|
||||
return user
|
||||
}
|
||||
}
|
1
libs/server/features/src/auth-user/index.ts
Normal file
1
libs/server/features/src/auth-user/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from './auth-user.service'
|
|
@ -4,6 +4,7 @@ export * from './account-balance'
|
|||
export * from './email'
|
||||
export * from './institution'
|
||||
export * from './security-pricing'
|
||||
export * from './auth-user'
|
||||
export * from './user'
|
||||
export * from './valuation'
|
||||
export * from './providers'
|
||||
|
|
|
@ -8,6 +8,7 @@ import type {
|
|||
Prisma,
|
||||
Security,
|
||||
User as PrismaUser,
|
||||
AuthUser,
|
||||
} from '@prisma/client'
|
||||
import type { Institution } from 'plaid'
|
||||
import type { TimeSeries, TimeSeriesResponseWithDetail, Trend } from './general-types'
|
||||
|
@ -28,6 +29,14 @@ export type UpdateUser = Partial<
|
|||
}
|
||||
>
|
||||
|
||||
/**
|
||||
* ================================================================
|
||||
* ====== Auth User ======
|
||||
* ================================================================
|
||||
*/
|
||||
|
||||
export type { AuthUser }
|
||||
|
||||
/**
|
||||
* ================================================================
|
||||
* ====== Net Worth ======
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@auth/prisma-adapter": "^1.0.14",
|
||||
"@auth0/auth0-react": "^2.0.0",
|
||||
"@auth0/nextjs-auth0": "^2.0.0",
|
||||
"@aws-sdk/client-s3": "^3.231.0",
|
||||
|
@ -98,6 +99,7 @@
|
|||
"auth0-deploy-cli": "^7.15.1",
|
||||
"autoprefixer": "10.4.13",
|
||||
"axios": "^0.26.1",
|
||||
"bcrypt": "^5.1.1",
|
||||
"bull": "^4.10.2",
|
||||
"classnames": "^2.3.1",
|
||||
"core-js": "^3.6.5",
|
||||
|
@ -127,6 +129,7 @@
|
|||
"morgan": "^1.10.0",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"next": "13.1.1",
|
||||
"next-auth": "^4.24.5",
|
||||
"pg": "^8.8.0",
|
||||
"plaid": "^12.1.0",
|
||||
"postcss": "8.4.19",
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[auth_id]` on the table `user` will be added. If there are existing duplicate values, this will fail.
|
||||
- Added the required column `auth_id` to the `user` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "user" ADD COLUMN "auth_id" TEXT NOT NULL;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "auth_account" (
|
||||
"id" TEXT NOT NULL,
|
||||
"user_id" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"provider" TEXT NOT NULL,
|
||||
"provider_account_id" TEXT NOT NULL,
|
||||
"refresh_token" TEXT,
|
||||
"access_token" TEXT,
|
||||
"expires_at" INTEGER,
|
||||
"token_type" TEXT,
|
||||
"scope" TEXT,
|
||||
"id_token" TEXT,
|
||||
"session_state" TEXT,
|
||||
|
||||
CONSTRAINT "auth_account_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "auth_user" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT,
|
||||
"email" TEXT,
|
||||
"email_verified" TIMESTAMP(3),
|
||||
"image" TEXT,
|
||||
|
||||
CONSTRAINT "auth_user_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "auth_session" (
|
||||
"id" TEXT NOT NULL,
|
||||
"session_token" TEXT NOT NULL,
|
||||
"user_id" TEXT NOT NULL,
|
||||
"expires" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "auth_session_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "auth_verification_token" (
|
||||
"identifier" TEXT NOT NULL,
|
||||
"token" TEXT NOT NULL,
|
||||
"expires" TIMESTAMP(3) NOT NULL
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "auth_account_provider_provider_account_id_key" ON "auth_account"("provider", "provider_account_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "auth_user_email_key" ON "auth_user"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "auth_session_session_token_key" ON "auth_session"("session_token");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "auth_verification_token_token_key" ON "auth_verification_token"("token");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "auth_verification_token_identifier_token_key" ON "auth_verification_token"("identifier", "token");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "user_auth_id_key" ON "user"("auth_id");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "auth_account" ADD CONSTRAINT "auth_account_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "auth_user"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "auth_session" ADD CONSTRAINT "auth_session_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "auth_user"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@ -0,0 +1,2 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "auth_user" ADD COLUMN "password" TEXT;
|
|
@ -396,6 +396,7 @@ model User {
|
|||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
||||
updatedAt DateTime @default(now()) @updatedAt @map("updated_at") @db.Timestamptz(6)
|
||||
auth0Id String @unique @map("auth0_id")
|
||||
authId String @unique @map("auth_id") // NextAuth user id
|
||||
|
||||
// profile
|
||||
email String @db.Citext
|
||||
|
@ -564,6 +565,59 @@ model PlanMilestone {
|
|||
@@map("plan_milestone")
|
||||
}
|
||||
|
||||
// Next Auth Models
|
||||
model AuthAccount {
|
||||
id String @id @default(cuid())
|
||||
userId String @map("user_id")
|
||||
type String
|
||||
provider String
|
||||
providerAccountId String @map("provider_account_id")
|
||||
refresh_token String? @db.Text
|
||||
access_token String? @db.Text
|
||||
expires_at Int?
|
||||
token_type String?
|
||||
scope String?
|
||||
id_token String? @db.Text
|
||||
session_state String?
|
||||
|
||||
user AuthUser @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([provider, providerAccountId])
|
||||
@@map("auth_account")
|
||||
}
|
||||
|
||||
model AuthUser {
|
||||
id String @id @default(cuid())
|
||||
name String?
|
||||
email String? @unique
|
||||
emailVerified DateTime? @map("email_verified")
|
||||
password String?
|
||||
image String?
|
||||
accounts AuthAccount[]
|
||||
sessions AuthSession[]
|
||||
|
||||
@@map("auth_user")
|
||||
}
|
||||
|
||||
model AuthSession {
|
||||
id String @id @default(cuid())
|
||||
sessionToken String @unique @map("session_token")
|
||||
userId String @map("user_id")
|
||||
expires DateTime
|
||||
user AuthUser @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@map("auth_session")
|
||||
}
|
||||
|
||||
model AuthVerificationToken {
|
||||
identifier String
|
||||
token String @unique
|
||||
expires DateTime
|
||||
|
||||
@@unique([identifier, token])
|
||||
@@map("auth_verification_token")
|
||||
}
|
||||
|
||||
enum ApprovalStatus {
|
||||
pending
|
||||
approved
|
||||
|
|
187
yarn.lock
187
yarn.lock
|
@ -9,6 +9,26 @@
|
|||
dependencies:
|
||||
"@jridgewell/trace-mapping" "^0.3.0"
|
||||
|
||||
"@auth/core@0.20.0":
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@auth/core/-/core-0.20.0.tgz#18b706b9708973b1fd4cb6aac5ef47d89201f925"
|
||||
integrity sha512-04lQH58H5d/9xQ63MOTDTOC7sXWYlr/RhJ97wfFLXzll7nYyCKbkrT3ZMdzdLC5O+qt90sQDK85TAtLlcZ2WBg==
|
||||
dependencies:
|
||||
"@panva/hkdf" "^1.1.1"
|
||||
"@types/cookie" "0.6.0"
|
||||
cookie "0.6.0"
|
||||
jose "^5.1.3"
|
||||
oauth4webapi "^2.4.0"
|
||||
preact "10.11.3"
|
||||
preact-render-to-string "5.2.3"
|
||||
|
||||
"@auth/prisma-adapter@^1.0.14":
|
||||
version "1.0.14"
|
||||
resolved "https://registry.yarnpkg.com/@auth/prisma-adapter/-/prisma-adapter-1.0.14.tgz#3b46f86beec618ab5d6756fdd1b520535cf010ac"
|
||||
integrity sha512-7urwnDT+K81SocU0SbfY/vtY/NbXgj8/AU2k6Ek8waHT/7YPLsOQnXQsTWROmolFshNVkt2kq9Z/HOVnRdHrkQ==
|
||||
dependencies:
|
||||
"@auth/core" "0.20.0"
|
||||
|
||||
"@auth0/auth0-react@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@auth0/auth0-react/-/auth0-react-2.0.0.tgz#74e4d3662896e71dd95cca70b395715825da3b4e"
|
||||
|
@ -2734,6 +2754,13 @@
|
|||
dependencies:
|
||||
regenerator-runtime "^0.13.10"
|
||||
|
||||
"@babel/runtime@^7.20.13":
|
||||
version "7.23.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.8.tgz#8ee6fe1ac47add7122902f257b8ddf55c898f650"
|
||||
integrity sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.14.0"
|
||||
|
||||
"@babel/template@^7.12.7", "@babel/template@^7.16.7", "@babel/template@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31"
|
||||
|
@ -3432,6 +3459,21 @@
|
|||
resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b"
|
||||
integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==
|
||||
|
||||
"@mapbox/node-pre-gyp@^1.0.11":
|
||||
version "1.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@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"
|
||||
|
||||
"@mdx-js/mdx@^1.6.22":
|
||||
version "1.6.22"
|
||||
resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-1.6.22.tgz#8a723157bf90e78f17dc0f27995398e6c731f1ba"
|
||||
|
@ -3966,6 +4008,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@panva/hkdf/-/hkdf-1.0.2.tgz#bab0f09d09de9fd83628220d496627681bc440d6"
|
||||
integrity sha512-MSAs9t3Go7GUkMhpKC44T58DJ5KGk2vBo+h1cqQeqlMfdGkxaVB78ZWpv9gYi/g2fa4sopag9gJsNvS8XGgWJA==
|
||||
|
||||
"@panva/hkdf@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@panva/hkdf/-/hkdf-1.1.1.tgz#ab9cd8755d1976e72fc77a00f7655a64efe6cd5d"
|
||||
integrity sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==
|
||||
|
||||
"@parcel/watcher@2.0.4":
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.4.tgz#f300fef4cc38008ff4b8c29d92588eced3ce014b"
|
||||
|
@ -5717,6 +5764,11 @@
|
|||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/cookie@0.6.0":
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.6.0.tgz#eac397f28bf1d6ae0ae081363eca2f425bedf0d5"
|
||||
integrity sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==
|
||||
|
||||
"@types/cors@^2.8.12":
|
||||
version "2.8.12"
|
||||
resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080"
|
||||
|
@ -7154,6 +7206,11 @@ abab@^2.0.6:
|
|||
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
|
||||
integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==
|
||||
|
||||
abbrev@1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
||||
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
||||
|
||||
accepts@~1.3.4:
|
||||
version "1.3.7"
|
||||
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
|
||||
|
@ -8138,6 +8195,14 @@ bcrypt-pbkdf@^1.0.0:
|
|||
dependencies:
|
||||
tweetnacl "^0.14.3"
|
||||
|
||||
bcrypt@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-5.1.1.tgz#0f732c6dcb4e12e5b70a25e326a72965879ba6e2"
|
||||
integrity sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==
|
||||
dependencies:
|
||||
"@mapbox/node-pre-gyp" "^1.0.11"
|
||||
node-addon-api "^5.0.0"
|
||||
|
||||
bcryptjs@^2.3.0:
|
||||
version "2.4.3"
|
||||
resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb"
|
||||
|
@ -9362,6 +9427,11 @@ cookie@0.5.0, cookie@^0.5.0:
|
|||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
|
||||
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
|
||||
|
||||
cookie@0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
|
||||
integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
|
||||
|
||||
cookie@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
|
||||
|
@ -10196,6 +10266,11 @@ detab@2.0.4:
|
|||
dependencies:
|
||||
repeat-string "^1.5.4"
|
||||
|
||||
detect-libc@^2.0.0:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.2.tgz#8ccf2ba9315350e1241b88d0ac3b0e1fbd99605d"
|
||||
integrity sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==
|
||||
|
||||
detect-newline@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
|
||||
|
@ -14393,6 +14468,16 @@ jose@^4.10.3:
|
|||
resolved "https://registry.yarnpkg.com/jose/-/jose-4.11.0.tgz#1c7f5c7806383d3e836434e8f49da531cb046a9d"
|
||||
integrity sha512-wLe+lJHeG8Xt6uEubS4x0LVjS/3kXXu9dGoj9BNnlhYq7Kts0Pbb2pvv5KiI0yaKH/eaiR0LUOBhOVo9ktd05A==
|
||||
|
||||
jose@^4.11.4, jose@^4.15.4:
|
||||
version "4.15.4"
|
||||
resolved "https://registry.yarnpkg.com/jose/-/jose-4.15.4.tgz#02a9a763803e3872cf55f29ecef0dfdcc218cc03"
|
||||
integrity sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==
|
||||
|
||||
jose@^5.1.3:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/jose/-/jose-5.2.0.tgz#d0ffd7f7e31253f633eefb190a930cd14a916995"
|
||||
integrity sha512-oW3PCnvyrcm1HMvGTzqjxxfnEs9EoFOFWi2HsEGhlFVOXxTE3K9GKWVMFoFw06yPUqwpvEWic1BmtUZBI/tIjw==
|
||||
|
||||
js-string-escape@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef"
|
||||
|
@ -15652,6 +15737,11 @@ minipass@^3.0.0, minipass@^3.1.1:
|
|||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
minipass@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d"
|
||||
integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==
|
||||
|
||||
minizlib@^2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
|
||||
|
@ -15879,6 +15969,21 @@ nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0:
|
|||
resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz#26c8a3cee6cc05fbcf1e333cd2fc3e003326c0b5"
|
||||
integrity sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==
|
||||
|
||||
next-auth@^4.24.5:
|
||||
version "4.24.5"
|
||||
resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-4.24.5.tgz#1fd1bfc0603c61fd2ba6fd81b976af690edbf07e"
|
||||
integrity sha512-3RafV3XbfIKk6rF6GlLE4/KxjTcuMCifqrmD+98ejFq73SRoj2rmzoca8u764977lH/Q7jo6Xu6yM+Re1Mz/Og==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.20.13"
|
||||
"@panva/hkdf" "^1.0.2"
|
||||
cookie "^0.5.0"
|
||||
jose "^4.11.4"
|
||||
oauth "^0.9.15"
|
||||
openid-client "^5.4.0"
|
||||
preact "^10.6.3"
|
||||
preact-render-to-string "^5.1.19"
|
||||
uuid "^8.3.2"
|
||||
|
||||
next-tick@^1.0.0, next-tick@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb"
|
||||
|
@ -15942,6 +16047,11 @@ node-addon-api@^3.2.1:
|
|||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161"
|
||||
integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==
|
||||
|
||||
node-addon-api@^5.0.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762"
|
||||
integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==
|
||||
|
||||
node-dir@^0.1.10:
|
||||
version "0.1.17"
|
||||
resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5"
|
||||
|
@ -16010,6 +16120,13 @@ node-releases@^2.0.2:
|
|||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01"
|
||||
integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==
|
||||
|
||||
nopt@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"
|
||||
integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
|
||||
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
|
||||
|
@ -16124,6 +16241,16 @@ nx@15.5.2:
|
|||
yargs "^17.6.2"
|
||||
yargs-parser "21.1.1"
|
||||
|
||||
oauth4webapi@^2.4.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/oauth4webapi/-/oauth4webapi-2.6.0.tgz#776a2eb5ca6ad5e5249c4bb6194516318406d254"
|
||||
integrity sha512-4P43og0d8fQ61RMQEl9L7zwGVduuYbLED7uP99MkFSGuOUvJL1Fs52/D3tRtKoFtiSwKblScTYJI+utQn3SUDg==
|
||||
|
||||
oauth@^0.9.15:
|
||||
version "0.9.15"
|
||||
resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1"
|
||||
integrity sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==
|
||||
|
||||
object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.1, object-assign@latest:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
|
@ -16138,7 +16265,7 @@ object-copy@^0.1.0:
|
|||
define-property "^0.2.5"
|
||||
kind-of "^3.0.3"
|
||||
|
||||
object-hash@^2.0.1:
|
||||
object-hash@^2.0.1, object-hash@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5"
|
||||
integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==
|
||||
|
@ -16297,6 +16424,11 @@ oidc-token-hash@^5.0.1:
|
|||
resolved "https://registry.yarnpkg.com/oidc-token-hash/-/oidc-token-hash-5.0.1.tgz#ae6beec3ec20f0fd885e5400d175191d6e2f10c6"
|
||||
integrity sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ==
|
||||
|
||||
oidc-token-hash@^5.0.3:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz#9a229f0a1ce9d4fc89bcaee5478c97a889e7b7b6"
|
||||
integrity sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==
|
||||
|
||||
on-finished@2.4.1:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
|
||||
|
@ -16382,6 +16514,16 @@ openid-client@^5.2.1:
|
|||
object-hash "^2.0.1"
|
||||
oidc-token-hash "^5.0.1"
|
||||
|
||||
openid-client@^5.4.0:
|
||||
version "5.6.4"
|
||||
resolved "https://registry.yarnpkg.com/openid-client/-/openid-client-5.6.4.tgz#b2c25e6d5338ba3ce00e04341bb286798a196177"
|
||||
integrity sha512-T1h3B10BRPKfcObdBklX639tVz+xh34O7GjofqrqiAQdm7eHsQ00ih18x6wuJ/E6FxdtS2u3FmUGPDeEcMwzNA==
|
||||
dependencies:
|
||||
jose "^4.15.4"
|
||||
lru-cache "^6.0.0"
|
||||
object-hash "^2.2.0"
|
||||
oidc-token-hash "^5.0.3"
|
||||
|
||||
opn@latest:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/opn/-/opn-6.0.0.tgz#3c5b0db676d5f97da1233d1ed42d182bc5a27d2d"
|
||||
|
@ -17452,11 +17594,30 @@ postmark@^3.0.14:
|
|||
dependencies:
|
||||
axios "^0.25.0"
|
||||
|
||||
preact@^10.5.13:
|
||||
preact-render-to-string@5.2.3:
|
||||
version "5.2.3"
|
||||
resolved "https://registry.yarnpkg.com/preact-render-to-string/-/preact-render-to-string-5.2.3.tgz#23d17376182af720b1060d5a4099843c7fe92fe4"
|
||||
integrity sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==
|
||||
dependencies:
|
||||
pretty-format "^3.8.0"
|
||||
|
||||
preact-render-to-string@^5.1.19:
|
||||
version "5.2.6"
|
||||
resolved "https://registry.yarnpkg.com/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz#0ff0c86cd118d30affb825193f18e92bd59d0604"
|
||||
integrity sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==
|
||||
dependencies:
|
||||
pretty-format "^3.8.0"
|
||||
|
||||
preact@10.11.3, preact@^10.5.13:
|
||||
version "10.11.3"
|
||||
resolved "https://registry.yarnpkg.com/preact/-/preact-10.11.3.tgz#8a7e4ba19d3992c488b0785afcc0f8aa13c78d19"
|
||||
integrity sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==
|
||||
|
||||
preact@^10.6.3:
|
||||
version "10.19.3"
|
||||
resolved "https://registry.yarnpkg.com/preact/-/preact-10.19.3.tgz#7a7107ed2598a60676c943709ea3efb8aaafa899"
|
||||
integrity sha512-nHHTeFVBTHRGxJXKkKu5hT8C/YWBkPso4/Gad6xuj5dbptt9iF9NZr9pHbPhBrnT2klheu7mHTxTZ/LjwJiEiQ==
|
||||
|
||||
prelude-ls@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
||||
|
@ -17526,6 +17687,11 @@ pretty-format@^28.1.1, pretty-format@^28.1.3:
|
|||
ansi-styles "^5.0.0"
|
||||
react-is "^18.0.0"
|
||||
|
||||
pretty-format@^3.8.0:
|
||||
version "3.8.0"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-3.8.0.tgz#bfbed56d5e9a776645f4b1ff7aa1a3ac4fa3c385"
|
||||
integrity sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==
|
||||
|
||||
pretty-hrtime@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
|
||||
|
@ -18281,6 +18447,11 @@ regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7:
|
|||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
|
||||
integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
|
||||
|
||||
regenerator-runtime@^0.14.0:
|
||||
version "0.14.1"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
|
||||
integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
|
||||
|
||||
regenerator-transform@^0.15.0:
|
||||
version "0.15.0"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537"
|
||||
|
@ -20087,6 +20258,18 @@ tar@^6.0.2:
|
|||
mkdirp "^1.0.3"
|
||||
yallist "^4.0.0"
|
||||
|
||||
tar@^6.1.11:
|
||||
version "6.2.0"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.0.tgz#b14ce49a79cb1cd23bc9b016302dea5474493f73"
|
||||
integrity sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==
|
||||
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"
|
||||
|
||||
telejson@^6.0.8:
|
||||
version "6.0.8"
|
||||
resolved "https://registry.yarnpkg.com/telejson/-/telejson-6.0.8.tgz#1c432db7e7a9212c1fbd941c3e5174ec385148f7"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue