chore(www): hcaptcha opt-out verification (#34265)

* chore(www): hcaptcha opt-out verification

* invisible HCaptcha

* small styling updates
This commit is contained in:
Alaister Young
2025-03-19 18:41:52 +01:00
committed by GitHub
parent 23cb42e567
commit 192e60b941
6 changed files with 134 additions and 117 deletions

View File

@@ -10,3 +10,5 @@ NEXT_PUBLIC_SUPABASE_ANON_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJz
NEXT_PUBLIC_SUPABASE_URL="https://xguihxuzqibwxjnimxev.supabase.co"
SUPABASE_COM_SERVICE_ROLE_KEY="secret"
NEXT_PUBLIC_URL="http://localhost:3000"
NEXT_PUBLIC_HCAPTCHA_SITE_KEY="10000000-ffff-ffff-ffff-000000000001"
HCAPTCHA_SECRET_KEY="0x0000000000000000000000000000000000000000

View File

@@ -3,10 +3,33 @@ import { createClient } from '@supabase/supabase-js'
const supabaseUrl = process.env.NEXT_PUBLIC_EMAIL_ABUSE_URL as string
const supabaseServiceKey = process.env.EMAIL_ABUSE_SERVICE_KEY as string
const hcaptchaSecret = process.env.HCAPTCHA_SECRET_KEY as string
// Function to verify hCaptcha token
async function verifyCaptcha(token: string): Promise<boolean> {
try {
const response = await fetch('https://api.hcaptcha.com/siteverify', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
secret: hcaptchaSecret,
response: token,
}),
})
const data = await response.json()
return data.success === true
} catch (error) {
console.error('Error verifying captcha:', error)
return false
}
}
export async function POST(req: NextRequest, { params }: { params: { ref: string } }) {
const ref = params.ref
const { reason, email } = await req.json()
const { reason, email, captchaToken } = await req.json()
const supabase = createClient(supabaseUrl, supabaseServiceKey)
@@ -27,6 +50,22 @@ export async function POST(req: NextRequest, { params }: { params: { ref: string
)
}
// Verify captcha token
if (!captchaToken) {
return NextResponse.json(
{ error: 'Bad Request: Missing captcha verification.' },
{ status: 400 }
)
}
const isValidCaptcha = await verifyCaptcha(captchaToken)
if (!isValidCaptcha) {
return NextResponse.json(
{ error: 'Bad Request: Invalid captcha verification.' },
{ status: 400 }
)
}
try {
const { error: supabaseError } = await supabase
.from('manual_reports')

View File

@@ -18,6 +18,7 @@
},
"dependencies": {
"@code-hike/mdx": "^0.9.0",
"@hcaptcha/react-hcaptcha": "^1.11.1",
"@heroicons/react": "^1.0.6",
"@mdx-js/react": "^2.3.0",
"@next/bundle-analyzer": "^14.2.3",

View File

@@ -1,8 +1,10 @@
import HCaptcha from '@hcaptcha/react-hcaptcha'
import { zodResolver } from '@hookform/resolvers/zod'
import Layout from 'components/Layouts/Default'
import { NextSeo } from 'next-seo'
import { useTheme } from 'next-themes'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { useEffect, useRef, useState } from 'react'
import { useForm } from 'react-hook-form'
import {
Button,
@@ -24,25 +26,29 @@ import { z } from 'zod'
const formSchema = z.object({
ref: z.string(),
reason: z.string().optional(),
captchaToken: z.string().min(1, 'Please complete the captcha verification'),
})
export default function OptOutPage() {
const router = useRouter()
const { resolvedTheme } = useTheme()
const ref = router.query.ref as string
const email = router.query.email as string | undefined
const [formMessage, setFormMessage] = useState<string | null>(null)
const [submissionType, setSubmissionType] = useState<'success' | 'error' | null>(null)
const captchaRef = useRef<HCaptcha | null>(null)
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
ref: ref,
reason: undefined,
captchaToken: '',
},
})
const { register } = form
const { register, setValue } = form
// Ensure ref is a string
const refString = typeof ref !== 'string'
@@ -50,6 +56,10 @@ export default function OptOutPage() {
const refIsInvalid = !refString && !refPattern.test(ref)
const SelectItemContainerClasses = 'flex flex-col text-sm items-start'
const handleCaptchaVerify = (token: string) => {
setValue('captchaToken', token)
}
const onSubmit = async (data: z.infer<typeof formSchema>) => {
try {
setSubmissionType(null)
@@ -60,7 +70,11 @@ export default function OptOutPage() {
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ reason: data.reason, email: email }),
body: JSON.stringify({
reason: data.reason,
email: email,
captchaToken: data.captchaToken,
}),
})
const message = await response.text()
@@ -68,17 +82,35 @@ export default function OptOutPage() {
setFormMessage('Error: Invalid project reference.')
setSubmissionType('error')
} else if (response.ok) {
setFormMessage(message)
try {
const parsedMessage = JSON.parse(message)
if (!parsedMessage.message) {
throw new Error()
}
setFormMessage(parsedMessage.message)
} catch {
setFormMessage(message)
}
setSubmissionType('success')
} else {
console.error('Form submission failed:', message)
setFormMessage('Error: Form submission failed.')
setSubmissionType('error')
}
// Reset captcha after submission
captchaRef.current?.resetCaptcha()
setValue('captchaToken', '')
} catch (error) {
console.error('Error submitting form:', error)
setFormMessage('Error: An unexpected error occurred.')
setSubmissionType('error')
// Reset captcha after error
captchaRef.current?.resetCaptcha()
setValue('captchaToken', '')
}
}
@@ -94,7 +126,7 @@ export default function OptOutPage() {
}
useEffect(() => {
form.reset({ ref: ref, reason: '' })
form.reset({ ref: ref, reason: '', captchaToken: '' })
}, [ref])
return (
@@ -114,8 +146,9 @@ export default function OptOutPage() {
)}
<Form_Shadcn_ {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="gap-4 max-w-xs flex flex-col">
<form onSubmit={form.handleSubmit(onSubmit)} className="gap-2 max-w-xs flex flex-col">
<input hidden value={form.getValues('ref')} readOnly {...register('ref')} />
<input hidden {...register('captchaToken')} />
<FormField_Shadcn_
name="reason"
control={form.control}
@@ -175,6 +208,25 @@ export default function OptOutPage() {
</FormItemLayout>
)}
/>
<div>
<HCaptcha
sitekey={process.env.NEXT_PUBLIC_HCAPTCHA_SITE_KEY || ''}
onVerify={handleCaptchaVerify}
ref={(ref) => {
captchaRef.current = ref
ref?.execute()
}}
theme={resolvedTheme}
size="invisible"
/>
{form.formState.errors.captchaToken && (
<p className="text-sm text-destructive mt-1">
{form.formState.errors.captchaToken.message}
</p>
)}
</div>
<Button htmlType="submit" size="small" disabled={submissionType === 'success'}>
Report spam
</Button>

141
pnpm-lock.yaml generated
View File

@@ -88,10 +88,10 @@ importers:
version: 1.2.0
next:
specifier: 'catalog:'
version: 14.2.21(@babel/core@7.26.9(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
version: 14.2.21(@babel/core@7.24.7(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
next-contentlayer2:
specifier: 0.4.6
version: 0.4.6(contentlayer2@0.4.6(esbuild@0.25.1)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.25.1)(markdown-wasm@1.2.0)(next@14.2.21(@babel/core@7.26.9(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(supports-color@8.1.1)
version: 0.4.6(contentlayer2@0.4.6(esbuild@0.25.1)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.25.1)(markdown-wasm@1.2.0)(next@14.2.21(@babel/core@7.24.7(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(supports-color@8.1.1)
next-themes:
specifier: ^0.3.0
version: 0.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -341,7 +341,7 @@ importers:
version: 1.0.1
next:
specifier: 'catalog:'
version: 14.2.21(@babel/core@7.26.9(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
version: 14.2.21(@babel/core@7.24.7(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
next-mdx-remote:
specifier: ^4.4.1
version: 4.4.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(supports-color@8.1.1)
@@ -868,7 +868,7 @@ importers:
version: 9.3.4
'@testing-library/jest-dom':
specifier: ^6.4.6
version: 6.4.6(@jest/globals@29.7.0(supports-color@8.1.1))(@types/jest@29.5.5)(jest@29.7.0(@types/node@20.12.11)(supports-color@8.1.1))(vitest@3.0.4)
version: 6.4.6(@jest/globals@29.7.0(supports-color@8.1.1))(@types/jest@29.5.5)(jest@29.7.0(@types/node@20.12.11)(supports-color@8.1.1))(vitest@3.0.4(@types/node@20.12.11)(@vitest/ui@3.0.4)(jsdom@20.0.3(supports-color@8.1.1))(msw@2.4.11(typescript@5.5.2))(sass@1.72.0)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.19.3)(yaml@2.4.5))
'@testing-library/react':
specifier: ^14.0.0
version: 14.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -1004,6 +1004,9 @@ importers:
'@code-hike/mdx':
specifier: ^0.9.0
version: 0.9.0(encoding@0.1.13)(react@18.2.0)
'@hcaptcha/react-hcaptcha':
specifier: ^1.11.1
version: 1.11.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@heroicons/react':
specifier: ^1.0.6
version: 1.0.6(react@18.2.0)
@@ -1096,7 +1099,7 @@ importers:
version: 1.2.0
next:
specifier: 'catalog:'
version: 14.2.21(@babel/core@7.26.9(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
version: 14.2.21(@babel/core@7.24.7(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
next-contentlayer2:
specifier: 0.5.3
version: 0.5.3(contentlayer2@0.5.3(esbuild@0.25.1)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.25.1)(markdown-wasm@1.2.0)(next@14.2.21(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(supports-color@8.1.1)
@@ -1353,7 +1356,7 @@ importers:
version: 0.7.12
'@vercel/flags':
specifier: ^2.6.0
version: 2.6.0(next@14.2.21(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
version: 2.6.0(next@14.2.21(@babel/core@7.24.7(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
api-types:
specifier: workspace:*
version: link:../api-types
@@ -1368,7 +1371,7 @@ importers:
version: 4.17.21
next:
specifier: 'catalog:'
version: 14.2.21(@babel/core@7.26.9(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
version: 14.2.21(@babel/core@7.24.7(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
next-themes:
specifier: ^0.3.0
version: 0.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -1492,7 +1495,7 @@ importers:
version: 8.11.11
'@vitest/coverage-v8':
specifier: 2.1.8
version: 2.1.8(supports-color@8.1.1)(vitest@3.0.4)
version: 2.1.8(supports-color@8.1.1)(vitest@3.0.4(@types/node@22.13.10)(@vitest/ui@3.0.4)(jsdom@20.0.3(supports-color@8.1.1))(msw@2.4.11(typescript@5.5.2))(sass@1.72.0)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.19.3)(yaml@2.4.5))
npm-run-all:
specifier: ^4.1.5
version: 4.1.5
@@ -1658,7 +1661,7 @@ importers:
version: 0.436.0(react@18.2.0)
next:
specifier: 'catalog:'
version: 14.2.21(@babel/core@7.26.9(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
version: 14.2.21(@babel/core@7.24.7(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
next-themes:
specifier: ^0.3.0
version: 0.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -1758,7 +1761,7 @@ importers:
version: 3.6.1
'@testing-library/jest-dom':
specifier: ^6.1.3
version: 6.4.6(@jest/globals@29.7.0(supports-color@8.1.1))(@types/jest@29.5.5)(jest@29.7.0(@types/node@20.12.11)(supports-color@8.1.1))(vitest@3.0.4)
version: 6.4.6(@jest/globals@29.7.0(supports-color@8.1.1))(@types/jest@29.5.5)(jest@29.7.0(@types/node@20.12.11)(supports-color@8.1.1))(vitest@3.0.4(@types/node@20.12.11)(@vitest/ui@3.0.4)(jsdom@20.0.3(supports-color@8.1.1))(msw@2.4.11(typescript@5.5.2))(sass@1.72.0)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.19.3)(yaml@2.4.5))
'@testing-library/react':
specifier: ^14.0.0
version: 14.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -1866,7 +1869,7 @@ importers:
version: 0.33.0
next:
specifier: 'catalog:'
version: 14.2.21(@babel/core@7.26.9(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
version: 14.2.21(@babel/core@7.24.7(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
next-themes:
specifier: '*'
version: 0.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -1945,7 +1948,7 @@ importers:
version: 10.1.0
'@testing-library/jest-dom':
specifier: ^6.4.6
version: 6.4.6(@jest/globals@29.7.0(supports-color@8.1.1))(@types/jest@29.5.5)(jest@29.7.0(@types/node@20.12.11)(supports-color@8.1.1))(vitest@3.0.4)
version: 6.4.6(@jest/globals@29.7.0(supports-color@8.1.1))(@types/jest@29.5.5)(jest@29.7.0(@types/node@20.12.11)(supports-color@8.1.1))(vitest@3.0.4(@types/node@20.12.11)(@vitest/ui@3.0.4)(jsdom@20.0.3(supports-color@8.1.1))(msw@2.4.11(typescript@5.5.2))(sass@1.72.0)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.19.3)(yaml@2.4.5))
'@testing-library/react':
specifier: ^16.0.0
version: 16.0.0(@testing-library/dom@10.1.0)(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -1975,7 +1978,7 @@ importers:
version: link:../api-types
next-router-mock:
specifier: ^0.9.13
version: 0.9.13(next@14.2.21(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0))(react@18.2.0)
version: 0.9.13(next@14.2.21(@babel/core@7.24.7(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0))(react@18.2.0)
typescript:
specifier: ~5.5.0
version: 5.5.2
@@ -2233,10 +2236,6 @@ packages:
resolution: {integrity: sha512-SRijHmF0PSPgLIBYlWnG0hyeJLwXE2CgpsXaMOrtt2yp9/86ALw6oUlj9KYuZ0JN07T4eBMVIW4li/9S1j2BGA==}
engines: {node: '>=6.9.0'}
'@babel/core@7.26.9':
resolution: {integrity: sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==}
engines: {node: '>=6.9.0'}
'@babel/generator@7.24.7':
resolution: {integrity: sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==}
engines: {node: '>=6.9.0'}
@@ -7433,6 +7432,7 @@ packages:
resolution: {integrity: sha512-t0q23FIpvHDTtnORW+bDJziGsal5uh9RJTJ1fyH8drd4lICOoXhJ5pLMUZ5C0VQei6dNmwTzzoTRgMkO9JgHEQ==}
peerDependencies:
eslint: '>= 5'
bundledDependencies: []
eslint-plugin-import@2.29.1:
resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
@@ -13462,27 +13462,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@babel/core@7.26.9(supports-color@8.1.1)':
dependencies:
'@ampproject/remapping': 2.3.0
'@babel/code-frame': 7.26.2
'@babel/generator': 7.26.10
'@babel/helper-compilation-targets': 7.26.5
'@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.9(supports-color@8.1.1))(supports-color@8.1.1)
'@babel/helpers': 7.26.10
'@babel/parser': 7.26.10
'@babel/template': 7.26.9
'@babel/traverse': 7.26.10(supports-color@8.1.1)
'@babel/types': 7.26.10
convert-source-map: 2.0.0
debug: 4.4.0(supports-color@8.1.1)
gensync: 1.0.0-beta.2
json5: 2.2.3
semver: 6.3.1
transitivePeerDependencies:
- supports-color
optional: true
'@babel/generator@7.24.7':
dependencies:
'@babel/types': 7.26.7
@@ -13580,16 +13559,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@babel/helper-module-transforms@7.26.0(@babel/core@7.26.9(supports-color@8.1.1))(supports-color@8.1.1)':
dependencies:
'@babel/core': 7.26.9(supports-color@8.1.1)
'@babel/helper-module-imports': 7.25.9(supports-color@8.1.1)
'@babel/helper-validator-identifier': 7.25.9
'@babel/traverse': 7.26.7(supports-color@8.1.1)
transitivePeerDependencies:
- supports-color
optional: true
'@babel/helper-plugin-utils@7.24.8': {}
'@babel/helper-plugin-utils@7.26.5':
@@ -17300,7 +17269,7 @@ snapshots:
lz-string: 1.5.0
pretty-format: 27.5.1
'@testing-library/jest-dom@6.4.6(@jest/globals@29.7.0(supports-color@8.1.1))(@types/jest@29.5.5)(jest@29.7.0(@types/node@20.12.11)(supports-color@8.1.1))(vitest@3.0.4)':
'@testing-library/jest-dom@6.4.6(@jest/globals@29.7.0(supports-color@8.1.1))(@types/jest@29.5.5)(jest@29.7.0(@types/node@20.12.11)(supports-color@8.1.1))(vitest@3.0.4(@types/node@20.12.11)(@vitest/ui@3.0.4)(jsdom@20.0.3(supports-color@8.1.1))(msw@2.4.11(typescript@5.5.2))(sass@1.72.0)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.19.3)(yaml@2.4.5))':
dependencies:
'@adobe/css-tools': 4.4.0
'@babel/runtime': 7.24.7
@@ -17952,14 +17921,6 @@ snapshots:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
'@vercel/flags@2.6.0(next@14.2.21(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
jose: 5.2.1
optionalDependencies:
next: 14.2.21(@babel/core@7.26.9(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
'@vercel/og@0.6.2':
dependencies:
'@resvg/resvg-wasm': 2.4.0
@@ -17977,7 +17938,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@vitest/coverage-v8@2.1.8(supports-color@8.1.1)(vitest@3.0.4)':
'@vitest/coverage-v8@2.1.8(supports-color@8.1.1)(vitest@3.0.4(@types/node@22.13.10)(@vitest/ui@3.0.4)(jsdom@20.0.3(supports-color@8.1.1))(msw@2.4.11(typescript@5.5.2))(sass@1.72.0)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.19.3)(yaml@2.4.5))':
dependencies:
'@ampproject/remapping': 2.3.0
'@bcoe/v8-coverage': 0.2.3
@@ -18962,7 +18923,7 @@ snapshots:
code-red@1.0.4:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
'@types/estree': 1.0.6
'@types/estree': 1.0.5
acorn: 8.14.1
estree-walker: 3.0.3
periscopic: 3.1.0
@@ -19889,7 +19850,7 @@ snapshots:
debug: 4.4.0(supports-color@8.1.1)
enhanced-resolve: 5.17.1
eslint: 8.57.0(supports-color@8.1.1)
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9(supports-color@8.1.1))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1)
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9(supports-color@8.1.1))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9(supports-color@8.1.1))(eslint-plugin-import@2.29.1)(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1))(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.5.2))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1)
fast-glob: 3.3.2
get-tsconfig: 4.7.2
@@ -19901,7 +19862,7 @@ snapshots:
- eslint-import-resolver-webpack
- supports-color
eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9(supports-color@8.1.1))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1):
eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9(supports-color@8.1.1))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9(supports-color@8.1.1))(eslint-plugin-import@2.29.1)(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1))(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1):
dependencies:
debug: 3.2.7(supports-color@8.1.1)
optionalDependencies:
@@ -19928,7 +19889,7 @@ snapshots:
doctrine: 2.1.0
eslint: 8.57.0(supports-color@8.1.1)
eslint-import-resolver-node: 0.3.9(supports-color@8.1.1)
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9(supports-color@8.1.1))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1)
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9(supports-color@8.1.1))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9(supports-color@8.1.1))(eslint-plugin-import@2.29.1)(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1))(eslint@8.57.0(supports-color@8.1.1))(supports-color@8.1.1)
hasown: 2.0.2
is-core-module: 2.13.1
is-glob: 4.0.3
@@ -23404,12 +23365,12 @@ snapshots:
neo-async@2.6.2: {}
next-contentlayer2@0.4.6(contentlayer2@0.4.6(esbuild@0.25.1)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.25.1)(markdown-wasm@1.2.0)(next@14.2.21(@babel/core@7.26.9(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(supports-color@8.1.1):
next-contentlayer2@0.4.6(contentlayer2@0.4.6(esbuild@0.25.1)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.25.1)(markdown-wasm@1.2.0)(next@14.2.21(@babel/core@7.24.7(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(supports-color@8.1.1):
dependencies:
'@contentlayer2/core': 0.4.3(esbuild@0.25.1)(markdown-wasm@1.2.0)(supports-color@8.1.1)
'@contentlayer2/utils': 0.4.3
contentlayer2: 0.4.6(esbuild@0.25.1)(markdown-wasm@1.2.0)(supports-color@8.1.1)
next: 14.2.21(@babel/core@7.26.9(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
next: 14.2.21(@babel/core@7.24.7(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
transitivePeerDependencies:
@@ -23423,7 +23384,7 @@ snapshots:
'@contentlayer2/core': 0.5.3(esbuild@0.25.1)(markdown-wasm@1.2.0)(supports-color@8.1.1)
'@contentlayer2/utils': 0.5.3
contentlayer2: 0.5.3(esbuild@0.25.1)(markdown-wasm@1.2.0)(supports-color@8.1.1)
next: 14.2.21(@babel/core@7.26.9(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
next: 14.2.21(@babel/core@7.24.7(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
transitivePeerDependencies:
@@ -23452,14 +23413,9 @@ snapshots:
next: 14.2.21(@babel/core@7.24.7(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
react: 18.2.0
next-router-mock@0.9.13(next@14.2.21(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0))(react@18.2.0):
dependencies:
next: 14.2.21(@babel/core@7.26.9(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
react: 18.2.0
next-seo@6.5.0(next@14.2.21(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
next: 14.2.21(@babel/core@7.26.9(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
next: 14.2.21(@babel/core@7.24.7(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
@@ -23496,34 +23452,6 @@ snapshots:
- '@babel/core'
- babel-plugin-macros
next@14.2.21(@babel/core@7.26.9(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0):
dependencies:
'@next/env': 14.2.21
'@swc/helpers': 0.5.5
busboy: 1.6.0
caniuse-lite: 1.0.30001695
graceful-fs: 4.2.11
postcss: 8.4.31
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
styled-jsx: 5.1.1(@babel/core@7.26.9(supports-color@8.1.1))(react@18.2.0)
optionalDependencies:
'@next/swc-darwin-arm64': 14.2.21
'@next/swc-darwin-x64': 14.2.21
'@next/swc-linux-arm64-gnu': 14.2.21
'@next/swc-linux-arm64-musl': 14.2.21
'@next/swc-linux-x64-gnu': 14.2.21
'@next/swc-linux-x64-musl': 14.2.21
'@next/swc-win32-arm64-msvc': 14.2.21
'@next/swc-win32-ia32-msvc': 14.2.21
'@next/swc-win32-x64-msvc': 14.2.21
'@opentelemetry/api': 1.9.0
'@playwright/test': 1.49.1
sass: 1.72.0
transitivePeerDependencies:
- '@babel/core'
- babel-plugin-macros
nice-try@1.0.5: {}
no-case@3.0.4:
@@ -23676,7 +23604,7 @@ snapshots:
nuqs@1.19.1(next@14.2.21(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)):
dependencies:
mitt: 3.0.1
next: 14.2.21(@babel/core@7.26.9(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
next: 14.2.21(@babel/core@7.24.7(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0)
nuqs@2.4.1(next@14.2.21(@babel/core@7.24.7(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.72.0))(react@18.2.0):
dependencies:
@@ -25866,13 +25794,6 @@ snapshots:
optionalDependencies:
'@babel/core': 7.24.7(supports-color@8.1.1)
styled-jsx@5.1.1(@babel/core@7.26.9(supports-color@8.1.1))(react@18.2.0):
dependencies:
client-only: 0.0.1
react: 18.2.0
optionalDependencies:
'@babel/core': 7.26.9(supports-color@8.1.1)
stylis@4.3.1: {}
sucrase@3.34.0:
@@ -25919,7 +25840,7 @@ snapshots:
'@ampproject/remapping': 2.3.0
'@jridgewell/sourcemap-codec': 1.5.0
'@jridgewell/trace-mapping': 0.3.25
'@types/estree': 1.0.6
'@types/estree': 1.0.5
acorn: 8.14.1
aria-query: 5.3.2
axobject-query: 4.1.0
@@ -26986,7 +26907,7 @@ snapshots:
webpack@5.94.0:
dependencies:
'@types/estree': 1.0.6
'@types/estree': 1.0.5
'@webassemblyjs/ast': 1.14.1
'@webassemblyjs/wasm-edit': 1.14.1
'@webassemblyjs/wasm-parser': 1.14.1
@@ -27016,7 +26937,7 @@ snapshots:
webpack@5.94.0(esbuild@0.25.1):
dependencies:
'@types/estree': 1.0.6
'@types/estree': 1.0.5
'@webassemblyjs/ast': 1.14.1
'@webassemblyjs/wasm-edit': 1.14.1
'@webassemblyjs/wasm-parser': 1.14.1

View File

@@ -89,6 +89,8 @@
"NEXT_PUBLIC_VERCEL_ENV",
"NEXT_PUBLIC_VERCEL_BRANCH_URL",
"NEXT_PUBLIC_API_URL",
"NEXT_PUBLIC_HCAPTCHA_SITE_KEY",
"HCAPTCHA_SECRET_KEY",
"NODE_ENV",
// These envs are used in the packages
"NEXT_PUBLIC_STORAGE_KEY",