Add contact form backend and deployment guide
- Resend API 통합 (이메일 발송) - ContactForm 클라이언트 컴포넌트 생성 - API Route (/api/contact) 구현 - 입력 검증 및 에러 처리 - 성공/실패 메시지 표시 - 환경변수 설정 (.env.local, .env.example) - 배포 가이드 작성 (DEPLOYMENT.md) - Resend 설정 방법 - Vercel 배포 가이드 - 가비아 도메인 연결 방법 - 트러블슈팅 가이드 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
237
DEPLOYMENT.md
Normal file
237
DEPLOYMENT.md
Normal file
@@ -0,0 +1,237 @@
|
||||
# 🚀 배포 가이드
|
||||
|
||||
## 1️⃣ Resend 설정 (이메일 발송)
|
||||
|
||||
### 1단계: Resend 계정 생성
|
||||
1. [resend.com](https://resend.com) 접속
|
||||
2. "Sign Up" 클릭 → GitHub 계정으로 가입
|
||||
3. 무료 티어: 월 3,000건 (충분함!)
|
||||
|
||||
### 2단계: API Key 발급
|
||||
1. Dashboard → "API Keys" 메뉴
|
||||
2. "Create API Key" 클릭
|
||||
3. Name: `jaengseung-made-production`
|
||||
4. Permission: `Sending access`
|
||||
5. 생성된 키 복사 (한 번만 표시됨!)
|
||||
|
||||
### 3단계: 도메인 인증 (선택사항)
|
||||
**옵션 A: Resend 서브도메인 사용 (간단)**
|
||||
- `onboarding@resend.dev`에서 발송
|
||||
- 바로 사용 가능
|
||||
|
||||
**옵션 B: 커스텀 도메인 사용 (전문적)**
|
||||
1. Resend Dashboard → "Domains"
|
||||
2. "Add Domain" 클릭
|
||||
3. `jaengseung-made.com` 입력
|
||||
4. DNS 레코드 복사
|
||||
|
||||
**가비아 DNS 설정:**
|
||||
1. [가비아 My가비아](https://my.gabia.com) 로그인
|
||||
2. "도메인" → "jaengseung-made.com" 선택
|
||||
3. "DNS 정보" → "DNS 관리" 클릭
|
||||
4. Resend에서 제공한 레코드 추가:
|
||||
```
|
||||
Type: TXT
|
||||
Host: _resend
|
||||
Value: [Resend에서 제공한 값]
|
||||
|
||||
Type: MX
|
||||
Host: @
|
||||
Value: [Resend에서 제공한 값]
|
||||
Priority: 10
|
||||
```
|
||||
5. 저장 후 10~30분 대기
|
||||
6. Resend에서 "Verify" 클릭
|
||||
|
||||
### 4단계: 로컬 환경변수 설정
|
||||
`.env.local` 파일 수정:
|
||||
```bash
|
||||
RESEND_API_KEY=re_your_actual_api_key_here
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2️⃣ Vercel 배포
|
||||
|
||||
### 1단계: GitHub 연동 (권장)
|
||||
|
||||
**GitHub에 푸시:**
|
||||
```bash
|
||||
# GitHub에 새 저장소 생성 (jaengseung-made)
|
||||
git remote add github https://github.com/your-username/jaengseung-made.git
|
||||
git push github main
|
||||
```
|
||||
|
||||
**Vercel 배포:**
|
||||
1. [vercel.com](https://vercel.com) 가입 (GitHub 연동)
|
||||
2. "Add New Project" 클릭
|
||||
3. GitHub 저장소 선택: `jaengseung-made`
|
||||
4. Environment Variables 추가:
|
||||
- `RESEND_API_KEY`: [발급받은 키 붙여넣기]
|
||||
5. "Deploy" 클릭
|
||||
6. 배포 완료! (약 2분)
|
||||
|
||||
### 2단계: 도메인 연결 (jaengseung-made.com)
|
||||
|
||||
**Vercel 설정:**
|
||||
1. Vercel Dashboard → 프로젝트 선택
|
||||
2. "Settings" → "Domains"
|
||||
3. "Add Domain" 클릭
|
||||
4. `jaengseung-made.com` 입력
|
||||
5. DNS 설정 안내 확인
|
||||
|
||||
**가비아 DNS 설정:**
|
||||
1. [가비아 My가비아](https://my.gabia.com) 로그인
|
||||
2. "도메인" → "jaengseung-made.com" 선택
|
||||
3. "DNS 정보" → "DNS 관리" 클릭
|
||||
4. 기존 A 레코드 삭제 (있다면)
|
||||
5. 새 레코드 추가:
|
||||
|
||||
**방법 A: A 레코드 (권장)**
|
||||
```
|
||||
Type: A
|
||||
Host: @
|
||||
Value: 76.76.19.19
|
||||
TTL: 600
|
||||
```
|
||||
|
||||
**방법 B: CNAME 레코드**
|
||||
```
|
||||
Type: CNAME
|
||||
Host: @
|
||||
Value: cname.vercel-dns.com.
|
||||
TTL: 600
|
||||
```
|
||||
|
||||
**www 서브도메인 추가:**
|
||||
```
|
||||
Type: CNAME
|
||||
Host: www
|
||||
Value: cname.vercel-dns.com.
|
||||
TTL: 600
|
||||
```
|
||||
|
||||
6. 저장 후 10~30분 대기
|
||||
7. Vercel에서 자동으로 SSL 인증서 발급 (HTTPS)
|
||||
|
||||
### 3단계: 배포 확인
|
||||
- https://jaengseung-made.com 접속
|
||||
- 문의 폼 테스트 (실제 이메일 발송 확인)
|
||||
|
||||
---
|
||||
|
||||
## 3️⃣ 대안: Gitea + Vercel CLI 직접 배포
|
||||
|
||||
Vercel CLI로 직접 배포:
|
||||
```bash
|
||||
# Vercel CLI 설치
|
||||
npm install -g vercel
|
||||
|
||||
# 프로젝트 폴더에서 실행
|
||||
cd C:\Users\박재오\Desktop\workspace\jaengseung-made
|
||||
|
||||
# 로그인
|
||||
vercel login
|
||||
|
||||
# 배포
|
||||
vercel --prod
|
||||
|
||||
# 환경변수 추가
|
||||
vercel env add RESEND_API_KEY
|
||||
# [발급받은 키 붙여넣기]
|
||||
# Production, Preview, Development 모두 선택
|
||||
|
||||
# 재배포
|
||||
vercel --prod
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4️⃣ Synology NAS 배포 (비추천)
|
||||
|
||||
성능/안정성 이유로 비추천하지만, 원하시면:
|
||||
|
||||
### Docker로 배포
|
||||
1. `Dockerfile` 생성 (이미 있음)
|
||||
2. Docker 이미지 빌드:
|
||||
```bash
|
||||
docker build -t jaengseung-made .
|
||||
```
|
||||
3. 컨테이너 실행:
|
||||
```bash
|
||||
docker run -d -p 3000:3000 \
|
||||
-e RESEND_API_KEY=your_key \
|
||||
--name jaengseung-made \
|
||||
jaengseung-made
|
||||
```
|
||||
4. 포트 포워딩: 라우터에서 80 → NAS IP:3000
|
||||
5. 가비아 DNS: A 레코드를 공인 IP로 설정
|
||||
|
||||
**문제점:**
|
||||
- 느린 속도 (가정용 인터넷)
|
||||
- 다운타임 (정전, 재부팅)
|
||||
- HTTPS 수동 설정 필요 (Let's Encrypt)
|
||||
- 보안 관리 필요
|
||||
|
||||
---
|
||||
|
||||
## 5️⃣ 최종 체크리스트
|
||||
|
||||
### 배포 전
|
||||
- [ ] Resend 계정 생성 및 API Key 발급
|
||||
- [ ] `.env.local`에 API Key 설정
|
||||
- [ ] 로컬에서 문의 폼 테스트 (http://localhost:3000)
|
||||
- [ ] Git 커밋 및 푸시
|
||||
|
||||
### Vercel 배포
|
||||
- [ ] Vercel 계정 생성 (GitHub 연동)
|
||||
- [ ] 프로젝트 배포
|
||||
- [ ] 환경변수 추가 (RESEND_API_KEY)
|
||||
- [ ] 배포 URL에서 테스트
|
||||
|
||||
### 도메인 연결
|
||||
- [ ] Vercel에 도메인 추가
|
||||
- [ ] 가비아 DNS 설정 (A 레코드)
|
||||
- [ ] www 서브도메인 추가 (CNAME)
|
||||
- [ ] SSL 인증서 자동 발급 확인 (10~30분)
|
||||
- [ ] https://jaengseung-made.com 접속 확인
|
||||
|
||||
### 최종 테스트
|
||||
- [ ] 문의 폼 실제 발송 테스트
|
||||
- [ ] bgg8988@gmail.com으로 이메일 수신 확인
|
||||
- [ ] 모바일에서 접속 테스트
|
||||
- [ ] 모든 링크 동작 확인
|
||||
|
||||
### 마케팅
|
||||
- [ ] 크몽 서비스 등록 (포트폴리오 URL 첨부)
|
||||
- [ ] 숨고 프로필 생성
|
||||
- [ ] Google Search Console 등록
|
||||
- [ ] 메타 태그 확인 (이미 적용됨)
|
||||
|
||||
---
|
||||
|
||||
## 🆘 트러블슈팅
|
||||
|
||||
### 문의 폼이 작동하지 않아요
|
||||
1. `.env.local`에 `RESEND_API_KEY` 확인
|
||||
2. Vercel 환경변수 설정 확인
|
||||
3. Resend Dashboard에서 "Logs" 확인
|
||||
4. 브라우저 개발자 도구 → Network 탭 확인
|
||||
|
||||
### 도메인이 연결되지 않아요
|
||||
1. DNS 전파 대기 (최대 24시간, 보통 30분)
|
||||
2. DNS 전파 확인: https://dnschecker.org
|
||||
3. 가비아 DNS 설정 재확인
|
||||
4. Vercel Domain 상태 확인
|
||||
|
||||
### 이메일이 오지 않아요
|
||||
1. Resend Dashboard → "Logs" 확인
|
||||
2. 스팸 메일함 확인
|
||||
3. API Key 권한 확인 (Sending access)
|
||||
4. 도메인 인증 상태 확인 (커스텀 도메인 사용 시)
|
||||
|
||||
---
|
||||
|
||||
## 📞 지원
|
||||
|
||||
배포 관련 문의: bgg8988@gmail.com
|
||||
52
app/api/contact/route.ts
Normal file
52
app/api/contact/route.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { Resend } from 'resend';
|
||||
|
||||
const resend = new Resend(process.env.RESEND_API_KEY);
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { name, phone, email, service, message } = body;
|
||||
|
||||
// 입력 검증
|
||||
if (!name || !email || !message) {
|
||||
return NextResponse.json(
|
||||
{ error: '필수 항목을 모두 입력해주세요.' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// 이메일 발송
|
||||
const data = await resend.emails.send({
|
||||
from: 'contact@jaengseung-made.com', // Resend에서 인증된 도메인
|
||||
to: ['bgg8988@gmail.com'], // 받는 이메일
|
||||
subject: `[쟁승메이드] 새로운 문의: ${service || '문의'}`,
|
||||
html: `
|
||||
<h2>새로운 프로젝트 문의가 도착했습니다</h2>
|
||||
<hr />
|
||||
<p><strong>이름:</strong> ${name}</p>
|
||||
<p><strong>연락처:</strong> ${phone || '미입력'}</p>
|
||||
<p><strong>이메일:</strong> ${email}</p>
|
||||
<p><strong>서비스:</strong> ${service || '미선택'}</p>
|
||||
<hr />
|
||||
<h3>문의 내용:</h3>
|
||||
<p style="white-space: pre-wrap;">${message}</p>
|
||||
<hr />
|
||||
<p style="color: #666; font-size: 12px;">
|
||||
이 메일은 jaengseung-made.com의 문의 폼에서 발송되었습니다.
|
||||
</p>
|
||||
`,
|
||||
});
|
||||
|
||||
return NextResponse.json(
|
||||
{ success: true, message: '문의가 성공적으로 전송되었습니다!' },
|
||||
{ status: 200 }
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Email send error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: '메일 전송에 실패했습니다. 다시 시도해주세요.' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
186
app/components/ContactForm.tsx
Normal file
186
app/components/ContactForm.tsx
Normal file
@@ -0,0 +1,186 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function ContactForm() {
|
||||
const [formData, setFormData] = useState({
|
||||
name: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
service: 'RPA 자동화',
|
||||
message: '',
|
||||
});
|
||||
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
|
||||
const [errorMessage, setErrorMessage] = useState('');
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setStatus('loading');
|
||||
setErrorMessage('');
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/contact', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(formData),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error || '문의 전송에 실패했습니다.');
|
||||
}
|
||||
|
||||
setStatus('success');
|
||||
// 폼 초기화
|
||||
setFormData({
|
||||
name: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
service: 'RPA 자동화',
|
||||
message: '',
|
||||
});
|
||||
|
||||
// 3초 후 성공 메시지 숨기기
|
||||
setTimeout(() => setStatus('idle'), 5000);
|
||||
} catch (error) {
|
||||
setStatus('error');
|
||||
setErrorMessage(error instanceof Error ? error.message : '문의 전송에 실패했습니다.');
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>
|
||||
) => {
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
[e.target.name]: e.target.value,
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white rounded-2xl shadow-xl p-8 md:p-12">
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label className="block text-sm font-semibold text-gray-700 mb-2">
|
||||
이름 <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
value={formData.name}
|
||||
onChange={handleChange}
|
||||
required
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none"
|
||||
placeholder="홍길동"
|
||||
disabled={status === 'loading'}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-semibold text-gray-700 mb-2">연락처</label>
|
||||
<input
|
||||
type="tel"
|
||||
name="phone"
|
||||
value={formData.phone}
|
||||
onChange={handleChange}
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none"
|
||||
placeholder="010-0000-0000"
|
||||
disabled={status === 'loading'}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-semibold text-gray-700 mb-2">
|
||||
이메일 <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
value={formData.email}
|
||||
onChange={handleChange}
|
||||
required
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none"
|
||||
placeholder="example@email.com"
|
||||
disabled={status === 'loading'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-semibold text-gray-700 mb-2">서비스 선택</label>
|
||||
<select
|
||||
name="service"
|
||||
value={formData.service}
|
||||
onChange={handleChange}
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none"
|
||||
disabled={status === 'loading'}
|
||||
>
|
||||
<option>RPA 자동화</option>
|
||||
<option>웹 개발</option>
|
||||
<option>앱 개발</option>
|
||||
<option>맞춤형 솔루션</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-semibold text-gray-700 mb-2">
|
||||
프로젝트 설명 <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<textarea
|
||||
name="message"
|
||||
value={formData.message}
|
||||
onChange={handleChange}
|
||||
required
|
||||
rows={6}
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none resize-none"
|
||||
placeholder="프로젝트에 대해 자세히 설명해주세요. 목적, 예상 기간, 예산 등을 포함하면 더 정확한 상담이 가능합니다."
|
||||
disabled={status === 'loading'}
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
{status === 'success' && (
|
||||
<div className="bg-green-50 border border-green-200 text-green-800 px-4 py-3 rounded-lg">
|
||||
✅ 문의가 성공적으로 전송되었습니다! 24시간 이내 답변드리겠습니다.
|
||||
</div>
|
||||
)}
|
||||
|
||||
{status === 'error' && (
|
||||
<div className="bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded-lg">
|
||||
❌ {errorMessage}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={status === 'loading'}
|
||||
className="w-full bg-blue-700 text-white py-4 rounded-lg text-lg font-bold hover:bg-blue-800 transition shadow-lg disabled:bg-gray-400 disabled:cursor-not-allowed"
|
||||
>
|
||||
{status === 'loading' ? '전송 중...' : '무료 상담 신청하기'}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div className="mt-8 pt-8 border-t border-gray-200">
|
||||
<div className="text-center text-gray-600">
|
||||
<p className="mb-4">또는 아래 연락처로 직접 문의주세요</p>
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<a
|
||||
href="mailto:bgg8988@gmail.com"
|
||||
className="flex items-center justify-center text-blue-700 hover:text-blue-800"
|
||||
>
|
||||
<span className="mr-2">📧</span> bgg8988@gmail.com
|
||||
</a>
|
||||
<a
|
||||
href="tel:010-3907-1392"
|
||||
className="flex items-center justify-center text-blue-700 hover:text-blue-800"
|
||||
>
|
||||
<span className="mr-2">📱</span> 010-3907-1392
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
74
app/page.tsx
74
app/page.tsx
@@ -1,3 +1,5 @@
|
||||
import ContactForm from './components/ContactForm';
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
@@ -331,77 +333,7 @@ export default function Home() {
|
||||
<p className="text-xl text-gray-600">무엇이든 편하게 상담해주세요. 24시간 이내 답변드립니다.</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-white rounded-2xl shadow-xl p-8 md:p-12">
|
||||
<form className="space-y-6">
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label className="block text-sm font-semibold text-gray-700 mb-2">이름</label>
|
||||
<input
|
||||
type="text"
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none"
|
||||
placeholder="홍길동"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-semibold text-gray-700 mb-2">연락처</label>
|
||||
<input
|
||||
type="tel"
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none"
|
||||
placeholder="010-0000-0000"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-semibold text-gray-700 mb-2">이메일</label>
|
||||
<input
|
||||
type="email"
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none"
|
||||
placeholder="example@email.com"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-semibold text-gray-700 mb-2">서비스 선택</label>
|
||||
<select className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none">
|
||||
<option>RPA 자동화</option>
|
||||
<option>웹 개발</option>
|
||||
<option>앱 개발</option>
|
||||
<option>맞춤형 솔루션</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-semibold text-gray-700 mb-2">프로젝트 설명</label>
|
||||
<textarea
|
||||
rows={6}
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none resize-none"
|
||||
placeholder="프로젝트에 대해 자세히 설명해주세요. 목적, 예상 기간, 예산 등을 포함하면 더 정확한 상담이 가능합니다."
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-blue-700 text-white py-4 rounded-lg text-lg font-bold hover:bg-blue-800 transition shadow-lg"
|
||||
>
|
||||
무료 상담 신청하기
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div className="mt-8 pt-8 border-t border-gray-200">
|
||||
<div className="text-center text-gray-600">
|
||||
<p className="mb-4">또는 아래 연락처로 직접 문의주세요</p>
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<a href="mailto:bgg8988@gmail.com" className="flex items-center justify-center text-blue-700 hover:text-blue-800">
|
||||
<span className="mr-2">📧</span> bgg8988@gmail.com
|
||||
</a>
|
||||
<a href="tel:010-3907-1392" className="flex items-center justify-center text-blue-700 hover:text-blue-800">
|
||||
<span className="mr-2">📱</span> 010-3907-1392
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ContactForm />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
383
package-lock.json
generated
383
package-lock.json
generated
@@ -10,7 +10,8 @@
|
||||
"dependencies": {
|
||||
"next": "16.1.6",
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3"
|
||||
"react-dom": "19.2.3",
|
||||
"resend": "^6.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4",
|
||||
@@ -1233,6 +1234,25 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@selderee/plugin-htmlparser2": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
|
||||
"integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"domhandler": "^5.0.3",
|
||||
"selderee": "^0.11.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/killymxi"
|
||||
}
|
||||
},
|
||||
"node_modules/@stablelib/base64": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz",
|
||||
"integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.15",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
||||
@@ -2113,6 +2133,17 @@
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@zone-eu/mailsplit": {
|
||||
"version": "5.4.8",
|
||||
"resolved": "https://registry.npmjs.org/@zone-eu/mailsplit/-/mailsplit-5.4.8.tgz",
|
||||
"integrity": "sha512-eEyACj4JZ7sjzRvy26QhLgKEMWwQbsw1+QZnlLX+/gihcNH07lVPOcnwf5U6UAL7gkc//J3jVd76o/WS+taUiA==",
|
||||
"license": "(MIT OR EUPL-1.1+)",
|
||||
"dependencies": {
|
||||
"libbase64": "1.3.0",
|
||||
"libmime": "5.3.7",
|
||||
"libqp": "2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
@@ -2718,6 +2749,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/deepmerge": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/define-data-property": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
||||
@@ -2777,6 +2817,61 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dom-serializer": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
"entities": "^4.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/domelementtype": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
|
||||
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
],
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/domhandler": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
|
||||
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
@@ -2806,6 +2901,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/encoding-japanese": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/encoding-japanese/-/encoding-japanese-2.2.0.tgz",
|
||||
"integrity": "sha512-EuJWwlHPZ1LbADuKTClvHtwbaFn4rOD+dRAbWysqEOXRc2Uui0hJInNJrsdH0c+OhJA4nrCBdSkW4DD5YxAo6A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.19.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz",
|
||||
@@ -2820,6 +2924,18 @@
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/es-abstract": {
|
||||
"version": "1.24.1",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz",
|
||||
@@ -3495,6 +3611,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-sha256": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz",
|
||||
"integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==",
|
||||
"license": "Unlicense"
|
||||
},
|
||||
"node_modules/fastq": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
|
||||
@@ -3873,6 +3995,15 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/hermes-estree": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz",
|
||||
@@ -3890,6 +4021,57 @@
|
||||
"hermes-estree": "0.25.1"
|
||||
}
|
||||
},
|
||||
"node_modules/html-to-text": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz",
|
||||
"integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@selderee/plugin-htmlparser2": "^0.11.0",
|
||||
"deepmerge": "^4.3.1",
|
||||
"dom-serializer": "^2.0.0",
|
||||
"htmlparser2": "^8.0.2",
|
||||
"selderee": "^0.11.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
|
||||
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
|
||||
"funding": [
|
||||
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3",
|
||||
"domutils": "^3.0.1",
|
||||
"entities": "^4.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
|
||||
"integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
@@ -4512,6 +4694,15 @@
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/leac": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz",
|
||||
"integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/killymxi"
|
||||
}
|
||||
},
|
||||
"node_modules/levn": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
||||
@@ -4526,6 +4717,42 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/libbase64": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.3.0.tgz",
|
||||
"integrity": "sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/libmime": {
|
||||
"version": "5.3.7",
|
||||
"resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.7.tgz",
|
||||
"integrity": "sha512-FlDb3Wtha8P01kTL3P9M+ZDNDWPKPmKHWaU/cG/lg5pfuAwdflVpZE+wm9m7pKmC5ww6s+zTxBKS1p6yl3KpSw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"encoding-japanese": "2.2.0",
|
||||
"iconv-lite": "0.6.3",
|
||||
"libbase64": "1.3.0",
|
||||
"libqp": "2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/libmime/node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/libqp": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/libqp/-/libqp-2.1.1.tgz",
|
||||
"integrity": "sha512-0Wd+GPz1O134cP62YU2GTOPNA7Qgl09XwCqM5zpBv87ERCXdfDtyKXvV7c9U22yWJh44QZqBocFnXN11K96qow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lightningcss": {
|
||||
"version": "1.30.2",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz",
|
||||
@@ -4787,6 +5014,15 @@
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/linkify-it": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"uc.micro": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
@@ -4843,6 +5079,24 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/mailparser": {
|
||||
"version": "3.9.1",
|
||||
"resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.9.1.tgz",
|
||||
"integrity": "sha512-6vHZcco3fWsDMkf4Vz9iAfxvwrKNGbHx0dV1RKVphQ/zaNY34Buc7D37LSa09jeSeybWzYcTPjhiZFxzVRJedA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@zone-eu/mailsplit": "5.4.8",
|
||||
"encoding-japanese": "2.2.0",
|
||||
"he": "1.2.0",
|
||||
"html-to-text": "9.0.5",
|
||||
"iconv-lite": "0.7.0",
|
||||
"libmime": "5.3.7",
|
||||
"linkify-it": "5.0.0",
|
||||
"nodemailer": "7.0.11",
|
||||
"punycode.js": "2.3.1",
|
||||
"tlds": "1.261.0"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
@@ -5036,6 +5290,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nodemailer": {
|
||||
"version": "7.0.11",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.11.tgz",
|
||||
"integrity": "sha512-gnXhNRE0FNhD7wPSCGhdNh46Hs6nm+uTyg+Kq0cZukNQiYdnCsoQjodNP9BQVG9XrcK/v6/MgpAPBUFyzh9pvw==",
|
||||
"license": "MIT-0",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
@@ -5240,6 +5503,19 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/parseley": {
|
||||
"version": "0.12.1",
|
||||
"resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz",
|
||||
"integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"leac": "^0.6.0",
|
||||
"peberminta": "^0.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/killymxi"
|
||||
}
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
@@ -5267,6 +5543,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/peberminta": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz",
|
||||
"integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/killymxi"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
@@ -5357,6 +5642,15 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/punycode.js": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
|
||||
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
@@ -5450,6 +5744,27 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/resend": {
|
||||
"version": "6.9.1",
|
||||
"resolved": "https://registry.npmjs.org/resend/-/resend-6.9.1.tgz",
|
||||
"integrity": "sha512-jFY3qPP2cith1npRXvS7PVdnhbR1CcuzHg65ty5Elv55GKiXhe+nItXuzzoOlKeYJez1iJAo2+8f6ae8sCj0iA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mailparser": "3.9.1",
|
||||
"svix": "1.84.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-email/render": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@react-email/render": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.11",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
|
||||
@@ -5581,12 +5896,30 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
|
||||
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/selderee": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz",
|
||||
"integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"parseley": "^0.12.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/killymxi"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
@@ -5819,6 +6152,16 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/standardwebhooks": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz",
|
||||
"integrity": "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stablelib/base64": "^1.0.0",
|
||||
"fast-sha256": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/stop-iteration-iterator": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
|
||||
@@ -6018,6 +6361,16 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/svix": {
|
||||
"version": "1.84.1",
|
||||
"resolved": "https://registry.npmjs.org/svix/-/svix-1.84.1.tgz",
|
||||
"integrity": "sha512-K8DPPSZaW/XqXiz1kEyzSHYgmGLnhB43nQCMeKjWGCUpLIpAMMM8kx3rVVOSm6Bo6EHyK1RQLPT4R06skM/MlQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"standardwebhooks": "1.0.0",
|
||||
"uuid": "^10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "4.1.18",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
|
||||
@@ -6087,6 +6440,15 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/tlds": {
|
||||
"version": "1.261.0",
|
||||
"resolved": "https://registry.npmjs.org/tlds/-/tlds-1.261.0.tgz",
|
||||
"integrity": "sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"tlds": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
@@ -6274,6 +6636,12 @@
|
||||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uc.micro": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
|
||||
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/unbox-primitive": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
|
||||
@@ -6376,6 +6744,19 @@
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
|
||||
"integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
"dependencies": {
|
||||
"next": "16.1.6",
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3"
|
||||
"react-dom": "19.2.3",
|
||||
"resend": "^6.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4",
|
||||
|
||||
Reference in New Issue
Block a user