diff --git a/@api/.dev.example.vars b/@api/.dev.example.vars index f7ba40c..2763e71 100644 --- a/@api/.dev.example.vars +++ b/@api/.dev.example.vars @@ -5,4 +5,5 @@ GOOGLE_CLIENT_SECRET= RESEND_API_KEY= RESEND_FROM= GITHUB_CLIENT_ID= -GITHUB_CLIENT_SECRET= \ No newline at end of file +GITHUB_CLIENT_SECRET= +TURNSTILE_SECRET_KEY= \ No newline at end of file diff --git a/@api/env.ts b/@api/env.ts index 0a5372c..906fc4c 100644 --- a/@api/env.ts +++ b/@api/env.ts @@ -12,6 +12,7 @@ export const envSchema = z.object({ GITHUB_CLIENT_SECRET: z.string(), RESEND_API_KEY: z.string(), RESEND_FROM: z.string(), + TURNSTILE_SECRET_KEY: z.string(), }) export type Env = z.infer diff --git a/@api/trpc.ts b/@api/trpc.ts index 9f4a5ad..9685ee3 100644 --- a/@api/trpc.ts +++ b/@api/trpc.ts @@ -9,7 +9,32 @@ const t = initTRPC.context().create({ export const middleware = t.middleware export const router = t.router -export const procedure = t.procedure +const turnstileMiddleware = middleware(async ({ ctx, next, type }) => { + if (type === 'mutation') { + const formData = new FormData() + formData.append('secret', ctx.env.TURNSTILE_SECRET_KEY) + formData.append('response', ctx.request.headers.get('X-Turnstile-Token')) + formData.append('remoteip', ctx.request.headers.get('CF-Connecting-IP')) + + const res = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', { + body: formData, + method: 'POST', + }) + const outcome = (await res.json()) as { success: boolean } + if (!outcome.success) { + throw new TRPCError({ + code: 'BAD_REQUEST', + message: 'You are behaving like an automated bot.', + }) + } + } + + return next({ + ctx, + }) +}) + +export const procedure = t.procedure.use(turnstileMiddleware) const authMiddleware = middleware(async ({ ctx, next }) => { const bearer = ctx.request.headers.get('Authorization') diff --git a/@web/.env.local b/@web/.env.local index f9feddb..4c79eda 100644 --- a/@web/.env.local +++ b/@web/.env.local @@ -1 +1,2 @@ -NEXT_PUBLIC_API_URL=http://localhost:8000 \ No newline at end of file +NEXT_PUBLIC_API_URL=http://localhost:8000 +NEXT_PUBLIC_TURNSTILE_SITE_KEY=0x4AAAAAAAOd1-P2R_2ooD0h diff --git a/@web/.env.preview b/@web/.env.preview index 63175ae..6f119fd 100644 --- a/@web/.env.preview +++ b/@web/.env.preview @@ -1 +1,2 @@ NEXT_PUBLIC_API_URL=https://preview.api.example.com +NEXT_PUBLIC_TURNSTILE_SITE_KEY=0x4AAAAAAAOd1-P2R_2ooD0h diff --git a/@web/.env.production b/@web/.env.production index 6c01aec..d61aef9 100644 --- a/@web/.env.production +++ b/@web/.env.production @@ -1 +1,2 @@ NEXT_PUBLIC_API_URL=https://api.example.com +NEXT_PUBLIC_TURNSTILE_SITE_KEY=0x4AAAAAAAOd1-P2R_2ooD0h diff --git a/@web/app/_providers/query.tsx b/@web/app/_providers/query.tsx index 4866571..1d03955 100644 --- a/@web/app/_providers/query.tsx +++ b/@web/app/_providers/query.tsx @@ -10,6 +10,7 @@ import { useState } from 'react' import SuperJSON from 'superjson' import { useToast } from '@ui/ui/use-toast' import { store } from './jotai' +import { showTurnstileAtom, turnstileRefAtom, turnstileTokenAtom } from './turnstile' export function QueryProvider({ children }: { children: React.ReactNode }) { const { toast } = useToast() @@ -66,6 +67,34 @@ export function QueryProvider({ children }: { children: React.ReactNode }) { return headers }, + async fetch(input, init) { + const method = init?.method?.toUpperCase() ?? 'GET' + if (method === 'POST' && init) { + if (!store.get(turnstileTokenAtom)) { + store.set(showTurnstileAtom, true) + await new Promise((resolve) => { + store.sub(turnstileTokenAtom, () => { + const token = store.get(turnstileTokenAtom) + if (token) { + resolve(token) + } + }) + }) + store.set(showTurnstileAtom, false) + } + + const token = store.get(turnstileTokenAtom) + + init.headers = { + ...init.headers, + 'X-Turnstile-Token': `${token}`, + } + store.set(turnstileTokenAtom, null) + store.get(turnstileRefAtom)?.reset() + } + + return await fetch(input, init) + }, }), ], }), diff --git a/@web/app/_providers/turnstile.tsx b/@web/app/_providers/turnstile.tsx new file mode 100644 index 0000000..acaa68b --- /dev/null +++ b/@web/app/_providers/turnstile.tsx @@ -0,0 +1,67 @@ +'use client' + +import type { TurnstileInstance } from '@marsidev/react-turnstile' +import { Turnstile } from '@marsidev/react-turnstile' +import * as Portal from '@radix-ui/react-portal' +import { env } from '@web/env' +import { atom, useAtom } from 'jotai' +import { useTheme } from 'next-themes' +import { useId, useRef } from 'react' +import { match } from 'ts-pattern' +import { useIsRendered } from '@ui/hooks/use-is-rendered' +import { cn } from '@ui/lib/utils' + +export const turnstileTokenAtom = atom(null) + +export const showTurnstileAtom = atom(false) + +export const turnstileRefAtom = atom(null) + +export default function TurnstileProvider({ children }: { children: React.ReactNode }) { + const { theme } = useTheme() + const [, setTurnstileToken] = useAtom(turnstileTokenAtom) + const [showTurnstile] = useAtom(showTurnstileAtom) + const turnstileRef = useRef(null) + const id = useId() + const isRendered = useIsRendered() + const [, _setTurnstileRef] = useAtom(turnstileRefAtom) + + return ( + <> + {children} + {isRendered && ( + +
+ 'dark' as const) + .with('light', () => 'light' as const) + .otherwise(() => 'auto' as const), + }} + onSuccess={(token) => { + _setTurnstileRef(turnstileRef.current) + setTurnstileToken(token) + }} + onError={() => setTurnstileToken(null)} + onExpire={() => { + setTurnstileToken(null) + turnstileRef.current?.reset() + }} + /> +
+
+ )} + + ) +} diff --git a/@web/app/layout.tsx b/@web/app/layout.tsx index 5c6f00d..b7564d8 100644 --- a/@web/app/layout.tsx +++ b/@web/app/layout.tsx @@ -6,6 +6,7 @@ import { Toaster } from '@ui/ui/toaster' import JotaiProvider from './_providers/jotai' import { QueryProvider } from './_providers/query' import { ThemeProvider } from './_providers/theme' +import TurnstileProvider from './_providers/turnstile' const inter = Inter({ subsets: ['latin'] }) @@ -21,9 +22,11 @@ export default function RootLayout({ children }: { children: React.ReactNode }) - -
{children}
-
+ + +
{children}
+
+
diff --git a/@web/components/profile-dropdown-menu.tsx b/@web/components/profile-dropdown-menu.tsx index bd2ec6f..d4f9563 100644 --- a/@web/components/profile-dropdown-menu.tsx +++ b/@web/components/profile-dropdown-menu.tsx @@ -175,7 +175,7 @@ function WorkspaceListItem(props: { organization: props.organization, }) }} - disabled={props.disabled} + disabled={mutation.isLoading || props.disabled} > {mutation.isLoading ? (
@@ -216,6 +216,7 @@ function WorkspaceListItem(props: { function LogoutDropdownMenuItem() { const [, setAuth] = useAtom(authAtom) + // TODO: call logout api return setAuth(RESET)}>Log out } diff --git a/@web/env.ts b/@web/env.ts index 1234046..63ca562 100644 --- a/@web/env.ts +++ b/@web/env.ts @@ -14,6 +14,7 @@ export const env = createEnv({ */ client: { NEXT_PUBLIC_API_URL: z.string().url(), + NEXT_PUBLIC_TURNSTILE_SITE_KEY: z.string(), }, /* * Due to how Next.js bundles environment variables on Edge and Client, @@ -23,5 +24,6 @@ export const env = createEnv({ */ runtimeEnv: { NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL, + NEXT_PUBLIC_TURNSTILE_SITE_KEY: process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY, }, }) diff --git a/@web/package.json b/@web/package.json index dadc83b..27a6482 100644 --- a/@web/package.json +++ b/@web/package.json @@ -11,7 +11,9 @@ }, "dependencies": { "@dinstack/ui": "workspace:^", + "@marsidev/react-turnstile": "^0.4.0", "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-portal": "^1.0.4", "@t3-oss/env-nextjs": "^0.7.1", "@tanstack/react-query": "^4.36.1", "@trpc/client": "^10.44.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 188ed0a..4f21171 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -131,7 +131,7 @@ importers: version: 1.0.5(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-slot': specifier: ^1.0.2 - version: 1.0.2(react@18.2.0) + version: 1.0.2(@types/react@18.2.43)(react@18.2.0) '@radix-ui/react-toast': specifier: ^1.1.5 version: 1.1.5(react-dom@18.2.0)(react@18.2.0) @@ -166,9 +166,15 @@ importers: '@dinstack/ui': specifier: workspace:^ version: link:../@ui + '@marsidev/react-turnstile': + specifier: ^0.4.0 + version: 0.4.0(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-icons': specifier: ^1.3.0 version: 1.3.0(react@18.2.0) + '@radix-ui/react-portal': + specifier: ^1.0.4 + version: 1.0.4(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) '@t3-oss/env-nextjs': specifier: ^0.7.1 version: 0.7.1(typescript@5.3.3)(zod@3.22.4) @@ -1211,6 +1217,16 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 dev: true + /@marsidev/react-turnstile@0.4.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-U0lwTWQhP04AnIdWEbLpF/phpqtblNbrnE4yJMdvGyeOZOTmuHW3wB+V8X+BO55pTXZitp2GgJsrGkbUjwJIeQ==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@neondatabase/serverless@0.6.0: resolution: {integrity: sha512-qXxBRYN0m2v8kVQBfMxbzNGn2xFAhTXFibzQlE++NfJ56Shz3m7+MyBBtXDlEH+3Wfa6lToDXf1MElocY4sJ3w==} dependencies: @@ -1621,7 +1637,7 @@ packages: optional: true dependencies: '@babel/runtime': 7.23.5 - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -1640,15 +1656,15 @@ packages: optional: true dependencies: '@babel/runtime': 7.23.5 - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.43)(react@18.2.0) '@radix-ui/react-context': 1.0.1(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-slot': 1.0.2(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.43)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-compose-refs@1.0.1(react@18.2.0): + /@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.43)(react@18.2.0): resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} peerDependencies: '@types/react': '*' @@ -1658,6 +1674,7 @@ packages: optional: true dependencies: '@babel/runtime': 7.23.5 + '@types/react': 18.2.43 react: 18.2.0 dev: false @@ -1689,16 +1706,16 @@ packages: dependencies: '@babel/runtime': 7.23.5 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.43)(react@18.2.0) '@radix-ui/react-context': 1.0.1(react@18.2.0) '@radix-ui/react-dismissable-layer': 1.0.5(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-focus-guards': 1.0.1(react@18.2.0) '@radix-ui/react-focus-scope': 1.0.4(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-id': 1.0.1(react@18.2.0) - '@radix-ui/react-portal': 1.0.4(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-presence': 1.0.1(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-slot': 1.0.2(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.43)(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) aria-hidden: 1.2.3 react: 18.2.0 @@ -1734,8 +1751,8 @@ packages: dependencies: '@babel/runtime': 7.23.5 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.43)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) '@radix-ui/react-use-escape-keydown': 1.0.3(react@18.2.0) react: 18.2.0 @@ -1757,11 +1774,11 @@ packages: dependencies: '@babel/runtime': 7.23.5 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.43)(react@18.2.0) '@radix-ui/react-context': 1.0.1(react@18.2.0) '@radix-ui/react-id': 1.0.1(react@18.2.0) '@radix-ui/react-menu': 2.0.6(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -1794,8 +1811,8 @@ packages: optional: true dependencies: '@babel/runtime': 7.23.5 - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.43)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -1837,7 +1854,7 @@ packages: optional: true dependencies: '@babel/runtime': 7.23.5 - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -1858,7 +1875,7 @@ packages: '@babel/runtime': 7.23.5 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.43)(react@18.2.0) '@radix-ui/react-context': 1.0.1(react@18.2.0) '@radix-ui/react-direction': 1.0.1(react@18.2.0) '@radix-ui/react-dismissable-layer': 1.0.5(react-dom@18.2.0)(react@18.2.0) @@ -1866,11 +1883,11 @@ packages: '@radix-ui/react-focus-scope': 1.0.4(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-id': 1.0.1(react@18.2.0) '@radix-ui/react-popper': 1.1.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-portal': 1.0.4(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-presence': 1.0.1(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-roving-focus': 1.0.4(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-slot': 1.0.2(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.43)(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) aria-hidden: 1.2.3 react: 18.2.0 @@ -1894,9 +1911,9 @@ packages: '@babel/runtime': 7.23.5 '@floating-ui/react-dom': 2.0.4(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-arrow': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.43)(react@18.2.0) '@radix-ui/react-context': 1.0.1(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) '@radix-ui/react-use-rect': 1.0.1(react@18.2.0) @@ -1906,7 +1923,7 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-portal@1.0.4(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-portal@1.0.4(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==} peerDependencies: '@types/react': '*' @@ -1920,7 +1937,9 @@ packages: optional: true dependencies: '@babel/runtime': 7.23.5 - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.43 + '@types/react-dom': 18.2.17 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -1939,13 +1958,13 @@ packages: optional: true dependencies: '@babel/runtime': 7.23.5 - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.43)(react@18.2.0) '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-primitive@1.0.3(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} peerDependencies: '@types/react': '*' @@ -1959,7 +1978,9 @@ packages: optional: true dependencies: '@babel/runtime': 7.23.5 - '@radix-ui/react-slot': 1.0.2(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.43)(react@18.2.0) + '@types/react': 18.2.43 + '@types/react-dom': 18.2.17 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -1980,11 +2001,11 @@ packages: '@babel/runtime': 7.23.5 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.43)(react@18.2.0) '@radix-ui/react-context': 1.0.1(react@18.2.0) '@radix-ui/react-direction': 1.0.1(react@18.2.0) '@radix-ui/react-id': 1.0.1(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) react: 18.2.0 @@ -2007,18 +2028,18 @@ packages: '@babel/runtime': 7.23.5 '@radix-ui/number': 1.0.1 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.43)(react@18.2.0) '@radix-ui/react-context': 1.0.1(react@18.2.0) '@radix-ui/react-direction': 1.0.1(react@18.2.0) '@radix-ui/react-presence': 1.0.1(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-slot@1.0.2(react@18.2.0): + /@radix-ui/react-slot@1.0.2(@types/react@18.2.43)(react@18.2.0): resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} peerDependencies: '@types/react': '*' @@ -2028,7 +2049,8 @@ packages: optional: true dependencies: '@babel/runtime': 7.23.5 - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.43)(react@18.2.0) + '@types/react': 18.2.43 react: 18.2.0 dev: false @@ -2048,12 +2070,12 @@ packages: '@babel/runtime': 7.23.5 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.43)(react@18.2.0) '@radix-ui/react-context': 1.0.1(react@18.2.0) '@radix-ui/react-dismissable-layer': 1.0.5(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-portal': 1.0.4(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-presence': 1.0.1(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) @@ -2158,7 +2180,7 @@ packages: optional: true dependencies: '@babel/runtime': 7.23.5 - '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.43)(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -2333,7 +2355,6 @@ packages: resolution: {integrity: sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==} dependencies: '@types/react': 18.2.43 - dev: true /@types/react@18.2.43: resolution: {integrity: sha512-nvOV01ZdBdd/KW6FahSbcNplt2jCJfyWdTos61RYHV+FVv5L/g9AOX1bmbVcWcLFL8+KHQfh1zVIQrud6ihyQA==}